UNPKG

@jqassistant/ts-lce

Version:

Tool to extract language concepts from a TypeScript codebase and export them to a JSON file.

86 lines (85 loc) 6.06 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ImportDeclarationProcessor = void 0; const utils_1 = require("@typescript-eslint/utils"); const concept_1 = require("../concept"); const context_1 = require("../context"); const execution_condition_1 = require("../execution-condition"); const modulepath_utils_1 = require("../utils/modulepath.utils"); const processor_1 = require("../processor"); const dependency_resolution_processor_1 = require("./dependency-resolution.processor"); const node_utils_1 = require("../utils/node.utils"); const path_1 = __importDefault(require("path")); class ImportDeclarationProcessor extends processor_1.Processor { executionCondition = new execution_condition_1.ExecutionCondition([utils_1.AST_NODE_TYPES.ImportDeclaration], () => true); postChildrenProcessing({ node, localContexts, globalContext }) { // TODO: resolve complex import paths, e.g. https://stackoverflow.com/questions/42749973/what-does-the-mean-inside-an-import-path // TODO: resolve internal node packages to paths const concepts = []; if (node.type === utils_1.AST_NODE_TYPES.ImportDeclaration) { const importSource = modulepath_utils_1.ModulePathUtils.normalizeImportPath(globalContext.projectInfo.rootPath, node.source.value, globalContext.sourceFilePathRelative); for (const specifier of node.specifiers) { let target = new context_1.FQN(""); let isModule = false; if (specifier.type === utils_1.AST_NODE_TYPES.ImportSpecifier) { const importSourceFqn = this.importSourceToFqn(importSource, globalContext); const importedName = specifier.imported.type === utils_1.AST_NODE_TYPES.Identifier ? specifier.imported.name : specifier.imported.raw; target = new context_1.FQN(importSourceFqn.globalFqn + "." + importedName, importSourceFqn.localFqn + "." + importedName); } else if (specifier.type === utils_1.AST_NODE_TYPES.ImportDefaultSpecifier) { const importSourceFqn = this.importSourceToFqn(importSource, globalContext); target = new context_1.FQN(importSourceFqn.globalFqn + ".default", importSourceFqn.localFqn + ".default"); } else if (specifier.type === utils_1.AST_NODE_TYPES.ImportNamespaceSpecifier) { target = new context_1.FQN(path_1.default.resolve(globalContext.projectInfo.rootPath, importSource), importSource); isModule = true; } if (!isModule && modulepath_utils_1.ModulePathUtils.getPathType(modulepath_utils_1.ModulePathUtils.extractFQNPath(target.globalFqn)) === "node") { // resolve node package names to the appropriate paths try { const resolvedModulePath = node_utils_1.NodeUtils.resolveImportPath(modulepath_utils_1.ModulePathUtils.extractFQNPath(target.globalFqn), globalContext.projectInfo, globalContext.sourceFilePathAbsolute); const targetDeclName = modulepath_utils_1.ModulePathUtils.extractFQNIdentifier(target.globalFqn); let packageName = undefined; if (resolvedModulePath.startsWith(globalContext.projectInfo.rootPath + "/node_modules")) { // only resolve node package name, if it's an actual node module, not some re-mapped source file (see tsconfig.json -> "paths" option) packageName = node_utils_1.NodeUtils.getPackageNameForPath(globalContext.projectInfo.rootPath, resolvedModulePath); } if (packageName) { target = context_1.FQN.id(`"${packageName}".${targetDeclName}`); } else { target = new context_1.FQN(`"${resolvedModulePath}".${targetDeclName}`, `"${modulepath_utils_1.ModulePathUtils.normalize(globalContext.projectInfo.rootPath, resolvedModulePath)}".${targetDeclName}`); } } catch (e) { console.log("\n" + `Error: Could not resolve import path for: ${modulepath_utils_1.ModulePathUtils.extractFQNPath(target.globalFqn)}`); } } // TODO: The registered declaration does not work for Node.js modules and potentially aliased exports dependency_resolution_processor_1.DependencyResolutionProcessor.registerDeclaration(localContexts, specifier.local.name, target); // NOTE: Disabled depdenencies due to unresolvable FQNs of imported declarations that have received an alias on export. // This means there will be no dependencies in the graph based solely on the existence of import statements. // concepts.push( // singleEntryConceptMap( // LCEDependency.conceptId, // new LCEDependency(target, isModule ? "module" : "declaration", sourceFileFQN, "module", 1) // ) // ); } } return (0, concept_1.mergeConceptMaps)(...concepts); } importSourceToFqn(importSource, globalContext) { const importPath = node_utils_1.NodeUtils.resolveImportPath(importSource, globalContext.projectInfo, globalContext.sourceFilePathAbsolute); if (path_1.default.relative(globalContext.projectInfo.rootPath, importPath).startsWith("node_modules")) { return modulepath_utils_1.ModulePathUtils.toFQN(importSource); } else { return modulepath_utils_1.ModulePathUtils.toFQN(importPath); } } } exports.ImportDeclarationProcessor = ImportDeclarationProcessor;