tutuca 0.9.107 → 0.9.109
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 +250 -143
- package/dist/tutuca-components.js +4 -2
- package/dist/tutuca-dev.ext.js +230 -138
- package/dist/tutuca-dev.js +230 -138
- package/dist/tutuca-dev.min.js +3 -3
- package/dist/tutuca-extra.ext.js +100 -118
- package/dist/tutuca-extra.js +100 -118
- package/dist/tutuca-extra.min.js +2 -2
- package/dist/tutuca-storybook.js +3 -3
- package/dist/tutuca.ext.js +100 -118
- package/dist/tutuca.js +100 -118
- package/dist/tutuca.min.js +2 -2
- package/package.json +1 -1
- package/skill/tutuca/core.md +10 -8
- package/skill/tutuca/iteration.md +3 -3
- package/skill/tutuca/patterns/filter-a-list.md +1 -1
- package/skill/tutuca/patterns/show-or-hide-content.md +1 -1
- package/skill/tutuca/request-response.md +3 -5
- package/skill/tutuca/semantics.md +1 -1
- package/skill/tutuca-source/tutuca.ext.js +100 -118
package/dist/tutuca-cli.js
CHANGED
|
@@ -4424,19 +4424,12 @@ class Path {
|
|
|
4424
4424
|
eventIds.push(eid);
|
|
4425
4425
|
const metas = metaChain(node.previousSibling);
|
|
4426
4426
|
let sawComp = false;
|
|
4427
|
-
for (
|
|
4428
|
-
const m = metas[i];
|
|
4427
|
+
for (const m of metas) {
|
|
4429
4428
|
if (m.$ === "Comp") {
|
|
4430
4429
|
sawComp = true;
|
|
4431
4430
|
if (!crossComponent(m.cid, m.vid))
|
|
4432
4431
|
return NO_EVENT_INFO;
|
|
4433
|
-
|
|
4434
|
-
if (outer?.$ === "Each" && outer.nid === m.nid) {
|
|
4435
|
-
nodeIds.push({ nid: outer.nid, si: outer.si, sk: outer.sk });
|
|
4436
|
-
i += 1;
|
|
4437
|
-
} else {
|
|
4438
|
-
nodeIds.push({ nid: m.nid });
|
|
4439
|
-
}
|
|
4432
|
+
nodeIds.push({ nid: m.nid });
|
|
4440
4433
|
} else {
|
|
4441
4434
|
nodeIds.push({ nid: m.nid, si: m.si, sk: m.sk });
|
|
4442
4435
|
}
|
|
@@ -4743,7 +4736,7 @@ class ValParser {
|
|
|
4743
4736
|
parseToken(s, px) {
|
|
4744
4737
|
const c0 = s.charCodeAt(0);
|
|
4745
4738
|
if (c0 === 39)
|
|
4746
|
-
return s.length >= 2 && s.charCodeAt(s.length - 1) === 39 ? new ConstVal(unescapeStr(s.slice(1, -1))
|
|
4739
|
+
return s.length >= 2 && s.charCodeAt(s.length - 1) === 39 ? new ConstVal(unescapeStr(s.slice(1, -1))) : null;
|
|
4747
4740
|
if (c0 === 36 && s.charCodeAt(1) === 39)
|
|
4748
4741
|
return s.length >= 3 && s.charCodeAt(s.length - 1) === 39 ? StrTplVal.parse(s.slice(2, -1), px) : null;
|
|
4749
4742
|
if (s.indexOf("[") !== -1 || s.indexOf("]") !== -1)
|
|
@@ -4768,14 +4761,18 @@ class ValParser {
|
|
|
4768
4761
|
}
|
|
4769
4762
|
case 36:
|
|
4770
4763
|
return mkVal(s.slice(1), MethodVal);
|
|
4771
|
-
case 64:
|
|
4772
|
-
|
|
4764
|
+
case 64: {
|
|
4765
|
+
const dot = s.indexOf(".", 1);
|
|
4766
|
+
if (dot === -1)
|
|
4767
|
+
return mkVal(s.slice(1), BindVal);
|
|
4768
|
+
const name = s.slice(1, dot);
|
|
4769
|
+
const member = s.slice(dot + 1);
|
|
4770
|
+
return isValidValId(name) && isValidValId(member) ? new BindMemberVal(name, member) : null;
|
|
4771
|
+
}
|
|
4773
4772
|
case 42:
|
|
4774
4773
|
return mkVal(s.slice(1), DynVal);
|
|
4775
4774
|
case 46:
|
|
4776
4775
|
return mkVal(s.slice(1), FieldVal);
|
|
4777
|
-
case 33:
|
|
4778
|
-
return mkVal(s.slice(1), RequestVal);
|
|
4779
4776
|
}
|
|
4780
4777
|
const num = VALID_FLOAT_RE.test(s) ? parseFloat(s) : null;
|
|
4781
4778
|
if (Number.isFinite(num))
|
|
@@ -4828,7 +4825,7 @@ class ValParser {
|
|
|
4828
4825
|
return this._parseSingle(s, px, G_PROVIDE);
|
|
4829
4826
|
}
|
|
4830
4827
|
parseHandlerArg(s, px) {
|
|
4831
|
-
return this._parseSingle(s, px,
|
|
4828
|
+
return this._parseSingle(s, px, G_VALUE);
|
|
4832
4829
|
}
|
|
4833
4830
|
parseMacroAttr(s, px) {
|
|
4834
4831
|
return this._parseSingle(s, px, G_ALL);
|
|
@@ -4860,7 +4857,7 @@ class ValParser {
|
|
|
4860
4857
|
const args = new Array(tokens.length - 1);
|
|
4861
4858
|
for (let i = 1;i < tokens.length; i++) {
|
|
4862
4859
|
const val = this.parseToken(tokens[i], px);
|
|
4863
|
-
if (val !== null && kindOf(val) &
|
|
4860
|
+
if (val !== null && kindOf(val) & G_VALUE)
|
|
4864
4861
|
args[i - 1] = val;
|
|
4865
4862
|
else {
|
|
4866
4863
|
if (report)
|
|
@@ -4886,7 +4883,7 @@ class ValParser {
|
|
|
4886
4883
|
for (let i = 0;i < arity; i++) {
|
|
4887
4884
|
const tok = tokens[i + 1];
|
|
4888
4885
|
const val = this.parseToken(tok, px);
|
|
4889
|
-
if (val === null || !(kindOf(val) &
|
|
4886
|
+
if (val === null || !(kindOf(val) & G_BOOL)) {
|
|
4890
4887
|
px.onParseIssue("bad-value", { role: "predicate-arg", value: tok });
|
|
4891
4888
|
return null;
|
|
4892
4889
|
}
|
|
@@ -4901,7 +4898,7 @@ function kindOf(val) {
|
|
|
4901
4898
|
if (val instanceof ConstVal)
|
|
4902
4899
|
return val.kind;
|
|
4903
4900
|
if (val instanceof StrTplVal)
|
|
4904
|
-
return
|
|
4901
|
+
return val.kind;
|
|
4905
4902
|
if (val instanceof SeqAccessVal)
|
|
4906
4903
|
return K_SEQ;
|
|
4907
4904
|
if (val instanceof FieldVal)
|
|
@@ -4912,8 +4909,6 @@ function kindOf(val) {
|
|
|
4912
4909
|
return K_BIND;
|
|
4913
4910
|
if (val instanceof DynVal)
|
|
4914
4911
|
return K_DYN;
|
|
4915
|
-
if (val instanceof RequestVal)
|
|
4916
|
-
return K_REQUEST;
|
|
4917
4912
|
if (val instanceof TypeVal)
|
|
4918
4913
|
return K_TYPE;
|
|
4919
4914
|
if (val instanceof NameVal)
|
|
@@ -4931,13 +4926,13 @@ class BaseVal {
|
|
|
4931
4926
|
return this.eval(stack);
|
|
4932
4927
|
}
|
|
4933
4928
|
}
|
|
4934
|
-
var VALID_VAL_ID_RE, isValidValId = (name) => VALID_VAL_ID_RE.test(name), VALID_FLOAT_RE, STR_TPL_SPLIT_RE, mkVal = (name, Cls) => isValidValId(name) ? new Cls(name) : null, VAL_TOKEN_RE, tokenizeValue = (s) => s.match(VAL_TOKEN_RE) ?? [], unescapeStr = (s) => s.replace(/\\(['\\])/g, "$1"), K_CONST = 1, K_STRTPL = 2, K_FIELD = 4, K_BIND = 8, K_DYN = 16, K_NAME = 32, K_TYPE = 64,
|
|
4929
|
+
var VALID_VAL_ID_RE, isValidValId = (name) => VALID_VAL_ID_RE.test(name), VALID_FLOAT_RE, STR_TPL_SPLIT_RE, mkVal = (name, Cls) => isValidValId(name) ? new Cls(name) : null, VAL_TOKEN_RE, tokenizeValue = (s) => s.match(VAL_TOKEN_RE) ?? [], unescapeStr = (s) => s.replace(/\\(['\\])/g, "$1"), K_CONST = 1, K_STRTPL = 2, K_FIELD = 4, K_BIND = 8, K_DYN = 16, K_NAME = 32, K_TYPE = 64, K_SEQ = 256, K_METHOD = 1024, G_BOOL, G_TEXT, G_COMPONENT, G_SEQUENCE, G_PROVIDE, G_FIELD, G_VALUE, G_ALL, predTruthy = (v) => {
|
|
4935
4930
|
const n = sizeOf(v);
|
|
4936
4931
|
return n === null ? !!v : n > 0;
|
|
4937
4932
|
}, PREDICATES, ConstVal, PredicateVal, VarVal, StrTplVal, NameVal, HandlerNameVal, mk404Handler = (type, name) => function(...args) {
|
|
4938
4933
|
console.warn("handler not found", { type, name, args }, this);
|
|
4939
4934
|
return this;
|
|
4940
|
-
}, TypeVal,
|
|
4935
|
+
}, TypeVal, RenderVal, RenderNameVal, BindVal, BindMemberVal, DynVal, FieldVal, MethodVal, SeqAccessVal, vp;
|
|
4941
4936
|
var init_value = __esm(() => {
|
|
4942
4937
|
init_immutable();
|
|
4943
4938
|
init_path();
|
|
@@ -4950,10 +4945,8 @@ var init_value = __esm(() => {
|
|
|
4950
4945
|
G_COMPONENT = K_FIELD | K_SEQ | K_DYN;
|
|
4951
4946
|
G_SEQUENCE = K_FIELD | K_DYN;
|
|
4952
4947
|
G_PROVIDE = K_FIELD | K_SEQ;
|
|
4953
|
-
G_FIELD = K_FIELD | K_METHOD | K_CONST |
|
|
4954
|
-
G_VALUE = K_FIELD | K_METHOD | K_BIND | K_DYN | K_NAME | K_TYPE |
|
|
4955
|
-
G_PRED_ARG = G_BOOL | K_STR;
|
|
4956
|
-
G_HANDLER_ARG = G_VALUE | K_STR;
|
|
4948
|
+
G_FIELD = K_FIELD | K_METHOD | K_CONST | K_SEQ;
|
|
4949
|
+
G_VALUE = K_FIELD | K_METHOD | K_BIND | K_DYN | K_NAME | K_TYPE | K_CONST;
|
|
4957
4950
|
G_ALL = G_VALUE | K_STRTPL | K_SEQ;
|
|
4958
4951
|
PREDICATES = {
|
|
4959
4952
|
"empty?": { name: "empty?", arity: 1, fn: (v) => v == null || sizeOf(v) === 0 },
|
|
@@ -5002,6 +4995,13 @@ var init_value = __esm(() => {
|
|
|
5002
4995
|
constructor(vals) {
|
|
5003
4996
|
super();
|
|
5004
4997
|
this.vals = vals;
|
|
4998
|
+
this.kind = this.isLiteral() ? K_CONST : K_STRTPL;
|
|
4999
|
+
}
|
|
5000
|
+
isLiteral() {
|
|
5001
|
+
for (const v of this.vals)
|
|
5002
|
+
if (!(v instanceof ConstVal) || v.fromMacroVar)
|
|
5003
|
+
return false;
|
|
5004
|
+
return true;
|
|
5005
5005
|
}
|
|
5006
5006
|
render(stack, _rx) {
|
|
5007
5007
|
return this.eval(stack);
|
|
@@ -5013,12 +5013,11 @@ var init_value = __esm(() => {
|
|
|
5013
5013
|
return strs.join("");
|
|
5014
5014
|
}
|
|
5015
5015
|
toLiteralSource() {
|
|
5016
|
+
if (!this.isLiteral())
|
|
5017
|
+
return null;
|
|
5016
5018
|
let out = "";
|
|
5017
|
-
for (const v of this.vals)
|
|
5018
|
-
if (!(v instanceof ConstVal) || v.fromMacroVar)
|
|
5019
|
-
return null;
|
|
5019
|
+
for (const v of this.vals)
|
|
5020
5020
|
out += v.val;
|
|
5021
|
-
}
|
|
5022
5021
|
return new ConstVal(out).toString();
|
|
5023
5022
|
}
|
|
5024
5023
|
static parse(s, px) {
|
|
@@ -5065,14 +5064,6 @@ var init_value = __esm(() => {
|
|
|
5065
5064
|
return stack.lookupType(this.name);
|
|
5066
5065
|
}
|
|
5067
5066
|
};
|
|
5068
|
-
RequestVal = class RequestVal extends NameVal {
|
|
5069
|
-
eval(stack) {
|
|
5070
|
-
return stack.lookupRequest(this.name);
|
|
5071
|
-
}
|
|
5072
|
-
toString() {
|
|
5073
|
-
return `!${this.name}`;
|
|
5074
|
-
}
|
|
5075
|
-
};
|
|
5076
5067
|
RenderVal = class RenderVal extends BaseVal {
|
|
5077
5068
|
render(stack, _rx) {
|
|
5078
5069
|
return this.eval(stack);
|
|
@@ -5092,6 +5083,19 @@ var init_value = __esm(() => {
|
|
|
5092
5083
|
return `@${this.name}`;
|
|
5093
5084
|
}
|
|
5094
5085
|
};
|
|
5086
|
+
BindMemberVal = class BindMemberVal extends BindVal {
|
|
5087
|
+
constructor(name, member) {
|
|
5088
|
+
super(name);
|
|
5089
|
+
this.member = member;
|
|
5090
|
+
}
|
|
5091
|
+
eval(stack) {
|
|
5092
|
+
const v = stack.lookupBind(this.name);
|
|
5093
|
+
return typeof v?.get === "function" ? v.get(this.member, null) : v?.[this.member] ?? null;
|
|
5094
|
+
}
|
|
5095
|
+
toString() {
|
|
5096
|
+
return `@${this.name}.${this.member}`;
|
|
5097
|
+
}
|
|
5098
|
+
};
|
|
5095
5099
|
DynVal = class DynVal extends RenderNameVal {
|
|
5096
5100
|
eval(stack) {
|
|
5097
5101
|
return stack.lookupDynamic(this.name);
|
|
@@ -5234,9 +5238,6 @@ class AttrParser {
|
|
|
5234
5238
|
this.attrs.push(new RawHtmlAttr(this._parseDirectiveValue(directiveName, s, vp.parseText)));
|
|
5235
5239
|
this.hasDynamic = true;
|
|
5236
5240
|
return;
|
|
5237
|
-
case "slot":
|
|
5238
|
-
this.pushWrapper("slot", s, vp.const(s));
|
|
5239
|
-
return;
|
|
5240
5241
|
case "push-view":
|
|
5241
5242
|
this.pushWrapper("push-view", s, this._parseDirectiveValue(directiveName, s, vp.parseText));
|
|
5242
5243
|
return;
|
|
@@ -5346,11 +5347,6 @@ class RequestHandler {
|
|
|
5346
5347
|
this.name = name;
|
|
5347
5348
|
this.fn = fn;
|
|
5348
5349
|
}
|
|
5349
|
-
toHandlerArg(disp) {
|
|
5350
|
-
const f = (...args) => disp.request(this.name, args);
|
|
5351
|
-
f.withOpts = (...args) => disp.request(this.name, args.slice(0, -1), args.at(-1));
|
|
5352
|
-
return f;
|
|
5353
|
-
}
|
|
5354
5350
|
}
|
|
5355
5351
|
var booleanAttrsRaw = "itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly,async,autofocus,autoplay,controls,default,defer,disabled,hidden,inert,loop,open,required,reversed,scoped,seamless,checked,muted,multiple,selected", booleanAttrs, ConstAttrs, DynAttrs, Attr, ConstAttr, RawHtmlAttr, NOT_SET_VAL, IfAttr, _attrParser = null;
|
|
5356
5352
|
var init_attribute = __esm(() => {
|
|
@@ -5942,24 +5938,6 @@ class Renderer {
|
|
|
5942
5938
|
pushEachEntry(r, nid, attrName, key, dom) {
|
|
5943
5939
|
r.push(this._renderMetadata({ $: "Each", nid, [attrName]: key }), dom);
|
|
5944
5940
|
}
|
|
5945
|
-
renderEach(stack, iterInfo, node, viewName) {
|
|
5946
|
-
const { seq, filter, loopWith } = iterInfo.eval(stack);
|
|
5947
|
-
const r = [];
|
|
5948
|
-
const { iterData, start, end, keys } = unpackLoopResult(loopWith.call(stack.it, seq, makeLoopCtx(stack, filter)), seq);
|
|
5949
|
-
const renderOne = (key, value, attrName) => {
|
|
5950
|
-
const dom = this.renderIt(stack.enter(value, { key }, true), node, key, viewName);
|
|
5951
|
-
if (dom != null)
|
|
5952
|
-
this.pushEachEntry(r, node.nodeId, attrName, key, dom);
|
|
5953
|
-
};
|
|
5954
|
-
if (keys)
|
|
5955
|
-
imKeysIter(seq, renderOne, keys);
|
|
5956
|
-
else
|
|
5957
|
-
getSeqInfo(seq)(seq, (key, value, attrName) => {
|
|
5958
|
-
if (filter.call(stack.it, key, value, iterData))
|
|
5959
|
-
renderOne(key, value, attrName);
|
|
5960
|
-
}, start, end);
|
|
5961
|
-
return r;
|
|
5962
|
-
}
|
|
5963
5941
|
renderEachWhen(stack, iterInfo, view, nid) {
|
|
5964
5942
|
const { seq, filter, loopWith, enricher } = iterInfo.eval(stack);
|
|
5965
5943
|
const r = [];
|
|
@@ -5970,7 +5948,7 @@ class Renderer {
|
|
|
5970
5948
|
const binds = { key, value };
|
|
5971
5949
|
const cacheKey = `${stack.viewsId ?? ""}\x1F${nid}\x1F${key}`;
|
|
5972
5950
|
if (enricher)
|
|
5973
|
-
enricher
|
|
5951
|
+
callEnricher(enricher, it, binds, key, value, iterData);
|
|
5974
5952
|
const cachedNode = this.cache.get(cachePath, cacheKey);
|
|
5975
5953
|
if (cachedNode)
|
|
5976
5954
|
this.pushEachEntry(r, nid, attrName, key, cachedNode);
|
|
@@ -6017,6 +5995,11 @@ var DATASET_ATTRS, getSeqInfo = (seq) => isIndexed(seq) ? imIndexedIter : isKeye
|
|
|
6017
5995
|
s = s < 0 ? 0 : s > size ? size : s;
|
|
6018
5996
|
e = e < 0 ? 0 : e > size ? size : e;
|
|
6019
5997
|
return [s, e < s ? s : e];
|
|
5998
|
+
}, callEnricher = (enricher, it, binds, key, value, iterData) => {
|
|
5999
|
+
enricher.call(it, binds, key, value, iterData);
|
|
6000
|
+
console.assert(binds.key === key && binds.value === value, "@enrich-with handlers must not overwrite binds.key or binds.value");
|
|
6001
|
+
binds.key = key;
|
|
6002
|
+
binds.value = value;
|
|
6020
6003
|
}, filterAlwaysTrue = (_v, _k, _seq) => true, nullLoopWith = (seq) => ({ iterData: { seq } }), unpackLoopResult = (result, seq) => {
|
|
6021
6004
|
const r = result ?? {};
|
|
6022
6005
|
return { iterData: r.iterData ?? { seq }, start: r.start, end: r.end, keys: r.keys };
|
|
@@ -6085,6 +6068,9 @@ class BaseNode {
|
|
|
6085
6068
|
isConstant() {
|
|
6086
6069
|
return false;
|
|
6087
6070
|
}
|
|
6071
|
+
isWhiteSpace() {
|
|
6072
|
+
return false;
|
|
6073
|
+
}
|
|
6088
6074
|
optimize() {}
|
|
6089
6075
|
}
|
|
6090
6076
|
function optimizeChilds(childs) {
|
|
@@ -6106,6 +6092,8 @@ function parseXOp(attrs, childs, opIdx, px) {
|
|
|
6106
6092
|
if (attrs.length <= opIdx)
|
|
6107
6093
|
return maybeFragment(childs);
|
|
6108
6094
|
const { name, value } = attrs[opIdx];
|
|
6095
|
+
if (X_OPS[name]?.ignoresChildren && hasMeaningfulChilds(childs))
|
|
6096
|
+
px.onParseIssue("x-op-ignores-children", { op: name });
|
|
6109
6097
|
const asAttr = attrs.getNamedItem("as")?.value ?? null;
|
|
6110
6098
|
const as = asAttr === null ? null : parseViewName(asAttr, px);
|
|
6111
6099
|
let node;
|
|
@@ -6123,7 +6111,7 @@ function parseXOp(attrs, childs, opIdx, px) {
|
|
|
6123
6111
|
node = px.addNodeIf(RenderItNode, vp.bindValIt, as);
|
|
6124
6112
|
break;
|
|
6125
6113
|
case "render-each":
|
|
6126
|
-
node =
|
|
6114
|
+
node = parseRenderEach(px, value, as, attrs);
|
|
6127
6115
|
break;
|
|
6128
6116
|
case "show": {
|
|
6129
6117
|
const val = parseXOpVal(name, value, px, vp.parseBool);
|
|
@@ -6158,8 +6146,12 @@ function processXExtras(node, attrs, opName, startIdx, px) {
|
|
|
6158
6146
|
const aName = a.name;
|
|
6159
6147
|
if (consumed.has(aName))
|
|
6160
6148
|
continue;
|
|
6161
|
-
const
|
|
6149
|
+
const atPrefixed = aName.charCodeAt(0) === 64;
|
|
6150
|
+
const baseName = atPrefixed ? aName.slice(1) : aName;
|
|
6151
|
+
const wrapper = wrappable ? X_OPS[baseName]?.wrapper : null;
|
|
6162
6152
|
if (wrapper) {
|
|
6153
|
+
if (!atPrefixed)
|
|
6154
|
+
maybeDeprecateBareXDirective(px, opName, baseName);
|
|
6163
6155
|
wrappers.push([wrapper, vp.parseBool(a.value, px)]);
|
|
6164
6156
|
continue;
|
|
6165
6157
|
}
|
|
@@ -6174,6 +6166,9 @@ function processXExtras(node, attrs, opName, startIdx, px) {
|
|
|
6174
6166
|
}
|
|
6175
6167
|
return node;
|
|
6176
6168
|
}
|
|
6169
|
+
function maybeDeprecateBareXDirective(px, opName, name) {
|
|
6170
|
+
px.onDeprecatedSyntax("bare-x-directive", { op: opName, name });
|
|
6171
|
+
}
|
|
6177
6172
|
function wrap(node, px, wrappers) {
|
|
6178
6173
|
if (wrappers) {
|
|
6179
6174
|
for (let i = wrappers.length - 1;i >= 0; i--) {
|
|
@@ -6202,6 +6197,29 @@ function dynRenderStep(comp, name, key) {
|
|
|
6202
6197
|
return null;
|
|
6203
6198
|
return key === undefined ? new DynStep(p.producerCompId, p.producerSteps) : new DynEachStep(p.producerCompId, p.producerSteps, key);
|
|
6204
6199
|
}
|
|
6200
|
+
function parseRenderEach(px, value, as, attrs) {
|
|
6201
|
+
const seqVal = parseXOpVal("render-each", value, px, vp.parseSequence);
|
|
6202
|
+
if (seqVal === null)
|
|
6203
|
+
return null;
|
|
6204
|
+
const renderIt = px.addNodeIf(RenderItNode, vp.bindValIt, as);
|
|
6205
|
+
const attrParser = getAttrParser(px);
|
|
6206
|
+
const eachAttr = attrParser.eachAttr = attrParser.pushWrapper("each", value, seqVal);
|
|
6207
|
+
const when = attrs.getNamedItem("@when") ?? attrs.getNamedItem("when");
|
|
6208
|
+
if (when) {
|
|
6209
|
+
if (when.name.charCodeAt(0) !== 64)
|
|
6210
|
+
maybeDeprecateBareXDirective(px, "render-each", "when");
|
|
6211
|
+
attrParser._parseWhen(when.value);
|
|
6212
|
+
}
|
|
6213
|
+
const lWith = attrs.getNamedItem("loop-with");
|
|
6214
|
+
if (lWith)
|
|
6215
|
+
attrParser._parseLoopWith(lWith.value);
|
|
6216
|
+
const each = px.addNodeIf(EachNode, seqVal);
|
|
6217
|
+
each.iterInfo.whenVal = eachAttr.whenVal ?? null;
|
|
6218
|
+
each.iterInfo.loopWithVal = eachAttr.loopWithVal ?? null;
|
|
6219
|
+
each.fromRenderEach = true;
|
|
6220
|
+
each.wrapNode(renderIt);
|
|
6221
|
+
return each;
|
|
6222
|
+
}
|
|
6205
6223
|
|
|
6206
6224
|
class IterInfo {
|
|
6207
6225
|
constructor(val, whenVal, loopWithVal, enrichWithVal) {
|
|
@@ -6223,13 +6241,13 @@ class IterInfo {
|
|
|
6223
6241
|
const binds = { key, value };
|
|
6224
6242
|
if (enricher) {
|
|
6225
6243
|
const { iterData } = unpackLoopResult(loopWith.call(stack.it, seq, makeLoopCtx(stack, filter)), seq);
|
|
6226
|
-
enricher
|
|
6244
|
+
callEnricher(enricher, stack.it, binds, key, value, iterData);
|
|
6227
6245
|
}
|
|
6228
6246
|
return binds;
|
|
6229
6247
|
}
|
|
6230
6248
|
}
|
|
6231
|
-
function xOp(consumed = [], { wrappable = false, wrapper = null } = {}) {
|
|
6232
|
-
return { consumed: new Set(consumed), wrappable, wrapper };
|
|
6249
|
+
function xOp(consumed = [], { wrappable = false, wrapper = null, ignoresChildren = false } = {}) {
|
|
6250
|
+
return { consumed: new Set(consumed), wrappable, wrapper, ignoresChildren };
|
|
6233
6251
|
}
|
|
6234
6252
|
|
|
6235
6253
|
class ParseContext {
|
|
@@ -6277,9 +6295,9 @@ class ParseContext {
|
|
|
6277
6295
|
const anySlot = [];
|
|
6278
6296
|
const slots = { _: new FragmentNode(anySlot) };
|
|
6279
6297
|
for (const child of childs)
|
|
6280
|
-
if (child
|
|
6298
|
+
if (child.isSlotNode)
|
|
6281
6299
|
slots[child.val.val] = child.node;
|
|
6282
|
-
else if (!
|
|
6300
|
+
else if (!child.isWhiteSpace())
|
|
6283
6301
|
anySlot.push(child);
|
|
6284
6302
|
const node = new MacroNode(macroName, mAttrs, slots, this);
|
|
6285
6303
|
this.macroNodes.push(node);
|
|
@@ -6303,6 +6321,7 @@ class ParseContext {
|
|
|
6303
6321
|
onParseIssue(kind, info) {
|
|
6304
6322
|
console.warn(`tutuca parse issue [${kind}]`, info);
|
|
6305
6323
|
}
|
|
6324
|
+
onDeprecatedSyntax(_kind, _info) {}
|
|
6306
6325
|
}
|
|
6307
6326
|
function trimEdgeWhite(node) {
|
|
6308
6327
|
if (!node.isWhiteSpace?.())
|
|
@@ -6382,10 +6401,10 @@ function compileModifiers(eventName, names) {
|
|
|
6382
6401
|
return w(this, f, args, ctx);
|
|
6383
6402
|
};
|
|
6384
6403
|
}
|
|
6385
|
-
var TextNode, CommentNode, ChildsNode, DomNode, FragmentNode, maybeFragment = (xs) => xs.length === 1 ? xs[0] : new FragmentNode(xs), VALID_NODE_RE, ANode, MacroNode, RenderViewId, RenderNode, RenderItNode,
|
|
6404
|
+
var TextNode, CommentNode, ChildsNode, DomNode, FragmentNode, maybeFragment = (xs) => xs.length === 1 ? xs[0] : new FragmentNode(xs), VALID_NODE_RE, ANode, MacroNode, RenderViewId, RenderNode, RenderItNode, RenderTextNode, RenderOnceNode, WrapperNode, ShowNode, HideNode, PushViewNameNode, SlotNode, ScopeNode, EachNode, X_OPS, WRAPPER_NODES, _htmlBlockTags = "ADDRESS,ARTICLE,ASIDE,BLOCKQUOTE,CAPTION,COL,COLGROUP,DETAILS,DIALOG,DIV,DD,DL,DT,FIELDSET,FIGCAPTION,FIGURE,FOOTER,FORM,H1,H2,H3,H4,H5,H6,HEADER,HGROUP,HR,LEGEND,LI,MAIN,MENU,NAV,OL,P,PRE,SECTION,SUMMARY,TABLE,TBODY,TD,TFOOT,TH,THEAD,TR,UL", HTML_BLOCK_TAGS, isBlockDomNode = (n) => {
|
|
6386
6405
|
const node = n instanceof FragmentNode ? n.childs[0] : n;
|
|
6387
6406
|
return node instanceof DomNode && HTML_BLOCK_TAGS.has(node.tagName);
|
|
6388
|
-
}, isEmptyText = (c) => c instanceof TextNode && c.val === "", fwdIfCtxPred = (pred) => (w) => (that, f, args, ctx) => pred(ctx) ? w(that, f, args, ctx) : that, fwdIfKey = (keyName) => fwdIfCtxPred((ctx) => ctx.e.key === keyName), fwdCtrl, fwdMeta, fwdAlt, metaWraps, MOD_WRAPPERS_BY_EVENT, identityModifierWrapper = (f, _ctx) => f;
|
|
6407
|
+
}, isEmptyText = (c) => c instanceof TextNode && c.val === "", isIgnorableXChild = (c) => c instanceof CommentNode || (c.isWhiteSpace?.() ?? false), hasMeaningfulChilds = (childs) => childs.some((c) => !isIgnorableXChild(c)), fwdIfCtxPred = (pred) => (w) => (that, f, args, ctx) => pred(ctx) ? w(that, f, args, ctx) : that, fwdIfKey = (keyName) => fwdIfCtxPred((ctx) => ctx.e.key === keyName), fwdCtrl, fwdMeta, fwdAlt, metaWraps, MOD_WRAPPERS_BY_EVENT, identityModifierWrapper = (f, _ctx) => f;
|
|
6389
6408
|
var init_anode = __esm(() => {
|
|
6390
6409
|
init_attribute();
|
|
6391
6410
|
init_path();
|
|
@@ -6617,36 +6636,6 @@ var init_anode = __esm(() => {
|
|
|
6617
6636
|
return null;
|
|
6618
6637
|
}
|
|
6619
6638
|
};
|
|
6620
|
-
RenderEachNode = class RenderEachNode extends RenderViewId {
|
|
6621
|
-
constructor(nodeId, val, viewVal) {
|
|
6622
|
-
super(nodeId, val, viewVal);
|
|
6623
|
-
this.iterInfo = new IterInfo(val, null, null, null);
|
|
6624
|
-
}
|
|
6625
|
-
render(stack, rx) {
|
|
6626
|
-
return rx.renderEach(stack, this.iterInfo, this, this.evalViewName(stack));
|
|
6627
|
-
}
|
|
6628
|
-
toPathStep(ctx) {
|
|
6629
|
-
if (this.val instanceof DynVal)
|
|
6630
|
-
return ctx.hasKey ? dynRenderStep(ctx.comp, this.val.name, ctx.key) : null;
|
|
6631
|
-
return super.toPathStep(ctx);
|
|
6632
|
-
}
|
|
6633
|
-
static parse(px, vp2, s, as, attrs) {
|
|
6634
|
-
const node = px.addNodeIf(RenderEachNode, parseXOpVal("render-each", s, px, vp2.parseSequence), as);
|
|
6635
|
-
if (node !== null) {
|
|
6636
|
-
const attrParser = getAttrParser(px);
|
|
6637
|
-
attrParser.eachAttr = attrParser.pushWrapper("each", s, node.val);
|
|
6638
|
-
const when = attrs.getNamedItem("when");
|
|
6639
|
-
if (when)
|
|
6640
|
-
attrParser._parseWhen(when.value);
|
|
6641
|
-
const lWith = attrs.getNamedItem("loop-with");
|
|
6642
|
-
if (lWith)
|
|
6643
|
-
attrParser._parseLoopWith(lWith.value);
|
|
6644
|
-
node.iterInfo.whenVal = attrParser.eachAttr.whenVal ?? null;
|
|
6645
|
-
node.iterInfo.loopWithVal = attrParser.eachAttr.loopWithVal ?? null;
|
|
6646
|
-
}
|
|
6647
|
-
return node;
|
|
6648
|
-
}
|
|
6649
|
-
};
|
|
6650
6639
|
RenderTextNode = class RenderTextNode extends ANode {
|
|
6651
6640
|
render(stack, _rx) {
|
|
6652
6641
|
return this.val.eval(stack);
|
|
@@ -6699,6 +6688,7 @@ var init_anode = __esm(() => {
|
|
|
6699
6688
|
}
|
|
6700
6689
|
};
|
|
6701
6690
|
SlotNode = class SlotNode extends WrapperNode {
|
|
6691
|
+
isSlotNode = true;
|
|
6702
6692
|
optimize() {
|
|
6703
6693
|
this.node.optimize();
|
|
6704
6694
|
}
|
|
@@ -6733,15 +6723,17 @@ var init_anode = __esm(() => {
|
|
|
6733
6723
|
};
|
|
6734
6724
|
X_OPS = {
|
|
6735
6725
|
slot: xOp(),
|
|
6736
|
-
text: xOp([], { wrappable: true }),
|
|
6737
|
-
render: xOp(["as"], { wrappable: true }),
|
|
6738
|
-
"render-it": xOp(["as"], { wrappable: true }),
|
|
6739
|
-
"render-each": xOp(["as", "when", "loop-with"], {
|
|
6726
|
+
text: xOp([], { wrappable: true, ignoresChildren: true }),
|
|
6727
|
+
render: xOp(["as"], { wrappable: true, ignoresChildren: true }),
|
|
6728
|
+
"render-it": xOp(["as"], { wrappable: true, ignoresChildren: true }),
|
|
6729
|
+
"render-each": xOp(["as", "when", "loop-with", "@when"], {
|
|
6730
|
+
wrappable: true,
|
|
6731
|
+
ignoresChildren: true
|
|
6732
|
+
}),
|
|
6740
6733
|
show: xOp([], { wrapper: ShowNode }),
|
|
6741
6734
|
hide: xOp([], { wrapper: HideNode })
|
|
6742
6735
|
};
|
|
6743
6736
|
WRAPPER_NODES = {
|
|
6744
|
-
slot: SlotNode,
|
|
6745
6737
|
show: ShowNode,
|
|
6746
6738
|
hide: HideNode,
|
|
6747
6739
|
each: EachNode,
|
|
@@ -9011,14 +9003,17 @@ function closestName(name, candidates, maxDistance = 2) {
|
|
|
9011
9003
|
|
|
9012
9004
|
// tools/core/lint-check.js
|
|
9013
9005
|
function protoHasMethod(proto, name) {
|
|
9006
|
+
return protoMethodValue(proto, name) !== null;
|
|
9007
|
+
}
|
|
9008
|
+
function protoMethodValue(proto, name) {
|
|
9014
9009
|
let cursor = proto;
|
|
9015
9010
|
while (cursor && cursor !== Object.prototype) {
|
|
9016
9011
|
const desc = Object.getOwnPropertyDescriptor(cursor, name);
|
|
9017
9012
|
if (desc !== undefined)
|
|
9018
|
-
return typeof desc.value === "function";
|
|
9013
|
+
return typeof desc.value === "function" ? desc.value : null;
|
|
9019
9014
|
cursor = Object.getPrototypeOf(cursor);
|
|
9020
9015
|
}
|
|
9021
|
-
return
|
|
9016
|
+
return null;
|
|
9022
9017
|
}
|
|
9023
9018
|
function collectProtoMethodNames(proto) {
|
|
9024
9019
|
const out = [];
|
|
@@ -9062,6 +9057,8 @@ function classifyBadValue(value) {
|
|
|
9062
9057
|
return "logical";
|
|
9063
9058
|
if (/^[.$][A-Za-z_]\w*\s+\S/.test(s))
|
|
9064
9059
|
return "call-with-args";
|
|
9060
|
+
if (/^\.[A-Za-z_]\w*\??(\.[A-Za-z_]\w*\??)+$/.test(s))
|
|
9061
|
+
return "field-path";
|
|
9065
9062
|
return null;
|
|
9066
9063
|
}
|
|
9067
9064
|
function checkComponent(Comp, lx = new LintContext, { wellKnownExtras = EMPTY_SET2 } = {}) {
|
|
@@ -9090,6 +9087,7 @@ function checkComponent(Comp, lx = new LintContext, { wellKnownExtras = EMPTY_SE
|
|
|
9090
9087
|
function checkView(lx, view, Comp, referencedAlters, referencedDynamics) {
|
|
9091
9088
|
checkParseIssues(lx, view);
|
|
9092
9089
|
checkRenderItInLoop(lx, view);
|
|
9090
|
+
checkEnrichProjection(lx, view, Comp);
|
|
9093
9091
|
checkEventModifiers(lx, view);
|
|
9094
9092
|
checkKnownHandlerNames(lx, view, Comp, referencedAlters, referencedDynamics);
|
|
9095
9093
|
checkMacroCallArgs(lx, view, Comp);
|
|
@@ -9105,11 +9103,31 @@ function checkParseIssues(lx, view) {
|
|
|
9105
9103
|
if (!issues)
|
|
9106
9104
|
return;
|
|
9107
9105
|
for (const { kind, info } of issues) {
|
|
9106
|
+
if (kind === "deprecated:bare-x-directive") {
|
|
9107
|
+
lx.warn(DEPRECATED_BARE_X_DIRECTIVE, info, {
|
|
9108
|
+
kind: "add-prefix",
|
|
9109
|
+
from: info.name,
|
|
9110
|
+
to: `@${info.name}`
|
|
9111
|
+
});
|
|
9112
|
+
continue;
|
|
9113
|
+
}
|
|
9114
|
+
if (kind === "x-op-ignores-children") {
|
|
9115
|
+
lx.warn(X_OP_IGNORES_CHILDREN, info, { kind: "remove", what: "the ignored children" });
|
|
9116
|
+
continue;
|
|
9117
|
+
}
|
|
9108
9118
|
const rule = PARSE_ISSUES[kind];
|
|
9109
9119
|
if (!rule)
|
|
9110
9120
|
continue;
|
|
9111
9121
|
const id = rule.id;
|
|
9112
9122
|
if (kind === "bad-value") {
|
|
9123
|
+
if (typeof info.value === "string" && BINDING_MEMBER_TOO_DEEP_RE.test(info.value.trim())) {
|
|
9124
|
+
lx.error(BINDING_MEMBER_TOO_DEEP, info, {
|
|
9125
|
+
kind: "rephrase",
|
|
9126
|
+
from: info.value,
|
|
9127
|
+
text: "Read one level off the binding and compute the rest in a method or an '@enrich-with' handler."
|
|
9128
|
+
});
|
|
9129
|
+
continue;
|
|
9130
|
+
}
|
|
9113
9131
|
const detected = classifyBadValue(info.value);
|
|
9114
9132
|
if (detected) {
|
|
9115
9133
|
lx.error(UNSUPPORTED_EXPR_SYNTAX, { ...info, detected }, { kind: "rephrase", from: info.value, text: UNSUPPORTED_EXPR_GUIDANCE[detected] });
|
|
@@ -9156,6 +9174,54 @@ function checkRenderItInLoop(lx, view) {
|
|
|
9156
9174
|
return;
|
|
9157
9175
|
walkForRenderIt(lx, view.anode, 0);
|
|
9158
9176
|
}
|
|
9177
|
+
function pureProjectionBinds(fn) {
|
|
9178
|
+
const src = Function.prototype.toString.call(fn);
|
|
9179
|
+
const head = src.match(/^[^(]*\(([^)]*)\)\s*(?:=>)?\s*/);
|
|
9180
|
+
if (!head)
|
|
9181
|
+
return null;
|
|
9182
|
+
const params = head[1].split(",").map((p) => p.trim());
|
|
9183
|
+
const [bindsName, , valueName] = params;
|
|
9184
|
+
if (!/^\w+$/.test(bindsName ?? "") || !/^\w+$/.test(valueName ?? ""))
|
|
9185
|
+
return null;
|
|
9186
|
+
let body = src.slice(head[0].length).trim();
|
|
9187
|
+
if (body.startsWith("{")) {
|
|
9188
|
+
if (!body.endsWith("}"))
|
|
9189
|
+
return null;
|
|
9190
|
+
body = body.slice(1, -1);
|
|
9191
|
+
}
|
|
9192
|
+
const statements = body.split(/[;\n]/).map((s) => s.trim()).filter((s) => s !== "" && !s.startsWith("//"));
|
|
9193
|
+
if (statements.length === 0)
|
|
9194
|
+
return null;
|
|
9195
|
+
const projectionRe = new RegExp(`^${bindsName}\\.(\\w+)\\s*=\\s*${valueName}(?:\\.(\\w+)|\\.get\\((['"])(\\w+)\\3\\))$`);
|
|
9196
|
+
const members = [];
|
|
9197
|
+
for (const statement of statements) {
|
|
9198
|
+
const m = statement.match(projectionRe);
|
|
9199
|
+
if (!m)
|
|
9200
|
+
return null;
|
|
9201
|
+
members.push({ bind: m[1], member: m[2] ?? m[4] });
|
|
9202
|
+
}
|
|
9203
|
+
return members;
|
|
9204
|
+
}
|
|
9205
|
+
function checkEnrichProjection(lx, view, Comp) {
|
|
9206
|
+
for (const node of view.ctx.nodes) {
|
|
9207
|
+
if (node.constructor.name !== "EachNode")
|
|
9208
|
+
continue;
|
|
9209
|
+
const enrich = node.iterInfo?.enrichWithVal;
|
|
9210
|
+
if (!enrich?.name)
|
|
9211
|
+
continue;
|
|
9212
|
+
const fn = enrich.constructor.name === "MethodVal" ? protoMethodValue(Comp.Class?.prototype, enrich.name) : Comp.alter?.[enrich.name];
|
|
9213
|
+
if (typeof fn !== "function")
|
|
9214
|
+
continue;
|
|
9215
|
+
const members = pureProjectionBinds(fn);
|
|
9216
|
+
if (members === null)
|
|
9217
|
+
continue;
|
|
9218
|
+
const rewrites = members.map(({ bind, member }) => `'@${bind}' -> '@value.${member}'`);
|
|
9219
|
+
lx.hint(SUGGEST_BINDING_MEMBER, { name: enrich.name, members }, {
|
|
9220
|
+
kind: "rephrase",
|
|
9221
|
+
text: `Replace ${rewrites.join(", ")} in the view, then remove the '@enrich-with' and the '${enrich.name}' alter handler.`
|
|
9222
|
+
});
|
|
9223
|
+
}
|
|
9224
|
+
}
|
|
9159
9225
|
function walkForRenderIt(lx, node, loopDepth) {
|
|
9160
9226
|
if (node === null || node === undefined)
|
|
9161
9227
|
return;
|
|
@@ -9275,12 +9341,12 @@ function checkEventHandlersHaveImpls(lx, Comp, referencedInputs) {
|
|
|
9275
9341
|
function reportUnknownName(lx, code, name, candidates, info) {
|
|
9276
9342
|
lx.error(code, { ...info, name }, replaceNameSuggestion(name, candidates));
|
|
9277
9343
|
}
|
|
9278
|
-
function checkConsistentAttrVal(lx, val, env, skipNameVal = false, errCtx = null) {
|
|
9344
|
+
function checkConsistentAttrVal(lx, val, env, skipNameVal = false, errCtx = null, isRoot = true) {
|
|
9279
9345
|
const check = ATTR_VAL_CHECKERS[val?.constructor.name];
|
|
9280
9346
|
if (check === undefined)
|
|
9281
9347
|
return;
|
|
9282
|
-
const recurse = (sub) => checkConsistentAttrVal(lx, sub, env, skipNameVal, errCtx);
|
|
9283
|
-
check({ lx, val, env, errCtx, skipNameVal, recurse });
|
|
9348
|
+
const recurse = (sub) => checkConsistentAttrVal(lx, sub, env, skipNameVal, errCtx, false);
|
|
9349
|
+
check({ lx, val, env, errCtx, skipNameVal, recurse, isRoot });
|
|
9284
9350
|
}
|
|
9285
9351
|
function nodeCtxForNode(nodeKind) {
|
|
9286
9352
|
return NODE_KIND_TO_CTX[nodeKind] ?? null;
|
|
@@ -9403,7 +9469,7 @@ function checkConsistentAttrs(lx, Comp, referencedAlters, referencedDynamics) {
|
|
|
9403
9469
|
if (node.val) {
|
|
9404
9470
|
checkConsistentAttrVal(lx, node.val, env, false, baseCtx);
|
|
9405
9471
|
}
|
|
9406
|
-
if (nodeKind === "
|
|
9472
|
+
if (nodeKind === "EachNode" && node.fromRenderEach) {
|
|
9407
9473
|
const iter = node.iterInfo;
|
|
9408
9474
|
if (iter.whenVal)
|
|
9409
9475
|
checkConsistentAttrVal(lx, iter.whenVal, env, false, {
|
|
@@ -9630,7 +9696,7 @@ class LintContext {
|
|
|
9630
9696
|
this.reports.push({ id, info, level, context: { ...this.frame }, suggestion });
|
|
9631
9697
|
}
|
|
9632
9698
|
}
|
|
9633
|
-
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",
|
|
9699
|
+
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_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", X_OP_IGNORES_CHILDREN = "X_OP_IGNORES_CHILDREN", MAYBE_DROP_AT_PREFIX = "MAYBE_DROP_AT_PREFIX", MAYBE_ADD_AT_PREFIX = "MAYBE_ADD_AT_PREFIX", DEPRECATED_BARE_X_DIRECTIVE = "DEPRECATED_BARE_X_DIRECTIVE", BAD_VALUE = "BAD_VALUE", UNSUPPORTED_EXPR_SYNTAX = "UNSUPPORTED_EXPR_SYNTAX", BINDING_MEMBER_TOO_DEEP = "BINDING_MEMBER_TOO_DEEP", SUGGEST_BINDING_MEMBER = "SUGGEST_BINDING_MEMBER", REDUNDANT_TEMPLATE_STRING = "REDUNDANT_TEMPLATE_STRING", PLACEHOLDERLESS_TEMPLATE_STRING = "PLACEHOLDERLESS_TEMPLATE_STRING", CONSTANT_CONDITION = "CONSTANT_CONDITION", 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, BINDING_MEMBER_TOO_DEEP_RE, UNSUPPORTED_EXPR_GUIDANCE, HTML_LINT_OPTS, NO_WRAPPERS, KNOWN_HANDLER_NAMES, fixTo = (from, to) => ({ kind: "rewrite", from, to }), BOOL_CONDITION_ORIGINS, isBoolConditionCtx = (errCtx) => errCtx != null && (BOOL_CONDITION_ORIGINS.has(errCtx.originAttr) || errCtx.branch === "@if"), 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;
|
|
9634
9700
|
var init_lint_check = __esm(() => {
|
|
9635
9701
|
init_anode();
|
|
9636
9702
|
init_htmllinter();
|
|
@@ -9673,11 +9739,13 @@ var init_lint_check = __esm(() => {
|
|
|
9673
9739
|
},
|
|
9674
9740
|
"bad-value": { id: BAD_VALUE }
|
|
9675
9741
|
};
|
|
9742
|
+
BINDING_MEMBER_TOO_DEEP_RE = /^@[a-zA-Z]\w*\??(\.[a-zA-Z]\w*\??){2,}$/;
|
|
9676
9743
|
UNSUPPORTED_EXPR_GUIDANCE = {
|
|
9677
9744
|
ternary: "Ternary expressions aren't supported in dynamic attributes. Define a method or computed field on the component that returns the value, then reference it as '$methodName'.",
|
|
9678
9745
|
comparison: "Comparisons aren't supported in dynamic attributes. Define a method like 'isFooSelected' that returns the boolean, then reference it as '$isFooSelected'.",
|
|
9679
9746
|
logical: "Logical operators aren't supported in dynamic attributes. Combine the conditions in a method on the component and reference it as '$methodName'.",
|
|
9680
|
-
"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."
|
|
9747
|
+
"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.",
|
|
9748
|
+
"field-path": "Fields can't be read through a dotted path. Define a method that returns the value, render a child component for the nested data, or — inside a loop — read one member off a binding ('@value.member')."
|
|
9681
9749
|
};
|
|
9682
9750
|
HTML_LINT_OPTS = {
|
|
9683
9751
|
fragmentContext: "template",
|
|
@@ -9704,7 +9772,12 @@ var init_lint_check = __esm(() => {
|
|
|
9704
9772
|
"ctx",
|
|
9705
9773
|
"dragInfo"
|
|
9706
9774
|
]);
|
|
9775
|
+
BOOL_CONDITION_ORIGINS = new Set(["@show", "@hide", "<x show>", "<x hide>"]);
|
|
9707
9776
|
ATTR_VAL_CHECKERS = {
|
|
9777
|
+
ConstVal({ lx, val, errCtx, isRoot }) {
|
|
9778
|
+
if (isRoot && isBoolConditionCtx(errCtx) && typeof val.val !== "boolean")
|
|
9779
|
+
lx.warn(CONSTANT_CONDITION, { ...errCtx, literal: String(val) });
|
|
9780
|
+
},
|
|
9708
9781
|
FieldVal({ lx, val, env, errCtx }) {
|
|
9709
9782
|
const { fields, proto } = env;
|
|
9710
9783
|
const { name } = val;
|
|
@@ -9732,10 +9805,6 @@ var init_lint_check = __esm(() => {
|
|
|
9732
9805
|
recurse(val.seqVal);
|
|
9733
9806
|
recurse(val.keyVal);
|
|
9734
9807
|
},
|
|
9735
|
-
RequestVal({ lx, val, env, errCtx }) {
|
|
9736
|
-
if (env.scope.lookupRequest(val.name) === null)
|
|
9737
|
-
reportUnknownName(lx, UNKNOWN_REQUEST_NAME, val.name, scopeKeysAlong(env.scope, "reqsByName"), errCtx);
|
|
9738
|
-
},
|
|
9739
9808
|
TypeVal({ lx, val, env, errCtx }) {
|
|
9740
9809
|
if (env.scope.lookupComponent(val.name) === null)
|
|
9741
9810
|
reportUnknownName(lx, UNKNOWN_COMPONENT_NAME, val.name, scopeKeysAlong(env.scope, "byName"), errCtx);
|
|
@@ -9744,11 +9813,15 @@ var init_lint_check = __esm(() => {
|
|
|
9744
9813
|
if (!skipNameVal && !isKnownHandlerName(val.name))
|
|
9745
9814
|
reportUnknownName(lx, UNKNOWN_HANDLER_ARG_NAME, val.name, KNOWN_HANDLER_NAMES, errCtx);
|
|
9746
9815
|
},
|
|
9747
|
-
StrTplVal({ lx, val, errCtx, recurse }) {
|
|
9816
|
+
StrTplVal({ lx, val, errCtx, recurse, isRoot }) {
|
|
9748
9817
|
const vs = val.vals;
|
|
9749
9818
|
const literal = val.toLiteralSource();
|
|
9750
9819
|
if (literal !== null) {
|
|
9751
|
-
|
|
9820
|
+
if (isRoot && isBoolConditionCtx(errCtx))
|
|
9821
|
+
lx.warn(CONSTANT_CONDITION, { ...errCtx, literal });
|
|
9822
|
+
else
|
|
9823
|
+
lx.hint(PLACEHOLDERLESS_TEMPLATE_STRING, { ...errCtx, literal }, fixTo(`$${literal}`, literal));
|
|
9824
|
+
return;
|
|
9752
9825
|
} else if (vs.length === 1) {
|
|
9753
9826
|
const simpler = String(vs[0]);
|
|
9754
9827
|
lx.warn(REDUNDANT_TEMPLATE_STRING, { ...errCtx, simpler }, fixTo(`$'{${simpler}}'`, simpler));
|
|
@@ -9761,7 +9834,10 @@ var init_lint_check = __esm(() => {
|
|
|
9761
9834
|
if (env.alter[val.name] === undefined)
|
|
9762
9835
|
reportUnknownName(lx, ALT_HANDLER_NOT_DEFINED, val.name, Object.keys(env.alter), errCtx);
|
|
9763
9836
|
},
|
|
9764
|
-
PredicateVal({ val, recurse }) {
|
|
9837
|
+
PredicateVal({ lx, val, errCtx, recurse }) {
|
|
9838
|
+
const isConstArg = (a) => a.constructor.name === "ConstVal" || a.constructor.name === "StrTplVal" && a.toLiteralSource() !== null;
|
|
9839
|
+
if (isBoolConditionCtx(errCtx) && val.args.every(isConstArg))
|
|
9840
|
+
lx.warn(CONSTANT_CONDITION, { ...errCtx, literal: String(val) });
|
|
9765
9841
|
for (const arg of val.args)
|
|
9766
9842
|
recurse(arg);
|
|
9767
9843
|
},
|
|
@@ -9775,7 +9851,6 @@ var init_lint_check = __esm(() => {
|
|
|
9775
9851
|
RenderTextNode: { originAttr: "<x text>" },
|
|
9776
9852
|
RenderNode: { originAttr: "<x render>" },
|
|
9777
9853
|
RenderItNode: { originAttr: "<x render-it>" },
|
|
9778
|
-
RenderEachNode: { originAttr: "<x render-each>" },
|
|
9779
9854
|
ShowNode: { originAttr: "<x show>" },
|
|
9780
9855
|
HideNode: { originAttr: "<x hide>" },
|
|
9781
9856
|
PushViewNameNode: { originAttr: "<x push-view>" }
|
|
@@ -9800,6 +9875,13 @@ var init_lint_check = __esm(() => {
|
|
|
9800
9875
|
const tag = this.currentTag;
|
|
9801
9876
|
this.parseIssues.push({ kind, info: tag && info.tag === undefined ? { ...info, tag } : info });
|
|
9802
9877
|
}
|
|
9878
|
+
onDeprecatedSyntax(kind, info) {
|
|
9879
|
+
const tag = this.currentTag;
|
|
9880
|
+
this.parseIssues.push({
|
|
9881
|
+
kind: `deprecated:${kind}`,
|
|
9882
|
+
info: tag && info.tag === undefined ? { ...info, tag } : info
|
|
9883
|
+
});
|
|
9884
|
+
}
|
|
9803
9885
|
};
|
|
9804
9886
|
});
|
|
9805
9887
|
|
|
@@ -9888,6 +9970,12 @@ var init_lint_rules = __esm(() => {
|
|
|
9888
9970
|
group: "Iteration helpers (`alter`)",
|
|
9889
9971
|
summary: "`alter` entry is defined but never used."
|
|
9890
9972
|
},
|
|
9973
|
+
{
|
|
9974
|
+
code: SUGGEST_BINDING_MEMBER,
|
|
9975
|
+
level: "hint",
|
|
9976
|
+
group: "Iteration helpers (`alter`)",
|
|
9977
|
+
summary: "`@enrich-with` handler only copies members of the loop value — read them directly as `@value.member` and drop the enrich."
|
|
9978
|
+
},
|
|
9891
9979
|
{
|
|
9892
9980
|
code: DYN_VAL_NOT_DEFINED,
|
|
9893
9981
|
level: "error",
|
|
@@ -9966,6 +10054,12 @@ var init_lint_rules = __esm(() => {
|
|
|
9966
10054
|
group: "Templates / events",
|
|
9967
10055
|
summary: "Extra attribute on `<x op>` not consumed by the op and not a known wrapper."
|
|
9968
10056
|
},
|
|
10057
|
+
{
|
|
10058
|
+
code: X_OP_IGNORES_CHILDREN,
|
|
10059
|
+
level: "warn",
|
|
10060
|
+
group: "Templates / events",
|
|
10061
|
+
summary: "`<x text/render/render-it/render-each>` has child content the op silently drops."
|
|
10062
|
+
},
|
|
9969
10063
|
{
|
|
9970
10064
|
code: MAYBE_DROP_AT_PREFIX,
|
|
9971
10065
|
level: "hint",
|
|
@@ -9978,6 +10072,12 @@ var init_lint_rules = __esm(() => {
|
|
|
9978
10072
|
group: "Templates / events",
|
|
9979
10073
|
summary: "A directive name (`when`/`enrich-with`/`loop-with`/`show`/`hide`) was written as a plain attribute on a host element — add the `@` prefix."
|
|
9980
10074
|
},
|
|
10075
|
+
{
|
|
10076
|
+
code: DEPRECATED_BARE_X_DIRECTIVE,
|
|
10077
|
+
level: "warn",
|
|
10078
|
+
group: "Templates / events",
|
|
10079
|
+
summary: "Bare `show`/`hide`/`when` on an `<x>` op is deprecated — use the `@`-prefixed directive (`@show`/`@hide`/`@when`)."
|
|
10080
|
+
},
|
|
9981
10081
|
{
|
|
9982
10082
|
code: BAD_VALUE,
|
|
9983
10083
|
level: "error",
|
|
@@ -9988,7 +10088,13 @@ var init_lint_rules = __esm(() => {
|
|
|
9988
10088
|
code: UNSUPPORTED_EXPR_SYNTAX,
|
|
9989
10089
|
level: "error",
|
|
9990
10090
|
group: "Value expressions",
|
|
9991
|
-
summary: "Value uses JS-style syntax (ternary, comparison, logical, call-with-args) tutuca does not support — move the logic into a method."
|
|
10091
|
+
summary: "Value uses JS-style syntax (ternary, comparison, logical, call-with-args, dotted field path) tutuca does not support — move the logic into a method."
|
|
10092
|
+
},
|
|
10093
|
+
{
|
|
10094
|
+
code: BINDING_MEMBER_TOO_DEEP,
|
|
10095
|
+
level: "error",
|
|
10096
|
+
group: "Value expressions",
|
|
10097
|
+
summary: "A binding member read goes more than one level deep (`@x.a.b`) — only one member is allowed."
|
|
9992
10098
|
},
|
|
9993
10099
|
{
|
|
9994
10100
|
code: REDUNDANT_TEMPLATE_STRING,
|
|
@@ -10003,10 +10109,10 @@ var init_lint_rules = __esm(() => {
|
|
|
10003
10109
|
summary: "`$'…'` template has no `{}` placeholder — use a plain string literal."
|
|
10004
10110
|
},
|
|
10005
10111
|
{
|
|
10006
|
-
code:
|
|
10007
|
-
level: "
|
|
10008
|
-
group: "
|
|
10009
|
-
summary: "
|
|
10112
|
+
code: CONSTANT_CONDITION,
|
|
10113
|
+
level: "warn",
|
|
10114
|
+
group: "Value expressions",
|
|
10115
|
+
summary: "A non-boolean literal in a boolean condition (`@show`, `@hide`, `@if`) never changes — reference a field or method instead."
|
|
10010
10116
|
},
|
|
10011
10117
|
{
|
|
10012
10118
|
code: UNKNOWN_COMPONENT_NAME,
|
|
@@ -10179,8 +10285,6 @@ function lintIdToMessage(id, info) {
|
|
|
10179
10285
|
}
|
|
10180
10286
|
case "IF_NO_BRANCH_SET":
|
|
10181
10287
|
return `'@if.${info.attr}' has no '@then' or '@else' branch — add '@then="…"' or '@else="…"' (or both)${fmtTagSuffix(info)}`;
|
|
10182
|
-
case "UNKNOWN_REQUEST_NAME":
|
|
10183
|
-
return `Unknown request '!${info.name}'${fmtOriginSuffix(info)}`;
|
|
10184
10288
|
case "UNKNOWN_COMPONENT_NAME":
|
|
10185
10289
|
return `Unknown component '${info.name}'${fmtOriginSuffix(info)}`;
|
|
10186
10290
|
case "ALT_HANDLER_NOT_DEFINED":
|
|
@@ -10205,20 +10309,32 @@ function lintIdToMessage(id, info) {
|
|
|
10205
10309
|
return `Unknown <x> op '${info.name}=${JSON.stringify(info.value)}'${fmtTagSuffix(info)}`;
|
|
10206
10310
|
case "UNKNOWN_X_ATTR":
|
|
10207
10311
|
return `Unknown attribute '${info.name}=${JSON.stringify(info.value)}' on <x ${info.op}>${fmtTagSuffix(info)}`;
|
|
10312
|
+
case "X_OP_IGNORES_CHILDREN":
|
|
10313
|
+
return `<x ${info.op}> has child content, but the '${info.op}' op ignores its children — they are silently dropped when the template is parsed; remove them${fmtTagSuffix(info)}`;
|
|
10208
10314
|
case "MAYBE_DROP_AT_PREFIX": {
|
|
10209
10315
|
const written = info.value !== undefined ? `${info.name}=${JSON.stringify(info.value)}` : info.name;
|
|
10210
10316
|
return `'${written}' on <x> looks like a directive but is actually an x op/attr written with a leading '@'`;
|
|
10211
10317
|
}
|
|
10212
10318
|
case "MAYBE_ADD_AT_PREFIX":
|
|
10213
10319
|
return `'${info.name}' on <${(info.tag ?? "").toLowerCase()}> is a plain attribute, but '@${info.name}' is a directive — add the leading '@'`;
|
|
10320
|
+
case "DEPRECATED_BARE_X_DIRECTIVE":
|
|
10321
|
+
return `'${info.name}' on <x ${info.op}> is deprecated — write '@${info.name}' instead${fmtTagSuffix(info)}`;
|
|
10214
10322
|
case "BAD_VALUE":
|
|
10215
10323
|
return `${badValueMessage(info)}${fmtTagSuffix(info)}`;
|
|
10216
10324
|
case "UNSUPPORTED_EXPR_SYNTAX":
|
|
10217
10325
|
return `${unsupportedExprMessage(info)}${fmtTagSuffix(info)}`;
|
|
10326
|
+
case "BINDING_MEMBER_TOO_DEEP":
|
|
10327
|
+
return `Binding member read ${JSON.stringify(info.value)} goes more than one level deep — only one member is allowed (like '@value.title')${fmtTagSuffix(info)}`;
|
|
10328
|
+
case "SUGGEST_BINDING_MEMBER": {
|
|
10329
|
+
const reads = (info.members ?? []).map(({ member }) => `'@value.${member}'`).join(", ");
|
|
10330
|
+
return `Enrich handler '${info.name}' only copies members of the loop value — read them directly${reads ? ` (${reads})` : ""} and remove the '@enrich-with'`;
|
|
10331
|
+
}
|
|
10218
10332
|
case "REDUNDANT_TEMPLATE_STRING":
|
|
10219
10333
|
return `Redundant template string — '{${info.simpler}}' should be just '${info.simpler}'${fmtOriginSuffix(info)}`;
|
|
10220
10334
|
case "PLACEHOLDERLESS_TEMPLATE_STRING":
|
|
10221
10335
|
return `Template string has no dynamic parts — use the string literal ${info.literal} instead${fmtOriginSuffix(info)}`;
|
|
10336
|
+
case "CONSTANT_CONDITION":
|
|
10337
|
+
return `Condition is the constant literal ${info.literal} — it never changes; reference a field ('.name') or a method ('$name') instead${fmtOriginSuffix(info)}`;
|
|
10222
10338
|
case "UNKNOWN_COMPONENT_SPEC_KEY":
|
|
10223
10339
|
return `Unknown component spec key '${info.key}' — value will be ignored at runtime`;
|
|
10224
10340
|
case "COMP_FIELD_BAD_SHAPE":
|
|
@@ -10321,7 +10437,8 @@ var init_lint = __esm(() => {
|
|
|
10321
10437
|
ternary: "ternary expression",
|
|
10322
10438
|
comparison: "comparison",
|
|
10323
10439
|
logical: "logical expression",
|
|
10324
|
-
"call-with-args": "method call with arguments"
|
|
10440
|
+
"call-with-args": "method call with arguments",
|
|
10441
|
+
"field-path": "dotted field path"
|
|
10325
10442
|
};
|
|
10326
10443
|
});
|
|
10327
10444
|
|
|
@@ -15129,9 +15246,6 @@ class Stack2 {
|
|
|
15129
15246
|
getHandlerFor(name, key) {
|
|
15130
15247
|
return this.comps.getHandlerFor(this.it, name, key);
|
|
15131
15248
|
}
|
|
15132
|
-
lookupRequest(name) {
|
|
15133
|
-
return this.comps.getRequestFor(this.it, name);
|
|
15134
|
-
}
|
|
15135
15249
|
lookupBestView(views, defaultViewName) {
|
|
15136
15250
|
let n = this.views;
|
|
15137
15251
|
while (n !== null) {
|
|
@@ -15540,13 +15654,6 @@ var init_transactor = __esm(() => {
|
|
|
15540
15654
|
const stack = this.buildStack(root, comps);
|
|
15541
15655
|
const [handler, args] = this.handler.getHandlerAndArgs(stack, this);
|
|
15542
15656
|
const path = this.dispatchPath;
|
|
15543
|
-
let dispatcher;
|
|
15544
|
-
for (let i = 0;i < args.length; i++) {
|
|
15545
|
-
if (args[i]?.toHandlerArg) {
|
|
15546
|
-
dispatcher ??= new Dispatcher(path, this.transactor, this);
|
|
15547
|
-
args[i] = args[i].toHandlerArg(dispatcher);
|
|
15548
|
-
}
|
|
15549
|
-
}
|
|
15550
15657
|
args.push(new EventContext(path, this.transactor, this));
|
|
15551
15658
|
return [handler, args];
|
|
15552
15659
|
}
|