@wcstack/typescript 4.0.4 → 4.1.1
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/index.esm.js +1 -1
- package/dist/schema-core.cjs +92 -33
- package/dist/wcs-schema.mjs +1 -1
- package/dist/wcs-tsc.mjs +1 -1
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
package/dist/schema-core.cjs
CHANGED
|
@@ -94,6 +94,7 @@ var WcsDiagnosticCode = {
|
|
|
94
94
|
// 静的にしか検出できない。対象はオブジェクトリテラル初期値のルートだけ(配列は `items`
|
|
95
95
|
// の依存で足りる — 行の置換は `items` 自体を書き換え、in-place 変異は array-mutation が止める)。
|
|
96
96
|
GetterUntrackedRead: "wcs/getter-untracked-read",
|
|
97
|
+
OnHandlerThis: "wcs/on-handler-this",
|
|
97
98
|
// --- <wcs-state> script: $watch declaration ---
|
|
98
99
|
// ランタイム(watch/processWatchDeclaration.ts)が raiseError で落とす宣言。
|
|
99
100
|
// 越境 `@` / `$` 始まり / 空キー・空セグメント / 明らかな非関数ハンドラ。
|
|
@@ -3239,9 +3240,15 @@ function analyzeWatchEntries(scriptContent) {
|
|
|
3239
3240
|
}));
|
|
3240
3241
|
}
|
|
3241
3242
|
function analyzeWatchHandlerSources(scriptContent) {
|
|
3243
|
+
return analyzeHandlerSources(scriptContent, RESERVED_WATCH_KEY);
|
|
3244
|
+
}
|
|
3245
|
+
function analyzeOnHandlerSources(scriptContent) {
|
|
3246
|
+
return analyzeHandlerSources(scriptContent, "$on");
|
|
3247
|
+
}
|
|
3248
|
+
function analyzeHandlerSources(scriptContent, key) {
|
|
3242
3249
|
const root = locateDefaultExportObject(scriptContent);
|
|
3243
3250
|
if (!root) return [];
|
|
3244
|
-
const prop = parseTopLevelProperties(root.content).find((p) => p.name ===
|
|
3251
|
+
const prop = parseTopLevelProperties(root.content).find((p) => p.name === key);
|
|
3245
3252
|
if (!prop || prop.kind !== "data" || !prop.value || !isObjectLiteral(prop.value) || prop.valueStart === void 0) {
|
|
3246
3253
|
return [];
|
|
3247
3254
|
}
|
|
@@ -3251,6 +3258,7 @@ function analyzeWatchHandlerSources(scriptContent) {
|
|
|
3251
3258
|
for (const entry of parseTopLevelProperties(extractObjectContent(prop.value))) {
|
|
3252
3259
|
if (entry.value === void 0 || entry.valueStart === void 0) continue;
|
|
3253
3260
|
out.push({
|
|
3261
|
+
name: entry.name,
|
|
3254
3262
|
kind: entry.kind === "data" ? "value" : "body",
|
|
3255
3263
|
text: entry.value,
|
|
3256
3264
|
start: innerStart + entry.valueStart
|
|
@@ -10906,6 +10914,35 @@ function propertyKeyIs(property, name) {
|
|
|
10906
10914
|
if (!property.computed && key.type === "Identifier") return key.name === name;
|
|
10907
10915
|
return key.type === "Literal" && key.value === name;
|
|
10908
10916
|
}
|
|
10917
|
+
function findOwnThis(text3, kind) {
|
|
10918
|
+
let program;
|
|
10919
|
+
const prefix = kind === "body" ? PREFIX : VALUE_PREFIX;
|
|
10920
|
+
try {
|
|
10921
|
+
program = parse3(prefix + text3 + (kind === "body" ? SUFFIX : VALUE_SUFFIX), { ecmaVersion: "latest", sourceType: "module" });
|
|
10922
|
+
} catch {
|
|
10923
|
+
return null;
|
|
10924
|
+
}
|
|
10925
|
+
const wrapper = unwrapWrapper(program);
|
|
10926
|
+
if (wrapper === null) return null;
|
|
10927
|
+
let root = wrapper.body;
|
|
10928
|
+
if (kind === "value") {
|
|
10929
|
+
const statement = wrapper.body.body.length === 1 ? wrapper.body.body[0] : null;
|
|
10930
|
+
if (statement === null || statement.type !== "ExpressionStatement" || statement.expression.type !== "FunctionExpression") return null;
|
|
10931
|
+
root = statement.expression.body;
|
|
10932
|
+
}
|
|
10933
|
+
let found = null;
|
|
10934
|
+
const walk = (node) => {
|
|
10935
|
+
if (found !== null || isClassNode(node)) return;
|
|
10936
|
+
if (isFunctionNode(node) && node.type !== "ArrowFunctionExpression") return;
|
|
10937
|
+
if (node.type === "ThisExpression") {
|
|
10938
|
+
found = { start: node.start - prefix.length, end: node.end - prefix.length };
|
|
10939
|
+
return;
|
|
10940
|
+
}
|
|
10941
|
+
forEachChild(node, walk);
|
|
10942
|
+
};
|
|
10943
|
+
forEachChild(root, walk);
|
|
10944
|
+
return found;
|
|
10945
|
+
}
|
|
10909
10946
|
|
|
10910
10947
|
// src/core/messages.ts
|
|
10911
10948
|
function resolveLocale(locale2) {
|
|
@@ -10945,6 +10982,7 @@ var ja = {
|
|
|
10945
10982
|
delegatedCurrentTarget: (suggested, eventName, handler) => `"${eventName}" \u30A4\u30D9\u30F3\u30C8\u306E\u675F\u7E1B\u306F root \u3078\u59D4\u8B72\u3055\u308C\u308B\u306E\u3067\u3001"${handler}" \u306E\u4E2D\u306E event.currentTarget \u306F\u3053\u306E\u8981\u7D20\u3067\u306F\u306A\u304F root \u306B\u306A\u308A\u307E\u3059\u3002\u8981\u7D20\u306B\u30EA\u30B9\u30CA\u30FC\u3092\u4ED8\u3051\u308B\u306B\u306F "${suggested}:" \u3068\u66F8\u304F\u304B\u3001event.target.closest(...) \u3067\u8981\u7D20\u3092\u63A2\u3057\u3066\u304F\u3060\u3055\u3044`,
|
|
10946
10983
|
getterCycle: (cycle) => `\u30D1\u30B9 getter \u304C\u5FAA\u74B0\u53C2\u7167\u3057\u3066\u3044\u307E\u3059: ${cycle}`,
|
|
10947
10984
|
updatedCallbackUnbound: (p) => `$renderedCallback \u306F binding \u99C6\u52D5\u3067\u3059\u3002"${p}" \u306F\u3053\u306E\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8\u306E\u3069\u306E\u30D0\u30A4\u30F3\u30C7\u30A3\u30F3\u30B0\u306B\u3082\u73FE\u308C\u306A\u3044\u305F\u3081\u3001\u3053\u306E\u5206\u5C90\u306F\u4E00\u5EA6\u3082\u5B9F\u884C\u3055\u308C\u307E\u305B\u3093\u3002\u63CF\u753B\u306B\u4F9D\u5B58\u305B\u305A\u53CD\u5FDC\u3059\u308B\u306A\u3089 $watch \u3092\u4F7F\u3063\u3066\u304F\u3060\u3055\u3044`,
|
|
10985
|
+
onHandlerThis: (name) => `$on \u306E\u30CF\u30F3\u30C9\u30E9 "${name}" \u304C this \u3092\u4F7F\u3063\u3066\u3044\u307E\u3059\u3002$on \u306E\u30CF\u30F3\u30C9\u30E9\u306F state \u3092\u7B2C 1 \u5F15\u6570\u3067\u53D7\u3051\u53D6\u308A\uFF08\`${name}(state, event) { state.x = \u2026 }\`\uFF09\u3001this \u306F undefined \u306A\u306E\u3067\u3001this.\u2026 \u306F\u547C\u3070\u308C\u305F\u3068\u304D\u306B\u4F8B\u5916\u306B\u306A\u308A\u307E\u3059\u3002$watch \u3084\u30E1\u30BD\u30C3\u30C9\u3068\u9055\u3046\u70B9\u306B\u6CE8\u610F`,
|
|
10948
10986
|
getterUntrackedRead: (root, sp) => `\u3053\u3053\u3067\u8FFD\u8DE1\u3055\u308C\u308B\u306E\u306F "${root}" \u3060\u3051\u3067\u3059\u3002"${sp}" \u304C\u5909\u308F\u3063\u3066\u3082\u3053\u306E getter \u306F\u518D\u8A55\u4FA1\u3055\u308C\u307E\u305B\u3093\uFF08\u30D1\u30B9\u8AAD\u307F\u53D6\u308A\u306E\u5148\u306E\u7D20\u306E\u30D7\u30ED\u30D1\u30C6\u30A3\u30A2\u30AF\u30BB\u30B9\u306F\u8FFD\u8DE1\u3055\u308C\u306A\u3044\uFF09\u3002this["${sp}"] \u3067\u8AAD\u3093\u3067\u304F\u3060\u3055\u3044`,
|
|
10949
10987
|
handlerFilterNotAllowed: (prop) => `\u30A4\u30D9\u30F3\u30C8\u30CF\u30F3\u30C9\u30E9 "${prop}" \u306B\u30D5\u30A3\u30EB\u30BF\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093`,
|
|
10950
10988
|
typeExpectation: (label, expected, resultType) => `"${label}" \u306B\u306F${JA_EXPECTED_LABEL[expected]}\u304C\u5FC5\u8981\u3067\u3059\uFF08\u73FE\u5728\u306E\u578B: ${resultType}\uFF09`,
|
|
@@ -10995,7 +11033,7 @@ var ja = {
|
|
|
10995
11033
|
didYouMean: (c) => `\u3002\u3082\u3057\u304B\u3057\u3066: "${c}"`,
|
|
10996
11034
|
none: () => `\u306A\u3057`,
|
|
10997
11035
|
triggerSeededTruthy: (path) => `trigger \u30D0\u30A4\u30F3\u30C9\u5148 "${path}" \u304C true \u3067\u30B7\u30FC\u30C9\u3055\u308C\u3066\u3044\u307E\u3059\u3002trigger \u306F\u30A8\u30C3\u30B8\u691C\u51FA\u306A\u3057\uFF08truthy \u66F8\u304D\u8FBC\u307F\u3067\u5373\u767A\u706B\u30FBmanual \u3082\u30D0\u30A4\u30D1\u30B9\uFF09\u306E\u305F\u3081\u3001\u30D0\u30A4\u30F3\u30C9\u6642\u306B\u5373\u767A\u706B\u3057\u307E\u3059\u3002false \u3067\u30B7\u30FC\u30C9\u3057\u3066\u304F\u3060\u3055\u3044`,
|
|
10998
|
-
storageSeedClobber: (path, raw) => `<wcs-storage> \u306E value \u30D0\u30A4\u30F3\u30C9\u5148 "${path}" \u304C ${raw} \u3067\u30B7\u30FC\u30C9\u3055\u308C\u3066\u3044\u307E\u3059\u3002\u8AAD\u307F\u8FBC\u307F\u306E\u305F\u3073\u306B\u521D\u671F\u66F8\u304D\u623B\u3057\u304C\u4FDD\u5B58\u5024\u3092\u4E0A\u66F8\u304D\u3057\u307E\u3059 \u2014 \u30D0\u30A4\u30F3\u30C9\u306B #init=element \u3092\u4ED8\u3051\u3066\uFF08\`value#init=element: ${path}\`\uFF09\u4FDD\u5B58\u5024\u3092\u52DD\u305F\u305B\u3001\u30B9\u30ED\u30C3\u30C8\u306F null\uFF08\u7A7A\u306E\u30AD\u30FC\u304C\u8AAD\u3080\u5024\uFF09\u3067\u30B7\u30FC\u30C9\u3057\u3066\u304F\u3060\u3055\u3044`,
|
|
11036
|
+
storageSeedClobber: (path, raw) => `<wcs-storage> \u306E value \u30D0\u30A4\u30F3\u30C9\u5148 "${path}" \u304C ${shortSeed(raw)} \u3067\u30B7\u30FC\u30C9\u3055\u308C\u3066\u3044\u307E\u3059\u3002\u8AAD\u307F\u8FBC\u307F\u306E\u305F\u3073\u306B\u521D\u671F\u66F8\u304D\u623B\u3057\u304C\u4FDD\u5B58\u5024\u3092\u4E0A\u66F8\u304D\u3057\u307E\u3059 \u2014 \u30D0\u30A4\u30F3\u30C9\u306B #init=element \u3092\u4ED8\u3051\u3066\uFF08\`value#init=element: ${path}\`\uFF09\u4FDD\u5B58\u5024\u3092\u52DD\u305F\u305B\u3001\u30B9\u30ED\u30C3\u30C8\u306F null\uFF08\u7A7A\u306E\u30AD\u30FC\u304C\u8AAD\u3080\u5024\uFF09\u3067\u30B7\u30FC\u30C9\u3057\u3066\u304F\u3060\u3055\u3044`,
|
|
10999
11037
|
storageInitSeed: (path, raw) => `<wcs-storage> \u306E value \u30D0\u30A4\u30F3\u30C9\u5148 "${path}" \u304C ${shortSeed(raw)} \u3067\u30B7\u30FC\u30C9\u3055\u308C\u3066\u3044\u307E\u3059\u304C\u3001#init=element \u306F\u8981\u7D20\u306E\u5024\u3092\u3053\u306E\u30B9\u30ED\u30C3\u30C8\u3078\u5F15\u304D\u8FBC\u307F\u307E\u3059\u3002\u521D\u56DE\uFF08\u7A7A\u306E\u30AD\u30FC\uFF09\u306F null \u306A\u306E\u3067\u3001\u30B7\u30FC\u30C9\u306F null \u306B\u7F6E\u304D\u63DB\u308F\u308A\u307E\u3059 \u2014 null \u3067\u30B7\u30FC\u30C9\u3057\u3066\u8AAD\u3080\u5074\u3067\u65E2\u5B9A\u5024\u3092\u88DC\u3046\uFF08\`this.${path} ?? \u2026\`\uFF09\u304B\u3001null \u3092\u7121\u8996\u3059\u308B setter \u3092\u6301\u3064\u30A2\u30AF\u30BB\u30B5\u30DA\u30A2\u3092\u675F\u306D\u3066\u304F\u3060\u3055\u3044`,
|
|
11000
11038
|
storagePairClobber: (path) => `<wcs-storage> \u306E value \u3092 #init=element \u306A\u3057\u3067\u30A2\u30AF\u30BB\u30B5\u30DA\u30A2 "${path}" \u306B\u675F\u306D\u3066\u3044\u307E\u3059\u3002state \u306E\u5074\u304C\u5148\u306B\u66F8\u304F\u306E\u3067\u3001\u8AAD\u307F\u8FBC\u307F\u306E\u305F\u3073\u306B getter \u306E\u6700\u521D\u306E\u5024\u304C\u4FDD\u5B58\u5024\u306E\u4E0A\u306B\u4FDD\u5B58\u3055\u308C\u3001setter \u306F\u4FDD\u5B58\u5024\u3092\u53D7\u3051\u53D6\u308C\u307E\u305B\u3093 \u2014 #init=element \u3092\u4ED8\u3051\u3066\u304F\u3060\u3055\u3044\uFF08\`value#init=element: ${path}\`\uFF09`,
|
|
11001
11039
|
inputNestedWrite: (tag, input, path, example) => `<${tag}> \u306E\u5165\u529B "${input}" \u306B "${path}" \u3092\u675F\u306D\u3066\u3044\u307E\u3059\u304C\u3001\u30DA\u30FC\u30B8\u306F\u305D\u306E\u4E0B\uFF08"${example}"\uFF09\u3078\u66F8\u304D\u8FBC\u3093\u3067\u3044\u307E\u3059\u3002\u675F\u7E1B\u306F "${path}" \u81EA\u8EAB\u3078\u306E\u4EE3\u5165\u3067\u3057\u304B\u5F53\u3066\u76F4\u3055\u308C\u306A\u3044\u306E\u3067\u3001\u4E0B\u3078\u306E\u66F8\u304D\u8FBC\u307F\u306F <${tag}> \u306B\u5C4A\u304D\u307E\u305B\u3093 \u2014 \u30D5\u30A3\u30FC\u30EB\u30C9\u3092\u30D1\u30B9\u3067\u8AAD\u3093\u3067\u65B0\u3057\u3044\u5024\u3092\u8FD4\u3059 getter\uFF08\`this["${example}"]\`\u30FB\`$getAll\`\uFF09\u3092\u675F\u306D\u308B\u304B\u3001\u4E0B\u3078\u66F8\u304B\u305A\u306B "${path}" \u3092\u5DEE\u3057\u66FF\u3048\u3066\u304F\u3060\u3055\u3044`,
|
|
@@ -11136,6 +11174,7 @@ var en = {
|
|
|
11136
11174
|
delegatedCurrentTarget: (suggested, eventName, handler) => `"${eventName}" bindings are delegated to the root, so event.currentTarget in "${handler}" is the root, not this element. Write "${suggested}:" to keep the listener on the element, or find the element with event.target.closest(...)`,
|
|
11137
11175
|
getterCycle: (cycle) => `Path getters form a dependency cycle: ${cycle}`,
|
|
11138
11176
|
updatedCallbackUnbound: (p) => `$renderedCallback is binding-driven. "${p}" is not bound anywhere in this document, so this branch never runs. Use $watch to react without depending on what is rendered`,
|
|
11177
|
+
onHandlerThis: (name) => `The $on handler "${name}" uses this. A $on handler receives the state as its first argument (\`${name}(state, event) { state.x = \u2026 }\`) and this is undefined, so this.\u2026 throws when it is called \u2014 unlike $watch handlers and methods`,
|
|
11139
11178
|
getterUntrackedRead: (root, sp) => `Only "${root}" is tracked here: the getter is not re-evaluated when "${sp}" changes (plain property access after a path read is not tracked). Read this["${sp}"] instead`,
|
|
11140
11179
|
handlerFilterNotAllowed: (prop) => `Filters cannot be applied to event handler "${prop}"`,
|
|
11141
11180
|
typeExpectation: (label, expected, resultType) => `"${label}" requires ${EN_EXPECTED_LABEL[expected]} (current type: ${resultType})`,
|
|
@@ -11186,7 +11225,7 @@ var en = {
|
|
|
11186
11225
|
didYouMean: (c) => `. Did you mean "${c}"?`,
|
|
11187
11226
|
none: () => `none`,
|
|
11188
11227
|
triggerSeededTruthy: (path) => `The trigger-bound slot "${path}" is seeded with true. trigger has no edge detection (any truthy write fires, and it bypasses manual), so it fires immediately at bind. Seed it with false`,
|
|
11189
|
-
storageSeedClobber: (path, raw) => `The <wcs-storage> value-bound slot "${path}" is seeded with ${raw}. The initial write-back overwrites the persisted value on every load \u2014 add #init=element to the binding (\`value#init=element: ${path}\`) so the stored value wins, and seed the slot with null (what an empty key loads as)`,
|
|
11228
|
+
storageSeedClobber: (path, raw) => `The <wcs-storage> value-bound slot "${path}" is seeded with ${shortSeed(raw)}. The initial write-back overwrites the persisted value on every load \u2014 add #init=element to the binding (\`value#init=element: ${path}\`) so the stored value wins, and seed the slot with null (what an empty key loads as)`,
|
|
11190
11229
|
storageInitSeed: (path, raw) => `The <wcs-storage> value-bound slot "${path}" is seeded with ${shortSeed(raw)}, but #init=element pulls the element's value into it. On a first visit (an empty key) that is null, so the seed is replaced by null \u2014 seed it with null and supply the default where you read it (\`this.${path} ?? \u2026\`), or bind an accessor pair whose setter ignores null`,
|
|
11191
11230
|
storagePairClobber: (path) => `The <wcs-storage> value is bound to the accessor pair "${path}" without #init=element. The state's side goes first, so on every load the getter's starting value is saved over the stored one, and the setter never receives it \u2014 add #init=element (\`value#init=element: ${path}\`)`,
|
|
11192
11231
|
inputNestedWrite: (tag, input, path, example) => `"${path}" is bound to the input "${input}" of <${tag}>, but the page writes below it ("${example}"). A binding is re-applied only when "${path}" itself is assigned, so those writes never reach <${tag}> \u2014 bind a getter that reads the fields by path (\`this["${example}"]\`, \`$getAll\`) and returns a new value, or replace "${path}" instead of writing below it`,
|
|
@@ -13534,7 +13573,8 @@ var BUILTIN_TAGS = {
|
|
|
13534
13573
|
"downlink",
|
|
13535
13574
|
"rtt",
|
|
13536
13575
|
"saveData",
|
|
13537
|
-
"supported"
|
|
13576
|
+
"supported",
|
|
13577
|
+
"offline"
|
|
13538
13578
|
],
|
|
13539
13579
|
"commands": []
|
|
13540
13580
|
},
|
|
@@ -14055,7 +14095,6 @@ var EXPLICIT_PROPERTY_REJECTED_HEADS2 = /* @__PURE__ */ new Set([
|
|
|
14055
14095
|
var EXPLICIT_PROPERTY_REJECTED_HEADS_RE = new RegExp(
|
|
14056
14096
|
`^(?:${[...EXPLICIT_PROPERTY_REJECTED_HEADS2].map((w) => w.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|")})(\\.|$)`
|
|
14057
14097
|
);
|
|
14058
|
-
var EMPTYISH_SEEDS = /* @__PURE__ */ new Set(["''", '""', "``", "null", "[]", "{}"]);
|
|
14059
14098
|
function validateIoNodes(html, bindAttribute = "data-wcs", stateTagName = "wcs-state", locale2, fileReader) {
|
|
14060
14099
|
const diagnostics = [];
|
|
14061
14100
|
const msgs = getMessages(locale2);
|
|
@@ -14202,12 +14241,12 @@ function validateBindingAgainstContract(tagName, contract, parsed, property, sta
|
|
|
14202
14241
|
if (tagName === "wcs-storage" && property === "value" && !hasManual && parsed.path && !/(?:^|,)init=(?:element|auto)\b/.test(modifiers)) {
|
|
14203
14242
|
const paths = getPaths();
|
|
14204
14243
|
const cand = findDataSlot(paths, parsed.path);
|
|
14205
|
-
if (cand?.rawInitial !== void 0 &&
|
|
14244
|
+
if (cand?.rawInitial !== void 0 && (cand.rawInitial.trim() === "null" || isNonNullLiteralSeed(cand.rawInitial))) {
|
|
14206
14245
|
diagnostics.push({
|
|
14207
14246
|
code: WcsDiagnosticCode.StorageSeedClobber,
|
|
14208
14247
|
start,
|
|
14209
14248
|
end,
|
|
14210
|
-
severity: "
|
|
14249
|
+
severity: "error",
|
|
14211
14250
|
tag: tagName,
|
|
14212
14251
|
statePath: parsed.path,
|
|
14213
14252
|
message: msgs.storageSeedClobber(parsed.path, cand.rawInitial)
|
|
@@ -14217,7 +14256,7 @@ function validateBindingAgainstContract(tagName, contract, parsed, property, sta
|
|
|
14217
14256
|
code: WcsDiagnosticCode.StorageSeedClobber,
|
|
14218
14257
|
start,
|
|
14219
14258
|
end,
|
|
14220
|
-
severity: "
|
|
14259
|
+
severity: "error",
|
|
14221
14260
|
tag: tagName,
|
|
14222
14261
|
statePath: parsed.path,
|
|
14223
14262
|
message: msgs.storagePairClobber(parsed.path)
|
|
@@ -14246,10 +14285,6 @@ function isNonNullLiteralSeed(raw) {
|
|
|
14246
14285
|
function findDataSlot(paths, path) {
|
|
14247
14286
|
return paths.find((c) => c.kind === "data" && c.path === path);
|
|
14248
14287
|
}
|
|
14249
|
-
function normalizeSeed(raw) {
|
|
14250
|
-
const compact = raw.replace(/\s+/g, "");
|
|
14251
|
-
return compact === "" ? raw : compact;
|
|
14252
|
-
}
|
|
14253
14288
|
function findBuiltinTagOccurrences(html) {
|
|
14254
14289
|
const out = [];
|
|
14255
14290
|
const regex = /<(wcs-[a-z0-9-]+)((?:"[^"]*"|'[^']*'|[^>"'])*)>/gi;
|
|
@@ -14392,7 +14427,8 @@ function validateDocumentEnv(html, locale2) {
|
|
|
14392
14427
|
});
|
|
14393
14428
|
}
|
|
14394
14429
|
}
|
|
14395
|
-
const
|
|
14430
|
+
const hasRouterTag = /<wcs-router\b/i.test(scanText);
|
|
14431
|
+
const router = autos.find((a) => a.pkgs.includes("router") && (!a.bundle || hasRouterTag)) ?? (hasRouterTag ? collectInlineImports(scanText).find((i) => /@wcstack\/router\b/.test(i.spec) || BUNDLE_AUTO.test(i.spec)) : void 0);
|
|
14396
14432
|
if (router && !/<base\b[^>]*\bhref\s*=/i.test(scanText)) {
|
|
14397
14433
|
diagnostics.push({
|
|
14398
14434
|
code: WcsDiagnosticCode.BaseHrefMissing,
|
|
@@ -14450,35 +14486,41 @@ function findWcstackAutoScripts(html) {
|
|
|
14450
14486
|
}
|
|
14451
14487
|
function collectSignalsRefs(html) {
|
|
14452
14488
|
const refs = [];
|
|
14453
|
-
const scriptRegex = /<script\b((?:"[^"]*"|'[^']*'|[^>"'])*)
|
|
14489
|
+
const scriptRegex = /<script\b((?:"[^"]*"|'[^']*'|[^>"'])*)>/gi;
|
|
14454
14490
|
let match;
|
|
14455
14491
|
while ((match = scriptRegex.exec(html)) !== null) {
|
|
14456
|
-
const
|
|
14457
|
-
const
|
|
14458
|
-
if (src) {
|
|
14459
|
-
|
|
14460
|
-
|
|
14461
|
-
|
|
14462
|
-
|
|
14463
|
-
|
|
14464
|
-
end: match.index + src.offsetInTag + src.value.length
|
|
14465
|
-
});
|
|
14466
|
-
}
|
|
14467
|
-
continue;
|
|
14492
|
+
const src = extractSrc(match[0]);
|
|
14493
|
+
const kind = src ? classifySignalsSpecifier(src.value) : null;
|
|
14494
|
+
if (src && kind) {
|
|
14495
|
+
refs.push({
|
|
14496
|
+
kind,
|
|
14497
|
+
start: match.index + src.offsetInTag,
|
|
14498
|
+
end: match.index + src.offsetInTag + src.value.length
|
|
14499
|
+
});
|
|
14468
14500
|
}
|
|
14469
|
-
|
|
14501
|
+
}
|
|
14502
|
+
for (const im of collectInlineImports(html)) {
|
|
14503
|
+
const kind = classifySignalsSpecifier(im.spec);
|
|
14504
|
+
if (kind) refs.push({ kind, start: im.start, end: im.end });
|
|
14505
|
+
}
|
|
14506
|
+
return refs.sort((a, b) => a.start - b.start);
|
|
14507
|
+
}
|
|
14508
|
+
function collectInlineImports(html) {
|
|
14509
|
+
const out = [];
|
|
14510
|
+
const scriptRegex = /<script\b((?:"[^"]*"|'[^']*'|[^>"'])*)>([\s\S]*?)<\/script\s*>/gi;
|
|
14511
|
+
let match;
|
|
14512
|
+
while ((match = scriptRegex.exec(html)) !== null) {
|
|
14513
|
+
if (extractSrc(`<script${match[1]}>`) || !/\btype\s*=\s*(["'])module\1/i.test(match[1])) continue;
|
|
14470
14514
|
const bodyStart = match.index + match[0].indexOf(">") + 1;
|
|
14471
14515
|
const body = blankJsComments(match[2]);
|
|
14472
|
-
const importRegex = /(?:\bfrom\s*|\bimport\s*\(?\s*)(["'])([^"']
|
|
14516
|
+
const importRegex = /(?:\bfrom\s*|\bimport\s*\(?\s*)(["'])([^"']*)\1/g;
|
|
14473
14517
|
let im;
|
|
14474
14518
|
while ((im = importRegex.exec(body)) !== null) {
|
|
14475
|
-
const
|
|
14476
|
-
|
|
14477
|
-
const specStart = bodyStart + im.index + im[0].indexOf(im[1]) + 1;
|
|
14478
|
-
refs.push({ kind, start: specStart, end: specStart + im[2].length });
|
|
14519
|
+
const start = bodyStart + im.index + im[0].indexOf(im[1]) + 1;
|
|
14520
|
+
out.push({ spec: im[2], start, end: start + im[2].length });
|
|
14479
14521
|
}
|
|
14480
14522
|
}
|
|
14481
|
-
return
|
|
14523
|
+
return out;
|
|
14482
14524
|
}
|
|
14483
14525
|
function classifySignalsSpecifier(spec) {
|
|
14484
14526
|
if (!spec.includes("@wcstack/signals")) return null;
|
|
@@ -16141,6 +16183,22 @@ function hasOutOfRangeIndexName(script) {
|
|
|
16141
16183
|
}
|
|
16142
16184
|
return false;
|
|
16143
16185
|
}
|
|
16186
|
+
function validateOnHandlerThis(script, scriptStart, locale2) {
|
|
16187
|
+
const msgs = getMessages(locale2);
|
|
16188
|
+
const out = [];
|
|
16189
|
+
for (const handler of analyzeOnHandlerSources(script)) {
|
|
16190
|
+
const first = findOwnThis(handler.text, handler.kind);
|
|
16191
|
+
if (first === null) continue;
|
|
16192
|
+
out.push({
|
|
16193
|
+
code: WcsDiagnosticCode.OnHandlerThis,
|
|
16194
|
+
start: scriptStart + handler.start + first.start,
|
|
16195
|
+
end: scriptStart + handler.start + first.end,
|
|
16196
|
+
severity: "error",
|
|
16197
|
+
message: msgs.onHandlerThis(handler.name)
|
|
16198
|
+
});
|
|
16199
|
+
}
|
|
16200
|
+
return out;
|
|
16201
|
+
}
|
|
16144
16202
|
function validateSemantics(html, stateTagName = "wcs-state", locale2, bindAttrName = "data-wcs") {
|
|
16145
16203
|
const out = [];
|
|
16146
16204
|
const blocks = parseLoadedScriptBlocks(html, stateTagName);
|
|
@@ -16152,6 +16210,7 @@ function validateSemantics(html, stateTagName = "wcs-state", locale2, bindAttrNa
|
|
|
16152
16210
|
out.push(...validateIndexParamReads(block.content, block.contentStart, locale2));
|
|
16153
16211
|
out.push(...validateGetterCycles(block.content, block.contentStart, locale2));
|
|
16154
16212
|
out.push(...validateGetterUntrackedReads(block.content, block.contentStart, getNestedWriteRoots, locale2));
|
|
16213
|
+
out.push(...validateOnHandlerThis(block.content, block.contentStart, locale2));
|
|
16155
16214
|
}
|
|
16156
16215
|
out.push(...validateInputNestedWrites(html, stateTagName, bindAttrName, getNestedWriteRoots, locale2));
|
|
16157
16216
|
out.push(...validateUpdatedCallbackDemand(html, stateTagName, bindAttrName, locale2));
|
package/dist/wcs-schema.mjs
CHANGED
package/dist/wcs-tsc.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wcstack/typescript",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.1.1",
|
|
4
4
|
"description": "TypeScript tooling for wcstack apps: wcs-schema generates the sidecar stateSchema from a typed state file, so wcs-validate checks data-wcs paths against real types in CI and every editor.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.esm.js",
|