@wcstack/lint 1.22.2 → 1.22.4
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/README.ja.md +2 -0
- package/README.md +2 -0
- package/dist/cli.cjs +139 -24
- package/package.json +1 -1
package/README.ja.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# @wcstack/lint
|
|
2
2
|
|
|
3
|
+
> 🤖 **AI coding agents**: This README is a package-level reference, not the primary entry point for building a wcstack application. If you have not already done so, first read the repository [README](https://github.com/wcstack/wcstack#readme) and [AGENTS.md](https://github.com/wcstack/wcstack/blob/main/AGENTS.md), then use the [wcstack-app skill](https://github.com/wcstack/wcstack-skill).
|
|
4
|
+
|
|
3
5
|
[wcstack](https://github.com/wcstack/wcstack) の静的契約検査 CLI。HTML の `data-wcs` バインディングと `wcstack.manifest.json`(sidecar)を headless に検査します。WcStack IntelliSense(VS Code 拡張)と**同一の validator core** を使うため、IDE と CLI の diagnostic code / range は完全に一致します。
|
|
4
6
|
|
|
5
7
|
[English README is here](./README.md)
|
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# @wcstack/lint
|
|
2
2
|
|
|
3
|
+
> 🤖 **AI coding agents**: This README is a package-level reference, not the primary entry point for building a wcstack application. If you have not already done so, first read the repository [README](https://github.com/wcstack/wcstack#readme) and [AGENTS.md](https://github.com/wcstack/wcstack/blob/main/AGENTS.md), then use the [wcstack-app skill](https://github.com/wcstack/wcstack-skill).
|
|
4
|
+
|
|
3
5
|
Static-contract validator CLI for [wcstack](https://github.com/wcstack/wcstack): checks HTML `data-wcs` bindings and `wcstack.manifest.json` sidecars headlessly, with the **same validator core** as the WcStack IntelliSense VS Code extension — the IDE and this CLI report identical diagnostic codes and ranges.
|
|
4
6
|
|
|
5
7
|
[日本語版 README はこちら](./README.ja.md)
|
package/dist/cli.cjs
CHANGED
|
@@ -91,6 +91,13 @@ var WcsDiagnosticCode = {
|
|
|
91
91
|
NestedAssign: "wcs/nested-assign",
|
|
92
92
|
TypeAnnotation: "wcs/type-annotation",
|
|
93
93
|
TemplateSyntax: "wcs/template-syntax",
|
|
94
|
+
// --- <wcs-state> script: array reactivity hazards ---
|
|
95
|
+
// 配列破壊的メソッド呼び出し(push 等 9 種)。Proxy を素通りしリアクティブ更新されない。
|
|
96
|
+
// 同一参照の自己再代入でも要素の追加・削除は反映されない(docs/array-mutation-diagnostic-design.md §3)。
|
|
97
|
+
ArrayMutation: "wcs/array-mutation",
|
|
98
|
+
// 配列インデックスへの直接代入(bracket-only チェーン)。同上。正はドットパス代入。
|
|
99
|
+
// ドットアクセスを含むチェーン代入は NestedAssign の担当(相補・二重報告なし)。
|
|
100
|
+
ArrayIndexAssign: "wcs/array-index-assign",
|
|
94
101
|
// --- built-in wcs-* tag contract (generated/builtinTags.generated.ts が正本) ---
|
|
95
102
|
// 未知メンバーへのバインド(プロパティ / command. / eventToken. キー)。黙って無視される。
|
|
96
103
|
TagMemberUnknown: "wcs/tag-member-unknown",
|
|
@@ -223,7 +230,7 @@ function parseWcsScriptBlocks(html, stateTagName = "wcs-state") {
|
|
|
223
230
|
continue;
|
|
224
231
|
}
|
|
225
232
|
const typeAttr = extractAttribute(scriptMatch.tagContent, "type");
|
|
226
|
-
if (typeAttr !== "module") {
|
|
233
|
+
if (typeAttr?.toLowerCase() !== "module") {
|
|
227
234
|
pos = scriptMatch.end;
|
|
228
235
|
continue;
|
|
229
236
|
}
|
|
@@ -288,7 +295,7 @@ function parseWcsStateElements(html, stateTagName = "wcs-state") {
|
|
|
288
295
|
continue;
|
|
289
296
|
}
|
|
290
297
|
const typeAttr = extractAttribute(scriptMatch.tagContent, "type");
|
|
291
|
-
if (typeAttr !== "module") {
|
|
298
|
+
if (typeAttr?.toLowerCase() !== "module") {
|
|
292
299
|
pos = scriptMatch.end;
|
|
293
300
|
continue;
|
|
294
301
|
}
|
|
@@ -333,7 +340,7 @@ function findScriptJsonById(html, id) {
|
|
|
333
340
|
}
|
|
334
341
|
const typeAttr = extractAttribute(scriptMatch.tagContent, "type");
|
|
335
342
|
const idAttr = extractAttribute(scriptMatch.tagContent, "id");
|
|
336
|
-
if (typeAttr === "application/json" && idAttr === id) {
|
|
343
|
+
if (typeAttr?.toLowerCase() === "application/json" && idAttr === id) {
|
|
337
344
|
const contentStart = scriptMatch.end;
|
|
338
345
|
const scriptCloseIdx = findCloseTag(html, contentStart, "script");
|
|
339
346
|
if (scriptCloseIdx === -1) return null;
|
|
@@ -898,6 +905,8 @@ var ja = {
|
|
|
898
905
|
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`,
|
|
899
906
|
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`,
|
|
900
907
|
typeAnnotationIncompatible: (vt, rt) => `\u578B "${vt}" \u306F @type {${rt}} \u3068\u4E92\u63DB\u6027\u304C\u3042\u308A\u307E\u305B\u3093`,
|
|
908
|
+
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`,
|
|
909
|
+
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`,
|
|
901
910
|
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`,
|
|
902
911
|
tagCommandUnknown: (name, tag, declared) => `"${name}" \u306F <${tag}> \u306E command \u3067\u306F\u3042\u308A\u307E\u305B\u3093\uFF08\u5BA3\u8A00\u6E08\u307F: ${declared}\uFF09`,
|
|
903
912
|
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`,
|
|
@@ -938,6 +947,8 @@ var en = {
|
|
|
938
947
|
moustacheFouc: (e) => `{{ }} outside a <template> causes FOUC (the raw template string is visible before binding). Consider the comment syntax <!--@@:${e}--> instead.`,
|
|
939
948
|
nestedAssign: (sp) => `Assigning to a nested property does not trigger a reactive update. Use this["${sp}"] instead.`,
|
|
940
949
|
typeAnnotationIncompatible: (vt, rt) => `Type "${vt}" is not compatible with @type {${rt}}`,
|
|
950
|
+
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}).`,
|
|
951
|
+
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.`,
|
|
941
952
|
tagMemberUnknown: (prop, tag) => `"${prop}" is not a wcBindable member of <${tag}> (bindings to unknown members are silently ignored)`,
|
|
942
953
|
tagCommandUnknown: (name, tag, declared) => `"${name}" is not a command of <${tag}> (declared: ${declared})`,
|
|
943
954
|
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})`,
|
|
@@ -1502,40 +1513,143 @@ function isValueCompatible(declaredTypes, valueType) {
|
|
|
1502
1513
|
return declaredTypes.includes(valueType);
|
|
1503
1514
|
}
|
|
1504
1515
|
|
|
1516
|
+
// src/service/scriptPatterns.ts
|
|
1517
|
+
var ID = String.raw`[\w$]+`;
|
|
1518
|
+
var SUB = String.raw`\s*(?:\?\.)?\s*\[(?!\s*["'])[^\[\]]+\]`;
|
|
1519
|
+
var DOT_SEG = String.raw`\s*\??\.\s*${ID}`;
|
|
1520
|
+
var CHAIN = String.raw`(?:${DOT_SEG}|${SUB})*`;
|
|
1521
|
+
var BRACKETS_ONLY = String.raw`(?:${SUB})+`;
|
|
1522
|
+
var CHAIN_ONE_PLUS = String.raw`(?:${DOT_SEG}|${SUB})+`;
|
|
1523
|
+
var ROOT_DOT = String.raw`\bthis\s*\??\.\s*(${ID})`;
|
|
1524
|
+
var ROOT_BRACKET = String.raw`\bthis\s*(?:\?\.)?\s*\[\s*["']([^"']+)["']\s*\]`;
|
|
1525
|
+
var ASSIGN_TAIL = String.raw`\s*(?:(?:\*\*|<<|>>>|>>|&&|\|\||\?\?|[+\-*/%&|^])?=(?!=)|\+\+|--)`;
|
|
1526
|
+
var PRE_INCDEC = String.raw`(?:\+\+|--)\s*`;
|
|
1527
|
+
function chainToDotted(chain) {
|
|
1528
|
+
const token = new RegExp(String.raw`\s*(?:\??\.\s*(${ID})|(?:\?\.)?\s*\[([^\[\]]+)\])`, "g");
|
|
1529
|
+
let out = "";
|
|
1530
|
+
let match;
|
|
1531
|
+
while ((match = token.exec(chain)) !== null) {
|
|
1532
|
+
if (match[1] !== void 0) {
|
|
1533
|
+
out += `.${match[1]}`;
|
|
1534
|
+
} else {
|
|
1535
|
+
const key = match[2].trim();
|
|
1536
|
+
out += /^\d+$/.test(key) ? `.${key}` : `.<${key}>`;
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
return out;
|
|
1540
|
+
}
|
|
1541
|
+
function hasDotSegment(chain) {
|
|
1542
|
+
return /[.]/.test(chain.replace(/\s*(?:\?\.)?\s*\[[^\[\]]+\]/g, ""));
|
|
1543
|
+
}
|
|
1544
|
+
function isApiRoot(root) {
|
|
1545
|
+
return root.startsWith("$");
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1505
1548
|
// src/service/nestedAssignValidator.ts
|
|
1549
|
+
var NESTED_ASSIGN = new RegExp(`${ROOT_DOT}(${CHAIN_ONE_PLUS})${ASSIGN_TAIL}`, "g");
|
|
1550
|
+
var PRE_NESTED_INCDEC = new RegExp(`${PRE_INCDEC}${ROOT_DOT}(${CHAIN_ONE_PLUS})`, "g");
|
|
1506
1551
|
function validateNestedAssigns(html, stateTagName = "wcs-state", locale) {
|
|
1507
1552
|
const msgs = getMessages(locale);
|
|
1508
1553
|
const blocks = parseWcsScriptBlocks(html, stateTagName);
|
|
1509
1554
|
const diagnostics = [];
|
|
1510
1555
|
for (const block of blocks) {
|
|
1511
|
-
|
|
1512
|
-
diagnostics.push(...blockDiags);
|
|
1556
|
+
findNestedAssigns(block.content, block.contentStart, msgs, diagnostics);
|
|
1513
1557
|
}
|
|
1514
1558
|
return diagnostics;
|
|
1515
1559
|
}
|
|
1516
|
-
function findNestedAssigns(script, baseOffset, msgs
|
|
1560
|
+
function findNestedAssigns(script, baseOffset, msgs, out) {
|
|
1561
|
+
for (const regex of [NESTED_ASSIGN, PRE_NESTED_INCDEC]) {
|
|
1562
|
+
regex.lastIndex = 0;
|
|
1563
|
+
let match;
|
|
1564
|
+
while ((match = regex.exec(script)) !== null) {
|
|
1565
|
+
const [full, topProp, chainPart] = match;
|
|
1566
|
+
if (isApiRoot(topProp)) continue;
|
|
1567
|
+
if (!hasDotSegment(chainPart)) continue;
|
|
1568
|
+
const suggestedPath = topProp + chainToDotted(chainPart);
|
|
1569
|
+
const start = baseOffset + match.index;
|
|
1570
|
+
out.push({
|
|
1571
|
+
start,
|
|
1572
|
+
end: start + full.length,
|
|
1573
|
+
message: msgs.nestedAssign(suggestedPath),
|
|
1574
|
+
severity: "warning"
|
|
1575
|
+
});
|
|
1576
|
+
}
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1580
|
+
// src/service/arrayMutationValidator.ts
|
|
1581
|
+
var DESTRUCTIVE_METHODS = "push|pop|shift|unshift|splice|sort|reverse|fill|copyWithin";
|
|
1582
|
+
var ALTERNATIVES = {
|
|
1583
|
+
push: (a) => `${a} = ${a}.concat(item)`,
|
|
1584
|
+
unshift: (a) => `${a} = [item, ...${a}]`,
|
|
1585
|
+
pop: (a) => `${a} = ${a}.slice(0, -1)`,
|
|
1586
|
+
shift: (a) => `${a} = ${a}.slice(1)`,
|
|
1587
|
+
splice: (a) => `${a} = ${a}.toSpliced(...)`,
|
|
1588
|
+
sort: (a) => `${a} = ${a}.toSorted(...)`,
|
|
1589
|
+
reverse: (a) => `${a} = ${a}.toReversed()`,
|
|
1590
|
+
fill: (a) => `${a} = ${a}.map(...)`,
|
|
1591
|
+
copyWithin: (a) => `${a} = ${a}.map(...)`
|
|
1592
|
+
};
|
|
1593
|
+
var METHOD_TAIL = String.raw`\s*\??\.\s*(${DESTRUCTIVE_METHODS})(?=\s*\()`;
|
|
1594
|
+
var DOT_ROOT_CALL = new RegExp(`${ROOT_DOT}(${CHAIN})${METHOD_TAIL}`, "g");
|
|
1595
|
+
var BRACKET_ROOT_CALL = new RegExp(`${ROOT_BRACKET}(${CHAIN})${METHOD_TAIL}`, "g");
|
|
1596
|
+
var DOT_INDEX_ASSIGN = new RegExp(`${ROOT_DOT}(${BRACKETS_ONLY})${ASSIGN_TAIL}`, "g");
|
|
1597
|
+
var BRACKET_INDEX_ASSIGN = new RegExp(`${ROOT_BRACKET}(${BRACKETS_ONLY})${ASSIGN_TAIL}`, "g");
|
|
1598
|
+
var PRE_DOT_INDEX = new RegExp(`${PRE_INCDEC}${ROOT_DOT}(${BRACKETS_ONLY})`, "g");
|
|
1599
|
+
var PRE_BRACKET_INDEX = new RegExp(`${PRE_INCDEC}${ROOT_BRACKET}(${BRACKETS_ONLY})`, "g");
|
|
1600
|
+
function toAccessor(path) {
|
|
1601
|
+
return /^[A-Za-z_]\w*$/.test(path) ? `this.${path}` : `this["${path}"]`;
|
|
1602
|
+
}
|
|
1603
|
+
function validateArrayMutations(html, stateTagName = "wcs-state", locale) {
|
|
1604
|
+
const msgs = getMessages(locale);
|
|
1605
|
+
const blocks = parseWcsScriptBlocks(html, stateTagName);
|
|
1517
1606
|
const diagnostics = [];
|
|
1518
|
-
const
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
const fullMatch = match[0];
|
|
1522
|
-
const topProp = match[1];
|
|
1523
|
-
const chainPart = match[2];
|
|
1524
|
-
if (topProp.startsWith("$")) continue;
|
|
1525
|
-
if (!/\.\w+/.test(chainPart)) continue;
|
|
1526
|
-
const assignStart = baseOffset + match.index;
|
|
1527
|
-
const assignEnd = assignStart + fullMatch.length - 1;
|
|
1528
|
-
const dotPath = topProp + chainPart.replace(/\[(\w+)\]/g, ".$1").replace(/^\./, "");
|
|
1529
|
-
const suggestedPath = topProp + chainPart.replace(/\[(\w+)\]/g, ".$1");
|
|
1530
|
-
diagnostics.push({
|
|
1531
|
-
start: assignStart,
|
|
1532
|
-
end: assignEnd,
|
|
1533
|
-
message: msgs.nestedAssign(suggestedPath),
|
|
1534
|
-
severity: "warning"
|
|
1535
|
-
});
|
|
1607
|
+
for (const block of blocks) {
|
|
1608
|
+
findDestructiveCalls(block.content, block.contentStart, msgs, diagnostics);
|
|
1609
|
+
findIndexAssigns(block.content, block.contentStart, msgs, diagnostics);
|
|
1536
1610
|
}
|
|
1537
1611
|
return diagnostics;
|
|
1538
1612
|
}
|
|
1613
|
+
function findDestructiveCalls(script, baseOffset, msgs, out) {
|
|
1614
|
+
for (const regex of [DOT_ROOT_CALL, BRACKET_ROOT_CALL]) {
|
|
1615
|
+
regex.lastIndex = 0;
|
|
1616
|
+
let match;
|
|
1617
|
+
while ((match = regex.exec(script)) !== null) {
|
|
1618
|
+
const [full, root, chain, method] = match;
|
|
1619
|
+
if (isApiRoot(root)) continue;
|
|
1620
|
+
const statePath = root + chainToDotted(chain);
|
|
1621
|
+
const start = baseOffset + match.index;
|
|
1622
|
+
out.push({
|
|
1623
|
+
code: WcsDiagnosticCode.ArrayMutation,
|
|
1624
|
+
start,
|
|
1625
|
+
end: start + full.length,
|
|
1626
|
+
message: msgs.arrayMutation(method, ALTERNATIVES[method](toAccessor(statePath))),
|
|
1627
|
+
severity: "warning",
|
|
1628
|
+
statePath
|
|
1629
|
+
});
|
|
1630
|
+
}
|
|
1631
|
+
}
|
|
1632
|
+
}
|
|
1633
|
+
function findIndexAssigns(script, baseOffset, msgs, out) {
|
|
1634
|
+
for (const regex of [DOT_INDEX_ASSIGN, BRACKET_INDEX_ASSIGN, PRE_DOT_INDEX, PRE_BRACKET_INDEX]) {
|
|
1635
|
+
regex.lastIndex = 0;
|
|
1636
|
+
let match;
|
|
1637
|
+
while ((match = regex.exec(script)) !== null) {
|
|
1638
|
+
const [full, root, chain] = match;
|
|
1639
|
+
if (isApiRoot(root)) continue;
|
|
1640
|
+
const suggestedPath = root + chainToDotted(chain);
|
|
1641
|
+
const start = baseOffset + match.index;
|
|
1642
|
+
out.push({
|
|
1643
|
+
code: WcsDiagnosticCode.ArrayIndexAssign,
|
|
1644
|
+
start,
|
|
1645
|
+
end: start + full.length,
|
|
1646
|
+
message: msgs.arrayIndexAssign(suggestedPath),
|
|
1647
|
+
severity: "warning",
|
|
1648
|
+
statePath: suggestedPath
|
|
1649
|
+
});
|
|
1650
|
+
}
|
|
1651
|
+
}
|
|
1652
|
+
}
|
|
1539
1653
|
|
|
1540
1654
|
// src/service/templateSyntax.ts
|
|
1541
1655
|
function findAllMustacheSyntax(html) {
|
|
@@ -2859,6 +2973,7 @@ function validateDocument(text, options = {}) {
|
|
|
2859
2973
|
out.push(...validateTemplateSyntax(text, stateTagName, bindAttribute, locale));
|
|
2860
2974
|
out.push(...validateIoNodes(text, bindAttribute, stateTagName, locale));
|
|
2861
2975
|
out.push(...validateDocumentEnv(text, locale));
|
|
2976
|
+
out.push(...validateArrayMutations(text, stateTagName, locale));
|
|
2862
2977
|
for (const d of validateStateTypes(text, stateTagName, locale)) {
|
|
2863
2978
|
out.push({ code: WcsDiagnosticCode.TypeAnnotation, start: d.start, end: d.end, message: d.message, severity: d.severity });
|
|
2864
2979
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wcstack/lint",
|
|
3
|
-
"version": "1.22.
|
|
3
|
+
"version": "1.22.4",
|
|
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": {
|