tutuca 0.9.107 → 0.9.108
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 +242 -138
- package/dist/tutuca-components.js +4 -2
- package/dist/tutuca-dev.ext.js +222 -133
- package/dist/tutuca-dev.js +222 -133
- 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;
|
|
@@ -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 }) {
|
|
9778
|
+
if (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);
|
|
@@ -9748,7 +9817,11 @@ var init_lint_check = __esm(() => {
|
|
|
9748
9817
|
const vs = val.vals;
|
|
9749
9818
|
const literal = val.toLiteralSource();
|
|
9750
9819
|
if (literal !== null) {
|
|
9751
|
-
|
|
9820
|
+
if (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));
|
|
@@ -9775,7 +9848,6 @@ var init_lint_check = __esm(() => {
|
|
|
9775
9848
|
RenderTextNode: { originAttr: "<x text>" },
|
|
9776
9849
|
RenderNode: { originAttr: "<x render>" },
|
|
9777
9850
|
RenderItNode: { originAttr: "<x render-it>" },
|
|
9778
|
-
RenderEachNode: { originAttr: "<x render-each>" },
|
|
9779
9851
|
ShowNode: { originAttr: "<x show>" },
|
|
9780
9852
|
HideNode: { originAttr: "<x hide>" },
|
|
9781
9853
|
PushViewNameNode: { originAttr: "<x push-view>" }
|
|
@@ -9800,6 +9872,13 @@ var init_lint_check = __esm(() => {
|
|
|
9800
9872
|
const tag = this.currentTag;
|
|
9801
9873
|
this.parseIssues.push({ kind, info: tag && info.tag === undefined ? { ...info, tag } : info });
|
|
9802
9874
|
}
|
|
9875
|
+
onDeprecatedSyntax(kind, info) {
|
|
9876
|
+
const tag = this.currentTag;
|
|
9877
|
+
this.parseIssues.push({
|
|
9878
|
+
kind: `deprecated:${kind}`,
|
|
9879
|
+
info: tag && info.tag === undefined ? { ...info, tag } : info
|
|
9880
|
+
});
|
|
9881
|
+
}
|
|
9803
9882
|
};
|
|
9804
9883
|
});
|
|
9805
9884
|
|
|
@@ -9888,6 +9967,12 @@ var init_lint_rules = __esm(() => {
|
|
|
9888
9967
|
group: "Iteration helpers (`alter`)",
|
|
9889
9968
|
summary: "`alter` entry is defined but never used."
|
|
9890
9969
|
},
|
|
9970
|
+
{
|
|
9971
|
+
code: SUGGEST_BINDING_MEMBER,
|
|
9972
|
+
level: "hint",
|
|
9973
|
+
group: "Iteration helpers (`alter`)",
|
|
9974
|
+
summary: "`@enrich-with` handler only copies members of the loop value — read them directly as `@value.member` and drop the enrich."
|
|
9975
|
+
},
|
|
9891
9976
|
{
|
|
9892
9977
|
code: DYN_VAL_NOT_DEFINED,
|
|
9893
9978
|
level: "error",
|
|
@@ -9966,6 +10051,12 @@ var init_lint_rules = __esm(() => {
|
|
|
9966
10051
|
group: "Templates / events",
|
|
9967
10052
|
summary: "Extra attribute on `<x op>` not consumed by the op and not a known wrapper."
|
|
9968
10053
|
},
|
|
10054
|
+
{
|
|
10055
|
+
code: X_OP_IGNORES_CHILDREN,
|
|
10056
|
+
level: "warn",
|
|
10057
|
+
group: "Templates / events",
|
|
10058
|
+
summary: "`<x text/render/render-it/render-each>` has child content the op silently drops."
|
|
10059
|
+
},
|
|
9969
10060
|
{
|
|
9970
10061
|
code: MAYBE_DROP_AT_PREFIX,
|
|
9971
10062
|
level: "hint",
|
|
@@ -9978,6 +10069,12 @@ var init_lint_rules = __esm(() => {
|
|
|
9978
10069
|
group: "Templates / events",
|
|
9979
10070
|
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
10071
|
},
|
|
10072
|
+
{
|
|
10073
|
+
code: DEPRECATED_BARE_X_DIRECTIVE,
|
|
10074
|
+
level: "warn",
|
|
10075
|
+
group: "Templates / events",
|
|
10076
|
+
summary: "Bare `show`/`hide`/`when` on an `<x>` op is deprecated — use the `@`-prefixed directive (`@show`/`@hide`/`@when`)."
|
|
10077
|
+
},
|
|
9981
10078
|
{
|
|
9982
10079
|
code: BAD_VALUE,
|
|
9983
10080
|
level: "error",
|
|
@@ -9988,7 +10085,13 @@ var init_lint_rules = __esm(() => {
|
|
|
9988
10085
|
code: UNSUPPORTED_EXPR_SYNTAX,
|
|
9989
10086
|
level: "error",
|
|
9990
10087
|
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."
|
|
10088
|
+
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."
|
|
10089
|
+
},
|
|
10090
|
+
{
|
|
10091
|
+
code: BINDING_MEMBER_TOO_DEEP,
|
|
10092
|
+
level: "error",
|
|
10093
|
+
group: "Value expressions",
|
|
10094
|
+
summary: "A binding member read goes more than one level deep (`@x.a.b`) — only one member is allowed."
|
|
9992
10095
|
},
|
|
9993
10096
|
{
|
|
9994
10097
|
code: REDUNDANT_TEMPLATE_STRING,
|
|
@@ -10003,10 +10106,10 @@ var init_lint_rules = __esm(() => {
|
|
|
10003
10106
|
summary: "`$'…'` template has no `{}` placeholder — use a plain string literal."
|
|
10004
10107
|
},
|
|
10005
10108
|
{
|
|
10006
|
-
code:
|
|
10007
|
-
level: "
|
|
10008
|
-
group: "
|
|
10009
|
-
summary: "
|
|
10109
|
+
code: CONSTANT_CONDITION,
|
|
10110
|
+
level: "warn",
|
|
10111
|
+
group: "Value expressions",
|
|
10112
|
+
summary: "A non-boolean literal in a boolean condition (`@show`, `@hide`, `@if`) never changes — reference a field or method instead."
|
|
10010
10113
|
},
|
|
10011
10114
|
{
|
|
10012
10115
|
code: UNKNOWN_COMPONENT_NAME,
|
|
@@ -10179,8 +10282,6 @@ function lintIdToMessage(id, info) {
|
|
|
10179
10282
|
}
|
|
10180
10283
|
case "IF_NO_BRANCH_SET":
|
|
10181
10284
|
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
10285
|
case "UNKNOWN_COMPONENT_NAME":
|
|
10185
10286
|
return `Unknown component '${info.name}'${fmtOriginSuffix(info)}`;
|
|
10186
10287
|
case "ALT_HANDLER_NOT_DEFINED":
|
|
@@ -10205,20 +10306,32 @@ function lintIdToMessage(id, info) {
|
|
|
10205
10306
|
return `Unknown <x> op '${info.name}=${JSON.stringify(info.value)}'${fmtTagSuffix(info)}`;
|
|
10206
10307
|
case "UNKNOWN_X_ATTR":
|
|
10207
10308
|
return `Unknown attribute '${info.name}=${JSON.stringify(info.value)}' on <x ${info.op}>${fmtTagSuffix(info)}`;
|
|
10309
|
+
case "X_OP_IGNORES_CHILDREN":
|
|
10310
|
+
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
10311
|
case "MAYBE_DROP_AT_PREFIX": {
|
|
10209
10312
|
const written = info.value !== undefined ? `${info.name}=${JSON.stringify(info.value)}` : info.name;
|
|
10210
10313
|
return `'${written}' on <x> looks like a directive but is actually an x op/attr written with a leading '@'`;
|
|
10211
10314
|
}
|
|
10212
10315
|
case "MAYBE_ADD_AT_PREFIX":
|
|
10213
10316
|
return `'${info.name}' on <${(info.tag ?? "").toLowerCase()}> is a plain attribute, but '@${info.name}' is a directive — add the leading '@'`;
|
|
10317
|
+
case "DEPRECATED_BARE_X_DIRECTIVE":
|
|
10318
|
+
return `'${info.name}' on <x ${info.op}> is deprecated — write '@${info.name}' instead${fmtTagSuffix(info)}`;
|
|
10214
10319
|
case "BAD_VALUE":
|
|
10215
10320
|
return `${badValueMessage(info)}${fmtTagSuffix(info)}`;
|
|
10216
10321
|
case "UNSUPPORTED_EXPR_SYNTAX":
|
|
10217
10322
|
return `${unsupportedExprMessage(info)}${fmtTagSuffix(info)}`;
|
|
10323
|
+
case "BINDING_MEMBER_TOO_DEEP":
|
|
10324
|
+
return `Binding member read ${JSON.stringify(info.value)} goes more than one level deep — only one member is allowed (like '@value.title')${fmtTagSuffix(info)}`;
|
|
10325
|
+
case "SUGGEST_BINDING_MEMBER": {
|
|
10326
|
+
const reads = (info.members ?? []).map(({ member }) => `'@value.${member}'`).join(", ");
|
|
10327
|
+
return `Enrich handler '${info.name}' only copies members of the loop value — read them directly${reads ? ` (${reads})` : ""} and remove the '@enrich-with'`;
|
|
10328
|
+
}
|
|
10218
10329
|
case "REDUNDANT_TEMPLATE_STRING":
|
|
10219
10330
|
return `Redundant template string — '{${info.simpler}}' should be just '${info.simpler}'${fmtOriginSuffix(info)}`;
|
|
10220
10331
|
case "PLACEHOLDERLESS_TEMPLATE_STRING":
|
|
10221
10332
|
return `Template string has no dynamic parts — use the string literal ${info.literal} instead${fmtOriginSuffix(info)}`;
|
|
10333
|
+
case "CONSTANT_CONDITION":
|
|
10334
|
+
return `Condition is the constant literal ${info.literal} — it never changes; reference a field ('.name') or a method ('$name') instead${fmtOriginSuffix(info)}`;
|
|
10222
10335
|
case "UNKNOWN_COMPONENT_SPEC_KEY":
|
|
10223
10336
|
return `Unknown component spec key '${info.key}' — value will be ignored at runtime`;
|
|
10224
10337
|
case "COMP_FIELD_BAD_SHAPE":
|
|
@@ -10321,7 +10434,8 @@ var init_lint = __esm(() => {
|
|
|
10321
10434
|
ternary: "ternary expression",
|
|
10322
10435
|
comparison: "comparison",
|
|
10323
10436
|
logical: "logical expression",
|
|
10324
|
-
"call-with-args": "method call with arguments"
|
|
10437
|
+
"call-with-args": "method call with arguments",
|
|
10438
|
+
"field-path": "dotted field path"
|
|
10325
10439
|
};
|
|
10326
10440
|
});
|
|
10327
10441
|
|
|
@@ -15129,9 +15243,6 @@ class Stack2 {
|
|
|
15129
15243
|
getHandlerFor(name, key) {
|
|
15130
15244
|
return this.comps.getHandlerFor(this.it, name, key);
|
|
15131
15245
|
}
|
|
15132
|
-
lookupRequest(name) {
|
|
15133
|
-
return this.comps.getRequestFor(this.it, name);
|
|
15134
|
-
}
|
|
15135
15246
|
lookupBestView(views, defaultViewName) {
|
|
15136
15247
|
let n = this.views;
|
|
15137
15248
|
while (n !== null) {
|
|
@@ -15540,13 +15651,6 @@ var init_transactor = __esm(() => {
|
|
|
15540
15651
|
const stack = this.buildStack(root, comps);
|
|
15541
15652
|
const [handler, args] = this.handler.getHandlerAndArgs(stack, this);
|
|
15542
15653
|
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
15654
|
args.push(new EventContext(path, this.transactor, this));
|
|
15551
15655
|
return [handler, args];
|
|
15552
15656
|
}
|