@wcstack/lint 3.1.0 → 3.2.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 +141 -52
  2. package/package.json +1 -1
package/dist/cli.cjs CHANGED
@@ -204,6 +204,9 @@ var WcsDiagnosticCode = {
204
204
  // タグのメンバー名が "on" で始まる(`once` 等)のに先頭ドット無しで束縛した: ランタイムはイベント束縛にして
205
205
  // "ce" イベントを待ち、値は届かない。明示のプロパティ形 `.once:` を提案する(@wcstack/state 3.1・要件 B5 / 3.x 計画 D36)
206
206
  OnPrefixedMember: "wcs/on-prefixed-member",
207
+ // 3.x の間だけ残る旧名(フィルタ `uc` → `upper`、`$trackDependency` → `$dependOn` …)を書いた(info)。
208
+ // 動くが 4.0 で外れるので正式名を提案する(@wcstack/state 3.2・要件 B12 / 3.x 計画 D39)
209
+ NameAlias: "wcs/name-alias",
207
210
  // wcBindable 無宣言タグ(wcs-fetch-header 等のヘルパー)への spread。
208
211
  // ランタイム(expandSpread)は raiseError で落とす。
209
212
  SpreadNoBindable: "wcs/spread-no-bindable",
@@ -267,6 +270,18 @@ function valueMustBeDate(fnName) {
267
270
  function valueMustBeArray(fnName) {
268
271
  raiseError(`filter ${fnName} requires an array value`);
269
272
  }
273
+ var builtinFilterAliases = {
274
+ inc: "add",
275
+ dec: "sub",
276
+ fix: "toFixed",
277
+ uc: "upper",
278
+ lc: "lower",
279
+ cap: "capitalize",
280
+ rep: "repeat",
281
+ rev: "reverse",
282
+ pad: "padStart",
283
+ null: "nullIfEmpty"
284
+ };
270
285
  function validateNumberString(value) {
271
286
  if (!value || isNaN(Number(value))) {
272
287
  return false;
@@ -362,25 +377,25 @@ var ge = (options) => {
362
377
  };
363
378
  };
364
379
  var inc = (options) => {
365
- const opt = options?.[0] ?? optionsRequired("inc");
380
+ const opt = options?.[0] ?? optionsRequired("add");
366
381
  if (!validateNumberString(opt)) {
367
- optionMustBeNumber("inc");
382
+ optionMustBeNumber("add");
368
383
  }
369
384
  return (value) => {
370
385
  if (typeof value !== "number") {
371
- valueMustBeNumber("inc");
386
+ valueMustBeNumber("add");
372
387
  }
373
388
  return value + Number(opt);
374
389
  };
375
390
  };
376
391
  var dec = (options) => {
377
- const opt = options?.[0] ?? optionsRequired("dec");
392
+ const opt = options?.[0] ?? optionsRequired("sub");
378
393
  if (!validateNumberString(opt)) {
379
- optionMustBeNumber("dec");
394
+ optionMustBeNumber("sub");
380
395
  }
381
396
  return (value) => {
382
397
  if (typeof value !== "number") {
383
- valueMustBeNumber("dec");
398
+ valueMustBeNumber("sub");
384
399
  }
385
400
  return value - Number(opt);
386
401
  };
@@ -450,11 +465,11 @@ var clamp = (options) => {
450
465
  var fix = (options) => {
451
466
  const opt = options?.[0] ?? "0";
452
467
  if (!validateNumberString(opt)) {
453
- optionMustBeNumber("fix");
468
+ optionMustBeNumber("toFixed");
454
469
  }
455
470
  return (value) => {
456
471
  if (typeof value !== "number") {
457
- valueMustBeNumber("fix");
472
+ valueMustBeNumber("toFixed");
458
473
  }
459
474
  return value.toFixed(Number(opt));
460
475
  };
@@ -527,19 +542,29 @@ var substr = (options) => {
527
542
  };
528
543
  };
529
544
  var pad = (options) => {
530
- const opt1 = options?.[0] ?? optionsRequired("pad");
545
+ const opt1 = options?.[0] ?? optionsRequired("padStart");
531
546
  if (!validateNumberString(opt1)) {
532
- optionMustBeNumber("pad");
547
+ optionMustBeNumber("padStart");
533
548
  }
534
549
  const opt2 = options?.[1] ?? "0";
535
550
  return (value) => {
536
551
  return String(value).padStart(Number(opt1), opt2);
537
552
  };
538
553
  };
554
+ var padEnd = (options) => {
555
+ const opt1 = options?.[0] ?? optionsRequired("padEnd");
556
+ if (!validateNumberString(opt1)) {
557
+ optionMustBeNumber("padEnd");
558
+ }
559
+ const opt2 = options?.[1] ?? " ";
560
+ return (value) => {
561
+ return String(value).padEnd(Number(opt1), opt2);
562
+ };
563
+ };
539
564
  var rep = (options) => {
540
- const opt = options?.[0] ?? optionsRequired("rep");
565
+ const opt = options?.[0] ?? optionsRequired("repeat");
541
566
  if (!validateNumberString(opt)) {
542
- optionMustBeNumber("rep");
567
+ optionMustBeNumber("repeat");
543
568
  }
544
569
  return (value) => {
545
570
  return String(value).repeat(Number(opt));
@@ -711,6 +736,11 @@ var defaults = (options, literals) => {
711
736
  return value;
712
737
  };
713
738
  };
739
+ var coalesce = (options, literals) => {
740
+ const opt = options?.[0] ?? optionsRequired("coalesce");
741
+ const fallback = literals !== void 0 && literals.length > 0 ? literals[0] : opt;
742
+ return (value) => value ?? fallback;
743
+ };
714
744
  var boolean = (_options) => {
715
745
  return (value) => {
716
746
  return Boolean(value);
@@ -739,24 +769,25 @@ var builtinFilters = {
739
769
  "le": le,
740
770
  "gt": gt,
741
771
  "ge": ge,
742
- "inc": inc,
743
- "dec": dec,
772
+ "add": inc,
773
+ "sub": dec,
744
774
  "mul": mul,
745
775
  "div": div,
746
776
  "mod": mod,
747
777
  "abs": abs,
748
778
  "clamp": clamp,
749
- "fix": fix,
779
+ "toFixed": fix,
750
780
  "locale": locale,
751
- "uc": uc,
752
- "lc": lc,
753
- "cap": cap,
781
+ "upper": uc,
782
+ "lower": lc,
783
+ "capitalize": cap,
754
784
  "trim": trim,
755
785
  "slice": slice,
756
786
  "substr": substr,
757
- "pad": pad,
758
- "rep": rep,
759
- "rev": rev,
787
+ "padStart": pad,
788
+ "padEnd": padEnd,
789
+ "repeat": rep,
790
+ "reverse": rev,
760
791
  "truncate": truncate,
761
792
  "join": join,
762
793
  "int": int,
@@ -774,10 +805,11 @@ var builtinFilters = {
774
805
  "falsy": falsy,
775
806
  "truthy": truthy,
776
807
  "defaults": defaults,
808
+ "coalesce": coalesce,
777
809
  "boolean": boolean,
778
810
  "number": number,
779
811
  "string": string,
780
- "null": _null
812
+ "nullIfEmpty": _null
781
813
  };
782
814
  var outputBuiltinFilters = builtinFilters;
783
815
  var builtinFilterMeta = {
@@ -790,26 +822,27 @@ var builtinFilterMeta = {
790
822
  gt: { description: "\u3088\u308A\u5927\u304D\u3044\u304B", hasArgs: true, resultType: "boolean", acceptTypes: ["number", "string"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
791
823
  ge: { description: "\u4EE5\u4E0A\u304B", hasArgs: true, resultType: "boolean", acceptTypes: ["number", "string"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
792
824
  // 算術
793
- inc: { description: "\u52A0\u7B97", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 0, maxArgs: 1, argTypes: ["number"] },
794
- dec: { description: "\u6E1B\u7B97", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 0, maxArgs: 1, argTypes: ["number"] },
825
+ add: { description: "\u52A0\u7B97", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
826
+ sub: { description: "\u6E1B\u7B97", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
795
827
  mul: { description: "\u4E57\u7B97", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
796
828
  div: { description: "\u9664\u7B97", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
797
829
  mod: { description: "\u5270\u4F59", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
798
830
  abs: { description: "\u7D76\u5BFE\u5024", hasArgs: false, resultType: "number", acceptTypes: ["number"], minArgs: 0, maxArgs: 0 },
799
831
  clamp: { description: "\u7BC4\u56F2\u5185\u306B\u4E38\u3081\u308B (min,max)", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 2, maxArgs: 2, argTypes: ["number", "number"] },
800
832
  // 数値フォーマット
801
- fix: { description: "\u56FA\u5B9A\u5C0F\u6570\u70B9\u8868\u8A18", hasArgs: true, resultType: "string", acceptTypes: ["number"], minArgs: 0, maxArgs: 1, argTypes: ["number"] },
833
+ toFixed: { description: "\u56FA\u5B9A\u5C0F\u6570\u70B9\u8868\u8A18", hasArgs: true, resultType: "string", acceptTypes: ["number"], minArgs: 0, maxArgs: 1, argTypes: ["number"] },
802
834
  locale: { description: "\u30ED\u30B1\u30FC\u30EB\u5F62\u5F0F\u3067\u6570\u5024\u30D5\u30A9\u30FC\u30DE\u30C3\u30C8", hasArgs: true, resultType: "string", acceptTypes: ["number"], minArgs: 0, maxArgs: 1, argTypes: ["string"] },
803
835
  // 文字列
804
- uc: { description: "\u5927\u6587\u5B57\u306B\u5909\u63DB", hasArgs: false, resultType: "string", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 },
805
- lc: { description: "\u5C0F\u6587\u5B57\u306B\u5909\u63DB", hasArgs: false, resultType: "string", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 },
806
- cap: { description: "\u5148\u982D\u6587\u5B57\u3092\u5927\u6587\u5B57\u306B", hasArgs: false, resultType: "string", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 },
836
+ upper: { description: "\u5927\u6587\u5B57\u306B\u5909\u63DB", hasArgs: false, resultType: "string", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 },
837
+ lower: { description: "\u5C0F\u6587\u5B57\u306B\u5909\u63DB", hasArgs: false, resultType: "string", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 },
838
+ capitalize: { description: "\u5148\u982D\u6587\u5B57\u3092\u5927\u6587\u5B57\u306B", hasArgs: false, resultType: "string", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 },
807
839
  trim: { description: "\u524D\u5F8C\u306E\u7A7A\u767D\u3092\u524A\u9664", hasArgs: false, resultType: "string", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 },
808
840
  slice: { description: "\u90E8\u5206\u6587\u5B57\u5217 (start[,end])", hasArgs: true, resultType: "string", acceptTypes: ["string"], minArgs: 1, maxArgs: 2, argTypes: ["number", "number"] },
809
841
  substr: { description: "\u90E8\u5206\u6587\u5B57\u5217 (pos,len)", hasArgs: true, resultType: "string", acceptTypes: ["string"], minArgs: 1, maxArgs: 2, argTypes: ["number", "number"] },
810
- pad: { description: "\u30D1\u30C7\u30A3\u30F3\u30B0 (length[,char])", hasArgs: true, resultType: "string", acceptTypes: ["string"], minArgs: 1, maxArgs: 2, argTypes: ["number", "string"] },
811
- rep: { description: "\u7E70\u308A\u8FD4\u3057 (count)", hasArgs: true, resultType: "string", acceptTypes: ["string"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
812
- rev: { description: "\u6587\u5B57\u9806\u3092\u53CD\u8EE2", hasArgs: false, resultType: "string", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 },
842
+ padStart: { description: "\u5148\u982D\u3092\u57CB\u3081\u308B (length[,char])", hasArgs: true, resultType: "string", acceptTypes: ["string"], minArgs: 1, maxArgs: 2, argTypes: ["number", "string"] },
843
+ padEnd: { description: "\u672B\u5C3E\u3092\u57CB\u3081\u308B (length[,char])", hasArgs: true, resultType: "string", acceptTypes: ["string"], minArgs: 1, maxArgs: 2, argTypes: ["number", "string"] },
844
+ repeat: { description: "\u7E70\u308A\u8FD4\u3057 (count)", hasArgs: true, resultType: "string", acceptTypes: ["string"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
845
+ reverse: { description: "\u6587\u5B57\u9806\u3092\u53CD\u8EE2", hasArgs: false, resultType: "string", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 },
813
846
  truncate: { description: "\u5207\u308A\u8A70\u3081\u3066\u7701\u7565\u8A18\u53F7 (length[,suffix])", hasArgs: true, resultType: "string", acceptTypes: ["string"], minArgs: 1, maxArgs: 2, argTypes: ["number", "string"] },
814
847
  join: { description: "\u914D\u5217\u3092\u9023\u7D50 ([separator])", hasArgs: true, resultType: "string", acceptTypes: ["array"], minArgs: 0, maxArgs: 1, argTypes: ["string"] },
815
848
  // 数値パース・丸め
@@ -832,10 +865,11 @@ var builtinFilterMeta = {
832
865
  falsy: { description: "\u507D\u5024\u304B\u5224\u5B9A", hasArgs: false, resultType: "boolean", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
833
866
  truthy: { description: "\u771F\u5024\u304B\u5224\u5B9A", hasArgs: false, resultType: "boolean", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
834
867
  defaults: { description: "\u507D\u5024\u306E\u5834\u5408\u30C7\u30D5\u30A9\u30EB\u30C8\u5024", hasArgs: true, resultType: "passthrough", acceptTypes: "any", minArgs: 1, maxArgs: 1, argTypes: ["any"] },
868
+ coalesce: { description: "null / undefined \u306E\u5834\u5408\u30C7\u30D5\u30A9\u30EB\u30C8\u5024", hasArgs: true, resultType: "passthrough", acceptTypes: "any", minArgs: 1, maxArgs: 1, argTypes: ["any"] },
835
869
  boolean: { description: "\u30D6\u30FC\u30EB\u5024\u306B\u5909\u63DB", hasArgs: false, resultType: "boolean", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
836
870
  number: { description: "\u6570\u5024\u306B\u5909\u63DB", hasArgs: false, resultType: "number", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
837
871
  string: { description: "\u6587\u5B57\u5217\u306B\u5909\u63DB", hasArgs: false, resultType: "string", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
838
- null: { description: "\u7A7A\u6587\u5B57\u5217\u3092null\u306B\u5909\u63DB", hasArgs: false, resultType: "passthrough", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 }
872
+ nullIfEmpty: { description: "\u7A7A\u6587\u5B57\u5217\u3092null\u306B\u5909\u63DB", hasArgs: false, resultType: "passthrough", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 }
839
873
  };
840
874
  var STRUCTURAL_BINDING_TYPE_SET = /* @__PURE__ */ new Set([
841
875
  "if",
@@ -880,7 +914,7 @@ for (let i = 0; i < MAX_WILDCARD_DEPTH; i++) {
880
914
  Object.freeze(tmpIndexByIndexName);
881
915
  var STATE_CONNECTED_CALLBACK_NAME = "$connectedCallback";
882
916
  var STATE_DISCONNECTED_CALLBACK_NAME = "$disconnectedCallback";
883
- var STATE_UPDATED_CALLBACK_NAME = "$updatedCallback";
917
+ var STATE_UPDATED_CALLBACK_NAME = "$renderedCallback";
884
918
  var STATE_ERROR_CALLBACK_NAME = "$errorCallback";
885
919
  var WEBCOMPONENT_STATE_READY_CALLBACK_NAME = "$stateReadyCallback";
886
920
  var STATE_BINDABLES_NAME = "$bindables";
@@ -889,7 +923,7 @@ var STATE_COMMAND_TOKENS_NAME = "$commandTokens";
889
923
  var STATE_COMMAND_NAMESPACE_NAME = "$command";
890
924
  var STATE_EVENT_TOKENS_NAME = "$eventTokens";
891
925
  var STATE_ON_NAME = "$on";
892
- var STATE_STREAMS_NAME = "$streams";
926
+ var STATE_STREAMS_NAME = "$stream";
893
927
  var STATE_WATCH_NAME = "$watch";
894
928
  var STATE_SCAN_NAME = "$scan";
895
929
  var STATE_RECURSION_NAME = "$recursion";
@@ -939,6 +973,7 @@ function getWcsManifest() {
939
973
  // 実装(Record のキー)から自動導出。手リストを持たない=ドリフトの構造的排除。
940
974
  filters: Object.keys(outputBuiltinFilters),
941
975
  filterMeta: builtinFilterMeta,
976
+ filterAliases: builtinFilterAliases,
942
977
  reservedLifecycle: [
943
978
  STATE_CONNECTED_CALLBACK_NAME,
944
979
  STATE_DISCONNECTED_CALLBACK_NAME,
@@ -965,6 +1000,9 @@ function getWcsManifest() {
965
1000
  }
966
1001
 
967
1002
  // src/service/completionData.ts
1003
+ function canonicalFilterName(name) {
1004
+ return Object.prototype.hasOwnProperty.call(builtinFilterAliases, name) ? builtinFilterAliases[name] : name;
1005
+ }
968
1006
  var BUILTIN_FILTERS = Object.entries(builtinFilterMeta).map(
969
1007
  ([name, meta]) => ({ name, ...meta })
970
1008
  );
@@ -1140,7 +1178,7 @@ function coversSuffix(spec, familySuffix, suffix) {
1140
1178
  }
1141
1179
 
1142
1180
  // src/service/stateAnalyzer.ts
1143
- var RESERVED_STREAMS_KEY = "$streams";
1181
+ var RESERVED_STREAMS_KEYS = /* @__PURE__ */ new Set(["$stream", "$streams"]);
1144
1182
  var RESERVED_COMMAND_TOKENS_KEY = "$commandTokens";
1145
1183
  var RESERVED_EVENT_TOKENS_KEY = "$eventTokens";
1146
1184
  var RESERVED_LIST_KEYS_KEY = "$listKeys";
@@ -1512,7 +1550,7 @@ function findNonObjectDeclaration(scriptContent, key, rejectArray = false) {
1512
1550
  return span;
1513
1551
  }
1514
1552
  function collectReservedKeyPaths(prop, paths, pendingStreamValues, pendingListKeys) {
1515
- if (prop.name === RESERVED_STREAMS_KEY && prop.kind === "data" && prop.value && isObjectLiteral(prop.value)) {
1553
+ if (RESERVED_STREAMS_KEYS.has(prop.name) && prop.kind === "data" && prop.value && isObjectLiteral(prop.value)) {
1516
1554
  const entries = parseTopLevelProperties(extractObjectContent(prop.value));
1517
1555
  for (const entry of entries) {
1518
1556
  if (entry.kind !== "data" || entry.name.startsWith("$")) continue;
@@ -2641,6 +2679,7 @@ var ja = {
2641
2679
  arrayMutation: (m, alt) => `\u914D\u5217\u306E\u7834\u58CA\u7684\u30E1\u30BD\u30C3\u30C9 "${m}" \u306F\u30EA\u30A2\u30AF\u30C6\u30A3\u30D6\u66F4\u65B0\u3092\u30C8\u30EA\u30AC\u30FC\u3057\u307E\u305B\u3093\uFF08\u540C\u4E00\u53C2\u7167\u306E\u81EA\u5DF1\u518D\u4EE3\u5165\u3067\u3082\u8981\u7D20\u306E\u8FFD\u52A0\u30FB\u524A\u9664\u306F\u53CD\u6620\u3055\u308C\u307E\u305B\u3093\uFF09\u3002\u975E\u7834\u58CA\u30E1\u30BD\u30C3\u30C9\u3068\u518D\u4EE3\u5165\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044\uFF08\u4F8B: ${alt}\uFF09\u3002`,
2642
2680
  arrayIndexAssign: (sp) => `\u914D\u5217\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u3078\u306E\u76F4\u63A5\u4EE3\u5165\u306F\u30EA\u30A2\u30AF\u30C6\u30A3\u30D6\u66F4\u65B0\u3092\u30C8\u30EA\u30AC\u30FC\u3057\u307E\u305B\u3093\u3002this["${sp}"] \u306E\u3088\u3046\u306A\u30C9\u30C3\u30C8\u30D1\u30B9\u4EE3\u5165\u3001\u307E\u305F\u306F with() \u3068\u518D\u4EE3\u5165\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002`,
2643
2681
  tagMemberUnknown: (prop, tag) => `"${prop}" \u306F <${tag}> \u306E wcBindable \u30E1\u30F3\u30D0\u30FC\u3067\u306F\u3042\u308A\u307E\u305B\u3093\uFF08\u672A\u77E5\u30E1\u30F3\u30D0\u30FC\u3078\u306E\u30D0\u30A4\u30F3\u30C9\u306F\u9ED9\u3063\u3066\u7121\u8996\u3055\u308C\u307E\u3059\uFF09`,
2682
+ nameAlias: (written, canonical) => `"${written}" \u306F "${canonical}" \u306E\u65E7\u540D\u3067\u3059\u30023.x \u306E\u9593\u306F\u52D5\u304D\u307E\u3059\u304C 4.0 \u3067\u5916\u308C\u308B\u306E\u3067\u3001"${canonical}" \u3068\u66F8\u3044\u3066\u304F\u3060\u3055\u3044\uFF08@wcstack/state 3.2\uFF09`,
2644
2683
  onPrefixedMember: (member, tag) => `"${member}" \u306F <${tag}> \u306E\u30E1\u30F3\u30D0\u30FC\u3067\u3059\u304C\u3001"on" \u3067\u59CB\u307E\u308B\u540D\u524D\u306F\u30A4\u30D9\u30F3\u30C8\u675F\u7E1B\u306B\u306A\u308A\uFF08"${member.slice(2)}" \u30A4\u30D9\u30F3\u30C8\u3092\u5F85\u3064\uFF09\u3001\u5024\u306F\u5C4A\u304D\u307E\u305B\u3093\u3002\u30D7\u30ED\u30D1\u30C6\u30A3\u3068\u3057\u3066\u675F\u7E1B\u3059\u308B\u306B\u306F ".${member}:" \u3068\u66F8\u3044\u3066\u304F\u3060\u3055\u3044\uFF08@wcstack/state 3.1\uFF09`,
2645
2684
  tagCommandUnknown: (name, tag, declared) => `"${name}" \u306F <${tag}> \u306E command \u3067\u306F\u3042\u308A\u307E\u305B\u3093\uFF08\u5BA3\u8A00\u6E08\u307F: ${declared}\uFF09`,
2646
2685
  spreadNoBindable: (tag) => `'...'\uFF08spread\uFF09\u306F <${tag}> \u306B\u6709\u52B9\u306A wcBindable \u5BA3\u8A00\u304C\u5FC5\u8981\u3067\u3059 \u2014 \u3053\u306E\u30BF\u30B0\u306F\u5BA3\u8A00\u3092\u6301\u305F\u306A\u3044\u305F\u3081\u3001\u30E9\u30F3\u30BF\u30A4\u30E0\u306F\u30A8\u30E9\u30FC\u3092\u9001\u51FA\u3057\u307E\u3059`,
@@ -2831,6 +2870,7 @@ var en = {
2831
2870
  arrayMutation: (m, alt) => `Destructive array method "${m}" does not trigger a reactive update (re-assigning the same reference does not reflect added/removed elements either). Use a non-destructive method with reassignment (e.g. ${alt}).`,
2832
2871
  arrayIndexAssign: (sp) => `Assigning directly to an array index does not trigger a reactive update. Use a dot-path assignment like this["${sp}"], or with() plus reassignment.`,
2833
2872
  tagMemberUnknown: (prop, tag) => `"${prop}" is not a wcBindable member of <${tag}> (bindings to unknown members are silently ignored)`,
2873
+ nameAlias: (written, canonical) => `"${written}" is the old name of "${canonical}". It works through 3.x and goes in 4.0 \u2014 write "${canonical}" (@wcstack/state 3.2)`,
2834
2874
  onPrefixedMember: (member, tag) => `"${member}" is a member of <${tag}>, but a name starting with "on" makes an event binding (it listens for a "${member.slice(2)}" event) and the value never arrives. Write ".${member}:" to bind the property (@wcstack/state 3.1)`,
2835
2875
  tagCommandUnknown: (name, tag, declared) => `"${name}" is not a command of <${tag}> (declared: ${declared})`,
2836
2876
  spreadNoBindable: (tag) => `'...' (spread) requires <${tag}> to expose a valid wcBindable declaration \u2014 this tag declares none, so the runtime raises an error`,
@@ -3156,7 +3196,6 @@ function validateBindings(html, attrName, stateTagName = "wcs-state", locale2, f
3156
3196
  structuralTemplates ??= collectStructuralTemplates(html, attrName);
3157
3197
  return structuralTemplates;
3158
3198
  };
3159
- const filterNameSet = new Set(BUILTIN_FILTERS.map((f) => f.name));
3160
3199
  for (const attr of attrs) {
3161
3200
  const bindings = splitBindingExpressions(attr.value);
3162
3201
  const nonEmptyCount = bindings.filter((b) => b.trim().length > 0).length;
@@ -3490,7 +3529,17 @@ function parseFilterSegments(expr, segments, searchStart) {
3490
3529
  }
3491
3530
  function validateFilterUsage(filter, bindingStart, msgs) {
3492
3531
  const diagnostics = [];
3493
- const info = filterMap.get(filter.name);
3532
+ const canonical = canonicalFilterName(filter.name);
3533
+ const info = filterMap.get(canonical);
3534
+ if (info && canonical !== filter.name) {
3535
+ diagnostics.push({
3536
+ code: WcsDiagnosticCode.NameAlias,
3537
+ start: bindingStart + filter.offset,
3538
+ end: bindingStart + filter.offset + filter.name.length,
3539
+ message: msgs.nameAlias(filter.name, canonical),
3540
+ severity: "info"
3541
+ });
3542
+ }
3494
3543
  if (!info) {
3495
3544
  diagnostics.push({
3496
3545
  code: WcsDiagnosticCode.FilterUnknown,
@@ -4120,8 +4169,17 @@ function validateTemplateSyntax(html, stateTagName, bindAttrName = "data-wcs", l
4120
4169
  }
4121
4170
  for (let i = 1; i < parts.length; i++) {
4122
4171
  const filterName = parts[i].trim().replace(/\(.*$/, "");
4123
- if (filterName && !filterNameSet.has(filterName)) {
4124
- const filterOffset = item.expression.indexOf(parts[i]);
4172
+ const filterOffset = item.expression.indexOf(parts[i]) + (parts[i].length - parts[i].trimStart().length);
4173
+ const canonical = canonicalFilterName(filterName);
4174
+ if (filterName && canonical !== filterName && filterNameSet.has(canonical)) {
4175
+ diagnostics.push({
4176
+ code: WcsDiagnosticCode.NameAlias,
4177
+ start: item.exprStart + filterOffset,
4178
+ end: item.exprStart + filterOffset + filterName.length,
4179
+ message: msgs.nameAlias(filterName, canonical),
4180
+ severity: "info"
4181
+ });
4182
+ } else if (filterName && !filterNameSet.has(filterName)) {
4125
4183
  diagnostics.push({
4126
4184
  code: WcsDiagnosticCode.FilterUnknown,
4127
4185
  start: item.exprStart + filterOffset,
@@ -6879,7 +6937,8 @@ var RECURSION_APIS = ["getAll", "setAll", "resolve", "postUpdate", "trackDepende
6879
6937
  var UNSUPPORTED_API_SITE = {
6880
6938
  $resolve: "resolve",
6881
6939
  $postUpdate: "postUpdate",
6882
- $trackDependency: "trackDependency"
6940
+ $trackDependency: "trackDependency",
6941
+ $dependOn: "trackDependency"
6883
6942
  };
6884
6943
  var BRACKET_ASSIGNMENT = new RegExp(`${ROOT_BRACKET}${ASSIGN_TAIL}`, "g");
6885
6944
  var PRE_BRACKET_INCDEC = new RegExp(`${PRE_INCDEC}${ROOT_BRACKET}`, "g");
@@ -9839,16 +9898,16 @@ pp$5.parseExprOp = function(left, leftStartPos, leftStartLoc, minPrec, forInit)
9839
9898
  if (prec != null && (!forInit || this.type !== types$1._in)) {
9840
9899
  if (prec > minPrec) {
9841
9900
  var logical = this.type === types$1.logicalOR || this.type === types$1.logicalAND;
9842
- var coalesce = this.type === types$1.coalesce;
9843
- if (coalesce) {
9901
+ var coalesce2 = this.type === types$1.coalesce;
9902
+ if (coalesce2) {
9844
9903
  prec = types$1.logicalAND.binop;
9845
9904
  }
9846
9905
  var op = this.value;
9847
9906
  this.next();
9848
9907
  var startPos = this.start, startLoc = this.startLoc;
9849
9908
  var right = this.parseExprOp(this.parseMaybeUnary(null, false, false, forInit), startPos, startLoc, prec, forInit);
9850
- var node = this.buildBinary(leftStartPos, leftStartLoc, left, right, op, logical || coalesce);
9851
- if (logical && this.type === types$1.coalesce || coalesce && (this.type === types$1.logicalOR || this.type === types$1.logicalAND)) {
9909
+ var node = this.buildBinary(leftStartPos, leftStartLoc, left, right, op, logical || coalesce2);
9910
+ if (logical && this.type === types$1.coalesce || coalesce2 && (this.type === types$1.logicalOR || this.type === types$1.logicalAND)) {
9852
9911
  this.raiseRecoverable(this.start, "Logical expressions and coalesce expressions cannot be mixed. Wrap either by parentheses");
9853
9912
  }
9854
9913
  return this.parseExprOp(node, leftStartPos, leftStartLoc, minPrec, forInit);
@@ -13099,8 +13158,9 @@ function parse3(input, options) {
13099
13158
  // src/service/scriptAst.ts
13100
13159
  var PREFIX = "(async function* () {\n";
13101
13160
  var SUFFIX = "\n})";
13102
- var PATH_ARG_APIS = /* @__PURE__ */ new Set(["$getAll", "$resolve", "$trackDependency"]);
13103
- var UNTRACK_API = "$untrackDependency";
13161
+ var PATH_ARG_APIS = /* @__PURE__ */ new Set(["$getAll", "$resolve", "$dependOn", "$trackDependency"]);
13162
+ var TRACK_APIS = /* @__PURE__ */ new Set(["$dependOn", "$trackDependency"]);
13163
+ var UNTRACK_APIS = /* @__PURE__ */ new Set(["$untracked", "$untrackDependency"]);
13104
13164
  function collectGetterReads(body) {
13105
13165
  let program;
13106
13166
  try {
@@ -13325,7 +13385,7 @@ function visitCall(node, scope, out) {
13325
13385
  const { segments, base } = resolveChain(callee);
13326
13386
  if (isThisRoot(base, scope) && segments.length === 1 && segments[0].text !== null) {
13327
13387
  const api = segments[0].text;
13328
- if (api === UNTRACK_API) return;
13388
+ if (UNTRACK_APIS.has(api)) return;
13329
13389
  if (PATH_ARG_APIS.has(api)) {
13330
13390
  const first = node.arguments[0];
13331
13391
  const path = first !== void 0 && first.type !== "SpreadElement" ? literalString2(first) : null;
@@ -13333,7 +13393,7 @@ function visitCall(node, scope, out) {
13333
13393
  out.push({
13334
13394
  path,
13335
13395
  chain: null,
13336
- form: api === "$trackDependency" ? "track" : "api",
13396
+ form: TRACK_APIS.has(api) ? "track" : "api",
13337
13397
  callee: false,
13338
13398
  written: false,
13339
13399
  start: node.start - PREFIX.length,
@@ -13516,7 +13576,35 @@ function buildReferenceIndex(html, options = {}) {
13516
13576
  }
13517
13577
 
13518
13578
  // src/service/semanticValidator.ts
13519
- var STATE_UPDATED_CALLBACK = "$updatedCallback";
13579
+ var STATE_UPDATED_CALLBACKS = /* @__PURE__ */ new Set(["$renderedCallback", "$updatedCallback"]);
13580
+ var OLD_API_NAMES = { $trackDependency: "$dependOn", $untrackDependency: "$untracked" };
13581
+ var OLD_DECLARATION_KEYS = { $streams: "$stream", $updatedCallback: "$renderedCallback" };
13582
+ var OLD_API_CALL = /\.\s*(\$trackDependency|\$untrackDependency)\b/g;
13583
+ var OLD_DECLARATION_KEY = /(^|[{,\s])(\$streams|\$updatedCallback)(?=\s*[:(])/g;
13584
+ function validateNameAliases(script, scriptStart, locale2) {
13585
+ const msgs = getMessages(locale2);
13586
+ const scan = blankComments(script);
13587
+ const out = [];
13588
+ const push2 = (name, canonical, offset2) => {
13589
+ out.push({
13590
+ code: WcsDiagnosticCode.NameAlias,
13591
+ start: scriptStart + offset2,
13592
+ end: scriptStart + offset2 + name.length,
13593
+ message: msgs.nameAlias(name, canonical),
13594
+ severity: "info"
13595
+ });
13596
+ };
13597
+ OLD_API_CALL.lastIndex = 0;
13598
+ let match;
13599
+ while ((match = OLD_API_CALL.exec(scan)) !== null) {
13600
+ push2(match[1], OLD_API_NAMES[match[1]], match.index + match[0].length - match[1].length);
13601
+ }
13602
+ OLD_DECLARATION_KEY.lastIndex = 0;
13603
+ while ((match = OLD_DECLARATION_KEY.exec(scan)) !== null) {
13604
+ push2(match[2], OLD_DECLARATION_KEYS[match[2]], match.index + match[1].length);
13605
+ }
13606
+ return out;
13607
+ }
13520
13608
  var API_CALL = /\.\s*\$(getAll|setAll|resolve)\s*\(/g;
13521
13609
  function validateIndexArity(script, scriptStart, locale2) {
13522
13610
  const msgs = getMessages(locale2);
@@ -13698,13 +13786,13 @@ var PATH_TEST_LITERAL = /(?:\.\s*(?:includes|indexOf)\s*\(\s*|[!=]==\s*)(["'])((
13698
13786
  function validateUpdatedCallbackDemand(html, stateTagName, bindAttrName, locale2) {
13699
13787
  const blocks = parseWcsScriptBlocks(html, stateTagName);
13700
13788
  if (blocks.length === 0) return [];
13701
- const hasCallback = blocks.some((block) => block.content.includes(STATE_UPDATED_CALLBACK));
13789
+ const hasCallback = blocks.some((block) => [...STATE_UPDATED_CALLBACKS].some((name) => block.content.includes(name)));
13702
13790
  if (!hasCallback) return [];
13703
13791
  const msgs = getMessages(locale2);
13704
13792
  const boundPaths = collectBoundPaths(html, stateTagName, bindAttrName);
13705
13793
  const out = [];
13706
13794
  for (const block of blocks) {
13707
- const callback = analyzeCallableBodies(block.content).find((entry) => entry.name === STATE_UPDATED_CALLBACK && entry.kind === "method");
13795
+ const callback = analyzeCallableBodies(block.content).find((entry) => STATE_UPDATED_CALLBACKS.has(entry.name) && entry.kind === "method");
13708
13796
  if (callback === void 0) continue;
13709
13797
  if (block.mountPath !== null) continue;
13710
13798
  const declared = new Set(analyzeStatePaths(block.content).map((p) => p.path));
@@ -13751,6 +13839,7 @@ function validateSemantics(html, stateTagName = "wcs-state", locale2, bindAttrNa
13751
13839
  const getNestedWriteRoots = () => nestedWriteRoots ??= collectNestedWriteRoots(html, stateTagName, bindAttrName, blocks);
13752
13840
  for (const block of blocks) {
13753
13841
  out.push(...validateIndexArity(block.content, block.contentStart, locale2));
13842
+ out.push(...validateNameAliases(block.content, block.contentStart, locale2));
13754
13843
  out.push(...validateGetterCycles(block.content, block.contentStart, locale2));
13755
13844
  out.push(...validateGetterUntrackedReads(block.content, block.contentStart, getNestedWriteRoots, locale2));
13756
13845
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wcstack/lint",
3
- "version": "3.1.0",
3
+ "version": "3.2.0",
4
4
  "description": "Static-contract validator CLI (wcs-validate) for wcstack data-wcs bindings and wcstack.manifest.json sidecars. Thin npm wrapper around the wcstack-intellisense validator core.",
5
5
  "type": "module",
6
6
  "bin": {