tutuca 0.9.31 → 0.9.32

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.
@@ -1147,6 +1147,8 @@ class AttrParser {
1147
1147
  this.parseThen(s);
1148
1148
  else if (directiveName.startsWith("else."))
1149
1149
  this.parseElse(s);
1150
+ else
1151
+ this.px.onParseIssue("unknown-directive", { name: directiveName, value: s });
1150
1152
  }
1151
1153
  _parseWhen(s) {
1152
1154
  if (this.eachAttr !== null)
@@ -1332,6 +1334,30 @@ function optimizeNode(node) {
1332
1334
  node.optimize();
1333
1335
  return node;
1334
1336
  }
1337
+ function processXExtras(node, attrs, opName, startIdx, px) {
1338
+ const consumed = X_OP_CONSUMED[opName];
1339
+ const wrappable = X_OP_WRAPPABLE.has(opName);
1340
+ const wrappers = [];
1341
+ for (let i = startIdx;i < attrs.length; i++) {
1342
+ const a = attrs[i];
1343
+ const aName = a.name;
1344
+ if (consumed.has(aName))
1345
+ continue;
1346
+ if (wrappable && X_ATTR_WRAPPERS[aName]) {
1347
+ wrappers.push([X_ATTR_WRAPPERS[aName], vp.parseCondValue(a.value, px)]);
1348
+ continue;
1349
+ }
1350
+ const issueInfo = { op: opName, name: aName, value: a.value };
1351
+ px.onParseIssue("unknown-x-attr", issueInfo);
1352
+ }
1353
+ for (let i = wrappers.length - 1;i >= 0; i--) {
1354
+ const [Cls, val] = wrappers[i];
1355
+ const wrapper = px.addNodeIf(Cls, val, node);
1356
+ if (wrapper !== null)
1357
+ node = wrapper;
1358
+ }
1359
+ return node;
1360
+ }
1335
1361
  function wrap(node, px, wrappers) {
1336
1362
  if (wrappers) {
1337
1363
  for (let i = wrappers.length - 1;i >= 0; i--) {
@@ -1438,6 +1464,9 @@ class ParseContext {
1438
1464
  return this.nodes[id] ?? null;
1439
1465
  }
1440
1466
  onAttributes(_attrs, _wrapperAttrs, _textChild, _isMacroCall) {}
1467
+ onParseIssue(kind, info) {
1468
+ console.warn(`tutuca parse issue [${kind}]`, info);
1469
+ }
1441
1470
  }
1442
1471
  function condenseChildsWhites(childs) {
1443
1472
  if (childs.length === 0)
@@ -1517,7 +1546,7 @@ function compileModifiers(eventName, names) {
1517
1546
  return w(this, f, args, ctx);
1518
1547
  };
1519
1548
  }
1520
- var TextNode, CommentNode, ChildsNode, DomNode, FragmentNode, maybeFragment = (xs) => xs.length === 1 ? xs[0] : new FragmentNode(xs), VALID_NODE_RE, ANode, MacroNode, RenderViewId, RenderNode, RenderItNode, RenderEachNode, RenderTextNode, RenderOnceNode, WrapperNode, ShowNode, HideNode, PushViewNameNode, SlotNode, ScopeNode, EachNode, filterAlwaysTrue = (_v, _k, _seq) => true, nullLoopWith = (seq) => ({ seq }), 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) => {
1549
+ var TextNode, CommentNode, ChildsNode, DomNode, FragmentNode, maybeFragment = (xs) => xs.length === 1 ? xs[0] : new FragmentNode(xs), VALID_NODE_RE, ANode, MacroNode, RenderViewId, RenderNode, RenderItNode, RenderEachNode, RenderTextNode, RenderOnceNode, WrapperNode, ShowNode, HideNode, PushViewNameNode, SlotNode, ScopeNode, EachNode, filterAlwaysTrue = (_v, _k, _seq) => true, nullLoopWith = (seq) => ({ seq }), X_OP_CONSUMED, X_OP_WRAPPABLE, X_ATTR_WRAPPERS, 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) => {
1521
1550
  const node = n instanceof FragmentNode ? n.childs[0] : n;
1522
1551
  return node instanceof DomNode && HTML_BLOCK_TAGS.has(node.tagName);
1523
1552
  }, isMac, 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;
@@ -1616,18 +1645,19 @@ var init_anode = __esm(() => {
1616
1645
  static parse(html, px) {
1617
1646
  const nodes = px.parseHTML(html);
1618
1647
  if (nodes.length === 0)
1619
- return new TextNode("");
1648
+ return new CommentNode("Empty View in ANode.parse");
1620
1649
  if (nodes.length === 1)
1621
1650
  return ANode.fromDOM(nodes[0], px);
1622
- const childs = new Array(nodes.length);
1623
- for (let i = 0;i < nodes.length; i++)
1624
- childs[i] = ANode.fromDOM(nodes[i], px);
1651
+ const childs = [];
1652
+ for (let i = 0;i < nodes.length; i++) {
1653
+ const child = ANode.fromDOM(nodes[i], px);
1654
+ if (child !== null)
1655
+ childs.push(child);
1656
+ }
1625
1657
  const trimmed = condenseChildsWhites(childs);
1626
1658
  if (trimmed.length === 0)
1627
- return new TextNode("");
1628
- if (trimmed.length === 1)
1629
- return trimmed[0];
1630
- return new FragmentNode(trimmed);
1659
+ return new CommentNode("Empty View in ANode.parse");
1660
+ return maybeFragment(trimmed);
1631
1661
  }
1632
1662
  static fromDOM(node, px) {
1633
1663
  if (node instanceof px.Text)
@@ -1642,25 +1672,37 @@ var init_anode = __esm(() => {
1642
1672
  if (tag === "X" || isPseudoX) {
1643
1673
  if (attrs.length === 0)
1644
1674
  return maybeFragment(childs);
1645
- const { name, value } = attrs[isPseudoX ? 1 : 0];
1675
+ const opIdx = isPseudoX ? 1 : 0;
1676
+ const { name, value } = attrs[opIdx];
1646
1677
  const as = attrs.getNamedItem("as")?.value ?? null;
1678
+ let node2;
1647
1679
  switch (name) {
1648
1680
  case "slot":
1649
- return new SlotNode(null, vp.const(value), maybeFragment(childs));
1681
+ node2 = new SlotNode(null, vp.const(value), maybeFragment(childs));
1682
+ break;
1650
1683
  case "text":
1651
- return px.addNodeIf(RenderTextNode, vp.parseText(value, px));
1684
+ node2 = px.addNodeIf(RenderTextNode, vp.parseText(value, px));
1685
+ break;
1652
1686
  case "render":
1653
- return px.addNodeIf(RenderNode, vp.parseRender(value, px), as);
1687
+ node2 = px.addNodeIf(RenderNode, vp.parseRender(value, px), as);
1688
+ break;
1654
1689
  case "render-it":
1655
- return px.addNodeIf(RenderItNode, vp.bindValIt, as);
1690
+ node2 = px.addNodeIf(RenderItNode, vp.bindValIt, as);
1691
+ break;
1656
1692
  case "render-each":
1657
- return RenderEachNode.parse(px, vp, value, as, attrs);
1693
+ node2 = RenderEachNode.parse(px, vp, value, as, attrs);
1694
+ break;
1658
1695
  case "show":
1659
- return px.addNodeIf(ShowNode, vp.parseCondValue(value, px), maybeFragment(childs));
1696
+ node2 = px.addNodeIf(ShowNode, vp.parseCondValue(value, px), maybeFragment(childs));
1697
+ break;
1660
1698
  case "hide":
1661
- return px.addNodeIf(HideNode, vp.parseCondValue(value, px), maybeFragment(childs));
1699
+ node2 = px.addNodeIf(HideNode, vp.parseCondValue(value, px), maybeFragment(childs));
1700
+ break;
1701
+ default:
1702
+ px.onParseIssue("unknown-x-op", { name, value });
1703
+ return new CommentNode(`Error: InvalidSpecialTagOp ${name}=${value}`);
1662
1704
  }
1663
- return new CommentNode(`Error: InvalidSpecialTagOp ${name}=${value}`);
1705
+ return processXExtras(node2, attrs, name, (isPseudoX ? 1 : 0) + 1, px);
1664
1706
  } else if (tag.charCodeAt(1) === 58 && tag.charCodeAt(0) === 88) {
1665
1707
  const macroName = tag.slice(2).toLowerCase();
1666
1708
  if (macroName === "slot") {
@@ -1844,6 +1886,17 @@ var init_anode = __esm(() => {
1844
1886
  }
1845
1887
  static register = true;
1846
1888
  };
1889
+ X_OP_CONSUMED = {
1890
+ slot: new Set,
1891
+ text: new Set,
1892
+ render: new Set(["as"]),
1893
+ "render-it": new Set(["as"]),
1894
+ "render-each": new Set(["as", "when", "loop-with"]),
1895
+ show: new Set,
1896
+ hide: new Set
1897
+ };
1898
+ X_OP_WRAPPABLE = new Set(["text", "render", "render-it", "render-each"]);
1899
+ X_ATTR_WRAPPERS = { show: ShowNode, hide: HideNode };
1847
1900
  WRAPPER_NODES = {
1848
1901
  slot: SlotNode,
1849
1902
  show: ShowNode,
@@ -2084,11 +2137,29 @@ function checkComponent(Comp, lx = new LintContext) {
2084
2137
  });
2085
2138
  }
2086
2139
  function checkView(lx, view, Comp, referencedAlters, referencedComputed) {
2140
+ checkParseIssues(lx, view);
2087
2141
  checkRenderItInLoop(lx, view);
2088
2142
  checkEventModifiers(lx, view);
2089
2143
  checkKnownHandlerNames(lx, view, Comp, referencedAlters, referencedComputed);
2090
2144
  checkMacroCallArgs(lx, view, Comp);
2091
2145
  }
2146
+ function checkParseIssues(lx, view) {
2147
+ const issues = view.ctx.parseIssues;
2148
+ if (!issues)
2149
+ return;
2150
+ for (const { kind, info } of issues) {
2151
+ const id = PARSE_ISSUE_KIND_TO_LINT_ID[kind];
2152
+ if (!id)
2153
+ continue;
2154
+ lx.error(id, info);
2155
+ const known = AT_PREFIX_HINT_KNOWN_BY_KIND[kind];
2156
+ if (known && info.name?.startsWith("@")) {
2157
+ const suggestion = info.name.slice(1);
2158
+ if (known.has(suggestion))
2159
+ lx.hint(MAYBE_DROP_AT_PREFIX, { ...info, suggestion });
2160
+ }
2161
+ }
2162
+ }
2092
2163
  function checkMacroCallArgs(lx, view, Comp) {
2093
2164
  const { scope } = Comp;
2094
2165
  for (const macroNode of view.ctx.macroNodes) {
@@ -2377,9 +2448,28 @@ class LintContext {
2377
2448
  this.reports.push({ id, info, level, context: { ...this.frame } });
2378
2449
  }
2379
2450
  }
2380
- var ALT_HANDLER_NOT_DEFINED = "ALT_HANDLER_NOT_DEFINED", ALT_HANDLER_NOT_REFERENCED = "ALT_HANDLER_NOT_REFERENCED", 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", COMPUTED_VAL_NOT_DEFINED = "COMPUTED_VAL_NOT_DEFINED", COMPUTED_NOT_REFERENCED = "COMPUTED_NOT_REFERENCED", DUPLICATE_ATTR_DEFINITION = "DUPLICATE_ATTR_DEFINITION", UNKNOWN_REQUEST_NAME = "UNKNOWN_REQUEST_NAME", UNKNOWN_COMPONENT_NAME = "UNKNOWN_COMPONENT_NAME", UNKNOWN_MACRO_ARG = "UNKNOWN_MACRO_ARG", LEVEL_WARN = "warn", LEVEL_ERROR = "error", LEVEL_HINT = "hint", NO_WRAPPERS, KNOWN_HANDLER_NAMES, LintParseContext;
2451
+ var ALT_HANDLER_NOT_DEFINED = "ALT_HANDLER_NOT_DEFINED", ALT_HANDLER_NOT_REFERENCED = "ALT_HANDLER_NOT_REFERENCED", 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", COMPUTED_VAL_NOT_DEFINED = "COMPUTED_VAL_NOT_DEFINED", COMPUTED_NOT_REFERENCED = "COMPUTED_NOT_REFERENCED", DUPLICATE_ATTR_DEFINITION = "DUPLICATE_ATTR_DEFINITION", UNKNOWN_REQUEST_NAME = "UNKNOWN_REQUEST_NAME", UNKNOWN_COMPONENT_NAME = "UNKNOWN_COMPONENT_NAME", UNKNOWN_MACRO_ARG = "UNKNOWN_MACRO_ARG", UNKNOWN_DIRECTIVE = "UNKNOWN_DIRECTIVE", UNKNOWN_X_OP = "UNKNOWN_X_OP", UNKNOWN_X_ATTR = "UNKNOWN_X_ATTR", MAYBE_DROP_AT_PREFIX = "MAYBE_DROP_AT_PREFIX", PARSE_ISSUE_KIND_TO_LINT_ID, X_KNOWN_OP_NAMES, X_KNOWN_ATTR_NAMES, AT_PREFIX_HINT_KNOWN_BY_KIND, LEVEL_WARN = "warn", LEVEL_ERROR = "error", LEVEL_HINT = "hint", NO_WRAPPERS, KNOWN_HANDLER_NAMES, LintParseContext;
2381
2452
  var init_lint_check = __esm(() => {
2382
2453
  init_anode();
2454
+ PARSE_ISSUE_KIND_TO_LINT_ID = {
2455
+ "unknown-directive": UNKNOWN_DIRECTIVE,
2456
+ "unknown-x-op": UNKNOWN_X_OP,
2457
+ "unknown-x-attr": UNKNOWN_X_ATTR
2458
+ };
2459
+ X_KNOWN_OP_NAMES = new Set([
2460
+ "slot",
2461
+ "text",
2462
+ "render",
2463
+ "render-it",
2464
+ "render-each",
2465
+ "show",
2466
+ "hide"
2467
+ ]);
2468
+ X_KNOWN_ATTR_NAMES = new Set(["as", "when", "loop-with", "show", "hide"]);
2469
+ AT_PREFIX_HINT_KNOWN_BY_KIND = {
2470
+ "unknown-x-op": X_KNOWN_OP_NAMES,
2471
+ "unknown-x-attr": X_KNOWN_ATTR_NAMES
2472
+ };
2383
2473
  NO_WRAPPERS = {};
2384
2474
  KNOWN_HANDLER_NAMES = new Set([
2385
2475
  "value",
@@ -2405,10 +2495,14 @@ var init_lint_check = __esm(() => {
2405
2495
  constructor(document2, Text, Comment) {
2406
2496
  super(document2, Text, Comment);
2407
2497
  this.attrs = [];
2498
+ this.parseIssues = [];
2408
2499
  }
2409
2500
  onAttributes(attrs, wrapperAttrs, textChild, isMacroCall = false) {
2410
2501
  this.attrs.push({ attrs, wrapperAttrs, textChild, isMacroCall });
2411
2502
  }
2503
+ onParseIssue(kind, info) {
2504
+ this.parseIssues.push({ kind, info });
2505
+ }
2412
2506
  };
2413
2507
  });
2414
2508
 
@@ -722,6 +722,8 @@ class AttrParser {
722
722
  this.parseThen(s);
723
723
  else if (directiveName.startsWith("else."))
724
724
  this.parseElse(s);
725
+ else
726
+ this.px.onParseIssue("unknown-directive", { name: directiveName, value: s });
725
727
  }
726
728
  _parseWhen(s) {
727
729
  if (this.eachAttr !== null)
@@ -1007,18 +1009,19 @@ class ANode extends BaseNode {
1007
1009
  static parse(html, px) {
1008
1010
  const nodes = px.parseHTML(html);
1009
1011
  if (nodes.length === 0)
1010
- return new TextNode("");
1012
+ return new CommentNode("Empty View in ANode.parse");
1011
1013
  if (nodes.length === 1)
1012
1014
  return ANode.fromDOM(nodes[0], px);
1013
- const childs = new Array(nodes.length);
1014
- for (let i = 0;i < nodes.length; i++)
1015
- childs[i] = ANode.fromDOM(nodes[i], px);
1015
+ const childs = [];
1016
+ for (let i = 0;i < nodes.length; i++) {
1017
+ const child = ANode.fromDOM(nodes[i], px);
1018
+ if (child !== null)
1019
+ childs.push(child);
1020
+ }
1016
1021
  const trimmed = condenseChildsWhites(childs);
1017
1022
  if (trimmed.length === 0)
1018
- return new TextNode("");
1019
- if (trimmed.length === 1)
1020
- return trimmed[0];
1021
- return new FragmentNode(trimmed);
1023
+ return new CommentNode("Empty View in ANode.parse");
1024
+ return maybeFragment(trimmed);
1022
1025
  }
1023
1026
  static fromDOM(node, px) {
1024
1027
  if (node instanceof px.Text)
@@ -1033,25 +1036,37 @@ class ANode extends BaseNode {
1033
1036
  if (tag === "X" || isPseudoX) {
1034
1037
  if (attrs.length === 0)
1035
1038
  return maybeFragment(childs);
1036
- const { name, value } = attrs[isPseudoX ? 1 : 0];
1039
+ const opIdx = isPseudoX ? 1 : 0;
1040
+ const { name, value } = attrs[opIdx];
1037
1041
  const as = attrs.getNamedItem("as")?.value ?? null;
1042
+ let node2;
1038
1043
  switch (name) {
1039
1044
  case "slot":
1040
- return new SlotNode(null, vp.const(value), maybeFragment(childs));
1045
+ node2 = new SlotNode(null, vp.const(value), maybeFragment(childs));
1046
+ break;
1041
1047
  case "text":
1042
- return px.addNodeIf(RenderTextNode, vp.parseText(value, px));
1048
+ node2 = px.addNodeIf(RenderTextNode, vp.parseText(value, px));
1049
+ break;
1043
1050
  case "render":
1044
- return px.addNodeIf(RenderNode, vp.parseRender(value, px), as);
1051
+ node2 = px.addNodeIf(RenderNode, vp.parseRender(value, px), as);
1052
+ break;
1045
1053
  case "render-it":
1046
- return px.addNodeIf(RenderItNode, vp.bindValIt, as);
1054
+ node2 = px.addNodeIf(RenderItNode, vp.bindValIt, as);
1055
+ break;
1047
1056
  case "render-each":
1048
- return RenderEachNode.parse(px, vp, value, as, attrs);
1057
+ node2 = RenderEachNode.parse(px, vp, value, as, attrs);
1058
+ break;
1049
1059
  case "show":
1050
- return px.addNodeIf(ShowNode, vp.parseCondValue(value, px), maybeFragment(childs));
1060
+ node2 = px.addNodeIf(ShowNode, vp.parseCondValue(value, px), maybeFragment(childs));
1061
+ break;
1051
1062
  case "hide":
1052
- return px.addNodeIf(HideNode, vp.parseCondValue(value, px), maybeFragment(childs));
1063
+ node2 = px.addNodeIf(HideNode, vp.parseCondValue(value, px), maybeFragment(childs));
1064
+ break;
1065
+ default:
1066
+ px.onParseIssue("unknown-x-op", { name, value });
1067
+ return new CommentNode(`Error: InvalidSpecialTagOp ${name}=${value}`);
1053
1068
  }
1054
- return new CommentNode(`Error: InvalidSpecialTagOp ${name}=${value}`);
1069
+ return processXExtras(node2, attrs, name, (isPseudoX ? 1 : 0) + 1, px);
1055
1070
  } else if (tag.charCodeAt(1) === 58 && tag.charCodeAt(0) === 88) {
1056
1071
  const macroName = tag.slice(2).toLowerCase();
1057
1072
  if (macroName === "slot") {
@@ -1072,6 +1087,30 @@ class ANode extends BaseNode {
1072
1087
  return new CommentNode(`Error: InvalidTagName ${tag}`);
1073
1088
  }
1074
1089
  }
1090
+ function processXExtras(node, attrs, opName, startIdx, px) {
1091
+ const consumed = X_OP_CONSUMED[opName];
1092
+ const wrappable = X_OP_WRAPPABLE.has(opName);
1093
+ const wrappers = [];
1094
+ for (let i = startIdx;i < attrs.length; i++) {
1095
+ const a = attrs[i];
1096
+ const aName = a.name;
1097
+ if (consumed.has(aName))
1098
+ continue;
1099
+ if (wrappable && X_ATTR_WRAPPERS[aName]) {
1100
+ wrappers.push([X_ATTR_WRAPPERS[aName], vp.parseCondValue(a.value, px)]);
1101
+ continue;
1102
+ }
1103
+ const issueInfo = { op: opName, name: aName, value: a.value };
1104
+ px.onParseIssue("unknown-x-attr", issueInfo);
1105
+ }
1106
+ for (let i = wrappers.length - 1;i >= 0; i--) {
1107
+ const [Cls, val] = wrappers[i];
1108
+ const wrapper = px.addNodeIf(Cls, val, node);
1109
+ if (wrapper !== null)
1110
+ node = wrapper;
1111
+ }
1112
+ return node;
1113
+ }
1075
1114
  function wrap(node, px, wrappers) {
1076
1115
  if (wrappers) {
1077
1116
  for (let i = wrappers.length - 1;i >= 0; i--) {
@@ -1299,6 +1338,17 @@ class IterInfo {
1299
1338
  }
1300
1339
  var filterAlwaysTrue = (_v, _k, _seq) => true;
1301
1340
  var nullLoopWith = (seq) => ({ seq });
1341
+ var X_OP_CONSUMED = {
1342
+ slot: new Set,
1343
+ text: new Set,
1344
+ render: new Set(["as"]),
1345
+ "render-it": new Set(["as"]),
1346
+ "render-each": new Set(["as", "when", "loop-with"]),
1347
+ show: new Set,
1348
+ hide: new Set
1349
+ };
1350
+ var X_OP_WRAPPABLE = new Set(["text", "render", "render-it", "render-each"]);
1351
+ var X_ATTR_WRAPPERS = { show: ShowNode, hide: HideNode };
1302
1352
  var WRAPPER_NODES = {
1303
1353
  slot: SlotNode,
1304
1354
  show: ShowNode,
@@ -1375,6 +1425,9 @@ class ParseContext {
1375
1425
  return this.nodes[id] ?? null;
1376
1426
  }
1377
1427
  onAttributes(_attrs, _wrapperAttrs, _textChild, _isMacroCall) {}
1428
+ onParseIssue(kind, info) {
1429
+ console.warn(`tutuca parse issue [${kind}]`, info);
1430
+ }
1378
1431
  }
1379
1432
  var _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";
1380
1433
  var HTML_BLOCK_TAGS = new Set(_htmlBlockTags.split(","));
@@ -1574,6 +1627,29 @@ var DUPLICATE_ATTR_DEFINITION = "DUPLICATE_ATTR_DEFINITION";
1574
1627
  var UNKNOWN_REQUEST_NAME = "UNKNOWN_REQUEST_NAME";
1575
1628
  var UNKNOWN_COMPONENT_NAME = "UNKNOWN_COMPONENT_NAME";
1576
1629
  var UNKNOWN_MACRO_ARG = "UNKNOWN_MACRO_ARG";
1630
+ var UNKNOWN_DIRECTIVE = "UNKNOWN_DIRECTIVE";
1631
+ var UNKNOWN_X_OP = "UNKNOWN_X_OP";
1632
+ var UNKNOWN_X_ATTR = "UNKNOWN_X_ATTR";
1633
+ var MAYBE_DROP_AT_PREFIX = "MAYBE_DROP_AT_PREFIX";
1634
+ var PARSE_ISSUE_KIND_TO_LINT_ID = {
1635
+ "unknown-directive": UNKNOWN_DIRECTIVE,
1636
+ "unknown-x-op": UNKNOWN_X_OP,
1637
+ "unknown-x-attr": UNKNOWN_X_ATTR
1638
+ };
1639
+ var X_KNOWN_OP_NAMES = new Set([
1640
+ "slot",
1641
+ "text",
1642
+ "render",
1643
+ "render-it",
1644
+ "render-each",
1645
+ "show",
1646
+ "hide"
1647
+ ]);
1648
+ var X_KNOWN_ATTR_NAMES = new Set(["as", "when", "loop-with", "show", "hide"]);
1649
+ var AT_PREFIX_HINT_KNOWN_BY_KIND = {
1650
+ "unknown-x-op": X_KNOWN_OP_NAMES,
1651
+ "unknown-x-attr": X_KNOWN_ATTR_NAMES
1652
+ };
1577
1653
  var LEVEL_WARN = "warn";
1578
1654
  var LEVEL_ERROR = "error";
1579
1655
  var LEVEL_HINT = "hint";
@@ -1594,11 +1670,29 @@ function checkComponent(Comp, lx = new LintContext) {
1594
1670
  });
1595
1671
  }
1596
1672
  function checkView(lx, view, Comp, referencedAlters, referencedComputed) {
1673
+ checkParseIssues(lx, view);
1597
1674
  checkRenderItInLoop(lx, view);
1598
1675
  checkEventModifiers(lx, view);
1599
1676
  checkKnownHandlerNames(lx, view, Comp, referencedAlters, referencedComputed);
1600
1677
  checkMacroCallArgs(lx, view, Comp);
1601
1678
  }
1679
+ function checkParseIssues(lx, view) {
1680
+ const issues = view.ctx.parseIssues;
1681
+ if (!issues)
1682
+ return;
1683
+ for (const { kind, info } of issues) {
1684
+ const id = PARSE_ISSUE_KIND_TO_LINT_ID[kind];
1685
+ if (!id)
1686
+ continue;
1687
+ lx.error(id, info);
1688
+ const known = AT_PREFIX_HINT_KNOWN_BY_KIND[kind];
1689
+ if (known && info.name?.startsWith("@")) {
1690
+ const suggestion = info.name.slice(1);
1691
+ if (known.has(suggestion))
1692
+ lx.hint(MAYBE_DROP_AT_PREFIX, { ...info, suggestion });
1693
+ }
1694
+ }
1695
+ }
1602
1696
  function checkMacroCallArgs(lx, view, Comp) {
1603
1697
  const { scope } = Comp;
1604
1698
  for (const macroNode of view.ctx.macroNodes) {
@@ -1913,10 +2007,14 @@ class LintParseContext extends ParseContext {
1913
2007
  constructor(document2, Text, Comment) {
1914
2008
  super(document2, Text, Comment);
1915
2009
  this.attrs = [];
2010
+ this.parseIssues = [];
1916
2011
  }
1917
2012
  onAttributes(attrs, wrapperAttrs, textChild, isMacroCall = false) {
1918
2013
  this.attrs.push({ attrs, wrapperAttrs, textChild, isMacroCall });
1919
2014
  }
2015
+ onParseIssue(kind, info) {
2016
+ this.parseIssues.push({ kind, info });
2017
+ }
1920
2018
  }
1921
2019
 
1922
2020
  // tools/format/lint.js
@@ -1956,6 +2054,14 @@ function lintIdToMessage(id, info) {
1956
2054
  return `Alter handler '${info.name}' is defined but not referenced`;
1957
2055
  case "UNKNOWN_MACRO_ARG":
1958
2056
  return `Argument '${info.name}' is not declared in macro '${info.macroName}'`;
2057
+ case "UNKNOWN_DIRECTIVE":
2058
+ return `Unknown directive '@${info.name}=${JSON.stringify(info.value)}'`;
2059
+ case "UNKNOWN_X_OP":
2060
+ return `Unknown <x> op '${info.name}=${JSON.stringify(info.value)}'`;
2061
+ case "UNKNOWN_X_ATTR":
2062
+ return `Unknown attribute '${info.name}=${JSON.stringify(info.value)}' on <x ${info.op}>`;
2063
+ case "MAYBE_DROP_AT_PREFIX":
2064
+ return `Did you mean '${info.suggestion}'? Drop the '@' prefix on <x>.`;
1959
2065
  case "LINT_ERROR":
1960
2066
  return info.message;
1961
2067
  default:
@@ -8624,6 +8730,7 @@ class LintClassCollectorCtx extends ParseCtxClassSetCollector {
8624
8730
  constructor(...args) {
8625
8731
  super(...args);
8626
8732
  this.attrs = [];
8733
+ this.parseIssues = [];
8627
8734
  }
8628
8735
  enterMacro(macroName, macroVars, macroSlots) {
8629
8736
  const { document: document2, Text, Comment, nodes, events, macroNodes } = this;
@@ -8631,12 +8738,16 @@ class LintClassCollectorCtx extends ParseCtxClassSetCollector {
8631
8738
  const v = new LintClassCollectorCtx(document2, Text, Comment, nodes, events, macroNodes, frame, this);
8632
8739
  v.classes = this.classes;
8633
8740
  v.attrs = this.attrs;
8741
+ v.parseIssues = this.parseIssues;
8634
8742
  return v;
8635
8743
  }
8636
8744
  onAttributes(attrs, wrapperAttrs, textChild, isMacroCall = false) {
8637
8745
  super.onAttributes(attrs, wrapperAttrs, textChild, isMacroCall);
8638
8746
  this.attrs.push({ attrs, wrapperAttrs, textChild, isMacroCall });
8639
8747
  }
8748
+ onParseIssue(kind, info) {
8749
+ this.parseIssues.push({ kind, info });
8750
+ }
8640
8751
  }
8641
8752
  export {
8642
8753
  version,
@@ -8688,10 +8799,13 @@ export {
8688
8799
  compileClassesToStyle,
8689
8800
  checkComponent,
8690
8801
  check,
8802
+ UNKNOWN_X_OP,
8803
+ UNKNOWN_X_ATTR,
8691
8804
  UNKNOWN_REQUEST_NAME,
8692
8805
  UNKNOWN_MACRO_ARG,
8693
8806
  UNKNOWN_HANDLER_ARG_NAME,
8694
8807
  UNKNOWN_EVENT_MODIFIER,
8808
+ UNKNOWN_DIRECTIVE,
8695
8809
  UNKNOWN_COMPONENT_NAME,
8696
8810
  Stack2 as Stack,
8697
8811
  Set2 as Set,
@@ -8707,6 +8821,7 @@ export {
8707
8821
  OrderedMap,
8708
8822
  OrderedMap as OMap,
8709
8823
  Map2 as Map,
8824
+ MAYBE_DROP_AT_PREFIX,
8710
8825
  List,
8711
8826
  LintParseContext,
8712
8827
  LintContext,