@vesk/compiler 0.2.93 → 0.2.94

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.
@@ -1 +1 @@
1
- {"version":3,"file":"client-codegen.d.ts","sourceRoot":"","sources":["../src/client-codegen.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAuB,MAAM,uBAAuB,CAAC;AACzE,OAAO,EAGL,cAAc,EAQd,gBAAgB,EAUjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAkGxD,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,SAAS,GAAG,MAAM,CAAC;CAC1B;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI1D;AAiDD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,gBAAgB,GAAG,cAAc,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,MAAM,CAgJlI;AAID,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAI5E;AAyCD;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,MAAM,EAAE,CAuB9F;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,MAAM,CAY5F;AAoFD,qDAAqD;AACrD,MAAM,MAAM,SAAS,GAAG;IAAE,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtC;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG,SAAS,CAQtE;AAiqED,iBAAS,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAe3C;AAuKD,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAO9C;AAwED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,eAAe,CAAC,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,aAAa,CAAC,EAAE,SAAS,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,MAAM,CAOpQ;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,GAAG,IAAI,EAC7B,UAAU,CAAC,EAAE,MAAM,EACnB,IAAI,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,CAAA;CAAE,GACjD;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,OAAO,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,aAAa,EAAE,MAAM,EAAE,CAAC;IAAC,cAAc,EAAE,MAAM,EAAE,CAAA;CAAE,CAyC5J;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAG/E;AAED,OAAO,EAAE,aAAa,IAAI,OAAO,EAAE,UAAU,EAAE,CAAC"}
1
+ {"version":3,"file":"client-codegen.d.ts","sourceRoot":"","sources":["../src/client-codegen.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAuB,MAAM,uBAAuB,CAAC;AACzE,OAAO,EAGL,cAAc,EAQd,gBAAgB,EAUjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAkGxD,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,SAAS,GAAG,MAAM,CAAC;CAC1B;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI1D;AAiDD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,gBAAgB,GAAG,cAAc,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,MAAM,CAgJlI;AAID,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAI5E;AAyCD;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,MAAM,EAAE,CAuB9F;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,MAAM,CAY5F;AAoFD,qDAAqD;AACrD,MAAM,MAAM,SAAS,GAAG;IAAE,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtC;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG,SAAS,CAQtE;AA0uED,iBAAS,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAe3C;AAuKD,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAO9C;AAwED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,eAAe,CAAC,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,aAAa,CAAC,EAAE,SAAS,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,MAAM,CAOpQ;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,GAAG,IAAI,EAC7B,UAAU,CAAC,EAAE,MAAM,EACnB,IAAI,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,CAAA;CAAE,GACjD;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,OAAO,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,aAAa,EAAE,MAAM,EAAE,CAAC;IAAC,cAAc,EAAE,MAAM,EAAE,CAAA;CAAE,CAyC5J;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAG/E;AAED,OAAO,EAAE,aAAa,IAAI,OAAO,EAAE,UAAU,EAAE,CAAC"}
@@ -685,6 +685,7 @@ function emitNode(ctx, node, tracked, effectsVar, parentVar, compPrefix = '__com
685
685
  ctx.push(` const __slot = createLayoutSlot(${ctx.walker}, ${parentVar});`);
686
686
  ctx.push(` const __child = props.children(__slot.walker);`);
687
687
  ctx.push(` if (__child && typeof __child.then === 'function') __pendingChild = __slot.track(__child);`);
688
+ ctx.push(` else if (__child && __child.nodeType === 11) ${parentVar}.appendChild(__child);`);
688
689
  ctx.push(` } else {`);
689
690
  ctx.push(` ${parentVar}.appendChild(props.children);`);
690
691
  ctx.push(` }`);
@@ -1269,6 +1270,65 @@ function emitFragment(ctx, nodes, tracked, effectsVar) {
1269
1270
  ctx.push(`return $f; })();`);
1270
1271
  return frag;
1271
1272
  }
1273
+ /**
1274
+ * True when any node in the subtree is a layout `{props.children}` slot.
1275
+ *
1276
+ * A slot must be hydrated on the walker scoped to the element that will
1277
+ * actually contain it. Building the children fragment eagerly on the caller's
1278
+ * walker is only correct when the callee appends that fragment to its own
1279
+ * mount point. A component that forwards children through a scoped container
1280
+ * (e.g. a shell that renders `{props.children}` inside `<main>`) invokes the
1281
+ * child hydrator with a sub-walker; passing an eagerly-built fragment skips
1282
+ * that scope and lets the page claim the shell's own SSR root.
1283
+ */
1284
+ function containsSlot(nodes) {
1285
+ for (const node of nodes) {
1286
+ if (node instanceof SlotNode)
1287
+ return true;
1288
+ if (node instanceof StaticNode) {
1289
+ if (containsSlot(node.children))
1290
+ return true;
1291
+ }
1292
+ else if (node instanceof ComponentCall) {
1293
+ if (containsSlot(node.children))
1294
+ return true;
1295
+ }
1296
+ else if (node instanceof OpaqueDynamicRegion) {
1297
+ if (containsSlot(node.consequentNodes) || containsSlot(node.alternateNodes))
1298
+ return true;
1299
+ }
1300
+ else if (node instanceof MapRegion) {
1301
+ if (containsSlot(node.bodyTemplate) || containsSlot(node.alternateNodes))
1302
+ return true;
1303
+ }
1304
+ else if (node instanceof WhileLoop) {
1305
+ if (containsSlot(node.bodyTemplate))
1306
+ return true;
1307
+ }
1308
+ else if (node instanceof ForLoop) {
1309
+ if (containsSlot(node.bodyTemplate))
1310
+ return true;
1311
+ }
1312
+ else if (node instanceof SwitchBlock) {
1313
+ for (const c of node.cases)
1314
+ if (containsSlot(c.body))
1315
+ return true;
1316
+ }
1317
+ else if (node instanceof TryCatch) {
1318
+ if (containsSlot(node.bodyTemplate) || containsSlot(node.catchBody))
1319
+ return true;
1320
+ }
1321
+ else if (node instanceof ServerBlock || node instanceof ClientBlock || node instanceof HeadBlock) {
1322
+ if (containsSlot(node.children))
1323
+ return true;
1324
+ }
1325
+ else if (node instanceof PropSlot) {
1326
+ if (containsSlot(node.body))
1327
+ return true;
1328
+ }
1329
+ }
1330
+ return false;
1331
+ }
1272
1332
  function emitComponentCall(ctx, node, tracked, effectsVar, parentVar, compPrefix = '__components', skipK = 0, regionBudget) {
1273
1333
  const propsEntries = node.props.map((p) => {
1274
1334
  if (typeof p.value === 'string')
@@ -1406,20 +1466,56 @@ function emitComponentCall(ctx, node, tracked, effectsVar, parentVar, compPrefix
1406
1466
  // fresh and let the runtime component adopt the existing root.
1407
1467
  if (wipeMount || ctx.selfClaimNames.has(node.componentName))
1408
1468
  ctx.hydrate = false;
1409
- ctx.push(`const ${frag} = (() => { const $f = document.createDocumentFragment();`);
1410
- const savedEffects = ctx.effects;
1411
- ctx.effects = [];
1412
- for (const child of regChildren) {
1413
- const childVar = emitNode(ctx, child, tracked, effectsVar, '$f');
1414
- if (childVar)
1415
- ctx.push(`$f.appendChild(${childVar});`);
1469
+ // A slot nested under a compiled component must be built by that
1470
+ // component's scoped walker, not the caller's. Pass children as a lazy
1471
+ // hydrator so the callee can invoke it with the walker for the element
1472
+ // that actually contains the slot (e.g. `<main>` in a shell). Eagerly
1473
+ // building the fragment here hydrates the page against the shell's own
1474
+ // SSR root, which detaches the shell on hydration.
1475
+ const lazySlotChildren = ctx.hydrate && !plainTarget && !ctx.selfClaimNames.has(node.componentName) && containsSlot(regChildren);
1476
+ if (lazySlotChildren) {
1477
+ const fnVar = ctx.n();
1478
+ const savedLines = ctx.lines;
1479
+ const savedEffects = ctx.effects;
1480
+ const savedWalker = ctx.walker;
1481
+ ctx.lines = [];
1482
+ ctx.effects = [];
1483
+ ctx.walker = '__childWalker';
1484
+ ctx.push(`const $f = document.createDocumentFragment();`);
1485
+ for (const child of regChildren) {
1486
+ const childVar = emitNode(ctx, child, tracked, effectsVar, '$f');
1487
+ if (childVar)
1488
+ ctx.push(`$f.appendChild(${childVar});`);
1489
+ }
1490
+ for (const eff of ctx.effects)
1491
+ ctx.push(effectsVar ? `${effectsVar}.push(${effectBlockToHandlerExpr(eff)});` : eff);
1492
+ ctx.push(`return $f;`);
1493
+ const body = ctx.lines.join('\n');
1494
+ ctx.lines = savedLines;
1495
+ ctx.effects = savedEffects;
1496
+ ctx.walker = savedWalker;
1497
+ const asyncKw = ctx.isAsyncScope ? 'async ' : '';
1498
+ ctx.push(`const ${fnVar} = ${asyncKw}(__childWalker) => {`);
1499
+ ctx.push(indent(body));
1500
+ ctx.push(`};`);
1501
+ propsEntries.push(`children: ${fnVar}`);
1502
+ }
1503
+ else {
1504
+ ctx.push(`const ${frag} = (() => { const $f = document.createDocumentFragment();`);
1505
+ const savedEffects = ctx.effects;
1506
+ ctx.effects = [];
1507
+ for (const child of regChildren) {
1508
+ const childVar = emitNode(ctx, child, tracked, effectsVar, '$f');
1509
+ if (childVar)
1510
+ ctx.push(`$f.appendChild(${childVar});`);
1511
+ }
1512
+ for (const eff of ctx.effects)
1513
+ ctx.push(effectsVar ? `${effectsVar}.push(${effectBlockToHandlerExpr(eff)});` : eff);
1514
+ ctx.effects = savedEffects;
1515
+ ctx.push(`return $f; })();`);
1516
+ propsEntries.push(`children: ${frag}`);
1416
1517
  }
1417
- for (const eff of ctx.effects)
1418
- ctx.push(effectsVar ? `${effectsVar}.push(${effectBlockToHandlerExpr(eff)});` : eff);
1419
- ctx.effects = savedEffects;
1420
1518
  ctx.hydrate = savedHydrate;
1421
- ctx.push(`return $f; })();`);
1422
- propsEntries.push(`children: ${frag}`);
1423
1519
  }
1424
1520
  // Deposit the residue for the child's first top-level claim (it runs on
1425
1521
  // this same walker with its own zero `topPendingSkip`). A region budget is
@@ -1667,7 +1763,7 @@ function emitTryCatch(ctx, node, tracked, effectsVar, parentVar, skipK = 0, regi
1667
1763
  ${effArr}.length = 0;
1668
1764
  __cleanup(${anchor}, ${endAnchor});
1669
1765
  try { ${asyncKw}${tryRenderComp}(); } catch(${catchParam}) { ${hasCatch ? `${asyncKw}${catchRenderComp}(${catchParam});` : 'throw ${catchParam};'} }
1670
- });
1766
+ }, true);
1671
1767
  }`);
1672
1768
  return null;
1673
1769
  }
@@ -1766,7 +1862,7 @@ function emitOpaque(ctx, node, tracked, effTarget, parentVar, skipK = 0, regionB
1766
1862
  ${effInner}
1767
1863
  __iv = __new;
1768
1864
  }
1769
- });`;
1865
+ }, true);`;
1770
1866
  if (effTarget) {
1771
1867
  ctx.push(`${effTarget}.push((() => {
1772
1868
  let __iv = ${branchInit};
@@ -1867,7 +1963,7 @@ function emitOpaque(ctx, node, tracked, effTarget, parentVar, skipK = 0, regionB
1867
1963
  ${renderBranch}
1868
1964
  __iv = __nv;
1869
1965
  }
1870
- });`;
1966
+ }, true);`;
1871
1967
  // A static condition renders once; an effect referencing it would only ever
1872
1968
  // reference statement/loop-local bindings that are out of scope at the flush
1873
1969
  // site (e.g. `const pages = …; if (pages.length > 0)` inside a for-of body).
@@ -1973,7 +2069,7 @@ function emitWhileLoop(ctx, node, tracked, parentVar, skipK = 0, regionBudget) {
1973
2069
  __busy = false;
1974
2070
  __iv = (${condExpr});
1975
2071
  }
1976
- });
2072
+ }, true);
1977
2073
  }`);
1978
2074
  return null;
1979
2075
  }
@@ -2087,7 +2183,7 @@ function emitForLoop(ctx, node, tracked, parentVar, skipK = 0, regionBudget) {
2087
2183
  __busy = false;
2088
2184
  __iv = (${srcExpr});
2089
2185
  }
2090
- });
2186
+ }, true);
2091
2187
  }`);
