Skip to content

Commit 16a8800

Browse files
devversionvivian-hu-zz
authored andcommitted
chore(schematics): better NgModule search logic (#14449)
* Similarly to #12636 (comment), I want to improve the logic for finding `NgModule` declarations within a source file by using BFS.
1 parent 7c2bfde commit 16a8800

File tree

1 file changed

+24
-13
lines changed

1 file changed

+24
-13
lines changed

src/cdk/schematics/utils/ast/ng-module-imports.ts

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,7 @@ export function hasNgModuleImport(tree: Tree, modulePath: string, className: str
2121

2222
const parsedFile = ts.createSourceFile(modulePath, moduleFileContent.toString(),
2323
ts.ScriptTarget.Latest, true);
24-
let ngModuleMetadata: ts.ObjectLiteralExpression | null = null;
25-
26-
const findModuleDecorator = (node: ts.Node) => {
27-
if (ts.isDecorator(node) && ts.isCallExpression(node.expression) &&
28-
isNgModuleCallExpression(node.expression)) {
29-
ngModuleMetadata = node.expression.arguments[0] as ts.ObjectLiteralExpression;
30-
return;
31-
}
32-
33-
ts.forEachChild(node, findModuleDecorator);
34-
};
35-
36-
ts.forEachChild(parsedFile, findModuleDecorator);
24+
const ngModuleMetadata = findNgModuleMetadata(parsedFile);
3725

3826
if (!ngModuleMetadata) {
3927
throw new SchematicsException(`Could not find NgModule declaration inside: "${modulePath}"`);
@@ -66,6 +54,29 @@ function resolveIdentifierOfExpression(expression: ts.Expression): ts.Identifier
6654
return null;
6755
}
6856

57+
/**
58+
* Finds a NgModule declaration within the specified TypeScript node and returns the
59+
* corresponding metadata for it. This function searches breadth first because
60+
* NgModule's are usually not nested within other expressions or declarations.
61+
*/
62+
function findNgModuleMetadata(rootNode: ts.Node): ts.ObjectLiteralExpression | null {
63+
// Add immediate child nodes of the root node to the queue.
64+
const nodeQueue: ts.Node[] = [...rootNode.getChildren()];
65+
66+
while (nodeQueue.length) {
67+
const node = nodeQueue.shift()!;
68+
69+
if (ts.isDecorator(node) && ts.isCallExpression(node.expression) &&
70+
isNgModuleCallExpression(node.expression)) {
71+
return node.expression.arguments[0] as ts.ObjectLiteralExpression;
72+
} else {
73+
nodeQueue.push(...node.getChildren());
74+
}
75+
}
76+
77+
return null;
78+
}
79+
6980
/** Whether the specified call expression is referring to a NgModule definition. */
7081
function isNgModuleCallExpression(callExpression: ts.CallExpression): boolean {
7182
if (!callExpression.arguments.length ||

0 commit comments

Comments
 (0)