@vesk/vesk-cli 0.2.50-canary.10 → 0.2.50-canary.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +432 -54
- 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])];
|
|
@@ -236,6 +240,84 @@ var init_errors = __esm({
|
|
|
236
240
|
}
|
|
237
241
|
);
|
|
238
242
|
}
|
|
243
|
+
/**
|
|
244
|
+
* A browser-only global used in code the SERVER evaluates.
|
|
245
|
+
*
|
|
246
|
+
* On the server these are either absent (`window is not defined`) or, worse,
|
|
247
|
+
* silently present-but-wrong (`navigator` exists in modern Node, so
|
|
248
|
+
* `navigator.onLine` is `undefined` and a page renders as if it were offline).
|
|
249
|
+
* A raw `ReferenceError` at request time is the worst possible report: it
|
|
250
|
+
* names neither the component nor the fix. This points at the line.
|
|
251
|
+
*/
|
|
252
|
+
static ssrUnsafeGlobal(name, context = {}) {
|
|
253
|
+
return new _VeskError(
|
|
254
|
+
`\`${name}\` is browser-only, and this component body runs during SSR.`,
|
|
255
|
+
{
|
|
256
|
+
...context,
|
|
257
|
+
code: context.code || "V0501",
|
|
258
|
+
suggestions: [
|
|
259
|
+
`Wrap the part that needs the DOM in a {#client} block.`,
|
|
260
|
+
`Move the code into an event handler \u2014 handlers never run on the server.`,
|
|
261
|
+
`Do the setup in on_destroy(), which the compiler only emits on the client.`
|
|
262
|
+
],
|
|
263
|
+
nextSteps: [
|
|
264
|
+
`component ${context.inComponent ?? "this component"}: wrap the \`${name}\` access in {#client}...{/client}.`,
|
|
265
|
+
`Or guard it: if (typeof ${name} !== 'undefined') { ... }`
|
|
266
|
+
],
|
|
267
|
+
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."
|
|
268
|
+
}
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* The second name from `track()` called as a function.
|
|
273
|
+
*
|
|
274
|
+
* `const &[count, setCount] = track(0)` returns a CELL, not a setter function, so
|
|
275
|
+
* `setCount(1)` throws `setCount is not a function` from generated code with
|
|
276
|
+
* no line of user code in the message. The cell is the writer: `.set(v)`.
|
|
277
|
+
*/
|
|
278
|
+
static cellCalledAsFunction(name, context = {}) {
|
|
279
|
+
return new _VeskError(
|
|
280
|
+
`\`${name}\` is a cell, not a function \u2014 cells are written with \`.set()\`.`,
|
|
281
|
+
{
|
|
282
|
+
...context,
|
|
283
|
+
code: context.code || "V0502",
|
|
284
|
+
suggestions: [
|
|
285
|
+
`Use \`${name}.set(...)\` instead of \`${name}(...)\`.`,
|
|
286
|
+
`Or use the tracked spelling inside an event handler: set(${context.value ?? "value"}, ...)`
|
|
287
|
+
],
|
|
288
|
+
nextSteps: [
|
|
289
|
+
`const &[${context.value ?? "value"}, ${name}] = track(0) \u2192 \`${name}.set(v)\``,
|
|
290
|
+
"The value read in markup is the first name; the second is the cell object."
|
|
291
|
+
],
|
|
292
|
+
tip: `\`track()\` returns [value, cell]. \`${name}\` is the cell half.`
|
|
293
|
+
}
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* `set(value, …)` used outside a rewritten expression.
|
|
298
|
+
*
|
|
299
|
+
* The compiler rewrites `set(count, v)` to `countCell.set(v)` inside JSX and
|
|
300
|
+
* event handlers — but a bare statement in the component body is NOT
|
|
301
|
+
* rewritten, so the runtime `set` receives the value and throws
|
|
302
|
+
* "Cannot read properties of undefined". Pass the CELL, not the value.
|
|
303
|
+
*/
|
|
304
|
+
static setWithValueName(name, context = {}) {
|
|
305
|
+
return new _VeskError(
|
|
306
|
+
`\`set(${name}, \u2026)\` needs the CELL, and \`${name}\` is the value half of track().`,
|
|
307
|
+
{
|
|
308
|
+
...context,
|
|
309
|
+
code: context.code || "V0503",
|
|
310
|
+
suggestions: [
|
|
311
|
+
`Use \`set(${context.cell ?? "cell"}, \u2026)\` or \`${context.cell ?? "cell"}.set(\u2026)\`.`,
|
|
312
|
+
`Or move the set() into an event handler, where the compiler rewrites it for you.`
|
|
313
|
+
],
|
|
314
|
+
nextSteps: [
|
|
315
|
+
`const &[${name}, ${context.cell ?? "cell"}] = track(0) \u2192 \`${context.cell ?? "cell"}.set(v)\``
|
|
316
|
+
],
|
|
317
|
+
tip: "set(cell, value) is only rewritten inside JSX and handlers; in a body statement it reaches the runtime untouched."
|
|
318
|
+
}
|
|
319
|
+
);
|
|
320
|
+
}
|
|
239
321
|
static serverBlockInClient(compName, context = {}) {
|
|
240
322
|
return new _VeskError(
|
|
241
323
|
`{#server} block found in client island "${compName}". Client islands render on both server and client, so {#server} blocks have no effect.`,
|
|
@@ -21282,7 +21364,7 @@ function validateBlocks(compName, isClient, body, file, source) {
|
|
|
21282
21364
|
const { line, column } = offsetToLineCol2(source, pos);
|
|
21283
21365
|
opts.line = line;
|
|
21284
21366
|
opts.column = column;
|
|
21285
|
-
opts.
|
|
21367
|
+
opts.frame = codeFrame(source, line, column);
|
|
21286
21368
|
}
|
|
21287
21369
|
throw VeskError.serverBlockInClient(compName, opts);
|
|
21288
21370
|
}
|
|
@@ -21294,7 +21376,7 @@ function validateBlocks(compName, isClient, body, file, source) {
|
|
|
21294
21376
|
const { line, column } = offsetToLineCol2(source, pos);
|
|
21295
21377
|
opts.line = line;
|
|
21296
21378
|
opts.column = column;
|
|
21297
|
-
opts.
|
|
21379
|
+
opts.frame = codeFrame(source, line, column);
|
|
21298
21380
|
}
|
|
21299
21381
|
throw VeskError.clientBlockInServer(compName, opts);
|
|
21300
21382
|
}
|
|
@@ -25890,8 +25972,8 @@ function isPublicMarkdownPath(v) {
|
|
|
25890
25972
|
const c = s.charCodeAt(i);
|
|
25891
25973
|
if (c === 63 || c === 35 || c === 92) return false;
|
|
25892
25974
|
}
|
|
25893
|
-
const
|
|
25894
|
-
return stringEndsWith(
|
|
25975
|
+
const lower2 = s.toLowerCase();
|
|
25976
|
+
return stringEndsWith(lower2, ".md") || stringEndsWith(lower2, ".markdown");
|
|
25895
25977
|
}
|
|
25896
25978
|
function getMdPathCell(path) {
|
|
25897
25979
|
let cell = mdPathCells.get(path);
|
|
@@ -26563,9 +26645,9 @@ function toDomNode(value) {
|
|
|
26563
26645
|
}
|
|
26564
26646
|
if (typeof value !== "string") return value;
|
|
26565
26647
|
if (value === "") return document.createDocumentFragment();
|
|
26566
|
-
const
|
|
26567
|
-
|
|
26568
|
-
const { content } =
|
|
26648
|
+
const template2 = document.createElement("template");
|
|
26649
|
+
template2.innerHTML = value;
|
|
26650
|
+
const { content } = template2;
|
|
26569
26651
|
if (content.childNodes.length === 1) {
|
|
26570
26652
|
const only = content.firstChild;
|
|
26571
26653
|
content.removeChild(only);
|
|
@@ -26758,7 +26840,7 @@ function resolveTitle(meta, child) {
|
|
|
26758
26840
|
}
|
|
26759
26841
|
function mergeMetadata(...sources) {
|
|
26760
26842
|
const out = {};
|
|
26761
|
-
let
|
|
26843
|
+
let template2;
|
|
26762
26844
|
let sawTemplate = false;
|
|
26763
26845
|
for (const source of sources) {
|
|
26764
26846
|
if (!source) continue;
|
|
@@ -26771,7 +26853,7 @@ function mergeMetadata(...sources) {
|
|
|
26771
26853
|
if (key === "title") {
|
|
26772
26854
|
if (value && typeof value === "object" && value.template) {
|
|
26773
26855
|
sawTemplate = true;
|
|
26774
|
-
|
|
26856
|
+
template2 = value.template || template2;
|
|
26775
26857
|
}
|
|
26776
26858
|
out.title = value;
|
|
26777
26859
|
continue;
|
|
@@ -26783,9 +26865,9 @@ function mergeMetadata(...sources) {
|
|
|
26783
26865
|
const own = out.title;
|
|
26784
26866
|
if (typeof own === "string") out.title = { absolute: own };
|
|
26785
26867
|
else if (own && typeof own === "object" && own.template) {
|
|
26786
|
-
out.title = { default: own.default, template: own.template ||
|
|
26868
|
+
out.title = { default: own.default, template: own.template || template2 };
|
|
26787
26869
|
} else if (own && typeof own === "object") {
|
|
26788
|
-
out.title = { ...own, template };
|
|
26870
|
+
out.title = { ...own, template: template2 };
|
|
26789
26871
|
}
|
|
26790
26872
|
}
|
|
26791
26873
|
return out;
|
|
@@ -29289,8 +29371,8 @@ function looksLikeMarkdownPath(value) {
|
|
|
29289
29371
|
const v = value.trim();
|
|
29290
29372
|
if (v.length === 0 || v.length > 4096) return false;
|
|
29291
29373
|
if (v.includes("\n") || v.includes("\r")) return false;
|
|
29292
|
-
const
|
|
29293
|
-
return
|
|
29374
|
+
const lower2 = v.toLowerCase();
|
|
29375
|
+
return lower2.endsWith(MD_EXT_MARKER) || lower2.endsWith(".markdown");
|
|
29294
29376
|
}
|
|
29295
29377
|
function isRelativeSpecifier(v) {
|
|
29296
29378
|
return v.startsWith("./") || v.startsWith("../");
|
|
@@ -31863,7 +31945,202 @@ var init_server_head = __esm({
|
|
|
31863
31945
|
}
|
|
31864
31946
|
});
|
|
31865
31947
|
|
|
31948
|
+
// ../compiler/src/server-jsx-lowering.ts
|
|
31949
|
+
function containsJsx2(node, depth = 0) {
|
|
31950
|
+
if (!node || typeof node !== "object" || depth > 40) return false;
|
|
31951
|
+
if (Array.isArray(node)) {
|
|
31952
|
+
for (const item of node) if (containsJsx2(item, depth + 1)) return true;
|
|
31953
|
+
return false;
|
|
31954
|
+
}
|
|
31955
|
+
const type = node.type;
|
|
31956
|
+
if (type === "JSXElement" || type === "JSXFragment") return true;
|
|
31957
|
+
for (const key of Object.keys(node)) {
|
|
31958
|
+
const value = node[key];
|
|
31959
|
+
if (value && typeof value === "object" && containsJsx2(value, depth + 1)) return true;
|
|
31960
|
+
}
|
|
31961
|
+
return false;
|
|
31962
|
+
}
|
|
31963
|
+
function normalizeJsxText(value) {
|
|
31964
|
+
const lines = value.split(/\r\n|\n|\r/);
|
|
31965
|
+
let lastNonEmpty = -1;
|
|
31966
|
+
for (let i = 0; i < lines.length; i++) {
|
|
31967
|
+
if (/[^ \t]/.test(lines[i])) lastNonEmpty = i;
|
|
31968
|
+
}
|
|
31969
|
+
let out = "";
|
|
31970
|
+
for (let i = 0; i < lines.length; i++) {
|
|
31971
|
+
let line = lines[i].replace(/\t/g, " ");
|
|
31972
|
+
if (i !== 0) line = line.replace(/^ +/, "");
|
|
31973
|
+
if (i !== lines.length - 1) line = line.replace(/ +$/, "");
|
|
31974
|
+
if (line) {
|
|
31975
|
+
if (i !== lastNonEmpty) line += " ";
|
|
31976
|
+
out += line;
|
|
31977
|
+
}
|
|
31978
|
+
}
|
|
31979
|
+
return out;
|
|
31980
|
+
}
|
|
31981
|
+
function lower(node, ctx2) {
|
|
31982
|
+
if (Array.isArray(node)) return node.map((n2) => lower(n2, ctx2));
|
|
31983
|
+
if (!node || typeof node !== "object") return node;
|
|
31984
|
+
const n = node;
|
|
31985
|
+
if (n.type === "JSXElement") {
|
|
31986
|
+
const opening = n.openingElement;
|
|
31987
|
+
const name = jsxTagName(opening.name);
|
|
31988
|
+
const attrs = lowerAttributes(opening.attributes, ctx2);
|
|
31989
|
+
const children = lowerChildren(n.children, ctx2);
|
|
31990
|
+
const statics = [`<${name}`, ...attrs.statics.slice(1)];
|
|
31991
|
+
statics[statics.length - 1] += ">";
|
|
31992
|
+
const quasis = [...statics, `</${name}>`];
|
|
31993
|
+
const expressions = [...attrs.exprs, ...children];
|
|
31994
|
+
return template(quasis, expressions);
|
|
31995
|
+
}
|
|
31996
|
+
if (n.type === "JSXFragment") {
|
|
31997
|
+
return template(["", ""], lowerChildren(n.children, ctx2));
|
|
31998
|
+
}
|
|
31999
|
+
const out = {};
|
|
32000
|
+
for (const key of Object.keys(n)) {
|
|
32001
|
+
if (key === "type" || key === "start" || key === "end" || key === "loc" || key === "range") {
|
|
32002
|
+
out[key] = n[key];
|
|
32003
|
+
continue;
|
|
32004
|
+
}
|
|
32005
|
+
const value = n[key];
|
|
32006
|
+
out[key] = value && typeof value === "object" ? lower(value, ctx2) : value;
|
|
32007
|
+
}
|
|
32008
|
+
return out;
|
|
32009
|
+
}
|
|
32010
|
+
function jsxTagName(nameNode) {
|
|
32011
|
+
const n = nameNode;
|
|
32012
|
+
if (!n) return "div";
|
|
32013
|
+
if (n.type === "JSXIdentifier") return String(n.name);
|
|
32014
|
+
if (n.type === "JSXMemberExpression") {
|
|
32015
|
+
const object = jsxTagName(n.object);
|
|
32016
|
+
const property = n.property;
|
|
32017
|
+
return `${object}.${String(property?.name)}`;
|
|
32018
|
+
}
|
|
32019
|
+
if (n.type === "JSXNamespacedName") {
|
|
32020
|
+
const ns = n.namespace;
|
|
32021
|
+
const name = n.name;
|
|
32022
|
+
return `${String(ns?.name)}:${String(name?.name)}`;
|
|
32023
|
+
}
|
|
32024
|
+
return "div";
|
|
32025
|
+
}
|
|
32026
|
+
function lowerAttributes(attrs, ctx2) {
|
|
32027
|
+
const statics = [""];
|
|
32028
|
+
const exprs = [];
|
|
32029
|
+
const push = (text, expr) => {
|
|
32030
|
+
if (expr === void 0) {
|
|
32031
|
+
statics[statics.length - 1] += text;
|
|
32032
|
+
return;
|
|
32033
|
+
}
|
|
32034
|
+
statics[statics.length - 1] += text;
|
|
32035
|
+
statics.push("");
|
|
32036
|
+
exprs.push(expr);
|
|
32037
|
+
};
|
|
32038
|
+
for (const attr of attrs || []) {
|
|
32039
|
+
const a = attr;
|
|
32040
|
+
if (a.type === "JSXSpreadAttribute") {
|
|
32041
|
+
console.error("[vesk] a spread attribute in a JSX expression is not supported yet (dropped):", String(a.argument ?? "").slice(0, 60));
|
|
32042
|
+
continue;
|
|
32043
|
+
}
|
|
32044
|
+
const name = jsxAttrName(a.name);
|
|
32045
|
+
const value = a.value;
|
|
32046
|
+
if (value === null || value === void 0) {
|
|
32047
|
+
push(` ${name}`);
|
|
32048
|
+
continue;
|
|
32049
|
+
}
|
|
32050
|
+
if (value.type === "StringLiteral") {
|
|
32051
|
+
push(` ${name}="${escapeAttrText(String(value.value))}"`);
|
|
32052
|
+
continue;
|
|
32053
|
+
}
|
|
32054
|
+
if (value.type === "JSXExpressionContainer") {
|
|
32055
|
+
const inner = value.expression;
|
|
32056
|
+
if (!inner || inner.type === "JSXEmptyExpression") {
|
|
32057
|
+
push(` ${name}="true"`);
|
|
32058
|
+
continue;
|
|
32059
|
+
}
|
|
32060
|
+
push(` ${name}="`, callNode(ATTR, [literal3(name), coerceString(lower(inner, ctx2))]));
|
|
32061
|
+
push('"');
|
|
32062
|
+
continue;
|
|
32063
|
+
}
|
|
32064
|
+
push(` ${name}="`, callNode(ATTR, [literal3(name), coerceString(lower(value, ctx2))]));
|
|
32065
|
+
push('"');
|
|
32066
|
+
}
|
|
32067
|
+
return { statics, exprs };
|
|
32068
|
+
}
|
|
32069
|
+
function jsxAttrName(nameNode) {
|
|
32070
|
+
const n = nameNode;
|
|
32071
|
+
if (!n) return "data";
|
|
32072
|
+
if (n.type === "JSXIdentifier") return String(n.name);
|
|
32073
|
+
return jsxTagName(n);
|
|
32074
|
+
}
|
|
32075
|
+
function lowerChildren(children, ctx2) {
|
|
32076
|
+
const out = [];
|
|
32077
|
+
for (const child of children || []) {
|
|
32078
|
+
const c = child;
|
|
32079
|
+
if (c.type === "JSXText") {
|
|
32080
|
+
const text = normalizeJsxText(String(c.value ?? ""));
|
|
32081
|
+
if (text) out.push(literal3(text));
|
|
32082
|
+
continue;
|
|
32083
|
+
}
|
|
32084
|
+
if (c.type === "JSXExpressionContainer") {
|
|
32085
|
+
const inner = c.expression;
|
|
32086
|
+
if (!inner || inner.type === "JSXEmptyExpression") continue;
|
|
32087
|
+
const lowered2 = lower(inner, ctx2);
|
|
32088
|
+
out.push(coerceString(lowered2));
|
|
32089
|
+
continue;
|
|
32090
|
+
}
|
|
32091
|
+
const lowered = lower(c, ctx2);
|
|
32092
|
+
out.push(coerceString(lowered));
|
|
32093
|
+
}
|
|
32094
|
+
return out;
|
|
32095
|
+
}
|
|
32096
|
+
function coerceString(node) {
|
|
32097
|
+
if (!node || typeof node !== "object") return callNode(ESCAPE, [literal3(String(node))]);
|
|
32098
|
+
const n = node;
|
|
32099
|
+
if (n.type === "TemplateLiteral") return n;
|
|
32100
|
+
if (n.type === "Literal" || n.type === "StringLiteral") return callNode(ESCAPE, [node]);
|
|
32101
|
+
return callNode(ESCAPE, [callNode("String", [node])]);
|
|
32102
|
+
}
|
|
32103
|
+
function template(statics, expressions) {
|
|
32104
|
+
const quasis = statics.map((raw2, i) => ({
|
|
32105
|
+
type: "TemplateElement",
|
|
32106
|
+
value: { raw: raw2 },
|
|
32107
|
+
tail: i === statics.length - 1
|
|
32108
|
+
}));
|
|
32109
|
+
return { type: "TemplateLiteral", quasis, expressions };
|
|
32110
|
+
}
|
|
32111
|
+
function literal3(value) {
|
|
32112
|
+
return { type: "Literal", value };
|
|
32113
|
+
}
|
|
32114
|
+
function callNode(callee, args2) {
|
|
32115
|
+
return {
|
|
32116
|
+
type: "CallExpression",
|
|
32117
|
+
callee: { type: "Identifier", name: callee },
|
|
32118
|
+
arguments: args2,
|
|
32119
|
+
optional: false
|
|
32120
|
+
};
|
|
32121
|
+
}
|
|
32122
|
+
function escapeAttrText(value) {
|
|
32123
|
+
return value.split("&").join("&").split("<").join("<").split(">").join(">").split('"').join(""");
|
|
32124
|
+
}
|
|
32125
|
+
function lowerJsxInExpression(ast) {
|
|
32126
|
+
if (!containsJsx2(ast)) return ast;
|
|
32127
|
+
return lower(ast, { track: false });
|
|
32128
|
+
}
|
|
32129
|
+
var ESCAPE, ATTR;
|
|
32130
|
+
var init_server_jsx_lowering = __esm({
|
|
32131
|
+
"../compiler/src/server-jsx-lowering.ts"() {
|
|
32132
|
+
"use strict";
|
|
32133
|
+
ESCAPE = "__escape";
|
|
32134
|
+
ATTR = "__attr";
|
|
32135
|
+
}
|
|
32136
|
+
});
|
|
32137
|
+
|
|
31866
32138
|
// ../compiler/src/server-jsgen.ts
|
|
32139
|
+
import { print as print6 } from "esrap";
|
|
32140
|
+
import tsPrinter from "esrap/languages/ts";
|
|
32141
|
+
function printLoweredTs(ast) {
|
|
32142
|
+
return print6(ast, tsPrinter()).code;
|
|
32143
|
+
}
|
|
31867
32144
|
function sanitizeMarkerName(name) {
|
|
31868
32145
|
return String(name).split("--").join("-").split("<").join("").split(">").join("");
|
|
31869
32146
|
}
|
|
@@ -31914,7 +32191,19 @@ function irNodeToJS(node, importedNames, isAsync = false, tracked2) {
|
|
|
31914
32191
|
`})();`
|
|
31915
32192
|
].join("\n");
|
|
31916
32193
|
}
|
|
31917
|
-
if (node instanceof RuntimeStatement)
|
|
32194
|
+
if (node instanceof RuntimeStatement) {
|
|
32195
|
+
const stmt = node;
|
|
32196
|
+
const lowered = stmt.ast ? lowerJsxInExpression(stmt.ast) : null;
|
|
32197
|
+
if (lowered && lowered !== stmt.ast && (tracked2?.size ?? 0) === 0) {
|
|
32198
|
+
return semicolonizeStatement(printLoweredTs(lowered));
|
|
32199
|
+
}
|
|
32200
|
+
if (lowered && lowered !== stmt.ast) {
|
|
32201
|
+
return semicolonizeStatement(
|
|
32202
|
+
transformTracked({ ...node, ast: lowered }, tracked2 || /* @__PURE__ */ new Map())
|
|
32203
|
+
);
|
|
32204
|
+
}
|
|
32205
|
+
return semicolonizeStatement(transformTracked(node, tracked2 || /* @__PURE__ */ new Map()));
|
|
32206
|
+
}
|
|
31918
32207
|
if (node instanceof SlotNode) {
|
|
31919
32208
|
if (__vskMarkerless) return `__out.push(props.children || '');`;
|
|
31920
32209
|
const sid = `s${nextVskId()}`;
|
|
@@ -31931,7 +32220,12 @@ function isEvent(target) {
|
|
|
31931
32220
|
return !!target && target.startsWith("on") && target.length > 2;
|
|
31932
32221
|
}
|
|
31933
32222
|
function exprJSX(node, tracked2) {
|
|
31934
|
-
|
|
32223
|
+
const lowered = node.ast ? lowerJsxInExpression(node.ast) : null;
|
|
32224
|
+
const didLower = lowered !== node.ast;
|
|
32225
|
+
if (didLower && (tracked2?.size ?? 0) === 0) {
|
|
32226
|
+
return exprJS(printLoweredTs(lowered));
|
|
32227
|
+
}
|
|
32228
|
+
return exprJS(transformTracked({ ...node, ast: lowered }, tracked2 || /* @__PURE__ */ new Map()));
|
|
31935
32229
|
}
|
|
31936
32230
|
function staticNodeToJS(node, isAsync = false, tracked2) {
|
|
31937
32231
|
const lines = [];
|
|
@@ -32079,13 +32373,13 @@ function mapRegionToJS(node, isAsync = false, tracked2) {
|
|
|
32079
32373
|
}
|
|
32080
32374
|
function keyedItemTemplate(node) {
|
|
32081
32375
|
if (!node.keyExpr) return node.bodyTemplate;
|
|
32082
|
-
const
|
|
32083
|
-
const idx =
|
|
32084
|
-
if (idx === -1) return
|
|
32085
|
-
const root3 =
|
|
32376
|
+
const template2 = node.bodyTemplate;
|
|
32377
|
+
const idx = template2.findIndex((n) => n instanceof StaticNode);
|
|
32378
|
+
if (idx === -1) return template2;
|
|
32379
|
+
const root3 = template2[idx];
|
|
32086
32380
|
const copy = new StaticNode(root3.tag, root3.attributes, [...root3.children, new DynamicBinding(node.keyExpr, "attribute", "data-vsk-key")], root3.keyExpr);
|
|
32087
32381
|
copy.selfClosing = root3.selfClosing;
|
|
32088
|
-
const out =
|
|
32382
|
+
const out = template2.slice();
|
|
32089
32383
|
out[idx] = copy;
|
|
32090
32384
|
return out;
|
|
32091
32385
|
}
|
|
@@ -32197,18 +32491,24 @@ function componentCallToJS(node, importedNames, isAsync = false, tracked2) {
|
|
|
32197
32491
|
}
|
|
32198
32492
|
}
|
|
32199
32493
|
if (regularChildren.length > 0) {
|
|
32200
|
-
const
|
|
32201
|
-
|
|
32202
|
-
|
|
32203
|
-
|
|
32204
|
-
}
|
|
32205
|
-
|
|
32206
|
-
const
|
|
32207
|
-
|
|
32208
|
-
|
|
32209
|
-
|
|
32210
|
-
|
|
32211
|
-
|
|
32494
|
+
const fnType = regularChildren.length === 1 && regularChildren[0] instanceof DynamicBinding && regularChildren[0].kind === "text" ? regularChildren[0].expression.ast?.type : null;
|
|
32495
|
+
const isFnChild = fnType === "ArrowFunctionExpression" || fnType === "FunctionExpression" || fnType === "Identifier" || fnType === "MemberExpression";
|
|
32496
|
+
if (isFnChild) {
|
|
32497
|
+
propsEntries.push(`children: ${exprJSX(regularChildren[0].expression, tracked2)}`);
|
|
32498
|
+
} else {
|
|
32499
|
+
const childLines = [];
|
|
32500
|
+
for (const child of regularChildren) {
|
|
32501
|
+
const code = irNodeToJS(child, importedNames, isAsync, tracked2);
|
|
32502
|
+
if (code) childLines.push(code);
|
|
32503
|
+
}
|
|
32504
|
+
if (childLines.length > 0) {
|
|
32505
|
+
const childrenVar = `__ch${nextVskId()}`;
|
|
32506
|
+
propsEntries.push(`children: ${childrenVar}`);
|
|
32507
|
+
lines.push(`const ${childrenVar} = ${isAsync ? "await (async " : "("}() => {`);
|
|
32508
|
+
lines.push(`const __out = [];`);
|
|
32509
|
+
lines.push(indent(childLines.join("\n")));
|
|
32510
|
+
lines.push(`return __out.join(''); })();`);
|
|
32511
|
+
}
|
|
32212
32512
|
}
|
|
32213
32513
|
}
|
|
32214
32514
|
const propsObj = `{ ${propsEntries.join(", ")} }`;
|
|
@@ -32225,9 +32525,9 @@ function componentCallToJS(node, importedNames, isAsync = false, tracked2) {
|
|
|
32225
32525
|
}
|
|
32226
32526
|
const callExpr3 = `${awaitKw}${calleeVar}(${propsObj}, __registry, (${calleeVar}.__veskScope || __vesk))`;
|
|
32227
32527
|
if (__vskHydrate && !__vskMarkerless) {
|
|
32228
|
-
lines.push(`__out.push(${JSON.stringify(componentMarker(compName))} + (${callExpr3}
|
|
32528
|
+
lines.push(`__out.push(${JSON.stringify(componentMarker(compName))} + __flat(${callExpr3}));`);
|
|
32229
32529
|
} else {
|
|
32230
|
-
lines.push(`__out.push(${callExpr3}
|
|
32530
|
+
lines.push(`__out.push(__flat(${callExpr3}));`);
|
|
32231
32531
|
}
|
|
32232
32532
|
return lines.join("\n");
|
|
32233
32533
|
}
|
|
@@ -32245,6 +32545,7 @@ function generateFunctionBody(comp, importedNames) {
|
|
|
32245
32545
|
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); };`);
|
|
32246
32546
|
lines.push(`const __attr = (n, v) => (v == null || v === false) ? '' : ' ' + n + '="' + __escape(n === 'style' ? __styleText(v) : String(v)) + '"';`);
|
|
32247
32547
|
lines.push(`const raw = (s) => s == null ? '' : String(s);`);
|
|
32548
|
+
lines.push(`const __flat = (v) => Array.isArray(v) ? v.join('') : (v == null ? '' : String(v));`);
|
|
32248
32549
|
lines.push(`const __tk = globalThis.__vsk_ssr_token || '';`);
|
|
32249
32550
|
if (asyncMode) {
|
|
32250
32551
|
lines.push(`const __pk = __tk ? '__vsk_ssr_promises_' + __tk : '__vsk_ssr_promises';`);
|
|
@@ -32390,6 +32691,7 @@ var init_server_jsgen = __esm({
|
|
|
32390
32691
|
init_scan();
|
|
32391
32692
|
init_server_utils();
|
|
32392
32693
|
init_module_imports();
|
|
32694
|
+
init_server_jsx_lowering();
|
|
32393
32695
|
init_vsk_imports();
|
|
32394
32696
|
__currentCompName = "";
|
|
32395
32697
|
}
|
|
@@ -33154,8 +33456,8 @@ function installMdReadHook(publicDirs) {
|
|
|
33154
33456
|
while (rel.length > 0 && rel.charCodeAt(0) === 47) rel = rel.slice(1);
|
|
33155
33457
|
const abs = resolveWithin(dir, rel);
|
|
33156
33458
|
if (!abs) continue;
|
|
33157
|
-
const
|
|
33158
|
-
if (!
|
|
33459
|
+
const lower2 = abs.toLowerCase();
|
|
33460
|
+
if (!lower2.endsWith(".md") && !lower2.endsWith(".markdown")) continue;
|
|
33159
33461
|
if (existsSync12(abs) && statSync4(abs).isFile()) return readFileSync12(abs, "utf8");
|
|
33160
33462
|
} catch {
|
|
33161
33463
|
}
|
|
@@ -37582,8 +37884,8 @@ function isPublicMarkdownPath2(v) {
|
|
|
37582
37884
|
if (c === 63 || c === 35 || c === 92)
|
|
37583
37885
|
return false;
|
|
37584
37886
|
}
|
|
37585
|
-
const
|
|
37586
|
-
return stringEndsWith2(
|
|
37887
|
+
const lower2 = s.toLowerCase();
|
|
37888
|
+
return stringEndsWith2(lower2, ".md") || stringEndsWith2(lower2, ".markdown");
|
|
37587
37889
|
}
|
|
37588
37890
|
function getMdPathCell2(path) {
|
|
37589
37891
|
let cell = mdPathCells2.get(path);
|
|
@@ -38323,7 +38625,10 @@ var init_errors2 = __esm({
|
|
|
38323
38625
|
suggestions;
|
|
38324
38626
|
nextSteps;
|
|
38325
38627
|
tip;
|
|
38628
|
+
/** The V-diagnostic code, e.g. `V0501`. */
|
|
38326
38629
|
code;
|
|
38630
|
+
/** The rendered code frame. Used to be written into `code`, which silently replaced the V-code. */
|
|
38631
|
+
frame;
|
|
38327
38632
|
constructor(message, opts = {}) {
|
|
38328
38633
|
super(message);
|
|
38329
38634
|
this.name = "VeskError";
|
|
@@ -38333,8 +38638,10 @@ var init_errors2 = __esm({
|
|
|
38333
38638
|
this.suggestions = opts.suggestions || [];
|
|
38334
38639
|
this.nextSteps = opts.nextSteps || [];
|
|
38335
38640
|
this.tip = opts.tip || "";
|
|
38336
|
-
if (opts.code !== void 0)
|
|
38641
|
+
if (opts.code !== void 0 && !opts.code.includes("\n"))
|
|
38337
38642
|
this.code = opts.code;
|
|
38643
|
+
if (opts.frame !== void 0)
|
|
38644
|
+
this.frame = opts.frame;
|
|
38338
38645
|
}
|
|
38339
38646
|
static notFound(name, candidates = [], context = {}) {
|
|
38340
38647
|
const allCandidates = [.../* @__PURE__ */ new Set([...candidates, ...VESK_BUILTINS2])];
|
|
@@ -38407,6 +38714,75 @@ var init_errors2 = __esm({
|
|
|
38407
38714
|
tip: "Use plain objects for data and factory functions for constructors inside .vsk files."
|
|
38408
38715
|
});
|
|
38409
38716
|
}
|
|
38717
|
+
/**
|
|
38718
|
+
* A browser-only global used in code the SERVER evaluates.
|
|
38719
|
+
*
|
|
38720
|
+
* On the server these are either absent (`window is not defined`) or, worse,
|
|
38721
|
+
* silently present-but-wrong (`navigator` exists in modern Node, so
|
|
38722
|
+
* `navigator.onLine` is `undefined` and a page renders as if it were offline).
|
|
38723
|
+
* A raw `ReferenceError` at request time is the worst possible report: it
|
|
38724
|
+
* names neither the component nor the fix. This points at the line.
|
|
38725
|
+
*/
|
|
38726
|
+
static ssrUnsafeGlobal(name, context = {}) {
|
|
38727
|
+
return new _VeskError(`\`${name}\` is browser-only, and this component body runs during SSR.`, {
|
|
38728
|
+
...context,
|
|
38729
|
+
code: context.code || "V0501",
|
|
38730
|
+
suggestions: [
|
|
38731
|
+
`Wrap the part that needs the DOM in a {#client} block.`,
|
|
38732
|
+
`Move the code into an event handler \u2014 handlers never run on the server.`,
|
|
38733
|
+
`Do the setup in on_destroy(), which the compiler only emits on the client.`
|
|
38734
|
+
],
|
|
38735
|
+
nextSteps: [
|
|
38736
|
+
`component ${context.inComponent ?? "this component"}: wrap the \`${name}\` access in {#client}...{/client}.`,
|
|
38737
|
+
`Or guard it: if (typeof ${name} !== 'undefined') { ... }`
|
|
38738
|
+
],
|
|
38739
|
+
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."
|
|
38740
|
+
});
|
|
38741
|
+
}
|
|
38742
|
+
/**
|
|
38743
|
+
* The second name from `track()` called as a function.
|
|
38744
|
+
*
|
|
38745
|
+
* `const &[count, setCount] = track(0)` returns a CELL, not a setter function, so
|
|
38746
|
+
* `setCount(1)` throws `setCount is not a function` from generated code with
|
|
38747
|
+
* no line of user code in the message. The cell is the writer: `.set(v)`.
|
|
38748
|
+
*/
|
|
38749
|
+
static cellCalledAsFunction(name, context = {}) {
|
|
38750
|
+
return new _VeskError(`\`${name}\` is a cell, not a function \u2014 cells are written with \`.set()\`.`, {
|
|
38751
|
+
...context,
|
|
38752
|
+
code: context.code || "V0502",
|
|
38753
|
+
suggestions: [
|
|
38754
|
+
`Use \`${name}.set(...)\` instead of \`${name}(...)\`.`,
|
|
38755
|
+
`Or use the tracked spelling inside an event handler: set(${context.value ?? "value"}, ...)`
|
|
38756
|
+
],
|
|
38757
|
+
nextSteps: [
|
|
38758
|
+
`const &[${context.value ?? "value"}, ${name}] = track(0) \u2192 \`${name}.set(v)\``,
|
|
38759
|
+
"The value read in markup is the first name; the second is the cell object."
|
|
38760
|
+
],
|
|
38761
|
+
tip: `\`track()\` returns [value, cell]. \`${name}\` is the cell half.`
|
|
38762
|
+
});
|
|
38763
|
+
}
|
|
38764
|
+
/**
|
|
38765
|
+
* `set(value, …)` used outside a rewritten expression.
|
|
38766
|
+
*
|
|
38767
|
+
* The compiler rewrites `set(count, v)` to `countCell.set(v)` inside JSX and
|
|
38768
|
+
* event handlers — but a bare statement in the component body is NOT
|
|
38769
|
+
* rewritten, so the runtime `set` receives the value and throws
|
|
38770
|
+
* "Cannot read properties of undefined". Pass the CELL, not the value.
|
|
38771
|
+
*/
|
|
38772
|
+
static setWithValueName(name, context = {}) {
|
|
38773
|
+
return new _VeskError(`\`set(${name}, \u2026)\` needs the CELL, and \`${name}\` is the value half of track().`, {
|
|
38774
|
+
...context,
|
|
38775
|
+
code: context.code || "V0503",
|
|
38776
|
+
suggestions: [
|
|
38777
|
+
`Use \`set(${context.cell ?? "cell"}, \u2026)\` or \`${context.cell ?? "cell"}.set(\u2026)\`.`,
|
|
38778
|
+
`Or move the set() into an event handler, where the compiler rewrites it for you.`
|
|
38779
|
+
],
|
|
38780
|
+
nextSteps: [
|
|
38781
|
+
`const &[${name}, ${context.cell ?? "cell"}] = track(0) \u2192 \`${context.cell ?? "cell"}.set(v)\``
|
|
38782
|
+
],
|
|
38783
|
+
tip: "set(cell, value) is only rewritten inside JSX and handlers; in a body statement it reaches the runtime untouched."
|
|
38784
|
+
});
|
|
38785
|
+
}
|
|
38410
38786
|
static serverBlockInClient(compName, context = {}) {
|
|
38411
38787
|
return new _VeskError(`{#server} block found in client island "${compName}". Client islands render on both server and client, so {#server} blocks have no effect.`, {
|
|
38412
38788
|
...context,
|
|
@@ -50155,7 +50531,7 @@ import { WebSocketServer as WebSocketServer2 } from "ws";
|
|
|
50155
50531
|
// ../compiler/dist/strip-ts.js
|
|
50156
50532
|
init_parser();
|
|
50157
50533
|
import { walk as walk6 } from "zimmerframe";
|
|
50158
|
-
import { print as
|
|
50534
|
+
import { print as print7 } from "esrap";
|
|
50159
50535
|
import ts6 from "esrap/languages/ts";
|
|
50160
50536
|
var TS_NODE_TYPES2 = /* @__PURE__ */ new Set([
|
|
50161
50537
|
"TSAsExpression",
|
|
@@ -50352,7 +50728,7 @@ function stripCodeTypes2(code) {
|
|
|
50352
50728
|
stripped.body = stripped.body.filter((n) => !isTypeOnlyStatement2(n));
|
|
50353
50729
|
}
|
|
50354
50730
|
try {
|
|
50355
|
-
return
|
|
50731
|
+
return print7(stripped, ts6()).code;
|
|
50356
50732
|
} catch {
|
|
50357
50733
|
return code;
|
|
50358
50734
|
}
|
|
@@ -50491,7 +50867,7 @@ init_vsk_imports();
|
|
|
50491
50867
|
init_md_inline();
|
|
50492
50868
|
init_strip_ts();
|
|
50493
50869
|
import { walk as walk7 } from "zimmerframe";
|
|
50494
|
-
import { print as
|
|
50870
|
+
import { print as print8 } from "esrap";
|
|
50495
50871
|
import ts7 from "esrap/languages/ts";
|
|
50496
50872
|
import tsx2 from "esrap/languages/tsx";
|
|
50497
50873
|
function callExpr2(callee, args2 = []) {
|
|
@@ -50558,12 +50934,12 @@ function semicolonizeStatement2(code) {
|
|
|
50558
50934
|
return code;
|
|
50559
50935
|
return code + ";";
|
|
50560
50936
|
}
|
|
50561
|
-
function
|
|
50937
|
+
function containsJsx3(node, depth = 0) {
|
|
50562
50938
|
if (!node || typeof node !== "object" || depth > 40)
|
|
50563
50939
|
return false;
|
|
50564
50940
|
if (Array.isArray(node)) {
|
|
50565
50941
|
for (const item of node) {
|
|
50566
|
-
if (
|
|
50942
|
+
if (containsJsx3(item, depth + 1))
|
|
50567
50943
|
return true;
|
|
50568
50944
|
}
|
|
50569
50945
|
return false;
|
|
@@ -50572,13 +50948,13 @@ function containsJsx2(node, depth = 0) {
|
|
|
50572
50948
|
return true;
|
|
50573
50949
|
for (const key of Object.keys(node)) {
|
|
50574
50950
|
const v = node[key];
|
|
50575
|
-
if (v && typeof v === "object" &&
|
|
50951
|
+
if (v && typeof v === "object" && containsJsx3(v, depth + 1))
|
|
50576
50952
|
return true;
|
|
50577
50953
|
}
|
|
50578
50954
|
return false;
|
|
50579
50955
|
}
|
|
50580
50956
|
function printAst2(ast) {
|
|
50581
|
-
return
|
|
50957
|
+
return print8(ast, containsJsx3(ast) ? tsx2() : ts7()).code;
|
|
50582
50958
|
}
|
|
50583
50959
|
function effectBlockToHandlerExpr2(eff) {
|
|
50584
50960
|
try {
|
|
@@ -50699,7 +51075,7 @@ function transformTracked2(irNode, tracked2) {
|
|
|
50699
51075
|
return context.next();
|
|
50700
51076
|
}
|
|
50701
51077
|
});
|
|
50702
|
-
return
|
|
51078
|
+
return print8(transformed, containsJsx3(transformed) ? tsx2() : ts7()).code;
|
|
50703
51079
|
}
|
|
50704
51080
|
function collectTrackedNames2(body) {
|
|
50705
51081
|
const names = /* @__PURE__ */ new Map();
|
|
@@ -53834,8 +54210,8 @@ function looksLikeMarkdownPath2(value) {
|
|
|
53834
54210
|
return false;
|
|
53835
54211
|
if (v.includes("\n") || v.includes("\r"))
|
|
53836
54212
|
return false;
|
|
53837
|
-
const
|
|
53838
|
-
return
|
|
54213
|
+
const lower2 = v.toLowerCase();
|
|
54214
|
+
return lower2.endsWith(MD_EXT_MARKER2) || lower2.endsWith(".markdown");
|
|
53839
54215
|
}
|
|
53840
54216
|
function isRelativeSpecifier2(v) {
|
|
53841
54217
|
return v.startsWith("./") || v.startsWith("../");
|
|
@@ -55041,8 +55417,8 @@ function installMdReadHook2(publicDirs) {
|
|
|
55041
55417
|
const abs = resolveWithin2(dir, rel);
|
|
55042
55418
|
if (!abs)
|
|
55043
55419
|
continue;
|
|
55044
|
-
const
|
|
55045
|
-
if (!
|
|
55420
|
+
const lower2 = abs.toLowerCase();
|
|
55421
|
+
if (!lower2.endsWith(".md") && !lower2.endsWith(".markdown"))
|
|
55046
55422
|
continue;
|
|
55047
55423
|
if (existsSync29(abs) && statSync15(abs).isFile())
|
|
55048
55424
|
return readFileSync25(abs, "utf8");
|
|
@@ -63160,12 +63536,14 @@ if (cmd === "build") {
|
|
|
63160
63536
|
const l = err.line;
|
|
63161
63537
|
const c = err.column;
|
|
63162
63538
|
const code = err.code;
|
|
63539
|
+
const frame = err.frame;
|
|
63163
63540
|
let out = `vesk build: error \u2014 ${err.message}`;
|
|
63541
|
+
if (code) out = `vesk build: [${code}] ${err.message}`;
|
|
63164
63542
|
if (f) out += `
|
|
63165
63543
|
File: ${f}${l ? `:${l}${c ? `:${c}` : ""}` : ""}`;
|
|
63166
|
-
if (
|
|
63544
|
+
if (frame) out += `
|
|
63167
63545
|
|
|
63168
|
-
${
|
|
63546
|
+
${frame}`;
|
|
63169
63547
|
console.error(out);
|
|
63170
63548
|
if (err.stack && !String(err.stack).includes(err.message)) console.error(err.stack);
|
|
63171
63549
|
} else {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vesk/vesk-cli",
|
|
3
|
-
"version": "0.2.50-canary.
|
|
3
|
+
"version": "0.2.50-canary.12",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Vesk — compiler-first framework for the post-VDOM web. vesk dev, vesk build.",
|
|
6
6
|
"bin": {
|
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
},
|
|
9
9
|
"main": "./dist/cli.js",
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"@vesk/adapter": "^0.2.50-canary.
|
|
12
|
-
"@vesk/compiler": "^0.2.50-canary.
|
|
13
|
-
"@vesk/plugin-tailwind": "^0.2.50-canary.
|
|
14
|
-
"@vesk/runtime": "^0.2.50-canary.
|
|
11
|
+
"@vesk/adapter": "^0.2.50-canary.12",
|
|
12
|
+
"@vesk/compiler": "^0.2.50-canary.12",
|
|
13
|
+
"@vesk/plugin-tailwind": "^0.2.50-canary.12",
|
|
14
|
+
"@vesk/runtime": "^0.2.50-canary.12",
|
|
15
15
|
"esrap": "^2.3.0",
|
|
16
16
|
"typescript": "^5.8.0",
|
|
17
17
|
"ws": "^8.18.0",
|