imports.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  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.getImportOfIdentifier = getImportOfIdentifier;
  11. const ts = require("typescript");
  12. /** Resolves the import of the specified identifier. */
  13. function getImportOfIdentifier(node, typeChecker) {
  14. // Free standing identifiers which resolve to an import will be handled
  15. // as direct imports. e.g. "@Component()" where "Component" is an identifier
  16. // referring to an import specifier.
  17. const directImport = getSpecificImportOfIdentifier(node, typeChecker);
  18. if (directImport !== null) {
  19. return directImport;
  20. }
  21. else if (ts.isQualifiedName(node.parent) && node.parent.right === node) {
  22. // Determines the import of a qualified name. e.g. "let t: core.Component". In that
  23. // case, the import of the most left identifier will be determined ("core").
  24. const qualifierRoot = getQualifiedNameRoot(node.parent);
  25. if (qualifierRoot) {
  26. const moduleName = getImportOfNamespacedIdentifier(qualifierRoot, typeChecker);
  27. if (moduleName) {
  28. return { moduleName, symbolName: node.text };
  29. }
  30. }
  31. }
  32. else if (ts.isPropertyAccessExpression(node.parent) && node.parent.name === node) {
  33. // Determines the import of a property expression. e.g. "@core.Component". In that
  34. // case, the import of the most left identifier will be determined ("core").
  35. const rootIdentifier = getPropertyAccessRoot(node.parent);
  36. if (rootIdentifier) {
  37. const moduleName = getImportOfNamespacedIdentifier(rootIdentifier, typeChecker);
  38. if (moduleName) {
  39. return { moduleName, symbolName: node.text };
  40. }
  41. }
  42. }
  43. return null;
  44. }
  45. /**
  46. * Resolves the import of the specified identifier. Expects the identifier to resolve
  47. * to a fine-grained import declaration with import specifiers.
  48. */
  49. function getSpecificImportOfIdentifier(node, typeChecker) {
  50. const symbol = typeChecker.getSymbolAtLocation(node);
  51. if (!symbol || !symbol.declarations || !symbol.declarations.length) {
  52. return null;
  53. }
  54. const declaration = symbol.declarations[0];
  55. if (!ts.isImportSpecifier(declaration)) {
  56. return null;
  57. }
  58. // Since the declaration is an import specifier, we can walk up three times to get a reference
  59. // to the import declaration node (NamedImports -> ImportClause -> ImportDeclaration).
  60. const importDecl = declaration.parent.parent.parent;
  61. if (!ts.isStringLiteral(importDecl.moduleSpecifier)) {
  62. return null;
  63. }
  64. return {
  65. moduleName: importDecl.moduleSpecifier.text,
  66. symbolName: declaration.propertyName ? declaration.propertyName.text : declaration.name.text,
  67. };
  68. }
  69. /**
  70. * Resolves the import of the specified identifier. Expects the identifier to
  71. * resolve to a namespaced import declaration. e.g. "import * as core from ...".
  72. */
  73. function getImportOfNamespacedIdentifier(node, typeChecker) {
  74. const symbol = typeChecker.getSymbolAtLocation(node);
  75. if (!symbol || !symbol.declarations || !symbol.declarations.length) {
  76. return null;
  77. }
  78. const declaration = symbol.declarations[0];
  79. if (!ts.isNamespaceImport(declaration)) {
  80. return null;
  81. }
  82. // Since the declaration is a namespace import, we can walk up three times to get a reference
  83. // to the import declaration node (NamespaceImport -> ImportClause -> ImportDeclaration).
  84. const importDecl = declaration.parent.parent;
  85. if (!ts.isStringLiteral(importDecl.moduleSpecifier)) {
  86. return null;
  87. }
  88. return importDecl.moduleSpecifier.text;
  89. }
  90. /**
  91. * Gets the root identifier of a qualified type chain. For example: "core.GestureConfig"
  92. * will return the "core" identifier. Allowing us to find the import of "core".
  93. */
  94. function getQualifiedNameRoot(name) {
  95. while (ts.isQualifiedName(name.left)) {
  96. name = name.left;
  97. }
  98. return ts.isIdentifier(name.left) ? name.left : null;
  99. }
  100. /**
  101. * Gets the root identifier of a property access chain. For example: "core.GestureConfig"
  102. * will return the "core" identifier. Allowing us to find the import of "core".
  103. */
  104. function getPropertyAccessRoot(node) {
  105. while (ts.isPropertyAccessExpression(node.expression)) {
  106. node = node.expression;
  107. }
  108. return ts.isIdentifier(node.expression) ? node.expression : null;
  109. }
  110. //# sourceMappingURL=imports.js.map