@jxsuite/compiler 0.23.1 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/compiler.js +155 -155
- package/package.json +18 -16
- package/src/{cli.js → cli.ts} +2 -2
- package/src/{compile-cli.js → compile-cli.ts} +1 -1
- package/src/{compiler.js → compiler.ts} +10 -8
- package/src/{shared.js → shared.ts} +161 -123
- package/src/site/{content-loader.js → content-loader.ts} +59 -52
- package/src/site/{context-injection.js → context-injection.ts} +18 -12
- package/src/site/{head-merger.js → head-merger.ts} +17 -11
- package/src/site/{image-cache.js → image-cache.ts} +22 -22
- package/src/site/{image-optimizer.js → image-optimizer.ts} +35 -44
- package/src/site/{image-transform.js → image-transform.ts} +52 -22
- package/src/site/{layout-resolver.js → layout-resolver.ts} +31 -26
- package/src/site/{pages-discovery.js → pages-discovery.ts} +31 -30
- package/src/site/{prototype-resolver.js → prototype-resolver.ts} +16 -5
- package/src/site/{site-build.js → site-build.ts} +134 -130
- package/src/site/{site-loader.js → site-loader.ts} +2 -2
- package/src/targets/{compile-class.js → compile-class.ts} +20 -19
- package/src/targets/{compile-client.js → compile-client.ts} +84 -105
- package/src/targets/{compile-element.js → compile-element.ts} +82 -88
- package/src/targets/{compile-markdown.js → compile-markdown.ts} +95 -81
- package/src/targets/{compile-server.js → compile-server.ts} +23 -6
- package/src/targets/{compile-static.js → compile-static.ts} +35 -18
- package/src/types.ts +16 -0
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
* Schema 2020-12 class definition.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import type { JxMutableNode } from "@jxsuite/schema/types";
|
|
9
|
+
|
|
8
10
|
/**
|
|
9
11
|
* Compile a .class.json schema to a JavaScript ES module string.
|
|
10
12
|
*
|
|
@@ -12,18 +14,17 @@
|
|
|
12
14
|
* @param {Record<string, unknown>} [_opts]
|
|
13
15
|
* @returns {string} JavaScript module source code
|
|
14
16
|
*/
|
|
15
|
-
export function compileClassJson(classDef, _opts = {}) {
|
|
17
|
+
export function compileClassJson(classDef: JxMutableNode, _opts: Record<string, unknown> = {}) {
|
|
16
18
|
const className = classDef.title;
|
|
17
19
|
if (!className) throw new Error("compileClassJson: missing title (class name)");
|
|
18
20
|
|
|
19
21
|
const baseClass = resolveBaseClass(classDef.extends);
|
|
20
|
-
const defs =
|
|
21
|
-
const fields =
|
|
22
|
-
const ctor =
|
|
23
|
-
const methods =
|
|
22
|
+
const defs = classDef.$defs as Record<string, unknown> | undefined;
|
|
23
|
+
const fields = (defs?.fields ?? {}) as Record<string, JxMutableNode>;
|
|
24
|
+
const ctor = defs?.constructor as JxMutableNode | undefined;
|
|
25
|
+
const methods = (defs?.methods ?? {}) as Record<string, JxMutableNode>;
|
|
24
26
|
|
|
25
|
-
|
|
26
|
-
const lines = [];
|
|
27
|
+
const lines: string[] = [];
|
|
27
28
|
lines.push("// Generated by @jxsuite/compiler from .class.json — do not edit manually");
|
|
28
29
|
if (classDef.$id) lines.push(`// Source: ${classDef.$id}`);
|
|
29
30
|
lines.push("");
|
|
@@ -34,7 +35,7 @@ export function compileClassJson(classDef, _opts = {}) {
|
|
|
34
35
|
|
|
35
36
|
// Static fields
|
|
36
37
|
for (const [key, field] of Object.entries(fields)) {
|
|
37
|
-
const f =
|
|
38
|
+
const f = field as JxMutableNode;
|
|
38
39
|
if (f.scope !== "static") continue;
|
|
39
40
|
const name = f.identifier ?? key;
|
|
40
41
|
const prefix = f.access === "private" ? "#" : "";
|
|
@@ -49,7 +50,7 @@ export function compileClassJson(classDef, _opts = {}) {
|
|
|
49
50
|
|
|
50
51
|
// Instance field declarations (private)
|
|
51
52
|
for (const [key, field] of Object.entries(fields)) {
|
|
52
|
-
const f =
|
|
53
|
+
const f = field as JxMutableNode;
|
|
53
54
|
if (f.scope === "static") continue;
|
|
54
55
|
if (f.access !== "private") continue;
|
|
55
56
|
const name = f.identifier ?? key;
|
|
@@ -67,7 +68,7 @@ export function compileClassJson(classDef, _opts = {}) {
|
|
|
67
68
|
|
|
68
69
|
// Initialize instance fields from config or defaults
|
|
69
70
|
for (const [key, field] of Object.entries(fields)) {
|
|
70
|
-
const f =
|
|
71
|
+
const f = field as JxMutableNode;
|
|
71
72
|
if (f.scope === "static") continue;
|
|
72
73
|
const name = f.identifier ?? key;
|
|
73
74
|
const prefix = f.access === "private" ? "#" : "";
|
|
@@ -93,7 +94,7 @@ export function compileClassJson(classDef, _opts = {}) {
|
|
|
93
94
|
|
|
94
95
|
// Methods
|
|
95
96
|
for (const [key, method] of Object.entries(methods)) {
|
|
96
|
-
const m =
|
|
97
|
+
const m = method as JxMutableNode;
|
|
97
98
|
const name = m.identifier ?? key;
|
|
98
99
|
const isStatic = m.scope === "static";
|
|
99
100
|
const isPrivate = m.access === "private";
|
|
@@ -101,7 +102,7 @@ export function compileClassJson(classDef, _opts = {}) {
|
|
|
101
102
|
const staticPrefix = isStatic ? "static " : "";
|
|
102
103
|
const asyncPrefix =
|
|
103
104
|
m.returnType?.$ref?.includes("Promise") ||
|
|
104
|
-
isMethodAsync(
|
|
105
|
+
isMethodAsync(m as unknown as { body?: string | string[] })
|
|
105
106
|
? "async "
|
|
106
107
|
: "";
|
|
107
108
|
|
|
@@ -148,10 +149,10 @@ export function compileClassJson(classDef, _opts = {}) {
|
|
|
148
149
|
* @param {unknown} ext
|
|
149
150
|
* @returns {string}
|
|
150
151
|
*/
|
|
151
|
-
function resolveBaseClass(ext) {
|
|
152
|
+
function resolveBaseClass(ext: unknown) {
|
|
152
153
|
if (!ext) return "Object";
|
|
153
154
|
if (typeof ext === "string") return ext;
|
|
154
|
-
const e =
|
|
155
|
+
const e = ext as JxMutableNode;
|
|
155
156
|
if (e.$ref) {
|
|
156
157
|
const ref = e.$ref;
|
|
157
158
|
const match = ref.match(/([A-Za-z0-9_]+)\.class\.json/);
|
|
@@ -166,10 +167,10 @@ function resolveBaseClass(ext) {
|
|
|
166
167
|
* @param {unknown[]} params
|
|
167
168
|
* @returns {string}
|
|
168
169
|
*/
|
|
169
|
-
function resolveParams(params) {
|
|
170
|
+
function resolveParams(params: unknown[]) {
|
|
170
171
|
return params
|
|
171
172
|
.map((p) => {
|
|
172
|
-
const param =
|
|
173
|
+
const param = p as JxMutableNode;
|
|
173
174
|
if (param.$ref) return param.$ref.split("/").pop();
|
|
174
175
|
return param.identifier ?? param.name ?? "arg";
|
|
175
176
|
})
|
|
@@ -182,10 +183,10 @@ function resolveParams(params) {
|
|
|
182
183
|
* @param {unknown} body
|
|
183
184
|
* @returns {string[]}
|
|
184
185
|
*/
|
|
185
|
-
function resolveBody(body) {
|
|
186
|
+
function resolveBody(body: unknown) {
|
|
186
187
|
if (!body) return [""];
|
|
187
188
|
if (Array.isArray(body)) return body;
|
|
188
|
-
return [
|
|
189
|
+
return [body as string];
|
|
189
190
|
}
|
|
190
191
|
|
|
191
192
|
/**
|
|
@@ -194,7 +195,7 @@ function resolveBody(body) {
|
|
|
194
195
|
* @param {{ body?: string | string[] }} method
|
|
195
196
|
* @returns {boolean}
|
|
196
197
|
*/
|
|
197
|
-
function isMethodAsync(method) {
|
|
198
|
+
function isMethodAsync(method: { body?: string | string[] }) {
|
|
198
199
|
const body = Array.isArray(method.body) ? method.body.join("\n") : (method.body ?? "");
|
|
199
200
|
return body.includes("await ");
|
|
200
201
|
}
|
|
@@ -25,7 +25,9 @@ import {
|
|
|
25
25
|
DEFAULT_LIT_HTML_SRC,
|
|
26
26
|
compileExpression,
|
|
27
27
|
isMutating,
|
|
28
|
-
} from "../shared.
|
|
28
|
+
} from "../shared.ts";
|
|
29
|
+
import type { ExpressionNode } from "../shared.ts";
|
|
30
|
+
import type { JxStyle, JxMutableNode } from "@jxsuite/schema/types";
|
|
29
31
|
|
|
30
32
|
/**
|
|
31
33
|
* Compile a Jx document to pre-rendered HTML + reactive JS module.
|
|
@@ -34,43 +36,38 @@ import {
|
|
|
34
36
|
* @param {Record<string, unknown>} opts
|
|
35
37
|
* @returns {{ html: string; files: { path: string; content: string }[] }}
|
|
36
38
|
*/
|
|
37
|
-
export function compileClient(
|
|
39
|
+
export function compileClient(
|
|
40
|
+
raw: JxMutableNode | Record<string, any>,
|
|
41
|
+
opts: Record<string, unknown>,
|
|
42
|
+
) {
|
|
38
43
|
const {
|
|
39
44
|
title,
|
|
40
45
|
reactivitySrc = DEFAULT_REACTIVITY_SRC,
|
|
41
46
|
litHtmlSrc = DEFAULT_LIT_HTML_SRC,
|
|
42
47
|
modulePath = "app.js",
|
|
43
|
-
} =
|
|
48
|
+
} = opts as JxMutableNode;
|
|
44
49
|
|
|
45
50
|
const context = createCompileContext(raw, null, raw.state ?? {}, raw.$media ?? {});
|
|
46
51
|
const styleBlock = compileStyles(
|
|
47
52
|
raw,
|
|
48
53
|
raw.$media ?? {},
|
|
49
|
-
|
|
54
|
+
(opts.projectStyle ?? null) as JxStyle | null,
|
|
50
55
|
);
|
|
51
56
|
|
|
52
57
|
// Collectors for bindings and handlers
|
|
53
58
|
const counter = { t: 0, s: 0, h: 0, m: 0, sw: 0, l: 0, needsLit: false };
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
/** @type {Map<string, any>} */
|
|
57
|
-
const handlers = new Map(); // key → { body, args }
|
|
59
|
+
const bindings: Map<string, string> = new Map(); // key → expression string
|
|
60
|
+
const handlers: Map<string, any> = new Map(); // key → { body, args }
|
|
58
61
|
|
|
59
62
|
// Classify state entries into reactive state, computed, bind, on, and init blocks
|
|
60
|
-
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
const bindEntries = []; // [key, bodyExpr] → bind = {...}
|
|
66
|
-
/** @type {[string, any][]} */
|
|
67
|
-
const onEntries = []; // [key, { args, body }] → on = {...}
|
|
68
|
-
/** @type {string[]} */
|
|
69
|
-
const initBlocks = []; // lines emitted after state for prototype init
|
|
63
|
+
const stateEntries: [string, any][] = []; // [key, initValue] → reactive({...})
|
|
64
|
+
const computedEntries: [string, string][] = []; // [key, bodyExpr] → state.key = computed(...)
|
|
65
|
+
const bindEntries: [string, string][] = []; // [key, bodyExpr] → bind = {...}
|
|
66
|
+
const onEntries: [string, any][] = []; // [key, { args, body }] → on = {...}
|
|
67
|
+
const initBlocks: string[] = []; // lines emitted after state for prototype init
|
|
70
68
|
|
|
71
69
|
// Map $src path → Set of function names to import
|
|
72
|
-
|
|
73
|
-
const srcImportMap = new Map();
|
|
70
|
+
const srcImportMap: Map<string, Set<string>> = new Map();
|
|
74
71
|
|
|
75
72
|
const defs = raw.state ?? {};
|
|
76
73
|
for (const [key, def] of Object.entries(defs)) {
|
|
@@ -85,11 +82,11 @@ export function compileClient(raw, opts) {
|
|
|
85
82
|
continue;
|
|
86
83
|
}
|
|
87
84
|
|
|
88
|
-
const d =
|
|
85
|
+
const d = def as JxMutableNode;
|
|
89
86
|
|
|
90
87
|
// $expression: Shape 5
|
|
91
88
|
if ("$expression" in d) {
|
|
92
|
-
const node =
|
|
89
|
+
const node = (d as Record<string, unknown>).$expression as ExpressionNode;
|
|
93
90
|
if (isMutating(node.operator)) {
|
|
94
91
|
const compiled = compileExpression(node, { statePrefix: "state", eventParam: "e" });
|
|
95
92
|
onEntries.push([key, { args: ["state", "e"], body: compiled }]);
|
|
@@ -105,7 +102,7 @@ export function compileClient(raw, opts) {
|
|
|
105
102
|
const args = d.parameters ?? d.arguments;
|
|
106
103
|
if (d.$src) {
|
|
107
104
|
if (!srcImportMap.has(d.$src)) srcImportMap.set(d.$src, new Set());
|
|
108
|
-
|
|
105
|
+
(srcImportMap.get(d.$src) as Set<string>).add(key);
|
|
109
106
|
|
|
110
107
|
// $src functions always produce computed entries (they return values)
|
|
111
108
|
computedEntries.push([key, "() => { return " + key + "(state); }"]);
|
|
@@ -232,7 +229,14 @@ ${importmapEntries.join(",\n")}
|
|
|
232
229
|
* }} counter
|
|
233
230
|
* @returns {string}
|
|
234
231
|
*/
|
|
235
|
-
function buildClientNode(
|
|
232
|
+
function buildClientNode(
|
|
233
|
+
def: JxMutableNode,
|
|
234
|
+
raw: JxMutableNode,
|
|
235
|
+
context: any,
|
|
236
|
+
bindings: Map<string, string>,
|
|
237
|
+
handlers: Map<string, any>,
|
|
238
|
+
counter: { t: number; s: number; h: number; m: number; sw: number; l: number; needsLit: boolean },
|
|
239
|
+
) {
|
|
236
240
|
// String children are text nodes
|
|
237
241
|
if (typeof def === "string") {
|
|
238
242
|
return escapeHtml(def);
|
|
@@ -255,13 +259,11 @@ function buildClientNode(def, raw, context, bindings, handlers, counter) {
|
|
|
255
259
|
|
|
256
260
|
// textContent bindings
|
|
257
261
|
if (def.textContent !== undefined) {
|
|
258
|
-
const tc =
|
|
259
|
-
/** @type {unknown} */ (raw?.textContent ?? def.textContent)
|
|
260
|
-
);
|
|
262
|
+
const tc = raw?.textContent ?? (def.textContent as unknown as JxMutableNode);
|
|
261
263
|
if (isRefObject(tc)) {
|
|
262
|
-
const key = refToBindingKey(
|
|
264
|
+
const key = refToBindingKey((tc as JxMutableNode).$ref as string);
|
|
263
265
|
bindAttrs.push(`:text-content="${key}"`);
|
|
264
|
-
addRefBinding(bindings, key,
|
|
266
|
+
addRefBinding(bindings, key, (tc as JxMutableNode).$ref as string);
|
|
265
267
|
needsBind = true;
|
|
266
268
|
} else if (isTemplateString(tc)) {
|
|
267
269
|
const key = `_t${counter.t++}`;
|
|
@@ -276,15 +278,11 @@ function buildClientNode(def, raw, context, bindings, handlers, counter) {
|
|
|
276
278
|
if (!prop.startsWith("on") || prop === "observedAttributes") continue;
|
|
277
279
|
const eventName = prop.slice(2).toLowerCase();
|
|
278
280
|
if (isRefObject(val)) {
|
|
279
|
-
const key = refToBindingKey(
|
|
281
|
+
const key = refToBindingKey((val as JxMutableNode).$ref as string);
|
|
280
282
|
bindAttrs.push(`@${eventName}="${key}"`);
|
|
281
283
|
needsBind = true;
|
|
282
|
-
} else if (
|
|
283
|
-
val
|
|
284
|
-
typeof val === "object" &&
|
|
285
|
-
/** @type {JxMutableNode} */ (val).$prototype === "Function"
|
|
286
|
-
) {
|
|
287
|
-
const v = /** @type {JxMutableNode} */ (val);
|
|
284
|
+
} else if (val && typeof val === "object" && (val as JxMutableNode).$prototype === "Function") {
|
|
285
|
+
const v = val as JxMutableNode;
|
|
288
286
|
const key = `_h${counter.h++}`;
|
|
289
287
|
bindAttrs.push(`@${eventName}="${key}"`);
|
|
290
288
|
handlers.set(key, { args: v.parameters ?? v.arguments ?? ["state", "event"], body: v.body });
|
|
@@ -292,10 +290,13 @@ function buildClientNode(def, raw, context, bindings, handlers, counter) {
|
|
|
292
290
|
} else if (val && typeof val === "object" && "$expression" in /** @type {any} */ (val)) {
|
|
293
291
|
const key = `_h${counter.h++}`;
|
|
294
292
|
bindAttrs.push(`@${eventName}="${key}"`);
|
|
295
|
-
const compiled = compileExpression(
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
293
|
+
const compiled = compileExpression(
|
|
294
|
+
(val as Record<string, unknown>).$expression as ExpressionNode,
|
|
295
|
+
{
|
|
296
|
+
statePrefix: "state",
|
|
297
|
+
eventParam: "e",
|
|
298
|
+
},
|
|
299
|
+
);
|
|
299
300
|
handlers.set(key, { args: ["state", "e"], body: compiled });
|
|
300
301
|
needsBind = true;
|
|
301
302
|
}
|
|
@@ -326,15 +327,9 @@ function buildClientNode(def, raw, context, bindings, handlers, counter) {
|
|
|
326
327
|
if (def.attributes && typeof def.attributes === "object") {
|
|
327
328
|
for (const [attr, val] of Object.entries(def.attributes)) {
|
|
328
329
|
if (isRefObject(val)) {
|
|
329
|
-
const key = refToBindingKey(
|
|
330
|
-
/** @type {string} */ (/** @type {JxMutableNode} */ (val).$ref),
|
|
331
|
-
);
|
|
330
|
+
const key = refToBindingKey((val as JxMutableNode).$ref as string);
|
|
332
331
|
bindAttrs.push(`:attr.${attr}="${key}"`);
|
|
333
|
-
addRefBinding(
|
|
334
|
-
bindings,
|
|
335
|
-
key,
|
|
336
|
-
/** @type {string} */ (/** @type {JxMutableNode} */ (val).$ref),
|
|
337
|
-
);
|
|
332
|
+
addRefBinding(bindings, key, (val as JxMutableNode).$ref as string);
|
|
338
333
|
needsBind = true;
|
|
339
334
|
} else if (isTemplateString(val)) {
|
|
340
335
|
const key = `_t${counter.t++}`;
|
|
@@ -362,9 +357,9 @@ function buildClientNode(def, raw, context, bindings, handlers, counter) {
|
|
|
362
357
|
)
|
|
363
358
|
continue;
|
|
364
359
|
if (isRefObject(val)) {
|
|
365
|
-
const key = refToBindingKey(
|
|
360
|
+
const key = refToBindingKey((val as JxMutableNode).$ref as string);
|
|
366
361
|
bindAttrs.push(`:${camelToKebab(prop)}="${key}"`);
|
|
367
|
-
addRefBinding(bindings, key,
|
|
362
|
+
addRefBinding(bindings, key, (val as JxMutableNode).$ref as string);
|
|
368
363
|
needsBind = true;
|
|
369
364
|
} else if (isTemplateString(val)) {
|
|
370
365
|
const key = `_t${counter.t++}`;
|
|
@@ -391,18 +386,17 @@ function buildClientNode(def, raw, context, bindings, handlers, counter) {
|
|
|
391
386
|
} else if (source.innerHTML) {
|
|
392
387
|
// resolveStaticValue may return null if innerHTML contains `${` from rendered content
|
|
393
388
|
// (e.g., code examples) that isn't an actual template expression. Fall back to raw value.
|
|
394
|
-
inner =
|
|
395
|
-
source.innerHTML;
|
|
389
|
+
inner = (resolveStaticValue(source.innerHTML, nextContext.scope) as string) ?? source.innerHTML;
|
|
396
390
|
} else if (
|
|
397
391
|
source.children &&
|
|
398
392
|
typeof source.children === "object" &&
|
|
399
393
|
!Array.isArray(source.children) &&
|
|
400
|
-
|
|
394
|
+
(source.children as JxMutableNode).$prototype === "Array"
|
|
401
395
|
) {
|
|
402
396
|
// ─── Mapped array → lit-html render binding ───
|
|
403
397
|
counter.needsLit = true;
|
|
404
398
|
const listKey = `_list${counter.l++}`;
|
|
405
|
-
const arrayDef =
|
|
399
|
+
const arrayDef = source.children as JxMutableNode;
|
|
406
400
|
|
|
407
401
|
// Resolve items source expression
|
|
408
402
|
let itemsExpr;
|
|
@@ -436,8 +430,8 @@ function buildClientNode(def, raw, context, bindings, handlers, counter) {
|
|
|
436
430
|
.map((c, i) => {
|
|
437
431
|
const childRaw = rawChildren?.[i] ?? c;
|
|
438
432
|
return buildClientNode(
|
|
439
|
-
|
|
440
|
-
|
|
433
|
+
c as unknown as JxMutableNode,
|
|
434
|
+
childRaw as unknown as JxMutableNode,
|
|
441
435
|
nextContext,
|
|
442
436
|
bindings,
|
|
443
437
|
handlers,
|
|
@@ -465,7 +459,7 @@ function buildClientNode(def, raw, context, bindings, handlers, counter) {
|
|
|
465
459
|
* @param {JxMutableNode} def
|
|
466
460
|
* @returns {string}
|
|
467
461
|
*/
|
|
468
|
-
function emitLitMapTemplate(def) {
|
|
462
|
+
function emitLitMapTemplate(def: JxMutableNode) {
|
|
469
463
|
if (!def) return "";
|
|
470
464
|
const tag = def.tagName ?? "div";
|
|
471
465
|
let attrs = "";
|
|
@@ -486,8 +480,7 @@ function emitLitMapTemplate(def) {
|
|
|
486
480
|
|
|
487
481
|
// style → inline CSS
|
|
488
482
|
if (def.style && typeof def.style === "object") {
|
|
489
|
-
|
|
490
|
-
const parts = [];
|
|
483
|
+
const parts: string[] = [];
|
|
491
484
|
for (const [k, v] of Object.entries(def.style)) {
|
|
492
485
|
if (
|
|
493
486
|
k.startsWith(":") ||
|
|
@@ -515,20 +508,19 @@ function emitLitMapTemplate(def) {
|
|
|
515
508
|
if (!prop.startsWith("on") || prop === "observedAttributes") continue;
|
|
516
509
|
const eventName = prop.slice(2).toLowerCase();
|
|
517
510
|
if (isRefObject(val)) {
|
|
518
|
-
const key = refToBindingKey(
|
|
511
|
+
const key = refToBindingKey((val as JxMutableNode).$ref as string);
|
|
519
512
|
attrs += " @" + eventName + "=${(e) => { state.$map = { item, index }; on." + key + "(e); }}";
|
|
520
|
-
} else if (
|
|
521
|
-
val
|
|
522
|
-
typeof val === "object" &&
|
|
523
|
-
/** @type {JxMutableNode} */ (val).$prototype === "Function"
|
|
524
|
-
) {
|
|
525
|
-
const body = mapRefsToLit(/** @type {string} */ (/** @type {JxMutableNode} */ (val).body));
|
|
513
|
+
} else if (val && typeof val === "object" && (val as JxMutableNode).$prototype === "Function") {
|
|
514
|
+
const body = mapRefsToLit((val as JxMutableNode).body as string);
|
|
526
515
|
attrs += " @" + eventName + "=${(e) => { " + body + " }}";
|
|
527
516
|
} else if (val && typeof val === "object" && "$expression" in /** @type {any} */ (val)) {
|
|
528
|
-
const compiled = compileExpression(
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
517
|
+
const compiled = compileExpression(
|
|
518
|
+
(val as Record<string, unknown>).$expression as ExpressionNode,
|
|
519
|
+
{
|
|
520
|
+
statePrefix: "state",
|
|
521
|
+
eventParam: "e",
|
|
522
|
+
},
|
|
523
|
+
);
|
|
532
524
|
attrs += " @" + eventName + "=${(e) => { state.$map = { item, index }; " + compiled + "; }}";
|
|
533
525
|
}
|
|
534
526
|
}
|
|
@@ -545,11 +537,7 @@ function emitLitMapTemplate(def) {
|
|
|
545
537
|
if (isTemplateString(tc)) {
|
|
546
538
|
inner = mapRefsToLit(tc);
|
|
547
539
|
} else if (isRefObject(def.textContent)) {
|
|
548
|
-
const path = refToBindingKey(
|
|
549
|
-
/** @type {string} */ (
|
|
550
|
-
/** @type {JxMutableNode} */ (/** @type {unknown} */ (def.textContent)).$ref
|
|
551
|
-
),
|
|
552
|
-
);
|
|
540
|
+
const path = refToBindingKey((def.textContent as unknown as JxMutableNode).$ref as string);
|
|
553
541
|
inner = "${state." + path + "}";
|
|
554
542
|
} else {
|
|
555
543
|
inner = escapeHtml(tc);
|
|
@@ -559,9 +547,7 @@ function emitLitMapTemplate(def) {
|
|
|
559
547
|
} else if (Array.isArray(def.children)) {
|
|
560
548
|
inner =
|
|
561
549
|
"\n " +
|
|
562
|
-
def.children
|
|
563
|
-
.map((c) => emitLitMapTemplate(/** @type {JxMutableNode} */ (c)))
|
|
564
|
-
.join("\n ") +
|
|
550
|
+
def.children.map((c) => emitLitMapTemplate(c as JxMutableNode)).join("\n ") +
|
|
565
551
|
"\n ";
|
|
566
552
|
}
|
|
567
553
|
|
|
@@ -576,7 +562,7 @@ function emitLitMapTemplate(def) {
|
|
|
576
562
|
* @param {string} str
|
|
577
563
|
* @returns {string}
|
|
578
564
|
*/
|
|
579
|
-
function mapRefsToLit(str) {
|
|
565
|
+
function mapRefsToLit(str: string) {
|
|
580
566
|
return str.replace(/\$map\./g, "");
|
|
581
567
|
}
|
|
582
568
|
|
|
@@ -602,17 +588,16 @@ function mapRefsToLit(str) {
|
|
|
602
588
|
* @returns {string}
|
|
603
589
|
*/
|
|
604
590
|
function emitClientModule(
|
|
605
|
-
stateEntries,
|
|
606
|
-
computedEntries,
|
|
607
|
-
bindEntries,
|
|
608
|
-
onEntries,
|
|
609
|
-
initBlocks,
|
|
610
|
-
srcImportMap,
|
|
611
|
-
counter,
|
|
612
|
-
_reactivitySrc,
|
|
591
|
+
stateEntries: [string, any][],
|
|
592
|
+
computedEntries: [string, string][],
|
|
593
|
+
bindEntries: [string, string][],
|
|
594
|
+
onEntries: [string, any][],
|
|
595
|
+
initBlocks: string[],
|
|
596
|
+
srcImportMap: Map<string, Set<string>>,
|
|
597
|
+
counter: { t: number; s: number; h: number; m: number; sw: number; l: number; needsLit: boolean },
|
|
598
|
+
_reactivitySrc: string,
|
|
613
599
|
) {
|
|
614
|
-
|
|
615
|
-
const lines = [];
|
|
600
|
+
const lines: string[] = [];
|
|
616
601
|
const needsLit = counter.needsLit;
|
|
617
602
|
const needsComputed = computedEntries.length > 0;
|
|
618
603
|
|
|
@@ -676,9 +661,7 @@ function emitClientModule(
|
|
|
676
661
|
lines.push("const on = {");
|
|
677
662
|
for (const [key, def] of onEntries) {
|
|
678
663
|
const argNames = def.args ?? ["state"];
|
|
679
|
-
const callArgs = argNames
|
|
680
|
-
.map((/** @type {string} */ a) => (a === "state" ? "state" : "e"))
|
|
681
|
-
.join(", ");
|
|
664
|
+
const callArgs = argNames.map((a: string) => (a === "state" ? "state" : "e")).join(", ");
|
|
682
665
|
lines.push(
|
|
683
666
|
" " +
|
|
684
667
|
key +
|
|
@@ -738,7 +721,7 @@ function emitClientModule(
|
|
|
738
721
|
* @param {JxMutableNode} def
|
|
739
722
|
* @returns {string}
|
|
740
723
|
*/
|
|
741
|
-
function emitRequestInit(key, def) {
|
|
724
|
+
function emitRequestInit(key: string, def: JxMutableNode) {
|
|
742
725
|
const url = def.url;
|
|
743
726
|
const method = def.method ?? "GET";
|
|
744
727
|
const isTemplateUrl = isTemplateString(url);
|
|
@@ -747,8 +730,7 @@ function emitRequestInit(key, def) {
|
|
|
747
730
|
return "// " + key + ": manual Request — fetch triggered by user action";
|
|
748
731
|
}
|
|
749
732
|
|
|
750
|
-
|
|
751
|
-
const lines = [];
|
|
733
|
+
const lines: string[] = [];
|
|
752
734
|
lines.push("// " + key + ": auto-fetch from " + (isTemplateUrl ? "(dynamic URL)" : url));
|
|
753
735
|
lines.push("effect(() => {");
|
|
754
736
|
|
|
@@ -759,8 +741,7 @@ function emitRequestInit(key, def) {
|
|
|
759
741
|
lines.push(" const url = " + JSON.stringify(url) + ";");
|
|
760
742
|
}
|
|
761
743
|
|
|
762
|
-
|
|
763
|
-
const fetchOpts = [];
|
|
744
|
+
const fetchOpts: string[] = [];
|
|
764
745
|
if (method !== "GET") fetchOpts.push("method: " + JSON.stringify(method));
|
|
765
746
|
if (def.headers) fetchOpts.push("headers: " + JSON.stringify(def.headers));
|
|
766
747
|
if (def.body) {
|
|
@@ -788,9 +769,8 @@ function emitRequestInit(key, def) {
|
|
|
788
769
|
* @param {unknown} defaultVal
|
|
789
770
|
* @returns {string}
|
|
790
771
|
*/
|
|
791
|
-
function emitStorageInit(key, storeName, storageKey, defaultVal) {
|
|
792
|
-
|
|
793
|
-
const lines = [];
|
|
772
|
+
function emitStorageInit(key: string, storeName: string, storageKey: string, defaultVal: unknown) {
|
|
773
|
+
const lines: string[] = [];
|
|
794
774
|
lines.push("// " + key + ": " + storeName + ' (key: "' + storageKey + '")');
|
|
795
775
|
lines.push("try {");
|
|
796
776
|
lines.push(" const _s = " + storeName + ".getItem(" + JSON.stringify(storageKey) + ");");
|
|
@@ -818,9 +798,8 @@ function emitStorageInit(key, storeName, storageKey, defaultVal) {
|
|
|
818
798
|
* @param {unknown} defaultVal
|
|
819
799
|
* @returns {string}
|
|
820
800
|
*/
|
|
821
|
-
function emitCookieInit(key, cookieName, defaultVal) {
|
|
822
|
-
|
|
823
|
-
const lines = [];
|
|
801
|
+
function emitCookieInit(key: string, cookieName: string, defaultVal: unknown) {
|
|
802
|
+
const lines: string[] = [];
|
|
824
803
|
lines.push("// " + key + ': Cookie (name: "' + cookieName + '")');
|
|
825
804
|
lines.push("{");
|
|
826
805
|
lines.push(
|
|
@@ -844,7 +823,7 @@ function emitCookieInit(key, cookieName, defaultVal) {
|
|
|
844
823
|
* @param {string} ref
|
|
845
824
|
* @returns {string}
|
|
846
825
|
*/
|
|
847
|
-
function refToBindingKey(ref) {
|
|
826
|
+
function refToBindingKey(ref: string) {
|
|
848
827
|
if (ref.startsWith("#/state/")) {
|
|
849
828
|
return ref.slice("#/state/".length).replace(/\//g, "_");
|
|
850
829
|
}
|
|
@@ -856,7 +835,7 @@ function refToBindingKey(ref) {
|
|
|
856
835
|
* @param {string} key
|
|
857
836
|
* @param {string} ref
|
|
858
837
|
*/
|
|
859
|
-
function addRefBinding(bindings, key, ref) {
|
|
838
|
+
function addRefBinding(bindings: Map<string, string>, key: string, ref: string) {
|
|
860
839
|
if (bindings.has(key)) return;
|
|
861
840
|
if (ref.startsWith("#/state/")) {
|
|
862
841
|
const path = ref.slice("#/state/".length);
|