tutuca 0.9.30 → 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.
@@ -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)
@@ -1005,7 +1007,21 @@ class ANode extends BaseNode {
1005
1007
  return this.val.toPathItem();
1006
1008
  }
1007
1009
  static parse(html, px) {
1008
- return ANode.fromDOM(px.parseHTML(html)[0] ?? new px.Text(""), px);
1010
+ const nodes = px.parseHTML(html);
1011
+ if (nodes.length === 0)
1012
+ return new CommentNode("Empty View in ANode.parse");
1013
+ if (nodes.length === 1)
1014
+ return ANode.fromDOM(nodes[0], 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
+ }
1021
+ const trimmed = condenseChildsWhites(childs);
1022
+ if (trimmed.length === 0)
1023
+ return new CommentNode("Empty View in ANode.parse");
1024
+ return maybeFragment(trimmed);
1009
1025
  }
1010
1026
  static fromDOM(node, px) {
1011
1027
  if (node instanceof px.Text)
@@ -1020,27 +1036,37 @@ class ANode extends BaseNode {
1020
1036
  if (tag === "X" || isPseudoX) {
1021
1037
  if (attrs.length === 0)
1022
1038
  return maybeFragment(childs);
1023
- const { name, value } = attrs[isPseudoX ? 1 : 0];
1039
+ const opIdx = isPseudoX ? 1 : 0;
1040
+ const { name, value } = attrs[opIdx];
1024
1041
  const as = attrs.getNamedItem("as")?.value ?? null;
1042
+ let node2;
1025
1043
  switch (name) {
1026
1044
  case "slot":
1027
- return new SlotNode(null, vp.const(value), maybeFragment(childs));
1028
- case "text": {
1029
- const v = vp.parseText(value, px);
1030
- return v !== null ? new RenderTextNode(null, v) : null;
1031
- }
1045
+ node2 = new SlotNode(null, vp.const(value), maybeFragment(childs));
1046
+ break;
1047
+ case "text":
1048
+ node2 = px.addNodeIf(RenderTextNode, vp.parseText(value, px));
1049
+ break;
1032
1050
  case "render":
1033
- return px.addNodeIf(RenderNode, vp.parseRender(value, px), as);
1051
+ node2 = px.addNodeIf(RenderNode, vp.parseRender(value, px), as);
1052
+ break;
1034
1053
  case "render-it":
1035
- return px.addNodeIf(RenderItNode, vp.bindValIt, as);
1054
+ node2 = px.addNodeIf(RenderItNode, vp.bindValIt, as);
1055
+ break;
1036
1056
  case "render-each":
1037
- return RenderEachNode.parse(px, vp, value, as, attrs);
1057
+ node2 = RenderEachNode.parse(px, vp, value, as, attrs);
1058
+ break;
1038
1059
  case "show":
1039
- return px.addNodeIf(ShowNode, vp.parseCondValue(value, px), maybeFragment(childs));
1060
+ node2 = px.addNodeIf(ShowNode, vp.parseCondValue(value, px), maybeFragment(childs));
1061
+ break;
1040
1062
  case "hide":
1041
- 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}`);
1042
1068
  }
1043
- return new CommentNode(`Error: InvalidSpecialTagOp ${name}=${value}`);
1069
+ return processXExtras(node2, attrs, name, (isPseudoX ? 1 : 0) + 1, px);
1044
1070
  } else if (tag.charCodeAt(1) === 58 && tag.charCodeAt(0) === 88) {
1045
1071
  const macroName = tag.slice(2).toLowerCase();
1046
1072
  if (macroName === "slot") {
@@ -1061,6 +1087,30 @@ class ANode extends BaseNode {
1061
1087
  return new CommentNode(`Error: InvalidTagName ${tag}`);
1062
1088
  }
1063
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
+ }
1064
1114
  function wrap(node, px, wrappers) {
1065
1115
  if (wrappers) {
1066
1116
  for (let i = wrappers.length - 1;i >= 0; i--) {
@@ -1288,6 +1338,17 @@ class IterInfo {
1288
1338
  }
1289
1339
  var filterAlwaysTrue = (_v, _k, _seq) => true;
1290
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 };
1291
1352
  var WRAPPER_NODES = {
1292
1353
  slot: SlotNode,
1293
1354
  show: ShowNode,
@@ -1320,7 +1381,7 @@ class ParseContext {
1320
1381
  parseHTML(html) {
1321
1382
  const t = this.document.createElement("template");
1322
1383
  t.innerHTML = html;
1323
- return Array.from(t.content.childNodes);
1384
+ return t.content.childNodes;
1324
1385
  }
1325
1386
  addNodeIf(Class, val, extra) {
1326
1387
  if (val !== null) {
@@ -1364,6 +1425,9 @@ class ParseContext {
1364
1425
  return this.nodes[id] ?? null;
1365
1426
  }
1366
1427
  onAttributes(_attrs, _wrapperAttrs, _textChild, _isMacroCall) {}
1428
+ onParseIssue(kind, info) {
1429
+ console.warn(`tutuca parse issue [${kind}]`, info);
1430
+ }
1367
1431
  }
1368
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";
1369
1433
  var HTML_BLOCK_TAGS = new Set(_htmlBlockTags.split(","));
@@ -1563,6 +1627,29 @@ var DUPLICATE_ATTR_DEFINITION = "DUPLICATE_ATTR_DEFINITION";
1563
1627
  var UNKNOWN_REQUEST_NAME = "UNKNOWN_REQUEST_NAME";
1564
1628
  var UNKNOWN_COMPONENT_NAME = "UNKNOWN_COMPONENT_NAME";
1565
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
+ };
1566
1653
  var LEVEL_WARN = "warn";
1567
1654
  var LEVEL_ERROR = "error";
1568
1655
  var LEVEL_HINT = "hint";
@@ -1583,11 +1670,29 @@ function checkComponent(Comp, lx = new LintContext) {
1583
1670
  });
1584
1671
  }
1585
1672
  function checkView(lx, view, Comp, referencedAlters, referencedComputed) {
1673
+ checkParseIssues(lx, view);
1586
1674
  checkRenderItInLoop(lx, view);
1587
1675
  checkEventModifiers(lx, view);
1588
1676
  checkKnownHandlerNames(lx, view, Comp, referencedAlters, referencedComputed);
1589
1677
  checkMacroCallArgs(lx, view, Comp);
1590
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
+ }
1591
1696
  function checkMacroCallArgs(lx, view, Comp) {
1592
1697
  const { scope } = Comp;
1593
1698
  for (const macroNode of view.ctx.macroNodes) {
@@ -1597,7 +1702,10 @@ function checkMacroCallArgs(lx, view, Comp) {
1597
1702
  const { defaults } = macro;
1598
1703
  for (const argName in macroNode.attrs) {
1599
1704
  if (!(argName in defaults)) {
1600
- lx.error(UNKNOWN_MACRO_ARG, { name: argName, macroName: macroNode.name });
1705
+ lx.error(UNKNOWN_MACRO_ARG, {
1706
+ name: argName,
1707
+ macroName: macroNode.name
1708
+ });
1601
1709
  }
1602
1710
  }
1603
1711
  }
@@ -1779,7 +1887,7 @@ function checkConsistentAttrVal(lx, val, fields, proto, computed, scope, alter,
1779
1887
  if (alter[val.name] === undefined) {
1780
1888
  lx.error(ALT_HANDLER_NOT_DEFINED, { name: val.name });
1781
1889
  }
1782
- } else if (valName !== "ConstVal" && valName !== "BindVal") {
1890
+ } else if (valName !== "ConstVal" && valName !== "BindVal" && valName !== "DynVal") {
1783
1891
  console.log(val);
1784
1892
  }
1785
1893
  }
@@ -1899,10 +2007,14 @@ class LintParseContext extends ParseContext {
1899
2007
  constructor(document2, Text, Comment) {
1900
2008
  super(document2, Text, Comment);
1901
2009
  this.attrs = [];
2010
+ this.parseIssues = [];
1902
2011
  }
1903
2012
  onAttributes(attrs, wrapperAttrs, textChild, isMacroCall = false) {
1904
2013
  this.attrs.push({ attrs, wrapperAttrs, textChild, isMacroCall });
1905
2014
  }
2015
+ onParseIssue(kind, info) {
2016
+ this.parseIssues.push({ kind, info });
2017
+ }
1906
2018
  }
1907
2019
 
1908
2020
  // tools/format/lint.js
@@ -1942,6 +2054,14 @@ function lintIdToMessage(id, info) {
1942
2054
  return `Alter handler '${info.name}' is defined but not referenced`;
1943
2055
  case "UNKNOWN_MACRO_ARG":
1944
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>.`;
1945
2065
  case "LINT_ERROR":
1946
2066
  return info.message;
1947
2067
  default:
@@ -2117,7 +2237,11 @@ class ComponentStack {
2117
2237
  }
2118
2238
  }
2119
2239
  registerMacros(macros) {
2120
- Object.assign(this.macros, macros);
2240
+ for (const key in macros) {
2241
+ const lower = key.toLowerCase();
2242
+ console.assert(this.macros[lower] === undefined, "macro key collision", lower);
2243
+ this.macros[lower] = macros[key];
2244
+ }
2121
2245
  }
2122
2246
  getCompFor(v) {
2123
2247
  return this.comps.getCompFor(v);
@@ -8068,7 +8192,7 @@ class ClassBuilder {
8068
8192
  return field;
8069
8193
  }
8070
8194
  }
8071
- var fieldsByClass = new Map;
8195
+ var FIELD_CLASS = Symbol.for("tutuca.fieldClass");
8072
8196
  var fieldsByTypeName = {
8073
8197
  text: FieldString,
8074
8198
  int: FieldInt,
@@ -8105,7 +8229,7 @@ function classFromData(name, { fields = {}, methods, statics }) {
8105
8229
  else if (Map2.isMap(value) || value?.constructor === Object)
8106
8230
  b.addField(field, Map2(value), FieldMap);
8107
8231
  else {
8108
- const Field2 = fieldsByClass.get(value?.constructor) ?? FieldAny;
8232
+ const Field2 = value?.[FIELD_CLASS] ?? FieldAny;
8109
8233
  b.addField(field, value, Field2);
8110
8234
  }
8111
8235
  }
@@ -8126,7 +8250,7 @@ class Renderer {
8126
8250
  this.cache = new WeakMapDomCache;
8127
8251
  }
8128
8252
  getSeqInfo(seq) {
8129
- return isIndexed(seq) ? imIndexedIter : isKeyed(seq) ? imKeyedIter : seqInfoByClass.get(seq?.constructor) ?? unkIter;
8253
+ return isIndexed(seq) ? imIndexedIter : isKeyed(seq) ? imKeyedIter : seq?.[SEQ_INFO] ?? unkIter;
8130
8254
  }
8131
8255
  renderTag(tag, attrs, childs) {
8132
8256
  return h(tag, attrs, childs);
@@ -8245,7 +8369,7 @@ var imKeyedIter = (seq, visit) => {
8245
8369
  visit(k, v, "sk");
8246
8370
  };
8247
8371
  var unkIter = () => {};
8248
- var seqInfoByClass = new Map;
8372
+ var SEQ_INFO = Symbol.for("tutuca.seqInfo");
8249
8373
 
8250
8374
  // extra/klist.js
8251
8375
  class KList {
@@ -8337,11 +8461,11 @@ class FieldKList extends Field {
8337
8461
  };
8338
8462
  }
8339
8463
  }
8340
- fieldsByClass.set(KList, FieldKList);
8341
- seqInfoByClass.set(KList, (seq, visit) => {
8464
+ KList.prototype[FIELD_CLASS] = FieldKList;
8465
+ KList.prototype[SEQ_INFO] = (seq, visit) => {
8342
8466
  for (const k of seq.order)
8343
8467
  visit(k, seq.items.get(k), "data-sk");
8344
- });
8468
+ };
8345
8469
  // index.js
8346
8470
  var css = String.raw;
8347
8471
  var html = String.raw;
@@ -8606,6 +8730,7 @@ class LintClassCollectorCtx extends ParseCtxClassSetCollector {
8606
8730
  constructor(...args) {
8607
8731
  super(...args);
8608
8732
  this.attrs = [];
8733
+ this.parseIssues = [];
8609
8734
  }
8610
8735
  enterMacro(macroName, macroVars, macroSlots) {
8611
8736
  const { document: document2, Text, Comment, nodes, events, macroNodes } = this;
@@ -8613,12 +8738,16 @@ class LintClassCollectorCtx extends ParseCtxClassSetCollector {
8613
8738
  const v = new LintClassCollectorCtx(document2, Text, Comment, nodes, events, macroNodes, frame, this);
8614
8739
  v.classes = this.classes;
8615
8740
  v.attrs = this.attrs;
8741
+ v.parseIssues = this.parseIssues;
8616
8742
  return v;
8617
8743
  }
8618
8744
  onAttributes(attrs, wrapperAttrs, textChild, isMacroCall = false) {
8619
8745
  super.onAttributes(attrs, wrapperAttrs, textChild, isMacroCall);
8620
8746
  this.attrs.push({ attrs, wrapperAttrs, textChild, isMacroCall });
8621
8747
  }
8748
+ onParseIssue(kind, info) {
8749
+ this.parseIssues.push({ kind, info });
8750
+ }
8622
8751
  }
8623
8752
  export {
8624
8753
  version,
@@ -8627,7 +8756,6 @@ export {
8627
8756
  tutuca,
8628
8757
  setIn$1 as setIn,
8629
8758
  set,
8630
- seqInfoByClass,
8631
8759
  removeIn,
8632
8760
  remove,
8633
8761
  mergeWith$1 as mergeWith,
@@ -8664,7 +8792,6 @@ export {
8664
8792
  getComponentsDocs,
8665
8793
  get,
8666
8794
  fromJS,
8667
- fieldsByClass,
8668
8795
  docComponents,
8669
8796
  css,
8670
8797
  component,
@@ -8672,14 +8799,18 @@ export {
8672
8799
  compileClassesToStyle,
8673
8800
  checkComponent,
8674
8801
  check,
8802
+ UNKNOWN_X_OP,
8803
+ UNKNOWN_X_ATTR,
8675
8804
  UNKNOWN_REQUEST_NAME,
8676
8805
  UNKNOWN_MACRO_ARG,
8677
8806
  UNKNOWN_HANDLER_ARG_NAME,
8678
8807
  UNKNOWN_EVENT_MODIFIER,
8808
+ UNKNOWN_DIRECTIVE,
8679
8809
  UNKNOWN_COMPONENT_NAME,
8680
8810
  Stack2 as Stack,
8681
8811
  Set2 as Set,
8682
8812
  Seq,
8813
+ SEQ_INFO,
8683
8814
  Repeat,
8684
8815
  Record,
8685
8816
  Range,
@@ -8690,6 +8821,7 @@ export {
8690
8821
  OrderedMap,
8691
8822
  OrderedMap as OMap,
8692
8823
  Map2 as Map,
8824
+ MAYBE_DROP_AT_PREFIX,
8693
8825
  List,
8694
8826
  LintParseContext,
8695
8827
  LintContext,
@@ -8703,6 +8835,7 @@ export {
8703
8835
  INPUT_HANDLER_FOR_INPUT_HANDLER_METHOD,
8704
8836
  Map2 as IMap,
8705
8837
  FIELD_VAL_NOT_DEFINED,
8838
+ FIELD_CLASS,
8706
8839
  DUPLICATE_ATTR_DEFINITION,
8707
8840
  Collection,
8708
8841
  COMPUTED_VAL_NOT_DEFINED,