"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.sameModule = exports.maybeRelativePath = exports.emitImports = exports.SideEffect = exports.Augmented = exports.ImportsAll = exports.ImportsDefault = exports.ImportsName = exports.Imported = exports.Implicit = exports.Import = exports.importType = void 0; const lodash_1 = __importDefault(require("lodash")); const path = __importStar(require("path")); const Node_1 = require("./Node"); const typeImportMarker = '(?:t:)?'; 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 = `^(${typeImportMarker}${identPattern})?(${exports.importType})(${modulePattern})(?:#(${identPattern}))?`; const sourceIdentPattern = `(?:(?:${identPattern}:)?)`; const sourceImportPattern = `^(${typeImportMarker}${sourceIdentPattern}${identPattern})?(@)(${modulePattern})(?:#(${identPattern}))?`; /** * Specifies a symbol and its related origin, either via import or implicit/local declaration. */ class Import extends Node_1.Node { constructor(symbol) { super(); this.symbol = symbol; } /** * 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 && // Ignore imports that are in our own file !(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; } if (modulePath in importMappings) { modulePath = importMappings[modulePath]; } const importPath = maybeRelativePath(ourModulePath, modulePath); // Output star imports individually unique(filterInstances(imports, ImportsAll).map((i) => i.symbol)).forEach((symbol) => { result += `import * as ${symbol} from '${importPath}';\n`; const augments = augmentImports[symbol]; if (augments) { augments.forEach((augment) => (result += `import '${augment.source}';\n`)); } }); // Partition named imported into `import type` vs. regular imports const allNames = filterInstances(imports, ImportsName); const names = unique(allNames.filter((i) => !i.typeImport).map((it) => it.toImportPiece())); const def = unique(filterInstances(imports, ImportsDefault).map((it) => it.symbol)); // Output named imports as a group if (names.length > 0 || def.length > 0) { const namesPart = names.length > 0 ? [`{ ${names.join(', ')} }`] : []; const defPart = def.length > 0 ? [def[0]] : []; result += `import ${[...defPart, ...namesPart].join(', ')} from '${importPath}';\n`; [...names, ...def].forEach((name) => { const augments = augmentImports[name]; if (augments) { augments.forEach((augment) => (result += `import '${augment.source}';\n`)); } }); } const typeImports = unique(allNames .filter((i) => i.typeImport) .map((it) => it.toImportPiece()) // If the `import type` is already used as a concrete import, just use that .filter((p) => !names.includes(p))); if (typeImports.length > 0) { result += `import type { ${typeImports.join(', ')} } from '${importPath}';\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; } importPath = path.normalize(importPath); outputPath = path.normalize(outputPath); const outputPathDir = path.dirname(outputPath); let relativePath = path.relative(outputPathDir, importPath).split(path.sep).join(path.posix.sep); if (!relativePath.startsWith('.')) { // ensure the js compiler recognizes this is a relative path. relativePath = './' + relativePath; } return relativePath; } exports.maybeRelativePath = maybeRelativePath; /** Checks if `path1 === path2` despite minor path differences like `./foo` and `foo`. */ function sameModule(path1, path2) { // TypeScript: import paths ending in .js and .ts are resolved to the .ts file. // Check the base paths (without the .js or .ts suffix). const [basePath1, basePath2] = [path1, path2].map((p) => p.replace(/\.[tj]sx?/, '')); return basePath1 === basePath2 || path.resolve(basePath1) === path.resolve(basePath2); } exports.sameModule = sameModule;