@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.
- package/dist/cli.cjs +141 -52
- 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("
|
|
380
|
+
const opt = options?.[0] ?? optionsRequired("add");
|
|
366
381
|
if (!validateNumberString(opt)) {
|
|
367
|
-
optionMustBeNumber("
|
|
382
|
+
optionMustBeNumber("add");
|
|
368
383
|
}
|
|
369
384
|
return (value) => {
|
|
370
385
|
if (typeof value !== "number") {
|
|
371
|
-
valueMustBeNumber("
|
|
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("
|
|
392
|
+
const opt = options?.[0] ?? optionsRequired("sub");
|
|
378
393
|
if (!validateNumberString(opt)) {
|
|
379
|
-
optionMustBeNumber("
|
|
394
|
+
optionMustBeNumber("sub");
|
|
380
395
|
}
|
|
381
396
|
return (value) => {
|
|
382
397
|
if (typeof value !== "number") {
|
|
383
|
-
valueMustBeNumber("
|
|
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("
|
|
468
|
+
optionMustBeNumber("toFixed");
|
|
454
469
|
}
|
|
455
470
|
return (value) => {
|
|
456
471
|
if (typeof value !== "number") {
|
|
457
|
-
valueMustBeNumber("
|
|
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("
|
|
545
|
+
const opt1 = options?.[0] ?? optionsRequired("padStart");
|
|
531
546
|
if (!validateNumberString(opt1)) {
|
|
532
|
-
optionMustBeNumber("
|
|
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("
|
|
565
|
+
const opt = options?.[0] ?? optionsRequired("repeat");
|
|
541
566
|
if (!validateNumberString(opt)) {
|
|
542
|
-
optionMustBeNumber("
|
|
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
|
-
"
|
|
743
|
-
"
|
|
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
|
-
"
|
|
779
|
+
"toFixed": fix,
|
|
750
780
|
"locale": locale,
|
|
751
|
-
"
|
|
752
|
-
"
|
|
753
|
-
"
|
|
781
|
+
"upper": uc,
|
|
782
|
+
"lower": lc,
|
|
783
|
+
"capitalize": cap,
|
|
754
784
|
"trim": trim,
|
|
755
785
|
"slice": slice,
|
|
756
786
|
"substr": substr,
|
|
757
|
-
"
|
|
758
|
-
"
|
|
759
|
-
"
|
|
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
|
-
"
|
|
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
|
-
|
|
794
|
-
|
|
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
|
-
|
|
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
|
-
|
|
805
|
-
|
|
806
|
-
|
|
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
|
-
|
|
811
|
-
|
|
812
|
-
|
|
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
|
-
|
|
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 = "$
|
|
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 = "$
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
4124
|
-
|
|
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
|
|
9843
|
-
if (
|
|
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 ||
|
|
9851
|
-
if (logical && this.type === types$1.coalesce ||
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
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
|
|
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.
|
|
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": {
|