@stacksjs/dtsx
Version:
A modern, fast .d.ts generation tool, powered by Bun.
5 lines (4 loc) • 4.84 kB
JavaScript
// @bun
class H{config;types=new Map;imports=new Map;relationships=[];usageMap=new Map;constructor(b={}){this.config={types:!1,relationships:!1,usage:!1,imports:!1,importUsage:!1,importRelationships:!1,...b}}trackType(b,j){if(!this.config.types)return;if(["interface","type","class","enum"].includes(b.kind)){if(this.types.get(b.name))return;let C={name:b.name,kind:b.kind,file:j,usedBy:new Set,references:new Set,extendsFrom:b.extends?[b.extends]:void 0,implementsFrom:b.implements};if(this.types.set(b.name,C),this.config.relationships){if(b.extends)this.relationships.push({from:b.name,to:b.extends,kind:"extends",file:j});if(b.implements)for(let E of b.implements)this.relationships.push({from:b.name,to:E,kind:"implements",file:j})}}}trackTypeUsage(b,j,q){if(!this.config.usage)return;let C=this.types.get(b);if(C)C.usedBy.add(j);let E=this.usageMap.get(b)||new Set;if(E.add(`${q}:${j}`),this.usageMap.set(b,E),this.config.relationships)this.relationships.push({from:j,to:b,kind:"uses",file:q})}trackImport(b,j,q,C){if(!this.config.imports)return;let E={source:b,specifiers:j,isTypeOnly:q,file:C,usedSpecifiers:new Set,unusedSpecifiers:new Set(j)},F=this.imports.get(C)||[];F.push(E),this.imports.set(C,F)}trackImportUsage(b,j){if(!this.config.importUsage)return;let q=this.imports.get(j);if(!q)return;for(let C of q)if(C.specifiers.includes(b))C.usedSpecifiers.add(b),C.unusedSpecifiers.delete(b)}trackTypeReference(b,j){if(!this.config.types)return;let q=this.types.get(b);if(q)q.references.add(j)}getResults(){let b=[],j=[];for(let[E,F]of this.types)if(F.usedBy.size===0&&F.references.size===0)b.push(E);for(let E of this.imports.values())for(let F of E)if(F.unusedSpecifiers.size===F.specifiers.length)j.push(F);let q=this.detectCircularReferences(),C={totalTypes:this.types.size,usedTypes:this.types.size-b.length,unusedTypes:b.length,totalImports:Array.from(this.imports.values()).flat().length,usedImports:Array.from(this.imports.values()).flat().filter((E)=>E.usedSpecifiers.size>0).length,unusedImports:j.length,totalRelationships:this.relationships.length,circularDependencies:q.length};return{types:this.types,imports:this.imports,relationships:this.relationships,unusedTypes:b,unusedImports:j,circularReferences:q,statistics:C}}detectCircularReferences(){let b=[],j=new Set,q=[],C=(E)=>{if(q.includes(E)){let G=q.indexOf(E);b.push(q.slice(G));return}if(j.has(E))return;j.add(E),q.push(E);let F=this.relationships.filter((G)=>G.from===E&&(G.kind==="extends"||G.kind==="implements"||G.kind==="references")).map((G)=>G.to);for(let G of F)C(G);q.pop()};for(let E of this.types.keys())C(E);return b}clear(){this.types.clear(),this.imports.clear(),this.relationships=[],this.usageMap.clear()}formatResults(){let b=this.getResults(),j=["=== Tracking Results ===",""];if(j.push("Statistics:"),j.push(` Total types: ${b.statistics.totalTypes}`),j.push(` Used types: ${b.statistics.usedTypes}`),j.push(` Unused types: ${b.statistics.unusedTypes}`),j.push(` Total imports: ${b.statistics.totalImports}`),j.push(` Used imports: ${b.statistics.usedImports}`),j.push(` Unused imports: ${b.statistics.unusedImports}`),j.push(` Type relationships: ${b.statistics.totalRelationships}`),j.push(` Circular dependencies: ${b.statistics.circularDependencies}`),j.push(""),b.unusedTypes.length>0){j.push("Unused types:");for(let q of b.unusedTypes){let C=b.types.get(q);j.push(` - ${q} (${C?.kind}) in ${C?.file}`)}j.push("")}if(b.unusedImports.length>0){j.push("Unused imports:");for(let q of b.unusedImports)j.push(` - ${q.source} in ${q.file}`),j.push(` Specifiers: ${Array.from(q.unusedSpecifiers).join(", ")}`);j.push("")}if(b.circularReferences.length>0){j.push("Circular references:");for(let q of b.circularReferences)j.push(` - ${q.join(" -> ")} -> ${q[0]}`);j.push("")}return j.join(`
`)}}function J(b){return new H(b)}function K(b,j,q){for(let C of b){if(q.trackType(C,j),C.typeAnnotation){let E=L(C.typeAnnotation);for(let F of E)q.trackTypeUsage(F,C.name,j)}if(C.extends)q.trackTypeUsage(C.extends,C.name,j);if(C.implements)for(let E of C.implements)q.trackTypeUsage(E,C.name,j);if(C.kind==="import"&&C.source&&C.specifiers)q.trackImport(C.source,C.specifiers.map((E)=>E.name),C.isTypeOnly||!1,j)}}function L(b){let j=[],q=new Set(["string","number","boolean","any","unknown","void","never","null","undefined","object","symbol","bigint","true","false","readonly","keyof","typeof","infer","extends","in","out"]),C=/\b([A-Z]\w*)\b/g,E;while((E=C.exec(b))!==null){let F=E[1];if(!q.has(F.toLowerCase())&&!j.includes(F))j.push(F)}return j}function M(b,j){let q=J({imports:!0,importUsage:!0,importRelationships:!0,...j});for(let[C,E]of b)K(E,C,q);return q.getResults()}function Q(b,j){let q=J({types:!0,relationships:!0,usage:!0,...j});for(let[C,E]of b)K(E,C,q);return q.getResults()}
export{H as c,J as d,K as e,M as f,Q as g};