tutuca 0.9.100 → 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.
- package/dist/tutuca-cli.js +104 -14
- package/dist/tutuca-dev.ext.js +42 -11
- package/dist/tutuca-dev.js +42 -11
- package/dist/tutuca-dev.min.js +2 -2
- package/dist/tutuca-extra.ext.js +26 -11
- package/dist/tutuca-extra.js +26 -11
- package/dist/tutuca-extra.min.js +1 -1
- package/dist/tutuca-storybook.js +168 -45
- package/dist/tutuca.ext.js +26 -11
- package/dist/tutuca.js +26 -11
- package/dist/tutuca.min.js +1 -1
- package/package.json +1 -1
- package/skill/tutuca/core.md +10 -6
- package/skill/tutuca/patterns/render-a-child-component.md +1 -0
- package/skill/tutuca/patterns/switch-between-views.md +9 -5
- package/skill/tutuca-source/tutuca.ext.js +26 -11
package/dist/tutuca-cli.js
CHANGED
|
@@ -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,
|
|
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
|
-
|
|
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
|
-
|
|
9869
|
+
if (dom != null)
|
|
9870
|
+
this.pushEachEntry(r, nid, attrName, key, dom);
|
|
9833
9871
|
this.cache.set(cachePath, cacheKey, dom);
|
|
9834
9872
|
}
|
|
9835
9873
|
};
|
|
@@ -9958,7 +9996,8 @@ function parseXOp(attrs, childs, opIdx, px) {
|
|
|
9958
9996
|
if (attrs.length <= opIdx)
|
|
9959
9997
|
return maybeFragment(childs);
|
|
9960
9998
|
const { name, value } = attrs[opIdx];
|
|
9961
|
-
const
|
|
9999
|
+
const asAttr = attrs.getNamedItem("as")?.value ?? null;
|
|
10000
|
+
const as = asAttr === null ? null : parseViewName(asAttr, px);
|
|
9962
10001
|
let node;
|
|
9963
10002
|
switch (name) {
|
|
9964
10003
|
case "slot":
|
|
@@ -9998,6 +10037,9 @@ function parseXOpVal(opName, value, px, parserFn) {
|
|
|
9998
10037
|
px.onParseIssue("bad-value", { role: "x-op", op: opName, value });
|
|
9999
10038
|
return val;
|
|
10000
10039
|
}
|
|
10040
|
+
function parseViewName(s, px) {
|
|
10041
|
+
return vp.parseText(s, px) ?? vp.const(s);
|
|
10042
|
+
}
|
|
10001
10043
|
function processXExtras(node, attrs, opName, startIdx, px) {
|
|
10002
10044
|
const { consumed, wrappable } = X_OPS[opName];
|
|
10003
10045
|
const wrappers = [];
|
|
@@ -10427,16 +10469,19 @@ var init_anode = __esm(() => {
|
|
|
10427
10469
|
}
|
|
10428
10470
|
};
|
|
10429
10471
|
RenderViewId = class RenderViewId extends ANode {
|
|
10430
|
-
constructor(nodeId, val,
|
|
10472
|
+
constructor(nodeId, val, viewVal) {
|
|
10431
10473
|
super(nodeId, val);
|
|
10432
|
-
this.
|
|
10474
|
+
this.viewVal = viewVal;
|
|
10475
|
+
}
|
|
10476
|
+
evalViewName(stack) {
|
|
10477
|
+
return this.viewVal ? this.viewVal.eval(stack) : null;
|
|
10433
10478
|
}
|
|
10434
10479
|
setDataAttr(_key, _val) {}
|
|
10435
10480
|
};
|
|
10436
10481
|
RenderNode = class RenderNode extends RenderViewId {
|
|
10437
10482
|
render(stack, rx) {
|
|
10438
10483
|
const newStack = stack.enter(this.val.eval(stack), {}, true);
|
|
10439
|
-
return rx.renderIt(newStack, this, "", this.
|
|
10484
|
+
return rx.renderIt(newStack, this, "", this.evalViewName(stack));
|
|
10440
10485
|
}
|
|
10441
10486
|
toPathStep(ctx) {
|
|
10442
10487
|
if (this.val instanceof DynVal)
|
|
@@ -10447,7 +10492,7 @@ var init_anode = __esm(() => {
|
|
|
10447
10492
|
RenderItNode = class RenderItNode extends RenderViewId {
|
|
10448
10493
|
render(stack, rx) {
|
|
10449
10494
|
const newStack = stack.enter(stack.it, {}, true);
|
|
10450
|
-
return rx.renderIt(newStack, this, "", this.
|
|
10495
|
+
return rx.renderIt(newStack, this, "", this.evalViewName(stack));
|
|
10451
10496
|
}
|
|
10452
10497
|
toPathStep(ctx) {
|
|
10453
10498
|
const next = ctx.next();
|
|
@@ -10463,12 +10508,12 @@ var init_anode = __esm(() => {
|
|
|
10463
10508
|
}
|
|
10464
10509
|
};
|
|
10465
10510
|
RenderEachNode = class RenderEachNode extends RenderViewId {
|
|
10466
|
-
constructor(nodeId, val,
|
|
10467
|
-
super(nodeId, val,
|
|
10511
|
+
constructor(nodeId, val, viewVal) {
|
|
10512
|
+
super(nodeId, val, viewVal);
|
|
10468
10513
|
this.iterInfo = new IterInfo(val, null, null, null);
|
|
10469
10514
|
}
|
|
10470
10515
|
render(stack, rx) {
|
|
10471
|
-
return rx.renderEach(stack, this.iterInfo, this, this.
|
|
10516
|
+
return rx.renderEach(stack, this.iterInfo, this, this.evalViewName(stack));
|
|
10472
10517
|
}
|
|
10473
10518
|
toPathStep(ctx) {
|
|
10474
10519
|
if (this.val instanceof DynVal)
|
|
@@ -13003,6 +13048,7 @@ function checkComponent(Comp, lx = new LintContext, { wellKnownExtras = EMPTY_SE
|
|
|
13003
13048
|
return lx.push({ componentName: Comp.name }, () => {
|
|
13004
13049
|
checkUnknownSpecKeys(lx, Comp, wellKnownExtras);
|
|
13005
13050
|
checkFieldDeclarations(lx, Comp);
|
|
13051
|
+
checkRecordFieldNameCollisions(lx, Comp);
|
|
13006
13052
|
checkProvidesAreAddressable(lx, Comp);
|
|
13007
13053
|
checkLookupShapes(lx, Comp);
|
|
13008
13054
|
checkHandlersNotAsync(lx, Comp);
|
|
@@ -13393,6 +13439,16 @@ function checkFieldDeclarations(lx, Comp) {
|
|
|
13393
13439
|
}
|
|
13394
13440
|
}
|
|
13395
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
|
+
}
|
|
13396
13452
|
function checkUnreferencedAlterHandlers(lx, Comp, referencedAlters) {
|
|
13397
13453
|
for (const name in Comp.alter) {
|
|
13398
13454
|
if (!referencedAlters.has(name)) {
|
|
@@ -13554,7 +13610,7 @@ class LintContext {
|
|
|
13554
13610
|
this.reports.push({ id, info, level, context: { ...this.frame }, suggestion });
|
|
13555
13611
|
}
|
|
13556
13612
|
}
|
|
13557
|
-
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;
|
|
13558
13614
|
var init_lint_check = __esm(() => {
|
|
13559
13615
|
init_anode();
|
|
13560
13616
|
init_htmllinter();
|
|
@@ -13575,6 +13631,7 @@ var init_lint_check = __esm(() => {
|
|
|
13575
13631
|
"then",
|
|
13576
13632
|
"else"
|
|
13577
13633
|
]);
|
|
13634
|
+
RECORD_FIELD_NAME_COLLISIONS = new Set(["entries", "hashCode"]);
|
|
13578
13635
|
X_KNOWN_OP_NAMES = new Set([
|
|
13579
13636
|
"slot",
|
|
13580
13637
|
"text",
|
|
@@ -15408,6 +15465,12 @@ var init_lint_rules = __esm(() => {
|
|
|
15408
15465
|
level: "error",
|
|
15409
15466
|
group: "Component field declarations",
|
|
15410
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."
|
|
15411
15474
|
}
|
|
15412
15475
|
];
|
|
15413
15476
|
});
|
|
@@ -15501,6 +15564,8 @@ function lintIdToMessage(id, info) {
|
|
|
15501
15564
|
return `'$${info.name}' is a method reference, but '${info.name}' is defined as an input handler${fmtEventSuffix(info)}`;
|
|
15502
15565
|
case "INPUT_HANDLER_METHOD_FOR_INPUT_HANDLER":
|
|
15503
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}'))`;
|
|
15504
15569
|
case "FIELD_VAL_NOT_DEFINED":
|
|
15505
15570
|
return `Field '.${info.name}' is not defined${fmtOriginSuffix(info)}`;
|
|
15506
15571
|
case "FIELD_VAL_IS_METHOD":
|
|
@@ -16205,6 +16270,23 @@ async function runDevTests(projectDir, devModuleUrls) {
|
|
|
16205
16270
|
}
|
|
16206
16271
|
return { totalTests, failedTests, withTests, failures, importErrors };
|
|
16207
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
|
+
}
|
|
16208
16290
|
async function discoverModules(projectDir, devModuleUrls) {
|
|
16209
16291
|
await createNodeEnv();
|
|
16210
16292
|
const modules = [];
|
|
@@ -16346,6 +16428,7 @@ async function run4(argv, opts = {}) {
|
|
|
16346
16428
|
const imports2 = buildImports(base2, { margaui });
|
|
16347
16429
|
const modules = await discoverModules(projectDir, devModuleUrls);
|
|
16348
16430
|
const tests = parsed.values["no-tests"] ? null : await runDevTests(projectDir, devModuleUrls);
|
|
16431
|
+
const componentNameConflicts = await checkComponentNameConflicts(projectDir, devModuleUrls);
|
|
16349
16432
|
const source = tutucaSource(base2);
|
|
16350
16433
|
const result = {
|
|
16351
16434
|
projectDir,
|
|
@@ -16353,7 +16436,8 @@ async function run4(argv, opts = {}) {
|
|
|
16353
16436
|
options: { margaui, check, noCache, runTests: !parsed.values["no-tests"] },
|
|
16354
16437
|
imports: imports2,
|
|
16355
16438
|
modules,
|
|
16356
|
-
tests
|
|
16439
|
+
tests,
|
|
16440
|
+
componentNameConflicts
|
|
16357
16441
|
};
|
|
16358
16442
|
if (opts.format === "json") {
|
|
16359
16443
|
process.stdout.write(`${JSON.stringify(result, null, 2)}
|
|
@@ -16396,6 +16480,9 @@ async function run4(argv, opts = {}) {
|
|
|
16396
16480
|
process.stdout.write(` tests: skipped (--no-tests)
|
|
16397
16481
|
`);
|
|
16398
16482
|
}
|
|
16483
|
+
for (const c of componentNameConflicts) {
|
|
16484
|
+
process.stdout.write(formatComponentNameConflict(c));
|
|
16485
|
+
}
|
|
16399
16486
|
return;
|
|
16400
16487
|
}
|
|
16401
16488
|
if (!parsed.values["no-tests"]) {
|
|
@@ -16416,6 +16503,9 @@ async function run4(argv, opts = {}) {
|
|
|
16416
16503
|
}
|
|
16417
16504
|
}
|
|
16418
16505
|
}
|
|
16506
|
+
for (const c of await checkComponentNameConflicts(projectDir, devModuleUrls)) {
|
|
16507
|
+
process.stdout.write(formatComponentNameConflict(c));
|
|
16508
|
+
}
|
|
16419
16509
|
const { base, serveDist } = resolveTutucaBase(projectDir, self, false);
|
|
16420
16510
|
const imports = buildImports(base, { margaui });
|
|
16421
16511
|
const indexHtml = renderIndexHtml(imports, { margaui, bootstrapUrl: BOOTSTRAP_URL });
|
package/dist/tutuca-dev.ext.js
CHANGED
|
@@ -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,
|
|
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
|
-
|
|
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
|
-
|
|
1878
|
+
if (dom != null)
|
|
1879
|
+
this.pushEachEntry(r, nid, attrName, key, dom);
|
|
1875
1880
|
this.cache.set(cachePath, cacheKey, dom);
|
|
1876
1881
|
}
|
|
1877
1882
|
};
|
|
@@ -2156,7 +2161,8 @@ function parseXOp(attrs, childs, opIdx, px) {
|
|
|
2156
2161
|
if (attrs.length <= opIdx)
|
|
2157
2162
|
return maybeFragment(childs);
|
|
2158
2163
|
const { name, value } = attrs[opIdx];
|
|
2159
|
-
const
|
|
2164
|
+
const asAttr = attrs.getNamedItem("as")?.value ?? null;
|
|
2165
|
+
const as = asAttr === null ? null : parseViewName(asAttr, px);
|
|
2160
2166
|
let node;
|
|
2161
2167
|
switch (name) {
|
|
2162
2168
|
case "slot":
|
|
@@ -2196,6 +2202,9 @@ function parseXOpVal(opName, value, px, parserFn) {
|
|
|
2196
2202
|
px.onParseIssue("bad-value", { role: "x-op", op: opName, value });
|
|
2197
2203
|
return val;
|
|
2198
2204
|
}
|
|
2205
|
+
function parseViewName(s, px) {
|
|
2206
|
+
return vp.parseText(s, px) ?? vp.const(s);
|
|
2207
|
+
}
|
|
2199
2208
|
function processXExtras(node, attrs, opName, startIdx, px) {
|
|
2200
2209
|
const { consumed, wrappable } = X_OPS[opName];
|
|
2201
2210
|
const wrappers = [];
|
|
@@ -2292,9 +2301,12 @@ class Macro {
|
|
|
2292
2301
|
}
|
|
2293
2302
|
|
|
2294
2303
|
class RenderViewId extends ANode {
|
|
2295
|
-
constructor(nodeId, val,
|
|
2304
|
+
constructor(nodeId, val, viewVal) {
|
|
2296
2305
|
super(nodeId, val);
|
|
2297
|
-
this.
|
|
2306
|
+
this.viewVal = viewVal;
|
|
2307
|
+
}
|
|
2308
|
+
evalViewName(stack) {
|
|
2309
|
+
return this.viewVal ? this.viewVal.eval(stack) : null;
|
|
2298
2310
|
}
|
|
2299
2311
|
setDataAttr(_key, _val) {}
|
|
2300
2312
|
}
|
|
@@ -2308,7 +2320,7 @@ function dynRenderStep(comp, name, key) {
|
|
|
2308
2320
|
class RenderNode extends RenderViewId {
|
|
2309
2321
|
render(stack, rx) {
|
|
2310
2322
|
const newStack = stack.enter(this.val.eval(stack), {}, true);
|
|
2311
|
-
return rx.renderIt(newStack, this, "", this.
|
|
2323
|
+
return rx.renderIt(newStack, this, "", this.evalViewName(stack));
|
|
2312
2324
|
}
|
|
2313
2325
|
toPathStep(ctx) {
|
|
2314
2326
|
if (this.val instanceof DynVal)
|
|
@@ -2320,7 +2332,7 @@ class RenderNode extends RenderViewId {
|
|
|
2320
2332
|
class RenderItNode extends RenderViewId {
|
|
2321
2333
|
render(stack, rx) {
|
|
2322
2334
|
const newStack = stack.enter(stack.it, {}, true);
|
|
2323
|
-
return rx.renderIt(newStack, this, "", this.
|
|
2335
|
+
return rx.renderIt(newStack, this, "", this.evalViewName(stack));
|
|
2324
2336
|
}
|
|
2325
2337
|
toPathStep(ctx) {
|
|
2326
2338
|
const next = ctx.next();
|
|
@@ -2337,12 +2349,12 @@ class RenderItNode extends RenderViewId {
|
|
|
2337
2349
|
}
|
|
2338
2350
|
|
|
2339
2351
|
class RenderEachNode extends RenderViewId {
|
|
2340
|
-
constructor(nodeId, val,
|
|
2341
|
-
super(nodeId, val,
|
|
2352
|
+
constructor(nodeId, val, viewVal) {
|
|
2353
|
+
super(nodeId, val, viewVal);
|
|
2342
2354
|
this.iterInfo = new IterInfo(val, null, null, null);
|
|
2343
2355
|
}
|
|
2344
2356
|
render(stack, rx) {
|
|
2345
|
-
return rx.renderEach(stack, this.iterInfo, this, this.
|
|
2357
|
+
return rx.renderEach(stack, this.iterInfo, this, this.evalViewName(stack));
|
|
2346
2358
|
}
|
|
2347
2359
|
toPathStep(ctx) {
|
|
2348
2360
|
if (this.val instanceof DynVal)
|
|
@@ -2628,6 +2640,9 @@ class View {
|
|
|
2628
2640
|
this.anode = optimizeNode(this.anode);
|
|
2629
2641
|
}
|
|
2630
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
|
+
}
|
|
2631
2646
|
return this.anode.render(stack, rx);
|
|
2632
2647
|
}
|
|
2633
2648
|
}
|
|
@@ -5081,6 +5096,8 @@ var COMP_FIELD_BAD_SHAPE = "COMP_FIELD_BAD_SHAPE";
|
|
|
5081
5096
|
var ASYNC_HANDLER = "ASYNC_HANDLER";
|
|
5082
5097
|
var TOP_LEVEL_AT_RULE_IN_SCOPED_STYLE = "TOP_LEVEL_AT_RULE_IN_SCOPED_STYLE";
|
|
5083
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"]);
|
|
5084
5101
|
var X_KNOWN_OP_NAMES = new Set([
|
|
5085
5102
|
"slot",
|
|
5086
5103
|
"text",
|
|
@@ -5169,6 +5186,7 @@ function checkComponent(Comp, lx = new LintContext, { wellKnownExtras = EMPTY_SE
|
|
|
5169
5186
|
return lx.push({ componentName: Comp.name }, () => {
|
|
5170
5187
|
checkUnknownSpecKeys(lx, Comp, wellKnownExtras);
|
|
5171
5188
|
checkFieldDeclarations(lx, Comp);
|
|
5189
|
+
checkRecordFieldNameCollisions(lx, Comp);
|
|
5172
5190
|
checkProvidesAreAddressable(lx, Comp);
|
|
5173
5191
|
checkLookupShapes(lx, Comp);
|
|
5174
5192
|
checkHandlersNotAsync(lx, Comp);
|
|
@@ -5661,6 +5679,16 @@ function checkFieldDeclarations(lx, Comp) {
|
|
|
5661
5679
|
}
|
|
5662
5680
|
}
|
|
5663
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
|
+
}
|
|
5664
5692
|
function checkUnreferencedAlterHandlers(lx, Comp, referencedAlters) {
|
|
5665
5693
|
for (const name in Comp.alter) {
|
|
5666
5694
|
if (!referencedAlters.has(name)) {
|
|
@@ -7249,6 +7277,8 @@ function lintIdToMessage(id, info) {
|
|
|
7249
7277
|
return `'$${info.name}' is a method reference, but '${info.name}' is defined as an input handler${fmtEventSuffix(info)}`;
|
|
7250
7278
|
case "INPUT_HANDLER_METHOD_FOR_INPUT_HANDLER":
|
|
7251
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}'))`;
|
|
7252
7282
|
case "FIELD_VAL_NOT_DEFINED":
|
|
7253
7283
|
return `Field '.${info.name}' is not defined${fmtOriginSuffix(info)}`;
|
|
7254
7284
|
case "FIELD_VAL_IS_METHOD":
|
|
@@ -8562,6 +8592,7 @@ export {
|
|
|
8562
8592
|
GLOBAL_SELECTOR_IN_SCOPED_STYLE,
|
|
8563
8593
|
FIELD_VAL_NOT_DEFINED,
|
|
8564
8594
|
FIELD_VAL_IS_METHOD,
|
|
8595
|
+
FIELD_NAME_RESERVED_BY_RECORD,
|
|
8565
8596
|
FIELD_CLASS,
|
|
8566
8597
|
ExampleIndex,
|
|
8567
8598
|
DescribeResult,
|
package/dist/tutuca-dev.js
CHANGED
|
@@ -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,
|
|
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
|
-
|
|
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
|
-
|
|
9529
|
+
if (dom != null)
|
|
9530
|
+
this.pushEachEntry(r, nid, attrName, key, dom);
|
|
9526
9531
|
this.cache.set(cachePath, cacheKey, dom);
|
|
9527
9532
|
}
|
|
9528
9533
|
};
|
|
@@ -9807,7 +9812,8 @@ function parseXOp(attrs, childs, opIdx, px) {
|
|
|
9807
9812
|
if (attrs.length <= opIdx)
|
|
9808
9813
|
return maybeFragment(childs);
|
|
9809
9814
|
const { name, value } = attrs[opIdx];
|
|
9810
|
-
const
|
|
9815
|
+
const asAttr = attrs.getNamedItem("as")?.value ?? null;
|
|
9816
|
+
const as = asAttr === null ? null : parseViewName(asAttr, px);
|
|
9811
9817
|
let node;
|
|
9812
9818
|
switch (name) {
|
|
9813
9819
|
case "slot":
|
|
@@ -9847,6 +9853,9 @@ function parseXOpVal(opName, value, px, parserFn) {
|
|
|
9847
9853
|
px.onParseIssue("bad-value", { role: "x-op", op: opName, value });
|
|
9848
9854
|
return val;
|
|
9849
9855
|
}
|
|
9856
|
+
function parseViewName(s, px) {
|
|
9857
|
+
return vp.parseText(s, px) ?? vp.const(s);
|
|
9858
|
+
}
|
|
9850
9859
|
function processXExtras(node, attrs, opName, startIdx, px) {
|
|
9851
9860
|
const { consumed, wrappable } = X_OPS[opName];
|
|
9852
9861
|
const wrappers = [];
|
|
@@ -9943,9 +9952,12 @@ class Macro {
|
|
|
9943
9952
|
}
|
|
9944
9953
|
|
|
9945
9954
|
class RenderViewId extends ANode {
|
|
9946
|
-
constructor(nodeId, val,
|
|
9955
|
+
constructor(nodeId, val, viewVal) {
|
|
9947
9956
|
super(nodeId, val);
|
|
9948
|
-
this.
|
|
9957
|
+
this.viewVal = viewVal;
|
|
9958
|
+
}
|
|
9959
|
+
evalViewName(stack) {
|
|
9960
|
+
return this.viewVal ? this.viewVal.eval(stack) : null;
|
|
9949
9961
|
}
|
|
9950
9962
|
setDataAttr(_key, _val) {}
|
|
9951
9963
|
}
|
|
@@ -9959,7 +9971,7 @@ function dynRenderStep(comp, name, key) {
|
|
|
9959
9971
|
class RenderNode extends RenderViewId {
|
|
9960
9972
|
render(stack, rx) {
|
|
9961
9973
|
const newStack = stack.enter(this.val.eval(stack), {}, true);
|
|
9962
|
-
return rx.renderIt(newStack, this, "", this.
|
|
9974
|
+
return rx.renderIt(newStack, this, "", this.evalViewName(stack));
|
|
9963
9975
|
}
|
|
9964
9976
|
toPathStep(ctx) {
|
|
9965
9977
|
if (this.val instanceof DynVal)
|
|
@@ -9971,7 +9983,7 @@ class RenderNode extends RenderViewId {
|
|
|
9971
9983
|
class RenderItNode extends RenderViewId {
|
|
9972
9984
|
render(stack, rx) {
|
|
9973
9985
|
const newStack = stack.enter(stack.it, {}, true);
|
|
9974
|
-
return rx.renderIt(newStack, this, "", this.
|
|
9986
|
+
return rx.renderIt(newStack, this, "", this.evalViewName(stack));
|
|
9975
9987
|
}
|
|
9976
9988
|
toPathStep(ctx) {
|
|
9977
9989
|
const next = ctx.next();
|
|
@@ -9988,12 +10000,12 @@ class RenderItNode extends RenderViewId {
|
|
|
9988
10000
|
}
|
|
9989
10001
|
|
|
9990
10002
|
class RenderEachNode extends RenderViewId {
|
|
9991
|
-
constructor(nodeId, val,
|
|
9992
|
-
super(nodeId, val,
|
|
10003
|
+
constructor(nodeId, val, viewVal) {
|
|
10004
|
+
super(nodeId, val, viewVal);
|
|
9993
10005
|
this.iterInfo = new IterInfo(val, null, null, null);
|
|
9994
10006
|
}
|
|
9995
10007
|
render(stack, rx) {
|
|
9996
|
-
return rx.renderEach(stack, this.iterInfo, this, this.
|
|
10008
|
+
return rx.renderEach(stack, this.iterInfo, this, this.evalViewName(stack));
|
|
9997
10009
|
}
|
|
9998
10010
|
toPathStep(ctx) {
|
|
9999
10011
|
if (this.val instanceof DynVal)
|
|
@@ -10279,6 +10291,9 @@ class View {
|
|
|
10279
10291
|
this.anode = optimizeNode(this.anode);
|
|
10280
10292
|
}
|
|
10281
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
|
+
}
|
|
10282
10297
|
return this.anode.render(stack, rx);
|
|
10283
10298
|
}
|
|
10284
10299
|
}
|
|
@@ -12732,6 +12747,8 @@ var COMP_FIELD_BAD_SHAPE = "COMP_FIELD_BAD_SHAPE";
|
|
|
12732
12747
|
var ASYNC_HANDLER = "ASYNC_HANDLER";
|
|
12733
12748
|
var TOP_LEVEL_AT_RULE_IN_SCOPED_STYLE = "TOP_LEVEL_AT_RULE_IN_SCOPED_STYLE";
|
|
12734
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"]);
|
|
12735
12752
|
var X_KNOWN_OP_NAMES = new Set([
|
|
12736
12753
|
"slot",
|
|
12737
12754
|
"text",
|
|
@@ -12820,6 +12837,7 @@ function checkComponent(Comp, lx = new LintContext, { wellKnownExtras = EMPTY_SE
|
|
|
12820
12837
|
return lx.push({ componentName: Comp.name }, () => {
|
|
12821
12838
|
checkUnknownSpecKeys(lx, Comp, wellKnownExtras);
|
|
12822
12839
|
checkFieldDeclarations(lx, Comp);
|
|
12840
|
+
checkRecordFieldNameCollisions(lx, Comp);
|
|
12823
12841
|
checkProvidesAreAddressable(lx, Comp);
|
|
12824
12842
|
checkLookupShapes(lx, Comp);
|
|
12825
12843
|
checkHandlersNotAsync(lx, Comp);
|
|
@@ -13312,6 +13330,16 @@ function checkFieldDeclarations(lx, Comp) {
|
|
|
13312
13330
|
}
|
|
13313
13331
|
}
|
|
13314
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
|
+
}
|
|
13315
13343
|
function checkUnreferencedAlterHandlers(lx, Comp, referencedAlters) {
|
|
13316
13344
|
for (const name in Comp.alter) {
|
|
13317
13345
|
if (!referencedAlters.has(name)) {
|
|
@@ -14900,6 +14928,8 @@ function lintIdToMessage(id, info) {
|
|
|
14900
14928
|
return `'$${info.name}' is a method reference, but '${info.name}' is defined as an input handler${fmtEventSuffix(info)}`;
|
|
14901
14929
|
case "INPUT_HANDLER_METHOD_FOR_INPUT_HANDLER":
|
|
14902
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}'))`;
|
|
14903
14933
|
case "FIELD_VAL_NOT_DEFINED":
|
|
14904
14934
|
return `Field '.${info.name}' is not defined${fmtOriginSuffix(info)}`;
|
|
14905
14935
|
case "FIELD_VAL_IS_METHOD":
|
|
@@ -16156,6 +16186,7 @@ export {
|
|
|
16156
16186
|
GLOBAL_SELECTOR_IN_SCOPED_STYLE,
|
|
16157
16187
|
FIELD_VAL_NOT_DEFINED,
|
|
16158
16188
|
FIELD_VAL_IS_METHOD,
|
|
16189
|
+
FIELD_NAME_RESERVED_BY_RECORD,
|
|
16159
16190
|
FIELD_CLASS,
|
|
16160
16191
|
ExampleIndex,
|
|
16161
16192
|
DescribeResult,
|