tutuca 0.9.69 → 0.9.71

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.
@@ -8763,9 +8763,10 @@ function checkParseIssues(lx, view) {
8763
8763
  if (!issues)
8764
8764
  return;
8765
8765
  for (const { kind, info } of issues) {
8766
- const id = PARSE_ISSUE_KIND_TO_LINT_ID[kind];
8767
- if (!id)
8766
+ const rule = PARSE_ISSUES[kind];
8767
+ if (!rule)
8768
8768
  continue;
8769
+ const id = rule.id;
8769
8770
  if (kind === "bad-value") {
8770
8771
  const detected = classifyBadValue(info.value);
8771
8772
  if (detected) {
@@ -8773,15 +8774,13 @@ function checkParseIssues(lx, view) {
8773
8774
  continue;
8774
8775
  }
8775
8776
  }
8776
- const atPrefixKnown = AT_PREFIX_HINT_KNOWN_BY_KIND[kind];
8777
+ const atPrefixKnown = rule.atPrefix;
8777
8778
  const isAtPrefixedTypo = atPrefixKnown && info.name?.startsWith("@") && atPrefixKnown.has(info.name.slice(1));
8778
8779
  let suggestion = null;
8779
8780
  if (isAtPrefixedTypo) {
8780
8781
  suggestion = { kind: "drop-prefix", from: info.name, to: info.name.slice(1) };
8781
- } else {
8782
- const candidates = PARSE_ISSUE_KIND_TO_KNOWN_NAMES[kind];
8783
- if (candidates)
8784
- suggestion = replaceNameSuggestion(info.name, candidates);
8782
+ } else if (rule.candidates) {
8783
+ suggestion = replaceNameSuggestion(info.name, rule.candidates);
8785
8784
  }
8786
8785
  lx.error(id, info, suggestion);
8787
8786
  if (isAtPrefixedTypo) {
@@ -8930,70 +8929,15 @@ function checkEventHandlersHaveImpls(lx, Comp, referencedInputs) {
8930
8929
  });
8931
8930
  }
8932
8931
  }
8932
+ function reportUnknownName(lx, code, name, candidates, info) {
8933
+ lx.error(code, { ...info, name }, replaceNameSuggestion(name, candidates));
8934
+ }
8933
8935
  function checkConsistentAttrVal(lx, val, env, skipNameVal = false, errCtx = null) {
8934
- const { fields, proto, scope, alter } = env;
8935
- const valName = val?.constructor.name;
8936
- if (valName === "FieldVal") {
8937
- const { name } = val;
8938
- if (fields[name] === undefined) {
8939
- if (proto[name] !== undefined) {
8940
- lx.error(FIELD_VAL_IS_METHOD, { ...errCtx, val, name }, { kind: "rewrite", from: `.${name}`, to: `$${name}` });
8941
- } else {
8942
- lx.error(FIELD_VAL_NOT_DEFINED, { ...errCtx, val, name }, replaceNameSuggestion(name, Object.keys(fields)));
8943
- }
8944
- }
8945
- } else if (valName === "MethodVal") {
8946
- const { name } = val;
8947
- if (proto[name] === undefined) {
8948
- if (fields[name] !== undefined) {
8949
- lx.error(METHOD_VAL_IS_FIELD, { ...errCtx, val, name }, { kind: "rewrite", from: `$${name}`, to: `.${name}` });
8950
- } else {
8951
- lx.error(METHOD_VAL_NOT_DEFINED, { ...errCtx, val, name }, replaceNameSuggestion(name, collectProtoMethodNames(proto)));
8952
- }
8953
- }
8954
- } else if (valName === "SeqAccessVal") {
8955
- checkConsistentAttrVal(lx, val.seqVal, env, skipNameVal, errCtx);
8956
- checkConsistentAttrVal(lx, val.keyVal, env, skipNameVal, errCtx);
8957
- } else if (valName === "RequestVal") {
8958
- if (scope.lookupRequest(val.name) === null) {
8959
- lx.error(UNKNOWN_REQUEST_NAME, { ...errCtx, name: val.name }, replaceNameSuggestion(val.name, scopeKeysAlong(scope, "reqsByName")));
8960
- }
8961
- } else if (valName === "TypeVal") {
8962
- if (scope.lookupComponent(val.name) === null) {
8963
- lx.error(UNKNOWN_COMPONENT_NAME, { ...errCtx, name: val.name }, replaceNameSuggestion(val.name, scopeKeysAlong(scope, "byName")));
8964
- }
8965
- } else if (valName === "NameVal") {
8966
- if (!skipNameVal && !isKnownHandlerName(val.name)) {
8967
- lx.error(UNKNOWN_HANDLER_ARG_NAME, { ...errCtx, name: val.name }, replaceNameSuggestion(val.name, KNOWN_HANDLER_NAMES));
8968
- }
8969
- } else if (valName === "StrTplVal") {
8970
- const vs = val.vals;
8971
- const literal = val.toLiteralSource();
8972
- if (literal !== null) {
8973
- lx.hint(PLACEHOLDERLESS_TEMPLATE_STRING, { ...errCtx, literal }, { kind: "rewrite", from: `$${literal}`, to: literal });
8974
- } else if (vs.length === 1) {
8975
- const simpler = String(vs[0]);
8976
- lx.warn(REDUNDANT_TEMPLATE_STRING, { ...errCtx, simpler }, { kind: "rewrite", from: `$'{${simpler}}'`, to: simpler });
8977
- }
8978
- for (const subVal of vs) {
8979
- checkConsistentAttrVal(lx, subVal, env, skipNameVal, errCtx);
8980
- }
8981
- } else if (valName === "HandlerNameVal") {
8982
- env.referencedAlters?.add(val.name);
8983
- if (alter[val.name] === undefined) {
8984
- lx.error(ALT_HANDLER_NOT_DEFINED, { ...errCtx, name: val.name }, replaceNameSuggestion(val.name, Object.keys(alter)));
8985
- }
8986
- } else if (valName === "PredicateVal") {
8987
- for (const arg of val.args)
8988
- checkConsistentAttrVal(lx, arg, env, skipNameVal, errCtx);
8989
- } else if (valName === "DynVal") {
8990
- env.referencedDynamics?.add(val.name);
8991
- if (env.dynamicMap[val.name] === undefined) {
8992
- lx.error(DYN_VAL_NOT_DEFINED, { ...errCtx, name: val.name }, replaceNameSuggestion(val.name, Object.keys(env.dynamicMap)));
8993
- }
8994
- } else if (valName !== "ConstVal" && valName !== "BindVal") {
8995
- console.log(val);
8996
- }
8936
+ const check = ATTR_VAL_CHECKERS[val?.constructor.name];
8937
+ if (check === undefined)
8938
+ return;
8939
+ const recurse = (sub) => checkConsistentAttrVal(lx, sub, env, skipNameVal, errCtx);
8940
+ check({ lx, val, env, errCtx, skipNameVal, recurse });
8997
8941
  }
8998
8942
  function nodeCtxForNode(nodeKind) {
8999
8943
  return NODE_KIND_TO_CTX[nodeKind] ?? null;
@@ -9016,6 +8960,23 @@ function attrOriginAttr(attr) {
9016
8960
  return "@dangerouslysetinnerhtml";
9017
8961
  return `:${attr.name}`;
9018
8962
  }
8963
+ function checkHostBareDirectives(lx, attrs, tag, isMacroCall) {
8964
+ if (isMacroCall || !attrs)
8965
+ return;
8966
+ const kind = attrs.constructor.name;
8967
+ let names;
8968
+ if (kind === "ConstAttrs")
8969
+ names = Object.keys(attrs.items);
8970
+ else if (kind === "DynAttrs")
8971
+ names = attrs.items.map((a) => a?.name);
8972
+ else
8973
+ return;
8974
+ for (const name of names) {
8975
+ if (HOST_DIRECTIVE_ONLY_NAMES.has(name)) {
8976
+ lx.hint(MAYBE_ADD_AT_PREFIX, { name, tag, suggestion: `@${name}` }, { kind: "add-prefix", from: name, to: `@${name}` });
8977
+ }
8978
+ }
8979
+ }
9019
8980
  function checkConsistentAttrs(lx, Comp, referencedAlters, referencedDynamics) {
9020
8981
  const { views } = Comp;
9021
8982
  const env = mkAttrValEnv(Comp, referencedAlters, referencedDynamics);
@@ -9024,6 +8985,7 @@ function checkConsistentAttrs(lx, Comp, referencedAlters, referencedDynamics) {
9024
8985
  const view = views[viewName];
9025
8986
  for (const entry of view.ctx.attrs) {
9026
8987
  const { attrs, wrapperAttrs, textChild, isMacroCall, tag } = entry;
8988
+ checkHostBareDirectives(lx, attrs, tag, isMacroCall);
9027
8989
  if (attrs?.constructor.name === "DynAttrs") {
9028
8990
  const sourcesByName = new Map;
9029
8991
  for (const attr of attrs.items) {
@@ -9200,7 +9162,7 @@ class LintContext {
9200
9162
  this.reports.push({ id, info, level, context: { ...this.frame }, suggestion });
9201
9163
  }
9202
9164
  }
9203
- var KNOWN_COMPONENT_SPEC_KEYS, EMPTY_SET2, KNOWN_DIRECTIVE_NAMES, ALT_HANDLER_NOT_DEFINED = "ALT_HANDLER_NOT_DEFINED", ALT_HANDLER_NOT_REFERENCED = "ALT_HANDLER_NOT_REFERENCED", DYN_VAL_NOT_DEFINED = "DYN_VAL_NOT_DEFINED", DYN_ALIAS_NOT_REFERENCED = "DYN_ALIAS_NOT_REFERENCED", RENDER_IT_OUTSIDE_OF_LOOP = "RENDER_IT_OUTSIDE_OF_LOOP", UNKNOWN_EVENT_MODIFIER = "UNKNOWN_EVENT_MODIFIER", UNKNOWN_HANDLER_ARG_NAME = "UNKNOWN_HANDLER_ARG_NAME", INPUT_HANDLER_NOT_IMPLEMENTED = "INPUT_HANDLER_NOT_IMPLEMENTED", INPUT_HANDLER_NOT_REFERENCED = "INPUT_HANDLER_NOT_REFERENCED", INPUT_HANDLER_METHOD_NOT_IMPLEMENTED = "INPUT_HANDLER_METHOD_NOT_IMPLEMENTED", INPUT_HANDLER_FOR_INPUT_HANDLER_METHOD = "INPUT_HANDLER_FOR_INPUT_HANDLER_METHOD", INPUT_HANDLER_METHOD_FOR_INPUT_HANDLER = "INPUT_HANDLER_METHOD_FOR_INPUT_HANDLER", FIELD_VAL_NOT_DEFINED = "FIELD_VAL_NOT_DEFINED", FIELD_VAL_IS_METHOD = "FIELD_VAL_IS_METHOD", METHOD_VAL_NOT_DEFINED = "METHOD_VAL_NOT_DEFINED", METHOD_VAL_IS_FIELD = "METHOD_VAL_IS_FIELD", DUPLICATE_ATTR_DEFINITION = "DUPLICATE_ATTR_DEFINITION", IF_NO_BRANCH_SET = "IF_NO_BRANCH_SET", UNKNOWN_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", UNSUPPORTED_EXPR_SYNTAX = "UNSUPPORTED_EXPR_SYNTAX", REDUNDANT_TEMPLATE_STRING = "REDUNDANT_TEMPLATE_STRING", PLACEHOLDERLESS_TEMPLATE_STRING = "PLACEHOLDERLESS_TEMPLATE_STRING", UNKNOWN_COMPONENT_SPEC_KEY = "UNKNOWN_COMPONENT_SPEC_KEY", COMP_FIELD_BAD_SHAPE = "COMP_FIELD_BAD_SHAPE", PARSE_ISSUE_KIND_TO_LINT_ID, X_KNOWN_OP_NAMES, X_KNOWN_ATTR_NAMES, AT_PREFIX_HINT_KNOWN_BY_KIND, LEVEL_WARN2 = "warn", LEVEL_ERROR2 = "error", LEVEL_HINT = "hint", PARSE_ISSUE_KIND_TO_KNOWN_NAMES, UNSUPPORTED_EXPR_GUIDANCE, HTML_LINT_OPTS, NO_WRAPPERS, KNOWN_HANDLER_NAMES, NODE_KIND_TO_CTX, LintParseContext;
9165
+ var KNOWN_COMPONENT_SPEC_KEYS, EMPTY_SET2, KNOWN_DIRECTIVE_NAMES, ALT_HANDLER_NOT_DEFINED = "ALT_HANDLER_NOT_DEFINED", ALT_HANDLER_NOT_REFERENCED = "ALT_HANDLER_NOT_REFERENCED", DYN_VAL_NOT_DEFINED = "DYN_VAL_NOT_DEFINED", DYN_ALIAS_NOT_REFERENCED = "DYN_ALIAS_NOT_REFERENCED", RENDER_IT_OUTSIDE_OF_LOOP = "RENDER_IT_OUTSIDE_OF_LOOP", UNKNOWN_EVENT_MODIFIER = "UNKNOWN_EVENT_MODIFIER", UNKNOWN_HANDLER_ARG_NAME = "UNKNOWN_HANDLER_ARG_NAME", INPUT_HANDLER_NOT_IMPLEMENTED = "INPUT_HANDLER_NOT_IMPLEMENTED", INPUT_HANDLER_NOT_REFERENCED = "INPUT_HANDLER_NOT_REFERENCED", INPUT_HANDLER_METHOD_NOT_IMPLEMENTED = "INPUT_HANDLER_METHOD_NOT_IMPLEMENTED", INPUT_HANDLER_FOR_INPUT_HANDLER_METHOD = "INPUT_HANDLER_FOR_INPUT_HANDLER_METHOD", INPUT_HANDLER_METHOD_FOR_INPUT_HANDLER = "INPUT_HANDLER_METHOD_FOR_INPUT_HANDLER", FIELD_VAL_NOT_DEFINED = "FIELD_VAL_NOT_DEFINED", FIELD_VAL_IS_METHOD = "FIELD_VAL_IS_METHOD", METHOD_VAL_NOT_DEFINED = "METHOD_VAL_NOT_DEFINED", METHOD_VAL_IS_FIELD = "METHOD_VAL_IS_FIELD", DUPLICATE_ATTR_DEFINITION = "DUPLICATE_ATTR_DEFINITION", IF_NO_BRANCH_SET = "IF_NO_BRANCH_SET", UNKNOWN_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", MAYBE_ADD_AT_PREFIX = "MAYBE_ADD_AT_PREFIX", BAD_VALUE = "BAD_VALUE", UNSUPPORTED_EXPR_SYNTAX = "UNSUPPORTED_EXPR_SYNTAX", REDUNDANT_TEMPLATE_STRING = "REDUNDANT_TEMPLATE_STRING", PLACEHOLDERLESS_TEMPLATE_STRING = "PLACEHOLDERLESS_TEMPLATE_STRING", UNKNOWN_COMPONENT_SPEC_KEY = "UNKNOWN_COMPONENT_SPEC_KEY", COMP_FIELD_BAD_SHAPE = "COMP_FIELD_BAD_SHAPE", X_KNOWN_OP_NAMES, X_KNOWN_ATTR_NAMES, HOST_DIRECTIVE_ONLY_NAMES, LEVEL_WARN2 = "warn", LEVEL_ERROR2 = "error", LEVEL_HINT = "hint", PARSE_ISSUES, UNSUPPORTED_EXPR_GUIDANCE, HTML_LINT_OPTS, NO_WRAPPERS, KNOWN_HANDLER_NAMES, fixTo = (from, to) => ({ kind: "rewrite", from, to }), ATTR_VAL_CHECKERS, NODE_KIND_TO_CTX, LintParseContext;
9204
9166
  var init_lint_check = __esm(() => {
9205
9167
  init_anode();
9206
9168
  init_htmllinter();
@@ -9220,12 +9182,6 @@ var init_lint_check = __esm(() => {
9220
9182
  "then",
9221
9183
  "else"
9222
9184
  ]);
9223
- PARSE_ISSUE_KIND_TO_LINT_ID = {
9224
- "unknown-directive": UNKNOWN_DIRECTIVE,
9225
- "unknown-x-op": UNKNOWN_X_OP,
9226
- "unknown-x-attr": UNKNOWN_X_ATTR,
9227
- "bad-value": BAD_VALUE
9228
- };
9229
9185
  X_KNOWN_OP_NAMES = new Set([
9230
9186
  "slot",
9231
9187
  "text",
@@ -9236,14 +9192,16 @@ var init_lint_check = __esm(() => {
9236
9192
  "hide"
9237
9193
  ]);
9238
9194
  X_KNOWN_ATTR_NAMES = new Set(["as", "when", "loop-with", "show", "hide"]);
9239
- AT_PREFIX_HINT_KNOWN_BY_KIND = {
9240
- "unknown-x-op": X_KNOWN_OP_NAMES,
9241
- "unknown-x-attr": X_KNOWN_ATTR_NAMES
9242
- };
9243
- PARSE_ISSUE_KIND_TO_KNOWN_NAMES = {
9244
- "unknown-directive": KNOWN_DIRECTIVE_NAMES,
9245
- "unknown-x-op": X_KNOWN_OP_NAMES,
9246
- "unknown-x-attr": X_KNOWN_ATTR_NAMES
9195
+ HOST_DIRECTIVE_ONLY_NAMES = new Set(["when", "enrich-with", "loop-with", "show", "hide"]);
9196
+ PARSE_ISSUES = {
9197
+ "unknown-directive": { id: UNKNOWN_DIRECTIVE, candidates: KNOWN_DIRECTIVE_NAMES },
9198
+ "unknown-x-op": { id: UNKNOWN_X_OP, candidates: X_KNOWN_OP_NAMES, atPrefix: X_KNOWN_OP_NAMES },
9199
+ "unknown-x-attr": {
9200
+ id: UNKNOWN_X_ATTR,
9201
+ candidates: X_KNOWN_ATTR_NAMES,
9202
+ atPrefix: X_KNOWN_ATTR_NAMES
9203
+ },
9204
+ "bad-value": { id: BAD_VALUE }
9247
9205
  };
9248
9206
  UNSUPPORTED_EXPR_GUIDANCE = {
9249
9207
  "legacy-template": "Unquoted {...} string templates are no longer supported. Wrap the value in $'...', e.g. $'flex {.color}'.",
@@ -9277,6 +9235,73 @@ var init_lint_check = __esm(() => {
9277
9235
  "ctx",
9278
9236
  "dragInfo"
9279
9237
  ]);
9238
+ ATTR_VAL_CHECKERS = {
9239
+ FieldVal({ lx, val, env, errCtx }) {
9240
+ const { fields, proto } = env;
9241
+ const { name } = val;
9242
+ if (fields[name] !== undefined)
9243
+ return;
9244
+ if (proto[name] !== undefined)
9245
+ lx.error(FIELD_VAL_IS_METHOD, { ...errCtx, val, name }, fixTo(`.${name}`, `$${name}`));
9246
+ else
9247
+ reportUnknownName(lx, FIELD_VAL_NOT_DEFINED, name, Object.keys(fields), { ...errCtx, val });
9248
+ },
9249
+ MethodVal({ lx, val, env, errCtx }) {
9250
+ const { fields, proto } = env;
9251
+ const { name } = val;
9252
+ if (proto[name] !== undefined)
9253
+ return;
9254
+ if (fields[name] !== undefined)
9255
+ lx.error(METHOD_VAL_IS_FIELD, { ...errCtx, val, name }, fixTo(`$${name}`, `.${name}`));
9256
+ else
9257
+ reportUnknownName(lx, METHOD_VAL_NOT_DEFINED, name, collectProtoMethodNames(proto), {
9258
+ ...errCtx,
9259
+ val
9260
+ });
9261
+ },
9262
+ SeqAccessVal({ val, recurse }) {
9263
+ recurse(val.seqVal);
9264
+ recurse(val.keyVal);
9265
+ },
9266
+ RequestVal({ lx, val, env, errCtx }) {
9267
+ if (env.scope.lookupRequest(val.name) === null)
9268
+ reportUnknownName(lx, UNKNOWN_REQUEST_NAME, val.name, scopeKeysAlong(env.scope, "reqsByName"), errCtx);
9269
+ },
9270
+ TypeVal({ lx, val, env, errCtx }) {
9271
+ if (env.scope.lookupComponent(val.name) === null)
9272
+ reportUnknownName(lx, UNKNOWN_COMPONENT_NAME, val.name, scopeKeysAlong(env.scope, "byName"), errCtx);
9273
+ },
9274
+ NameVal({ lx, val, errCtx, skipNameVal }) {
9275
+ if (!skipNameVal && !isKnownHandlerName(val.name))
9276
+ reportUnknownName(lx, UNKNOWN_HANDLER_ARG_NAME, val.name, KNOWN_HANDLER_NAMES, errCtx);
9277
+ },
9278
+ StrTplVal({ lx, val, errCtx, recurse }) {
9279
+ const vs = val.vals;
9280
+ const literal = val.toLiteralSource();
9281
+ if (literal !== null) {
9282
+ lx.hint(PLACEHOLDERLESS_TEMPLATE_STRING, { ...errCtx, literal }, fixTo(`$${literal}`, literal));
9283
+ } else if (vs.length === 1) {
9284
+ const simpler = String(vs[0]);
9285
+ lx.warn(REDUNDANT_TEMPLATE_STRING, { ...errCtx, simpler }, fixTo(`$'{${simpler}}'`, simpler));
9286
+ }
9287
+ for (const subVal of vs)
9288
+ recurse(subVal);
9289
+ },
9290
+ HandlerNameVal({ lx, val, env, errCtx }) {
9291
+ env.referencedAlters?.add(val.name);
9292
+ if (env.alter[val.name] === undefined)
9293
+ reportUnknownName(lx, ALT_HANDLER_NOT_DEFINED, val.name, Object.keys(env.alter), errCtx);
9294
+ },
9295
+ PredicateVal({ val, recurse }) {
9296
+ for (const arg of val.args)
9297
+ recurse(arg);
9298
+ },
9299
+ DynVal({ lx, val, env, errCtx }) {
9300
+ env.referencedDynamics?.add(val.name);
9301
+ if (env.dynamicMap[val.name] === undefined)
9302
+ reportUnknownName(lx, DYN_VAL_NOT_DEFINED, val.name, Object.keys(env.dynamicMap), errCtx);
9303
+ }
9304
+ };
9280
9305
  NODE_KIND_TO_CTX = {
9281
9306
  RenderTextNode: { originAttr: "<x text>" },
9282
9307
  RenderNode: { originAttr: "<x render>" },
@@ -9453,6 +9478,12 @@ var init_lint_rules = __esm(() => {
9453
9478
  group: "Templates / events",
9454
9479
  summary: "An `<x>` op/attr was written with a leading `@` like a directive."
9455
9480
  },
9481
+ {
9482
+ code: MAYBE_ADD_AT_PREFIX,
9483
+ level: "hint",
9484
+ group: "Templates / events",
9485
+ summary: "A directive name (`when`/`enrich-with`/`loop-with`/`show`/`hide`) was written as a plain attribute on a host element — add the `@` prefix."
9486
+ },
9456
9487
  {
9457
9488
  code: BAD_VALUE,
9458
9489
  level: "error",
@@ -14919,6 +14950,8 @@ function lintIdToMessage(id, info) {
14919
14950
  const written = info.value !== undefined ? `${info.name}=${JSON.stringify(info.value)}` : info.name;
14920
14951
  return `'${written}' on <x> looks like a directive but is actually an x op/attr written with a leading '@'`;
14921
14952
  }
14953
+ case "MAYBE_ADD_AT_PREFIX":
14954
+ return `'${info.name}' on <${(info.tag ?? "").toLowerCase()}> is a plain attribute, but '@${info.name}' is a directive — add the leading '@'`;
14922
14955
  case "BAD_VALUE":
14923
14956
  return `${badValueMessage(info)}${fmtTagSuffix(info)}`;
14924
14957
  case "UNSUPPORTED_EXPR_SYNTAX":
@@ -14929,6 +14962,8 @@ function lintIdToMessage(id, info) {
14929
14962
  return `Template string has no dynamic parts — use the string literal ${info.literal} instead${fmtOriginSuffix(info)}`;
14930
14963
  case "UNKNOWN_COMPONENT_SPEC_KEY":
14931
14964
  return `Unknown component spec key '${info.key}' — value will be ignored at runtime`;
14965
+ case "COMP_FIELD_BAD_SHAPE":
14966
+ return info.kind === "args-not-object" ? `Field '${info.fieldName}': in { component, args }, 'args' must be a plain object, got ${info.got}` : `Field '${info.fieldName}': in { component, args }, 'component' must be the component name as a string, got ${info.gotName ? `the ${info.gotName} class` : info.got}`;
14932
14967
  case "HTML_TAG_NAME_HAS_UPPERCASE":
14933
14968
  return `Tag <${info.raw}> will be lowercased to <${info.lowercased}>${fmtLocationSuffix(info)}`;
14934
14969
  case "HTML_SVG_TAG_WILL_LOWERCASE":
@@ -89,6 +89,7 @@ __export(exports_dev, {
89
89
  METHOD_VAL_NOT_DEFINED: () => METHOD_VAL_NOT_DEFINED,
90
90
  METHOD_VAL_IS_FIELD: () => METHOD_VAL_IS_FIELD,
91
91
  MAYBE_DROP_AT_PREFIX: () => MAYBE_DROP_AT_PREFIX,
92
+ MAYBE_ADD_AT_PREFIX: () => MAYBE_ADD_AT_PREFIX,
92
93
  LintReport: () => LintReport,
93
94
  LintParseContext: () => LintParseContext,
94
95
  LintFinding: () => LintFinding,
@@ -5854,6 +5855,7 @@ __export(exports_lint_check, {
5854
5855
  METHOD_VAL_NOT_DEFINED: () => METHOD_VAL_NOT_DEFINED,
5855
5856
  METHOD_VAL_IS_FIELD: () => METHOD_VAL_IS_FIELD,
5856
5857
  MAYBE_DROP_AT_PREFIX: () => MAYBE_DROP_AT_PREFIX,
5858
+ MAYBE_ADD_AT_PREFIX: () => MAYBE_ADD_AT_PREFIX,
5857
5859
  LintParseContext: () => LintParseContext,
5858
5860
  LintContext: () => LintContext,
5859
5861
  INPUT_HANDLER_NOT_REFERENCED: () => INPUT_HANDLER_NOT_REFERENCED,
@@ -8174,18 +8176,13 @@ var UNKNOWN_DIRECTIVE = "UNKNOWN_DIRECTIVE";
8174
8176
  var UNKNOWN_X_OP = "UNKNOWN_X_OP";
8175
8177
  var UNKNOWN_X_ATTR = "UNKNOWN_X_ATTR";
8176
8178
  var MAYBE_DROP_AT_PREFIX = "MAYBE_DROP_AT_PREFIX";
8179
+ var MAYBE_ADD_AT_PREFIX = "MAYBE_ADD_AT_PREFIX";
8177
8180
  var BAD_VALUE = "BAD_VALUE";
8178
8181
  var UNSUPPORTED_EXPR_SYNTAX = "UNSUPPORTED_EXPR_SYNTAX";
8179
8182
  var REDUNDANT_TEMPLATE_STRING = "REDUNDANT_TEMPLATE_STRING";
8180
8183
  var PLACEHOLDERLESS_TEMPLATE_STRING = "PLACEHOLDERLESS_TEMPLATE_STRING";
8181
8184
  var UNKNOWN_COMPONENT_SPEC_KEY = "UNKNOWN_COMPONENT_SPEC_KEY";
8182
8185
  var COMP_FIELD_BAD_SHAPE = "COMP_FIELD_BAD_SHAPE";
8183
- var PARSE_ISSUE_KIND_TO_LINT_ID = {
8184
- "unknown-directive": UNKNOWN_DIRECTIVE,
8185
- "unknown-x-op": UNKNOWN_X_OP,
8186
- "unknown-x-attr": UNKNOWN_X_ATTR,
8187
- "bad-value": BAD_VALUE
8188
- };
8189
8186
  var X_KNOWN_OP_NAMES = new Set([
8190
8187
  "slot",
8191
8188
  "text",
@@ -8196,17 +8193,19 @@ var X_KNOWN_OP_NAMES = new Set([
8196
8193
  "hide"
8197
8194
  ]);
8198
8195
  var X_KNOWN_ATTR_NAMES = new Set(["as", "when", "loop-with", "show", "hide"]);
8199
- var AT_PREFIX_HINT_KNOWN_BY_KIND = {
8200
- "unknown-x-op": X_KNOWN_OP_NAMES,
8201
- "unknown-x-attr": X_KNOWN_ATTR_NAMES
8202
- };
8196
+ var HOST_DIRECTIVE_ONLY_NAMES = new Set(["when", "enrich-with", "loop-with", "show", "hide"]);
8203
8197
  var LEVEL_WARN2 = "warn";
8204
8198
  var LEVEL_ERROR2 = "error";
8205
8199
  var LEVEL_HINT = "hint";
8206
- var PARSE_ISSUE_KIND_TO_KNOWN_NAMES = {
8207
- "unknown-directive": KNOWN_DIRECTIVE_NAMES,
8208
- "unknown-x-op": X_KNOWN_OP_NAMES,
8209
- "unknown-x-attr": X_KNOWN_ATTR_NAMES
8200
+ var PARSE_ISSUES = {
8201
+ "unknown-directive": { id: UNKNOWN_DIRECTIVE, candidates: KNOWN_DIRECTIVE_NAMES },
8202
+ "unknown-x-op": { id: UNKNOWN_X_OP, candidates: X_KNOWN_OP_NAMES, atPrefix: X_KNOWN_OP_NAMES },
8203
+ "unknown-x-attr": {
8204
+ id: UNKNOWN_X_ATTR,
8205
+ candidates: X_KNOWN_ATTR_NAMES,
8206
+ atPrefix: X_KNOWN_ATTR_NAMES
8207
+ },
8208
+ "bad-value": { id: BAD_VALUE }
8210
8209
  };
8211
8210
  function collectProtoMethodNames(proto) {
8212
8211
  const out = [];
@@ -8301,9 +8300,10 @@ function checkParseIssues(lx, view) {
8301
8300
  if (!issues)
8302
8301
  return;
8303
8302
  for (const { kind, info } of issues) {
8304
- const id = PARSE_ISSUE_KIND_TO_LINT_ID[kind];
8305
- if (!id)
8303
+ const rule = PARSE_ISSUES[kind];
8304
+ if (!rule)
8306
8305
  continue;
8306
+ const id = rule.id;
8307
8307
  if (kind === "bad-value") {
8308
8308
  const detected = classifyBadValue(info.value);
8309
8309
  if (detected) {
@@ -8311,15 +8311,13 @@ function checkParseIssues(lx, view) {
8311
8311
  continue;
8312
8312
  }
8313
8313
  }
8314
- const atPrefixKnown = AT_PREFIX_HINT_KNOWN_BY_KIND[kind];
8314
+ const atPrefixKnown = rule.atPrefix;
8315
8315
  const isAtPrefixedTypo = atPrefixKnown && info.name?.startsWith("@") && atPrefixKnown.has(info.name.slice(1));
8316
8316
  let suggestion = null;
8317
8317
  if (isAtPrefixedTypo) {
8318
8318
  suggestion = { kind: "drop-prefix", from: info.name, to: info.name.slice(1) };
8319
- } else {
8320
- const candidates = PARSE_ISSUE_KIND_TO_KNOWN_NAMES[kind];
8321
- if (candidates)
8322
- suggestion = replaceNameSuggestion(info.name, candidates);
8319
+ } else if (rule.candidates) {
8320
+ suggestion = replaceNameSuggestion(info.name, rule.candidates);
8323
8321
  }
8324
8322
  lx.error(id, info, suggestion);
8325
8323
  if (isAtPrefixedTypo) {
@@ -8489,70 +8487,83 @@ function checkEventHandlersHaveImpls(lx, Comp, referencedInputs) {
8489
8487
  });
8490
8488
  }
8491
8489
  }
8492
- function checkConsistentAttrVal(lx, val, env, skipNameVal = false, errCtx = null) {
8493
- const { fields, proto, scope, alter } = env;
8494
- const valName = val?.constructor.name;
8495
- if (valName === "FieldVal") {
8490
+ var fixTo = (from, to) => ({ kind: "rewrite", from, to });
8491
+ function reportUnknownName(lx, code, name, candidates, info) {
8492
+ lx.error(code, { ...info, name }, replaceNameSuggestion(name, candidates));
8493
+ }
8494
+ var ATTR_VAL_CHECKERS = {
8495
+ FieldVal({ lx, val, env, errCtx }) {
8496
+ const { fields, proto } = env;
8496
8497
  const { name } = val;
8497
- if (fields[name] === undefined) {
8498
- if (proto[name] !== undefined) {
8499
- lx.error(FIELD_VAL_IS_METHOD, { ...errCtx, val, name }, { kind: "rewrite", from: `.${name}`, to: `$${name}` });
8500
- } else {
8501
- lx.error(FIELD_VAL_NOT_DEFINED, { ...errCtx, val, name }, replaceNameSuggestion(name, Object.keys(fields)));
8502
- }
8503
- }
8504
- } else if (valName === "MethodVal") {
8498
+ if (fields[name] !== undefined)
8499
+ return;
8500
+ if (proto[name] !== undefined)
8501
+ lx.error(FIELD_VAL_IS_METHOD, { ...errCtx, val, name }, fixTo(`.${name}`, `$${name}`));
8502
+ else
8503
+ reportUnknownName(lx, FIELD_VAL_NOT_DEFINED, name, Object.keys(fields), { ...errCtx, val });
8504
+ },
8505
+ MethodVal({ lx, val, env, errCtx }) {
8506
+ const { fields, proto } = env;
8505
8507
  const { name } = val;
8506
- if (proto[name] === undefined) {
8507
- if (fields[name] !== undefined) {
8508
- lx.error(METHOD_VAL_IS_FIELD, { ...errCtx, val, name }, { kind: "rewrite", from: `$${name}`, to: `.${name}` });
8509
- } else {
8510
- lx.error(METHOD_VAL_NOT_DEFINED, { ...errCtx, val, name }, replaceNameSuggestion(name, collectProtoMethodNames(proto)));
8511
- }
8512
- }
8513
- } else if (valName === "SeqAccessVal") {
8514
- checkConsistentAttrVal(lx, val.seqVal, env, skipNameVal, errCtx);
8515
- checkConsistentAttrVal(lx, val.keyVal, env, skipNameVal, errCtx);
8516
- } else if (valName === "RequestVal") {
8517
- if (scope.lookupRequest(val.name) === null) {
8518
- lx.error(UNKNOWN_REQUEST_NAME, { ...errCtx, name: val.name }, replaceNameSuggestion(val.name, scopeKeysAlong(scope, "reqsByName")));
8519
- }
8520
- } else if (valName === "TypeVal") {
8521
- if (scope.lookupComponent(val.name) === null) {
8522
- lx.error(UNKNOWN_COMPONENT_NAME, { ...errCtx, name: val.name }, replaceNameSuggestion(val.name, scopeKeysAlong(scope, "byName")));
8523
- }
8524
- } else if (valName === "NameVal") {
8525
- if (!skipNameVal && !isKnownHandlerName(val.name)) {
8526
- lx.error(UNKNOWN_HANDLER_ARG_NAME, { ...errCtx, name: val.name }, replaceNameSuggestion(val.name, KNOWN_HANDLER_NAMES));
8527
- }
8528
- } else if (valName === "StrTplVal") {
8508
+ if (proto[name] !== undefined)
8509
+ return;
8510
+ if (fields[name] !== undefined)
8511
+ lx.error(METHOD_VAL_IS_FIELD, { ...errCtx, val, name }, fixTo(`$${name}`, `.${name}`));
8512
+ else
8513
+ reportUnknownName(lx, METHOD_VAL_NOT_DEFINED, name, collectProtoMethodNames(proto), {
8514
+ ...errCtx,
8515
+ val
8516
+ });
8517
+ },
8518
+ SeqAccessVal({ val, recurse }) {
8519
+ recurse(val.seqVal);
8520
+ recurse(val.keyVal);
8521
+ },
8522
+ RequestVal({ lx, val, env, errCtx }) {
8523
+ if (env.scope.lookupRequest(val.name) === null)
8524
+ reportUnknownName(lx, UNKNOWN_REQUEST_NAME, val.name, scopeKeysAlong(env.scope, "reqsByName"), errCtx);
8525
+ },
8526
+ TypeVal({ lx, val, env, errCtx }) {
8527
+ if (env.scope.lookupComponent(val.name) === null)
8528
+ reportUnknownName(lx, UNKNOWN_COMPONENT_NAME, val.name, scopeKeysAlong(env.scope, "byName"), errCtx);
8529
+ },
8530
+ NameVal({ lx, val, errCtx, skipNameVal }) {
8531
+ if (!skipNameVal && !isKnownHandlerName(val.name))
8532
+ reportUnknownName(lx, UNKNOWN_HANDLER_ARG_NAME, val.name, KNOWN_HANDLER_NAMES, errCtx);
8533
+ },
8534
+ StrTplVal({ lx, val, errCtx, recurse }) {
8529
8535
  const vs = val.vals;
8530
8536
  const literal = val.toLiteralSource();
8531
8537
  if (literal !== null) {
8532
- lx.hint(PLACEHOLDERLESS_TEMPLATE_STRING, { ...errCtx, literal }, { kind: "rewrite", from: `$${literal}`, to: literal });
8538
+ lx.hint(PLACEHOLDERLESS_TEMPLATE_STRING, { ...errCtx, literal }, fixTo(`$${literal}`, literal));
8533
8539
  } else if (vs.length === 1) {
8534
8540
  const simpler = String(vs[0]);
8535
- lx.warn(REDUNDANT_TEMPLATE_STRING, { ...errCtx, simpler }, { kind: "rewrite", from: `$'{${simpler}}'`, to: simpler });
8536
- }
8537
- for (const subVal of vs) {
8538
- checkConsistentAttrVal(lx, subVal, env, skipNameVal, errCtx);
8541
+ lx.warn(REDUNDANT_TEMPLATE_STRING, { ...errCtx, simpler }, fixTo(`$'{${simpler}}'`, simpler));
8539
8542
  }
8540
- } else if (valName === "HandlerNameVal") {
8543
+ for (const subVal of vs)
8544
+ recurse(subVal);
8545
+ },
8546
+ HandlerNameVal({ lx, val, env, errCtx }) {
8541
8547
  env.referencedAlters?.add(val.name);
8542
- if (alter[val.name] === undefined) {
8543
- lx.error(ALT_HANDLER_NOT_DEFINED, { ...errCtx, name: val.name }, replaceNameSuggestion(val.name, Object.keys(alter)));
8544
- }
8545
- } else if (valName === "PredicateVal") {
8548
+ if (env.alter[val.name] === undefined)
8549
+ reportUnknownName(lx, ALT_HANDLER_NOT_DEFINED, val.name, Object.keys(env.alter), errCtx);
8550
+ },
8551
+ PredicateVal({ val, recurse }) {
8546
8552
  for (const arg of val.args)
8547
- checkConsistentAttrVal(lx, arg, env, skipNameVal, errCtx);
8548
- } else if (valName === "DynVal") {
8553
+ recurse(arg);
8554
+ },
8555
+ DynVal({ lx, val, env, errCtx }) {
8549
8556
  env.referencedDynamics?.add(val.name);
8550
- if (env.dynamicMap[val.name] === undefined) {
8551
- lx.error(DYN_VAL_NOT_DEFINED, { ...errCtx, name: val.name }, replaceNameSuggestion(val.name, Object.keys(env.dynamicMap)));
8552
- }
8553
- } else if (valName !== "ConstVal" && valName !== "BindVal") {
8554
- console.log(val);
8557
+ if (env.dynamicMap[val.name] === undefined)
8558
+ reportUnknownName(lx, DYN_VAL_NOT_DEFINED, val.name, Object.keys(env.dynamicMap), errCtx);
8555
8559
  }
8560
+ };
8561
+ function checkConsistentAttrVal(lx, val, env, skipNameVal = false, errCtx = null) {
8562
+ const check = ATTR_VAL_CHECKERS[val?.constructor.name];
8563
+ if (check === undefined)
8564
+ return;
8565
+ const recurse = (sub) => checkConsistentAttrVal(lx, sub, env, skipNameVal, errCtx);
8566
+ check({ lx, val, env, errCtx, skipNameVal, recurse });
8556
8567
  }
8557
8568
  var NODE_KIND_TO_CTX = {
8558
8569
  RenderTextNode: { originAttr: "<x text>" },
@@ -8584,6 +8595,23 @@ function attrOriginAttr(attr) {
8584
8595
  return "@dangerouslysetinnerhtml";
8585
8596
  return `:${attr.name}`;
8586
8597
  }
8598
+ function checkHostBareDirectives(lx, attrs, tag, isMacroCall) {
8599
+ if (isMacroCall || !attrs)
8600
+ return;
8601
+ const kind = attrs.constructor.name;
8602
+ let names;
8603
+ if (kind === "ConstAttrs")
8604
+ names = Object.keys(attrs.items);
8605
+ else if (kind === "DynAttrs")
8606
+ names = attrs.items.map((a) => a?.name);
8607
+ else
8608
+ return;
8609
+ for (const name of names) {
8610
+ if (HOST_DIRECTIVE_ONLY_NAMES.has(name)) {
8611
+ lx.hint(MAYBE_ADD_AT_PREFIX, { name, tag, suggestion: `@${name}` }, { kind: "add-prefix", from: name, to: `@${name}` });
8612
+ }
8613
+ }
8614
+ }
8587
8615
  function checkConsistentAttrs(lx, Comp, referencedAlters, referencedDynamics) {
8588
8616
  const { views } = Comp;
8589
8617
  const env = mkAttrValEnv(Comp, referencedAlters, referencedDynamics);
@@ -8592,6 +8620,7 @@ function checkConsistentAttrs(lx, Comp, referencedAlters, referencedDynamics) {
8592
8620
  const view = views[viewName];
8593
8621
  for (const entry of view.ctx.attrs) {
8594
8622
  const { attrs, wrapperAttrs, textChild, isMacroCall, tag } = entry;
8623
+ checkHostBareDirectives(lx, attrs, tag, isMacroCall);
8595
8624
  if (attrs?.constructor.name === "DynAttrs") {
8596
8625
  const sourcesByName = new Map;
8597
8626
  for (const attr of attrs.items) {
@@ -9393,6 +9422,8 @@ function lintIdToMessage(id, info) {
9393
9422
  const written = info.value !== undefined ? `${info.name}=${JSON.stringify(info.value)}` : info.name;
9394
9423
  return `'${written}' on <x> looks like a directive but is actually an x op/attr written with a leading '@'`;
9395
9424
  }
9425
+ case "MAYBE_ADD_AT_PREFIX":
9426
+ return `'${info.name}' on <${(info.tag ?? "").toLowerCase()}> is a plain attribute, but '@${info.name}' is a directive — add the leading '@'`;
9396
9427
  case "BAD_VALUE":
9397
9428
  return `${badValueMessage(info)}${fmtTagSuffix(info)}`;
9398
9429
  case "UNSUPPORTED_EXPR_SYNTAX":
@@ -9403,6 +9434,8 @@ function lintIdToMessage(id, info) {
9403
9434
  return `Template string has no dynamic parts — use the string literal ${info.literal} instead${fmtOriginSuffix(info)}`;
9404
9435
  case "UNKNOWN_COMPONENT_SPEC_KEY":
9405
9436
  return `Unknown component spec key '${info.key}' — value will be ignored at runtime`;
9437
+ case "COMP_FIELD_BAD_SHAPE":
9438
+ return info.kind === "args-not-object" ? `Field '${info.fieldName}': in { component, args }, 'args' must be a plain object, got ${info.got}` : `Field '${info.fieldName}': in { component, args }, 'component' must be the component name as a string, got ${info.gotName ? `the ${info.gotName} class` : info.got}`;
9406
9439
  case "HTML_TAG_NAME_HAS_UPPERCASE":
9407
9440
  return `Tag <${info.raw}> will be lowercased to <${info.lowercased}>${fmtLocationSuffix(info)}`;
9408
9441
  case "HTML_SVG_TAG_WILL_LOWERCASE":
@@ -11622,6 +11655,7 @@ export {
11622
11655
  METHOD_VAL_NOT_DEFINED,
11623
11656
  METHOD_VAL_IS_FIELD,
11624
11657
  MAYBE_DROP_AT_PREFIX,
11658
+ MAYBE_ADD_AT_PREFIX,
11625
11659
  LintReport,
11626
11660
  LintParseContext,
11627
11661
  LintFinding,