@wcstack/lint 1.28.0 → 1.30.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 +169 -42
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -110,6 +110,9 @@ var WcsDiagnosticCode = {
|
|
|
110
110
|
// --- built-in wcs-* tag contract (generated/builtinTags.generated.ts が正本) ---
|
|
111
111
|
// 未知メンバーへのバインド(プロパティ / command. / eventToken. キー)。黙って無視される。
|
|
112
112
|
TagMemberUnknown: "wcs/tag-member-unknown",
|
|
113
|
+
// wcBindable 無宣言タグ(wcs-fetch-header 等のヘルパー)への spread。
|
|
114
|
+
// ランタイム(expandSpread)は raiseError で落とす。
|
|
115
|
+
SpreadNoBindable: "wcs/spread-no-bindable",
|
|
113
116
|
// trigger バインド先スロットの true シード(エッジ検出なし・manual バイパスで即発火)。
|
|
114
117
|
TriggerSeededTruthy: "wcs/trigger-seeded-truthy",
|
|
115
118
|
// 非 manual <wcs-storage> value バインド先の空値シード(初期書き戻しが保存値を上書き)。
|
|
@@ -310,6 +313,8 @@ function parseWcsStateElements(html, stateTagName = "wcs-state") {
|
|
|
310
313
|
const jsonAttr = extractAttribute(wcsMatch.tagContent, "json") ?? void 0;
|
|
311
314
|
const stateAttr = extractAttribute(wcsMatch.tagContent, "state") ?? void 0;
|
|
312
315
|
const srcAttr = extractAttribute(wcsMatch.tagContent, "src") ?? void 0;
|
|
316
|
+
const tagStart = pos;
|
|
317
|
+
const tagEnd = wcsMatch.end;
|
|
313
318
|
pos = wcsMatch.end;
|
|
314
319
|
const scriptBlocks = [];
|
|
315
320
|
const wcsCloseIdx = findCloseTag(html, pos, stateTagName);
|
|
@@ -346,7 +351,7 @@ function parseWcsStateElements(html, stateTagName = "wcs-state") {
|
|
|
346
351
|
pos = html.indexOf(">", scriptCloseIdx) + 1;
|
|
347
352
|
if (pos === 0) break;
|
|
348
353
|
}
|
|
349
|
-
elements.push({ stateName, jsonAttr, stateAttr, srcAttr, scriptBlocks });
|
|
354
|
+
elements.push({ stateName, jsonAttr, stateAttr, srcAttr, scriptBlocks, tagStart, tagEnd });
|
|
350
355
|
pos = wcsEnd;
|
|
351
356
|
if (wcsCloseIdx !== -1) {
|
|
352
357
|
const closeEnd = html.indexOf(">", wcsCloseIdx);
|
|
@@ -515,6 +520,26 @@ function isNonFunctionLiteral(value) {
|
|
|
515
520
|
if (/^(?:async\s+)?function\b/.test(trimmed) || scan.includes("=>")) return false;
|
|
516
521
|
return /^["'`]/.test(trimmed) || /^-?\d/.test(trimmed) || /^(?:true|false|null|undefined)\b/.test(trimmed) || trimmed.startsWith("[") || trimmed.startsWith("{");
|
|
517
522
|
}
|
|
523
|
+
function findNonObjectWatch(scriptContent) {
|
|
524
|
+
const root = locateDefaultExportObject(scriptContent);
|
|
525
|
+
if (!root) return null;
|
|
526
|
+
const watchProp = parseTopLevelProperties(root.content).find((p) => p.name === RESERVED_WATCH_KEY);
|
|
527
|
+
if (!watchProp || watchProp.nameStart === void 0 || watchProp.nameEnd === void 0) {
|
|
528
|
+
return null;
|
|
529
|
+
}
|
|
530
|
+
const span = { start: root.start + watchProp.nameStart, end: root.start + watchProp.nameEnd };
|
|
531
|
+
if (watchProp.kind === "method") {
|
|
532
|
+
return span;
|
|
533
|
+
}
|
|
534
|
+
if (watchProp.kind !== "data" || !watchProp.value) return null;
|
|
535
|
+
const trimmed = watchProp.value.trim();
|
|
536
|
+
if (trimmed.startsWith("{")) return null;
|
|
537
|
+
const scan = maskCommentsAndStrings(trimmed).trim();
|
|
538
|
+
const isArrowFunction = /^(?:async\s+)?\([^()]*\)\s*=>/.test(scan) || /^(?:async\s+)?[$\w]+\s*=>/.test(scan);
|
|
539
|
+
const isWholeLiteral = /^(["'`])[^"'`]*\1$/.test(scan) || /^-?\d[\w.]*$/.test(scan) || /^(?:true|false|null)$/.test(scan) || /^(?:async\s+)?function\b[\s\S]*\}$/.test(scan);
|
|
540
|
+
if (!isArrowFunction && !isWholeLiteral) return null;
|
|
541
|
+
return span;
|
|
542
|
+
}
|
|
518
543
|
function collectReservedKeyPaths(prop, paths, pendingStreamValues, pendingListKeys, stateName) {
|
|
519
544
|
if (prop.name === RESERVED_STREAMS_KEY && prop.kind === "data" && prop.value && isObjectLiteral(prop.value)) {
|
|
520
545
|
const entries = parseTopLevelProperties(extractObjectContent(prop.value));
|
|
@@ -598,14 +623,9 @@ function pushDataPropertyPathsAt(path, prop, paths, stateName, depth) {
|
|
|
598
623
|
if (prop.value && isArrayLiteral(prop.value)) {
|
|
599
624
|
paths.push({ path: `${path}.*`, kind: "list", stateName });
|
|
600
625
|
paths.push({ path: `${path}.length`, kind: "data", typeHint: "number", stateName });
|
|
601
|
-
|
|
602
|
-
for (const childProp of
|
|
603
|
-
|
|
604
|
-
path: `${path}.*.${childProp.name}`,
|
|
605
|
-
kind: "data",
|
|
606
|
-
typeHint: childProp.typeHint,
|
|
607
|
-
stateName
|
|
608
|
-
});
|
|
626
|
+
if (depth >= MAX_OBJECT_NEST_DEPTH) return;
|
|
627
|
+
for (const childProp of extractArrayElementDataProperties(prop.value)) {
|
|
628
|
+
pushDataPropertyPathsAt(`${path}.*.${childProp.name}`, childProp, paths, stateName, depth + 1);
|
|
609
629
|
}
|
|
610
630
|
return;
|
|
611
631
|
}
|
|
@@ -631,25 +651,27 @@ function analyzeJsonPaths(jsonString, stateName = "default") {
|
|
|
631
651
|
return paths;
|
|
632
652
|
}
|
|
633
653
|
function collectJsonPaths(obj, prefix, paths, stateName, depth) {
|
|
634
|
-
if (depth
|
|
654
|
+
if (depth >= MAX_OBJECT_NEST_DEPTH) return;
|
|
635
655
|
for (const [key, value] of Object.entries(obj)) {
|
|
636
656
|
if (prefix === "" && key.startsWith("$")) continue;
|
|
637
657
|
const path = prefix ? `${prefix}.${key}` : key;
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
658
|
+
pushJsonValuePaths(path, value, paths, stateName, depth);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
function pushJsonValuePaths(path, value, paths, stateName, depth) {
|
|
662
|
+
paths.push({ path, kind: "data", typeHint: inferJsonTypeHint(value), stateName });
|
|
663
|
+
if (Array.isArray(value)) {
|
|
664
|
+
paths.push({ path: `${path}.*`, kind: "list", stateName });
|
|
665
|
+
paths.push({ path: `${path}.length`, kind: "data", typeHint: "number", stateName });
|
|
666
|
+
if (depth >= MAX_OBJECT_NEST_DEPTH) return;
|
|
667
|
+
if (value.length > 0 && typeof value[0] === "object" && value[0] !== null && !Array.isArray(value[0])) {
|
|
668
|
+
const firstElement = value[0];
|
|
669
|
+
for (const [childKey, childValue] of Object.entries(firstElement)) {
|
|
670
|
+
pushJsonValuePaths(`${path}.*.${childKey}`, childValue, paths, stateName, depth + 1);
|
|
649
671
|
}
|
|
650
|
-
} else if (typeof value === "object" && value !== null) {
|
|
651
|
-
collectJsonPaths(value, path, paths, stateName, depth + 1);
|
|
652
672
|
}
|
|
673
|
+
} else if (typeof value === "object" && value !== null) {
|
|
674
|
+
collectJsonPaths(value, path, paths, stateName, depth + 1);
|
|
653
675
|
}
|
|
654
676
|
}
|
|
655
677
|
function inferJsonTypeHint(value) {
|
|
@@ -820,21 +842,15 @@ function extractObjectContent(value) {
|
|
|
820
842
|
if (start === -1) return "";
|
|
821
843
|
return extractBracedContent(trimmed, scan, start);
|
|
822
844
|
}
|
|
823
|
-
function
|
|
845
|
+
function extractArrayElementDataProperties(value) {
|
|
824
846
|
const trimmed = value.trim();
|
|
825
847
|
if (!trimmed.startsWith("[")) return [];
|
|
826
848
|
const scan = maskCommentsAndStrings(trimmed);
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
const
|
|
831
|
-
|
|
832
|
-
for (const prop of allProps) {
|
|
833
|
-
if (prop.kind === "data") {
|
|
834
|
-
props.push({ name: prop.name, typeHint: prop.typeHint });
|
|
835
|
-
}
|
|
836
|
-
}
|
|
837
|
-
return props;
|
|
849
|
+
let first = 1;
|
|
850
|
+
while (first < scan.length && /\s/.test(scan[first])) first++;
|
|
851
|
+
if (scan[first] !== "{") return [];
|
|
852
|
+
const objectContent = extractBracedContent(trimmed, scan, first);
|
|
853
|
+
return parseTopLevelProperties(objectContent).filter((prop) => prop.kind === "data");
|
|
838
854
|
}
|
|
839
855
|
function extractJsDocType(content, propIndex) {
|
|
840
856
|
const before = content.slice(Math.max(0, propIndex - 200), propIndex);
|
|
@@ -966,25 +982,30 @@ function isInsideForTemplate(html, offset, bindAttrName = "data-wcs") {
|
|
|
966
982
|
return false;
|
|
967
983
|
}
|
|
968
984
|
function getInnermostForPath(html, offset, bindAttrName = "data-wcs") {
|
|
985
|
+
const chain = getEnclosingForPaths(html, offset, bindAttrName);
|
|
986
|
+
return chain.length === 0 ? null : chain[chain.length - 1];
|
|
987
|
+
}
|
|
988
|
+
function getEnclosingForPaths(html, offset, bindAttrName = "data-wcs") {
|
|
989
|
+
return getEnclosingFors(html, offset, bindAttrName).map((entry) => entry.path);
|
|
990
|
+
}
|
|
991
|
+
function getEnclosingFors(html, offset, bindAttrName = "data-wcs") {
|
|
969
992
|
const escaped = bindAttrName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
970
993
|
const openRegex = new RegExp(
|
|
971
994
|
`<template[^>]*${escaped}\\s*=\\s*["']\\s*for\\s*:\\s*([^"']+?)\\s*["']`,
|
|
972
995
|
"gi"
|
|
973
996
|
);
|
|
974
|
-
|
|
975
|
-
let bestPos = -1;
|
|
997
|
+
const enclosing = [];
|
|
976
998
|
let match;
|
|
977
999
|
while ((match = openRegex.exec(html)) !== null) {
|
|
978
1000
|
if (match.index >= offset) break;
|
|
979
1001
|
const tagEnd = html.indexOf(">", match.index);
|
|
980
1002
|
if (tagEnd === -1 || tagEnd >= offset) continue;
|
|
981
1003
|
const depth = getForTemplateDepthAt(html, match.index, offset, bindAttrName);
|
|
982
|
-
if (depth > 0
|
|
983
|
-
|
|
984
|
-
bestPos = match.index;
|
|
1004
|
+
if (depth > 0) {
|
|
1005
|
+
enclosing.push({ path: match[1].trim(), anchor: match.index });
|
|
985
1006
|
}
|
|
986
1007
|
}
|
|
987
|
-
return
|
|
1008
|
+
return enclosing;
|
|
988
1009
|
}
|
|
989
1010
|
function getForTemplateDepthAt(html, openPos, offset, bindAttrName) {
|
|
990
1011
|
const tagEnd = html.indexOf(">", openPos);
|
|
@@ -1028,6 +1049,7 @@ var JA_EXPECTED_LABEL = {
|
|
|
1028
1049
|
var ja = {
|
|
1029
1050
|
spreadFilterNotAllowed: () => `\u30B9\u30D7\u30EC\u30C3\u30C9\u306E\u30BF\u30FC\u30B2\u30C3\u30C8\u306B\u30D5\u30A3\u30EB\u30BF\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093`,
|
|
1030
1051
|
spreadTargetRequired: () => `\u30B9\u30D7\u30EC\u30C3\u30C9\u306B\u306F\u30BF\u30FC\u30B2\u30C3\u30C8\u30D1\u30B9\u304C\u5FC5\u8981\u3067\u3059`,
|
|
1052
|
+
structuralMustBeSingle: (d) => `'${d}' \u30D0\u30A4\u30F3\u30C7\u30A3\u30F3\u30B0\u306F\u5358\u72EC\u3067\u6307\u5B9A\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\uFF08';' \u3067\u4ED6\u306E\u30D0\u30A4\u30F3\u30C7\u30A3\u30F3\u30B0\u3068\u4F75\u8A18\u3067\u304D\u307E\u305B\u3093\u3002\u30E9\u30F3\u30BF\u30A4\u30E0\u306F\u8AAD\u307F\u8FBC\u307F\u6642\u306B throw \u3057\u307E\u3059\uFF09`,
|
|
1031
1053
|
eventTokenUndeclared: (t) => `\u30A4\u30D9\u30F3\u30C8\u30C8\u30FC\u30AF\u30F3 "${t}" \u306F $eventTokens \u306B\u5BA3\u8A00\u3055\u308C\u3066\u3044\u307E\u305B\u3093`,
|
|
1032
1054
|
commandRhsFormat: () => `command \u30D0\u30A4\u30F3\u30C7\u30A3\u30F3\u30B0\u306E\u53F3\u8FBA\u306B\u306F $command.<name>\uFF08$commandTokens \u3067\u5BA3\u8A00\uFF09\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044`,
|
|
1033
1055
|
commandTokenUndeclared: (t) => `\u30B3\u30DE\u30F3\u30C9\u30C8\u30FC\u30AF\u30F3 "${t}" \u306F $commandTokens \u306B\u5BA3\u8A00\u3055\u308C\u3066\u3044\u307E\u305B\u3093`,
|
|
@@ -1048,6 +1070,7 @@ var ja = {
|
|
|
1048
1070
|
wcsTextInfo: (e) => `wcs-text \u30D0\u30A4\u30F3\u30C7\u30A3\u30F3\u30B0: ${e}`,
|
|
1049
1071
|
moustacheFouc: (e) => `<template> \u5916\u306E {{ }} \u69CB\u6587\u306F FOUC\uFF08\u521D\u671F\u8868\u793A\u6642\u306B\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u6587\u5B57\u5217\u304C\u898B\u3048\u308B\uFF09\u306E\u539F\u56E0\u306B\u306A\u308A\u307E\u3059\u3002<!--@@:${e}--> \u307E\u305F\u306F\u30B3\u30E1\u30F3\u30C8\u69CB\u6587\u306E\u4F7F\u7528\u3092\u691C\u8A0E\u3057\u3066\u304F\u3060\u3055\u3044\u3002`,
|
|
1050
1072
|
nestedAssign: (sp) => `\u30CD\u30B9\u30C8\u3055\u308C\u305F\u30D7\u30ED\u30D1\u30C6\u30A3\u3078\u306E\u4EE3\u5165\u306F\u30EA\u30A2\u30AF\u30C6\u30A3\u30D6\u66F4\u65B0\u3092\u30C8\u30EA\u30AC\u30FC\u3057\u307E\u305B\u3093\u3002this["${sp}"] \u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002`,
|
|
1073
|
+
watchNotObject: () => `$watch \u306F\u300C\u30D1\u30B9 \u2192 \u30CF\u30F3\u30C9\u30E9\u95A2\u6570\u300D\u306E\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\uFF08\u3053\u306E\u5F62\u306F\u30E9\u30F3\u30BF\u30A4\u30E0\u304C\u8AAD\u307F\u8FBC\u307F\u6642\u306B throw \u3057\u307E\u3059\uFF09`,
|
|
1051
1074
|
watchKeyCrossState: (k) => `$watch \u306E\u30AD\u30FC "${k}" \u306F\u4ED6\u306E state \u3092\u6307\u3057\u3066\u3044\u307E\u3059\u3002@ \u4ED8\u304D\u306E\u8D8A\u5883 watch \u306F\u4F7F\u3048\u307E\u305B\u3093\uFF08\u81EA state \u306E\u30D1\u30B9\u306E\u307F\uFF09`,
|
|
1052
1075
|
watchKeyReserved: (k) => `$watch \u306E\u30AD\u30FC "${k}" \u306F "$" \u3067\u59CB\u3081\u3089\u308C\u307E\u305B\u3093\uFF08\u4E88\u7D04\u540D\u524D\u7A7A\u9593\uFF09`,
|
|
1053
1076
|
watchKeyEmptySegment: (k) => `$watch \u306E\u30AD\u30FC "${k}" \u306B\u7A7A\u306E\u30D1\u30B9\u30BB\u30B0\u30E1\u30F3\u30C8\u304C\u3042\u308A\u307E\u3059`,
|
|
@@ -1058,6 +1081,7 @@ var ja = {
|
|
|
1058
1081
|
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`,
|
|
1059
1082
|
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`,
|
|
1060
1083
|
tagCommandUnknown: (name, tag, declared) => `"${name}" \u306F <${tag}> \u306E command \u3067\u306F\u3042\u308A\u307E\u305B\u3093\uFF08\u5BA3\u8A00\u6E08\u307F: ${declared}\uFF09`,
|
|
1084
|
+
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`,
|
|
1061
1085
|
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`,
|
|
1062
1086
|
didYouMean: (c) => `\u3002\u3082\u3057\u304B\u3057\u3066: "${c}"`,
|
|
1063
1087
|
none: () => `\u306A\u3057`,
|
|
@@ -1075,6 +1099,7 @@ var EN_EXPECTED_LABEL = {
|
|
|
1075
1099
|
var en = {
|
|
1076
1100
|
spreadFilterNotAllowed: () => `Filters cannot be applied to a spread target`,
|
|
1077
1101
|
spreadTargetRequired: () => `Spread requires a target path`,
|
|
1102
|
+
structuralMustBeSingle: (d) => `'${d}' must be the only binding in this attribute (it cannot be combined with ';'; the runtime throws at load time)`,
|
|
1078
1103
|
eventTokenUndeclared: (t) => `Event token "${t}" is not declared in $eventTokens`,
|
|
1079
1104
|
commandRhsFormat: () => `The right side of a command binding must be $command.<name> (declared in $commandTokens)`,
|
|
1080
1105
|
commandTokenUndeclared: (t) => `Command token "${t}" is not declared in $commandTokens`,
|
|
@@ -1095,6 +1120,7 @@ var en = {
|
|
|
1095
1120
|
wcsTextInfo: (e) => `wcs-text binding: ${e}`,
|
|
1096
1121
|
moustacheFouc: (e) => `{{ }} outside a <template> causes FOUC (the raw template string is visible before binding). Consider the comment syntax <!--@@:${e}--> instead.`,
|
|
1097
1122
|
nestedAssign: (sp) => `Assigning to a nested property does not trigger a reactive update. Use this["${sp}"] instead.`,
|
|
1123
|
+
watchNotObject: () => `$watch must be an object mapping state paths to handler functions (the runtime throws on this shape at load time)`,
|
|
1098
1124
|
watchKeyCrossState: (k) => `$watch key "${k}" targets another state. Cross-state watching with @ is not supported (own paths only)`,
|
|
1099
1125
|
watchKeyReserved: (k) => `$watch key "${k}" must not start with "$" (reserved namespace)`,
|
|
1100
1126
|
watchKeyEmptySegment: (k) => `$watch key "${k}" has an empty path segment`,
|
|
@@ -1105,6 +1131,7 @@ var en = {
|
|
|
1105
1131
|
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.`,
|
|
1106
1132
|
tagMemberUnknown: (prop, tag) => `"${prop}" is not a wcBindable member of <${tag}> (bindings to unknown members are silently ignored)`,
|
|
1107
1133
|
tagCommandUnknown: (name, tag, declared) => `"${name}" is not a command of <${tag}> (declared: ${declared})`,
|
|
1134
|
+
spreadNoBindable: (tag) => `'...' (spread) requires <${tag}> to expose a valid wcBindable declaration \u2014 this tag declares none, so the runtime raises an error`,
|
|
1108
1135
|
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})`,
|
|
1109
1136
|
didYouMean: (c) => `. Did you mean "${c}"?`,
|
|
1110
1137
|
none: () => `none`,
|
|
@@ -1140,6 +1167,25 @@ function validateBindings(html, attrName, stateTagName = "wcs-state", locale, fi
|
|
|
1140
1167
|
const filterNameSet = new Set(BUILTIN_FILTERS.map((f) => f.name));
|
|
1141
1168
|
for (const attr of attrs) {
|
|
1142
1169
|
const bindings = splitBindingExpressions(attr.value);
|
|
1170
|
+
const nonEmptyCount = bindings.filter((b) => b.trim().length > 0).length;
|
|
1171
|
+
if (nonEmptyCount > 1) {
|
|
1172
|
+
let scanPos = 0;
|
|
1173
|
+
for (const b of bindings) {
|
|
1174
|
+
const colon = b.indexOf(":");
|
|
1175
|
+
const prop = (colon === -1 ? b : b.slice(0, colon)).trim();
|
|
1176
|
+
if (STRUCTURAL_BINDING_TYPE_SET.has(prop)) {
|
|
1177
|
+
const leading = b.length - b.trimStart().length;
|
|
1178
|
+
diagnostics.push({
|
|
1179
|
+
code: WcsDiagnosticCode.TemplateSyntax,
|
|
1180
|
+
start: attr.valueStart + scanPos + leading,
|
|
1181
|
+
end: attr.valueStart + scanPos + b.trimEnd().length,
|
|
1182
|
+
message: msgs.structuralMustBeSingle(prop),
|
|
1183
|
+
severity: "error"
|
|
1184
|
+
});
|
|
1185
|
+
}
|
|
1186
|
+
scanPos += b.length + 1;
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1143
1189
|
let pos = 0;
|
|
1144
1190
|
for (const binding of bindings) {
|
|
1145
1191
|
const bindingStart = attr.valueStart + pos;
|
|
@@ -2032,6 +2078,7 @@ function isValidTemplatePath(path, pathSet, scopedPaths) {
|
|
|
2032
2078
|
var BUILTIN_TAGS = {
|
|
2033
2079
|
"wcs-accelerometer": {
|
|
2034
2080
|
"package": "accelerometer",
|
|
2081
|
+
"hasWcBindable": true,
|
|
2035
2082
|
"observedAttributes": [],
|
|
2036
2083
|
"inputs": {
|
|
2037
2084
|
"frequency": null
|
|
@@ -2050,6 +2097,7 @@ var BUILTIN_TAGS = {
|
|
|
2050
2097
|
},
|
|
2051
2098
|
"wcs-ambient-light-sensor": {
|
|
2052
2099
|
"package": "ambient-light-sensor",
|
|
2100
|
+
"hasWcBindable": true,
|
|
2053
2101
|
"observedAttributes": [],
|
|
2054
2102
|
"inputs": {
|
|
2055
2103
|
"frequency": null
|
|
@@ -2066,6 +2114,7 @@ var BUILTIN_TAGS = {
|
|
|
2066
2114
|
},
|
|
2067
2115
|
"wcs-audio": {
|
|
2068
2116
|
"package": "audio",
|
|
2117
|
+
"hasWcBindable": true,
|
|
2069
2118
|
"observedAttributes": [
|
|
2070
2119
|
"volume",
|
|
2071
2120
|
"limiter",
|
|
@@ -2098,6 +2147,7 @@ var BUILTIN_TAGS = {
|
|
|
2098
2147
|
},
|
|
2099
2148
|
"wcs-voice": {
|
|
2100
2149
|
"package": "audio",
|
|
2150
|
+
"hasWcBindable": false,
|
|
2101
2151
|
"observedAttributes": [
|
|
2102
2152
|
"poly"
|
|
2103
2153
|
],
|
|
@@ -2107,6 +2157,7 @@ var BUILTIN_TAGS = {
|
|
|
2107
2157
|
},
|
|
2108
2158
|
"wcs-osc": {
|
|
2109
2159
|
"package": "audio",
|
|
2160
|
+
"hasWcBindable": true,
|
|
2110
2161
|
"observedAttributes": [
|
|
2111
2162
|
"frequency",
|
|
2112
2163
|
"detune",
|
|
@@ -2132,6 +2183,7 @@ var BUILTIN_TAGS = {
|
|
|
2132
2183
|
},
|
|
2133
2184
|
"wcs-noise": {
|
|
2134
2185
|
"package": "audio",
|
|
2186
|
+
"hasWcBindable": true,
|
|
2135
2187
|
"observedAttributes": [
|
|
2136
2188
|
"id",
|
|
2137
2189
|
"out",
|
|
@@ -2146,6 +2198,7 @@ var BUILTIN_TAGS = {
|
|
|
2146
2198
|
},
|
|
2147
2199
|
"wcs-biquad": {
|
|
2148
2200
|
"package": "audio",
|
|
2201
|
+
"hasWcBindable": true,
|
|
2149
2202
|
"observedAttributes": [
|
|
2150
2203
|
"frequency",
|
|
2151
2204
|
"q",
|
|
@@ -2171,6 +2224,7 @@ var BUILTIN_TAGS = {
|
|
|
2171
2224
|
},
|
|
2172
2225
|
"wcs-gain": {
|
|
2173
2226
|
"package": "audio",
|
|
2227
|
+
"hasWcBindable": true,
|
|
2174
2228
|
"observedAttributes": [
|
|
2175
2229
|
"gain",
|
|
2176
2230
|
"id",
|
|
@@ -2188,6 +2242,7 @@ var BUILTIN_TAGS = {
|
|
|
2188
2242
|
},
|
|
2189
2243
|
"wcs-delay": {
|
|
2190
2244
|
"package": "audio",
|
|
2245
|
+
"hasWcBindable": true,
|
|
2191
2246
|
"observedAttributes": [
|
|
2192
2247
|
"time",
|
|
2193
2248
|
"feedback",
|
|
@@ -2209,6 +2264,7 @@ var BUILTIN_TAGS = {
|
|
|
2209
2264
|
},
|
|
2210
2265
|
"wcs-shaper": {
|
|
2211
2266
|
"package": "audio",
|
|
2267
|
+
"hasWcBindable": true,
|
|
2212
2268
|
"observedAttributes": [
|
|
2213
2269
|
"amount",
|
|
2214
2270
|
"id",
|
|
@@ -2226,6 +2282,7 @@ var BUILTIN_TAGS = {
|
|
|
2226
2282
|
},
|
|
2227
2283
|
"wcs-env": {
|
|
2228
2284
|
"package": "audio",
|
|
2285
|
+
"hasWcBindable": true,
|
|
2229
2286
|
"observedAttributes": [
|
|
2230
2287
|
"attack",
|
|
2231
2288
|
"decay",
|
|
@@ -2251,6 +2308,7 @@ var BUILTIN_TAGS = {
|
|
|
2251
2308
|
},
|
|
2252
2309
|
"wcs-lfo": {
|
|
2253
2310
|
"package": "audio",
|
|
2311
|
+
"hasWcBindable": true,
|
|
2254
2312
|
"observedAttributes": [
|
|
2255
2313
|
"rate",
|
|
2256
2314
|
"depth",
|
|
@@ -2272,6 +2330,7 @@ var BUILTIN_TAGS = {
|
|
|
2272
2330
|
},
|
|
2273
2331
|
"wcs-analyser": {
|
|
2274
2332
|
"package": "audio",
|
|
2333
|
+
"hasWcBindable": true,
|
|
2275
2334
|
"observedAttributes": [
|
|
2276
2335
|
"fft",
|
|
2277
2336
|
"smoothing",
|
|
@@ -2295,6 +2354,7 @@ var BUILTIN_TAGS = {
|
|
|
2295
2354
|
},
|
|
2296
2355
|
"wcs-broadcast": {
|
|
2297
2356
|
"package": "broadcast",
|
|
2357
|
+
"hasWcBindable": true,
|
|
2298
2358
|
"observedAttributes": [
|
|
2299
2359
|
"name"
|
|
2300
2360
|
],
|
|
@@ -2315,6 +2375,7 @@ var BUILTIN_TAGS = {
|
|
|
2315
2375
|
},
|
|
2316
2376
|
"wcs-camera": {
|
|
2317
2377
|
"package": "camera",
|
|
2378
|
+
"hasWcBindable": true,
|
|
2318
2379
|
"observedAttributes": [
|
|
2319
2380
|
"facing-mode",
|
|
2320
2381
|
"device-id",
|
|
@@ -2350,6 +2411,7 @@ var BUILTIN_TAGS = {
|
|
|
2350
2411
|
},
|
|
2351
2412
|
"wcs-recorder": {
|
|
2352
2413
|
"package": "camera",
|
|
2414
|
+
"hasWcBindable": true,
|
|
2353
2415
|
"observedAttributes": [],
|
|
2354
2416
|
"inputs": {
|
|
2355
2417
|
"mimeType": "mime-type",
|
|
@@ -2379,6 +2441,7 @@ var BUILTIN_TAGS = {
|
|
|
2379
2441
|
},
|
|
2380
2442
|
"wcs-clipboard": {
|
|
2381
2443
|
"package": "clipboard",
|
|
2444
|
+
"hasWcBindable": true,
|
|
2382
2445
|
"observedAttributes": [],
|
|
2383
2446
|
"inputs": {
|
|
2384
2447
|
"monitor": "monitor"
|
|
@@ -2407,6 +2470,7 @@ var BUILTIN_TAGS = {
|
|
|
2407
2470
|
},
|
|
2408
2471
|
"wcs-contacts": {
|
|
2409
2472
|
"package": "contacts",
|
|
2473
|
+
"hasWcBindable": true,
|
|
2410
2474
|
"observedAttributes": [],
|
|
2411
2475
|
"inputs": {},
|
|
2412
2476
|
"properties": [
|
|
@@ -2422,6 +2486,7 @@ var BUILTIN_TAGS = {
|
|
|
2422
2486
|
},
|
|
2423
2487
|
"wcs-credential": {
|
|
2424
2488
|
"package": "credential",
|
|
2489
|
+
"hasWcBindable": true,
|
|
2425
2490
|
"observedAttributes": [],
|
|
2426
2491
|
"inputs": {},
|
|
2427
2492
|
"properties": [
|
|
@@ -2438,6 +2503,7 @@ var BUILTIN_TAGS = {
|
|
|
2438
2503
|
},
|
|
2439
2504
|
"wcs-debounce": {
|
|
2440
2505
|
"package": "debounce",
|
|
2506
|
+
"hasWcBindable": true,
|
|
2441
2507
|
"observedAttributes": [],
|
|
2442
2508
|
"inputs": {
|
|
2443
2509
|
"source": null,
|
|
@@ -2459,6 +2525,7 @@ var BUILTIN_TAGS = {
|
|
|
2459
2525
|
},
|
|
2460
2526
|
"wcs-throttle": {
|
|
2461
2527
|
"package": "debounce",
|
|
2528
|
+
"hasWcBindable": true,
|
|
2462
2529
|
"observedAttributes": [],
|
|
2463
2530
|
"inputs": {
|
|
2464
2531
|
"source": null,
|
|
@@ -2480,6 +2547,7 @@ var BUILTIN_TAGS = {
|
|
|
2480
2547
|
},
|
|
2481
2548
|
"wcs-defined": {
|
|
2482
2549
|
"package": "defined",
|
|
2550
|
+
"hasWcBindable": true,
|
|
2483
2551
|
"observedAttributes": [],
|
|
2484
2552
|
"inputs": {
|
|
2485
2553
|
"tags": "tags",
|
|
@@ -2498,6 +2566,7 @@ var BUILTIN_TAGS = {
|
|
|
2498
2566
|
},
|
|
2499
2567
|
"wcs-eyedropper": {
|
|
2500
2568
|
"package": "eyedropper",
|
|
2569
|
+
"hasWcBindable": true,
|
|
2501
2570
|
"observedAttributes": [],
|
|
2502
2571
|
"inputs": {},
|
|
2503
2572
|
"properties": [
|
|
@@ -2514,6 +2583,7 @@ var BUILTIN_TAGS = {
|
|
|
2514
2583
|
},
|
|
2515
2584
|
"wcs-fetch": {
|
|
2516
2585
|
"package": "fetch",
|
|
2586
|
+
"hasWcBindable": true,
|
|
2517
2587
|
"observedAttributes": [
|
|
2518
2588
|
"url"
|
|
2519
2589
|
],
|
|
@@ -2542,6 +2612,7 @@ var BUILTIN_TAGS = {
|
|
|
2542
2612
|
},
|
|
2543
2613
|
"wcs-fetch-header": {
|
|
2544
2614
|
"package": "fetch",
|
|
2615
|
+
"hasWcBindable": false,
|
|
2545
2616
|
"observedAttributes": [],
|
|
2546
2617
|
"inputs": {},
|
|
2547
2618
|
"properties": [],
|
|
@@ -2549,6 +2620,7 @@ var BUILTIN_TAGS = {
|
|
|
2549
2620
|
},
|
|
2550
2621
|
"wcs-fetch-body": {
|
|
2551
2622
|
"package": "fetch",
|
|
2623
|
+
"hasWcBindable": false,
|
|
2552
2624
|
"observedAttributes": [],
|
|
2553
2625
|
"inputs": {},
|
|
2554
2626
|
"properties": [],
|
|
@@ -2556,6 +2628,7 @@ var BUILTIN_TAGS = {
|
|
|
2556
2628
|
},
|
|
2557
2629
|
"wcs-infinite-scroll": {
|
|
2558
2630
|
"package": "fetch",
|
|
2631
|
+
"hasWcBindable": false,
|
|
2559
2632
|
"observedAttributes": [
|
|
2560
2633
|
"target",
|
|
2561
2634
|
"root",
|
|
@@ -2569,6 +2642,7 @@ var BUILTIN_TAGS = {
|
|
|
2569
2642
|
},
|
|
2570
2643
|
"wcs-fullscreen": {
|
|
2571
2644
|
"package": "fullscreen",
|
|
2645
|
+
"hasWcBindable": true,
|
|
2572
2646
|
"observedAttributes": [
|
|
2573
2647
|
"target"
|
|
2574
2648
|
],
|
|
@@ -2587,6 +2661,7 @@ var BUILTIN_TAGS = {
|
|
|
2587
2661
|
},
|
|
2588
2662
|
"wcs-geo": {
|
|
2589
2663
|
"package": "geolocation",
|
|
2664
|
+
"hasWcBindable": true,
|
|
2590
2665
|
"observedAttributes": [],
|
|
2591
2666
|
"inputs": {
|
|
2592
2667
|
"highAccuracy": "high-accuracy",
|
|
@@ -2618,6 +2693,7 @@ var BUILTIN_TAGS = {
|
|
|
2618
2693
|
},
|
|
2619
2694
|
"wcs-gyroscope": {
|
|
2620
2695
|
"package": "gyroscope",
|
|
2696
|
+
"hasWcBindable": true,
|
|
2621
2697
|
"observedAttributes": [],
|
|
2622
2698
|
"inputs": {
|
|
2623
2699
|
"frequency": null
|
|
@@ -2636,6 +2712,7 @@ var BUILTIN_TAGS = {
|
|
|
2636
2712
|
},
|
|
2637
2713
|
"wcs-idle": {
|
|
2638
2714
|
"package": "idle",
|
|
2715
|
+
"hasWcBindable": true,
|
|
2639
2716
|
"observedAttributes": [],
|
|
2640
2717
|
"inputs": {
|
|
2641
2718
|
"threshold": "threshold"
|
|
@@ -2655,6 +2732,7 @@ var BUILTIN_TAGS = {
|
|
|
2655
2732
|
},
|
|
2656
2733
|
"wcs-intersect": {
|
|
2657
2734
|
"package": "intersection",
|
|
2735
|
+
"hasWcBindable": true,
|
|
2658
2736
|
"observedAttributes": [
|
|
2659
2737
|
"target",
|
|
2660
2738
|
"root",
|
|
@@ -2688,6 +2766,7 @@ var BUILTIN_TAGS = {
|
|
|
2688
2766
|
},
|
|
2689
2767
|
"wcs-magnetometer": {
|
|
2690
2768
|
"package": "magnetometer",
|
|
2769
|
+
"hasWcBindable": true,
|
|
2691
2770
|
"observedAttributes": [],
|
|
2692
2771
|
"inputs": {
|
|
2693
2772
|
"frequency": null
|
|
@@ -2706,6 +2785,7 @@ var BUILTIN_TAGS = {
|
|
|
2706
2785
|
},
|
|
2707
2786
|
"wcs-midi": {
|
|
2708
2787
|
"package": "midi",
|
|
2788
|
+
"hasWcBindable": true,
|
|
2709
2789
|
"observedAttributes": [
|
|
2710
2790
|
"input",
|
|
2711
2791
|
"output",
|
|
@@ -2743,6 +2823,7 @@ var BUILTIN_TAGS = {
|
|
|
2743
2823
|
},
|
|
2744
2824
|
"wcs-network": {
|
|
2745
2825
|
"package": "network",
|
|
2826
|
+
"hasWcBindable": true,
|
|
2746
2827
|
"observedAttributes": [],
|
|
2747
2828
|
"inputs": {},
|
|
2748
2829
|
"properties": [
|
|
@@ -2756,6 +2837,7 @@ var BUILTIN_TAGS = {
|
|
|
2756
2837
|
},
|
|
2757
2838
|
"wcs-notify": {
|
|
2758
2839
|
"package": "notification",
|
|
2840
|
+
"hasWcBindable": true,
|
|
2759
2841
|
"observedAttributes": [],
|
|
2760
2842
|
"inputs": {
|
|
2761
2843
|
"notice": null,
|
|
@@ -2792,6 +2874,7 @@ var BUILTIN_TAGS = {
|
|
|
2792
2874
|
},
|
|
2793
2875
|
"wcs-permission": {
|
|
2794
2876
|
"package": "permission",
|
|
2877
|
+
"hasWcBindable": true,
|
|
2795
2878
|
"observedAttributes": [],
|
|
2796
2879
|
"inputs": {
|
|
2797
2880
|
"name": "name",
|
|
@@ -2809,6 +2892,7 @@ var BUILTIN_TAGS = {
|
|
|
2809
2892
|
},
|
|
2810
2893
|
"wcs-pip": {
|
|
2811
2894
|
"package": "picture-in-picture",
|
|
2895
|
+
"hasWcBindable": true,
|
|
2812
2896
|
"observedAttributes": [
|
|
2813
2897
|
"target"
|
|
2814
2898
|
],
|
|
@@ -2827,6 +2911,7 @@ var BUILTIN_TAGS = {
|
|
|
2827
2911
|
},
|
|
2828
2912
|
"wcs-pointer-lock": {
|
|
2829
2913
|
"package": "pointer-lock",
|
|
2914
|
+
"hasWcBindable": true,
|
|
2830
2915
|
"observedAttributes": [
|
|
2831
2916
|
"target"
|
|
2832
2917
|
],
|
|
@@ -2845,6 +2930,7 @@ var BUILTIN_TAGS = {
|
|
|
2845
2930
|
},
|
|
2846
2931
|
"wcs-raf": {
|
|
2847
2932
|
"package": "raf",
|
|
2933
|
+
"hasWcBindable": true,
|
|
2848
2934
|
"observedAttributes": [],
|
|
2849
2935
|
"inputs": {
|
|
2850
2936
|
"once": "once",
|
|
@@ -2870,6 +2956,7 @@ var BUILTIN_TAGS = {
|
|
|
2870
2956
|
},
|
|
2871
2957
|
"wcs-resize": {
|
|
2872
2958
|
"package": "resize",
|
|
2959
|
+
"hasWcBindable": true,
|
|
2873
2960
|
"observedAttributes": [
|
|
2874
2961
|
"target",
|
|
2875
2962
|
"box",
|
|
@@ -2898,6 +2985,7 @@ var BUILTIN_TAGS = {
|
|
|
2898
2985
|
},
|
|
2899
2986
|
"wcs-screen-orientation": {
|
|
2900
2987
|
"package": "screen-orientation",
|
|
2988
|
+
"hasWcBindable": true,
|
|
2901
2989
|
"observedAttributes": [],
|
|
2902
2990
|
"inputs": {},
|
|
2903
2991
|
"properties": [
|
|
@@ -2915,6 +3003,7 @@ var BUILTIN_TAGS = {
|
|
|
2915
3003
|
},
|
|
2916
3004
|
"wcs-share": {
|
|
2917
3005
|
"package": "share",
|
|
3006
|
+
"hasWcBindable": true,
|
|
2918
3007
|
"observedAttributes": [],
|
|
2919
3008
|
"inputs": {},
|
|
2920
3009
|
"properties": [
|
|
@@ -2930,6 +3019,7 @@ var BUILTIN_TAGS = {
|
|
|
2930
3019
|
},
|
|
2931
3020
|
"wcs-speak": {
|
|
2932
3021
|
"package": "speech",
|
|
3022
|
+
"hasWcBindable": true,
|
|
2933
3023
|
"observedAttributes": [],
|
|
2934
3024
|
"inputs": {
|
|
2935
3025
|
"say": null,
|
|
@@ -2960,6 +3050,7 @@ var BUILTIN_TAGS = {
|
|
|
2960
3050
|
},
|
|
2961
3051
|
"wcs-listen": {
|
|
2962
3052
|
"package": "speech",
|
|
3053
|
+
"hasWcBindable": true,
|
|
2963
3054
|
"observedAttributes": [],
|
|
2964
3055
|
"inputs": {
|
|
2965
3056
|
"lang": "lang",
|
|
@@ -2988,6 +3079,7 @@ var BUILTIN_TAGS = {
|
|
|
2988
3079
|
},
|
|
2989
3080
|
"wcs-sse": {
|
|
2990
3081
|
"package": "sse",
|
|
3082
|
+
"hasWcBindable": true,
|
|
2991
3083
|
"observedAttributes": [
|
|
2992
3084
|
"url"
|
|
2993
3085
|
],
|
|
@@ -3015,6 +3107,7 @@ var BUILTIN_TAGS = {
|
|
|
3015
3107
|
},
|
|
3016
3108
|
"wcs-storage": {
|
|
3017
3109
|
"package": "storage",
|
|
3110
|
+
"hasWcBindable": true,
|
|
3018
3111
|
"observedAttributes": [
|
|
3019
3112
|
"key",
|
|
3020
3113
|
"type"
|
|
@@ -3041,6 +3134,7 @@ var BUILTIN_TAGS = {
|
|
|
3041
3134
|
},
|
|
3042
3135
|
"wcs-tilt": {
|
|
3043
3136
|
"package": "tilt",
|
|
3137
|
+
"hasWcBindable": true,
|
|
3044
3138
|
"observedAttributes": [],
|
|
3045
3139
|
"inputs": {},
|
|
3046
3140
|
"properties": [
|
|
@@ -3060,6 +3154,7 @@ var BUILTIN_TAGS = {
|
|
|
3060
3154
|
},
|
|
3061
3155
|
"wcs-timer": {
|
|
3062
3156
|
"package": "timer",
|
|
3157
|
+
"hasWcBindable": true,
|
|
3063
3158
|
"observedAttributes": [
|
|
3064
3159
|
"interval"
|
|
3065
3160
|
],
|
|
@@ -3087,6 +3182,7 @@ var BUILTIN_TAGS = {
|
|
|
3087
3182
|
},
|
|
3088
3183
|
"wcs-upload": {
|
|
3089
3184
|
"package": "upload",
|
|
3185
|
+
"hasWcBindable": true,
|
|
3090
3186
|
"observedAttributes": [
|
|
3091
3187
|
"url"
|
|
3092
3188
|
],
|
|
@@ -3118,6 +3214,7 @@ var BUILTIN_TAGS = {
|
|
|
3118
3214
|
},
|
|
3119
3215
|
"wcs-wakelock": {
|
|
3120
3216
|
"package": "wakelock",
|
|
3217
|
+
"hasWcBindable": true,
|
|
3121
3218
|
"observedAttributes": [
|
|
3122
3219
|
"active",
|
|
3123
3220
|
"type"
|
|
@@ -3139,6 +3236,7 @@ var BUILTIN_TAGS = {
|
|
|
3139
3236
|
},
|
|
3140
3237
|
"wcs-ws": {
|
|
3141
3238
|
"package": "websocket",
|
|
3239
|
+
"hasWcBindable": true,
|
|
3142
3240
|
"observedAttributes": [
|
|
3143
3241
|
"url"
|
|
3144
3242
|
],
|
|
@@ -3171,6 +3269,7 @@ var BUILTIN_TAGS = {
|
|
|
3171
3269
|
},
|
|
3172
3270
|
"wcs-worker": {
|
|
3173
3271
|
"package": "worker",
|
|
3272
|
+
"hasWcBindable": true,
|
|
3174
3273
|
"observedAttributes": [
|
|
3175
3274
|
"src"
|
|
3176
3275
|
],
|
|
@@ -3224,10 +3323,28 @@ function validateIoNodes(html, bindAttribute = "data-wcs", stateTagName = "wcs-s
|
|
|
3224
3323
|
const getPaths = () => statePaths ??= getStatePathsFromHtml(html, stateTagName, fileReader);
|
|
3225
3324
|
for (const occ of occurrences) {
|
|
3226
3325
|
const contract = BUILTIN_TAGS[occ.tagName];
|
|
3227
|
-
if (contract.properties.length === 0 && contract.commands.length === 0 && Object.keys(contract.inputs).length === 0) continue;
|
|
3228
3326
|
const bindAttr = extractAttributeValue(occ.attrsText, bindAttribute);
|
|
3229
3327
|
if (!bindAttr) continue;
|
|
3230
3328
|
const valueStart = occ.attrsStart + bindAttr.valueOffsetInAttrs;
|
|
3329
|
+
if (!contract.hasWcBindable) {
|
|
3330
|
+
let spreadExprOffset = 0;
|
|
3331
|
+
for (const expr of splitBindingExpressions(bindAttr.value)) {
|
|
3332
|
+
const exprStart = valueStart + spreadExprOffset;
|
|
3333
|
+
spreadExprOffset += expr.length + 1;
|
|
3334
|
+
if (parseBindingExpression(expr).property !== "...") continue;
|
|
3335
|
+
const start = exprStart + expr.indexOf("...");
|
|
3336
|
+
diagnostics.push({
|
|
3337
|
+
code: WcsDiagnosticCode.SpreadNoBindable,
|
|
3338
|
+
start,
|
|
3339
|
+
end: start + 3,
|
|
3340
|
+
severity: "error",
|
|
3341
|
+
tag: occ.tagName,
|
|
3342
|
+
message: msgs.spreadNoBindable(occ.tagName)
|
|
3343
|
+
});
|
|
3344
|
+
}
|
|
3345
|
+
continue;
|
|
3346
|
+
}
|
|
3347
|
+
if (contract.properties.length === 0 && contract.commands.length === 0 && Object.keys(contract.inputs).length === 0) continue;
|
|
3231
3348
|
const hasManual = hasBooleanAttribute(occ.attrsText, "manual");
|
|
3232
3349
|
let exprOffset = 0;
|
|
3233
3350
|
for (const expr of splitBindingExpressions(bindAttr.value)) {
|
|
@@ -3525,6 +3642,16 @@ function validateWatchDeclarations(html, stateTagName = "wcs-state", locale) {
|
|
|
3525
3642
|
const msgs = getMessages(locale);
|
|
3526
3643
|
const out = [];
|
|
3527
3644
|
for (const block of parseWcsScriptBlocks(html, stateTagName)) {
|
|
3645
|
+
const nonObject = findNonObjectWatch(block.content);
|
|
3646
|
+
if (nonObject !== null) {
|
|
3647
|
+
out.push({
|
|
3648
|
+
code: WcsDiagnosticCode.WatchDeclarationInvalid,
|
|
3649
|
+
start: block.contentStart + nonObject.start,
|
|
3650
|
+
end: block.contentStart + nonObject.end,
|
|
3651
|
+
message: msgs.watchNotObject(),
|
|
3652
|
+
severity: "error"
|
|
3653
|
+
});
|
|
3654
|
+
}
|
|
3528
3655
|
const entries = analyzeWatchEntries(block.content);
|
|
3529
3656
|
if (entries.length === 0) continue;
|
|
3530
3657
|
const paths = analyzeStatePaths(block.content, block.stateName);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wcstack/lint",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.30.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": {
|