unplugin-dts
Version:
<h1 align="center">unplugin-dts</h1>
1,463 lines (1,442 loc) • 70.4 kB
JavaScript
'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 &