feat(angular): add ast utils for standalone decorators (#14108)
This commit is contained in:
parent
666e057a50
commit
64d7ceb447
154
packages/angular/src/utils/nx-devkit/ast-utils.spec.ts
Normal file
154
packages/angular/src/utils/nx-devkit/ast-utils.spec.ts
Normal file
@ -0,0 +1,154 @@
|
||||
import {
|
||||
addImportToComponent,
|
||||
addImportToDirective,
|
||||
addImportToModule,
|
||||
addImportToPipe,
|
||||
} from './ast-utils';
|
||||
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
||||
import { createSourceFile, ScriptTarget } from 'typescript';
|
||||
|
||||
describe('Angular AST Utils', () => {
|
||||
it('should correctly add the imported symbol to the NgModule', () => {
|
||||
// ARRANGE
|
||||
const tree = createTreeWithEmptyWorkspace();
|
||||
const pathToModule = `my.module.ts`;
|
||||
const originalContents = `import { NgModule } from '@angular/core';
|
||||
|
||||
@NgModule({})
|
||||
export class MyModule {}
|
||||
`;
|
||||
|
||||
tree.write(pathToModule, originalContents);
|
||||
|
||||
const symbolToAdd = `CommonModule`;
|
||||
|
||||
const sourceText = tree.read(pathToModule, 'utf-8');
|
||||
const tsSourceFile = createSourceFile(
|
||||
pathToModule,
|
||||
sourceText,
|
||||
ScriptTarget.Latest,
|
||||
true
|
||||
);
|
||||
|
||||
// ACT
|
||||
addImportToModule(tree, tsSourceFile, pathToModule, symbolToAdd);
|
||||
|
||||
// ASSERT
|
||||
expect(tree.read(pathToModule, 'utf-8')).toMatchInlineSnapshot(`
|
||||
"import { NgModule } from '@angular/core';
|
||||
|
||||
@NgModule({ imports: [CommonModule]
|
||||
})
|
||||
export class MyModule {}
|
||||
"
|
||||
`);
|
||||
});
|
||||
|
||||
it('should correctly add the imported symbol to the Component', () => {
|
||||
// ARRANGE
|
||||
const tree = createTreeWithEmptyWorkspace();
|
||||
const pathToFile = `my.component.ts`;
|
||||
const originalContents = `import { Component } from '@angular/core';
|
||||
|
||||
@Component({})
|
||||
export class MyComponent {}
|
||||
`;
|
||||
|
||||
tree.write(pathToFile, originalContents);
|
||||
|
||||
const symbolToAdd = `CommonModule`;
|
||||
|
||||
const sourceText = tree.read(pathToFile, 'utf-8');
|
||||
const tsSourceFile = createSourceFile(
|
||||
pathToFile,
|
||||
sourceText,
|
||||
ScriptTarget.Latest,
|
||||
true
|
||||
);
|
||||
|
||||
// ACT
|
||||
addImportToComponent(tree, tsSourceFile, pathToFile, symbolToAdd);
|
||||
|
||||
// ASSERT
|
||||
expect(tree.read(pathToFile, 'utf-8')).toMatchInlineSnapshot(`
|
||||
"import { Component } from '@angular/core';
|
||||
|
||||
@Component({ imports: [CommonModule]
|
||||
})
|
||||
export class MyComponent {}
|
||||
"
|
||||
`);
|
||||
});
|
||||
|
||||
it('should correctly add the imported symbol to the Directive', () => {
|
||||
// ARRANGE
|
||||
const tree = createTreeWithEmptyWorkspace();
|
||||
const pathToFile = `my.directive.ts`;
|
||||
const originalContents = `import { Directive } from '@angular/core';
|
||||
|
||||
@Directive({})
|
||||
export class MyDirective {}
|
||||
`;
|
||||
|
||||
tree.write(pathToFile, originalContents);
|
||||
|
||||
const symbolToAdd = `CommonModule`;
|
||||
|
||||
const sourceText = tree.read(pathToFile, 'utf-8');
|
||||
const tsSourceFile = createSourceFile(
|
||||
pathToFile,
|
||||
sourceText,
|
||||
ScriptTarget.Latest,
|
||||
true
|
||||
);
|
||||
|
||||
// ACT
|
||||
addImportToDirective(tree, tsSourceFile, pathToFile, symbolToAdd);
|
||||
|
||||
// ASSERT
|
||||
expect(tree.read(pathToFile, 'utf-8')).toMatchInlineSnapshot(`
|
||||
"import { Directive } from '@angular/core';
|
||||
|
||||
@Directive({ imports: [CommonModule]
|
||||
})
|
||||
export class MyDirective {}
|
||||
"
|
||||
`);
|
||||
});
|
||||
|
||||
it('should correctly add the imported symbol to the Pipe', () => {
|
||||
// ARRANGE
|
||||
const tree = createTreeWithEmptyWorkspace();
|
||||
const pathToFile = `my.pipe.ts`;
|
||||
const originalContents = `import { Pipe } from '@angular/core';
|
||||
|
||||
@Pipe({})
|
||||
export class MyPipe {}
|
||||
`;
|
||||
|
||||
tree.write(pathToFile, originalContents);
|
||||
|
||||
const symbolToAdd = `CommonModule`;
|
||||
|
||||
const sourceText = tree.read(pathToFile, 'utf-8');
|
||||
const tsSourceFile = createSourceFile(
|
||||
pathToFile,
|
||||
sourceText,
|
||||
ScriptTarget.Latest,
|
||||
true
|
||||
);
|
||||
|
||||
// ACT
|
||||
addImportToPipe(tree, tsSourceFile, pathToFile, symbolToAdd);
|
||||
|
||||
// ASSERT
|
||||
expect(tree.read(pathToFile, 'utf-8')).toMatchInlineSnapshot(`
|
||||
"import { Pipe } from '@angular/core';
|
||||
|
||||
@Pipe({ imports: [CommonModule]
|
||||
})
|
||||
export class MyPipe {}
|
||||
"
|
||||
`);
|
||||
});
|
||||
});
|
||||
@ -128,14 +128,15 @@ export function getDecoratorMetadata(
|
||||
.map((expr) => expr.arguments[0] as ts.ObjectLiteralExpression);
|
||||
}
|
||||
|
||||
function _addSymbolToNgModuleMetadata(
|
||||
function _addSymbolToDecoratorMetadata(
|
||||
host: Tree,
|
||||
source: ts.SourceFile,
|
||||
ngModulePath: string,
|
||||
filePath: string,
|
||||
metadataField: string,
|
||||
expression: string
|
||||
expression: string,
|
||||
decoratorName: 'Component' | 'Directive' | 'NgModule' | 'Pipe'
|
||||
): ts.SourceFile {
|
||||
const nodes = getDecoratorMetadata(source, 'NgModule', '@angular/core');
|
||||
const nodes = getDecoratorMetadata(source, decoratorName, '@angular/core');
|
||||
let node: any = nodes[0]; // tslint:disable-line:no-any
|
||||
|
||||
// Find the decorator declaration.
|
||||
@ -187,7 +188,7 @@ function _addSymbolToNgModuleMetadata(
|
||||
}
|
||||
}
|
||||
|
||||
return insertChange(host, source, ngModulePath, position, toInsert);
|
||||
return insertChange(host, source, filePath, position, toInsert);
|
||||
}
|
||||
|
||||
const assignment = matchingProperties[0] as ts.PropertyAssignment;
|
||||
@ -259,7 +260,24 @@ function _addSymbolToNgModuleMetadata(
|
||||
toInsert = `, ${expression}`;
|
||||
}
|
||||
}
|
||||
return insertChange(host, source, ngModulePath, position, toInsert);
|
||||
return insertChange(host, source, filePath, position, toInsert);
|
||||
}
|
||||
|
||||
function _addSymbolToNgModuleMetadata(
|
||||
host: Tree,
|
||||
source: ts.SourceFile,
|
||||
ngModulePath: string,
|
||||
metadataField: string,
|
||||
expression: string
|
||||
): ts.SourceFile {
|
||||
return _addSymbolToDecoratorMetadata(
|
||||
host,
|
||||
source,
|
||||
ngModulePath,
|
||||
metadataField,
|
||||
expression,
|
||||
'NgModule'
|
||||
);
|
||||
}
|
||||
|
||||
export function removeFromNgModule(
|
||||
@ -294,6 +312,54 @@ export function removeFromNgModule(
|
||||
}
|
||||
}
|
||||
|
||||
export function addImportToComponent(
|
||||
host: Tree,
|
||||
source: ts.SourceFile,
|
||||
componentPath: string,
|
||||
symbolName: string
|
||||
): ts.SourceFile {
|
||||
return _addSymbolToDecoratorMetadata(
|
||||
host,
|
||||
source,
|
||||
componentPath,
|
||||
'imports',
|
||||
symbolName,
|
||||
'Component'
|
||||
);
|
||||
}
|
||||
|
||||
export function addImportToDirective(
|
||||
host: Tree,
|
||||
source: ts.SourceFile,
|
||||
directivePath: string,
|
||||
symbolName: string
|
||||
): ts.SourceFile {
|
||||
return _addSymbolToDecoratorMetadata(
|
||||
host,
|
||||
source,
|
||||
directivePath,
|
||||
'imports',
|
||||
symbolName,
|
||||
'Directive'
|
||||
);
|
||||
}
|
||||
|
||||
export function addImportToPipe(
|
||||
host: Tree,
|
||||
source: ts.SourceFile,
|
||||
pipePath: string,
|
||||
symbolName: string
|
||||
): ts.SourceFile {
|
||||
return _addSymbolToDecoratorMetadata(
|
||||
host,
|
||||
source,
|
||||
pipePath,
|
||||
'imports',
|
||||
symbolName,
|
||||
'Pipe'
|
||||
);
|
||||
}
|
||||
|
||||
export function addImportToModule(
|
||||
host: Tree,
|
||||
source: ts.SourceFile,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user