UNPKG

typeroll

Version:

An extremely fast TypeScript declaration file generator and bundler that outputs to a single file.

745 lines (729 loc) 28.5 kB
var import_node_module = require("node:module"); var __create = Object.create; var __getProtoOf = Object.getPrototypeOf; var __defProp = Object.defineProperty; var __getOwnPropNames = Object.getOwnPropertyNames; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __hasOwnProp = Object.prototype.hasOwnProperty; var __toESM = (mod, isNodeMode, target) => { target = mod != null ? __create(__getProtoOf(mod)) : {}; const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target; for (let key of __getOwnPropNames(mod)) if (!__hasOwnProp.call(to, key)) __defProp(to, key, { get: () => mod[key], enumerable: true }); return to; }; var __moduleCache = /* @__PURE__ */ new WeakMap; var __toCommonJS = (from) => { var entry = __moduleCache.get(from), desc; if (entry) return entry; entry = __defProp({}, "__esModule", { value: true }); if (from && typeof from === "object" || typeof from === "function") __getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable })); __moduleCache.set(from, entry); return entry; }; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true, configurable: true, set: (newValue) => all[name] = () => newValue }); }; // src/index.ts var exports_src = {}; __export(exports_src, { logIsolatedDeclarationErrors: () => logIsolatedDeclarationErrors, generateDts: () => generateDts }); module.exports = __toCommonJS(exports_src); // src/isolated-decl-logger.ts var import_picocolors = __toESM(require("picocolors")); // src/utils.ts var import_node_fs = require("node:fs"); var import_node_path = require("node:path"); var import_coffi = require("coffi"); var import_oxc_minify = require("oxc-minify"); var import_std_env = require("std-env"); // src/re.ts var IMPORT_TYPE_RE = /import\s+type\s+/g; var EXPORT_TYPE_RE = /export\s+type\s+/g; var IMPORT_EXPORT_NAMES_RE = /(import|export)\s*{([^}]*)}/g; var IMPORT_EXPORT_WITH_DEFAULT_RE = /(import|export)(\s+[^{,]+,)?\s*{([^}]*)}/g; var TYPE_WORD_RE = /\btype\s+/g; var EXPORT_DEFAULT_RE = /\bexport\s+default\s+/g; var EXPORT_RE = /\bexport\s+/g; var TOKENIZE_RE = /(\s+|\/\/.*?(?:\n|$)|\/\*[\s\S]*?\*\/|[a-zA-Z_$][a-zA-Z0-9_$]*|"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|`(?:\\.|[^`\\])*`|\d+(?:\.\d*)?(?:[eE][+-]?\d+)?|[(){}\[\],.;:]|=>|&&|\|\||[=!<>]=?|\+\+|--|[-+*/%&|^!~?]|\.{3}|::|\.)/g; var CAPITAL_LETTER_RE = /[A-Z]/; var JS_RE = /\.[cm]?jsx?$/; var TS_RE = /\.[cm]?tsx?$|\.d\.[cm]?ts$/; var EXTENSION_REGEX = /\.(d\.(ts|cts|mts)|[cm]?[jt]s)$/; var NODE_MODULES_RE = /node_modules/; // src/utils.ts function isTypeScriptFile(path2) { if (!path2) return false; return TS_RE.test(path2); } function returnPathIfExists(path2) { return import_node_fs.existsSync(path2) ? path2 : null; } function getExtension(filename) { const match = filename.match(EXTENSION_REGEX); if (!match) return ""; const ext = match[0]; return ext; } function replaceExtension(filename, newExt) { if (EXTENSION_REGEX.test(filename)) { return filename.replace(EXTENSION_REGEX, newExt); } return filename + newExt; } function deleteExtension(filename) { return filename.replace(EXTENSION_REGEX, ""); } async function loadTsConfig(cwd, preferredPath) { const config = await import_coffi.loadConfig({ name: "tsconfig", extensions: [".json"], preferredPath, cwd }); return config; } function getShortFilePath(filePath, maxLength = 3) { const fileParts = filePath.split("/"); const shortPath = fileParts.slice(-maxLength).join("/"); return shortPath; } function generateRandomString(length = 10) { return Array.from({ length }, () => String.fromCharCode(97 + Math.floor(Math.random() * 26))).join(""); } function isDev() { return import_std_env.isDevelopment || !import_std_env.isCI; } function isNullOrUndefined(value) { return value === undefined || value === null; } function cleanPath(path2) { let cleaned = import_node_path.normalize(path2).replace(/\\/g, "/"); cleaned = cleaned.replace(/^[a-zA-Z]:\//, ""); cleaned = cleaned.replace(/^\/+/, ""); cleaned = cleaned.replace(/\/+/g, "/"); return cleaned; } function getDeclarationExtensionFromJsExtension(ext) { if (ext === ".mjs") return ".d.mts"; if (ext === ".cjs") return ".d.cts"; return ".d.ts"; } async function getFilesFromGlobs(patterns, cwd) { const includePatterns = patterns.filter((p) => !p.startsWith("!")); const excludePatterns = patterns.filter((p) => p.startsWith("!")).map((p) => p.slice(1)); const includedFiles = new Set; for (const pattern of includePatterns) { const glob = new Bun.Glob(pattern); for await (const file of glob.scan(cwd)) { includedFiles.add(file); } } if (excludePatterns.length > 0) { for (const pattern of excludePatterns) { const glob = new Bun.Glob(pattern); for await (const file of glob.scan(cwd)) { includedFiles.delete(file); } } } return Array.from(includedFiles); } function filterTypescriptFiles(files) { return files.filter((file) => isTypeScriptFile(file)); } function minifyDts(dts) { return import_oxc_minify.minify(`${generateRandomString()}.d.ts`, dts, { codegen: { removeWhitespace: true }, mangle: false, compress: false, sourcemap: false }).code; } // src/isolated-decl-logger.ts var SEVERITY_CONFIG = { dev: { Error: { color: import_picocolors.default.yellow, prefix: "WARN" }, Warning: { color: import_picocolors.default.yellow, prefix: "WARN" }, Advice: { color: import_picocolors.default.blue, prefix: "ADVICE" }, default: { color: import_picocolors.default.blue, prefix: "WARN" } }, prod: { Error: { color: import_picocolors.default.red, prefix: "Error" }, Warning: { color: import_picocolors.default.yellow, prefix: "Warning" }, Advice: { color: import_picocolors.default.blue, prefix: "Advice" }, default: { color: import_picocolors.default.red, prefix: "Error" } } }; var ISOLATED_DECLARATION_ERRORS = { TS9007: `Function requires an explicit return type, e.g., \`function foo(): ${import_picocolors.default.green("string")} { ... }\`.`, TS9008: `Method requires an explicit return type, e.g., \`myMethod(): ${import_picocolors.default.green("number")} { ... }\`.`, TS9009: "Ensure at least one accessor (getter/setter) has an explicit return type.", TS9010: `Variable requires an explicit type annotation, e.g., \`let name: ${import_picocolors.default.green("string")} = "Bob";\`.`, TS9011: `Function parameter requires an explicit type, e.g., \`(param: ${import_picocolors.default.green("number")}) => {}\`.`, TS9012: `Class property requires an explicit type, e.g., \`class MyClass { id: ${import_picocolors.default.green("number")}; }\`.`, TS9013: "Expression type cannot be inferred. Add a type annotation where this expression is assigned or used.", TS9014: "Computed property names must be simple (e.g., string/number literals or basic identifiers).", TS9015: "Either add an explicit type to the object or avoid spread.", TS9016: "Either add an explicit type to the object or use full `key: value` syntax.", TS9017: `For array type inference, use \`as const\` (e.g., \`[1, 2, 3] ${import_picocolors.default.green("as const")}\`).`, TS9018: "Either add an explicit type to the array or avoid spread.", TS9019: `Avoid direct export of destructured bindings. Instead, declare and then export, e.g., \`const { x } = obj; ${import_picocolors.default.green("export { x };")}\`.`, TS9020: "Enum member initializers must be simple, constant values (like numbers or strings), not expressions or external references.", TS9021: "The `extends` clause must refer to a direct class name, not an expression.", TS9022: `Class expressions cannot infer types. Assign the class expression to an explicitly typed variable, e.g., \`const MyClass: ${import_picocolors.default.green("typeof OtherClass")} = class { ... };\`.`, TS9023: `Properties assigned to functions must be explicitly declared on the function type/interface, e.g., \`interface MyFunc { (): void; ${import_picocolors.default.green("myProp: string;")} }\`.`, TS9025: `Parameter can implicitly be \`undefined\`. Explicitly add \`| undefined\` to its type, e.g., \`param?: string\` becomes \`param: ${import_picocolors.default.green("string | undefined")}\`.`, TS9037: `Default export requires an explicit type, e.g., \`const MyValue: ${import_picocolors.default.green("number")} = 42; export default MyValue;\`.`, TS9038: "Computed property names in class/object literals must be simple (string/number literals or plain identifiers), not complex expressions.", TS9039: "A type references a private class member (`{name}`). Private members cannot be part of publicly exposed types." }; function logIsolatedDeclarationErrors(errors) { if (!errors.length) return; const hasErrors = errors.some(({ error }) => error.severity === "Error"); console.log(); errors.forEach(logSingle); if (hasErrors) { if (!isDev()) process.exit(1); } } function logSingle({ error, file, content }) { const label = error.labels?.[0]; const errorCode = extractErrorCode(error.message); const errorMessage = ISOLATED_DECLARATION_ERRORS[errorCode]; if (!errorMessage) return; const position = label ? calculatePosition(content, label.start) : ""; const shortPath = getShortFilePath(file); const { color, prefix } = getSeverityFormatting(error.severity); const formattedMessage = `${color(prefix)} ${shortPath}${position}: ${errorCode} ${errorMessage}`; const codeFrame = label ? generateOxcCodeFrame(content, label.start, label.end) : error.codeframe || ""; const helpMessage = error.helpMessage ? ` ${import_picocolors.default.cyan("Help:")} ${error.helpMessage}` : ""; console.log(`${formattedMessage}${helpMessage} ${import_picocolors.default.gray(codeFrame)} `); } function extractErrorCode(message) { return message.split(":")[0]; } function getSeverityFormatting(severity) { const config = SEVERITY_CONFIG[isDev() ? "dev" : "prod"]; return config[severity] || config.default; } function calculatePosition(sourceText, labelStart) { if (labelStart === undefined) return ""; const lines = sourceText.slice(0, labelStart).split(` `); const lineNumber = lines.length; const columnStart = lines[lines.length - 1].length + 1; return ` (${lineNumber}:${columnStart})`; } function generateOxcCodeFrame(sourceText, start, end) { const lines = sourceText.split(` `); const errorLine = sourceText.slice(0, start).split(` `).length; const lineContent = lines[errorLine - 1]; const lastNewlineIndex = sourceText.slice(0, start).lastIndexOf(` `); const startCol = start - lastNewlineIndex - 1; const endCol = end ? Math.min(end - lastNewlineIndex - 1, lineContent.length) : startCol + 1; const underlineLength = Math.max(1, endCol - startCol); const arrowLine = " ".repeat(startCol) + import_picocolors.default.dim(import_picocolors.default.blue("⎯".repeat(underlineLength))); return `${lineContent} ${arrowLine}`; } // src/generate.ts var import_node_path3 = __toESM(require("node:path")); var import_oxc_transform = require("oxc-transform"); var import_ts_import_resolver = require("ts-import-resolver"); // src/constants.ts var EMPTY_EXPORT = "export {};"; // src/errors.ts class TyperollError extends Error { constructor(message) { super(`typeroll: ${message}`); } } // src/fake-js.ts var import_parser = require("@babel/parser"); // src/ast.ts function isLikelyVariableOrTypeName(token) { return CAPITAL_LETTER_RE.test(token) && !token.startsWith("/*") && !token.startsWith("@") && !token.startsWith('"') && !token.startsWith("'") && !token.startsWith("`"); } function isImportDeclaration(node) { return node.type === "ImportDeclaration"; } function removeExportSyntaxes(text) { return text.replace(EXPORT_DEFAULT_RE, "").replace(EXPORT_RE, ""); } function isExportAllDeclaration(node) { return node.type === "ExportAllDeclaration"; } function isReExportStatement(node) { return node.type === "ExportNamedDeclaration" && !node.declaration; } function isSideEffectImport(node) { return node.type === "ImportDeclaration" && node.specifiers.length === 0; } function hasExportModifier(node, text) { return node.type.startsWith("Export") || text.trim().startsWith("export"); } function hasDefaultExportModifier(node, text) { return node.type === "ExportDefaultDeclaration" || text.trim().startsWith("export default"); } function isDefaultReExport(node) { return node.type === "ExportDefaultDeclaration" && node.declaration?.type === "Identifier"; } function getName(node, source) { if (!node) return null; if (node.type === "ExportNamedDeclaration" && node.declaration) { return getName(node.declaration, source); } if (node.type === "ExportDefaultDeclaration" && node.declaration) { if (node.declaration.type === "Identifier") { return node.declaration.name; } return getName(node.declaration, source); } switch (node.type) { case "TSInterfaceDeclaration": case "TSTypeAliasDeclaration": case "ClassDeclaration": case "TSEnumDeclaration": case "FunctionDeclaration": case "TSDeclareFunction": if (node.id && node.id.type === "Identifier") { return node.id.name; } break; case "TSModuleDeclaration": if (node.id && node.id.type === "Identifier") { return node.id.name; } break; case "VariableDeclaration": { const declarations = node.declarations; if (declarations?.length === 1 && declarations[0].id?.type === "Identifier") { return declarations[0].id.name; } break; } } return null; } function getCommentText(comments) { if (!comments) return null; return comments.map((comment) => { return comment.type === "CommentBlock" ? `/*${comment.value}*/` : comment.type === "CommentLine" ? `//${comment.value}` : null; }).join(` `); } function getAllImportNames(body) { const importNames = []; for (const statement of body) { if (isImportDeclaration(statement)) { const importDecl = statement; if (importDecl.specifiers) { for (const specifier of importDecl.specifiers) { if (specifier.type === "ImportDefaultSpecifier") { importNames.push(specifier.local.name); } else if (specifier.type === "ImportSpecifier") { importNames.push(specifier.local.name); } else if (specifier.type === "ImportNamespaceSpecifier") { importNames.push(specifier.local.name); } } } } } return importNames; } // src/fake-js.ts async function dtsToFakeJs(dtsContent) { const parsed = import_parser.parse(dtsContent, { sourceType: "module", plugins: ["typescript"] }); const referencedNames = new Set; const exportedNames = new Set; const result = []; for (const name of getAllImportNames(parsed.program.body)) { referencedNames.add(name); } for (const statement of parsed.program.body) { if (isNullOrUndefined(statement.start) || isNullOrUndefined(statement.end)) { continue; } const statementText = dtsContent.substring(statement.start, statement.end); const name = getName(statement, dtsContent); if (name) { referencedNames.add(name); } const isDefaultExport = hasDefaultExportModifier(statement, statementText); if (isDefaultExport) { result.push(`export { ${name} as default };`); if (isDefaultReExport(statement)) { continue; } } if (isImportDeclaration(statement) || isExportAllDeclaration(statement) || isReExportStatement(statement)) { if (isSideEffectImport(statement)) { continue; } const jsImportExport = jsifyImportExport(statementText); result.push(jsImportExport); continue; } let leadingComment = null; leadingComment = getCommentText(statement.leadingComments); let statementTextWithCommentsAttatched = `${leadingComment ? `${leadingComment} ` : ""}${statementText}`; const isExported = hasExportModifier(statement, statementText); if (isExported) { statementTextWithCommentsAttatched = removeExportSyntaxes(statementTextWithCommentsAttatched); } const tokens = tokenizeText(statementTextWithCommentsAttatched, referencedNames); const varName = name || generateRandomString(); result.push(`var ${varName} = [${tokens.join(", ")}];`); if (isExported && !isDefaultExport && !exportedNames.has(varName)) { result.push(`export { ${varName} };`); exportedNames.add(varName); } } return result.join(` `); } async function fakeJsToDts(fakeJsContent) { const parseResult = import_parser.parse(fakeJsContent, { sourceType: "module", attachComment: false }); const program = parseResult.program; const resultParts = []; for (const statement of program.body) { if (isNullOrUndefined(statement.start) || isNullOrUndefined(statement.end)) { continue; } const statementText = fakeJsContent.substring(statement.start, statement.end); if (isImportDeclaration(statement) || isExportAllDeclaration(statement) || isReExportStatement(statement)) { if (isImportDeclaration(statement)) { resultParts.push(statementText.replace(/.(?:mjs|cjs|js)\b/g, "")); continue; } resultParts.push(statementText); continue; } if (statement.type === "ExpressionStatement") { const namespaceDecl = handleNamespace(statement); if (namespaceDecl) { resultParts.push(namespaceDecl); continue; } } if (statement.type === "VariableDeclaration") { for (const declaration of statement.declarations) { if (declaration.init?.type === "ArrayExpression") { const dtsContent = processTokenArray(declaration.init); if (dtsContent) { resultParts.push(dtsContent); } } } } } return resultParts.join(` `); } function jsifyImportExport(text) { let result = text.replace(IMPORT_TYPE_RE, "import ").replace(EXPORT_TYPE_RE, "export ").replace(IMPORT_EXPORT_NAMES_RE, (_, keyword, names) => `${keyword} {${names.replace(TYPE_WORD_RE, "")}}`); result = result.replace(IMPORT_EXPORT_WITH_DEFAULT_RE, (_, keyword, defaultPart = "", names = "") => { const cleanedNames = names.replace(TYPE_WORD_RE, ""); return `${keyword}${defaultPart}{${cleanedNames}}`; }); return result; } function tokenizeText(text, referencedNames) { const tokens = []; let match; TOKENIZE_RE.lastIndex = 0; while (true) { match = TOKENIZE_RE.exec(text); if (match === null) break; const token = match[0]; if (isLikelyVariableOrTypeName(token) || referencedNames.has(token)) { tokens.push(token); } else { tokens.push(JSON.stringify(escapeNewlinesAndTabs(token))); } } return tokens; } function processTokenArray(arrayLiteral) { if (arrayLiteral.type !== "ArrayExpression") { return null; } const tokens = []; for (const element of arrayLiteral.elements) { if (!element) continue; const processed = processTokenElement(element); if (processed !== null) { tokens.push(processed); } } return tokens.join(""); } function processTokenElement(element) { if (element.type === "StringLiteral" && typeof element.value === "string") { return unescapeNewlinesAndTabs(element.value); } if (element.type === "Identifier") { return element.name; } if (element.type === "TemplateLiteral") { const parts = []; parts.push(unescapeNewlinesAndTabs(element.quasis[0]?.value?.raw || "")); for (let i = 0;i < element.expressions.length; i++) { const expr = element.expressions[i]; if (expr.type === "Identifier") { parts.push(expr.name); } parts.push(unescapeNewlinesAndTabs(element.quasis[i + 1]?.value?.raw || "")); } return parts.join(""); } return null; } function escapeNewlinesAndTabs(text) { return text.replace(/\n/g, "__typeroll_intermediate_new__line__").replace(/\t/g, "__typeroll_intermediate__tab__"); } function unescapeNewlinesAndTabs(text) { return text.replace(/__typeroll_intermediate_new__line__/g, ` `).replace(/__typeroll_intermediate__tab__/g, "\t"); } function handleNamespace(stmt) { const expr = stmt.expression; if (!expr || expr.type !== "CallExpression" || expr.callee?.type !== "Identifier" || expr.arguments?.length !== 2 || expr.arguments[0].type !== "Identifier" || expr.arguments[1].type !== "ObjectExpression") { return null; } const namespaceName = expr.arguments[0].name; const properties = expr.arguments[1].properties.filter((prop) => prop.type === "ObjectProperty").map((prop) => { if (prop.type === "ObjectProperty" && prop.key.type === "Identifier" && prop.value.type === "ArrowFunctionExpression" && prop.value.body.type === "Identifier") { const keyName = prop.key.name; const returnName = prop.value.body.name; return keyName === returnName ? keyName : `${returnName} as ${keyName}`; } return null; }).filter(Boolean); if (properties.length === 0) { return null; } return `declare namespace ${namespaceName} { export { ${properties.join(", ")} }; }`; } // src/resolver.ts var import_node_path2 = require("node:path"); var import_node_process = __toESM(require("node:process")); var import_oxc_resolver = require("oxc-resolver"); function createResolver({ tsconfig, cwd = import_node_process.default.cwd(), resolveOption }) { const resolver = new import_oxc_resolver.ResolverFactory({ mainFields: ["types", "typings", "module", "main"], conditionNames: ["types", "typings", "import", "require"], extensions: [".d.ts", ".d.mts", ".d.cts", ".ts", ".mts", ".cts"], tsconfig: tsconfig ? { configFile: tsconfig, references: "auto" } : undefined }); const resolutionCache = new Map; return (importSource, importer) => { if (importSource === "bun") return null; const cacheKey = `${importSource}:${importer || ""}`; if (resolutionCache.has(cacheKey)) { return resolutionCache.get(cacheKey) || null; } let shouldResolve = false; if (resolveOption !== undefined) { if (typeof resolveOption === "boolean") { shouldResolve = resolveOption; } else if (Array.isArray(resolveOption)) { shouldResolve = resolveOption.some((resolver2) => { if (typeof resolver2 === "string") { return resolver2 === importSource; } return resolver2.test(importSource); }); } } if (!shouldResolve) { resolutionCache.set(cacheKey, null); return null; } const directory = importer ? import_node_path2.dirname(importer) : cwd; const resolution = resolver.sync(directory, importSource); if (!resolution.path) { resolutionCache.set(cacheKey, null); return null; } const resolved = resolution.path; if (JS_RE.test(resolved)) { const dts = returnPathIfExists(resolved.replace(JS_RE, ".d.ts")) || returnPathIfExists(resolved.replace(JS_RE, ".d.mts")) || returnPathIfExists(resolved.replace(JS_RE, ".d.cts")); const result2 = isTypeScriptFile(dts) ? dts : null; resolutionCache.set(cacheKey, result2); return result2; } const result = isTypeScriptFile(resolved) ? resolved : null; resolutionCache.set(cacheKey, result); return result; }; } // src/generate.ts async function generateDts(entrypoints, options = {}) { const { resolve, preferredTsConfigPath, naming } = options; const cwd = options.cwd ? import_node_path3.default.resolve(options.cwd) : process.cwd(); const tsconfig = await loadTsConfig(cwd, preferredTsConfigPath); const nonAbsoluteEntrypoints = entrypoints.filter((entrypoint) => !import_node_path3.default.isAbsolute(entrypoint)); const resolvedEntrypoints = await getFilesFromGlobs(nonAbsoluteEntrypoints, cwd); const absoluteEntrypoints = entrypoints.filter((entrypoint) => import_node_path3.default.isAbsolute(entrypoint)); if (!filterTypescriptFiles([...resolvedEntrypoints, ...absoluteEntrypoints]).length) { throw new TyperollError("One or more of the entrypoints you provided do not exist. Please check that each entrypoint points to a valid file."); } const collectedErrors = []; const resolver = createResolver({ cwd, resolveOption: resolve, tsconfig: tsconfig.filepath }); const fakeJsPlugin = { name: "fake-js", setup(build) { build.onResolve({ filter: /.*/ }, (args) => { if (!NODE_MODULES_RE.test(args.importer)) { const resolved = import_ts_import_resolver.resolveTsImportPath({ importer: args.importer, path: args.path, cwd, tsconfig: tsconfig.config }); if (resolved && isTypeScriptFile(resolved)) { return { path: resolved }; } } const resolvedFromNodeModules = resolver(args.path, args.importer); if (resolvedFromNodeModules) { return { path: resolvedFromNodeModules }; } return { path: args.path, external: true }; }); build.onLoad({ filter: /\.(ts|tsx|d\.ts|d\.mts|d\.cts)$/ }, async (args) => { const sourceText = await Bun.file(args.path).text(); const declarationResult = import_oxc_transform.isolatedDeclaration(args.path, sourceText); let fakeJsContent = ""; if (!collectedErrors.some((e) => e.file === args.path)) { for (const error of declarationResult.errors) { collectedErrors.push({ error, file: args.path, content: sourceText }); } } if (declarationResult.code) { fakeJsContent = await dtsToFakeJs(declarationResult.code); } else { fakeJsContent = EMPTY_EXPORT; } return { loader: "js", contents: fakeJsContent }; }); } }; const result = await Bun.build({ entrypoints: [ ...filterTypescriptFiles(resolvedEntrypoints).map((entry) => import_node_path3.default.resolve(import_node_path3.default.join(cwd, entry))), ...filterTypescriptFiles(absoluteEntrypoints) ], format: "esm", target: "node", naming, splitting: options.splitting, plugins: [fakeJsPlugin], packages: "external", minify: options.minify, throw: false }); if (!result.success) { throw new TyperollError(`DTS bundling failed: ${result.logs}`); } const outputs = result.outputs.filter((output) => output.kind === "chunk" || output.kind === "entry-point"); const bundledFiles = []; for (const output of outputs) { const bundledFakeJsContent = await output.text(); const dtsContent = await fakeJsToDts(bundledFakeJsContent); const entrypoint = output.kind === "entry-point" ? entrypoints[bundledFiles.length] : undefined; const chunkFileName = output.kind === "chunk" ? replaceExtension(import_node_path3.default.basename(output.path), getDeclarationExtensionFromJsExtension(getExtension(output.path))) : undefined; const outputPath = cleanPath(replaceExtension(cleanPath(output.path), getDeclarationExtensionFromJsExtension(getExtension(output.path)))); const treeshakedDts = import_oxc_transform.isolatedDeclaration(`${generateRandomString()}.d.ts`, dtsContent); if (!treeshakedDts.code.length && !treeshakedDts.errors.length) { continue; } if (treeshakedDts.errors.length && !treeshakedDts.code) { throw new TyperollError(`DTS treeshaking failed for ${entrypoint || outputPath} ${JSON.stringify(treeshakedDts.errors, null, 2)}`); } bundledFiles.push({ kind: output.kind === "entry-point" ? "entry-point" : "chunk", entrypoint, chunkFileName, outputPath, dts: options.minify ? minifyDts(treeshakedDts.code) : treeshakedDts.code, pathInfo: { outputPathWithoutExtension: deleteExtension(outputPath), ext: getExtension(outputPath) } }); } return { files: bundledFiles, errors: collectedErrors }; }