UNPKG

surfstar

Version:

A modern template engine for Bun, inspired by Handlebars and EJS, with a focus on simplicity and performance.

7 lines (6 loc) 8.18 kB
// @bun var m={eachStart:{begin:2,end:7,wordBegin:3},eachEnd:{end:7}};var g;((i)=>{i.LEXER_ERROR="LEXER_ERROR";i.PARSER_ERROR="PARSER_ERROR";i.RENDERER_ERROR="RENDERER_ERROR";i.FILE_ERROR="FILE_ERROR";i.COMPILATION_ERROR="COMPILATION_ERROR"})(g||={});class a extends Error{type;filePath;lineNumber;columnNumber;originalError;constructor(r){let{message:e,type:n,filePath:t,lineNumber:o,columnNumber:i,originalError:c}=r,u=e;if(t){if(u+=` in ${t}`,o!==void 0){if(u+=`:${o}`,i!==void 0)u+=`:${i}`}}super(u);if(this.name="SurfstarError",this.type=n,this.filePath=t,this.lineNumber=o,this.columnNumber=i,this.originalError=c,Error.captureStackTrace)Error.captureStackTrace(this,a)}static lexerError(r,e={}){return new a({message:r,type:"LEXER_ERROR",...e})}static parserError(r,e={}){return new a({message:r,type:"PARSER_ERROR",...e})}static rendererError(r,e={}){return new a({message:r,type:"RENDERER_ERROR",...e})}static fileError(r,e={}){return new a({message:r,type:"FILE_ERROR",...e})}static compilationError(r,e={}){return new a({message:r,type:"COMPILATION_ERROR",...e})}}function s(r,e){let{filePath:n,lineNumber:t,columnNumber:o,defaultMessage:i,errorFactory:c}=e;if(r instanceof a)throw r;throw c(r instanceof Error?r.message:i,{filePath:n,lineNumber:t,columnNumber:o,originalError:r instanceof Error?r:void 0})}function N(r,e){let n=[],t="",o=1,i=1;try{for(let c=0;c<r.length;c++){let u=r[c];if(u===` `)o++,i=1;else i++;if(_(u,r[c+1])){if(t=T(n,t,o,i-1),B(r,c)){try{let l=L(r,c);V(l,o,i,e),n.push(E("EACH_START",l,o,i));let p=f(r,c);y(p,o,i,e),c+=p}catch(l){s(l,{filePath:e,lineNumber:o,columnNumber:i,defaultMessage:"Invalid each block syntax",errorFactory:a.lexerError})}continue}if(v(r,c)){n.push(E("EACH_END","/each",o,i));let l=f(r,c);y(l,o,i,e),c+=l;continue}n.push(E("OPEN_BRACE","{{",o,i)),c=b(c);continue}if(O(u,r[c+1])){try{t=I(n,t,o,i-t.length),n.push(E("CLOSE_BRACE","}}",o,i)),c=b(c)}catch(l){s(l,{filePath:e,lineNumber:o,columnNumber:i,defaultMessage:"Invalid variable syntax",errorFactory:a.lexerError})}continue}t+=u}return T(n,t,o,i),S(n,e),n}catch(c){if(c instanceof a)throw c;throw a.lexerError("Error during tokenization",{filePath:e,originalError:c instanceof Error?c:void 0})}}function S(r,e){let n=0,t=0;for(let o of r){if(o.type==="OPEN_BRACE")n++;if(o.type==="CLOSE_BRACE"){if(n--,n<0)throw a.lexerError("Unmatched closing brace",{filePath:e,lineNumber:o.line,columnNumber:o.column})}if(o.type==="EACH_START")t++;if(o.type==="EACH_END"){if(t--,t<0)throw a.lexerError("Unmatched {{/each}} tag",{filePath:e,lineNumber:o.line,columnNumber:o.column})}}if(n>0){let o=r[r.length-1];throw a.lexerError("Unclosed braces in template",{filePath:e,lineNumber:o.line,columnNumber:o.column})}if(t>0){let o=r[r.length-1];throw a.lexerError("Unclosed {{#each}} block in template",{filePath:e,lineNumber:o.line,columnNumber:o.column})}}function _(r,e){return r==="{"&&e==="{"}function O(r,e){return r==="}"&&e==="}"}function B(r,e){return r[e+m.eachStart.begin]==="#"&&r.slice(e+m.eachStart.wordBegin,e+m.eachStart.end)==="each"}function v(r,e){return r[e+2]==="/"&&r.slice(e+3,e+7)==="each"}function L(r,e){return r.slice(e+m.eachEnd.end).split("}}")[0].trim()}function f(r,e){let n=r.slice(e).indexOf("}}");return n>=0?n+1:-1}function T(r,e,n,t){if(e)return r.push(E("TEXT",e,n,t-e.length+1)),"";return e}function I(r,e,n,t){if(e){let o=e.trim();if(!o)throw a.lexerError("Empty variable name",{lineNumber:n,columnNumber:t});return r.push(E("VARIABLE",o,n,t)),""}return e}function E(r,e,n,t){return{type:r,value:e,line:n,column:t}}function b(r){return r+1}function V(r,e,n,t){if(!r)throw a.lexerError("Each block is missing array name",{filePath:t,lineNumber:e,columnNumber:n})}function y(r,e,n,t){if(r<0)throw a.lexerError("Unclosed tag",{filePath:t,lineNumber:e,columnNumber:n})}function h(r,e){try{let n=F(),t="",o=0;while(o<r.length){let i=r[o];if(i.type==="TEXT")t+=i.value;else if(i.type==="VARIABLE")t=d(n,t),R(n,i.value);else if(i.type==="EACH_START"){t=d(n,t);try{let[c,u]=A(r,o,e);n.content.push(c),o=u}catch(c){s(c,{filePath:e,lineNumber:i.line,columnNumber:i.column,defaultMessage:"Error parsing each block",errorFactory:a.parserError})}}o++}return d(n,t),n}catch(n){s(n,{filePath:e,defaultMessage:"Error parsing template",errorFactory:a.parserError})}}function F(){return{type:"TEMPLATE",content:[]}}function d(r,e){if(!e)return e;let n=H(r,e);if(n){let t={type:"TEXT",content:n};r.content.push(t)}return""}function H(r,e){if(r.type==="EACH")return M(r,e);return e}function M(r,e){if(r.content.length===0)return $(e);return X(e)}function $(r){return r.replace(/^\s+/,"")}function X(r){return r.replace(/\n/g,` `)}function R(r,e){let n={type:"VARIABLE",name:e};r.content.push(n)}function A(r,e,n){let t=r[e],o=D(t.value),i="",c=e+1;while(c<r.length){let u=r[c];if(U(u))return z(o,i),[o,c];try{[i,c]=W(u,i,o,r,c,n)}catch(l){s(l,{filePath:n,lineNumber:u.line,columnNumber:u.column,defaultMessage:"Error processing token in each block",errorFactory:a.parserError})}c++}throw a.parserError("Unclosed each block",{filePath:n,lineNumber:t.line,columnNumber:t.column})}function D(r){return{type:"EACH",arrayName:r,content:[]}}function U(r){return r.type==="EACH_END"}function z(r,e){if(!e)return;let n=j(e);d(r,n)}function j(r){return r.includes(` `)?r:` `+r}function W(r,e,n,t,o,i){if(q(r))return G(e,r,o);return J(r,e,n,t,o,i)}function q(r){return r.type==="TEXT"}function G(r,e,n){return[r+e.value,n]}function J(r,e,n,t,o,i){return[K(r,e,n,t,o,i),Z(r)?o:o]}function K(r,e,n,t,o,i){if(e)d(n,e);if(Q(r))R(n,r.value);else if(Y(r))P(n,t,o,i);return""}function Q(r){return r.type==="VARIABLE"}function Y(r){return r.type==="EACH_START"}function Z(r){return r.type==="EACH_START"}function P(r,e,n,t){try{let[o,i]=A(e,n,t);r.content.push(o),n=i}catch(o){if(o instanceof a)throw o;let i=e[n];throw a.parserError("Error processing nested each block",{filePath:t,lineNumber:i.line,columnNumber:i.column,originalError:o instanceof Error?o:void 0})}}function k(r,e,n){try{return rr(r,n),r.content.map((t)=>x(t,e,n)).join("")}catch(t){return s(t,{filePath:n,defaultMessage:"Error rendering template",errorFactory:a.rendererError})}}function rr(r,e){if(r.type!=="TEMPLATE")throw a.rendererError(`Expected template node but got ${r.type}`,{filePath:e})}function x(r,e,n){try{switch(r.type){case"TEXT":return r.content;case"VARIABLE":return er(r,e,n);case"EACH":return nr(r,e,n);default:throw a.rendererError(`Unknown node type: ${r.type}`,{filePath:n})}}catch(t){return s(t,{filePath:n,defaultMessage:`Error rendering ${r.type} node`,errorFactory:a.rendererError})}}function er(r,e,n){if(r.type!=="VARIABLE")throw a.rendererError(`Expected variable node but got ${r.type}`,{filePath:n});try{let t=r.name.split("."),o=C(e,t);return o!==void 0&&o!==null?String(o):""}catch(t){return s(t,{filePath:n,defaultMessage:`Error accessing variable '${r.name}'`,errorFactory:a.rendererError})}}function C(r,e){try{return e.reduce((n,t)=>{if(n===void 0||n===null)return;return n[t]},r)}catch(n){return}}function nr(r,e,n){if(r.type!=="EACH")throw a.rendererError(`Expected each node but got ${r.type}`,{filePath:n});try{let t=C(e,r.arrayName.split("."));if(!tr(t,r.arrayName,n))return"";return t.map((i,c)=>{let u={...e,this:i,"@index":c};return r.content.map((l)=>x(l,u,n)).join("")}).join("")}catch(t){return s(t,{filePath:n,defaultMessage:`Error rendering each block for '${r.arrayName}'`,errorFactory:a.rendererError})}}function tr(r,e,n){if(r===void 0)throw a.rendererError(`Cannot find array '${e}' in template data`,{filePath:n});if(!Array.isArray(r))throw a.rendererError(`Expected '${e}' to be an array, but got ${typeof r}`,{filePath:n});return!0}import{existsSync as or}from"fs";async function w(r){try{return ir(r),await Bun.file(r).text()}catch(e){s(e,{filePath:r,defaultMessage:`Error loading file: ${r}`,errorFactory:a.fileError})}}function ir(r){if(!or(r))throw a.fileError(`File not found: ${r}`,{filePath:r})}async function ar(r,e){try{let n=await w(r),t=N(n,r),o=h(t,r);return k(o,e,r)}catch(n){s(n,{filePath:r,defaultMessage:"Error compiling template",errorFactory:a.compilationError})}}export{ar as compileTemplate,g as SurfstarErrorType,a as SurfstarError};