@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
JavaScript
;
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;