2092
2188
  }
2093
2189
  else {
@@ -2156,7 +2252,7 @@ function emitForLoop(ctx, node, tracked, parentVar, skipK = 0, regionBudget) {
2156
2252
  __cleanup(${anchor}, ${endAnchor});
2157
2253
  ${ctx.isAsyncScope ? 'await ' : ''}${renderLoop}();
2158
2254
  __busy = false;
2159
- });
2255
+ }, true);
2160
2256
  }`);
2161
2257
  }
2162
2258
  }
@@ -2233,7 +2329,7 @@ function emitSwitchBlock(ctx, node, tracked, parentVar, skipK = 0, regionBudget)
2233
2329
  __busy = false;
2234
2330
  __iv = (${discExpr});
2235
2331
  }
2236
- });
2332
+ }, true);
2237
2333
  }`);
2238
2334
  return null;
2239
2335
  }
@@ -2456,7 +2552,7 @@ function emitMap(ctx, node, tracked, effTarget, parentVar, skipK = 0, regionBudg
2456
2552
  ${effectsVar}.length = 0;
2457
2553
  __cleanup(${anchor}, ${endAnchor});
2458
2554
  if (__new) { ${initList}(); } else { ${aw}${emptyRenderName}(); }
2459
- })`);
2555
+ }, true)`);
2460
2556
  }
