@wcstack/typescript 4.0.4 → 4.1.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/index.esm.js +1 -1
- package/dist/schema-core.cjs +63 -32
- 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
|
|
@@ -10945,6 +10953,7 @@ var ja = {
|
|
|
10945
10953
|
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
10954
|
getterCycle: (cycle) => `\u30D1\u30B9 getter \u304C\u5FAA\u74B0\u53C2\u7167\u3057\u3066\u3044\u307E\u3059: ${cycle}`,
|
|
10947
10955
|
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`,
|
|
10956
|
+
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
10957
|
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
10958
|
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
10959
|
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 +11004,7 @@ var ja = {
|
|
|
10995
11004
|
didYouMean: (c) => `\u3002\u3082\u3057\u304B\u3057\u3066: "${c}"`,
|
|
10996
11005
|
none: () => `\u306A\u3057`,
|
|
10997
11006
|
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`,
|
|
11007
|
+
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
11008
|
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
11009
|
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
11010
|
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 +11145,7 @@ var en = {
|
|
|
11136
11145
|
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
11146
|
getterCycle: (cycle) => `Path getters form a dependency cycle: ${cycle}`,
|
|
11138
11147
|
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`,
|
|
11148
|
+
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
11149
|
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
11150
|
handlerFilterNotAllowed: (prop) => `Filters cannot be applied to event handler "${prop}"`,
|
|
11141
11151
|
typeExpectation: (label, expected, resultType) => `"${label}" requires ${EN_EXPECTED_LABEL[expected]} (current type: ${resultType})`,
|
|
@@ -11186,7 +11196,7 @@ var en = {
|
|
|
11186
11196
|
didYouMean: (c) => `. Did you mean "${c}"?`,
|
|
11187
11197
|
none: () => `none`,
|
|
11188
11198
|
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)`,
|
|
11199
|
+
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
11200
|
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
11201
|
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
11202
|
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`,
|
|
@@ -14055,7 +14065,6 @@ var EXPLICIT_PROPERTY_REJECTED_HEADS2 = /* @__PURE__ */ new Set([
|
|
|
14055
14065
|
var EXPLICIT_PROPERTY_REJECTED_HEADS_RE = new RegExp(
|
|
14056
14066
|
`^(?:${[...EXPLICIT_PROPERTY_REJECTED_HEADS2].map((w) => w.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|")})(\\.|$)`
|
|
14057
14067
|
);
|
|
14058
|
-
var EMPTYISH_SEEDS = /* @__PURE__ */ new Set(["''", '""', "``", "null", "[]", "{}"]);
|
|
14059
14068
|
function validateIoNodes(html, bindAttribute = "data-wcs", stateTagName = "wcs-state", locale2, fileReader) {
|
|
14060
14069
|
const diagnostics = [];
|
|
14061
14070
|
const msgs = getMessages(locale2);
|
|
@@ -14202,12 +14211,12 @@ function validateBindingAgainstContract(tagName, contract, parsed, property, sta
|
|
|
14202
14211
|
if (tagName === "wcs-storage" && property === "value" && !hasManual && parsed.path && !/(?:^|,)init=(?:element|auto)\b/.test(modifiers)) {
|
|
14203
14212
|
const paths = getPaths();
|
|
14204
14213
|
const cand = findDataSlot(paths, parsed.path);
|
|
14205
|
-
if (cand?.rawInitial !== void 0 &&
|
|
14214
|
+
if (cand?.rawInitial !== void 0 && (cand.rawInitial.trim() === "null" || isNonNullLiteralSeed(cand.rawInitial))) {
|
|
14206
14215
|
diagnostics.push({
|
|
14207
14216
|
code: WcsDiagnosticCode.StorageSeedClobber,
|
|
14208
14217
|
start,
|
|
14209
14218
|
end,
|
|
14210
|
-
severity: "
|
|
14219
|
+
severity: "error",
|
|
14211
14220
|
tag: tagName,
|
|
14212
14221
|
statePath: parsed.path,
|
|
14213
14222
|
message: msgs.storageSeedClobber(parsed.path, cand.rawInitial)
|
|
@@ -14217,7 +14226,7 @@ function validateBindingAgainstContract(tagName, contract, parsed, property, sta
|
|
|
14217
14226
|
code: WcsDiagnosticCode.StorageSeedClobber,
|
|
14218
14227
|
start,
|
|
14219
14228
|
end,
|
|
14220
|
-
severity: "
|
|
14229
|
+
severity: "error",
|
|
14221
14230
|
tag: tagName,
|
|
14222
14231
|
statePath: parsed.path,
|
|
14223
14232
|
message: msgs.storagePairClobber(parsed.path)
|
|
@@ -14246,10 +14255,6 @@ function isNonNullLiteralSeed(raw) {
|
|
|
14246
14255
|
function findDataSlot(paths, path) {
|
|
14247
14256
|
return paths.find((c) => c.kind === "data" && c.path === path);
|
|
14248
14257
|
}
|
|
14249
|
-
function normalizeSeed(raw) {
|
|
14250
|
-
const compact = raw.replace(/\s+/g, "");
|
|
14251
|
-
return compact === "" ? raw : compact;
|
|
14252
|
-
}
|
|
14253
14258
|
function findBuiltinTagOccurrences(html) {
|
|
14254
14259
|
const out = [];
|
|
14255
14260
|
const regex = /<(wcs-[a-z0-9-]+)((?:"[^"]*"|'[^']*'|[^>"'])*)>/gi;
|
|
@@ -14392,7 +14397,8 @@ function validateDocumentEnv(html, locale2) {
|
|
|
14392
14397
|
});
|
|
14393
14398
|
}
|
|
14394
14399
|
}
|
|
14395
|
-
const
|
|
14400
|
+
const hasRouterTag = /<wcs-router\b/i.test(scanText);
|
|
14401
|
+
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
14402
|
if (router && !/<base\b[^>]*\bhref\s*=/i.test(scanText)) {
|
|
14397
14403
|
diagnostics.push({
|
|
14398
14404
|
code: WcsDiagnosticCode.BaseHrefMissing,
|
|
@@ -14450,35 +14456,41 @@ function findWcstackAutoScripts(html) {
|
|
|
14450
14456
|
}
|
|
14451
14457
|
function collectSignalsRefs(html) {
|
|
14452
14458
|
const refs = [];
|
|
14453
|
-
const scriptRegex = /<script\b((?:"[^"]*"|'[^']*'|[^>"'])*)
|
|
14459
|
+
const scriptRegex = /<script\b((?:"[^"]*"|'[^']*'|[^>"'])*)>/gi;
|
|
14454
14460
|
let match;
|
|
14455
14461
|
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;
|
|
14462
|
+
const src = extractSrc(match[0]);
|
|
14463
|
+
const kind = src ? classifySignalsSpecifier(src.value) : null;
|
|
14464
|
+
if (src && kind) {
|
|
14465
|
+
refs.push({
|
|
14466
|
+
kind,
|
|
14467
|
+
start: match.index + src.offsetInTag,
|
|
14468
|
+
end: match.index + src.offsetInTag + src.value.length
|
|
14469
|
+
});
|
|
14468
14470
|
}
|
|
14469
|
-
|
|
14471
|
+
}
|
|
14472
|
+
for (const im of collectInlineImports(html)) {
|
|
14473
|
+
const kind = classifySignalsSpecifier(im.spec);
|
|
14474
|
+
if (kind) refs.push({ kind, start: im.start, end: im.end });
|
|
14475
|
+
}
|
|
14476
|
+
return refs.sort((a, b) => a.start - b.start);
|
|
14477
|
+
}
|
|
14478
|
+
function collectInlineImports(html) {
|
|
14479
|
+
const out = [];
|
|
14480
|
+
const scriptRegex = /<script\b((?:"[^"]*"|'[^']*'|[^>"'])*)>([\s\S]*?)<\/script\s*>/gi;
|
|
14481
|
+
let match;
|
|
14482
|
+
while ((match = scriptRegex.exec(html)) !== null) {
|
|
14483
|
+
if (extractSrc(`<script${match[1]}>`) || !/\btype\s*=\s*(["'])module\1/i.test(match[1])) continue;
|
|
14470
14484
|
const bodyStart = match.index + match[0].indexOf(">") + 1;
|
|
14471
14485
|
const body = blankJsComments(match[2]);
|
|
14472
|
-
const importRegex = /(?:\bfrom\s*|\bimport\s*\(?\s*)(["'])([^"']
|
|
14486
|
+
const importRegex = /(?:\bfrom\s*|\bimport\s*\(?\s*)(["'])([^"']*)\1/g;
|
|
14473
14487
|
let im;
|
|
14474
14488
|
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 });
|
|
14489
|
+
const start = bodyStart + im.index + im[0].indexOf(im[1]) + 1;
|
|
14490
|
+
out.push({ spec: im[2], start, end: start + im[2].length });
|
|
14479
14491
|
}
|
|
14480
14492
|
}
|
|
14481
|
-
return
|
|
14493
|
+
return out;
|
|
14482
14494
|
}
|
|
14483
14495
|
function classifySignalsSpecifier(spec) {
|
|
14484
14496
|
if (!spec.includes("@wcstack/signals")) return null;
|
|
@@ -16141,6 +16153,24 @@ function hasOutOfRangeIndexName(script) {
|
|
|
16141
16153
|
}
|
|
16142
16154
|
return false;
|
|
16143
16155
|
}
|
|
16156
|
+
var ANY_MEMBER = { has: () => true };
|
|
16157
|
+
function validateOnHandlerThis(script, scriptStart, locale2) {
|
|
16158
|
+
const msgs = getMessages(locale2);
|
|
16159
|
+
const out = [];
|
|
16160
|
+
for (const handler of analyzeOnHandlerSources(script)) {
|
|
16161
|
+
const refs = handler.kind === "body" ? collectThisMemberRefs(handler.text, ANY_MEMBER) : collectThisMemberRefsInValue(handler.text, ANY_MEMBER);
|
|
16162
|
+
const first = refs?.[0];
|
|
16163
|
+
if (first === void 0) continue;
|
|
16164
|
+
out.push({
|
|
16165
|
+
code: WcsDiagnosticCode.OnHandlerThis,
|
|
16166
|
+
start: scriptStart + handler.start + first.start,
|
|
16167
|
+
end: scriptStart + handler.start + first.end,
|
|
16168
|
+
severity: "error",
|
|
16169
|
+
message: msgs.onHandlerThis(handler.name)
|
|
16170
|
+
});
|
|
16171
|
+
}
|
|
16172
|
+
return out;
|
|
16173
|
+
}
|
|
16144
16174
|
function validateSemantics(html, stateTagName = "wcs-state", locale2, bindAttrName = "data-wcs") {
|
|
16145
16175
|
const out = [];
|
|
16146
16176
|
const blocks = parseLoadedScriptBlocks(html, stateTagName);
|
|
@@ -16152,6 +16182,7 @@ function validateSemantics(html, stateTagName = "wcs-state", locale2, bindAttrNa
|
|
|
16152
16182
|
out.push(...validateIndexParamReads(block.content, block.contentStart, locale2));
|
|
16153
16183
|
out.push(...validateGetterCycles(block.content, block.contentStart, locale2));
|
|
16154
16184
|
out.push(...validateGetterUntrackedReads(block.content, block.contentStart, getNestedWriteRoots, locale2));
|
|
16185
|
+
out.push(...validateOnHandlerThis(block.content, block.contentStart, locale2));
|
|
16155
16186
|
}
|
|
16156
16187
|
out.push(...validateInputNestedWrites(html, stateTagName, bindAttrName, getNestedWriteRoots, locale2));
|
|
16157
16188
|
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.0
|
|
3
|
+
"version": "4.1.0",
|
|
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",
|