@xaendar/compiler 0.7.30 → 0.7.32

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.
@@ -0,0 +1,15 @@
1
+ import{indent as b}from"@xaendar/common";var h=(l=>(l[l.Element=0]="Element",l[l.Text=1]="Text",l[l.Interpolation=2]="Interpolation",l[l.If=3]="If",l[l.Else=4]="Else",l[l.ElseIf=5]="ElseIf",l[l.For=6]="For",l[l.Switch=7]="Switch",l[l.Case=8]="Case",l[l.Import=9]="Import",l))(h||{});var x=class{constructor(t=[],r){this._parent=r;for(let o of t)typeof o=="string"?this._identifiers.set(o,"value"):this._identifiers.set(o[0],o[1])}_parent;_identifiers=new Map;_unresolvableIdentifiers=new Array;addIdentifier(t,r="value"){if(this.hasIdentifier(t))throw new Error(`Identifier "${t}" is already declared in this scope.`);this._identifiers.set(t,r)}addUnresolvableIdentifier(t){if(this.hasIdentifier(t))throw new Error(`Identifier "${t}" is already declared in this scope.`);this._unresolvableIdentifiers.push(t)}removeIdentifier(t){this._identifiers.delete(t)}removeUnresolvabledIdentifier(t){this._unresolvableIdentifiers=this._unresolvableIdentifiers.filter(r=>r!==t)}hasIdentifier(t){return this._identifiers.has(t)||(this._parent?.hasIdentifier(t)??!1)}getIdentifierKind(t){return this._identifiers.get(t)??this._parent?.getIdentifierKind(t)}hasUnresolvableIdentifier(t){return this._unresolvableIdentifiers.includes(t)||(this._parent?.hasUnresolvableIdentifier(t)??!1)}};import{indent as F}from"@xaendar/common";import{forEachChild as ke,isIdentifier as Ne,isPropertyAccessExpression as It,isPropertyAssignment as At}from"typescript";var gt=new Set(["undefined","NaN","Infinity","globalThis","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape","Object","Function","Boolean","Symbol","Error","AggregateError","EvalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError","SuppressedError","InternalError","Number","BigInt","Math","Date","Temporal","String","RegExp","Array","TypedArray","Int8Array","Uint8Array","Uint8ClampedArray","Int16Array","Uint16Array","Int32Array","Uint32Array","BigInt64Array","BigUint64Array","Float16Array","Float32Array","Float64Array","Map","Set","WeakMap","WeakSet","ArrayBuffer","SharedArrayBuffer","DataView","Atomics","JSON","WeakRef","FinalizationRegistry","Iterator","AsyncIterator","Promise","GeneratorFunction","AsyncGeneratorFunction","Generator","AsyncGenerator","AsyncFunction","DisposableStack","AsyncDisposableStack","Reflect","Proxy","Intl","WebAssembly","window","document","navigator","location","history","screen","console","performance","crypto","fetch","alert","confirm","prompt","setTimeout","setInterval","clearTimeout","clearInterval","requestAnimationFrame","cancelAnimationFrame","queueMicrotask","structuredClone","URL","URLSearchParams","FormData","Headers","Request","Response","AbortController","AbortSignal","CustomEvent","Event","EventTarget","MutationObserver","IntersectionObserver","ResizeObserver","PerformanceObserver","Worker","SharedWorker","ServiceWorker","Blob","File","FileReader","ReadableStream","WritableStream","TransformStream","TextEncoder","TextDecoder","ImageData","Canvas","Storage","localStorage","sessionStorage","indexedDB","WebSocket","XMLHttpRequest","HTMLElement","HTMLInputElement","HTMLButtonElement","HTMLFormElement","HTMLAnchorElement","HTMLImageElement","HTMLVideoElement","HTMLAudioElement","HTMLCanvasElement","HTMLSelectElement","HTMLTextAreaElement","HTMLDivElement","HTMLSpanElement","HTMLParagraphElement","HTMLHeadingElement","HTMLTableElement","HTMLTableRowElement","HTMLTableCellElement","HTMLUListElement","HTMLOListElement","HTMLLIElement","HTMLLabelElement","HTMLDialogElement","HTMLDetailsElement","HTMLSlotElement","HTMLTemplateElement","SVGElement","SVGSVGElement","Element","Node","NodeList","DocumentFragment","ShadowRoot","Document","Window"]),U="root";function d(e,t,r){return Ie(e,e,t,yt(r))}function Ie(e,t,r,o){if(Ne(e)&&ge(e,t)){let a=e.text;return r?.hasUnresolvableIdentifier(a)||o.skipResolution?a:o.resolver?`${o.resolver}.${a}`:r?Lt(a,r):a}if(!Ae(e,t))return e.getText();let n=e.getSourceFile().text,i="",s=e.getStart();return ke(e,a=>{i=`${i}${n.slice(s,a.getStart())}${Ie(a,e,r,o)}`,s=a.getEnd()}),`${i}${n.slice(s,e.getEnd())}`}function Lt(e,t){if(t.hasIdentifier(e)){let r=t.getIdentifierKind(e),o=`context.get('${e}')`;return r==="signal"?`${o}()`:o}return e}function Ae(e,t){if(Ne(e)&&ge(e,t))return!0;let r=!1;return ke(e,o=>{r||(r=Ae(o,e))}),r}function ge(e,t){return!(It(t)&&t.name===e||At(t)&&t.name===e||gt.has(e.text)||!e.text)}function Le(e,t,r){return pe(e.tagName,t,r)}function ae(e="text",t,r){return pe(e,t,r)}function S(e,t,r){return pe(e,t,r)}function pe(e,t,r){return(t!==U?`${t}__${e}${r}`:`${e}${r}`).replace(/-/g,"_")}function yt(e){return{skipResolution:e?.skipResolution??!1,resolver:e?.resolver??"this"}}function ye(e,t,r,o,n){let i=vt(e.attributes,o),s=_t(e.events,o),a=Le(e,t,r),c=e.tagName,m={code:[],functionsToProcess:new Map};switch(c){case"svg":m.code.push("context.createElement = createSVGElement");break;case"math":m.code.push("context.createElement = createMATHMLElement")}switch(m.code.push(`const ${a} = _renderElement(${t}, context, ${n}, '${c}',`),i.length?m.code.push(...F(["[",...F(i),"],"])):m.code[m.code.length-1]=`${m.code[m.code.length-1]} [],`,s.length?m.code.push(...F(["[",...F(s),"]"]),");"):m.code[m.code.length-1]=`${m.code[m.code.length-1]} []);`,c){case"svg":case"math":m.code.push("context.createElement = createElement")}return e.children.length&&(m.functionsToProcess.set(`${a}Children`,{fn:{node:e,parentNode:a,context:o,precode:Ot(c)},args:[a,"parentContext"]}),m.code.push(`this.${a}Children(${a}, context);`)),m}function vt(e,t){return e?.map(({name:r,value:o})=>{let n=typeof o=="string";return`{ name: '${r}', value: () => ${n?`'${o}'`:d(o.expression,t)}, literal: ${n} },`})}function _t(e,t){t.addUnresolvableIdentifier("$event");let r=e.map(o=>{let n=!1,i=o.parameters.map(a=>{let c=d(a,t);return!n&&c==="$event"?(n=!0,`($event) => ${c},`):`() => ${c},`}),s=["{",...F([`name: '${o.name}',`,`handler: '${o.handler}',`,"parameters: ["])];return i.length?s.push(...F([...F(i),"]"]),"},"):(s[s.length-1]=`${s[s.length-1]}]`,s.push("},")),s}).flat();return t.removeIdentifier("$event"),r}function Ot(e){switch(e){case"svg":return"context.createElement = createSVGElement;";case"math":return"context.createElement = createMATHMLElement;";default:return""}}function ve(e,t,r,o){let n={code:[],functionsToProcess:new Map},i=e.iterableSource,s=o.hasIdentifier(i)?i:`this.${i}`,a=ae("items",t,r),c=ae("i",t,r),m=V(e,"$index"),l=V(e,"$first"),E=V(e,"$last"),k=V(e,"$even"),I=V(e,"$odd"),A=new x([e.itemAlias,[m,"signal"],[l,"signal"],[E,"signal"],[k,"signal"],[I,"signal"]],o),R=S("for",t,r);return n.functionsToProcess.set(R,{fn:{precode:`const { vars, update } = _iterationVariables(context, ${a}, ${c}, '${e.itemAlias}', {
2
+ $index: '${m}',
3
+ $first: '${l}',
4
+ $last: '${E}',
5
+ $even: '${k}',
6
+ $odd: '${I}'
7
+ });
8
+ const { ${e.itemAlias}, ${m}, ${l}, ${E}, ${k}, ${I} } = vars;`,node:e,parentNode:R,context:A,anchor:"anchor",isForBody:!0},args:[R,"parentContext",a,c,"anchor"]}),n.code.push(`_for(${t}, context, () => ${s}, ${e.itemAlias} => ${d(e.trackExpression,A,{skipResolution:!0})}, this.${R}.bind(this));`),n}function V(e,t){return e.implicitAliases.get(t)??t}import{indent as $}from"@xaendar/common";function _e(e,t,r,o){let n=new x([],o),i={code:[],functionsToProcess:new Map};i.code.push(`_if(${t}, context, [`);let s=S("if",t,r);i.code.push(...$(["{",...$([`condition: () => ${d(e.conditionNode,o)},`,`block: this.${s}.bind(this)`]),"},"])),i.functionsToProcess.set(s,{fn:{node:e,parentNode:s,context:n,anchor:"anchor"},args:[s,"parentContext","anchor"]});let a=e.alternate,c=0;for(;a?.type===5;){let m=new x([],o),l=S("elseIf",t,`${r}_${c}`),E=a.conditionNode;i.code.push(...$(["{",...$([`condition: () => ${d(E,o)},`,`block: this.${l}.bind(this)`]),"},"])),i.functionsToProcess.set(l,{fn:{node:a,parentNode:t,context:m,anchor:"anchor"},args:[t,"parentContext","anchor"]}),a=a.alternate,c++}if(a){let m=new x([],o),l=S("else",t,r);i.code.push(...$(["{",...$([`block: this.${l}.bind(this)`]),"},"])),i.functionsToProcess.set(l,{fn:{node:a,parentNode:t,context:m,anchor:"anchor"},args:[t,"parentContext","anchor"]})}return i.code.push("]);"),i}import{indent as Oe}from"@xaendar/common";function Re(e,t,r,o){let n={code:[],functionsToProcess:new Map};return n.code.push(`_switch(${t}, context, () => ${d(e.expression,o)}, [`),e.children.forEach((i,s)=>{let a=new x([],o),c=i.condition?S("case",t,`${r}_${s}`):S("default",t,r);n.functionsToProcess.set(c,{fn:{node:i,parentNode:c,context:a},args:[c,"parentContext","anchor"]});let m=`this.${c}.bind(this)`;n.code.push(...Oe(["{",...Oe([`condition: ${i.condition?`[${i.condition.join(", ")}]`:"null"},`,`block: ${m}`]),"},"]))}),n.code.push("])"),n}function ce(e,t,r,o){return{code:[`${e.type===1?`_renderLiteralText(${t}, context, '${e.value}');`:`_renderText(${t}, context, () => ${d(e.expression,o)});`}`]}}function Se(e,t,r,o){}var z=class{constructor(t){this._ast=t}_ast;_nodeToProcess=new Map;_states={1:ce,2:ce,0:ye,3:_e,6:ve,7:Re,9:Se};generate(t){this._nodeToProcess.clear();let r=new x,o=["_render() {",...b([`const ${U} = this._root;`,"const context = new Context(this, { createElement: document.createElement.bind(document), get: () => undefined });"])];t&&o.push(b(`${U}.adoptedStyleSheets = [${t}];`));for(let n=0;n<this._ast.length;n++){let i=this._processNode(this._ast[n],U,n.toString(),r,null);if(i){let{code:s,functionsToProcess:a}=i;a?.forEach((c,m)=>this._nodeToProcess.set(m,c)),o.push(...b(s))}}o.push(...b(["return context;"]),"}");for(let[n,i]of this._nodeToProcess.entries()){let{node:s,parentNode:a,context:c,precode:m,anchor:l}=i.fn;o.push(`
9
+ ${n}(${i.args?.join(", ")}) {`,...b(["const context = new Context(this, parentContext);"])),m&&o.push(b(m)),o.push(...b([...s.children.map((E,k)=>{let I=this._processNode(E,a,k.toString(),c,l??null);if(I){let{code:A,functionsToProcess:R}=I;return R?.forEach((X,Q)=>this._nodeToProcess.set(Q,X)),A}return""}).flat(),i.fn.isForBody?"return { context, update };":"return context;"]),"}")}return o.join(`
10
+ `)}_processNode(t,r,o,n,i){let s=this._states[t.type];if(!s)throw new Error(`[Generator] No transition function for token type ${h[t.type]}`);return s(t,r,o,n,i)}};import{Stack as bt}from"@xaendar/common";var u=(f=>(f[f.TEXT=0]="TEXT",f[f.TAG_OPEN_NAME=1]="TAG_OPEN_NAME",f[f.TAG_SELF_CLOSE=2]="TAG_SELF_CLOSE",f[f.TAG_OPEN_END=3]="TAG_OPEN_END",f[f.TAG_CLOSE_NAME=4]="TAG_CLOSE_NAME",f[f.ATTRIBUTE=5]="ATTRIBUTE",f[f.ATTRIBUTE_VALUE=6]="ATTRIBUTE_VALUE",f[f.EVENT=7]="EVENT",f[f.EVENT_PAREMETER=8]="EVENT_PAREMETER",f[f.INTERPOLATION_LITERAL=9]="INTERPOLATION_LITERAL",f[f.INTERPOLATION_EXPRESSION=10]="INTERPOLATION_EXPRESSION",f[f.IF=11]="IF",f[f.FOR=12]="FOR",f[f.ELSE=13]="ELSE",f[f.ELSE_IF=14]="ELSE_IF",f[f.SWITCH=15]="SWITCH",f[f.CASE=16]="CASE",f[f.DEFAULT=17]="DEFAULT",f[f.CONDITION=18]="CONDITION",f[f.BLOCK_OPEN=19]="BLOCK_OPEN",f[f.BLOCK_CLOSE=20]="BLOCK_CLOSE",f[f.IMPORT=21]="IMPORT",f[f.IMPORT_PATH=22]="IMPORT_PATH",f[f.EOF=23]="EOF",f))(u||{});function we(e,t){let r=!0,o="",n;for(;r;)e.peek()===34?(e.advance(),r=!1,n={state:"tag-body",tokens:[{type:6,parts:[o]}],popState:!0}):(e.advance(),o=`${o}${e.currentChar.value}`);return n}function Fe(e,t){let r=!0,o="",n;for(;r;)switch(e.peek()){case 32:e.advance(),r=!1,n={state:"tag-body",tokens:[{type:5,parts:[o]}]};break;case 61:if(e.advance(),e.peek()!==34){let{row:s,column:a}=e.position;throw new Error(`Attribute value must start with double quotes '"'.Row ${s} Col ${a}`)}e.advance(),r=!1,n={state:e.peek()===123?"interpolation":"attribute-value",pushState:!0,tokens:[{type:5,parts:[o]}]};break;default:e.advance(),o=`${o}${e.currentChar.value}`}return n}function j(e,t){if(e.skipSpaces(),e.peek()!==40)throw new Error(`Expected '(' but got '${String.fromCharCode(e.peek())}' at row ${e.position.row}, col ${e.position.column}`);e.advance();let r="",o=1;for(;o>0;)switch(e.peek()){case 40:o++,r=me(e,r);break;case 41:if(o--,!o){e.advance();break}r=me(e,r);break;default:r=me(e,r)}return r}function me(e,t){return e.advance(),`${t}${e.currentChar.value}`}function be(e,t){let r=j(e,t);return e.skipSpaces(),{state:e.peekMatch("@case")?"flow-control":"flow-control-block",tokens:[{type:18,parts:[r]}],popState:!0}}function Pe(e,t){return{state:"flow-control-block",tokens:[{type:18,parts:[j(e,t)]}],popState:!0}}function $e(e,t){let r=!0,o="",n="",i={state:"tag-body",tokens:[]};for(;r;)switch(e.peek()){case 91:case 93:case 123:case 125:case 34:case 39:case 40:o=le(e,o),n?(n===e.currentChar.value||n==="["&&e.currentChar.value==="]"||n==="{"&&e.currentChar.value==="}")&&(n=""):n=e.currentChar.value;break;case 44:n?o=le(e,o):(i.tokens.push({type:8,parts:[o]}),e.advance(),e.skipSpaces(),o="");break;case 41:e.advance(),n||(i.tokens.push({type:8,parts:[o]}),r=!1);default:o=le(e,o)}return i}function le(e,t){return e.advance(),`${t}${e.currentChar.value}`}function Me(e,t){let r=!0,o="",n;for(e.advance();r;)switch(e.peek()){case 32:case 47:case 62:n={state:"tag-body"},r=!1;break;case 40:let i="parameter";e.advance(),e.skipSpaces(),e.peek()===41&&(i="tag-body",e.advance(2)),n={state:i,tokens:[{type:7,parts:[o]}]},r=!1;break;default:e.advance(),o=`${o}${e.currentChar.value}`}return n}function Be(e,t){let r;return e.advance(),e.peekMatch("for ")?(e.advance(4),r={state:"flow-control-condition",tokens:[{type:12}],pushState:!0}):e.peekMatch("if ")?(e.advance(2),r={state:"flow-control-condition",tokens:[{type:11}],pushState:!0}):e.peekMatch("else if ")?(e.advance(8),r={state:"flow-control-condition",tokens:[{type:14}],pushState:!0}):e.peekMatch("else ")?(e.advance(5),r={state:"flow-control-block",tokens:[{type:13}]}):e.peekMatch("switch ")?(e.advance(7),r={state:"flow-control-condition",tokens:[{type:15}],pushState:!0}):e.peekMatch("case ")?(e.advance(5),r={state:"case-flow-control-condition",tokens:[{type:16}],pushState:!0}):e.peekMatch("default ")?(e.advance(8),r={state:"flow-control-block",tokens:[{type:17}]}):e.peekMatch("import ")&&(e.advance(7),r={state:"import"}),r}function De(e,t){if(e.skipSpaces(),e.peek()!==123)throw new Error(`Expected '{' but got '${String.fromCharCode(e.peek())}' at row ${e.position.row}, col ${e.position.column}`);return e.advance(),{state:"text",tokens:[{type:19}],pushState:!0}}function Ge(e,t){let r=!0,o="",n,i=!1;if(e.skipSpaces(),!e.peekMatch("from"))throw new Error(`Expected from keywork after list of imports at ${e.currentChar}`);switch(e.advance(4),e.skipSpaces(),e.advance(),e.currentChar.code){case 39:i=!0;break;case 34:break;default:throw new Error(`Import statement must start with ' or ".
11
+ Found character ${e.currentChar.value} at ${e.formattedPosition}`)}let s=i?39:34;for(;r;)e.peek()===s?(e.advance(),r=!1,n={state:"text",tokens:[{type:22,parts:[o]}]}):(e.advance(),o=`${o}${e.currentChar.value}`);return n}function Ve(e,t){let r=!0,o="",n={state:"import-path",tokens:[]};if(e.skipSpaces(),e.advance(),e.currentChar.code!==123)throw new Error(`Expected { after @import at ${e.formattedPosition}`);for(;r;)switch(e.peek()){case 32:e.skipSpaces(),o&&e.peek()!==44&&e.peek()!==125&&(o=`${o} `);break;case 44:Ue(n,e,o),o="";break;case 125:Ue(n,e,o),r=!1;break;default:e.advance(),o=`${o}${e.currentChar.value}`}return n}function Ue(e,t,r){t.advance(),e.tokens.push({type:21,parts:[r]})}function He(e,t){let r=!0,o="",n=1,i;for(;r;)switch(e.peek()){case 123:n++,o=fe(e,o);break;case 125:if(n--,n===0){e.advance(),o=o.trimEnd();let s=t.history.pop(),a;switch(s){case"attribute":if(e.peek()!==34)throw new Error(`Interpolation must end with double quotes '"' Found ${String.fromCharCode(e.peek())} at ${e.formattedPosition}`);e.advance(),a="tag-body";break;case"text":a="text"}i={state:a,tokens:[{type:10,parts:[o]}],popState:!0},r=!1}else o=fe(e,o);break;default:o=fe(e,o)}return i}function fe(e,t){return e.advance(1),`${t}${e.currentChar.value}`}function We(e,t){let r=!0,o="`",n;for(e.advance();r;)switch(e.peek()){case 96:if(o=Ke(e,o),e.peek()===125){e.advance();let i=t.history.pop(),s;switch(i){case"attribute":if(e.peek()!==34)throw new Error(`Attribute interpolation expression must end with double quotes at ${e.formattedPosition}`);e.advance(),s="tag-body";break;case"text":s="text"}n={state:s,tokens:[{type:9,parts:[o]}],popState:!0},r=!1}else o=`${o}${e.currentChar.value}`;break;default:o=Ke(e,o)}return n}function Ke(e,t){return e.advance(),`${t}${e.currentChar.value}`}function qe(e,t){return e.advance(),e.skipSpaces(),e.peek()===96?{state:"interpolation-literal"}:{state:"interpolation-expression"}}function Xe(e,t){let r=!0,o;for(;r;)switch(e.peek()){case 64:o={state:"event"},r=!1;break;case 32:e.skipSpaces();break;case 62:case 47:o={state:"tag-open-end"},r=!1;break;default:o={state:"attribute"},r=!1}return o}function Qe(e,t){let r=!0,o="",n;for(e.advance(2),e.skipSpaces();r;)switch(e.peek()){case 62:e.advance(),n={state:"text",tokens:[{type:4,parts:[o]}]},r=!1;break;case 32:throw new Error("Tag Close Name cannot contains spaces");default:e.advance(),o=`${o}${e.currentChar.value}`}return n}function ze(e,t){let r;if(e.peek()===62)e.advance(),r={state:"text",tokens:[{type:3,parts:[]}]};else{e.advance();let o=e.peek();if(o===62)e.advance(),r={state:"text",tokens:[{type:2,parts:[]}]};else throw new Error(`Unexpected character ${o} for closing tag.
12
+ Expected />
13
+ Read of /${String.fromCharCode(o)} at ${e.formattedPosition}`)}return r}function je(e,t){let r=!0,o="",n;for(e.advance(),e.skipSpaces();r;)switch(e.peek()){case 32:case 47:case 62:n={state:"tag-body",tokens:[{type:1,parts:[o]}]},r=!1;break;default:e.advance(),o=`${o}${e.currentChar.value}`}return n}function Ye(e){return/\S/.test(e)}function Ze(e,t){let r=!0,o="",n;for(;r;)switch(e.peek()){case 60:n={state:e.peek(1,{offset:1})===47?"tag-close":"tag-open-name"},r=!1;break;case 123:n={state:"interpolation",pushState:!0},r=!1;break;case 64:n={state:"flow-control"},r=!1;break;case 125:t.history[t.history.length-1]==="flow-control-block"?(e.advance(),n={state:"text",tokens:[{type:20}],popState:!0},r=!1):(e.advance(),o=`${o}${e.currentChar.value}`);break;case 10:case 13:e.advance();break;default:e.advance(),o=`${o}${e.currentChar.value}`}return n.tokens??=Ye(o)?[{type:0,parts:[o]}]:void 0,n}var re=class{constructor(t){this.input=t}input;_currentChar={code:0,index:-1,value:""};get currentChar(){return this._currentChar}_peekCache=new Map;_position={row:0,column:0};get position(){return this._position}get formattedPosition(){return`[Ln ${this._position.row}, Col ${this._position.column}]`}advance(t=1){if(t<1)throw new Error(`${t} is not a valid value. Please enter a number equal or greater than 1`);let r=this._currentChar.index+t;r>=this.input.length?(this._currentChar.code=0,this._currentChar.index=-1,this._currentChar.value="",this.throwEOFError()):([10,13].includes(this._currentChar.code)?(this._position.row++,this._position.column=0):this._position.column++,this._currentChar.index=r,this._currentChar.value=this.input[r],this._currentChar.code=this.input.charCodeAt(r))}peekMatch(t,r){if(typeof t=="string"){let i=this.peek(t.length);for(let s=0;s<t.length;s++)if(i[s]!==t.charCodeAt(s))return!1;return!0}let o=this._currentChar.index+1,n=this.input.slice(o,o+r);return t.test(n)}peek(t,r){let o=this._peekCache,n=typeof t=="number"?t:1,i=(typeof t=="object"?t:r)?.offset??0;return n===1?this.peekOneChar(this._currentChar.index+i+1,o):this.peekMany(n+i,o)}skipSpaces(){for(;this.peek()===32||this.peek()===10||this.peek()===13;)this.advance()}peekMany(t,r){let o=new Array,n=this._currentChar.index+1;for(let i=n;i<n+t;i++)o.push(this.peekOneChar(i,r));return o}peekOneChar(t,r){if(r.has(t))return r.get(t);t>=this.input.length&&this.throwEOFError();let o=this.input.charCodeAt(t);return r.set(t,o),o}throwEOFError(){throw new Error("",{cause:0})}};var oe=class{constructor(t){this.input=t;this._cursor=new re(this.input)}input;_cursor;_state="text";_stack=new bt;_tokens=new Array;_states={text:Ze,"tag-open-name":je,"tag-body":Xe,"tag-open-end":ze,"tag-close":Qe,attribute:Fe,"attribute-value":we,event:Me,parameter:$e,"flow-control":Be,"flow-control-condition":Pe,"case-flow-control-condition":be,"flow-control-block":De,interpolation:qe,"interpolation-expression":He,"interpolation-literal":We,import:Ve,"import-path":Ge};tokenize(){let t=!1;for(;!t;)try{let r=this._states[this._state],{state:o,tokens:n,popState:i,pushState:s}=r(this._cursor,{history:this._stack.values,tokens:[...this._tokens]});n?.length&&this._tokens.push(...n),s&&this._stack.push(this._state),i&&this._stack.pop(),this._state=o}catch(r){if(r.cause===0)t=!0;else throw console.log(`Something went wrong while computing state ${this._state} at ${this._cursor.formattedPosition}`),r}return this._tokens}};var ne=class{constructor(t){this._tokens=t}_tokens;_currentToken={value:{type:23},index:-1};getCurrentToken(){return this._currentToken}advance(t=1){if(t<1)throw new Error(`${t} is not a valid value. Please enter a number equal or greater than 1`);let r=this._currentToken.index+t;r>=this._tokens.length?(this._currentToken.value={type:23},this._currentToken.index=-1):(this._currentToken.index=r,this._currentToken.value=this._tokens[r])}peek(t,r){let o=typeof t=="number"?t:1,n=(typeof t=="object"?t:r)?.offset??0;return o===1?this.peekOneToken(this._currentToken.index+n+1):this.peekMany(o+n)}peekMany(t){let r=new Array,o=this._currentToken.index+1;for(let n=o;n<o+t;n++)r.push(this.peekOneToken(n));return r}peekOneToken(t){return t<this._tokens.length?this._tokens[t]:{type:23}}};import{ScriptTarget as Pt,SyntaxKind as p,createSourceFile as $t,forEachChild as Mt}from"typescript";function y(e){let t="const x = ",n=$t("expression.ts",`${t}${e}`,Pt.ESNext,!0).statements[0].declarationList.declarations[0].initializer,i=new Array;if(Je(n,t.length,i),i.length)throw new Error(i.reduce((s,a)=>`${s}${a.message}
14
+ `,""));return{node:n}}function Je(e,t,r){if(!Bt(e))throw new Error(Dt(e));if(Mt(e,o=>Je(o,t,r)),r.length)throw new Error(r[0].message)}function Bt(e){switch(e.kind){case p.StringLiteral:case p.NumericLiteral:case p.BigIntLiteral:case p.TrueKeyword:case p.FalseKeyword:case p.NullKeyword:case p.UndefinedKeyword:case p.Identifier:case p.PropertyAccessExpression:case p.ElementAccessExpression:case p.CallExpression:case p.BinaryExpression:case p.EqualsEqualsToken:case p.EqualsEqualsEqualsToken:case p.ExclamationEqualsToken:case p.ExclamationEqualsEqualsToken:case p.LessThanToken:case p.LessThanEqualsToken:case p.GreaterThanToken:case p.GreaterThanEqualsToken:case p.PlusToken:case p.MinusToken:case p.AsteriskToken:case p.SlashToken:case p.PercentToken:case p.AsteriskAsteriskToken:case p.AmpersandAmpersandToken:case p.BarBarToken:case p.QuestionQuestionToken:case p.QuestionDotToken:case p.QuestionToken:case p.ColonToken:case p.AmpersandToken:case p.BarToken:case p.CaretToken:case p.LessThanLessThanToken:case p.GreaterThanGreaterThanToken:case p.GreaterThanGreaterThanGreaterThanToken:case p.InstanceOfKeyword:case p.InKeyword:case p.PrefixUnaryExpression:case p.PostfixUnaryExpression:case p.TypeOfExpression:case p.VoidExpression:case p.ConditionalExpression:case p.ParenthesizedExpression:case p.TemplateExpression:case p.NoSubstitutionTemplateLiteral:case p.TemplateHead:case p.TemplateMiddle:case p.TemplateTail:case p.TemplateSpan:case p.ArrayLiteralExpression:case p.ObjectLiteralExpression:case p.PropertyAssignment:case p.ShorthandPropertyAssignment:case p.SpreadAssignment:case p.SpreadElement:case p.TaggedTemplateExpression:case p.SyntaxList:return!0;default:return!1}}function Dt(e){switch(e.kind){case p.AwaitExpression:return"'await' is not allowed inside template expressions.";case p.YieldExpression:return"'yield' is not allowed inside template expressions.";case p.NewExpression:return"'new' is not allowed inside template expressions.";case p.ArrowFunction:case p.FunctionExpression:return"Function expressions are not allowed inside template expressions.";case p.BinaryExpression:return Gt(e.operatorToken.kind)?"Assignments are not allowed inside template expressions. Use @const to declare local template variables instead.":`'${p[e.kind]}' is not allowed inside template expressions.`;default:return`'${p[e.kind]}' is not allowed inside template expressions.`}}function Gt(e){return e>=p.FirstAssignment&&e<=p.LastAssignment}function K(e,t,r){return e.advance(),{type:2,expression:y(r.parts[0]).node}}function et(e,t,r){e.advance();let o=r.parts[0],n=e.peek();if(n.type===5||n.type===4||n.type===7)return{name:o,value:"true"};if(n.type===10||n.type===9)return{name:o,value:K(e,t,n)};if(n.type!==6)throw new Error(`[Parser] Attribute value missing for ${o} in: ${o}`);return e.advance(),{name:o,value:n.parts[0]}}function tt(e,t,r){e.advance();let o=r.parts[0],[n,i]=o.split("=");if(!n||!i)throw new Error(`[Parser] Invalid event format: ${o}`);let s=new Array;for(;e.peek().type===8;)e.advance(),s.push(y(e.getCurrentToken().value.parts[0]).node);return{name:n,handler:i.replace(/^[""]|[""]$/g,""),parameters:s}}function rt(e,t,r){e.advance();let o=r.parts[0],n=new Array,i=new Array,s=!0;for(;s;){let c=e.peek();switch(c.type){case 5:n.push(et(e,t,c));break;case 7:i.push(tt(e,t,c));break;default:s=!1}}if(e.peek().type===3&&e.advance(),e.peek().type===2)return e.advance(),{type:0,tagName:o,attributes:n,events:i,children:[]};let a=new Array;for(;!Ut(e,o);){let c=t();c&&a.push(c)}return e.advance(),{type:0,tagName:o,attributes:n,events:i,children:a}}function Ut(e,t){let r=e.peek();return r.type===4&&r.parts[0]===t}import{createSourceFile as Vt,isExpressionStatement as Ht,isIdentifier as Kt,ScriptTarget as Wt}from"typescript";function w(e,t){let r=new Array;for(;e.peek().type!==20;){let o=t();o&&r.push(o)}return e.advance(),r}function ot(e,t,r){e.advance();let o=e.peek();if(o.type!==18)throw new Error(`[Parser] Expected CONDITION after FOR, got ${u[o.type]}`);let n=qt(o.parts[0],0);e.advance(2);let i=w(e,t);return{type:6,...n,children:i}}function qt(e,t){let r=Qt(e);if(r.length<2)throw new Error('[Parser] @for requires at least "item of iterable; track expr".');let o=r[0].trim(),n=o.indexOf(" of ");if(n===-1)throw new Error('[Parser] @for expression must be in the form "item of iterable".');let i=o.slice(0,n).trim(),s=o.slice(n+4).trim();if(!nt(i))throw new Error(`[Parser] '${i}' is not a valid item alias.`);let a=y(s),c=r[1].trim();if(!c.startsWith("track "))throw new Error('[Parser] Second section of @for must start with "track".');let m=c.slice(6).trim(),l=y(m),E=new Map;if(r.length>=3&&r[2]!==void 0){let k=r[2].trim(),I=t+e.indexOf(r[2]);Xt(k,I,E)}return{itemAlias:i,iterableExpression:a.node,iterableSource:s,trackExpression:l.node,trackSource:m,implicitAliases:E}}function Xt(e,t,r){let o=e.split(","),n=0,i=new Set(["$index","$last","$first","$even","$odd"]);for(let s of o){let a=s.trim(),c=a.indexOf("=");if(c===-1)throw new Error(`[Parser] Invalid alias declaration '${a}'. Expected '$implicit = alias'.`);n+=s.length+1;let m=a.slice(0,c).trim(),l=a.slice(c+1).trim();if(!(k=>i.has(k))(l))throw new Error(`[Parser] '${l}' is not a known implicit variable. Known variables: ${[...i].join(", ")}.`);if(n+=s.length+1,!nt(m))throw new Error(`[Parser] '${m}' is not a valid alias identifier.`);if(n+=s.length+1,r.has(l))throw new Error(`[Parser] '${l}' is already aliased in this @for expression.`);r.set(l,m),n+=s.length+1}}function Qt(e){let t=new Array,r="",o=0,n;for(let i=0;i<e.length;i++){let s=e[i];if(!(!r&&s===" ")){if(n){r+=s,s===n&&e[i-1]!=="\\"&&(n=null);continue}if(s==='"'||s==="'"||s==="`"){n=s,r+=s;continue}if(s==="("||s==="["||s==="{"){o++,r+=s;continue}if(s===")"||s==="]"||s==="}"){o--,r+=s;continue}if(s===";"&&o===0){t.push(r),r="";continue}r+=s}}return r.trim().length&&t.push(r),t}function nt(e){if(!e.length)return!1;let r=Vt("__id.ts",e,Wt.ESNext,!1).statements[0];return!!r&&Ht(r)&&Kt(r.expression)&&r.expression.text===e}function it(e,t,r){return st(e,t,r)}function zt(e,t,r){switch(r.type){case 14:return st(e,t,r);case 13:e.advance(2);let o=w(e,t);return{type:4,children:o}}}function st(e,t,r){e.advance();let o=e.peek();if(o.type!==18)throw new Error(`[Parser] Expected CONDITION after ${u[r.type]}, got ${u[o.type]}`);e.advance(2);let n=o.parts[0],i=y(n),s=w(e,t);return{type:r.type===11?3:5,condition:n,conditionNode:i.node,children:s,alternate:zt(e,t,e.peek())}}function at(e,t,r){let o=new Array;for(;e.peek().type===21;){e.advance();let n=e.getCurrentToken().value.parts[0],i=jt(n);o.push(i)}return e.advance(),{type:9,specifiers:o,path:e.getCurrentToken().value.parts[0]}}function jt(e){let t=e.trim(),r=t.match(/^\*\s+as\s+([A-Za-z_$][\w$]*)$/);if(r)return{imported:"*",local:r[1]};let o=t.match(/^default\s+as\s+([A-Za-z_$][\w$]*)$/);if(o)return{imported:"default",local:o[1]};let n=t.match(/^([A-Za-z_$][\w$]*)(?:\s+as\s+([A-Za-z_$][\w$]*))?$/);if(n)return{imported:n[1],local:n[2]??n[1]};throw new Error(`[Parser] Invalid import specifier "${e}".`)}function pt(e,t,r){e.advance();let o=e.peek();if(o.type!==18)throw new Error(`[Parser] Expected CONDITION after SWITCH, got ${u[o.type]}`);let n=y(o.parts[0]).node;e.advance(2);let i=new Array;for(;e.peek().type!==20;)switch(e.peek().type){case 16:let a=new Array;do{e.advance();let c=e.peek();if(c.type!==18)throw new Error("[Parser] Expected CONDITION after CASE");a.push(c.parts[0]),e.advance()}while(e.peek().type!==19);e.advance(),i.push({type:8,condition:a,children:w(e,t)});break;case 17:e.advance(2),i.push({type:8,condition:null,children:w(e,t)});break}return e.advance(),{type:7,expression:n,children:i}}function ct(e,t,r){return e.advance(),{type:1,value:r.parts[0]}}var ie=class{_cursor;_states={0:ct,10:K,9:K,1:rt,11:it,12:ot,15:pt,21:at};constructor(t){this._cursor=new ne(t)}parse(){let t=new Array;for(;this._cursor.peek().type!==23;){let r=this.parseNode();r&&t.push(r)}return t}parseNode(){let t=this._cursor.peek();if(t.type===23)return;let r=this._states[t.type];if(!r)throw new Error(`[Parser] No transition function for token type ${u[t.type]}`);return r(this._cursor,this.parseNode.bind(this),t)}};import{indent as Er}from"@xaendar/common";var B=class extends x{_imports=new Array;addImport(t){this._imports.push(t)}getImportBySelector(t){return this._imports.find(r=>r.type==="component"&&r.selectors.includes(t))}};function mt(e,t,r){let o=new Array;if(er(e.tagName)){let n=r.getImportBySelector(e.tagName);if(!n)throw new Error(`[Type Checker] ${e.tagName} selector is not associated to any WebComponent imported in the template`);o.push(...Yt(e,n,r))}else e.attributes.forEach(({value:n})=>{typeof n!="string"&&o.push(`${d(n.expression,r,{resolver:"root"})};`)}),e.events.forEach(({handler:n,parameters:i})=>{let s=new x([],r);s.addUnresolvableIdentifier("$event");let a=i.map(c=>d(c,s,{resolver:"root"})).join(", ");o.push(`root.${n}(${a});`)});return e.children.forEach(n=>o.push(...t(n,r))),o}function Yt(e,t,r){let o=new Array;return e.attributes.forEach(({name:n,value:i})=>{let s=Zt(t,n);if(!s)throw new Error(`[Type Checker] Unknown property "${n}" on <${e.tagName}> (${t.className} has no @Property with this name or alias).`);if(typeof i=="string")return;let a=d(i.expression,r,{resolver:"root"});o.push(s.type?`(${a}) satisfies ${s.type};`:`${a};`)}),e.events.forEach(({name:n,handler:i,parameters:s})=>{let a=Jt(t,n);if(!a)throw new Error(`[Type Checker] Unknown event "${n}" on <${e.tagName}> (${t.className} has no @Event with this name).`);let c=new x([],r);c.addUnresolvableIdentifier("$event");let m=s.map(l=>d(l,c,{resolver:"root"})).join(", ");o.push("{"),o.push(` let $event!: ${a.detailType??"unknown"};`),o.push(` root.${i}(${m});`),o.push("}")}),o}function Zt(e,t){return e.properties.find(r=>(r.alias??r.name)===t)}function Jt(e,t){return e.events.find(r=>r.name===t)}function er(e){return/^[a-z][a-z0-9._\-]*-[a-z0-9._\-]*$/.test(e)}import{indent as tr}from"@xaendar/common";function lt(e,t,r){let o=new B([],r),n=W(e,"$index"),i=W(e,"$first"),s=W(e,"$last"),a=W(e,"$even"),c=W(e,"$odd");[n,i,s,a,c,e.itemAlias].forEach(l=>o.addUnresolvableIdentifier(l));let m=new Array;return m.push(`for (const ${e.itemAlias} of root.${e.iterableSource}) {`),m.push(...tr([`let ${n}!: number;`,`let ${i}!: boolean;`,`let ${s}!: boolean;`,`let ${a}!: boolean;`,`let ${c}!: boolean;`,`${d(e.trackExpression,r,{skipResolution:!0})};`,...e.children.flatMap(l=>t(l,o))])),m.push("}"),m}function W(e,t){return e.implicitAliases.get(t)??t}import{indent as Te}from"@xaendar/common";function ft(e,t,r){let o=new Array,n=d(e.conditionNode,r,{resolver:"root"});o.push(`if (${n}) {`),o.push(...Te(e.children.flatMap(s=>t(s,r)))),o.push("}");let i=e.alternate;for(;i?.type===5;){let s=d(i.conditionNode,r,{resolver:"root"});o.push(`else if (${s}) {`),o.push(...Te(i.children.flatMap(a=>t(a,r)))),o.push("}"),i=i.alternate}return i&&(o.push("else {"),o.push(...Te(i.children.flatMap(s=>t(s,r)))),o.push("}")),o}function dt(e,t,r){let o=e.path,n=ut(o),i=new Array;for(let s of e.specifiers){let{imported:a,local:c}=s;switch(a){case"*":i.push(`let ${c}!: typeof import('${n}');`);break;case"default":i.push(`let ${c}!: typeof import('${n}')['default'];`);break;default:let m=ut(a);i.push(`let ${c}!: typeof import('${n}')['${m}'];`);break}}return i}function ut(e){return e.replace(/\\/g,"\\\\").replace(/'/g,"\\'")}import{indent as Tt}from"@xaendar/common";function xt(e,t,r){let n=[`switch (${d(e.expression,r,{resolver:"root"})}) {`];return e.children.forEach(i=>{i.condition?.length?i.condition.forEach(s=>n.push(` case ${s}:`)):n.push(" default:"),n.push(...Tt(Tt([...i.children.flatMap(s=>t(s,r)),"break;"])))}),n.push("}"),n}function xe(e,t,r){return e.type===2?[`${d(e.expression,r,{resolver:"root"})};`]:[]}import{existsSync as he}from"fs";import{readFile as rr}from"fs/promises";import{resolve as or}from"path";import{createSourceFile as nr,forEachChild as ir,getNameOfDeclaration as ht,isAccessor as sr,isArrayLiteralExpression as ar,isCallExpression as q,isClassDeclaration as pr,isIdentifier as v,isObjectLiteralExpression as Et,isPropertyAccessExpression as Ct,isPropertyAssignment as kt,isStringLiteral as Ee,ScriptTarget as cr,SyntaxKind as Ce}from"typescript";async function Nt(e,t,r=process.cwd()){try{let o=mr(e,r);if(!o)return;let n=await rr(o,"utf8"),i=nr(o,n,cr.Latest,!0),s;return ir(i,a=>{if(!s&&pr(a)){let c=a.name?.text;if(c!==t)return;let m=a.modifiers??[],l=Array.from(m).find(A=>lr(A));if(!l)return;let E=dr(l);if(!E?.length)return;let k=new Array,I=new Array;a.members.forEach(A=>{if(!sr(A))return;let R=A.modifiers??[],X=Array.from(R).find(g=>fr(g));if(X){let g=ht(A),D=g&&v(g)?g.text:void 0;if(D){let G=xr(D,X);G&&k.push(G)}return}let Q=Array.from(R).find(g=>ur(g));if(Q){let g=ht(A),D=g&&v(g)?g.text:void 0;if(D){let G=hr(D,Q);G&&I.push(G)}}}),s={type:"component",className:c,selectors:E,properties:k,events:I}}}),s}catch(o){console.error(`Failed to extract component metadata from ${e}:`,o);return}}function mr(e,t){if(e.startsWith(".")){let r=or(t,e);if(he(`${r}.ts`))return r+".ts";if(he(`${r}/index.ts`))return`${r}/index.ts`;if(he(r))return r}}function lr(e){if(e.kind!==Ce.Decorator)return!1;let t=q(e.expression)?e.expression.expression:e.expression;return v(t)&&t.text==="WebComponent"}function fr(e){if(e.kind!==Ce.Decorator)return!1;let t=e.expression;return q(t)?v(t.expression)&&t.expression.text==="Property":Ct(t)?v(t.expression)&&t.expression.text==="Property"&&v(t.name)&&t.name.text==="required":v(t)&&t.text==="Property"}function ur(e){if(e.kind!==Ce.Decorator)return!1;let t=q(e.expression)?e.expression.expression:e.expression;return v(t)&&t.text==="Event"}function dr(e){try{let t=e.expression;if(!q(t))return[];let r=t.arguments;if(r.length===0)return[];let o=r[0];if(!o||!Et(o))return[];let n=Array.from(o.properties).find(i=>kt(i)&&v(i.name)&&i.name.text==="selector");return Tr(n.initializer)}catch{return[]}}function Tr(e){return Ee(e)?[e.text]:ar(e)?e.elements?.filter(t=>Ee(t)).map(t=>t.text):[]}function xr(e,t){let r={name:e,required:!1},o=t.expression;if(Ct(o)&&v(o.name)&&o.name.text==="required"&&(r.required=!0),q(o)){let n=o.arguments;if(n.length){let i=n[0];if(Et(i)){let s=i.properties?.find(a=>kt(a)&&v(a.name)&&a.name.text==="alias");s&&Ee(s.initializer)&&(r.alias=s.initializer.text)}}}return r}function hr(e,t){return{name:e}}var se=class{constructor(t){this._ast=t}_ast;_context=new B;_states={1:xe,2:xe,0:mt,3:ft,6:lt,7:xt,9:dt};async populateImportMetadata(t){let r=this._ast.filter(o=>o.type===9);await Promise.all(r.flatMap(o=>o.specifiers.filter(({imported:n})=>n!=="*").map(async({imported:n,local:i})=>{let s=n==="default"?i:n,a=await Nt(o.path,s,t);a&&this._context.addImport(a)})))}async generate(t){await this.populateImportMetadata(t);let r=this._ast.flatMap(o=>this._processNode(o,this._context));return["function typeCheck() {",...Er(r),"}"].join(`
15
+ `)}_processNode=(t,r)=>{let o=this._states[t.type];if(!o)throw new Error(`[Type Checker] No transition function for token type ${h[t.type]}`);return o(t,this._processNode,r)}};async function Ws(e,t,r){let o=new oe(e).tokenize(),n=new ie(o).parse();return{javascript:new z(n).generate(r),typescript:await new se(n).generate(t)}}export{Ws as compile};
package/package.json CHANGED
@@ -1,23 +1,20 @@
1
1
  {
2
2
  "name": "@xaendar/compiler",
3
- "version": "0.7.30",
3
+ "version": "0.7.32",
4
4
  "description": "A library for transpiling Xaendar Templates into JavaScript code",
5
- "sideEffects": false,
5
+ "author": "Kaitenjo",
6
+ "license": "MIT",
6
7
  "type": "module",
7
- "main": "./dist/xaendar-compiler.es.js",
8
- "module": "./dist/xaendar-compiler.es.js",
9
- "types": "./dist/xaendar-compiler.es.d.ts",
10
8
  "exports": {
11
9
  ".": {
12
- "import": {
13
- "types": "./dist/xaendar-compiler.es.d.ts",
14
- "default": "./dist/xaendar-compiler.es.js"
15
- }
10
+ "import": "./dist/compiler.js",
11
+ "require": "./dist/compiler.js"
16
12
  }
17
13
  },
14
+ "main": "./dist/compiler.js",
18
15
  "dependencies": {
19
- "@xaendar/common": "0.7.30",
20
- "@xaendar/types": "0.7.30",
16
+ "@xaendar/common": "0.7.32",
17
+ "@xaendar/types": "0.7.32",
21
18
  "typescript": "^6.0.3"
22
19
  }
23
20
  }
@@ -1,241 +0,0 @@
1
- /**
2
- * Compiles a template string into a Javascript render function body.
3
- *
4
- * Runs the three-stage pipeline:
5
- * 1. **Lexer** — tokenises the raw template text.
6
- * 2. **Parser** — transforms the token stream into an AST.
7
- * 3. **Render generator** — emits Javascript source lines from the AST.
8
- *
9
- * @param input - The raw HTML-like template source to compile.
10
- * @param cssVariableName - Optional name of the CSS variable to inject
11
- * into the generated `adoptedStyleSheets` assignment.
12
- * @returns A string containing the compiled Javascript render method body.
13
- */
14
- export declare function compile(input: string, cssVariableName?: string): {
15
- javascript: string;
16
- typescript: string;
17
- };
18
-
19
- /**
20
- * @fileoverview CompilerHost interface — the contract between the compiler and the environment it runs in.
21
- *
22
- * The compiler never accesses the filesystem, network, or any external resource directly.
23
- * All I/O is delegated to the CompilerHost, allowing the same compiler core to run in
24
- * different environments by swapping the host implementation:
25
- *
26
- * - **Node.js** (`build-tools`, `cli`) — reads and writes real files on disk
27
- * - **Editor** (`language-tools`) — reads live document content from the editor buffer,
28
- * which may differ from the file on disk when unsaved changes are present
29
- * - **Tests** — uses in-memory virtual files without touching the real filesystem
30
- *
31
- * @example
32
- * // Minimal Node.js implementation
33
- * import * as fs from 'node:fs';
34
- * import * as path from 'node:path';
35
- *
36
- * class NodeCompilerHost implements CompilerHost {
37
- * readFile(filePath: string) {
38
- * try { return fs.readFileSync(filePath, 'utf8'); }
39
- * catch { return undefined; }
40
- * }
41
- * fileExists(filePath: string) { return fs.existsSync(filePath); }
42
- * resolvePath(from: string, to: string) { return path.resolve(path.dirname(from), to); }
43
- * getDirectoryEntries(dirPath: string) { return fs.readdirSync(dirPath); }
44
- * isDirectory(filePath: string) { return fs.statSync(filePath).isDirectory(); }
45
- * getRealPath(filePath: string) { return fs.realpathSync(filePath); }
46
- * getCurrentDirectory() { return process.cwd(); }
47
- * }
48
- */
49
- /**
50
- * The contract between the compiler and the filesystem environment it runs in.
51
- *
52
- * The compiler uses this host for all I/O operations. It never accesses the filesystem,
53
- * the network, or any other external resource directly. This makes it possible to use
54
- * the same compiler in different environments:
55
- *
56
- * - **Node.js** (`build-tools`, `cli`) — reads and writes real files on disk
57
- * - **Editor** (`language-tools`) — reads live document content from open editor buffers,
58
- * which may differ from the file on disk when unsaved changes are present
59
- * - **Tests** — uses in-memory virtual files without touching the real filesystem
60
- *
61
- * Implementations should be **synchronous** wherever possible to ensure compatibility
62
- * with the TypeScript compiler host API, which does not support async operations
63
- * in its core methods.
64
- *
65
- * @example
66
- * // Typical usage — the compiler receives the host as a dependency
67
- * const host: CompilerHost = new NodeCompilerHost();
68
- * const compiler = new Compiler(host);
69
- * const result = compiler.compile('/src/app.component.html');
70
- */
71
- export declare interface CompilerHost {
72
- /**
73
- * Checks whether a file exists and can be read.
74
- *
75
- * Used by the compiler to:
76
- * - Verify that a template associated with a component exists before attempting
77
- * to read it (e.g. `app.component.html` paired with `app.component.ts`)
78
- * - Resolve optional imports
79
- * - Decide which resolution strategy to apply
80
- *
81
- * In environments with a virtual file system (such as `language-tools`),
82
- * this method must return `true` for virtual files that do not exist on disk,
83
- * such as Template Check Blocks (TCBs) generated in memory.
84
- *
85
- * @param filePath - Absolute path of the file whose existence to check.
86
- * @returns `true` if the file exists and is accessible, `false` otherwise.
87
- *
88
- * @example
89
- * const templatePath = host.resolvePath(componentPath, './app.component.html');
90
- * if (host.fileExists(templatePath)) {
91
- * const template = host.readFile(templatePath);
92
- * }
93
- */
94
- fileExists(filePath: string): boolean;
95
- /**
96
- * Returns the current working directory of the process.
97
- *
98
- * Used by the compiler as the base for resolving relative paths that have
99
- * no associated source file — for example, paths specified in the project
100
- * configuration or passed as CLI arguments.
101
- *
102
- * In an editor environment, this should return the root of the open workspace,
103
- * not the directory of the editor process itself.
104
- *
105
- * @returns The absolute path of the current working directory.
106
- *
107
- * @example
108
- * // Resolves a relative path from the project configuration
109
- * const configRelativePath = './src';
110
- * const absolutePath = host.resolvePath(
111
- * host.getCurrentDirectory() + '/placeholder',
112
- * configRelativePath
113
- * );
114
- */
115
- getCurrentDirectory(): string;
116
- /**
117
- * Returns the list of files and subdirectories inside a directory.
118
- *
119
- * Used by the compiler during the discovery phase — when it needs to find
120
- * all components in the project without them being explicitly listed, or
121
- * when it needs to resolve glob patterns in the project configuration.
122
- *
123
- * Returns only entry names, not absolute paths. The caller is responsible
124
- * for combining the results with `dirPath` via `resolvePath` to obtain
125
- * absolute paths.
126
- *
127
- * @param dirPath - Absolute path of the directory to read.
128
- * @returns An array of file and directory names inside `dirPath`.
129
- * Returns an empty array if the directory is empty or does not exist.
130
- *
131
- * @example
132
- * const entries = host.getDirectoryEntries('/src/components');
133
- * // → ['button', 'input', 'modal']
134
- *
135
- * const componentFiles = entries
136
- * .map(entry => host.resolvePath('/src/components', entry))
137
- * .filter(p => host.fileExists(p) && p.endsWith('.ts'));
138
- */
139
- getDirectoryEntries(dirPath: string): string[];
140
- /**
141
- * Resolves symlinks and returns the real physical path of a file.
142
- *
143
- * Used by the compiler to normalise paths before using them as keys in
144
- * internal caches. Two different paths pointing to the same physical file
145
- * (one through a symlink) must produce the same compiled output and must
146
- * not generate duplicates in the module graph.
147
- *
148
- * Particularly important in monorepos using workspace links (npm/yarn/pnpm),
149
- * where local packages are often symlinked inside `node_modules`.
150
- *
151
- * @param filePath - Absolute path, potentially containing symlinks.
152
- * @returns The real absolute path with all symlinks resolved.
153
- * If the path does not exist or cannot be resolved, returns `filePath` unchanged.
154
- *
155
- * @example
156
- * // In a pnpm monorepo:
157
- * // /app/node_modules/@my-lib/core → /packages/core/src
158
- * host.getRealPath('/app/node_modules/@my-lib/core/index.ts');
159
- * // → '/packages/core/src/index.ts'
160
- */
161
- getRealPath(filePath: string): string;
162
- /**
163
- * Checks whether the given path refers to a directory.
164
- *
165
- * Used together with `getDirectoryEntries` to distinguish files from
166
- * subdirectories when recursing through the filesystem. Also needed to
167
- * validate output paths before writing files.
168
- *
169
- * @param filePath - Absolute path to check.
170
- * @returns `true` if the path exists and is a directory, `false` in all
171
- * other cases (regular file, symlink to a file, non-existent path).
172
- *
173
- * @example
174
- * const entries = host.getDirectoryEntries('/src');
175
- * for (const entry of entries) {
176
- * const fullPath = host.resolvePath('/src', entry);
177
- * if (host.isDirectory(fullPath)) {
178
- * // recurse into subdirectory
179
- * }
180
- * }
181
- */
182
- isDirectory(filePath: string): boolean;
183
- /**
184
- * Reads the content of a file as a UTF-8 string.
185
- *
186
- * The compiler calls this method to read:
187
- * - Template files (`.html` files containing the custom DSL)
188
- * - TypeScript source files (`.ts`) when needed for analysis
189
- * - Project configuration files
190
- *
191
- * Returns `undefined` instead of throwing when the file does not exist or
192
- * cannot be read. The compiler handles the `undefined` case by emitting
193
- * an appropriate diagnostic.
194
- *
195
- * In an editor environment, this method must return the content currently
196
- * held in the **editor buffer**, not the content on disk. This ensures the
197
- * compiler always operates on the most up-to-date code, even when unsaved
198
- * changes are present.
199
- *
200
- * @param filePath - Absolute path of the file to read.
201
- * @returns The file content as a string, or `undefined` if the file does
202
- * not exist or cannot be read.
203
- *
204
- * @example
205
- * const content = host.readFile('/src/app.component.html');
206
- * if (content === undefined) {
207
- * // file not found — the compiler will emit a diagnostic
208
- * }
209
- */
210
- readFile(filePath: string): string | undefined;
211
- /**
212
- * Resolves a path relative to the source file that contains the reference.
213
- *
214
- * The compiler calls this method whenever it needs to turn a relative path
215
- * (such as `./app.component.html` inside a `@Component` decorator) into an
216
- * absolute path suitable for passing to `readFile` and `fileExists`.
217
- *
218
- * The default implementation should behave like
219
- * `path.resolve(path.dirname(from), to)` in Node.js, but can be overridden
220
- * to handle path aliases, `tsconfig.json` path mappings, or custom project
221
- * conventions.
222
- *
223
- * @param from - Absolute path of the source file that contains the reference.
224
- * Typically the `.ts` file of the component.
225
- * @param to - Relative or absolute path to resolve. May be relative
226
- * (`./template.html`), aliased (`@components/button.html`), or already absolute.
227
- * @returns The resolved absolute path of the target file.
228
- *
229
- * @example
230
- * // from: '/src/features/user/user.component.ts'
231
- * // to: './user.component.html'
232
- * // → '/src/features/user/user.component.html'
233
- * const templatePath = host.resolvePath(
234
- * '/src/features/user/user.component.ts',
235
- * './user.component.html'
236
- * );
237
- */
238
- resolvePath(from: string, to: string): string;
239
- }
240
-
241
- export { }