2461
2557
  else {
2462
2558
  ctx.push(`${initList}();`);
@@ -2466,7 +2562,7 @@ function emitMap(ctx, node, tracked, effTarget, parentVar, skipK = 0, regionBudg
2466
2562
  const __nv = ${arrExpr};
2467
2563
  if (__first) { __first = false; __nv; ${breakReset}${reconciler}(${arrExpr}); return; }
2468
2564
  ${breakVar ? `if (${breakVar}) ${breakVar} = false;` : ''}${reconciler}(${arrExpr});
2469
- })`);
2565
+ }, true)`);
2470
2566
  }
2471
2567
  }
2472
2568
  else {
@@ -2524,7 +2620,7 @@ ${renderAllItems(' ', null)}
2524
2620
  if (__new) {
2525
2621
  ${renderAllItems(' ', null)}
2526
2622
  } else { ${aw}${emptyRenderName}(${collectVar ? collectVar : ''}); }
2527
- })`);
2623
+ }, true)`);
2528
2624
  }
2529
2625
  else {
2530
2626
  const collectVar = hyd ? ctx.n() : null;
@@ -2542,7 +2638,7 @@ ${renderAllItems(' ', null)}
2542
2638
  ${effectsVar}.length = 0;
2543
2639
  __cleanup(${anchor}, ${endAnchor});
2544
2640
  ${renderAllItems(' ', null)}
2545
- })`);
2641
+ }, true)`);
2546
2642
  }
