tutuca 0.9.108 → 0.9.110
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 +25 -19
- package/dist/tutuca-components.js +6 -6
- package/dist/tutuca-dev.ext.js +24 -18
- package/dist/tutuca-dev.js +24 -18
- package/dist/tutuca-dev.min.js +2 -2
- package/dist/tutuca-extra.ext.js +6 -3
- package/dist/tutuca-extra.js +6 -3
- package/dist/tutuca-extra.min.js +1 -1
- package/dist/tutuca.ext.js +6 -3
- package/dist/tutuca.js +6 -3
- package/dist/tutuca.min.js +1 -1
- package/package.json +1 -1
- package/skill/tutuca/cli.md +13 -1
- package/skill/tutuca/core.md +10 -6
- package/skill/tutuca/iteration.md +15 -9
- package/skill/tutuca/patterns/README.md +1 -1
- package/skill/tutuca-source/tutuca.ext.js +6 -3
package/dist/tutuca-cli.js
CHANGED
|
@@ -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
|
}),
|
|
@@ -9341,12 +9344,12 @@ function checkEventHandlersHaveImpls(lx, Comp, referencedInputs) {
|
|
|
9341
9344
|
function reportUnknownName(lx, code, name, candidates, info) {
|
|
9342
9345
|
lx.error(code, { ...info, name }, replaceNameSuggestion(name, candidates));
|
|
9343
9346
|
}
|
|
9344
|
-
function checkConsistentAttrVal(lx, val, env, skipNameVal = false, errCtx = null) {
|
|
9347
|
+
function checkConsistentAttrVal(lx, val, env, skipNameVal = false, errCtx = null, isRoot = true) {
|
|
9345
9348
|
const check = ATTR_VAL_CHECKERS[val?.constructor.name];
|
|
9346
9349
|
if (check === undefined)
|
|
9347
9350
|
return;
|
|
9348
|
-
const recurse = (sub) => checkConsistentAttrVal(lx, sub, env, skipNameVal, errCtx);
|
|
9349
|
-
check({ lx, val, env, errCtx, skipNameVal, recurse });
|
|
9351
|
+
const recurse = (sub) => checkConsistentAttrVal(lx, sub, env, skipNameVal, errCtx, false);
|
|
9352
|
+
check({ lx, val, env, errCtx, skipNameVal, recurse, isRoot });
|
|
9350
9353
|
}
|
|
9351
9354
|
function nodeCtxForNode(nodeKind) {
|
|
9352
9355
|
return NODE_KIND_TO_CTX[nodeKind] ?? null;
|
|
@@ -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
|
|
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.",
|
|
@@ -9774,8 +9777,8 @@ var init_lint_check = __esm(() => {
|
|
|
9774
9777
|
]);
|
|
9775
9778
|
BOOL_CONDITION_ORIGINS = new Set(["@show", "@hide", "<x show>", "<x hide>"]);
|
|
9776
9779
|
ATTR_VAL_CHECKERS = {
|
|
9777
|
-
ConstVal({ lx, val, errCtx }) {
|
|
9778
|
-
if (isBoolConditionCtx(errCtx) && typeof val.val !== "boolean")
|
|
9780
|
+
ConstVal({ lx, val, errCtx, isRoot }) {
|
|
9781
|
+
if (isRoot && isBoolConditionCtx(errCtx) && typeof val.val !== "boolean")
|
|
9779
9782
|
lx.warn(CONSTANT_CONDITION, { ...errCtx, literal: String(val) });
|
|
9780
9783
|
},
|
|
9781
9784
|
FieldVal({ lx, val, env, errCtx }) {
|
|
@@ -9813,11 +9816,11 @@ var init_lint_check = __esm(() => {
|
|
|
9813
9816
|
if (!skipNameVal && !isKnownHandlerName(val.name))
|
|
9814
9817
|
reportUnknownName(lx, UNKNOWN_HANDLER_ARG_NAME, val.name, KNOWN_HANDLER_NAMES, errCtx);
|
|
9815
9818
|
},
|
|
9816
|
-
StrTplVal({ lx, val, errCtx, recurse }) {
|
|
9819
|
+
StrTplVal({ lx, val, errCtx, recurse, isRoot }) {
|
|
9817
9820
|
const vs = val.vals;
|
|
9818
9821
|
const literal = val.toLiteralSource();
|
|
9819
9822
|
if (literal !== null) {
|
|
9820
|
-
if (isBoolConditionCtx(errCtx))
|
|
9823
|
+
if (isRoot && isBoolConditionCtx(errCtx))
|
|
9821
9824
|
lx.warn(CONSTANT_CONDITION, { ...errCtx, literal });
|
|
9822
9825
|
else
|
|
9823
9826
|
lx.hint(PLACEHOLDERLESS_TEMPLATE_STRING, { ...errCtx, literal }, fixTo(`$${literal}`, literal));
|
|
@@ -9834,7 +9837,10 @@ var init_lint_check = __esm(() => {
|
|
|
9834
9837
|
if (env.alter[val.name] === undefined)
|
|
9835
9838
|
reportUnknownName(lx, ALT_HANDLER_NOT_DEFINED, val.name, Object.keys(env.alter), errCtx);
|
|
9836
9839
|
},
|
|
9837
|
-
PredicateVal({ val, recurse }) {
|
|
9840
|
+
PredicateVal({ lx, val, errCtx, recurse }) {
|
|
9841
|
+
const isConstArg = (a) => a.constructor.name === "ConstVal" || a.constructor.name === "StrTplVal" && a.toLiteralSource() !== null;
|
|
9842
|
+
if (isBoolConditionCtx(errCtx) && val.args.every(isConstArg))
|
|
9843
|
+
lx.warn(CONSTANT_CONDITION, { ...errCtx, literal: String(val) });
|
|
9838
9844
|
for (const arg of val.args)
|
|
9839
9845
|
recurse(arg);
|
|
9840
9846
|
},
|
|
@@ -10073,7 +10079,7 @@ var init_lint_rules = __esm(() => {
|
|
|
10073
10079
|
code: DEPRECATED_BARE_X_DIRECTIVE,
|
|
10074
10080
|
level: "warn",
|
|
10075
10081
|
group: "Templates / events",
|
|
10076
|
-
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`)."
|
|
10077
10083
|
},
|
|
10078
10084
|
{
|
|
10079
10085
|
code: BAD_VALUE,
|
|
@@ -10209,7 +10215,7 @@ function badValueMessage(info) {
|
|
|
10209
10215
|
case "handler-arg":
|
|
10210
10216
|
return `Cannot parse handler argument ${v}`;
|
|
10211
10217
|
case "macro-var":
|
|
10212
|
-
return `Macro
|
|
10218
|
+
return `Macro parameter '^${info.name}' is not defined`;
|
|
10213
10219
|
default:
|
|
10214
10220
|
return `Cannot parse value ${v}`;
|
|
10215
10221
|
}
|
|
@@ -10289,7 +10295,7 @@ function lintIdToMessage(id, info) {
|
|
|
10289
10295
|
case "ALT_HANDLER_NOT_REFERENCED":
|
|
10290
10296
|
return `Alter handler '${info.name}' is defined but never used — remove it or reference it from @when, @enrich-with, or @loop-with`;
|
|
10291
10297
|
case "DYN_VAL_NOT_DEFINED":
|
|
10292
|
-
return `Dynamic
|
|
10298
|
+
return `Dynamic binding '*${info.name}' is not defined${fmtOriginSuffix(info)}`;
|
|
10293
10299
|
case "DYN_ALIAS_NOT_REFERENCED":
|
|
10294
10300
|
return `Lookup '${info.name}' is defined but never used — remove it or reference it as '*${info.name}' in a view`;
|
|
10295
10301
|
case "PROVIDE_NOT_ADDRESSABLE":
|
|
@@ -10327,9 +10333,9 @@ function lintIdToMessage(id, info) {
|
|
|
10327
10333
|
return `Enrich handler '${info.name}' only copies members of the loop value — read them directly${reads ? ` (${reads})` : ""} and remove the '@enrich-with'`;
|
|
10328
10334
|
}
|
|
10329
10335
|
case "REDUNDANT_TEMPLATE_STRING":
|
|
10330
|
-
return `Redundant template
|
|
10336
|
+
return `Redundant string template — '{${info.simpler}}' should be just '${info.simpler}'${fmtOriginSuffix(info)}`;
|
|
10331
10337
|
case "PLACEHOLDERLESS_TEMPLATE_STRING":
|
|
10332
|
-
return `
|
|
10338
|
+
return `String template has no dynamic parts — use the string literal ${info.literal} instead${fmtOriginSuffix(info)}`;
|
|
10333
10339
|
case "CONSTANT_CONDITION":
|
|
10334
10340
|
return `Condition is the constant literal ${info.literal} — it never changes; reference a field ('.name') or a method ('$name') instead${fmtOriginSuffix(info)}`;
|
|
10335
10341
|
case "UNKNOWN_COMPONENT_SPEC_KEY":
|
|
@@ -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
|
|
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
|
|
1651
|
+
return `Redundant string template — '{${info.simpler}}' should be just '${info.simpler}'${originSuffix(info)}`;
|
|
1652
1652
|
case "PLACEHOLDERLESS_TEMPLATE_STRING":
|
|
1653
|
-
return `
|
|
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":
|
package/dist/tutuca-dev.ext.js
CHANGED
|
@@ -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
|
|
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.",
|
|
@@ -5515,8 +5518,8 @@ function reportUnknownName(lx, code, name, candidates, info) {
|
|
|
5515
5518
|
var BOOL_CONDITION_ORIGINS = new Set(["@show", "@hide", "<x show>", "<x hide>"]);
|
|
5516
5519
|
var isBoolConditionCtx = (errCtx) => errCtx != null && (BOOL_CONDITION_ORIGINS.has(errCtx.originAttr) || errCtx.branch === "@if");
|
|
5517
5520
|
var ATTR_VAL_CHECKERS = {
|
|
5518
|
-
ConstVal({ lx, val, errCtx }) {
|
|
5519
|
-
if (isBoolConditionCtx(errCtx) && typeof val.val !== "boolean")
|
|
5521
|
+
ConstVal({ lx, val, errCtx, isRoot }) {
|
|
5522
|
+
if (isRoot && isBoolConditionCtx(errCtx) && typeof val.val !== "boolean")
|
|
5520
5523
|
lx.warn(CONSTANT_CONDITION, { ...errCtx, literal: String(val) });
|
|
5521
5524
|
},
|
|
5522
5525
|
FieldVal({ lx, val, env, errCtx }) {
|
|
@@ -5554,11 +5557,11 @@ var ATTR_VAL_CHECKERS = {
|
|
|
5554
5557
|
if (!skipNameVal && !isKnownHandlerName(val.name))
|
|
5555
5558
|
reportUnknownName(lx, UNKNOWN_HANDLER_ARG_NAME, val.name, KNOWN_HANDLER_NAMES, errCtx);
|
|
5556
5559
|
},
|
|
5557
|
-
StrTplVal({ lx, val, errCtx, recurse }) {
|
|
5560
|
+
StrTplVal({ lx, val, errCtx, recurse, isRoot }) {
|
|
5558
5561
|
const vs = val.vals;
|
|
5559
5562
|
const literal = val.toLiteralSource();
|
|
5560
5563
|
if (literal !== null) {
|
|
5561
|
-
if (isBoolConditionCtx(errCtx))
|
|
5564
|
+
if (isRoot && isBoolConditionCtx(errCtx))
|
|
5562
5565
|
lx.warn(CONSTANT_CONDITION, { ...errCtx, literal });
|
|
5563
5566
|
else
|
|
5564
5567
|
lx.hint(PLACEHOLDERLESS_TEMPLATE_STRING, { ...errCtx, literal }, fixTo(`$${literal}`, literal));
|
|
@@ -5575,7 +5578,10 @@ var ATTR_VAL_CHECKERS = {
|
|
|
5575
5578
|
if (env.alter[val.name] === undefined)
|
|
5576
5579
|
reportUnknownName(lx, ALT_HANDLER_NOT_DEFINED, val.name, Object.keys(env.alter), errCtx);
|
|
5577
5580
|
},
|
|
5578
|
-
PredicateVal({ val, recurse }) {
|
|
5581
|
+
PredicateVal({ lx, val, errCtx, recurse }) {
|
|
5582
|
+
const isConstArg = (a) => a.constructor.name === "ConstVal" || a.constructor.name === "StrTplVal" && a.toLiteralSource() !== null;
|
|
5583
|
+
if (isBoolConditionCtx(errCtx) && val.args.every(isConstArg))
|
|
5584
|
+
lx.warn(CONSTANT_CONDITION, { ...errCtx, literal: String(val) });
|
|
5579
5585
|
for (const arg of val.args)
|
|
5580
5586
|
recurse(arg);
|
|
5581
5587
|
},
|
|
@@ -5585,12 +5591,12 @@ var ATTR_VAL_CHECKERS = {
|
|
|
5585
5591
|
reportUnknownName(lx, DYN_VAL_NOT_DEFINED, val.name, Object.keys(env.dynamicMap), errCtx);
|
|
5586
5592
|
}
|
|
5587
5593
|
};
|
|
5588
|
-
function checkConsistentAttrVal(lx, val, env, skipNameVal = false, errCtx = null) {
|
|
5594
|
+
function checkConsistentAttrVal(lx, val, env, skipNameVal = false, errCtx = null, isRoot = true) {
|
|
5589
5595
|
const check = ATTR_VAL_CHECKERS[val?.constructor.name];
|
|
5590
5596
|
if (check === undefined)
|
|
5591
5597
|
return;
|
|
5592
|
-
const recurse = (sub) => checkConsistentAttrVal(lx, sub, env, skipNameVal, errCtx);
|
|
5593
|
-
check({ lx, val, env, errCtx, skipNameVal, recurse });
|
|
5598
|
+
const recurse = (sub) => checkConsistentAttrVal(lx, sub, env, skipNameVal, errCtx, false);
|
|
5599
|
+
check({ lx, val, env, errCtx, skipNameVal, recurse, isRoot });
|
|
5594
5600
|
}
|
|
5595
5601
|
var NODE_KIND_TO_CTX = {
|
|
5596
5602
|
RenderTextNode: { originAttr: "<x text>" },
|
|
@@ -5725,11 +5731,11 @@ function checkConsistentAttrs(lx, Comp, referencedAlters, referencedDynamics) {
|
|
|
5725
5731
|
const iter = node.iterInfo;
|
|
5726
5732
|
if (iter.whenVal)
|
|
5727
5733
|
checkConsistentAttrVal(lx, iter.whenVal, env, false, {
|
|
5728
|
-
originAttr: "<x render-each when>"
|
|
5734
|
+
originAttr: "<x render-each @when>"
|
|
5729
5735
|
});
|
|
5730
5736
|
if (iter.loopWithVal)
|
|
5731
5737
|
checkConsistentAttrVal(lx, iter.loopWithVal, env, false, {
|
|
5732
|
-
originAttr: "<x render-each loop-with>"
|
|
5738
|
+
originAttr: "<x render-each @loop-with>"
|
|
5733
5739
|
});
|
|
5734
5740
|
}
|
|
5735
5741
|
}
|
|
@@ -7396,7 +7402,7 @@ function badValueMessage(info) {
|
|
|
7396
7402
|
case "handler-arg":
|
|
7397
7403
|
return `Cannot parse handler argument ${v}`;
|
|
7398
7404
|
case "macro-var":
|
|
7399
|
-
return `Macro
|
|
7405
|
+
return `Macro parameter '^${info.name}' is not defined`;
|
|
7400
7406
|
default:
|
|
7401
7407
|
return `Cannot parse value ${v}`;
|
|
7402
7408
|
}
|
|
@@ -7476,7 +7482,7 @@ function lintIdToMessage(id, info) {
|
|
|
7476
7482
|
case "ALT_HANDLER_NOT_REFERENCED":
|
|
7477
7483
|
return `Alter handler '${info.name}' is defined but never used — remove it or reference it from @when, @enrich-with, or @loop-with`;
|
|
7478
7484
|
case "DYN_VAL_NOT_DEFINED":
|
|
7479
|
-
return `Dynamic
|
|
7485
|
+
return `Dynamic binding '*${info.name}' is not defined${fmtOriginSuffix(info)}`;
|
|
7480
7486
|
case "DYN_ALIAS_NOT_REFERENCED":
|
|
7481
7487
|
return `Lookup '${info.name}' is defined but never used — remove it or reference it as '*${info.name}' in a view`;
|
|
7482
7488
|
case "PROVIDE_NOT_ADDRESSABLE":
|
|
@@ -7514,9 +7520,9 @@ function lintIdToMessage(id, info) {
|
|
|
7514
7520
|
return `Enrich handler '${info.name}' only copies members of the loop value — read them directly${reads ? ` (${reads})` : ""} and remove the '@enrich-with'`;
|
|
7515
7521
|
}
|
|
7516
7522
|
case "REDUNDANT_TEMPLATE_STRING":
|
|
7517
|
-
return `Redundant template
|
|
7523
|
+
return `Redundant string template — '{${info.simpler}}' should be just '${info.simpler}'${fmtOriginSuffix(info)}`;
|
|
7518
7524
|
case "PLACEHOLDERLESS_TEMPLATE_STRING":
|
|
7519
|
-
return `
|
|
7525
|
+
return `String template has no dynamic parts — use the string literal ${info.literal} instead${fmtOriginSuffix(info)}`;
|
|
7520
7526
|
case "CONSTANT_CONDITION":
|
|
7521
7527
|
return `Condition is the constant literal ${info.literal} — it never changes; reference a field ('.name') or a method ('$name') instead${fmtOriginSuffix(info)}`;
|
|
7522
7528
|
case "UNKNOWN_COMPONENT_SPEC_KEY":
|
package/dist/tutuca-dev.js
CHANGED
|
@@ -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
|
|
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.",
|
|
@@ -13164,8 +13167,8 @@ function reportUnknownName(lx, code, name, candidates, info) {
|
|
|
13164
13167
|
var BOOL_CONDITION_ORIGINS = new Set(["@show", "@hide", "<x show>", "<x hide>"]);
|
|
13165
13168
|
var isBoolConditionCtx = (errCtx) => errCtx != null && (BOOL_CONDITION_ORIGINS.has(errCtx.originAttr) || errCtx.branch === "@if");
|
|
13166
13169
|
var ATTR_VAL_CHECKERS = {
|
|
13167
|
-
ConstVal({ lx, val, errCtx }) {
|
|
13168
|
-
if (isBoolConditionCtx(errCtx) && typeof val.val !== "boolean")
|
|
13170
|
+
ConstVal({ lx, val, errCtx, isRoot }) {
|
|
13171
|
+
if (isRoot && isBoolConditionCtx(errCtx) && typeof val.val !== "boolean")
|
|
13169
13172
|
lx.warn(CONSTANT_CONDITION, { ...errCtx, literal: String(val) });
|
|
13170
13173
|
},
|
|
13171
13174
|
FieldVal({ lx, val, env, errCtx }) {
|
|
@@ -13203,11 +13206,11 @@ var ATTR_VAL_CHECKERS = {
|
|
|
13203
13206
|
if (!skipNameVal && !isKnownHandlerName(val.name))
|
|
13204
13207
|
reportUnknownName(lx, UNKNOWN_HANDLER_ARG_NAME, val.name, KNOWN_HANDLER_NAMES, errCtx);
|
|
13205
13208
|
},
|
|
13206
|
-
StrTplVal({ lx, val, errCtx, recurse }) {
|
|
13209
|
+
StrTplVal({ lx, val, errCtx, recurse, isRoot }) {
|
|
13207
13210
|
const vs = val.vals;
|
|
13208
13211
|
const literal = val.toLiteralSource();
|
|
13209
13212
|
if (literal !== null) {
|
|
13210
|
-
if (isBoolConditionCtx(errCtx))
|
|
13213
|
+
if (isRoot && isBoolConditionCtx(errCtx))
|
|
13211
13214
|
lx.warn(CONSTANT_CONDITION, { ...errCtx, literal });
|
|
13212
13215
|
else
|
|
13213
13216
|
lx.hint(PLACEHOLDERLESS_TEMPLATE_STRING, { ...errCtx, literal }, fixTo(`$${literal}`, literal));
|
|
@@ -13224,7 +13227,10 @@ var ATTR_VAL_CHECKERS = {
|
|
|
13224
13227
|
if (env.alter[val.name] === undefined)
|
|
13225
13228
|
reportUnknownName(lx, ALT_HANDLER_NOT_DEFINED, val.name, Object.keys(env.alter), errCtx);
|
|
13226
13229
|
},
|
|
13227
|
-
PredicateVal({ val, recurse }) {
|
|
13230
|
+
PredicateVal({ lx, val, errCtx, recurse }) {
|
|
13231
|
+
const isConstArg = (a) => a.constructor.name === "ConstVal" || a.constructor.name === "StrTplVal" && a.toLiteralSource() !== null;
|
|
13232
|
+
if (isBoolConditionCtx(errCtx) && val.args.every(isConstArg))
|
|
13233
|
+
lx.warn(CONSTANT_CONDITION, { ...errCtx, literal: String(val) });
|
|
13228
13234
|
for (const arg of val.args)
|
|
13229
13235
|
recurse(arg);
|
|
13230
13236
|
},
|
|
@@ -13234,12 +13240,12 @@ var ATTR_VAL_CHECKERS = {
|
|
|
13234
13240
|
reportUnknownName(lx, DYN_VAL_NOT_DEFINED, val.name, Object.keys(env.dynamicMap), errCtx);
|
|
13235
13241
|
}
|
|
13236
13242
|
};
|
|
13237
|
-
function checkConsistentAttrVal(lx, val, env, skipNameVal = false, errCtx = null) {
|
|
13243
|
+
function checkConsistentAttrVal(lx, val, env, skipNameVal = false, errCtx = null, isRoot = true) {
|
|
13238
13244
|
const check = ATTR_VAL_CHECKERS[val?.constructor.name];
|
|
13239
13245
|
if (check === undefined)
|
|
13240
13246
|
return;
|
|
13241
|
-
const recurse = (sub) => checkConsistentAttrVal(lx, sub, env, skipNameVal, errCtx);
|
|
13242
|
-
check({ lx, val, env, errCtx, skipNameVal, recurse });
|
|
13247
|
+
const recurse = (sub) => checkConsistentAttrVal(lx, sub, env, skipNameVal, errCtx, false);
|
|
13248
|
+
check({ lx, val, env, errCtx, skipNameVal, recurse, isRoot });
|
|
13243
13249
|
}
|
|
13244
13250
|
var NODE_KIND_TO_CTX = {
|
|
13245
13251
|
RenderTextNode: { originAttr: "<x text>" },
|
|
@@ -13374,11 +13380,11 @@ function checkConsistentAttrs(lx, Comp, referencedAlters, referencedDynamics) {
|
|
|
13374
13380
|
const iter = node.iterInfo;
|
|
13375
13381
|
if (iter.whenVal)
|
|
13376
13382
|
checkConsistentAttrVal(lx, iter.whenVal, env, false, {
|
|
13377
|
-
originAttr: "<x render-each when>"
|
|
13383
|
+
originAttr: "<x render-each @when>"
|
|
13378
13384
|
});
|
|
13379
13385
|
if (iter.loopWithVal)
|
|
13380
13386
|
checkConsistentAttrVal(lx, iter.loopWithVal, env, false, {
|
|
13381
|
-
originAttr: "<x render-each loop-with>"
|
|
13387
|
+
originAttr: "<x render-each @loop-with>"
|
|
13382
13388
|
});
|
|
13383
13389
|
}
|
|
13384
13390
|
}
|
|
@@ -15045,7 +15051,7 @@ function badValueMessage(info) {
|
|
|
15045
15051
|
case "handler-arg":
|
|
15046
15052
|
return `Cannot parse handler argument ${v}`;
|
|
15047
15053
|
case "macro-var":
|
|
15048
|
-
return `Macro
|
|
15054
|
+
return `Macro parameter '^${info.name}' is not defined`;
|
|
15049
15055
|
default:
|
|
15050
15056
|
return `Cannot parse value ${v}`;
|
|
15051
15057
|
}
|
|
@@ -15125,7 +15131,7 @@ function lintIdToMessage(id, info) {
|
|
|
15125
15131
|
case "ALT_HANDLER_NOT_REFERENCED":
|
|
15126
15132
|
return `Alter handler '${info.name}' is defined but never used — remove it or reference it from @when, @enrich-with, or @loop-with`;
|
|
15127
15133
|
case "DYN_VAL_NOT_DEFINED":
|
|
15128
|
-
return `Dynamic
|
|
15134
|
+
return `Dynamic binding '*${info.name}' is not defined${fmtOriginSuffix(info)}`;
|
|
15129
15135
|
case "DYN_ALIAS_NOT_REFERENCED":
|
|
15130
15136
|
return `Lookup '${info.name}' is defined but never used — remove it or reference it as '*${info.name}' in a view`;
|
|
15131
15137
|
case "PROVIDE_NOT_ADDRESSABLE":
|
|
@@ -15163,9 +15169,9 @@ function lintIdToMessage(id, info) {
|
|
|
15163
15169
|
return `Enrich handler '${info.name}' only copies members of the loop value — read them directly${reads ? ` (${reads})` : ""} and remove the '@enrich-with'`;
|
|
15164
15170
|
}
|
|
15165
15171
|
case "REDUNDANT_TEMPLATE_STRING":
|
|
15166
|
-
return `Redundant template
|
|
15172
|
+
return `Redundant string template — '{${info.simpler}}' should be just '${info.simpler}'${fmtOriginSuffix(info)}`;
|
|
15167
15173
|
case "PLACEHOLDERLESS_TEMPLATE_STRING":
|
|
15168
|
-
return `
|
|
15174
|
+
return `String template has no dynamic parts — use the string literal ${info.literal} instead${fmtOriginSuffix(info)}`;
|
|
15169
15175
|
case "CONSTANT_CONDITION":
|
|
15170
15176
|
return `Condition is the constant literal ${info.literal} — it never changes; reference a field ('.name') or a method ('$name') instead${fmtOriginSuffix(info)}`;
|
|
15171
15177
|
case "UNKNOWN_COMPONENT_SPEC_KEY":
|