@vesk/vesk-cli 0.2.50-canary.9 → 0.2.51

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.
Files changed (2) hide show
  1. package/dist/cli.js +1415 -139
  2. package/package.json +5 -5
package/dist/cli.js CHANGED
@@ -147,7 +147,10 @@ var init_errors = __esm({
147
147
  suggestions;
148
148
  nextSteps;
149
149
  tip;
150
+ /** The V-diagnostic code, e.g. `V0501`. */
150
151
  code;
152
+ /** The rendered code frame. Used to be written into `code`, which silently replaced the V-code. */
153
+ frame;
151
154
  constructor(message, opts = {}) {
152
155
  super(message);
153
156
  this.name = "VeskError";
@@ -157,7 +160,8 @@ var init_errors = __esm({
157
160
  this.suggestions = opts.suggestions || [];
158
161
  this.nextSteps = opts.nextSteps || [];
159
162
  this.tip = opts.tip || "";
160
- if (opts.code !== void 0) this.code = opts.code;
163
+ if (opts.code !== void 0 && !opts.code.includes("\n")) this.code = opts.code;
164
+ if (opts.frame !== void 0) this.frame = opts.frame;
161
165
  }
162
166
  static notFound(name, candidates = [], context = {}) {
163
167
  const allCandidates = [.../* @__PURE__ */ new Set([...candidates, ...VESK_BUILTINS])];
@@ -195,6 +199,42 @@ var init_errors = __esm({
195
199
  * - `value` — `ns.max` read as a value. Component tags resolve; plain value
196
200
  * reads do not, because nothing binds `ns` at runtime.
197
201
  */
202
+ /**
203
+ * An imported `.ts`/`.js` module could not be parsed.
204
+ *
205
+ * This used to be silent, and that is the whole point of the diagnostic. A
206
+ * parse failure meant the module's RAW, untranspiled source was substituted,
207
+ * so TypeScript syntax reached `new Function` and the module blew up much
208
+ * later with a bare `Unexpected token ':'` — attributed to no file, at a
209
+ * point in the build far from the code that caused it. It also poisoned the
210
+ * whole shared module graph: one unparseable module left its exports
211
+ * undefined, so unrelated consumers failed with `X is not iterable`.
212
+ *
213
+ * Two real constructs hit this: a parameter annotation that survived the
214
+ * stripper only when the parameter also had a default value, and a generic
215
+ * arrow's type parameter list, which the JSX tokenizer cannot read at all.
216
+ * Both are fixed; this error exists so the NEXT such gap is reported at the
217
+ * right file with the right line instead of surfacing three modules later.
218
+ */
219
+ static moduleParseFailed(context = {}) {
220
+ return new _VeskError(
221
+ `Could not parse an imported module${context.reason ? `: ${context.reason}` : "."}`,
222
+ {
223
+ ...context,
224
+ code: context.code || "V0901",
225
+ suggestions: [
226
+ "Check the line the ^ marker points at \u2014 it is the construct the parser stopped on.",
227
+ "If it is TypeScript syntax the stripper does not handle, simplifying it here fixes every module that imports this file.",
228
+ "This is a bug in the compiler, not in your code, if the construct is ordinary TypeScript \u2014 please report it with the source line."
229
+ ],
230
+ nextSteps: [
231
+ "A module that fails to parse is substituted with its raw source, so every type annotation it contains becomes a runtime SyntaxError.",
232
+ "The failure is reported here, at the offending file and line, rather than as an `Unexpected token` in whichever module happened to import it."
233
+ ],
234
+ tip: "Ordinary TypeScript should parse; if this fires on valid TS, the parser is missing a construct."
235
+ }
236
+ );
237
+ }
198
238
  static vskNamespaceMember(context = {}) {
199
239
  const nested = context.form === "nested";
200
240
  return new _VeskError(
@@ -236,6 +276,84 @@ var init_errors = __esm({
236
276
  }
237
277
  );
238
278
  }
279
+ /**
280
+ * A browser-only global used in code the SERVER evaluates.
281
+ *
282
+ * On the server these are either absent (`window is not defined`) or, worse,
283
+ * silently present-but-wrong (`navigator` exists in modern Node, so
284
+ * `navigator.onLine` is `undefined` and a page renders as if it were offline).
285
+ * A raw `ReferenceError` at request time is the worst possible report: it
286
+ * names neither the component nor the fix. This points at the line.
287
+ */
288
+ static ssrUnsafeGlobal(name, context = {}) {
289
+ return new _VeskError(
290
+ `\`${name}\` is browser-only, and this component body runs during SSR.`,
291
+ {
292
+ ...context,
293
+ code: context.code || "V0501",
294
+ suggestions: [
295
+ `Wrap the part that needs the DOM in a {#client} block.`,
296
+ `Move the code into an event handler \u2014 handlers never run on the server.`,
297
+ `Do the setup in on_destroy(), which the compiler only emits on the client.`
298
+ ],
299
+ nextSteps: [
300
+ `component ${context.inComponent ?? "this component"}: wrap the \`${name}\` access in {#client}...{/client}.`,
301
+ `Or guard it: if (typeof ${name} !== 'undefined') { ... }`
302
+ ],
303
+ tip: "SSR renders this component before the client exists. Reading a browser global here either throws during the request or (for `navigator`) silently returns undefined."
304
+ }
305
+ );
306
+ }
307
+ /**
308
+ * The second name from `track()` called as a function.
309
+ *
310
+ * `const &[count, setCount] = track(0)` returns a CELL, not a setter function, so
311
+ * `setCount(1)` throws `setCount is not a function` from generated code with
312
+ * no line of user code in the message. The cell is the writer: `.set(v)`.
313
+ */
314
+ static cellCalledAsFunction(name, context = {}) {
315
+ return new _VeskError(
316
+ `\`${name}\` is a cell, not a function \u2014 cells are written with \`.set()\`.`,
317
+ {
318
+ ...context,
319
+ code: context.code || "V0502",
320
+ suggestions: [
321
+ `Use \`${name}.set(...)\` instead of \`${name}(...)\`.`,
322
+ `Or use the tracked spelling inside an event handler: set(${context.value ?? "value"}, ...)`
323
+ ],
324
+ nextSteps: [
325
+ `const &[${context.value ?? "value"}, ${name}] = track(0) \u2192 \`${name}.set(v)\``,
326
+ "The value read in markup is the first name; the second is the cell object."
327
+ ],
328
+ tip: `\`track()\` returns [value, cell]. \`${name}\` is the cell half.`
329
+ }
330
+ );
331
+ }
332
+ /**
333
+ * `set(value, …)` used outside a rewritten expression.
334
+ *
335
+ * The compiler rewrites `set(count, v)` to `countCell.set(v)` inside JSX and
336
+ * event handlers — but a bare statement in the component body is NOT
337
+ * rewritten, so the runtime `set` receives the value and throws
338
+ * "Cannot read properties of undefined". Pass the CELL, not the value.
339
+ */
340
+ static setWithValueName(name, context = {}) {
341
+ return new _VeskError(
342
+ `\`set(${name}, \u2026)\` needs the CELL, and \`${name}\` is the value half of track().`,
343
+ {
344
+ ...context,
345
+ code: context.code || "V0503",
346
+ suggestions: [
347
+ `Use \`set(${context.cell ?? "cell"}, \u2026)\` or \`${context.cell ?? "cell"}.set(\u2026)\`.`,
348
+ `Or move the set() into an event handler, where the compiler rewrites it for you.`
349
+ ],
350
+ nextSteps: [
351
+ `const &[${name}, ${context.cell ?? "cell"}] = track(0) \u2192 \`${context.cell ?? "cell"}.set(v)\``
352
+ ],
353
+ tip: "set(cell, value) is only rewritten inside JSX and handlers; in a body statement it reaches the runtime untouched."
354
+ }
355
+ );
356
+ }
239
357
  static serverBlockInClient(compName, context = {}) {
240
358
  return new _VeskError(
241
359
  `{#server} block found in client island "${compName}". Client islands render on both server and client, so {#server} blocks have no effect.`,
@@ -3487,7 +3605,13 @@ function flattenLayoutChain(tree, pathParts, result = []) {
3487
3605
  for (let i = 0; i < tree.length; i++) {
3488
3606
  const node = tree[i];
3489
3607
  if (node.isGroup) {
3608
+ const before = result.length;
3490
3609
  flattenLayoutChain(node.children || [], pathParts, result);
3610
+ if (result.length > before) continue;
3611
+ if (node.page && (pathParts.length === 0 || pathParts.every((p) => p === ""))) {
3612
+ result.push(node);
3613
+ break;
3614
+ }
3491
3615
  continue;
3492
3616
  }
3493
3617
  const part = pathParts[0];
@@ -3509,6 +3633,11 @@ function flattenLayoutChain(tree, pathParts, result = []) {
3509
3633
  if (node.standalone) result.length = 0;
3510
3634
  result.push(node);
3511
3635
  if (isLeaf2) {
3636
+ if (!node.page && (node.children || []).length > 0) {
3637
+ const before = result.length;
3638
+ flattenLayoutChain(node.children || [], remaining, result);
3639
+ if (result.length > before) break;
3640
+ }
3512
3641
  break;
3513
3642
  } else if ((node.children || []).length > 0) {
3514
3643
  flattenLayoutChain(node.children || [], remaining, result);
@@ -18025,6 +18154,52 @@ function containsForOfIn(text) {
18025
18154
  }
18026
18155
  return false;
18027
18156
  }
18157
+ function callsIdentifier(text, ident) {
18158
+ let i = 0;
18159
+ const len = text.length;
18160
+ let afterDot = false;
18161
+ while (i < len) {
18162
+ const ch = text[i];
18163
+ if (isWhitespaceChar(ch)) {
18164
+ i++;
18165
+ continue;
18166
+ }
18167
+ const commentEnd = skipComment(text, i);
18168
+ if (commentEnd !== i) {
18169
+ i = commentEnd;
18170
+ continue;
18171
+ }
18172
+ if (ch === '"' || ch === "'" || ch === "`") {
18173
+ i = skipString(text, i);
18174
+ afterDot = false;
18175
+ continue;
18176
+ }
18177
+ if (ch === "." || ch === "?" && text[i + 1] === ".") {
18178
+ afterDot = true;
18179
+ i += ch === "." ? 1 : 2;
18180
+ continue;
18181
+ }
18182
+ if (isIdentStartCode2(ch.charCodeAt(0))) {
18183
+ let j = i + 1;
18184
+ while (j < len && isIdentCharCode2(text.charCodeAt(j))) j++;
18185
+ const name = text.slice(i, j);
18186
+ let k = skipWhitespace(text, j);
18187
+ if (text[k] === "<") {
18188
+ k = skipTrackGeneric(text, k);
18189
+ k = skipWhitespace(text, k);
18190
+ }
18191
+ if (name === ident && text[k] === "(" && !afterDot) {
18192
+ return true;
18193
+ }
18194
+ afterDot = false;
18195
+ i = j;
18196
+ continue;
18197
+ }
18198
+ afterDot = false;
18199
+ i++;
18200
+ }
18201
+ return false;
18202
+ }
18028
18203
  function unwrapTrackCall(init) {
18029
18204
  const text = init.trim();
18030
18205
  if (!startsWithIdentifier(text, "track")) return init;
@@ -18645,6 +18820,162 @@ function preprocessForClauses(source) {
18645
18820
  }
18646
18821
  return { code: chars.join(""), annotations };
18647
18822
  }
18823
+ function blankGenericArrowTypeParams(source) {
18824
+ let changed = false;
18825
+ const chars = source.split("");
18826
+ let i = 0;
18827
+ const isSpace = (ch) => isSpaceChar(ch);
18828
+ while (i < source.length) {
18829
+ const ch = source[i];
18830
+ if (ch === '"' || ch === "'" || ch === "`") {
18831
+ const quote = ch;
18832
+ let j2 = i + 1;
18833
+ while (j2 < source.length) {
18834
+ if (source[j2] === "\\") {
18835
+ j2 += 2;
18836
+ continue;
18837
+ }
18838
+ if (source[j2] === quote) {
18839
+ j2++;
18840
+ break;
18841
+ }
18842
+ if (quote === "`" && source[j2] === "$" && source[j2 + 1] === "{") {
18843
+ let depth = 1;
18844
+ j2 += 2;
18845
+ while (j2 < source.length && depth > 0) {
18846
+ if (source[j2] === "{") depth++;
18847
+ else if (source[j2] === "}") depth--;
18848
+ j2++;
18849
+ }
18850
+ continue;
18851
+ }
18852
+ j2++;
18853
+ }
18854
+ i = j2;
18855
+ continue;
18856
+ }
18857
+ if (ch === "/" && source[i + 1] === "/") {
18858
+ while (i < source.length && source[i] !== "\n") i++;
18859
+ continue;
18860
+ }
18861
+ if (ch === "/" && source[i + 1] === "*") {
18862
+ i += 2;
18863
+ while (i < source.length && !(source[i] === "*" && source[i + 1] === "/")) i++;
18864
+ i += 2;
18865
+ continue;
18866
+ }
18867
+ if (ch !== "<") {
18868
+ i++;
18869
+ continue;
18870
+ }
18871
+ let j = i + 1;
18872
+ let angle = 1;
18873
+ let end = -1;
18874
+ let bail = false;
18875
+ while (j < source.length) {
18876
+ const c = source[j];
18877
+ if (c === "<") {
18878
+ angle++;
18879
+ j++;
18880
+ continue;
18881
+ }
18882
+ if (c === ">") {
18883
+ angle--;
18884
+ j++;
18885
+ if (angle === 0) {
18886
+ end = j;
18887
+ break;
18888
+ }
18889
+ continue;
18890
+ }
18891
+ if (c === "(" || c === "[" || c === "{") {
18892
+ const close = c === "(" ? ")" : c === "[" ? "]" : "}";
18893
+ let depth = 0;
18894
+ while (j < source.length) {
18895
+ const d = source[j];
18896
+ if (d === c) depth++;
18897
+ else if (d === close) {
18898
+ depth--;
18899
+ if (depth === 0) {
18900
+ j++;
18901
+ break;
18902
+ }
18903
+ }
18904
+ j++;
18905
+ }
18906
+ continue;
18907
+ }
18908
+ if (c === ";" || c === "\n") {
18909
+ bail = true;
18910
+ break;
18911
+ }
18912
+ j++;
18913
+ }
18914
+ if (bail || end < 0) {
18915
+ i++;
18916
+ continue;
18917
+ }
18918
+ if (!isArrowParameterList(source, end)) {
18919
+ i = end;
18920
+ continue;
18921
+ }
18922
+ for (let p = i; p < end; p++) {
18923
+ if (chars[p] !== "\n") chars[p] = " ";
18924
+ }
18925
+ changed = true;
18926
+ i = end;
18927
+ }
18928
+ return changed ? chars.join("") : source;
18929
+ }
18930
+ function isArrowParameterList(source, from) {
18931
+ let i = from;
18932
+ while (i < source.length && isSpaceChar(source[i])) i++;
18933
+ if (source[i] !== "(") return false;
18934
+ let depth = 0;
18935
+ while (i < source.length) {
18936
+ const ch = source[i];
18937
+ if (ch === "(" || ch === "[" || ch === "{") {
18938
+ depth++;
18939
+ i++;
18940
+ continue;
18941
+ }
18942
+ if (ch === ")" || ch === "]" || ch === "}") {
18943
+ depth--;
18944
+ i++;
18945
+ if (depth === 0) break;
18946
+ continue;
18947
+ }
18948
+ i++;
18949
+ }
18950
+ if (depth !== 0) return false;
18951
+ while (i < source.length && isSpaceChar(source[i])) i++;
18952
+ if (source[i] === ":") {
18953
+ i++;
18954
+ let tdepth = 0;
18955
+ while (i < source.length) {
18956
+ const ch = source[i];
18957
+ if (ch === "(" || ch === "[" || ch === "{") {
18958
+ tdepth++;
18959
+ i++;
18960
+ continue;
18961
+ }
18962
+ if (ch === ")" || ch === "]" || ch === "}") {
18963
+ if (tdepth === 0) return false;
18964
+ tdepth--;
18965
+ i++;
18966
+ continue;
18967
+ }
18968
+ if (tdepth === 0 && ch === "=" && source[i + 1] === ">") return true;
18969
+ if (tdepth === 0 && (ch === ";" || ch === "\n")) return false;
18970
+ i++;
18971
+ }
18972
+ return false;
18973
+ }
18974
+ return source[i] === "=" && source[i + 1] === ">";
18975
+ }
18976
+ function isSpaceChar(ch) {
18977
+ return ch === " " || ch === " " || ch === "\n" || ch === "\r" || ch === "\f" || ch === "\v";
18978
+ }
18648
18979
  function createBaseParser() {
18649
18980
  return Parser.extend(tsPlugin({}), VeskParserPlugin());
18650
18981
  }
@@ -18657,7 +18988,7 @@ function parseGeneratedJs(source) {
18657
18988
  }
18658
18989
  function parse4(source, options = {}) {
18659
18990
  const ParserClass = createBaseParser();
18660
- const { code, annotations } = preprocessForClauses(blankComments(source));
18991
+ const { code, annotations } = preprocessForClauses(blankGenericArrowTypeParams(blankComments(source)));
18661
18992
  const vskSource = !options.filename || String(options.filename).endsWith(".vsk");
18662
18993
  const specifierExports = vskSource ? findSpecifierExports(code).filter((e) => !hasTopLevelValueDeclaration(code, e.local)) : [];
18663
18994
  let parseable = code;
@@ -18859,13 +19190,33 @@ function stripTsTypes(ast) {
18859
19190
  }
18860
19191
  });
18861
19192
  }
19193
+ function stripParamTypes(p) {
19194
+ if (!p) return;
19195
+ if (p.typeAnnotation) p.typeAnnotation = null;
19196
+ if (p.optional) p.optional = false;
19197
+ switch (p.type) {
19198
+ case "AssignmentPattern":
19199
+ stripParamTypes(p.left);
19200
+ break;
19201
+ case "RestElement":
19202
+ stripParamTypes(p.argument);
19203
+ break;
19204
+ case "ObjectPattern":
19205
+ for (const prop of p.properties || []) {
19206
+ stripParamTypes(prop.value || prop.argument || prop);
19207
+ }
19208
+ break;
19209
+ case "ArrayPattern":
19210
+ for (const el of p.elements || []) if (el) stripParamTypes(el);
19211
+ break;
19212
+ default:
19213
+ break;
19214
+ }
19215
+ }
18862
19216
  function stripFunctionTypes(node) {
18863
19217
  if (node.returnType) node.returnType = null;
18864
19218
  if (node.typeParameters) node.typeParameters = null;
18865
- for (const p of node.params || []) {
18866
- if (p.typeAnnotation) p.typeAnnotation = null;
18867
- if (p.optional) p.optional = false;
18868
- }
19219
+ for (const p of node.params || []) stripParamTypes(p);
18869
19220
  }
18870
19221
  function stripCodeTypes(code) {
18871
19222
  let ast;
@@ -19043,6 +19394,7 @@ function loadSsrModule(absPath) {
19043
19394
  }
19044
19395
  } else {
19045
19396
  const src2 = readSsrSource(absPath);
19397
+ if (src2?.parseError) throw src2.parseError;
19046
19398
  const body = src2?.ast?.body || [];
19047
19399
  if (src2 && isPureReexportBarrel(body)) {
19048
19400
  exportsObj = createLazyBarrelExports(buildBarrelSpec(body), dirname2(absPath));
@@ -19119,13 +19471,19 @@ function readSsrSource(absPath) {
19119
19471
  return null;
19120
19472
  }
19121
19473
  const raw2 = cachedRaw;
19122
- let ast = null;
19123
19474
  try {
19124
- ast = parse4(raw2, { filename: absPath });
19125
- } catch {
19126
- ast = null;
19475
+ return { raw: raw2, ast: parse4(raw2, { filename: absPath }) };
19476
+ } catch (e) {
19477
+ const err = e;
19478
+ let parseError;
19479
+ if (err instanceof VeskError) {
19480
+ parseError = err;
19481
+ if (err.code === void 0) err.code = "V0901";
19482
+ } else {
19483
+ parseError = VeskError.moduleParseFailed({ file: absPath, reason: e?.message });
19484
+ }
19485
+ return { raw: raw2, ast: null, parseError };
19127
19486
  }
19128
- return { raw: raw2, ast };
19129
19487
  }
19130
19488
  function isPureReexportBarrel(body) {
19131
19489
  for (const stmt of body) {
@@ -19191,7 +19549,7 @@ function createLazyBarrelExports(spec, dir) {
19191
19549
  const loadSource = (source) => {
19192
19550
  let target = targets.get(source);
19193
19551
  if (!target) {
19194
- target = resolveSsrModule(source, dir) ?? "";
19552
+ target = (isCompilerOwnedTarget(source) ? resolveCompilerOwnedModule(source) : resolveSsrModule(source, dir)) ?? "";
19195
19553
  if (!target) return null;
19196
19554
  targets.set(source, target);
19197
19555
  }
@@ -19276,6 +19634,7 @@ function evaluateModuleFile(absPath, exportsObj, src2) {
19276
19634
  let ast;
19277
19635
  if (src2) {
19278
19636
  ast = src2.ast;
19637
+ if (!ast && src2.parseError) throw src2.parseError;
19279
19638
  } else {
19280
19639
  try {
19281
19640
  ast = parse4(raw2, { filename: absPath });
@@ -19349,8 +19708,25 @@ function scanUnsupportedNode(node, inFunction = false) {
19349
19708
  }
19350
19709
  return null;
19351
19710
  }
19711
+ function resolveCompilerOwnedModule(specifier) {
19712
+ const viaExports = resolveViaPackageExports(specifier, process.cwd());
19713
+ if (viaExports) return viaExports;
19714
+ const viaModuleField = resolveViaPackageModuleField(specifier, process.cwd());
19715
+ if (viaModuleField) return viaModuleField;
19716
+ const native = nativeResolve(specifier, process.cwd());
19717
+ if (native && !isBuiltinPath(native)) return native;
19718
+ return null;
19719
+ }
19352
19720
  function createModuleRequire(fromDir) {
19353
19721
  return (specifier) => {
19722
+ if (isCompilerOwnedTarget(specifier)) {
19723
+ const resolved2 = resolveCompilerOwnedModule(specifier);
19724
+ if (resolved2) {
19725
+ const native = nativeRequireFallback(resolved2);
19726
+ if (native) return native;
19727
+ }
19728
+ throw new Error(`Cannot load module '${specifier}'`);
19729
+ }
19354
19730
  const resolved = resolveSsrModule(specifier, fromDir);
19355
19731
  if (!resolved) throw new Error(`Cannot find module '${specifier}'`);
19356
19732
  for (const frame of depStack) frame.add(resolved);
@@ -19898,6 +20274,7 @@ function collectModuleBundled(absPath, collector) {
19898
20274
  } else {
19899
20275
  const src2 = readSsrSource(absPath);
19900
20276
  if (!src2 || !src2.ast) {
20277
+ if (src2?.parseError) throw src2.parseError;
19901
20278
  const raw2 = src2 ? src2.raw : "// unreadable during build\nmodule.exports = {};";
19902
20279
  collector.modules.push({ key, code: raw2, dir, deps: {} });
19903
20280
  return key;
@@ -19944,6 +20321,7 @@ var init_module_imports = __esm({
19944
20321
  init_parser();
19945
20322
  init_strip_ts();
19946
20323
  init_tokens();
20324
+ init_errors();
19947
20325
  RUNTIME_PREFIXES = ["@vesk/runtime/", "@vesk/reactivity/", "@vesk/types", "@vesk/"];
19948
20326
  EXTENSIONS = [".ts", ".tsx", ".mts", ".cts", ".js", ".mjs", ".cjs", ".jsx", ".json"];
19949
20327
  BUILTIN_PREFIX = "\0builtin:";
@@ -20413,6 +20791,22 @@ function jsxTagDepth(nameNode) {
20413
20791
  }
20414
20792
  return depth;
20415
20793
  }
20794
+ function unwrapHelperBody(node) {
20795
+ let body = node;
20796
+ if (body?.type === "ArrowFunctionExpression" || body?.type === "FunctionExpression") body = body.body;
20797
+ if (body?.type === "BlockStatement") {
20798
+ const stmts = (body.body || []).filter((s) => s.type !== "EmptyStatement");
20799
+ if (stmts.length !== 1) return null;
20800
+ body = stmts[0];
20801
+ }
20802
+ if (body?.type === "ReturnStatement") body = body.argument;
20803
+ if (!body) return null;
20804
+ if (body.type !== "CallExpression") return null;
20805
+ if (body.callee?.type !== "Identifier") return null;
20806
+ const args2 = body.arguments || [];
20807
+ if (args2.length === 0 || args2[0]?.type !== "ObjectExpression") return null;
20808
+ return body;
20809
+ }
20416
20810
  function collectVskNamespaceLocals(ast) {
20417
20811
  const namespaceLocals = /* @__PURE__ */ new Map();
20418
20812
  for (const node of ast.body || []) {
@@ -20446,6 +20840,34 @@ function markShadowedBindings(node, namespaceLocals) {
20446
20840
  markShadowedBindings(node[key], namespaceLocals);
20447
20841
  }
20448
20842
  }
20843
+ function collectFileValueBindings(ast) {
20844
+ const names = /* @__PURE__ */ new Set();
20845
+ for (const node of ast.body || []) {
20846
+ if (node.type === "ComponentDeclaration") continue;
20847
+ if (node.type === "ImportDeclaration") continue;
20848
+ const target = node.type === "ExportNamedDeclaration" || node.type === "ExportDefaultDeclaration" ? node.declaration : node;
20849
+ if (!target) continue;
20850
+ if (target.type === "VariableDeclaration") {
20851
+ for (const d of target.declarations || []) for (const n of declaredBindingNames(d)) names.add(n);
20852
+ continue;
20853
+ }
20854
+ for (const n of declaredBindingNames(target)) names.add(n);
20855
+ }
20856
+ return names;
20857
+ }
20858
+ function collectComponentValueNames(compNode) {
20859
+ const names = /* @__PURE__ */ new Set();
20860
+ if (!compNode) return names;
20861
+ for (const p of compNode.params || []) for (const n of declaredBindingNames(p)) names.add(n);
20862
+ for (const stmt of compNode.body?.body || []) {
20863
+ if (stmt.type === "VariableDeclaration") {
20864
+ for (const d of stmt.declarations || []) for (const n of declaredBindingNames(d)) names.add(n);
20865
+ continue;
20866
+ }
20867
+ for (const n of declaredBindingNames(stmt)) names.add(n);
20868
+ }
20869
+ return names;
20870
+ }
20449
20871
  function declaredBindingNames(node) {
20450
20872
  const out = [];
20451
20873
  const pushPattern = (id) => {
@@ -20515,9 +20937,149 @@ function findNamespaceValueUse(node, locals2) {
20515
20937
  }
20516
20938
  return null;
20517
20939
  }
20940
+ function collectComponentCallHelpers(source, ast) {
20941
+ const out = /* @__PURE__ */ new Map();
20942
+ for (const node of ast.body || []) {
20943
+ const decl = node.type === "ExportNamedDeclaration" || node.type === "ExportDefaultDeclaration" ? node.declaration : node;
20944
+ if (!decl) continue;
20945
+ let name = null;
20946
+ let fn = null;
20947
+ if (decl.type === "VariableDeclaration" && decl.declarations?.length === 1) {
20948
+ const d = decl.declarations[0];
20949
+ if (d.id?.type === "Identifier") {
20950
+ name = d.id.name;
20951
+ fn = d.init;
20952
+ }
20953
+ } else if (decl.type === "FunctionDeclaration" && decl.id?.name) {
20954
+ name = decl.id.name;
20955
+ fn = decl;
20956
+ }
20957
+ if (!name || !fn) continue;
20958
+ if (fn.type !== "ArrowFunctionExpression" && fn.type !== "FunctionExpression" && fn.type !== "FunctionDeclaration") continue;
20959
+ const params = fn.params || [];
20960
+ if (params.some((p) => p.type !== "Identifier")) continue;
20961
+ const body = unwrapHelperBody(fn);
20962
+ if (body === null) continue;
20963
+ const args2 = body.arguments || [];
20964
+ const propsObj = args2[0];
20965
+ const props = [];
20966
+ const spreadProps = [];
20967
+ const slots = [];
20968
+ for (const prop of propsObj.properties || []) {
20969
+ if (prop.type === "SpreadElement") {
20970
+ spreadProps.push(prop.argument);
20971
+ continue;
20972
+ }
20973
+ const pname = prop.key.type === "Identifier" ? prop.key.name : prop.key.value;
20974
+ if (prop.value.type === "JSXElement" || prop.value.type === "JSXFragment") {
20975
+ slots.push({ name: pname, nodes: exprToIR(source, prop.value) });
20976
+ continue;
20977
+ }
20978
+ props.push({ name: pname, value: prop.value });
20979
+ }
20980
+ const paramNames = params.map((p) => p.name);
20981
+ out.set(name, { props, spreadProps, slots, paramNames, componentName: body.callee.name });
20982
+ }
20983
+ return out;
20984
+ }
20985
+ function substituteHelperParams(node, bindings) {
20986
+ if (!node || typeof node !== "object") return node;
20987
+ if (Array.isArray(node)) {
20988
+ const out2 = [];
20989
+ for (const child of node) {
20990
+ const next = substituteHelperParams(child, bindings);
20991
+ if (next === null) return null;
20992
+ out2.push(next);
20993
+ }
20994
+ return out2;
20995
+ }
20996
+ if (typeof node.type !== "string") return node;
20997
+ if (node.type === "ArrowFunctionExpression" || node.type === "FunctionExpression") return null;
20998
+ if (node.type === "Identifier" && bindings.has(node.name)) {
20999
+ const bound = bindings.get(node.name);
21000
+ return bound === null ? null : bound;
21001
+ }
21002
+ const out = {};
21003
+ for (const key of Object.keys(node)) {
21004
+ if (key === "loc" || key === "range" || key === "start" || key === "end") {
21005
+ out[key] = node[key];
21006
+ continue;
21007
+ }
21008
+ const next = substituteHelperParams(node[key], bindings);
21009
+ if (next === null) return null;
21010
+ out[key] = next;
21011
+ }
21012
+ return out;
21013
+ }
21014
+ function helperCallToIR(source, helper, args2) {
21015
+ const compName = helper.componentName;
21016
+ const bindings = /* @__PURE__ */ new Map();
21017
+ helper.paramNames.forEach((param, i) => bindings.set(param, args2[i] ?? null));
21018
+ for (const bound of bindings.values()) if (bound === null) return null;
21019
+ const props = [];
21020
+ for (const p of helper.props) {
21021
+ const substituted = substituteHelperParams(p.value, bindings);
21022
+ if (substituted === null) return null;
21023
+ props.push({ name: p.name, value: toExpression(source, substituted) });
21024
+ }
21025
+ const spreadProps = [];
21026
+ for (const sp of helper.spreadProps) {
21027
+ const substituted = substituteHelperParams(sp, bindings);
21028
+ if (substituted === null) return null;
21029
+ spreadProps.push(toExpression(source, substituted));
21030
+ }
21031
+ return [new ComponentCall(compName, props, helper.slots.flatMap((s) => [new PropSlot(s.name, s.nodes)]), spreadProps, -1, componentValueCallee(compName))];
21032
+ }
20518
21033
  function isHTMLTag(name) {
20519
21034
  return name.length > 0 && name[0] === name[0].toLowerCase();
20520
21035
  }
21036
+ function componentValueCallee(tagName) {
21037
+ if (!currentComponentValues || !currentComponentValues.has(tagName)) return null;
21038
+ return tagName;
21039
+ }
21040
+ function componentCallInExpression(expr) {
21041
+ if (!expr || expr.type !== "CallExpression") return null;
21042
+ const callee = expr.callee;
21043
+ if (!callee || callee.type !== "Identifier") return null;
21044
+ if (!isComponentValueName(callee.name)) return null;
21045
+ const args2 = expr.arguments || [];
21046
+ if (args2.length === 0 || !args2[0] || args2[0].type !== "ObjectExpression") return null;
21047
+ return expr;
21048
+ }
21049
+ function isComponentValueName(name) {
21050
+ if (currentFileComponentNames?.has(name)) return true;
21051
+ if (currentComponentValues?.has(name)) return true;
21052
+ return currentFileValueBindings?.has(name) || currentImportedNames?.has(name) || false;
21053
+ }
21054
+ function componentCallToIR(source, expr) {
21055
+ const calleeName = expr.callee.name;
21056
+ const args2 = expr.arguments || [];
21057
+ const propsArg = args2[0];
21058
+ const props = [];
21059
+ const spreadProps = [];
21060
+ const slots = [];
21061
+ for (const prop of propsArg.properties || []) {
21062
+ if (prop.type === "SpreadElement") {
21063
+ spreadProps.push(toExpression(source, prop.argument));
21064
+ continue;
21065
+ }
21066
+ const name = prop.key.type === "Identifier" ? prop.key.name : prop.key.value;
21067
+ if (prop.value.type === "JSXElement" || prop.value.type === "JSXFragment") {
21068
+ slots.push(new PropSlot(name, exprToIR(source, prop.value)));
21069
+ continue;
21070
+ }
21071
+ props.push({ name, value: toExpression(source, prop.value) });
21072
+ }
21073
+ const children = args2.length > 1 ? [new RuntimeStatement(`/* [vesk] extra arguments to a component call are ignored */ ${getSource(source, args2[1])}`)] : [];
21074
+ return [new ComponentCall(
21075
+ calleeName,
21076
+ props,
21077
+ [...children, ...slots],
21078
+ spreadProps,
21079
+ expr.start ?? -1,
21080
+ componentValueCallee(calleeName)
21081
+ )];
21082
+ }
20521
21083
  function isMapCall(expr) {
20522
21084
  return expr.type === "CallExpression" && expr.callee.type === "MemberExpression" && expr.callee.property.name === "map" && expr.arguments.length === 1 && expr.arguments[0].type === "ArrowFunctionExpression";
20523
21085
  }
@@ -20786,7 +21348,7 @@ function processJSXChildren(source, children) {
20786
21348
  continue;
20787
21349
  }
20788
21350
  }
20789
- result.push(new DynamicBinding(toExpression(source, expr)));
21351
+ result.push(...exprToIR(source, expr));
20790
21352
  i++;
20791
21353
  } else if (child.type === "JSXElement") {
20792
21354
  result.push(...processJSXElement(source, child));
@@ -20832,6 +21394,12 @@ function exprToIR(source, expr) {
20832
21394
  return [new MapRegion(arrayExpr, itemVar, bodyNodes, keyExpr, indexVar)];
20833
21395
  }
20834
21396
  if (expr.type === "ParenthesizedExpression") return exprToIR(source, expr.expression);
21397
+ if (componentCallInExpression(expr) !== null) return componentCallToIR(source, expr);
21398
+ if (expr?.type === "CallExpression" && currentComponentCallHelpers?.has(expr.callee?.name)) {
21399
+ const helper = currentComponentCallHelpers.get(expr.callee.name);
21400
+ const inlined = helperCallToIR(source, helper, expr.arguments || []);
21401
+ if (inlined !== null) return inlined;
21402
+ }
20835
21403
  if (expr.type === "ConditionalExpression") {
20836
21404
  const condExpr = toExpression(source, expr.test);
20837
21405
  const consequent = exprToIR(source, expr.consequent);
@@ -20899,12 +21467,12 @@ function processJSXElement(source, element) {
20899
21467
  }
20900
21468
  if (!isHTMLTag(tagName) && selfClosing) {
20901
21469
  const { props, spreadProps, slots } = extractProps(source, element);
20902
- return [new ComponentCall(tagName, props, slots.map((s) => new PropSlot(s.name, s.nodes)), spreadProps, element.start)];
21470
+ return [new ComponentCall(tagName, props, slots.map((s) => new PropSlot(s.name, s.nodes)), spreadProps, element.start, componentValueCallee(tagName))];
20903
21471
  }
20904
21472
  if (!isHTMLTag(tagName)) {
20905
21473
  const { props, spreadProps, slots } = extractProps(source, element);
20906
21474
  const children2 = processJSXChildren(source, element.children || []);
20907
- return [new ComponentCall(tagName, props, [...children2, ...slots.map((s) => new PropSlot(s.name, s.nodes))], spreadProps, element.start)];
21475
+ return [new ComponentCall(tagName, props, [...children2, ...slots.map((s) => new PropSlot(s.name, s.nodes))], spreadProps, element.start, componentValueCallee(tagName))];
20908
21476
  }
20909
21477
  const attributes = element.openingElement.attributes.filter((attr) => attr.type !== "JSXSpreadAttribute").map((attr) => processAttribute(source, attr));
20910
21478
  const staticAttrs = [];
@@ -21236,7 +21804,7 @@ function validateBlocks(compName, isClient, body, file, source) {
21236
21804
  const { line, column } = offsetToLineCol2(source, pos);
21237
21805
  opts.line = line;
21238
21806
  opts.column = column;
21239
- opts.code = codeFrame(source, line, column);
21807
+ opts.frame = codeFrame(source, line, column);
21240
21808
  }
21241
21809
  throw VeskError.serverBlockInClient(compName, opts);
21242
21810
  }
@@ -21248,7 +21816,7 @@ function validateBlocks(compName, isClient, body, file, source) {
21248
21816
  const { line, column } = offsetToLineCol2(source, pos);
21249
21817
  opts.line = line;
21250
21818
  opts.column = column;
21251
- opts.code = codeFrame(source, line, column);
21819
+ opts.frame = codeFrame(source, line, column);
21252
21820
  }
21253
21821
  throw VeskError.clientBlockInServer(compName, opts);
21254
21822
  }
@@ -21317,6 +21885,17 @@ function generateIR(ast, source, filename) {
21317
21885
  const vskNamespaceLocals = collectVskNamespaceLocals(ast);
21318
21886
  const prevNamespaceLocals = currentVskNamespaceLocals;
21319
21887
  const prevSourceFile = currentSourceFile;
21888
+ const fileValueBindings = collectFileValueBindings(ast);
21889
+ currentComponentCallHelpers = collectComponentCallHelpers(source, ast);
21890
+ const prevFileComponentNames = currentFileComponentNames;
21891
+ const prevFileValueBindings = currentFileValueBindings;
21892
+ const prevImportedNames = currentImportedNames;
21893
+ const fileComponentNames = new Set(
21894
+ (ast.body || []).map((n) => n.type === "ExportNamedDeclaration" || n.type === "ExportDefaultDeclaration" ? n.declaration : n).filter((n) => n?.type === "ComponentDeclaration").map((n) => n.id.name)
21895
+ );
21896
+ currentFileComponentNames = fileComponentNames;
21897
+ currentFileValueBindings = fileValueBindings;
21898
+ currentImportedNames = importedNames;
21320
21899
  currentVskNamespaceLocals = vskNamespaceLocals;
21321
21900
  currentSourceFile = file;
21322
21901
  try {
@@ -21422,61 +22001,68 @@ function generateIR(ast, source, filename) {
21422
22001
  }
21423
22002
  const name = inner.id.name;
21424
22003
  const paramNames = getParamNames(inner.params, source);
21425
- const firstParam = inner.params?.[0];
21426
- const propsAlias = firstParam && firstParam.type === "Identifier" ? firstParam.name : null;
21427
- const propsType = getPropsType(inner.params, source);
21428
- const bodyStmts = inner.body.body;
21429
- const isClientComp = !!inner.client;
21430
- const prevSlotProps = __slotProps;
21431
- __slotProps = slotPropNamesFromType(propsType);
21432
- __propsParam = propsAlias || null;
21433
- if (isStatementMode(bodyStmts)) {
21434
- const raw2 = processStatementModeBody(source, bodyStmts, file);
21435
- const { body, css } = extractStyle(raw2);
21436
- validateBlocks(name, isClientComp, body, file, source);
21437
- const comp = new ComponentIR(name, paramNames, body, { mode: "statement", exported, defaultExport, isClient: inner.client, isAsync: inner.async, ssrAwait: componentUsesFetch(body), propsType, propsAlias });
21438
- comp.style = css;
21439
- components.push(comp);
21440
- __slotProps = prevSlotProps;
21441
- } else {
21442
- const guardClauses = [];
21443
- let mainReturn = null;
21444
- const preamble = [];
21445
- for (const stmt of bodyStmts) {
21446
- if (stmt.type === "VeskBlock") {
21447
- const innerBody = processStatementModeBody(source, stmt.body, file);
21448
- if (stmt.tag === "server") {
21449
- preamble.push(new ServerBlock(innerBody));
21450
- } else if (stmt.tag === "client") {
21451
- preamble.push(new ClientBlock(innerBody));
21452
- }
21453
- } else if (stmt.type === "ReturnStatement") {
21454
- mainReturn = stmt;
21455
- } else if (isTrackDeclaration(stmt)) {
21456
- const elements = stmt.declarations[0].id.elements;
21457
- const trackName = elements[0]?.name;
21458
- const rawName = elements.length > 1 ? elements[1]?.name : null;
21459
- const init = getSource(source, stmt.declarations[0].init);
21460
- if (trackName) preamble.push(new TrackDecl(trackName, init, rawName));
21461
- const refName = getComponentRefName(stmt);
21462
- if (refName) preamble.push(new ComponentRef(refName));
21463
- } else if (stmt.type === "IfStatement" && !mainReturn && stmt.consequent.type !== "ThrowStatement") {
21464
- guardClauses.push(stmt);
21465
- } else if (stmt.type === "ClassDeclaration") {
21466
- const { line, column } = offsetToLineCol2(source, stmt.start ?? 0);
21467
- throw VeskError.classDecl({ file, line, column, code: codeFrame(source, line, column) });
21468
- } else {
21469
- const raw2 = getSource(source, stmt);
21470
- if (raw2) preamble.push(new RuntimeStatement(raw2, stmt, source));
22004
+ const valueNames = collectComponentValueNames(inner);
22005
+ const prevComponentValues = currentComponentValues;
22006
+ currentComponentValues = new Set([...valueNames].filter((n) => !fileComponentNames.has(n)));
22007
+ try {
22008
+ const firstParam = inner.params?.[0];
22009
+ const propsAlias = firstParam && firstParam.type === "Identifier" ? firstParam.name : null;
22010
+ const propsType = getPropsType(inner.params, source);
22011
+ const bodyStmts = inner.body.body;
22012
+ const isClientComp = !!inner.client;
22013
+ const prevSlotProps = __slotProps;
22014
+ __slotProps = slotPropNamesFromType(propsType);
22015
+ __propsParam = propsAlias || null;
22016
+ if (isStatementMode(bodyStmts)) {
22017
+ const raw2 = processStatementModeBody(source, bodyStmts, file);
22018
+ const { body, css } = extractStyle(raw2);
22019
+ validateBlocks(name, isClientComp, body, file, source);
22020
+ const comp = new ComponentIR(name, paramNames, body, { mode: "statement", exported, defaultExport, isClient: inner.client, isAsync: inner.async, ssrAwait: componentUsesFetch(body), propsType, propsAlias });
22021
+ comp.style = css;
22022
+ components.push(comp);
22023
+ __slotProps = prevSlotProps;
22024
+ } else {
22025
+ const guardClauses = [];
22026
+ let mainReturn = null;
22027
+ const preamble = [];
22028
+ for (const stmt of bodyStmts) {
22029
+ if (stmt.type === "VeskBlock") {
22030
+ const innerBody = processStatementModeBody(source, stmt.body, file);
22031
+ if (stmt.tag === "server") {
22032
+ preamble.push(new ServerBlock(innerBody));
22033
+ } else if (stmt.tag === "client") {
22034
+ preamble.push(new ClientBlock(innerBody));
22035
+ }
22036
+ } else if (stmt.type === "ReturnStatement") {
22037
+ mainReturn = stmt;
22038
+ } else if (isTrackDeclaration(stmt)) {
22039
+ const elements = stmt.declarations[0].id.elements;
22040
+ const trackName = elements[0]?.name;
22041
+ const rawName = elements.length > 1 ? elements[1]?.name : null;
22042
+ const init = getSource(source, stmt.declarations[0].init);
22043
+ if (trackName) preamble.push(new TrackDecl(trackName, init, rawName));
22044
+ const refName = getComponentRefName(stmt);
22045
+ if (refName) preamble.push(new ComponentRef(refName));
22046
+ } else if (stmt.type === "IfStatement" && !mainReturn && stmt.consequent.type !== "ThrowStatement") {
22047
+ guardClauses.push(stmt);
22048
+ } else if (stmt.type === "ClassDeclaration") {
22049
+ const { line, column } = offsetToLineCol2(source, stmt.start ?? 0);
22050
+ throw VeskError.classDecl({ file, line, column, code: codeFrame(source, line, column) });
22051
+ } else {
22052
+ const raw2 = getSource(source, stmt);
22053
+ if (raw2) preamble.push(new RuntimeStatement(raw2, stmt, source));
22054
+ }
21471
22055
  }
22056
+ const guardBody = buildGuardChain(source, guardClauses, mainReturn);
22057
+ const { body, css } = extractStyle([...preamble, ...guardBody]);
22058
+ validateBlocks(name, isClientComp, body, file, source);
22059
+ const comp = new ComponentIR(name, paramNames, body, { exported, defaultExport, isClient: inner.client, isAsync: inner.async, ssrAwait: componentUsesFetch(body), propsType, propsAlias });
22060
+ comp.style = css;
22061
+ components.push(comp);
22062
+ __slotProps = prevSlotProps;
21472
22063
  }
21473
- const guardBody = buildGuardChain(source, guardClauses, mainReturn);
21474
- const { body, css } = extractStyle([...preamble, ...guardBody]);
21475
- validateBlocks(name, isClientComp, body, file, source);
21476
- const comp = new ComponentIR(name, paramNames, body, { exported, defaultExport, isClient: inner.client, isAsync: inner.async, ssrAwait: componentUsesFetch(body), propsType, propsAlias });
21477
- comp.style = css;
21478
- components.push(comp);
21479
- __slotProps = prevSlotProps;
22064
+ } finally {
22065
+ currentComponentValues = prevComponentValues;
21480
22066
  }
21481
22067
  }
21482
22068
  const asyncNames = new Set(components.filter((c) => c.isAsync || c.ssrAwait).map((c) => c.name));
@@ -21573,9 +22159,13 @@ function generateIR(ast, source, filename) {
21573
22159
  } finally {
21574
22160
  currentVskNamespaceLocals = prevNamespaceLocals;
21575
22161
  currentSourceFile = prevSourceFile;
22162
+ currentFileComponentNames = prevFileComponentNames;
22163
+ currentFileValueBindings = prevFileValueBindings;
22164
+ currentImportedNames = prevImportedNames;
22165
+ currentComponentCallHelpers = null;
21576
22166
  }
21577
22167
  }
21578
- var __vskAnnotations, __slotProps, __propsParam, currentVskNamespaceLocals, currentSourceFile;
22168
+ var __vskAnnotations, __slotProps, __propsParam, currentVskNamespaceLocals, currentSourceFile, currentComponentValues, currentFileComponentNames, currentFileValueBindings, currentImportedNames, currentComponentCallHelpers;
21579
22169
  var init_ir_generator = __esm({
21580
22170
  "../compiler/src/ir-generator.ts"() {
21581
22171
  "use strict";
@@ -21591,6 +22181,11 @@ var init_ir_generator = __esm({
21591
22181
  __slotProps = null;
21592
22182
  __propsParam = null;
21593
22183
  currentVskNamespaceLocals = null;
22184
+ currentComponentValues = null;
22185
+ currentFileComponentNames = null;
22186
+ currentFileValueBindings = null;
22187
+ currentImportedNames = null;
22188
+ currentComponentCallHelpers = null;
21594
22189
  }
21595
22190
  });
21596
22191
 
@@ -21599,6 +22194,7 @@ var server_utils_exports = {};
21599
22194
  __export(server_utils_exports, {
21600
22195
  CorsResponse: () => CorsResponse,
21601
22196
  DEFAULT_MAX_BODY_BYTES: () => DEFAULT_MAX_BODY_BYTES,
22197
+ VOID_ELEMENTS: () => VOID_ELEMENTS2,
21602
22198
  __vskForceClaim: () => __vskForceClaim,
21603
22199
  __vskHydrate: () => __vskHydrate,
21604
22200
  __vskId: () => __vskId,
@@ -25844,8 +26440,8 @@ function isPublicMarkdownPath(v) {
25844
26440
  const c = s.charCodeAt(i);
25845
26441
  if (c === 63 || c === 35 || c === 92) return false;
25846
26442
  }
25847
- const lower = s.toLowerCase();
25848
- return stringEndsWith(lower, ".md") || stringEndsWith(lower, ".markdown");
26443
+ const lower2 = s.toLowerCase();
26444
+ return stringEndsWith(lower2, ".md") || stringEndsWith(lower2, ".markdown");
25849
26445
  }
25850
26446
  function getMdPathCell(path) {
25851
26447
  let cell = mdPathCells.get(path);
@@ -26517,9 +27113,9 @@ function toDomNode(value) {
26517
27113
  }
26518
27114
  if (typeof value !== "string") return value;
26519
27115
  if (value === "") return document.createDocumentFragment();
26520
- const template = document.createElement("template");
26521
- template.innerHTML = value;
26522
- const { content } = template;
27116
+ const template2 = document.createElement("template");
27117
+ template2.innerHTML = value;
27118
+ const { content } = template2;
26523
27119
  if (content.childNodes.length === 1) {
26524
27120
  const only = content.firstChild;
26525
27121
  content.removeChild(only);
@@ -26712,7 +27308,7 @@ function resolveTitle(meta, child) {
26712
27308
  }
26713
27309
  function mergeMetadata(...sources) {
26714
27310
  const out = {};
26715
- let template;
27311
+ let template2;
26716
27312
  let sawTemplate = false;
26717
27313
  for (const source of sources) {
26718
27314
  if (!source) continue;
@@ -26725,7 +27321,7 @@ function mergeMetadata(...sources) {
26725
27321
  if (key === "title") {
26726
27322
  if (value && typeof value === "object" && value.template) {
26727
27323
  sawTemplate = true;
26728
- template = value.template || template;
27324
+ template2 = value.template || template2;
26729
27325
  }
26730
27326
  out.title = value;
26731
27327
  continue;
@@ -26737,9 +27333,9 @@ function mergeMetadata(...sources) {
26737
27333
  const own = out.title;
26738
27334
  if (typeof own === "string") out.title = { absolute: own };
26739
27335
  else if (own && typeof own === "object" && own.template) {
26740
- out.title = { default: own.default, template: own.template || template };
27336
+ out.title = { default: own.default, template: own.template || template2 };
26741
27337
  } else if (own && typeof own === "object") {
26742
- out.title = { ...own, template };
27338
+ out.title = { ...own, template: template2 };
26743
27339
  }
26744
27340
  }
26745
27341
  return out;
@@ -26825,6 +27421,56 @@ var init_metadata = __esm({
26825
27421
  }
26826
27422
  });
26827
27423
 
27424
+ // ../runtime/src/nested-update.ts
27425
+ function isObject(value) {
27426
+ return value !== null && typeof value === "object";
27427
+ }
27428
+ function setIn(value, path, next) {
27429
+ if (path.length === 0) return next;
27430
+ const [key, ...rest] = path;
27431
+ const container = Array.isArray(value) ? value : isObject(value) ? value : null;
27432
+ if (container === null) return value;
27433
+ const current2 = Array.isArray(container) ? container[typeof key === "number" ? key : Number(key)] : container[String(key)];
27434
+ if (rest.length > 0 && current2 === void 0) return value;
27435
+ if (Array.isArray(value)) {
27436
+ const index = typeof key === "number" ? key : Number(key);
27437
+ if (!Number.isInteger(index) || index < 0) return value;
27438
+ const copy2 = value.slice();
27439
+ copy2[index] = rest.length === 0 ? next : setIn(value[index], rest, next);
27440
+ return copy2;
27441
+ }
27442
+ if (!isObject(value)) return value;
27443
+ const copy = { ...value };
27444
+ copy[String(key)] = rest.length === 0 ? next : setIn(value[String(key)], rest, next);
27445
+ return copy;
27446
+ }
27447
+ function updateIn(value, path, fn) {
27448
+ if (path.length === 0) return fn(value);
27449
+ const [key, ...rest] = path;
27450
+ const child = getIn(value, [key]);
27451
+ const next = rest.length === 0 ? fn(child) : updateIn(child, rest, fn);
27452
+ return setIn(value, [key], next);
27453
+ }
27454
+ function getIn(value, path) {
27455
+ let current2 = value;
27456
+ for (const key of path) {
27457
+ if (Array.isArray(current2)) {
27458
+ const index = typeof key === "number" ? key : Number(key);
27459
+ if (!Number.isInteger(index)) return void 0;
27460
+ current2 = current2[index];
27461
+ continue;
27462
+ }
27463
+ if (!isObject(current2)) return void 0;
27464
+ current2 = current2[String(key)];
27465
+ }
27466
+ return current2;
27467
+ }
27468
+ var init_nested_update = __esm({
27469
+ "../runtime/src/nested-update.ts"() {
27470
+ "use strict";
27471
+ }
27472
+ });
27473
+
26828
27474
  // ../runtime/src/index-server.ts
26829
27475
  var index_server_exports = {};
26830
27476
  __export(index_server_exports, {
@@ -26897,6 +27543,7 @@ __export(index_server_exports, {
26897
27543
  get: () => get,
26898
27544
  getAction: () => getAction,
26899
27545
  getActiveComponent: () => getActiveComponent,
27546
+ getIn: () => getIn,
26900
27547
  getLoadingError: () => getLoadingError,
26901
27548
  getLoadingProgress: () => getLoadingProgress,
26902
27549
  getServerContext: () => getServerContext,
@@ -26950,6 +27597,7 @@ __export(index_server_exports, {
26950
27597
  server_locals: () => server_locals,
26951
27598
  set: () => set,
26952
27599
  setActiveComponent: () => setActiveComponent,
27600
+ setIn: () => setIn,
26953
27601
  setServerContext: () => setServerContext,
26954
27602
  setSignedCookie: () => setSignedCookie2,
26955
27603
  setSsrData: () => setSsrData,
@@ -26964,6 +27612,7 @@ __export(index_server_exports, {
26964
27612
  unlink_block: () => unlink_block,
26965
27613
  unsignCookie: () => unsignCookie2,
26966
27614
  untrack: () => untrack2,
27615
+ updateIn: () => updateIn,
26967
27616
  useBody: () => useBody,
26968
27617
  useFetch: () => useFetch,
26969
27618
  useLoadingIndicator: () => useLoadingIndicator,
@@ -27002,6 +27651,7 @@ var init_index_server = __esm({
27002
27651
  init_loading_indicator();
27003
27652
  init_action();
27004
27653
  init_metadata();
27654
+ init_nested_update();
27005
27655
  }
27006
27656
  });
27007
27657
 
@@ -29243,8 +29893,8 @@ function looksLikeMarkdownPath(value) {
29243
29893
  const v = value.trim();
29244
29894
  if (v.length === 0 || v.length > 4096) return false;
29245
29895
  if (v.includes("\n") || v.includes("\r")) return false;
29246
- const lower = v.toLowerCase();
29247
- return lower.endsWith(MD_EXT_MARKER) || lower.endsWith(".markdown");
29896
+ const lower2 = v.toLowerCase();
29897
+ return lower2.endsWith(MD_EXT_MARKER) || lower2.endsWith(".markdown");
29248
29898
  }
29249
29899
  function isRelativeSpecifier(v) {
29250
29900
  return v.startsWith("./") || v.startsWith("../");
@@ -31817,7 +32467,202 @@ var init_server_head = __esm({
31817
32467
  }
31818
32468
  });
31819
32469
 
32470
+ // ../compiler/src/server-jsx-lowering.ts
32471
+ function containsJsx2(node, depth = 0) {
32472
+ if (!node || typeof node !== "object" || depth > 40) return false;
32473
+ if (Array.isArray(node)) {
32474
+ for (const item of node) if (containsJsx2(item, depth + 1)) return true;
32475
+ return false;
32476
+ }
32477
+ const type = node.type;
32478
+ if (type === "JSXElement" || type === "JSXFragment") return true;
32479
+ for (const key of Object.keys(node)) {
32480
+ const value = node[key];
32481
+ if (value && typeof value === "object" && containsJsx2(value, depth + 1)) return true;
32482
+ }
32483
+ return false;
32484
+ }
32485
+ function normalizeJsxText(value) {
32486
+ const lines = value.split(/\r\n|\n|\r/);
32487
+ let lastNonEmpty = -1;
32488
+ for (let i = 0; i < lines.length; i++) {
32489
+ if (/[^ \t]/.test(lines[i])) lastNonEmpty = i;
32490
+ }
32491
+ let out = "";
32492
+ for (let i = 0; i < lines.length; i++) {
32493
+ let line = lines[i].replace(/\t/g, " ");
32494
+ if (i !== 0) line = line.replace(/^ +/, "");
32495
+ if (i !== lines.length - 1) line = line.replace(/ +$/, "");
32496
+ if (line) {
32497
+ if (i !== lastNonEmpty) line += " ";
32498
+ out += line;
32499
+ }
32500
+ }
32501
+ return out;
32502
+ }
32503
+ function lower(node, ctx2) {
32504
+ if (Array.isArray(node)) return node.map((n2) => lower(n2, ctx2));
32505
+ if (!node || typeof node !== "object") return node;
32506
+ const n = node;
32507
+ if (n.type === "JSXElement") {
32508
+ const opening = n.openingElement;
32509
+ const name = jsxTagName(opening.name);
32510
+ const attrs = lowerAttributes(opening.attributes, ctx2);
32511
+ const children = lowerChildren(n.children, ctx2);
32512
+ const statics = [`<${name}`, ...attrs.statics.slice(1)];
32513
+ statics[statics.length - 1] += ">";
32514
+ const quasis = [...statics, `</${name}>`];
32515
+ const expressions = [...attrs.exprs, ...children];
32516
+ return template(quasis, expressions);
32517
+ }
32518
+ if (n.type === "JSXFragment") {
32519
+ return template(["", ""], lowerChildren(n.children, ctx2));
32520
+ }
32521
+ const out = {};
32522
+ for (const key of Object.keys(n)) {
32523
+ if (key === "type" || key === "start" || key === "end" || key === "loc" || key === "range") {
32524
+ out[key] = n[key];
32525
+ continue;
32526
+ }
32527
+ const value = n[key];
32528
+ out[key] = value && typeof value === "object" ? lower(value, ctx2) : value;
32529
+ }
32530
+ return out;
32531
+ }
32532
+ function jsxTagName(nameNode) {
32533
+ const n = nameNode;
32534
+ if (!n) return "div";
32535
+ if (n.type === "JSXIdentifier") return String(n.name);
32536
+ if (n.type === "JSXMemberExpression") {
32537
+ const object = jsxTagName(n.object);
32538
+ const property = n.property;
32539
+ return `${object}.${String(property?.name)}`;
32540
+ }
32541
+ if (n.type === "JSXNamespacedName") {
32542
+ const ns = n.namespace;
32543
+ const name = n.name;
32544
+ return `${String(ns?.name)}:${String(name?.name)}`;
32545
+ }
32546
+ return "div";
32547
+ }
32548
+ function lowerAttributes(attrs, ctx2) {
32549
+ const statics = [""];
32550
+ const exprs = [];
32551
+ const push = (text, expr) => {
32552
+ if (expr === void 0) {
32553
+ statics[statics.length - 1] += text;
32554
+ return;
32555
+ }
32556
+ statics[statics.length - 1] += text;
32557
+ statics.push("");
32558
+ exprs.push(expr);
32559
+ };
32560
+ for (const attr of attrs || []) {
32561
+ const a = attr;
32562
+ if (a.type === "JSXSpreadAttribute") {
32563
+ console.error("[vesk] a spread attribute in a JSX expression is not supported yet (dropped):", String(a.argument ?? "").slice(0, 60));
32564
+ continue;
32565
+ }
32566
+ const name = jsxAttrName(a.name);
32567
+ const value = a.value;
32568
+ if (value === null || value === void 0) {
32569
+ push(` ${name}`);
32570
+ continue;
32571
+ }
32572
+ if (value.type === "StringLiteral") {
32573
+ push(` ${name}="${escapeAttrText(String(value.value))}"`);
32574
+ continue;
32575
+ }
32576
+ if (value.type === "JSXExpressionContainer") {
32577
+ const inner = value.expression;
32578
+ if (!inner || inner.type === "JSXEmptyExpression") {
32579
+ push(` ${name}="true"`);
32580
+ continue;
32581
+ }
32582
+ push(` ${name}="`, callNode(ATTR, [literal3(name), coerceString(lower(inner, ctx2))]));
32583
+ push('"');
32584
+ continue;
32585
+ }
32586
+ push(` ${name}="`, callNode(ATTR, [literal3(name), coerceString(lower(value, ctx2))]));
32587
+ push('"');
32588
+ }
32589
+ return { statics, exprs };
32590
+ }
32591
+ function jsxAttrName(nameNode) {
32592
+ const n = nameNode;
32593
+ if (!n) return "data";
32594
+ if (n.type === "JSXIdentifier") return String(n.name);
32595
+ return jsxTagName(n);
32596
+ }
32597
+ function lowerChildren(children, ctx2) {
32598
+ const out = [];
32599
+ for (const child of children || []) {
32600
+ const c = child;
32601
+ if (c.type === "JSXText") {
32602
+ const text = normalizeJsxText(String(c.value ?? ""));
32603
+ if (text) out.push(literal3(text));
32604
+ continue;
32605
+ }
32606
+ if (c.type === "JSXExpressionContainer") {
32607
+ const inner = c.expression;
32608
+ if (!inner || inner.type === "JSXEmptyExpression") continue;
32609
+ const lowered2 = lower(inner, ctx2);
32610
+ out.push(coerceString(lowered2));
32611
+ continue;
32612
+ }
32613
+ const lowered = lower(c, ctx2);
32614
+ out.push(coerceString(lowered));
32615
+ }
32616
+ return out;
32617
+ }
32618
+ function coerceString(node) {
32619
+ if (!node || typeof node !== "object") return callNode(ESCAPE, [literal3(String(node))]);
32620
+ const n = node;
32621
+ if (n.type === "TemplateLiteral") return n;
32622
+ if (n.type === "Literal" || n.type === "StringLiteral") return callNode(ESCAPE, [node]);
32623
+ return callNode(ESCAPE, [callNode("String", [node])]);
32624
+ }
32625
+ function template(statics, expressions) {
32626
+ const quasis = statics.map((raw2, i) => ({
32627
+ type: "TemplateElement",
32628
+ value: { raw: raw2 },
32629
+ tail: i === statics.length - 1
32630
+ }));
32631
+ return { type: "TemplateLiteral", quasis, expressions };
32632
+ }
32633
+ function literal3(value) {
32634
+ return { type: "Literal", value };
32635
+ }
32636
+ function callNode(callee, args2) {
32637
+ return {
32638
+ type: "CallExpression",
32639
+ callee: { type: "Identifier", name: callee },
32640
+ arguments: args2,
32641
+ optional: false
32642
+ };
32643
+ }
32644
+ function escapeAttrText(value) {
32645
+ return value.split("&").join("&amp;").split("<").join("&lt;").split(">").join("&gt;").split('"').join("&quot;");
32646
+ }
32647
+ function lowerJsxInExpression(ast) {
32648
+ if (!containsJsx2(ast)) return ast;
32649
+ return lower(ast, { track: false });
32650
+ }
32651
+ var ESCAPE, ATTR;
32652
+ var init_server_jsx_lowering = __esm({
32653
+ "../compiler/src/server-jsx-lowering.ts"() {
32654
+ "use strict";
32655
+ ESCAPE = "__escape";
32656
+ ATTR = "__attr";
32657
+ }
32658
+ });
32659
+
31820
32660
  // ../compiler/src/server-jsgen.ts
32661
+ import { print as print6 } from "esrap";
32662
+ import tsPrinter from "esrap/languages/ts";
32663
+ function printLoweredTs(ast) {
32664
+ return print6(ast, tsPrinter()).code;
32665
+ }
31821
32666
  function sanitizeMarkerName(name) {
31822
32667
  return String(name).split("--").join("-").split("<").join("").split(">").join("");
31823
32668
  }
@@ -31826,7 +32671,7 @@ function componentMarker(compName) {
31826
32671
  }
31827
32672
  function irNodeToJS(node, importedNames, isAsync = false, tracked2) {
31828
32673
  importedNames = importedNames || __vskImportedNames;
31829
- if (node instanceof StaticNode) return staticNodeToJS(node, isAsync, tracked2);
32674
+ if (node instanceof StaticNode) return staticNodeToJS(node, isAsync, tracked2, __inForeignContent);
31830
32675
  if (node instanceof TextNode) {
31831
32676
  if (!node.value) return "";
31832
32677
  return `__out.push(${JSON.stringify(escapeHtml(node.value))});`;
@@ -31868,7 +32713,19 @@ function irNodeToJS(node, importedNames, isAsync = false, tracked2) {
31868
32713
  `})();`
31869
32714
  ].join("\n");
31870
32715
  }
31871
- if (node instanceof RuntimeStatement) return semicolonizeStatement(transformTracked(node, tracked2 || /* @__PURE__ */ new Map()));
32716
+ if (node instanceof RuntimeStatement) {
32717
+ const stmt = node;
32718
+ const lowered = stmt.ast ? lowerJsxInExpression(stmt.ast) : null;
32719
+ if (lowered && lowered !== stmt.ast && (tracked2?.size ?? 0) === 0) {
32720
+ return semicolonizeStatement(printLoweredTs(lowered));
32721
+ }
32722
+ if (lowered && lowered !== stmt.ast) {
32723
+ return semicolonizeStatement(
32724
+ transformTracked({ ...node, ast: lowered }, tracked2 || /* @__PURE__ */ new Map())
32725
+ );
32726
+ }
32727
+ return semicolonizeStatement(transformTracked(node, tracked2 || /* @__PURE__ */ new Map()));
32728
+ }
31872
32729
  if (node instanceof SlotNode) {
31873
32730
  if (__vskMarkerless) return `__out.push(props.children || '');`;
31874
32731
  const sid = `s${nextVskId()}`;
@@ -31885,9 +32742,14 @@ function isEvent(target) {
31885
32742
  return !!target && target.startsWith("on") && target.length > 2;
31886
32743
  }
31887
32744
  function exprJSX(node, tracked2) {
31888
- return exprJS(transformTracked(node, tracked2 || /* @__PURE__ */ new Map()));
32745
+ const lowered = node.ast ? lowerJsxInExpression(node.ast) : null;
32746
+ const didLower = lowered !== node.ast;
32747
+ if (didLower && (tracked2?.size ?? 0) === 0) {
32748
+ return exprJS(printLoweredTs(lowered));
32749
+ }
32750
+ return exprJS(transformTracked({ ...node, ast: lowered }, tracked2 || /* @__PURE__ */ new Map()));
31889
32751
  }
31890
- function staticNodeToJS(node, isAsync = false, tracked2) {
32752
+ function staticNodeToJS(node, isAsync = false, tracked2, inForeign = false) {
31891
32753
  const lines = [];
31892
32754
  const dynAttrTargets = /* @__PURE__ */ new Set();
31893
32755
  for (const child of node.children) {
@@ -31913,17 +32775,19 @@ function staticNodeToJS(node, isAsync = false, tracked2) {
31913
32775
  }
31914
32776
  }
31915
32777
  if (node.selfClosing) {
31916
- let tag = openTag + " />";
32778
+ const voidOrForeign = VOID_ELEMENTS2.has(node.tag) || inForeign;
32779
+ const tail = voidOrForeign ? " />" : `></${node.tag}>`;
31917
32780
  if (hasDynamicAttrs) {
31918
- let expr = JSON.stringify(tag);
32781
+ let expr = JSON.stringify(openTag);
31919
32782
  for (const child of node.children) {
31920
32783
  if (child instanceof DynamicBinding && child.kind === "attribute" && child.target !== "ref" && !isEvent(child.target)) {
31921
32784
  expr += ` + __attr(${JSON.stringify(child.target)}, ${exprJSX(child.expression, tracked2)})`;
31922
32785
  }
31923
32786
  }
32787
+ expr += ` + ${JSON.stringify(tail)}`;
31924
32788
  lines.push(`__out.push(${expr});`);
31925
32789
  } else {
31926
- lines.push(`__out.push(${JSON.stringify(tag)});`);
32790
+ lines.push(`__out.push(${JSON.stringify(openTag + tail)});`);
31927
32791
  }
31928
32792
  return lines.join("\n");
31929
32793
  }
@@ -31942,10 +32806,13 @@ function staticNodeToJS(node, isAsync = false, tracked2) {
31942
32806
  } else {
31943
32807
  lines.push(`__out.push(${JSON.stringify(openTag + ">")});`);
31944
32808
  }
32809
+ const prevForeign = __inForeignContent;
32810
+ if (FOREIGN_ROOTS.has(node.tag)) __inForeignContent = true;
31945
32811
  for (const child of childNodes) {
31946
32812
  const code = irNodeToJS(child, null, isAsync, tracked2);
31947
32813
  if (code) lines.push(code);
31948
32814
  }
32815
+ __inForeignContent = prevForeign;
31949
32816
  lines.push(`__out.push(${JSON.stringify("</" + node.tag + ">")});`);
31950
32817
  return lines.join("\n");
31951
32818
  }
@@ -32033,13 +32900,13 @@ function mapRegionToJS(node, isAsync = false, tracked2) {
32033
32900
  }
32034
32901
  function keyedItemTemplate(node) {
32035
32902
  if (!node.keyExpr) return node.bodyTemplate;
32036
- const template = node.bodyTemplate;
32037
- const idx = template.findIndex((n) => n instanceof StaticNode);
32038
- if (idx === -1) return template;
32039
- const root3 = template[idx];
32903
+ const template2 = node.bodyTemplate;
32904
+ const idx = template2.findIndex((n) => n instanceof StaticNode);
32905
+ if (idx === -1) return template2;
32906
+ const root3 = template2[idx];
32040
32907
  const copy = new StaticNode(root3.tag, root3.attributes, [...root3.children, new DynamicBinding(node.keyExpr, "attribute", "data-vsk-key")], root3.keyExpr);
32041
32908
  copy.selfClosing = root3.selfClosing;
32042
- const out = template.slice();
32909
+ const out = template2.slice();
32043
32910
  out[idx] = copy;
32044
32911
  return out;
32045
32912
  }
@@ -32151,18 +33018,24 @@ function componentCallToJS(node, importedNames, isAsync = false, tracked2) {
32151
33018
  }
32152
33019
  }
32153
33020
  if (regularChildren.length > 0) {
32154
- const childLines = [];
32155
- for (const child of regularChildren) {
32156
- const code = irNodeToJS(child, importedNames, isAsync, tracked2);
32157
- if (code) childLines.push(code);
32158
- }
32159
- if (childLines.length > 0) {
32160
- const childrenVar = `__ch${nextVskId()}`;
32161
- propsEntries.push(`children: ${childrenVar}`);
32162
- lines.push(`const ${childrenVar} = ${isAsync ? "await (async " : "("}() => {`);
32163
- lines.push(`const __out = [];`);
32164
- lines.push(indent(childLines.join("\n")));
32165
- lines.push(`return __out.join(''); })();`);
33021
+ const fnType = regularChildren.length === 1 && regularChildren[0] instanceof DynamicBinding && regularChildren[0].kind === "text" ? regularChildren[0].expression.ast?.type : null;
33022
+ const isFnChild = fnType === "ArrowFunctionExpression" || fnType === "FunctionExpression" || fnType === "Identifier" || fnType === "MemberExpression";
33023
+ if (isFnChild) {
33024
+ propsEntries.push(`children: ${exprJSX(regularChildren[0].expression, tracked2)}`);
33025
+ } else {
33026
+ const childLines = [];
33027
+ for (const child of regularChildren) {
33028
+ const code = irNodeToJS(child, importedNames, isAsync, tracked2);
33029
+ if (code) childLines.push(code);
33030
+ }
33031
+ if (childLines.length > 0) {
33032
+ const childrenVar = `__ch${nextVskId()}`;
33033
+ propsEntries.push(`children: ${childrenVar}`);
33034
+ lines.push(`const ${childrenVar} = ${isAsync ? "await (async " : "("}() => {`);
33035
+ lines.push(`const __out = [];`);
33036
+ lines.push(indent(childLines.join("\n")));
33037
+ lines.push(`return __out.join(''); })();`);
33038
+ }
32166
33039
  }
32167
33040
  }
32168
33041
  const propsObj = `{ ${propsEntries.join(", ")} }`;
@@ -32179,9 +33052,9 @@ function componentCallToJS(node, importedNames, isAsync = false, tracked2) {
32179
33052
  }
32180
33053
  const callExpr3 = `${awaitKw}${calleeVar}(${propsObj}, __registry, (${calleeVar}.__veskScope || __vesk))`;
32181
33054
  if (__vskHydrate && !__vskMarkerless) {
32182
- lines.push(`__out.push(${JSON.stringify(componentMarker(compName))} + (${callExpr3} || ''));`);
33055
+ lines.push(`__out.push(${JSON.stringify(componentMarker(compName))} + __flat(${callExpr3}));`);
32183
33056
  } else {
32184
- lines.push(`__out.push(${callExpr3} || '');`);
33057
+ lines.push(`__out.push(__flat(${callExpr3}));`);
32185
33058
  }
32186
33059
  return lines.join("\n");
32187
33060
  }
@@ -32199,6 +33072,7 @@ function generateFunctionBody(comp, importedNames) {
32199
33072
  lines.push(`const __styleText = (v) => { if (typeof v === 'string') return v; if (v && typeof v === 'object') { let s = ''; for (const k in v) { const x = v[k]; if (x == null || x === false) continue; s += k.replace(/[A-Z]/g, (m) => '-' + m.toLowerCase()) + ':' + x + ';'; } return s; } return String(v); };`);
32200
33073
  lines.push(`const __attr = (n, v) => (v == null || v === false) ? '' : ' ' + n + '="' + __escape(n === 'style' ? __styleText(v) : String(v)) + '"';`);
32201
33074
  lines.push(`const raw = (s) => s == null ? '' : String(s);`);
33075
+ lines.push(`const __flat = (v) => Array.isArray(v) ? v.join('') : (v == null ? '' : String(v));`);
32202
33076
  lines.push(`const __tk = globalThis.__vsk_ssr_token || '';`);
32203
33077
  if (asyncMode) {
32204
33078
  lines.push(`const __pk = __tk ? '__vsk_ssr_promises_' + __tk : '__vsk_ssr_promises';`);
@@ -32235,6 +33109,64 @@ function generateFunctionBody(comp, importedNames) {
32235
33109
  __currentCompName = "";
32236
33110
  return lines.join("\n");
32237
33111
  }
33112
+ function bodyNeedsRuntimeCells(nodes) {
33113
+ for (const node of nodes) {
33114
+ if (node instanceof TrackDecl) return true;
33115
+ if (node instanceof RuntimeStatement && callsIdentifier(node.raw, "track")) return true;
33116
+ if (node instanceof Expression && callsIdentifier(node.raw, "track")) return true;
33117
+ if (node instanceof ForLoop) {
33118
+ if (callsIdentifier(node.init, "track")) return true;
33119
+ if (callsIdentifier(node.update, "track")) return true;
33120
+ if (callsIdentifier(node.condition.raw, "track")) return true;
33121
+ if (bodyNeedsRuntimeCells(node.bodyTemplate)) return true;
33122
+ }
33123
+ if (node instanceof StaticNode) {
33124
+ for (const attr of node.attributes) {
33125
+ if (callsIdentifier(attr.value, "track")) return true;
33126
+ }
33127
+ if (bodyNeedsRuntimeCells(node.children)) return true;
33128
+ }
33129
+ if (node instanceof ComponentCall) {
33130
+ for (const prop of node.props) {
33131
+ if (callsIdentifier(prop.value.raw, "track")) return true;
33132
+ }
33133
+ for (const spread of node.spreadProps) {
33134
+ if (callsIdentifier(spread.raw, "track")) return true;
33135
+ }
33136
+ if (bodyNeedsRuntimeCells(node.children)) return true;
33137
+ }
33138
+ if (node instanceof ServerBlock || node instanceof ClientBlock || node instanceof HeadBlock) {
33139
+ if (bodyNeedsRuntimeCells(node.children)) return true;
33140
+ }
33141
+ if (node instanceof PropSlot && bodyNeedsRuntimeCells(node.body)) return true;
33142
+ if (node instanceof MapRegion) {
33143
+ if (callsIdentifier(node.expression.raw, "track")) return true;
33144
+ if (bodyNeedsRuntimeCells(node.bodyTemplate)) return true;
33145
+ if (bodyNeedsRuntimeCells(node.alternateNodes)) return true;
33146
+ }
33147
+ if (node instanceof OpaqueDynamicRegion) {
33148
+ if (callsIdentifier(node.condition.raw, "track")) return true;
33149
+ if (bodyNeedsRuntimeCells(node.consequentNodes)) return true;
33150
+ if (bodyNeedsRuntimeCells(node.alternateNodes)) return true;
33151
+ }
33152
+ if (node instanceof WhileLoop) {
33153
+ if (callsIdentifier(node.condition.raw, "track")) return true;
33154
+ if (bodyNeedsRuntimeCells(node.bodyTemplate)) return true;
33155
+ }
33156
+ if (node instanceof SwitchBlock) {
33157
+ if (callsIdentifier(node.discriminant.raw, "track")) return true;
33158
+ for (const c of node.cases) {
33159
+ if (c.test && callsIdentifier(c.test.raw, "track")) return true;
33160
+ if (bodyNeedsRuntimeCells(c.body)) return true;
33161
+ }
33162
+ }
33163
+ if (node instanceof TryCatch) {
33164
+ if (bodyNeedsRuntimeCells(node.bodyTemplate)) return true;
33165
+ if (bodyNeedsRuntimeCells(node.catchBody)) return true;
33166
+ }
33167
+ }
33168
+ return false;
33169
+ }
32238
33170
  function buildComponentEntries(irRoot) {
32239
33171
  const runtimeNames = extractRuntimeNames(irRoot.imports);
32240
33172
  const localValueNames = localValueImportNames(irRoot.imports);
@@ -32242,7 +33174,7 @@ function buildComponentEntries(irRoot) {
32242
33174
  const componentNames = new Set(irRoot.components.map((c) => c.name));
32243
33175
  const topValueNames = topNames.filter((n) => !componentNames.has(n));
32244
33176
  const importedNames = /* @__PURE__ */ new Set([...runtimeNames, ...localValueNames, ...topValueNames]);
32245
- const hasTracked = irRoot.components.some((c) => c.body.some((n) => n instanceof TrackDecl));
33177
+ const hasTracked = irRoot.components.some((c) => bodyNeedsRuntimeCells(c.body));
32246
33178
  const extraNames = hasTracked ? ["get", "set", "track"] : [];
32247
33179
  const vskValueNames = vskImportValueNames(irRoot.imports);
32248
33180
  const allNames = [.../* @__PURE__ */ new Set([...runtimeNames, ...topNames, ...extraNames, ...localValueNames, ...vskValueNames])];
@@ -32277,7 +33209,7 @@ ${entry.source}
32277
33209
  }
32278
33210
  return map;
32279
33211
  }
32280
- var __currentCompName;
33212
+ var __currentCompName, __inForeignContent, FOREIGN_ROOTS;
32281
33213
  var init_server_jsgen = __esm({
32282
33214
  "../compiler/src/server-jsgen.ts"() {
32283
33215
  "use strict";
@@ -32286,8 +33218,11 @@ var init_server_jsgen = __esm({
32286
33218
  init_scan();
32287
33219
  init_server_utils();
32288
33220
  init_module_imports();
33221
+ init_server_jsx_lowering();
32289
33222
  init_vsk_imports();
32290
33223
  __currentCompName = "";
33224
+ __inForeignContent = false;
33225
+ FOREIGN_ROOTS = /* @__PURE__ */ new Set(["svg", "math"]);
32291
33226
  }
32292
33227
  });
32293
33228
 
@@ -33050,8 +33985,8 @@ function installMdReadHook(publicDirs) {
33050
33985
  while (rel.length > 0 && rel.charCodeAt(0) === 47) rel = rel.slice(1);
33051
33986
  const abs = resolveWithin(dir, rel);
33052
33987
  if (!abs) continue;
33053
- const lower = abs.toLowerCase();
33054
- if (!lower.endsWith(".md") && !lower.endsWith(".markdown")) continue;
33988
+ const lower2 = abs.toLowerCase();
33989
+ if (!lower2.endsWith(".md") && !lower2.endsWith(".markdown")) continue;
33055
33990
  if (existsSync12(abs) && statSync4(abs).isFile()) return readFileSync12(abs, "utf8");
33056
33991
  } catch {
33057
33992
  }
@@ -37478,8 +38413,8 @@ function isPublicMarkdownPath2(v) {
37478
38413
  if (c === 63 || c === 35 || c === 92)
37479
38414
  return false;
37480
38415
  }
37481
- const lower = s.toLowerCase();
37482
- return stringEndsWith2(lower, ".md") || stringEndsWith2(lower, ".markdown");
38416
+ const lower2 = s.toLowerCase();
38417
+ return stringEndsWith2(lower2, ".md") || stringEndsWith2(lower2, ".markdown");
37483
38418
  }
37484
38419
  function getMdPathCell2(path) {
37485
38420
  let cell = mdPathCells2.get(path);
@@ -38219,7 +39154,10 @@ var init_errors2 = __esm({
38219
39154
  suggestions;
38220
39155
  nextSteps;
38221
39156
  tip;
39157
+ /** The V-diagnostic code, e.g. `V0501`. */
38222
39158
  code;
39159
+ /** The rendered code frame. Used to be written into `code`, which silently replaced the V-code. */
39160
+ frame;
38223
39161
  constructor(message, opts = {}) {
38224
39162
  super(message);
38225
39163
  this.name = "VeskError";
@@ -38229,8 +39167,10 @@ var init_errors2 = __esm({
38229
39167
  this.suggestions = opts.suggestions || [];
38230
39168
  this.nextSteps = opts.nextSteps || [];
38231
39169
  this.tip = opts.tip || "";
38232
- if (opts.code !== void 0)
39170
+ if (opts.code !== void 0 && !opts.code.includes("\n"))
38233
39171
  this.code = opts.code;
39172
+ if (opts.frame !== void 0)
39173
+ this.frame = opts.frame;
38234
39174
  }
38235
39175
  static notFound(name, candidates = [], context = {}) {
38236
39176
  const allCandidates = [.../* @__PURE__ */ new Set([...candidates, ...VESK_BUILTINS2])];
@@ -38268,6 +39208,39 @@ var init_errors2 = __esm({
38268
39208
  * - `value` — `ns.max` read as a value. Component tags resolve; plain value
38269
39209
  * reads do not, because nothing binds `ns` at runtime.
38270
39210
  */
39211
+ /**
39212
+ * An imported `.ts`/`.js` module could not be parsed.
39213
+ *
39214
+ * This used to be silent, and that is the whole point of the diagnostic. A
39215
+ * parse failure meant the module's RAW, untranspiled source was substituted,
39216
+ * so TypeScript syntax reached `new Function` and the module blew up much
39217
+ * later with a bare `Unexpected token ':'` — attributed to no file, at a
39218
+ * point in the build far from the code that caused it. It also poisoned the
39219
+ * whole shared module graph: one unparseable module left its exports
39220
+ * undefined, so unrelated consumers failed with `X is not iterable`.
39221
+ *
39222
+ * Two real constructs hit this: a parameter annotation that survived the
39223
+ * stripper only when the parameter also had a default value, and a generic
39224
+ * arrow's type parameter list, which the JSX tokenizer cannot read at all.
39225
+ * Both are fixed; this error exists so the NEXT such gap is reported at the
39226
+ * right file with the right line instead of surfacing three modules later.
39227
+ */
39228
+ static moduleParseFailed(context = {}) {
39229
+ return new _VeskError(`Could not parse an imported module${context.reason ? `: ${context.reason}` : "."}`, {
39230
+ ...context,
39231
+ code: context.code || "V0901",
39232
+ suggestions: [
39233
+ "Check the line the ^ marker points at \u2014 it is the construct the parser stopped on.",
39234
+ "If it is TypeScript syntax the stripper does not handle, simplifying it here fixes every module that imports this file.",
39235
+ "This is a bug in the compiler, not in your code, if the construct is ordinary TypeScript \u2014 please report it with the source line."
39236
+ ],
39237
+ nextSteps: [
39238
+ "A module that fails to parse is substituted with its raw source, so every type annotation it contains becomes a runtime SyntaxError.",
39239
+ "The failure is reported here, at the offending file and line, rather than as an `Unexpected token` in whichever module happened to import it."
39240
+ ],
39241
+ tip: "Ordinary TypeScript should parse; if this fires on valid TS, the parser is missing a construct."
39242
+ });
39243
+ }
38271
39244
  static vskNamespaceMember(context = {}) {
38272
39245
  const nested = context.form === "nested";
38273
39246
  return new _VeskError(nested ? "A `.vsk` namespace is flat, so `<ns.Sub.Icon />` cannot be resolved." : "A `.vsk` namespace resolves component tags only, so `ns.value` is not available.", {
@@ -38303,6 +39276,75 @@ var init_errors2 = __esm({
38303
39276
  tip: "Use plain objects for data and factory functions for constructors inside .vsk files."
38304
39277
  });
38305
39278
  }
39279
+ /**
39280
+ * A browser-only global used in code the SERVER evaluates.
39281
+ *
39282
+ * On the server these are either absent (`window is not defined`) or, worse,
39283
+ * silently present-but-wrong (`navigator` exists in modern Node, so
39284
+ * `navigator.onLine` is `undefined` and a page renders as if it were offline).
39285
+ * A raw `ReferenceError` at request time is the worst possible report: it
39286
+ * names neither the component nor the fix. This points at the line.
39287
+ */
39288
+ static ssrUnsafeGlobal(name, context = {}) {
39289
+ return new _VeskError(`\`${name}\` is browser-only, and this component body runs during SSR.`, {
39290
+ ...context,
39291
+ code: context.code || "V0501",
39292
+ suggestions: [
39293
+ `Wrap the part that needs the DOM in a {#client} block.`,
39294
+ `Move the code into an event handler \u2014 handlers never run on the server.`,
39295
+ `Do the setup in on_destroy(), which the compiler only emits on the client.`
39296
+ ],
39297
+ nextSteps: [
39298
+ `component ${context.inComponent ?? "this component"}: wrap the \`${name}\` access in {#client}...{/client}.`,
39299
+ `Or guard it: if (typeof ${name} !== 'undefined') { ... }`
39300
+ ],
39301
+ tip: "SSR renders this component before the client exists. Reading a browser global here either throws during the request or (for `navigator`) silently returns undefined."
39302
+ });
39303
+ }
39304
+ /**
39305
+ * The second name from `track()` called as a function.
39306
+ *
39307
+ * `const &[count, setCount] = track(0)` returns a CELL, not a setter function, so
39308
+ * `setCount(1)` throws `setCount is not a function` from generated code with
39309
+ * no line of user code in the message. The cell is the writer: `.set(v)`.
39310
+ */
39311
+ static cellCalledAsFunction(name, context = {}) {
39312
+ return new _VeskError(`\`${name}\` is a cell, not a function \u2014 cells are written with \`.set()\`.`, {
39313
+ ...context,
39314
+ code: context.code || "V0502",
39315
+ suggestions: [
39316
+ `Use \`${name}.set(...)\` instead of \`${name}(...)\`.`,
39317
+ `Or use the tracked spelling inside an event handler: set(${context.value ?? "value"}, ...)`
39318
+ ],
39319
+ nextSteps: [
39320
+ `const &[${context.value ?? "value"}, ${name}] = track(0) \u2192 \`${name}.set(v)\``,
39321
+ "The value read in markup is the first name; the second is the cell object."
39322
+ ],
39323
+ tip: `\`track()\` returns [value, cell]. \`${name}\` is the cell half.`
39324
+ });
39325
+ }
39326
+ /**
39327
+ * `set(value, …)` used outside a rewritten expression.
39328
+ *
39329
+ * The compiler rewrites `set(count, v)` to `countCell.set(v)` inside JSX and
39330
+ * event handlers — but a bare statement in the component body is NOT
39331
+ * rewritten, so the runtime `set` receives the value and throws
39332
+ * "Cannot read properties of undefined". Pass the CELL, not the value.
39333
+ */
39334
+ static setWithValueName(name, context = {}) {
39335
+ return new _VeskError(`\`set(${name}, \u2026)\` needs the CELL, and \`${name}\` is the value half of track().`, {
39336
+ ...context,
39337
+ code: context.code || "V0503",
39338
+ suggestions: [
39339
+ `Use \`set(${context.cell ?? "cell"}, \u2026)\` or \`${context.cell ?? "cell"}.set(\u2026)\`.`,
39340
+ `Or move the set() into an event handler, where the compiler rewrites it for you.`
39341
+ ],
39342
+ nextSteps: [
39343
+ `const &[${name}, ${context.cell ?? "cell"}] = track(0) \u2192 \`${context.cell ?? "cell"}.set(v)\``
39344
+ ],
39345
+ tip: "set(cell, value) is only rewritten inside JSX and handlers; in a body statement it reaches the runtime untouched."
39346
+ });
39347
+ }
38306
39348
  static serverBlockInClient(compName, context = {}) {
38307
39349
  return new _VeskError(`{#server} block found in client island "${compName}". Client islands render on both server and client, so {#server} blocks have no effect.`, {
38308
39350
  ...context,
@@ -45705,12 +46747,182 @@ function preprocessForClauses2(source) {
45705
46747
  }
45706
46748
  return { code: chars.join(""), annotations };
45707
46749
  }
46750
+ function blankGenericArrowTypeParams2(source) {
46751
+ let changed = false;
46752
+ const chars = source.split("");
46753
+ let i = 0;
46754
+ const isSpace = (ch) => isSpaceChar2(ch);
46755
+ while (i < source.length) {
46756
+ const ch = source[i];
46757
+ if (ch === '"' || ch === "'" || ch === "`") {
46758
+ const quote = ch;
46759
+ let j2 = i + 1;
46760
+ while (j2 < source.length) {
46761
+ if (source[j2] === "\\") {
46762
+ j2 += 2;
46763
+ continue;
46764
+ }
46765
+ if (source[j2] === quote) {
46766
+ j2++;
46767
+ break;
46768
+ }
46769
+ if (quote === "`" && source[j2] === "$" && source[j2 + 1] === "{") {
46770
+ let depth = 1;
46771
+ j2 += 2;
46772
+ while (j2 < source.length && depth > 0) {
46773
+ if (source[j2] === "{")
46774
+ depth++;
46775
+ else if (source[j2] === "}")
46776
+ depth--;
46777
+ j2++;
46778
+ }
46779
+ continue;
46780
+ }
46781
+ j2++;
46782
+ }
46783
+ i = j2;
46784
+ continue;
46785
+ }
46786
+ if (ch === "/" && source[i + 1] === "/") {
46787
+ while (i < source.length && source[i] !== "\n")
46788
+ i++;
46789
+ continue;
46790
+ }
46791
+ if (ch === "/" && source[i + 1] === "*") {
46792
+ i += 2;
46793
+ while (i < source.length && !(source[i] === "*" && source[i + 1] === "/"))
46794
+ i++;
46795
+ i += 2;
46796
+ continue;
46797
+ }
46798
+ if (ch !== "<") {
46799
+ i++;
46800
+ continue;
46801
+ }
46802
+ let j = i + 1;
46803
+ let angle = 1;
46804
+ let end = -1;
46805
+ let bail = false;
46806
+ while (j < source.length) {
46807
+ const c = source[j];
46808
+ if (c === "<") {
46809
+ angle++;
46810
+ j++;
46811
+ continue;
46812
+ }
46813
+ if (c === ">") {
46814
+ angle--;
46815
+ j++;
46816
+ if (angle === 0) {
46817
+ end = j;
46818
+ break;
46819
+ }
46820
+ continue;
46821
+ }
46822
+ if (c === "(" || c === "[" || c === "{") {
46823
+ const close = c === "(" ? ")" : c === "[" ? "]" : "}";
46824
+ let depth = 0;
46825
+ while (j < source.length) {
46826
+ const d = source[j];
46827
+ if (d === c)
46828
+ depth++;
46829
+ else if (d === close) {
46830
+ depth--;
46831
+ if (depth === 0) {
46832
+ j++;
46833
+ break;
46834
+ }
46835
+ }
46836
+ j++;
46837
+ }
46838
+ continue;
46839
+ }
46840
+ if (c === ";" || c === "\n") {
46841
+ bail = true;
46842
+ break;
46843
+ }
46844
+ j++;
46845
+ }
46846
+ if (bail || end < 0) {
46847
+ i++;
46848
+ continue;
46849
+ }
46850
+ if (!isArrowParameterList2(source, end)) {
46851
+ i = end;
46852
+ continue;
46853
+ }
46854
+ for (let p = i; p < end; p++) {
46855
+ if (chars[p] !== "\n")
46856
+ chars[p] = " ";
46857
+ }
46858
+ changed = true;
46859
+ i = end;
46860
+ }
46861
+ return changed ? chars.join("") : source;
46862
+ }
46863
+ function isArrowParameterList2(source, from) {
46864
+ let i = from;
46865
+ while (i < source.length && isSpaceChar2(source[i]))
46866
+ i++;
46867
+ if (source[i] !== "(")
46868
+ return false;
46869
+ let depth = 0;
46870
+ while (i < source.length) {
46871
+ const ch = source[i];
46872
+ if (ch === "(" || ch === "[" || ch === "{") {
46873
+ depth++;
46874
+ i++;
46875
+ continue;
46876
+ }
46877
+ if (ch === ")" || ch === "]" || ch === "}") {
46878
+ depth--;
46879
+ i++;
46880
+ if (depth === 0)
46881
+ break;
46882
+ continue;
46883
+ }
46884
+ i++;
46885
+ }
46886
+ if (depth !== 0)
46887
+ return false;
46888
+ while (i < source.length && isSpaceChar2(source[i]))
46889
+ i++;
46890
+ if (source[i] === ":") {
46891
+ i++;
46892
+ let tdepth = 0;
46893
+ while (i < source.length) {
46894
+ const ch = source[i];
46895
+ if (ch === "(" || ch === "[" || ch === "{") {
46896
+ tdepth++;
46897
+ i++;
46898
+ continue;
46899
+ }
46900
+ if (ch === ")" || ch === "]" || ch === "}") {
46901
+ if (tdepth === 0)
46902
+ return false;
46903
+ tdepth--;
46904
+ i++;
46905
+ continue;
46906
+ }
46907
+ if (tdepth === 0 && ch === "=" && source[i + 1] === ">")
46908
+ return true;
46909
+ if (tdepth === 0 && (ch === ";" || ch === "\n"))
46910
+ return false;
46911
+ i++;
46912
+ }
46913
+ return false;
46914
+ }
46915
+ return source[i] === "=" && source[i + 1] === ">";
46916
+ }
46917
+ function isSpaceChar2(ch) {
46918
+ return ch === " " || ch === " " || ch === "\n" || ch === "\r" || ch === "\f" || ch === "\v";
46919
+ }
45708
46920
  function createBaseParser2() {
45709
46921
  return Parser.extend(tsPlugin2({}), VeskParserPlugin());
45710
46922
  }
45711
46923
  function parse5(source, options = {}) {
45712
46924
  const ParserClass = createBaseParser2();
45713
- const { code, annotations } = preprocessForClauses2(blankComments(source));
46925
+ const { code, annotations } = preprocessForClauses2(blankGenericArrowTypeParams2(blankComments(source)));
45714
46926
  const vskSource = !options.filename || String(options.filename).endsWith(".vsk");
45715
46927
  const specifierExports = vskSource ? findSpecifierExports(code).filter((e) => !hasTopLevelValueDeclaration(code, e.local)) : [];
45716
46928
  let parseable = code;
@@ -48655,12 +49867,26 @@ ${entry.code}
48655
49867
  write: false,
48656
49868
  logLevel: "silent",
48657
49869
  loader: { ".js": "tsx" },
49870
+ // Bundled dependencies (lucide-vesk above all) carry a license
49871
+ // banner per module, and a barrel import pulls in hundreds of
49872
+ // them. Those banners were ~339 KB of a 350 KB chunk, which is
49873
+ // what kept a barrel import from being usable at all. Attribution
49874
+ // for a dependency stays in its own package; shipping every
49875
+ // module's header inside our own chunk adds nothing.
49876
+ legalComments: "none",
48658
49877
  ...appTsconfig ? { tsconfig: appTsconfig } : {}
48659
49878
  });
48660
49879
  finalCode = result.outputFiles[0].text;
48661
49880
  } catch (e) {
48662
49881
  const err = e;
48663
- console.error("[vesk] chunk bundle failed", entry.name, err?.errors?.map((x) => x.text).join(" | ") || err?.message || String(e));
49882
+ const detail = err?.errors?.map((x) => {
49883
+ const at2 = x.location?.file ? ` (${x.location.file}${x.location.line ? `:${x.location.line}` : ""})` : "";
49884
+ return x.text + at2;
49885
+ }).join(" | ") || err?.message || String(e);
49886
+ console.error("[vesk] chunk bundle failed", entry.name, detail);
49887
+ if (options?.strict) {
49888
+ throw new Error(`[vesk] chunk bundle failed: ${entry.name} \u2014 ${detail}`);
49889
+ }
48664
49890
  const stripped = demoteExports(removeCompiledNodes(entry.code, isAnyImport));
48665
49891
  finalCode = chunkIIFE(nativeLibraryImportStubs(entry.code) + stripped);
48666
49892
  } finally {
@@ -49844,6 +51070,8 @@ async function build2(appDir, options) {
49844
51070
  bundleOpts.codeSplit = true;
49845
51071
  if (options?.hmr)
49846
51072
  bundleOpts.hmr = true;
51073
+ if (options?.strict)
51074
+ bundleOpts.strict = true;
49847
51075
  if (options?.routeDataCache !== void 0)
49848
51076
  bundleOpts.routeDataCache = options.routeDataCache;
49849
51077
  if (pluginsPipelines.length > 0)
@@ -50051,7 +51279,7 @@ import { WebSocketServer as WebSocketServer2 } from "ws";
50051
51279
  // ../compiler/dist/strip-ts.js
50052
51280
  init_parser();
50053
51281
  import { walk as walk6 } from "zimmerframe";
50054
- import { print as print6 } from "esrap";
51282
+ import { print as print7 } from "esrap";
50055
51283
  import ts6 from "esrap/languages/ts";
50056
51284
  var TS_NODE_TYPES2 = /* @__PURE__ */ new Set([
50057
51285
  "TSAsExpression",
@@ -50222,17 +51450,41 @@ function stripTsTypes2(ast) {
50222
51450
  }
50223
51451
  });
50224
51452
  }
51453
+ function stripParamTypes2(p) {
51454
+ if (!p)
51455
+ return;
51456
+ if (p.typeAnnotation)
51457
+ p.typeAnnotation = null;
51458
+ if (p.optional)
51459
+ p.optional = false;
51460
+ switch (p.type) {
51461
+ case "AssignmentPattern":
51462
+ stripParamTypes2(p.left);
51463
+ break;
51464
+ case "RestElement":
51465
+ stripParamTypes2(p.argument);
51466
+ break;
51467
+ case "ObjectPattern":
51468
+ for (const prop of p.properties || []) {
51469
+ stripParamTypes2(prop.value || prop.argument || prop);
51470
+ }
51471
+ break;
51472
+ case "ArrayPattern":
51473
+ for (const el of p.elements || [])
51474
+ if (el)
51475
+ stripParamTypes2(el);
51476
+ break;
51477
+ default:
51478
+ break;
51479
+ }
51480
+ }
50225
51481
  function stripFunctionTypes2(node) {
50226
51482
  if (node.returnType)
50227
51483
  node.returnType = null;
50228
51484
  if (node.typeParameters)
50229
51485
  node.typeParameters = null;
50230
- for (const p of node.params || []) {
50231
- if (p.typeAnnotation)
50232
- p.typeAnnotation = null;
50233
- if (p.optional)
50234
- p.optional = false;
50235
- }
51486
+ for (const p of node.params || [])
51487
+ stripParamTypes2(p);
50236
51488
  }
50237
51489
  function stripCodeTypes2(code) {
50238
51490
  let ast;
@@ -50248,7 +51500,7 @@ function stripCodeTypes2(code) {
50248
51500
  stripped.body = stripped.body.filter((n) => !isTypeOnlyStatement2(n));
50249
51501
  }
50250
51502
  try {
50251
- return print6(stripped, ts6()).code;
51503
+ return print7(stripped, ts6()).code;
50252
51504
  } catch {
50253
51505
  return code;
50254
51506
  }
@@ -50387,7 +51639,7 @@ init_vsk_imports();
50387
51639
  init_md_inline();
50388
51640
  init_strip_ts();
50389
51641
  import { walk as walk7 } from "zimmerframe";
50390
- import { print as print7 } from "esrap";
51642
+ import { print as print8 } from "esrap";
50391
51643
  import ts7 from "esrap/languages/ts";
50392
51644
  import tsx2 from "esrap/languages/tsx";
50393
51645
  function callExpr2(callee, args2 = []) {
@@ -50454,12 +51706,12 @@ function semicolonizeStatement2(code) {
50454
51706
  return code;
50455
51707
  return code + ";";
50456
51708
  }
50457
- function containsJsx2(node, depth = 0) {
51709
+ function containsJsx3(node, depth = 0) {
50458
51710
  if (!node || typeof node !== "object" || depth > 40)
50459
51711
  return false;
50460
51712
  if (Array.isArray(node)) {
50461
51713
  for (const item of node) {
50462
- if (containsJsx2(item, depth + 1))
51714
+ if (containsJsx3(item, depth + 1))
50463
51715
  return true;
50464
51716
  }
50465
51717
  return false;
@@ -50468,13 +51720,13 @@ function containsJsx2(node, depth = 0) {
50468
51720
  return true;
50469
51721
  for (const key of Object.keys(node)) {
50470
51722
  const v = node[key];
50471
- if (v && typeof v === "object" && containsJsx2(v, depth + 1))
51723
+ if (v && typeof v === "object" && containsJsx3(v, depth + 1))
50472
51724
  return true;
50473
51725
  }
50474
51726
  return false;
50475
51727
  }
50476
51728
  function printAst2(ast) {
50477
- return print7(ast, containsJsx2(ast) ? tsx2() : ts7()).code;
51729
+ return print8(ast, containsJsx3(ast) ? tsx2() : ts7()).code;
50478
51730
  }
50479
51731
  function effectBlockToHandlerExpr2(eff) {
50480
51732
  try {
@@ -50595,7 +51847,7 @@ function transformTracked2(irNode, tracked2) {
50595
51847
  return context.next();
50596
51848
  }
50597
51849
  });
50598
- return print7(transformed, containsJsx2(transformed) ? tsx2() : ts7()).code;
51850
+ return print8(transformed, containsJsx3(transformed) ? tsx2() : ts7()).code;
50599
51851
  }
50600
51852
  function collectTrackedNames2(body) {
50601
51853
  const names = /* @__PURE__ */ new Map();
@@ -53012,6 +54264,10 @@ function matchUrl(tree, pathname) {
53012
54264
  pushWithStandalone(node);
53013
54265
  return true;
53014
54266
  }
54267
+ if (partIndex >= parts.length && node.page && node.fullPath === "/" + parts.join("/")) {
54268
+ pushWithStandalone(node);
54269
+ return true;
54270
+ }
53015
54271
  continue;
53016
54272
  }
53017
54273
  if (node.fullPath === "/") {
@@ -53730,8 +54986,8 @@ function looksLikeMarkdownPath2(value) {
53730
54986
  return false;
53731
54987
  if (v.includes("\n") || v.includes("\r"))
53732
54988
  return false;
53733
- const lower = v.toLowerCase();
53734
- return lower.endsWith(MD_EXT_MARKER2) || lower.endsWith(".markdown");
54989
+ const lower2 = v.toLowerCase();
54990
+ return lower2.endsWith(MD_EXT_MARKER2) || lower2.endsWith(".markdown");
53735
54991
  }
53736
54992
  function isRelativeSpecifier2(v) {
53737
54993
  return v.startsWith("./") || v.startsWith("../");
@@ -54581,12 +55837,26 @@ ${entry.code}
54581
55837
  write: false,
54582
55838
  logLevel: "silent",
54583
55839
  loader: { ".js": "tsx" },
55840
+ // Bundled dependencies (lucide-vesk above all) carry a license
55841
+ // banner per module, and a barrel import pulls in hundreds of
55842
+ // them. Those banners were ~339 KB of a 350 KB chunk, which is
55843
+ // what kept a barrel import from being usable at all. Attribution
55844
+ // for a dependency stays in its own package; shipping every
55845
+ // module's header inside our own chunk adds nothing.
55846
+ legalComments: "none",
54584
55847
  ...appTsconfig ? { tsconfig: appTsconfig } : {}
54585
55848
  });
54586
55849
  finalCode = result.outputFiles[0].text;
54587
55850
  } catch (e) {
54588
55851
  const err = e;
54589
- console.error("[vesk] chunk bundle failed", entry.name, err?.errors?.map((x) => x.text).join(" | ") || err?.message || String(e));
55852
+ const detail = err?.errors?.map((x) => {
55853
+ const at2 = x.location?.file ? ` (${x.location.file}${x.location.line ? `:${x.location.line}` : ""})` : "";
55854
+ return x.text + at2;
55855
+ }).join(" | ") || err?.message || String(e);
55856
+ console.error("[vesk] chunk bundle failed", entry.name, detail);
55857
+ if (options?.strict) {
55858
+ throw new Error(`[vesk] chunk bundle failed: ${entry.name} \u2014 ${detail}`);
55859
+ }
54590
55860
  const stripped = demoteExports2(removeCompiledNodes2(entry.code, isAnyImport2));
54591
55861
  finalCode = chunkIIFE(nativeLibraryImportStubs2(entry.code) + stripped);
54592
55862
  } finally {
@@ -54937,8 +56207,8 @@ function installMdReadHook2(publicDirs) {
54937
56207
  const abs = resolveWithin2(dir, rel);
54938
56208
  if (!abs)
54939
56209
  continue;
54940
- const lower = abs.toLowerCase();
54941
- if (!lower.endsWith(".md") && !lower.endsWith(".markdown"))
56210
+ const lower2 = abs.toLowerCase();
56211
+ if (!lower2.endsWith(".md") && !lower2.endsWith(".markdown"))
54942
56212
  continue;
54943
56213
  if (existsSync29(abs) && statSync15(abs).isFile())
54944
56214
  return readFileSync25(abs, "utf8");
@@ -62809,6 +64079,7 @@ __export(index_server_exports2, {
62809
64079
  get: () => get,
62810
64080
  getAction: () => getAction,
62811
64081
  getActiveComponent: () => getActiveComponent,
64082
+ getIn: () => getIn,
62812
64083
  getLoadingError: () => getLoadingError,
62813
64084
  getLoadingProgress: () => getLoadingProgress,
62814
64085
  getServerContext: () => getServerContext,
@@ -62862,6 +64133,7 @@ __export(index_server_exports2, {
62862
64133
  server_locals: () => server_locals,
62863
64134
  set: () => set,
62864
64135
  setActiveComponent: () => setActiveComponent,
64136
+ setIn: () => setIn,
62865
64137
  setServerContext: () => setServerContext,
62866
64138
  setSignedCookie: () => setSignedCookie2,
62867
64139
  setSsrData: () => setSsrData,
@@ -62876,6 +64148,7 @@ __export(index_server_exports2, {
62876
64148
  unlink_block: () => unlink_block,
62877
64149
  unsignCookie: () => unsignCookie2,
62878
64150
  untrack: () => untrack2,
64151
+ updateIn: () => updateIn,
62879
64152
  useBody: () => useBody,
62880
64153
  useFetch: () => useFetch,
62881
64154
  useLoadingIndicator: () => useLoadingIndicator,
@@ -62911,6 +64184,7 @@ init_primitive();
62911
64184
  init_loading_indicator();
62912
64185
  init_action();
62913
64186
  init_metadata();
64187
+ init_nested_update();
62914
64188
 
62915
64189
  // src/index.ts
62916
64190
  var __filename2 = fileURLToPath9(import.meta.url);
@@ -63020,7 +64294,7 @@ if (cmd === "build") {
63020
64294
  const config = rawConfig;
63021
64295
  const plugins = config.plugins || [];
63022
64296
  const mdCfg = config.md;
63023
- const opts = { outDir, publicDir, plugins, seo, strictSeo: strict, codeSplit: !restArgs.includes("--skip-split"), target };
64297
+ const opts = { outDir, publicDir, plugins, seo, strictSeo: strict, strict, codeSplit: !restArgs.includes("--skip-split"), target };
63024
64298
  if (mdCfg) opts.md = mdCfg;
63025
64299
  if (config.routeDataCache !== void 0) opts.routeDataCache = config.routeDataCache;
63026
64300
  if (platform) opts.platform = platform;
@@ -63056,12 +64330,14 @@ if (cmd === "build") {
63056
64330
  const l = err.line;
63057
64331
  const c = err.column;
63058
64332
  const code = err.code;
64333
+ const frame = err.frame;
63059
64334
  let out = `vesk build: error \u2014 ${err.message}`;
64335
+ if (code) out = `vesk build: [${code}] ${err.message}`;
63060
64336
  if (f) out += `
63061
64337
  File: ${f}${l ? `:${l}${c ? `:${c}` : ""}` : ""}`;
63062
- if (code) out += `
64338
+ if (frame) out += `
63063
64339
 
63064
- ${code}`;
64340
+ ${frame}`;
63065
64341
  console.error(out);
63066
64342
  if (err.stack && !String(err.stack).includes(err.message)) console.error(err.stack);
63067
64343
  } else {