@stacksjs/dtsx
Version:
A modern, fast .d.ts generation tool, powered by Bun.
31 lines (27 loc) • 16.2 kB
JavaScript
// @bun
import{bc as r,cc as Zj,dc as s}from"./chunk-gapg5f4h.js";import{ec as Qj,fc as Uj}from"./chunk-3ad4xrgw.js";import{gc as Nj}from"./chunk-gxkksf4a.js";import{nc as $j}from"./chunk-q5wtqk0e.js";import{zc as Yj}from"./chunk-shwj5718.js";import{Ic as Gj,Kc as y,Mc as Ij,Nc as Kj,Oc as Bj,Pc as Hj,Qc as Lj}from"./chunk-vrhjahk1.js";import{Rc as g,Uc as Vj,Wc as Wj,Xc as S}from"./chunk-nkp89e28.js";import{ed as f}from"./chunk-rr7k2pw0.js";import{fd as _j}from"./chunk-09ss191z.js";import{Ad as n,Bd as Xj}from"./chunk-3nd5cpav.js";import{Jd as i,Md as zj}from"./chunk-r3tgppjs.js";import{oe as Jj}from"./chunk-t1vsc910.js";import{De as N,Fe as p}from"./chunk-dx7m458f.js";import{Le as Aj}from"./chunk-sc0mtgkd.js";import{kf as jj}from"./chunk-736mzc3x.js";var{Glob:Tj}=globalThis.Bun;import{mkdir as h,readdir as Dj,realpath as Rj,rm as vj}from"fs/promises";import{availableParallelism as wj}from"os";import{basename as kj,dirname as x,extname as Ej,isAbsolute as o,parse as Sj,relative as L,resolve as k}from"path";async function t(U,W,j,Y,$){let Q=kj(U)||"output.d.ts",J=L(x(U),W),z=`${Q}.map`,B=j.lastIndexOf(`
${Gj()}`),_=B===-1?j:j.slice(0,B),I=Hj(_,Q,J,Y),K=`${U}.map`;return await y(K,JSON.stringify(I)),N.debug(` Generated source map: ${L($,K)}`),z}async function Mj(U){let W=Date.now(),j={...f,...U};if(j.logLevel)p(j.logLevel);else if(j.verbose)p("debug");let Y=new _j;if(j.plugins&&j.plugins.length>0){for(let A of j.plugins)Y.register(A),N.debug(`Registered plugin: ${A.name}`);j=await Y.runOnStart(j)}if(await yj(j),j.isolatedDeclarations===void 0)j.isolatedDeclarations=await Ij(j);let $=j.typeMappings?i(j.typeMappings):void 0,Q=null;if(j.incremental){if(Q=new Qj(j),j.clearCache){if(N.debug("Clearing build cache..."),!j.dryRun)Q.clear()}else if(Q.load()){let X=Q.getStats();N.debug(`Loaded build cache with ${X.entries} entries`)}else N.debug("No existing build cache found, starting fresh");if(!j.dryRun)Uj(j.cwd)}let J={generationMode:j.isolatedDeclarations?"isolated":"semantic",filesProcessed:0,filesGenerated:0,filesFailed:0,filesValidated:0,validationErrors:0,declarationsFound:0,importsProcessed:0,exportsProcessed:0,durationMs:0,errors:[]},z=0;if(N.debug("Starting DTS generation..."),N.debug(`Using ${J.generationMode} declaration generation path`),N.debug("Config:",j),j.clean&&!j.dryRun)await bj(j);let B=await Cj(j),_=B.slice(),I=null;if(j.autoIncludeReExports!==!1&&_.length>0){I=await s(_,{includeImports:!0});let A=k(j.cwd,j.root),X=j.exclude||[],Z=[];for(let V of I.reachable){if(_.includes(V))continue;if(!a(V))continue;if(V.endsWith(".d.ts"))continue;if(V.includes("node_modules"))continue;if(!l(V,A)){N.warn(`Skipping auto-included source outside root: ${L(j.cwd,V)}`);continue}if(u(V,X,A))continue;Z.push(V)}if(Z.length>0)_=[..._,...Z],N.debug(`Auto-included ${Z.length} file(s) reached via relative re-exports`)}if(Pj(_,j),Q&&!j.dryRun){let A=Q.prune(new Set(_),j.cwd);if(A>0)N.debug(`Pruned ${A} deleted files from cache`)}if(N.debug(`Found ${_.length} TypeScript files`),j.progress&&_.length>0){let A=j.parallel?"parallel":"sequential";N.info(`Processing ${_.length} files (${A})...`)}let K=async(A,X)=>{let Z;try{let V=b(A,j),G=async(T)=>{if(!j.diff)return;try{let w=await S(V),E=Bj(w,T,L(j.cwd,V));if(E)N.info(`
${E}`);else N.debug(`[no changes] ${V}`)}catch{N.info(`[new file] ${L(j.cwd,V)}`)}},D=(T)=>{if(!j.validate)return 0;let w=Kj(T,V);if(w.isValid)return N.debug(`[validation] ${V} - OK`),0;N.warn(`[validation] ${L(j.cwd,V)} has ${w.errors.length} error(s):`);for(let E of w.errors){let c=` Line ${E.line}:${E.column}`;if(E.code)c+=` [${E.code}]`;if(c+=` - ${E.message}`,N.warn(c),E.suggestion)N.warn(` Suggestion: ${E.suggestion}`)}return w.errors.length},M=(T)=>{N.info(`[dry-run] Would generate: ${V}`),N.debug("--- Content preview ---"),N.debug(T.slice(0,500)+(T.length>500?`
...`:"")),N.debug("--- End preview ---")};if(Q){let T=Q.getCachedIfValid(A,j.cwd);if(T){await G(T);let w=D(T);if(j.dryRun)M(T);else{if(await h(x(V),{recursive:!0}),j.declarationMap)Z=X??await S(A),await t(V,A,T,Z,j.cwd);await y(V,T,j.lineEnding)}return N.debug(`[cached] ${L(j.cwd,V)}`),{success:!0,file:A,declarationCount:0,importCount:0,exportCount:0,cached:!0,validationErrorCount:w}}}Z=X??await S(A);let{content:d,declarationCount:C,importCount:m,exportCount:R}=await Fj(A,Z,j,Y,$),q=d;if(j.prettier||j.indentStyle||j.indentSize){let T=await Yj(q,{usePrettier:j.prettier,builtIn:{indentSize:j.indentSize||2,useTabs:j.indentStyle==="tabs",normalizeWhitespace:!0,sortImports:!0,trailingNewline:!0}},V);q=T.content;for(let w of T.warnings??[])N.warn(`[format] ${w}`)}if(j.declarationMap){let T=`${kj(V)||"output.d.ts"}.map`;q=Lj(q,T)}await G(q);let Oj=D(q);if(j.dryRun)M(q);else{if(await h(x(V),{recursive:!0}),j.declarationMap&&Z)await t(V,A,q,Z,j.cwd);if(await y(V,q,j.lineEnding),Q&&Z)Q.update(A,Z,q,j.cwd);N.debug(`Generated: ${V}`)}return{success:!0,file:A,declarationCount:C,importCount:m,exportCount:R,validationErrorCount:Oj}}catch(V){let G=n(V,A,Z);if(j.plugins&&j.plugins.length>0)await Y.runOnError(V instanceof Error?V:Error(String(V)),A,Z||"");return{success:!1,file:A,declarationCount:0,importCount:0,exportCount:0,dtsError:G,validationErrorCount:0}}},H=j.parallel||j.parallel!==!1&&_.length>=10,F=jj(j.concurrency,wj?.()??8),v=new Map;if(H&&_.length>1){let A=_.map(async(X)=>{try{let Z=await S(X);return{file:X,source:Z}}catch{return{file:X,source:null}}});for(let X of await Promise.all(A))if(X.source!==null)v.set(X.file,X.source)}let O=(A)=>{if(J.filesProcessed++,A.success){if(A.cached)z++;else J.filesGenerated++,J.declarationsFound+=A.declarationCount,J.importsProcessed+=A.importCount,J.exportsProcessed+=A.exportCount;if(j.validate){if(J.filesValidated++,A.validationErrorCount)J.validationErrors+=A.validationErrorCount}}else if(J.filesFailed++,A.dtsError){J.errors.push(A.dtsError);let X=Xj(A.dtsError);if(j.continueOnError)N.warn(X);else throw N.error(X),Error(A.dtsError.message)}};if(H)for(let A=0;A<_.length;A+=F){let X=_.slice(A,A+F),Z=await Promise.all(X.map((V)=>K(V,v.get(V))));for(let V of Z)O(V);if(j.progress){let V=Math.round(J.filesProcessed/_.length*100);N.info(`[${J.filesProcessed}/${_.length}] ${V}%`)}}else for(let A of _){let X=await K(A);if(O(X),j.progress){let Z=Math.round(J.filesProcessed/_.length*100),V=X.cached?"[cached]":"";N.info(`[${J.filesProcessed}/${_.length}] ${Z}% - ${L(j.cwd,A)} ${V}`)}}if(Q&&!j.dryRun)Q.save(),N.debug("Saved build cache");if(!j.bundle){let A=[];if(I)for(let X of I.unresolved)A.push({from:X.from,specifier:X.specifier,reason:"missing"});if(j.autoIncludeReExports===!1&&_.length>0){let X=new Set(_);for(let Z of _){let V;try{V=await S(Z)}catch{continue}for(let G of Zj(V)){if(!G.specifier.startsWith("."))continue;let D=r(G.specifier,Z);if(!D.resolved)A.push({from:Z,specifier:G.specifier,reason:"missing"});else if(!/\.d\.(?:ts|mts|cts)$/.test(D.resolved)&&!X.has(D.resolved))A.push({from:Z,specifier:G.specifier,reason:"not-emitted"})}}}if(A.length>0){let X=[];X.push(`Found ${A.length} re-export(s) pointing at siblings that won't be in the output:`);for(let V of A){let G=L(j.cwd,V.from);if(V.reason==="missing")X.push(` ${G} \u2192 '${V.specifier}' (path not found on disk)`);else X.push(` ${G} \u2192 '${V.specifier}' (resolved but not in entrypoints; set autoIncludeReExports: true or add to entrypoints)`)}let Z=X.join(`
`);if(j.failOnUnresolvedReExport)throw Error(Z);N.warn(Z),N.warn('Generated .d.ts files reference modules that were not emitted \u2014 consumers will see "has no exported member" errors.')}}if(j.bundle&&(J.filesGenerated>0||z>0)&&B.length>0)try{N.debug("Bundling declarations...");let A=new Map,X=async(V)=>{let G=A.get(V);if(G!==void 0)return G;return G=await S(V),A.set(V,G),G};for(let V of _)await X(V);let Z=B.length===1&&!!j.bundleOutput;for(let V of B){let G=await s([V],{includeImports:!0}),D=new Set;for(let R of G.reachable){if(R.endsWith(".d.ts"))continue;if(R.includes("node_modules"))continue;D.add(R)}let M=_.filter((R)=>D.has(R));if(!M.includes(V))M.push(V);let d=new Map;for(let R of M){let q=A.get(R)??await X(R);d.set(R,q)}let C=await Nj(M,d,j),m=Z?k(j.cwd,j.outdir,j.bundleOutput):b(V,j);if(j.dryRun)N.info(`[dry-run] Would bundle ${C.files.length} files to: ${L(j.cwd,m)}`);else await h(x(m),{recursive:!0}),await y(m,C.content,j.lineEnding),N.info(`Bundled ${C.files.length} files to: ${L(j.cwd,m)}`);if(Z)break}}catch(A){let X=A instanceof Error?A.message:String(A);N.error(`Bundle failed: ${X}`)}if(J.durationMs=Date.now()-W,j.stats)if(j.outputFormat==="json")console.log(JSON.stringify(J,null,2));else{if(N.info(`
--- Generation Statistics ---`),N.info(`Files processed: ${J.filesProcessed}`),N.info(`Files generated: ${J.filesGenerated}`),z>0)N.info(`Files cached: ${z}`);if(J.filesFailed>0)N.info(`Files failed: ${J.filesFailed}`);if(N.info(`Declarations found: ${J.declarationsFound}`),N.info(`Imports processed: ${J.importsProcessed}`),N.info(`Exports processed: ${J.exportsProcessed}`),J.filesValidated>0){if(N.info(`Files validated: ${J.filesValidated}`),J.validationErrors>0)N.info(`Validation errors: ${J.validationErrors}`)}if(N.info(`Duration: ${J.durationMs}ms`),J.errors.length>0){N.info(`
Errors:`);for(let A of J.errors){let X=` - ${A.file}`;if(A.location)X+=`:${A.location.line}:${A.location.column}`;if(A.code)X+=` [${A.code}]`;if(X+=`: ${A.message}`,N.info(X),A.suggestion)N.info(` Suggestion: ${A.suggestion}`)}}N.info(`-----------------------------
`)}if(j.plugins&&j.plugins.length>0)await Y.runOnEnd(J);return N.debug("DTS generation complete!"),J}var mj=50,P=new Map;async function e(U){try{return await Rj(U)}catch{return k(U)}}async function yj(U){let W=k(U.cwd,U.outdir);if(U.bundle&&U.bundleOutput){if(o(U.bundleOutput))throw Error("bundleOutput must be relative to outdir");let $=k(W,U.bundleOutput);if(!l($,W))throw Error("bundleOutput must stay within outdir")}if(!U.clean||U.dryRun)return;if(W===Sj(W).root)throw Error("Refusing to clean declarations from the filesystem root");let[j,Y]=await Promise.all([e(W),e(k(U.cwd,U.root))]);if(l(Y,j))throw Error("Refusing to clean an outdir that contains the source root")}function xj(U){let W=P.get(U);if(!W){if(W=new Tj(U),P.set(U,W),P.size>mj){let j=P.keys().next().value;if(j!==void 0)P.delete(j)}}return W}async function bj(U){let W=k(U.cwd,U.outdir);async function j(Y){let $;try{$=await Dj(Y,{withFileTypes:!0})}catch{return}await Promise.all($.map(async(Q)=>{let J=k(Y,Q.name);if(Q.isDirectory()){await j(J);return}if(Q.name.endsWith(".d.ts")||Q.name.endsWith(".d.mts")||Q.name.endsWith(".d.cts")||Q.name.endsWith(".d.ts.map")||Q.name.endsWith(".d.mts.map")||Q.name.endsWith(".d.cts.map"))await vj(J,{force:!0})}))}await j(W)}function u(U,W,j){if(!W||W.length===0)return!1;let Y=L(j,U);for(let $ of W){let Q=xj($);if(Q.match(Y)||Q.match(U))return!0}return!1}async function Cj(U){let W=[],j=k(U.cwd,U.root),Y=U.exclude||[],$=[...U.entrypoints,...U.include??[]];for(let Q of $)if(o(Q)&&a(Q)){if(!Q.includes("node_modules")){if(!l(Q,j)&&U.outputStructure!=="flat")N.warn(`Skipping entrypoint outside root: ${L(U.cwd,Q)}`);else if(!u(Q,Y,j))W.push(Q)}}else{let J=new Tj(Q);for await(let z of J.scan({cwd:j,absolute:!0,onlyFiles:!0}))if(a(z)&&!z.includes("node_modules")){if(!u(z,Y,j))W.push(z)}}return[...new Set(W)].sort()}function l(U,W){let j=L(W,U);return j!==".."&&!j.startsWith(`..${process.platform==="win32"?"\\":"/"}`)&&!o(j)}function Pj(U,W){let j=new Map;for(let Y of U){let $=b(Y,W),Q=j.get($);if(Q&&Q!==Y)throw Error(`Output path collision: ${L(W.cwd,Q)} and ${L(W.cwd,Y)} both emit ${L(W.cwd,$)}`);j.set($,Y)}}function a(U){return/\.(m?tsx?|cts|jsx?|mjs|cjs|vue)$/.test(U)&&!/\.d\.(?:ts|mts|cts)$/.test(U)}function b(U,W){let j=k(W.cwd,W.root),$=L(j,U).replace(/\.(m?tsx?|cts|jsx?|mjs|cjs|vue)$/,(Q)=>{if(Q===".mts"||Q===".mjs")return".d.mts";if(Q===".cts"||Q===".cjs")return".d.cts";return".d.ts"});if(W.outputStructure==="mirror")return k(W.cwd,W.outdir,$);else{let Q=$.split("/").pop();return k(W.cwd,W.outdir,Q)}}function dj(U,W,j=""){let Y=L(x(U),W).replace(/\\/g,"/");if(Y=Y.replace(/\.d\.mts$/,"").replace(/\.d\.cts$/,"").replace(/\.d\.ts$/,""),j)Y+=j;if(!Y.startsWith("."))Y=`./${Y}`;return Y}function hj(U,W,j){let Y=b(W,j),$=(Q)=>{let J=r(Q,W);if(!J.isRelative||!J.resolved)return Q;if(/\.d\.(?:ts|mts|cts)$/.test(J.resolved))return Q;let z=Q.match(/[?#].*$/)?.[0]??"",B=z?Q.slice(0,-z.length):Q,_=Ej(B),I=/^(?:\.js|\.jsx|\.mjs|\.cjs)$/.test(_)?_:"";return dj(Y,b(J.resolved,j),I)+z};return U.replace(/\b(from\s*)(['"])(\.{1,2}\/[^'"]+)\2/g,(Q,J,z,B)=>{return`${J}${z}${$(B)}${z}`}).replace(/\b(import\s*)(['"])(\.{1,2}\/[^'"]+)\2/g,(Q,J,z,B)=>{return`${J}${z}${$(B)}${z}`}).replace(/\b(import\s*\(\s*)(['"])(\.{1,2}\/[^'"]+)\2/g,(Q,J,z,B)=>{return`${J}${z}${$(B)}${z}`})}async function YA(U,W){return(await qj(U,W)).content}async function qj(U,W,j){let Y=await S(U),$=W.typeMappings?i(W.typeMappings):void 0;return Fj(U,Y,W,j,$)}async function Fj(U,W,j,Y,$){let Q=W;if(Y)Q=await Y.runOnBeforeFile(U,W);let J=Aj(Q,U,j.keepComments,j.isolatedDeclarations??!1);if(Y)J=await Y.runOnDeclarations(U,Q,J);let z=0,B=0;for(let K=0;K<J.length;K++){let H=J[K];if(H.kind==="import")z++;if(H.kind==="export"||H.isExported)B++}let I=Jj(J,{filePath:U,sourceCode:Q,declarations:J},j.keepComments,j.importOrder);if(I=hj(I,U,j),$)I=zj(I,$,{filePath:U});if(j.normalizeOutput===!0||j.declarationOrder)I=$j(I,{lineEnding:"lf",declarationOrder:j.declarationOrder,indent:{style:j.indentStyle??"spaces",size:j.indentSize??2}});if(Y)I=await Y.runOnAfterFile(U,Q,I);return{content:I,declarationCount:J.length,importCount:z,exportCount:B}}async function ZA(U){let W={...f,...U};if(W.logLevel)p(W.logLevel);let j=k(W.cwd,W.root),Y=150,$=5,Q=1e4,J={pendingChanges:new Set,debounceTimer:null,isProcessing:!1,errorCount:0,lastErrorTime:0};N.info(`Watching for changes in ${j}...`),N.info(`Press Ctrl+C to stop
`);try{await Mj(W),N.info(`[watch] Initial generation complete
`)}catch(K){let H=K instanceof Error?K.message:String(K);N.error(`[watch] Initial generation failed: ${H}`),N.info(`[watch] Continuing to watch for changes...
`)}async function z(){if(J.isProcessing||J.pendingChanges.size===0)return;let K=Date.now();if(J.errorCount>=$){if(K-J.lastErrorTime<Q){N.warn(`[watch] Too many errors, pausing for ${Math.ceil((Q-(K-J.lastErrorTime))/1000)}s...`);return}J.errorCount=0}J.isProcessing=!0;let H=Array.from(J.pendingChanges);J.pendingChanges.clear();let F=new Date().toLocaleTimeString();if(H.length===1)N.info(`
[${F}] File changed: ${H[0]}`);else N.info(`
[${F}] ${H.length} files changed`);let v=0,O=0;for(let A of H){let X=k(j,A);try{let Z=W.exclude||[];if(u(X,Z,j)){N.debug(` Skipping excluded file: ${A}`);continue}if(!await Vj(X).exists()){N.debug(` Skipping deleted file: ${A}`);continue}let G=b(X,W),{content:D}=await qj(X,W);await h(x(G),{recursive:!0}),await y(G,D,W.lineEnding),N.info(` \u2713 ${L(W.cwd,G)}`),v++}catch(Z){O++,J.errorCount++,J.lastErrorTime=Date.now();let V=n(Z,X);if(N.error(` \u2717 ${A}: ${V.message}`),V.suggestion)N.error(` Suggestion: ${V.suggestion}`)}}if(H.length>1)N.info(` Done: ${v} generated, ${O} failed`);if(O===0)J.errorCount=0;if(J.isProcessing=!1,J.pendingChanges.size>0)J.debounceTimer=setTimeout(z,Y)}function B(K){if(J.pendingChanges.add(K),J.debounceTimer)clearTimeout(J.debounceTimer);J.debounceTimer=setTimeout(z,Y)}let I=Wj([g?"bun":"node","-e",`
const fs = require('fs');
const rootPath = '${j}';
fs.watch(rootPath, { recursive: true }, (eventType, filename) => {
if (filename && filename.endsWith('.ts') && !filename.endsWith('.d.ts')) {
console.log(\`CHANGED:\${filename}\`);
}
});
// Keep process alive
setInterval(() => {}, 1000);
`],{stdout:"pipe",stderr:"inherit"});if(g){let K=I.stdout.getReader(),H=new TextDecoder,F="";while(!0){let{done:v,value:O}=await K.read();if(v)break;F+=H.decode(O,{stream:!0});let A=F.split(`
`);F=A.pop()||"";for(let X of A)if(X.startsWith("CHANGED:")){let Z=X.slice(8);B(Z)}}}else{let K=I.stdout,H="";K.on("data",(F)=>{H+=F.toString();let v=H.split(`
`);H=v.pop()||"";for(let O of v)if(O.startsWith("CHANGED:")){let A=O.slice(8);B(A)}}),await I.exited}}
export{Mj as _b,YA as $b,ZA as ac};