@jxsuite/runtime 6.2.2 → 7.0.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/runtime.js CHANGED
@@ -1491,6 +1491,9 @@ function isTemplateString(value) {
1491
1491
  function bodyReturnsValue(body) {
1492
1492
  return /\breturn\b[^\S\n]*(?![;}\s]|$)/.test(maskCode(body));
1493
1493
  }
1494
+ function isFunctionEntry(value) {
1495
+ return value.$prototype === "Function" || isString2(value.role) && value.role !== "field";
1496
+ }
1494
1497
  function maskCode(body) {
1495
1498
  if (!/[/'"`]/u.test(body)) {
1496
1499
  return body;
@@ -1508,7 +1511,91 @@ function maskCode(body) {
1508
1511
  }
1509
1512
  var masked = new Map;
1510
1513
  var MASKED_LIMIT = 2048;
1511
- function scanCode(body) {
1514
+ function templateExpressions(template) {
1515
+ if (!template.includes("${")) {
1516
+ return NO_EXPRESSIONS;
1517
+ }
1518
+ const known = scanned.get(template);
1519
+ if (known !== undefined) {
1520
+ return known;
1521
+ }
1522
+ const found = [];
1523
+ let from = 0;
1524
+ while (from < template.length) {
1525
+ const spans = [];
1526
+ scanCode(template.slice(from), spans);
1527
+ let unclosed = -1;
1528
+ for (let i = 0;i < spans.length; i += 2) {
1529
+ const start = from + (spans[i] ?? 0);
1530
+ const end = spans[i + 1] ?? -1;
1531
+ if (end === -1) {
1532
+ unclosed = start;
1533
+ break;
1534
+ }
1535
+ found.push(expressionAt(template, start, from + end));
1536
+ }
1537
+ if (unclosed === -1) {
1538
+ break;
1539
+ }
1540
+ const end = closeByBraceDepth(template, unclosed);
1541
+ if (end === -1) {
1542
+ from = unclosed + 2;
1543
+ } else {
1544
+ found.push(expressionAt(template, unclosed, end));
1545
+ from = end;
1546
+ }
1547
+ }
1548
+ if (scanned.size >= MASKED_LIMIT) {
1549
+ scanned.clear();
1550
+ }
1551
+ scanned.set(template, found);
1552
+ return found;
1553
+ }
1554
+ var NO_EXPRESSIONS = [];
1555
+ var scanned = new Map;
1556
+ function expressionAt(template, start, end) {
1557
+ return { end, expr: template.slice(start + 2, end - 1), start };
1558
+ }
1559
+ function closeByBraceDepth(template, start) {
1560
+ let depth = 0;
1561
+ for (let at = start + 1;at < template.length; at += 1) {
1562
+ const char = template.charAt(at);
1563
+ if (char === "{") {
1564
+ depth += 1;
1565
+ } else if (char === "}") {
1566
+ depth -= 1;
1567
+ if (depth === 0) {
1568
+ return at + 1;
1569
+ }
1570
+ }
1571
+ }
1572
+ return -1;
1573
+ }
1574
+ var BEFORE_OPERAND = new Set("(,=:[!&|?{;+-*%<>~^");
1575
+ function endsUpdateOperator(body, before, at) {
1576
+ return (before === "+" || before === "-") && body.charAt(at - 1) === before;
1577
+ }
1578
+ function regexLiteralEnd(body, at) {
1579
+ let inClass = false;
1580
+ for (let i = at + 1;i < body.length; i += 1) {
1581
+ const char = body.charAt(i);
1582
+ if (char === `
1583
+ `) {
1584
+ return -1;
1585
+ }
1586
+ if (char === "\\") {
1587
+ i += 1;
1588
+ } else if (char === "[") {
1589
+ inClass = true;
1590
+ } else if (char === "]") {
1591
+ inClass = false;
1592
+ } else if (char === "/" && !inClass) {
1593
+ return i + 1;
1594
+ }
1595
+ }
1596
+ return -1;
1597
+ }
1598
+ function scanCode(body, spans) {
1512
1599
  const out = body.split("");
1513
1600
  const blank = (at) => {
1514
1601
  if (out[at] !== undefined && out[at] !== `
@@ -1517,7 +1604,9 @@ function scanCode(body) {
1517
1604
  }
1518
1605
  };
1519
1606
  const substitutions = [];
1520
- let inTemplate = false;
1607
+ let inTemplate = spans !== undefined;
1608
+ let before = "";
1609
+ let beforeAt = -1;
1521
1610
  let at = 0;
1522
1611
  while (at < body.length) {
1523
1612
  const char = body.charAt(at);
@@ -1526,12 +1615,17 @@ function scanCode(body) {
1526
1615
  blank(at);
1527
1616
  blank(at + 1);
1528
1617
  at += 2;
1529
- } else if (char === "`") {
1618
+ } else if (char === "`" && !(spans && substitutions.length === 0)) {
1530
1619
  inTemplate = false;
1620
+ before = char;
1531
1621
  at += 1;
1532
1622
  } else if (char === "$" && body.charAt(at + 1) === "{") {
1623
+ if (substitutions.length === 0) {
1624
+ spans?.push(at, -1);
1625
+ }
1533
1626
  substitutions.push(0);
1534
1627
  inTemplate = false;
1628
+ before = "{";
1535
1629
  at += 2;
1536
1630
  } else {
1537
1631
  blank(at);
@@ -1560,10 +1654,18 @@ function scanCode(body) {
1560
1654
  blank(at);
1561
1655
  at += 1;
1562
1656
  }
1657
+ before = char;
1563
1658
  at += 1;
1564
1659
  } else if (char === "`") {
1565
1660
  inTemplate = true;
1566
1661
  at += 1;
1662
+ } else if (spans && char === "/" && BEFORE_OPERAND.has(before) && !endsUpdateOperator(body, before, beforeAt) && regexLiteralEnd(body, at) > 0) {
1663
+ const stop = regexLiteralEnd(body, at);
1664
+ for (at += 1;at < stop - 1; at += 1) {
1665
+ blank(at);
1666
+ }
1667
+ before = "/";
1668
+ at = stop;
1567
1669
  } else {
1568
1670
  const open = substitutions.length - 1;
1569
1671
  if (open >= 0 && char === "{") {
@@ -1572,10 +1674,17 @@ function scanCode(body) {
1572
1674
  if (substitutions[open] === 0) {
1573
1675
  substitutions.pop();
1574
1676
  inTemplate = true;
1677
+ if (spans && substitutions.length === 0) {
1678
+ spans[spans.length - 1] = at + 1;
1679
+ }
1575
1680
  } else {
1576
1681
  substitutions[open] = (substitutions[open] ?? 1) - 1;
1577
1682
  }
1578
1683
  }
1684
+ if (char.trim() !== "") {
1685
+ before = char;
1686
+ beforeAt = at;
1687
+ }
1579
1688
  at += 1;
1580
1689
  }
1581
1690
  }
@@ -2222,12 +2331,77 @@ function withPageLocale(path, args, state) {
2222
2331
  filled[index] = locale;
2223
2332
  return filled;
2224
2333
  }
2334
+ function windowRoot() {
2335
+ const root = globalThis.window;
2336
+ return root ?? globalThis;
2337
+ }
2225
2338
  function isBlessedGlobal(ref) {
2226
2339
  return ref.startsWith("window#/") && BLESSED_GLOBALS.has(ref.slice("window#/".length));
2227
2340
  }
2228
2341
  function isMutating(op) {
2229
2342
  return MUTATING_OPS.has(op);
2230
2343
  }
2344
+ function operandMutates(operand) {
2345
+ if (Array.isArray(operand)) {
2346
+ return operand.some((item) => operandMutates(item));
2347
+ }
2348
+ if (operand === undefined || !isNodeOperand(operand)) {
2349
+ return false;
2350
+ }
2351
+ return isMutating(operand.operator) || [operand.target, operand.value, operand.initial, operand.default].some((part) => operandMutates(part)) || Object.values(operand.cases ?? {}).some((part) => operandMutates(part));
2352
+ }
2353
+ function isPureNamedFormula(def) {
2354
+ return isNamedFormulaDef(def) && !operandMutates(def.$expression);
2355
+ }
2356
+ var OUTSIDE_SCOPE_REF = /^(?:\$args\/|\$reduce\/|\$map\/|window#\/|document#\/|event#\/)/;
2357
+ function collectScopeReads(operand, into) {
2358
+ if (Array.isArray(operand)) {
2359
+ for (const item of operand) {
2360
+ collectScopeReads(item, into);
2361
+ }
2362
+ return;
2363
+ }
2364
+ if (operand === undefined || !isNonNullObject(operand)) {
2365
+ return;
2366
+ }
2367
+ if (isRefOperand(operand)) {
2368
+ if (!OUTSIDE_SCOPE_REF.test(operand.$ref)) {
2369
+ const path = operand.$ref.replace(/^(?:#\/state\/|parent#\/)/, "");
2370
+ into.add(refSegments(path)[0] ?? "");
2371
+ }
2372
+ return;
2373
+ }
2374
+ if (isNodeOperand(operand)) {
2375
+ const parts = [operand.target, operand.value, operand.initial, operand.default];
2376
+ for (const part of [...parts, ...Object.values(operand.cases ?? {})]) {
2377
+ collectScopeReads(part, into);
2378
+ }
2379
+ }
2380
+ }
2381
+ function formulaScopeReads(def) {
2382
+ const reads = new Set;
2383
+ collectScopeReads(def.$expression, reads);
2384
+ return [...reads];
2385
+ }
2386
+ function inheritableFormulas(projectState) {
2387
+ const candidates = new Map;
2388
+ for (const [key, def] of Object.entries(projectState ?? {})) {
2389
+ if (!key.startsWith("$") && isPureNamedFormula(def)) {
2390
+ candidates.set(key, def);
2391
+ }
2392
+ }
2393
+ let settled = false;
2394
+ while (!settled) {
2395
+ settled = true;
2396
+ for (const [key, def] of candidates) {
2397
+ if (formulaScopeReads(def).some((read) => !candidates.has(read))) {
2398
+ candidates.delete(key);
2399
+ settled = false;
2400
+ }
2401
+ }
2402
+ }
2403
+ return Object.fromEntries(candidates);
2404
+ }
2231
2405
  var MAX_CALL_DEPTH = 64;
2232
2406
  var MAX_REPORT_DEPTH = 64;
2233
2407
  function subTrace(trace, seg) {
@@ -2321,7 +2495,7 @@ function resolveExprRef(ref, state, event, iterCtx) {
2321
2495
  return readPath(state, ref.slice("parent#/".length));
2322
2496
  }
2323
2497
  if (ref.startsWith("window#/")) {
2324
- return readPath(globalThis.window, ref.slice("window#/".length));
2498
+ return readPath(windowRoot(), ref.slice("window#/".length));
2325
2499
  }
2326
2500
  if (ref.startsWith("document#/")) {
2327
2501
  return readPath(globalThis.document, ref.slice("document#/".length));
@@ -2437,9 +2611,10 @@ function evaluateNode(node, state, event, iterCtx, trace) {
2437
2611
  if (helper) {
2438
2612
  return helper(...withPageLocale(globalPath, argValues, state));
2439
2613
  }
2440
- const fn = readPath(globalThis.window, globalPath);
2614
+ const root = windowRoot();
2615
+ const fn = readPath(root, globalPath);
2441
2616
  const lastSlash = globalPath.lastIndexOf("/");
2442
- const thisArg = lastSlash === -1 ? globalThis.window : readPath(globalThis.window, globalPath.slice(0, lastSlash));
2617
+ const thisArg = lastSlash === -1 ? root : readPath(root, globalPath.slice(0, lastSlash));
2443
2618
  return fn.apply(thisArg, argValues);
2444
2619
  }
2445
2620
  const callee = resolveExprRef(calleeRef, state, event, iterCtx);
@@ -2573,6 +2748,96 @@ function evaluateOperand(operand, state, event, iterCtx) {
2573
2748
  return resolveOperand(operand, state, event, iterCtx);
2574
2749
  }
2575
2750
 
2751
+ // ../schema/src/function-role.ts
2752
+ var LIFECYCLE_KEYS = new Set(["onMount", "onUnmount", "onAdopted"]);
2753
+ function collectCallableKeys(doc) {
2754
+ const keys = new Set;
2755
+ const seen = new Set;
2756
+ const addStateRef = (ref) => {
2757
+ if (ref.startsWith("#/state/")) {
2758
+ keys.add(ref.slice("#/state/".length).split("/")[0]);
2759
+ }
2760
+ };
2761
+ const visit = (node) => {
2762
+ if (isString2(node)) {
2763
+ for (const call of node.matchAll(/\bstate\.([A-Za-z_$][\w$]*)\s*\(/gu)) {
2764
+ keys.add(call[1]);
2765
+ }
2766
+ return;
2767
+ }
2768
+ if (Array.isArray(node)) {
2769
+ if (!seen.has(node)) {
2770
+ seen.add(node);
2771
+ for (const item of node) {
2772
+ visit(item);
2773
+ }
2774
+ }
2775
+ return;
2776
+ }
2777
+ if (!isJsonObject(node) || seen.has(node)) {
2778
+ return;
2779
+ }
2780
+ seen.add(node);
2781
+ if (node.operator === "call" && isRef2(node.target)) {
2782
+ addStateRef(node.target.$ref);
2783
+ }
2784
+ for (const [key, value] of Object.entries(node)) {
2785
+ if (key === "$defs") {
2786
+ continue;
2787
+ }
2788
+ if (key.startsWith("on") && isRef2(value)) {
2789
+ addStateRef(value.$ref);
2790
+ }
2791
+ visit(value);
2792
+ }
2793
+ };
2794
+ visit(doc);
2795
+ for (const hook of LIFECYCLE_KEYS) {
2796
+ if (isJsonObject(doc.state) && hook in doc.state) {
2797
+ keys.add(hook);
2798
+ }
2799
+ }
2800
+ return keys;
2801
+ }
2802
+ function declaresBodyAndSrc(def) {
2803
+ return "body" in def && "$src" in def;
2804
+ }
2805
+ function handlerParamNames(def) {
2806
+ const list = ["state"];
2807
+ for (const name of paramNames(def.parameters ?? def.arguments)) {
2808
+ if (name !== "state") {
2809
+ list.push(name);
2810
+ }
2811
+ }
2812
+ return list;
2813
+ }
2814
+ function functionEntryRole(key, def, callableKeys) {
2815
+ if (hasStructuredBody(def)) {
2816
+ return "callable";
2817
+ }
2818
+ if (paramNames(def.parameters ?? def.arguments).length > 0) {
2819
+ return "callable";
2820
+ }
2821
+ if (isString2(def.body)) {
2822
+ return bodyReturnsValue(def.body) ? "computed" : "callable";
2823
+ }
2824
+ if (def.$src) {
2825
+ return callableKeys().has(key) ? "callable" : "computed";
2826
+ }
2827
+ return "callable";
2828
+ }
2829
+ function classifyFunctionEntries(doc) {
2830
+ const roles = new Map;
2831
+ let callable = null;
2832
+ const callableKeys = () => callable ??= collectCallableKeys(doc);
2833
+ for (const [key, def] of Object.entries(doc.state ?? {})) {
2834
+ if (isFunctionDef(def)) {
2835
+ roles.set(key, functionEntryRole(key, def, callableKeys));
2836
+ }
2837
+ }
2838
+ return roles;
2839
+ }
2840
+
2576
2841
  // ../schema/src/asset-paths.ts
2577
2842
  var URL_TERMINATOR = String.raw`"'\s<>()\\`;
2578
2843
  function parseSrcset(value) {
@@ -2701,6 +2966,205 @@ async function runStatements(statements, state, event, opts = {}) {
2701
2966
  }
2702
2967
  }
2703
2968
 
2969
+ // src/body-eraser.ts
2970
+ var eraser = null;
2971
+ var moduleLoader = null;
2972
+ var loader = null;
2973
+ var loading = null;
2974
+ var erased = new Map;
2975
+ function setBodyEraser(fn) {
2976
+ eraser = fn;
2977
+ erased.clear();
2978
+ if (!fn) {
2979
+ loading = null;
2980
+ }
2981
+ }
2982
+ function setModuleLoader(fn) {
2983
+ moduleLoader = fn;
2984
+ if (!fn) {
2985
+ loading = null;
2986
+ }
2987
+ }
2988
+ function canLoadModules() {
2989
+ return moduleLoader !== null || loader !== null;
2990
+ }
2991
+ function fetchEraser(load) {
2992
+ loading ??= load().then((module) => {
2993
+ if (loader !== load) {
2994
+ return;
2995
+ }
2996
+ if (!eraser) {
2997
+ setBodyEraser(module.eraseBody);
2998
+ }
2999
+ if (!moduleLoader && module.loadModule) {
3000
+ setModuleLoader(module.loadModule);
3001
+ }
3002
+ });
3003
+ return loading;
3004
+ }
3005
+ async function moduleLoaderFor() {
3006
+ if (!moduleLoader && loader) {
3007
+ await fetchEraser(loader);
3008
+ }
3009
+ return moduleLoader;
3010
+ }
3011
+ function setBodyEraserLoader(load) {
3012
+ loader = load;
3013
+ loading = null;
3014
+ }
3015
+ function compiles(text) {
3016
+ for (const source of [text, `return async function () {
3017
+ ${text}
3018
+ }`]) {
3019
+ try {
3020
+ Reflect.construct(Function, [source]);
3021
+ return true;
3022
+ } catch {}
3023
+ }
3024
+ return false;
3025
+ }
3026
+ var GENERIC_CALL = /<[^<>]*>\s*[(`]/u;
3027
+ function bodyNeedsEraser(text) {
3028
+ return GENERIC_CALL.test(text) || !compiles(text);
3029
+ }
3030
+ function* bodiesOf(value) {
3031
+ if (Array.isArray(value)) {
3032
+ for (const item of value) {
3033
+ yield* bodiesOf(item);
3034
+ }
3035
+ return;
3036
+ }
3037
+ if (!isJsonObject(value)) {
3038
+ return;
3039
+ }
3040
+ const isFunction = isFunctionEntry(value);
3041
+ for (const [key, child] of Object.entries(value)) {
3042
+ if (isFunction && key === "body") {
3043
+ if (isString2(child)) {
3044
+ yield child;
3045
+ } else if (Array.isArray(child) && child.every((line) => isString2(line))) {
3046
+ yield child.join(`
3047
+ `);
3048
+ } else {
3049
+ yield* bodiesOf(child);
3050
+ }
3051
+ } else if (isFunction && (key === "getter" || key === "setter") && isJsonObject(child)) {
3052
+ if (isString2(child.body)) {
3053
+ yield child.body;
3054
+ }
3055
+ } else {
3056
+ yield* bodiesOf(child);
3057
+ }
3058
+ }
3059
+ }
3060
+ async function prepareBodies(doc) {
3061
+ const load = loader;
3062
+ if (eraser || !load) {
3063
+ return;
3064
+ }
3065
+ const tree = doc;
3066
+ if (!bodiesOf(tree).some((body) => bodyNeedsEraser(body))) {
3067
+ return;
3068
+ }
3069
+ await fetchEraser(load);
3070
+ }
3071
+ function javaScriptOf(body, where) {
3072
+ if (!eraser) {
3073
+ return body;
3074
+ }
3075
+ let code = erased.get(body);
3076
+ if (code === undefined) {
3077
+ const result = eraser(body);
3078
+ const refused = result.problems.find((problem) => problem.kind === "unsupported");
3079
+ if (refused) {
3080
+ throw new SyntaxError(`Jx: ${where} cannot run: ${refused.message}`);
3081
+ }
3082
+ ({ code } = result);
3083
+ erased.set(body, code);
3084
+ }
3085
+ return code;
3086
+ }
3087
+ function compileBody(params, body, where) {
3088
+ const code = javaScriptOf(body, where);
3089
+ try {
3090
+ return new Function(...params, code);
3091
+ } catch (error) {
3092
+ if (!(error instanceof SyntaxError) || eraser) {
3093
+ throw error;
3094
+ }
3095
+ throw new SyntaxError(`Jx: ${where} does not compile as JavaScript (${error.message}). A function body may be ` + `TypeScript: give this page an eraser with setBodyEraser(eraseBody), eraseBody from ` + `@jxsuite/erase/browser.`, { cause: error });
3096
+ }
3097
+ }
3098
+
3099
+ // ../schema/src/document-scripts.ts
3100
+ var SCRIPT_SPECIFIER_PREFIX = "jx-script:";
3101
+ var CLIENT_SCRIPT_REF = "#client";
3102
+ var SERVER_SCRIPT_REF = "#server";
3103
+ var TYPESCRIPT_PATH = /\.[cm]?ts$/iu;
3104
+ function isTypeScriptPath(pathname) {
3105
+ return TYPESCRIPT_PATH.test(pathname);
3106
+ }
3107
+ function scriptRefSide(src) {
3108
+ if (src === CLIENT_SCRIPT_REF) {
3109
+ return "client";
3110
+ }
3111
+ if (src === SERVER_SCRIPT_REF) {
3112
+ return "server";
3113
+ }
3114
+ return null;
3115
+ }
3116
+ function normalizedPath(path) {
3117
+ return path.replaceAll("\\", "/").replace(/^(?:\.\/)+/, "");
3118
+ }
3119
+ function scriptSpecifier(path, side) {
3120
+ return `${SCRIPT_SPECIFIER_PREFIX}${normalizedPath(path)}#${side}`;
3121
+ }
3122
+ function isScriptSpecifier(src) {
3123
+ return src.startsWith(SCRIPT_SPECIFIER_PREFIX);
3124
+ }
3125
+ function parseScriptSpecifier(src) {
3126
+ if (!isScriptSpecifier(src)) {
3127
+ return null;
3128
+ }
3129
+ const rest = src.slice(SCRIPT_SPECIFIER_PREFIX.length);
3130
+ const hash = rest.lastIndexOf("#");
3131
+ if (hash <= 0) {
3132
+ return null;
3133
+ }
3134
+ const side = rest.slice(hash + 1);
3135
+ if (side !== "client" && side !== "server") {
3136
+ return null;
3137
+ }
3138
+ return { path: rest.slice(0, hash), side };
3139
+ }
3140
+ function qualifiedValue(value, path) {
3141
+ if (Array.isArray(value)) {
3142
+ const items = value.map((item) => qualifiedValue(item, path));
3143
+ return items.some((item, index) => item !== value[index]) ? items : value;
3144
+ }
3145
+ if (!isJsonObject(value)) {
3146
+ return value;
3147
+ }
3148
+ let copy = null;
3149
+ for (const [key, member] of Object.entries(value)) {
3150
+ let next = member;
3151
+ if (key === "$src" && isString2(member)) {
3152
+ const side = scriptRefSide(member);
3153
+ next = side === null ? member : scriptSpecifier(path, side);
3154
+ } else if (key !== "$script") {
3155
+ next = qualifiedValue(member, path);
3156
+ }
3157
+ if (next !== member) {
3158
+ copy ??= { ...value };
3159
+ copy[key] = next;
3160
+ }
3161
+ }
3162
+ return copy === null ? value : copy;
3163
+ }
3164
+ function qualifyScripts(doc, path) {
3165
+ return qualifiedValue(doc, path);
3166
+ }
3167
+
2704
3168
  // src/cookie.ts
2705
3169
  var HOST_PREFIX = "__Host-";
2706
3170
  var SECURE_PREFIX = "__Secure-";
@@ -2739,7 +3203,6 @@ function serializeCookie(name, value, options) {
2739
3203
  }
2740
3204
  return parts.join("; ");
2741
3205
  }
2742
-
2743
3206
  // src/runtime.ts
2744
3207
  var SUPPORTED_SCHEMA_VERSION = 1;
2745
3208
  var _schemaVersionWarned = false;
@@ -2783,10 +3246,11 @@ function assertHostScope(scope) {
2783
3246
  }
2784
3247
  }
2785
3248
  }
2786
- async function mount(doc, target, options = {}) {
3249
+ async function mount(source, target, options = {}) {
2787
3250
  const hostScope = options.scope ? hostScopeOf(options.scope) : {};
2788
3251
  assertHostScope(hostScope);
2789
3252
  const base = options.base ? new URL(options.base, location.href).href : location.href;
3253
+ const doc = inlineDocument(source, base);
2790
3254
  const ctx = {
2791
3255
  base,
2792
3256
  media: options.media ?? doc.$media ?? null,
@@ -2822,6 +3286,15 @@ async function mount(doc, target, options = {}) {
2822
3286
  if (options.onNodeMoved) {
2823
3287
  renderOptions.onNodeMoved = options.onNodeMoved;
2824
3288
  }
3289
+ if (options.rowLimit !== undefined) {
3290
+ renderOptions.rowLimit = options.rowLimit;
3291
+ }
3292
+ if (options.emptyRow) {
3293
+ renderOptions.emptyRow = options.emptyRow;
3294
+ }
3295
+ if (options.onListReconciled) {
3296
+ renderOptions.onListReconciled = options.onListReconciled;
3297
+ }
2825
3298
  const { result: root, stop } = runScoped(() => renderNode(doc, scope, renderOptions));
2826
3299
  ctx.root = root;
2827
3300
  let mounted = false;
@@ -2863,16 +3336,17 @@ function responseContentType(res) {
2863
3336
  }
2864
3337
  async function resolve(source, ctx) {
2865
3338
  if (!isString2(source)) {
3339
+ await prepareBodies(source);
2866
3340
  return source;
2867
3341
  }
2868
3342
  const served = ctx?.resolver?.(source);
2869
3343
  if (served) {
2870
- return served;
3344
+ return withOwnScripts(await served, source);
2871
3345
  }
2872
3346
  if (_resolveCache.has(source)) {
2873
3347
  return _resolveCache.get(source);
2874
3348
  }
2875
- const p = fetch(source).then(async (res) => {
3349
+ const fetched = fetch(source).then(async (res) => {
2876
3350
  if (!res.ok) {
2877
3351
  throw new Error(`Jx: failed to fetch ${source} (${res.status})`);
2878
3352
  }
@@ -2888,6 +3362,11 @@ async function resolve(source, ctx) {
2888
3362
  }
2889
3363
  return await res.json();
2890
3364
  });
3365
+ const p = fetched.then(async (read) => {
3366
+ const doc = withOwnScripts(read, source);
3367
+ await prepareBodies(doc);
3368
+ return doc;
3369
+ });
2891
3370
  _resolveCache.set(source, p);
2892
3371
  return p;
2893
3372
  }
@@ -2917,6 +3396,10 @@ var _autoRequestConfig = { skip: false };
2917
3396
  function setSkipAutoRequests(v) {
2918
3397
  _autoRequestConfig.skip = v;
2919
3398
  }
3399
+ var _remoteLookupHandler = null;
3400
+ function setRemoteLookupHandler(handler) {
3401
+ _remoteLookupHandler = handler;
3402
+ }
2920
3403
  var _resolveToken = null;
2921
3404
  function setResolveToken(token) {
2922
3405
  _resolveToken = token || null;
@@ -2973,8 +3456,20 @@ function setCanvasDelinkCommands(on) {
2973
3456
  _canvasDelinkCommands = on;
2974
3457
  }
2975
3458
  var _canvasInsideStampedHost = false;
3459
+ function insideStampedHost(inside, fn) {
3460
+ const was = _canvasInsideStampedHost;
3461
+ _canvasInsideStampedHost = inside;
3462
+ try {
3463
+ return fn();
3464
+ } finally {
3465
+ _canvasInsideStampedHost = was;
3466
+ }
3467
+ }
2976
3468
  function canvasStamped(el) {
2977
- return _canvasInsideStampedHost || el.dataset.jxPath !== undefined;
3469
+ return _canvasInsideStampedHost || carriesCanvasStamp(el);
3470
+ }
3471
+ function carriesCanvasStamp(el) {
3472
+ return el.dataset.jxPath !== undefined || el.dataset.jxEchoPath !== undefined;
2978
3473
  }
2979
3474
  function canvasAttrName(el, key) {
2980
3475
  if (_canvasDelinkAnchors && key === "href" && (el.tagName === "A" || el.tagName === "AREA")) {
@@ -3072,7 +3567,8 @@ function boundPropKey(key, val, state) {
3072
3567
  }
3073
3568
  return sub;
3074
3569
  }
3075
- async function buildScope(doc, parentScope = {}, base = location.href, ctx) {
3570
+ async function buildScope(source, parentScope = {}, base = location.href, ctx) {
3571
+ const doc = inlineDocument(source, base);
3076
3572
  const dispatchRoot = () => ctx?.root ?? null;
3077
3573
  const raw = {};
3078
3574
  const defs = doc.state ?? {};
@@ -3159,7 +3655,11 @@ async function buildScope(doc, parentScope = {}, base = location.href, ctx) {
3159
3655
  }
3160
3656
  }
3161
3657
  }
3658
+ const roles = classifyFunctionEntries(doc);
3162
3659
  for (const [key, def] of Object.entries(defs)) {
3660
+ if (isFunctionDef(def) && declaresBodyAndSrc(def)) {
3661
+ throw new Error(`Jx: '${key}' declares both body and $src — these are mutually exclusive`);
3662
+ }
3163
3663
  if (hasStructuredBody(def)) {
3164
3664
  const { body } = def;
3165
3665
  if (Array.isArray(def.parameters) && def.parameters.length > 0) {
@@ -3175,7 +3675,7 @@ async function buildScope(doc, parentScope = {}, base = location.href, ctx) {
3175
3675
  state[key] = handler;
3176
3676
  }
3177
3677
  } else if (isFunctionDef(def)) {
3178
- state[key] = await resolveFunction(def, state, key, base);
3678
+ state[key] = await resolveFunction(def, state, key, roles.get(key) ?? "callable", base);
3179
3679
  }
3180
3680
  }
3181
3681
  for (const [key, def] of Object.entries(defs)) {
@@ -3282,6 +3782,7 @@ function bindTemplate(source, run, fallback) {
3282
3782
  run();
3283
3783
  heldTemplateErrors.delete(run);
3284
3784
  } catch (error) {
3785
+ _templateThrows += 1;
3285
3786
  const thrown = error instanceof Error ? error : new Error(String(error));
3286
3787
  if (_templateErrorHandler) {
3287
3788
  _templateErrorHandler(thrown, source);
@@ -3294,6 +3795,8 @@ function bindTemplate(source, run, fallback) {
3294
3795
  }
3295
3796
  });
3296
3797
  }
3798
+ var _templateThrows = 0;
3799
+ var _listRedraws = 0;
3297
3800
  function rowContext(state) {
3298
3801
  return state.$map;
3299
3802
  }
@@ -3301,19 +3804,8 @@ function isSingleExpression(str) {
3301
3804
  if (!str.startsWith("${") || !str.endsWith("}")) {
3302
3805
  return false;
3303
3806
  }
3304
- let depth = 0;
3305
- for (let i = 1;i < str.length; i += 1) {
3306
- const c = str[i];
3307
- if (c === "{") {
3308
- depth += 1;
3309
- } else if (c === "}") {
3310
- depth -= 1;
3311
- if (depth === 0) {
3312
- return i === str.length - 1;
3313
- }
3314
- }
3315
- }
3316
- return false;
3807
+ const [only, ...more] = templateExpressions(str);
3808
+ return only !== undefined && more.length === 0 && only.start === 0 && only.end === str.length;
3317
3809
  }
3318
3810
  function evaluateValueTemplate(str, state) {
3319
3811
  if (!isSingleExpression(str)) {
@@ -3326,6 +3818,9 @@ function evaluateValueTemplate(str, state) {
3326
3818
  }
3327
3819
  return fn(...templateArgs(state));
3328
3820
  }
3821
+ function evaluateTemplateValue(str, scope) {
3822
+ return evaluateValueTemplate(str, scope);
3823
+ }
3329
3824
  var _npmModuleResolver = null;
3330
3825
  function setNpmModuleResolver(resolver) {
3331
3826
  _npmModuleResolver = resolver;
@@ -3336,6 +3831,13 @@ async function importSource(src, base) {
3336
3831
  const specifier = src.slice(NPM_SCHEME.length);
3337
3832
  return importModule(_npmModuleResolver?.(specifier) ?? specifier);
3338
3833
  }
3834
+ const typed = typeScriptSource(src, base);
3835
+ if (typed !== null && (canLoadModules() || isScriptSpecifier(src))) {
3836
+ const loaded = await importTypeScript(typed, src, base);
3837
+ if (loaded) {
3838
+ return loaded;
3839
+ }
3840
+ }
3339
3841
  if (base) {
3340
3842
  try {
3341
3843
  return await importModule(new URL(src, base).href);
@@ -3345,6 +3847,70 @@ async function importSource(src, base) {
3345
3847
  }
3346
3848
  return importModule(src);
3347
3849
  }
3850
+ var FETCHED_SCHEMES = new Set(["http:", "https:"]);
3851
+ function typeScriptSource(src, base) {
3852
+ if (isScriptSpecifier(src)) {
3853
+ return src;
3854
+ }
3855
+ if (scriptRefSide(src) !== null) {
3856
+ throw new Error(`Jx: $src "${src}" names the script of the document it is written in, and that document ` + `has no $script`);
3857
+ }
3858
+ const from = base ?? location.href;
3859
+ if (!URL.canParse(src, from)) {
3860
+ return null;
3861
+ }
3862
+ const url = new URL(src, from);
3863
+ return FETCHED_SCHEMES.has(url.protocol) && isTypeScriptPath(url.pathname) ? url.href : null;
3864
+ }
3865
+ async function importTypeScript(specifier, src, base) {
3866
+ const load = await moduleLoaderFor();
3867
+ if (load) {
3868
+ const module = await load(specifier, {
3869
+ base,
3870
+ resolveNpm: _npmModuleResolver,
3871
+ text: _documentScripts.get(src)
3872
+ });
3873
+ return module;
3874
+ }
3875
+ if (isScriptSpecifier(src)) {
3876
+ throw new Error(`Jx: ${parseScriptSpecifier(src)?.path ?? src} has a script, and this page has nothing ` + `that can load one. Give it a module loader with setModuleLoader(loadModule), loadModule ` + `from @jxsuite/erase/browser, or let setBodyEraserLoader fetch that file when it is needed.`);
3877
+ }
3878
+ return null;
3879
+ }
3880
+ var _documentScripts = new Map;
3881
+ function withOwnScripts(doc, source) {
3882
+ if (!doc.$script) {
3883
+ return doc;
3884
+ }
3885
+ const address = URL.canParse(source, location.href) ? new URL(source, location.href).href : source;
3886
+ const { client } = doc.$script;
3887
+ const specifier = scriptSpecifier(address, "client");
3888
+ if (isString2(client) && _documentScripts.get(specifier) !== client) {
3889
+ if (_documentScripts.has(specifier) && !_hostSeeded.has(specifier)) {
3890
+ _moduleCache.delete(specifier);
3891
+ }
3892
+ _documentScripts.set(specifier, client);
3893
+ }
3894
+ const own = qualifyScripts(doc, address);
3895
+ _addressed.set(own, own);
3896
+ return own;
3897
+ }
3898
+ var _addressed = new WeakMap;
3899
+ var _inlineCount = 0;
3900
+ function inlineDocument(doc, base) {
3901
+ if (!doc.$script) {
3902
+ return doc;
3903
+ }
3904
+ let own = _addressed.get(doc);
3905
+ if (!own) {
3906
+ _inlineCount += 1;
3907
+ const address = new URL(base, location.href);
3908
+ address.hash = `jx-inline-${_inlineCount}`;
3909
+ own = withOwnScripts(doc, address.href);
3910
+ _addressed.set(doc, own);
3911
+ }
3912
+ return own;
3913
+ }
3348
3914
  function importModule(specifier) {
3349
3915
  return import(specifier);
3350
3916
  }
@@ -3388,12 +3954,31 @@ function seededModule(src) {
3388
3954
  _moduleLoaders.set(src, load);
3389
3955
  return load;
3390
3956
  }
3391
- async function resolveFunction(def, state, key, base) {
3392
- if (def.body && def.$src) {
3393
- throw new Error(`Jx: '${key}' declares both body and $src — these are mutually exclusive`);
3957
+ function acquireModule(src, base) {
3958
+ const seeded = seededModule(src);
3959
+ if (seeded) {
3960
+ return seeded;
3961
+ }
3962
+ const loading = importSource(src, base);
3963
+ loading.then((mod) => {
3964
+ _moduleCache.set(src, mod);
3965
+ }, () => {});
3966
+ return loading;
3967
+ }
3968
+ function exportedFunction(def, key, src, mod) {
3969
+ const exportName = def.$export ?? key;
3970
+ const candidate = mod[exportName] ?? mod.default?.[exportName];
3971
+ if (!isFunction2(candidate)) {
3972
+ throw new TypeError(`Jx: export "${exportName}" not found or not a function in "${src}"`);
3394
3973
  }
3974
+ return candidate;
3975
+ }
3976
+ async function importFunctionExport(def, key, src, base) {
3977
+ return exportedFunction(def, key, src, await acquireModule(src, base));
3978
+ }
3979
+ async function resolveFunction(def, state, key, role, base) {
3395
3980
  if (!def.body && !def.$src) {
3396
- const params = resolveParamNames(def);
3981
+ const params = handlerParamNames(def);
3397
3982
  const noop = new Function(...params, "");
3398
3983
  Object.defineProperty(noop, "name", {
3399
3984
  configurable: true,
@@ -3403,48 +3988,37 @@ async function resolveFunction(def, state, key, base) {
3403
3988
  }
3404
3989
  let fn;
3405
3990
  if (isString2(def.body)) {
3406
- const params = resolveParamNames(def);
3407
- fn = new Function(...params, def.body);
3991
+ const params = handlerParamNames(def);
3992
+ fn = compileBody(params, def.body, `'${key}'`);
3993
+ Object.defineProperty(fn, "name", {
3994
+ configurable: true,
3995
+ value: def.name ?? key
3996
+ });
3997
+ } else if (def.$lazy === true && def.$src) {
3998
+ const { $src: src } = def;
3999
+ if (role === "computed") {
4000
+ throw new Error(`Jx: "${key}" declares "$lazy": true but is used as a computed value, not called. A lazily loaded function resolves to a promise; a computed must resolve now. Remove "$lazy", or call ${key}() from a handler instead of binding its value.`);
4001
+ }
4002
+ let loaded;
4003
+ const load = () => loaded ??= importFunctionExport(def, key, src, base);
4004
+ fn = (...args) => load().then((target) => target(...args));
3408
4005
  Object.defineProperty(fn, "name", {
3409
4006
  configurable: true,
3410
4007
  value: def.name ?? key
3411
4008
  });
4009
+ return fn;
3412
4010
  } else {
3413
- const src = def.$src;
3414
- if (!src) {
4011
+ if (!def.$src) {
3415
4012
  throw new Error(`Jx: '${key}' has neither body nor $src`);
3416
4013
  }
3417
- const exportName = def.$export ?? key;
3418
- let mod;
3419
- const seeded = seededModule(src);
3420
- if (seeded instanceof Promise) {
3421
- mod = await seeded;
3422
- } else if (seeded) {
3423
- mod = seeded;
3424
- } else {
3425
- mod = await importSource(src, base);
3426
- _moduleCache.set(src, mod);
3427
- }
3428
- const candidate = mod[exportName] ?? mod.default?.[exportName];
3429
- if (!isFunction2(candidate)) {
3430
- throw new TypeError(`Jx: export "${exportName}" not found or not a function in "${src}"`);
3431
- }
3432
- fn = candidate;
3433
- }
3434
- const hasParams = (def.parameters ?? def.arguments ?? []).length > 0;
3435
- let isComputed = false;
3436
- if (!hasParams) {
3437
- isComputed = isString2(def.body) ? bodyReturnsValue(def.body) : fn.length <= 1 && bodyReturnsValue(fn.toString());
4014
+ const acquired = acquireModule(def.$src, base);
4015
+ fn = exportedFunction(def, key, def.$src, acquired instanceof Promise ? await acquired : acquired);
3438
4016
  }
3439
- if (isComputed) {
4017
+ if (role === "computed") {
3440
4018
  return computed(() => fn(state));
3441
4019
  }
3442
4020
  return fn;
3443
4021
  }
3444
- function resolveParamNames(def) {
3445
- const names = def.parameters ? paramNames(def.parameters) : def.arguments ?? [];
3446
- return names.length > 0 && names[0] === "state" ? names : ["state", ...names];
3447
- }
3448
4022
  var RESERVED_KEYS = new Set([
3449
4023
  "$schema",
3450
4024
  "$id",
@@ -3459,6 +4033,7 @@ var RESERVED_KEYS = new Set([
3459
4033
  "$prototype",
3460
4034
  "$src",
3461
4035
  "$export",
4036
+ "$script",
3462
4037
  "$media",
3463
4038
  "$map",
3464
4039
  "timing",
@@ -3593,6 +4168,8 @@ function renderNode(def, state, options) {
3593
4168
  const childOpts = options || childNs ? { ...options, _ns: childNs, _path: [...path, "children", i] } : undefined;
3594
4169
  if (isMappedArray(child)) {
3595
4170
  renderMappedArrayInto(el, child, localState, childOpts);
4171
+ } else if (isString2(child) && isSingleExpression(child)) {
4172
+ renderTemplatedChild(el, child, localState, childOpts);
3596
4173
  } else {
3597
4174
  el.append(renderNode(child, localState, childOpts));
3598
4175
  }
@@ -3607,7 +4184,6 @@ function renderNode(def, state, options) {
3607
4184
  return el;
3608
4185
  }
3609
4186
  function renderComputedChildren(el, template, state, options) {
3610
- const path = options._path ?? [];
3611
4187
  let live = null;
3612
4188
  const retire = () => {
3613
4189
  el.replaceChildren();
@@ -3620,21 +4196,62 @@ function renderComputedChildren(el, template, state, options) {
3620
4196
  if (!Array.isArray(nodes)) {
3621
4197
  return;
3622
4198
  }
3623
- const scope = effectScope(true);
3624
- live = scope;
3625
- pauseTracking();
3626
- try {
3627
- scope.run(() => {
3628
- for (const [i, child] of nodes.entries()) {
3629
- el.append(renderNode(child, state, { ...options, _path: [...path, i] }));
3630
- }
3631
- });
3632
- } finally {
3633
- resetTracking();
3634
- }
4199
+ live = effectScope(true);
4200
+ drawTemplateNodes(live, nodes, state, options, (node) => {
4201
+ el.append(node);
4202
+ });
3635
4203
  }, retire);
3636
4204
  onScopeDispose(() => live?.stop(), true);
3637
4205
  }
4206
+ function drawTemplateNodes(scope, nodes, state, options, place) {
4207
+ const path = options?._path ?? [];
4208
+ const members = [...nodes];
4209
+ pauseTracking();
4210
+ try {
4211
+ scope.run(() => {
4212
+ for (const [i, child] of members.entries()) {
4213
+ place(renderNode(child, state, options ? { ...options, _path: [...path, i] } : undefined));
4214
+ }
4215
+ });
4216
+ } finally {
4217
+ resetTracking();
4218
+ }
4219
+ }
4220
+ function renderTemplatedChild(parent, template, state, options) {
4221
+ const anchor = document.createTextNode(template);
4222
+ parent.append(anchor);
4223
+ let live = null;
4224
+ let drawn = [];
4225
+ const retire = () => {
4226
+ for (const node of drawn) {
4227
+ node.remove();
4228
+ }
4229
+ drawn = [];
4230
+ live?.stop();
4231
+ live = null;
4232
+ };
4233
+ bindTemplate(template, () => {
4234
+ const value = evaluateValueTemplate(template, state);
4235
+ retire();
4236
+ if (!Array.isArray(value)) {
4237
+ anchor.textContent = templateText(value);
4238
+ return;
4239
+ }
4240
+ anchor.textContent = "";
4241
+ live = effectScope(true);
4242
+ drawTemplateNodes(live, value, state, options, (node) => {
4243
+ drawn.push(node);
4244
+ anchor.before(node);
4245
+ });
4246
+ }, () => {
4247
+ retire();
4248
+ anchor.textContent = "";
4249
+ });
4250
+ onScopeDispose(() => live?.stop(), true);
4251
+ }
4252
+ function templateText(value) {
4253
+ return `${value}`;
4254
+ }
3638
4255
  function applyProperties(el, def, state) {
3639
4256
  for (const [key, val] of Object.entries(def)) {
3640
4257
  if (RESERVED_KEYS.has(key)) {
@@ -3659,6 +4276,9 @@ function bindHandler(el, key, val, state) {
3659
4276
  }
3660
4277
  return true;
3661
4278
  }
4279
+ if (isFunctionDef(val) && declaresBodyAndSrc(val)) {
4280
+ throw new Error(`Jx: inline '${key}' handler declares both body and $src — these are mutually exclusive`);
4281
+ }
3662
4282
  if (hasStructuredBody(val)) {
3663
4283
  const { body } = val;
3664
4284
  el.addEventListener(type, (e) => {
@@ -3667,8 +4287,8 @@ function bindHandler(el, key, val, state) {
3667
4287
  return true;
3668
4288
  }
3669
4289
  if (isFunctionDef(val) && isString2(val.body)) {
3670
- const params = resolveParamNames(val);
3671
- const fn = new Function(...params, val.body);
4290
+ const params = handlerParamNames(val);
4291
+ const fn = compileBody(params, val.body, `the ${type} handler`);
3672
4292
  el.addEventListener(type, (e) => fn(scope, e));
3673
4293
  return true;
3674
4294
  }
@@ -4005,10 +4625,14 @@ function applyStyleInto(el, styleDef, mediaQueries, state, live) {
4005
4625
  const scope = effectScope();
4006
4626
  scope.run(() => {
4007
4627
  for (const { name, value } of sources) {
4008
- effect(() => {
4009
- const resolved = isRef2(value) ? resolveRef(value.$ref, state) : evaluateTemplate(value, state);
4628
+ const write = (resolved) => {
4010
4629
  el.style.setProperty(name, canvasStyleValue(String(resolved ?? "")));
4011
- });
4630
+ };
4631
+ if (isRef2(value)) {
4632
+ effect(() => write(resolveRef(value.$ref, state)));
4633
+ } else {
4634
+ bindTemplate(value, () => write(evaluateTemplate(value, state)));
4635
+ }
4012
4636
  }
4013
4637
  });
4014
4638
  entry.stop = () => scope.stop();
@@ -4062,6 +4686,7 @@ function renderMappedArrayInto(parentEl, arrayDef, state, options) {
4062
4686
  const { items: itemsSrc, map: mapDef, filter: filterRef, sort: sortRef, key: keyRef } = arrayDef;
4063
4687
  const keyPointer = isRef2(keyRef) ? keyRef.$ref : null;
4064
4688
  const instancePath = _instancePath;
4689
+ const insideStamped = _canvasInsideStampedHost;
4065
4690
  let warned = false;
4066
4691
  const warnOnce = (message) => {
4067
4692
  if (!warned) {
@@ -4083,7 +4708,9 @@ function renderMappedArrayInto(parentEl, arrayDef, state, options) {
4083
4708
  const scope = effectScope(true);
4084
4709
  const childOpts = options ? { ...options, _path: [...path, "map", index] } : undefined;
4085
4710
  const node = scope.run(() => renderNode(mapDef, child, childOpts));
4086
- return { key, map, node, scope };
4711
+ const row = { key, map, node, scope };
4712
+ listRows.set(node, row);
4713
+ return row;
4087
4714
  };
4088
4715
  const reconcile = (list, keys) => {
4089
4716
  const previous = new Map;
@@ -4138,8 +4765,17 @@ function renderMappedArrayInto(parentEl, arrayDef, state, options) {
4138
4765
  items = [...unsorted].toSorted(compare);
4139
4766
  }
4140
4767
  }
4141
- const list = Array.isArray(items) && mapDef ? items : [];
4142
- const keys = list.map((item, index) => mappedRowKey(keyPointer, item, index, warnOnce));
4768
+ let list = Array.isArray(items) && mapDef ? items : [];
4769
+ const count = list.length;
4770
+ const placeholder = count === 0 && mapDef ? options?.emptyRow?.(arrayDef, path) : undefined;
4771
+ if (placeholder !== undefined) {
4772
+ list = [placeholder];
4773
+ }
4774
+ const limit = options?.rowLimit;
4775
+ if (isNumber(limit) && limit >= 0 && list.length > limit) {
4776
+ list = list.slice(0, Math.floor(limit));
4777
+ }
4778
+ const keys = placeholder === undefined ? list.map((item, index) => mappedRowKey(keyPointer, item, index, warnOnce)) : list.map(() => EMPTY_ROW_KEY);
4143
4779
  const seen = new Set;
4144
4780
  for (let i = 0;i < keys.length; i++) {
4145
4781
  if (seen.has(keys[i])) {
@@ -4151,7 +4787,13 @@ function renderMappedArrayInto(parentEl, arrayDef, state, options) {
4151
4787
  }
4152
4788
  pauseTracking();
4153
4789
  try {
4154
- underInstancePath(reexpand(instancePath), () => reconcile(list, keys));
4790
+ underInstancePath(reexpand(instancePath), () => insideStampedHost(insideStamped, () => reconcile(list, keys)));
4791
+ options?.onListReconciled?.(path, {
4792
+ count,
4793
+ empty: count === 0,
4794
+ nodes: rows.map((row) => row.node),
4795
+ rendered: rows.length
4796
+ });
4155
4797
  } finally {
4156
4798
  resetTracking();
4157
4799
  }
@@ -4160,6 +4802,7 @@ function renderMappedArrayInto(parentEl, arrayDef, state, options) {
4160
4802
  let stopped = false;
4161
4803
  const runner = effect(update, {
4162
4804
  scheduler: () => {
4805
+ _listRedraws += 1;
4163
4806
  if (queued) {
4164
4807
  return;
4165
4808
  }
@@ -4180,6 +4823,21 @@ function renderMappedArrayInto(parentEl, arrayDef, state, options) {
4180
4823
  rows = [];
4181
4824
  }, true);
4182
4825
  }
4826
+ var EMPTY_ROW_KEY = Object.freeze({ emptyRow: true });
4827
+ var listRows = new WeakMap;
4828
+ function replaceListRow(current, next, stop) {
4829
+ const row = listRows.get(current);
4830
+ if (!row || row.node !== current) {
4831
+ return false;
4832
+ }
4833
+ row.node.replaceWith(next);
4834
+ row.scope.stop();
4835
+ listRows.delete(current);
4836
+ row.node = next;
4837
+ row.scope = { stop: () => stop?.() };
4838
+ listRows.set(next, row);
4839
+ return true;
4840
+ }
4183
4841
  function mappedRowKey(pointer, item, index, warnOnce) {
4184
4842
  if (pointer === null) {
4185
4843
  return index;
@@ -4216,6 +4874,7 @@ function renderSwitch(def, state, options) {
4216
4874
  const path = options?._path ?? [];
4217
4875
  const container = document.createElement(resolveTagName(def.tagName, state));
4218
4876
  const instancePath = _instancePath;
4877
+ const insideStamped = _canvasInsideStampedHost;
4219
4878
  if (options?.onNodeCreated) {
4220
4879
  options.onNodeCreated(container, path, def, state);
4221
4880
  }
@@ -4258,18 +4917,18 @@ function renderSwitch(def, state, options) {
4258
4917
  if (gen !== generation) {
4259
4918
  return;
4260
4919
  }
4261
- const childScope = await buildScope(doc, {}, href, options?._ctx);
4920
+ const childScope = await buildScope(withProjectFormulas(doc), {}, href, options?._ctx);
4262
4921
  if (gen !== generation) {
4263
4922
  return;
4264
4923
  }
4265
4924
  container.replaceChildren();
4266
- underInstancePath(reexpand(instancePath), () => scope.run(() => container.append(renderNode(doc, childScope, childOpts))));
4925
+ underInstancePath(reexpand(instancePath), () => insideStampedHost(insideStamped, () => scope.run(() => container.append(renderNode(doc, childScope, childOpts)))));
4267
4926
  }).catch((error) => console.error("Jx $switch: failed to load external case", caseDef.$ref, error));
4268
4927
  return;
4269
4928
  }
4270
4929
  pauseTracking();
4271
4930
  try {
4272
- underInstancePath(reexpand(instancePath), () => scope.run(() => container.append(renderNode(caseDef, state, childOpts))));
4931
+ underInstancePath(reexpand(instancePath), () => insideStampedHost(insideStamped, () => scope.run(() => container.append(renderNode(caseDef, state, childOpts)))));
4273
4932
  } finally {
4274
4933
  resetTracking();
4275
4934
  }
@@ -4305,18 +4964,46 @@ async function resolvePrototype(def, state, key, base, ctx) {
4305
4964
  clearTimeout(debounceTimer);
4306
4965
  }
4307
4966
  });
4967
+ const request = (signal) => fetch(url, {
4968
+ method: def.method ?? "GET",
4969
+ ...signal && { signal },
4970
+ ...def.headers && { headers: def.headers },
4971
+ ...def.body && {
4972
+ body: isNonNullObject(def.body) ? JSON.stringify(def.body) : def.body
4973
+ }
4974
+ }).then((r) => r.ok ? r.json() : Promise.reject(r.statusText));
4308
4975
  const doFetch = () => {
4309
- holdTemplateErrorsFor(fetch(url, {
4310
- method: def.method ?? "GET",
4311
- signal: controller.signal,
4312
- ...def.headers && { headers: def.headers },
4313
- ...def.body && {
4314
- body: isNonNullObject(def.body) ? JSON.stringify(def.body) : def.body
4976
+ const handler = _remoteLookupHandler;
4977
+ let lookup;
4978
+ if (handler) {
4979
+ const answer = handler({
4980
+ key,
4981
+ kind: "request",
4982
+ request: {
4983
+ method: def.method ?? "GET",
4984
+ url,
4985
+ ...def.headers && { headers: def.headers },
4986
+ ...def.body !== undefined && { body: def.body }
4987
+ },
4988
+ scope: state
4989
+ }, () => request());
4990
+ if (answer === null) {
4991
+ return;
4992
+ }
4993
+ if (!(answer instanceof Promise)) {
4994
+ s.value = answer.value;
4995
+ return;
4996
+ }
4997
+ lookup = answer;
4998
+ } else {
4999
+ lookup = request(controller.signal);
5000
+ }
5001
+ holdTemplateErrorsFor(lookup.then((d) => {
5002
+ if (!controller.signal.aborted) {
5003
+ s.value = d;
4315
5004
  }
4316
- }).then((r) => r.ok ? r.json() : Promise.reject(r.statusText)).then((d) => {
4317
- s.value = d;
4318
5005
  }).catch((error) => {
4319
- if (!(error instanceof Error && error.name === "AbortError")) {
5006
+ if (!controller.signal.aborted && !(error instanceof Error && error.name === "AbortError")) {
4320
5007
  s.value = { error: String(error) };
4321
5008
  }
4322
5009
  }));
@@ -4534,6 +5221,7 @@ async function resolveClassJson(def, state, key, base) {
4534
5221
  } catch {
4535
5222
  return resolveViaDevProxy(def, state, key, base);
4536
5223
  }
5224
+ await prepareBodies(classDef);
4537
5225
  if (classDef.$implementation) {
4538
5226
  const schemaStr = JSON.stringify(classDef);
4539
5227
  if (schemaStr.includes('"#/$context/')) {
@@ -4567,6 +5255,7 @@ function classFromSchema(classDef) {
4567
5255
  const rawCtor = classDef.$defs?.constructor;
4568
5256
  const ctor = isCtorDef(rawCtor) ? rawCtor : undefined;
4569
5257
  const methods = classDef.$defs?.methods ?? {};
5258
+ const className = classDef.title ?? "a class";
4570
5259
 
4571
5260
  class DynClass {
4572
5261
  constructor(config = {}) {
@@ -4586,7 +5275,7 @@ function classFromSchema(classDef) {
4586
5275
  if (ctor?.body) {
4587
5276
  const bodyStr = Array.isArray(ctor.body) ? ctor.body.join(`
4588
5277
  `) : ctor.body;
4589
- const init = new Function("config", bodyStr);
5278
+ const init = compileBody(["config"], bodyStr, `the constructor of ${className}`);
4590
5279
  init.call(this, config);
4591
5280
  }
4592
5281
  }
@@ -4605,20 +5294,20 @@ function classFromSchema(classDef) {
4605
5294
  if (typedMethod.role === "accessor") {
4606
5295
  const descriptor = {};
4607
5296
  if (typedMethod.getter) {
4608
- descriptor.get = new Function(typedMethod.getter.body ?? "");
5297
+ descriptor.get = compileBody([], typedMethod.getter.body ?? "", `the getter ${name} of ${className}`);
4609
5298
  }
4610
5299
  if (typedMethod.setter) {
4611
5300
  const sp = (typedMethod.setter.parameters ?? []).map((p) => p.$ref?.split("/").pop() ?? "v");
4612
- descriptor.set = new Function(...sp, typedMethod.setter.body ?? "");
5301
+ descriptor.set = compileBody(sp, typedMethod.setter.body ?? "", `the setter ${name} of ${className}`);
4613
5302
  }
4614
5303
  Object.defineProperty(DynClass.prototype, name, {
4615
5304
  ...descriptor,
4616
5305
  configurable: true
4617
5306
  });
4618
5307
  } else if (typedMethod.scope === "static") {
4619
- DynClass[name] = new Function(...params, bodyStr);
5308
+ DynClass[name] = compileBody(params, bodyStr, `${name} of ${className}`);
4620
5309
  } else {
4621
- DynClass.prototype[name] = new Function(...params, bodyStr);
5310
+ DynClass.prototype[name] = compileBody(params, bodyStr, `${name} of ${className}`);
4622
5311
  }
4623
5312
  }
4624
5313
  Object.defineProperty(DynClass, "name", {
@@ -4665,24 +5354,46 @@ async function resolveViaDevProxy(def, state, key, base) {
4665
5354
  }
4666
5355
  return s;
4667
5356
  }
4668
- function latestServerCall(s, invoke, label) {
5357
+ function latestServerCall(s, invoke, label, describe) {
4669
5358
  let seq = 0;
4670
5359
  return (args) => {
4671
5360
  seq += 1;
4672
5361
  const n = seq;
4673
- holdTemplateErrorsFor(new Promise((settle) => {
5362
+ const run = () => new Promise((settle) => {
4674
5363
  settle(invoke(args));
4675
- }).then((result) => {
5364
+ });
5365
+ const answer = _remoteLookupHandler ? _remoteLookupHandler(describe(args), run) : run();
5366
+ if (answer === null) {
5367
+ return;
5368
+ }
5369
+ if (!(answer instanceof Promise)) {
5370
+ s.value = answer.value;
5371
+ return;
5372
+ }
5373
+ holdTemplateErrorsFor(answer.then((result) => {
4676
5374
  if (n === seq) {
4677
5375
  s.value = result;
4678
5376
  }
4679
5377
  }).catch((error) => {
4680
- if (n === seq) {
5378
+ if (n === seq && !(error instanceof Error && error.name === "AbortError")) {
4681
5379
  console.error(label, error);
4682
5380
  }
4683
5381
  }));
4684
5382
  };
4685
5383
  }
5384
+ function serverLookup(def, state, key, args, base) {
5385
+ return {
5386
+ key,
5387
+ kind: "server",
5388
+ request: {
5389
+ $export: def.$export,
5390
+ $src: def.$src,
5391
+ arguments: args,
5392
+ ...base !== undefined && { $base: base }
5393
+ },
5394
+ scope: state
5395
+ };
5396
+ }
4686
5397
  async function resolveServerFunction(def, state, key, base) {
4687
5398
  const src = def.$src;
4688
5399
  const exportName = def.$export;
@@ -4710,7 +5421,7 @@ async function resolveServerFunction(def, state, key, base) {
4710
5421
  };
4711
5422
  const s = ref(null);
4712
5423
  if (hasReactiveArg) {
4713
- const call = latestServerCall(s, fn, "Jx server function:");
5424
+ const call = latestServerCall(s, fn, "Jx server function:", (args) => serverLookup(def, state, key, args, base));
4714
5425
  effect(() => {
4715
5426
  const args = resolveArgs();
4716
5427
  onEffectCleanup(() => {});
@@ -4747,7 +5458,7 @@ async function resolveServerFunctionViaProxy(def, state, key, base) {
4747
5458
  return r.json();
4748
5459
  });
4749
5460
  const s = ref(null);
4750
- const call = latestServerCall(s, doResolve, "Jx server proxy:");
5461
+ const call = latestServerCall(s, doResolve, "Jx server proxy:", (args) => serverLookup(def, state, key, args, base));
4751
5462
  if (hasReactiveArg) {
4752
5463
  effect(() => {
4753
5464
  const args = resolveArgs();
@@ -4890,6 +5601,23 @@ async function redefineElement(doc, baseUrl) {
4890
5601
  }
4891
5602
  _elementDefs.set(tagName, { base, doc });
4892
5603
  }
5604
+ var _projectFormulas = {};
5605
+ var _withFormulas = new WeakMap;
5606
+ function setProjectFormulas(projectState) {
5607
+ _projectFormulas = inheritableFormulas(projectState);
5608
+ _withFormulas = new WeakMap;
5609
+ }
5610
+ function withProjectFormulas(doc) {
5611
+ const cached = _withFormulas.get(doc);
5612
+ if (cached) {
5613
+ return cached;
5614
+ }
5615
+ const own = doc.state ?? {};
5616
+ const added = Object.entries(_projectFormulas).filter(([key]) => !(key in own));
5617
+ const merged = added.length > 0 ? { ...doc, state: { ...Object.fromEntries(added), ...own } } : doc;
5618
+ _withFormulas.set(doc, merged);
5619
+ return merged;
5620
+ }
4893
5621
  function setRootMedia(map) {
4894
5622
  _rootMedia = map ?? {};
4895
5623
  }
@@ -5036,7 +5764,7 @@ async function defineElement(source, baseUrl) {
5036
5764
  _definedSources.add(base);
5037
5765
  source_ = await resolve(source);
5038
5766
  } else {
5039
- source_ = source;
5767
+ source_ = inlineDocument(source, new URL(base ?? location.href, location.href).href);
5040
5768
  }
5041
5769
  base ??= location.href;
5042
5770
  const { tagName } = source_;
@@ -5053,6 +5781,7 @@ async function defineElement(source, baseUrl) {
5053
5781
  const initialDef = source_;
5054
5782
  const initialBase = base;
5055
5783
  const observedAttrs = initialDef.observedAttributes ?? [];
5784
+ _observedAttributes.set(tagName, observedAttrs);
5056
5785
  const ElementClass = class extends HTMLElement {
5057
5786
  _jxInitialized = false;
5058
5787
  _state = null;
@@ -5070,7 +5799,8 @@ async function defineElement(source, baseUrl) {
5070
5799
  const enclosingPath = _instancePath;
5071
5800
  const supplied = {};
5072
5801
  const live = _elementDefs.get(tagName) ?? { base: initialBase, doc: initialDef };
5073
- const def = live.doc;
5802
+ _connectedDefs.set(this, live.doc);
5803
+ const def = withProjectFormulas(live.doc);
5074
5804
  const defBase = live.base;
5075
5805
  const state = await buildScope(def, {}, defBase, { base: defBase, media: null, root: this });
5076
5806
  for (const attr of observedAttrs) {
@@ -5127,10 +5857,14 @@ async function defineElement(source, baseUrl) {
5127
5857
  reportUnrendered(this, tagName, error instanceof Error ? error : new Error(String(error)));
5128
5858
  return;
5129
5859
  }
5860
+ const declared = live.doc.state ?? {};
5130
5861
  for (const key of Object.keys(def.state ?? {})) {
5131
5862
  if (isPrivateStateKey(key)) {
5132
5863
  continue;
5133
5864
  }
5865
+ if (!(key in declared) && !(key in supplied)) {
5866
+ continue;
5867
+ }
5134
5868
  const native = nativeSetter(this, key);
5135
5869
  Object.defineProperty(this, key, {
5136
5870
  configurable: true,
@@ -5156,7 +5890,7 @@ async function defineElement(source, baseUrl) {
5156
5890
  const children = Array.isArray(def.children) ? def.children : [];
5157
5891
  const draw = () => {
5158
5892
  const wasInside = _canvasInsideStampedHost;
5159
- _canvasInsideStampedHost ||= this.dataset.jxPath !== undefined;
5893
+ _canvasInsideStampedHost ||= carriesCanvasStamp(this);
5160
5894
  let failure = null;
5161
5895
  try {
5162
5896
  underInstancePath(ownPath, () => {
@@ -5246,6 +5980,195 @@ async function defineElement(source, baseUrl) {
5246
5980
  };
5247
5981
  customElements.define(tagName, ElementClass);
5248
5982
  }
5983
+ function writeInstanceProp(el, key, resolved) {
5984
+ const value = isString2(resolved) ? canvasAssetValue(el.tagName, key, resolved) : resolved;
5985
+ elementProperties(el)[key] = value;
5986
+ const instanceState = instanceStateOf(el);
5987
+ if (instanceState && key in HTMLElement.prototype && Object.hasOwn(toRaw(instanceState), key)) {
5988
+ instanceState[key] = value;
5989
+ }
5990
+ }
5991
+ var _observedAttributes = new Map;
5992
+ var _connectedDefs = new WeakMap;
5993
+ function drawnByCurrent(el) {
5994
+ const drawn = _connectedDefs.get(el);
5995
+ return drawn !== undefined && drawn === _elementDefs.get(el.localName)?.doc;
5996
+ }
5997
+ function producedElsewhere(entry) {
5998
+ if (!isJsonObject(entry)) {
5999
+ return false;
6000
+ }
6001
+ const { $prototype: prototype } = entry;
6002
+ if (prototype !== undefined) {
6003
+ return prototype !== "Function";
6004
+ }
6005
+ return "$src" in entry || "timing" in entry;
6006
+ }
6007
+ function isScalarProp(value) {
6008
+ return isString2(value) && !isTemplateString(value) || isNumber(value) || isBoolean(value);
6009
+ }
6010
+ var VERBATIM_PROPS = new Set(["id", "lang", "role", "slot", "title"]);
6011
+ function isBoundProp(value) {
6012
+ return isRef2(value) || isTemplateString(value);
6013
+ }
6014
+ function rendersOnce(def, drawing = new Set) {
6015
+ const declared = def.state ?? {};
6016
+ if ("onMount" in declared || Object.values(declared).some((entry) => producedElsewhere(entry))) {
6017
+ return true;
6018
+ }
6019
+ drawing.add(def);
6020
+ const walk = (value, isRoot, redrawn) => {
6021
+ if (Array.isArray(value)) {
6022
+ return value.some((item) => walk(item, false, redrawn));
6023
+ }
6024
+ if (!isNonNullObject(value)) {
6025
+ return false;
6026
+ }
6027
+ const node = Object.fromEntries(Object.entries(value));
6028
+ const { attributes, tagName } = node;
6029
+ if (tagName !== undefined && !isString2(tagName)) {
6030
+ return true;
6031
+ }
6032
+ const attrs = isJsonObject(attributes) ? attributes : {};
6033
+ if (tagName === "slot" && (redrawn || isBoundProp(attrs.name) || isBoundProp(node.name) || isBoundProp(node.textContent) || node.$switch !== undefined)) {
6034
+ return true;
6035
+ }
6036
+ if (isBoundProp(node.innerHTML) || !isRoot && isBoundProp(node.children)) {
6037
+ return true;
6038
+ }
6039
+ const isInstance = !isRoot && isString2(tagName) && tagName.includes("-");
6040
+ const inner = isInstance ? _elementDefs.get(tagName)?.doc : undefined;
6041
+ if (isInstance && handsOverOnce(node, attrs, inner)) {
6042
+ return true;
6043
+ }
6044
+ if (inner && (drawing.has(inner) || rendersOnce(inner, drawing))) {
6045
+ return true;
6046
+ }
6047
+ for (const [key, entry] of Object.entries(node)) {
6048
+ if (isRoot && (key === "state" || key === "$props")) {
6049
+ continue;
6050
+ }
6051
+ if (key === "$props") {
6052
+ if (!isInstance && isJsonObject(entry) && Object.values(entry).some((v) => isRef2(v))) {
6053
+ return true;
6054
+ }
6055
+ continue;
6056
+ }
6057
+ if ((key === "id" || key.startsWith("$") && !RESERVED_KEYS.has(key)) && isRef2(entry)) {
6058
+ return true;
6059
+ }
6060
+ const drawn = key === "cases" && isJsonObject(entry) ? Object.values(entry) : entry;
6061
+ if (walk(drawn, false, redrawn || key === "cases" || key === "map")) {
6062
+ return true;
6063
+ }
6064
+ }
6065
+ return false;
6066
+ };
6067
+ const answer = walk(def, true, false);
6068
+ drawing.delete(def);
6069
+ return answer;
6070
+ }
6071
+ function handsOverOnce(node, attrs, inner) {
6072
+ if (isBoundProp(node.textContent)) {
6073
+ return true;
6074
+ }
6075
+ const kids = Array.isArray(node.children) ? node.children : [];
6076
+ if (kids.some((kid) => isBoundProp(kid) || isMappedArray(kid) || isJsonObject(kid) && (isBoundProp(kid.slot) || isJsonObject(kid.attributes) && isBoundProp(kid.attributes.slot)))) {
6077
+ return true;
6078
+ }
6079
+ const coerced = (given) => Object.entries(given).some(([key, value]) => isBoundProp(value) && (key in HTMLElement.prototype) && key !== "textContent");
6080
+ if (coerced(node) || isJsonObject(node.$props) && coerced(node.$props)) {
6081
+ return true;
6082
+ }
6083
+ const observed = isString2(node.tagName) ? _observedAttributes.get(node.tagName) ?? [] : [];
6084
+ return Object.entries(attrs).some(([name, given]) => {
6085
+ if (!isBoundProp(given)) {
6086
+ return false;
6087
+ }
6088
+ if (name.startsWith("props.")) {
6089
+ return true;
6090
+ }
6091
+ const prop = name.replaceAll(/-([a-z])/g, (_, c) => c.toUpperCase());
6092
+ return !inner || prop in (inner.state ?? {}) && !observed.includes(name);
6093
+ });
6094
+ }
6095
+ function mountedFromProps(host, state) {
6096
+ if (isScopeHook(state.onMount) || !drawnByCurrent(host)) {
6097
+ return true;
6098
+ }
6099
+ for (const inner of host.querySelectorAll("*")) {
6100
+ const innerState = instanceStateOf(inner);
6101
+ if (!innerState || !isScopeHook(innerState.onMount) && drawnByCurrent(inner)) {
6102
+ continue;
6103
+ }
6104
+ let owner = inner;
6105
+ while (owner && owner !== host && owner.dataset.jxPath === undefined) {
6106
+ owner = owner.parentElement;
6107
+ }
6108
+ if (owner === host) {
6109
+ return true;
6110
+ }
6111
+ }
6112
+ return false;
6113
+ }
6114
+ function updateInstanceProps(el, before, after) {
6115
+ const state = instanceStateOf(el);
6116
+ const registered = _elementDefs.get(el.localName)?.doc;
6117
+ if (!state || !registered) {
6118
+ return false;
6119
+ }
6120
+ const def = withProjectFormulas(registered);
6121
+ const defaults = declaredDefaults(def);
6122
+ const declared = def.state ?? {};
6123
+ const observed = _observedAttributes.get(el.localName) ?? [];
6124
+ const writes = [];
6125
+ for (const key of new Set([...Object.keys(before ?? {}), ...Object.keys(after ?? {})])) {
6126
+ const was = before?.[key];
6127
+ const now = after?.[key];
6128
+ if (isPrivateStateKey(key) || JSON.stringify(was) === JSON.stringify(now)) {
6129
+ continue;
6130
+ }
6131
+ if (was !== undefined && !isScalarProp(was) || now !== undefined && !isScalarProp(now) || producedElsewhere(declared[key]) || key in declared && !isScalarProp(toRaw(state)[key]) || key === "_state" || key === "_jxInitialized") {
6132
+ return false;
6133
+ }
6134
+ if (key in HTMLElement.prototype && !(VERBATIM_PROPS.has(key) && (key in declared) && isString2(now))) {
6135
+ return false;
6136
+ }
6137
+ if (now !== undefined) {
6138
+ writes.push(() => {
6139
+ writeInstanceProp(el, key, now);
6140
+ });
6141
+ continue;
6142
+ }
6143
+ if (!(key in declared)) {
6144
+ writes.push(() => {
6145
+ Reflect.deleteProperty(el, key);
6146
+ });
6147
+ continue;
6148
+ }
6149
+ const fallback = defaults.get(key);
6150
+ const attribute = key.replaceAll(/[A-Z]/gu, (c) => `-${c.toLowerCase()}`);
6151
+ if (!isScalarProp(fallback) || observed.includes(attribute) && el.hasAttribute(attribute)) {
6152
+ return false;
6153
+ }
6154
+ writes.push(() => {
6155
+ state[key] = fallback;
6156
+ });
6157
+ }
6158
+ if (writes.length === 0 || mountedFromProps(el, state) || rendersOnce(def)) {
6159
+ return false;
6160
+ }
6161
+ const thrown = _templateThrows;
6162
+ const redraws = _listRedraws;
6163
+ try {
6164
+ for (const write of writes) {
6165
+ write();
6166
+ }
6167
+ } catch {
6168
+ return false;
6169
+ }
6170
+ return _templateThrows === thrown && _listRedraws === redraws;
6171
+ }
5249
6172
  function renderCustomElementWithProps(def, state, options, path) {
5250
6173
  const el = document.createElement(resolveTagName(def.tagName, state));
5251
6174
  if (options?.onNodeCreated) {
@@ -5256,12 +6179,7 @@ function renderCustomElementWithProps(def, state, options, path) {
5256
6179
  continue;
5257
6180
  }
5258
6181
  const write = (resolved) => {
5259
- const value = isString2(resolved) ? canvasAssetValue(el.tagName, key, resolved) : resolved;
5260
- elementProperties(el)[key] = value;
5261
- const instanceState = instanceStateOf(el);
5262
- if (instanceState && key in HTMLElement.prototype && Object.hasOwn(toRaw(instanceState), key)) {
5263
- instanceState[key] = value;
5264
- }
6182
+ writeInstanceProp(el, key, resolved);
5265
6183
  };
5266
6184
  if (isRef2(val)) {
5267
6185
  const refVal = val;
@@ -5289,6 +6207,8 @@ function renderCustomElementWithProps(def, state, options, path) {
5289
6207
  const childOpts = options && path ? { ...options, _path: [...path, "children", i] } : undefined;
5290
6208
  if (isMappedArray(child)) {
5291
6209
  renderMappedArrayInto(el, child, state, childOpts);
6210
+ } else if (isString2(child) && isSingleExpression(child)) {
6211
+ renderTemplatedChild(el, child, state, childOpts);
5292
6212
  } else {
5293
6213
  el.append(renderNode(child, state, childOpts));
5294
6214
  }
@@ -5397,6 +6317,7 @@ export {
5397
6317
  SUPPORTED_SCHEMA_VERSION,
5398
6318
  _resetPrivatePropWarnings,
5399
6319
  applyStyle,
6320
+ bodyNeedsEraser,
5400
6321
  booleanAttrValue,
5401
6322
  buildScope,
5402
6323
  buildStyleRules,
@@ -5410,6 +6331,7 @@ export {
5410
6331
  documentStyleText,
5411
6332
  elementDefinition,
5412
6333
  enumeratedAttrNames,
6334
+ evaluateTemplateValue,
5413
6335
  hasSchemaKeywords,
5414
6336
  hashCss,
5415
6337
  isDeclarationAtRule,
@@ -5422,11 +6344,13 @@ export {
5422
6344
  observeScope,
5423
6345
  preloadDocument,
5424
6346
  preloadModule,
6347
+ prepareBodies,
5425
6348
  pureSchemeOf,
5426
6349
  reapplyStyle,
5427
6350
  redefineElement,
5428
6351
  releaseElementStyles,
5429
6352
  renderNode,
6353
+ replaceListRow,
5430
6354
  resetDocumentStyles,
5431
6355
  resolve,
5432
6356
  resolveAtQuery,
@@ -5436,13 +6360,18 @@ export {
5436
6360
  resolveTagName,
5437
6361
  runScoped,
5438
6362
  schemeSelectors,
6363
+ setBodyEraser,
6364
+ setBodyEraserLoader,
5439
6365
  setCanvasAssetResolver,
5440
6366
  setCanvasDelinkAnchors,
5441
6367
  setCanvasDelinkCommands,
5442
6368
  setCanvasDelinkPopovers,
5443
6369
  setCanvasViewportTranspose,
5444
6370
  setDocumentParser,
6371
+ setModuleLoader,
5445
6372
  setNpmModuleResolver,
6373
+ setProjectFormulas,
6374
+ setRemoteLookupHandler,
5446
6375
  setResolveToken,
5447
6376
  setRootMedia,
5448
6377
  setSkipAutoRequests,
@@ -5454,8 +6383,9 @@ export {
5454
6383
  toCSSText,
5455
6384
  transposeCanvasOverlaySelector,
5456
6385
  transposeCanvasPopoverSelector,
5457
- transposeCanvasUnits
6386
+ transposeCanvasUnits,
6387
+ updateInstanceProps
5458
6388
  };
5459
6389
 
5460
- //# debugId=0833DD60FD5CF0CE64756E2164756E21
6390
+ //# debugId=A3ACE1824EF1406664756E2164756E21
5461
6391
  //# sourceMappingURL=runtime.js.map