sommark 5.0.3 → 5.0.4
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/core/evaluator.js +37 -10
- package/core/evaluator.stub.js +1 -0
- package/core/helpers/lib.js +1 -1
- package/core/modules.js +64 -4
- package/core/parser.js +5 -2
- package/core/transpiler.js +81 -82
- package/dist/sommark.browser.js +188 -97
- package/dist/sommark.browser.lite.js +150 -86
- package/dist/sommark.parser.js +5 -2
- package/index.shared.js +2 -1
- package/package.json +1 -1
package/dist/sommark.browser.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
|
+
|
|
1
3
|
let _lazyMatch = () => { var __lib__=(()=>{var m=Object.defineProperty,V=Object.getOwnPropertyDescriptor,G=Object.getOwnPropertyNames,T=Object.prototype.hasOwnProperty,q=(r,e)=>{for(var n in e)m(r,n,{get:e[n],enumerable:true});},H=(r,e,n,a)=>{if(e&&typeof e=="object"||typeof e=="function")for(let t of G(e))!T.call(r,t)&&t!==n&&m(r,t,{get:()=>e[t],enumerable:!(a=V(e,t))||a.enumerable});return r},J=r=>H(m({},"__esModule",{value:true}),r),w={};q(w,{default:()=>re});var A=r=>Array.isArray(r),d=r=>typeof r=="function",Q=r=>r.length===0,W=r=>typeof r=="number",K=r=>typeof r=="object"&&r!==null,X=r=>r instanceof RegExp,b=r=>typeof r=="string",h=r=>r===void 0,Y=r=>{const e=new Map;return n=>{const a=e.get(n);if(a)return a;const t=r(n);return e.set(n,t),t}},rr=(r,e,n={})=>{const a={cache:{},input:r,index:0,indexMax:0,options:n,output:[]};if(v(e)(a)&&a.index===r.length)return a.output;throw new Error(`Failed to parse at index ${a.indexMax}`)},i=(r,e)=>A(r)?er(r,e):b(r)?ar(r,e):nr(r,e),er=(r,e)=>{const n={};for(const a of r){if(a.length!==1)throw new Error(`Invalid character: "${a}"`);const t=a.charCodeAt(0);n[t]=true;}return a=>{const t=a.index,o=a.input;for(;a.index<o.length&&o.charCodeAt(a.index)in n;)a.index+=1;const u=a.index;if(u>t){if(!h(e)&&!a.options.silent){const s=a.input.slice(t,u),c=d(e)?e(s,o,String(t)):e;h(c)||a.output.push(c);}a.indexMax=Math.max(a.indexMax,a.index);}return true}},nr=(r,e)=>{const n=r.source,a=r.flags.replace(/y|$/,"y"),t=new RegExp(n,a);return g(o=>{t.lastIndex=o.index;const u=t.exec(o.input);if(u){if(!h(e)&&!o.options.silent){const s=d(e)?e(...u,o.input,String(o.index)):e;h(s)||o.output.push(s);}return o.index+=u[0].length,o.indexMax=Math.max(o.indexMax,o.index),true}else return false})},ar=(r,e)=>n=>{if(n.input.startsWith(r,n.index)){if(!h(e)&&!n.options.silent){const t=d(e)?e(r,n.input,String(n.index)):e;h(t)||n.output.push(t);}return n.index+=r.length,n.indexMax=Math.max(n.indexMax,n.index),true}else return false},C=(r,e,n,a)=>{const t=v(r);return g(_(M(o=>{let u=0;for(;u<n;){const s=o.index;if(!t(o)||(u+=1,o.index===s))break}return u>=e})))},tr=(r,e)=>C(r,0,1),f=(r,e)=>C(r,0,1/0),x=(r,e)=>{const n=r.map(v);return g(_(M(a=>{for(let t=0,o=n.length;t<o;t++)if(!n[t](a))return false;return true})))},l=(r,e)=>{const n=r.map(v);return g(_(a=>{for(let t=0,o=n.length;t<o;t++)if(n[t](a))return true;return false}))},M=(r,e=false)=>{const n=v(r);return a=>{const t=a.index,o=a.output.length,u=n(a);return (!u||e)&&(a.index=t,a.output.length!==o&&(a.output.length=o)),u}},_=(r,e)=>{const n=v(r);return n},g=(()=>{let r=0;return e=>{const n=v(e),a=r+=1;return t=>{var o;if(t.options.memoization===false)return n(t);const u=t.index,s=(o=t.cache)[a]||(o[a]=new Map),c=s.get(u);if(c===false)return false;if(W(c))return t.index=c,true;if(c)return t.index=c.index,c.output?.length&&t.output.push(...c.output),true;{const Z=t.output.length;if(n(t)){const D=t.index,U=t.output.length;if(U>Z){const ee=t.output.slice(Z,U);s.set(u,{index:D,output:ee});}else s.set(u,D);return true}else return s.set(u,false),false}}}})(),E=r=>{let e;return n=>(e||(e=v(r())),e(n))},v=Y(r=>{if(d(r))return Q(r)?E(r):r;if(b(r)||X(r))return i(r);if(A(r))return x(r);if(K(r))return l(Object.values(r));throw new Error("Invalid rule")}),P="abcdefghijklmnopqrstuvwxyz",ir=r=>{let e="";for(;r>0;){const n=(r-1)%26;e=P[n]+e,r=Math.floor((r-1)/26);}return e},O=r=>{let e=0;for(let n=0,a=r.length;n<a;n++)e=e*26+P.indexOf(r[n])+1;return e},S=(r,e)=>{if(e<r)return S(e,r);const n=[];for(;r<=e;)n.push(r++);return n},or=(r,e,n)=>S(r,e).map(a=>String(a).padStart(n,"0")),R=(r,e)=>S(O(r),O(e)).map(ir),p=r=>r,z=r=>ur(e=>rr(e,r,{memoization:false}).join("")),ur=r=>{const e={};return n=>e[n]??(e[n]=r(n))},sr=i(/^\*\*\/\*$/,".*"),cr=i(/^\*\*\/(\*)?([ a-zA-Z0-9._-]+)$/,(r,e,n)=>`.*${e?"":"(?:^|/)"}${n.replaceAll(".","\\.")}`),lr=i(/^\*\*\/(\*)?([ a-zA-Z0-9._-]*)\{([ a-zA-Z0-9._-]+(?:,[ a-zA-Z0-9._-]+)*)\}$/,(r,e,n,a)=>`.*${e?"":"(?:^|/)"}${n.replaceAll(".","\\.")}(?:${a.replaceAll(",","|").replaceAll(".","\\.")})`),y=i(/\\./,p),pr=i(/[$.*+?^(){}[\]\|]/,r=>`\\${r}`),vr=i(/./,p),hr=i(/^(?:!!)*!(.*)$/,(r,e)=>`(?!^${L(e)}$).*?`),dr=i(/^(!!)+/,""),fr=l([hr,dr]),xr=i(/\/(\*\*\/)+/,"(?:/.+/|/)"),gr=i(/^(\*\*\/)+/,"(?:^|.*/)"),mr=i(/\/(\*\*)$/,"(?:/.*|$)"),_r=i(/\*\*/,".*"),j=l([xr,gr,mr,_r]),Sr=i(/\*\/(?!\*\*\/)/,"[^/]*/"),yr=i(/\*/,"[^/]*"),N=l([Sr,yr]),k=i("?","[^/]"),$r=i("[",p),wr=i("]",p),Ar=i(/[!^]/,"^/"),br=i(/[a-z]-[a-z]|[0-9]-[0-9]/i,p),Cr=i(/[$.*+?^(){}[\|]/,r=>`\\${r}`),Mr=i(/[^\]]/,p),Er=l([y,Cr,br,Mr]),B=x([$r,tr(Ar),f(Er),wr]),Pr=i("{","(?:"),Or=i("}",")"),Rr=i(/(\d+)\.\.(\d+)/,(r,e,n)=>or(+e,+n,Math.min(e.length,n.length)).join("|")),zr=i(/([a-z]+)\.\.([a-z]+)/,(r,e,n)=>R(e,n).join("|")),jr=i(/([A-Z]+)\.\.([A-Z]+)/,(r,e,n)=>R(e.toLowerCase(),n.toLowerCase()).join("|").toUpperCase()),Nr=l([Rr,zr,jr]),I=x([Pr,Nr,Or]),kr=i("{","(?:"),Br=i("}",")"),Ir=i(",","|"),Fr=i(/[$.*+?^(){[\]\|]/,r=>`\\${r}`),Lr=i(/[^}]/,p),Zr=E(()=>F),Dr=l([j,N,k,B,I,Zr,y,Fr,Ir,Lr]),F=x([kr,f(Dr),Br]),Ur=f(l([sr,cr,lr,fr,j,N,k,B,I,F,y,pr,vr])),Vr=Ur,Gr=z(Vr),L=Gr,Tr=i(/\\./,p),qr=i(/./,p),Hr=i(/\*\*\*+/,"*"),Jr=i(/([^/{[(!])\*\*/,(r,e)=>`${e}*`),Qr=i(/(^|.)\*\*(?=[^*/)\]}])/,(r,e)=>`${e}*`),Wr=f(l([Tr,Hr,Jr,Qr,qr])),Kr=Wr,Xr=z(Kr),Yr=Xr,$=(r,e)=>{const n=Array.isArray(r)?r:[r];if(!n.length)return false;const a=n.map($.compile),t=n.every(s=>/(\/(?:\*\*)?|\[\/\])$/.test(s)),o=e.replace(/[\\\/]+/g,"/").replace(/\/$/,t?"/":"");return a.some(s=>s.test(o))};$.compile=r=>new RegExp(`^${L(Yr(r))}$`,"s");var re=$;return J(w)})();
|
|
2
4
|
return __lib__.default || __lib__; };
|
|
3
5
|
let _match;
|
|
@@ -1786,7 +1788,9 @@ function parseValue(tokens, i, placeholders = {}, variables = {}, allowLogic = t
|
|
|
1786
1788
|
}
|
|
1787
1789
|
variables.__consumed__.add(vKey);
|
|
1788
1790
|
} else {
|
|
1789
|
-
|
|
1791
|
+
// Encode fallback in the envelope key so resolveAstVariables can apply it
|
|
1792
|
+
// at instantiation time instead of baking it in now.
|
|
1793
|
+
val = getPrefixValue('v', vFallback !== undefined ? `${vKey}|${vFallback}` : vKey);
|
|
1790
1794
|
}
|
|
1791
1795
|
return [val, i, false];
|
|
1792
1796
|
} else if (current_token(tokens, i).type === TOKEN_TYPES.PREFIX_P) {
|
|
@@ -2180,7 +2184,8 @@ function parseText(tokens, i, placeholders = {}, variables = {}, depth = 0, opti
|
|
|
2180
2184
|
}
|
|
2181
2185
|
variables.__consumed__.add(tvKey);
|
|
2182
2186
|
} else {
|
|
2183
|
-
|
|
2187
|
+
// Encode fallback in envelope so resolveAstVariables can apply it later.
|
|
2188
|
+
textNode.text += getPrefixValue('v', tvFallback !== undefined ? `${tvKey}|${tvFallback}` : tvKey);
|
|
2184
2189
|
}
|
|
2185
2190
|
} else {
|
|
2186
2191
|
break;
|
|
@@ -8622,7 +8627,7 @@ function registerHostSettings(settings) {
|
|
|
8622
8627
|
hostSettings = settings || {};
|
|
8623
8628
|
}
|
|
8624
8629
|
|
|
8625
|
-
const version = "5.0.
|
|
8630
|
+
const version = "5.0.4";
|
|
8626
8631
|
|
|
8627
8632
|
const SomMark$1 = {
|
|
8628
8633
|
version,
|
|
@@ -8673,6 +8678,17 @@ const SomMark$1 = {
|
|
|
8673
8678
|
// Freeze the entire Standard Library to make it completely immutable and tamper-proof
|
|
8674
8679
|
Object.freeze(SomMark$1);
|
|
8675
8680
|
|
|
8681
|
+
// Each transpile() call gets its own isolated EvaluatorState stack via async context.
|
|
8682
|
+
const evaluatorStorage = new AsyncLocalStorage();
|
|
8683
|
+
|
|
8684
|
+
/**
|
|
8685
|
+
* Runs fn inside an isolated evaluator context.
|
|
8686
|
+
* Concurrent transpile() calls each get their own stack — no cross-contamination.
|
|
8687
|
+
*/
|
|
8688
|
+
function withEvaluator(fn) {
|
|
8689
|
+
return evaluatorStorage.run([], fn);
|
|
8690
|
+
}
|
|
8691
|
+
|
|
8676
8692
|
// Global tracker to ensure deep recursive Smark compilation never exceeds safe boundaries
|
|
8677
8693
|
let globalCompilationDepth = 0;
|
|
8678
8694
|
|
|
@@ -9399,8 +9415,10 @@ class EvaluatorState {
|
|
|
9399
9415
|
this.expose(vars);
|
|
9400
9416
|
}
|
|
9401
9417
|
|
|
9402
|
-
async execute(code) {
|
|
9418
|
+
async execute(code, baseDir = null) {
|
|
9403
9419
|
if (!this.context) throw new Error("Evaluator not initialized");
|
|
9420
|
+
const prevBaseDir = this.baseDir;
|
|
9421
|
+
if (baseDir) this.baseDir = baseDir;
|
|
9404
9422
|
|
|
9405
9423
|
const timeout = this.security?.timeout ?? 5000;
|
|
9406
9424
|
this.deadline = Date.now() + timeout;
|
|
@@ -9634,6 +9652,7 @@ class EvaluatorState {
|
|
|
9634
9652
|
} finally {
|
|
9635
9653
|
this.deadline = 0;
|
|
9636
9654
|
clearInterval(interval);
|
|
9655
|
+
if (baseDir) this.baseDir = prevBaseDir;
|
|
9637
9656
|
}
|
|
9638
9657
|
}
|
|
9639
9658
|
|
|
@@ -9670,30 +9689,42 @@ class EvaluatorState {
|
|
|
9670
9689
|
|
|
9671
9690
|
class Evaluator {
|
|
9672
9691
|
constructor() {
|
|
9673
|
-
|
|
9692
|
+
// Fallback stack for callers that use init() outside withEvaluator() (e.g. tests).
|
|
9693
|
+
this._fallbackStack = [];
|
|
9674
9694
|
}
|
|
9675
9695
|
|
|
9696
|
+
_getStack() {
|
|
9697
|
+
return evaluatorStorage.getStore() ?? this._fallbackStack;
|
|
9698
|
+
}
|
|
9699
|
+
|
|
9700
|
+
// Expose the active stack so tests can check .instances.length
|
|
9701
|
+
get instances() { return this._getStack(); }
|
|
9702
|
+
|
|
9676
9703
|
setDefaultFs(fs) {
|
|
9677
9704
|
defaultFs$1 = fs;
|
|
9678
9705
|
}
|
|
9679
9706
|
|
|
9680
9707
|
get active() {
|
|
9681
|
-
|
|
9708
|
+
const stack = this._getStack();
|
|
9709
|
+
if (stack.length === 0) {
|
|
9682
9710
|
throw new Error("No active EvaluatorState instance. Did you call init()?");
|
|
9683
9711
|
}
|
|
9684
|
-
return
|
|
9712
|
+
return stack[stack.length - 1];
|
|
9685
9713
|
}
|
|
9686
9714
|
|
|
9715
|
+
// Forward .runtime to the active state so tests can assert on it
|
|
9716
|
+
get runtime() { return this.active?.runtime ?? null; }
|
|
9717
|
+
|
|
9687
9718
|
async init(baseDir = null, security = {}, settings = {}, mapperFile = null) {
|
|
9688
9719
|
const state = new EvaluatorState();
|
|
9689
9720
|
await state.init(baseDir, security, settings, mapperFile);
|
|
9690
|
-
this.
|
|
9721
|
+
this._getStack().push(state);
|
|
9691
9722
|
}
|
|
9692
9723
|
|
|
9693
9724
|
destroy() {
|
|
9694
|
-
|
|
9695
|
-
|
|
9696
|
-
|
|
9725
|
+
const stack = this._getStack();
|
|
9726
|
+
if (stack.length > 0) {
|
|
9727
|
+
stack.pop().destroy();
|
|
9697
9728
|
}
|
|
9698
9729
|
}
|
|
9699
9730
|
|
|
@@ -9709,8 +9740,8 @@ class Evaluator {
|
|
|
9709
9740
|
this.active.inject(vars);
|
|
9710
9741
|
}
|
|
9711
9742
|
|
|
9712
|
-
async execute(code) {
|
|
9713
|
-
return await this.active.execute(code);
|
|
9743
|
+
async execute(code, baseDir = null) {
|
|
9744
|
+
return await this.active.execute(code, baseDir);
|
|
9714
9745
|
}
|
|
9715
9746
|
|
|
9716
9747
|
hasDynamicTag(id) {
|
|
@@ -10075,7 +10106,7 @@ async function generateOutput(ast, i, format, mapper_file, security = {}, parent
|
|
|
10075
10106
|
|
|
10076
10107
|
if (node.type === STATIC_LOGIC) {
|
|
10077
10108
|
try {
|
|
10078
|
-
const result = await Evaluator$1.execute(node.code);
|
|
10109
|
+
const result = await Evaluator$1.execute(node.code, node.baseDir || null);
|
|
10079
10110
|
if (generateRuntimeOutput) return "";
|
|
10080
10111
|
if (result && typeof result === "object" && result.__raw !== undefined) {
|
|
10081
10112
|
if (security?.allowRaw === false) {
|
|
@@ -10281,7 +10312,7 @@ async function generateOutput(ast, i, format, mapper_file, security = {}, parent
|
|
|
10281
10312
|
}
|
|
10282
10313
|
} else if (child.type === STATIC_LOGIC) {
|
|
10283
10314
|
try {
|
|
10284
|
-
const val = await Evaluator$1.execute(child.code);
|
|
10315
|
+
const val = await Evaluator$1.execute(child.code, child.baseDir || null);
|
|
10285
10316
|
if (val !== undefined && typeof val !== "object") richText += String(val);
|
|
10286
10317
|
} catch (err) {
|
|
10287
10318
|
transpilerError([
|
|
@@ -10398,7 +10429,7 @@ async function generateOutput(ast, i, format, mapper_file, security = {}, parent
|
|
|
10398
10429
|
|
|
10399
10430
|
case STATIC_LOGIC:
|
|
10400
10431
|
try {
|
|
10401
|
-
const result = await Evaluator$1.execute(body_node.code);
|
|
10432
|
+
const result = await Evaluator$1.execute(body_node.code, body_node.baseDir || null);
|
|
10402
10433
|
if (result && typeof result === "object" && result.__raw !== undefined) {
|
|
10403
10434
|
if (security?.allowRaw === false) {
|
|
10404
10435
|
bodyOutput = mapper_file ? mapper_file.text(String(result.__raw)) : String(result.__raw);
|
|
@@ -10512,109 +10543,108 @@ async function transpiler(optionsOrAst, format, mapperFile) {
|
|
|
10512
10543
|
})();
|
|
10513
10544
|
|
|
10514
10545
|
const dualOutput = optionsOrAst?.dualOutput || false;
|
|
10515
|
-
|
|
10516
|
-
// Initialize Logic Sandbox
|
|
10517
|
-
await Evaluator$1.init(fileBaseDir, security, settings, targetMapper);
|
|
10518
|
-
// Inject global data
|
|
10519
10546
|
const placeholders = optionsOrAst?.placeholders || settings?.placeholders || {};
|
|
10520
10547
|
const variables = optionsOrAst?.variables || settings?.variables || {};
|
|
10521
10548
|
warnDroppedVariables(variables);
|
|
10522
|
-
Evaluator$1.inject(placeholders);
|
|
10523
|
-
Evaluator$1.inject(variables);
|
|
10524
10549
|
|
|
10525
|
-
|
|
10526
|
-
|
|
10527
|
-
|
|
10550
|
+
return withEvaluator(async () => {
|
|
10551
|
+
// Initialize Logic Sandbox inside isolated async context
|
|
10552
|
+
await Evaluator$1.init(fileBaseDir, security, settings, targetMapper);
|
|
10553
|
+
Evaluator$1.inject(placeholders);
|
|
10554
|
+
Evaluator$1.inject(variables);
|
|
10528
10555
|
|
|
10529
|
-
|
|
10530
|
-
|
|
10556
|
+
let output = "";
|
|
10557
|
+
let prev_body_node = null;
|
|
10558
|
+
let prev_was_silent = false;
|
|
10531
10559
|
|
|
10532
|
-
|
|
10533
|
-
|
|
10534
|
-
|
|
10535
|
-
|
|
10536
|
-
|
|
10537
|
-
|
|
10538
|
-
let
|
|
10539
|
-
|
|
10540
|
-
|
|
10541
|
-
|
|
10542
|
-
prev_was_silent =
|
|
10543
|
-
|
|
10544
|
-
|
|
10545
|
-
|
|
10546
|
-
|
|
10547
|
-
|
|
10560
|
+
if (dualOutput) {
|
|
10561
|
+
const idState = { mode: 'record', ids: [], idx: 0 };
|
|
10562
|
+
|
|
10563
|
+
// HTML pass — generate HTML, record element IDs for runtime blocks
|
|
10564
|
+
let htmlOutput = "";
|
|
10565
|
+
try {
|
|
10566
|
+
for (let i = 0; i < body.length; i++) {
|
|
10567
|
+
const node = body[i];
|
|
10568
|
+
const blockOutput = await generateOutput(body, i, targetFormat, targetMapper, security, null, false, true, instance, idState);
|
|
10569
|
+
let finalBlockOutput = blockOutput;
|
|
10570
|
+
if (prev_was_silent && node.type === TEXT$1) finalBlockOutput = finalBlockOutput.replace(/^\n/, "");
|
|
10571
|
+
if (finalBlockOutput) {
|
|
10572
|
+
htmlOutput += finalBlockOutput;
|
|
10573
|
+
prev_was_silent = false;
|
|
10574
|
+
} else {
|
|
10575
|
+
prev_was_silent = true;
|
|
10576
|
+
if ((node.type === COMMENT || node.type === COMMENT_BLOCK) && targetMapper?.options?.removeComments) {
|
|
10577
|
+
const nextNode = body[i + 1];
|
|
10578
|
+
if (nextNode && nextNode.type === TEXT$1 && (nextNode.text === "\n" || nextNode.text === "\r\n")) i++;
|
|
10579
|
+
}
|
|
10548
10580
|
}
|
|
10549
10581
|
}
|
|
10582
|
+
} finally {
|
|
10583
|
+
Evaluator$1.destroy();
|
|
10550
10584
|
}
|
|
10551
|
-
} finally {
|
|
10552
|
-
Evaluator$1.destroy();
|
|
10553
|
-
}
|
|
10554
10585
|
|
|
10555
|
-
|
|
10556
|
-
|
|
10557
|
-
|
|
10558
|
-
|
|
10586
|
+
// JS pass — replay the same IDs so querySelector targets match HTML
|
|
10587
|
+
idState.mode = 'replay';
|
|
10588
|
+
idState.idx = 0;
|
|
10589
|
+
prev_was_silent = false;
|
|
10559
10590
|
|
|
10560
|
-
|
|
10561
|
-
|
|
10562
|
-
|
|
10591
|
+
await Evaluator$1.init(fileBaseDir, security, settings, targetMapper);
|
|
10592
|
+
Evaluator$1.inject(placeholders);
|
|
10593
|
+
Evaluator$1.inject(variables);
|
|
10594
|
+
|
|
10595
|
+
let jsOutput = "";
|
|
10596
|
+
try {
|
|
10597
|
+
for (let i = 0; i < body.length; i++) {
|
|
10598
|
+
const node = body[i];
|
|
10599
|
+
const blockOutput = await generateOutput(body, i, targetFormat, targetMapper, security, null, true, false, instance, idState);
|
|
10600
|
+
let finalBlockOutput = blockOutput;
|
|
10601
|
+
if (prev_was_silent && node.type === TEXT$1) finalBlockOutput = finalBlockOutput.replace(/^\n/, "");
|
|
10602
|
+
if (finalBlockOutput) {
|
|
10603
|
+
jsOutput += finalBlockOutput;
|
|
10604
|
+
prev_was_silent = false;
|
|
10605
|
+
} else {
|
|
10606
|
+
prev_was_silent = true;
|
|
10607
|
+
}
|
|
10608
|
+
}
|
|
10609
|
+
} finally {
|
|
10610
|
+
Evaluator$1.destroy();
|
|
10611
|
+
}
|
|
10612
|
+
|
|
10613
|
+
return [htmlOutput.trim(), jsOutput.trim()];
|
|
10614
|
+
}
|
|
10563
10615
|
|
|
10564
|
-
let jsOutput = "";
|
|
10565
10616
|
try {
|
|
10566
10617
|
for (let i = 0; i < body.length; i++) {
|
|
10567
10618
|
const node = body[i];
|
|
10568
|
-
const blockOutput = await generateOutput(body, i, targetFormat, targetMapper, security, null,
|
|
10619
|
+
const blockOutput = await generateOutput(body, i, targetFormat, targetMapper, security, null, false, false, instance);
|
|
10620
|
+
|
|
10569
10621
|
let finalBlockOutput = blockOutput;
|
|
10570
|
-
if (prev_was_silent && node.type === TEXT$1)
|
|
10622
|
+
if (prev_was_silent && node.type === TEXT$1) {
|
|
10623
|
+
finalBlockOutput = finalBlockOutput.replace(/^\n/, "");
|
|
10624
|
+
}
|
|
10625
|
+
|
|
10571
10626
|
if (finalBlockOutput) {
|
|
10572
|
-
|
|
10627
|
+
output += finalBlockOutput;
|
|
10573
10628
|
prev_was_silent = false;
|
|
10629
|
+
if (node.type !== TEXT$1 || node.text.trim().length > 0) {
|
|
10630
|
+
prev_body_node = node;
|
|
10631
|
+
}
|
|
10574
10632
|
} else {
|
|
10575
10633
|
prev_was_silent = true;
|
|
10634
|
+
if ((node.type === COMMENT || node.type === COMMENT_BLOCK) && targetMapper?.options?.removeComments) {
|
|
10635
|
+
const nextNode = body[i + 1];
|
|
10636
|
+
if (nextNode && nextNode.type === TEXT$1 && (nextNode.text === "\n" || nextNode.text === "\r\n")) {
|
|
10637
|
+
i++;
|
|
10638
|
+
}
|
|
10639
|
+
}
|
|
10576
10640
|
}
|
|
10577
10641
|
}
|
|
10578
10642
|
} finally {
|
|
10579
10643
|
Evaluator$1.destroy();
|
|
10580
10644
|
}
|
|
10581
10645
|
|
|
10582
|
-
return
|
|
10583
|
-
}
|
|
10584
|
-
|
|
10585
|
-
try {
|
|
10586
|
-
for (let i = 0; i < body.length; i++) {
|
|
10587
|
-
const node = body[i];
|
|
10588
|
-
const blockOutput = await generateOutput(body, i, targetFormat, targetMapper, security, null, false, false, instance);
|
|
10589
|
-
|
|
10590
|
-
let finalBlockOutput = blockOutput;
|
|
10591
|
-
if (prev_was_silent && node.type === TEXT$1) {
|
|
10592
|
-
finalBlockOutput = finalBlockOutput.replace(/^\n/, "");
|
|
10593
|
-
}
|
|
10594
|
-
|
|
10595
|
-
if (finalBlockOutput) {
|
|
10596
|
-
output += finalBlockOutput;
|
|
10597
|
-
prev_was_silent = false;
|
|
10598
|
-
if (node.type !== TEXT$1 || node.text.trim().length > 0) {
|
|
10599
|
-
prev_body_node = node;
|
|
10600
|
-
}
|
|
10601
|
-
} else {
|
|
10602
|
-
prev_was_silent = true;
|
|
10603
|
-
if ((node.type === COMMENT || node.type === COMMENT_BLOCK) && targetMapper?.options?.removeComments) {
|
|
10604
|
-
// If a comment is removed, check the next node.
|
|
10605
|
-
// If it's just a blank line, skip it so we don't have extra gaps in the output.
|
|
10606
|
-
const nextNode = body[i + 1];
|
|
10607
|
-
if (nextNode && nextNode.type === TEXT$1 && (nextNode.text === "\n" || nextNode.text === "\r\n")) {
|
|
10608
|
-
i++; // Skip the next newline node
|
|
10609
|
-
}
|
|
10610
|
-
}
|
|
10611
|
-
}
|
|
10612
|
-
}
|
|
10613
|
-
} finally {
|
|
10614
|
-
Evaluator$1.destroy();
|
|
10615
|
-
}
|
|
10616
|
-
|
|
10617
|
-
return output.trim();
|
|
10646
|
+
return output.trim();
|
|
10647
|
+
});
|
|
10618
10648
|
}
|
|
10619
10649
|
|
|
10620
10650
|
/**
|
|
@@ -10637,7 +10667,7 @@ async function transpileArgs(props) {
|
|
|
10637
10667
|
result[key] = "";
|
|
10638
10668
|
} else if (value.type === STATIC_LOGIC) {
|
|
10639
10669
|
try {
|
|
10640
|
-
result[key] = await Evaluator$1.execute(value.code);
|
|
10670
|
+
result[key] = await Evaluator$1.execute(value.code, value.baseDir || null);
|
|
10641
10671
|
} catch (err) {
|
|
10642
10672
|
transpilerError([
|
|
10643
10673
|
`<$red:Logic Error (Argument):$> ${err.message}{line}`,
|
|
@@ -13275,7 +13305,10 @@ const resolveAstVariables = (nodes, variables) => {
|
|
|
13275
13305
|
for (const node of nodes) {
|
|
13276
13306
|
if (node.type === TEXT$1) {
|
|
13277
13307
|
if (node.text.includes(VAR_PREFIX)) {
|
|
13278
|
-
node.text = node.text.replace(VAR_PATTERN, (match,
|
|
13308
|
+
node.text = node.text.replace(VAR_PATTERN, (match, keyAndFallback) => {
|
|
13309
|
+
const pipeIdx = keyAndFallback.indexOf('|');
|
|
13310
|
+
const key = pipeIdx >= 0 ? keyAndFallback.slice(0, pipeIdx) : keyAndFallback;
|
|
13311
|
+
const fallback = pipeIdx >= 0 ? keyAndFallback.slice(pipeIdx + 1) : undefined;
|
|
13279
13312
|
if (variables[key] !== undefined) {
|
|
13280
13313
|
if (!variables.__consumed__) {
|
|
13281
13314
|
Object.defineProperty(variables, "__consumed__", {
|
|
@@ -13288,14 +13321,21 @@ const resolveAstVariables = (nodes, variables) => {
|
|
|
13288
13321
|
variables.__consumed__.add(key);
|
|
13289
13322
|
return String(variables[key]);
|
|
13290
13323
|
}
|
|
13324
|
+
if (fallback !== undefined) return fallback;
|
|
13291
13325
|
return match;
|
|
13292
13326
|
});
|
|
13293
13327
|
}
|
|
13294
13328
|
} else if (node.type === BLOCK) {
|
|
13295
13329
|
// Resolve any unresolved variables in block arguments
|
|
13296
13330
|
for (const [argKey, argVal] of Object.entries(node.props)) {
|
|
13297
|
-
if (typeof argVal
|
|
13298
|
-
|
|
13331
|
+
if (typeof argVal !== "string" || !argVal.includes(VAR_PREFIX)) continue;
|
|
13332
|
+
|
|
13333
|
+
if (argVal.startsWith(VAR_PREFIX) && argVal.endsWith(VAR_SUFFIX)) {
|
|
13334
|
+
// Entire value is an envelope — resolve to scalar or fallback
|
|
13335
|
+
const keyAndFallback = argVal.slice(VAR_PREFIX.length, -VAR_SUFFIX.length);
|
|
13336
|
+
const pipeIdx = keyAndFallback.indexOf('|');
|
|
13337
|
+
const varKey = pipeIdx >= 0 ? keyAndFallback.slice(0, pipeIdx) : keyAndFallback;
|
|
13338
|
+
const fallback = pipeIdx >= 0 ? keyAndFallback.slice(pipeIdx + 1) : undefined;
|
|
13299
13339
|
if (variables[varKey] !== undefined) {
|
|
13300
13340
|
node.props[argKey] = variables[varKey];
|
|
13301
13341
|
if (!variables.__consumed__) {
|
|
@@ -13307,7 +13347,31 @@ const resolveAstVariables = (nodes, variables) => {
|
|
|
13307
13347
|
});
|
|
13308
13348
|
}
|
|
13309
13349
|
variables.__consumed__.add(varKey);
|
|
13350
|
+
} else if (fallback !== undefined) {
|
|
13351
|
+
node.props[argKey] = fallback;
|
|
13310
13352
|
}
|
|
13353
|
+
} else {
|
|
13354
|
+
// Envelope embedded inside a larger string — replace in-place.
|
|
13355
|
+
// Unresolved envelopes become "" so they don't pollute class names etc.
|
|
13356
|
+
node.props[argKey] = argVal.replace(VAR_PATTERN, (match, keyAndFallback) => {
|
|
13357
|
+
const pipeIdx = keyAndFallback.indexOf('|');
|
|
13358
|
+
const key = pipeIdx >= 0 ? keyAndFallback.slice(0, pipeIdx) : keyAndFallback;
|
|
13359
|
+
const fallback = pipeIdx >= 0 ? keyAndFallback.slice(pipeIdx + 1) : undefined;
|
|
13360
|
+
if (variables[key] !== undefined) {
|
|
13361
|
+
if (!variables.__consumed__) {
|
|
13362
|
+
Object.defineProperty(variables, "__consumed__", {
|
|
13363
|
+
value: new Set(),
|
|
13364
|
+
writable: true,
|
|
13365
|
+
enumerable: false,
|
|
13366
|
+
configurable: true
|
|
13367
|
+
});
|
|
13368
|
+
}
|
|
13369
|
+
variables.__consumed__.add(key);
|
|
13370
|
+
return String(variables[key]);
|
|
13371
|
+
}
|
|
13372
|
+
if (fallback !== undefined) return fallback;
|
|
13373
|
+
return "";
|
|
13374
|
+
});
|
|
13311
13375
|
}
|
|
13312
13376
|
}
|
|
13313
13377
|
if (node.body) {
|
|
@@ -13337,6 +13401,7 @@ const cloneAst = (nodes) => {
|
|
|
13337
13401
|
if (node.id !== undefined) nodeCopy.id = node.id;
|
|
13338
13402
|
if (node.code !== undefined) nodeCopy.code = node.code;
|
|
13339
13403
|
if (node.isSelfClosing !== undefined) nodeCopy.isSelfClosing = node.isSelfClosing;
|
|
13404
|
+
if (node.baseDir !== undefined) nodeCopy.baseDir = node.baseDir;
|
|
13340
13405
|
if (node.props !== undefined) {
|
|
13341
13406
|
nodeCopy.props = { ...node.props };
|
|
13342
13407
|
}
|
|
@@ -13348,6 +13413,20 @@ const cloneAst = (nodes) => {
|
|
|
13348
13413
|
return copy;
|
|
13349
13414
|
};
|
|
13350
13415
|
|
|
13416
|
+
/**
|
|
13417
|
+
* Tags all STATIC_LOGIC and RUNTIME_LOGIC nodes in a subtree with their
|
|
13418
|
+
* source module's baseDir so the evaluator can resolve imports correctly.
|
|
13419
|
+
*/
|
|
13420
|
+
const tagLogicNodes = (nodes, baseDir) => {
|
|
13421
|
+
if (!nodes) return;
|
|
13422
|
+
for (const node of nodes) {
|
|
13423
|
+
if ((node.type === STATIC_LOGIC || node.type === RUNTIME_LOGIC) && !node.baseDir) {
|
|
13424
|
+
node.baseDir = baseDir;
|
|
13425
|
+
}
|
|
13426
|
+
if (node.body) tagLogicNodes(node.body, baseDir);
|
|
13427
|
+
}
|
|
13428
|
+
};
|
|
13429
|
+
|
|
13351
13430
|
/**
|
|
13352
13431
|
* Handles all [import] and [$use-module] blocks in your code.
|
|
13353
13432
|
* It loads the requested files, checks for errors, and puts the content into the main document.
|
|
@@ -13521,6 +13600,7 @@ async function resolveModules(ast, context) {
|
|
|
13521
13600
|
format: context.format,
|
|
13522
13601
|
filename: mod.path,
|
|
13523
13602
|
baseDir: posix.dirname(mod.localPath),
|
|
13603
|
+
fs: context.instance.fs,
|
|
13524
13604
|
mapperFile: context.instance.mapperFile,
|
|
13525
13605
|
placeholders: context.instance.placeholders,
|
|
13526
13606
|
variables: {},
|
|
@@ -13536,6 +13616,7 @@ async function resolveModules(ast, context) {
|
|
|
13536
13616
|
});
|
|
13537
13617
|
|
|
13538
13618
|
const subAst = await subSmark.parse();
|
|
13619
|
+
tagLogicNodes(subAst, posix.dirname(mod.localPath));
|
|
13539
13620
|
context.instance.moduleCache.set(mod.localPath, subAst);
|
|
13540
13621
|
expandedNodes = trimAst(subAst);
|
|
13541
13622
|
}
|
|
@@ -13579,6 +13660,7 @@ async function resolveModules(ast, context) {
|
|
|
13579
13660
|
format: context.format,
|
|
13580
13661
|
filename: mod.path,
|
|
13581
13662
|
baseDir: posix.dirname(mod.localPath),
|
|
13663
|
+
fs: context.instance.fs,
|
|
13582
13664
|
mapperFile: context.instance.mapperFile,
|
|
13583
13665
|
placeholders: context.instance.placeholders,
|
|
13584
13666
|
variables: {}, // Parse without variables to keep the cached AST pure
|
|
@@ -13594,6 +13676,7 @@ async function resolveModules(ast, context) {
|
|
|
13594
13676
|
});
|
|
13595
13677
|
|
|
13596
13678
|
subAst = await subSmark.parse();
|
|
13679
|
+
tagLogicNodes(subAst, posix.dirname(mod.localPath));
|
|
13597
13680
|
context.instance.moduleCache.set(mod.localPath, subAst);
|
|
13598
13681
|
subAst = cloneAst(subAst);
|
|
13599
13682
|
}
|
|
@@ -13663,6 +13746,13 @@ async function resolveModules(ast, context) {
|
|
|
13663
13746
|
return ast;
|
|
13664
13747
|
}
|
|
13665
13748
|
|
|
13749
|
+
/**
|
|
13750
|
+
* After full transpilation of the top-level file, apply any v{} fallbacks that
|
|
13751
|
+
* remain unresolved. Envelopes with no fallback are kept as-is (debugging signal).
|
|
13752
|
+
* Must NOT be called on sub-module ASTs — only on the final top-level AST.
|
|
13753
|
+
*/
|
|
13754
|
+
const applyVariableFallbacks = (ast) => resolveAstVariables(ast, {});
|
|
13755
|
+
|
|
13666
13756
|
/**
|
|
13667
13757
|
* SomMark Rules Validator
|
|
13668
13758
|
*
|
|
@@ -14157,6 +14247,7 @@ class SomMark {
|
|
|
14157
14247
|
if (this.showSpinner) startSpinner();
|
|
14158
14248
|
try {
|
|
14159
14249
|
const ast = this.ast || await this.parse(src);
|
|
14250
|
+
applyVariableFallbacks(ast);
|
|
14160
14251
|
let result = await transpiler({
|
|
14161
14252
|
ast,
|
|
14162
14253
|
format: this.targetFormat,
|