ng-module-imports.js 3.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. "use strict";
  2. /**
  3. * @license
  4. * Copyright Google LLC All Rights Reserved.
  5. *
  6. * Use of this source code is governed by an MIT-style license that can be
  7. * found in the LICENSE file at https://angular.dev/license
  8. */
  9. Object.defineProperty(exports, "__esModule", { value: true });
  10. exports.hasNgModuleImport = hasNgModuleImport;
  11. const schematics_1 = require("@angular-devkit/schematics");
  12. const ts = require("typescript");
  13. /**
  14. * Whether the Angular module in the given path imports the specified module class name.
  15. */
  16. function hasNgModuleImport(tree, modulePath, className) {
  17. const moduleFileContent = tree.read(modulePath);
  18. if (!moduleFileContent) {
  19. throw new schematics_1.SchematicsException(`Could not read Angular module file: ${modulePath}`);
  20. }
  21. const parsedFile = ts.createSourceFile(modulePath, moduleFileContent.toString(), ts.ScriptTarget.Latest, true);
  22. const ngModuleMetadata = findNgModuleMetadata(parsedFile);
  23. if (!ngModuleMetadata) {
  24. throw new schematics_1.SchematicsException(`Could not find NgModule declaration inside: "${modulePath}"`);
  25. }
  26. for (let property of ngModuleMetadata.properties) {
  27. if (!ts.isPropertyAssignment(property) ||
  28. property.name.getText() !== 'imports' ||
  29. !ts.isArrayLiteralExpression(property.initializer)) {
  30. continue;
  31. }
  32. if (property.initializer.elements.some(element => element.getText() === className)) {
  33. return true;
  34. }
  35. }
  36. return false;
  37. }
  38. /**
  39. * Resolves the last identifier that is part of the given expression. This helps resolving
  40. * identifiers of nested property access expressions (e.g. myNamespace.core.NgModule).
  41. */
  42. function resolveIdentifierOfExpression(expression) {
  43. if (ts.isIdentifier(expression)) {
  44. return expression;
  45. }
  46. else if (ts.isPropertyAccessExpression(expression) && ts.isIdentifier(expression.name)) {
  47. return expression.name;
  48. }
  49. return null;
  50. }
  51. /**
  52. * Finds a NgModule declaration within the specified TypeScript node and returns the
  53. * corresponding metadata for it. This function searches breadth first because
  54. * NgModule's are usually not nested within other expressions or declarations.
  55. */
  56. function findNgModuleMetadata(rootNode) {
  57. // Add immediate child nodes of the root node to the queue.
  58. const nodeQueue = [...rootNode.getChildren()];
  59. while (nodeQueue.length) {
  60. const node = nodeQueue.shift();
  61. if (ts.isDecorator(node) &&
  62. ts.isCallExpression(node.expression) &&
  63. isNgModuleCallExpression(node.expression)) {
  64. return node.expression.arguments[0];
  65. }
  66. else {
  67. nodeQueue.push(...node.getChildren());
  68. }
  69. }
  70. return null;
  71. }
  72. /** Whether the specified call expression is referring to a NgModule definition. */
  73. function isNgModuleCallExpression(callExpression) {
  74. if (!callExpression.arguments.length ||
  75. !ts.isObjectLiteralExpression(callExpression.arguments[0])) {
  76. return false;
  77. }
  78. // The `NgModule` call expression name is never referring to a `PrivateIdentifier`.
  79. const decoratorIdentifier = resolveIdentifierOfExpression(callExpression.expression);
  80. return decoratorIdentifier ? decoratorIdentifier.text === 'NgModule' : false;
  81. }
  82. //# sourceMappingURL=ng-module-imports.js.map