@hey-api/codegen-core 0.5.1 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1618 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +1568 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,3 +1,1620 @@
|
|
|
1
1
|
|
|
2
|
-
var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require(`node:path`);c=s(c);let l=require(`ansi-colors`);l=s(l);let u=require(`color-support`);u=s(u);const d=`heyapi.file`,f=`heyapi.node`,p=`heyapi.symbol`;l.default.enabled=(0,u.default)().hasBasic;const m=`heyapi`,h=/^(1|true|yes|on)$/i.test(process.env.HEYAPI_DISABLE_WARNINGS??``),g={analyzer:l.default.greenBright,dsl:l.default.cyanBright,file:l.default.yellowBright,registry:l.default.blueBright,symbol:l.default.magentaBright},_={deprecated:l.default.magentaBright};let v;function y(){if(v)return v;let e=process.env.DEBUG;return v=new Set(e?e.split(`,`).map(e=>e.trim().toLowerCase()):[]),v}const b=new Set;function x(e,t){let n=y();if(!(n.has(`*`)||n.has(`${m}:*`)||n.has(`${m}:${t}`)||n.has(t)))return;let r=(g[t]??l.default.whiteBright)(`${m}:${t}`);console.debug(`${r} ${e}`)}function S(e,t){if(h)return;let n=_[t]??l.default.yellowBright;console.warn(n(`${e}`))}function C({context:e,field:t,replacement:n}){let r=e?`${e}:${t}:${JSON.stringify(n)}`:`${t}:${JSON.stringify(n)}`;if(b.has(r))return;b.add(r);let i=`\`${t}\` is deprecated.`;if(n){let e=typeof n==`function`?n(t):n,r=(e instanceof Array?e:[e]).map(e=>`\`${e}\``).join(` or `);i+=` Use ${r} instead.`}S(`${e?`[${e}] `:``}${i}`,`deprecated`)}const w={debug:x,warn:S,warnDeprecated:C};var T=class{_exports=[];_extension;_finalPath;_imports=[];_language;_logicalFilePath;_name;_nodes=[];_renderer;"~brand"=`heyapi.file`;allNames=new Map;external;id;project;topLevelNames=new Map;constructor(e,t,n){this.external=e.external??!1,this.id=t,e.language!==void 0&&(this._language=e.language),this._logicalFilePath=e.logicalFilePath.split(c.default.sep).join(`/`),e.name!==void 0&&(this._name=e.name),this.project=n}get exports(){return[...this._exports]}get extension(){if(this.external)return;if(this._extension)return this._extension;let e=this.language,t=e?this.project.extensions[e]:void 0;if(t&&t[0])return t[0]}get finalPath(){return this._finalPath?this._finalPath:[...this._logicalFilePath?this._logicalFilePath.split(`/`).slice(0,-1):[],`${this.name}${this.extension??``}`].join(`/`)}get imports(){return[...this._imports]}get language(){if(this._language)return this._language;if(this._nodes[0])return this._nodes[0].language}get logicalFilePath(){return this._logicalFilePath}get name(){if(this._name)return this._name;let e=this._logicalFilePath.split(`/`).pop();if(e)return e;let t=`File ${this.toString()} has no name`;throw w.debug(t,`file`),Error(t)}get nodes(){return[...this._nodes]}get renderer(){return this._renderer}addExport(e){this._exports.push(e)}addImport(e){this._imports.push(e)}addNode(e){this._nodes.push(e),e.file=this}setExtension(e){this._extension=e}setFinalPath(e){this._finalPath=e}setLanguage(e){this._language=e}setName(e){this._name=e}setRenderer(e){this._renderer=e}toString(){return`[File ${this._logicalFilePath}#${this.id}]`}};function E(e,t){return!e||typeof e!=`object`?!1:e[`~brand`]===t}function D(e){return!e||typeof e!=`object`?!1:E(e,f)}function O(e){return E(e[`~ref`],f)}function k(e){return E(e,p)}function A(e){return E(e[`~ref`],p)}const j={c:[`.c`],"c#":[`.cs`],"c++":[`.cpp`,`.hpp`],css:[`.css`],dart:[`.dart`],go:[`.go`],haskell:[`.hs`],html:[`.html`],java:[`.java`],javascript:[`.js`,`.jsx`],json:[`.json`],kotlin:[`.kt`],lua:[`.lua`],markdown:[`.md`],matlab:[`.m`],perl:[`.pl`],php:[`.php`],python:[`.py`],r:[`.r`],ruby:[`.rb`],rust:[`.rs`],scala:[`.scala`],shell:[`.sh`],sql:[`.sql`],swift:[`.swift`],typescript:[`.ts`,`.tsx`],yaml:[`.yaml`,`.yml`]},M=({attempt:e,baseName:t})=>e===0?t:`${t}${e+1}`,N=({attempt:e,baseName:t})=>e===0?t:`${t}_${e+1}`,P={php:N,python:N,ruby:N};var F=class{_id=0;_values=new Map;project;constructor(e){this.project=e}get(e){return this._values.get(this.createFileKey(e))}isRegistered(e){return this._values.has(this.createFileKey(e))}get nextId(){return this._id++}register(e){let t=this.createFileKey(e),n=this._values.get(t);return n?e.name&&n.setName(e.name):n=new T(e,this.nextId,this.project),this._values.set(t,n),n}*registered(){for(let e of this._values.values())yield e}createFileKey(e){let t=e.logicalFilePath.split(c.default.sep).join(`/`);return`${e.external?`ext:`:``}${t}${e.language?`:${e.language}`:``}`}};const I=e=>B(e)?e:{"~ref":e},L=e=>{let t={};for(let n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=I(e[n]));return t},R=e=>e?.[`~ref`],z=e=>{let t={};for(let n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=R(e[n]));return t},B=e=>typeof e==`object`&&!!e&&`~ref`in e;var V=class{list=[];add(e){return this.list.push(I(e))-1}*all(){for(let e of this.list){let t=R(e);t&&(yield t)}}remove(e){this.list[e]=I(null)}update(e,t){this.list[e]=I(t)}};const H={class:3,enum:4,function:5,interface:1,namespace:0,type:2,var:6};function U(e,t){switch(H[e]>H[t]&&([e,t]=[t,e]),e){case`interface`:return t===`class`||t===`interface`;case`namespace`:return t===`class`||t===`enum`||t===`function`||t===`namespace`;case`type`:return t===`function`||t===`var`;default:return!1}}const W=(e={})=>({children:[],localNames:e.localNames||new Map,parent:e.parent,symbols:[]});var G=class{_parentStack=[];scope;scopes=W();symbol;constructor(e){this._parentStack.push(e),this.scope=this.scopes,this.symbol=e.symbol}get currentParent(){return this._parentStack[this._parentStack.length-1]}addChild(e,t=`container`){let n=this.currentParent;n&&(n.structuralChildren||=new Map,n.structuralChildren.set(e,t),e.structuralParents||=new Map,e.structuralParents.set(n,t))}addDependency(e){this.symbol!==R(e)&&this.scope.symbols.push(e)}analyze(e){let t=B(e)?e:I(e);if(A(t)){let e=R(t);e.node&&this.currentParent!==e.node&&this.addChild(e.node,`reference`),this.addDependency(t)}else if(O(t)){let e=R(t);this.addChild(e,`container`),this.pushParent(e),e.analyze(this),this.popParent()}}localNames(e){let t=new Map;for(let[n,r]of e.localNames)t.set(n,new Set(r));if(e.parent){let n=this.localNames(e.parent);for(let[e,r]of n)if(!t.has(e))t.set(e,r);else{let n=t.get(e);for(let e of r)n.add(e)}}return t}popParent(){this._parentStack.pop()}popScope(){this.scope=this.scope.parent??this.scope}pushParent(e){this._parentStack.push(e)}pushScope(){let e=W({parent:this.scope});this.scope.children.push(e),this.scope=e}walkScopes(e,t=this.scopes){this.scope=t;for(let n of t.symbols)e(n,t);for(let n of t.children)t=n,this.walkScopes(e,t);this.scope=this.scopes}},K=class{nodeCache=new WeakMap;analyzeNode(e){let t=this.nodeCache.get(e);if(t)return t;e.root=!0;let n=new G(e);return e.analyze(n),this.nodeCache.set(e,n),n}analyze(e,t){for(let n of e){let e=this.analyzeNode(n);t?.(e,n)}}};const q=e=>e===`type`||e===`interface`;var J=class{analyzer=new K;cacheResolvedNames=new Set;project;constructor(e){this.project=e}plan(e){this.cacheResolvedNames.clear(),this.allocateFiles(),this.assignLocalNames(),this.resolveFilePaths(e),this.planExports(),this.planImports()}allocateFiles(){this.analyzer.analyze(this.project.nodes.all(),(e,t)=>{let n=t.symbol;if(!n)return;let r=this.project.files.register({external:!1,language:t.language,logicalFilePath:n.getFilePath?.(n)||this.project.defaultFileName});r.addNode(t),n.setFile(r);for(let e of n.exportFrom)this.project.files.register({external:!1,language:r.language,logicalFilePath:e});e.walkScopes(e=>{let t=R(e);if(t.external&&t.isCanonical&&!t.file){let e=this.project.files.register({external:!0,language:t.node?.language,logicalFilePath:t.external});t.setFile(e)}})})}assignLocalNames(){this.analyzer.analyze(this.project.nodes.all(),(e,t)=>{let n=t.symbol;n&&this.assignTopLevelName({ctx:e,node:t,symbol:n})}),this.analyzer.analyze(this.project.nodes.all(),(e,t)=>{let n=t.file;n&&e.walkScopes(t=>{let r=R(t);r.file||this.assignLocalName({ctx:e,file:n,scopesToUpdate:[W({localNames:n.allNames})],symbol:r})})})}resolveFilePaths(e){for(let t of this.project.files.registered()){if(t.external){t.setFinalPath(t.logicalFilePath);continue}let n=this.project.fileName?.(t.name)||t.name;t.setName(n);let r=t.finalPath;r&&t.setFinalPath(c.default.resolve(this.project.root,r));let i={file:t,meta:e,project:this.project},a=this.project.renderers.find(e=>e.supports(i));a&&t.setRenderer(a)}}planExports(){let e=new Map,t=new Map;this.analyzer.analyze(this.project.nodes.all(),(n,r)=>{if(!r.exported)return;let i=r.symbol;if(!i)return;let a=r.file;if(a)for(let o of i.exportFrom){let s=this.project.files.register({external:!1,language:r.language,logicalFilePath:o});if(s.id===a.id)continue;let c=e.get(s);c||(c=new Map,e.set(s,c));let l=this.project.symbols.register({exported:!0,external:i.external,importKind:i.importKind,kind:i.kind,name:i.finalName});l.setFile(s),t.set(l.id,a),this.assignTopLevelName({ctx:n,symbol:l});let u=c.get(l.finalName);u||(u={kinds:new Set,symbol:l},c.set(l.finalName,u)),u.kinds.add(l.kind)}});for(let[n,r]of e){let e=new Map;for(let[,n]of r){let r=t.get(n.symbol.id),i=e.get(r);i||={canExportAll:!0,exports:[],from:r,isTypeOnly:!0};let a=[...n.kinds].every(e=>q(e)),o=n.symbol.finalName;i.exports.push({exportedName:o,isTypeOnly:a,kind:n.symbol.importKind,sourceName:n.symbol.name}),n.symbol.name!==n.symbol.finalName&&(i.canExportAll=!1),a||(i.isTypeOnly=!1),e.set(r,i)}for(let[,t]of e)n.addExport(t)}}planImports(){let e=new Map;this.analyzer.analyze(this.project.nodes.all(),t=>{let n=t.symbol;if(!n)return;let r=n.file;if(!r)return;let i=e.get(r);i||(i=new Map,e.set(r,i)),t.walkScopes(e=>{let n=R(e);if(!n.file||n.file.id===r.id)return;n.external&&this.assignTopLevelName({ctx:t,symbol:n});let a=n.file.id,o=n.finalName,s=q(n.kind),c=`${a}|${o}|${n.importKind}|${s}`,l=i.get(c);if(!l){let e=this.project.symbols.register({exported:n.exported,external:n.external,importKind:n.importKind,kind:n.kind,name:n.finalName});e.setFile(r),this.assignTopLevelName({ctx:t,scope:W({localNames:e.file.allNames}),symbol:e}),l={dep:n,kinds:new Set,symbol:e},i.set(c,l),l.kinds.add(e.kind)}e[`~ref`]=l.symbol})});for(let[t,n]of e){let e=new Map;for(let[,t]of n){let n=t.dep.file,r=e.get(n);r||={from:n,imports:[],isTypeOnly:!0,kind:`named`};let i=[...t.kinds].every(e=>q(e));t.symbol.importKind===`namespace`?(r.imports=[],r.kind=`namespace`,r.localName=t.symbol.finalName):t.symbol.importKind===`default`?(r.kind=`default`,r.localName=t.symbol.finalName):r.imports.push({isTypeOnly:i,localName:t.symbol.finalName,sourceName:t.dep.finalName}),i||(r.isTypeOnly=!1),e.set(n,r)}for(let[,n]of e)t.addImport(n)}}assignTopLevelName(e){e.symbol.file&&this.assignSymbolName({...e,file:e.symbol.file,scope:e?.scope??W({localNames:e.symbol.file.topLevelNames}),scopesToUpdate:[W({localNames:e.symbol.file.allNames}),e.ctx.scopes,...e?.scopesToUpdate??[]]})}assignLocalName(e){this.assignSymbolName({...e,scope:e.scope??e.ctx.scope})}assignSymbolName(e){let{ctx:t,file:n,node:r,scope:i,scopesToUpdate:a,symbol:o}=e;if(this.cacheResolvedNames.has(o.id))return;let s=o.name,c=r?.nameSanitizer?.(s)??o.node?.nameSanitizer?.(s)??s,l=1,u=t.localNames(i);for(;![...u.get(c)??[]].every(e=>U(o.kind,e));){let e=r?.language||o.node?.language||n.language,t=((e?this.project.nameConflictResolvers[e]:void 0)??this.project.defaultNameConflictResolver)({attempt:l,baseName:s});if(!t)throw Error(`Unresolvable name conflict: ${o.toString()}`);c=r?.nameSanitizer?.(t)??o.node?.nameSanitizer?.(t)??t,l+=1}o.setFinalName(c),this.cacheResolvedNames.add(o.id);let d=[i,...a];for(let e of d)this.updateScope(o,e)}updateScope(e,t){let n=e.finalName,r=t.localNames.get(n)??new Set;r.add(e.kind),t.localNames.set(n,r)}},Y=class{_canonical;_exported;_exportFrom;_external;_file;_finalName;_getFilePath;_importKind;_kind;_meta;_name;_node;"~brand"=p;id;constructor(e,t){this._exported=e.exported??!1,this._exportFrom=e.exportFrom??[],this._external=e.external,this._getFilePath=e.getFilePath,this.id=t,this._importKind=e.importKind??`named`,this._kind=e.kind??`var`,this._meta=e.meta,this._name=e.name}get canonical(){return this._canonical??this}get exported(){return this.canonical._exported}get exportFrom(){return this.canonical._exportFrom}get external(){return this.canonical._external}get file(){return this.canonical._file}get finalName(){if(!this.canonical._finalName){let e=`Symbol finalName has not been resolved yet for ${this.canonical.toString()}`;throw w.debug(e,`symbol`),Error(e)}return this.canonical._finalName}get getFilePath(){return this.canonical._getFilePath}get importKind(){return this.canonical._importKind}get isCanonical(){return!this._canonical||this._canonical===this}get kind(){return this.canonical._kind}get meta(){return this.canonical._meta}get name(){return this.canonical._name}get node(){return this.canonical._node}setCanonical(e){this._canonical=e}setExported(e){this.assertCanonical(),this._exported=e}setExportFrom(e){this.assertCanonical(),this._exportFrom=e}setFile(e){if(this.assertCanonical(),this._file&&this._file!==e){let e=`Symbol ${this.canonical.toString()} is already assigned to a different file.`;throw w.debug(e,`symbol`),Error(e)}this._file=e}setFinalName(e){if(this.assertCanonical(),this._finalName&&this._finalName!==e){let e=`Symbol finalName has already been resolved for ${this.canonical.toString()}.`;throw w.debug(e,`symbol`),Error(e)}this._finalName=e}setImportKind(e){this.assertCanonical(),this._importKind=e}setKind(e){this.assertCanonical(),this._kind=e}setName(e){this.assertCanonical(),this._name=e}setNode(e){if(this.assertCanonical(),this._node&&this._node!==e){let e=`Symbol ${this.canonical.toString()} is already bound to a different node.`;w.debug(e,`symbol`)}this._node=e,e.symbol=this}toString(){let e=this.canonical;return e._finalName&&e._finalName!==e._name?`[Symbol ${e._name} → ${e._finalName}#${e.id}]`:`[Symbol ${e._name}#${e.id}]`}assertCanonical(){if(this._canonical&&this._canonical!==this){let e=`Illegal mutation of stub symbol ${this.toString()} → canonical: ${this._canonical.toString()}`;throw w.debug(e,`symbol`),Error(e)}}},X=class{_id=0;_indices=new Map;_queryCache=new Map;_queryCacheDependencies=new Map;_registered=new Set;_stubs=new Set;_stubCache=new Map;_values=new Map;get(e){return typeof e==`number`?this._values.get(e):this.query(e)[0]}isRegistered(e){let t=this.get(e);return t?this._registered.has(t.id):!1}get nextId(){return this._id++}query(e){let t=this.buildCacheKey(e),n=this._queryCache.get(t);if(n)return n.map(e=>this._values.get(e));let r=[],i=this.buildIndexKeySpace(e),a=new Set,o=!1;for(let e of i){a.add(this.serializeIndexEntry(e));let t=this._indices.get(e[0]);if(!t){o=!0;break}let n=t.get(e[1]);if(!n){o=!0;break}r.push(n)}if(o||!r.length)return this._queryCacheDependencies.set(t,a),this._queryCache.set(t,[]),[];let s=new Set(r[0]);for(let e of r.slice(1))s=new Set([...s].filter(t=>e.has(t)));let c=[...s];return this._queryCacheDependencies.set(t,a),this._queryCache.set(t,c),c.map(e=>this._values.get(e))}reference(e){let[t]=this.query(e);if(t)return t;let n=this.buildCacheKey(e),r=this._stubCache.get(n);if(r!==void 0)return this._values.get(r);let i=new Y({meta:e,name:``},this.nextId);return this._values.set(i.id,i),this._stubs.add(i.id),this._stubCache.set(n,i.id),i}register(e){let t=new Y(e,this.nextId);if(this._values.set(t.id,t),this._registered.add(t.id),t.meta){let e=this.buildIndexKeySpace(t.meta);this.indexSymbol(t.id,e),this.invalidateCache(e),this.replaceStubs(t,e)}return t}*registered(){for(let e of this._registered.values())yield this._values.get(e)}buildCacheKey(e){return this.buildIndexKeySpace(e).map(e=>this.serializeIndexEntry(e)).sort().join(`|`)}buildIndexKeySpace(e,t=``){let n=[];for(let[r,i]of Object.entries(e)){let e=t?`${t}.${r}`:r;i&&typeof i==`object`&&!Array.isArray(i)?n.push(...this.buildIndexKeySpace(i,e)):n.push([e,i])}return n}indexSymbol(e,t){for(let[n,r]of t){this._indices.has(n)||this._indices.set(n,new Map);let t=this._indices.get(n),i=t.get(r)??new Set;i.add(e),t.set(r,i)}}invalidateCache(e){let t=e.map(e=>this.serializeIndexEntry(e));for(let[e,n]of this._queryCacheDependencies.entries())for(let r of t)if(n.has(r)){this._queryCacheDependencies.delete(e),this._queryCache.delete(e);break}}isSubset(e,t){let n=new Map(t);for(let[t,r]of e)if(!n.has(t)||n.get(t)!==r)return!1;return!0}replaceStubs(e,t){for(let n of this._stubs.values()){let r=this._values.get(n);if(r?.meta&&this.isSubset(this.buildIndexKeySpace(r.meta),t)){let t=this.buildCacheKey(r.meta);this._stubCache.delete(t),this._stubs.delete(n),r.setCanonical(e)}}}serializeIndexEntry(e){return`${e[0]}:${JSON.stringify(e[1])}`}},Z=class{_isPlanned=!1;files;nodes=new V;symbols=new X;defaultFileName;defaultNameConflictResolver;extensions;fileName;nameConflictResolvers;renderers;root;constructor(e){let t=e.fileName;this.defaultFileName=e.defaultFileName??`main`,this.defaultNameConflictResolver=e.defaultNameConflictResolver??M,this.extensions={...j,...e.extensions},this.fileName=typeof t==`string`?()=>t:t,this.files=new F(this),this.nameConflictResolvers={...P,...e.nameConflictResolvers},this.renderers=e.renderers??[],this.root=c.default.resolve(e.root).replace(/[/\\]+$/,``)}plan(e){this._isPlanned||=(new J(this).plan(e),!0)}render(e){this._isPlanned||this.plan(e);let t=[];for(let n of this.files.registered())if(!n.external&&n.finalPath&&n.renderer){let r=n.renderer.render({file:n,meta:e,project:this});t.push({content:r,path:n.finalPath})}return t}},Q=class e{children=new Map;items=[];name;parent;shell;shellSource;virtual;constructor(e,t,n){this.name=e,this.parent=t,this.virtual=n?.virtual??!1}get isRoot(){return!this.parent}child(t){return this.children.has(t)||this.children.set(t,new e(t,this)),this.children.get(t)}getPath(){let e=[],t=this;for(;t;)e.unshift(t.name),t=t.parent;return e}*itemsFrom(e){for(let t of this.items)t.source===e&&(yield t)}*walk(){for(let e of this.children.values())yield*e.walk();yield this}},$=class{_roots=new Map;_virtualRoot;get roots(){let e=Array.from(this._roots.values());return this._virtualRoot&&e.unshift(this._virtualRoot),e}insert(e){let{data:t,locations:n,source:r}=e;for(let e of n){let{path:n,shell:i}=e,a=n.filter(e=>!!e),o=a.slice(0,-1);if(!a[a.length-1])throw Error(`Cannot insert data without path.`);let s=null;for(let e of o)s=s?s.child(e):this.root(e),i&&!s.shell&&(s.shell=i,s.shellSource=r);s||=this.root(null),s.items.push({data:t,location:a,source:r})}}root(e){return e?(this._roots.has(e)||this._roots.set(e,new Q(e)),this._roots.get(e)):this._virtualRoot??=new Q(``,void 0,{virtual:!0})}*walk(){this._virtualRoot&&(yield*this._virtualRoot.walk());for(let e of this._roots.values())yield*e.walk()}};exports.File=T,exports.Project=Z,exports.StructureModel=$,exports.StructureNode=Q,exports.Symbol=Y,exports.defaultExtensions=j,exports.defaultNameConflictResolvers=P,exports.fromRef=R,exports.fromRefs=z,exports.isNode=D,exports.isNodeRef=O,exports.isRef=B,exports.isSymbol=k,exports.isSymbolRef=A,exports.log=w,exports.nodeBrand=f,exports.ref=I,exports.refs=L,exports.simpleNameConflictResolver=M,exports.symbolBrand=p,exports.underscoreNameConflictResolver=N;
|
|
2
|
+
//#region rolldown:runtime
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
12
|
+
key = keys[i];
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except) {
|
|
14
|
+
__defProp(to, key, {
|
|
15
|
+
get: ((k) => from[k]).bind(null, key),
|
|
16
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return to;
|
|
22
|
+
};
|
|
23
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
24
|
+
value: mod,
|
|
25
|
+
enumerable: true
|
|
26
|
+
}) : target, mod));
|
|
27
|
+
|
|
28
|
+
//#endregion
|
|
29
|
+
let node_path = require("node:path");
|
|
30
|
+
node_path = __toESM(node_path);
|
|
31
|
+
let ansi_colors = require("ansi-colors");
|
|
32
|
+
ansi_colors = __toESM(ansi_colors);
|
|
33
|
+
let color_support = require("color-support");
|
|
34
|
+
color_support = __toESM(color_support);
|
|
35
|
+
|
|
36
|
+
//#region src/brands.ts
|
|
37
|
+
const fileBrand = "heyapi.file";
|
|
38
|
+
const nodeBrand = "heyapi.node";
|
|
39
|
+
const symbolBrand = "heyapi.symbol";
|
|
40
|
+
|
|
41
|
+
//#endregion
|
|
42
|
+
//#region src/log.ts
|
|
43
|
+
ansi_colors.default.enabled = (0, color_support.default)().hasBasic;
|
|
44
|
+
const DEBUG_NAMESPACE = "heyapi";
|
|
45
|
+
const NO_WARNINGS = /^(1|true|yes|on)$/i.test(process.env.HEYAPI_DISABLE_WARNINGS ?? "");
|
|
46
|
+
const DebugGroups = {
|
|
47
|
+
analyzer: ansi_colors.default.greenBright,
|
|
48
|
+
dsl: ansi_colors.default.cyanBright,
|
|
49
|
+
file: ansi_colors.default.yellowBright,
|
|
50
|
+
registry: ansi_colors.default.blueBright,
|
|
51
|
+
symbol: ansi_colors.default.magentaBright
|
|
52
|
+
};
|
|
53
|
+
const WarnGroups = { deprecated: ansi_colors.default.magentaBright };
|
|
54
|
+
let cachedDebugGroups;
|
|
55
|
+
function getDebugGroups() {
|
|
56
|
+
if (cachedDebugGroups) return cachedDebugGroups;
|
|
57
|
+
const value = process.env.DEBUG;
|
|
58
|
+
cachedDebugGroups = new Set(value ? value.split(",").map((x) => x.trim().toLowerCase()) : []);
|
|
59
|
+
return cachedDebugGroups;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Tracks which deprecations have been shown to avoid spam.
|
|
63
|
+
*/
|
|
64
|
+
const shownDeprecations = /* @__PURE__ */ new Set();
|
|
65
|
+
function debug(message, group) {
|
|
66
|
+
const groups = getDebugGroups();
|
|
67
|
+
if (!(groups.has("*") || groups.has(`${DEBUG_NAMESPACE}:*`) || groups.has(`${DEBUG_NAMESPACE}:${group}`) || groups.has(group))) return;
|
|
68
|
+
const prefix = (DebugGroups[group] ?? ansi_colors.default.whiteBright)(`${DEBUG_NAMESPACE}:${group}`);
|
|
69
|
+
console.debug(`${prefix} ${message}`);
|
|
70
|
+
}
|
|
71
|
+
function warn(message, group) {
|
|
72
|
+
if (NO_WARNINGS) return;
|
|
73
|
+
const color = WarnGroups[group] ?? ansi_colors.default.yellowBright;
|
|
74
|
+
console.warn(color(`${message}`));
|
|
75
|
+
}
|
|
76
|
+
function warnDeprecated({ context, field, replacement }) {
|
|
77
|
+
const key = context ? `${context}:${field}:${JSON.stringify(replacement)}` : `${field}:${JSON.stringify(replacement)}`;
|
|
78
|
+
if (shownDeprecations.has(key)) return;
|
|
79
|
+
shownDeprecations.add(key);
|
|
80
|
+
let message = `\`${field}\` is deprecated.`;
|
|
81
|
+
if (replacement) {
|
|
82
|
+
const reps = typeof replacement === "function" ? replacement(field) : replacement;
|
|
83
|
+
const repString = (reps instanceof Array ? reps : [reps]).map((r) => `\`${r}\``).join(" or ");
|
|
84
|
+
message += ` Use ${repString} instead.`;
|
|
85
|
+
}
|
|
86
|
+
warn(`${context ? `[${context}] ` : ""}${message}`, "deprecated");
|
|
87
|
+
}
|
|
88
|
+
const log = {
|
|
89
|
+
debug,
|
|
90
|
+
warn,
|
|
91
|
+
warnDeprecated
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
//#endregion
|
|
95
|
+
//#region src/files/file.ts
|
|
96
|
+
var File = class {
|
|
97
|
+
/**
|
|
98
|
+
* Exports from this file.
|
|
99
|
+
*/
|
|
100
|
+
_exports = [];
|
|
101
|
+
/**
|
|
102
|
+
* File extension (e.g. `.ts`).
|
|
103
|
+
*/
|
|
104
|
+
_extension;
|
|
105
|
+
/**
|
|
106
|
+
* Actual emitted file path, including extension and directories.
|
|
107
|
+
*/
|
|
108
|
+
_finalPath;
|
|
109
|
+
/**
|
|
110
|
+
* Imports to this file.
|
|
111
|
+
*/
|
|
112
|
+
_imports = [];
|
|
113
|
+
/**
|
|
114
|
+
* Language of the file.
|
|
115
|
+
*/
|
|
116
|
+
_language;
|
|
117
|
+
/**
|
|
118
|
+
* Logical, extension-free path used for planning and routing.
|
|
119
|
+
*/
|
|
120
|
+
_logicalFilePath;
|
|
121
|
+
/**
|
|
122
|
+
* Base name of the file (without extension).
|
|
123
|
+
*/
|
|
124
|
+
_name;
|
|
125
|
+
/**
|
|
126
|
+
* Syntax nodes contained in this file.
|
|
127
|
+
*/
|
|
128
|
+
_nodes = [];
|
|
129
|
+
/**
|
|
130
|
+
* Renderer assigned to this file.
|
|
131
|
+
*/
|
|
132
|
+
_renderer;
|
|
133
|
+
/** Brand used for identifying files. */
|
|
134
|
+
"~brand" = fileBrand;
|
|
135
|
+
/** All names defined in this file, including local scopes. */
|
|
136
|
+
allNames = /* @__PURE__ */ new Map();
|
|
137
|
+
/** Whether this file is external to the project. */
|
|
138
|
+
external;
|
|
139
|
+
/** Unique identifier for the file. */
|
|
140
|
+
id;
|
|
141
|
+
/** The project this file belongs to. */
|
|
142
|
+
project;
|
|
143
|
+
/** Names declared at the top level of the file. */
|
|
144
|
+
topLevelNames = /* @__PURE__ */ new Map();
|
|
145
|
+
constructor(input, id, project) {
|
|
146
|
+
this.external = input.external ?? false;
|
|
147
|
+
this.id = id;
|
|
148
|
+
if (input.language !== void 0) this._language = input.language;
|
|
149
|
+
this._logicalFilePath = input.logicalFilePath.split(node_path.default.sep).join("/");
|
|
150
|
+
if (input.name !== void 0) this._name = input.name;
|
|
151
|
+
this.project = project;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Exports from this file.
|
|
155
|
+
*/
|
|
156
|
+
get exports() {
|
|
157
|
+
return [...this._exports];
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Read-only accessor for the file extension.
|
|
161
|
+
*/
|
|
162
|
+
get extension() {
|
|
163
|
+
if (this.external) return;
|
|
164
|
+
if (this._extension) return this._extension;
|
|
165
|
+
const language = this.language;
|
|
166
|
+
const extension = language ? this.project.extensions[language] : void 0;
|
|
167
|
+
if (extension && extension[0]) return extension[0];
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Read-only accessor for the final emitted path.
|
|
171
|
+
*
|
|
172
|
+
* If undefined, the file has not yet been assigned a final path
|
|
173
|
+
* or is external to the project and should not be emitted.
|
|
174
|
+
*/
|
|
175
|
+
get finalPath() {
|
|
176
|
+
if (this._finalPath) return this._finalPath;
|
|
177
|
+
return [...this._logicalFilePath ? this._logicalFilePath.split("/").slice(0, -1) : [], `${this.name}${this.extension ?? ""}`].join("/");
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Imports to this file.
|
|
181
|
+
*/
|
|
182
|
+
get imports() {
|
|
183
|
+
return [...this._imports];
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Language of the file; inferred from nodes or fallback if not set explicitly.
|
|
187
|
+
*/
|
|
188
|
+
get language() {
|
|
189
|
+
if (this._language) return this._language;
|
|
190
|
+
if (this._nodes[0]) return this._nodes[0].language;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Logical, extension-free path used for planning and routing.
|
|
194
|
+
*/
|
|
195
|
+
get logicalFilePath() {
|
|
196
|
+
return this._logicalFilePath;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Base name of the file (without extension).
|
|
200
|
+
*
|
|
201
|
+
* If no name was set explicitly, it is inferred from the logical file path.
|
|
202
|
+
*/
|
|
203
|
+
get name() {
|
|
204
|
+
if (this._name) return this._name;
|
|
205
|
+
const name = this._logicalFilePath.split("/").pop();
|
|
206
|
+
if (name) return name;
|
|
207
|
+
const message = `File ${this.toString()} has no name`;
|
|
208
|
+
log.debug(message, "file");
|
|
209
|
+
throw new Error(message);
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Syntax nodes contained in this file.
|
|
213
|
+
*/
|
|
214
|
+
get nodes() {
|
|
215
|
+
return [...this._nodes];
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Renderer assigned to this file.
|
|
219
|
+
*/
|
|
220
|
+
get renderer() {
|
|
221
|
+
return this._renderer;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Add an export group to the file.
|
|
225
|
+
*/
|
|
226
|
+
addExport(group) {
|
|
227
|
+
this._exports.push(group);
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Add an import group to the file.
|
|
231
|
+
*/
|
|
232
|
+
addImport(group) {
|
|
233
|
+
this._imports.push(group);
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Add a syntax node to the file.
|
|
237
|
+
*/
|
|
238
|
+
addNode(node) {
|
|
239
|
+
this._nodes.push(node);
|
|
240
|
+
node.file = this;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Sets the file extension.
|
|
244
|
+
*/
|
|
245
|
+
setExtension(extension) {
|
|
246
|
+
this._extension = extension;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Sets the final emitted path of the file.
|
|
250
|
+
*/
|
|
251
|
+
setFinalPath(path$4) {
|
|
252
|
+
this._finalPath = path$4;
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Sets the language of the file.
|
|
256
|
+
*/
|
|
257
|
+
setLanguage(lang) {
|
|
258
|
+
this._language = lang;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Sets the name of the file.
|
|
262
|
+
*/
|
|
263
|
+
setName(name) {
|
|
264
|
+
this._name = name;
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Sets the renderer assigned to this file.
|
|
268
|
+
*/
|
|
269
|
+
setRenderer(renderer) {
|
|
270
|
+
this._renderer = renderer;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Returns a debug‑friendly string representation identifying the file.
|
|
274
|
+
*/
|
|
275
|
+
toString() {
|
|
276
|
+
return `[File ${this._logicalFilePath}#${this.id}]`;
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
//#endregion
|
|
281
|
+
//#region src/guards.ts
|
|
282
|
+
function isBrand(value, brand) {
|
|
283
|
+
if (!value || typeof value !== "object") return false;
|
|
284
|
+
return value["~brand"] === brand;
|
|
285
|
+
}
|
|
286
|
+
function isNode(value) {
|
|
287
|
+
if (!value || typeof value !== "object") return false;
|
|
288
|
+
return isBrand(value, nodeBrand);
|
|
289
|
+
}
|
|
290
|
+
function isNodeRef(value) {
|
|
291
|
+
return isBrand(value["~ref"], nodeBrand);
|
|
292
|
+
}
|
|
293
|
+
function isSymbol(value) {
|
|
294
|
+
return isBrand(value, symbolBrand);
|
|
295
|
+
}
|
|
296
|
+
function isSymbolRef(value) {
|
|
297
|
+
return isBrand(value["~ref"], symbolBrand);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
//#endregion
|
|
301
|
+
//#region src/languages/extensions.ts
|
|
302
|
+
const defaultExtensions = {
|
|
303
|
+
c: [".c"],
|
|
304
|
+
"c#": [".cs"],
|
|
305
|
+
"c++": [".cpp", ".hpp"],
|
|
306
|
+
css: [".css"],
|
|
307
|
+
dart: [".dart"],
|
|
308
|
+
go: [".go"],
|
|
309
|
+
haskell: [".hs"],
|
|
310
|
+
html: [".html"],
|
|
311
|
+
java: [".java"],
|
|
312
|
+
javascript: [".js", ".jsx"],
|
|
313
|
+
json: [".json"],
|
|
314
|
+
kotlin: [".kt"],
|
|
315
|
+
lua: [".lua"],
|
|
316
|
+
markdown: [".md"],
|
|
317
|
+
matlab: [".m"],
|
|
318
|
+
perl: [".pl"],
|
|
319
|
+
php: [".php"],
|
|
320
|
+
python: [".py"],
|
|
321
|
+
r: [".r"],
|
|
322
|
+
ruby: [".rb"],
|
|
323
|
+
rust: [".rs"],
|
|
324
|
+
scala: [".scala"],
|
|
325
|
+
shell: [".sh"],
|
|
326
|
+
sql: [".sql"],
|
|
327
|
+
swift: [".swift"],
|
|
328
|
+
typescript: [".ts", ".tsx"],
|
|
329
|
+
yaml: [".yaml", ".yml"]
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
//#endregion
|
|
333
|
+
//#region src/planner/resolvers.ts
|
|
334
|
+
const simpleNameConflictResolver = ({ attempt, baseName }) => attempt === 0 ? baseName : `${baseName}${attempt + 1}`;
|
|
335
|
+
const underscoreNameConflictResolver = ({ attempt, baseName }) => attempt === 0 ? baseName : `${baseName}_${attempt + 1}`;
|
|
336
|
+
|
|
337
|
+
//#endregion
|
|
338
|
+
//#region src/languages/resolvers.ts
|
|
339
|
+
const defaultNameConflictResolvers = {
|
|
340
|
+
php: underscoreNameConflictResolver,
|
|
341
|
+
python: underscoreNameConflictResolver,
|
|
342
|
+
ruby: underscoreNameConflictResolver
|
|
343
|
+
};
|
|
344
|
+
|
|
345
|
+
//#endregion
|
|
346
|
+
//#region src/files/registry.ts
|
|
347
|
+
var FileRegistry = class {
|
|
348
|
+
_id = 0;
|
|
349
|
+
_values = /* @__PURE__ */ new Map();
|
|
350
|
+
project;
|
|
351
|
+
constructor(project) {
|
|
352
|
+
this.project = project;
|
|
353
|
+
}
|
|
354
|
+
get(args) {
|
|
355
|
+
return this._values.get(this.createFileKey(args));
|
|
356
|
+
}
|
|
357
|
+
isRegistered(args) {
|
|
358
|
+
return this._values.has(this.createFileKey(args));
|
|
359
|
+
}
|
|
360
|
+
get nextId() {
|
|
361
|
+
return this._id++;
|
|
362
|
+
}
|
|
363
|
+
register(file) {
|
|
364
|
+
const key = this.createFileKey(file);
|
|
365
|
+
let result = this._values.get(key);
|
|
366
|
+
if (result) {
|
|
367
|
+
if (file.name) result.setName(file.name);
|
|
368
|
+
} else result = new File(file, this.nextId, this.project);
|
|
369
|
+
this._values.set(key, result);
|
|
370
|
+
return result;
|
|
371
|
+
}
|
|
372
|
+
*registered() {
|
|
373
|
+
for (const file of this._values.values()) yield file;
|
|
374
|
+
}
|
|
375
|
+
createFileKey(args) {
|
|
376
|
+
const logicalPath = args.logicalFilePath.split(node_path.default.sep).join("/");
|
|
377
|
+
return `${args.external ? "ext:" : ""}${logicalPath}${args.language ? `:${args.language}` : ""}`;
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
//#endregion
|
|
382
|
+
//#region src/refs/refs.ts
|
|
383
|
+
/**
|
|
384
|
+
* Wraps a single value in a Ref object.
|
|
385
|
+
*
|
|
386
|
+
* If the value is already a Ref, returns it as-is (idempotent).
|
|
387
|
+
*
|
|
388
|
+
* @example
|
|
389
|
+
* ```ts
|
|
390
|
+
* const r = ref(123); // { '~ref': 123 }
|
|
391
|
+
* console.log(r['~ref']); // 123
|
|
392
|
+
*
|
|
393
|
+
* const r2 = ref(r); // { '~ref': 123 } (not double-wrapped)
|
|
394
|
+
* ```
|
|
395
|
+
*/
|
|
396
|
+
const ref = (value) => {
|
|
397
|
+
if (isRef(value)) return value;
|
|
398
|
+
return { "~ref": value };
|
|
399
|
+
};
|
|
400
|
+
/**
|
|
401
|
+
* Converts a plain object to an object of Refs (deep, per property).
|
|
402
|
+
*
|
|
403
|
+
* @example
|
|
404
|
+
* ```ts
|
|
405
|
+
* const obj = { a: 1, b: "x" };
|
|
406
|
+
* const refs = refs(obj); // { a: { '~ref': 1 }, b: { '~ref': "x" } }
|
|
407
|
+
* ```
|
|
408
|
+
*/
|
|
409
|
+
const refs = (obj) => {
|
|
410
|
+
const result = {};
|
|
411
|
+
for (const key in obj) if (Object.prototype.hasOwnProperty.call(obj, key)) result[key] = ref(obj[key]);
|
|
412
|
+
return result;
|
|
413
|
+
};
|
|
414
|
+
/**
|
|
415
|
+
* Unwraps a single Ref object to its value.
|
|
416
|
+
*
|
|
417
|
+
* @example
|
|
418
|
+
* ```ts
|
|
419
|
+
* const r = { '~ref': 42 };
|
|
420
|
+
* const n = fromRef(r); // 42
|
|
421
|
+
* console.log(n); // 42
|
|
422
|
+
* ```
|
|
423
|
+
*/
|
|
424
|
+
const fromRef = (ref$1) => ref$1?.["~ref"];
|
|
425
|
+
/**
|
|
426
|
+
* Converts an object of Refs back to a plain object (unwraps all refs).
|
|
427
|
+
*
|
|
428
|
+
* @example
|
|
429
|
+
* ```ts
|
|
430
|
+
* const refs = { a: { '~ref': 1 }, b: { '~ref': "x" } };
|
|
431
|
+
* const plain = fromRefs(refs); // { a: 1, b: "x" }
|
|
432
|
+
* ```
|
|
433
|
+
*/
|
|
434
|
+
const fromRefs = (obj) => {
|
|
435
|
+
const result = {};
|
|
436
|
+
for (const key in obj) if (Object.prototype.hasOwnProperty.call(obj, key)) result[key] = fromRef(obj[key]);
|
|
437
|
+
return result;
|
|
438
|
+
};
|
|
439
|
+
/**
|
|
440
|
+
* Checks whether a value is a Ref object.
|
|
441
|
+
*
|
|
442
|
+
* @param value Value to check
|
|
443
|
+
* @returns True if the value is a Ref object.
|
|
444
|
+
*/
|
|
445
|
+
const isRef = (value) => typeof value === "object" && value !== null && "~ref" in value;
|
|
446
|
+
|
|
447
|
+
//#endregion
|
|
448
|
+
//#region src/nodes/registry.ts
|
|
449
|
+
var NodeRegistry = class {
|
|
450
|
+
list = [];
|
|
451
|
+
add(node) {
|
|
452
|
+
return this.list.push(ref(node)) - 1;
|
|
453
|
+
}
|
|
454
|
+
*all() {
|
|
455
|
+
for (const r of this.list) {
|
|
456
|
+
const node = fromRef(r);
|
|
457
|
+
if (node) yield node;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
remove(index) {
|
|
461
|
+
this.list[index] = ref(null);
|
|
462
|
+
}
|
|
463
|
+
update(index, node) {
|
|
464
|
+
this.list[index] = ref(node);
|
|
465
|
+
}
|
|
466
|
+
};
|
|
467
|
+
|
|
468
|
+
//#endregion
|
|
469
|
+
//#region src/project/namespace.ts
|
|
470
|
+
const kindRank = {
|
|
471
|
+
class: 3,
|
|
472
|
+
enum: 4,
|
|
473
|
+
function: 5,
|
|
474
|
+
interface: 1,
|
|
475
|
+
namespace: 0,
|
|
476
|
+
type: 2,
|
|
477
|
+
var: 6
|
|
478
|
+
};
|
|
479
|
+
/**
|
|
480
|
+
* Returns true if two declarations of given kinds
|
|
481
|
+
* are allowed to share the same identifier in TypeScript.
|
|
482
|
+
*/
|
|
483
|
+
function canShareName(a, b) {
|
|
484
|
+
if (kindRank[a] > kindRank[b]) [a, b] = [b, a];
|
|
485
|
+
switch (a) {
|
|
486
|
+
case "interface": return b === "class" || b === "interface";
|
|
487
|
+
case "namespace": return b === "class" || b === "enum" || b === "function" || b === "namespace";
|
|
488
|
+
case "type": return b === "function" || b === "var";
|
|
489
|
+
default: return false;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
//#endregion
|
|
494
|
+
//#region src/planner/scope.ts
|
|
495
|
+
const createScope = (args = {}) => ({
|
|
496
|
+
children: [],
|
|
497
|
+
localNames: args.localNames || /* @__PURE__ */ new Map(),
|
|
498
|
+
parent: args.parent,
|
|
499
|
+
symbols: []
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
//#endregion
|
|
503
|
+
//#region src/planner/analyzer.ts
|
|
504
|
+
var AnalysisContext = class {
|
|
505
|
+
/**
|
|
506
|
+
* Stack of parent nodes during analysis.
|
|
507
|
+
*
|
|
508
|
+
* The top of the stack is the current semantic container.
|
|
509
|
+
*/
|
|
510
|
+
_parentStack = [];
|
|
511
|
+
scope;
|
|
512
|
+
scopes = createScope();
|
|
513
|
+
symbol;
|
|
514
|
+
constructor(node) {
|
|
515
|
+
this._parentStack.push(node);
|
|
516
|
+
this.scope = this.scopes;
|
|
517
|
+
this.symbol = node.symbol;
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* Get the current semantic parent (top of stack).
|
|
521
|
+
*/
|
|
522
|
+
get currentParent() {
|
|
523
|
+
return this._parentStack[this._parentStack.length - 1];
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Register a child node under the current parent.
|
|
527
|
+
*/
|
|
528
|
+
addChild(child, relationship = "container") {
|
|
529
|
+
const parent = this.currentParent;
|
|
530
|
+
if (!parent) return;
|
|
531
|
+
if (!parent.structuralChildren) parent.structuralChildren = /* @__PURE__ */ new Map();
|
|
532
|
+
parent.structuralChildren.set(child, relationship);
|
|
533
|
+
if (!child.structuralParents) child.structuralParents = /* @__PURE__ */ new Map();
|
|
534
|
+
child.structuralParents.set(parent, relationship);
|
|
535
|
+
}
|
|
536
|
+
addDependency(symbol) {
|
|
537
|
+
if (this.symbol !== fromRef(symbol)) this.scope.symbols.push(symbol);
|
|
538
|
+
}
|
|
539
|
+
analyze(input) {
|
|
540
|
+
const value = isRef(input) ? input : ref(input);
|
|
541
|
+
if (isSymbolRef(value)) {
|
|
542
|
+
const symbol = fromRef(value);
|
|
543
|
+
if (symbol.node && this.currentParent !== symbol.node) this.addChild(symbol.node, "reference");
|
|
544
|
+
this.addDependency(value);
|
|
545
|
+
} else if (isNodeRef(value)) {
|
|
546
|
+
const node = fromRef(value);
|
|
547
|
+
this.addChild(node, "container");
|
|
548
|
+
this.pushParent(node);
|
|
549
|
+
node.analyze(this);
|
|
550
|
+
this.popParent();
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
localNames(scope) {
|
|
554
|
+
const names = /* @__PURE__ */ new Map();
|
|
555
|
+
for (const [name, kinds] of scope.localNames) names.set(name, new Set(kinds));
|
|
556
|
+
if (scope.parent) {
|
|
557
|
+
const parentNames = this.localNames(scope.parent);
|
|
558
|
+
for (const [name, kinds] of parentNames) if (!names.has(name)) names.set(name, kinds);
|
|
559
|
+
else {
|
|
560
|
+
const existingKinds = names.get(name);
|
|
561
|
+
for (const kind of kinds) existingKinds.add(kind);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
return names;
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* Pop the current semantic parent.
|
|
568
|
+
* Call this when exiting a container node.
|
|
569
|
+
*/
|
|
570
|
+
popParent() {
|
|
571
|
+
this._parentStack.pop();
|
|
572
|
+
}
|
|
573
|
+
popScope() {
|
|
574
|
+
this.scope = this.scope.parent ?? this.scope;
|
|
575
|
+
}
|
|
576
|
+
/**
|
|
577
|
+
* Push a node as the current semantic parent.
|
|
578
|
+
*/
|
|
579
|
+
pushParent(node) {
|
|
580
|
+
this._parentStack.push(node);
|
|
581
|
+
}
|
|
582
|
+
pushScope() {
|
|
583
|
+
const scope = createScope({ parent: this.scope });
|
|
584
|
+
this.scope.children.push(scope);
|
|
585
|
+
this.scope = scope;
|
|
586
|
+
}
|
|
587
|
+
walkScopes(callback, scope = this.scopes) {
|
|
588
|
+
this.scope = scope;
|
|
589
|
+
for (const symbol of scope.symbols) callback(symbol, scope);
|
|
590
|
+
for (const child of scope.children) {
|
|
591
|
+
scope = child;
|
|
592
|
+
this.walkScopes(callback, scope);
|
|
593
|
+
}
|
|
594
|
+
this.scope = this.scopes;
|
|
595
|
+
}
|
|
596
|
+
};
|
|
597
|
+
var Analyzer = class {
|
|
598
|
+
nodeCache = /* @__PURE__ */ new WeakMap();
|
|
599
|
+
analyzeNode(node) {
|
|
600
|
+
const cached = this.nodeCache.get(node);
|
|
601
|
+
if (cached) return cached;
|
|
602
|
+
node.root = true;
|
|
603
|
+
const ctx = new AnalysisContext(node);
|
|
604
|
+
node.analyze(ctx);
|
|
605
|
+
this.nodeCache.set(node, ctx);
|
|
606
|
+
return ctx;
|
|
607
|
+
}
|
|
608
|
+
analyze(nodes, callback) {
|
|
609
|
+
for (const node of nodes) {
|
|
610
|
+
const ctx = this.analyzeNode(node);
|
|
611
|
+
callback?.(ctx, node);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
};
|
|
615
|
+
|
|
616
|
+
//#endregion
|
|
617
|
+
//#region src/planner/planner.ts
|
|
618
|
+
const isTypeOnlyKind = (kind) => kind === "type" || kind === "interface";
|
|
619
|
+
var Planner = class {
|
|
620
|
+
analyzer = new Analyzer();
|
|
621
|
+
cacheResolvedNames = /* @__PURE__ */ new Set();
|
|
622
|
+
project;
|
|
623
|
+
constructor(project) {
|
|
624
|
+
this.project = project;
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* Executes the planning phase for the project.
|
|
628
|
+
*/
|
|
629
|
+
plan(meta) {
|
|
630
|
+
this.cacheResolvedNames.clear();
|
|
631
|
+
this.allocateFiles();
|
|
632
|
+
this.assignLocalNames();
|
|
633
|
+
this.resolveFilePaths(meta);
|
|
634
|
+
this.planExports();
|
|
635
|
+
this.planImports();
|
|
636
|
+
}
|
|
637
|
+
/**
|
|
638
|
+
* Creates and assigns a file to every node, re-export,
|
|
639
|
+
* and external dependency.
|
|
640
|
+
*/
|
|
641
|
+
allocateFiles() {
|
|
642
|
+
this.analyzer.analyze(this.project.nodes.all(), (ctx, node) => {
|
|
643
|
+
const symbol = node.symbol;
|
|
644
|
+
if (!symbol) return;
|
|
645
|
+
const file = this.project.files.register({
|
|
646
|
+
external: false,
|
|
647
|
+
language: node.language,
|
|
648
|
+
logicalFilePath: symbol.getFilePath?.(symbol) || this.project.defaultFileName
|
|
649
|
+
});
|
|
650
|
+
file.addNode(node);
|
|
651
|
+
symbol.setFile(file);
|
|
652
|
+
for (const exportFrom of symbol.exportFrom) this.project.files.register({
|
|
653
|
+
external: false,
|
|
654
|
+
language: file.language,
|
|
655
|
+
logicalFilePath: exportFrom
|
|
656
|
+
});
|
|
657
|
+
ctx.walkScopes((dependency) => {
|
|
658
|
+
const dep = fromRef(dependency);
|
|
659
|
+
if (dep.external && dep.isCanonical && !dep.file) {
|
|
660
|
+
const file$1 = this.project.files.register({
|
|
661
|
+
external: true,
|
|
662
|
+
language: dep.node?.language,
|
|
663
|
+
logicalFilePath: dep.external
|
|
664
|
+
});
|
|
665
|
+
dep.setFile(file$1);
|
|
666
|
+
}
|
|
667
|
+
});
|
|
668
|
+
});
|
|
669
|
+
}
|
|
670
|
+
/**
|
|
671
|
+
* Assigns final names to all symbols.
|
|
672
|
+
*
|
|
673
|
+
* First assigns top-level (file-scoped) symbol names, then local symbols.
|
|
674
|
+
*/
|
|
675
|
+
assignLocalNames() {
|
|
676
|
+
this.analyzer.analyze(this.project.nodes.all(), (ctx, node) => {
|
|
677
|
+
const symbol = node.symbol;
|
|
678
|
+
if (!symbol) return;
|
|
679
|
+
this.assignTopLevelName({
|
|
680
|
+
ctx,
|
|
681
|
+
node,
|
|
682
|
+
symbol
|
|
683
|
+
});
|
|
684
|
+
});
|
|
685
|
+
this.analyzer.analyze(this.project.nodes.all(), (ctx, node) => {
|
|
686
|
+
const file = node.file;
|
|
687
|
+
if (!file) return;
|
|
688
|
+
ctx.walkScopes((dependency) => {
|
|
689
|
+
const dep = fromRef(dependency);
|
|
690
|
+
if (dep.file) return;
|
|
691
|
+
this.assignLocalName({
|
|
692
|
+
ctx,
|
|
693
|
+
file,
|
|
694
|
+
scopesToUpdate: [createScope({ localNames: file.allNames })],
|
|
695
|
+
symbol: dep
|
|
696
|
+
});
|
|
697
|
+
});
|
|
698
|
+
});
|
|
699
|
+
}
|
|
700
|
+
/**
|
|
701
|
+
* Resolves and sets final file paths for all non-external files. Attaches renderers.
|
|
702
|
+
*
|
|
703
|
+
* Uses the project's fileName function if provided, otherwise uses the file's current name.
|
|
704
|
+
*
|
|
705
|
+
* Resolves final paths relative to the project's root directory.
|
|
706
|
+
*/
|
|
707
|
+
resolveFilePaths(meta) {
|
|
708
|
+
for (const file of this.project.files.registered()) {
|
|
709
|
+
if (file.external) {
|
|
710
|
+
file.setFinalPath(file.logicalFilePath);
|
|
711
|
+
continue;
|
|
712
|
+
}
|
|
713
|
+
const finalName = this.project.fileName?.(file.name) || file.name;
|
|
714
|
+
file.setName(finalName);
|
|
715
|
+
const finalPath = file.finalPath;
|
|
716
|
+
if (finalPath) file.setFinalPath(node_path.default.resolve(this.project.root, finalPath));
|
|
717
|
+
const ctx = {
|
|
718
|
+
file,
|
|
719
|
+
meta,
|
|
720
|
+
project: this.project
|
|
721
|
+
};
|
|
722
|
+
const renderer = this.project.renderers.find((r) => r.supports(ctx));
|
|
723
|
+
if (renderer) file.setRenderer(renderer);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
/**
|
|
727
|
+
* Plans exports by analyzing all exported symbols.
|
|
728
|
+
*
|
|
729
|
+
* Registers re-export targets as files and creates new exported symbols for them.
|
|
730
|
+
*
|
|
731
|
+
* Assigns names to re-exported symbols and collects re-export metadata,
|
|
732
|
+
* distinguishing type-only exports based on symbol kinds.
|
|
733
|
+
*/
|
|
734
|
+
planExports() {
|
|
735
|
+
const seenByFile = /* @__PURE__ */ new Map();
|
|
736
|
+
const sourceFile = /* @__PURE__ */ new Map();
|
|
737
|
+
this.analyzer.analyze(this.project.nodes.all(), (ctx, node) => {
|
|
738
|
+
if (!node.exported) return;
|
|
739
|
+
const symbol = node.symbol;
|
|
740
|
+
if (!symbol) return;
|
|
741
|
+
const file = node.file;
|
|
742
|
+
if (!file) return;
|
|
743
|
+
for (const exportFrom of symbol.exportFrom) {
|
|
744
|
+
const target = this.project.files.register({
|
|
745
|
+
external: false,
|
|
746
|
+
language: node.language,
|
|
747
|
+
logicalFilePath: exportFrom
|
|
748
|
+
});
|
|
749
|
+
if (target.id === file.id) continue;
|
|
750
|
+
let fileMap = seenByFile.get(target);
|
|
751
|
+
if (!fileMap) {
|
|
752
|
+
fileMap = /* @__PURE__ */ new Map();
|
|
753
|
+
seenByFile.set(target, fileMap);
|
|
754
|
+
}
|
|
755
|
+
const exp = this.project.symbols.register({
|
|
756
|
+
exported: true,
|
|
757
|
+
external: symbol.external,
|
|
758
|
+
importKind: symbol.importKind,
|
|
759
|
+
kind: symbol.kind,
|
|
760
|
+
name: symbol.finalName
|
|
761
|
+
});
|
|
762
|
+
exp.setFile(target);
|
|
763
|
+
sourceFile.set(exp.id, file);
|
|
764
|
+
this.assignTopLevelName({
|
|
765
|
+
ctx,
|
|
766
|
+
symbol: exp
|
|
767
|
+
});
|
|
768
|
+
let entry = fileMap.get(exp.finalName);
|
|
769
|
+
if (!entry) {
|
|
770
|
+
entry = {
|
|
771
|
+
kinds: /* @__PURE__ */ new Set(),
|
|
772
|
+
symbol: exp
|
|
773
|
+
};
|
|
774
|
+
fileMap.set(exp.finalName, entry);
|
|
775
|
+
}
|
|
776
|
+
entry.kinds.add(exp.kind);
|
|
777
|
+
}
|
|
778
|
+
});
|
|
779
|
+
for (const [file, fileMap] of seenByFile) {
|
|
780
|
+
const exports$1 = /* @__PURE__ */ new Map();
|
|
781
|
+
for (const [, entry] of fileMap) {
|
|
782
|
+
const source = sourceFile.get(entry.symbol.id);
|
|
783
|
+
let exp = exports$1.get(source);
|
|
784
|
+
if (!exp) exp = {
|
|
785
|
+
canExportAll: true,
|
|
786
|
+
exports: [],
|
|
787
|
+
from: source,
|
|
788
|
+
isTypeOnly: true
|
|
789
|
+
};
|
|
790
|
+
const isTypeOnly = [...entry.kinds].every((kind) => isTypeOnlyKind(kind));
|
|
791
|
+
const exportedName = entry.symbol.finalName;
|
|
792
|
+
exp.exports.push({
|
|
793
|
+
exportedName,
|
|
794
|
+
isTypeOnly,
|
|
795
|
+
kind: entry.symbol.importKind,
|
|
796
|
+
sourceName: entry.symbol.name
|
|
797
|
+
});
|
|
798
|
+
if (entry.symbol.name !== entry.symbol.finalName) exp.canExportAll = false;
|
|
799
|
+
if (!isTypeOnly) exp.isTypeOnly = false;
|
|
800
|
+
exports$1.set(source, exp);
|
|
801
|
+
}
|
|
802
|
+
for (const [, exp] of exports$1) file.addExport(exp);
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
/**
|
|
806
|
+
* Plans imports by analyzing symbol dependencies across files.
|
|
807
|
+
*
|
|
808
|
+
* For external dependencies, assigns top-level names.
|
|
809
|
+
*
|
|
810
|
+
* Creates or reuses import symbols for dependencies from other files,
|
|
811
|
+
* assigning names and updating import metadata including type-only flags.
|
|
812
|
+
*/
|
|
813
|
+
planImports() {
|
|
814
|
+
const seenByFile = /* @__PURE__ */ new Map();
|
|
815
|
+
this.analyzer.analyze(this.project.nodes.all(), (ctx) => {
|
|
816
|
+
const symbol = ctx.symbol;
|
|
817
|
+
if (!symbol) return;
|
|
818
|
+
const file = symbol.file;
|
|
819
|
+
if (!file) return;
|
|
820
|
+
let fileMap = seenByFile.get(file);
|
|
821
|
+
if (!fileMap) {
|
|
822
|
+
fileMap = /* @__PURE__ */ new Map();
|
|
823
|
+
seenByFile.set(file, fileMap);
|
|
824
|
+
}
|
|
825
|
+
ctx.walkScopes((dependency) => {
|
|
826
|
+
const dep = fromRef(dependency);
|
|
827
|
+
if (!dep.file || dep.file.id === file.id) return;
|
|
828
|
+
if (dep.external) this.assignTopLevelName({
|
|
829
|
+
ctx,
|
|
830
|
+
symbol: dep
|
|
831
|
+
});
|
|
832
|
+
const fromFileId = dep.file.id;
|
|
833
|
+
const importedName = dep.finalName;
|
|
834
|
+
const isTypeOnly = isTypeOnlyKind(dep.kind);
|
|
835
|
+
const key = `${fromFileId}|${importedName}|${dep.importKind}|${isTypeOnly}`;
|
|
836
|
+
let entry = fileMap.get(key);
|
|
837
|
+
if (!entry) {
|
|
838
|
+
const imp = this.project.symbols.register({
|
|
839
|
+
exported: dep.exported,
|
|
840
|
+
external: dep.external,
|
|
841
|
+
importKind: dep.importKind,
|
|
842
|
+
kind: dep.kind,
|
|
843
|
+
name: dep.finalName
|
|
844
|
+
});
|
|
845
|
+
imp.setFile(file);
|
|
846
|
+
this.assignTopLevelName({
|
|
847
|
+
ctx,
|
|
848
|
+
scope: createScope({ localNames: imp.file.allNames }),
|
|
849
|
+
symbol: imp
|
|
850
|
+
});
|
|
851
|
+
entry = {
|
|
852
|
+
dep,
|
|
853
|
+
kinds: /* @__PURE__ */ new Set(),
|
|
854
|
+
symbol: imp
|
|
855
|
+
};
|
|
856
|
+
fileMap.set(key, entry);
|
|
857
|
+
entry.kinds.add(imp.kind);
|
|
858
|
+
}
|
|
859
|
+
dependency["~ref"] = entry.symbol;
|
|
860
|
+
});
|
|
861
|
+
});
|
|
862
|
+
for (const [file, fileMap] of seenByFile) {
|
|
863
|
+
const imports = /* @__PURE__ */ new Map();
|
|
864
|
+
for (const [, entry] of fileMap) {
|
|
865
|
+
const source = entry.dep.file;
|
|
866
|
+
let imp = imports.get(source);
|
|
867
|
+
if (!imp) imp = {
|
|
868
|
+
from: source,
|
|
869
|
+
imports: [],
|
|
870
|
+
isTypeOnly: true,
|
|
871
|
+
kind: "named"
|
|
872
|
+
};
|
|
873
|
+
const isTypeOnly = [...entry.kinds].every((kind) => isTypeOnlyKind(kind));
|
|
874
|
+
if (entry.symbol.importKind === "namespace") {
|
|
875
|
+
imp.imports = [];
|
|
876
|
+
imp.kind = "namespace";
|
|
877
|
+
imp.localName = entry.symbol.finalName;
|
|
878
|
+
} else if (entry.symbol.importKind === "default") {
|
|
879
|
+
imp.kind = "default";
|
|
880
|
+
imp.localName = entry.symbol.finalName;
|
|
881
|
+
} else imp.imports.push({
|
|
882
|
+
isTypeOnly,
|
|
883
|
+
localName: entry.symbol.finalName,
|
|
884
|
+
sourceName: entry.dep.finalName
|
|
885
|
+
});
|
|
886
|
+
if (!isTypeOnly) imp.isTypeOnly = false;
|
|
887
|
+
imports.set(source, imp);
|
|
888
|
+
}
|
|
889
|
+
for (const [, imp] of imports) file.addImport(imp);
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
/**
|
|
893
|
+
* Assigns the final name to a top-level (file-scoped) symbol.
|
|
894
|
+
*
|
|
895
|
+
* Uses the symbol's file top-level names as the default scope,
|
|
896
|
+
* and updates all relevant name scopes including the file's allNames and local scopes.
|
|
897
|
+
*
|
|
898
|
+
* Supports optional overrides for the naming scope and scopes to update.
|
|
899
|
+
*/
|
|
900
|
+
assignTopLevelName(args) {
|
|
901
|
+
if (!args.symbol.file) return;
|
|
902
|
+
this.assignSymbolName({
|
|
903
|
+
...args,
|
|
904
|
+
file: args.symbol.file,
|
|
905
|
+
scope: args?.scope ?? createScope({ localNames: args.symbol.file.topLevelNames }),
|
|
906
|
+
scopesToUpdate: [
|
|
907
|
+
createScope({ localNames: args.symbol.file.allNames }),
|
|
908
|
+
args.ctx.scopes,
|
|
909
|
+
...args?.scopesToUpdate ?? []
|
|
910
|
+
]
|
|
911
|
+
});
|
|
912
|
+
}
|
|
913
|
+
/**
|
|
914
|
+
* Assigns the final name to a non-top-level (local) symbol.
|
|
915
|
+
*
|
|
916
|
+
* Uses the provided scope or derives it from the current analysis context's local names.
|
|
917
|
+
*
|
|
918
|
+
* Updates all provided name scopes accordingly.
|
|
919
|
+
*/
|
|
920
|
+
assignLocalName(args) {
|
|
921
|
+
this.assignSymbolName({
|
|
922
|
+
...args,
|
|
923
|
+
scope: args.scope ?? args.ctx.scope
|
|
924
|
+
});
|
|
925
|
+
}
|
|
926
|
+
/**
|
|
927
|
+
* Assigns the final name to a symbol within the provided name scope.
|
|
928
|
+
*
|
|
929
|
+
* Resolves name conflicts until a unique name is found.
|
|
930
|
+
*
|
|
931
|
+
* Updates all specified name scopes with the assigned final name.
|
|
932
|
+
*/
|
|
933
|
+
assignSymbolName(args) {
|
|
934
|
+
const { ctx, file, node, scope, scopesToUpdate, symbol } = args;
|
|
935
|
+
if (this.cacheResolvedNames.has(symbol.id)) return;
|
|
936
|
+
const baseName = symbol.name;
|
|
937
|
+
let finalName = node?.nameSanitizer?.(baseName) ?? symbol.node?.nameSanitizer?.(baseName) ?? baseName;
|
|
938
|
+
let attempt = 1;
|
|
939
|
+
const localNames = ctx.localNames(scope);
|
|
940
|
+
while (true) {
|
|
941
|
+
if ([...localNames.get(finalName) ?? []].every((kind) => canShareName(symbol.kind, kind))) break;
|
|
942
|
+
const language = node?.language || symbol.node?.language || file.language;
|
|
943
|
+
const resolvedName = ((language ? this.project.nameConflictResolvers[language] : void 0) ?? this.project.defaultNameConflictResolver)({
|
|
944
|
+
attempt,
|
|
945
|
+
baseName
|
|
946
|
+
});
|
|
947
|
+
if (!resolvedName) throw new Error(`Unresolvable name conflict: ${symbol.toString()}`);
|
|
948
|
+
finalName = node?.nameSanitizer?.(resolvedName) ?? symbol.node?.nameSanitizer?.(resolvedName) ?? resolvedName;
|
|
949
|
+
attempt = attempt + 1;
|
|
950
|
+
}
|
|
951
|
+
symbol.setFinalName(finalName);
|
|
952
|
+
this.cacheResolvedNames.add(symbol.id);
|
|
953
|
+
const updateScopes = [scope, ...scopesToUpdate];
|
|
954
|
+
for (const scope$1 of updateScopes) this.updateScope(symbol, scope$1);
|
|
955
|
+
}
|
|
956
|
+
/**
|
|
957
|
+
* Updates the provided name scope with the symbol's final name and kind.
|
|
958
|
+
*
|
|
959
|
+
* Ensures the name scope tracks all kinds associated with a given name.
|
|
960
|
+
*/
|
|
961
|
+
updateScope(symbol, scope) {
|
|
962
|
+
const name = symbol.finalName;
|
|
963
|
+
const cache = scope.localNames.get(name) ?? /* @__PURE__ */ new Set();
|
|
964
|
+
cache.add(symbol.kind);
|
|
965
|
+
scope.localNames.set(name, cache);
|
|
966
|
+
}
|
|
967
|
+
};
|
|
968
|
+
|
|
969
|
+
//#endregion
|
|
970
|
+
//#region src/symbols/symbol.ts
|
|
971
|
+
var Symbol$1 = class {
|
|
972
|
+
/**
|
|
973
|
+
* Canonical symbol this stub resolves to, if any.
|
|
974
|
+
*
|
|
975
|
+
* Stubs created during DSL construction may later be associated
|
|
976
|
+
* with a fully registered symbol. Once set, all property lookups
|
|
977
|
+
* should defer to the canonical symbol.
|
|
978
|
+
*/
|
|
979
|
+
_canonical;
|
|
980
|
+
/**
|
|
981
|
+
* True if this symbol is exported from its defining file.
|
|
982
|
+
*
|
|
983
|
+
* @default false
|
|
984
|
+
*/
|
|
985
|
+
_exported;
|
|
986
|
+
/**
|
|
987
|
+
* Names of files (without extension) from which this symbol is re-exported.
|
|
988
|
+
*
|
|
989
|
+
* @default []
|
|
990
|
+
*/
|
|
991
|
+
_exportFrom;
|
|
992
|
+
/**
|
|
993
|
+
* External module name if this symbol is imported from a module not managed
|
|
994
|
+
* by the project (e.g. "zod", "lodash").
|
|
995
|
+
*
|
|
996
|
+
* @default undefined
|
|
997
|
+
*/
|
|
998
|
+
_external;
|
|
999
|
+
/**
|
|
1000
|
+
* The file this symbol is ultimately emitted into.
|
|
1001
|
+
*
|
|
1002
|
+
* Only top-level symbols have an assigned file.
|
|
1003
|
+
*/
|
|
1004
|
+
_file;
|
|
1005
|
+
/**
|
|
1006
|
+
* The alias-resolved, conflict-free emitted name.
|
|
1007
|
+
*/
|
|
1008
|
+
_finalName;
|
|
1009
|
+
/**
|
|
1010
|
+
* Custom strategy to determine file output path.
|
|
1011
|
+
*
|
|
1012
|
+
* @returns The file path to output the symbol to, or undefined to fallback to default behavior.
|
|
1013
|
+
*/
|
|
1014
|
+
_getFilePath;
|
|
1015
|
+
/**
|
|
1016
|
+
* How this symbol should be imported (namespace/default/named).
|
|
1017
|
+
*
|
|
1018
|
+
* @default 'named'
|
|
1019
|
+
*/
|
|
1020
|
+
_importKind;
|
|
1021
|
+
/**
|
|
1022
|
+
* Kind of symbol (class, type, alias, etc.).
|
|
1023
|
+
*
|
|
1024
|
+
* @default 'var'
|
|
1025
|
+
*/
|
|
1026
|
+
_kind;
|
|
1027
|
+
/**
|
|
1028
|
+
* Arbitrary user metadata.
|
|
1029
|
+
*
|
|
1030
|
+
* @default undefined
|
|
1031
|
+
*/
|
|
1032
|
+
_meta;
|
|
1033
|
+
/**
|
|
1034
|
+
* Intended user-facing name before conflict resolution.
|
|
1035
|
+
*
|
|
1036
|
+
* @example "UserModel"
|
|
1037
|
+
*/
|
|
1038
|
+
_name;
|
|
1039
|
+
/**
|
|
1040
|
+
* Node that defines this symbol.
|
|
1041
|
+
*/
|
|
1042
|
+
_node;
|
|
1043
|
+
/** Brand used for identifying symbols. */
|
|
1044
|
+
"~brand" = symbolBrand;
|
|
1045
|
+
/** Globally unique, stable symbol ID. */
|
|
1046
|
+
id;
|
|
1047
|
+
constructor(input, id) {
|
|
1048
|
+
this._exported = input.exported ?? false;
|
|
1049
|
+
this._exportFrom = input.exportFrom ?? [];
|
|
1050
|
+
this._external = input.external;
|
|
1051
|
+
this._getFilePath = input.getFilePath;
|
|
1052
|
+
this.id = id;
|
|
1053
|
+
this._importKind = input.importKind ?? "named";
|
|
1054
|
+
this._kind = input.kind ?? "var";
|
|
1055
|
+
this._meta = input.meta;
|
|
1056
|
+
this._name = input.name;
|
|
1057
|
+
}
|
|
1058
|
+
/**
|
|
1059
|
+
* Returns the canonical symbol for this instance.
|
|
1060
|
+
*
|
|
1061
|
+
* If this symbol was created as a stub, this getter returns
|
|
1062
|
+
* the fully registered canonical symbol. Otherwise, it returns
|
|
1063
|
+
* the symbol itself.
|
|
1064
|
+
*/
|
|
1065
|
+
get canonical() {
|
|
1066
|
+
return this._canonical ?? this;
|
|
1067
|
+
}
|
|
1068
|
+
/**
|
|
1069
|
+
* Indicates whether this symbol is exported from its defining file.
|
|
1070
|
+
*/
|
|
1071
|
+
get exported() {
|
|
1072
|
+
return this.canonical._exported;
|
|
1073
|
+
}
|
|
1074
|
+
/**
|
|
1075
|
+
* Names of files (without extension) that re-export this symbol.
|
|
1076
|
+
*/
|
|
1077
|
+
get exportFrom() {
|
|
1078
|
+
return this.canonical._exportFrom;
|
|
1079
|
+
}
|
|
1080
|
+
/**
|
|
1081
|
+
* External module from which this symbol originates, if any.
|
|
1082
|
+
*/
|
|
1083
|
+
get external() {
|
|
1084
|
+
return this.canonical._external;
|
|
1085
|
+
}
|
|
1086
|
+
/**
|
|
1087
|
+
* Read‑only accessor for the assigned output file.
|
|
1088
|
+
*
|
|
1089
|
+
* Only top-level symbols have an assigned file.
|
|
1090
|
+
*/
|
|
1091
|
+
get file() {
|
|
1092
|
+
return this.canonical._file;
|
|
1093
|
+
}
|
|
1094
|
+
/**
|
|
1095
|
+
* Read‑only accessor for the resolved final emitted name.
|
|
1096
|
+
*/
|
|
1097
|
+
get finalName() {
|
|
1098
|
+
if (!this.canonical._finalName) {
|
|
1099
|
+
const message = `Symbol finalName has not been resolved yet for ${this.canonical.toString()}`;
|
|
1100
|
+
log.debug(message, "symbol");
|
|
1101
|
+
throw new Error(message);
|
|
1102
|
+
}
|
|
1103
|
+
return this.canonical._finalName;
|
|
1104
|
+
}
|
|
1105
|
+
/**
|
|
1106
|
+
* Custom file path resolver, if provided.
|
|
1107
|
+
*/
|
|
1108
|
+
get getFilePath() {
|
|
1109
|
+
return this.canonical._getFilePath;
|
|
1110
|
+
}
|
|
1111
|
+
/**
|
|
1112
|
+
* How this symbol should be imported (named/default/namespace).
|
|
1113
|
+
*/
|
|
1114
|
+
get importKind() {
|
|
1115
|
+
return this.canonical._importKind;
|
|
1116
|
+
}
|
|
1117
|
+
/**
|
|
1118
|
+
* Indicates whether this is a canonical symbol (not a stub).
|
|
1119
|
+
*/
|
|
1120
|
+
get isCanonical() {
|
|
1121
|
+
return !this._canonical || this._canonical === this;
|
|
1122
|
+
}
|
|
1123
|
+
/**
|
|
1124
|
+
* The symbol's kind (class, type, alias, variable, etc.).
|
|
1125
|
+
*/
|
|
1126
|
+
get kind() {
|
|
1127
|
+
return this.canonical._kind;
|
|
1128
|
+
}
|
|
1129
|
+
/**
|
|
1130
|
+
* Arbitrary user‑provided metadata associated with this symbol.
|
|
1131
|
+
*/
|
|
1132
|
+
get meta() {
|
|
1133
|
+
return this.canonical._meta;
|
|
1134
|
+
}
|
|
1135
|
+
/**
|
|
1136
|
+
* User-intended name before aliasing or conflict resolution.
|
|
1137
|
+
*/
|
|
1138
|
+
get name() {
|
|
1139
|
+
return this.canonical._name;
|
|
1140
|
+
}
|
|
1141
|
+
/**
|
|
1142
|
+
* Read‑only accessor for the defining node.
|
|
1143
|
+
*/
|
|
1144
|
+
get node() {
|
|
1145
|
+
return this.canonical._node;
|
|
1146
|
+
}
|
|
1147
|
+
/**
|
|
1148
|
+
* Marks this symbol as a stub and assigns its canonical symbol.
|
|
1149
|
+
*
|
|
1150
|
+
* After calling this, all semantic queries (name, kind, file,
|
|
1151
|
+
* meta, etc.) should reflect the canonical symbol's values.
|
|
1152
|
+
*
|
|
1153
|
+
* @param symbol — The canonical symbol this stub should resolve to.
|
|
1154
|
+
*/
|
|
1155
|
+
setCanonical(symbol) {
|
|
1156
|
+
this._canonical = symbol;
|
|
1157
|
+
}
|
|
1158
|
+
/**
|
|
1159
|
+
* Marks the symbol as exported from its file.
|
|
1160
|
+
*
|
|
1161
|
+
* @param exported — Whether the symbol is exported.
|
|
1162
|
+
*/
|
|
1163
|
+
setExported(exported) {
|
|
1164
|
+
this.assertCanonical();
|
|
1165
|
+
this._exported = exported;
|
|
1166
|
+
}
|
|
1167
|
+
/**
|
|
1168
|
+
* Records file names that re‑export this symbol.
|
|
1169
|
+
*
|
|
1170
|
+
* @param list — Source files re‑exporting this symbol.
|
|
1171
|
+
*/
|
|
1172
|
+
setExportFrom(list) {
|
|
1173
|
+
this.assertCanonical();
|
|
1174
|
+
this._exportFrom = list;
|
|
1175
|
+
}
|
|
1176
|
+
/**
|
|
1177
|
+
* Assigns the output file this symbol will be emitted into.
|
|
1178
|
+
*
|
|
1179
|
+
* This may only be set once.
|
|
1180
|
+
*/
|
|
1181
|
+
setFile(file) {
|
|
1182
|
+
this.assertCanonical();
|
|
1183
|
+
if (this._file && this._file !== file) {
|
|
1184
|
+
const message = `Symbol ${this.canonical.toString()} is already assigned to a different file.`;
|
|
1185
|
+
log.debug(message, "symbol");
|
|
1186
|
+
throw new Error(message);
|
|
1187
|
+
}
|
|
1188
|
+
this._file = file;
|
|
1189
|
+
}
|
|
1190
|
+
/**
|
|
1191
|
+
* Assigns the conflict‑resolved final local name for this symbol.
|
|
1192
|
+
*
|
|
1193
|
+
* This may only be set once.
|
|
1194
|
+
*/
|
|
1195
|
+
setFinalName(name) {
|
|
1196
|
+
this.assertCanonical();
|
|
1197
|
+
if (this._finalName && this._finalName !== name) {
|
|
1198
|
+
const message = `Symbol finalName has already been resolved for ${this.canonical.toString()}.`;
|
|
1199
|
+
log.debug(message, "symbol");
|
|
1200
|
+
throw new Error(message);
|
|
1201
|
+
}
|
|
1202
|
+
this._finalName = name;
|
|
1203
|
+
}
|
|
1204
|
+
/**
|
|
1205
|
+
* Sets how this symbol should be imported.
|
|
1206
|
+
*
|
|
1207
|
+
* @param kind — The import strategy (named/default/namespace).
|
|
1208
|
+
*/
|
|
1209
|
+
setImportKind(kind) {
|
|
1210
|
+
this.assertCanonical();
|
|
1211
|
+
this._importKind = kind;
|
|
1212
|
+
}
|
|
1213
|
+
/**
|
|
1214
|
+
* Sets the symbol's kind (class, type, alias, variable, etc.).
|
|
1215
|
+
*
|
|
1216
|
+
* @param kind — The new symbol kind.
|
|
1217
|
+
*/
|
|
1218
|
+
setKind(kind) {
|
|
1219
|
+
this.assertCanonical();
|
|
1220
|
+
this._kind = kind;
|
|
1221
|
+
}
|
|
1222
|
+
/**
|
|
1223
|
+
* Updates the intended user‑facing name for this symbol.
|
|
1224
|
+
*
|
|
1225
|
+
* @param name — The new name.
|
|
1226
|
+
*/
|
|
1227
|
+
setName(name) {
|
|
1228
|
+
this.assertCanonical();
|
|
1229
|
+
this._name = name;
|
|
1230
|
+
}
|
|
1231
|
+
/**
|
|
1232
|
+
* Binds the node that defines this symbol.
|
|
1233
|
+
*
|
|
1234
|
+
* This may only be set once.
|
|
1235
|
+
*/
|
|
1236
|
+
setNode(node) {
|
|
1237
|
+
this.assertCanonical();
|
|
1238
|
+
if (this._node && this._node !== node) {
|
|
1239
|
+
const message = `Symbol ${this.canonical.toString()} is already bound to a different node.`;
|
|
1240
|
+
log.debug(message, "symbol");
|
|
1241
|
+
}
|
|
1242
|
+
this._node = node;
|
|
1243
|
+
node.symbol = this;
|
|
1244
|
+
}
|
|
1245
|
+
/**
|
|
1246
|
+
* Returns a debug‑friendly string representation identifying the symbol.
|
|
1247
|
+
*/
|
|
1248
|
+
toString() {
|
|
1249
|
+
const canonical = this.canonical;
|
|
1250
|
+
if (canonical._finalName && canonical._finalName !== canonical._name) return `[Symbol ${canonical._name} → ${canonical._finalName}#${canonical.id}]`;
|
|
1251
|
+
return `[Symbol ${canonical._name}#${canonical.id}]`;
|
|
1252
|
+
}
|
|
1253
|
+
/**
|
|
1254
|
+
* Ensures this symbol is canonical before allowing mutation.
|
|
1255
|
+
*
|
|
1256
|
+
* A symbol that has been marked as a stub (i.e., its `_canonical` points
|
|
1257
|
+
* to a different symbol) may not be mutated. This guard throws an error
|
|
1258
|
+
* if any setter attempts to modify a stub, preventing accidental writes
|
|
1259
|
+
* to non‑canonical instances.
|
|
1260
|
+
*
|
|
1261
|
+
* @throws {Error} If the symbol is a stub and is being mutated.
|
|
1262
|
+
*/
|
|
1263
|
+
assertCanonical() {
|
|
1264
|
+
if (this._canonical && this._canonical !== this) {
|
|
1265
|
+
const message = `Illegal mutation of stub symbol ${this.toString()} → canonical: ${this._canonical.toString()}`;
|
|
1266
|
+
log.debug(message, "symbol");
|
|
1267
|
+
throw new Error(message);
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
};
|
|
1271
|
+
|
|
1272
|
+
//#endregion
|
|
1273
|
+
//#region src/symbols/registry.ts
|
|
1274
|
+
var SymbolRegistry = class {
|
|
1275
|
+
_id = 0;
|
|
1276
|
+
_indices = /* @__PURE__ */ new Map();
|
|
1277
|
+
_queryCache = /* @__PURE__ */ new Map();
|
|
1278
|
+
_queryCacheDependencies = /* @__PURE__ */ new Map();
|
|
1279
|
+
_registered = /* @__PURE__ */ new Set();
|
|
1280
|
+
_stubs = /* @__PURE__ */ new Set();
|
|
1281
|
+
_stubCache = /* @__PURE__ */ new Map();
|
|
1282
|
+
_values = /* @__PURE__ */ new Map();
|
|
1283
|
+
get(identifier) {
|
|
1284
|
+
return typeof identifier === "number" ? this._values.get(identifier) : this.query(identifier)[0];
|
|
1285
|
+
}
|
|
1286
|
+
isRegistered(identifier) {
|
|
1287
|
+
const symbol = this.get(identifier);
|
|
1288
|
+
return symbol ? this._registered.has(symbol.id) : false;
|
|
1289
|
+
}
|
|
1290
|
+
get nextId() {
|
|
1291
|
+
return this._id++;
|
|
1292
|
+
}
|
|
1293
|
+
query(filter) {
|
|
1294
|
+
const cacheKey = this.buildCacheKey(filter);
|
|
1295
|
+
const cachedIds = this._queryCache.get(cacheKey);
|
|
1296
|
+
if (cachedIds) return cachedIds.map((symbolId) => this._values.get(symbolId));
|
|
1297
|
+
const sets = [];
|
|
1298
|
+
const indexKeySpace = this.buildIndexKeySpace(filter);
|
|
1299
|
+
const cacheDependencies = /* @__PURE__ */ new Set();
|
|
1300
|
+
let missed = false;
|
|
1301
|
+
for (const indexEntry of indexKeySpace) {
|
|
1302
|
+
cacheDependencies.add(this.serializeIndexEntry(indexEntry));
|
|
1303
|
+
const values = this._indices.get(indexEntry[0]);
|
|
1304
|
+
if (!values) {
|
|
1305
|
+
missed = true;
|
|
1306
|
+
break;
|
|
1307
|
+
}
|
|
1308
|
+
const set = values.get(indexEntry[1]);
|
|
1309
|
+
if (!set) {
|
|
1310
|
+
missed = true;
|
|
1311
|
+
break;
|
|
1312
|
+
}
|
|
1313
|
+
sets.push(set);
|
|
1314
|
+
}
|
|
1315
|
+
if (missed || !sets.length) {
|
|
1316
|
+
this._queryCacheDependencies.set(cacheKey, cacheDependencies);
|
|
1317
|
+
this._queryCache.set(cacheKey, []);
|
|
1318
|
+
return [];
|
|
1319
|
+
}
|
|
1320
|
+
let result = new Set(sets[0]);
|
|
1321
|
+
for (const set of sets.slice(1)) result = new Set([...result].filter((symbolId) => set.has(symbolId)));
|
|
1322
|
+
const resultIds = [...result];
|
|
1323
|
+
this._queryCacheDependencies.set(cacheKey, cacheDependencies);
|
|
1324
|
+
this._queryCache.set(cacheKey, resultIds);
|
|
1325
|
+
return resultIds.map((symbolId) => this._values.get(symbolId));
|
|
1326
|
+
}
|
|
1327
|
+
reference(meta) {
|
|
1328
|
+
const [registered] = this.query(meta);
|
|
1329
|
+
if (registered) return registered;
|
|
1330
|
+
const cacheKey = this.buildCacheKey(meta);
|
|
1331
|
+
const cachedId = this._stubCache.get(cacheKey);
|
|
1332
|
+
if (cachedId !== void 0) return this._values.get(cachedId);
|
|
1333
|
+
const stub = new Symbol$1({
|
|
1334
|
+
meta,
|
|
1335
|
+
name: ""
|
|
1336
|
+
}, this.nextId);
|
|
1337
|
+
this._values.set(stub.id, stub);
|
|
1338
|
+
this._stubs.add(stub.id);
|
|
1339
|
+
this._stubCache.set(cacheKey, stub.id);
|
|
1340
|
+
return stub;
|
|
1341
|
+
}
|
|
1342
|
+
register(symbol) {
|
|
1343
|
+
const result = new Symbol$1(symbol, this.nextId);
|
|
1344
|
+
this._values.set(result.id, result);
|
|
1345
|
+
this._registered.add(result.id);
|
|
1346
|
+
if (result.meta) {
|
|
1347
|
+
const indexKeySpace = this.buildIndexKeySpace(result.meta);
|
|
1348
|
+
this.indexSymbol(result.id, indexKeySpace);
|
|
1349
|
+
this.invalidateCache(indexKeySpace);
|
|
1350
|
+
this.replaceStubs(result, indexKeySpace);
|
|
1351
|
+
}
|
|
1352
|
+
return result;
|
|
1353
|
+
}
|
|
1354
|
+
*registered() {
|
|
1355
|
+
for (const id of this._registered.values()) yield this._values.get(id);
|
|
1356
|
+
}
|
|
1357
|
+
buildCacheKey(filter) {
|
|
1358
|
+
return this.buildIndexKeySpace(filter).map((indexEntry) => this.serializeIndexEntry(indexEntry)).sort().join("|");
|
|
1359
|
+
}
|
|
1360
|
+
buildIndexKeySpace(meta, prefix = "") {
|
|
1361
|
+
const entries = [];
|
|
1362
|
+
for (const [key, value] of Object.entries(meta)) {
|
|
1363
|
+
const path$4 = prefix ? `${prefix}.${key}` : key;
|
|
1364
|
+
if (value && typeof value === "object" && !Array.isArray(value)) entries.push(...this.buildIndexKeySpace(value, path$4));
|
|
1365
|
+
else entries.push([path$4, value]);
|
|
1366
|
+
}
|
|
1367
|
+
return entries;
|
|
1368
|
+
}
|
|
1369
|
+
indexSymbol(symbolId, indexKeySpace) {
|
|
1370
|
+
for (const [key, value] of indexKeySpace) {
|
|
1371
|
+
if (!this._indices.has(key)) this._indices.set(key, /* @__PURE__ */ new Map());
|
|
1372
|
+
const values = this._indices.get(key);
|
|
1373
|
+
const set = values.get(value) ?? /* @__PURE__ */ new Set();
|
|
1374
|
+
set.add(symbolId);
|
|
1375
|
+
values.set(value, set);
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
invalidateCache(indexKeySpace) {
|
|
1379
|
+
const changed = indexKeySpace.map((indexEntry) => this.serializeIndexEntry(indexEntry));
|
|
1380
|
+
for (const [cacheKey, cacheDependencies] of this._queryCacheDependencies.entries()) for (const key of changed) if (cacheDependencies.has(key)) {
|
|
1381
|
+
this._queryCacheDependencies.delete(cacheKey);
|
|
1382
|
+
this._queryCache.delete(cacheKey);
|
|
1383
|
+
break;
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
isSubset(sub, sup) {
|
|
1387
|
+
const supMap = new Map(sup);
|
|
1388
|
+
for (const [key, value] of sub) if (!supMap.has(key) || supMap.get(key) !== value) return false;
|
|
1389
|
+
return true;
|
|
1390
|
+
}
|
|
1391
|
+
replaceStubs(symbol, indexKeySpace) {
|
|
1392
|
+
for (const stubId of this._stubs.values()) {
|
|
1393
|
+
const stub = this._values.get(stubId);
|
|
1394
|
+
if (stub?.meta && this.isSubset(this.buildIndexKeySpace(stub.meta), indexKeySpace)) {
|
|
1395
|
+
const cacheKey = this.buildCacheKey(stub.meta);
|
|
1396
|
+
this._stubCache.delete(cacheKey);
|
|
1397
|
+
this._stubs.delete(stubId);
|
|
1398
|
+
stub.setCanonical(symbol);
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
serializeIndexEntry(indexEntry) {
|
|
1403
|
+
return `${indexEntry[0]}:${JSON.stringify(indexEntry[1])}`;
|
|
1404
|
+
}
|
|
1405
|
+
};
|
|
1406
|
+
|
|
1407
|
+
//#endregion
|
|
1408
|
+
//#region src/project/project.ts
|
|
1409
|
+
var Project = class {
|
|
1410
|
+
_isPlanned = false;
|
|
1411
|
+
files;
|
|
1412
|
+
nodes = new NodeRegistry();
|
|
1413
|
+
symbols = new SymbolRegistry();
|
|
1414
|
+
defaultFileName;
|
|
1415
|
+
defaultNameConflictResolver;
|
|
1416
|
+
extensions;
|
|
1417
|
+
fileName;
|
|
1418
|
+
nameConflictResolvers;
|
|
1419
|
+
renderers;
|
|
1420
|
+
root;
|
|
1421
|
+
constructor(args) {
|
|
1422
|
+
const fileName = args.fileName;
|
|
1423
|
+
this.defaultFileName = args.defaultFileName ?? "main";
|
|
1424
|
+
this.defaultNameConflictResolver = args.defaultNameConflictResolver ?? simpleNameConflictResolver;
|
|
1425
|
+
this.extensions = {
|
|
1426
|
+
...defaultExtensions,
|
|
1427
|
+
...args.extensions
|
|
1428
|
+
};
|
|
1429
|
+
this.fileName = typeof fileName === "string" ? () => fileName : fileName;
|
|
1430
|
+
this.files = new FileRegistry(this);
|
|
1431
|
+
this.nameConflictResolvers = {
|
|
1432
|
+
...defaultNameConflictResolvers,
|
|
1433
|
+
...args.nameConflictResolvers
|
|
1434
|
+
};
|
|
1435
|
+
this.renderers = args.renderers ?? [];
|
|
1436
|
+
this.root = node_path.default.resolve(args.root).replace(/[/\\]+$/, "");
|
|
1437
|
+
}
|
|
1438
|
+
plan(meta) {
|
|
1439
|
+
if (this._isPlanned) return;
|
|
1440
|
+
new Planner(this).plan(meta);
|
|
1441
|
+
this._isPlanned = true;
|
|
1442
|
+
}
|
|
1443
|
+
render(meta) {
|
|
1444
|
+
if (!this._isPlanned) this.plan(meta);
|
|
1445
|
+
const files = [];
|
|
1446
|
+
for (const file of this.files.registered()) if (!file.external && file.finalPath && file.renderer) {
|
|
1447
|
+
const content = file.renderer.render({
|
|
1448
|
+
file,
|
|
1449
|
+
meta,
|
|
1450
|
+
project: this
|
|
1451
|
+
});
|
|
1452
|
+
files.push({
|
|
1453
|
+
content,
|
|
1454
|
+
path: file.finalPath
|
|
1455
|
+
});
|
|
1456
|
+
}
|
|
1457
|
+
return files;
|
|
1458
|
+
}
|
|
1459
|
+
};
|
|
1460
|
+
|
|
1461
|
+
//#endregion
|
|
1462
|
+
//#region src/structure/node.ts
|
|
1463
|
+
var StructureNode = class StructureNode {
|
|
1464
|
+
/** Nested nodes within this node. */
|
|
1465
|
+
children = /* @__PURE__ */ new Map();
|
|
1466
|
+
/** Items contained in this node. */
|
|
1467
|
+
items = [];
|
|
1468
|
+
/** The name of this node (e.g., "Users", "Accounts"). */
|
|
1469
|
+
name;
|
|
1470
|
+
/** Parent node in the hierarchy. Undefined if this is the root node. */
|
|
1471
|
+
parent;
|
|
1472
|
+
/** Shell claimed for this node. */
|
|
1473
|
+
shell;
|
|
1474
|
+
/** Source of the claimed shell. */
|
|
1475
|
+
shellSource;
|
|
1476
|
+
/** True if this is a virtual root. */
|
|
1477
|
+
virtual;
|
|
1478
|
+
constructor(name, parent, options) {
|
|
1479
|
+
this.name = name;
|
|
1480
|
+
this.parent = parent;
|
|
1481
|
+
this.virtual = options?.virtual ?? false;
|
|
1482
|
+
}
|
|
1483
|
+
get isRoot() {
|
|
1484
|
+
return !this.parent;
|
|
1485
|
+
}
|
|
1486
|
+
/**
|
|
1487
|
+
* Gets or creates a child node.
|
|
1488
|
+
*
|
|
1489
|
+
* If the child doesn't exist, it's created automatically.
|
|
1490
|
+
*
|
|
1491
|
+
* @param name - The name of the child node
|
|
1492
|
+
* @returns The child node instance
|
|
1493
|
+
*/
|
|
1494
|
+
child(name) {
|
|
1495
|
+
if (!this.children.has(name)) this.children.set(name, new StructureNode(name, this));
|
|
1496
|
+
return this.children.get(name);
|
|
1497
|
+
}
|
|
1498
|
+
/**
|
|
1499
|
+
* Gets the full path of this node in the hierarchy.
|
|
1500
|
+
*
|
|
1501
|
+
* @returns An array of node names from the root to this node
|
|
1502
|
+
*/
|
|
1503
|
+
getPath() {
|
|
1504
|
+
const path$4 = [];
|
|
1505
|
+
let cursor = this;
|
|
1506
|
+
while (cursor) {
|
|
1507
|
+
path$4.unshift(cursor.name);
|
|
1508
|
+
cursor = cursor.parent;
|
|
1509
|
+
}
|
|
1510
|
+
return path$4;
|
|
1511
|
+
}
|
|
1512
|
+
/**
|
|
1513
|
+
* Yields items from a specific source with typed data.
|
|
1514
|
+
*
|
|
1515
|
+
* @param source - The source symbol to filter by
|
|
1516
|
+
* @returns Generator of items from that source
|
|
1517
|
+
*/
|
|
1518
|
+
*itemsFrom(source) {
|
|
1519
|
+
for (const item of this.items) if (item.source === source) yield item;
|
|
1520
|
+
}
|
|
1521
|
+
/**
|
|
1522
|
+
* Walk all nodes in the structure (depth-first, post-order).
|
|
1523
|
+
*
|
|
1524
|
+
* @returns Generator of all structure nodes
|
|
1525
|
+
*/
|
|
1526
|
+
*walk() {
|
|
1527
|
+
for (const node of this.children.values()) yield* node.walk();
|
|
1528
|
+
yield this;
|
|
1529
|
+
}
|
|
1530
|
+
};
|
|
1531
|
+
|
|
1532
|
+
//#endregion
|
|
1533
|
+
//#region src/structure/model.ts
|
|
1534
|
+
var StructureModel = class {
|
|
1535
|
+
/** Root nodes mapped by their names. */
|
|
1536
|
+
_roots = /* @__PURE__ */ new Map();
|
|
1537
|
+
/** Node for data without a specific root. */
|
|
1538
|
+
_virtualRoot;
|
|
1539
|
+
/**
|
|
1540
|
+
* Get all root nodes.
|
|
1541
|
+
*/
|
|
1542
|
+
get roots() {
|
|
1543
|
+
const roots = Array.from(this._roots.values());
|
|
1544
|
+
if (this._virtualRoot) roots.unshift(this._virtualRoot);
|
|
1545
|
+
return roots;
|
|
1546
|
+
}
|
|
1547
|
+
/**
|
|
1548
|
+
* Insert data into the structure.
|
|
1549
|
+
*/
|
|
1550
|
+
insert(args) {
|
|
1551
|
+
const { data, locations, source } = args;
|
|
1552
|
+
for (const location of locations) {
|
|
1553
|
+
const { path: path$4, shell } = location;
|
|
1554
|
+
const fullPath = path$4.filter((s) => Boolean(s));
|
|
1555
|
+
const segments = fullPath.slice(0, -1);
|
|
1556
|
+
if (!fullPath[fullPath.length - 1]) throw new Error("Cannot insert data without path.");
|
|
1557
|
+
let cursor = null;
|
|
1558
|
+
for (const segment of segments) {
|
|
1559
|
+
if (!cursor) cursor = this.root(segment);
|
|
1560
|
+
else cursor = cursor.child(segment);
|
|
1561
|
+
if (shell && !cursor.shell) {
|
|
1562
|
+
cursor.shell = shell;
|
|
1563
|
+
cursor.shellSource = source;
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
if (!cursor) cursor = this.root(null);
|
|
1567
|
+
cursor.items.push({
|
|
1568
|
+
data,
|
|
1569
|
+
location: fullPath,
|
|
1570
|
+
source
|
|
1571
|
+
});
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
/**
|
|
1575
|
+
* Gets or creates a root by name.
|
|
1576
|
+
*
|
|
1577
|
+
* If the root doesn't exist, it's created automatically.
|
|
1578
|
+
*
|
|
1579
|
+
* @param name - The name of the root
|
|
1580
|
+
* @returns The root instance
|
|
1581
|
+
*/
|
|
1582
|
+
root(name) {
|
|
1583
|
+
if (!name) return this._virtualRoot ??= new StructureNode("", void 0, { virtual: true });
|
|
1584
|
+
if (!this._roots.has(name)) this._roots.set(name, new StructureNode(name));
|
|
1585
|
+
return this._roots.get(name);
|
|
1586
|
+
}
|
|
1587
|
+
/**
|
|
1588
|
+
* Walk all nodes in the structure (depth-first, post-order).
|
|
1589
|
+
*
|
|
1590
|
+
* @returns Generator of all structure nodes
|
|
1591
|
+
*/
|
|
1592
|
+
*walk() {
|
|
1593
|
+
if (this._virtualRoot) yield* this._virtualRoot.walk();
|
|
1594
|
+
for (const root of this._roots.values()) yield* root.walk();
|
|
1595
|
+
}
|
|
1596
|
+
};
|
|
1597
|
+
|
|
1598
|
+
//#endregion
|
|
1599
|
+
exports.File = File;
|
|
1600
|
+
exports.Project = Project;
|
|
1601
|
+
exports.StructureModel = StructureModel;
|
|
1602
|
+
exports.StructureNode = StructureNode;
|
|
1603
|
+
exports.Symbol = Symbol$1;
|
|
1604
|
+
exports.defaultExtensions = defaultExtensions;
|
|
1605
|
+
exports.defaultNameConflictResolvers = defaultNameConflictResolvers;
|
|
1606
|
+
exports.fromRef = fromRef;
|
|
1607
|
+
exports.fromRefs = fromRefs;
|
|
1608
|
+
exports.isNode = isNode;
|
|
1609
|
+
exports.isNodeRef = isNodeRef;
|
|
1610
|
+
exports.isRef = isRef;
|
|
1611
|
+
exports.isSymbol = isSymbol;
|
|
1612
|
+
exports.isSymbolRef = isSymbolRef;
|
|
1613
|
+
exports.log = log;
|
|
1614
|
+
exports.nodeBrand = nodeBrand;
|
|
1615
|
+
exports.ref = ref;
|
|
1616
|
+
exports.refs = refs;
|
|
1617
|
+
exports.simpleNameConflictResolver = simpleNameConflictResolver;
|
|
1618
|
+
exports.symbolBrand = symbolBrand;
|
|
1619
|
+
exports.underscoreNameConflictResolver = underscoreNameConflictResolver;
|
|
3
1620
|
//# sourceMappingURL=index.cjs.map
|