UNPKG

@eclipse-scout/cli

Version:
85 lines (76 loc) 3.26 kB
/* * Copyright (c) 2010, 2025 BSI Business Systems Integration AG * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 */ const ts = require('typescript'); /** * Class to compute the external module name (e.g. '@eclipse-scout/core') of types used in the TS file given. * * It parses all imports in the file and stores all names imported from external modules together with the module the name is declared in. * External module means an import from a module different from the one this files belongs to. */ module.exports = class ModuleDetector { /** * @param node A node in the TS file for which the module detector should be created. All external modules used (imported) in this file are stored. */ constructor(node) { this.sourceFile = this._findSourceFile(node); const imports = this._findImportDeclarations(this.sourceFile); this._moduleByTypeMap = this._computeImportMap(imports); // Map only contains types in 'other' modules (modules different from the one of the source file) } /** * @param typeNode {ts.TypeReferenceNode} * @returns {{module: string;exportName:string}} The name of the module (e.g. '@eclipse-scout/core') the given type is declared in and the name it was exported in this module. * Only returns a value if it is a different module than the one this detector was created in (only external modules). * For imports in the same module, this function returns undefined. */ detectExportInfoOf(typeNode) { const name = typeNode?.typeName?.escapedText; return this._moduleByTypeMap.get(name); } _computeImportMap(imports) { const moduleByTypeMap = new Map(); for (let imp of imports) { const moduleName = imp.moduleSpecifier?.text; // e.g. '@eclipse-scout/core' or './index' const isExternalModule = !moduleName?.startsWith('.'); // only store imports to other modules if (isExternalModule) { this._putExternalNamedBindings(imp.importClause?.namedBindings, moduleByTypeMap, moduleName); } } return moduleByTypeMap; } _putExternalNamedBindings(namedBindings, moduleByTypeMap, moduleName) { const importElements = namedBindings?.elements; if (Array.isArray(importElements)) { // multi import e.g.: import {a, b, c as d} from 'whatever' for (let importElement of importElements) { const name = importElement?.name?.escapedText; if (!name) { continue; } const exportedName = importElement?.propertyName?.escapedText || name; moduleByTypeMap.set(name, {module: moduleName, exportName: exportedName}); } } else { // single import e.g.: import * as self from './index'; const name = namedBindings?.name?.escapedText; if (name) { moduleByTypeMap.set(name, {module: moduleName, exportName: name}); } } } _findImportDeclarations(sourceFile) { return sourceFile.statements.filter(s => ts.isImportDeclaration(s)); } _findSourceFile(node) { while (!ts.isSourceFile(node)) { node = node.parent; } return node; } };