diff --git a/packages/angular/src/utils/nx-devkit/ast-utils.spec.ts b/packages/angular/src/utils/nx-devkit/ast-utils.spec.ts index c26ff6c147..f438acd2cf 100644 --- a/packages/angular/src/utils/nx-devkit/ast-utils.spec.ts +++ b/packages/angular/src/utils/nx-devkit/ast-utils.spec.ts @@ -3,6 +3,7 @@ import { addImportToDirective, addImportToModule, addImportToPipe, + isStandalone, } from './ast-utils'; import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; import { createSourceFile, ScriptTarget } from 'typescript'; @@ -151,4 +152,112 @@ describe('Angular AST Utils', () => { " `); }); + + it('should allow checking if a component is standalone and return true if so', () => { + // ARRANGE + const tree = createTreeWithEmptyWorkspace(); + const pathToFile = `my.component.ts`; + const originalContents = `import { Component } from '@angular/core'; + + @Component({ + standalone: true + }) + export class MyComponent {} + `; + + tree.write(pathToFile, originalContents); + + const sourceText = tree.read(pathToFile, 'utf-8'); + const tsSourceFile = createSourceFile( + pathToFile, + sourceText, + ScriptTarget.Latest, + true + ); + + // ACT + // ASSERT + expect(isStandalone(tsSourceFile, 'Component')).toBeTruthy(); + }); + + it('should allow checking if a component is standalone and return false if not', () => { + // ARRANGE + const tree = createTreeWithEmptyWorkspace(); + const pathToFile = `my.component.ts`; + const originalContents = `import { Component } from '@angular/core'; + + @Component({ + standalone: false + }) + export class MyComponent {} + `; + + tree.write(pathToFile, originalContents); + + const sourceText = tree.read(pathToFile, 'utf-8'); + const tsSourceFile = createSourceFile( + pathToFile, + sourceText, + ScriptTarget.Latest, + true + ); + + // ACT + // ASSERT + expect(isStandalone(tsSourceFile, 'Component')).not.toBeTruthy(); + }); + + it('should allow checking if a directive is standalone and return true if so', () => { + // ARRANGE + const tree = createTreeWithEmptyWorkspace(); + const pathToFile = `my.directive.ts`; + const originalContents = `import { Directive } from '@angular/core'; + + @Directive({ + standalone: true + }) + export class MyDirective {} + `; + + tree.write(pathToFile, originalContents); + + const sourceText = tree.read(pathToFile, 'utf-8'); + const tsSourceFile = createSourceFile( + pathToFile, + sourceText, + ScriptTarget.Latest, + true + ); + + // ACT + // ASSERT + expect(isStandalone(tsSourceFile, 'Directive')).toBeTruthy(); + }); + + it('should allow checking if a pipe is standalone and return true if so', () => { + // ARRANGE + const tree = createTreeWithEmptyWorkspace(); + const pathToFile = `my.pipe.ts`; + const originalContents = `import { Pipe } from '@angular/core'; + + @Pipe({ + standalone: true + }) + export class MyPipe {} + `; + + tree.write(pathToFile, originalContents); + + const sourceText = tree.read(pathToFile, 'utf-8'); + const tsSourceFile = createSourceFile( + pathToFile, + sourceText, + ScriptTarget.Latest, + true + ); + + // ACT + // ASSERT + expect(isStandalone(tsSourceFile, 'Pipe')).toBeTruthy(); + }); }); diff --git a/packages/angular/src/utils/nx-devkit/ast-utils.ts b/packages/angular/src/utils/nx-devkit/ast-utils.ts index 079cda7a4c..9e4dc05a79 100644 --- a/packages/angular/src/utils/nx-devkit/ast-utils.ts +++ b/packages/angular/src/utils/nx-devkit/ast-utils.ts @@ -10,6 +10,8 @@ import { replaceChange, } from '@nrwl/workspace/src/utilities/ast-utils'; +type DecoratorName = 'Component' | 'Directive' | 'NgModule' | 'Pipe'; + function _angularImportsFromNode( node: ts.ImportDeclaration, _sourceFile: ts.SourceFile @@ -62,6 +64,20 @@ function _angularImportsFromNode( } } +export function isStandalone( + sourceFile: ts.SourceFile, + decoratorName: DecoratorName +) { + const decoratorMetadata = getDecoratorMetadata( + sourceFile, + decoratorName, + '@angular/core' + ); + return decoratorMetadata.some((node) => + node.getText().includes('standalone: true') + ); +} + export function getDecoratorMetadata( source: ts.SourceFile, identifier: string, @@ -134,7 +150,7 @@ function _addSymbolToDecoratorMetadata( filePath: string, metadataField: string, expression: string, - decoratorName: 'Component' | 'Directive' | 'NgModule' | 'Pipe' + decoratorName: DecoratorName ): ts.SourceFile { const nodes = getDecoratorMetadata(source, decoratorName, '@angular/core'); let node: any = nodes[0]; // tslint:disable-line:no-any