"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const lodash_1 = __importDefault(require("lodash")); const path_1 = __importDefault(require("path")); const Node_1 = require("./Node"); const fileNamePattern = '(?:[a-zA-Z0-9._-]+)'; const modulePattern = `@?(?:(?:${fileNamePattern}(?:/${fileNamePattern})*))`; const identPattern = `(?:(?:[a-zA-Z][_a-zA-Z0-9.]*)|(?:[_a-zA-Z][_a-zA-Z0-9.]+))`; exports.importType = '[*@+=]'; const importPattern = `^(${identPattern})?(${exports.importType})(${modulePattern})(?:#(${identPattern}))?`; /** * Specifies a symbol and its related origin, either via import or implicit/local declaration. * * @param value Value of the symbol */ class SymbolSpec extends Node_1.Node { constructor(value) { super(); this.value = value; } /** * Parses a symbol reference pattern to create a symbol. The pattern * allows the simple definition of all symbol types including any possible * import variation. If the spec to parse does not follow the proper format * an implicit symbol is created from the unparsed spec. * * Pattern: `symbolName? importType modulePath (#)?` * * Where: * * - `symbolName` is any legal JS/TS symbol. If none, we use the last part of the module path as a guess. * - `importType` is one of `@` or `*` or `+`, where: * - `@` is a named import * - `Foo@bar` becomes `import { Foo } from 'bar'` * - `*` is a star import, * - `*Foo` becomes `import * as Foo from 'Foo'` * - `Foo*foo` becomes `import * as Foo from 'foo'` * - `+` is an implicit import * - E.g. `Foo+foo` becomes `import 'foo'` * - `modulePath` is a path * - E.g. `(/ a.augmented); // Group the imports by source module they're imported from const importsByModule = lodash_1.default.groupBy(imports.filter((it) => it.source !== undefined && !(it instanceof ImportsName && it.definedIn && sameModule(it.definedIn, ourModulePath))), (it) => it.source); // Output each source module as one line Object.entries(importsByModule).forEach(([modulePath, imports]) => { // Skip imports from the current module if (sameModule(ourModulePath, modulePath)) { return; } const importPath = maybeRelativePath(ourModulePath, modulePath); // Output star imports individually filterInstances(imports, ImportsAll).forEach((i) => { result += `import * as ${i.value} from '${importPath}';\n`; const augments = augmentImports[i.value]; if (augments) { augments.forEach((augment) => (result += `import '${augment.source}';\n`)); } }); // Output named imports as a group const names = unique(filterInstances(imports, ImportsName).map((it) => it.toImportPiece())); const def = unique(filterInstances(imports, ImportsDefault).map((it) => it.value)); if (names.length > 0 || def.length > 0) { const namesPart = names.length > 0 ? [`{ ${names.join(', ')} }`] : []; const defPart = def.length > 0 ? [def[0]] : []; const allNames = [...defPart, ...namesPart]; result += `import ${allNames.join(', ')} from '${importPath}';\n`; [...names, ...def].forEach((name) => { const augments = augmentImports[name]; if (augments) { augments.forEach((augment) => (result += `import '${augment.source}';\n`)); } }); } }); const sideEffectImports = lodash_1.default.groupBy(filterInstances(imports, SideEffect), (a) => a.source); Object.keys(sideEffectImports).forEach((it) => (result += `import '${it}';\n`)); return result; } exports.emitImports = emitImports; function filterInstances(list, t) { return list.filter((e) => e instanceof t); } function unique(list) { return [...new Set(list)]; } function maybeRelativePath(outputPath, importPath) { if (!importPath.startsWith('./')) { return importPath; } // Drop the `./` prefix from the outputPath if it exists. const basePath = outputPath.replace(/^.\//, ''); // Ideally we'd use a path library to do all this. const numberOfDirs = basePath.split('').filter((l) => l === '/').length; if (numberOfDirs === 0) { return importPath; } // Make an array of `..` to get our importPath to the root directory. const a = new Array(numberOfDirs); const prefix = a.fill('..', 0, numberOfDirs).join('/'); return prefix + importPath.substring(1); } exports.maybeRelativePath = maybeRelativePath; /** Checks if `path1 === path2` despite minor path differences like `./foo` and `foo`. */ function sameModule(path1, path2) { return path1 === path2 || path_1.default.resolve(path1) === path_1.default.resolve(path2); } exports.sameModule = sameModule;