subscript 9.1.0 → 10.0.0
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/README.md +123 -171
- package/feature/access.js +67 -7
- package/feature/accessor.js +49 -0
- package/feature/asi.js +15 -0
- package/feature/async.js +45 -0
- package/feature/block.js +41 -0
- package/feature/class.js +69 -0
- package/feature/collection.js +40 -0
- package/feature/comment.js +25 -6
- package/feature/destruct.js +33 -0
- package/feature/function.js +44 -0
- package/feature/group.js +41 -12
- package/feature/if.js +28 -0
- package/feature/literal.js +13 -0
- package/feature/loop.js +123 -0
- package/feature/module.js +42 -0
- package/feature/number.js +45 -10
- package/feature/op/arithmetic.js +29 -0
- package/feature/op/arrow.js +33 -0
- package/feature/op/assign-logical.js +33 -0
- package/feature/op/assignment.js +47 -0
- package/feature/op/bitwise-unsigned.js +17 -0
- package/feature/op/bitwise.js +29 -0
- package/feature/op/comparison.js +19 -0
- package/feature/op/defer.js +15 -0
- package/feature/op/equality.js +16 -0
- package/feature/op/identity.js +15 -0
- package/feature/op/increment.js +23 -0
- package/feature/op/logical.js +21 -0
- package/feature/op/membership.js +17 -0
- package/feature/op/nullish.js +13 -0
- package/feature/op/optional.js +61 -0
- package/feature/op/pow.js +19 -0
- package/feature/op/range.js +26 -0
- package/feature/op/spread.js +15 -0
- package/feature/op/ternary.js +15 -0
- package/feature/op/type.js +18 -0
- package/feature/op/unary.js +41 -0
- package/feature/prop.js +34 -0
- package/feature/regex.js +31 -0
- package/feature/seq.js +21 -0
- package/feature/string.js +24 -16
- package/feature/switch.js +48 -0
- package/feature/template.js +39 -0
- package/feature/try.js +57 -0
- package/feature/unit.js +35 -0
- package/feature/var.js +59 -0
- package/jessie.js +31 -0
- package/jessie.min.js +8 -0
- package/justin.js +39 -48
- package/justin.min.js +8 -1
- package/package.json +18 -23
- package/parse.js +153 -0
- package/subscript.d.ts +45 -5
- package/subscript.js +62 -22
- package/subscript.min.js +5 -1
- package/util/bundle.js +507 -0
- package/util/stringify.js +172 -0
- package/feature/add.js +0 -22
- package/feature/array.js +0 -11
- package/feature/arrow.js +0 -23
- package/feature/assign.js +0 -11
- package/feature/bitwise.js +0 -11
- package/feature/bool.js +0 -5
- package/feature/call.js +0 -15
- package/feature/compare.js +0 -11
- package/feature/increment.js +0 -11
- package/feature/logic.js +0 -11
- package/feature/mult.js +0 -25
- package/feature/object.js +0 -17
- package/feature/optional.js +0 -30
- package/feature/pow.js +0 -5
- package/feature/shift.js +0 -12
- package/feature/spread.js +0 -6
- package/feature/ternary.js +0 -10
- package/src/compile.d.ts +0 -17
- package/src/compile.js +0 -28
- package/src/const.js +0 -42
- package/src/parse.d.ts +0 -22
- package/src/parse.js +0 -114
- package/src/stringify.js +0 -31
- /package/{LICENSE → license} +0 -0
package/subscript.js
CHANGED
|
@@ -1,24 +1,64 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* subscript: Minimal expression parser + compiler
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* subscript`a + b`(ctx) - template tag, returns compiled evaluator
|
|
6
|
+
* subscript`a + ${x}`(ctx) - interpolations: primitives, objects, AST nodes
|
|
7
|
+
* subscript('a + b')(ctx) - direct call (no caching)
|
|
8
|
+
*
|
|
9
|
+
* For more features:
|
|
10
|
+
* import { parse, compile } from 'subscript/justin.js' // + JSON, arrows, templates
|
|
11
|
+
* import { parse, compile } from 'subscript/jessie.js' // + statements, functions
|
|
3
12
|
*/
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import './feature/
|
|
7
|
-
import './feature/
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
import './feature/
|
|
11
|
-
import './feature/
|
|
12
|
-
import './feature/
|
|
13
|
-
import './feature/
|
|
14
|
-
import './feature/
|
|
15
|
-
import './feature/
|
|
16
|
-
import './feature/
|
|
17
|
-
|
|
18
|
-
import
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
export
|
|
23
|
-
|
|
24
|
-
|
|
13
|
+
|
|
14
|
+
// Expression features
|
|
15
|
+
import './feature/number.js'; // Decimal numbers: 123, 1.5, 1e3
|
|
16
|
+
import './feature/string.js'; // Double-quoted strings with escapes
|
|
17
|
+
|
|
18
|
+
// Operators (C-family common set) - order matters for token chain performance
|
|
19
|
+
import './feature/op/assignment.js'; // = += -= *= /= %= |= &= ^= >>= <<=
|
|
20
|
+
import './feature/op/logical.js'; // ! && ||
|
|
21
|
+
import './feature/op/bitwise.js'; // ~ | & ^ >> <<
|
|
22
|
+
import './feature/op/comparison.js'; // < > <= >=
|
|
23
|
+
import './feature/op/equality.js'; // == !=
|
|
24
|
+
import './feature/op/arithmetic.js'; // + - * / %
|
|
25
|
+
import './feature/op/increment.js'; // ++ --
|
|
26
|
+
|
|
27
|
+
import './feature/group.js'; // Grouping: (a), sequences: a, b; a; b
|
|
28
|
+
import './feature/access.js'; // Property access: a.b, a[b], f(), [a,b]
|
|
29
|
+
|
|
30
|
+
import { parse, compile } from './parse.js';
|
|
31
|
+
export * from './parse.js';
|
|
32
|
+
|
|
33
|
+
// Cache for compiled templates (keyed by template strings array reference)
|
|
34
|
+
const cache = new WeakMap();
|
|
35
|
+
|
|
36
|
+
// Template tag: subscript`a + b` or subscript`a + ${x}`
|
|
37
|
+
const subscript = (strings, ...values) =>
|
|
38
|
+
// Direct call subscript('code') - strings is just a string
|
|
39
|
+
typeof strings === 'string' ? compile(parse(strings)) :
|
|
40
|
+
// Template literal - use cache
|
|
41
|
+
cache.get(strings) || cache.set(strings, compileTemplate(strings, values)).get(strings);
|
|
42
|
+
|
|
43
|
+
// Compile template with placeholders (using Private Use Area chars)
|
|
44
|
+
const PUA = 0xE000;
|
|
45
|
+
const compileTemplate = (strings, values) => {
|
|
46
|
+
const code = strings.reduce((acc, s, i) => acc + (i ? String.fromCharCode(PUA + i - 1) : '') + s, '');
|
|
47
|
+
const ast = parse(code);
|
|
48
|
+
const inject = node => {
|
|
49
|
+
if (typeof node === 'string' && node.length === 1) {
|
|
50
|
+
let i = node.charCodeAt(0) - PUA, v;
|
|
51
|
+
if (i >= 0 && i < values.length) return v = values[i], isAST(v) ? v : [, v];
|
|
52
|
+
}
|
|
53
|
+
return Array.isArray(node) ? node.map(inject) : node;
|
|
54
|
+
};
|
|
55
|
+
return compile(inject(ast));
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// Detect AST node vs regular value
|
|
59
|
+
// AST: string (identifier), or array with string/undefined first element
|
|
60
|
+
const isAST = v =>
|
|
61
|
+
typeof v === 'string' ||
|
|
62
|
+
(Array.isArray(v) && (typeof v[0] === 'string' || v[0] === undefined));
|
|
63
|
+
|
|
64
|
+
export default subscript;
|
package/subscript.min.js
CHANGED
|
@@ -1 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
var f,A,m=r=>(f=0,A=r,m.newline=!1,r=h(),A[f]?S():r||""),S=(r="Unexpected token",e=f,t=A.slice(0,e).split(`
|
|
2
|
+
`),n=t.pop(),o=A.slice(Math.max(0,e-40),e),s="\u032D",u=(A[e]||"\u2205")+s,c=A.slice(e+1,e+20))=>{throw SyntaxError(`${r} at ${t.length+1}:${n.length+1}
|
|
3
|
+
${(A[e-41]!==`
|
|
4
|
+
`?"...":"")+o}${u}${c}`)},W=(r,e=f)=>(Array.isArray(r)&&(r.loc=e),r),N=(r,e=f,t)=>{for(;t=r(A.charCodeAt(f));)f+=t;return A.slice(e,f)},g=(r=1)=>A[f+=r],z=r=>f=r,h=(r=0,e)=>{let t,n,o,s,u=m.reserved,c;for(e&&m.asi&&(m.newline=!1),m.reserved=0;(t=m.space())&&(c=m.newline,1)&&t!==e&&(o=((s=C[t])&&s(n,r))??(m.asi&&n&&c&&(o=m.asi(n,r,h)))??(!n&&!m.reserved&&N(m.id)));)n=o,m.reserved=0;return m.reserved=u,e&&(t==e?f++:S("Unclosed "+String.fromCharCode(e-(e>42?2:1)))),n},k=m.space=(r,e=f)=>{for(;(r=A.charCodeAt(f))<=32;)m.asi&&r===10&&(m.newline=!0),f++;return r},Zr=m.id=r=>r>=48&&r<=57||r>=65&&r<=90||r>=97&&r<=122||r==36||r==95||r>=192&&r!=215&&r!=247,b=(r,e=r.length)=>A.substr(f,e)===r&&!m.id(A.charCodeAt(f+e)),M=()=>(g(),h(0,41)),C=[],v=(r,e=32,t,n=r.charCodeAt(0),o=r.length,s=C[n],u=r.toUpperCase()!==r,c,d)=>C[n]=(y,U,L,x=f)=>(c=L,(L?r==L:(o<2||r.charCodeAt(1)===A.charCodeAt(f+1)&&(o<3||A.substr(f,o)==r))&&(!u||!m.id(A.charCodeAt(f+o)))&&(c=L=r))&&U<e&&(f+=o,(d=t(y))?W(d,x):(f=x,c=0,u&&d!==!1&&(m.reserved=1),!u&&!s&&S()),d)||s?.(y,U,c)),p=(r,e,t=!1)=>v(r,e,(n,o)=>n&&(o=h(e-(t?.5:0)))&&[r,n,o]),T=(r,e,t)=>v(r,e,n=>t?n&&[r,n]:!n&&(n=h(e-.5))&&[r,n]),qr=(r,e)=>v(r,200,t=>!t&&[,e]),J=(r,e,t)=>{v(r,e,(n,o)=>(o=h(e-(t?.5:0)),n?.[0]!==r&&(n=[r,n||null]),o?.[0]===r?n.push(...o.slice(1)):n.push(o||null),n))},rr=(r,e)=>v(r[0],e,t=>!t&&[r,h(0,r.charCodeAt(1))||null]),V=(r,e)=>v(r[0],e,t=>t&&[r,t,h(0,r.charCodeAt(1))||null]),er,Cr=(r="Compile error",e=er)=>S(r,e?.loc),G={},l=(r,e,t=G[r])=>G[r]=(...n)=>e(...n)||t?.(...n),i=r=>(er=r,Array.isArray(r)?r[0]===void 0?(e=>()=>e)(r[1]):G[r[0]]?.(...r.slice(1))??Cr(`Unknown operator: ${r[0]}`):r===void 0?()=>{}:e=>e?.[r]);var $=46,_=48,F=57,Er=69,gr=101,wr=43,Sr=45,kr=97,vr=102,Tr=65,Ir=70,Y=r=>[,(r=+N(e=>e===$&&A.charCodeAt(f+1)!==$||e>=_&&e<=F||((e===Er||e===gr)&&((e=A.charCodeAt(f+1))>=_&&e<=F||e===wr||e===Sr)?2:0)))!=r?S():r],Rr={2:r=>r===48||r===49,8:r=>r>=48&&r<=55,16:r=>r>=_&&r<=F||r>=kr&&r<=vr||r>=Tr&&r<=Ir};m.number=null;C[$]=r=>!r&&A.charCodeAt(f+1)!==$&&Y();for(let r=_;r<=F;r++)C[r]=e=>e?void 0:Y();C[_]=r=>{if(r)return;let e=m.number;if(e){for(let[t,n]of Object.entries(e))if(t[0]==="0"&&A[f+1]?.toLowerCase()===t[1])return g(2),[,parseInt(N(Rr[n]),n)]}return Y()};var Nr=92,tr=34,nr=39,Ur={n:`
|
|
5
|
+
`,r:"\r",t:" ",b:"\b",f:"\f",v:"\v"},or=r=>(e,t,n="")=>{if(!(e||!m.string?.[String.fromCharCode(r)]))return g(),N(o=>o-r&&(o===Nr?(n+=Ur[A[f+1]]||A[f+1],2):(n+=A[f],1))),A[f]===String.fromCharCode(r)?g():S("Bad string"),[,n]};C[tr]=or(tr);C[nr]=or(nr);m.string={'"':!0};var w=20;p("=",w,!0);p("+=",w,!0);p("-=",w,!0);p("*=",w,!0);p("/=",w,!0);p("%=",w,!0);p("|=",w,!0);p("&=",w,!0);p("^=",w,!0);p(">>=",w,!0);p("<<=",w,!0);var E=(r,e,t,n)=>typeof r=="string"?o=>e(o,r,o):r[0]==="."?(t=i(r[1]),n=r[2],o=>e(t(o),n,o)):r[0]==="[]"&&r.length===3?(t=i(r[1]),n=i(r[2]),o=>e(t(o),n(o),o)):r[0]==="()"&&r.length===2?E(r[1],e):(()=>{throw Error("Invalid assignment target")})();l("=",(r,e)=>(e=i(e),E(r,(t,n,o)=>t[n]=e(o))));l("+=",(r,e)=>(e=i(e),E(r,(t,n,o)=>t[n]+=e(o))));l("-=",(r,e)=>(e=i(e),E(r,(t,n,o)=>t[n]-=e(o))));l("*=",(r,e)=>(e=i(e),E(r,(t,n,o)=>t[n]*=e(o))));l("/=",(r,e)=>(e=i(e),E(r,(t,n,o)=>t[n]/=e(o))));l("%=",(r,e)=>(e=i(e),E(r,(t,n,o)=>t[n]%=e(o))));l("|=",(r,e)=>(e=i(e),E(r,(t,n,o)=>t[n]|=e(o))));l("&=",(r,e)=>(e=i(e),E(r,(t,n,o)=>t[n]&=e(o))));l("^=",(r,e)=>(e=i(e),E(r,(t,n,o)=>t[n]^=e(o))));l(">>=",(r,e)=>(e=i(e),E(r,(t,n,o)=>t[n]>>=e(o))));l("<<=",(r,e)=>(e=i(e),E(r,(t,n,o)=>t[n]<<=e(o))));var Mr=30,_r=40,ir=140;p("!",ir);T("!",ir);p("||",Mr);p("&&",_r);l("!",r=>(r=i(r),e=>!r(e)));l("||",(r,e)=>(r=i(r),e=i(e),t=>r(t)||e(t)));l("&&",(r,e)=>(r=i(r),e=i(e),t=>r(t)&&e(t)));var Pr=50,Br=60,Dr=70,sr=100,Lr=140;p("|",Pr);p("&",Dr);p("^",Br);p(">>",sr);p("<<",sr);T("~",Lr);l("~",r=>(r=i(r),e=>~r(e)));l("|",(r,e)=>(r=i(r),e=i(e),t=>r(t)|e(t)));l("&",(r,e)=>(r=i(r),e=i(e),t=>r(t)&e(t)));l("^",(r,e)=>(r=i(r),e=i(e),t=>r(t)^e(t)));l(">>",(r,e)=>(r=i(r),e=i(e),t=>r(t)>>e(t)));l("<<",(r,e)=>(r=i(r),e=i(e),t=>r(t)<<e(t)));var X=90;p("<",X);p(">",X);p("<=",X);p(">=",X);l(">",(r,e)=>(r=i(r),e=i(e),t=>r(t)>e(t)));l("<",(r,e)=>(r=i(r),e=i(e),t=>r(t)<e(t)));l(">=",(r,e)=>(r=i(r),e=i(e),t=>r(t)>=e(t)));l("<=",(r,e)=>(r=i(r),e=i(e),t=>r(t)<=e(t)));var lr=80;p("==",lr);p("!=",lr);l("==",(r,e)=>(r=i(r),e=i(e),t=>r(t)==e(t)));l("!=",(r,e)=>(r=i(r),e=i(e),t=>r(t)!=e(t)));var ur=110,Z=120,fr=140;p("+",ur);p("-",ur);p("*",Z);p("/",Z);p("%",Z);T("+",fr);T("-",fr);l("+",(r,e)=>e!==void 0?(r=i(r),e=i(e),t=>r(t)+e(t)):(r=i(r),t=>+r(t)));l("-",(r,e)=>e!==void 0?(r=i(r),e=i(e),t=>r(t)-e(t)):(r=i(r),t=>-r(t)));l("*",(r,e)=>(r=i(r),e=i(e),t=>r(t)*e(t)));l("/",(r,e)=>(r=i(r),e=i(e),t=>r(t)/e(t)));l("%",(r,e)=>(r=i(r),e=i(e),t=>r(t)%e(t)));var O=150;v("++",O,r=>r?["++",r,null]:["++",h(O-1)]);v("--",O,r=>r?["--",r,null]:["--",h(O-1)]);var q=(r,e,t,n)=>typeof r=="string"?o=>e(o,r):r[0]==="."?(t=i(r[1]),n=r[2],o=>e(t(o),n)):r[0]==="[]"&&r.length===3?(t=i(r[1]),n=i(r[2]),o=>e(t(o),n(o))):r[0]==="()"&&r.length===2?q(r[1],e):(()=>{throw Error("Invalid increment target")})();l("++",(r,e)=>q(r,e===null?(t,n)=>t[n]++:(t,n)=>++t[n]));l("--",(r,e)=>q(r,e===null?(t,n)=>t[n]--:(t,n)=>--t[n]));var pr=5,$r=123,Fr=125,I=(r,e,t,n=r.charCodeAt(0),o=r.length,s=C[n],u)=>C[n]=(c,d,y,U=f)=>!c&&(y?r==y:(o<2||A.substr(f,o)==r)&&(y=r))&&d<e&&!m.id(A.charCodeAt(f+o))&&(z(f+o),(u=t())?W(u,U):(z(U),!s&&S()),u)||s?.(c,d,y);var P=()=>k()!==$r?h(pr+.5):(g(),["block",h(pr-.5,Fr)||null]);l("block",r=>r===void 0?()=>{}:(r=i(r),e=>r(e)));var B=(r,e,t)=>{if(typeof r=="string"){t[r]=e;return}let[n,...o]=r;if(n==="{}")for(let s of o){let u,c,d;s[0]==="="?[,[,u,c],d]=s:[,u,c]=s;let y=e[u];y===void 0&&d&&(y=i(d)(t)),B(c,y,t)}else if(n==="[]"){let s=0;for(let u of o){if(u===null){s++;continue}if(Array.isArray(u)&&u[0]==="..."){t[u[1]]=e.slice(s);break}let c=u,d;Array.isArray(u)&&u[0]==="="&&([,c,d]=u);let y=e[s++];y===void 0&&d&&(y=i(d)(t)),B(c,y,t)}}};var Q=Symbol("break"),H=Symbol("continue"),mr=Symbol("return"),D=(r,e)=>{try{return{v:r(e)}}catch(t){if(t?.type===Q)return{b:1};if(t?.type===H)return{c:1};if(t?.type===mr)return{r:1,v:t.value};throw t}},R=5,Xr=125,Or=59;I("while",R+1,()=>(k(),["while",M(),P()]));I("do",R+1,()=>(r=>(k(),g(5),k(),["do",r,M()]))(P()));I("for",R+1,()=>(k(),b("await")?(g(5),k(),["for await",M(),P()]):["for",M(),P()]));I("break",R+1,()=>["break"]);I("continue",R+1,()=>["continue"]);I("return",R+1,()=>{m.asi&&(m.newline=!1),k();let r=A.charCodeAt(f);return!r||r===Xr||r===Or||m.newline?["return"]:["return",h(R)]});l("while",(r,e)=>(r=i(r),e=i(e),t=>{let n,o;for(;r(t)&&!(n=D(e,t)).b;){if(n.r)return n.v;n.c||(o=n.v)}return o}));l("do",(r,e)=>(r=i(r),e=i(e),t=>{let n,o;do{if((n=D(r,t)).b)break;if(n.r)return n.v;n.c||(o=n.v)}while(e(t));return o}));l("for",(r,e)=>{if(Array.isArray(r)&&r[0]===";"){let[,t,n,o]=r;return t=t?i(t):null,n=n?i(n):()=>!0,o=o?i(o):null,e=i(e),s=>{let u,c;for(t?.(s);n(s)&&!(u=D(e,s)).b;o?.(s)){if(u.r)return u.v;u.c||(c=u.v)}return c}}if(Array.isArray(r)&&(r[0]==="in"||r[0]==="of")){let[t,n,o]=r;if(Array.isArray(n)&&(n[0]==="let"||n[0]==="const"||n[0]==="var")&&(n=n[1]),t==="in")return Hr(n,o,e);if(t==="of")return Qr(n,o,e)}});var Qr=(r,e,t)=>{e=i(e),t=i(t);let n=Array.isArray(r);return o=>{let s,u,c=n?null:o[r];for(let d of e(o)){if(n?B(r,d,o):o[r]=d,(s=D(t,o)).b)break;if(s.r)return s.v;s.c||(u=s.v)}return n||(o[r]=c),u}},Hr=(r,e,t)=>{e=i(e),t=i(t);let n=Array.isArray(r);return o=>{let s,u,c=n?null:o[r];for(let d in e(o)){if(n?B(r,d,o):o[r]=d,(s=D(t,o)).b)break;if(s.r)return s.v;s.c||(u=s.v)}return n||(o[r]=c),u}};l("break",()=>()=>{throw{type:Q}});l("continue",()=>()=>{throw{type:H}});l("return",r=>(r=r!==void 0?i(r):null,e=>{throw{type:mr,value:r?.(e)}}));var cr=r=>r?.[0]==="_"&&r[1]==="_"||r==="constructor"||r==="prototype",j=170;V("[]",j);p(".",j);V("()",j);var a=r=>{throw Error(r)};l("[]",(r,e)=>e===void 0?(r=r?r[0]===","?r.slice(1):[r]:[],r=r.map(t=>t==null?(()=>{}):t[0]==="..."?(t=i(t[1]),n=>t(n)):(t=i(t),n=>[t(n)])),t=>r.flatMap(n=>n(t))):(e==null&&a("Missing index"),r=i(r),e=i(e),t=>{let n=e(t);return cr(n)?void 0:r(t)[n]}));l(".",(r,e)=>(r=i(r),e=e[0]?e:e[1],cr(e)?()=>{}:t=>r(t)[e]));l("()",(r,e)=>{if(e===void 0)return r==null?a("Empty ()"):i(r);let t=o=>o?.[0]===","&&o.slice(1).some(s=>s==null||t(s));t(e)&&a("Empty argument");let n=e?e[0]===","?(e=e.slice(1).map(i),o=>e.map(s=>s(o))):(e=i(e),o=>[e(o)]):()=>[];return K(r,(o,s,u)=>o[s](...n(u)),!0)});var Kr=r=>{throw Error(r)},K=(r,e,t,n,o)=>r==null?Kr("Empty ()"):r[0]==="()"&&r.length==2?K(r[1],e,t):typeof r=="string"?s=>e(s,r,s):r[0]==="."?(n=i(r[1]),o=r[2],s=>e(n(s),o,s)):r[0]==="?."?(n=i(r[1]),o=r[2],s=>{let u=n(s);return u==null?void 0:e(u,o,s)}):r[0]==="[]"&&r.length===3?(n=i(r[1]),o=i(r[2]),s=>e(n(s),o(s),s)):r[0]==="?.[]"?(n=i(r[1]),o=i(r[2]),s=>{let u=n(s);return u==null?void 0:e(u,o(s),s)}):(r=i(r),s=>e([r(s)],0,s));var Gr=5,Wr=10,zr=170;rr("()",zr);J(",",Wr);J(";",Gr,!0);var Ar=r=>{throw Error(r)};l("()",(r,e)=>{if(e===void 0)return r==null?Ar("Empty ()"):i(r);let t=o=>o?.[0]===","&&o.slice(1).some(s=>s==null||t(s));t(e)&&Ar("Empty argument");let n=e?e[0]===","?(e=e.slice(1).map(i),o=>e.map(s=>s(o))):(e=i(e),o=>[e(o)]):()=>[];return K(r,(o,s,u)=>o[s](...n(u)),!0)});var dr=(...r)=>(r=r.map(i),e=>{let t;for(let n of r)try{t=n(e)}catch(o){throw(o?.type===Q||o?.type===H)&&(o.value=t),o}return t});l(",",dr);l(";",dr);var hr=new WeakMap,Jr=(r,...e)=>typeof r=="string"?i(m(r)):hr.get(r)||hr.set(r,Vr(r,e)).get(r),yr=57344,Vr=(r,e)=>{let t=r.reduce((s,u,c)=>s+(c?String.fromCharCode(yr+c-1):"")+u,""),n=m(t),o=s=>{if(typeof s=="string"&&s.length===1){let u=s.charCodeAt(0)-yr,c;if(u>=0&&u<e.length)return c=e[u],Yr(c)?c:[,c]}return Array.isArray(s)?s.map(o):s};return i(o(n))},Yr=r=>typeof r=="string"||Array.isArray(r)&&(typeof r[0]=="string"||r[0]===void 0),De=Jr;export{V as access,p as binary,i as compile,A as cur,De as default,S as err,h as expr,rr as group,Zr as id,f as idx,qr as literal,W as loc,C as lookup,J as nary,N as next,l as operator,G as operators,M as parens,m as parse,z as seek,g as skip,k as space,v as token,T as unary,b as word};
|
package/util/bundle.js
ADDED
|
@@ -0,0 +1,507 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ESM Bundler using subscript's own parser (dogfooding)
|
|
3
|
+
*
|
|
4
|
+
* Thin layer: scope analysis + tree transform
|
|
5
|
+
* Parser comes from the dialect (jessie by default)
|
|
6
|
+
*/
|
|
7
|
+
import { parse } from '../jessie.js';
|
|
8
|
+
import { codegen } from './stringify.js';
|
|
9
|
+
import { readFile } from 'fs/promises';
|
|
10
|
+
import { resolve } from 'path';
|
|
11
|
+
|
|
12
|
+
// === AST Utilities ===
|
|
13
|
+
|
|
14
|
+
/** Walk AST, call fn(node, parent, key) for each node */
|
|
15
|
+
const walk = (node, fn, parent = null, key = null) => {
|
|
16
|
+
if (!node || typeof node !== 'object') return;
|
|
17
|
+
fn(node, parent, key);
|
|
18
|
+
if (Array.isArray(node)) {
|
|
19
|
+
for (let i = 0; i < node.length; i++) walk(node[i], fn, node, i);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/** Deep clone AST */
|
|
24
|
+
const clone = node =>
|
|
25
|
+
!node ? node :
|
|
26
|
+
Array.isArray(node) ? node.map(clone) :
|
|
27
|
+
node instanceof RegExp ? new RegExp(node.source, node.flags) :
|
|
28
|
+
typeof node === 'object' ? Object.fromEntries(Object.entries(node).map(([k,v]) => [k, clone(v)])) :
|
|
29
|
+
node;
|
|
30
|
+
|
|
31
|
+
/** Rename identifier in AST - skip property access positions */
|
|
32
|
+
const renameId = (ast, old, neu) => {
|
|
33
|
+
walk(ast, (node, parent, key) => {
|
|
34
|
+
if (Array.isArray(node)) {
|
|
35
|
+
for (let i = 0; i < node.length; i++) {
|
|
36
|
+
if (node[i] === old) {
|
|
37
|
+
// Don't rename if this is a property name in a '.' or '?.' access
|
|
38
|
+
if ((node[0] === '.' || node[0] === '?.') && i === 2) continue;
|
|
39
|
+
// Don't rename if this is a property name in object literal {a: b} or shorthand {a}
|
|
40
|
+
if (node[0] === ':' && i === 1 && typeof node[1] === 'string') continue;
|
|
41
|
+
node[i] = neu;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
return ast;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/** Flatten comma nodes into array: [',', 'a', 'b'] → ['a', 'b'], 'x' → ['x'] */
|
|
50
|
+
const flattenComma = node =>
|
|
51
|
+
Array.isArray(node) && node[0] === ',' ? node.slice(1) :
|
|
52
|
+
node ? [node] : [];
|
|
53
|
+
|
|
54
|
+
// === Module Analysis ===
|
|
55
|
+
|
|
56
|
+
/** Extract string from path node [null, 'path'] (string literal) */
|
|
57
|
+
const getPath = node => Array.isArray(node) && (node[0] === undefined || node[0] === null) ? node[1] : node;
|
|
58
|
+
|
|
59
|
+
/** Extract imports from AST
|
|
60
|
+
* New AST shapes:
|
|
61
|
+
* import './x.js' → ['import', [null, path]]
|
|
62
|
+
* import X from './x.js' → ['import', ['from', 'X', [null, path]]]
|
|
63
|
+
* import {a,b} from './x' → ['import', ['from', ['{}', ...], [null, path]]]
|
|
64
|
+
* import * as X from './x' → ['import', ['from', ['as', '*', 'X'], [null, path]]]
|
|
65
|
+
*/
|
|
66
|
+
const getImports = ast => {
|
|
67
|
+
const imports = [];
|
|
68
|
+
walk(ast, node => {
|
|
69
|
+
if (!Array.isArray(node) || node[0] !== 'import') return;
|
|
70
|
+
const body = node[1];
|
|
71
|
+
const imp = { node };
|
|
72
|
+
|
|
73
|
+
// import './x.js' - bare import: [, 'path'] sparse array with undefined at index 0
|
|
74
|
+
if (Array.isArray(body) && (body[0] === undefined || body[0] === null)) {
|
|
75
|
+
imp.path = body[1];
|
|
76
|
+
imports.push(imp);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// import X from './x.js' or import {...} from './x.js'
|
|
81
|
+
if (Array.isArray(body) && body[0] === 'from') {
|
|
82
|
+
const spec = body[1];
|
|
83
|
+
const pathNode = body[2];
|
|
84
|
+
imp.path = getPath(pathNode);
|
|
85
|
+
|
|
86
|
+
if (typeof spec === 'string') {
|
|
87
|
+
// import X from - default import
|
|
88
|
+
imp.default_ = spec;
|
|
89
|
+
} else if (Array.isArray(spec)) {
|
|
90
|
+
if (spec[0] === '{}') {
|
|
91
|
+
// import { a, b, c as d }
|
|
92
|
+
const items = spec.slice(1).flatMap(flattenComma);
|
|
93
|
+
imp.named = items.map(s =>
|
|
94
|
+
Array.isArray(s) && s[0] === 'as' ? { name: s[1], alias: s[2] } : { name: s, alias: s }
|
|
95
|
+
);
|
|
96
|
+
} else if (spec[0] === 'as' && spec[1] === '*') {
|
|
97
|
+
// import * as X
|
|
98
|
+
imp.namespace = spec[2];
|
|
99
|
+
} else if (spec[0] === '*') {
|
|
100
|
+
// import * as X (alternate shape)
|
|
101
|
+
imp.namespace = spec[1];
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
imports.push(imp);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
return imports;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
/** Extract exports from AST
|
|
111
|
+
* New AST shapes:
|
|
112
|
+
* export const x = 1 → ['export', ['const', ['=', 'x', val]]]
|
|
113
|
+
* export default x → ['export', ['default', 'x']]
|
|
114
|
+
* export { a } → ['export', ['{}', 'a']]
|
|
115
|
+
* export { a } from './x' → ['export', ['from', ['{}', 'a'], [null, path]]]
|
|
116
|
+
* export * from './x' → ['export', ['from', '*', [null, path]]]
|
|
117
|
+
*/
|
|
118
|
+
const getExports = ast => {
|
|
119
|
+
const exports = { named: {}, reexports: [], default_: null };
|
|
120
|
+
|
|
121
|
+
walk(ast, node => {
|
|
122
|
+
if (!Array.isArray(node) || node[0] !== 'export') return;
|
|
123
|
+
const spec = node[1];
|
|
124
|
+
|
|
125
|
+
// export { a } from './x' or export * from './x'
|
|
126
|
+
if (Array.isArray(spec) && spec[0] === 'from') {
|
|
127
|
+
const what = spec[1];
|
|
128
|
+
const pathNode = spec[2];
|
|
129
|
+
const path = getPath(pathNode);
|
|
130
|
+
|
|
131
|
+
if (what === '*') {
|
|
132
|
+
exports.reexports.push({ star: true, path });
|
|
133
|
+
} else if (Array.isArray(what) && what[0] === '{}') {
|
|
134
|
+
const items = what.slice(1).flatMap(flattenComma);
|
|
135
|
+
const names = items.map(s =>
|
|
136
|
+
Array.isArray(s) && s[0] === 'as' ? { name: s[1], alias: s[2] } : { name: s, alias: s }
|
|
137
|
+
);
|
|
138
|
+
exports.reexports.push({ names, path });
|
|
139
|
+
}
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// export { a, b }
|
|
144
|
+
if (Array.isArray(spec) && spec[0] === '{}') {
|
|
145
|
+
const items = spec.slice(1).flatMap(flattenComma);
|
|
146
|
+
const names = items.map(s =>
|
|
147
|
+
Array.isArray(s) && s[0] === 'as' ? { name: s[1], alias: s[2] } : { name: s, alias: s }
|
|
148
|
+
);
|
|
149
|
+
for (const { name, alias } of names) exports.named[alias] = name;
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// export default x
|
|
154
|
+
if (Array.isArray(spec) && spec[0] === 'default') {
|
|
155
|
+
exports.default_ = spec[1];
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// export const/let/var x = ... - varargs: ['let', decl1, decl2, ...]
|
|
160
|
+
if (Array.isArray(spec) && (spec[0] === 'const' || spec[0] === 'let' || spec[0] === 'var')) {
|
|
161
|
+
for (let i = 1; i < spec.length; i++) {
|
|
162
|
+
const decl = spec[i];
|
|
163
|
+
if (typeof decl === 'string') {
|
|
164
|
+
exports.named[decl] = decl;
|
|
165
|
+
} else if (Array.isArray(decl) && decl[0] === '=') {
|
|
166
|
+
const name = decl[1];
|
|
167
|
+
if (typeof name === 'string') exports.named[name] = name;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// export function x() {} or export class x {}
|
|
174
|
+
if (Array.isArray(spec) && (spec[0] === 'function' || spec[0] === 'class')) {
|
|
175
|
+
if (typeof spec[1] === 'string') exports.named[spec[1]] = spec[1];
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
return exports;
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
/** Get all declared names in AST
|
|
183
|
+
* New AST shapes:
|
|
184
|
+
* const x = 1 → ['const', ['=', 'x', val]]
|
|
185
|
+
* let x → ['let', 'x']
|
|
186
|
+
* function f() → ['function', 'f', ...]
|
|
187
|
+
* const a = 1, b = 2 → ['const', ['=', 'a', ...], ['=', 'b', ...]] (varargs)
|
|
188
|
+
*/
|
|
189
|
+
const getDecls = ast => {
|
|
190
|
+
const decls = new Set();
|
|
191
|
+
|
|
192
|
+
const addDecl = node => {
|
|
193
|
+
if (typeof node === 'string') decls.add(node);
|
|
194
|
+
else if (Array.isArray(node)) {
|
|
195
|
+
if (node[0] === '=') {
|
|
196
|
+
if (typeof node[1] === 'string') decls.add(node[1]);
|
|
197
|
+
} else if (node[0] === ',') {
|
|
198
|
+
// Multiple declarations: const a = 1, b = 2 (older AST shape)
|
|
199
|
+
for (let i = 1; i < node.length; i++) addDecl(node[i]);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
walk(ast, node => {
|
|
205
|
+
if (!Array.isArray(node)) return;
|
|
206
|
+
const op = node[0];
|
|
207
|
+
|
|
208
|
+
if (op === 'const' || op === 'let' || op === 'var') {
|
|
209
|
+
// Handle varargs: ['const', decl1, decl2, ...] for multiple declarations
|
|
210
|
+
for (let i = 1; i < node.length; i++) addDecl(node[i]);
|
|
211
|
+
}
|
|
212
|
+
if (op === 'function' || op === 'class') {
|
|
213
|
+
if (typeof node[1] === 'string') decls.add(node[1]);
|
|
214
|
+
}
|
|
215
|
+
if (op === 'export') {
|
|
216
|
+
const spec = node[1];
|
|
217
|
+
if (Array.isArray(spec) && (spec[0] === 'const' || spec[0] === 'let' || spec[0] === 'var')) {
|
|
218
|
+
addDecl(spec[1]);
|
|
219
|
+
}
|
|
220
|
+
if (Array.isArray(spec) && (spec[0] === 'function' || spec[0] === 'class') && typeof spec[1] === 'string') {
|
|
221
|
+
decls.add(spec[1]);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
return decls;
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
// === AST Transforms ===
|
|
230
|
+
|
|
231
|
+
/** Remove import/export nodes, extract declarations */
|
|
232
|
+
/** Remove import/export nodes, extract declarations
|
|
233
|
+
* New AST shapes for export:
|
|
234
|
+
* export const x = 1 → ['export', ['const', ...]] → keep ['const', ...]
|
|
235
|
+
* export default x → ['export', ['default', x]] → keep, or convert to __default
|
|
236
|
+
* export { a } → ['export', ['{}', ...]] → remove
|
|
237
|
+
* export { a } from './x' → ['export', ['from', ['{}', ...], path]] → remove
|
|
238
|
+
* export * from './x' → ['export', ['from', '*', path]] → remove
|
|
239
|
+
*/
|
|
240
|
+
const stripModuleSyntax = ast => {
|
|
241
|
+
const defaultExpr = { value: null };
|
|
242
|
+
|
|
243
|
+
const process = node => {
|
|
244
|
+
if (!Array.isArray(node)) return node;
|
|
245
|
+
const op = node[0];
|
|
246
|
+
|
|
247
|
+
if (op === 'import') return null;
|
|
248
|
+
|
|
249
|
+
if (op === 'export') {
|
|
250
|
+
const spec = node[1];
|
|
251
|
+
// Re-exports: export { a } from './x' or export * from './x'
|
|
252
|
+
if (Array.isArray(spec) && spec[0] === 'from') return null;
|
|
253
|
+
// Named exports: export { a, b }
|
|
254
|
+
if (Array.isArray(spec) && spec[0] === '{}') return null;
|
|
255
|
+
// Default export
|
|
256
|
+
if (Array.isArray(spec) && spec[0] === 'default') {
|
|
257
|
+
defaultExpr.value = spec[1];
|
|
258
|
+
if (typeof spec[1] === 'string') return null;
|
|
259
|
+
return ['const', ['=', '__default', spec[1]]];
|
|
260
|
+
}
|
|
261
|
+
// Declaration export: export const x = 1
|
|
262
|
+
return spec;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (op === ';') {
|
|
266
|
+
const parts = node.slice(1).map(process).filter(Boolean);
|
|
267
|
+
if (parts.length === 0) return null;
|
|
268
|
+
if (parts.length === 1) return parts[0];
|
|
269
|
+
return [';', ...parts];
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return node;
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
return { ast: process(ast), defaultExpr: defaultExpr.value };
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
// === Path Resolution ===
|
|
279
|
+
|
|
280
|
+
const resolvePath = (from, to) => {
|
|
281
|
+
if (!to.startsWith('.')) return to;
|
|
282
|
+
const base = from.split('/').slice(0, -1);
|
|
283
|
+
for (const part of to.split('/')) {
|
|
284
|
+
if (part === '..') base.pop();
|
|
285
|
+
else if (part !== '.') base.push(part);
|
|
286
|
+
}
|
|
287
|
+
let path = base.join('/');
|
|
288
|
+
if (!path.endsWith('.js')) path += '.js';
|
|
289
|
+
return path;
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
// === Bundler ===
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Bundle ES modules into single file
|
|
296
|
+
* @param {string} entry - Entry file path
|
|
297
|
+
* @param {(path: string) => string|Promise<string>} read - File reader
|
|
298
|
+
*/
|
|
299
|
+
export async function bundle(entry, read) {
|
|
300
|
+
const modules = new Map();
|
|
301
|
+
const order = [];
|
|
302
|
+
|
|
303
|
+
async function load(path) {
|
|
304
|
+
if (modules.has(path)) return;
|
|
305
|
+
modules.set(path, null);
|
|
306
|
+
|
|
307
|
+
const code = await read(path);
|
|
308
|
+
const ast = parse(code);
|
|
309
|
+
const imports = getImports(ast);
|
|
310
|
+
const exports = getExports(ast);
|
|
311
|
+
const decls = getDecls(ast);
|
|
312
|
+
|
|
313
|
+
for (const imp of imports) {
|
|
314
|
+
imp.resolved = resolvePath(path, imp.path);
|
|
315
|
+
await load(imp.resolved);
|
|
316
|
+
}
|
|
317
|
+
for (const re of exports.reexports) {
|
|
318
|
+
re.resolved = resolvePath(path, re.path);
|
|
319
|
+
await load(re.resolved);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
modules.set(path, { ast: clone(ast), imports, exports, decls });
|
|
323
|
+
order.push(path);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
await load(entry);
|
|
327
|
+
|
|
328
|
+
// Detect conflicts
|
|
329
|
+
const allDecls = new Map();
|
|
330
|
+
for (const [path, mod] of modules) {
|
|
331
|
+
const importAliases = new Set();
|
|
332
|
+
for (const imp of mod.imports) {
|
|
333
|
+
if (imp.default_) importAliases.add(imp.default_);
|
|
334
|
+
if (imp.namespace) importAliases.add(imp.namespace);
|
|
335
|
+
if (imp.named) for (const { alias } of imp.named) importAliases.add(alias);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
for (const name of mod.decls) {
|
|
339
|
+
if (importAliases.has(name)) continue;
|
|
340
|
+
if (!allDecls.has(name)) allDecls.set(name, []);
|
|
341
|
+
allDecls.get(name).push(path);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Build rename maps
|
|
346
|
+
const renames = new Map();
|
|
347
|
+
for (const [name, paths] of allDecls) {
|
|
348
|
+
if (paths.length > 1) {
|
|
349
|
+
for (const path of paths) {
|
|
350
|
+
if (!renames.has(path)) renames.set(path, {});
|
|
351
|
+
// Make valid JS identifier: replace non-alphanumeric with underscore
|
|
352
|
+
const prefix = path.split('/').pop().replace('.js', '').replace(/[^a-zA-Z0-9]/g, '_') + '_';
|
|
353
|
+
renames.get(path)[name] = prefix + name;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
const traceDefault = path => {
|
|
359
|
+
const mod = modules.get(path);
|
|
360
|
+
if (!mod) return null;
|
|
361
|
+
const def = mod.exports.default_;
|
|
362
|
+
if (!def) return null;
|
|
363
|
+
if (typeof def === 'string') {
|
|
364
|
+
const pathRenames = renames.get(path) || {};
|
|
365
|
+
if (pathRenames[def]) return pathRenames[def];
|
|
366
|
+
const defImp = mod.imports.find(i => i.default_ === def);
|
|
367
|
+
if (defImp) return traceDefault(defImp.resolved);
|
|
368
|
+
return def;
|
|
369
|
+
}
|
|
370
|
+
return '__default';
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
// Transform each module
|
|
374
|
+
const chunks = [];
|
|
375
|
+
for (const path of order) {
|
|
376
|
+
const mod = modules.get(path);
|
|
377
|
+
const pathRenames = renames.get(path) || {};
|
|
378
|
+
|
|
379
|
+
let ast = clone(mod.ast);
|
|
380
|
+
for (const [old, neu] of Object.entries(pathRenames)) {
|
|
381
|
+
renameId(ast, old, neu);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
for (const imp of mod.imports) {
|
|
385
|
+
const dep = modules.get(imp.resolved);
|
|
386
|
+
if (!dep) continue;
|
|
387
|
+
const depRenames = renames.get(imp.resolved) || {};
|
|
388
|
+
|
|
389
|
+
if (imp.named) {
|
|
390
|
+
for (const { name, alias } of imp.named) {
|
|
391
|
+
// `name` is the exported name, look up what local name it maps to in the dep
|
|
392
|
+
const localName = dep.exports.named[name] || name;
|
|
393
|
+
// Check if that local name was renamed in the dep
|
|
394
|
+
const resolved = depRenames[localName] || localName;
|
|
395
|
+
if (alias !== resolved) renameId(ast, alias, resolved);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
if (imp.default_) {
|
|
400
|
+
const resolved = traceDefault(imp.resolved);
|
|
401
|
+
if (resolved && imp.default_ !== resolved) {
|
|
402
|
+
renameId(ast, imp.default_, resolved);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
if (imp.namespace) {
|
|
407
|
+
walk(ast, node => {
|
|
408
|
+
if (Array.isArray(node) && node[0] === '.' && node[1] === imp.namespace) {
|
|
409
|
+
const prop = node[2];
|
|
410
|
+
if (typeof prop === 'string' && dep.exports.named[prop]) {
|
|
411
|
+
const resolved = depRenames[dep.exports.named[prop]] || dep.exports.named[prop];
|
|
412
|
+
node.length = 0;
|
|
413
|
+
node.push(resolved);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
const { ast: stripped } = stripModuleSyntax(ast);
|
|
421
|
+
|
|
422
|
+
if (stripped) {
|
|
423
|
+
const code = codegen(stripped);
|
|
424
|
+
if (code.trim()) {
|
|
425
|
+
chunks.push(`// === ${path} ===\n${code}`);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// Generate exports
|
|
431
|
+
const entryMod = modules.get(entry);
|
|
432
|
+
const entryRenames = renames.get(entry) || {};
|
|
433
|
+
const exportLines = [];
|
|
434
|
+
|
|
435
|
+
// Resolve all named exports including from re-exports
|
|
436
|
+
const resolveExports = (path, seen = new Set()) => {
|
|
437
|
+
if (seen.has(path)) return {};
|
|
438
|
+
seen.add(path);
|
|
439
|
+
const mod = modules.get(path);
|
|
440
|
+
if (!mod) return {};
|
|
441
|
+
const pathRenames = renames.get(path) || {};
|
|
442
|
+
const result = {};
|
|
443
|
+
|
|
444
|
+
// Direct named exports
|
|
445
|
+
for (const [exp, local] of Object.entries(mod.exports.named)) {
|
|
446
|
+
result[exp] = pathRenames[local] || local;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// Re-exports
|
|
450
|
+
for (const re of mod.exports.reexports) {
|
|
451
|
+
const depRenames = renames.get(re.resolved) || {};
|
|
452
|
+
if (re.star) {
|
|
453
|
+
// export * from './x' - get all exports from that module
|
|
454
|
+
const depExports = resolveExports(re.resolved, seen);
|
|
455
|
+
for (const [exp, resolved] of Object.entries(depExports)) {
|
|
456
|
+
if (!(exp in result)) result[exp] = resolved; // don't override local exports
|
|
457
|
+
}
|
|
458
|
+
} else if (re.names) {
|
|
459
|
+
// export { a, b } from './x'
|
|
460
|
+
const depMod = modules.get(re.resolved);
|
|
461
|
+
if (depMod) {
|
|
462
|
+
for (const { name, alias } of re.names) {
|
|
463
|
+
const local = depMod.exports.named[name] || name;
|
|
464
|
+
result[alias] = depRenames[local] || local;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
return result;
|
|
470
|
+
};
|
|
471
|
+
|
|
472
|
+
const allExports = resolveExports(entry);
|
|
473
|
+
for (const [exp, resolved] of Object.entries(allExports)) {
|
|
474
|
+
exportLines.push(exp === resolved ? exp : `${resolved} as ${exp}`);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
if (entryMod.exports.default_) {
|
|
478
|
+
const resolved = traceDefault(entry) || '__default';
|
|
479
|
+
exportLines.push(`${resolved} as default`);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
let result = chunks.join('\n\n');
|
|
483
|
+
if (exportLines.length) {
|
|
484
|
+
result += `\n\nexport { ${exportLines.join(', ')} }`;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
return result;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/** Bundle with Node.js fs */
|
|
491
|
+
export const bundleFile = (entry) => bundle(resolve(entry), path => readFile(path, 'utf-8'));
|
|
492
|
+
|
|
493
|
+
// CLI
|
|
494
|
+
if (typeof process !== 'undefined' && process.argv[1]?.includes('bundle')) {
|
|
495
|
+
const entry = process.argv[2];
|
|
496
|
+
if (!entry) {
|
|
497
|
+
console.error('Usage: node bundle.js <entry>');
|
|
498
|
+
process.exit(1);
|
|
499
|
+
}
|
|
500
|
+
bundleFile(entry)
|
|
501
|
+
.then(result => console.log(result))
|
|
502
|
+
.catch(e => {
|
|
503
|
+
console.error('Error:', e.message);
|
|
504
|
+
console.error(e.stack);
|
|
505
|
+
process.exit(1);
|
|
506
|
+
});
|
|
507
|
+
}
|