2547
2643
  }
2548
2644
  return null;
@@ -106,7 +106,7 @@ export declare function resolveViaPackageExports(specifier: string, fromDir: str
106
106
  /** Rewrites an ESM program body (imports/exports removed) into CJS statements. */
107
107
  export declare function esmToCjs(body: Array<{
108
108
  type: string;
109
- } & Record<string, unknown>>): string;
109
+ } & Record<string, unknown>>, rewriteImports?: ReadonlySet<string>): string;
110
110
  export interface BundledModuleData {
111
111
  /** Synthetic loader key (e.g. `__veskMod0`), referenced by deps/bindings. */
112
112
  key: string;
@@ -142,6 +142,13 @@ export interface ModuleEntry {
142
142
  dir: string;
143
143
  /** Relative specifier (as written) -> sibling module key. */
144
144
  deps: Record<string, string>;
145
+ /**
146
+ * Absolute path the entry was registered under. Kept so a plan can be
147
+ * replayed into a fresh registry (see `precompile.ts`), where the module
148
+ * key is derived from this path. Never emitted into the deployment
149
+ * registry (which only serializes code/dir/deps).
150
+ */
151
+ absPath?: string;
145
152
  }
146
153
  /**
147
154
  * Global registry of bundled module source code, shared across every SSR
@@ -159,7 +166,7 @@ export declare class ModuleRegistry {
159
166
  has(absPath: string): boolean;
160
167
  getKey(absPath: string): string | undefined;
161
168
  get size(): number;
162
- /** Register a module's transpiled body, returning its globally-unique key. */
169
+ /** Register a module's transpiled body, returning its stable key. */
163
170
  register(absPath: string, entry: ModuleEntry): string;
164
171
  getModule(key: string): ModuleEntry | undefined;
165
172
  /** All registered modules as a plain object keyed by synthetic key, for
@@ -1 +1 @@
1
- {"version":3,"file":"module-imports.d.ts","sourceRoot":"","sources":["../src/module-imports.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAGlD,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAyEtD,gFAAgF;AAChF,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAM7D;AAED,gEAAgE;AAChE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAOzD;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAgC1F;AAED,yEAAyE;AACzE,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAQpE;AAED,0FAA0F;AAC1F,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAIvD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,UAAU,EAAE,MAAM,EAAE,EACpB,UAAU,EAAE,MAAM,GAAG,SAAS,GAC7B,IAAI,CAuBN;AAiBD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CA8E7E;AAmFD,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,UAAU,CAAC,OAAO,KAAK,CAAC,GAAG,IAAI,CAAC;IACrC,mEAAmE;IACnE,UAAU,CAAC,EAAE,SAAS,CAAC;CACxB;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CA+B/D;AAgbD,8DAA8D;AAC9D,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAU/D;AAgDD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAiB/E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAoBvE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA+ClF;AA6DD;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAwCpF;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA8B9F;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAiC1F;AAsGD,kFAAkF;AAClF,wBAAgB,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,MAAM,CAiGxF;AAaD,MAAM,WAAW,iBAAiB;IAChC,6EAA6E;IAC7E,GAAG,EAAE,MAAM,CAAC;IACZ,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAC;IACb,6EAA6E;IAC7E,GAAG,EAAE,MAAM,CAAC;IACZ,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,iBAAiB;IAChC,sDAAsD;IACtD,KAAK,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,GAAG,EAAE,MAAM,CAAC;IACZ,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAC;CACd;AAED,6EAA6E;AAC7E,MAAM,WAAW,SAAS;IACxB,6EAA6E;IAC7E,GAAG,EAAE,MAAM,CAAC;IACZ,6EAA6E;IAC7E,GAAG,EAAE,MAAM,CAAC;IACZ,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED,kFAAkF;AAClF,MAAM,WAAW,WAAW;IAC1B,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAC;IACb,6EAA6E;IAC7E,GAAG,EAAE,MAAM,CAAC;IACZ,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED;;;;;;;;;GASG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,SAAS,CAA6B;IAC9C,OAAO,CAAC,IAAI,CAAkC;IAE9C,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAI7B,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAI3C,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,8EAA8E;IAC9E,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,MAAM;IASrD,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAI/C;2DACuD;IACvD,OAAO,IAAI,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC;IAItC,yDAAyD;IACzD,cAAc,IAAI,MAAM;CAOzB;AAgDD,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,SAAS,EAAE,CAAC;CACtB,CAAC;AAEF;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,GAAG,MAAM,CAkEtF;AAID;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,MAAM,EAAE,EACpB,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,QAAQ,EAAE,cAAc,EACxB,SAAS,EAAE,eAAe,GACzB,iBAAiB,EAAE,CAuBrB"}
1
+ {"version":3,"file":"module-imports.d.ts","sourceRoot":"","sources":["../src/module-imports.ts"],"names":[],"mappings":"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"}
@@ -1345,10 +1345,82 @@ function exportGetter(lines, key, valueExpr) {
1345
1345
  lines.push(`Object.defineProperty(exports, ${JSON.stringify(key)}, { get: () => ${valueExpr}, enumerable: true });`);
1346
1346
  }
1347
1347
  let exportCounter = 0;
1348
+ /**
1349
+ * `Promise.resolve().then(() => require("<spec>"))` as an AST expression.
1350
+ * Reusing the original literal node keeps its raw quoting.
1351
+ */
1352
+ function promiseOfRequire(sourceNode) {
1353
+ return {
1354
+ type: 'CallExpression',
1355
+ optional: false,
1356
+ callee: {
1357
+ type: 'MemberExpression',
1358
+ optional: false,
1359
+ computed: false,
1360
+ object: {
1361
+ type: 'CallExpression',
1362
+ optional: false,
1363
+ callee: {
1364
+ type: 'MemberExpression',
1365
+ optional: false,
1366
+ computed: false,
1367
+ object: { type: 'Identifier', name: 'Promise' },
1368
+ property: { type: 'Identifier', name: 'resolve' },
1369
+ },
1370
+ arguments: [],
1371
+ },
1372
+ property: { type: 'Identifier', name: 'then' },
1373
+ },
1374
+ arguments: [
1375
+ {
1376
+ type: 'ArrowFunctionExpression',
1377
+ id: null,
1378
+ expression: true,
1379
+ generator: false,
1380
+ async: false,
1381
+ params: [],
1382
+ body: {
1383
+ type: 'CallExpression',
1384
+ optional: false,
1385
+ callee: { type: 'Identifier', name: 'require' },
1386
+ arguments: [sourceNode],
1387
+ },
1388
+ },
1389
+ ],
1390
+ };
1391
+ }
1392
+ /**
1393
+ * Rewrites `import("<spec>")` for specifiers the SSR module bundle resolved
1394
+ * (those present in the module's `deps`) into a promise of the same
1395
+ * `require` the static-import rewrite emits.
1396
+ *
1397
+ * Registry bodies run inside `new Function`, where a native dynamic `import()`
1398
+ * has no referrer and Node resolves it against the generated function's
1399
+ * location (`/var/task` on Vercel). That directory ships no node_modules, so
1400
+ * e.g. vesk-qr's lazy `import("qrcode-generator")` fails even though the
1401
+ * encoder is already in the bundle. Routing it through the require shim makes
1402
+ * it use `entry.deps`, exactly like a static import.
1403
+ *
1404
+ * Specifiers that were not bundled (framework-owned, `.vsk`, builtins) keep
1405
+ * their original form: the shim and the host loader know how to handle them.
1406
+ */
1407
+ function rewriteDynamicImports(node, specs) {
1408
+ return walk(node, null, {
1409
+ ImportExpression(n) {
1410
+ const spec = stringLiteralValue(n.source);
1411
+ if (!spec || !specs.has(spec))
1412
+ return;
1413
+ return promiseOfRequire(n.source);
1414
+ },
1415
+ });
1416
+ }
1348
1417
  /** Rewrites an ESM program body (imports/exports removed) into CJS statements. */
1349
- export function esmToCjs(body) {
1418
+ export function esmToCjs(body, rewriteImports) {
1419
+ const statements = rewriteImports
1420
+ ? body.map((stmt) => rewriteDynamicImports(stmt, rewriteImports))
1421
+ : body;
1350
1422
  const lines = [];
1351
- for (const stmt of body) {
1423
+ for (const stmt of statements) {
1352
1424
  switch (stmt.type) {
1353
1425
  case 'ImportDeclaration': {
1354
1426
  const source = printNode(stmt.source);
@@ -1457,6 +1529,35 @@ export function esmToCjs(body) {
1457
1529
  }
1458
1530
  return lines.join('\n');
1459
1531
  }
1532
+ /**
1533
+ * Synthetic key for a module. Derived from the absolute path rather than the
1534
+ * registry's insertion order so the SAME module always gets the same key in
1535
+ * every build. Positional keys (`__veskMod${size}`) made cross-build plan
1536
+ * caching unsafe: a second in-process build (the dev server after the prod
1537
+ * build) started with an empty registry, served cached plans whose keys
1538
+ * referred to modules it never registered, and emitted `export const
1539
+ * __veskModules = {}`. Paired with the plan cache replaying each plan's
1540
+ * modules into the fresh registry, a path-derived key makes that replay
1541
+ * idempotent and collision-free.
1542
+ */
1543
+ function moduleKeyFor(absPath) {
1544
+ // Four independent FNV-1a 32-bit lanes → 128 bits of key space, which makes
1545
+ // an accidental collision between two paths (which would silently swap one
1546
+ // module for another) effectively impossible. Hand-rolled rather than
1547
+ // `node:crypto` because this file is bundled into the edge/server runtime,
1548
+ // where a `node:` import fails to resolve.
1549
+ const seeds = [0x811c9dc5, 0x9e3779b1, 0x85ebca6b, 0xc2b2ae35];
1550
+ let hex = '';
1551
+ for (const seed of seeds) {
1552
+ let h = seed >>> 0;
1553
+ for (let i = 0; i < absPath.length; i++) {
1554
+ h ^= absPath.charCodeAt(i);
1555
+ h = Math.imul(h, 0x01000193) >>> 0;
1556
+ }
1557
+ hex += h.toString(16).padStart(8, '0');
1558
+ }
1559
+ return `__veskMod${hex}`;
1560
+ }
1460
1561
  /**
1461
1562
  * Global registry of bundled module source code, shared across every SSR
1462
1563
  * function in a single build. Without it, every page plan re-embedded the
@@ -1479,14 +1580,14 @@ export class ModuleRegistry {
1479
1580
  get size() {
1480
1581
  return this.data.size;
1481
1582
  }
1482
- /** Register a module's transpiled body, returning its globally-unique key. */
1583
+ /** Register a module's transpiled body, returning its stable key. */
1483
1584
  register(absPath, entry) {
1484
1585
  const existing = this.keysByAbs.get(absPath);
1485
1586
  if (existing)
1486
1587
  return existing;
1487
- const key = `__veskMod${this.data.size}`;
1588
+ const key = moduleKeyFor(absPath);
1488
1589
  this.keysByAbs.set(absPath, key);
1489
- this.data.set(key, entry);
1590
+ this.data.set(key, { ...entry, absPath });
1490
1591
  return key;
1491
1592
  }
1492
1593
  getModule(key) {
@@ -1520,41 +1621,51 @@ function stringLiteralValue(node) {
1520
1621
  */
1521
1622
  function collectModuleSpecifiers(ast) {
1522
1623
  const specs = new Set();
1624
+ // Every type-specific visitor MUST call `next()`. zimmerframe only recurses
1625
+ // into a node's children when its visitor does — the default visitor is the
1626
+ // one that calls `next`. Without it, an `import()`/`require()` nested inside
1627
+ // an exported function (e.g. vesk-qr's lazy encoder load) was never seen, so
1628
+ // the module was neither bundled nor recorded in `deps`.
1523
1629
  walk(ast, null, {
1524
- ImportDeclaration(node) {
1525
- if (node.importKind === 'type')
1526
- return;
1527
- const v = stringLiteralValue(node.source);
1528
- if (v)
1529
- specs.add(v);
1630
+ ImportDeclaration(node, ctx) {
1631
+ if (node.importKind !== 'type') {
1632
+ const v = stringLiteralValue(node.source);
1633
+ if (v)
1634
+ specs.add(v);
1635
+ }
1636
+ ctx.next();
1530
1637
  },
1531
- ExportNamedDeclaration(node) {
1532
- if ((node.exportKind === 'type') || !node.source)
1533
- return;
1534
- const v = stringLiteralValue(node.source);
1535
- if (v)
1536
- specs.add(v);
1638
+ ExportNamedDeclaration(node, ctx) {
1639
+ if (node.exportKind !== 'type' && node.source) {
1640
+ const v = stringLiteralValue(node.source);
1641
+ if (v)
1642
+ specs.add(v);
1643
+ }
1644
+ ctx.next();
1537
1645
  },
1538
- ExportAllDeclaration(node) {
1539
- if (node.exportKind === 'type')
1540
- return;
1541
- const v = stringLiteralValue(node.source);
1542
- if (v)
1543
- specs.add(v);
1646
+ ExportAllDeclaration(node, ctx) {
1647
+ if (node.exportKind !== 'type') {
1648
+ const v = stringLiteralValue(node.source);
1649
+ if (v)
1650
+ specs.add(v);
1651
+ }
1652
+ ctx.next();
1544
1653
  },
1545
- CallExpression(node) {
1654
+ CallExpression(node, ctx) {
1546
1655
  const callee = node.callee;
1547
- if (!callee || callee.type !== 'Identifier' || callee.name !== 'require')
1548
- return;
1549
- const args = (node.arguments || []);
1550
- const v = stringLiteralValue(args[0]);
1551
- if (v)
1552
- specs.add(v);
1656
+ if (callee && callee.type === 'Identifier' && callee.name === 'require') {
1657
+ const args = (node.arguments || []);
1658
+ const v = stringLiteralValue(args[0]);
1659
+ if (v)
1660
+ specs.add(v);
1661
+ }
1662
+ ctx.next();
1553
1663
  },
1554
- ImportExpression(node) {
1664
+ ImportExpression(node, ctx) {
1555
1665
  const v = stringLiteralValue(node.source);
1556
1666
  if (v)
1557
1667
  specs.add(v);
1668
+ ctx.next();
1558
1669
  },
1559
1670
  });
1560
1671
  return specs;
@@ -1594,6 +1705,7 @@ export function collectModuleBundled(absPath, registry) {
1594
1705
  const cached = mtimeMs >= 0 ? bundledCodeCache.get(absPath) : undefined;
1595
1706
  let code;
1596
1707
  let specifiers;
1708
+ let deps = null;
1597
1709
  if (cached && cached.mtimeMs === mtimeMs) {
1598
1710
  code = cached.code;
1599
1711
  specifiers = cached.specifiers;
@@ -1614,17 +1726,30 @@ export function collectModuleBundled(absPath, registry) {
1614
1726
  stripped = stripTsTypes(src.ast);
1615
1727
  stripped.body = (stripped.body || []).filter((n) => (n ? !isTypeOnlyStatement(n) : false));
1616
1728
  specifiers = [...collectModuleSpecifiers(src.ast)];
1617
- code = esmToCjs(stripped.body);
1729
+ // Resolve the closure first: the emitter needs the set of specifiers that
1730
+ // became registry modules so it can route `import("<spec>")` through the
1731
+ // same require shim instead of leaving a bare dynamic import for the host
1732
+ // loader (see `rewriteDynamicImports`).
1733
+ deps = resolveBundledDeps(specifiers, dir, registry);
1734
+ code = esmToCjs(stripped.body, new Set(Object.keys(deps)));
1618
1735
  bundledCodeCache.set(absPath, { mtimeMs, code, specifiers });
1619
1736
  evict(bundledCodeCache);
1620
1737
  }
1738
+ if (!deps)
1739
+ deps = resolveBundledDeps(specifiers, dir, registry);
1740
+ return registry.register(absPath, { code, dir, deps });
1741
+ }
1742
+ /**
1743
+ * Resolves every specifier a module reaches for into the registry key of its
1744
+ * bundled closure. Compiler-owned (`@vesk/*`) targets are injected by the SSR
1745
+ * require shim at runtime (`precompile-runtime.ts`), never bundled: their built
1746
+ * JS may contain identifiers the `.vsk` grammar reserves (`component` in
1747
+ * ripple-runtime.js) and would fail to parse here. `.vsk`/`.css`/`.md` carry no
1748
+ * SSR value. Node builtins load natively through the shim.
1749
+ */
1750
+ function resolveBundledDeps(specifiers, dir, registry) {
1621
1751
  const deps = {};
1622
1752
  for (const spec of specifiers) {
1623
- // Compiler-owned (`@vesk/*`) targets are injected by the SSR require shim
1624
- // at runtime (`precompile-runtime.ts`), never bundled: their built JS may
1625
- // contain identifiers the `.vsk` grammar reserves (`component` in
1626
- // ripple-runtime.js) and would fail to parse here. `.vsk`/`.css`/`.md`
1627
- // carry no SSR value. Node builtins load natively through the shim.
1628
1753
  if (isCompilerOwnedTarget(spec) || isValueLessTarget(spec))
1629
1754
  continue;
1630
1755
  const depPath = resolveSsrModule(spec, dir);
@@ -1632,7 +1757,7 @@ export function collectModuleBundled(absPath, registry) {
1632
1757
  continue;
1633
1758
  deps[spec] = collectModuleBundled(depPath, registry);
1634
1759
  }
1635
- return registry.register(absPath, { code, dir, deps });
1760
+ return deps;
1636
1761
  }
1637
1762
  const bundledCodeCache = new Map();
1638
1763
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"precompile.d.ts","sourceRoot":"","sources":["../src/precompile.ts"],"names":[],"mappings":"AASA,OAAO,EAGL,cAAc,EACf,MAAM,mCAAmC,CAAC;AAC3C,OAAO,KAAK,EACV,kBAAkB,EAGnB,MAAM,uCAAuC,CAAC;AAG/C;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,MAAM,EACnB,QAAQ,CAAC,EAAE,cAAc,GACxB,kBAAkB,CAapB;AAeD,iFAAiF;AACjF,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C"}
1
+ {"version":3,"file":"precompile.d.ts","sourceRoot":"","sources":["../src/precompile.ts"],"names":[],"mappings":"AASA,OAAO,EAIL,cAAc,EACf,MAAM,mCAAmC,CAAC;AAC3C,OAAO,KAAK,EACV,kBAAkB,EAGnB,MAAM,uCAAuC,CAAC;AAG/C;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,MAAM,EACnB,QAAQ,CAAC,EAAE,cAAc,GACxB,kBAAkB,CAsBpB;AA8CD,iFAAiF;AACjF,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C"}
@@ -26,16 +26,54 @@ export function precompileFile(source, sourcePath, registry) {
26
26
  const hit = precompileCache.get(sourcePath);
27
27
  // Compare the source, not just the path: the dev server rebuilds in-process
28
28
  // and a stale plan would silently ship yesterday's component.
29
- if (hit !== undefined && hit.source === source)
29
+ if (hit !== undefined && hit.source === source) {
30
+ // A plan is only half of the output: it references module keys that live
31
+ // in the caller's registry. A second build in the same process (prod then
32
+ // dev under `e2e-setup`) starts with a fresh registry, so replaying the
33
+ // memoized plan without its modules left `__veskModules` empty and every
34
+ // bare-package import (`vesk-qr`, …) resolved to `undefined`. Keys are
35
+ // path-derived, so registering the same absPaths here is idempotent.
36
+ for (const { absPath, entry } of hit.modules)
37
+ reg.register(absPath, entry);
30
38
  return hit.plan;
39
+ }
31
40
  const plan = precompileFileInternal(source, sourcePath, new Set(), reg);
32
41
  // Bound it: plans are sizeable on a large app, and a watch session can
33
42
  // outlive many builds.
34
43
  if (precompileCache.size >= 512)
35
44
  precompileCache.clear();
36
- precompileCache.set(sourcePath, { source, plan });
45
+ precompileCache.set(sourcePath, { source, plan, modules: collectPlanModules(plan, reg) });
37
46
  return plan;
38
47
  }
48
+ /**
49
+ * Every module entry a plan (and its nested `.vsk` sub-plans) resolves
50
+ * against, including transitive deps. The shared `__veskModules` registry
51
+ * must contain the whole closure, not just the keys named by `plan.modules`,
52
+ * or `evaluateModule` cannot walk `deps` at hydrate time.
53
+ */
54
+ function collectPlanModules(plan, registry) {
55
+ const out = [];
56
+ const seen = new Set();
57
+ const visitKey = (key) => {
58
+ if (seen.has(key))
59
+ return;
60
+ seen.add(key);
61
+ const entry = registry.getModule(key);
62
+ if (!entry || !entry.absPath)
63
+ return;
64
+ out.push({ absPath: entry.absPath, entry });
65
+ for (const depKey of Object.values(entry.deps))
66
+ visitKey(depKey);
67
+ };
68
+ const visitPlan = (p) => {
69
+ for (const mod of p.modules)
70
+ visitKey(mod.key);
71
+ for (const sub of p.subFiles)
72
+ visitPlan(sub.plan);
73
+ };
74
+ visitPlan(plan);
75
+ return out;
76
+ }
39
77
  /**
40
78
  * Compiled plans, keyed by absolute path.
41
79
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vesk/compiler",
3
- "version": "0.2.93",
3
+ "version": "0.2.94",
4
4
  "type": "module",
5
5
  "description": "Vesk compiler — lexer, parser, semantic analysis, IR, codegen",
6
6
  "main": "./dist/index.js",
@@ -20,7 +20,7 @@
20
20
  },
21
21
  "dependencies": {
22
22
  "@sveltejs/acorn-typescript": "^1.0.0",
23
- "@vesk/types": "^0.2.93",
23
+ "@vesk/types": "^0.2.94",
24
24
  "acorn": "^8.15.0",
25
25
  "esrap": "^2.3.0",
26
26
  "is-reference": "^3.0.0",