tutuca 0.9.101 → 0.9.102

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.
@@ -3447,9 +3447,10 @@ function resolveComponentName(value, components) {
3447
3447
  }
3448
3448
 
3449
3449
  class ExampleSection {
3450
- constructor({ title, description = null, items = [] }) {
3450
+ constructor({ title, description = null, group = "", items = [] }) {
3451
3451
  this.title = title;
3452
3452
  this.description = description;
3453
+ this.group = group;
3453
3454
  this.items = items;
3454
3455
  }
3455
3456
  }
@@ -3500,9 +3501,13 @@ function parseSection(raw, components, where) {
3500
3501
  if (items.length === 0) {
3501
3502
  throw shapeError(`section at ${where} has no items`, where);
3502
3503
  }
3504
+ if (raw.group != null && typeof raw.group !== "string") {
3505
+ throw shapeError(`section at ${where} has a non-string "group" (got ${typeof raw.group}); ` + `group must be a string naming the sidebar group, or be omitted`, where);
3506
+ }
3503
3507
  return new ExampleSection({
3504
3508
  title: raw.title ?? "Examples",
3505
3509
  description: raw.description ?? null,
3510
+ group: raw.group ?? "",
3506
3511
  items
3507
3512
  });
3508
3513
  }
@@ -3547,6 +3552,34 @@ function normalizeModule(mod, { path = null } = {}) {
3547
3552
  present
3548
3553
  };
3549
3554
  }
3555
+ function findComponentNameConflicts(entries) {
3556
+ const byName = new Map;
3557
+ for (const { path, components } of entries) {
3558
+ for (const comp of components ?? []) {
3559
+ if (!comp || typeof comp.name !== "string")
3560
+ continue;
3561
+ let objs = byName.get(comp.name);
3562
+ if (!objs)
3563
+ byName.set(comp.name, objs = new Map);
3564
+ let paths = objs.get(comp);
3565
+ if (!paths)
3566
+ objs.set(comp, paths = new Set);
3567
+ if (path != null)
3568
+ paths.add(path);
3569
+ }
3570
+ }
3571
+ const conflicts = [];
3572
+ for (const [name, objs] of byName) {
3573
+ if (objs.size < 2)
3574
+ continue;
3575
+ const paths = new Set;
3576
+ for (const set2 of objs.values())
3577
+ for (const p of set2)
3578
+ paths.add(p);
3579
+ conflicts.push({ name, paths: [...paths].sort() });
3580
+ }
3581
+ return conflicts.sort((a, b) => a.name.localeCompare(b.name));
3582
+ }
3550
3583
  var EXAMPLES_SHAPE_MISMATCH = "EXAMPLES_SHAPE_MISMATCH";
3551
3584
 
3552
3585
  // tools/core/results.js
@@ -9783,13 +9816,16 @@ class Renderer {
9783
9816
  if (cachedNode)
9784
9817
  return cachedNode;
9785
9818
  const view = viewName ? comp.getView(viewName) : stack.lookupBestView(comp.views, "main");
9819
+ const body = this.renderView(view, stack);
9820
+ if (body == null)
9821
+ return null;
9786
9822
  const meta = this._renderMetadata({
9787
9823
  $: "Comp",
9788
9824
  nid: node?.nodeId ?? null,
9789
9825
  cid: comp.id,
9790
9826
  vid: view.name
9791
9827
  });
9792
- const dom = new VFragment([meta, this.renderView(view, stack)]);
9828
+ const dom = new VFragment([meta, body]);
9793
9829
  this.cache.set(cachePath, cacheKey, dom);
9794
9830
  return dom;
9795
9831
  }
