@wcstack/lint 3.0.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 +190 -53
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -201,6 +201,12 @@ var WcsDiagnosticCode = {
|
|
|
201
201
|
// --- built-in wcs-* tag contract (generated/builtinTags.generated.ts が正本) ---
|
|
202
202
|
// 未知メンバーへのバインド(プロパティ / command. / eventToken. キー)。黙って無視される。
|
|
203
203
|
TagMemberUnknown: "wcs/tag-member-unknown",
|
|
204
|
+
// タグのメンバー名が "on" で始まる(`once` 等)のに先頭ドット無しで束縛した: ランタイムはイベント束縛にして
|
|
205
|
+
// "ce" イベントを待ち、値は届かない。明示のプロパティ形 `.once:` を提案する(@wcstack/state 3.1・要件 B5 / 3.x 計画 D36)
|
|
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",
|
|
204
210
|
// wcBindable 無宣言タグ(wcs-fetch-header 等のヘルパー)への spread。
|
|
205
211
|
// ランタイム(expandSpread)は raiseError で落とす。
|
|
206
212
|
SpreadNoBindable: "wcs/spread-no-bindable",
|
|
@@ -264,6 +270,18 @@ function valueMustBeDate(fnName) {
|
|
|
264
270
|
function valueMustBeArray(fnName) {
|
|
265
271
|
raiseError(`filter ${fnName} requires an array value`);
|
|
266
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
|
+
};
|
|
267
285
|
function validateNumberString(value) {
|
|
268
286
|
if (!value || isNaN(Number(value))) {
|
|
269
287
|
return false;
|
|
@@ -359,25 +377,25 @@ var ge = (options) => {
|
|
|
359
377
|
};
|
|
360
378
|
};
|
|
361
379
|
var inc = (options) => {
|
|
362
|
-
const opt = options?.[0] ?? optionsRequired("
|
|
380
|
+
const opt = options?.[0] ?? optionsRequired("add");
|
|
363
381
|
if (!validateNumberString(opt)) {
|
|
364
|
-
optionMustBeNumber("
|
|
382
|
+
optionMustBeNumber("add");
|
|
365
383
|
}
|
|
366
384
|
return (value) => {
|
|
367
385
|
if (typeof value !== "number") {
|
|
368
|
-
valueMustBeNumber("
|
|
386
|
+
valueMustBeNumber("add");
|
|
369
387
|
}
|
|
370
388
|
return value + Number(opt);
|
|
371
389
|
};
|
|
372
390
|
};
|
|
373
391
|
var dec = (options) => {
|
|
374
|
-
const opt = options?.[0] ?? optionsRequired("
|
|
392
|
+
const opt = options?.[0] ?? optionsRequired("sub");
|
|
375
393
|
if (!validateNumberString(opt)) {
|
|
376
|
-
optionMustBeNumber("
|
|
394
|
+
optionMustBeNumber("sub");
|
|
377
395
|
}
|
|
378
396
|
return (value) => {
|
|
379
397
|
if (typeof value !== "number") {
|
|
380
|
-
valueMustBeNumber("
|
|
398
|
+
valueMustBeNumber("sub");
|
|
381
399
|
}
|
|
382
400
|
return value - Number(opt);
|
|
383
401
|
};
|
|
@@ -447,11 +465,11 @@ var clamp = (options) => {
|
|
|
447
465
|
var fix = (options) => {
|
|
448
466
|
const opt = options?.[0] ?? "0";
|
|
449
467
|
if (!validateNumberString(opt)) {
|
|
450
|
-
optionMustBeNumber("
|
|
468
|
+
optionMustBeNumber("toFixed");
|
|
451
469
|
}
|
|
452
470
|
return (value) => {
|
|
453
471
|
if (typeof value !== "number") {
|
|
454
|
-
valueMustBeNumber("
|
|
472
|
+
valueMustBeNumber("toFixed");
|
|
455
473
|
}
|
|
456
474
|
return value.toFixed(Number(opt));
|
|
457
475
|
};
|
|
@@ -524,19 +542,29 @@ var substr = (options) => {
|
|
|
524
542
|
};
|
|
525
543
|
};
|
|
526
544
|
var pad = (options) => {
|
|
527
|
-
const opt1 = options?.[0] ?? optionsRequired("
|
|
545
|
+
const opt1 = options?.[0] ?? optionsRequired("padStart");
|
|
528
546
|
if (!validateNumberString(opt1)) {
|
|
529
|
-
optionMustBeNumber("
|
|
547
|
+
optionMustBeNumber("padStart");
|
|
530
548
|
}
|
|
531
549
|
const opt2 = options?.[1] ?? "0";
|
|
532
550
|
return (value) => {
|
|
533
551
|
return String(value).padStart(Number(opt1), opt2);
|
|
534
552
|
};
|
|
535
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
|
+
};
|
|
536
564
|
var rep = (options) => {
|
|
537
|
-
const opt = options?.[0] ?? optionsRequired("
|
|
565
|
+
const opt = options?.[0] ?? optionsRequired("repeat");
|
|
538
566
|
if (!validateNumberString(opt)) {
|
|
539
|
-
optionMustBeNumber("
|
|
567
|
+
optionMustBeNumber("repeat");
|
|
540
568
|
}
|
|
541
569
|
return (value) => {
|
|
542
570
|
return String(value).repeat(Number(opt));
|
|
@@ -708,6 +736,11 @@ var defaults = (options, literals) => {
|
|
|
708
736
|
return value;
|
|
709
737
|
};
|
|
710
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
|
+
};
|
|
711
744
|
var boolean = (_options) => {
|
|
712
745
|
return (value) => {
|
|
713
746
|
return Boolean(value);
|
|
@@ -736,24 +769,25 @@ var builtinFilters = {
|
|
|
736
769
|
"le": le,
|
|
737
770
|
"gt": gt,
|
|
738
771
|
"ge": ge,
|
|
739
|
-
"
|
|
740
|
-
"
|
|
772
|
+
"add": inc,
|
|
773
|
+
"sub": dec,
|
|
741
774
|
"mul": mul,
|
|
742
775
|
"div": div,
|
|
743
776
|
"mod": mod,
|
|
744
777
|
"abs": abs,
|
|
745
778
|
"clamp": clamp,
|
|
746
|
-
"
|
|
779
|
+
"toFixed": fix,
|
|
747
780
|
"locale": locale,
|
|
748
|
-
"
|
|
749
|
-
"
|
|
750
|
-
"
|
|
781
|
+
"upper": uc,
|
|
782
|
+
"lower": lc,
|
|
783
|
+
"capitalize": cap,
|
|
751
784
|
"trim": trim,
|
|
752
785
|
"slice": slice,
|
|
753
786
|
"substr": substr,
|
|
754
|
-
"
|
|
755
|
-
"
|
|
756
|
-
"
|
|
787
|
+
"padStart": pad,
|
|
788
|
+
"padEnd": padEnd,
|
|
789
|
+
"repeat": rep,
|
|
790
|
+
"reverse": rev,
|
|
757
791
|
"truncate": truncate,
|
|
758
792
|
"join": join,
|
|
759
793
|
"int": int,
|
|
@@ -771,10 +805,11 @@ var builtinFilters = {
|
|
|
771
805
|
"falsy": falsy,
|
|
772
806
|
"truthy": truthy,
|
|
773
807
|
"defaults": defaults,
|
|
808
|
+
"coalesce": coalesce,
|
|
774
809
|
"boolean": boolean,
|
|
775
810
|
"number": number,
|
|
776
811
|
"string": string,
|
|
777
|
-
"
|
|
812
|
+
"nullIfEmpty": _null
|
|
778
813
|
};
|
|
779
814
|
var outputBuiltinFilters = builtinFilters;
|
|
780
815
|
var builtinFilterMeta = {
|
|
@@ -787,26 +822,27 @@ var builtinFilterMeta = {
|
|
|
787
822
|
gt: { description: "\u3088\u308A\u5927\u304D\u3044\u304B", hasArgs: true, resultType: "boolean", acceptTypes: ["number", "string"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
|
|
788
823
|
ge: { description: "\u4EE5\u4E0A\u304B", hasArgs: true, resultType: "boolean", acceptTypes: ["number", "string"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
|
|
789
824
|
// 算術
|
|
790
|
-
|
|
791
|
-
|
|
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"] },
|
|
792
827
|
mul: { description: "\u4E57\u7B97", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
|
|
793
828
|
div: { description: "\u9664\u7B97", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
|
|
794
829
|
mod: { description: "\u5270\u4F59", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
|
|
795
830
|
abs: { description: "\u7D76\u5BFE\u5024", hasArgs: false, resultType: "number", acceptTypes: ["number"], minArgs: 0, maxArgs: 0 },
|
|
796
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"] },
|
|
797
832
|
// 数値フォーマット
|
|
798
|
-
|
|
833
|
+
toFixed: { description: "\u56FA\u5B9A\u5C0F\u6570\u70B9\u8868\u8A18", hasArgs: true, resultType: "string", acceptTypes: ["number"], minArgs: 0, maxArgs: 1, argTypes: ["number"] },
|
|
799
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"] },
|
|
800
835
|
// 文字列
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
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 },
|
|
804
839
|
trim: { description: "\u524D\u5F8C\u306E\u7A7A\u767D\u3092\u524A\u9664", hasArgs: false, resultType: "string", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 },
|
|
805
840
|
slice: { description: "\u90E8\u5206\u6587\u5B57\u5217 (start[,end])", hasArgs: true, resultType: "string", acceptTypes: ["string"], minArgs: 1, maxArgs: 2, argTypes: ["number", "number"] },
|
|
806
841
|
substr: { description: "\u90E8\u5206\u6587\u5B57\u5217 (pos,len)", hasArgs: true, resultType: "string", acceptTypes: ["string"], minArgs: 1, maxArgs: 2, argTypes: ["number", "number"] },
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
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 },
|
|
810
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"] },
|
|
811
847
|
join: { description: "\u914D\u5217\u3092\u9023\u7D50 ([separator])", hasArgs: true, resultType: "string", acceptTypes: ["array"], minArgs: 0, maxArgs: 1, argTypes: ["string"] },
|
|
812
848
|
// 数値パース・丸め
|
|
@@ -829,10 +865,11 @@ var builtinFilterMeta = {
|
|
|
829
865
|
falsy: { description: "\u507D\u5024\u304B\u5224\u5B9A", hasArgs: false, resultType: "boolean", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
|
|
830
866
|
truthy: { description: "\u771F\u5024\u304B\u5224\u5B9A", hasArgs: false, resultType: "boolean", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
|
|
831
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"] },
|
|
832
869
|
boolean: { description: "\u30D6\u30FC\u30EB\u5024\u306B\u5909\u63DB", hasArgs: false, resultType: "boolean", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
|
|
833
870
|
number: { description: "\u6570\u5024\u306B\u5909\u63DB", hasArgs: false, resultType: "number", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
|
|
834
871
|
string: { description: "\u6587\u5B57\u5217\u306B\u5909\u63DB", hasArgs: false, resultType: "string", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
|
|
835
|
-
|
|
872
|
+
nullIfEmpty: { description: "\u7A7A\u6587\u5B57\u5217\u3092null\u306B\u5909\u63DB", hasArgs: false, resultType: "passthrough", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 }
|
|
836
873
|
};
|
|
837
874
|
var STRUCTURAL_BINDING_TYPE_SET = /* @__PURE__ */ new Set([
|
|
838
875
|
"if",
|
|
@@ -877,7 +914,7 @@ for (let i = 0; i < MAX_WILDCARD_DEPTH; i++) {
|
|
|
877
914
|
Object.freeze(tmpIndexByIndexName);
|
|
878
915
|
var STATE_CONNECTED_CALLBACK_NAME = "$connectedCallback";
|
|
879
916
|
var STATE_DISCONNECTED_CALLBACK_NAME = "$disconnectedCallback";
|
|
880
|
-
var STATE_UPDATED_CALLBACK_NAME = "$
|
|
917
|
+
var STATE_UPDATED_CALLBACK_NAME = "$renderedCallback";
|
|
881
918
|
var STATE_ERROR_CALLBACK_NAME = "$errorCallback";
|
|
882
919
|
var WEBCOMPONENT_STATE_READY_CALLBACK_NAME = "$stateReadyCallback";
|
|
883
920
|
var STATE_BINDABLES_NAME = "$bindables";
|
|
@@ -886,7 +923,7 @@ var STATE_COMMAND_TOKENS_NAME = "$commandTokens";
|
|
|
886
923
|
var STATE_COMMAND_NAMESPACE_NAME = "$command";
|
|
887
924
|
var STATE_EVENT_TOKENS_NAME = "$eventTokens";
|
|
888
925
|
var STATE_ON_NAME = "$on";
|
|
889
|
-
var STATE_STREAMS_NAME = "$
|
|
926
|
+
var STATE_STREAMS_NAME = "$stream";
|
|
890
927
|
var STATE_WATCH_NAME = "$watch";
|
|
891
928
|
var STATE_SCAN_NAME = "$scan";
|
|
892
929
|
var STATE_RECURSION_NAME = "$recursion";
|
|
@@ -923,6 +960,7 @@ function getWcsManifest() {
|
|
|
923
960
|
elseKeyword: ELSE_KEYWORD,
|
|
924
961
|
spread: SPREAD_PROP,
|
|
925
962
|
eventPropertyPrefix: EVENT_PROP_PREFIX,
|
|
963
|
+
explicitPropertyPrefix: DELIMITER,
|
|
926
964
|
propNamespaces: {
|
|
927
965
|
eventToken: EVENT_TOKEN_NAMESPACE,
|
|
928
966
|
command: COMMAND_NAMESPACE,
|
|
@@ -935,6 +973,7 @@ function getWcsManifest() {
|
|
|
935
973
|
// 実装(Record のキー)から自動導出。手リストを持たない=ドリフトの構造的排除。
|
|
936
974
|
filters: Object.keys(outputBuiltinFilters),
|
|
937
975
|
filterMeta: builtinFilterMeta,
|
|
976
|
+
filterAliases: builtinFilterAliases,
|
|
938
977
|
reservedLifecycle: [
|
|
939
978
|
STATE_CONNECTED_CALLBACK_NAME,
|
|
940
979
|
STATE_DISCONNECTED_CALLBACK_NAME,
|
|
@@ -961,6 +1000,9 @@ function getWcsManifest() {
|
|
|
961
1000
|
}
|
|
962
1001
|
|
|
963
1002
|
// src/service/completionData.ts
|
|
1003
|
+
function canonicalFilterName(name) {
|
|
1004
|
+
return Object.prototype.hasOwnProperty.call(builtinFilterAliases, name) ? builtinFilterAliases[name] : name;
|
|
1005
|
+
}
|
|
964
1006
|
var BUILTIN_FILTERS = Object.entries(builtinFilterMeta).map(
|
|
965
1007
|
([name, meta]) => ({ name, ...meta })
|
|
966
1008
|
);
|
|
@@ -1136,7 +1178,7 @@ function coversSuffix(spec, familySuffix, suffix) {
|
|
|
1136
1178
|
}
|
|
1137
1179
|
|
|
1138
1180
|
// src/service/stateAnalyzer.ts
|
|
1139
|
-
var
|
|
1181
|
+
var RESERVED_STREAMS_KEYS = /* @__PURE__ */ new Set(["$stream", "$streams"]);
|
|
1140
1182
|
var RESERVED_COMMAND_TOKENS_KEY = "$commandTokens";
|
|
1141
1183
|
var RESERVED_EVENT_TOKENS_KEY = "$eventTokens";
|
|
1142
1184
|
var RESERVED_LIST_KEYS_KEY = "$listKeys";
|
|
@@ -1508,7 +1550,7 @@ function findNonObjectDeclaration(scriptContent, key, rejectArray = false) {
|
|
|
1508
1550
|
return span;
|
|
1509
1551
|
}
|
|
1510
1552
|
function collectReservedKeyPaths(prop, paths, pendingStreamValues, pendingListKeys) {
|
|
1511
|
-
if (prop.name
|
|
1553
|
+
if (RESERVED_STREAMS_KEYS.has(prop.name) && prop.kind === "data" && prop.value && isObjectLiteral(prop.value)) {
|
|
1512
1554
|
const entries = parseTopLevelProperties(extractObjectContent(prop.value));
|
|
1513
1555
|
for (const entry of entries) {
|
|
1514
1556
|
if (entry.kind !== "data" || entry.name.startsWith("$")) continue;
|
|
@@ -2637,6 +2679,8 @@ var ja = {
|
|
|
2637
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`,
|
|
2638
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`,
|
|
2639
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`,
|
|
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`,
|
|
2640
2684
|
tagCommandUnknown: (name, tag, declared) => `"${name}" \u306F <${tag}> \u306E command \u3067\u306F\u3042\u308A\u307E\u305B\u3093\uFF08\u5BA3\u8A00\u6E08\u307F: ${declared}\uFF09`,
|
|
2641
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`,
|
|
2642
2686
|
tagEventTokenKeyUnknown: (name, tag, declared) => `eventToken \u306E\u30AD\u30FC "${name}" \u306F <${tag}> \u306E wcBindable \u30D7\u30ED\u30D1\u30C6\u30A3\u3067\u306F\u3042\u308A\u307E\u305B\u3093\u3002\u751F DOM \u30A4\u30D9\u30F3\u30C8\u540D\u306F\u767A\u706B\u3057\u307E\u305B\u3093 \u2014 \u30D7\u30ED\u30D1\u30C6\u30A3\u540D\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\uFF08\u5BA3\u8A00\u6E08\u307F: ${declared}\uFF09`,
|
|
@@ -2826,6 +2870,8 @@ var en = {
|
|
|
2826
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}).`,
|
|
2827
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.`,
|
|
2828
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)`,
|
|
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)`,
|
|
2829
2875
|
tagCommandUnknown: (name, tag, declared) => `"${name}" is not a command of <${tag}> (declared: ${declared})`,
|
|
2830
2876
|
spreadNoBindable: (tag) => `'...' (spread) requires <${tag}> to expose a valid wcBindable declaration \u2014 this tag declares none, so the runtime raises an error`,
|
|
2831
2877
|
tagEventTokenKeyUnknown: (name, tag, declared) => `eventToken key "${name}" is not a wcBindable property of <${tag}>. Raw DOM event names never fire \u2014 use the property name (declared: ${declared})`,
|
|
@@ -3150,7 +3196,6 @@ function validateBindings(html, attrName, stateTagName = "wcs-state", locale2, f
|
|
|
3150
3196
|
structuralTemplates ??= collectStructuralTemplates(html, attrName);
|
|
3151
3197
|
return structuralTemplates;
|
|
3152
3198
|
};
|
|
3153
|
-
const filterNameSet = new Set(BUILTIN_FILTERS.map((f) => f.name));
|
|
3154
3199
|
for (const attr of attrs) {
|
|
3155
3200
|
const bindings = splitBindingExpressions(attr.value);
|
|
3156
3201
|
const nonEmptyCount = bindings.filter((b) => b.trim().length > 0).length;
|
|
@@ -3484,7 +3529,17 @@ function parseFilterSegments(expr, segments, searchStart) {
|
|
|
3484
3529
|
}
|
|
3485
3530
|
function validateFilterUsage(filter, bindingStart, msgs) {
|
|
3486
3531
|
const diagnostics = [];
|
|
3487
|
-
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
|
+
}
|
|
3488
3543
|
if (!info) {
|
|
3489
3544
|
diagnostics.push({
|
|
3490
3545
|
code: WcsDiagnosticCode.FilterUnknown,
|
|
@@ -4114,8 +4169,17 @@ function validateTemplateSyntax(html, stateTagName, bindAttrName = "data-wcs", l
|
|
|
4114
4169
|
}
|
|
4115
4170
|
for (let i = 1; i < parts.length; i++) {
|
|
4116
4171
|
const filterName = parts[i].trim().replace(/\(.*$/, "");
|
|
4117
|
-
|
|
4118
|
-
|
|
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)) {
|
|
4119
4183
|
diagnostics.push({
|
|
4120
4184
|
code: WcsDiagnosticCode.FilterUnknown,
|
|
4121
4185
|
start: item.exprStart + filterOffset,
|
|
@@ -4150,6 +4214,10 @@ var ELSE_KEYWORD2 = "else";
|
|
|
4150
4214
|
var SPREAD_PROP2 = "...";
|
|
4151
4215
|
var EVENT_PROP_PREFIX2 = "on";
|
|
4152
4216
|
var EVENT_TOKEN_NAMESPACE2 = "eventToken";
|
|
4217
|
+
var COMMAND_NAMESPACE2 = "command";
|
|
4218
|
+
var CLASS_NAMESPACE2 = "class";
|
|
4219
|
+
var ATTR_NAMESPACE2 = "attr";
|
|
4220
|
+
var STYLE_NAMESPACE2 = "style";
|
|
4153
4221
|
var INDEX_PARAM_PREFIX2 = "$";
|
|
4154
4222
|
var tmpIndexByIndexName2 = {};
|
|
4155
4223
|
for (let i = 0; i < MAX_WILDCARD_DEPTH2; i++) {
|
|
@@ -4474,6 +4542,13 @@ function parseStatePart(statePart) {
|
|
|
4474
4542
|
};
|
|
4475
4543
|
}
|
|
4476
4544
|
var KEYWORDS_WITHOUT_MODIFIERS = /* @__PURE__ */ new Set([ELSE_KEYWORD2, "if", "elseif", "for", SPREAD_PROP2]);
|
|
4545
|
+
var EXPLICIT_PROPERTY_REJECTED_HEADS = /* @__PURE__ */ new Set([
|
|
4546
|
+
CLASS_NAMESPACE2,
|
|
4547
|
+
ATTR_NAMESPACE2,
|
|
4548
|
+
STYLE_NAMESPACE2,
|
|
4549
|
+
COMMAND_NAMESPACE2,
|
|
4550
|
+
EVENT_TOKEN_NAMESPACE2
|
|
4551
|
+
]);
|
|
4477
4552
|
function splitBindTexts(bindText) {
|
|
4478
4553
|
return splitOutsideQuotes(bindText, BINDING_SEPARATOR2);
|
|
4479
4554
|
}
|
|
@@ -4542,6 +4617,19 @@ function parseBindTextsForElement(bindText) {
|
|
|
4542
4617
|
} else {
|
|
4543
4618
|
const stateResult = parseStatePart(statePart);
|
|
4544
4619
|
const propResult = parsePropPart(propPart);
|
|
4620
|
+
if (propResult.propSegments[0] === "" && propResult.propSegments.length > 1) {
|
|
4621
|
+
const propSegments = propResult.propSegments.slice(1);
|
|
4622
|
+
if (propSegments.includes("") || EXPLICIT_PROPERTY_REJECTED_HEADS.has(propSegments[0])) {
|
|
4623
|
+
raiseError2(`[wcs/binding-syntax] "${propPart}": a leading "." binds an element property by name \u2014 write a non-empty property that is not a namespace (${[...EXPLICIT_PROPERTY_REJECTED_HEADS].join(", ")}).${LINT_HINT}`);
|
|
4624
|
+
}
|
|
4625
|
+
return {
|
|
4626
|
+
...propResult,
|
|
4627
|
+
propName: propSegments.join(DELIMITER2),
|
|
4628
|
+
propSegments,
|
|
4629
|
+
...stateResult,
|
|
4630
|
+
bindingType: "prop"
|
|
4631
|
+
};
|
|
4632
|
+
}
|
|
4545
4633
|
if (propResult.propSegments[0] === EVENT_TOKEN_NAMESPACE2) {
|
|
4546
4634
|
return {
|
|
4547
4635
|
...propResult,
|
|
@@ -6057,10 +6145,28 @@ function validateBindingAgainstContract(tagName, contract, parsed, property, sta
|
|
|
6057
6145
|
const hashIndex = property.indexOf("#");
|
|
6058
6146
|
const modifiers = hashIndex === -1 ? "" : property.slice(hashIndex + 1);
|
|
6059
6147
|
property = hashIndex === -1 ? property : property.slice(0, hashIndex);
|
|
6148
|
+
const explicit = property.startsWith(".") && property !== "...";
|
|
6149
|
+
if (explicit) {
|
|
6150
|
+
property = property.slice(1);
|
|
6151
|
+
if (/^(class|style|attr|command|eventToken)(\.|$)/.test(property)) return;
|
|
6152
|
+
}
|
|
6060
6153
|
if (property === "...") return;
|
|
6061
6154
|
if (STRUCTURAL_DIRECTIVES2.has(property)) return;
|
|
6062
6155
|
if (/^(class|style|attr)\./.test(property)) return;
|
|
6063
|
-
if (/^on\w/.test(property))
|
|
6156
|
+
if (!explicit && /^on\w/.test(property)) {
|
|
6157
|
+
if (contract.properties.includes(property) || property in contract.inputs) {
|
|
6158
|
+
diagnostics.push({
|
|
6159
|
+
code: WcsDiagnosticCode.OnPrefixedMember,
|
|
6160
|
+
start,
|
|
6161
|
+
end,
|
|
6162
|
+
severity: "warning",
|
|
6163
|
+
tag: tagName,
|
|
6164
|
+
member: property,
|
|
6165
|
+
message: msgs.onPrefixedMember(property, tagName)
|
|
6166
|
+
});
|
|
6167
|
+
}
|
|
6168
|
+
return;
|
|
6169
|
+
}
|
|
6064
6170
|
const inputNames = Object.keys(contract.inputs);
|
|
6065
6171
|
if (property.startsWith("command.")) {
|
|
6066
6172
|
const name = property.slice("command.".length);
|
|
@@ -6831,7 +6937,8 @@ var RECURSION_APIS = ["getAll", "setAll", "resolve", "postUpdate", "trackDepende
|
|
|
6831
6937
|
var UNSUPPORTED_API_SITE = {
|
|
6832
6938
|
$resolve: "resolve",
|
|
6833
6939
|
$postUpdate: "postUpdate",
|
|
6834
|
-
$trackDependency: "trackDependency"
|
|
6940
|
+
$trackDependency: "trackDependency",
|
|
6941
|
+
$dependOn: "trackDependency"
|
|
6835
6942
|
};
|
|
6836
6943
|
var BRACKET_ASSIGNMENT = new RegExp(`${ROOT_BRACKET}${ASSIGN_TAIL}`, "g");
|
|
6837
6944
|
var PRE_BRACKET_INCDEC = new RegExp(`${PRE_INCDEC}${ROOT_BRACKET}`, "g");
|
|
@@ -9791,16 +9898,16 @@ pp$5.parseExprOp = function(left, leftStartPos, leftStartLoc, minPrec, forInit)
|
|
|
9791
9898
|
if (prec != null && (!forInit || this.type !== types$1._in)) {
|
|
9792
9899
|
if (prec > minPrec) {
|
|
9793
9900
|
var logical = this.type === types$1.logicalOR || this.type === types$1.logicalAND;
|
|
9794
|
-
var
|
|
9795
|
-
if (
|
|
9901
|
+
var coalesce2 = this.type === types$1.coalesce;
|
|
9902
|
+
if (coalesce2) {
|
|
9796
9903
|
prec = types$1.logicalAND.binop;
|
|
9797
9904
|
}
|
|
9798
9905
|
var op = this.value;
|
|
9799
9906
|
this.next();
|
|
9800
9907
|
var startPos = this.start, startLoc = this.startLoc;
|
|
9801
9908
|
var right = this.parseExprOp(this.parseMaybeUnary(null, false, false, forInit), startPos, startLoc, prec, forInit);
|
|
9802
|
-
var node = this.buildBinary(leftStartPos, leftStartLoc, left, right, op, logical ||
|
|
9803
|
-
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)) {
|
|
9804
9911
|
this.raiseRecoverable(this.start, "Logical expressions and coalesce expressions cannot be mixed. Wrap either by parentheses");
|
|
9805
9912
|
}
|
|
9806
9913
|
return this.parseExprOp(node, leftStartPos, leftStartLoc, minPrec, forInit);
|
|
@@ -13051,8 +13158,9 @@ function parse3(input, options) {
|
|
|
13051
13158
|
// src/service/scriptAst.ts
|
|
13052
13159
|
var PREFIX = "(async function* () {\n";
|
|
13053
13160
|
var SUFFIX = "\n})";
|
|
13054
|
-
var PATH_ARG_APIS = /* @__PURE__ */ new Set(["$getAll", "$resolve", "$trackDependency"]);
|
|
13055
|
-
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"]);
|
|
13056
13164
|
function collectGetterReads(body) {
|
|
13057
13165
|
let program;
|
|
13058
13166
|
try {
|
|
@@ -13277,7 +13385,7 @@ function visitCall(node, scope, out) {
|
|
|
13277
13385
|
const { segments, base } = resolveChain(callee);
|
|
13278
13386
|
if (isThisRoot(base, scope) && segments.length === 1 && segments[0].text !== null) {
|
|
13279
13387
|
const api = segments[0].text;
|
|
13280
|
-
if (api
|
|
13388
|
+
if (UNTRACK_APIS.has(api)) return;
|
|
13281
13389
|
if (PATH_ARG_APIS.has(api)) {
|
|
13282
13390
|
const first = node.arguments[0];
|
|
13283
13391
|
const path = first !== void 0 && first.type !== "SpreadElement" ? literalString2(first) : null;
|
|
@@ -13285,7 +13393,7 @@ function visitCall(node, scope, out) {
|
|
|
13285
13393
|
out.push({
|
|
13286
13394
|
path,
|
|
13287
13395
|
chain: null,
|
|
13288
|
-
form: api
|
|
13396
|
+
form: TRACK_APIS.has(api) ? "track" : "api",
|
|
13289
13397
|
callee: false,
|
|
13290
13398
|
written: false,
|
|
13291
13399
|
start: node.start - PREFIX.length,
|
|
@@ -13468,7 +13576,35 @@ function buildReferenceIndex(html, options = {}) {
|
|
|
13468
13576
|
}
|
|
13469
13577
|
|
|
13470
13578
|
// src/service/semanticValidator.ts
|
|
13471
|
-
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
|
+
}
|
|
13472
13608
|
var API_CALL = /\.\s*\$(getAll|setAll|resolve)\s*\(/g;
|
|
13473
13609
|
function validateIndexArity(script, scriptStart, locale2) {
|
|
13474
13610
|
const msgs = getMessages(locale2);
|
|
@@ -13650,13 +13786,13 @@ var PATH_TEST_LITERAL = /(?:\.\s*(?:includes|indexOf)\s*\(\s*|[!=]==\s*)(["'])((
|
|
|
13650
13786
|
function validateUpdatedCallbackDemand(html, stateTagName, bindAttrName, locale2) {
|
|
13651
13787
|
const blocks = parseWcsScriptBlocks(html, stateTagName);
|
|
13652
13788
|
if (blocks.length === 0) return [];
|
|
13653
|
-
const hasCallback = blocks.some((block) => block.content.includes(
|
|
13789
|
+
const hasCallback = blocks.some((block) => [...STATE_UPDATED_CALLBACKS].some((name) => block.content.includes(name)));
|
|
13654
13790
|
if (!hasCallback) return [];
|
|
13655
13791
|
const msgs = getMessages(locale2);
|
|
13656
13792
|
const boundPaths = collectBoundPaths(html, stateTagName, bindAttrName);
|
|
13657
13793
|
const out = [];
|
|
13658
13794
|
for (const block of blocks) {
|
|
13659
|
-
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");
|
|
13660
13796
|
if (callback === void 0) continue;
|
|
13661
13797
|
if (block.mountPath !== null) continue;
|
|
13662
13798
|
const declared = new Set(analyzeStatePaths(block.content).map((p) => p.path));
|
|
@@ -13703,6 +13839,7 @@ function validateSemantics(html, stateTagName = "wcs-state", locale2, bindAttrNa
|
|
|
13703
13839
|
const getNestedWriteRoots = () => nestedWriteRoots ??= collectNestedWriteRoots(html, stateTagName, bindAttrName, blocks);
|
|
13704
13840
|
for (const block of blocks) {
|
|
13705
13841
|
out.push(...validateIndexArity(block.content, block.contentStart, locale2));
|
|
13842
|
+
out.push(...validateNameAliases(block.content, block.contentStart, locale2));
|
|
13706
13843
|
out.push(...validateGetterCycles(block.content, block.contentStart, locale2));
|
|
13707
13844
|
out.push(...validateGetterUntrackedReads(block.content, block.contentStart, getNestedWriteRoots, locale2));
|
|
13708
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": {
|