app_config.js 4.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  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.findAppConfig = findAppConfig;
  14. const node_path_1 = require("node:path");
  15. const typescript_1 = __importDefault(require("../../third_party/github.com/Microsoft/TypeScript/lib/typescript"));
  16. const util_1 = require("./util");
  17. /**
  18. * Resolves the node that defines the app config from a bootstrap call.
  19. * @param bootstrapCall Call for which to resolve the config.
  20. * @param tree File tree of the project.
  21. * @param filePath File path of the bootstrap call.
  22. */
  23. function findAppConfig(bootstrapCall, tree, filePath) {
  24. if (bootstrapCall.arguments.length > 1) {
  25. const config = bootstrapCall.arguments[1];
  26. if (typescript_1.default.isObjectLiteralExpression(config)) {
  27. return { filePath, node: config };
  28. }
  29. if (typescript_1.default.isIdentifier(config)) {
  30. return resolveAppConfigFromIdentifier(config, tree, filePath);
  31. }
  32. }
  33. return null;
  34. }
  35. /**
  36. * Resolves the app config from an identifier referring to it.
  37. * @param identifier Identifier referring to the app config.
  38. * @param tree File tree of the project.
  39. * @param bootstapFilePath Path of the bootstrap call.
  40. */
  41. function resolveAppConfigFromIdentifier(identifier, tree, bootstapFilePath) {
  42. const sourceFile = identifier.getSourceFile();
  43. for (const node of sourceFile.statements) {
  44. // Only look at relative imports. This will break if the app uses a path
  45. // mapping to refer to the import, but in order to resolve those, we would
  46. // need knowledge about the entire program.
  47. if (!typescript_1.default.isImportDeclaration(node) ||
  48. !node.importClause?.namedBindings ||
  49. !typescript_1.default.isNamedImports(node.importClause.namedBindings) ||
  50. !typescript_1.default.isStringLiteralLike(node.moduleSpecifier) ||
  51. !node.moduleSpecifier.text.startsWith('.')) {
  52. continue;
  53. }
  54. for (const specifier of node.importClause.namedBindings.elements) {
  55. if (specifier.name.text !== identifier.text) {
  56. continue;
  57. }
  58. // Look for a variable with the imported name in the file. Note that ideally we would use
  59. // the type checker to resolve this, but we can't because these utilities are set up to
  60. // operate on individual files, not the entire program.
  61. const filePath = (0, node_path_1.join)((0, node_path_1.dirname)(bootstapFilePath), node.moduleSpecifier.text + '.ts');
  62. const importedSourceFile = (0, util_1.getSourceFile)(tree, filePath);
  63. const resolvedVariable = findAppConfigFromVariableName(importedSourceFile, (specifier.propertyName || specifier.name).text);
  64. if (resolvedVariable) {
  65. return { filePath, node: resolvedVariable };
  66. }
  67. }
  68. }
  69. const variableInSameFile = findAppConfigFromVariableName(sourceFile, identifier.text);
  70. return variableInSameFile ? { filePath: bootstapFilePath, node: variableInSameFile } : null;
  71. }
  72. /**
  73. * Finds an app config within the top-level variables of a file.
  74. * @param sourceFile File in which to search for the config.
  75. * @param variableName Name of the variable containing the config.
  76. */
  77. function findAppConfigFromVariableName(sourceFile, variableName) {
  78. for (const node of sourceFile.statements) {
  79. if (typescript_1.default.isVariableStatement(node)) {
  80. for (const decl of node.declarationList.declarations) {
  81. if (typescript_1.default.isIdentifier(decl.name) &&
  82. decl.name.text === variableName &&
  83. decl.initializer &&
  84. typescript_1.default.isObjectLiteralExpression(decl.initializer)) {
  85. return decl.initializer;
  86. }
  87. }
  88. }
  89. }
  90. return null;
  91. }