tutuca 0.9.109 → 0.9.111

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.
@@ -6210,9 +6210,12 @@ function parseRenderEach(px, value, as, attrs) {
6210
6210
  maybeDeprecateBareXDirective(px, "render-each", "when");
6211
6211
  attrParser._parseWhen(when.value);
6212
6212
  }
6213
- const lWith = attrs.getNamedItem("loop-with");
6214
- if (lWith)
6213
+ const lWith = attrs.getNamedItem("@loop-with") ?? attrs.getNamedItem("loop-with");
6214
+ if (lWith) {
6215
+ if (lWith.name.charCodeAt(0) !== 64)
6216
+ maybeDeprecateBareXDirective(px, "render-each", "loop-with");
6215
6217
  attrParser._parseLoopWith(lWith.value);
6218
+ }
6216
6219
  const each = px.addNodeIf(EachNode, seqVal);
6217
6220
  each.iterInfo.whenVal = eachAttr.whenVal ?? null;
6218
6221
  each.iterInfo.loopWithVal = eachAttr.loopWithVal ?? null;
@@ -6726,7 +6729,7 @@ var init_anode = __esm(() => {
6726
6729
  text: xOp([], { wrappable: true, ignoresChildren: true }),
6727
6730
  render: xOp(["as"], { wrappable: true, ignoresChildren: true }),
6728
6731
  "render-it": xOp(["as"], { wrappable: true, ignoresChildren: true }),
6729
- "render-each": xOp(["as", "when", "loop-with", "@when"], {
6732
+ "render-each": xOp(["as", "when", "loop-with", "@when", "@loop-with"], {
6730
6733
  wrappable: true,
6731
6734
  ignoresChildren: true
6732
6735
  }),
@@ -9473,11 +9476,11 @@ function checkConsistentAttrs(lx, Comp, referencedAlters, referencedDynamics) {
9473
9476
  const iter = node.iterInfo;
9474
9477
  if (iter.whenVal)
9475
9478
  checkConsistentAttrVal(lx, iter.whenVal, env, false, {
9476
- originAttr: "<x render-each when>"
9479
+ originAttr: "<x render-each @when>"
9477
9480
  });
9478
9481
  if (iter.loopWithVal)
9479
9482
  checkConsistentAttrVal(lx, iter.loopWithVal, env, false, {
9480
- originAttr: "<x render-each loop-with>"
9483
+ originAttr: "<x render-each @loop-with>"
9481
9484
  });
9482
9485
  }
9483
9486
  }
@@ -9741,7 +9744,7 @@ var init_lint_check = __esm(() => {
9741
9744
  };
9742
9745
  BINDING_MEMBER_TOO_DEEP_RE = /^@[a-zA-Z]\w*\??(\.[a-zA-Z]\w*\??){2,}$/;
9743
9746
  UNSUPPORTED_EXPR_GUIDANCE = {
9744
- ternary: "Ternary expressions aren't supported in dynamic attributes. Define a method or computed field on the component that returns the value, then reference it as '$methodName'.",
9747
+ ternary: "Ternary expressions aren't supported in dynamic attributes. Define a method or computed value on the component that returns the value, then reference it as '$methodName'.",
9745
9748
  comparison: "Comparisons aren't supported in dynamic attributes. Define a method like 'isFooSelected' that returns the boolean, then reference it as '$isFooSelected'.",
9746
9749
  logical: "Logical operators aren't supported in dynamic attributes. Combine the conditions in a method on the component and reference it as '$methodName'.",
9747
9750
  "call-with-args": "Method calls with arguments aren't supported here. Reference a no-arg method ('$methodName') and read what you need from component state, or split into per-case methods.",
@@ -10076,7 +10079,7 @@ var init_lint_rules = __esm(() => {
10076
10079
  code: DEPRECATED_BARE_X_DIRECTIVE,
10077
10080
  level: "warn",
10078
10081
  group: "Templates / events",
10079
- summary: "Bare `show`/`hide`/`when` on an `<x>` op is deprecated — use the `@`-prefixed directive (`@show`/`@hide`/`@when`)."
10082
+ summary: "Bare `show`/`hide`/`when`/`loop-with` on an `<x>` op is deprecated — use the `@`-prefixed directive (`@show`/`@hide`/`@when`/`@loop-with`)."
10080
10083
  },
10081
10084
  {
10082
10085
  code: BAD_VALUE,
@@ -10212,7 +10215,7 @@ function badValueMessage(info) {
10212
10215
  case "handler-arg":
10213
10216
  return `Cannot parse handler argument ${v}`;
10214
10217
  case "macro-var":
10215
- return `Macro variable '^${info.name}' is not defined`;
10218
+ return `Macro parameter '^${info.name}' is not defined`;
10216
10219
  default:
10217
10220
  return `Cannot parse value ${v}`;
10218
10221
  }
@@ -10292,7 +10295,7 @@ function lintIdToMessage(id, info) {
10292
10295
  case "ALT_HANDLER_NOT_REFERENCED":
10293
10296
  return `Alter handler '${info.name}' is defined but never used — remove it or reference it from @when, @enrich-with, or @loop-with`;
10294
10297
  case "DYN_VAL_NOT_DEFINED":
10295
- return `Dynamic variable '*${info.name}' is not defined${fmtOriginSuffix(info)}`;
10298
+ return `Dynamic binding '*${info.name}' is not defined${fmtOriginSuffix(info)}`;
10296
10299
  case "DYN_ALIAS_NOT_REFERENCED":
10297
10300
  return `Lookup '${info.name}' is defined but never used — remove it or reference it as '*${info.name}' in a view`;
10298
10301
  case "PROVIDE_NOT_ADDRESSABLE":
@@ -10330,9 +10333,9 @@ function lintIdToMessage(id, info) {
10330
10333
  return `Enrich handler '${info.name}' only copies members of the loop value — read them directly${reads ? ` (${reads})` : ""} and remove the '@enrich-with'`;
10331
10334
  }
10332
10335
  case "REDUNDANT_TEMPLATE_STRING":
10333
- return `Redundant template string — '{${info.simpler}}' should be just '${info.simpler}'${fmtOriginSuffix(info)}`;
10336
+ return `Redundant string template — '{${info.simpler}}' should be just '${info.simpler}'${fmtOriginSuffix(info)}`;
10334
10337
  case "PLACEHOLDERLESS_TEMPLATE_STRING":
10335
- return `Template string has no dynamic parts — use the string literal ${info.literal} instead${fmtOriginSuffix(info)}`;
10338
+ return `String template has no dynamic parts — use the string literal ${info.literal} instead${fmtOriginSuffix(info)}`;
10336
10339
  case "CONSTANT_CONDITION":
10337
10340
  return `Condition is the constant literal ${info.literal} — it never changes; reference a field ('.name') or a method ('$name') instead${fmtOriginSuffix(info)}`;
10338
10341
  case "UNKNOWN_COMPONENT_SPEC_KEY":
@@ -14453,16 +14456,23 @@ class Example {
14453
14456
  value,
14454
14457
  view = "main",
14455
14458
  componentName = null,
14456
- requestHandlerNames = []
14459
+ requestHandlers = null,
14460
+ requestHandlerNames = [],
14461
+ on = null
14457
14462
  }) {
14458
14463
  this.title = title;
14459
14464
  this.description = description;
14460
14465
  this.value = value;
14461
14466
  this.view = view;
14462
14467
  this.componentName = componentName;
14468
+ this.requestHandlers = requestHandlers;
14463
14469
  this.requestHandlerNames = requestHandlerNames;
14470
+ this.on = on;
14464
14471
  }
14465
14472
  }
14473
+ function isPlainObject2(v) {
14474
+ return v != null && typeof v === "object" && !Array.isArray(v);
14475
+ }
14466
14476
  function resolveComponentName(value, components) {
14467
14477
  for (const comp of components) {
14468
14478
  if (value instanceof comp.Class)
@@ -14509,13 +14519,29 @@ function parseExample(raw, index, components, parentPath) {
14509
14519
  if (rh != null && (typeof rh !== "object" || Array.isArray(rh))) {
14510
14520
  throw shapeError(`example at ${where} "requestHandlers" must be an object of functions`, where);
14511
14521
  }
14522
+ const on = raw.on;
14523
+ if (on != null) {
14524
+ if (!isPlainObject2(on)) {
14525
+ throw shapeError(`example at ${where} "on" must be an object of lifecycle phases (${PHASE_NAMES.join(", ")})`, where);
14526
+ }
14527
+ for (const key in on) {
14528
+ if (!PHASE_NAMES.includes(key)) {
14529
+ throw shapeError(`example at ${where} has unknown lifecycle phase "on.${key}"; expected one of ${PHASE_NAMES.join(", ")}`, where);
14530
+ }
14531
+ if (!isPlainObject2(on[key])) {
14532
+ throw shapeError(`example at ${where} "on.${key}" must be an object of actions (send, bubble, request, input, do)`, where);
14533
+ }
14534
+ }
14535
+ }
14512
14536
  return new Example({
14513
14537
  title: raw.title ?? `Example ${index + 1}`,
14514
14538
  description: raw.description ?? null,
14515
14539
  value: raw.value,
14516
14540
  view: raw.view ?? "main",
14517
14541
  componentName: resolveComponentName(raw.value, components),
14518
- requestHandlerNames: rh ? Object.keys(rh) : []
14542
+ requestHandlers: rh ?? null,
14543
+ requestHandlerNames: rh ? Object.keys(rh) : [],
14544
+ on: on ?? null
14519
14545
  });
14520
14546
  }
14521
14547
  function parseSection(raw, components, where) {
@@ -14609,7 +14635,10 @@ function findComponentNameConflicts(entries) {
14609
14635
  }
14610
14636
  return conflicts.sort((a, b) => a.name.localeCompare(b.name));
14611
14637
  }
14612
- var EXAMPLES_SHAPE_MISMATCH = "EXAMPLES_SHAPE_MISMATCH";
14638
+ var EXAMPLES_SHAPE_MISMATCH = "EXAMPLES_SHAPE_MISMATCH", PHASE_NAMES;
14639
+ var init_module = __esm(() => {
14640
+ PHASE_NAMES = ["init", "resume", "suspend"];
14641
+ });
14613
14642
 
14614
14643
  // tools/core/results.js
14615
14644
  class ModuleInfo {
@@ -14781,7 +14810,9 @@ function describeModule(mod, { path = null } = {}) {
14781
14810
  }
14782
14811
  return new ModuleInfo({ path, present, counts, warnings });
14783
14812
  }
14784
- var init_describe = () => {};
14813
+ var init_describe = __esm(() => {
14814
+ init_module();
14815
+ });
14785
14816
 
14786
14817
  // tools/core/docs.js
14787
14818
  function getSignature(name, fn) {
@@ -15819,6 +15850,7 @@ class App {
15819
15850
  this._compiled = false;
15820
15851
  this._renderOpts = { document: rootNode.ownerDocument };
15821
15852
  this._renderState = null;
15853
+ this.rootViewName = null;
15822
15854
  }
15823
15855
  get state() {
15824
15856
  return this.transactor.state;
@@ -15930,7 +15962,7 @@ class App {
15930
15962
  const root = this.state.val;
15931
15963
  const stack = this.makeStack(root);
15932
15964
  const { renderer, rootNode, _renderOpts, _renderState } = this;
15933
- const newState = render(renderer.renderRoot(stack, root), rootNode, _renderOpts, _renderState);
15965
+ const newState = render(renderer.renderRoot(stack, root, this.rootViewName), rootNode, _renderOpts, _renderState);
15934
15966
  this._renderState = newState;
15935
15967
  return newState.dom;
15936
15968
  }
@@ -16069,12 +16101,71 @@ var init_app = __esm(() => {
16069
16101
  _evs = "dragstart dragover dragend touchstart touchmove touchend touchcancel".split(" ");
16070
16102
  });
16071
16103
 
16104
+ // src/on.js
16105
+ function phaseOps(phase) {
16106
+ const ops = [];
16107
+ for (const type3 of OP_KINDS)
16108
+ for (const a of phase[type3] ?? [])
16109
+ ops.push({ type: type3, ...a });
16110
+ for (const a of phase.do ?? [])
16111
+ ops.push(a);
16112
+ return ops;
16113
+ }
16114
+ function resolveArgs(args, self) {
16115
+ return typeof args === "function" ? args(self) ?? [] : args ?? [];
16116
+ }
16117
+ function phaseHasBubble(phase) {
16118
+ if (!phase)
16119
+ return false;
16120
+ if (phase.bubble?.length)
16121
+ return true;
16122
+ return (phase.do ?? []).some((op) => op.type === "bubble");
16123
+ }
16124
+ function dispatchPhase(dispatcher, targetPath, phase, self) {
16125
+ if (!phase)
16126
+ return;
16127
+ for (const op of phaseOps(phase)) {
16128
+ const args = resolveArgs(op.args, self);
16129
+ switch (op.type) {
16130
+ case "send":
16131
+ dispatcher.sendAtPath(targetPath, op.name, args, op.opts);
16132
+ break;
16133
+ case "bubble":
16134
+ dispatcher.sendAtPath(targetPath, op.name, args, {
16135
+ skipSelf: true,
16136
+ bubbles: true,
16137
+ ...op.opts
16138
+ });
16139
+ break;
16140
+ case "request":
16141
+ dispatcher.requestAtPath(targetPath, op.name, args, op.opts);
16142
+ break;
16143
+ case "input":
16144
+ dispatcher.inputAtPath(targetPath, op.name, args, op.opts);
16145
+ break;
16146
+ }
16147
+ }
16148
+ }
16149
+ var OP_KINDS;
16150
+ var init_on = __esm(() => {
16151
+ OP_KINDS = ["send", "bubble", "request", "input"];
16152
+ });
16153
+
16072
16154
  // src/util/render.js
16073
16155
  function reindexComponents(comps) {
16074
16156
  for (let i = 0;i < comps.length; i++) {
16075
16157
  comps[i].id = i;
16076
16158
  }
16077
16159
  }
16160
+ function serializeContainer(container) {
16161
+ for (const input of container.querySelectorAll("input")) {
16162
+ if (input.value)
16163
+ input.setAttribute("value", input.value);
16164
+ if (input.checked)
16165
+ input.setAttribute("checked", "");
16166
+ }
16167
+ return container.innerHTML;
16168
+ }
16078
16169
  function renderToHTMLNode(document2, components, macros, rootState, ParseContext2, opts = { noCache: true }) {
16079
16170
  const container = document2.createElement("div");
16080
16171
  document2.body.appendChild(container);
@@ -16085,14 +16176,11 @@ function renderToHTMLNode(document2, components, macros, rootState, ParseContext
16085
16176
  const scope = app.registerComponents(components);
16086
16177
  if (macros)
16087
16178
  scope.registerMacros(macros);
16179
+ if (opts.requestHandlers)
16180
+ scope.registerRequestHandlers(opts.requestHandlers);
16181
+ app.rootViewName = opts.view ?? null;
16088
16182
  app.transactor.state.set(rootState);
16089
16183
  app.start(opts);
16090
- for (const input of container.querySelectorAll("input")) {
16091
- if (input.value)
16092
- input.setAttribute("value", input.value);
16093
- if (input.checked)
16094
- input.setAttribute("checked", "");
16095
- }
16096
16184
  return {
16097
16185
  container,
16098
16186
  app,
@@ -16102,20 +16190,44 @@ function renderToHTMLNode(document2, components, macros, rootState, ParseContext
16102
16190
  }
16103
16191
  };
16104
16192
  }
16105
- function renderToHTML(document2, components, macros, rootState, ParseContext2) {
16106
- const { container, cleanup } = renderToHTMLNode(document2, components, macros, rootState, ParseContext2);
16107
- const html = container.innerHTML;
16108
- cleanup();
16109
- return html;
16193
+ async function renderToHTMLDriven(document2, components, macros, rootState, ParseContext2, { phase = null, requestHandlers = null, view = null, warn = console.warn } = {}) {
16194
+ const { container, app, cleanup } = renderToHTMLNode(document2, components, macros, rootState, ParseContext2, { noCache: true, requestHandlers, view });
16195
+ try {
16196
+ if (phase) {
16197
+ if (phaseHasBubble(phase))
16198
+ warn("render: a `bubble` action is a no-op here — the example's value is the render root, so there is no ancestor to receive it. Use send/request/input to drive a preset state.");
16199
+ dispatchPhase(rootDispatcher(app.transactor), new Path([]), phase, app.state.val);
16200
+ await app.transactor.settle();
16201
+ }
16202
+ return serializeContainer(container);
16203
+ } finally {
16204
+ cleanup();
16205
+ }
16110
16206
  }
16111
16207
  var init_render = __esm(() => {
16112
16208
  init_app();
16113
16209
  init_components();
16210
+ init_on();
16211
+ init_path();
16114
16212
  init_renderer();
16213
+ init_transactor();
16115
16214
  });
16116
16215
 
16117
16216
  // tools/core/render.js
16118
- function renderExamples(normalized, env, { name = null, title = null, view = null } = {}) {
16217
+ function checkView2(value, components, viewName) {
16218
+ if (viewName === "main")
16219
+ return null;
16220
+ const comp = components.find((c) => value instanceof c.Class);
16221
+ if (!comp || comp.views[viewName])
16222
+ return null;
16223
+ const known = Object.keys(comp.views).sort().join(", ");
16224
+ return new Error(`view "${viewName}" is not defined on ${comp.name} (has: ${known})`);
16225
+ }
16226
+ function handlersFor(normalized, example) {
16227
+ const merged = { ...normalized.requestHandlers ?? {}, ...example.requestHandlers ?? {} };
16228
+ return Object.keys(merged).length > 0 ? merged : null;
16229
+ }
16230
+ async function renderExamples(normalized, env, { name = null, title = null, view = null } = {}) {
16119
16231
  const sections = [];
16120
16232
  for (const section of normalized.sections) {
16121
16233
  const items = [];
@@ -16129,7 +16241,14 @@ function renderExamples(normalized, env, { name = null, title = null, view = nul
16129
16241
  let html = "";
16130
16242
  let error = null;
16131
16243
  try {
16132
- html = renderToHTML(env.document, normalized.components, normalized.macros, example.value, env.ParseContext);
16244
+ const bad = checkView2(example.value, normalized.components, viewName);
16245
+ if (bad)
16246
+ throw bad;
16247
+ html = await renderToHTMLDriven(env.document, normalized.components, normalized.macros, example.value, env.ParseContext, {
16248
+ phase: example.on?.init ?? null,
16249
+ requestHandlers: handlersFor(normalized, example),
16250
+ view: viewName
16251
+ });
16133
16252
  } catch (e) {
16134
16253
  error = { message: e.message, stack: e.stack };
16135
16254
  }
@@ -16156,56 +16275,6 @@ var init_render2 = __esm(() => {
16156
16275
  init_render();
16157
16276
  });
16158
16277
 
16159
- // src/on.js
16160
- function phaseOps(phase) {
16161
- const ops = [];
16162
- for (const type3 of OP_KINDS)
16163
- for (const a of phase[type3] ?? [])
16164
- ops.push({ type: type3, ...a });
16165
- for (const a of phase.do ?? [])
16166
- ops.push(a);
16167
- return ops;
16168
- }
16169
- function resolveArgs(args, self) {
16170
- return typeof args === "function" ? args(self) ?? [] : args ?? [];
16171
- }
16172
- function phaseHasBubble(phase) {
16173
- if (!phase)
16174
- return false;
16175
- if (phase.bubble?.length)
16176
- return true;
16177
- return (phase.do ?? []).some((op) => op.type === "bubble");
16178
- }
16179
- function dispatchPhase(dispatcher, targetPath, phase, self) {
16180
- if (!phase)
16181
- return;
16182
- for (const op of phaseOps(phase)) {
16183
- const args = resolveArgs(op.args, self);
16184
- switch (op.type) {
16185
- case "send":
16186
- dispatcher.sendAtPath(targetPath, op.name, args, op.opts);
16187
- break;
16188
- case "bubble":
16189
- dispatcher.sendAtPath(targetPath, op.name, args, {
16190
- skipSelf: true,
16191
- bubbles: true,
16192
- ...op.opts
16193
- });
16194
- break;
16195
- case "request":
16196
- dispatcher.requestAtPath(targetPath, op.name, args, op.opts);
16197
- break;
16198
- case "input":
16199
- dispatcher.inputAtPath(targetPath, op.name, args, op.opts);
16200
- break;
16201
- }
16202
- }
16203
- }
16204
- var OP_KINDS;
16205
- var init_on = __esm(() => {
16206
- OP_KINDS = ["send", "bubble", "request", "input"];
16207
- });
16208
-
16209
16278
  // tools/core/tests.js
16210
16279
  class Describe {
16211
16280
  constructor({ title, componentName = null, parent = null }) {
@@ -17686,6 +17755,7 @@ async function run5(argv, opts = {}) {
17686
17755
  var describe5 = "Serve a storybook for the project's co-located *.dev.js modules (auto-discovered).", BOOTSTRAP_URL = "/__tutuca_storybook__.js", DIST_PREFIX = "/__tutuca__/", MARGAUI_PREFIX = "/__margaui__/", MIME, MARGAUI_CDN = "https://cdn.jsdelivr.net/npm/margaui/+esm", MARGAUI_THEME = "https://marianoguerra.github.io/margaui/themes/theme.css";
17687
17756
  var init_storybook = __esm(() => {
17688
17757
  init_chai2();
17758
+ init_module();
17689
17759
  init_test();
17690
17760
  init_env2();
17691
17761
  init_errors();
@@ -17864,6 +17934,7 @@ import { statSync as statSync2 } from "node:fs";
17864
17934
  import { parseArgs as parseArgs4 } from "node:util";
17865
17935
 
17866
17936
  // tools/cli/load.js
17937
+ init_module();
17867
17938
  import { existsSync as existsSync4 } from "node:fs";
17868
17939
  import { resolve as resolve6 } from "node:path";
17869
17940
  async function loadAndNormalize(modulePath) {
@@ -151,7 +151,7 @@ function makeCompositeView({
151
151
  @show=".isExpanded"
152
152
  class="ml-1 flex flex-col gap-0.5 border-l ${borderClass} pl-2 mt-0.5"
153
153
  >
154
- <x render-each=".items" loop-with="getPageRange"></x>
154
+ <x render-each=".items" @loop-with="getPageRange"></x>
155
155
  </div>
156
156
  </span>`;
157
157
  }
@@ -786,13 +786,13 @@ var GRID_BODY = html4`<div
786
786
  class="ml-1 grid gap-x-2 gap-y-0.5 items-baseline border-l border-base-content/10 pl-2 mt-0.5"
787
787
  style="grid-template-columns: auto 1fr"
788
788
  >
789
- <x render-each=".items" loop-with="getPageRange"></x>
789
+ <x render-each=".items" @loop-with="getPageRange"></x>
790
790
  </div>`;
791
791
  var LIST_BODY = html4`<div
792
792
  @show=".isExpanded"
793
793
  class="ml-1 flex flex-col gap-0.5 border-l border-base-content/10 pl-2 mt-0.5"
794
794
  >
795
- <x render-each=".items" loop-with="getPageRange"></x>
795
+ <x render-each=".items" @loop-with="getPageRange"></x>
796
796
  </div>`;
797
797
  function makeSchemaView(accent, body = GRID_BODY) {
798
798
  return html4`<span class="font-mono text-sm leading-tight inline-block">
@@ -1640,7 +1640,7 @@ function lintMessage(id, info = {}) {
1640
1640
  case "ALT_HANDLER_NOT_DEFINED":
1641
1641
  return `Alter handler '${info.name}' is not defined${originSuffix(info)}`;
1642
1642
  case "DYN_VAL_NOT_DEFINED":
1643
- return `Dynamic variable '*${info.name}' is not defined${originSuffix(info)}`;
1643
+ return `Dynamic binding '*${info.name}' is not defined${originSuffix(info)}`;
1644
1644
  case "UNKNOWN_COMPONENT_NAME":
1645
1645
  return `Unknown component '${info.name}'${originSuffix(info)}`;
1646
1646
  case "UNKNOWN_DIRECTIVE":
@@ -1648,9 +1648,9 @@ function lintMessage(id, info = {}) {
1648
1648
  case "IF_NO_BRANCH_SET":
1649
1649
  return `'@if.${info.attr}' has no '@then' or '@else' branch${tagSuffix(info)}`;
1650
1650
  case "REDUNDANT_TEMPLATE_STRING":
1651
- return `Redundant template string — '{${info.simpler}}' should be just '${info.simpler}'${originSuffix(info)}`;
1651
+ return `Redundant string template — '{${info.simpler}}' should be just '${info.simpler}'${originSuffix(info)}`;
1652
1652
  case "PLACEHOLDERLESS_TEMPLATE_STRING":
1653
- return `Template string has no dynamic parts — use the literal ${info.literal} instead${originSuffix(info)}`;
1653
+ return `String template has no dynamic parts — use the literal ${info.literal} instead${originSuffix(info)}`;
1654
1654
  case "CONSTANT_CONDITION":
1655
1655
  return `Constant condition ${info.literal} — reference a field ('.name') or method ('$name')${originSuffix(info)}`;
1656
1656
  case "ASYNC_HANDLER":
@@ -2375,9 +2375,12 @@ function parseRenderEach(px, value, as, attrs) {
2375
2375
  maybeDeprecateBareXDirective(px, "render-each", "when");
2376
2376
  attrParser._parseWhen(when.value);
2377
2377
  }
2378
- const lWith = attrs.getNamedItem("loop-with");
2379
- if (lWith)
2378
+ const lWith = attrs.getNamedItem("@loop-with") ?? attrs.getNamedItem("loop-with");
2379
+ if (lWith) {
2380
+ if (lWith.name.charCodeAt(0) !== 64)
2381
+ maybeDeprecateBareXDirective(px, "render-each", "loop-with");
2380
2382
  attrParser._parseLoopWith(lWith.value);
2383
+ }
2381
2384
  const each = px.addNodeIf(EachNode, seqVal);
2382
2385
  each.iterInfo.whenVal = eachAttr.whenVal ?? null;
2383
2386
  each.iterInfo.loopWithVal = eachAttr.loopWithVal ?? null;
@@ -2513,7 +2516,7 @@ var X_OPS = {
2513
2516
  text: xOp([], { wrappable: true, ignoresChildren: true }),
2514
2517
  render: xOp(["as"], { wrappable: true, ignoresChildren: true }),
2515
2518
  "render-it": xOp(["as"], { wrappable: true, ignoresChildren: true }),
2516
- "render-each": xOp(["as", "when", "loop-with", "@when"], {
2519
+ "render-each": xOp(["as", "when", "loop-with", "@when", "@loop-with"], {
2517
2520
  wrappable: true,
2518
2521
  ignoresChildren: true
2519
2522
  }),
@@ -5200,7 +5203,7 @@ function classifyBadValue(value) {
5200
5203
  }
5201
5204
  var BINDING_MEMBER_TOO_DEEP_RE = /^@[a-zA-Z]\w*\??(\.[a-zA-Z]\w*\??){2,}$/;
5202
5205
  var UNSUPPORTED_EXPR_GUIDANCE = {
5203
- ternary: "Ternary expressions aren't supported in dynamic attributes. Define a method or computed field on the component that returns the value, then reference it as '$methodName'.",
5206
+ ternary: "Ternary expressions aren't supported in dynamic attributes. Define a method or computed value on the component that returns the value, then reference it as '$methodName'.",
5204
5207
  comparison: "Comparisons aren't supported in dynamic attributes. Define a method like 'isFooSelected' that returns the boolean, then reference it as '$isFooSelected'.",
5205
5208
  logical: "Logical operators aren't supported in dynamic attributes. Combine the conditions in a method on the component and reference it as '$methodName'.",
5206
5209
  "call-with-args": "Method calls with arguments aren't supported here. Reference a no-arg method ('$methodName') and read what you need from component state, or split into per-case methods.",
@@ -5728,11 +5731,11 @@ function checkConsistentAttrs(lx, Comp, referencedAlters, referencedDynamics) {
5728
5731
  const iter = node.iterInfo;
5729
5732
  if (iter.whenVal)
5730
5733
  checkConsistentAttrVal(lx, iter.whenVal, env, false, {
5731
- originAttr: "<x render-each when>"
5734
+ originAttr: "<x render-each @when>"
5732
5735
  });
5733
5736
  if (iter.loopWithVal)
5734
5737
  checkConsistentAttrVal(lx, iter.loopWithVal, env, false, {
5735
- originAttr: "<x render-each loop-with>"
5738
+ originAttr: "<x render-each @loop-with>"
5736
5739
  });
5737
5740
  }
5738
5741
  }
@@ -7399,7 +7402,7 @@ function badValueMessage(info) {
7399
7402
  case "handler-arg":
7400
7403
  return `Cannot parse handler argument ${v}`;
7401
7404
  case "macro-var":
7402
- return `Macro variable '^${info.name}' is not defined`;
7405
+ return `Macro parameter '^${info.name}' is not defined`;
7403
7406
  default:
7404
7407
  return `Cannot parse value ${v}`;
7405
7408
  }
@@ -7479,7 +7482,7 @@ function lintIdToMessage(id, info) {
7479
7482
  case "ALT_HANDLER_NOT_REFERENCED":
7480
7483
  return `Alter handler '${info.name}' is defined but never used — remove it or reference it from @when, @enrich-with, or @loop-with`;
7481
7484
  case "DYN_VAL_NOT_DEFINED":
7482
- return `Dynamic variable '*${info.name}' is not defined${fmtOriginSuffix(info)}`;
7485
+ return `Dynamic binding '*${info.name}' is not defined${fmtOriginSuffix(info)}`;
7483
7486
  case "DYN_ALIAS_NOT_REFERENCED":
7484
7487
  return `Lookup '${info.name}' is defined but never used — remove it or reference it as '*${info.name}' in a view`;
7485
7488
  case "PROVIDE_NOT_ADDRESSABLE":
@@ -7517,9 +7520,9 @@ function lintIdToMessage(id, info) {
7517
7520
  return `Enrich handler '${info.name}' only copies members of the loop value — read them directly${reads ? ` (${reads})` : ""} and remove the '@enrich-with'`;
7518
7521
  }
7519
7522
  case "REDUNDANT_TEMPLATE_STRING":
7520
- return `Redundant template string — '{${info.simpler}}' should be just '${info.simpler}'${fmtOriginSuffix(info)}`;
7523
+ return `Redundant string template — '{${info.simpler}}' should be just '${info.simpler}'${fmtOriginSuffix(info)}`;
7521
7524
  case "PLACEHOLDERLESS_TEMPLATE_STRING":
7522
- return `Template string has no dynamic parts — use the string literal ${info.literal} instead${fmtOriginSuffix(info)}`;
7525
+ return `String template has no dynamic parts — use the string literal ${info.literal} instead${fmtOriginSuffix(info)}`;
7523
7526
  case "CONSTANT_CONDITION":
7524
7527
  return `Condition is the constant literal ${info.literal} — it never changes; reference a field ('.name') or a method ('$name') instead${fmtOriginSuffix(info)}`;
7525
7528
  case "UNKNOWN_COMPONENT_SPEC_KEY":
@@ -7642,6 +7645,7 @@ class App {
7642
7645
  this._compiled = false;
7643
7646
  this._renderOpts = { document: rootNode.ownerDocument };
7644
7647
  this._renderState = null;
7648
+ this.rootViewName = null;
7645
7649
  }
7646
7650
  get state() {
7647
7651
  return this.transactor.state;
@@ -7753,7 +7757,7 @@ class App {
7753
7757
  const root = this.state.val;
7754
7758
  const stack = this.makeStack(root);
7755
7759
  const { renderer, rootNode, _renderOpts, _renderState } = this;
7756
- const newState = render(renderer.renderRoot(stack, root), rootNode, _renderOpts, _renderState);
7760
+ const newState = render(renderer.renderRoot(stack, root, this.rootViewName), rootNode, _renderOpts, _renderState);
7757
7761
  this._renderState = newState;
7758
7762
  return newState.dom;
7759
7763
  }
@@ -10024,9 +10024,12 @@ function parseRenderEach(px, value, as, attrs) {
10024
10024
  maybeDeprecateBareXDirective(px, "render-each", "when");
10025
10025
  attrParser._parseWhen(when.value);
10026
10026
  }
10027
- const lWith = attrs.getNamedItem("loop-with");
10028
- if (lWith)
10027
+ const lWith = attrs.getNamedItem("@loop-with") ?? attrs.getNamedItem("loop-with");
10028
+ if (lWith) {
10029
+ if (lWith.name.charCodeAt(0) !== 64)
10030
+ maybeDeprecateBareXDirective(px, "render-each", "loop-with");
10029
10031
  attrParser._parseLoopWith(lWith.value);
10032
+ }
10030
10033
  const each = px.addNodeIf(EachNode, seqVal);
10031
10034
  each.iterInfo.whenVal = eachAttr.whenVal ?? null;
10032
10035
  each.iterInfo.loopWithVal = eachAttr.loopWithVal ?? null;
@@ -10162,7 +10165,7 @@ var X_OPS = {
10162
10165
  text: xOp([], { wrappable: true, ignoresChildren: true }),
10163
10166
  render: xOp(["as"], { wrappable: true, ignoresChildren: true }),
10164
10167
  "render-it": xOp(["as"], { wrappable: true, ignoresChildren: true }),
10165
- "render-each": xOp(["as", "when", "loop-with", "@when"], {
10168
+ "render-each": xOp(["as", "when", "loop-with", "@when", "@loop-with"], {
10166
10169
  wrappable: true,
10167
10170
  ignoresChildren: true
10168
10171
  }),
@@ -12849,7 +12852,7 @@ function classifyBadValue(value) {
12849
12852
  }
12850
12853
  var BINDING_MEMBER_TOO_DEEP_RE = /^@[a-zA-Z]\w*\??(\.[a-zA-Z]\w*\??){2,}$/;
12851
12854
  var UNSUPPORTED_EXPR_GUIDANCE = {
12852
- ternary: "Ternary expressions aren't supported in dynamic attributes. Define a method or computed field on the component that returns the value, then reference it as '$methodName'.",
12855
+ ternary: "Ternary expressions aren't supported in dynamic attributes. Define a method or computed value on the component that returns the value, then reference it as '$methodName'.",
12853
12856
  comparison: "Comparisons aren't supported in dynamic attributes. Define a method like 'isFooSelected' that returns the boolean, then reference it as '$isFooSelected'.",
12854
12857
  logical: "Logical operators aren't supported in dynamic attributes. Combine the conditions in a method on the component and reference it as '$methodName'.",
12855
12858
  "call-with-args": "Method calls with arguments aren't supported here. Reference a no-arg method ('$methodName') and read what you need from component state, or split into per-case methods.",
@@ -13377,11 +13380,11 @@ function checkConsistentAttrs(lx, Comp, referencedAlters, referencedDynamics) {
13377
13380
  const iter = node.iterInfo;
13378
13381
  if (iter.whenVal)
13379
13382
  checkConsistentAttrVal(lx, iter.whenVal, env, false, {
13380
- originAttr: "<x render-each when>"
13383
+ originAttr: "<x render-each @when>"
13381
13384
  });
13382
13385
  if (iter.loopWithVal)
13383
13386
  checkConsistentAttrVal(lx, iter.loopWithVal, env, false, {
13384
- originAttr: "<x render-each loop-with>"
13387
+ originAttr: "<x render-each @loop-with>"
13385
13388
  });
13386
13389
  }
13387
13390
  }
@@ -15048,7 +15051,7 @@ function badValueMessage(info) {
15048
15051
  case "handler-arg":
15049
15052
  return `Cannot parse handler argument ${v}`;
15050
15053
  case "macro-var":
15051
- return `Macro variable '^${info.name}' is not defined`;
15054
+ return `Macro parameter '^${info.name}' is not defined`;
15052
15055
  default:
15053
15056
  return `Cannot parse value ${v}`;
15054
15057
  }
@@ -15128,7 +15131,7 @@ function lintIdToMessage(id, info) {
15128
15131
  case "ALT_HANDLER_NOT_REFERENCED":
15129
15132
  return `Alter handler '${info.name}' is defined but never used — remove it or reference it from @when, @enrich-with, or @loop-with`;
15130
15133
  case "DYN_VAL_NOT_DEFINED":
15131
- return `Dynamic variable '*${info.name}' is not defined${fmtOriginSuffix(info)}`;
15134
+ return `Dynamic binding '*${info.name}' is not defined${fmtOriginSuffix(info)}`;
15132
15135
  case "DYN_ALIAS_NOT_REFERENCED":
15133
15136
  return `Lookup '${info.name}' is defined but never used — remove it or reference it as '*${info.name}' in a view`;
15134
15137
  case "PROVIDE_NOT_ADDRESSABLE":
@@ -15166,9 +15169,9 @@ function lintIdToMessage(id, info) {
15166
15169
  return `Enrich handler '${info.name}' only copies members of the loop value — read them directly${reads ? ` (${reads})` : ""} and remove the '@enrich-with'`;
15167
15170
  }
15168
15171
  case "REDUNDANT_TEMPLATE_STRING":
15169
- return `Redundant template string — '{${info.simpler}}' should be just '${info.simpler}'${fmtOriginSuffix(info)}`;
15172
+ return `Redundant string template — '{${info.simpler}}' should be just '${info.simpler}'${fmtOriginSuffix(info)}`;
15170
15173
  case "PLACEHOLDERLESS_TEMPLATE_STRING":
15171
- return `Template string has no dynamic parts — use the string literal ${info.literal} instead${fmtOriginSuffix(info)}`;
15174
+ return `String template has no dynamic parts — use the string literal ${info.literal} instead${fmtOriginSuffix(info)}`;
15172
15175
  case "CONSTANT_CONDITION":
15173
15176
  return `Condition is the constant literal ${info.literal} — it never changes; reference a field ('.name') or a method ('$name') instead${fmtOriginSuffix(info)}`;
15174
15177
  case "UNKNOWN_COMPONENT_SPEC_KEY":
@@ -15291,6 +15294,7 @@ class App {
15291
15294
  this._compiled = false;
15292
15295
  this._renderOpts = { document: rootNode.ownerDocument };
15293
15296
  this._renderState = null;
15297
+ this.rootViewName = null;
15294
15298
  }
15295
15299
  get state() {
15296
15300
  return this.transactor.state;
@@ -15402,7 +15406,7 @@ class App {
15402
15406
  const root = this.state.val;
15403
15407
  const stack = this.makeStack(root);
15404
15408
  const { renderer, rootNode, _renderOpts, _renderState } = this;
15405
- const newState = render(renderer.renderRoot(stack, root), rootNode, _renderOpts, _renderState);
15409
+ const newState = render(renderer.renderRoot(stack, root, this.rootViewName), rootNode, _renderOpts, _renderState);
15406
15410
  this._renderState = newState;
15407
15411
  return newState.dom;
15408
15412
  }