tutuca 0.9.32 → 0.9.34

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.
@@ -734,9 +734,11 @@ class ValParser {
734
734
  const charCode = s.charCodeAt(0);
735
735
  switch (charCode) {
736
736
  case 94: {
737
- const newS = px.frame.macroVars?.[s.slice(1)];
737
+ const name = s.slice(1);
738
+ const newS = px.frame.macroVars?.[name];
738
739
  if (newS !== undefined)
739
740
  return this.parse(newS, px);
741
+ px.onParseIssue("bad-value", { role: "macro-var", name, value: s });
740
742
  return null;
741
743
  }
742
744
  case 39:
@@ -1057,6 +1059,8 @@ class AttrParser {
1057
1059
  this.attrs ??= [];
1058
1060
  this.attrs.push(new Attr(name, val));
1059
1061
  this.hasDynamic ||= !(val instanceof ConstVal);
1062
+ } else {
1063
+ this.px.onParseIssue("bad-value", { role: "attr", attr: name, value });
1060
1064
  }
1061
1065
  }
1062
1066
  pushWrapper(name, raw, val) {
@@ -1072,6 +1076,9 @@ class AttrParser {
1072
1076
  this.attrs ??= [];
1073
1077
  this.attrs.push(this.ifAttr);
1074
1078
  this.hasDynamic = true;
1079
+ } else {
1080
+ const info = { role: "if", attr: directiveName.slice(3), value };
1081
+ this.px.onParseIssue("bad-value", info);
1075
1082
  }
1076
1083
  }
1077
1084
  parseThen(s) {
@@ -1094,36 +1101,44 @@ class AttrParser {
1094
1101
  this.events.add(eventName, handler, modifiers);
1095
1102
  }
1096
1103
  }
1104
+ _parseDirectiveValue(directiveName, s, parserFn) {
1105
+ const val = parserFn.call(vp, s, this.px);
1106
+ if (val === null) {
1107
+ const info = { role: "directive", directive: directiveName, value: s };
1108
+ this.px.onParseIssue("bad-value", info);
1109
+ }
1110
+ return val;
1111
+ }
1097
1112
  parseDirective(s, directiveName) {
1098
1113
  switch (directiveName) {
1099
1114
  case "dangerouslysetinnerhtml":
1100
1115
  this.attrs ??= [];
1101
- this.attrs.push(new RawHtmlAttr(vp.parseText(s, this.px)));
1116
+ this.attrs.push(new RawHtmlAttr(this._parseDirectiveValue(directiveName, s, vp.parseText)));
1102
1117
  this.hasDynamic = true;
1103
1118
  return;
1104
1119
  case "slot":
1105
1120
  this.pushWrapper("slot", s, vp.const(s));
1106
1121
  return;
1107
1122
  case "push-view":
1108
- this.pushWrapper("push-view", s, vp.parseText(s, this.px));
1123
+ this.pushWrapper("push-view", s, this._parseDirectiveValue(directiveName, s, vp.parseText));
1109
1124
  return;
1110
1125
  case "text":
1111
- this.textChild = vp.parseText(s, this.px);
1126
+ this.textChild = this._parseDirectiveValue(directiveName, s, vp.parseText);
1112
1127
  return;
1113
1128
  case "show":
1114
- this.pushWrapper("show", s, vp.parseCondValue(s, this.px));
1129
+ this.pushWrapper("show", s, this._parseDirectiveValue(directiveName, s, vp.parseCondValue));
1115
1130
  return;
1116
1131
  case "hide":
1117
- this.pushWrapper("hide", s, vp.parseCondValue(s, this.px));
1132
+ this.pushWrapper("hide", s, this._parseDirectiveValue(directiveName, s, vp.parseCondValue));
1118
1133
  return;
1119
1134
  case "each":
1120
- this.eachAttr = this.pushWrapper("each", s, vp.parseEach(s, this.px));
1135
+ this.eachAttr = this.pushWrapper("each", s, this._parseDirectiveValue(directiveName, s, vp.parseEach));
1121
1136
  return;
1122
1137
  case "enrich-with":
1123
1138
  if (this.eachAttr !== null) {
1124
- this.eachAttr.enrichWithVal = vp.parseAlter(s, this.px);
1139
+ this.eachAttr.enrichWithVal = this._parseDirectiveValue(directiveName, s, vp.parseAlter);
1125
1140
  } else {
1126
- this.pushWrapper("scope", s, vp.parseAlter(s, this.px));
1141
+ this.pushWrapper("scope", s, this._parseDirectiveValue(directiveName, s, vp.parseAlter));
1127
1142
  }
1128
1143
  return;
1129
1144
  case "when":
@@ -1147,16 +1162,18 @@ class AttrParser {
1147
1162
  this.parseThen(s);
1148
1163
  else if (directiveName.startsWith("else."))
1149
1164
  this.parseElse(s);
1150
- else
1151
- this.px.onParseIssue("unknown-directive", { name: directiveName, value: s });
1165
+ else {
1166
+ const info = { name: directiveName, value: s };
1167
+ this.px.onParseIssue("unknown-directive", info);
1168
+ }
1152
1169
  }
1153
1170
  _parseWhen(s) {
1154
1171
  if (this.eachAttr !== null)
1155
- this.eachAttr.whenVal = vp.parseAlter(s, this.px);
1172
+ this.eachAttr.whenVal = this._parseDirectiveValue("when", s, vp.parseAlter);
1156
1173
  }
1157
1174
  _parseLoopWith(s) {
1158
1175
  if (this.eachAttr !== null)
1159
- this.eachAttr.loopWithVal = vp.parseAlter(s, this.px);
1176
+ this.eachAttr.loopWithVal = this._parseDirectiveValue("loop-with", s, vp.parseAlter);
1160
1177
  }
1161
1178
  parse(attributes, parseAll = false) {
1162
1179
  for (const { name, value } of attributes) {
@@ -1202,13 +1219,22 @@ class EventHandler {
1202
1219
  static parse(s, px) {
1203
1220
  const [handlerName, ...rawArgs] = s.trim().split(/\s+/);
1204
1221
  const handlerVal = vp.parseHandlerName(handlerName, px);
1205
- if (handlerVal === null)
1222
+ if (handlerVal === null) {
1223
+ const info = { role: "handler-name", value: handlerName };
1224
+ px.onParseIssue("bad-value", info);
1206
1225
  return null;
1226
+ }
1207
1227
  const args = new Array(rawArgs.length);
1208
1228
  vp.allowHandlerArg();
1209
1229
  for (let i = 0;i < rawArgs.length; i++) {
1210
1230
  const val = vp.parse(rawArgs[i], px);
1211
- args[i] = val !== null ? val : vp.nullConstVal;
1231
+ if (val !== null) {
1232
+ args[i] = val;
1233
+ } else {
1234
+ const info = { role: "handler-arg", value: rawArgs[i] };
1235
+ px.onParseIssue("bad-value", info);
1236
+ args[i] = vp.nullConstVal;
1237
+ }
1212
1238
  }
1213
1239
  return new EventHandler(handlerVal, args);
1214
1240
  }
@@ -1334,6 +1360,50 @@ function optimizeNode(node) {
1334
1360
  node.optimize();
1335
1361
  return node;
1336
1362
  }
1363
+ function parseXOp(attrs, childs, opIdx, px) {
1364
+ if (attrs.length === 0)
1365
+ return maybeFragment(childs);
1366
+ const { name, value } = attrs[opIdx];
1367
+ const as = attrs.getNamedItem("as")?.value ?? null;
1368
+ let node;
1369
+ switch (name) {
1370
+ case "slot":
1371
+ node = new SlotNode(null, vp.const(value), maybeFragment(childs));
1372
+ break;
1373
+ case "text":
1374
+ node = px.addNodeIf(RenderTextNode, parseXOpVal(name, value, px, vp.parseText));
1375
+ break;
1376
+ case "render":
1377
+ node = px.addNodeIf(RenderNode, parseXOpVal(name, value, px, vp.parseRender), as);
1378
+ break;
1379
+ case "render-it":
1380
+ node = px.addNodeIf(RenderItNode, vp.bindValIt, as);
1381
+ break;
1382
+ case "render-each":
1383
+ node = RenderEachNode.parse(px, vp, value, as, attrs);
1384
+ break;
1385
+ case "show": {
1386
+ const val = parseXOpVal(name, value, px, vp.parseCondValue);
1387
+ node = px.addNodeIf(ShowNode, val, maybeFragment(childs));
1388
+ break;
1389
+ }
1390
+ case "hide": {
1391
+ const val = parseXOpVal(name, value, px, vp.parseCondValue);
1392
+ node = px.addNodeIf(HideNode, val, maybeFragment(childs));
1393
+ break;
1394
+ }
1395
+ default:
1396
+ px.onParseIssue("unknown-x-op", { name, value });
1397
+ return new CommentNode(`Error: InvalidSpecialTagOp ${name}=${value}`);
1398
+ }
1399
+ return processXExtras(node, attrs, name, opIdx + 1, px);
1400
+ }
1401
+ function parseXOpVal(opName, value, px, parserFn) {
1402
+ const val = parserFn.call(vp, value, px);
1403
+ if (val === null)
1404
+ px.onParseIssue("bad-value", { role: "x-op", op: opName, value });
1405
+ return val;
1406
+ }
1337
1407
  function processXExtras(node, attrs, opName, startIdx, px) {
1338
1408
  const consumed = X_OP_CONSUMED[opName];
1339
1409
  const wrappable = X_OP_WRAPPABLE.has(opName);
@@ -1408,6 +1478,7 @@ class ParseContext {
1408
1478
  this.Text = Text ?? globalThis.Text;
1409
1479
  this.Comment = Comment ?? globalThis.Comment;
1410
1480
  this.cacheConstNodes = true;
1481
+ this.currentTag = null;
1411
1482
  }
1412
1483
  isInsideMacro(name) {
1413
1484
  return this.frame.macroName === name || this.parent?.isInsideMacro(name);
@@ -1463,7 +1534,7 @@ class ParseContext {
1463
1534
  getNodeForId(id) {
1464
1535
  return this.nodes[id] ?? null;
1465
1536
  }
1466
- onAttributes(_attrs, _wrapperAttrs, _textChild, _isMacroCall) {}
1537
+ onAttributes(_attrs, _wrapperAttrs, _textChild, _isMacroCall, _tag) {}
1467
1538
  onParseIssue(kind, info) {
1468
1539
  console.warn(`tutuca parse issue [${kind}]`, info);
1469
1540
  }
@@ -1665,62 +1736,39 @@ var init_anode = __esm(() => {
1665
1736
  else if (node instanceof px.Comment)
1666
1737
  return new CommentNode(node.textContent);
1667
1738
  const { childNodes, attributes: attrs, tagName: tag } = node;
1668
- const childs = new Array(childNodes.length);
1669
- for (let i = 0;i < childNodes.length; i++)
1670
- childs[i] = ANode.fromDOM(childNodes[i], px);
1671
- const isPseudoX = attrs[0]?.name === "@x";
1672
- if (tag === "X" || isPseudoX) {
1673
- if (attrs.length === 0)
1674
- return maybeFragment(childs);
1675
- const opIdx = isPseudoX ? 1 : 0;
1676
- const { name, value } = attrs[opIdx];
1677
- const as = attrs.getNamedItem("as")?.value ?? null;
1678
- let node2;
1679
- switch (name) {
1680
- case "slot":
1681
- node2 = new SlotNode(null, vp.const(value), maybeFragment(childs));
1682
- break;
1683
- case "text":
1684
- node2 = px.addNodeIf(RenderTextNode, vp.parseText(value, px));
1685
- break;
1686
- case "render":
1687
- node2 = px.addNodeIf(RenderNode, vp.parseRender(value, px), as);
1688
- break;
1689
- case "render-it":
1690
- node2 = px.addNodeIf(RenderItNode, vp.bindValIt, as);
1691
- break;
1692
- case "render-each":
1693
- node2 = RenderEachNode.parse(px, vp, value, as, attrs);
1694
- break;
1695
- case "show":
1696
- node2 = px.addNodeIf(ShowNode, vp.parseCondValue(value, px), maybeFragment(childs));
1697
- break;
1698
- case "hide":
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}`);
1704
- }
1705
- return processXExtras(node2, attrs, name, (isPseudoX ? 1 : 0) + 1, px);
1706
- } else if (tag.charCodeAt(1) === 58 && tag.charCodeAt(0) === 88) {
1707
- const macroName = tag.slice(2).toLowerCase();
1708
- if (macroName === "slot") {
1709
- const slotName = attrs.getNamedItem("name")?.value ?? "_";
1710
- return px.frame.macroSlots[slotName] ?? maybeFragment(childs);
1739
+ const childs = [];
1740
+ for (let i = 0;i < childNodes.length; i++) {
1741
+ const child = ANode.fromDOM(childNodes[i], px);
1742
+ if (child !== null)
1743
+ childs.push(child);
1744
+ }
1745
+ const prevTag = px.currentTag;
1746
+ px.currentTag = tag;
1747
+ try {
1748
+ const isPseudoX = attrs[0]?.name === "@x";
1749
+ if (tag === "X" || isPseudoX) {
1750
+ return parseXOp(attrs, childs, isPseudoX ? 1 : 0, px);
1751
+ } else if (tag.charCodeAt(1) === 58 && tag.charCodeAt(0) === 88) {
1752
+ const macroName = tag.slice(2).toLowerCase();
1753
+ if (macroName === "slot") {
1754
+ const slotName = attrs.getNamedItem("name")?.value ?? "_";
1755
+ return px.frame.macroSlots[slotName] ?? maybeFragment(childs);
1756
+ }
1757
+ const [nAttrs, wrappers] = Attributes.parse(attrs, px, true);
1758
+ px.onAttributes(nAttrs, wrappers, null, true, tag);
1759
+ return wrap(px.newMacroNode(macroName, nAttrs.toMacroVars(), childs), px, wrappers);
1760
+ } else if (VALID_NODE_RE.test(tag)) {
1761
+ const [nAttrs, wrappers, textChild] = Attributes.parse(attrs, px);
1762
+ px.onAttributes(nAttrs, wrappers, textChild, false, tag);
1763
+ if (textChild)
1764
+ childs.unshift(new RenderTextNode(null, textChild));
1765
+ const domChilds = tag !== "PRE" ? condenseChildsWhites(childs) : childs;
1766
+ return wrap(new DomNode(tag, nAttrs, domChilds), px, wrappers);
1711
1767
  }
1712
- const [nAttrs, wrappers] = Attributes.parse(attrs, px, true);
1713
- px.onAttributes(nAttrs, wrappers, null, true);
1714
- return wrap(px.newMacroNode(macroName, nAttrs.toMacroVars(), childs), px, wrappers);
1715
- } else if (VALID_NODE_RE.test(tag)) {
1716
- const [nAttrs, wrappers, textChild] = Attributes.parse(attrs, px);
1717
- px.onAttributes(nAttrs, wrappers, textChild);
1718
- if (textChild)
1719
- childs.unshift(new RenderTextNode(null, textChild));
1720
- const domChilds = tag !== "PRE" ? condenseChildsWhites(childs) : childs;
1721
- return wrap(new DomNode(tag, nAttrs, domChilds), px, wrappers);
1768
+ return new CommentNode(`Error: InvalidTagName ${tag}`);
1769
+ } finally {
1770
+ px.currentTag = prevTag;
1722
1771
  }
1723
- return new CommentNode(`Error: InvalidTagName ${tag}`);
1724
1772
  }
1725
1773
  };
1726
1774
  MacroNode = class MacroNode extends BaseNode {
@@ -1788,7 +1836,7 @@ var init_anode = __esm(() => {
1788
1836
  return rx.renderEach(stack, this.iterInfo, this.nodeId, this.viewId);
1789
1837
  }
1790
1838
  static parse(px, vp2, s, as, attrs) {
1791
- const node = px.addNodeIf(RenderEachNode, vp2.parseEach(s, px), as);
1839
+ const node = px.addNodeIf(RenderEachNode, parseXOpVal("render-each", s, px, vp2.parseEach), as);
1792
1840
  if (node !== null) {
1793
1841
  const attrParser = getAttrParser(px);
1794
1842
  attrParser.eachAttr = attrParser.pushWrapper("each", s, node.val);
@@ -2171,7 +2219,8 @@ function checkMacroCallArgs(lx, view, Comp) {
2171
2219
  if (!(argName in defaults)) {
2172
2220
  lx.error(UNKNOWN_MACRO_ARG, {
2173
2221
  name: argName,
2174
- macroName: macroNode.name
2222
+ macroName: macroNode.name,
2223
+ tag: `x:${macroNode.name}`
2175
2224
  });
2176
2225
  }
2177
2226
  }
@@ -2225,7 +2274,13 @@ function checkEventModifiers(lx, view) {
2225
2274
  const modWrappers = MOD_WRAPPERS_BY_EVENT[name] ?? NO_WRAPPERS;
2226
2275
  for (const modifier of modifiers) {
2227
2276
  if (modWrappers[modifier] === undefined) {
2228
- lx.error(UNKNOWN_EVENT_MODIFIER, { name, modifier, handler, event });
2277
+ lx.error(UNKNOWN_EVENT_MODIFIER, {
2278
+ name,
2279
+ modifier,
2280
+ handler,
2281
+ event,
2282
+ originAttr: `@on.${name}+${modifiers.join("+")}`
2283
+ });
2229
2284
  }
2230
2285
  }
2231
2286
  }
@@ -2240,10 +2295,16 @@ function checkKnownHandlerNames(lx, view, Comp, referencedAlters, referencedComp
2240
2295
  const { fields } = Class.getMetaClass();
2241
2296
  for (const event of view.ctx.events) {
2242
2297
  for (const handler of event.handlers) {
2243
- const { args } = handler.handlerCall;
2298
+ const { args, handlerVal } = handler.handlerCall;
2299
+ const handlerName = handlerVal?.name;
2300
+ const eventName = handler.name;
2301
+ const errCtx = {
2302
+ eventName,
2303
+ handlerName,
2304
+ originAttr: `@on.${eventName}`
2305
+ };
2244
2306
  for (let i = 0;i < args.length; i++) {
2245
- const arg = args[i];
2246
- checkConsistentAttrVal(lx, arg, fields, proto, computed, scope, alter, referencedAlters, referencedComputed);
2307
+ checkConsistentAttrVal(lx, args[i], fields, proto, computed, scope, alter, referencedAlters, referencedComputed, false, { ...errCtx, argIndex: i });
2247
2308
  }
2248
2309
  }
2249
2310
  }
@@ -2258,19 +2319,25 @@ function checkEventHandlersHaveImpls(lx, Comp, referencedInputs) {
2258
2319
  for (const handler of event.handlers) {
2259
2320
  const { handlerVal } = handler.handlerCall;
2260
2321
  const hvName = handlerVal?.constructor.name;
2322
+ const eventName = handler.name;
2323
+ const originAttr = `@on.${eventName}`;
2261
2324
  if (hvName === "InputHandlerNameVal") {
2262
2325
  referencedInputs?.add(handlerVal.name);
2263
2326
  if (input[handlerVal.name] === undefined) {
2264
2327
  lx.error(INPUT_HANDLER_NOT_IMPLEMENTED, {
2265
2328
  name: handlerVal.name,
2266
2329
  handler,
2267
- event
2330
+ event,
2331
+ eventName,
2332
+ originAttr
2268
2333
  });
2269
2334
  if (proto[handlerVal.name] !== undefined) {
2270
2335
  lx.hint(INPUT_HANDLER_METHOD_FOR_INPUT_HANDLER, {
2271
2336
  name: handlerVal.name,
2272
2337
  handler,
2273
- event
2338
+ event,
2339
+ eventName,
2340
+ originAttr
2274
2341
  });
2275
2342
  }
2276
2343
  }
@@ -2280,13 +2347,17 @@ function checkEventHandlersHaveImpls(lx, Comp, referencedInputs) {
2280
2347
  lx.error(INPUT_HANDLER_METHOD_NOT_IMPLEMENTED, {
2281
2348
  name: handlerVal.name,
2282
2349
  handler,
2283
- event
2350
+ event,
2351
+ eventName,
2352
+ originAttr
2284
2353
  });
2285
2354
  if (input[handlerVal.name] !== undefined) {
2286
2355
  lx.hint(INPUT_HANDLER_FOR_INPUT_HANDLER_METHOD, {
2287
2356
  name: handlerVal.name,
2288
2357
  handler,
2289
- event
2358
+ event,
2359
+ eventName,
2360
+ originAttr
2290
2361
  });
2291
2362
  }
2292
2363
  }
@@ -2296,47 +2367,68 @@ function checkEventHandlersHaveImpls(lx, Comp, referencedInputs) {
2296
2367
  });
2297
2368
  }
2298
2369
  }
2299
- function checkConsistentAttrVal(lx, val, fields, proto, computed, scope, alter, referencedAlters, referencedComputed, skipNameVal = false) {
2370
+ function checkConsistentAttrVal(lx, val, fields, proto, computed, scope, alter, referencedAlters, referencedComputed, skipNameVal = false, errCtx = null) {
2300
2371
  const valName = val?.constructor.name;
2301
2372
  if (valName === "FieldVal" || valName === "RawFieldVal") {
2302
2373
  const { name } = val;
2303
2374
  if (fields[name] === undefined && proto[name] === undefined) {
2304
- lx.error(FIELD_VAL_NOT_DEFINED, { val, name });
2375
+ lx.error(FIELD_VAL_NOT_DEFINED, { ...errCtx, val, name });
2305
2376
  }
2306
2377
  } else if (valName === "ComputedVal") {
2307
2378
  const { name } = val;
2308
2379
  referencedComputed?.add(name);
2309
2380
  if (computed[name] === undefined) {
2310
- lx.error(COMPUTED_VAL_NOT_DEFINED, { val, name });
2381
+ lx.error(COMPUTED_VAL_NOT_DEFINED, { ...errCtx, val, name });
2311
2382
  }
2312
2383
  } else if (valName === "SeqAccessVal") {
2313
- checkConsistentAttrVal(lx, val.seqVal, fields, proto, computed, scope, alter, referencedAlters, referencedComputed, skipNameVal);
2314
- checkConsistentAttrVal(lx, val.keyVal, fields, proto, computed, scope, alter, referencedAlters, referencedComputed, skipNameVal);
2384
+ checkConsistentAttrVal(lx, val.seqVal, fields, proto, computed, scope, alter, referencedAlters, referencedComputed, skipNameVal, errCtx);
2385
+ checkConsistentAttrVal(lx, val.keyVal, fields, proto, computed, scope, alter, referencedAlters, referencedComputed, skipNameVal, errCtx);
2315
2386
  } else if (valName === "RequestVal") {
2316
2387
  if (scope.lookupRequest(val.name) === null) {
2317
- lx.error(UNKNOWN_REQUEST_NAME, { name: val.name });
2388
+ lx.error(UNKNOWN_REQUEST_NAME, { ...errCtx, name: val.name });
2318
2389
  }
2319
2390
  } else if (valName === "TypeVal") {
2320
2391
  if (scope.lookupComponent(val.name) === null) {
2321
- lx.error(UNKNOWN_COMPONENT_NAME, { name: val.name });
2392
+ lx.error(UNKNOWN_COMPONENT_NAME, { ...errCtx, name: val.name });
2322
2393
  }
2323
2394
  } else if (valName === "NameVal") {
2324
2395
  if (!skipNameVal && !isKnownHandlerName(val.name)) {
2325
- lx.error(UNKNOWN_HANDLER_ARG_NAME, { name: val.name });
2396
+ lx.error(UNKNOWN_HANDLER_ARG_NAME, { ...errCtx, name: val.name });
2326
2397
  }
2327
2398
  } else if (valName === "StrTplVal") {
2328
2399
  for (const subVal of val.vals) {
2329
- checkConsistentAttrVal(lx, subVal, fields, proto, computed, scope, alter, referencedAlters, referencedComputed, skipNameVal);
2400
+ checkConsistentAttrVal(lx, subVal, fields, proto, computed, scope, alter, referencedAlters, referencedComputed, skipNameVal, errCtx);
2330
2401
  }
2331
2402
  } else if (valName === "AlterHandlerNameVal") {
2332
2403
  referencedAlters?.add(val.name);
2333
2404
  if (alter[val.name] === undefined) {
2334
- lx.error(ALT_HANDLER_NOT_DEFINED, { name: val.name });
2405
+ lx.error(ALT_HANDLER_NOT_DEFINED, { ...errCtx, name: val.name });
2335
2406
  }
2336
2407
  } else if (valName !== "ConstVal" && valName !== "BindVal" && valName !== "DynVal") {
2337
2408
  console.log(val);
2338
2409
  }
2339
2410
  }
2411
+ function nodeCtxForNode(nodeKind) {
2412
+ return NODE_KIND_TO_CTX[nodeKind] ?? null;
2413
+ }
2414
+ function attrSourceLabel(attr) {
2415
+ const cn = attr.constructor.name;
2416
+ if (cn === "ConstAttr")
2417
+ return "literal";
2418
+ if (cn === "IfAttr")
2419
+ return `@if.${attr.name}`;
2420
+ if (cn === "RawHtmlAttr")
2421
+ return "@dangerouslysetinnerhtml";
2422
+ return `:${attr.name}`;
2423
+ }
2424
+ function attrOriginAttr(attr) {
2425
+ const cn = attr.constructor.name;
2426
+ if (cn === "IfAttr")
2427
+ return `@if.${attr.name}`;
2428
+ if (cn === "RawHtmlAttr")
2429
+ return "@dangerouslysetinnerhtml";
2430
+ return `:${attr.name}`;
2431
+ }
2340
2432
  function checkConsistentAttrs(lx, Comp, referencedAlters, referencedComputed) {
2341
2433
  const { computed, scope, views, alter, Class } = Comp;
2342
2434
  const { prototype: proto } = Class;
@@ -2344,25 +2436,39 @@ function checkConsistentAttrs(lx, Comp, referencedAlters, referencedComputed) {
2344
2436
  for (const viewName in views) {
2345
2437
  lx.push({ viewName }, () => {
2346
2438
  const view = views[viewName];
2347
- for (const attr of view.ctx.attrs) {
2348
- const { attrs, wrapperAttrs, textChild, isMacroCall } = attr;
2439
+ for (const entry of view.ctx.attrs) {
2440
+ const { attrs, wrapperAttrs, textChild, isMacroCall, tag } = entry;
2349
2441
  if (attrs?.constructor.name === "DynAttrs") {
2350
- const seenNames = new Set;
2351
- for (const attr2 of attrs.items) {
2352
- const name = attr2?.name;
2442
+ const sourcesByName = new Map;
2443
+ for (const attr of attrs.items) {
2444
+ const name = attr?.name;
2353
2445
  if (name !== undefined && name !== "data-eid") {
2354
- if (seenNames.has(name)) {
2355
- lx.error(DUPLICATE_ATTR_DEFINITION, { name });
2356
- } else {
2357
- seenNames.add(name);
2358
- }
2446
+ const sources = sourcesByName.get(name);
2447
+ const label = attrSourceLabel(attr);
2448
+ if (sources)
2449
+ sources.push(label);
2450
+ else
2451
+ sourcesByName.set(name, [label]);
2359
2452
  }
2360
- if (attr2?.constructor.name === "IfAttr") {
2361
- for (const subVal of [attr2.condVal, attr2.thenVal, attr2.elseVal]) {
2362
- checkConsistentAttrVal(lx, subVal, fields, proto, computed, scope, alter, referencedAlters, referencedComputed, isMacroCall);
2453
+ if (attr?.constructor.name === "IfAttr") {
2454
+ if (!attr.anyBranchIsSet) {
2455
+ lx.error(IF_NO_BRANCH_SET, { attr: attr.name, tag });
2363
2456
  }
2364
- } else if (attr2?.val !== undefined) {
2365
- checkConsistentAttrVal(lx, attr2.val, fields, proto, computed, scope, alter, referencedAlters, referencedComputed, isMacroCall);
2457
+ const branches = [
2458
+ ["@if", attr.condVal],
2459
+ ["@then", attr.thenVal],
2460
+ ["@else", attr.elseVal]
2461
+ ];
2462
+ for (const [branch, subVal] of branches) {
2463
+ checkConsistentAttrVal(lx, subVal, fields, proto, computed, scope, alter, referencedAlters, referencedComputed, isMacroCall, { tag, originAttr: `@if.${attr.name}`, branch });
2464
+ }
2465
+ } else if (attr?.val !== undefined) {
2466
+ checkConsistentAttrVal(lx, attr.val, fields, proto, computed, scope, alter, referencedAlters, referencedComputed, isMacroCall, { tag, originAttr: attrOriginAttr(attr) });
2467
+ }
2468
+ }
2469
+ for (const [name, sources] of sourcesByName) {
2470
+ if (sources.length > 1) {
2471
+ lx.error(DUPLICATE_ATTR_DEFINITION, { name, sources, tag });
2366
2472
  }
2367
2473
  }
2368
2474
  }
@@ -2370,30 +2476,35 @@ function checkConsistentAttrs(lx, Comp, referencedAlters, referencedComputed) {
2370
2476
  for (const w of wrapperAttrs) {
2371
2477
  if (w.name === "each") {
2372
2478
  if (w.whenVal)
2373
- checkConsistentAttrVal(lx, w.whenVal, fields, proto, computed, scope, alter, referencedAlters, referencedComputed);
2479
+ checkConsistentAttrVal(lx, w.whenVal, fields, proto, computed, scope, alter, referencedAlters, referencedComputed, false, { tag, originAttr: "@when" });
2374
2480
  if (w.enrichWithVal)
2375
- checkConsistentAttrVal(lx, w.enrichWithVal, fields, proto, computed, scope, alter, referencedAlters, referencedComputed);
2481
+ checkConsistentAttrVal(lx, w.enrichWithVal, fields, proto, computed, scope, alter, referencedAlters, referencedComputed, false, { tag, originAttr: "@enrich-with" });
2376
2482
  if (w.loopWithVal)
2377
- checkConsistentAttrVal(lx, w.loopWithVal, fields, proto, computed, scope, alter, referencedAlters, referencedComputed);
2378
- } else if (w.name !== "scope") {
2379
- checkConsistentAttrVal(lx, w.val, fields, proto, computed, scope, alter, referencedAlters, referencedComputed);
2483
+ checkConsistentAttrVal(lx, w.loopWithVal, fields, proto, computed, scope, alter, referencedAlters, referencedComputed, false, { tag, originAttr: "@loop-with" });
2484
+ } else {
2485
+ const originAttr = w.name === "scope" ? "@enrich-with" : `@${w.name}`;
2486
+ checkConsistentAttrVal(lx, w.val, fields, proto, computed, scope, alter, referencedAlters, referencedComputed, false, { tag, originAttr });
2380
2487
  }
2381
2488
  }
2382
2489
  }
2383
2490
  if (textChild) {
2384
- checkConsistentAttrVal(lx, textChild, fields, proto, computed, scope, alter, referencedAlters, referencedComputed);
2491
+ checkConsistentAttrVal(lx, textChild, fields, proto, computed, scope, alter, referencedAlters, referencedComputed, false, { tag, originAttr: "@text" });
2385
2492
  }
2386
2493
  }
2387
2494
  for (const node of view.ctx.nodes) {
2495
+ const nodeKind = node.constructor.name;
2496
+ if (nodeKind === "ScopeNode")
2497
+ continue;
2498
+ const baseCtx = nodeCtxForNode(nodeKind);
2388
2499
  if (node.val) {
2389
- checkConsistentAttrVal(lx, node.val, fields, proto, computed, scope, alter, referencedAlters, referencedComputed);
2500
+ checkConsistentAttrVal(lx, node.val, fields, proto, computed, scope, alter, referencedAlters, referencedComputed, false, baseCtx);
2390
2501
  }
2391
- if (node.constructor.name === "RenderEachNode") {
2502
+ if (nodeKind === "RenderEachNode") {
2392
2503
  const iter = node.iterInfo;
2393
2504
  if (iter.whenVal)
2394
- checkConsistentAttrVal(lx, iter.whenVal, fields, proto, computed, scope, alter, referencedAlters, referencedComputed);
2505
+ checkConsistentAttrVal(lx, iter.whenVal, fields, proto, computed, scope, alter, referencedAlters, referencedComputed, false, { originAttr: "<x render-each when>" });
2395
2506
  if (iter.loopWithVal)
2396
- checkConsistentAttrVal(lx, iter.loopWithVal, fields, proto, computed, scope, alter, referencedAlters, referencedComputed);
2507
+ checkConsistentAttrVal(lx, iter.loopWithVal, fields, proto, computed, scope, alter, referencedAlters, referencedComputed, false, { originAttr: "<x render-each loop-with>" });
2397
2508
  }
2398
2509
  }
2399
2510
  });
@@ -2448,13 +2559,14 @@ class LintContext {
2448
2559
  this.reports.push({ id, info, level, context: { ...this.frame } });
2449
2560
  }
2450
2561
  }
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;
2562
+ 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", IF_NO_BRANCH_SET = "IF_NO_BRANCH_SET", 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", BAD_VALUE = "BAD_VALUE", 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, NODE_KIND_TO_CTX, LintParseContext;
2452
2563
  var init_lint_check = __esm(() => {
2453
2564
  init_anode();
2454
2565
  PARSE_ISSUE_KIND_TO_LINT_ID = {
2455
2566
  "unknown-directive": UNKNOWN_DIRECTIVE,
2456
2567
  "unknown-x-op": UNKNOWN_X_OP,
2457
- "unknown-x-attr": UNKNOWN_X_ATTR
2568
+ "unknown-x-attr": UNKNOWN_X_ATTR,
2569
+ "bad-value": BAD_VALUE
2458
2570
  };
2459
2571
  X_KNOWN_OP_NAMES = new Set([
2460
2572
  "slot",
@@ -2491,17 +2603,27 @@ var init_lint_check = __esm(() => {
2491
2603
  "ctx",
2492
2604
  "dragInfo"
2493
2605
  ]);
2606
+ NODE_KIND_TO_CTX = {
2607
+ RenderTextNode: { originAttr: "<x text>" },
2608
+ RenderNode: { originAttr: "<x render>" },
2609
+ RenderItNode: { originAttr: "<x render-it>" },
2610
+ RenderEachNode: { originAttr: "<x render-each>" },
2611
+ ShowNode: { originAttr: "<x show>" },
2612
+ HideNode: { originAttr: "<x hide>" },
2613
+ PushViewNameNode: { originAttr: "<x push-view>" }
2614
+ };
2494
2615
  LintParseContext = class LintParseContext extends ParseContext {
2495
2616
  constructor(document2, Text, Comment) {
2496
2617
  super(document2, Text, Comment);
2497
2618
  this.attrs = [];
2498
2619
  this.parseIssues = [];
2499
2620
  }
2500
- onAttributes(attrs, wrapperAttrs, textChild, isMacroCall = false) {
2501
- this.attrs.push({ attrs, wrapperAttrs, textChild, isMacroCall });
2621
+ onAttributes(attrs, wrapperAttrs, textChild, isMacroCall = false, tag = null) {
2622
+ this.attrs.push({ attrs, wrapperAttrs, textChild, isMacroCall, tag });
2502
2623
  }
2503
2624
  onParseIssue(kind, info) {
2504
- this.parseIssues.push({ kind, info });
2625
+ const tag = this.currentTag;
2626
+ this.parseIssues.push({ kind, info: tag && info.tag === undefined ? { ...info, tag } : info });
2505
2627
  }
2506
2628
  };
2507
2629
  });
@@ -8467,6 +8589,121 @@ function makeFormatter(name, table) {
8467
8589
  };
8468
8590
  }
8469
8591
 
8592
+ // tools/format/lint.js
8593
+ function badValueMessage(info) {
8594
+ const v = JSON.stringify(info.value);
8595
+ switch (info.role) {
8596
+ case "attr":
8597
+ return `Cannot parse value ${v} for attribute ':${info.attr}'`;
8598
+ case "directive":
8599
+ return `Cannot parse value ${v} for directive '@${info.directive}'`;
8600
+ case "if":
8601
+ return `Cannot parse condition ${v} for '@if.${info.attr}'`;
8602
+ case "x-op":
8603
+ return `Cannot parse value ${v} for <x ${info.op}>`;
8604
+ case "handler-name":
8605
+ return `Cannot parse handler name ${v}`;
8606
+ case "handler-arg":
8607
+ return `Cannot parse handler argument ${v}`;
8608
+ case "macro-var":
8609
+ return `Macro variable '^${info.name}' is not defined`;
8610
+ default:
8611
+ return `Cannot parse value ${v}`;
8612
+ }
8613
+ }
8614
+ function tagDisplay(tag) {
8615
+ return tag ? String(tag).toLowerCase() : null;
8616
+ }
8617
+ function fmtTagSuffix(info) {
8618
+ const t = tagDisplay(info?.tag);
8619
+ return t && t !== "x" ? ` on <${t}>` : "";
8620
+ }
8621
+ function fmtOriginSuffix(info) {
8622
+ if (!info)
8623
+ return "";
8624
+ const parts = [];
8625
+ if (info.originAttr) {
8626
+ const branch = info.branch ? `[${info.branch}]` : "";
8627
+ parts.push(`in ${info.originAttr}${branch}`);
8628
+ }
8629
+ if (info.handlerName) {
8630
+ parts.push(`handler '${info.handlerName}'${info.argIndex !== undefined ? ` arg ${info.argIndex}` : ""}`);
8631
+ }
8632
+ const t = tagDisplay(info.tag);
8633
+ if (t && t !== "x")
8634
+ parts.push(`on <${t}>`);
8635
+ return parts.length ? ` (${parts.join(", ")})` : "";
8636
+ }
8637
+ function fmtEventSuffix(info) {
8638
+ if (info?.originAttr)
8639
+ return ` in ${info.originAttr}`;
8640
+ if (info?.eventName)
8641
+ return ` in @on.${info.eventName}`;
8642
+ return "";
8643
+ }
8644
+ function lintIdToMessage(id, info) {
8645
+ switch (id) {
8646
+ case "RENDER_IT_OUTSIDE_OF_LOOP":
8647
+ return "render-it used outside of a loop";
8648
+ case "UNKNOWN_EVENT_MODIFIER": {
8649
+ const mods = info.handler?.modifiers ?? [info.modifier];
8650
+ const written = `@on.${info.name}+${mods.join("+")}`;
8651
+ return `Unknown modifier '+${info.modifier}' in '${written}'`;
8652
+ }
8653
+ case "UNKNOWN_HANDLER_ARG_NAME":
8654
+ return `Unknown handler argument '${info.name}'${fmtOriginSuffix(info)}`;
8655
+ case "INPUT_HANDLER_NOT_IMPLEMENTED":
8656
+ return `Input handler '${info.name}' is not implemented${fmtEventSuffix(info)}`;
8657
+ case "INPUT_HANDLER_NOT_REFERENCED":
8658
+ return `Input handler '${info.name}' is defined but not referenced`;
8659
+ case "INPUT_HANDLER_METHOD_NOT_IMPLEMENTED":
8660
+ return `Method '.${info.name}' is not implemented${fmtEventSuffix(info)}`;
8661
+ case "INPUT_HANDLER_FOR_INPUT_HANDLER_METHOD":
8662
+ return `'${info.name}' exists as input handler — use without '.' prefix${fmtEventSuffix(info)}`;
8663
+ case "INPUT_HANDLER_METHOD_FOR_INPUT_HANDLER":
8664
+ return `'${info.name}' exists as method — use with '.' prefix${fmtEventSuffix(info)}`;
8665
+ case "FIELD_VAL_NOT_DEFINED":
8666
+ return `Field '.${info.name}' is not defined${fmtOriginSuffix(info)}`;
8667
+ case "COMPUTED_VAL_NOT_DEFINED":
8668
+ return `Computed property '$${info.name}' is not defined${fmtOriginSuffix(info)}`;
8669
+ case "COMPUTED_NOT_REFERENCED":
8670
+ return `Computed property '$${info.name}' is defined but not referenced`;
8671
+ case "DUPLICATE_ATTR_DEFINITION": {
8672
+ const sources = info.sources?.length ? ` (${info.sources.join(", ")})` : "";
8673
+ const tag = info.tag ? ` on <${String(info.tag).toLowerCase()}>` : "";
8674
+ return `Attribute '${info.name}' is set ${info.sources?.length ?? "multiple"} times${sources}${tag}`;
8675
+ }
8676
+ case "IF_NO_BRANCH_SET":
8677
+ return `'@if.${info.attr}' has no '@then' or '@else' branch — at least one must be set${fmtTagSuffix(info)}`;
8678
+ case "UNKNOWN_REQUEST_NAME":
8679
+ return `Unknown request '!${info.name}'${fmtOriginSuffix(info)}`;
8680
+ case "UNKNOWN_COMPONENT_NAME":
8681
+ return `Unknown component '${info.name}'${fmtOriginSuffix(info)}`;
8682
+ case "ALT_HANDLER_NOT_DEFINED":
8683
+ return `Alter handler '${info.name}' is not defined${fmtOriginSuffix(info)}`;
8684
+ case "ALT_HANDLER_NOT_REFERENCED":
8685
+ return `Alter handler '${info.name}' is defined but not referenced`;
8686
+ case "UNKNOWN_MACRO_ARG":
8687
+ return `Argument '${info.name}' is not declared in macro '${info.macroName}'`;
8688
+ case "UNKNOWN_DIRECTIVE":
8689
+ return `Unknown directive '@${info.name}=${JSON.stringify(info.value)}'${fmtTagSuffix(info)}`;
8690
+ case "UNKNOWN_X_OP":
8691
+ return `Unknown <x> op '${info.name}=${JSON.stringify(info.value)}'${fmtTagSuffix(info)}`;
8692
+ case "UNKNOWN_X_ATTR":
8693
+ return `Unknown attribute '${info.name}=${JSON.stringify(info.value)}' on <x ${info.op}>${fmtTagSuffix(info)}`;
8694
+ case "MAYBE_DROP_AT_PREFIX": {
8695
+ const written = info.value !== undefined ? `${info.name}=${JSON.stringify(info.value)}` : info.name;
8696
+ return `Did you mean '${info.suggestion}'? Drop the '@' from '${written}' on <x>.`;
8697
+ }
8698
+ case "BAD_VALUE":
8699
+ return `${badValueMessage(info)}${fmtTagSuffix(info)}`;
8700
+ case "LINT_ERROR":
8701
+ return info.message;
8702
+ default:
8703
+ return id;
8704
+ }
8705
+ }
8706
+
8470
8707
  // tools/format/cli.js
8471
8708
  function fmtModuleInfo(info) {
8472
8709
  const lines = [];
@@ -8536,15 +8773,6 @@ function fmtComponentDocs(docs) {
8536
8773
  return lines.join(`
8537
8774
  `);
8538
8775
  }
8539
- function fmtFindingInfo(info) {
8540
- const keys = ["name", "modifier", "id"];
8541
- const parts = [];
8542
- for (const k of keys) {
8543
- if (info?.[k] !== undefined)
8544
- parts.push(`${k}=${info[k]}`);
8545
- }
8546
- return parts.join(" ");
8547
- }
8548
8776
  function fmtLintReport(rep) {
8549
8777
  if (rep.components.length === 0)
8550
8778
  return "(no components)";
@@ -8557,9 +8785,8 @@ function fmtLintReport(rep) {
8557
8785
  lines.push(`${c.componentName}:`);
8558
8786
  for (const f of c.findings) {
8559
8787
  const tag = f.level.toUpperCase();
8560
- const view = f.context?.viewName ? ` view=${f.context.viewName}` : "";
8561
- const extra = fmtFindingInfo(f.info);
8562
- lines.push(` [${tag}] ${f.id}${view}${extra ? ` (${extra})` : ""}`);
8788
+ const view = f.context?.viewName ? ` [view=${f.context.viewName}]` : "";
8789
+ lines.push(` [${tag}]${view} ${lintIdToMessage(f.id, f.info)}`);
8563
8790
  }
8564
8791
  }
8565
8792
  lines.push("");
@@ -8706,8 +8933,8 @@ function fmtLintReport2(rep) {
8706
8933
  continue;
8707
8934
  }
8708
8935
  for (const f of c.findings) {
8709
- const view = f.context?.viewName ? ` view: \`${f.context.viewName}\`` : "";
8710
- lines.push(`- **${f.level.toUpperCase()}** \`${f.id}\`${view}`);
8936
+ const view = f.context?.viewName ? ` _(view: \`${f.context.viewName}\`)_` : "";
8937
+ lines.push(`- **${f.level.toUpperCase()}** ${lintIdToMessage(f.id, f.info)}${view}`);
8711
8938
  }
8712
8939
  lines.push("");
8713
8940
  }