@@ -9802,7 +9838,8 @@ class Renderer {
9802
9838
  const { iterData, start, end, keys } = unpackLoopResult(loopWith.call(stack.it, seq, makeLoopCtx(stack, filter)), seq);
9803
9839
  const renderOne = (key, value, attrName) => {
9804
9840
  const dom = this.renderIt(stack.enter(value, { key }, true), node, key, viewName);
9805
- this.pushEachEntry(r, node.nodeId, attrName, key, dom);
9841
+ if (dom != null)
9842
+ this.pushEachEntry(r, node.nodeId, attrName, key, dom);
9806
9843
  };
9807
9844
  if (keys)
9808
9845
  imKeysIter(seq, renderOne, keys);
@@ -9829,7 +9866,8 @@ class Renderer {
9829
9866
  this.pushEachEntry(r, nid, attrName, key, cachedNode);
9830
9867
  else {
9831
9868
  const dom = this.renderView(view, stack.enter(value, binds, false));
9832
- this.pushEachEntry(r, nid, attrName, key, dom);
9869
+ if (dom != null)
9870
+ this.pushEachEntry(r, nid, attrName, key, dom);
9833
9871
  this.cache.set(cachePath, cacheKey, dom);
9834
9872
  }
9835
9873
  };
@@ -13010,6 +13048,7 @@ function checkComponent(Comp, lx = new LintContext, { wellKnownExtras = EMPTY_SE
13010
13048
  return lx.push({ componentName: Comp.name }, () => {
13011
13049
  checkUnknownSpecKeys(lx, Comp, wellKnownExtras);
13012
13050
  checkFieldDeclarations(lx, Comp);
13051
+ checkRecordFieldNameCollisions(lx, Comp);
13013
13052
  checkProvidesAreAddressable(lx, Comp);
13014
13053
  checkLookupShapes(lx, Comp);
13015
13054
  checkHandlersNotAsync(lx, Comp);
@@ -13400,6 +13439,16 @@ function checkFieldDeclarations(lx, Comp) {
13400
13439
  }
13401
13440
  }
13402
13441
  }
13442
+ function checkRecordFieldNameCollisions(lx, Comp) {
13443
+ const fields = Comp.Class?.getMetaClass?.().fields;
13444
+ if (!fields)
13445
+ return;
13446
+ for (const name in fields) {
13447
+ if (RECORD_FIELD_NAME_COLLISIONS.has(name)) {
13448
+ lx.error(FIELD_NAME_RESERVED_BY_RECORD, { name });
13449
+ }
13450
+ }
13451
+ }
13403
13452
  function checkUnreferencedAlterHandlers(lx, Comp, referencedAlters) {
13404
13453
  for (const name in Comp.alter) {
13405
13454
  if (!referencedAlters.has(name)) {
@@ -13561,7 +13610,7 @@ class LintContext {
13561
13610
  this.reports.push({ id, info, level, context: { ...this.frame }, suggestion });
13562
13611
  }
13563
13612
  }
13564
- var KNOWN_COMPONENT_SPEC_KEYS, EMPTY_SET2, FRAMEWORK_WELL_KNOWN_EXTRAS, KNOWN_DIRECTIVE_NAMES, ALT_HANDLER_NOT_DEFINED = "ALT_HANDLER_NOT_DEFINED", ALT_HANDLER_NOT_REFERENCED = "ALT_HANDLER_NOT_REFERENCED", DYN_VAL_NOT_DEFINED = "DYN_VAL_NOT_DEFINED", DYN_ALIAS_NOT_REFERENCED = "DYN_ALIAS_NOT_REFERENCED", PROVIDE_NOT_ADDRESSABLE = "PROVIDE_NOT_ADDRESSABLE", LOOKUP_BAD_SHAPE = "LOOKUP_BAD_SHAPE", LOOKUP_TARGET_MALFORMED = "LOOKUP_TARGET_MALFORMED", RENDER_IT_OUTSIDE_OF_LOOP = "RENDER_IT_OUTSIDE_OF_LOOP", UNKNOWN_EVENT_MODIFIER = "UNKNOWN_EVENT_MODIFIER", UNKNOWN_HANDLER_ARG_NAME = "UNKNOWN_HANDLER_ARG_NAME", INPUT_HANDLER_NOT_IMPLEMENTED = "INPUT_HANDLER_NOT_IMPLEMENTED", INPUT_HANDLER_NOT_REFERENCED = "INPUT_HANDLER_NOT_REFERENCED", INPUT_HANDLER_METHOD_NOT_IMPLEMENTED = "INPUT_HANDLER_METHOD_NOT_IMPLEMENTED", INPUT_HANDLER_FOR_INPUT_HANDLER_METHOD = "INPUT_HANDLER_FOR_INPUT_HANDLER_METHOD", INPUT_HANDLER_METHOD_FOR_INPUT_HANDLER = "INPUT_HANDLER_METHOD_FOR_INPUT_HANDLER", FIELD_VAL_NOT_DEFINED = "FIELD_VAL_NOT_DEFINED", FIELD_VAL_IS_METHOD = "FIELD_VAL_IS_METHOD", METHOD_VAL_NOT_DEFINED = "METHOD_VAL_NOT_DEFINED", METHOD_VAL_IS_FIELD = "METHOD_VAL_IS_FIELD", DUPLICATE_ATTR_DEFINITION = "DUPLICATE_ATTR_DEFINITION", IF_NO_BRANCH_SET = "IF_NO_BRANCH_SET", UNKNOWN_REQUEST_NAME = "UNKNOWN_REQUEST_NAME", UNKNOWN_COMPONENT_NAME = "UNKNOWN_COMPONENT_NAME", UNKNOWN_MACRO_ARG = "UNKNOWN_MACRO_ARG", UNKNOWN_DIRECTIVE = "UNKNOWN_DIRECTIVE", UNKNOWN_X_OP = "UNKNOWN_X_OP", UNKNOWN_X_ATTR = "UNKNOWN_X_ATTR", MAYBE_DROP_AT_PREFIX = "MAYBE_DROP_AT_PREFIX", MAYBE_ADD_AT_PREFIX = "MAYBE_ADD_AT_PREFIX", BAD_VALUE = "BAD_VALUE", UNSUPPORTED_EXPR_SYNTAX = "UNSUPPORTED_EXPR_SYNTAX", REDUNDANT_TEMPLATE_STRING = "REDUNDANT_TEMPLATE_STRING", PLACEHOLDERLESS_TEMPLATE_STRING = "PLACEHOLDERLESS_TEMPLATE_STRING", UNKNOWN_COMPONENT_SPEC_KEY = "UNKNOWN_COMPONENT_SPEC_KEY", COMP_FIELD_BAD_SHAPE = "COMP_FIELD_BAD_SHAPE", ASYNC_HANDLER = "ASYNC_HANDLER", TOP_LEVEL_AT_RULE_IN_SCOPED_STYLE = "TOP_LEVEL_AT_RULE_IN_SCOPED_STYLE", GLOBAL_SELECTOR_IN_SCOPED_STYLE = "GLOBAL_SELECTOR_IN_SCOPED_STYLE", X_KNOWN_OP_NAMES, X_KNOWN_ATTR_NAMES, HOST_DIRECTIVE_ONLY_NAMES, LEVEL_WARN2 = "warn", LEVEL_ERROR2 = "error", LEVEL_HINT = "hint", PARSE_ISSUES, UNSUPPORTED_EXPR_GUIDANCE, HTML_LINT_OPTS, NO_WRAPPERS, KNOWN_HANDLER_NAMES, fixTo = (from, to) => ({ kind: "rewrite", from, to }), ATTR_VAL_CHECKERS, NODE_KIND_TO_CTX, HANDLER_CHANNELS, ASYNC_HANDLER_HELP, NON_NESTABLE_AT_RULE, GLOBAL_LEADING_SELECTOR, IGNORE_DIRECTIVE, blankRun = (m) => m.replace(/[^\n]/g, " "), STYLE_TO_GLOBAL_HELP, KNOWN_LOOKUP_KEYS, LintParseContext;
13613
+ var KNOWN_COMPONENT_SPEC_KEYS, EMPTY_SET2, FRAMEWORK_WELL_KNOWN_EXTRAS, KNOWN_DIRECTIVE_NAMES, ALT_HANDLER_NOT_DEFINED = "ALT_HANDLER_NOT_DEFINED", ALT_HANDLER_NOT_REFERENCED = "ALT_HANDLER_NOT_REFERENCED", DYN_VAL_NOT_DEFINED = "DYN_VAL_NOT_DEFINED", DYN_ALIAS_NOT_REFERENCED = "DYN_ALIAS_NOT_REFERENCED", PROVIDE_NOT_ADDRESSABLE = "PROVIDE_NOT_ADDRESSABLE", LOOKUP_BAD_SHAPE = "LOOKUP_BAD_SHAPE", LOOKUP_TARGET_MALFORMED = "LOOKUP_TARGET_MALFORMED", RENDER_IT_OUTSIDE_OF_LOOP = "RENDER_IT_OUTSIDE_OF_LOOP", UNKNOWN_EVENT_MODIFIER = "UNKNOWN_EVENT_MODIFIER", UNKNOWN_HANDLER_ARG_NAME = "UNKNOWN_HANDLER_ARG_NAME", INPUT_HANDLER_NOT_IMPLEMENTED = "INPUT_HANDLER_NOT_IMPLEMENTED", INPUT_HANDLER_NOT_REFERENCED = "INPUT_HANDLER_NOT_REFERENCED", INPUT_HANDLER_METHOD_NOT_IMPLEMENTED = "INPUT_HANDLER_METHOD_NOT_IMPLEMENTED", INPUT_HANDLER_FOR_INPUT_HANDLER_METHOD = "INPUT_HANDLER_FOR_INPUT_HANDLER_METHOD", INPUT_HANDLER_METHOD_FOR_INPUT_HANDLER = "INPUT_HANDLER_METHOD_FOR_INPUT_HANDLER", FIELD_VAL_NOT_DEFINED = "FIELD_VAL_NOT_DEFINED", FIELD_VAL_IS_METHOD = "FIELD_VAL_IS_METHOD", METHOD_VAL_NOT_DEFINED = "METHOD_VAL_NOT_DEFINED", METHOD_VAL_IS_FIELD = "METHOD_VAL_IS_FIELD", DUPLICATE_ATTR_DEFINITION = "DUPLICATE_ATTR_DEFINITION", IF_NO_BRANCH_SET = "IF_NO_BRANCH_SET", UNKNOWN_REQUEST_NAME = "UNKNOWN_REQUEST_NAME", UNKNOWN_COMPONENT_NAME = "UNKNOWN_COMPONENT_NAME", UNKNOWN_MACRO_ARG = "UNKNOWN_MACRO_ARG", UNKNOWN_DIRECTIVE = "UNKNOWN_DIRECTIVE", UNKNOWN_X_OP = "UNKNOWN_X_OP", UNKNOWN_X_ATTR = "UNKNOWN_X_ATTR", MAYBE_DROP_AT_PREFIX = "MAYBE_DROP_AT_PREFIX", MAYBE_ADD_AT_PREFIX = "MAYBE_ADD_AT_PREFIX", BAD_VALUE = "BAD_VALUE", UNSUPPORTED_EXPR_SYNTAX = "UNSUPPORTED_EXPR_SYNTAX", REDUNDANT_TEMPLATE_STRING = "REDUNDANT_TEMPLATE_STRING", PLACEHOLDERLESS_TEMPLATE_STRING = "PLACEHOLDERLESS_TEMPLATE_STRING", UNKNOWN_COMPONENT_SPEC_KEY = "UNKNOWN_COMPONENT_SPEC_KEY", COMP_FIELD_BAD_SHAPE = "COMP_FIELD_BAD_SHAPE", ASYNC_HANDLER = "ASYNC_HANDLER", TOP_LEVEL_AT_RULE_IN_SCOPED_STYLE = "TOP_LEVEL_AT_RULE_IN_SCOPED_STYLE", GLOBAL_SELECTOR_IN_SCOPED_STYLE = "GLOBAL_SELECTOR_IN_SCOPED_STYLE", FIELD_NAME_RESERVED_BY_RECORD = "FIELD_NAME_RESERVED_BY_RECORD", RECORD_FIELD_NAME_COLLISIONS, X_KNOWN_OP_NAMES, X_KNOWN_ATTR_NAMES, HOST_DIRECTIVE_ONLY_NAMES, LEVEL_WARN2 = "warn", LEVEL_ERROR2 = "error", LEVEL_HINT = "hint", PARSE_ISSUES, UNSUPPORTED_EXPR_GUIDANCE, HTML_LINT_OPTS, NO_WRAPPERS, KNOWN_HANDLER_NAMES, fixTo = (from, to) => ({ kind: "rewrite", from, to }), ATTR_VAL_CHECKERS, NODE_KIND_TO_CTX, HANDLER_CHANNELS, ASYNC_HANDLER_HELP, NON_NESTABLE_AT_RULE, GLOBAL_LEADING_SELECTOR, IGNORE_DIRECTIVE, blankRun = (m) => m.replace(/[^\n]/g, " "), STYLE_TO_GLOBAL_HELP, KNOWN_LOOKUP_KEYS, LintParseContext;
13565
13614
  var init_lint_check = __esm(() => {
13566
13615
  init_anode();
13567
13616
  init_htmllinter();
@@ -13582,6 +13631,7 @@ var init_lint_check = __esm(() => {
13582
13631
  "then",
13583
13632
  "else"
13584
13633
  ]);
13634
+ RECORD_FIELD_NAME_COLLISIONS = new Set(["entries", "hashCode"]);
13585
13635
  X_KNOWN_OP_NAMES = new Set([
13586
13636
  "slot",
13587
13637
  "text",
@@ -15415,6 +15465,12 @@ var init_lint_rules = __esm(() => {
15415
15465
  level: "error",
15416
15466
  group: "Component field declarations",
15417
15467
  summary: "`fields: { x: { component, args } }` shape is wrong: `component` must be a string and `args` must be a plain object."
15468
+ },
15469
+ {
15470
+ code: FIELD_NAME_RESERVED_BY_RECORD,
15471
+ level: "error",
15472
+ group: "Component field declarations",
15473
+ summary: "Field name matches an Immutable Record API member, so `.field` reads the API member instead of the value."
15418
15474
  }
15419
15475
  ];
15420
15476
  });
@@ -15508,6 +15564,8 @@ function lintIdToMessage(id, info) {
15508
15564
  return `'$${info.name}' is a method reference, but '${info.name}' is defined as an input handler${fmtEventSuffix(info)}`;
15509
15565
  case "INPUT_HANDLER_METHOD_FOR_INPUT_HANDLER":
15510
15566
  return `'${info.name}' is an input handler reference, but '${info.name}' is defined as a method${fmtEventSuffix(info)}`;
15567
+ case "FIELD_NAME_RESERVED_BY_RECORD":
15568
+ return `Field '${info.name}' collides with the Immutable Record API: '.${info.name}' reads the Record member, not your value — rename the field (its value is only reachable via .get('${info.name}'))`;
15511
15569
  case "FIELD_VAL_NOT_DEFINED":
15512
15570
  return `Field '.${info.name}' is not defined${fmtOriginSuffix(info)}`;
15513
15571
  case "FIELD_VAL_IS_METHOD":
@@ -16212,6 +16270,23 @@ async function runDevTests(projectDir, devModuleUrls) {
16212
16270
  }
16213
16271
  return { totalTests, failedTests, withTests, failures, importErrors };
16214
16272
  }
16273
+ async function checkComponentNameConflicts(projectDir, devModuleUrls) {
16274
+ await createNodeEnv();
16275
+ const entries = [];
16276
+ for (const url of devModuleUrls) {
16277
+ const abs = resolve5(projectDir, url.slice(1));
16278
+ try {
16279
+ const mod = await import(abs);
16280
+ const components = typeof mod.getComponents === "function" ? mod.getComponents() : [];
16281
+ entries.push({ path: url, components });
16282
+ } catch {}
16283
+ }
16284
+ return findComponentNameConflicts(entries);
16285
+ }
16286
+ function formatComponentNameConflict(c) {
16287
+ return ` ! component name conflict: "${c.name}" is defined by different component objects in ${c.paths.length} modules (${c.paths.join(", ")}). They share a name but are distinct objects, so the storybook registers one and the other renders uncompiled (throws on ` + `render). Make those modules import the same definition — e.g. all from "tutuca/components" ` + `rather than a relative path.
16288
+ `;
16289
+ }
16215
16290
  async function discoverModules(projectDir, devModuleUrls) {
16216
16291
  await createNodeEnv();
16217
16292
  const modules = [];
@@ -16353,6 +16428,7 @@ async function run4(argv, opts = {}) {
16353
16428
  const imports2 = buildImports(base2, { margaui });
16354
16429
  const modules = await discoverModules(projectDir, devModuleUrls);
16355
16430
  const tests = parsed.values["no-tests"] ? null : await runDevTests(projectDir, devModuleUrls);
16431
+ const componentNameConflicts = await checkComponentNameConflicts(projectDir, devModuleUrls);
16356
16432
  const source = tutucaSource(base2);
16357
16433
  const result = {
16358
16434
  projectDir,
@@ -16360,7 +16436,8 @@ async function run4(argv, opts = {}) {
16360
16436
  options: { margaui, check, noCache, runTests: !parsed.values["no-tests"] },
16361
16437
  imports: imports2,
16362
16438
  modules,
16363
- tests
16439
+ tests,
16440
+ componentNameConflicts
16364
16441
  };
16365
16442
  if (opts.format === "json") {
16366
16443
  process.stdout.write(`${JSON.stringify(result, null, 2)}
@@ -16403,6 +16480,9 @@ async function run4(argv, opts = {}) {
16403
16480
  process.stdout.write(` tests: skipped (--no-tests)
16404
16481
  `);
16405
16482
  }
16483
+ for (const c of componentNameConflicts) {
16484
+ process.stdout.write(formatComponentNameConflict(c));
16485
+ }
16406
16486
  return;
16407
16487
  }
16408
16488
  if (!parsed.values["no-tests"]) {
@@ -16423,6 +16503,9 @@ async function run4(argv, opts = {}) {
16423
16503
  }
16424
16504
  }
16425
16505
  }
16506
+ for (const c of await checkComponentNameConflicts(projectDir, devModuleUrls)) {
16507
+ process.stdout.write(formatComponentNameConflict(c));
16508
+ }
16426
16509
  const { base, serveDist } = resolveTutucaBase(projectDir, self, false);
16427
16510
  const imports = buildImports(base, { margaui });
16428
16511
  const indexHtml = renderIndexHtml(imports, { margaui, bootstrapUrl: BOOTSTRAP_URL });
@@ -1825,13 +1825,16 @@ class Renderer {
1825
1825
  if (cachedNode)
1826
1826
  return cachedNode;
1827
1827
  const view = viewName ? comp.getView(viewName) : stack.lookupBestView(comp.views, "main");
1828
+ const body = this.renderView(view, stack);
1829
+ if (body == null)
1830
+ return null;
1828
1831
  const meta = this._renderMetadata({
1829
1832
  $: "Comp",
1830
1833
  nid: node?.nodeId ?? null,
1831
1834
  cid: comp.id,
1832
1835
  vid: view.name
1833
1836
  });
1834
- const dom = new VFragment([meta, this.renderView(view, stack)]);
1837
+ const dom = new VFragment([meta, body]);
1835
1838
  this.cache.set(cachePath, cacheKey, dom);
1836
1839
  return dom;
1837
1840
  }
@@ -1844,7 +1847,8 @@ class Renderer {
1844
1847
  const { iterData, start, end, keys } = unpackLoopResult(loopWith.call(stack.it, seq, makeLoopCtx(stack, filter)), seq);
1845
1848
  const renderOne = (key, value, attrName) => {
1846
1849
  const dom = this.renderIt(stack.enter(value, { key }, true), node, key, viewName);
1847
- this.pushEachEntry(r, node.nodeId, attrName, key, dom);
1850
+ if (dom != null)
1851
+ this.pushEachEntry(r, node.nodeId, attrName, key, dom);
1848
1852
  };
1849
1853
  if (keys)
1850
1854
  imKeysIter(seq, renderOne, keys);
@@ -1871,7 +1875,8 @@ class Renderer {
1871
1875
  this.pushEachEntry(r, nid, attrName, key, cachedNode);
1872
1876
  else {
1873
1877
  const dom = this.renderView(view, stack.enter(value, binds, false));
1874
- this.pushEachEntry(r, nid, attrName, key, dom);
1878
+ if (dom != null)
1879
+ this.pushEachEntry(r, nid, attrName, key, dom);
1875
1880
  this.cache.set(cachePath, cacheKey, dom);
1876
1881
  }
1877
1882
  };
@@ -2635,6 +2640,9 @@ class View {
2635
2640
  this.anode = optimizeNode(this.anode);
2636
2641
  }
2637
2642
  render(stack, rx) {
2643
+ if (this.anode === null) {
2644
+ throw new Error(`tutuca: view "${this.name}" was rendered before it was compiled — its ` + `component is not registered in this app/scope. Source: ` + `${String(this.rawView).slice(0, 80).replace(/\s+/g, " ")}…`);
2645
+ }
2638
2646
  return this.anode.render(stack, rx);
2639
2647
  }
2640
2648
  }
@@ -5088,6 +5096,8 @@ var COMP_FIELD_BAD_SHAPE = "COMP_FIELD_BAD_SHAPE";
5088
5096
  var ASYNC_HANDLER = "ASYNC_HANDLER";
5089
5097
  var TOP_LEVEL_AT_RULE_IN_SCOPED_STYLE = "TOP_LEVEL_AT_RULE_IN_SCOPED_STYLE";
5090
5098
  var GLOBAL_SELECTOR_IN_SCOPED_STYLE = "GLOBAL_SELECTOR_IN_SCOPED_STYLE";
5099
+ var FIELD_NAME_RESERVED_BY_RECORD = "FIELD_NAME_RESERVED_BY_RECORD";
5100
+ var RECORD_FIELD_NAME_COLLISIONS = new Set(["entries", "hashCode"]);
5091
5101
  var X_KNOWN_OP_NAMES = new Set([
5092
5102
  "slot",
5093
5103
  "text",
@@ -5176,6 +5186,7 @@ function checkComponent(Comp, lx = new LintContext, { wellKnownExtras = EMPTY_SE
5176
5186
  return lx.push({ componentName: Comp.name }, () => {
5177
5187
  checkUnknownSpecKeys(lx, Comp, wellKnownExtras);
5178
5188
  checkFieldDeclarations(lx, Comp);
5189
+ checkRecordFieldNameCollisions(lx, Comp);
5179
5190
  checkProvidesAreAddressable(lx, Comp);
5180
5191
  checkLookupShapes(lx, Comp);
5181
5192
  checkHandlersNotAsync(lx, Comp);
@@ -5668,6 +5679,16 @@ function checkFieldDeclarations(lx, Comp) {
5668
5679
  }
5669
5680
  }
5670
5681
  }
5682
+ function checkRecordFieldNameCollisions(lx, Comp) {
5683
+ const fields = Comp.Class?.getMetaClass?.().fields;
5684
+ if (!fields)
5685
+ return;
5686
+ for (const name in fields) {
5687
+ if (RECORD_FIELD_NAME_COLLISIONS.has(name)) {
5688
+ lx.error(FIELD_NAME_RESERVED_BY_RECORD, { name });
5689
+ }
5690
+ }
5691
+ }
5671
5692
  function checkUnreferencedAlterHandlers(lx, Comp, referencedAlters) {
5672
5693
  for (const name in Comp.alter) {
5673
5694
  if (!referencedAlters.has(name)) {
@@ -7256,6 +7277,8 @@ function lintIdToMessage(id, info) {
7256
7277
  return `'$${info.name}' is a method reference, but '${info.name}' is defined as an input handler${fmtEventSuffix(info)}`;
7257
7278
  case "INPUT_HANDLER_METHOD_FOR_INPUT_HANDLER":
7258
7279
  return `'${info.name}' is an input handler reference, but '${info.name}' is defined as a method${fmtEventSuffix(info)}`;
7280
+ case "FIELD_NAME_RESERVED_BY_RECORD":
7281
+ return `Field '${info.name}' collides with the Immutable Record API: '.${info.name}' reads the Record member, not your value — rename the field (its value is only reachable via .get('${info.name}'))`;
7259
7282
  case "FIELD_VAL_NOT_DEFINED":
7260
7283
  return `Field '.${info.name}' is not defined${fmtOriginSuffix(info)}`;
7261
7284
  case "FIELD_VAL_IS_METHOD":
@@ -8569,6 +8592,7 @@ export {
8569
8592
  GLOBAL_SELECTOR_IN_SCOPED_STYLE,
8570
8593
  FIELD_VAL_NOT_DEFINED,
8571
8594
  FIELD_VAL_IS_METHOD,
8595
+ FIELD_NAME_RESERVED_BY_RECORD,
8572
8596
  FIELD_CLASS,
8573
8597
  ExampleIndex,
8574
8598
  DescribeResult,
@@ -9476,13 +9476,16 @@ class Renderer {
9476
9476
  if (cachedNode)
9477
9477
  return cachedNode;
9478
9478
  const view = viewName ? comp.getView(viewName) : stack.lookupBestView(comp.views, "main");
9479
+ const body = this.renderView(view, stack);
9480
+ if (body == null)
9481
+ return null;
9479
9482
  const meta = this._renderMetadata({
9480
9483
  $: "Comp",
9481
9484
  nid: node?.nodeId ?? null,
9482
9485
  cid: comp.id,
9483
9486
  vid: view.name
9484
9487
  });
9485
- const dom = new VFragment([meta, this.renderView(view, stack)]);
9488
+ const dom = new VFragment([meta, body]);
9486
9489
  this.cache.set(cachePath, cacheKey, dom);
9487
9490
  return dom;
9488
9491
  }
@@ -9495,7 +9498,8 @@ class Renderer {
9495
9498
  const { iterData, start, end, keys } = unpackLoopResult(loopWith.call(stack.it, seq, makeLoopCtx(stack, filter)), seq);
9496
9499
  const renderOne = (key, value, attrName) => {
9497
9500
  const dom = this.renderIt(stack.enter(value, { key }, true), node, key, viewName);
9498
- this.pushEachEntry(r, node.nodeId, attrName, key, dom);
9501
+ if (dom != null)
9502
+ this.pushEachEntry(r, node.nodeId, attrName, key, dom);
9499
9503
  };
9500
9504
  if (keys)
9501
9505
  imKeysIter(seq, renderOne, keys);
@@ -9522,7 +9526,8 @@ class Renderer {
9522
9526
  this.pushEachEntry(r, nid, attrName, key, cachedNode);
9523
9527
  else {
9524
9528
  const dom = this.renderView(view, stack.enter(value, binds, false));
9525
- this.pushEachEntry(r, nid, attrName, key, dom);
9529
+ if (dom != null)
9530
+ this.pushEachEntry(r, nid, attrName, key, dom);
9526
9531
  this.cache.set(cachePath, cacheKey, dom);
9527
9532
  }
9528
9533
  };
@@ -10286,6 +10291,9 @@ class View {
10286
10291
  this.anode = optimizeNode(this.anode);
10287
10292
  }
10288
10293
  render(stack, rx) {
10294
+ if (this.anode === null) {
10295
+ throw new Error(`tutuca: view "${this.name}" was rendered before it was compiled — its ` + `component is not registered in this app/scope. Source: ` + `${String(this.rawView).slice(0, 80).replace(/\s+/g, " ")}…`);
10296
+ }
10289
10297
  return this.anode.render(stack, rx);
10290
10298
  }
10291
10299
  }
@@ -12739,6 +12747,8 @@ var COMP_FIELD_BAD_SHAPE = "COMP_FIELD_BAD_SHAPE";
12739
12747
  var ASYNC_HANDLER = "ASYNC_HANDLER";
12740
12748
  var TOP_LEVEL_AT_RULE_IN_SCOPED_STYLE = "TOP_LEVEL_AT_RULE_IN_SCOPED_STYLE";
12741
12749
  var GLOBAL_SELECTOR_IN_SCOPED_STYLE = "GLOBAL_SELECTOR_IN_SCOPED_STYLE";
12750
+ var FIELD_NAME_RESERVED_BY_RECORD = "FIELD_NAME_RESERVED_BY_RECORD";
12751
+ var RECORD_FIELD_NAME_COLLISIONS = new Set(["entries", "hashCode"]);
12742
12752
  var X_KNOWN_OP_NAMES = new Set([
12743
12753
  "slot",
12744
12754
  "text",
@@ -12827,6 +12837,7 @@ function checkComponent(Comp, lx = new LintContext, { wellKnownExtras = EMPTY_SE
12827
12837
  return lx.push({ componentName: Comp.name }, () => {
12828
12838
  checkUnknownSpecKeys(lx, Comp, wellKnownExtras);
12829
12839
  checkFieldDeclarations(lx, Comp);
12840
+ checkRecordFieldNameCollisions(lx, Comp);
12830
12841
  checkProvidesAreAddressable(lx, Comp);
12831
12842
  checkLookupShapes(lx, Comp);
12832
12843
  checkHandlersNotAsync(lx, Comp);
@@ -13319,6 +13330,16 @@ function checkFieldDeclarations(lx, Comp) {
13319
13330
  }
13320
13331
  }
13321
13332
  }
13333
+ function checkRecordFieldNameCollisions(lx, Comp) {
13334
+ const fields = Comp.Class?.getMetaClass?.().fields;
13335
+ if (!fields)
13336
+ return;
13337
+ for (const name in fields) {
13338
+ if (RECORD_FIELD_NAME_COLLISIONS.has(name)) {
13339
+ lx.error(FIELD_NAME_RESERVED_BY_RECORD, { name });
13340
+ }
13341
+ }
13342
+ }
13322
13343
  function checkUnreferencedAlterHandlers(lx, Comp, referencedAlters) {
13323
13344
  for (const name in Comp.alter) {
13324
13345
  if (!referencedAlters.has(name)) {
@@ -14907,6 +14928,8 @@ function lintIdToMessage(id, info) {
14907
14928
  return `'$${info.name}' is a method reference, but '${info.name}' is defined as an input handler${fmtEventSuffix(info)}`;
14908
14929
  case "INPUT_HANDLER_METHOD_FOR_INPUT_HANDLER":
14909
14930
  return `'${info.name}' is an input handler reference, but '${info.name}' is defined as a method${fmtEventSuffix(info)}`;
14931
+ case "FIELD_NAME_RESERVED_BY_RECORD":
14932
+ return `Field '${info.name}' collides with the Immutable Record API: '.${info.name}' reads the Record member, not your value — rename the field (its value is only reachable via .get('${info.name}'))`;
14910
14933
  case "FIELD_VAL_NOT_DEFINED":
14911
14934
  return `Field '.${info.name}' is not defined${fmtOriginSuffix(info)}`;
14912
14935
  case "FIELD_VAL_IS_METHOD":
@@ -16163,6 +16186,7 @@ export {
16163
16186
  GLOBAL_SELECTOR_IN_SCOPED_STYLE,
16164
16187
  FIELD_VAL_NOT_DEFINED,
16165
16188
  FIELD_VAL_IS_METHOD,
16189
+ FIELD_NAME_RESERVED_BY_RECORD,
16166
16190
  FIELD_CLASS,
16167
16191
  ExampleIndex,
16168
16192
  DescribeResult,