marko 6.3.2 → 6.3.4

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.
@@ -104,7 +104,6 @@ let AccessorPrefix$1 = /* @__PURE__ */ function(AccessorPrefix) {
104
104
  AccessorPrefix["ControlledValue"] = "ControlledValue:";
105
105
  AccessorPrefix["DynamicHTMLLastChild"] = "DynamicHTMLLastChild:";
106
106
  AccessorPrefix["EventAttributes"] = "EventAttributes:";
107
- AccessorPrefix["Getter"] = "Getter:";
108
107
  AccessorPrefix["KeyedScopes"] = "KeyedScopes:";
109
108
  AccessorPrefix["Lifecycle"] = "Lifecycle:";
110
109
  AccessorPrefix["Promise"] = "Promise:";
@@ -302,6 +301,7 @@ const decodeAccessor = (num) => (num + (num < 26 ? 10 : num < 962 ? 334 : 11998)
302
301
  const K_SCOPE_ID = Symbol("Scope ID");
303
302
  const kTouchedIterator = Symbol.for("marko.touchedIterator");
304
303
  const { hasOwnProperty: hasOwnProperty$1 } = {};
304
+ Array.prototype;
305
305
  const Generator = (function* () {})().constructor;
306
306
  const AsyncGenerator = (async function* () {})().constructor;
307
307
  patchIteratorNext(Generator.prototype);
@@ -856,7 +856,6 @@ let AccessorPrefix = /* @__PURE__ */ function(AccessorPrefix) {
856
856
  AccessorPrefix["ControlledValue"] = "G";
857
857
  AccessorPrefix["DynamicHTMLLastChild"] = "H";
858
858
  AccessorPrefix["EventAttributes"] = "I";
859
- AccessorPrefix["Getter"] = "J";
860
859
  AccessorPrefix["KeyedScopes"] = "O";
861
860
  AccessorPrefix["Lifecycle"] = "K";
862
861
  AccessorPrefix["Promise"] = "L";
@@ -1249,6 +1248,7 @@ function startSection(path) {
1249
1248
  upstreamExpression: void 0,
1250
1249
  downstreamBinding: void 0,
1251
1250
  hasAbortSignal: false,
1251
+ abortSignalExprs: 0,
1252
1252
  readsOwner: false,
1253
1253
  isBranch: false
1254
1254
  };
@@ -1539,6 +1539,21 @@ function isStaticRoot(path) {
1539
1539
  }
1540
1540
  }
1541
1541
  //#endregion
1542
+ //#region src/translator/util/analyze-errors.ts
1543
+ const [getHasAnalyzeErrors, setHasAnalyzeErrors] = createProgramState(() => false);
1544
+ function reportAnalyzeError(path, error) {
1545
+ if (!(error instanceof Error)) throw error;
1546
+ const { label = error.message, loc } = error;
1547
+ setHasAnalyzeErrors(true);
1548
+ (0, _marko_compiler_babel_utils.diagnosticError)(path, {
1549
+ label,
1550
+ loc: loc ?? path.node.loc ?? void 0
1551
+ });
1552
+ }
1553
+ function hasAnalyzeErrors() {
1554
+ return getHasAnalyzeErrors();
1555
+ }
1556
+ //#endregion
1542
1557
  //#region src/translator/util/asset-imports.ts
1543
1558
  function addAssetImport(file, request) {
1544
1559
  (file.metadata.marko.assetImports ??= /* @__PURE__ */ new Set()).add(request);
@@ -2062,6 +2077,7 @@ const pureDOMFunctions = /* @__PURE__ */ new Set([
2062
2077
  "_load_race_trigger"
2063
2078
  ]);
2064
2079
  function importRuntime(name) {
2080
+ if (!isTranslate()) throw new Error(`\`importRuntime(${JSON.stringify(name)})\` may only be called during the translate stage.`);
2065
2081
  const { output } = getMarkoOpts();
2066
2082
  return (0, _marko_compiler_babel_utils.importNamed)((0, _marko_compiler_babel_utils.getFile)(), getRuntimePath(output), name);
2067
2083
  }
@@ -3676,7 +3692,28 @@ function getRegisteredFnExpression(node) {
3676
3692
  }
3677
3693
  //#endregion
3678
3694
  //#region src/translator/util/body-to-text-literal.ts
3695
+ const kRawText = Symbol("raw text placeholder");
3679
3696
  function bodyToTextLiteral(body) {
3697
+ return buildTextLiteral(body, toText, false);
3698
+ }
3699
+ function bodyToRawTextLiteral(body) {
3700
+ return buildTextLiteral(body, (value) => value, true);
3701
+ }
3702
+ function injectTextCoercion(expr) {
3703
+ switch (expr.type) {
3704
+ case "ConditionalExpression":
3705
+ injectTextCoercion(expr.consequent);
3706
+ injectTextCoercion(expr.alternate);
3707
+ break;
3708
+ case "TemplateLiteral":
3709
+ expr.expressions = expr.expressions.map((child) => toText(child));
3710
+ break;
3711
+ }
3712
+ }
3713
+ function toText(value) {
3714
+ return callRuntime("_to_text", value);
3715
+ }
3716
+ function buildTextLiteral(body, coerce, bareSingle) {
3680
3717
  const templateQuasis = [];
3681
3718
  const templateExpressions = [];
3682
3719
  let currentQuasi = "";
@@ -3685,10 +3722,11 @@ function bodyToTextLiteral(body) {
3685
3722
  else if (_marko_compiler.types.isMarkoPlaceholder(child)) {
3686
3723
  placeholderExtra ||= child.value.extra;
3687
3724
  templateQuasis.push(templateElement(currentQuasi, false));
3688
- templateExpressions.push(callRuntime("_to_text", child.value));
3725
+ templateExpressions.push(coerce(child.value));
3689
3726
  currentQuasi = "";
3690
3727
  }
3691
3728
  if (templateExpressions.length) {
3729
+ if (bareSingle && templateExpressions.length === 1 && !currentQuasi && !templateQuasis[0].value.cooked) return templateExpressions[0];
3692
3730
  templateQuasis.push(templateElement(currentQuasi, true));
3693
3731
  const literal = _marko_compiler.types.templateLiteral(templateQuasis, templateExpressions);
3694
3732
  literal.extra = placeholderExtra;
@@ -3766,9 +3804,9 @@ var for_default = {
3766
3804
  if (!isAttrTag) allowAttrs.push("by");
3767
3805
  (0, _marko_compiler_babel_utils.assertAllowedAttributes)(tag, allowAttrs);
3768
3806
  if (isAttrTag) return;
3769
- if (forType !== "of") {
3770
- if (getKnownAttrValues(tag.node).by?.type === "StringLiteral") throw (tag.get("attributes").find((attr) => attr.isMarkoAttribute() && attr.node.name === "by") || tag).buildCodeFrameError(`The [\`<for>\` tag](https://markojs.com/docs/reference/core-tag#for) only supports a string \`by\` key with \`of\`; use a \`by=(${forType === "in" ? "key, value" : "index"}) => ...\` function for \`<for ${forType}>\`.`);
3771
- }
3807
+ const byAttr = getKnownAttrValues(tag.node).by;
3808
+ if (forType !== "of" && byAttr?.type === "StringLiteral") throw tag.hub.buildError(byAttr, `The [\`<for>\` tag](https://markojs.com/docs/reference/core-tag#for) only supports a string \`by\` key with \`of\`; use a \`by=(${forType === "in" ? "key, value" : "index"}) => ...\` function for \`<for ${forType}>\`.`);
3809
+ if (byAttr?.type === "Identifier" && !tag.scope.getBinding(byAttr.name) && tag.node.body.params.some((param) => Object.hasOwn(_marko_compiler.types.getBindingIdentifiers(param), byAttr.name))) throw tag.hub.buildError(byAttr, `The \`by=\` attribute is evaluated before the loop runs, so \`${byAttr.name}\` is not in scope. Key with a property name string (\`by="id"\`) or a function (\`by=(${byAttr.name}) => key\`).`);
3772
3810
  const bodySection = startSection(tagBody);
3773
3811
  if (!bodySection) {
3774
3812
  dropNodes(getAllTagReferenceNodes(tag.node));
@@ -4773,6 +4811,7 @@ function assertNativeAttrValueType(tag, attr) {
4773
4811
  if (_marko_compiler.types.isObjectExpression(attr.value)) throw tag.hub.buildError(attr, `The \`${name}\` attribute cannot be a plain object (it would render as \`[object Object]\`).`, Error);
4774
4812
  }
4775
4813
  function assertNativeHandlerAttr(tag, attr) {
4814
+ if (_marko_compiler.types.isObjectExpression(attr.value)) throw tag.hub.buildError(attr.value, `The \`${attr.name}\` ${isEventHandler(attr.name) ? "event handler" : "change handler"} on a [native tag](https://markojs.com/docs/reference/native-tag) must be a function. Attribute values in Marko are plain JavaScript expressions, not JSX; remove the wrapping \`{ }\` (e.g. \`${attr.name}=myHandler\` or \`${attr.name}() { ... }\`).`, Error);
4776
4815
  if ((0, _marko_compiler_babel_utils.computeNode)(attr.value)?.value) throw tag.hub.buildError(attr.value, `The \`${attr.name}\` ${isEventHandler(attr.name) ? "event handler" : "change handler"} on a [native tag](https://markojs.com/docs/reference/native-tag) must be a function or a falsey value (\`null\`, \`undefined\`, \`false\`, \`0\`, …).`, Error);
4777
4816
  }
4778
4817
  const lowercaseEventHandlerReg = /^on[a-z]/;
@@ -5188,17 +5227,22 @@ function flattenTextOnlyConditional(rootTag) {
5188
5227
  } while (cur.node && (isCoreTagName(cur, "else-if") || isCoreTagName(cur, "else")));
5189
5228
  for (const branchTag of branches) assertValidCondition(branchTag);
5190
5229
  let expr = _marko_compiler.types.stringLiteral("");
5230
+ let rawText = false;
5191
5231
  for (let i = branches.length; i--;) {
5192
5232
  const branchTag = branches[i];
5193
- const text = bodyToTextLiteral(branchTag.node.body);
5233
+ const text = bodyToRawTextLiteral(branchTag.node.body);
5234
+ rawText ||= _marko_compiler.types.isTemplateLiteral(text);
5194
5235
  expr = isCoreTagName(branchTag, "else") ? text : _marko_compiler.types.conditionalExpression(branchTag.node.attributes[0].value, text, expr);
5195
5236
  }
5196
5237
  for (let i = branches.length; i-- > 1;) branches[i].remove();
5197
- rootTag.replaceWith(_marko_compiler.types.markoPlaceholder(expr, true));
5238
+ const placeholder = _marko_compiler.types.markoPlaceholder(expr, true);
5239
+ if (rawText) (placeholder.extra ??= {})[kRawText] = true;
5240
+ rootTag.replaceWith(placeholder);
5198
5241
  }
5199
5242
  function assertValidCondition(tag) {
5243
+ const conditionTagName = getTagName(tag);
5200
5244
  (0, _marko_compiler_babel_utils.assertNoVar)(tag);
5201
- (0, _marko_compiler_babel_utils.assertNoArgs)(tag);
5245
+ (0, _marko_compiler_babel_utils.assertNoArgs)(tag, conditionTagName === "else" ? "Write the condition as an attribute instead: `<else if=condition>`." : `Write the condition as a value attribute instead: \`<${conditionTagName}=condition>\`.`);
5202
5246
  (0, _marko_compiler_babel_utils.assertNoParams)(tag);
5203
5247
  assertHasBody$1(tag);
5204
5248
  assertNoSpreadAttrs(tag);
@@ -5550,6 +5594,7 @@ var program_default = {
5550
5594
  }
5551
5595
  },
5552
5596
  exit(program) {
5597
+ if (hasAnalyzeErrors()) return;
5553
5598
  finalizeReferences();
5554
5599
  const programExtra = program.node.extra;
5555
5600
  const paramsBinding = programExtra.binding;
@@ -5806,7 +5851,7 @@ function knownTagTranslateDOM(tag, propTree, getBindingIdentifier, callSetup) {
5806
5851
  if (node.var) {
5807
5852
  const varBinding = node.var.extra.binding;
5808
5853
  const source = initValue(varBinding);
5809
- source.register = true;
5854
+ source.register = !!getSerializeReason(tagSection, childScopeBinding) || !signalHasStatements(source);
5810
5855
  source.buildAssignment = (valueSection, value) => {
5811
5856
  const changeArgs = [createScopeReadExpression(childScopeBinding, valueSection), value];
5812
5857
  if (!isOptimize()) changeArgs.push(_marko_compiler.types.stringLiteral(varBinding.name));
@@ -7011,7 +7056,7 @@ function addReadToExpression(root, binding, getter) {
7011
7056
  const fnRoot = getFnRoot(root);
7012
7057
  const exprRoot = getExprRoot(fnRoot || root);
7013
7058
  const section = getOrCreateSection(exprRoot);
7014
- const exprExtra = exprRoot.node.extra ??= { section };
7059
+ const exprExtra = getCanonicalExtra(exprRoot.node.extra ??= { section });
7015
7060
  const read = addRead(exprExtra, node.extra ??= {}, binding, section, getter);
7016
7061
  const { parent } = root;
7017
7062
  if (parent.type === "BinaryExpression" && (parent.operator === "===" || parent.operator === "!==")) read.comparedTo = parent.left === node ? parent.right : parent.left;
@@ -7488,9 +7533,9 @@ const kDOMBinding$2 = Symbol("await tag dom binding");
7488
7533
  var await_default = {
7489
7534
  analyze(tag) {
7490
7535
  (0, _marko_compiler_babel_utils.assertNoVar)(tag);
7491
- (0, _marko_compiler_babel_utils.assertNoArgs)(tag);
7536
+ (0, _marko_compiler_babel_utils.assertNoArgs)(tag, "Write the promise as a value attribute and receive the result as a tag parameter instead: `<await|result|=promise>`.");
7492
7537
  assertNoSpreadAttrs(tag);
7493
- (0, _marko_compiler_babel_utils.assertNoAttributeTags)(tag);
7538
+ (0, _marko_compiler_babel_utils.assertNoAttributeTags)(tag, "For pending and error UI, wrap the `<await>` in a [`<try>` tag](https://markojs.com/docs/reference/core-tag#try) with `<@placeholder>` and `<@catch|err|>` attribute tags.");
7494
7539
  const { node } = tag;
7495
7540
  const tagBody = tag.get("body");
7496
7541
  const section = getOrCreateSection(tag);
@@ -7599,7 +7644,10 @@ var const_default = {
7599
7644
  assertNoBodyContent(tag);
7600
7645
  const { node } = tag;
7601
7646
  const [valueAttr] = node.attributes;
7602
- if (!node.var) throw tag.get("name").buildCodeFrameError("The [`<const>` tag](https://markojs.com/docs/reference/core-tag#const) requires a [tag variable](https://markojs.com/docs/reference/language#tag-variables).");
7647
+ if (!node.var) {
7648
+ const looksLikeDeclaration = !node.attributes.some((attr) => _marko_compiler.types.isMarkoAttribute(attr) && (attr.default || attr.name === "value")) && node.attributes.length === 1 && _marko_compiler.types.isMarkoAttribute(node.attributes[0]) && /^[A-Za-z_$][\w$]*$/.test(node.attributes[0].name);
7649
+ throw tag.get("name").buildCodeFrameError(`The [\`<const>\` tag](https://markojs.com/docs/reference/core-tag#const) requires a [tag variable](https://markojs.com/docs/reference/language#tag-variables)${looksLikeDeclaration ? `; the variable goes after a slash: \`<const/${node.attributes[0].name}=...>\`. For a one time module level value, prefix a plain JavaScript statement with \`static\`.` : ", e.g. `<const/doubled=count * 2>`."}`);
7650
+ }
7603
7651
  if (!valueAttr) throw tag.get("name").buildCodeFrameError("The [`<const>` tag](https://markojs.com/docs/reference/core-tag#const) requires a [`value=` attribute](https://markojs.com/docs/reference/language#shorthand-value).");
7604
7652
  if (node.attributes.length > 1 || !_marko_compiler.types.isMarkoAttribute(valueAttr) || !valueAttr.default && valueAttr.name !== "value") throw tag.get("name").buildCodeFrameError("The [`<const>` tag](https://markojs.com/docs/reference/core-tag#const) only supports the [`value=` attribute](https://markojs.com/docs/reference/language#shorthand-value).");
7605
7653
  const valueExtra = evaluate(valueAttr.value);
@@ -7964,7 +8012,8 @@ var let_default = {
7964
8012
  } else {
7965
8013
  const start = attr.loc?.start;
7966
8014
  const end = attr.loc?.end;
7967
- const msg = "The [`<let>` tag](https://markojs.com/docs/reference/core-tag#let) only supports the [`value=` attribute](https://markojs.com/docs/reference/language#shorthand-value) and its change handler.";
8015
+ let msg = "The [`<let>` tag](https://markojs.com/docs/reference/core-tag#let) only supports the [`value=` attribute](https://markojs.com/docs/reference/language#shorthand-value) and its change handler.";
8016
+ if (!tagVar && /^[A-Za-z_$][\w$]*$/.test(attr.name)) msg += ` To declare reactive state, the variable goes after a slash: \`<let/${attr.name}=...>\`. For a one time module level value, prefix a plain JavaScript statement with \`static\`.`;
7968
8017
  if (start == null || end == null) throw tag.get("name").buildCodeFrameError(msg);
7969
8018
  else throw tag.hub.buildError({ loc: {
7970
8019
  start,
@@ -7975,7 +8024,7 @@ var let_default = {
7975
8024
  (0, _marko_compiler_babel_utils.assertNoParams)(tag);
7976
8025
  assertNoBodyContent(tag);
7977
8026
  assertNoSpreadAttrs(tag);
7978
- if (!tagVar) throw tag.get("name").buildCodeFrameError("The [`<let>` tag](https://markojs.com/docs/reference/core-tag#let) requires a [tag variable](https://markojs.com/docs/reference/language#tag-variables).");
8027
+ if (!tagVar) throw tag.get("name").buildCodeFrameError("The [`<let>` tag](https://markojs.com/docs/reference/core-tag#let) requires a [tag variable](https://markojs.com/docs/reference/language#tag-variables), e.g. `<let/count=0>`.");
7979
8028
  if (!_marko_compiler.types.isIdentifier(tagVar)) throw tag.get("var").buildCodeFrameError("The [`<let>` tag](https://markojs.com/docs/reference/core-tag#let) variable cannot be destructured.");
7980
8029
  if (valueChangeAttr && (0, _marko_compiler_babel_utils.computeNode)(valueChangeAttr.value)?.value) throw tag.get("attributes").find((attr) => attr.node === valueChangeAttr).get("value").buildCodeFrameError("The [`<let>` tag](https://markojs.com/docs/reference/core-tag#let) [`valueChange=` attribute](https://markojs.com/docs/reference/core-tag#controllable-let) must be a function.");
7981
8030
  const tagSection = getOrCreateSection(tag);
@@ -8339,7 +8388,7 @@ function isLiteral(expr) {
8339
8388
  }
8340
8389
  function assertValidShow(tag) {
8341
8390
  (0, _marko_compiler_babel_utils.assertNoVar)(tag);
8342
- (0, _marko_compiler_babel_utils.assertNoArgs)(tag);
8391
+ (0, _marko_compiler_babel_utils.assertNoArgs)(tag, "Write the condition as a value attribute instead: `<show=condition>`.");
8343
8392
  (0, _marko_compiler_babel_utils.assertNoParams)(tag);
8344
8393
  assertNoSpreadAttrs(tag);
8345
8394
  assertHasBody(tag);
@@ -8968,6 +9017,7 @@ var placeholder_default = {
8968
9017
  if (isNonHTMLText(placeholder)) return;
8969
9018
  const { node } = placeholder;
8970
9019
  const { value } = node;
9020
+ if (node.extra?.[kRawText]) injectTextCoercion(value);
8971
9021
  const valueExtra = evaluate(value);
8972
9022
  const { confident, computed } = valueExtra;
8973
9023
  if (confident && isVoid(computed)) {
@@ -9080,7 +9130,7 @@ function getInlinedBodyTag(parent) {
9080
9130
  }
9081
9131
  //#endregion
9082
9132
  //#region src/translator/visitors/referenced-identifier.ts
9083
- const abortIdsByExpressionForSection = /* @__PURE__ */ new WeakMap();
9133
+ const [getAbortResetEmitted] = createSectionState("abortResetEmitted", () => /* @__PURE__ */ new Set());
9084
9134
  var referenced_identifier_default = {
9085
9135
  migrate(identifier) {
9086
9136
  const { name } = identifier.node;
@@ -9100,6 +9150,9 @@ var referenced_identifier_default = {
9100
9150
  const section = getOrCreateSection(identifier);
9101
9151
  section.hasAbortSignal = true;
9102
9152
  setReferencesScope(identifier);
9153
+ const exprRoot = getExprRoot(identifier);
9154
+ const rootExtra = exprRoot.node.extra ??= { section };
9155
+ if (rootExtra.abortId === void 0) rootExtra.abortId = section.abortSignalExprs++;
9103
9156
  }
9104
9157
  },
9105
9158
  translate(identifier) {
@@ -9114,16 +9167,10 @@ var referenced_identifier_default = {
9114
9167
  else {
9115
9168
  const section = getSection(identifier);
9116
9169
  const exprRoot = getExprRoot(identifier);
9117
- let abortIdsByExpression = abortIdsByExpressionForSection.get(section);
9118
- let exprId;
9119
- if (abortIdsByExpression) exprId = abortIdsByExpression.get(exprRoot);
9120
- else {
9121
- abortIdsByExpression = /* @__PURE__ */ new Map();
9122
- abortIdsByExpressionForSection.set(section, abortIdsByExpression);
9123
- }
9124
- if (exprId === void 0) {
9125
- exprId = abortIdsByExpression.size;
9126
- abortIdsByExpression.set(exprRoot, exprId);
9170
+ const exprId = exprRoot.node.extra.abortId;
9171
+ const resetEmitted = getAbortResetEmitted(section);
9172
+ if (!resetEmitted.has(exprRoot)) {
9173
+ resetEmitted.add(exprRoot);
9127
9174
  addStatement("render", section, exprRoot.node.extra?.referencedBindings, _marko_compiler.types.expressionStatement(_marko_compiler.types.callExpression(importRuntime("$signalReset"), [scopeIdentifier, _marko_compiler.types.numericLiteral(exprId)])), false);
9128
9175
  }
9129
9176
  identifier.replaceWith(_marko_compiler.types.callExpression(importRuntime("$signal"), [scopeIdentifier, _marko_compiler.types.numericLiteral(exprId)]));
@@ -9135,7 +9182,11 @@ var referenced_identifier_default = {
9135
9182
  //#region src/translator/visitors/scriptlet.ts
9136
9183
  var scriptlet_default = {
9137
9184
  analyze(scriptlet) {
9138
- if (!scriptlet.node.static) throw scriptlet.buildCodeFrameError("Scriptlets are not supported when using the tags api.");
9185
+ if (!scriptlet.node.static) {
9186
+ reportAnalyzeError(scriptlet, scriptlet.buildCodeFrameError("Scriptlets are not supported when using the tags api."));
9187
+ scriptlet.skip();
9188
+ return;
9189
+ }
9139
9190
  mergeReferences(getOrCreateSection(scriptlet), scriptlet.node, scriptlet.node.body);
9140
9191
  if (scriptlet.node.target === "client") (0, _marko_compiler_babel_utils.getProgram)().node.extra.isInteractive = true;
9141
9192
  },
@@ -9294,11 +9345,18 @@ function getTagRelativePath(tag) {
9294
9345
  if (!relativePath) throw tagNotFoundError(tag);
9295
9346
  return relativePath;
9296
9347
  }
9348
+ const knownWrongTags = /* @__PURE__ */ new Map([
9349
+ ["slot", "To render content passed to this tag, use a [dynamic tag](https://markojs.com/docs/reference/language#dynamic-tags): `<${input.content}/>`."],
9350
+ ["state", "Reactive state is declared with the [`<let>` tag](https://markojs.com/docs/reference/core-tag#let): `<let/name=initialValue>`."],
9351
+ ["fragment", "Marko templates and tag bodies may have multiple root nodes; no fragment wrapper is needed."]
9352
+ ]);
9297
9353
  function tagNotFoundError(tag) {
9298
9354
  const tagName = getTagName(tag);
9299
9355
  if (tagName && tag.scope.hasBinding(tagName)) return tag.get("name").buildCodeFrameError(`Local variables must be in a [dynamic tag](https://markojs.com/docs/reference/language#dynamic-tags) unless they are PascalCase. Use \`<\${${tagName}}/>\` or rename to \`${tagName.charAt(0).toUpperCase() + tagName.slice(1)}\`.`);
9300
9356
  let didYouMean = "";
9301
- if (tagName) {
9357
+ const knownWrongTagHint = tagName && knownWrongTags.get(tagName);
9358
+ if (knownWrongTagHint) didYouMean = ` ${knownWrongTagHint}`;
9359
+ else if (tagName) {
9302
9360
  const closestTag = (0, fastest_levenshtein.closest)(tagName, Object.keys((0, _marko_compiler_babel_utils.getTaglibLookup)(tag.hub.file).merged.tags));
9303
9361
  if ((0, fastest_levenshtein.distance)(tagName, closestTag) < 4) didYouMean = ` Did you mean \`<${closestTag}>\`?`;
9304
9362
  }
@@ -9505,33 +9563,46 @@ function enableDynamicTagResume(tag) {
9505
9563
  var tag_default = {
9506
9564
  analyze: {
9507
9565
  enter(tag) {
9508
- const tagDef = (0, _marko_compiler_babel_utils.getTagDef)(tag);
9509
- const type = analyzeTagNameType(tag);
9510
- const hook = tagDef?.analyzer?.hook;
9511
- if (hook) {
9512
- enter$1(hook, tag);
9513
- return;
9514
- }
9515
- if (type === 0) {
9516
- native_tag_default.analyze.enter(tag);
9517
- return;
9518
- }
9519
- switch (type) {
9520
- case 1:
9521
- custom_tag_default.analyze.enter(tag);
9522
- break;
9523
- case 3:
9524
- attribute_tag_default.analyze.enter(tag);
9525
- break;
9526
- case 2:
9527
- dynamic_tag_default.analyze.enter(tag);
9528
- break;
9566
+ try {
9567
+ const tagDef = (0, _marko_compiler_babel_utils.getTagDef)(tag);
9568
+ const type = analyzeTagNameType(tag);
9569
+ const hook = tagDef?.analyzer?.hook;
9570
+ if (hook) {
9571
+ enter$1(hook, tag);
9572
+ return;
9573
+ }
9574
+ if (type === 0) {
9575
+ native_tag_default.analyze.enter(tag);
9576
+ return;
9577
+ }
9578
+ switch (type) {
9579
+ case 1:
9580
+ custom_tag_default.analyze.enter(tag);
9581
+ break;
9582
+ case 3:
9583
+ attribute_tag_default.analyze.enter(tag);
9584
+ break;
9585
+ case 2:
9586
+ dynamic_tag_default.analyze.enter(tag);
9587
+ break;
9588
+ }
9589
+ } catch (err) {
9590
+ (tag.node.extra ??= {}).analyzeFailed = true;
9591
+ reportAnalyzeError(tag, err);
9592
+ tag.skip();
9529
9593
  }
9530
9594
  },
9531
9595
  exit(tag) {
9532
- const hook = (0, _marko_compiler_babel_utils.getTagDef)(tag)?.analyzer?.hook;
9533
- if (hook) {
9534
- exit$1(hook, tag);
9596
+ if (tag.node.extra?.analyzeFailed) return;
9597
+ try {
9598
+ const hook = (0, _marko_compiler_babel_utils.getTagDef)(tag)?.analyzer?.hook;
9599
+ if (hook) {
9600
+ exit$1(hook, tag);
9601
+ return;
9602
+ }
9603
+ } catch (err) {
9604
+ (tag.node.extra ??= {}).analyzeFailed = true;
9605
+ reportAnalyzeError(tag, err);
9535
9606
  return;
9536
9607
  }
9537
9608
  }
@@ -0,0 +1,3 @@
1
+ import type { types as t } from "@marko/compiler";
2
+ export declare function reportAnalyzeError(path: t.NodePath<t.Node>, error: unknown): void;
3
+ export declare function hasAnalyzeErrors(): boolean;
@@ -1,2 +1,10 @@
1
1
  import { types as t } from "@marko/compiler";
2
- export declare function bodyToTextLiteral(body: t.MarkoTagBody): t.StringLiteral | t.TemplateLiteral;
2
+ export declare const kRawText: unique symbol;
3
+ declare module "@marko/compiler/dist/types" {
4
+ interface MarkoPlaceholderExtra {
5
+ [kRawText]?: true;
6
+ }
7
+ }
8
+ export declare function bodyToTextLiteral(body: t.MarkoTagBody): t.Expression;
9
+ export declare function bodyToRawTextLiteral(body: t.MarkoTagBody): t.Expression;
10
+ export declare function injectTextCoercion(expr: t.Expression): void;
@@ -47,6 +47,9 @@ export interface Section {
47
47
  properties: Opt<string>;
48
48
  } | false | undefined;
49
49
  hasAbortSignal: boolean;
50
+ /** Count of distinct `$signal` expression roots; analyze allocates each
51
+ * root's `abortId` from this so translates read, never re-derive. */
52
+ abortSignalExprs: number;
50
53
  readsOwner: boolean;
51
54
  isBranch: boolean;
52
55
  content: null | {
@@ -1,4 +1,11 @@
1
1
  import { types as t } from "@marko/compiler";
2
+ declare module "@marko/compiler/dist/types" {
3
+ interface NodeExtra {
4
+ /** `$signal` abort id for this expression root, allocated in analyze
5
+ * (see below) so every translate reads the same id. */
6
+ abortId?: number;
7
+ }
8
+ }
2
9
  declare const _default: {
3
10
  migrate(this: unknown, identifier: t.NodePath<t.Identifier>): void;
4
11
  analyze(this: unknown, identifier: t.NodePath<t.Identifier>): void;
@@ -1,4 +1,9 @@
1
1
  import { types as t } from "@marko/compiler";
2
+ declare module "@marko/compiler/dist/types" {
3
+ interface MarkoTagExtra {
4
+ analyzeFailed?: boolean;
5
+ }
6
+ }
2
7
  declare const _default: {
3
8
  analyze: {
4
9
  enter(this: unknown, tag: t.NodePath<t.MarkoTag>): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "marko",
3
- "version": "6.3.2",
3
+ "version": "6.3.4",
4
4
  "description": "Optimized runtime for Marko templates.",
5
5
  "keywords": [
6
6
  "api",
@@ -20,6 +20,7 @@
20
20
  ".": {
21
21
  "types": "./index.d.ts"
22
22
  },
23
+ "./cheatsheet.md": "./cheatsheet.md",
23
24
  "./package.json": "./package.json",
24
25
  "./translator": "./dist/translator/index.js",
25
26
  "./tags/*": "./tags/*",
@@ -43,13 +44,14 @@
43
44
  "tags-html.d.ts",
44
45
  "!**/meta.*.json",
45
46
  "!**/__tests__",
46
- "!**/*.tsbuildinfo"
47
+ "!**/*.tsbuildinfo",
48
+ "cheatsheet.md"
47
49
  ],
48
50
  "scripts": {
49
51
  "build": "node -r ~ts ./scripts/bundle.mts"
50
52
  },
51
53
  "dependencies": {
52
- "@marko/compiler": "^5.39.66",
54
+ "@marko/compiler": "^5.40.2",
53
55
  "csstype": "^3.2.3",
54
56
  "fastest-levenshtein": "^1.0.16",
55
57
  "magic-string": "^0.30.21"
@@ -61,6 +63,7 @@
61
63
  ".": {
62
64
  "types": "./index.d.ts"
63
65
  },
66
+ "./cheatsheet.md": "./cheatsheet.md",
64
67
  "./translator": "./src/translator/index.ts",
65
68
  "./tags/*": "./tags/*",
66
69
  "./debug/*": "./src/*.ts",