util.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  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. var __importDefault = (this && this.__importDefault) || function (mod) {
  10. return (mod && mod.__esModule) ? mod : { "default": mod };
  11. };
  12. Object.defineProperty(exports, "__esModule", { value: true });
  13. exports.getMainFilePath = getMainFilePath;
  14. exports.getSourceFile = getSourceFile;
  15. exports.findBootstrapApplicationCall = findBootstrapApplicationCall;
  16. exports.applyChangesToFile = applyChangesToFile;
  17. exports.isMergeAppConfigCall = isMergeAppConfigCall;
  18. exports.findProvidersLiteral = findProvidersLiteral;
  19. const schematics_1 = require("@angular-devkit/schematics");
  20. const typescript_1 = __importDefault(require("../../third_party/github.com/Microsoft/TypeScript/lib/typescript"));
  21. const change_1 = require("../change");
  22. const project_targets_1 = require("../project-targets");
  23. const workspace_1 = require("../workspace");
  24. const workspace_models_1 = require("../workspace-models");
  25. /**
  26. * Finds the main file of a project.
  27. * @param tree File tree for the project.
  28. * @param projectName Name of the project in which to search.
  29. */
  30. async function getMainFilePath(tree, projectName) {
  31. const workspace = await (0, workspace_1.getWorkspace)(tree);
  32. const project = workspace.projects.get(projectName);
  33. const buildTarget = project?.targets.get('build');
  34. if (!buildTarget) {
  35. throw (0, project_targets_1.targetBuildNotFoundError)();
  36. }
  37. const options = buildTarget.options;
  38. return buildTarget.builder === workspace_models_1.Builders.Application ||
  39. buildTarget.builder === workspace_models_1.Builders.BuildApplication
  40. ? options.browser
  41. : options.main;
  42. }
  43. /**
  44. * Gets a TypeScript source file at a specific path.
  45. * @param tree File tree of a project.
  46. * @param path Path to the file.
  47. */
  48. function getSourceFile(tree, path) {
  49. const content = tree.readText(path);
  50. const source = typescript_1.default.createSourceFile(path, content, typescript_1.default.ScriptTarget.Latest, true);
  51. return source;
  52. }
  53. /** Finds the call to `bootstrapApplication` within a file. */
  54. function findBootstrapApplicationCall(tree, mainFilePath) {
  55. const sourceFile = getSourceFile(tree, mainFilePath);
  56. const localName = findImportLocalName(sourceFile, 'bootstrapApplication', '@angular/platform-browser');
  57. if (localName) {
  58. let result = null;
  59. sourceFile.forEachChild(function walk(node) {
  60. if (typescript_1.default.isCallExpression(node) &&
  61. typescript_1.default.isIdentifier(node.expression) &&
  62. node.expression.text === localName) {
  63. result = node;
  64. }
  65. if (!result) {
  66. node.forEachChild(walk);
  67. }
  68. });
  69. if (result) {
  70. return result;
  71. }
  72. }
  73. throw new schematics_1.SchematicsException(`Could not find bootstrapApplication call in ${mainFilePath}`);
  74. }
  75. /**
  76. * Finds the local name of an imported symbol. Could be the symbol name itself or its alias.
  77. * @param sourceFile File within which to search for the import.
  78. * @param name Actual name of the import, not its local alias.
  79. * @param moduleName Name of the module from which the symbol is imported.
  80. */
  81. function findImportLocalName(sourceFile, name, moduleName) {
  82. for (const node of sourceFile.statements) {
  83. // Only look for top-level imports.
  84. if (!typescript_1.default.isImportDeclaration(node) ||
  85. !typescript_1.default.isStringLiteral(node.moduleSpecifier) ||
  86. node.moduleSpecifier.text !== moduleName) {
  87. continue;
  88. }
  89. // Filter out imports that don't have the right shape.
  90. if (!node.importClause ||
  91. !node.importClause.namedBindings ||
  92. !typescript_1.default.isNamedImports(node.importClause.namedBindings)) {
  93. continue;
  94. }
  95. // Look through the elements of the declaration for the specific import.
  96. for (const element of node.importClause.namedBindings.elements) {
  97. if ((element.propertyName || element.name).text === name) {
  98. // The local name is always in `name`.
  99. return element.name.text;
  100. }
  101. }
  102. }
  103. return null;
  104. }
  105. /**
  106. * Applies a set of changes to a file.
  107. * @param tree File tree of the project.
  108. * @param path Path to the file that is being changed.
  109. * @param changes Changes that should be applied to the file.
  110. */
  111. function applyChangesToFile(tree, path, changes) {
  112. if (changes.length > 0) {
  113. const recorder = tree.beginUpdate(path);
  114. (0, change_1.applyToUpdateRecorder)(recorder, changes);
  115. tree.commitUpdate(recorder);
  116. }
  117. }
  118. /** Checks whether a node is a call to `mergeApplicationConfig`. */
  119. function isMergeAppConfigCall(node) {
  120. if (!typescript_1.default.isCallExpression(node)) {
  121. return false;
  122. }
  123. const localName = findImportLocalName(node.getSourceFile(), 'mergeApplicationConfig', '@angular/core');
  124. return !!localName && typescript_1.default.isIdentifier(node.expression) && node.expression.text === localName;
  125. }
  126. /** Finds the `providers` array literal within an application config. */
  127. function findProvidersLiteral(config) {
  128. for (const prop of config.properties) {
  129. if (typescript_1.default.isPropertyAssignment(prop) &&
  130. typescript_1.default.isIdentifier(prop.name) &&
  131. prop.name.text === 'providers' &&
  132. typescript_1.default.isArrayLiteralExpression(prop.initializer)) {
  133. return prop.initializer;
  134. }
  135. }
  136. return null;
  137. }