chore(schematics): better NgModule search logic (#14449)

* Similarly to https://github.com/angular/material2/pull/12636#discussion_r209788320, I want to improve the logic for finding `NgModule` declarations within a source file by using BFS.
This commit is contained in:
Paul Gschwendtner
2018-12-11 23:56:46 +01:00
committed by vivian-hu
parent 7c2bfdebb4
commit 16a88002fc
@@ -21,19 +21,7 @@ export function hasNgModuleImport(tree: Tree, modulePath: string, className: str
const parsedFile = ts.createSourceFile(modulePath, moduleFileContent.toString(),
ts.ScriptTarget.Latest, true);
let ngModuleMetadata: ts.ObjectLiteralExpression | null = null;
const findModuleDecorator = (node: ts.Node) => {
if (ts.isDecorator(node) && ts.isCallExpression(node.expression) &&
isNgModuleCallExpression(node.expression)) {
ngModuleMetadata = node.expression.arguments[0] as ts.ObjectLiteralExpression;
return;
}
ts.forEachChild(node, findModuleDecorator);
};
ts.forEachChild(parsedFile, findModuleDecorator);
const ngModuleMetadata = findNgModuleMetadata(parsedFile);
if (!ngModuleMetadata) {
throw new SchematicsException(`Could not find NgModule declaration inside: "${modulePath}"`);
@@ -66,6 +54,29 @@ function resolveIdentifierOfExpression(expression: ts.Expression): ts.Identifier
return null;
}
/**
* Finds a NgModule declaration within the specified TypeScript node and returns the
* corresponding metadata for it. This function searches breadth first because
* NgModule's are usually not nested within other expressions or declarations.
*/
function findNgModuleMetadata(rootNode: ts.Node): ts.ObjectLiteralExpression | null {
// Add immediate child nodes of the root node to the queue.
const nodeQueue: ts.Node[] = [...rootNode.getChildren()];
while (nodeQueue.length) {
const node = nodeQueue.shift()!;
if (ts.isDecorator(node) && ts.isCallExpression(node.expression) &&
isNgModuleCallExpression(node.expression)) {
return node.expression.arguments[0] as ts.ObjectLiteralExpression;
} else {
nodeQueue.push(...node.getChildren());
}
}
return null;
}
/** Whether the specified call expression is referring to a NgModule definition. */
function isNgModuleCallExpression(callExpression: ts.CallExpression): boolean {
if (!callExpression.arguments.length ||