@vesk/compiler 0.2.41 → 0.2.43

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":"actions.d.ts","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;CACb;AAED,eAAO,MAAM,aAAa,mBAAmB,CAAC;AAE9C,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAW9C;AA6BD;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAqCtF;AAeD,wBAAgB,2BAA2B,CAAC,YAAY,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,EAAE,CAOvG;AAED,iFAAiF;AACjF,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAsBzD"}
1
+ {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;CACb;AAED,eAAO,MAAM,aAAa,mBAAmB,CAAC;AAE9C,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAW9C;AA6BD;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAqCtF;AAeD,wBAAgB,2BAA2B,CAAC,YAAY,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,EAAE,CAWvG;AAaD,iFAAiF;AACjF,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAsBzD"}
package/dist/actions.js CHANGED
@@ -3,6 +3,7 @@ import { print } from 'esrap';
3
3
  import ts from 'esrap/languages/ts';
4
4
  import { parse } from '@vesk/compiler/src/parser';
5
5
  import { stripTsTypes, hasTsSyntax, isTypeOnlyStatement, stripCodeTypes } from '@vesk/compiler/src/strip-ts';
6
+ import { stripTrackDeclMarkers } from '@vesk/compiler/src/tokens';
6
7
  export const ACTION_PREFIX = '/_vesk/action/';
7
8
  export function hashString(str) {
8
9
  let h1 = 0x811c9dc5;
@@ -102,12 +103,27 @@ function printWithTypesStripped(ast, code, hadTs = hasTsSyntax(ast)) {
102
103
  export function transformTopLevelForActions(topLevelCode, mode) {
103
104
  const out = [];
104
105
  for (const c of topLevelCode) {
105
- const rewritten = rewriteTopLevelActions(c, mode);
106
+ // A top-level TrackDecl (`const &[count] = track(0)`) is parser-only syntax:
107
+ // the `&` is still in this text, and both consumers are plain JavaScript
108
+ // engines — `new Function` on the server, a browser module parse for the
109
+ // client. Blank the markers before either sees the code.
110
+ const rewritten = rewriteTopLevelActions(stripTopLevelTrackDecls(c), mode);
106
111
  if (rewritten !== '')
107
112
  out.push(rewritten);
108
113
  }
109
114
  return out;
110
115
  }
116
+ /** Remove TrackDecl `&` markers from a top-level code chunk. */
117
+ function stripTopLevelTrackDecls(code) {
118
+ let ast;
119
+ try {
120
+ ast = parse(code);
121
+ }
122
+ catch {
123
+ return code;
124
+ }
125
+ return stripTrackDeclMarkers(code, 0, ast);
126
+ }
111
127
  /** Collect the stable action ids defined by a page source (for the manifest). */
112
128
  export function collectActionIds(source) {
113
129
  const ids = [];
@@ -8,6 +8,18 @@ export interface TrackedInfo {
8
8
  export declare function semicolonizeStatement(code: string): string;
9
9
  export declare function transformTracked(irNode: Expression | RuntimeStatement | DynamicBinding, tracked: Map<string, TrackedInfo>): string;
10
10
  export declare function collectTrackedNames(body: IRNode[]): Map<string, TrackedInfo>;
11
+ /**
12
+ * Collect the tracked bindings a prop expression READS, so a string-returning
13
+ * component call can be re-rendered when one of them changes.
14
+ *
15
+ * `primitive()` / `leaf()` bodies run once and their markup is converted once,
16
+ * so a tracked read inside them subscribes nothing. The call site passes the
17
+ * deps to {@link rerenderNode}, which re-reads them inside an effect.
18
+ *
19
+ * Property keys and member properties (`obj.bump`, `x.set(...)`) are not
20
+ * tracked reads — only the object positions are, matching `transformTracked`.
21
+ */
22
+ export declare function collectTrackedDeps(value: unknown, tracked: Map<string, TrackedInfo>): string[];
11
23
  /**
12
24
  * Tracked reads inside a track/derived declaration init are re-emitted as
13
25
  * `get(…)` subscriptions so a `derived(() => … cell …)` (or
@@ -56,6 +68,11 @@ export declare function compileClientBoth(source: string, _componentName: string
56
68
  comp: string;
57
69
  hyd: string;
58
70
  name: string | null;
71
+ aliases: Array<{
72
+ local: string;
73
+ exported: string;
74
+ }>;
75
+ reexportPaths: string[];
59
76
  };
60
77
  export { compileClient as compile, isStaticIR };
61
78
  //# sourceMappingURL=client-codegen.d.ts.map
@@ -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,EASjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAyCxD,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,CAiHlI;AAID,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAU5E;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,MAAM,CAY5F;AAoBD,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;AAu3DD,iBAAS,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAe3C;AAmJD,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAO9C;AAqED,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,CAAA;CAAE,CA0BpD;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,EASjB,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,CAU5E;AAED;;;;;;;;;;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;AAoBD,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;AAi7DD,iBAAS,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAe3C;AAmJD,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAO9C;AAuED,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,CAAA;CAAE,CAqClI;AAED,OAAO,EAAE,aAAa,IAAI,OAAO,EAAE,UAAU,EAAE,CAAC"}
@@ -10,6 +10,7 @@ import { extractRuntimeNames, extractTopLevelNames } from '@vesk/compiler/src/se
10
10
  import { importBindingPairs, localValueImportNames } from '@vesk/compiler/src/module-imports';
11
11
  import { stripTrackGeneric } from '@vesk/compiler/src/scan';
12
12
  import { importModuleTarget } from '@vesk/compiler/src/tokens';
13
+ import { collectVskReexportPaths, vskRegistryAliases } from '@vesk/compiler/src/vsk-imports';
13
14
  import { inlineMdImportsFrom } from '@vesk/compiler/src/md-inline';
14
15
  import { stripTsTypes, hasTsSyntax } from '@vesk/compiler/src/strip-ts';
15
16
  function memberExpr(object, property) {
@@ -42,6 +43,66 @@ function simpleGetName(expr) {
42
43
  }
43
44
  return inner;
44
45
  }
46
+ const BINDING_REF_CALLS = ['bindValue', 'bindChecked', 'bindGroup'];
47
+ /**
48
+ * A binding ref (`bindValue`/`bindChecked`/`bindGroup`) two-way-binds the raw
49
+ * tracked CELL — the web runtime expects the cell object, never its current
50
+ * value. transformTracked rewrites a virtual tracked name read to
51
+ * `get(cell)`, so `ref={bindValue(name)}` would compile to
52
+ * `bindValue(get(cell))` and hand the binding the cell's value. Untrack the
53
+ * first argument back to the bare cell name (`bindValue(cell)`), mirroring
54
+ * how a plain `ref={cell}` emits `set(cell, el)`. Function-form bindings
55
+ * (`bindValue(() => get(x), v => set(x, v))`) never start with `get(` and
56
+ * pass through unchanged. String scan only — no regex.
57
+ */
58
+ function untrackBindingArg(expr) {
59
+ let head = -1;
60
+ for (const name of BINDING_REF_CALLS) {
61
+ if (expr.startsWith(`${name}(`)) {
62
+ head = name.length;
63
+ break;
64
+ }
65
+ }
66
+ if (head < 0)
67
+ return expr;
68
+ const rest = expr.slice(head + 1);
69
+ if (rest[0] !== 'g' || rest[1] !== 'e' || rest[2] !== 't' || rest[3] !== '(')
70
+ return expr;
71
+ let i = 4;
72
+ let word = '';
73
+ for (; i < rest.length; i++) {
74
+ const c = rest.charCodeAt(i);
75
+ const ok = (c >= 48 && c <= 57) || (c >= 65 && c <= 90) || (c >= 97 && c <= 122) || c === 95 || c === 36;
76
+ if (!ok)
77
+ break;
78
+ word += rest[i];
79
+ }
80
+ if (word.length === 0 || rest[i] !== ')')
81
+ return expr;
82
+ const after = i + 1;
83
+ if (rest[after] !== ',' && rest[after] !== ')')
84
+ return expr;
85
+ return expr.slice(0, head + 1) + word + rest.slice(after);
86
+ }
87
+ /**
88
+ * For a `ref=` binding whose expression resolves to a tracked cell — either a
89
+ * virtual name (`ref={box}` → emitted `get(boxCell)`) or the raw cell
90
+ * (`ref={boxCell}` → emitted `boxCell`) — the compiled mount must SET the cell
91
+ * to the element, not call the cell's current value. The old `(get(x))(el)`
92
+ * call form is only correct for function refs (`ref={el => x = el}`).
93
+ * Returns the cell name to assign, or null to keep the call form.
94
+ */
95
+ function trackedRefTarget(expr, tracked) {
96
+ const cell = simpleGetName(expr);
97
+ if (cell !== null)
98
+ return cell;
99
+ if (/^[A-Za-z_$][\w$]*$/.test(expr)) {
100
+ const info = tracked.get(expr);
101
+ if (info && info.kind === 'cell' && info.cellName === expr)
102
+ return expr;
103
+ }
104
+ return null;
105
+ }
45
106
  export function semicolonizeStatement(code) {
46
107
  const trimmed = code.trimEnd();
47
108
  if (!trimmed || trimmed.endsWith(';') || trimmed.endsWith('}'))
@@ -162,6 +223,25 @@ export function transformTracked(irNode, tracked) {
162
223
  }
163
224
  return context.next();
164
225
  },
226
+ Property(node, context) {
227
+ // Shorthand `{ bump }` shares ONE node for key and value, so the key
228
+ // skip below cannot apply. Rewriting the value makes the property
229
+ // non-shorthand, and the shorthand flag has to go with it — otherwise
230
+ // the printer emits `get(cell): get(cell)`, which is not parseable.
231
+ if (node.shorthand && node.value && node.value.type === 'Identifier' && !node.computed) {
232
+ const info = context.state.get(node.value.name);
233
+ if (info && info.kind === 'virtual') {
234
+ return {
235
+ ...node,
236
+ shorthand: false,
237
+ value: callExpr({ type: 'Identifier', name: 'get' }, [
238
+ { type: 'Identifier', name: info.cellName },
239
+ ]),
240
+ };
241
+ }
242
+ }
243
+ return context.next();
244
+ },
165
245
  Identifier(node, context) {
166
246
  const parent = context.path.at(-1);
167
247
  if (parent) {
@@ -184,6 +264,16 @@ export function transformTracked(irNode, tracked) {
184
264
  parent.key.type === 'Identifier' &&
185
265
  parent.key.name === 'into')
186
266
  return context.next();
267
+ // A non-computed, non-shorthand property KEY is a name, not a read:
268
+ // `{ bump: bump }` must keep the key `bump` even when `bump` is a
269
+ // tracked cell — rewriting it yields the unparseable
270
+ // `{ get(bump): get(bump) }`. Shorthand keys are the value node, so
271
+ // they fall through to the rewrite below (with `shorthand` cleared).
272
+ if (parent.type === 'Property' &&
273
+ parent.key === node &&
274
+ !parent.computed &&
275
+ !parent.shorthand)
276
+ return context.next();
187
277
  if (parent.type === 'MemberExpression' &&
188
278
  !parent.computed &&
189
279
  parent.object === node &&
@@ -216,6 +306,42 @@ export function collectTrackedNames(body) {
216
306
  }
217
307
  return names;
218
308
  }
309
+ /**
310
+ * Collect the tracked bindings a prop expression READS, so a string-returning
311
+ * component call can be re-rendered when one of them changes.
312
+ *
313
+ * `primitive()` / `leaf()` bodies run once and their markup is converted once,
314
+ * so a tracked read inside them subscribes nothing. The call site passes the
315
+ * deps to {@link rerenderNode}, which re-reads them inside an effect.
316
+ *
317
+ * Property keys and member properties (`obj.bump`, `x.set(...)`) are not
318
+ * tracked reads — only the object positions are, matching `transformTracked`.
319
+ */
320
+ export function collectTrackedDeps(value, tracked) {
321
+ const ast = value?.ast;
322
+ if (!ast || typeof ast !== 'object' || tracked.size === 0)
323
+ return [];
324
+ const found = [];
325
+ const seen = new Set();
326
+ walk(ast, tracked, {
327
+ Identifier(node, context) {
328
+ const parent = context.path.at(-1);
329
+ if (parent) {
330
+ if (parent.type === 'MemberExpression' && !parent.computed && parent.property === node)
331
+ return context.next();
332
+ if (parent.type === 'Property' && parent.key === node)
333
+ return context.next();
334
+ }
335
+ const info = context.state.get(node.name);
336
+ if (info && !seen.has(node.name)) {
337
+ seen.add(node.name);
338
+ found.push(node.name);
339
+ }
340
+ return context.next();
341
+ },
342
+ });
343
+ return found;
344
+ }
219
345
  /**
220
346
  * Tracked reads inside a track/derived declaration init are re-emitted as
221
347
  * `get(…)` subscriptions so a `derived(() => … cell …)` (or
@@ -597,8 +723,9 @@ function emitStatic(ctx, node, tracked, effectsVar, skipK = 0, regionBudget) {
597
723
  const target = attr.target || '';
598
724
  const isEvent = target.startsWith('on') && target.length > 2;
599
725
  if (target === 'ref') {
600
- const expr = transformTracked(attr.expression, tracked);
601
- ctx.push(`(${expr})(${ssrEl});`);
726
+ const expr = untrackBindingArg(transformTracked(attr.expression, tracked));
727
+ const cell = trackedRefTarget(expr, tracked);
728
+ ctx.push(cell !== null ? `set(${cell}, ${ssrEl});` : `(${expr})(${ssrEl});`);
602
729
  }
603
730
  else if (isEvent) {
604
731
  const eventName = target.slice(2).toLowerCase();
@@ -689,8 +816,9 @@ function emitStatic(ctx, node, tracked, effectsVar, skipK = 0, regionBudget) {
689
816
  const target = attr.target || '';
690
817
  const isEvent = target.startsWith('on') && target.length > 2;
691
818
  if (target === 'ref') {
692
- const expr = transformTracked(attr.expression, tracked);
693
- ctx.push(`(${expr})(${el});`);
819
+ const expr = untrackBindingArg(transformTracked(attr.expression, tracked));
820
+ const cell = trackedRefTarget(expr, tracked);
821
+ ctx.push(cell !== null ? `set(${cell}, ${el});` : `(${expr})(${el});`);
694
822
  }
695
823
  else if (isEvent) {
696
824
  const eventName = target.slice(2).toLowerCase();
@@ -962,7 +1090,36 @@ function emitComponentCall(ctx, node, tracked, effectsVar, parentVar, compPrefix
962
1090
  // as `children`: a fresh DocumentFragment per slot hoisted from the IR.
963
1091
  const slotChildren = node.children.filter((c) => c instanceof PropSlot);
964
1092
  const regChildren = node.children.filter((c) => !(c instanceof PropSlot));
965
- const callArgs = () => `{ ${propsEntries.join(', ')} }`;
1093
+ // Call targets that are not known compiled components (imported values,
1094
+ // member-expression tags) cannot claim, so the caller adopts their SSR root
1095
+ // itself. They also do not run the `props = reactiveProps(props)` prologue
1096
+ // that compiled components carry, so tracked cells passed as props would
1097
+ // reach them raw — the server unwraps them, so a `primitive()`/`leaf()`
1098
+ // reading `props.bump` would render `0[object Object]` on the client only.
1099
+ // Wrap the literal here to keep both sides reading values.
1100
+ const plainTarget = !!(calleeExpr || ctx.importedNames.has(node.componentName)) && !ctx.selfClaimNames.has(node.componentName);
1101
+ // Tracked bindings this call's markup is derived from. Only a plain target
1102
+ // needs them: a compiled component re-runs its own bindings, but a
1103
+ // `primitive()`/`leaf()`/imported helper that READS a cell through
1104
+ // `reactiveProps` would otherwise leave its markup stale forever.
1105
+ const trackedDeps = [];
1106
+ if (plainTarget) {
1107
+ for (const p of node.props) {
1108
+ if (typeof p.value === 'string')
1109
+ continue;
1110
+ for (const d of collectTrackedDeps(p.value, tracked))
1111
+ if (!trackedDeps.includes(d))
1112
+ trackedDeps.push(d);
1113
+ }
1114
+ for (const sp of node.spreadProps) {
1115
+ for (const d of collectTrackedDeps(sp, tracked))
1116
+ if (!trackedDeps.includes(d))
1117
+ trackedDeps.push(d);
1118
+ }
1119
+ }
1120
+ const callArgs = () => (plainTarget
1121
+ ? `reactiveProps({ ${propsEntries.join(', ')} })`
1122
+ : `{ ${propsEntries.join(', ')} }`);
966
1123
  if (ctx.hydrate) {
967
1124
  const access = calleeExpr
968
1125
  ?? (ctx.importedNames.has(node.componentName)
@@ -982,7 +1139,6 @@ function emitComponentCall(ctx, node, tracked, effectsVar, parentVar, compPrefix
982
1139
  // compiled components (imported values, member-expression tags) cannot
983
1140
  // claim, so after the call we adopt their SSR root ourselves and replace it
984
1141
  // with the fresh node they returned — never a duplicate, never a box.
985
- const plainTarget = !!(calleeExpr || ctx.importedNames.has(node.componentName)) && !ctx.selfClaimNames.has(node.componentName);
986
1142
  const walkerArg = ctx.walker;
987
1143
  // Markerless value-thread offset (Phase 3.c): the residue that precedes THIS
988
1144
  // call site — a static sibling the walker never claimed (`skipK`), or a
@@ -1001,13 +1157,21 @@ function emitComponentCall(ctx, node, tracked, effectsVar, parentVar, compPrefix
1001
1157
  const maybeReplace = (v) => {
1002
1158
  if (!plainTarget)
1003
1159
  return;
1004
- // nodeType 11 = DocumentFragment: self-claiming imports (Link/Md/Form)
1160
+ // nodeType 11 = DocumentFragment. Self-claiming imports (Link/Md/Form)
1005
1161
  // return a fragment when they adopted their SSR root, so there is nothing
1006
- // to replace — claiming here would steal the NEXT sibling's root.
1162
+ // to replace — claiming here would steal the NEXT sibling's root. Those
1163
+ // are excluded by `plainTarget` above, so a fragment reaching this branch
1164
+ // is a plain target that returned SEVERAL roots (a leaf/primitive string
1165
+ // with siblings in it) and its children must be spliced in. Branch on the
1166
+ // runtime nodeType rather than guessing at the target's authoring style.
1007
1167
  const claim = promptExpr
1008
1168
  ? `${walkerArg}.claimOnly(undefined, ${promptExpr})`
1009
1169
  : `${walkerArg}.claimOnly()`;
1010
- ctx.push(`if (${v} && ${v}.parentNode == null && ${v}.nodeType !== 11) { const __sr = ${claim}; if (__sr && __sr.parentNode) __sr.parentNode.replaceChild(${v}, __sr); }`);
1170
+ // A several-root render owns as many SSR slots as it has roots. Claiming
1171
+ // one and splicing the rest in front of it left the unclaimed SSR
1172
+ // siblings in place, duplicating them; the extra claims are removed with
1173
+ // the first so the fresh roots land exactly where the SSR range sat.
1174
+ ctx.push(`if (${v} && ${v}.parentNode == null) { if (${v}.nodeType === 11) { const __cnt = ${v}.childNodes.length; let __sr = null; for (let __i = 0; __i < __cnt; __i++) { const __c = ${claim}; if (__c && __c.parentNode) { if (__sr) { __c.remove(); } else { __sr = __c; } } } if (__sr) { const __p = __sr.parentNode; while (${v}.firstChild) __p.insertBefore(${v}.firstChild, __sr); __p.removeChild(__sr); } } else { const __sr = ${claim}; if (__sr && __sr.parentNode) __sr.parentNode.replaceChild(${v}, __sr); } }`);
1011
1175
  // A plain target consumes the region budget at adoption; subsequent
1012
1176
  // claims in the enclosing branch must resolve positionally from here.
1013
1177
  if (regionBudget && ctx.markerless)
@@ -1026,7 +1190,14 @@ function emitComponentCall(ctx, node, tracked, effectsVar, parentVar, compPrefix
1026
1190
  const frag = ctx.n();
1027
1191
  const wipeMount = ctx.linkNames.has(node.componentName);
1028
1192
  const savedHydrate = ctx.hydrate;
1029
- if (wipeMount)
1193
+ // Self-claiming runtime components (Form/Field/Link/Md/etc.) claim their
1194
+ // own SSR root before their children are useful. Building their children
1195
+ // through the caller's active walker would let a nested Field consume
1196
+ // the component's preceding static sibling (for example <h1> before
1197
+ // <Form>), leaving the real Form slot misaligned. Their hydrate path
1198
+ // deliberately preserves the SSR interior, so construct the argument
1199
+ // fresh and let the runtime component adopt the existing root.
1200
+ if (wipeMount || ctx.selfClaimNames.has(node.componentName))
1030
1201
  ctx.hydrate = false;
1031
1202
  ctx.push(`const ${frag} = (() => { const $f = document.createDocumentFragment();`);
1032
1203
  const savedEffects = ctx.effects;
@@ -1051,7 +1222,13 @@ function emitComponentCall(ctx, node, tracked, effectsVar, parentVar, compPrefix
1051
1222
  }
1052
1223
  ctx.push(`let ${v} = undefined;`);
1053
1224
  ctx.push(`if (__hydrate) __hydrate.childFrame = (__hydrate.childFrame || 0) + 1;`);
1054
- ctx.push(`try { ${v} = ${awaitKw}${access}(${callArgs()}, __registry, ${walkerArg}); } finally { if (__hydrate) __hydrate.childFrame--; }`);
1225
+ ctx.push(`try { ${v} = toDomNode(${awaitKw}${access}(${callArgs()}, __registry, ${walkerArg})); } finally { if (__hydrate) __hydrate.childFrame--; }`);
1226
+ // Snapshot a several-root render's roots HERE, while the fragment still
1227
+ // holds them: adoption drains it, and an emptied fragment is no handle for
1228
+ // `rerenderNode` to follow on the next update.
1229
+ const rootsVar = trackedDeps.length > 0 ? ctx.n() : null;
1230
+ if (rootsVar)
1231
+ ctx.push(`const ${rootsVar} = ${v} && ${v}.nodeType === 11 ? Array.from(${v}.childNodes) : [${v}];`);
1055
1232
  // Spend the region budget only once the call RETURNS: a self-claiming child
1056
1233
  // that throws before claiming (the try/catch fallback in / with fail:true)
1057
1234
  // consumed the takeSkipK deposit but never advanced the walker cursor, so the
@@ -1062,6 +1239,9 @@ function emitComponentCall(ctx, node, tracked, effectsVar, parentVar, compPrefix
1062
1239
  ctx.push(`${regionBudget} = 0;`);
1063
1240
  maybeReplace(v);
1064
1241
  maybeRetire();
1242
+ if (trackedDeps.length > 0) {
1243
+ ctx.push(`rerenderNode(${rootsVar}, [${trackedDeps.join(', ')}], () => ${awaitKw}${access}(${callArgs()}, __registry, ${walkerArg}));`);
1244
+ }
1065
1245
  return v;
1066
1246
  }
1067
1247
  else {
@@ -1086,14 +1266,24 @@ function emitComponentCall(ctx, node, tracked, effectsVar, parentVar, compPrefix
1086
1266
  propsEntries.push(`children: ${frag}`);
1087
1267
  }
1088
1268
  if (calleeExpr) {
1089
- ctx.push(`const ${v} = ${calleeExpr}(${callArgs()});`);
1269
+ ctx.push(`const ${v} = toDomNode(${calleeExpr}(${callArgs()}));`);
1090
1270
  }
1091
1271
  else if (ctx.importedNames.has(node.componentName)) {
1092
- ctx.push(`const ${v} = ${awaitKw}${node.componentName}(${callArgs()});`);
1272
+ ctx.push(`const ${v} = toDomNode(${awaitKw}${node.componentName}(${callArgs()}));`);
1093
1273
  }
1094
1274
  else {
1095
1275
  ctx.push(`if (${compPrefix}[${JSON.stringify(node.componentName)}] == null) throw new Error(${JSON.stringify(`Component "${node.componentName}" was not found while rendering. Declare it with the \`component\` keyword, import it, or register it in the component registry.`)});`);
1096
- ctx.push(`const ${v} = ${awaitKw}${compPrefix}[${JSON.stringify(node.componentName)}](${callArgs()});`);
1276
+ ctx.push(`const ${v} = toDomNode(${awaitKw}${compPrefix}[${JSON.stringify(node.componentName)}](${callArgs()}));`);
1277
+ }
1278
+ if (trackedDeps.length > 0) {
1279
+ const calleeRef = calleeExpr
1280
+ ?? (ctx.importedNames.has(node.componentName)
1281
+ ? node.componentName
1282
+ : `${compPrefix}[${JSON.stringify(node.componentName)}]`);
1283
+ // Snapshot the roots while the fragment still holds them — see above.
1284
+ const rootsVar2 = ctx.n();
1285
+ ctx.push(`const ${rootsVar2} = ${v} && ${v}.nodeType === 11 ? Array.from(${v}.childNodes) : [${v}];`);
1286
+ ctx.push(`rerenderNode(${rootsVar2}, [${trackedDeps.join(', ')}], () => ${awaitKw}${calleeRef}(${callArgs()}));`);
1097
1287
  }
1098
1288
  }
1099
1289
  return v;
@@ -2547,7 +2737,9 @@ function emitClientFromIR(ir, options) {
2547
2737
  }
2548
2738
  }
2549
2739
  const exportCode = exportLines.join('\n');
2550
- const runtimeNames = ['track', 'get', 'set', 'destroy_block', 'getActiveComponent', 'setActiveComponent', 'reactiveProps', 'applyStyle'];
2740
+ // `toDomNode` normalizes a component call's return (a primitive/leaf string)
2741
+ // into a Node; it is emitted at every call site, so it is always needed.
2742
+ const runtimeNames = ['track', 'get', 'set', 'destroy_block', 'getActiveComponent', 'setActiveComponent', 'reactiveProps', 'applyStyle', 'toDomNode', 'rerenderNode'];
2551
2743
  if (ir.components.some(c => !isStaticIR(c.body)))
2552
2744
  runtimeNames.push('effect');
2553
2745
  for (const name of usedRuntimeBindings(ir))
@@ -2631,12 +2823,23 @@ export function compileClientBoth(source, _componentName, sourcePath, opts) {
2631
2823
  // allocator: hyd continues after the names comp already consumed.
2632
2824
  const alloc = nameAllocFor(sourcePath);
2633
2825
  const comp = emitClientFromIR(ir, { forceClient: true, nameAllocator: alloc });
2826
+ // `.vsk` modules are registry-keyed, not real ES modules: `export { A as B }`
2827
+ // and `import { A as B } from './x.vsk'` are aliases the client bundle must
2828
+ // register on `__components`, since nothing is emitted for them.
2829
+ const aliases = vskRegistryAliases(ir.imports, ir.exportAliases);
2830
+ // `export * from './x.vsk'` targets must be compiled and registered in this
2831
+ // file's chunk too, exactly like `.vsk` imports.
2832
+ const reexportPaths = sourcePath
2833
+ ? collectVskReexportPaths(ir.reexportSources, sourcePath)
2834
+ : [];
2634
2835
  if (opts?.skipHyd)
2635
- return { comp, hyd: '', name };
2836
+ return { comp, hyd: '', name, aliases, reexportPaths };
2636
2837
  return {
2637
2838
  comp,
2638
2839
  hyd: emitClientFromIR(irHyd, { forceClient: true, hydrate: true, includeTopLevel: false, nameAllocator: alloc, markerless: opts?.markerless !== false }),
2639
2840
  name,
2841
+ aliases,
2842
+ reexportPaths,
2640
2843
  };
2641
2844
  }
2642
2845
  export { compileClient as compile, isStaticIR };
package/dist/errors.d.ts CHANGED
@@ -22,6 +22,7 @@ export declare class VeskError extends Error {
22
22
  code?: string;
23
23
  constructor(message: string, opts?: VeskErrorOptions);
24
24
  static notFound(name: string, candidates?: string[], context?: VeskErrorOptions): VeskError;
25
+ static vskNamespaceTag(context?: VeskErrorOptions): VeskError;
25
26
  static classDecl(context?: VeskErrorOptions): VeskError;
26
27
  static serverBlockInClient(compName: string, context?: VeskErrorOptions): VeskError;
27
28
  static clientBlockInServer(compName: string, context?: VeskErrorOptions): VeskError;
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAoBxD;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,WAAW,GAAE,MAAU,GAAG,MAAM,GAAG,IAAI,CAWrG;AAqCD,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,SAAI,EAAE,KAAK,SAAI,GAAG,MAAM,CAkBrG;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAgBD,qBAAa,SAAU,SAAQ,KAAK;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;gBAEF,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,gBAAqB;IAYxD,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,GAAE,MAAM,EAAO,EAAE,OAAO,GAAE,gBAAqB,GAAG,SAAS;IA8BnG,MAAM,CAAC,SAAS,CAAC,OAAO,GAAE,gBAAqB,GAAG,SAAS;IAoB3D,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,SAAS;IAmBvF,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,SAAS;IAmBvF,MAAM,CAAC,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,GAAE,MAAM,EAAO,EAAE,OAAO,GAAE,gBAAqB,GAAG,SAAS;IAO3G,MAAM,CAAC,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,GAAE,MAAM,EAAO,EAAE,OAAO,GAAE,gBAAqB,GAAG,SAAS;IAYvG,MAAM,CAAC,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,SAAS;IAmB/G,MAAM,CAAC,cAAc,CAAC,OAAO,GAAE,gBAAgB,GAAG;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,SAAS;IAmBpF,QAAQ,IAAI,MAAM;IA0BlB,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAclC"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAoBxD;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,WAAW,GAAE,MAAU,GAAG,MAAM,GAAG,IAAI,CAWrG;AAqCD,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,SAAI,EAAE,KAAK,SAAI,GAAG,MAAM,CAkBrG;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAgBD,qBAAa,SAAU,SAAQ,KAAK;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;gBAEF,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,gBAAqB;IAYxD,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,GAAE,MAAM,EAAO,EAAE,OAAO,GAAE,gBAAqB,GAAG,SAAS;IA8BnG,MAAM,CAAC,eAAe,CAAC,OAAO,GAAE,gBAAqB,GAAG,SAAS;IAmBjE,MAAM,CAAC,SAAS,CAAC,OAAO,GAAE,gBAAqB,GAAG,SAAS;IAoB3D,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,SAAS;IAmBvF,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,SAAS;IAmBvF,MAAM,CAAC,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,GAAE,MAAM,EAAO,EAAE,OAAO,GAAE,gBAAqB,GAAG,SAAS;IAO3G,MAAM,CAAC,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,GAAE,MAAM,EAAO,EAAE,OAAO,GAAE,gBAAqB,GAAG,SAAS;IAYvG,MAAM,CAAC,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,SAAS;IAmB/G,MAAM,CAAC,cAAc,CAAC,OAAO,GAAE,gBAAgB,GAAG;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,SAAS;IAmBpF,QAAQ,IAAI,MAAM;IA0BlB,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAclC"}
package/dist/errors.js CHANGED
@@ -150,6 +150,21 @@ export class VeskError extends Error {
150
150
  : '',
151
151
  });
152
152
  }
153
+ static vskNamespaceTag(context = {}) {
154
+ return new VeskError('Namespace imports are not supported for `.vsk` modules.', {
155
+ ...context,
156
+ code: context.code || 'V0410',
157
+ suggestions: [
158
+ "Import the component by name: import { MyIcon } from './icons.vsk'",
159
+ "Rename on import: import { MyIcon as Icon } from './icons.vsk'",
160
+ ],
161
+ nextSteps: [
162
+ 'A `.vsk` component is a registry entry keyed by its name, not a module namespace object, so `<ns.Icon />` cannot be resolved.',
163
+ 'If you need a namespace object, import from a `.ts`/`.js` module instead — those are real ES modules.',
164
+ ],
165
+ tip: 'A `.vsk` module exposes its components as named exports; use a named or renamed import rather than `import * as ns`.',
166
+ });
167
+ }
153
168
  static classDecl(context = {}) {
154
169
  return new VeskError('class declarations are not supported inside Vesk components.', {
155
170
  ...context,
@@ -1 +1 @@
1
- {"version":3,"file":"ir-generator.d.ts","sourceRoot":"","sources":["../src/ir-generator.ts"],"names":[],"mappings":"AACA,OAAO,EACL,MAAM,EAsBP,MAAM,uBAAuB,CAAC;AA2T/B,wBAAgB,YAAY,CAAC,MAAM,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,GAAG,CAAC;IAAC,cAAc,CAAC,EAAE,GAAG,CAAC;IAAC,UAAU,CAAC,EAAE,GAAG,EAAE,CAAA;CAAE,CAAC,GAAG,SAAS,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkCnL;AA48BD,wBAAgB,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CA6N9E"}
1
+ {"version":3,"file":"ir-generator.d.ts","sourceRoot":"","sources":["../src/ir-generator.ts"],"names":[],"mappings":"AACA,OAAO,EACL,MAAM,EAsBP,MAAM,uBAAuB,CAAC;AA2T/B,wBAAgB,YAAY,CAAC,MAAM,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,GAAG,CAAC;IAAC,cAAc,CAAC,EAAE,GAAG,CAAC;IAAC,UAAU,CAAC,EAAE,GAAG,EAAE,CAAA;CAAE,CAAC,GAAG,SAAS,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkCnL;AA++BD,wBAAgB,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAgS9E"}