UNPKG

unplugin-dts

Version:

<h1 align="center">unplugin-dts</h1>

1,463 lines (1,442 loc) 70.4 kB
'use strict'; const node_path = require('node:path'); const node_fs = require('node:fs'); const require$$0 = require('node:module'); const kolorist = require('kolorist'); const promises = require('node:fs/promises'); const node_os = require('node:os'); const pluginutils = require('@rollup/pluginutils'); const compareVersions = require('compare-versions'); const debug = require('debug'); const localPkg = require('local-pkg'); const MagicString = require('magic-string'); var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null; function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; } const require$$0__default = /*#__PURE__*/_interopDefaultCompat(require$$0); const debug__default = /*#__PURE__*/_interopDefaultCompat(debug); const MagicString__default = /*#__PURE__*/_interopDefaultCompat(MagicString); function getDefaultExportFromCjs (x) { return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; } var tsLoader; var hasRequiredTsLoader; function requireTsLoader () { if (hasRequiredTsLoader) return tsLoader; hasRequiredTsLoader = 1; const { createRequire } = require$$0__default; const require_ = createRequire(__filename); function loadTs() { try { const ts = require_("typescript"); if (typeof ts.createProgram === "function") { return ts; } } catch { } try { const ts = require_("@typescript/typescript6"); if (typeof ts.createProgram === "function") { return ts; } } catch { } throw new Error( '[unplugin-dts] The installed "typescript" package does not provide the JavaScript Compiler API (this happens with TypeScript 7+), and the fallback "@typescript/typescript6" was not found.\nPlease install it alongside TypeScript 7:\n npm install -D @typescript/typescript6\nThis allows TypeScript 7 to be used for compilation while keeping the JS API available for tooling.\nSee: https://devblogs.microsoft.com/typescript/announcing-typescript-7-0-beta/' ); } tsLoader = loadTs(); return tsLoader; } var tsLoaderExports = requireTsLoader(); const ts = /*@__PURE__*/getDefaultExportFromCjs(tsLoaderExports); async function loadProgramProcessor(type = "ts") { if (type === "vue") { try { const mod = await import('../chunks/vue.cjs'); return mod.default ?? mod; } catch { const mod = await import('../chunks/vue.cjs'); return mod.default ?? mod; } } try { const mod = await import('../chunks/ts.cjs'); return mod.default ?? mod; } catch { const mod = await import('../chunks/ts.cjs'); return mod.default ?? mod; } } const handleDebug = debug__default("dts-debug"); const defaultIndex = "index.d.ts"; const jsRE = /\.([cm])?jsx?$/; const tsRE = /\.([cm])?tsx?$/; const dtsRE$1 = /\.d\.([cm])?tsx?$/; const tjsRE = /\.([cm])?([jt])sx?$/; const mtjsRE = /\.m([jt])sx?$/; const ctjsRE = /\.c([jt])sx?$/; const fullRelativeRE = /^\.\.?\//; const globSignRE = /[-^$*+?.()|[\]{}]/g; function getJsExtPrefix(file) { return mtjsRE.test(file) ? "m" : ctjsRE.test(file) ? "c" : ""; } function tsToDtsWithExtension(path, dtsExtension = ".d.ts") { return `${path.replace(tsRE, "")}${dtsExtension}`; } const windowsSlashRE = /\\+/g; function slash(p) { return p.replace(windowsSlashRE, "/"); } function resolveConfigDir(path, configDir) { return path.startsWith("${configDir}") ? path.replace("${configDir}", configDir) : path; } function normalizePath(id) { return node_path.posix.normalize(slash(id)); } function resolve(...paths) { return normalizePath(node_path.resolve(...paths)); } function isNativeObj(value) { return Object.prototype.toString.call(value) === "[object Object]"; } function isRegExp(value) { return Object.prototype.toString.call(value) === "[object RegExp]"; } function isPromise(value) { return !!value && (typeof value === "function" || typeof value === "object") && typeof value.then === "function"; } async function unwrapPromise(maybePromise) { return isPromise(maybePromise) ? await maybePromise : maybePromise; } function mergeObjects(sourceObj, targetObj) { const loop = [ { source: sourceObj, target: targetObj // merged: mergedObj } ]; while (loop.length) { const { source, target } = loop.pop(); Object.keys(target).forEach((key) => { if (isNativeObj(target[key])) { if (!isNativeObj(source[key])) { source[key] = {}; } loop.push({ source: source[key], target: target[key] }); } else if (Array.isArray(target[key])) { if (!Array.isArray(source[key])) { source[key] = []; } loop.push({ source: source[key], target: target[key] }); } else { source[key] = target[key]; } }); } return sourceObj; } function ensureAbsolute(path, root) { return normalizePath(path ? node_path.isAbsolute(path) ? path : resolve(root, path) : root); } function ensureArray(value) { return Array.isArray(value) ? value : value ? [value] : []; } async function runParallel(maxConcurrency, source, iteratorFn) { const ret = []; const executing = []; for (const item of source) { const p = Promise.resolve().then(() => iteratorFn(item, source)); ret.push(p); if (maxConcurrency <= source.length) { const e = p.then(() => executing.splice(executing.indexOf(e), 1)); executing.push(e); if (executing.length >= maxConcurrency) { await Promise.race(executing); } } } return Promise.all(ret); } const speRE = /[\\/]/; function queryPublicPath(paths) { if (paths.length === 0) { return ""; } else if (paths.length === 1) { return node_path.dirname(paths[0]); } let publicPath = node_path.normalize(node_path.dirname(paths[0])) + node_path.sep; let publicUnits = publicPath.split(speRE); let index = publicUnits.length - 1; for (const path of paths.slice(1)) { if (!index) { return publicPath; } const dirPath = node_path.normalize(node_path.dirname(path)) + node_path.sep; if (dirPath.startsWith(publicPath)) { continue; } const units = dirPath.split(speRE); if (units.length < index) { publicPath = dirPath; publicUnits = units; continue; } for (let i = 0; i <= index; ++i) { if (publicUnits[i] !== units[i]) { if (!i) { return ""; } index = i - 1; publicUnits = publicUnits.slice(0, index + 1); publicPath = publicUnits.join(node_path.sep) + node_path.sep; break; } } } return publicPath.slice(0, -1); } function removeDirIfEmpty(dir) { if (!node_fs.existsSync(dir)) { return; } let onlyHasDir = true; for (const file of node_fs.readdirSync(dir)) { const abs = resolve(dir, file); if (node_fs.lstatSync(abs).isDirectory()) { if (!removeDirIfEmpty(abs)) { onlyHasDir = false; } } else { onlyHasDir = false; } } if (onlyHasDir) { node_fs.rmdirSync(dir); } return onlyHasDir; } function getTsConfig(tsConfigPath, readFileSync) { const baseConfig = ts.readConfigFile(tsConfigPath, readFileSync).config ?? {}; const tsConfig = { ...baseConfig, compilerOptions: {} }; if (tsConfig.extends) { ensureArray(tsConfig.extends).forEach((configPath) => { const config = getTsConfig(ensureAbsolute(configPath, node_path.dirname(tsConfigPath)), readFileSync); Object.assign(tsConfig.compilerOptions, config.compilerOptions); if (!tsConfig.include) { tsConfig.include = config.include; } if (!tsConfig.exclude) { tsConfig.exclude = config.exclude; } }); } Object.assign(tsConfig.compilerOptions, baseConfig.compilerOptions); return tsConfig; } function getTsLibFolder() { const libFolder = tryGetPackageInfo("typescript")?.rootPath; return libFolder && normalizePath(libFolder); } const BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split(""); function base64Encode(number) { if (number >= 0 && number < BASE64_ALPHABET.length) { return BASE64_ALPHABET[number]; } throw new TypeError("Base64 integer must be between 0 and 63: " + number); } const VLQ_BASE_SHIFT = 5; const VLQ_BASE = 1 << VLQ_BASE_SHIFT; const VLQ_BASE_MASK = VLQ_BASE - 1; const VLQ_CONTINUATION_BIT = VLQ_BASE; function toVLQSigned(number) { return number < 0 ? (-number << 1) + 1 : (number << 1) + 0; } function base64VLQEncode(numbers) { let encoded = ""; for (const number of numbers) { let vlq = toVLQSigned(number); let digit; do { digit = vlq & VLQ_BASE_MASK; vlq >>>= VLQ_BASE_SHIFT; if (vlq > 0) { digit |= VLQ_CONTINUATION_BIT; } encoded += base64Encode(digit); } while (vlq > 0); } return encoded; } const pkgPathCache = /* @__PURE__ */ new Map(); function tryGetPkgPath(beginPath) { beginPath = normalizePath(beginPath); if (pkgPathCache.has(beginPath)) { return pkgPathCache.get(beginPath); } const pkgPath = resolve(beginPath, "package.json"); if (node_fs.existsSync(pkgPath)) { pkgPathCache.set(beginPath, pkgPath); return pkgPath; } const parentDir = normalizePath(node_path.dirname(beginPath)); if (!parentDir || parentDir === beginPath) { pkgPathCache.set(beginPath, void 0); return; } return tryGetPkgPath(parentDir); } function toCapitalCase(value) { value = value.trim().replace(/\s+/g, "-"); value = value.replace(/-+(\w)/g, (_, char) => char ? char.toUpperCase() : ""); return (value.charAt(0).toLocaleUpperCase() + value.slice(1)).replace( /[^\w]/g, "" ); } function findTypesPath(...pkgs) { let path; for (const pkg of pkgs) { if (typeof pkg !== "object") continue; path = pkg.types || pkg.typings || pkg.exports?.types || pkg.exports?.["."]?.types || pkg.exports?.["./"]?.types; if (path) return path; } } function setModuleResolution(options) { if (options.moduleResolution) return; const module = typeof options.module === "number" ? options.module : options.target ?? ts.ScriptTarget.ES5 >= 2 ? ts.ModuleKind.ES2015 : ts.ModuleKind.CommonJS; let moduleResolution; switch (module) { case ts.ModuleKind.CommonJS: moduleResolution = ts.ModuleResolutionKind.Node10; break; case ts.ModuleKind.Node16: moduleResolution = ts.ModuleResolutionKind.Node16; break; case ts.ModuleKind.NodeNext: moduleResolution = ts.ModuleResolutionKind.NodeNext; break; default: moduleResolution = ts.version.startsWith("5") ? ts.ModuleResolutionKind.Bundler : ts.ModuleResolutionKind.Classic; break; } options.moduleResolution = moduleResolution; } function editSourceMapDir(content, fromDir, toDir) { const relativeOutDir = node_path.relative(fromDir, toDir); if (relativeOutDir) { try { const sourceMap = JSON.parse(content); sourceMap.sources = sourceMap.sources.map((source) => { return normalizePath(node_path.relative(relativeOutDir, source)); }); return JSON.stringify(sourceMap); } catch (e) { return false; } } return true; } const regexpSymbolRE = /([$.\\+?()[\]!<=|{}^,])/g; const asteriskRE = /[*]+/g; function parseTsAliases(basePath, paths) { const result = []; for (const [pathWithAsterisk, replacements] of Object.entries(paths)) { const find = new RegExp( `^${pathWithAsterisk.replace(regexpSymbolRE, "\\$1").replace(asteriskRE, "(?!\\.{1,2}\\/)([^*]+)")}$` ); let index = 1; result.push({ find, replacement: ensureAbsolute( replacements[0].replace(asteriskRE, () => `$${index++}`), basePath ) }); } return result; } const rootAsteriskImportRE = /^(?!\.{1,2}\/)([^*]+)$/; function isAliasGlobal(alias) { return alias.find.toString() === rootAsteriskImportRE.toString(); } function importResolves(path) { const files = [ // js ".js", ".jsx", ".mjs", ".cjs", // ts ".ts", ".tsx", ".mts", ".cts", ".d.ts", // json ".json", // vue ".vue", ".vue.d.ts", // svelte ".svelte" ]; for (const ext of files) { if (node_fs.existsSync(path + ext)) { return true; } } return false; } function tryGetPackageInfo(name) { if (process.versions.pnp) { const targetRequire = require$$0.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/unplugin-dts.Bd7VMaAx.cjs', document.baseURI).href))); try { return localPkg.getPackageInfoSync( targetRequire.resolve(`${name}/package.json`, { paths: [process.cwd()] }) ); } catch (e) { } } try { return localPkg.getPackageInfoSync(name) ?? localPkg.getPackageInfoSync(name, { paths: [localPkg.resolveModule(name) || process.cwd()] }); } catch (e) { } } function getDtsExtension(moduleFormat) { switch (moduleFormat) { case "cjs": return ".d.cts"; case "esm": return ".d.mts"; default: return ".d.ts"; } } function getMapExtension(moduleFormat) { switch (moduleFormat) { case "cjs": return ".d.cts.map"; case "esm": return ".d.mts.map"; default: return ".d.ts.map"; } } function isOutDirConfig(value) { return isNativeObj(value) && typeof value.dir === "string"; } function normalizeOutDirItem(item, root) { if (typeof item === "string") { return { dir: ensureAbsolute(item, root), moduleFormat: void 0, dtsExtension: ".d.ts", mapExtension: ".d.ts.map" }; } const moduleFormat = item.moduleFormat; return { dir: ensureAbsolute(item.dir || "", root), moduleFormat, dtsExtension: getDtsExtension(moduleFormat), mapExtension: getMapExtension(moduleFormat) }; } function normalizeOutDirs(outDirs, root, defaultDir) { if (outDirs === void 0 || outDirs === null) { return [normalizeOutDirItem(defaultDir, root)]; } if (typeof outDirs === "string") { return [normalizeOutDirItem(outDirs, root)]; } if (isOutDirConfig(outDirs)) { return [normalizeOutDirItem(outDirs, root)]; } if (Array.isArray(outDirs)) { if (outDirs.length === 0) { return [normalizeOutDirItem(defaultDir, root)]; } return outDirs.map((item) => normalizeOutDirItem(item, root)); } return [normalizeOutDirItem(defaultDir, root)]; } function transformDtsPath(filePath, targetExtension) { if (targetExtension === ".d.ts") { return filePath; } if (filePath.endsWith(".d.ts.map")) { const mapExtension = targetExtension === ".d.cts" ? ".d.cts.map" : ".d.mts.map"; return filePath.slice(0, -9) + mapExtension; } if (filePath.endsWith(".d.ts")) { return filePath.slice(0, -5) + targetExtension; } return filePath; } function cleanVueDtsFileName(filePath) { return filePath.replace(".vue.d.ts", ".d.ts").replace(".vue.d.cts", ".d.cts").replace(".vue.d.mts", ".d.mts"); } function transformSourceMappingURL(content, targetMapExtension) { if (targetMapExtension === ".d.ts.map") { return content; } return content.replace( /\/\/# sourceMappingURL=(.+)\.d\.ts\.map$/m, `//# sourceMappingURL=$1${targetMapExtension}` ); } let hasExtractor; function getHasExtractor() { return typeof hasExtractor !== "undefined" ? hasExtractor : hasExtractor = !!tryGetPackageInfo("@microsoft/api-extractor"); } const dtsRE = /\.d\.(m|c)?tsx?$/; async function bundleDtsFiles({ root, configPath, tsconfigPath, compilerOptions, outDir, entryPath, outputPath, fileName, libFolder, extractorConfig = {}, bundledPackages, invokeOptions = {} }) { const { Extractor, ExtractorConfig } = await import('@microsoft/api-extractor'); configPath = configPath ? ensureAbsolute(configPath, root) : ""; const configObjectFullPath = configPath || resolve(root, "api-extractor.json"); if (!dtsRE.test(fileName)) { fileName += ".d.ts"; } if (/preserve/i.test(compilerOptions.module)) { compilerOptions = { ...compilerOptions, module: "ESNext" }; } const configObject = { bundledPackages, projectFolder: root, mainEntryPointFilePath: entryPath, compiler: { tsconfigFilePath: tsconfigPath, overrideTsconfig: { $schema: "http://json.schemastore.org/tsconfig", compilerOptions } }, apiReport: { enabled: false, reportFileName: "<unscopedPackageName>.api.md" }, docModel: { enabled: false }, dtsRollup: { enabled: true, publicTrimmedFilePath: outputPath ?? resolve(outDir, fileName) }, tsdocMetadata: { enabled: false }, messages: { compilerMessageReporting: { default: { logLevel: "none" } }, extractorMessageReporting: { default: { logLevel: "none" } } } }; if (configPath) { mergeObjects(configObject, ExtractorConfig.loadFile(configPath)); } if (Object.keys(extractorConfig).length) { mergeObjects(configObject, extractorConfig); } const config = ExtractorConfig.prepare({ configObject, configObjectFullPath, packageJsonFullPath: tryGetPkgPath(configObjectFullPath) }); try { return Extractor.invoke(config, { localBuild: false, showVerboseMessages: false, showDiagnostics: false, typescriptCompilerFolder: libFolder, ...invokeOptions }); } catch (error) { if (error?.message?.includes("Unable to follow symbol")) { const symbolMatch = error.message.match(/Unable to follow symbol for "([^"]+)"/); const symbol = symbolMatch ? symbolMatch[1] : "unknown"; throw new Error( `[unplugin-dts] Failed to bundle declaration files due to an API Extractor limitation when analyzing the symbol "${symbol}". This is usually caused by complex type references from external packages (such as Vue) that API Extractor cannot resolve. You can try the following solutions: 1. Update \`@microsoft/api-extractor\` to the latest version. 2. Ensure the TypeScript version matches what \`@microsoft/api-extractor\` uses internally. 3. If the symbol is from an external package, try adding it to \`bundleTypes.bundledPackages\`. For Vue projects, you can try: \`bundledPackages: ['vue']\`. Original error: ${error.message}` ); } throw error; } } function createApiExtractorProvider({ configPath, extractorConfig, bundledPackages, invokeOptions }) { return { name: "api-extractor", async bundle(context) { const result = await bundleDtsFiles({ root: context.root, configPath, tsconfigPath: context.tsconfigPath, compilerOptions: context.compilerOptions, outDir: context.outDir, entryPath: context.entryPath, outputPath: context.outputPath, fileName: context.fileName, libFolder: context.libFolder, extractorConfig, bundledPackages, invokeOptions }); return { succeeded: result.succeeded, warningCount: result.warningCount, errorCount: result.errorCount, outputPath: context.outputPath, meta: result }; } }; } function normalizeProvider(provider) { return typeof provider === "function" ? { bundle: provider } : provider; } const jsonRE = /\.json$/; function JsonResolver() { return { name: "json", supports(id) { return jsonRE.test(id); }, transform({ id, root, program }) { const sourceFile = program.getSourceFile(id); if (!sourceFile) return []; return [ { path: node_path.relative(root, `${id}.d.ts`), content: `declare const _default: ${sourceFile.text}; export default _default; ` } ]; } }; } const svelteRE = /\.svelte$/; let lowerVersion; function querySvelteVersion() { if (typeof lowerVersion === "boolean") return; try { const version = tryGetPackageInfo("svelte")?.version; lowerVersion = version ? compareVersions.compare(version, "4.0.0", "<") : false; } catch (e) { lowerVersion = false; } } function SvelteResolver() { return { name: "svelte", supports(id) { return svelteRE.test(id); }, transform({ id, root }) { querySvelteVersion(); return [ { path: node_path.relative(root, `${id}.d.ts`), content: `export { ${lowerVersion ? "SvelteComponentTyped" : "SvelteComponent"} as default } from 'svelte'; ` } ]; } }; } const vueRE = /\.vue$/; function VueResolver() { return { name: "vue", supports(id) { return vueRE.test(id); }, transform({ id, code, program }) { const sourceFile = program.getSourceFile(id) || program.getSourceFile(id + ".ts") || program.getSourceFile(id + ".js") || program.getSourceFile(id + ".tsx") || program.getSourceFile(id + ".jsx"); if (!sourceFile) return { outputs: [] }; const outputs = []; const { emitSkipped, diagnostics } = program.emit( sourceFile, (path, content) => { outputs.push({ path, content }); }, void 0, true ); if (!program.getCompilerOptions().declarationMap) { return { outputs, emitSkipped, diagnostics }; } const [beforeScript] = code.split(/\s*<script.*>/); const beforeLines = beforeScript.split("\n").length; for (const output of outputs) { if (output.path.endsWith(".map")) { try { const sourceMap = JSON.parse(output.content); sourceMap.sources = sourceMap.sources.map( (source) => source.replace(/\.vue\.ts$/, ".vue") ); if (beforeScript && beforeScript !== code && beforeLines) { sourceMap.mappings = `${base64VLQEncode([0, 0, beforeLines, 0])};${sourceMap.mappings}`; } output.content = JSON.stringify(sourceMap); } catch (e) { } } } return { outputs, emitSkipped, diagnostics }; } }; } function parseResolvers(resolvers) { const nameMap = /* @__PURE__ */ new Map(); for (const resolver of resolvers) { resolver.name && nameMap.set(resolver.name, resolver); } return Array.from(nameMap.values()); } const globSuffixRE = /^((?:.*\.[^.]+)|(?:\*+))$/; function normalizeGlob(path) { if (/[\\/]$/.test(path)) { return path + "**"; } else if (!globSuffixRE.test(path.split(/[\\/]/).pop())) { return path + "/**"; } return path; } function walkSourceFile(sourceFile, callback) { function walkNode(node, parent, callback2) { if (callback2(node, parent) !== false) { node.forEachChild((child) => walkNode(child, node, callback2)); } } sourceFile.forEachChild((child) => walkNode(child, sourceFile, callback)); } function isAliasMatch(alias, importer) { if (isRegExp(alias.find)) return alias.find.test(importer); if (importer.length < alias.find.length) return false; if (importer === alias.find) return true; return importer.indexOf(alias.find) === 0 && (alias.find.endsWith("/") || importer.substring(alias.find.length)[0] === "/"); } function transformAlias(importer, dir, aliases, aliasesExclude) { if (aliases?.length && !aliasesExclude.some((e) => isRegExp(e) ? e.test(importer) : String(e) === importer)) { for (const alias of aliases) { if (!isAliasMatch(alias, importer)) continue; const replacement = node_path.isAbsolute(alias.replacement) ? normalizePath(node_path.relative(dir, alias.replacement)) : normalizePath(alias.replacement); const endsWithSlash = typeof alias.find === "string" ? alias.find.endsWith("/") : importer.match(alias.find)[0].endsWith("/"); const truthPath = importer.replace(alias.find, replacement + (endsWithSlash ? "/" : "")); const absolutePath = node_path.resolve(dir, truthPath); const normalizedPath = normalizePath(node_path.relative(dir, absolutePath)); const resultPath = normalizedPath.startsWith(".") ? normalizedPath : `./${normalizedPath}`; if (!isAliasGlobal(alias)) return resultPath; if (importResolves(absolutePath)) return resultPath; } } return importer; } const vlsRE = /^_?__VLS_/; function isVLSNode(node) { if (ts.isVariableStatement(node)) { return node.declarationList.declarations.some( (d) => ts.isIdentifier(d.name) && vlsRE.test(`${d.name.escapedText}`) ); } if (ts.isTypeAliasDeclaration(node)) { return vlsRE.test(`${node.name.escapedText}`); } if (ts.isFunctionDeclaration(node)) { return !!node.name && vlsRE.test(`${node.name.escapedText}`); } return false; } function transformCode(options) { const s = new MagicString__default(options.content); const ast = ts.createSourceFile("a.ts", options.content, ts.ScriptTarget.Latest); const dir = node_path.dirname(options.filePath); const importMap = /* @__PURE__ */ new Map(); const usedDefault = /* @__PURE__ */ new Map(); const declareModules = []; const toLibName = (origin) => { const name = transformAlias(origin, dir, options.aliases, options.aliasesExclude); return options.cleanVueFileName ? name.replace(/\.vue$/, "") : name; }; let indexCount = 0; let importCount = 0; const declaredVLS = /* @__PURE__ */ new Set(); const shouldReplaceVLS = options.replaceUnresolvedVLS ?? false; if (shouldReplaceVLS) { walkSourceFile(ast, (node) => { if (ts.isTypeAliasDeclaration(node) && ts.isIdentifier(node.name) && vlsRE.test(`${node.name.escapedText}`)) { declaredVLS.add(`${node.name.escapedText}`); } if (ts.isInterfaceDeclaration(node) && vlsRE.test(`${node.name.escapedText}`)) { declaredVLS.add(`${node.name.escapedText}`); } if (ts.isFunctionDeclaration(node) && node.name && vlsRE.test(`${node.name.escapedText}`)) { declaredVLS.add(`${node.name.escapedText}`); } if (ts.isVariableStatement(node)) { node.declarationList.declarations.forEach((d) => { if (ts.isIdentifier(d.name) && vlsRE.test(`${d.name.escapedText}`)) { declaredVLS.add(`${d.name.escapedText}`); } }); } }); } walkSourceFile(ast, (node, parent) => { if (ts.isImportDeclaration(node)) { if (!node.importClause) { options.clearPureImport && s.remove(node.pos, node.end); ++importCount; } else if (ts.isStringLiteral(node.moduleSpecifier) && (node.importClause.name || node.importClause.namedBindings && ts.isNamedImports(node.importClause.namedBindings))) { const libName = toLibName(node.moduleSpecifier.text); const importSet = importMap.get(libName) ?? importMap.set(libName, /* @__PURE__ */ new Set()).get(libName); if (node.importClause.name && !usedDefault.has(libName)) { const usedType = node.importClause.name.escapedText; usedDefault.set(libName, usedType); importSet.add(`default as ${usedType}`); } if (node.importClause.namedBindings && ts.isNamedImports(node.importClause.namedBindings)) { node.importClause.namedBindings.elements.forEach((element) => { if (element.propertyName) { importSet.add(`${element.propertyName.getText(ast)} as ${element.name.escapedText}`); } else { importSet.add(element.name.escapedText); } }); } s.remove(node.pos, node.end); ++importCount; } else if (ts.isStringLiteral(node.moduleSpecifier) && node.importClause.namedBindings && ts.isNamespaceImport(node.importClause.namedBindings)) { const libName = toLibName(node.moduleSpecifier.text); if (libName !== node.moduleSpecifier.text) { s.update(node.moduleSpecifier.pos, node.moduleSpecifier.end, ` '${libName}'`); } ++importCount; } return false; } if (shouldReplaceVLS && ts.isTypeReferenceNode(node) && ts.isIdentifier(node.typeName) && vlsRE.test(`${node.typeName.escapedText}`) && !declaredVLS.has(`${node.typeName.escapedText}`)) { s.update(node.getStart(ast), node.end, "{}"); return false; } if (ts.isImportTypeNode(node) && node.qualifier && ts.isLiteralTypeNode(node.argument) && ts.isIdentifier(node.qualifier) && ts.isStringLiteral(node.argument.literal)) { const libName = toLibName(node.argument.literal.text); if (!options.staticImport) { s.update(node.argument.literal.pos, node.argument.literal.end, `'${libName}'`); return !!node.typeArguments; } const importSet = importMap.get(libName) ?? importMap.set(libName, /* @__PURE__ */ new Set()).get(libName); let usedType = node.qualifier.escapedText; if (usedType === "default") { usedType = usedDefault.get(libName) ?? usedDefault.set(libName, `__DTS_DEFAULT_${indexCount++}__`).get(libName); importSet.add(`default as ${usedType}`); s.update(node.qualifier.pos, node.qualifier.end, usedType); } else { importSet.add(usedType); } if (ts.isImportTypeNode(parent) && parent.typeArguments && parent.typeArguments[0] === node) { s.remove(node.pos, node.argument.end + 2); } else { s.update(node.pos, node.argument.end + 2, " "); } return !!node.typeArguments; } if (ts.isCallExpression(node) && node.expression.kind === ts.SyntaxKind.ImportKeyword && ts.isStringLiteral(node.arguments[0])) { s.update( node.arguments[0].pos, node.arguments[0].end, `'${toLibName(node.arguments[0].text)}'` ); return false; } if (ts.isExportDeclaration(node) && node.moduleSpecifier && ts.isStringLiteral(node.moduleSpecifier)) { s.update( node.moduleSpecifier.pos, node.moduleSpecifier.end, ` '${toLibName(node.moduleSpecifier.text)}'` ); return false; } if (ts.isModuleDeclaration(node) && node.body && ts.isModuleBlock(node.body)) { if (ts.isIdentifier(node.name) && node.name.escapedText === "global" && node.body.statements.some(isVLSNode)) { s.remove(node.pos, node.end); } else { let libName = ""; if (ts.isStringLiteral(node.name)) { libName = toLibName(node.name.text); if (libName !== node.name.text) { s.update(node.name.pos, node.name.end, ` '${libName}'`); } } if ((!libName || !libName.startsWith(".")) && node.modifiers?.[0] && node.modifiers[0].kind === ts.SyntaxKind.DeclareKeyword && !node.body.statements.some( (s2) => ts.isExportAssignment(s2) || ts.isExportDeclaration(s2) || ts.isImportDeclaration(s2) )) { declareModules.push(s.slice(node.pos, node.end + 1)); } } return false; } }); let prependImports = ""; importMap.forEach((importSet, libName) => { prependImports += `import { ${Array.from(importSet).join(", ")} } from '${libName}'; `; }); s.trimStart("\n").prepend(prependImports); return { content: s.toString(), declareModules, diffLineCount: importMap.size && importCount < importMap.size ? importMap.size - importCount : null }; } function hasNormalExport(content) { const ast = ts.createSourceFile("a.ts", content, ts.ScriptTarget.Latest); let has = false; walkSourceFile(ast, (node) => { if (ts.isExportDeclaration(node)) { if (node.exportClause && ts.isNamedExports(node.exportClause)) { for (const element of node.exportClause.elements) { if (element.name.getText(ast) !== "default") { has = true; break; } } } else { has = true; } } else if ("modifiers" in node && Array.isArray(node.modifiers) && node.modifiers.length > 1) { for (let i = 0, len = node.modifiers.length; i < len; ++i) { if (node.modifiers[i].kind === ts.SyntaxKind.ExportKeyword && node.modifiers[i + 1]?.kind !== ts.SyntaxKind.DefaultKeyword) { has = true; break; } } } return false; }); return has; } function hasExportDefault(content) { const ast = ts.createSourceFile("a.ts", content, ts.ScriptTarget.Latest); let has = false; walkSourceFile(ast, (node) => { if (ts.isExportAssignment(node)) { has = true; } else if (ts.isExportDeclaration(node) && node.exportClause && ts.isNamedExports(node.exportClause)) { for (const element of node.exportClause.elements) { if (element.name.getText(ast) === "default") { has = true; break; } } } else if ("modifiers" in node && Array.isArray(node.modifiers) && node.modifiers.length > 1) { for (let i = 0, len = node.modifiers.length; i < len; ++i) { if (node.modifiers[i].kind === ts.SyntaxKind.ExportKeyword && node.modifiers[i + 1]?.kind === ts.SyntaxKind.DefaultKeyword) { has = true; break; } } } return false; }); return has; } const fixedCompilerOptions = { noEmit: false, declaration: true, emitDeclarationOnly: true, checkJs: false, skipLibCheck: true, preserveSymlinks: false, noEmitOnError: void 0, target: ts.ScriptTarget.ESNext }; function parseAliases(aliasOptions = [], aliasesExclude = []) { let aliases; if (isNativeObj(aliasOptions)) { aliases = Object.entries(aliasOptions).map(([key, value]) => { return { find: key, replacement: value }; }); } else { aliases = ensureArray(aliasOptions).map((alias) => ({ ...alias })); } if (aliasesExclude.length > 0) { aliases = aliases.filter( ({ find }) => !aliasesExclude.some( (aliasExclude) => aliasExclude && (isRegExp(find) ? find.toString() === aliasExclude.toString() : isRegExp(aliasExclude) ? find.match(aliasExclude)?.[0] : find === aliasExclude) ) ); } return aliases; } class Runtime { static async toInstance({ processor = "ts", ...options }) { const mod = await loadProgramProcessor(processor); const api = mod.default ?? mod; return new Runtime(options, api); } root; publicRoot; entryRoot; configPath; compilerOptions; rawCompilerOptions; host; program; rootNames; diagnostics; outDirs; entries; // protected include: string[] // protected exclude: string[] aliases; aliasesExclude; libName; indexName; logger; resolvers; rootFiles; outputFiles; transformedFiles; filter; rebuildProgram; constructor(options, { createParsedCommandLine, createProgram }) { const { root, tsconfigPath, aliasesExclude = [], pathsToAliases, entries = {}, logger = console } = options; const resolvers = parseResolvers([ JsonResolver(), VueResolver(), SvelteResolver(), ...options.resolvers || [] ]); const aliases = parseAliases(options.aliases, aliasesExclude); const configPath = tsconfigPath ? ensureAbsolute(tsconfigPath, root) : ts.findConfigFile(root, ts.sys.fileExists); const content = configPath ? createParsedCommandLine(ts, ts.sys, configPath) : void 0; const compilerOptions = { ...content?.options || {}, ...options.compilerOptions || {}, ...fixedCompilerOptions, outDir: ".", declarationDir: "." }; const rawCompilerOptions = content?.raw.compilerOptions || {}; if (content?.fileNames.find((name) => name.endsWith(".vue"))) { setModuleResolution(compilerOptions); } const defaultOutDir = ensureAbsolute( content?.raw.compilerOptions?.outDir ? resolveConfigDir(content.raw.compilerOptions.outDir, root) : "dist", root ); const outDirs = normalizeOutDirs(options.outDirs, root, defaultOutDir); const { baseUrl, paths } = compilerOptions; const resolvedBaseUrl = baseUrl ?? (paths && configPath ? node_path.dirname(configPath) : root); if (pathsToAliases && resolvedBaseUrl && paths) { aliases.push( ...parseTsAliases( ensureAbsolute( resolveConfigDir(resolvedBaseUrl, root), configPath ? node_path.dirname(configPath) : root ), paths ) ); } const computeGlobs = (rootGlobs, tsGlobs, defaultGlob) => { if (rootGlobs?.length) { return ensureArray(rootGlobs).map((glob) => normalizeGlob(resolveConfigDir(glob, "."))); } const relativeRoot = configPath ? normalizePath(node_path.relative(root, node_path.dirname(configPath))) : "."; const relativeRootGlob = relativeRoot === "." ? "." : relativeRoot.replace(globSignRE, "\\$&"); const resolveTsGlobToRoot = (glob) => { glob = normalizePath(glob); if (glob.startsWith("/") || /^[a-zA-Z]:\//.test(glob)) return glob; if (relativeRootGlob === ".") return glob; return `${relativeRootGlob}/${glob}`; }; return ensureArray(tsGlobs?.length ? tsGlobs : defaultGlob).map( (glob) => normalizeGlob(resolveTsGlobToRoot(resolveConfigDir(glob, "."))) ); }; const include = computeGlobs( options.include, [...ensureArray(content?.raw.include ?? []), ...ensureArray(content?.raw.files ?? [])], "**/*" ); const exclude = [ ...computeGlobs(options.exclude, content?.raw.exclude, "node_modules/**"), ...outDirs.map((outDir) => normalizeGlob(outDir.dir)) ]; const filter = pluginutils.createFilter(include, exclude, { resolve: root }); const rootNames = [ ...new Set( Object.values(entries).map((entry) => ensureAbsolute(entry, root)).concat(content?.fileNames.filter(filter) || []).map(normalizePath) ) ]; const host = ts.createCompilerHost(compilerOptions); const rebuildProgram = () => createProgram({ host, rootNames, options: compilerOptions, projectReferences: content?.projectReferences }); const program = rebuildProgram(); const libName = toCapitalCase(options.libName || "_default"); const indexName = options.indexName || defaultIndex; const maybeEmitted = (sourceFile) => { return !(compilerOptions.noEmitForJsFiles && jsRE.test(sourceFile.fileName)) && !sourceFile.isDeclarationFile && !program.isSourceFileFromExternalLibrary(sourceFile); }; const emittableSourceFiles = program.getSourceFiles().filter(maybeEmitted).map((sourceFile) => sourceFile.fileName); const sourcePublicPath = queryPublicPath(emittableSourceFiles); const useTs6ImplicitRootDir = !compilerOptions.rootDir && !(compilerOptions.composite && compilerOptions.configFilePath) && compareVersions.compare(ts.version, "6.0.0", ">=") && !!configPath; let publicRoot = compilerOptions.rootDir ? ensureAbsolute(resolveConfigDir(compilerOptions.rootDir, root), root) : compilerOptions.composite && compilerOptions.configFilePath ? node_path.dirname(compilerOptions.configFilePath) : useTs6ImplicitRootDir ? node_path.dirname(configPath) : sourcePublicPath || (configPath ? node_path.dirname(configPath) : root); publicRoot = normalizePath(publicRoot); let entryRoot = options.entryRoot || (useTs6ImplicitRootDir ? sourcePublicPath || publicRoot : publicRoot); entryRoot = ensureAbsolute(entryRoot, root); const diagnostics = [ ...program.getDeclarationDiagnostics(), ...program.getSemanticDiagnostics(), ...program.getSyntacticDiagnostics() ]; if (diagnostics?.length) { logger.error(ts.formatDiagnosticsWithColorAndContext(diagnostics, host)); } const rootFiles = /* @__PURE__ */ new Set(); for (const file of rootNames) { rootFiles.add(file); } this.root = root; this.publicRoot = publicRoot; this.entryRoot = entryRoot; this.configPath = configPath; this.compilerOptions = compilerOptions; this.rawCompilerOptions = rawCompilerOptions; this.host = host; this.rootNames = rootNames; this.diagnostics = diagnostics; this.outDirs = outDirs; this.entries = entries; this.aliases = aliases; this.aliasesExclude = aliasesExclude; this.libName = libName; this.indexName = indexName; this.logger = logger; this.resolvers = resolvers; this.rootFiles = rootFiles; this.outputFiles = /* @__PURE__ */ new Map(); this.transformedFiles = /* @__PURE__ */ new Set(); this.filter = filter; this.program = program; this.rebuildProgram = () => { this.program = rebuildProgram(); }; } getHost() { return this.host; } getProgram() { return this.program; } matchResolver(id) { return this.resolvers.find((r) => r.supports(id)); } getRootFiles() { return [...this.rootFiles]; } restoreRootFiles() { for (const file of this.rootNames) { this.rootFiles.add(file); } } addRootFile(fileName) { this.rootFiles.add(normalizePath(fileName)); } clearTransformedFiles() { this.transformedFiles.clear(); } getDiagnostics() { return [...this.diagnostics]; } async transform(id, code) { const { publicRoot, outDirs, resolvers, rootFiles, outputFiles, transformedFiles } = this; let resolver; id = normalizePath(id).split("?")[0]; if (!this.filter(id) || !(resolver = resolvers.find((r) => r.supports(id))) && !tjsRE.test(id) || transformedFiles.has(id)) { return; } rootFiles.delete(id); transformedFiles.add(id); const outDir = outDirs[0].dir; if (resolver) { const result = await resolver.transform({ id, code, root: publicRoot, outDir, host: this.host, program: this.program }); let outputs; if (Array.isArray(result)) { outputs = result; } else { const { emitSkipped, diagnostics = [] } = result; if (emitSkipped && diagnostics.length > 0) { this.logger.error(ts.formatDiagnosticsWithColorAndContext(diagnostics, this.host)); this.diagnostics.push(...diagnostics); } outputs = result.outputs; } for (const { path, content } of outputs) { outputFiles.set( resolve(publicRoot, node_path.relative(outDir, ensureAbsolute(path, outDir))), content ); } } else { const sourceFile = this.program.getSourceFile(id); if (sourceFile) { const { emitSkipped, diagnostics } = this.program.emit( sourceFile, (name, text) => { outputFiles.set( resolve(publicRoot, node_path.relative(outDir, ensureAbsolute(name, outDir))), text ); }, void 0, true ); if (emitSkipped && diagnostics.length > 0) { this.logger.error(ts.formatDiagnosticsWithColorAndContext(diagnostics, this.host)); this.diagnostics.push(...diagnostics); } } } const dtsId = id.replace(tjsRE, "") + ".d.ts"; const dtsSourceFile = this.program.getSourceFile(dtsId); dtsSourceFile && this.filter(dtsSourceFile.fileName) && outputFiles.set(normalizePath(dtsSourceFile.fileName), dtsSourceFile.getFullText()); } async emitOutput(options = {}) { const { outDirs, logger, outputFiles, transformedFiles, rootFiles, root, publicRoot, entryRoot, aliases, aliasesExclude, entries, indexName, libName, configPath, rawCompilerOptions } = this; const { strictOutput = true, logPrefix = "[dts]", copyDtsFiles = false, cleanVueFileName = false, staticImport: staticImportOpt = false, clearPureImport = true, insertTypesEntry = false, bundleTypes = false, beforeWriteFile, afterRollup } = options; const staticImport = bundleTypes ? true : staticImportOpt; const { extractorConfig, bundledPackages, invokeOptions, configPath: bundleConfigPath } = isNativeObj(bundleTypes) ? bundleTypes : {}; const cleanPath = (path, emittedFiles2) => { const cleanedPath = path.replace(".vue.d.ts", ".d.ts").replace(".vue.d.cts", ".d.cts").replace(".vue.d.mts", ".d.mts"); return !emittedFiles2.has(cleanedPath) && cleanVueFileName ? cleanedPath : path; }; const outDir = outDirs[0].dir; const primaryOutDirConfig = outDirs[0]; const emittedFiles = /* @__PURE__ */ new Map(); const declareModules = []; const writeOutput = async (path, content, outDir2, record = true, dtsExtension = ".d.ts") => { path = transformDtsPath(path, dtsExtension); if (!path.endsWith(".map")) { const mapExtension = dtsExtension === ".d.cts" ? ".d.cts.map" : dtsExtension === ".d.mts" ? ".d.mts.map" : ".d.ts.map"; content = transformSourceMappingURL(content, mapExtension); } if (typeof beforeWriteFile === "function") { const result = await unwrapPromise(beforeWriteFile(path, content)); if (result === false) return; if (result) { path = result.filePath || path; content = result.content ?? content; } } path = normalizePath(path); const dir = normalizePath(node_path.dirname(path)); if (strictOutput && !dir.startsWith(normalizePath(outDir2))) { logger.warn(`${logPrefix} ${kolorist.yellow("Outside emitted:")} ${path}`); return; } if (!node_fs.existsSync(dir)) { await promises.mkdir(dir, { recursive: true }); } await promises.writeFile(path, content, "utf-8"); record && emittedFiles.set(path, content); }; const sourceFiles = this.program.getSourceFiles(); for (const sourceFile of sourceFiles) { if (!this.filter(sourceFile.fileName)) continue; if ((copyDtsFiles || bundleTypes) && dtsRE$1.test(sourceFile.fileName)) { outputFiles.set(normalizePath(sourceFile.fileName), sourceFile.getFullText()); } if (rootFiles.has(sourceFile.fileName)) { this.program.emit( sourceFile, (name, text) => { outputFiles.set( resolve(publicRoot, node_path.relative(outDir, ensureAbsolute(name, outDir))), text ); }, void 0, true ); rootFiles.delete(sourceFile.fileName); } } handleDebug("emit output patch"); const currentDir = this.host.getCurrentDirectory(); const declarationFiles = /* @__PURE__ */ new Map(); const mapFiles = /* @__PURE__ */ new Map(); const prependMappings = /* @__PURE__ */ new Map(); for (const [filePath, content] of outputFiles.entries()) { if (filePath.endsWith(".map")) { mapFiles.set(filePath, content); } else { declarationFiles.set(filePath, content); } } await runParallel( node_os.cpus().length, Array.from(declarationFiles.entries()), async ([filePath, content]) => { let relativePath = node_path.relative( entryRoot, cleanVueFileName ? cleanVueDtsFileName(filePath) : filePath ); if (relativePath.startsWith("..")) { relativePath = node_path.relative(root, cleanVueFileName ? cleanVueDtsFileName(filePath) : filePath); } const newFilePath = resolve(outDir, relativePath); if (content) { const result = transformCode({ filePath, content, aliases, aliasesExclude, staticImport, clearPureImport, cleanVueFileName, replaceUnresolvedVLS: !!bundleTypes }); content = result.content; declareModules.push(...result.declareModules); if (result.diffLineCount) { const transformedPath = transformDtsPath(newFilePath, primaryOutDirConfig.dtsExtension); prependMappings.set(`${transformedPath}.map`, ";".repeat(result.diffLineCount)); } } await writeOutput(newFilePath, content, outDir, true, primaryOutDirConfig.dtsExtension); } ); await runParallel( node_os.cpus().length, Array.from(mapFiles.entries()), async ([filePath, content]) => { const baseDir = node_path.dirname(filePath); let relativePath = node_path.relative( entryRoot, cleanVueFileName ? cleanVueDtsFileName(filePath) : filePath ); if (relativePath.startsWith("..")) { relativePath = node_path.relative(root, cleanVueFileName ? cleanVueDtsFileName(filePath) : filePath); } filePath = resolve(outDir, relativePath); try { const sourceMap = JSON.parse(content); sourceMap.sources = sourceMap.sources.map((source) => { return normalizePath( node_path.relative( node_path.dirname(filePath), resolve(currentDir, node_path.relative(publicRoot, baseDir), source) ) ); }); const transformedFilePath = transformDtsPath(filePath, primaryOutDirConfig.dtsExtension); if (prependMappings.has(transformedFilePath)) { sourceMap.mappings = `${prependMappings.get(transformedFilePath)}${sourceMap.mappings}`; } content = JSON.stringify(sourceMap); } catch (e) { logger.warn(`${logPrefix} ${kolorist.yellow("Processing source map fail:")} ${filePath}`); } await writeOutput(filePath, content, outDir, true, primaryOutDirConfig.dtsExtension); } ); handleDebug("write output"); if (insertTypesEntry || bundleTypes) { const pkgPath = tryGetPkgPath(root); let pkg; try { pkg = pkgPath &