@wcstack/lint 2.6.0 → 3.0.0

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.
Files changed (2) hide show
  1. package/dist/cli.cjs +233 -864
  2. package/package.json +1 -1
package/dist/cli.cjs CHANGED
@@ -16,7 +16,7 @@ var __copyProps = (to, from, except, desc) => {
16
16
  }
17
17
  return to;
18
18
  };
19
- var __toCommonJS = (mod3) => __copyProps(__defProp({}, "__esModule", { value: true }), mod3);
19
+ var __toCommonJS = (mod2) => __copyProps(__defProp({}, "__esModule", { value: true }), mod2);
20
20
 
21
21
  // src/cli.ts
22
22
  var cli_exports = {};
@@ -187,9 +187,10 @@ var WcsDiagnosticCode = {
187
187
  RecursionDeclarationInvalid: "wcs/recursion-declaration-invalid",
188
188
  TypeAnnotation: "wcs/type-annotation",
189
189
  TemplateSyntax: "wcs/template-syntax",
190
- // @wcstack/state 3.0 が拒否する(または読み方を変える)書き方の予告(info)。判定はランタイムの
191
- // [wcs/v3-migration] と同じ正本(@wcstack/state/parser findV3MigrationIssues)。2.x 系だけの code。
192
- V3Migration: "wcs/v3-migration",
190
+ // ランタイムの正本パーサが [wcs/binding-syntax] で拒否する書き方(@wcstack/state 3.0 の文法の
191
+ // 厳格化: 閉じていない引用符・2 つ目の '#'・else: の値・構造ディレクティブの修飾子・空のフィルタ)。
192
+ // 判定は正本パーサに委ねる(service/bindingSyntaxValidator.ts)。
193
+ BindingSyntax: "wcs/binding-syntax",
193
194
  // --- <wcs-state> script: array reactivity hazards ---
194
195
  // 配列破壊的メソッド呼び出し(push 等 9 種)。Proxy を素通りしリアクティブ更新されない。
195
196
  // 同一参照の自己再代入でも要素の追加・削除は反映されない(docs/array-mutation-diagnostic-design.md §3)。
@@ -263,22 +264,15 @@ function valueMustBeDate(fnName) {
263
264
  function valueMustBeArray(fnName) {
264
265
  raiseError(`filter ${fnName} requires an array value`);
265
266
  }
266
- var warned = /* @__PURE__ */ new Set();
267
- function warnV3Migration(message) {
268
- if (warned.has(message)) {
269
- return;
270
- }
271
- warned.add(message);
272
- console.warn(`[@wcstack/state] [wcs/v3-migration] ${message} See "Preparing for 3.0" in the @wcstack/state README.`);
273
- }
274
267
  function validateNumberString(value) {
275
268
  if (!value || isNaN(Number(value))) {
276
269
  return false;
277
270
  }
278
271
  return true;
279
272
  }
280
- var eq = (options) => {
273
+ var eq = (options, literals) => {
281
274
  const opt = options?.[0] ?? optionsRequired("eq");
275
+ const literal2 = literals !== void 0 && literals.length > 0 ? literals[0] : opt;
282
276
  return (value) => {
283
277
  if (typeof value === "number") {
284
278
  if (!validateNumberString(opt)) {
@@ -289,11 +283,12 @@ var eq = (options) => {
289
283
  if (typeof value === "string") {
290
284
  return value === opt;
291
285
  }
292
- return value === opt;
286
+ return value === literal2;
293
287
  };
294
288
  };
295
- var ne = (options) => {
289
+ var ne = (options, literals) => {
296
290
  const opt = options?.[0] ?? optionsRequired("ne");
291
+ const literal2 = literals !== void 0 && literals.length > 0 ? literals[0] : opt;
297
292
  return (value) => {
298
293
  if (typeof value === "number") {
299
294
  if (!validateNumberString(opt)) {
@@ -304,7 +299,7 @@ var ne = (options) => {
304
299
  if (typeof value === "string") {
305
300
  return value !== opt;
306
301
  }
307
- return value !== opt;
302
+ return value !== literal2;
308
303
  };
309
304
  };
310
305
  var not = (_options) => {
@@ -697,29 +692,18 @@ var hms = (options) => {
697
692
  return `${hours}${opt}${minutes}${opt}${seconds}`;
698
693
  };
699
694
  };
700
- function warnBigIntZero(fnName, value) {
701
- if (value === 0n) {
702
- warnV3Migration(`"${fnName}" got 0n: 3.0 treats it as falsy.`);
703
- }
704
- }
705
695
  var falsy = (_options) => {
706
- return (value) => {
707
- warnBigIntZero("falsy", value);
708
- return value === false || value === null || value === void 0 || value === 0 || value === "" || Number.isNaN(value);
709
- };
696
+ return (value) => !value;
710
697
  };
711
698
  var truthy = (_options) => {
712
- return (value) => {
713
- warnBigIntZero("truthy", value);
714
- return value !== false && value !== null && value !== void 0 && value !== 0 && value !== "" && !Number.isNaN(value);
715
- };
699
+ return (value) => !!value;
716
700
  };
717
- var defaults = (options) => {
701
+ var defaults = (options, literals) => {
718
702
  const opt = options?.[0] ?? optionsRequired("defaults");
703
+ const fallback = literals !== void 0 && literals.length > 0 ? literals[0] : opt;
719
704
  return (value) => {
720
- warnBigIntZero("defaults", value);
721
- if (value === false || value === null || value === void 0 || value === 0 || value === "" || Number.isNaN(value)) {
722
- return opt;
705
+ if (!value) {
706
+ return fallback;
723
707
  }
724
708
  return value;
725
709
  };
@@ -1034,11 +1018,11 @@ function foldSuffixIndexes(suffix) {
1034
1018
  }
1035
1019
  function foldRecursion(spec, path) {
1036
1020
  if (!path.startsWith(spec.anchor)) return null;
1037
- const unit3 = "." + spec.repeat;
1021
+ const unit2 = "." + spec.repeat;
1038
1022
  let cursor = spec.anchor.length;
1039
1023
  let depth = 0;
1040
- while (path.startsWith(unit3, cursor)) {
1041
- cursor += unit3.length;
1024
+ while (path.startsWith(unit2, cursor)) {
1025
+ cursor += unit2.length;
1042
1026
  depth++;
1043
1027
  }
1044
1028
  if (cursor !== path.length && path.charCodeAt(cursor) !== 46) return null;
@@ -1048,9 +1032,9 @@ function matchesRecursion(specs, path, has) {
1048
1032
  for (const spec of specs) {
1049
1033
  const folded = foldRecursion(spec, path);
1050
1034
  if (folded === null) continue;
1051
- const unit3 = "." + spec.repeat;
1035
+ const unit2 = "." + spec.repeat;
1052
1036
  for (let depth = folded.depth; depth >= 0; depth--) {
1053
- const rest = unit3.repeat(folded.depth - depth) + folded.rest;
1037
+ const rest = unit2.repeat(folded.depth - depth) + folded.rest;
1054
1038
  if (has(spec.anchor + rest)) return true;
1055
1039
  if (has(spec.recursiveAnchor + rest)) return true;
1056
1040
  for (let dot = rest.lastIndexOf("."); dot > 0; dot = rest.lastIndexOf(".", dot - 1)) {
@@ -1064,10 +1048,10 @@ function owningGetterSuffix(spec, getterSuffixes, path) {
1064
1048
  const pattern = indexSegmentsToWildcard(path);
1065
1049
  const folded = foldRecursion(spec, pattern);
1066
1050
  if (folded === null) return null;
1067
- const unit3 = "." + spec.repeat;
1051
+ const unit2 = "." + spec.repeat;
1068
1052
  for (const suffix of getterSuffixes) {
1069
1053
  for (let depth = folded.depth; depth >= 0; depth--) {
1070
- const expansion = spec.anchor + unit3.repeat(depth) + suffix;
1054
+ const expansion = spec.anchor + unit2.repeat(depth) + suffix;
1071
1055
  if (pattern === expansion || pattern.startsWith(expansion + ".")) return suffix;
1072
1056
  }
1073
1057
  }
@@ -1079,10 +1063,10 @@ function indexSegmentsToWildcard(path) {
1079
1063
  function concreteExpansionSuffix(spec, getterSuffixes, key) {
1080
1064
  const folded = foldRecursion(spec, key);
1081
1065
  if (folded === null) return null;
1082
- const unit3 = "." + spec.repeat;
1066
+ const unit2 = "." + spec.repeat;
1083
1067
  for (const suffix of getterSuffixes) {
1084
1068
  for (let depth = folded.depth; depth >= 0; depth--) {
1085
- if (key === spec.anchor + unit3.repeat(depth) + suffix) return suffix;
1069
+ if (key === spec.anchor + unit2.repeat(depth) + suffix) return suffix;
1086
1070
  }
1087
1071
  }
1088
1072
  return null;
@@ -1114,9 +1098,9 @@ function impliedStructurePaths(spec) {
1114
1098
  return out;
1115
1099
  }
1116
1100
  function structuralWriteTarget(spec, suffix) {
1117
- const unit3 = "." + spec.repeat;
1101
+ const unit2 = "." + spec.repeat;
1118
1102
  let rest = suffix;
1119
- while (rest.startsWith(unit3)) rest = rest.slice(unit3.length);
1103
+ while (rest.startsWith(unit2)) rest = rest.slice(unit2.length);
1120
1104
  if (rest.length === 0) return "node";
1121
1105
  if (rest === "." + spec.repeatList + ".length") return "length";
1122
1106
  const segments = spec.repeatList.split(".");
@@ -1126,15 +1110,15 @@ function structuralWriteTarget(spec, suffix) {
1126
1110
  return null;
1127
1111
  }
1128
1112
  function sameFamily(spec, a, b) {
1129
- const unit3 = "." + spec.repeat;
1113
+ const unit2 = "." + spec.repeat;
1130
1114
  const shorter = a.length <= b.length ? a : b;
1131
1115
  const longer = a.length <= b.length ? b : a;
1132
1116
  if (!longer.endsWith(shorter)) return false;
1133
1117
  const gap = longer.slice(0, longer.length - shorter.length);
1134
1118
  if (gap.length === 0) return true;
1135
- if (gap.length % unit3.length !== 0) return false;
1136
- for (let cursor = 0; cursor < gap.length; cursor += unit3.length) {
1137
- if (!gap.startsWith(unit3, cursor)) return false;
1119
+ if (gap.length % unit2.length !== 0) return false;
1120
+ for (let cursor = 0; cursor < gap.length; cursor += unit2.length) {
1121
+ if (!gap.startsWith(unit2, cursor)) return false;
1138
1122
  }
1139
1123
  return true;
1140
1124
  }
@@ -2324,8 +2308,8 @@ function matchOpenTag(html, pos, tagName) {
2324
2308
  const nameStart = pos + 1;
2325
2309
  const nameEnd = nameStart + tagName.length;
2326
2310
  if (nameEnd > html.length) return null;
2327
- const slice3 = html.slice(nameStart, nameEnd);
2328
- if (slice3.toLowerCase() !== tagName.toLowerCase()) return null;
2311
+ const slice2 = html.slice(nameStart, nameEnd);
2312
+ if (slice2.toLowerCase() !== tagName.toLowerCase()) return null;
2329
2313
  const charAfter = html[nameEnd];
2330
2314
  if (charAfter !== ">" && charAfter !== " " && charAfter !== " " && charAfter !== "\n" && charAfter !== "\r" && charAfter !== "/") {
2331
2315
  return null;
@@ -2575,8 +2559,8 @@ function getForTemplateDepthAt(html, openPos, offset2, bindAttrName) {
2575
2559
  }
2576
2560
 
2577
2561
  // src/core/messages.ts
2578
- function resolveLocale(locale3) {
2579
- if (locale3 === void 0 || locale3 === "" || /^ja\b|^ja[-_]/i.test(locale3) || locale3.toLowerCase() === "ja") return "ja";
2562
+ function resolveLocale(locale2) {
2563
+ if (locale2 === void 0 || locale2 === "" || /^ja\b|^ja[-_]/i.test(locale2) || locale2.toLowerCase() === "ja") return "ja";
2580
2564
  return "en";
2581
2565
  }
2582
2566
  var JA_EXPECTED_LABEL = {
@@ -2587,8 +2571,8 @@ var JA_EXPECTED_LABEL = {
2587
2571
  var ja = {
2588
2572
  spreadFilterNotAllowed: () => `\u30B9\u30D7\u30EC\u30C3\u30C9\u306E\u30BF\u30FC\u30B2\u30C3\u30C8\u306B\u30D5\u30A3\u30EB\u30BF\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093`,
2589
2573
  spreadTargetRequired: () => `\u30B9\u30D7\u30EC\u30C3\u30C9\u306B\u306F\u30BF\u30FC\u30B2\u30C3\u30C8\u30D1\u30B9\u304C\u5FC5\u8981\u3067\u3059`,
2590
- v3Migration: (detail) => `3.0 \u3078\u306E\u6E96\u5099\uFF082.x \u3067\u306F\u3053\u306E\u307E\u307E\u52D5\u304D\u307E\u3059\uFF09: ${detail}`,
2591
2574
  structuralMustBeSingle: (d) => `'${d}' \u30D0\u30A4\u30F3\u30C7\u30A3\u30F3\u30B0\u306F\u5358\u72EC\u3067\u6307\u5B9A\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\uFF08';' \u3067\u4ED6\u306E\u30D0\u30A4\u30F3\u30C7\u30A3\u30F3\u30B0\u3068\u4F75\u8A18\u3067\u304D\u307E\u305B\u3093\u3002\u30E9\u30F3\u30BF\u30A4\u30E0\u306F\u8AAD\u307F\u8FBC\u307F\u6642\u306B throw \u3057\u307E\u3059\uFF09`,
2575
+ bindingSyntax: (detail) => `\u30D0\u30A4\u30F3\u30C7\u30A3\u30F3\u30B0\u306E\u69CB\u6587\u30A8\u30E9\u30FC\uFF08\u30E9\u30F3\u30BF\u30A4\u30E0\u306F\u8AAD\u307F\u8FBC\u307F\u6642\u306B throw \u3057\u307E\u3059\uFF09: ${detail}`,
2592
2576
  eventTokenUndeclared: (t) => `\u30A4\u30D9\u30F3\u30C8\u30C8\u30FC\u30AF\u30F3 "${t}" \u306F $eventTokens \u306B\u5BA3\u8A00\u3055\u308C\u3066\u3044\u307E\u305B\u3093`,
2593
2577
  commandRhsFormat: () => `command \u30D0\u30A4\u30F3\u30C7\u30A3\u30F3\u30B0\u306E\u53F3\u8FBA\u306B\u306F $command.<name>\uFF08$commandTokens \u3067\u5BA3\u8A00\uFF09\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044`,
2594
2578
  commandTokenUndeclared: (t) => `\u30B3\u30DE\u30F3\u30C9\u30C8\u30FC\u30AF\u30F3 "${t}" \u306F $commandTokens \u306B\u5BA3\u8A00\u3055\u308C\u3066\u3044\u307E\u305B\u3093`,
@@ -2776,8 +2760,8 @@ var EN_EXPECTED_LABEL = {
2776
2760
  var en = {
2777
2761
  spreadFilterNotAllowed: () => `Filters cannot be applied to a spread target`,
2778
2762
  spreadTargetRequired: () => `Spread requires a target path`,
2779
- v3Migration: (detail) => `Preparing for 3.0 (this still runs on 2.x): ${detail}`,
2780
2763
  structuralMustBeSingle: (d) => `'${d}' must be the only binding in this attribute (it cannot be combined with ';'; the runtime throws at load time)`,
2764
+ bindingSyntax: (detail) => `Binding syntax error (the runtime throws at load time): ${detail}`,
2781
2765
  eventTokenUndeclared: (t) => `Event token "${t}" is not declared in $eventTokens`,
2782
2766
  commandRhsFormat: () => `The right side of a command binding must be $command.<name> (declared in $commandTokens)`,
2783
2767
  commandTokenUndeclared: (t) => `Command token "${t}" is not declared in $commandTokens`,
@@ -2958,8 +2942,8 @@ var en = {
2958
2942
  recursionInMountedComponent: (subject) => `${subject} is not run by a mounted component (bind-component); the runtime warns with wcs/mount-dollar-declaration and drops it. Declare $recursion and "**" getters on the root state \u2014 the anchor path is resolved against the root tree`
2959
2943
  };
2960
2944
  var CATALOGS = { ja, en };
2961
- function getMessages(locale3) {
2962
- return CATALOGS[resolveLocale(locale3)];
2945
+ function getMessages(locale2) {
2946
+ return CATALOGS[resolveLocale(locale2)];
2963
2947
  }
2964
2948
 
2965
2949
  // src/core/sidecar/schemaSubset.ts
@@ -3156,9 +3140,9 @@ function escape(key) {
3156
3140
 
3157
3141
  // src/service/bindingValidator.ts
3158
3142
  var filterMap = new Map(BUILTIN_FILTERS.map((f) => [f.name, f]));
3159
- function validateBindings(html, attrName, stateTagName = "wcs-state", locale3, fileReader, applicationSchema) {
3143
+ function validateBindings(html, attrName, stateTagName = "wcs-state", locale2, fileReader, applicationSchema) {
3160
3144
  const diagnostics = [];
3161
- const msgs = getMessages(locale3);
3145
+ const msgs = getMessages(locale2);
3162
3146
  const statePaths = mergeSchemaCandidates(getStatePathsFromHtml(html, stateTagName, fileReader), applicationSchema);
3163
3147
  const attrs = findAllBindAttributes(html, attrName);
3164
3148
  let structuralTemplates = null;
@@ -3715,8 +3699,8 @@ function isLiteral(value) {
3715
3699
  }
3716
3700
 
3717
3701
  // src/service/stateTypeValidator.ts
3718
- function validateStateTypes(html, stateTagName = "wcs-state", locale3) {
3719
- const msgs = getMessages(locale3);
3702
+ function validateStateTypes(html, stateTagName = "wcs-state", locale2) {
3703
+ const msgs = getMessages(locale2);
3720
3704
  const blocks = parseWcsScriptBlocks(html, stateTagName);
3721
3705
  const diagnostics = [];
3722
3706
  for (const block of blocks) {
@@ -3843,8 +3827,8 @@ function isApiRoot(root) {
3843
3827
  // src/service/nestedAssignValidator.ts
3844
3828
  var NESTED_ASSIGN = new RegExp(`${ROOT_DOT}(${CHAIN_ONE_PLUS})${ASSIGN_TAIL}`, "g");
3845
3829
  var PRE_NESTED_INCDEC = new RegExp(`${PRE_INCDEC}${ROOT_DOT}(${CHAIN_ONE_PLUS})`, "g");
3846
- function validateNestedAssigns(html, stateTagName = "wcs-state", locale3) {
3847
- const msgs = getMessages(locale3);
3830
+ function validateNestedAssigns(html, stateTagName = "wcs-state", locale2) {
3831
+ const msgs = getMessages(locale2);
3848
3832
  const blocks = parseWcsScriptBlocks(html, stateTagName);
3849
3833
  const diagnostics = [];
3850
3834
  for (const block of blocks) {
@@ -3895,8 +3879,8 @@ var PRE_BRACKET_INDEX = new RegExp(`${PRE_INCDEC}${ROOT_BRACKET}(${BRACKETS_ONLY
3895
3879
  function toAccessor(path) {
3896
3880
  return /^[A-Za-z_]\w*$/.test(path) ? `this.${path}` : `this["${path}"]`;
3897
3881
  }
3898
- function validateArrayMutations(html, stateTagName = "wcs-state", locale3) {
3899
- const msgs = getMessages(locale3);
3882
+ function validateArrayMutations(html, stateTagName = "wcs-state", locale2) {
3883
+ const msgs = getMessages(locale2);
3900
3884
  const blocks = parseWcsScriptBlocks(html, stateTagName);
3901
3885
  const diagnostics = [];
3902
3886
  for (const block of blocks) {
@@ -4006,9 +3990,9 @@ function isInsideTag(html, offset2, tagName) {
4006
3990
  }
4007
3991
 
4008
3992
  // src/service/templateSyntaxValidator.ts
4009
- function validateTemplateSyntax(html, stateTagName, bindAttrName = "data-wcs", locale3, fileReader, applicationSchema) {
3993
+ function validateTemplateSyntax(html, stateTagName, bindAttrName = "data-wcs", locale2, fileReader, applicationSchema) {
4010
3994
  const diagnostics = [];
4011
- const msgs = getMessages(locale3);
3995
+ const msgs = getMessages(locale2);
4012
3996
  const allPaths = mergeSchemaCandidates(getStatePathsFromHtml(html, stateTagName, fileReader), applicationSchema);
4013
3997
  const defaultSchema = applicationSchema;
4014
3998
  const missingVerdict = (path, displayPath, pathSet2, scoped) => {
@@ -4274,43 +4258,6 @@ var PathInfo = class {
4274
4258
  this.wildcardCount = wildcardCount;
4275
4259
  }
4276
4260
  };
4277
- function editDistance(a, b, max) {
4278
- if (Math.abs(a.length - b.length) > max) {
4279
- return max + 1;
4280
- }
4281
- const prev = new Array(b.length + 1);
4282
- const curr = new Array(b.length + 1);
4283
- for (let j = 0; j <= b.length; j++) {
4284
- prev[j] = j;
4285
- }
4286
- for (let i = 1; i <= a.length; i++) {
4287
- curr[0] = i;
4288
- for (let j = 1; j <= b.length; j++) {
4289
- const cost = a[i - 1] === b[j - 1] ? 0 : 1;
4290
- curr[j] = Math.min(prev[j] + 1, curr[j - 1] + 1, prev[j - 1] + cost);
4291
- }
4292
- for (let j = 0; j <= b.length; j++) {
4293
- prev[j] = curr[j];
4294
- }
4295
- }
4296
- return prev[b.length];
4297
- }
4298
- function didYouMean(input, candidates) {
4299
- if (input.length === 0) {
4300
- return "";
4301
- }
4302
- const folded = input.toLowerCase();
4303
- let best = null;
4304
- let bestDistance = 3;
4305
- for (const candidate of candidates) {
4306
- const distance = editDistance(folded, candidate.toLowerCase(), 2);
4307
- if (distance < bestDistance) {
4308
- best = candidate;
4309
- bestDistance = distance;
4310
- }
4311
- }
4312
- return best !== null ? ` Did you mean "${best}"?` : "";
4313
- }
4314
4261
  var LINT_HINT = " Validate statically: npx @wcstack/lint <file>.";
4315
4262
  var STRUCTURAL_BINDING_TYPE_SET2 = /* @__PURE__ */ new Set([
4316
4263
  "if",
@@ -4318,660 +4265,10 @@ var STRUCTURAL_BINDING_TYPE_SET2 = /* @__PURE__ */ new Set([
4318
4265
  "else",
4319
4266
  "for"
4320
4267
  ]);
4321
- var _config2 = {
4322
- locale: "en"
4323
- };
4324
- var config2 = _config2;
4325
- function optionsRequired2(fnName) {
4326
- raiseError2(`filter ${fnName} requires at least one option`);
4327
- }
4328
- function optionMustBeNumber2(fnName) {
4329
- raiseError2(`filter ${fnName} requires a number as option`);
4330
- }
4331
- function valueMustBeNumber2(fnName) {
4332
- raiseError2(`filter ${fnName} requires a number value`);
4333
- }
4334
- function valueMustBeBoolean2(fnName) {
4335
- raiseError2(`filter ${fnName} requires a boolean value`);
4336
- }
4337
- function valueMustBeDate2(fnName) {
4338
- raiseError2(`filter ${fnName} requires a date value`);
4339
- }
4340
- function valueMustBeArray2(fnName) {
4341
- raiseError2(`filter ${fnName} requires an array value`);
4342
- }
4343
- var NO_ARGS = /* @__PURE__ */ new Set([
4344
- "not",
4345
- "abs",
4346
- "uc",
4347
- "lc",
4348
- "cap",
4349
- "trim",
4350
- "rev",
4351
- "int",
4352
- "float",
4353
- "date",
4354
- "time",
4355
- "datetime",
4356
- "falsy",
4357
- "truthy",
4358
- "boolean",
4359
- "number",
4360
- "string",
4361
- "null"
4362
- ]);
4363
- var TWO_ARGS = /* @__PURE__ */ new Set(["clamp", "slice", "substr", "pad", "truncate"]);
4364
- function maxFilterArgs(name) {
4365
- return NO_ARGS.has(name) ? 0 : TWO_ARGS.has(name) ? 2 : 1;
4366
- }
4367
- var STRUCTURAL_KEYWORDS = /* @__PURE__ */ new Set(["for", "if", "elseif", "else", "..."]);
4368
- var TYPED_LITERAL = /(?:^|\|)\s*(eq|ne|defaults)\s*\(\s*(true|false|null)\s*\)/g;
4369
- function hasUnterminatedQuote(text) {
4370
- let quote = null;
4371
- for (let i = 0; i < text.length; i++) {
4372
- const c = text[i];
4373
- if (quote !== null) {
4374
- if (c === quote)
4375
- quote = null;
4376
- } else if (c === "'" || c === '"') {
4377
- quote = c;
4378
- }
4379
- }
4380
- return quote !== null;
4381
- }
4382
- function checkStatePart(text, parsed, issues) {
4383
- if (hasUnterminatedQuote(text)) {
4384
- issues.push(`"${text}": 3.0 rejects the unterminated quote.`);
4385
- }
4386
- for (const [, fnName, literal2] of text.matchAll(TYPED_LITERAL)) {
4387
- issues.push(`"${fnName}(${literal2})": 3.0 reads an unquoted ${literal2} as a ${literal2 === "null" ? "null" : "boolean"}, not the text. Write ${fnName}('${literal2}') to keep the text.`);
4388
- }
4389
- if (parsed !== null) {
4390
- issues.push(...findFilterArityIssues([parsed]));
4391
- }
4392
- }
4393
- function findFilterArityIssues(results) {
4394
- const issues = [];
4395
- for (const result of results) {
4396
- for (const filter of [...result.inFilters, ...result.outFilters]) {
4397
- const max = maxFilterArgs(filter.filterName);
4398
- if (filter.args.length > max) {
4399
- issues.push(`"${filter.filterName}" takes at most ${max} argument(s); 3.0 rejects more.`);
4400
- }
4401
- }
4402
- }
4403
- return issues;
4404
- }
4405
- function findV3MigrationIssues(expr, parsed = null) {
4406
- const issues = [];
4407
- const colon = expr.indexOf(":");
4408
- if (colon === -1)
4409
- return issues;
4410
- const propPart = expr.slice(0, colon).trim();
4411
- const modifierParts = propPart.split("#");
4412
- const keyword = modifierParts[0].split("|")[0].trim();
4413
- if (modifierParts.length > 2) {
4414
- issues.push(`"${propPart}": 3.0 rejects a second "#". Write "${modifierParts[0].trim()}#${modifierParts.slice(1).map((m) => m.trim()).join(",")}".`);
4415
- }
4416
- if (keyword === "else" && expr.slice(colon + 1).trim().length > 0) {
4417
- issues.push(`"${expr}": 3.0 rejects a value after "else:".`);
4418
- }
4419
- if (STRUCTURAL_KEYWORDS.has(keyword) && keyword !== propPart) {
4420
- issues.push(`"${propPart}": 3.0 rejects modifiers and filters on "${keyword}". Write "${keyword}:".`);
4421
- }
4422
- if ((keyword === "radio" || keyword === "checkbox") && keyword !== propPart) {
4423
- issues.push(`"${propPart}": 3.0 keeps this a ${keyword} binding that honours the modifiers (2.x binds a property named "${keyword}").`);
4424
- }
4425
- checkStatePart(expr.slice(colon + 1).trim(), parsed, issues);
4426
- return issues;
4427
- }
4428
- function findEmbeddedV3MigrationIssues(expression, parsed = null) {
4429
- const issues = [];
4430
- checkStatePart(expression, parsed, issues);
4431
- return issues;
4432
- }
4433
- var warned2 = /* @__PURE__ */ new Set();
4434
- function warnV3Migration2(message) {
4435
- if (warned2.has(message)) {
4436
- return;
4437
- }
4438
- warned2.add(message);
4439
- console.warn(`[@wcstack/state] [wcs/v3-migration] ${message} See "Preparing for 3.0" in the @wcstack/state README.`);
4440
- }
4441
- function validateNumberString2(value) {
4442
- if (!value || isNaN(Number(value))) {
4443
- return false;
4444
- }
4445
- return true;
4446
- }
4447
- var eq2 = (options) => {
4448
- const opt = options?.[0] ?? optionsRequired2("eq");
4449
- return (value) => {
4450
- if (typeof value === "number") {
4451
- if (!validateNumberString2(opt)) {
4452
- optionMustBeNumber2("eq");
4453
- }
4454
- return value === Number(opt);
4455
- }
4456
- if (typeof value === "string") {
4457
- return value === opt;
4458
- }
4459
- return value === opt;
4460
- };
4461
- };
4462
- var ne2 = (options) => {
4463
- const opt = options?.[0] ?? optionsRequired2("ne");
4464
- return (value) => {
4465
- if (typeof value === "number") {
4466
- if (!validateNumberString2(opt)) {
4467
- optionMustBeNumber2("ne");
4468
- }
4469
- return value !== Number(opt);
4470
- }
4471
- if (typeof value === "string") {
4472
- return value !== opt;
4473
- }
4474
- return value !== opt;
4475
- };
4476
- };
4477
- var not2 = (_options) => {
4478
- return (value) => {
4479
- if (typeof value !== "boolean") {
4480
- valueMustBeBoolean2("not");
4481
- }
4482
- return !value;
4483
- };
4484
- };
4485
- var lt2 = (options) => {
4486
- const opt = options?.[0] ?? optionsRequired2("lt");
4487
- if (!validateNumberString2(opt)) {
4488
- optionMustBeNumber2("lt");
4489
- }
4490
- return (value) => {
4491
- if (typeof value !== "number") {
4492
- valueMustBeNumber2("lt");
4493
- }
4494
- return value < Number(opt);
4495
- };
4496
- };
4497
- var le2 = (options) => {
4498
- const opt = options?.[0] ?? optionsRequired2("le");
4499
- if (!validateNumberString2(opt)) {
4500
- optionMustBeNumber2("le");
4501
- }
4502
- return (value) => {
4503
- if (typeof value !== "number") {
4504
- valueMustBeNumber2("le");
4505
- }
4506
- return value <= Number(opt);
4507
- };
4508
- };
4509
- var gt2 = (options) => {
4510
- const opt = options?.[0] ?? optionsRequired2("gt");
4511
- if (!validateNumberString2(opt)) {
4512
- optionMustBeNumber2("gt");
4513
- }
4514
- return (value) => {
4515
- if (typeof value !== "number") {
4516
- valueMustBeNumber2("gt");
4517
- }
4518
- return value > Number(opt);
4519
- };
4520
- };
4521
- var ge2 = (options) => {
4522
- const opt = options?.[0] ?? optionsRequired2("ge");
4523
- if (!validateNumberString2(opt)) {
4524
- optionMustBeNumber2("ge");
4525
- }
4526
- return (value) => {
4527
- if (typeof value !== "number") {
4528
- valueMustBeNumber2("ge");
4529
- }
4530
- return value >= Number(opt);
4531
- };
4532
- };
4533
- var inc2 = (options) => {
4534
- const opt = options?.[0] ?? optionsRequired2("inc");
4535
- if (!validateNumberString2(opt)) {
4536
- optionMustBeNumber2("inc");
4537
- }
4538
- return (value) => {
4539
- if (typeof value !== "number") {
4540
- valueMustBeNumber2("inc");
4541
- }
4542
- return value + Number(opt);
4543
- };
4544
- };
4545
- var dec2 = (options) => {
4546
- const opt = options?.[0] ?? optionsRequired2("dec");
4547
- if (!validateNumberString2(opt)) {
4548
- optionMustBeNumber2("dec");
4549
- }
4550
- return (value) => {
4551
- if (typeof value !== "number") {
4552
- valueMustBeNumber2("dec");
4553
- }
4554
- return value - Number(opt);
4555
- };
4556
- };
4557
- var mul2 = (options) => {
4558
- const opt = options?.[0] ?? optionsRequired2("mul");
4559
- if (!validateNumberString2(opt)) {
4560
- optionMustBeNumber2("mul");
4561
- }
4562
- return (value) => {
4563
- if (typeof value !== "number") {
4564
- valueMustBeNumber2("mul");
4565
- }
4566
- return value * Number(opt);
4567
- };
4568
- };
4569
- var div2 = (options) => {
4570
- const opt = options?.[0] ?? optionsRequired2("div");
4571
- if (!validateNumberString2(opt)) {
4572
- optionMustBeNumber2("div");
4573
- }
4574
- return (value) => {
4575
- if (typeof value !== "number") {
4576
- valueMustBeNumber2("div");
4577
- }
4578
- return value / Number(opt);
4579
- };
4580
- };
4581
- var mod2 = (options) => {
4582
- const opt = options?.[0] ?? optionsRequired2("mod");
4583
- if (!validateNumberString2(opt)) {
4584
- optionMustBeNumber2("mod");
4585
- }
4586
- return (value) => {
4587
- if (typeof value !== "number") {
4588
- valueMustBeNumber2("mod");
4589
- }
4590
- return value % Number(opt);
4591
- };
4592
- };
4593
- var abs2 = (_options) => {
4594
- return (value) => {
4595
- if (typeof value !== "number") {
4596
- valueMustBeNumber2("abs");
4597
- }
4598
- return Math.abs(value);
4599
- };
4600
- };
4601
- var clamp2 = (options) => {
4602
- const opt1 = options?.[0] ?? optionsRequired2("clamp");
4603
- if (!validateNumberString2(opt1)) {
4604
- optionMustBeNumber2("clamp");
4605
- }
4606
- const opt2 = options?.[1] ?? optionsRequired2("clamp");
4607
- if (!validateNumberString2(opt2)) {
4608
- optionMustBeNumber2("clamp");
4609
- }
4610
- const min = Number(opt1);
4611
- const max = Number(opt2);
4612
- return (value) => {
4613
- if (typeof value !== "number") {
4614
- valueMustBeNumber2("clamp");
4615
- }
4616
- return Math.min(Math.max(value, min), max);
4617
- };
4618
- };
4619
- var fix2 = (options) => {
4620
- const opt = options?.[0] ?? "0";
4621
- if (!validateNumberString2(opt)) {
4622
- optionMustBeNumber2("fix");
4623
- }
4624
- return (value) => {
4625
- if (typeof value !== "number") {
4626
- valueMustBeNumber2("fix");
4627
- }
4628
- return value.toFixed(Number(opt));
4629
- };
4630
- };
4631
- var locale2 = (options) => {
4632
- const explicit = options?.[0];
4633
- return (value) => {
4634
- if (typeof value !== "number") {
4635
- valueMustBeNumber2("locale");
4636
- }
4637
- return value.toLocaleString(explicit ?? config2.locale);
4638
- };
4639
- };
4640
- var uc2 = (_options) => {
4641
- return (value) => {
4642
- return String(value).toUpperCase();
4643
- };
4644
- };
4645
- var lc2 = (_options) => {
4646
- return (value) => {
4647
- return String(value).toLowerCase();
4648
- };
4649
- };
4650
- var cap2 = (_options) => {
4651
- return (value) => {
4652
- const v = String(value);
4653
- if (v.length === 0) {
4654
- return v;
4655
- }
4656
- if (v.length === 1) {
4657
- return v.toUpperCase();
4658
- }
4659
- return v.charAt(0).toUpperCase() + v.slice(1);
4660
- };
4661
- };
4662
- var trim2 = (_options) => {
4663
- return (value) => {
4664
- return String(value).trim();
4665
- };
4666
- };
4667
- var slice2 = (options) => {
4668
- const numberedOpts = [];
4669
- const opt1 = options?.[0] ?? optionsRequired2("slice");
4670
- if (!validateNumberString2(opt1)) {
4671
- optionMustBeNumber2("slice");
4672
- }
4673
- numberedOpts.push(Number(opt1));
4674
- const opt2 = options?.[1];
4675
- if (typeof opt2 !== "undefined") {
4676
- if (!validateNumberString2(opt2)) {
4677
- optionMustBeNumber2("slice");
4678
- }
4679
- numberedOpts.push(Number(opt2));
4680
- }
4681
- return (value) => {
4682
- return String(value).slice(...numberedOpts);
4683
- };
4684
- };
4685
- var substr2 = (options) => {
4686
- const opt1 = options?.[0] ?? optionsRequired2("substr");
4687
- if (!validateNumberString2(opt1)) {
4688
- optionMustBeNumber2("substr");
4689
- }
4690
- const opt2 = options?.[1] ?? optionsRequired2("substr");
4691
- if (!validateNumberString2(opt2)) {
4692
- optionMustBeNumber2("substr");
4693
- }
4694
- return (value) => {
4695
- return String(value).substr(Number(opt1), Number(opt2));
4696
- };
4697
- };
4698
- var pad2 = (options) => {
4699
- const opt1 = options?.[0] ?? optionsRequired2("pad");
4700
- if (!validateNumberString2(opt1)) {
4701
- optionMustBeNumber2("pad");
4702
- }
4703
- const opt2 = options?.[1] ?? "0";
4704
- return (value) => {
4705
- return String(value).padStart(Number(opt1), opt2);
4706
- };
4707
- };
4708
- var rep2 = (options) => {
4709
- const opt = options?.[0] ?? optionsRequired2("rep");
4710
- if (!validateNumberString2(opt)) {
4711
- optionMustBeNumber2("rep");
4712
- }
4713
- return (value) => {
4714
- return String(value).repeat(Number(opt));
4715
- };
4716
- };
4717
- var rev2 = (_options) => {
4718
- return (value) => {
4719
- return String(value).split("").reverse().join("");
4720
- };
4721
- };
4722
- var int2 = (_options) => {
4723
- return (value) => {
4724
- return parseInt(String(value), 10);
4725
- };
4726
- };
4727
- var float2 = (_options) => {
4728
- return (value) => {
4729
- return parseFloat(String(value));
4730
- };
4731
- };
4732
- var round2 = (options) => {
4733
- const opt = options?.[0] ?? "0";
4734
- if (!validateNumberString2(opt)) {
4735
- optionMustBeNumber2("round");
4736
- }
4737
- return (value) => {
4738
- if (typeof value !== "number") {
4739
- valueMustBeNumber2("round");
4740
- }
4741
- const optValue = Math.pow(10, Number(opt));
4742
- return Math.round(value * optValue) / optValue;
4743
- };
4744
- };
4745
- var floor2 = (options) => {
4746
- const opt = options?.[0] ?? "0";
4747
- if (!validateNumberString2(opt)) {
4748
- optionMustBeNumber2("floor");
4749
- }
4750
- return (value) => {
4751
- if (typeof value !== "number") {
4752
- valueMustBeNumber2("floor");
4753
- }
4754
- const optValue = Math.pow(10, Number(opt));
4755
- return Math.floor(value * optValue) / optValue;
4756
- };
4757
- };
4758
- var ceil2 = (options) => {
4759
- const opt = options?.[0] ?? "0";
4760
- if (!validateNumberString2(opt)) {
4761
- optionMustBeNumber2("ceil");
4762
- }
4763
- return (value) => {
4764
- if (typeof value !== "number") {
4765
- valueMustBeNumber2("ceil");
4766
- }
4767
- const optValue = Math.pow(10, Number(opt));
4768
- return Math.ceil(value * optValue) / optValue;
4769
- };
4770
- };
4771
- var percent2 = (options) => {
4772
- const opt = options?.[0] ?? "0";
4773
- if (!validateNumberString2(opt)) {
4774
- optionMustBeNumber2("percent");
4775
- }
4776
- return (value) => {
4777
- if (typeof value !== "number") {
4778
- valueMustBeNumber2("percent");
4779
- }
4780
- return `${(value * 100).toFixed(Number(opt))}%`;
4781
- };
4782
- };
4783
- var unit2 = (options) => {
4784
- const opt = options?.[0] ?? optionsRequired2("unit");
4785
- return (value) => {
4786
- if (value === null || typeof value === "undefined") {
4787
- return value;
4788
- }
4789
- return String(value) + opt;
4790
- };
4791
- };
4792
- var join2 = (options) => {
4793
- const opt = options?.[0] ?? ", ";
4794
- return (value) => {
4795
- if (!Array.isArray(value)) {
4796
- valueMustBeArray2("join");
4797
- }
4798
- return value.join(opt);
4799
- };
4800
- };
4801
- var truncate2 = (options) => {
4802
- const opt1 = options?.[0] ?? optionsRequired2("truncate");
4803
- if (!validateNumberString2(opt1)) {
4804
- optionMustBeNumber2("truncate");
4805
- }
4806
- const maxLength = Number(opt1);
4807
- const suffix = options?.[1] ?? "\u2026";
4808
- return (value) => {
4809
- const v = String(value);
4810
- if (v.length <= maxLength) {
4811
- return v;
4812
- }
4813
- return v.slice(0, maxLength) + suffix;
4814
- };
4815
- };
4816
- var date2 = (options) => {
4817
- const explicit = options?.[0];
4818
- return (value) => {
4819
- if (!(value instanceof Date)) {
4820
- valueMustBeDate2("date");
4821
- }
4822
- return value.toLocaleDateString(explicit ?? config2.locale);
4823
- };
4824
- };
4825
- var time2 = (options) => {
4826
- const explicit = options?.[0];
4827
- return (value) => {
4828
- if (!(value instanceof Date)) {
4829
- valueMustBeDate2("time");
4830
- }
4831
- return value.toLocaleTimeString(explicit ?? config2.locale);
4832
- };
4833
- };
4834
- var datetime2 = (options) => {
4835
- const explicit = options?.[0];
4836
- return (value) => {
4837
- if (!(value instanceof Date)) {
4838
- valueMustBeDate2("datetime");
4839
- }
4840
- return value.toLocaleString(explicit ?? config2.locale);
4841
- };
4842
- };
4843
- var ymd2 = (options) => {
4844
- const opt = options?.[0] ?? "-";
4845
- return (value) => {
4846
- if (!(value instanceof Date)) {
4847
- valueMustBeDate2("ymd");
4848
- }
4849
- const year = value.getFullYear().toString();
4850
- const month = (value.getMonth() + 1).toString().padStart(2, "0");
4851
- const day = value.getDate().toString().padStart(2, "0");
4852
- return `${year}${opt}${month}${opt}${day}`;
4853
- };
4854
- };
4855
- var hms2 = (options) => {
4856
- const opt = options?.[0] ?? ":";
4857
- return (value) => {
4858
- if (!(value instanceof Date)) {
4859
- valueMustBeDate2("hms");
4860
- }
4861
- const hours = value.getHours().toString().padStart(2, "0");
4862
- const minutes = value.getMinutes().toString().padStart(2, "0");
4863
- const seconds = value.getSeconds().toString().padStart(2, "0");
4864
- return `${hours}${opt}${minutes}${opt}${seconds}`;
4865
- };
4866
- };
4867
- function warnBigIntZero2(fnName, value) {
4868
- if (value === 0n) {
4869
- warnV3Migration2(`"${fnName}" got 0n: 3.0 treats it as falsy.`);
4870
- }
4268
+ var resolvedByKey = /* @__PURE__ */ new Map();
4269
+ function clearFilterResolutionCache() {
4270
+ resolvedByKey.clear();
4871
4271
  }
4872
- var falsy2 = (_options) => {
4873
- return (value) => {
4874
- warnBigIntZero2("falsy", value);
4875
- return value === false || value === null || value === void 0 || value === 0 || value === "" || Number.isNaN(value);
4876
- };
4877
- };
4878
- var truthy2 = (_options) => {
4879
- return (value) => {
4880
- warnBigIntZero2("truthy", value);
4881
- return value !== false && value !== null && value !== void 0 && value !== 0 && value !== "" && !Number.isNaN(value);
4882
- };
4883
- };
4884
- var defaults2 = (options) => {
4885
- const opt = options?.[0] ?? optionsRequired2("defaults");
4886
- return (value) => {
4887
- warnBigIntZero2("defaults", value);
4888
- if (value === false || value === null || value === void 0 || value === 0 || value === "" || Number.isNaN(value)) {
4889
- return opt;
4890
- }
4891
- return value;
4892
- };
4893
- };
4894
- var boolean2 = (_options) => {
4895
- return (value) => {
4896
- return Boolean(value);
4897
- };
4898
- };
4899
- var number2 = (_options) => {
4900
- return (value) => {
4901
- return Number(value);
4902
- };
4903
- };
4904
- var string2 = (_options) => {
4905
- return (value) => {
4906
- return String(value);
4907
- };
4908
- };
4909
- var _null2 = (_options) => {
4910
- return (value) => {
4911
- return value === "" ? null : value;
4912
- };
4913
- };
4914
- var builtinFilters2 = {
4915
- "eq": eq2,
4916
- "ne": ne2,
4917
- "not": not2,
4918
- "lt": lt2,
4919
- "le": le2,
4920
- "gt": gt2,
4921
- "ge": ge2,
4922
- "inc": inc2,
4923
- "dec": dec2,
4924
- "mul": mul2,
4925
- "div": div2,
4926
- "mod": mod2,
4927
- "abs": abs2,
4928
- "clamp": clamp2,
4929
- "fix": fix2,
4930
- "locale": locale2,
4931
- "uc": uc2,
4932
- "lc": lc2,
4933
- "cap": cap2,
4934
- "trim": trim2,
4935
- "slice": slice2,
4936
- "substr": substr2,
4937
- "pad": pad2,
4938
- "rep": rep2,
4939
- "rev": rev2,
4940
- "truncate": truncate2,
4941
- "join": join2,
4942
- "int": int2,
4943
- "float": float2,
4944
- "round": round2,
4945
- "floor": floor2,
4946
- "ceil": ceil2,
4947
- "percent": percent2,
4948
- "unit": unit2,
4949
- "date": date2,
4950
- "time": time2,
4951
- "datetime": datetime2,
4952
- "ymd": ymd2,
4953
- "hms": hms2,
4954
- "falsy": falsy2,
4955
- "truthy": truthy2,
4956
- "defaults": defaults2,
4957
- "boolean": boolean2,
4958
- "number": number2,
4959
- "string": string2,
4960
- "null": _null2
4961
- };
4962
- var outputBuiltinFilters2 = builtinFilters2;
4963
- var inputBuiltinFilters = builtinFilters2;
4964
- var builtinFiltersByFilterIOType = {
4965
- "input": inputBuiltinFilters,
4966
- "output": outputBuiltinFilters2
4967
- };
4968
- var builtinFilterFn = (name, options) => (filters) => {
4969
- const filter = filters[name];
4970
- if (!filter) {
4971
- raiseError2(`[wcs/filter-unknown] filter not found: ${name}.${didYouMean(name, Object.keys(filters))}${LINT_HINT}`);
4972
- }
4973
- return filter(options);
4974
- };
4975
4272
  function finalizeArg(text, firstQuoteStart, lastQuoteEnd) {
4976
4273
  const startLimit = firstQuoteStart === -1 ? text.length : firstQuoteStart;
4977
4274
  let start = 0;
@@ -4985,15 +4282,30 @@ function finalizeArg(text, firstQuoteStart, lastQuoteEnd) {
4985
4282
  }
4986
4283
  return text.slice(start, end);
4987
4284
  }
4988
- function parseFilterArgs(argsText) {
4285
+ var NUMBER_LITERAL = /^[+-]?(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?$/;
4286
+ function toLiteral(text, quoted) {
4287
+ if (quoted)
4288
+ return text;
4289
+ if (text === "true")
4290
+ return true;
4291
+ if (text === "false")
4292
+ return false;
4293
+ if (text === "null")
4294
+ return null;
4295
+ return NUMBER_LITERAL.test(text) ? Number(text) : text;
4296
+ }
4297
+ function parseFilterArgsWithLiterals(argsText) {
4989
4298
  const args = [];
4299
+ const literals = [];
4990
4300
  let current2 = "";
4991
4301
  let inQuote = null;
4992
4302
  let hasQuote = false;
4993
4303
  let firstQuoteStart = -1;
4994
4304
  let lastQuoteEnd = -1;
4995
4305
  const flush = () => {
4996
- args.push(finalizeArg(current2, firstQuoteStart, lastQuoteEnd));
4306
+ const arg = finalizeArg(current2, firstQuoteStart, lastQuoteEnd);
4307
+ args.push(arg);
4308
+ literals.push(toLiteral(arg, hasQuote));
4997
4309
  current2 = "";
4998
4310
  hasQuote = false;
4999
4311
  firstQuoteStart = -1;
@@ -5020,19 +4332,21 @@ function parseFilterArgs(argsText) {
5020
4332
  current2 += char;
5021
4333
  }
5022
4334
  }
4335
+ if (inQuote !== null) {
4336
+ raiseError2(`[wcs/binding-syntax] unterminated ${inQuote} quote in the filter arguments "(${argsText})". Close the quote.${LINT_HINT}`);
4337
+ }
5023
4338
  const last = finalizeArg(current2, firstQuoteStart, lastQuoteEnd);
5024
4339
  if (last || hasQuote) {
5025
4340
  args.push(last);
4341
+ literals.push(toLiteral(last, hasQuote));
5026
4342
  }
5027
- return args;
4343
+ return { args, literals };
5028
4344
  }
5029
- var filterFnByKey = /* @__PURE__ */ new Map();
5030
4345
  function clearFilterFnCacheForTooling() {
5031
- filterFnByKey.clear();
4346
+ clearFilterResolutionCache();
5032
4347
  }
5033
- function parseFilters(filterTextList, filterIOType) {
5034
- const builtinFilters3 = builtinFiltersByFilterIOType[filterIOType];
5035
- const filters = filterTextList.map((filterText) => {
4348
+ function parseFilters(filterTextList, _filterIOType) {
4349
+ return filterTextList.map((filterText) => {
5036
4350
  const openParenIndex = filterText.indexOf("(");
5037
4351
  const closeParenIndex = filterText.lastIndexOf(")");
5038
4352
  if (openParenIndex !== -1 && closeParenIndex === -1) {
@@ -5041,45 +4355,59 @@ function parseFilters(filterTextList, filterIOType) {
5041
4355
  if (closeParenIndex !== -1 && openParenIndex === -1) {
5042
4356
  raiseError2(`Invalid filter format: missing opening parenthesis in "${filterText}"`);
5043
4357
  }
4358
+ const filterName = (openParenIndex === -1 ? filterText : filterText.substring(0, openParenIndex)).trim();
4359
+ if (filterName.length === 0) {
4360
+ raiseError2(`[wcs/binding-syntax] an empty filter in "${filterTextList.join("|")}" \u2014 remove the extra "|" or name the filter.${LINT_HINT}`);
4361
+ }
5044
4362
  if (openParenIndex === -1) {
5045
- const filterName = filterText.trim();
5046
- const filterKey = `${filterName}():${filterIOType}`;
5047
- let filterFn = filterFnByKey.get(filterKey);
5048
- if (typeof filterFn === "undefined") {
5049
- filterFn = builtinFilterFn(filterName, [])(builtinFilters3);
5050
- filterFnByKey.set(filterKey, filterFn);
5051
- }
5052
- return {
5053
- filterName,
5054
- args: [],
5055
- filterFn
5056
- };
5057
- } else {
5058
- const argsText = filterText.substring(openParenIndex + 1, closeParenIndex);
5059
- const filterName = filterText.substring(0, openParenIndex).trim();
5060
- const args = parseFilterArgs(argsText);
5061
- const filterKey = `${filterName}(${args.join(",")}):${filterIOType}`;
5062
- let filterFn = filterFnByKey.get(filterKey);
5063
- if (typeof filterFn === "undefined") {
5064
- filterFn = builtinFilterFn(filterName, args)(builtinFilters3);
5065
- filterFnByKey.set(filterKey, filterFn);
5066
- }
5067
- return {
5068
- filterName,
5069
- args,
5070
- filterFn
5071
- };
4363
+ return { filterName, args: [], literals: [] };
5072
4364
  }
4365
+ const argsText = filterText.substring(openParenIndex + 1, closeParenIndex);
4366
+ return { filterName, ...parseFilterArgsWithLiterals(argsText) };
5073
4367
  });
5074
- return filters;
5075
4368
  }
5076
4369
  var trimFn = (s) => s.trim();
4370
+ var isQuote = (c) => c === "'" || c === '"';
4371
+ function indexOfOutsideQuotes(text, char) {
4372
+ let quote = null;
4373
+ for (let i = 0; i < text.length; i++) {
4374
+ const c = text[i];
4375
+ if (quote !== null) {
4376
+ if (c === quote)
4377
+ quote = null;
4378
+ } else if (isQuote(c)) {
4379
+ quote = c;
4380
+ } else if (c === char) {
4381
+ return i;
4382
+ }
4383
+ }
4384
+ return -1;
4385
+ }
4386
+ function splitOutsideQuotes(text, separator) {
4387
+ const parts = [];
4388
+ let quote = null;
4389
+ let start = 0;
4390
+ for (let i = 0; i < text.length; i++) {
4391
+ const c = text[i];
4392
+ if (quote !== null) {
4393
+ if (c === quote)
4394
+ quote = null;
4395
+ } else if (isQuote(c)) {
4396
+ quote = c;
4397
+ } else if (c === separator) {
4398
+ parts.push(text.slice(start, i));
4399
+ start = i + 1;
4400
+ }
4401
+ }
4402
+ parts.push(text.slice(start));
4403
+ return parts;
4404
+ }
5077
4405
  var cacheFilterInfos$1 = /* @__PURE__ */ new Map();
5078
4406
  function clearPropPartCacheForTooling() {
5079
4407
  cacheFilterInfos$1.clear();
5080
4408
  }
5081
4409
  function parsePropPart(propPart) {
5082
- const pos = propPart.indexOf(FILTER_SEPARATOR2);
4410
+ const pos = indexOfOutsideQuotes(propPart, FILTER_SEPARATOR2);
5083
4411
  let propText = "";
5084
4412
  let filterTexts = [];
5085
4413
  let filtersText = "";
@@ -5090,14 +4418,18 @@ function parsePropPart(propPart) {
5090
4418
  if (cacheFilterInfos$1.has(filtersText)) {
5091
4419
  filters = cacheFilterInfos$1.get(filtersText);
5092
4420
  } else {
5093
- filterTexts = filtersText.split(FILTER_SEPARATOR2).map(trimFn);
5094
- filters = parseFilters(filterTexts, "input");
4421
+ filterTexts = splitOutsideQuotes(filtersText, FILTER_SEPARATOR2).map(trimFn);
4422
+ filters = parseFilters(filterTexts);
5095
4423
  cacheFilterInfos$1.set(filtersText, filters);
5096
4424
  }
5097
4425
  } else {
5098
4426
  propText = propPart.trim();
5099
4427
  }
5100
- const [propName, propModifiersText] = propText.split(MODIFIER_SEPARATOR2).map(trimFn);
4428
+ const modifierParts = propText.split(MODIFIER_SEPARATOR2).map(trimFn);
4429
+ if (modifierParts.length > 2) {
4430
+ raiseError2(`[wcs/binding-syntax] "${propText}": a binding takes one modifier list after a single "${MODIFIER_SEPARATOR2}" \u2014 write "${modifierParts[0]}${MODIFIER_SEPARATOR2}${modifierParts.slice(1).join(",")}".${LINT_HINT}`);
4431
+ }
4432
+ const [propName, propModifiersText] = modifierParts;
5101
4433
  const propSegments = propName.split(DELIMITER2).map(trimFn);
5102
4434
  const propModifiers = propModifiersText ? propModifiersText.split(",").map(trimFn) : [];
5103
4435
  return {
@@ -5112,7 +4444,7 @@ function clearStatePartCacheForTooling() {
5112
4444
  cacheFilterInfos.clear();
5113
4445
  }
5114
4446
  function parseStatePart(statePart) {
5115
- const pos = statePart.indexOf(FILTER_SEPARATOR2);
4447
+ const pos = indexOfOutsideQuotes(statePart, FILTER_SEPARATOR2);
5116
4448
  let stateAndPath = "";
5117
4449
  let filterTexts = [];
5118
4450
  let filtersText = "";
@@ -5123,8 +4455,8 @@ function parseStatePart(statePart) {
5123
4455
  if (cacheFilterInfos.has(filtersText)) {
5124
4456
  filters = cacheFilterInfos.get(filtersText);
5125
4457
  } else {
5126
- filterTexts = filtersText.split(FILTER_SEPARATOR2).map(trimFn);
5127
- filters = parseFilters(filterTexts, "output");
4458
+ filterTexts = splitOutsideQuotes(filtersText, FILTER_SEPARATOR2).map(trimFn);
4459
+ filters = parseFilters(filterTexts);
5128
4460
  cacheFilterInfos.set(filtersText, filters);
5129
4461
  }
5130
4462
  } else {
@@ -5141,8 +4473,12 @@ function parseStatePart(statePart) {
5141
4473
  outFilters: filters
5142
4474
  };
5143
4475
  }
4476
+ var KEYWORDS_WITHOUT_MODIFIERS = /* @__PURE__ */ new Set([ELSE_KEYWORD2, "if", "elseif", "for", SPREAD_PROP2]);
4477
+ function splitBindTexts(bindText) {
4478
+ return splitOutsideQuotes(bindText, BINDING_SEPARATOR2);
4479
+ }
5144
4480
  function parseBindTextsForElement(bindText) {
5145
- const [...bindTexts] = bindText.split(BINDING_SEPARATOR2).map(trimFn).filter((s) => s.length > 0);
4481
+ const [...bindTexts] = splitBindTexts(bindText).map(trimFn).filter((s) => s.length > 0);
5146
4482
  const results = bindTexts.map((bindText2) => {
5147
4483
  const separatorIndex = bindText2.indexOf(PROP_VALUE_SEPARATOR2);
5148
4484
  if (separatorIndex === -1) {
@@ -5150,7 +4486,14 @@ function parseBindTextsForElement(bindText) {
5150
4486
  }
5151
4487
  const propPart = bindText2.slice(0, separatorIndex).trim();
5152
4488
  const statePart = bindText2.slice(separatorIndex + 1).trim();
4489
+ const keyword = propPart.split(MODIFIER_SEPARATOR2)[0].split(FILTER_SEPARATOR2)[0].trim();
4490
+ if (keyword !== propPart && KEYWORDS_WITHOUT_MODIFIERS.has(keyword)) {
4491
+ raiseError2(`[wcs/binding-syntax] "${bindText2}": "${keyword}" takes no modifiers or filters on its left side \u2014 write "${keyword}:".${LINT_HINT}`);
4492
+ }
5153
4493
  if (propPart === ELSE_KEYWORD2) {
4494
+ if (statePart.length > 0) {
4495
+ raiseError2(`[wcs/binding-syntax] "${bindText2}": "else" takes no value \u2014 write "else:".${LINT_HINT}`);
4496
+ }
5154
4497
  const pathInfo = getPathInfo("#else");
5155
4498
  return {
5156
4499
  propName: ELSE_KEYWORD2,
@@ -5178,7 +4521,7 @@ function parseBindTextsForElement(bindText) {
5178
4521
  ...stateResult,
5179
4522
  bindingType: "spread"
5180
4523
  };
5181
- } else if (propPart === "if" || propPart === "elseif" || propPart === "for" || propPart === "radio" || propPart === "checkbox") {
4524
+ } else if (propPart === "if" || propPart === "elseif" || propPart === "for") {
5182
4525
  const stateResult = parseStatePart(statePart);
5183
4526
  return {
5184
4527
  propName: propPart,
@@ -5188,6 +4531,14 @@ function parseBindTextsForElement(bindText) {
5188
4531
  ...stateResult,
5189
4532
  bindingType: propPart
5190
4533
  };
4534
+ } else if (keyword === "radio" || keyword === "checkbox") {
4535
+ const stateResult = parseStatePart(statePart);
4536
+ const propResult = parsePropPart(propPart);
4537
+ return {
4538
+ ...propResult,
4539
+ ...stateResult,
4540
+ bindingType: keyword
4541
+ };
5191
4542
  } else {
5192
4543
  const stateResult = parseStatePart(statePart);
5193
4544
  const propResult = parsePropPart(propPart);
@@ -5273,7 +4624,7 @@ function parseEmbeddedTextWithPositions(expression) {
5273
4624
  }
5274
4625
  function parseBindTextWithPositions(bindText) {
5275
4626
  const results = [];
5276
- const segments = bindText.split(delimiters.binding);
4627
+ const segments = splitBindTexts(bindText);
5277
4628
  let segmentStart = 0;
5278
4629
  for (const segment of segments) {
5279
4630
  const leading = segment.length - segment.trimStart().length;
@@ -5316,24 +4667,42 @@ function parseBindTextWithPositions(bindText) {
5316
4667
  return results;
5317
4668
  }
5318
4669
 
5319
- // src/service/v3MigrationValidator.ts
5320
- function validateV3Migration(html, bindAttrName = "data-wcs", locale3) {
4670
+ // src/service/bindingSyntaxValidator.ts
4671
+ var CODE_MARKER = "[wcs/binding-syntax]";
4672
+ function bindingSyntaxDetail(error) {
4673
+ if (error === null) return null;
4674
+ const at2 = error.indexOf(CODE_MARKER);
4675
+ if (at2 === -1) return null;
4676
+ const detail = error.slice(at2 + CODE_MARKER.length).trim();
4677
+ const hint = detail.indexOf(" Validate statically:");
4678
+ return hint === -1 ? detail : detail.slice(0, hint);
4679
+ }
4680
+ function validateBindingSyntax(html, bindAttrName = "data-wcs", locale2) {
5321
4681
  const diagnostics = [];
5322
- const msgs = getMessages(locale3);
5323
- const push2 = (detail, start, end) => {
5324
- diagnostics.push({ code: WcsDiagnosticCode.V3Migration, start, end, message: msgs.v3Migration(detail), severity: "info" });
5325
- };
4682
+ const msgs = getMessages(locale2);
5326
4683
  for (const attr of findAllBindAttributes(html, bindAttrName)) {
5327
4684
  for (const binding of parseBindTextWithPositions(attr.value)) {
5328
- for (const detail of findV3MigrationIssues(binding.exprText)) {
5329
- push2(detail, attr.valueStart + binding.exprRange.start, attr.valueStart + binding.exprRange.end);
5330
- }
4685
+ const detail = bindingSyntaxDetail(binding.error);
4686
+ if (detail === null) continue;
4687
+ diagnostics.push({
4688
+ code: WcsDiagnosticCode.BindingSyntax,
4689
+ start: attr.valueStart + binding.exprRange.start,
4690
+ end: attr.valueStart + binding.exprRange.end,
4691
+ message: msgs.bindingSyntax(detail),
4692
+ severity: "error"
4693
+ });
5331
4694
  }
5332
4695
  }
5333
- for (const item of [...findAllMustacheSyntax(html), ...findAllCommentBindings(html)]) {
5334
- for (const detail of findEmbeddedV3MigrationIssues(item.expression)) {
5335
- push2(detail, item.exprStart, item.exprEnd);
5336
- }
4696
+ for (const mustache of findAllMustacheSyntax(html)) {
4697
+ const detail = bindingSyntaxDetail(parseEmbeddedTextWithPositions(mustache.expression).error);
4698
+ if (detail === null) continue;
4699
+ diagnostics.push({
4700
+ code: WcsDiagnosticCode.BindingSyntax,
4701
+ start: mustache.exprStart,
4702
+ end: mustache.exprStart + mustache.expression.length,
4703
+ message: msgs.bindingSyntax(detail),
4704
+ severity: "error"
4705
+ });
5337
4706
  }
5338
4707
  return diagnostics;
5339
4708
  }
@@ -6626,9 +5995,9 @@ var DOM_COMMON_PROPERTIES = /* @__PURE__ */ new Set([
6626
5995
  ]);
6627
5996
  var STRUCTURAL_DIRECTIVES2 = /* @__PURE__ */ new Set(["for", "if", "elseif", "else"]);
6628
5997
  var EMPTYISH_SEEDS = /* @__PURE__ */ new Set(["''", '""', "``", "null", "[]", "{}"]);
6629
- function validateIoNodes(html, bindAttribute = "data-wcs", stateTagName = "wcs-state", locale3, fileReader) {
5998
+ function validateIoNodes(html, bindAttribute = "data-wcs", stateTagName = "wcs-state", locale2, fileReader) {
6630
5999
  const diagnostics = [];
6631
- const msgs = getMessages(locale3);
6000
+ const msgs = getMessages(locale2);
6632
6001
  const occurrences = findBuiltinTagOccurrences(html);
6633
6002
  if (occurrences.length === 0) return diagnostics;
6634
6003
  let statePaths = null;
@@ -6776,7 +6145,7 @@ function suggestion(input, candidates, msgs) {
6776
6145
  let best = null;
6777
6146
  let bestDistance = 3;
6778
6147
  for (const c of candidates) {
6779
- const d = editDistance2(input.toLowerCase(), c.toLowerCase(), bestDistance);
6148
+ const d = editDistance(input.toLowerCase(), c.toLowerCase(), bestDistance);
6780
6149
  if (d < bestDistance) {
6781
6150
  best = c;
6782
6151
  bestDistance = d;
@@ -6784,7 +6153,7 @@ function suggestion(input, candidates, msgs) {
6784
6153
  }
6785
6154
  return best !== null ? msgs.didYouMean(best) : "";
6786
6155
  }
6787
- function editDistance2(a, b, bound) {
6156
+ function editDistance(a, b, bound) {
6788
6157
  if (Math.abs(a.length - b.length) >= bound) return bound;
6789
6158
  const prev = new Array(b.length + 1);
6790
6159
  const curr = new Array(b.length + 1);
@@ -6898,9 +6267,9 @@ var ARIA_ATTRIBUTES = /* @__PURE__ */ new Set([
6898
6267
  "aria-brailleroledescription",
6899
6268
  "aria-description"
6900
6269
  ]);
6901
- function validateAriaAttributes(html, bindAttribute = "data-wcs", locale3) {
6270
+ function validateAriaAttributes(html, bindAttribute = "data-wcs", locale2) {
6902
6271
  const diagnostics = [];
6903
- const msgs = getMessages(locale3);
6272
+ const msgs = getMessages(locale2);
6904
6273
  for (const attr of findAllBindAttributes(html, bindAttribute)) {
6905
6274
  let exprOffset = 0;
6906
6275
  for (const expr of splitBindingExpressions(attr.value)) {
@@ -6929,9 +6298,9 @@ function validateAriaAttributes(html, bindAttribute = "data-wcs", locale3) {
6929
6298
  }
6930
6299
 
6931
6300
  // src/service/documentEnvValidator.ts
6932
- function validateDocumentEnv(html, locale3) {
6301
+ function validateDocumentEnv(html, locale2) {
6933
6302
  const diagnostics = [];
6934
- const msgs = getMessages(locale3);
6303
+ const msgs = getMessages(locale2);
6935
6304
  const scanText = blankHtmlComments(html);
6936
6305
  const autos = findWcstackAutoScripts(scanText);
6937
6306
  const stateIndex = autos.findIndex((a) => a.pkg === "state");
@@ -7042,8 +6411,8 @@ function blankJsComments(code) {
7042
6411
 
7043
6412
  // src/service/watchDeclarationValidator.ts
7044
6413
  var STATE_NAME_SEPARATOR = "@";
7045
- function validateWatchDeclarations(html, stateTagName = "wcs-state", locale3) {
7046
- const msgs = getMessages(locale3);
6414
+ function validateWatchDeclarations(html, stateTagName = "wcs-state", locale2) {
6415
+ const msgs = getMessages(locale2);
7047
6416
  const out = [];
7048
6417
  for (const block of parseWcsScriptBlocks(html, stateTagName)) {
7049
6418
  const nonObject = findNonObjectWatch(block.content);
@@ -7107,8 +6476,8 @@ function validateEntry(entry, pathSet, paths, msgs) {
7107
6476
  }
7108
6477
 
7109
6478
  // src/service/scanDeclarationValidator.ts
7110
- function validateScanDeclarations(html, stateTagName = "wcs-state", locale3) {
7111
- const msgs = getMessages(locale3);
6479
+ function validateScanDeclarations(html, stateTagName = "wcs-state", locale2) {
6480
+ const msgs = getMessages(locale2);
7112
6481
  const out = [];
7113
6482
  for (const element of parseWcsStateElements(html, stateTagName)) {
7114
6483
  const mounted = element.bindComponent;
@@ -7466,8 +6835,8 @@ var UNSUPPORTED_API_SITE = {
7466
6835
  };
7467
6836
  var BRACKET_ASSIGNMENT = new RegExp(`${ROOT_BRACKET}${ASSIGN_TAIL}`, "g");
7468
6837
  var PRE_BRACKET_INCDEC = new RegExp(`${PRE_INCDEC}${ROOT_BRACKET}`, "g");
7469
- function validateRecursion(html, stateTagName = "wcs-state", locale3) {
7470
- const msgs = getMessages(locale3);
6838
+ function validateRecursion(html, stateTagName = "wcs-state", locale2) {
6839
+ const msgs = getMessages(locale2);
7471
6840
  const out = [];
7472
6841
  for (const element of parseWcsStateElements(html, stateTagName)) {
7473
6842
  const mounted = element.bindComponent;
@@ -7898,8 +7267,8 @@ function findStateSelector(expr, embedded = false) {
7898
7267
  const nameStart = at2 + 1 + (raw.length - raw.trimStart().length);
7899
7268
  return { start: at2, end: name.length === 0 ? at2 + 1 : nameStart + name.length, name: name.length === 0 ? "default" : name };
7900
7269
  }
7901
- function validateNamedState(html, attrName, stateTagName = "wcs-state", locale3) {
7902
- const msgs = getMessages(locale3);
7270
+ function validateNamedState(html, attrName, stateTagName = "wcs-state", locale2) {
7271
+ const msgs = getMessages(locale2);
7903
7272
  const diagnostics = [];
7904
7273
  for (const element of parseWcsStateElements(html, stateTagName)) {
7905
7274
  const tagText = html.slice(element.tagStart, element.tagEnd);
@@ -7957,8 +7326,8 @@ function findMountPathProblem(mountPath) {
7957
7326
  }
7958
7327
  return null;
7959
7328
  }
7960
- function validateMountAttributes(html, stateTagName = "wcs-state", locale3) {
7961
- const msgs = getMessages(locale3);
7329
+ function validateMountAttributes(html, stateTagName = "wcs-state", locale2) {
7330
+ const msgs = getMessages(locale2);
7962
7331
  const diagnostics = [];
7963
7332
  for (const element of parseWcsStateElements(html, stateTagName)) {
7964
7333
  if (element.mountPath === null) continue;
@@ -14101,8 +13470,8 @@ function buildReferenceIndex(html, options = {}) {
14101
13470
  // src/service/semanticValidator.ts
14102
13471
  var STATE_UPDATED_CALLBACK = "$updatedCallback";
14103
13472
  var API_CALL = /\.\s*\$(getAll|setAll|resolve)\s*\(/g;
14104
- function validateIndexArity(script, scriptStart, locale3) {
14105
- const msgs = getMessages(locale3);
13473
+ function validateIndexArity(script, scriptStart, locale2) {
13474
+ const msgs = getMessages(locale2);
14106
13475
  const out = [];
14107
13476
  API_CALL.lastIndex = 0;
14108
13477
  let match;
@@ -14133,8 +13502,8 @@ function validateIndexArity(script, scriptStart, locale3) {
14133
13502
  }
14134
13503
  return out;
14135
13504
  }
14136
- function validateGetterCycles(script, scriptStart, locale3) {
14137
- const msgs = getMessages(locale3);
13505
+ function validateGetterCycles(script, scriptStart, locale2) {
13506
+ const msgs = getMessages(locale2);
14138
13507
  const getters = analyzeCallableBodies(script).filter((entry) => entry.kind === "getter");
14139
13508
  if (getters.length === 0) return [];
14140
13509
  const declared = new Set(getters.map((getter) => getter.name));
@@ -14189,7 +13558,7 @@ function validateGetterCycles(script, scriptStart, locale3) {
14189
13558
  }
14190
13559
  return out;
14191
13560
  }
14192
- function validateGetterUntrackedReads(script, scriptStart, nestedWriteRoots, locale3) {
13561
+ function validateGetterUntrackedReads(script, scriptStart, nestedWriteRoots, locale2) {
14193
13562
  const getters = analyzeCallableBodies(script).filter((entry) => entry.kind === "getter" && entry.accessor === "get");
14194
13563
  if (getters.length === 0) return [];
14195
13564
  const objectRoots = /* @__PURE__ */ new Set();
@@ -14199,7 +13568,7 @@ function validateGetterUntrackedReads(script, scriptStart, nestedWriteRoots, loc
14199
13568
  }
14200
13569
  }
14201
13570
  if (objectRoots.size === 0) return [];
14202
- const msgs = getMessages(locale3);
13571
+ const msgs = getMessages(locale2);
14203
13572
  const out = [];
14204
13573
  for (const getter of getters) {
14205
13574
  for (const read of collectGetterReads(getter.body) ?? []) {
@@ -14278,12 +13647,12 @@ function collectNestedWriteRoots(html, stateTagName, bindAttrName, blocks) {
14278
13647
  return roots;
14279
13648
  }
14280
13649
  var PATH_TEST_LITERAL = /(?:\.\s*(?:includes|indexOf)\s*\(\s*|[!=]==\s*)(["'])((?:\\.|(?!\1)[^\\])*)\1/g;
14281
- function validateUpdatedCallbackDemand(html, stateTagName, bindAttrName, locale3) {
13650
+ function validateUpdatedCallbackDemand(html, stateTagName, bindAttrName, locale2) {
14282
13651
  const blocks = parseWcsScriptBlocks(html, stateTagName);
14283
13652
  if (blocks.length === 0) return [];
14284
13653
  const hasCallback = blocks.some((block) => block.content.includes(STATE_UPDATED_CALLBACK));
14285
13654
  if (!hasCallback) return [];
14286
- const msgs = getMessages(locale3);
13655
+ const msgs = getMessages(locale2);
14287
13656
  const boundPaths = collectBoundPaths(html, stateTagName, bindAttrName);
14288
13657
  const out = [];
14289
13658
  for (const block of blocks) {
@@ -14327,17 +13696,17 @@ function collectBoundPaths(html, stateTagName, bindAttrName) {
14327
13696
  }
14328
13697
  return bound;
14329
13698
  }
14330
- function validateSemantics(html, stateTagName = "wcs-state", locale3, bindAttrName = "data-wcs") {
13699
+ function validateSemantics(html, stateTagName = "wcs-state", locale2, bindAttrName = "data-wcs") {
14331
13700
  const out = [];
14332
13701
  const blocks = parseWcsScriptBlocks(html, stateTagName);
14333
13702
  let nestedWriteRoots = null;
14334
13703
  const getNestedWriteRoots = () => nestedWriteRoots ??= collectNestedWriteRoots(html, stateTagName, bindAttrName, blocks);
14335
13704
  for (const block of blocks) {
14336
- out.push(...validateIndexArity(block.content, block.contentStart, locale3));
14337
- out.push(...validateGetterCycles(block.content, block.contentStart, locale3));
14338
- out.push(...validateGetterUntrackedReads(block.content, block.contentStart, getNestedWriteRoots, locale3));
13705
+ out.push(...validateIndexArity(block.content, block.contentStart, locale2));
13706
+ out.push(...validateGetterCycles(block.content, block.contentStart, locale2));
13707
+ out.push(...validateGetterUntrackedReads(block.content, block.contentStart, getNestedWriteRoots, locale2));
14339
13708
  }
14340
- out.push(...validateUpdatedCallbackDemand(html, stateTagName, bindAttrName, locale3));
13709
+ out.push(...validateUpdatedCallbackDemand(html, stateTagName, bindAttrName, locale2));
14341
13710
  return out;
14342
13711
  }
14343
13712
 
@@ -14732,27 +14101,27 @@ function joinRelativeSource(htmlSource, relativePath) {
14732
14101
  function validateDocument(text, options = {}) {
14733
14102
  const bindAttribute = options.bindAttribute ?? "data-wcs";
14734
14103
  const stateTagName = options.stateTagName ?? "wcs-state";
14735
- const locale3 = options.locale;
14104
+ const locale2 = options.locale;
14736
14105
  const fileReader = options.fileReader;
14737
14106
  const applicationSchema = options.applicationSchema ?? (fileReader !== void 0 ? discoverApplicationManifest(fileReader)?.schema : void 0);
14738
14107
  const out = [];
14739
- out.push(...validateBindings(text, bindAttribute, stateTagName, locale3, fileReader, applicationSchema));
14740
- out.push(...validateTemplateSyntax(text, stateTagName, bindAttribute, locale3, fileReader, applicationSchema));
14741
- out.push(...validateV3Migration(text, bindAttribute, locale3));
14742
- out.push(...validateIoNodes(text, bindAttribute, stateTagName, locale3, fileReader));
14743
- out.push(...validateAriaAttributes(text, bindAttribute, locale3));
14744
- out.push(...validateDocumentEnv(text, locale3));
14745
- out.push(...validateSemantics(text, stateTagName, locale3, bindAttribute));
14746
- out.push(...validateArrayMutations(text, stateTagName, locale3));
14747
- out.push(...validateWatchDeclarations(text, stateTagName, locale3));
14748
- out.push(...validateScanDeclarations(text, stateTagName, locale3));
14749
- out.push(...validateRecursion(text, stateTagName, locale3));
14750
- out.push(...validateNamedState(text, bindAttribute, stateTagName, locale3));
14751
- out.push(...validateMountAttributes(text, stateTagName, locale3));
14752
- for (const d of validateStateTypes(text, stateTagName, locale3)) {
14108
+ out.push(...validateBindings(text, bindAttribute, stateTagName, locale2, fileReader, applicationSchema));
14109
+ out.push(...validateTemplateSyntax(text, stateTagName, bindAttribute, locale2, fileReader, applicationSchema));
14110
+ out.push(...validateBindingSyntax(text, bindAttribute, locale2));
14111
+ out.push(...validateIoNodes(text, bindAttribute, stateTagName, locale2, fileReader));
14112
+ out.push(...validateAriaAttributes(text, bindAttribute, locale2));
14113
+ out.push(...validateDocumentEnv(text, locale2));
14114
+ out.push(...validateSemantics(text, stateTagName, locale2, bindAttribute));
14115
+ out.push(...validateArrayMutations(text, stateTagName, locale2));
14116
+ out.push(...validateWatchDeclarations(text, stateTagName, locale2));
14117
+ out.push(...validateScanDeclarations(text, stateTagName, locale2));
14118
+ out.push(...validateRecursion(text, stateTagName, locale2));
14119
+ out.push(...validateNamedState(text, bindAttribute, stateTagName, locale2));
14120
+ out.push(...validateMountAttributes(text, stateTagName, locale2));
14121
+ for (const d of validateStateTypes(text, stateTagName, locale2)) {
14753
14122
  out.push({ code: WcsDiagnosticCode.TypeAnnotation, start: d.start, end: d.end, message: d.message, severity: d.severity });
14754
14123
  }
14755
- for (const d of validateNestedAssigns(text, stateTagName, locale3)) {
14124
+ for (const d of validateNestedAssigns(text, stateTagName, locale2)) {
14756
14125
  out.push({ code: WcsDiagnosticCode.NestedAssign, start: d.start, end: d.end, message: d.message, severity: d.severity });
14757
14126
  }
14758
14127
  return sortDiagnostics(out);
@@ -14986,7 +14355,7 @@ function resolveCliLocale(explicit, env = process.env) {
14986
14355
  }
14987
14356
  function main(argv) {
14988
14357
  const { options, files } = parseArgs(argv);
14989
- const locale3 = resolveCliLocale(options.locale);
14358
+ const locale2 = resolveCliLocale(options.locale);
14990
14359
  if (files.length === 0) {
14991
14360
  process.stderr.write("usage: wcs-validate [--attr=data-wcs] [--state-tag=wcs-state] [--lang=ja|en] [--errors-only] [--strict] <file> [<file> ...]\n");
14992
14361
  return 2;
@@ -15004,7 +14373,7 @@ function main(argv) {
15004
14373
  const kind = classify(path);
15005
14374
  inputs.push({ source: path, text, kind, fileReader: kind === "html" ? createFileReader(path) : void 0 });
15006
14375
  }
15007
- const result = runValidation(inputs, { ...options, locale: locale3 });
14376
+ const result = runValidation(inputs, { ...options, locale: locale2 });
15008
14377
  for (const line of result.lines) {
15009
14378
  process.stdout.write(line + "\n");
15010
14379
  }