@wcstack/typescript 4.2.0 → 4.4.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.
@@ -53,8 +53,12 @@ var WcsDiagnosticCode = {
53
53
  // --- path / type resolution against a stateSchema ---
54
54
  PathNonexistent: "wcs/path-nonexistent",
55
55
  PathTypeMismatch: "wcs/path-type-mismatch",
56
+ // 書き戻す束縛(`value:` / `checked:` / `radio:` / `checkbox:`、`#ro` なし)が、setter の無い getter を指す。ランタイムは
57
+ // 入力のたびに `"<path>" is a getter without a setter` を投げる(code なし — 7GUIs の評価の Temperature)。error。
56
58
  PathReadonly: "wcs/path-readonly",
57
59
  PathReservedName: "wcs/path-reserved-name",
60
+ // lint の限界の告知(作者の誤りではない): `export default { … }` のトップレベルの spread が持ち込むキーは読めないので、
61
+ // stateSchema の無い state のパスは検査しない — それを spread の上で 1 回だけ言う。info。
58
62
  PathDynamicUnknown: "wcs/path-dynamic-unknown",
59
63
  // --- existing binding-expression validators (retrofitted) ---
60
64
  FilterUnknown: "wcs/filter-unknown",
@@ -65,15 +69,29 @@ var WcsDiagnosticCode = {
65
69
  BindingTypeExpectation: "wcs/binding-type-expectation",
66
70
  TokenUndeclared: "wcs/token-undeclared",
67
71
  TokenMisconfigured: "wcs/token-misconfigured",
72
+ // 宣言したコマンドトークンを emit する(スクリプトの `.emit()`・マークアップの `on*: $command.x`)のに、どの
73
+ // `command.<method>:` 束縛にも結ばれていない。emit は誰にも届かず、ランタイムは何も言わない(7GUIs の評価)。warning
74
+ // (ページの外 — 別ファイルのルートのテンプレート — で束ねる形は見えない)。
75
+ CommandTokenUnbound: "wcs/command-token-unbound",
76
+ // state が宣言していないトップレベルのキーへの書き込み(`this.selectedID = …` と `selectedId`)。新しいキーができる
77
+ // だけで、宣言したキーの束縛は変わらない。ランタイムは何も言わない。近い名前(打ち間違い)があるときだけ、warning。
78
+ WritePathMissing: "wcs/write-path-missing",
79
+ // getter・メソッドの中で読む state のパス(`this["items.*.amout"]`・`$getAll("items.*.amout")`・`this.totl`)が宣言に無い。
80
+ // 入れ子のパスの読みは undefined になり、そこから計算した金額が黙って違う(確定申告の下書きツールの評価)。トップレベルの
81
+ // キーは読んだ時点で throw する。近い名前(打ち間違い)があるときだけ、warning。ランタイムの diagnostics も同じ code。
82
+ ReadPathMissing: "wcs/read-path-missing",
68
83
  NestedAssign: "wcs/nested-assign",
69
84
  // --- 意味論(構文・存在検査では捕まらない取り違え。service/semanticValidator.ts) ---
70
85
  // `$getAll` / `$setAll` / `$resolve` の添字の本数がパスの `*` の本数と噛み合わない。
71
- // ランタイムは同じ code で raiseError する(超過は以前は黙って無視されていた)。
86
+ // ランタイムは #901 / #902 で throw する(diagnostics の後付けがあれば同じ code の文面。超過は 3.x では
87
+ // 黙って無視されていた)。error。
72
88
  IndexArity: "wcs/index-arity",
73
89
  // ワイルドカードの階数がスコープの段数を超える(`matrix.*.*` を 1 段の for で読む、
74
90
  // `$2` を 1 段のループで読む。ランタイムの #1401)。既存の「for の外」検査の深さ方向の一般化。
75
91
  // 4.0 は各段の `*` が**その段で囲む for のリスト**の行であることも確かめる(#1403・F32 — `for: a`
76
- // の行の中の `b.*.y` は投げる)。静的側も囲む for の一覧と段ごとに比べて同じ code で報告する。
92
+ // の行の中の `b.*.y` は投げる)。静的側も囲む for の一覧と段ごとに比べて同じ code で報告する
93
+ // (ランタイムの文面に code が付くのは diagnostics の後付けがあるとき)。for のスコープを組み直しきれない
94
+ // ので、ランタイムは初期化を失敗させるが warning のまま(vscode-wcs の README の重大度の例外)。
77
95
  WildcardRank: "wcs/wildcard-rank",
78
96
  // ループの添字の範囲(`$1`〜`$128`。上限は manifest の `syntax.indexParam.maxDepth`)の外。ランタイムと同じ code:
79
97
  // for の中のマークアップの `$129`(バインディングが失敗する)と、スクリプトの `this.$0` / `this.$129` / `this.$1000`
@@ -81,7 +99,8 @@ var WcsDiagnosticCode = {
81
99
  // `wcs/binding-path-missing`(ただしけっして動かないので error)。for の外の `$129` はランタイムでは #1401 なので
82
100
  // 従来どおり「for の外のループ添字」(`wcs/template-syntax`)で報告する。
83
101
  IndexParamRange: "wcs/index-param-range",
84
- // パス getter どうしの循環参照。ランタイムはアドレススタック上限まで再帰してから落ちる。
102
+ // パス getter どうしの循環参照。4.0 のランタイムは評価の時点で #701 として throw し、その getter を読む
103
+ // 束縛はすべて失敗する(3.x はアドレススタック上限まで再帰してから落ちた)。error。
85
104
  GetterCycle: "wcs/getter-cycle",
86
105
  // `$renderedCallback`(3.x の旧名 `$updatedCallback`)が、どのバインディングにも現れないパスを判定に使っている。
87
106
  // 同コールバックは **binding 駆動**(live binding が適用された path しか報告しない)
@@ -96,8 +115,9 @@ var WcsDiagnosticCode = {
96
115
  GetterUntrackedRead: "wcs/getter-untracked-read",
97
116
  OnHandlerThis: "wcs/on-handler-this",
98
117
  // --- <wcs-state> script: $watch declaration ---
99
- // ランタイム(watch/processWatchDeclaration.ts)が raiseError で落とす宣言。
100
- // 越境 `@` / `$` 始まり / 空キー・空セグメント / 明らかな非関数ハンドラ。
118
+ // temporal の後付け(state の temporal/watch.ts)が読み込みで throw する宣言: 越境 `@` / `$` 始まり /
119
+ // 空キー / 明らかな非関数ハンドラ。空の段(`a..b`)はランタイムが調べず、その watch は黙って発火しない
120
+ // (lint だけが知らせる — docs/mistake-catalogue.md)。
101
121
  WatchDeclarationInvalid: "wcs/watch-declaration-invalid",
102
122
  // `$watch` のキーが状態定義に存在しない。バインディング側と違い黙って発火しない
103
123
  // だけなので気づけない。severity は binding-path-missing に揃える(warning)。
@@ -116,8 +136,8 @@ var WcsDiagnosticCode = {
116
136
  //
117
137
  // `**` を解釈しない場所へ `**` が渡った(data-wcs / mustache / $watch キー / $listKeys
118
138
  // キー / $resolve / $postUpdate / $dependOn(旧名 $trackDependency) / 代入)、または `$recursion` 宣言が
119
- // 無いのに `**` を使った。runtime は PathInfo の不変条件として raiseError するか
120
- //(API 経由)、getter を黙って無視する(宣言なしの `**` getter)。
139
+ // 無いのに `**` を使った。4.0 の runtime はどれも #1101 で throw する — 宣言なしの `**` getter も、
140
+ // アクセサを登録する時点で(3.x は黙って無視した)。error。
121
141
  RecursionUnsupported: "wcs/recursion-unsupported",
122
142
  // 宣言済みアンカーと合致しない `**`(綴り違い・2 つ目の `**`)、または `**` の後ろが
123
143
  // 整形されていない(空セグメント・`**` 直後の素の `*`)。
@@ -155,7 +175,8 @@ var WcsDiagnosticCode = {
155
175
  // ドットアクセスを含むチェーン代入は NestedAssign の担当(相補・二重報告なし)。
156
176
  ArrayIndexAssign: "wcs/array-index-assign",
157
177
  // --- built-in wcs-* tag contract (generated/builtinTags.generated.ts が正本) ---
158
- // 未知メンバーへのバインド(プロパティ / command. / eventToken. キー)。黙って無視される。
178
+ // 未知メンバーへのバインド(プロパティ / command. / eventToken. キー)。4.0 のランタイムは #38 / #1203 /
179
+ // #1204 で拒み、root では初期化が、行では束縛が失敗する(3.x の「黙って無視」ではない)。error。
159
180
  TagMemberUnknown: "wcs/tag-member-unknown",
160
181
  // タグのメンバー名が "on" で始まる(`once` 等)のに先頭ドット無しで束縛した: ランタイムはイベント束縛にして
161
182
  // "ce" イベントを待ち、値は届かない。明示のプロパティ形 `.once:` を提案する(@wcstack/state 3.1・要件 B5 / 3.x 計画 D36)
@@ -217,7 +238,8 @@ var WcsDiagnosticCode = {
217
238
  // (error 昇格時は packages/lint/scripts/smoke-test.mjs の対ケース更新が必須)。
218
239
  AriaAttrUnknown: "wcs/aria-attr-unknown",
219
240
  // --- document-level load configuration ---
220
- // @wcstack/state/auto より後に他 wcstack /auto が読まれている。
241
+ // @wcstack/state/auto より後に @wcstack/devtools/auto が読まれている。info: 4.0 は後から付いた DevTools に
242
+ // 既存の束縛を送り直すので、欠けるのは付く前のタイムラインだけ。
221
243
  ScriptOrder: "wcs/script-order",
222
244
  // router/auto があるのに <base href> がない(SPA の basename 誤導出)。
223
245
  BaseHrefMissing: "wcs/base-href-missing",
@@ -441,8 +463,8 @@ function derefUnion(node, rootDefs) {
441
463
  }
442
464
  return { kind: "ok", nodes: out };
443
465
  }
444
- function firstDefined(nodes, pick) {
445
- for (const n of nodes) {
466
+ function firstDefined(nodes2, pick) {
467
+ for (const n of nodes2) {
446
468
  const v = pick(n);
447
469
  if (v !== void 0) return v;
448
470
  }
@@ -1005,8 +1027,8 @@ function checkPathLikeGetPathInfo(path) {
1005
1027
  function recursionUnsupported(path) {
1006
1028
  raise(1101, [path]);
1007
1029
  }
1008
- function parseStatePart(statePart) {
1009
- const [stateAndPath, filters] = splitFilters(statePart, "output", cacheFilterInfos);
1030
+ function parseStatePart(statePart2) {
1031
+ const [stateAndPath, filters] = splitFilters(statePart2, "output", cacheFilterInfos);
1010
1032
  if (stateAndPath.includes("@")) {
1011
1033
  raise(32, [stateAndPath]);
1012
1034
  }
@@ -1015,7 +1037,7 @@ function parseStatePart(statePart) {
1015
1037
  const body = isLoopRelative ? statePathName.slice(DELIMITER.length) : statePathName;
1016
1038
  const hasEmptySegment = body.length > 0 && body.split(DELIMITER).some((segment) => segment.length === 0);
1017
1039
  if (hasEmptySegment || !isLoopRelative && body.length === 0) {
1018
- raise(119, [statePart]);
1040
+ raise(119, [statePart2]);
1019
1041
  }
1020
1042
  checkPathLikeGetPathInfo(statePathName);
1021
1043
  return {
@@ -1577,7 +1599,7 @@ function parseBindTextsForElement(bindText) {
1577
1599
  raise(101, [bindText2]);
1578
1600
  }
1579
1601
  const propPart = bindText2.slice(0, separatorIndex).trim();
1580
- const statePart = bindText2.slice(separatorIndex + 1).trim();
1602
+ const statePart2 = bindText2.slice(separatorIndex + 1).trim();
1581
1603
  const keyword = propPart.split(MODIFIER_SEPARATOR)[0].split(FILTER_SEPARATOR)[0].trim();
1582
1604
  if (KEYWORDS_WITHOUT_MODIFIERS.has(keyword)) {
1583
1605
  if (keyword !== propPart) {
@@ -1585,20 +1607,20 @@ function parseBindTextsForElement(bindText) {
1585
1607
  }
1586
1608
  let stateResult2;
1587
1609
  if (keyword === ELSE_KEYWORD) {
1588
- if (statePart.length > 0) {
1610
+ if (statePart2.length > 0) {
1589
1611
  raise(103, [bindText2]);
1590
1612
  }
1591
1613
  stateResult2 = { statePathName: "#else", outFilters: [] };
1592
1614
  } else if (keyword === SPREAD_PROP) {
1593
- if (statePart.length === 0) {
1615
+ if (statePart2.length === 0) {
1594
1616
  raise(104, [bindText2]);
1595
1617
  }
1596
- stateResult2 = parseStatePart(statePart);
1618
+ stateResult2 = parseStatePart(statePart2);
1597
1619
  if (stateResult2.outFilters.length > 0) {
1598
1620
  raise(105, [bindText2]);
1599
1621
  }
1600
1622
  } else {
1601
- stateResult2 = parseStatePart(statePart);
1623
+ stateResult2 = parseStatePart(statePart2);
1602
1624
  if (keyword === "for" && stateResult2.outFilters.length > 0) {
1603
1625
  raise(121, [bindText2]);
1604
1626
  }
@@ -1615,7 +1637,7 @@ function parseBindTextsForElement(bindText) {
1615
1637
  if (keyword === CLASS_NAMESPACE || keyword === ATTR_NAMESPACE) {
1616
1638
  raise(122, [bindText2, keyword]);
1617
1639
  }
1618
- const stateResult = parseStatePart(statePart);
1640
+ const stateResult = parseStatePart(statePart2);
1619
1641
  const propResult = parsePropPart(propPart);
1620
1642
  const [head] = propResult.propSegments;
1621
1643
  if (head === "" && propResult.propSegments.length > 1) {
@@ -1861,6 +1883,9 @@ function parseWcsStateElements(html, stateTagName = "wcs-state") {
1861
1883
  const jsonAttr = extractAttribute(wcsMatch.tagContent, "json") ?? void 0;
1862
1884
  const stateAttr = extractAttribute(wcsMatch.tagContent, "state") ?? void 0;
1863
1885
  const srcAttr = extractAttribute(wcsMatch.tagContent, "src") ?? void 0;
1886
+ const contentAt = pos + 1 + stateTagName.length;
1887
+ const srcSpan = extractAttributeSpan(wcsMatch.tagContent, "src", contentAt);
1888
+ const jsonSpan = extractAttributeSpan(wcsMatch.tagContent, "json", contentAt);
1864
1889
  const tagStart = pos;
1865
1890
  const tagEnd = wcsMatch.end;
1866
1891
  pos = wcsMatch.end;
@@ -1904,7 +1929,18 @@ function parseWcsStateElements(html, stateTagName = "wcs-state") {
1904
1929
  wcsEnd = wcsCloseIdx === -1 ? len : wcsCloseIdx;
1905
1930
  }
1906
1931
  }
1907
- elements.push({ mountPath, bindComponent, jsonAttr, stateAttr, srcAttr, scriptBlocks, tagStart, tagEnd });
1932
+ elements.push({
1933
+ mountPath,
1934
+ bindComponent,
1935
+ jsonAttr,
1936
+ stateAttr,
1937
+ srcAttr,
1938
+ scriptBlocks,
1939
+ tagStart,
1940
+ tagEnd,
1941
+ ...srcSpan !== null ? { srcSpan } : {},
1942
+ ...jsonSpan !== null ? { jsonSpan } : {}
1943
+ });
1908
1944
  pos = wcsEnd;
1909
1945
  if (wcsCloseIdx !== -1) pos = afterCloseTag(html, wcsCloseIdx);
1910
1946
  }
@@ -2039,13 +2075,13 @@ function findCloseTag(html, startPos, tagName, lower2 = asciiLowerCase(html)) {
2039
2075
  return -1;
2040
2076
  }
2041
2077
  function parseAttributeNames(tagContent) {
2042
- const names = /* @__PURE__ */ new Set();
2078
+ const names2 = /* @__PURE__ */ new Set();
2043
2079
  const attribute = /([^\s"'<>/=]+)(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s"'<>`=]+))?/g;
2044
2080
  let match;
2045
2081
  while ((match = attribute.exec(tagContent)) !== null) {
2046
- names.add(match[1].toLowerCase());
2082
+ names2.add(match[1].toLowerCase());
2047
2083
  }
2048
- return names;
2084
+ return names2;
2049
2085
  }
2050
2086
  function extractAttribute(tagContent, attrName) {
2051
2087
  const regex = new RegExp(
@@ -2056,6 +2092,71 @@ function extractAttribute(tagContent, attrName) {
2056
2092
  if (!match) return null;
2057
2093
  return match[1] ?? match[2] ?? match[3] ?? null;
2058
2094
  }
2095
+ function extractAttributeSpan(tagContent, attrName, at2) {
2096
+ const regex = new RegExp(`(^|\\s)${attrName}\\s*=\\s*(?:"([^"]*)"|'([^']*)'|(\\S+))`, "i");
2097
+ const match = regex.exec(tagContent);
2098
+ if (match === null) return null;
2099
+ const start = at2 + match.index + match[1].length;
2100
+ const end = at2 + match.index + match[0].length;
2101
+ const value = match[2] ?? match[3] ?? match[4] ?? "";
2102
+ const valueEnd = match[4] === void 0 ? end - 1 : end;
2103
+ return { start, end, valueStart: valueEnd - value.length, valueEnd };
2104
+ }
2105
+ var IGNORE_VOID_ELEMENTS = /* @__PURE__ */ new Set([
2106
+ "area",
2107
+ "base",
2108
+ "br",
2109
+ "col",
2110
+ "embed",
2111
+ "hr",
2112
+ "img",
2113
+ "input",
2114
+ "link",
2115
+ "meta",
2116
+ "param",
2117
+ "source",
2118
+ "track",
2119
+ "wbr"
2120
+ ]);
2121
+ function findIgnoredRanges(html, bindAttribute) {
2122
+ const marker = asciiLowerCase(`${bindAttribute}-ignore`);
2123
+ const lower2 = asciiLowerCase(html);
2124
+ if (!lower2.includes(marker)) return [];
2125
+ const out = [];
2126
+ const stack = [];
2127
+ const tag = /<!--[\s\S]*?(?:-->|$)|<(\/?)([a-zA-Z][^\s/>]*)((?:[^>"']|"[^"]*"|'[^']*')*)>/g;
2128
+ let match;
2129
+ while ((match = tag.exec(html)) !== null) {
2130
+ if (match[2] === void 0) continue;
2131
+ const name = asciiLowerCase(match[2]);
2132
+ const end = match.index + match[0].length;
2133
+ if (match[1] === "/") {
2134
+ for (let i = stack.length - 1; i >= 0; i--) {
2135
+ if (stack[i].name !== name) continue;
2136
+ for (const open of stack.slice(i)) if (open.start !== null) out.push([open.start, end]);
2137
+ stack.length = i;
2138
+ break;
2139
+ }
2140
+ continue;
2141
+ }
2142
+ const ignored = parseAttributeNames(match[3]).has(marker) ? match.index : null;
2143
+ if (IGNORE_VOID_ELEMENTS.has(name)) {
2144
+ if (ignored !== null) out.push([ignored, end]);
2145
+ continue;
2146
+ }
2147
+ if (RAW_TEXT_ELEMENTS.has(name)) {
2148
+ const close = name === "plaintext" ? -1 : lower2.indexOf(`</${name}`, end);
2149
+ const closeEnd = close === -1 ? html.length : html.indexOf(">", close) + 1 || html.length;
2150
+ if (ignored !== null) out.push([ignored, closeEnd]);
2151
+ if (close === -1) break;
2152
+ tag.lastIndex = closeEnd;
2153
+ continue;
2154
+ }
2155
+ stack.push({ name, start: ignored });
2156
+ }
2157
+ for (const open of stack) if (open.start !== null) out.push([open.start, html.length]);
2158
+ return out;
2159
+ }
2059
2160
 
2060
2161
  // src/core/parser/quoteAware.ts
2061
2162
  var isQuote = (c) => c === "'" || c === '"';
@@ -2563,10 +2664,11 @@ var builtinFilterMeta = {
2563
2664
  // `not` は真偽性(truthy / falsy)の反転。`if:` が `Boolean()` で寄せるのと同じ規則で、
2564
2665
  // `else:` はこのフィルタを足した束縛として組み立てられる(structural/createNotFilter.ts)
2565
2666
  not: { description: "\u771F\u507D\u6027\u3092\u53CD\u8EE2\uFF08falsy \u2192 true\uFF09", hasArgs: false, resultType: "boolean", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
2566
- lt: { description: "\u3088\u308A\u5C0F\u3055\u3044\u304B", hasArgs: true, resultType: "boolean", acceptTypes: ["number", "string"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
2567
- le: { description: "\u4EE5\u4E0B\u304B", hasArgs: true, resultType: "boolean", acceptTypes: ["number", "string"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
2568
- gt: { description: "\u3088\u308A\u5927\u304D\u3044\u304B", hasArgs: true, resultType: "boolean", acceptTypes: ["number", "string"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
2569
- ge: { description: "\u4EE5\u4E0A\u304B", hasArgs: true, resultType: "boolean", acceptTypes: ["number", "string"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
2667
+ // 比較は数値だけを受ける(filters/core.ts の `numeric` は数値以外の値で #28。3.x も同じで、"string" は誤りだった)
2668
+ lt: { description: "\u3088\u308A\u5C0F\u3055\u3044\u304B", hasArgs: true, resultType: "boolean", acceptTypes: ["number"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
2669
+ le: { description: "\u4EE5\u4E0B\u304B", hasArgs: true, resultType: "boolean", acceptTypes: ["number"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
2670
+ gt: { description: "\u3088\u308A\u5927\u304D\u3044\u304B", hasArgs: true, resultType: "boolean", acceptTypes: ["number"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
2671
+ ge: { description: "\u4EE5\u4E0A\u304B", hasArgs: true, resultType: "boolean", acceptTypes: ["number"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
2570
2672
  // 算術
2571
2673
  add: { description: "\u52A0\u7B97", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
2572
2674
  sub: { description: "\u6E1B\u7B97", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
@@ -3354,17 +3456,25 @@ function hasDefaultExportObject(scriptContent) {
3354
3456
  return locateDefaultExportObject(scriptContent) !== null;
3355
3457
  }
3356
3458
  function hasTopLevelSpread(scriptContent) {
3459
+ return findTopLevelSpread(scriptContent) !== null;
3460
+ }
3461
+ function findTopLevelSpread(scriptContent) {
3357
3462
  const root = locateDefaultExportObject(scriptContent);
3358
- if (!root) return false;
3463
+ if (!root) return null;
3359
3464
  const scan = maskCommentsAndStrings(root.content);
3360
3465
  let depth = 0;
3466
+ let start = -1;
3361
3467
  for (let i = 0; i < scan.length; i++) {
3362
3468
  const ch = scan[i];
3363
3469
  if (ch === "(" || ch === "[" || ch === "{") depth++;
3364
3470
  else if (ch === ")" || ch === "]" || ch === "}") depth--;
3365
- else if (depth === 0 && ch === "." && scan.startsWith("...", i)) return true;
3471
+ else if (depth === 0 && start < 0 && ch === "." && scan.startsWith("...", i)) start = i;
3472
+ else if (depth === 0 && start >= 0 && ch === ",") return spreadRange(root.start, scan, start, i);
3366
3473
  }
3367
- return false;
3474
+ return start < 0 ? null : spreadRange(root.start, scan, start, scan.length);
3475
+ }
3476
+ function spreadRange(base, scan, start, stop) {
3477
+ return { start: base + start, end: base + start + scan.slice(start, stop).trimEnd().length };
3368
3478
  }
3369
3479
  function analyzeObjectEntries(scriptContent, key, allowEmptyKeys = false) {
3370
3480
  const root = locateDefaultExportObject(scriptContent);
@@ -4318,9 +4428,9 @@ function derefSchemaNodes(node, defs) {
4318
4428
  }
4319
4429
  return out;
4320
4430
  }
4321
- function schemaTypeHint(nodes) {
4431
+ function schemaTypeHint(nodes2) {
4322
4432
  const hints = /* @__PURE__ */ new Set();
4323
- for (const n of nodes) {
4433
+ for (const n of nodes2) {
4324
4434
  const types2 = typeof n.type === "string" ? [n.type] : Array.isArray(n.type) ? n.type : [];
4325
4435
  if (types2.length > 0) {
4326
4436
  for (const t of types2) {
@@ -4359,10 +4469,10 @@ function collectSchemaObjectPaths(node, prefix, paths, defs, depth) {
4359
4469
  }
4360
4470
  }
4361
4471
  function pushSchemaValuePaths(path, node, paths, defs, depth) {
4362
- const nodes = derefSchemaNodes(node, defs);
4363
- const typeHint = schemaTypeHint(nodes);
4472
+ const nodes2 = derefSchemaNodes(node, defs);
4473
+ const typeHint = schemaTypeHint(nodes2);
4364
4474
  paths.push(withHint({ path, kind: "data", fromSchema: true }, typeHint));
4365
- const items = nodes.map((n) => n.items).find((i) => i !== void 0 && i !== null && typeof i === "object");
4475
+ const items = nodes2.map((n) => n.items).find((i) => i !== void 0 && i !== null && typeof i === "object");
4366
4476
  const isArray2 = items !== void 0 || (typeHint?.split("|").includes("array") ?? false);
4367
4477
  if (isArray2) {
4368
4478
  const itemNodes = items !== void 0 ? derefSchemaNodes(items, defs) : [];
@@ -4379,7 +4489,7 @@ function pushSchemaValuePaths(path, node, paths, defs, depth) {
4379
4489
  }
4380
4490
  return;
4381
4491
  }
4382
- if (nodes.some((n) => n.properties !== void 0)) {
4492
+ if (nodes2.some((n) => n.properties !== void 0)) {
4383
4493
  collectSchemaObjectPaths(node, path, paths, defs, depth + 1);
4384
4494
  }
4385
4495
  }
@@ -4478,9 +4588,12 @@ function fromJson(text3) {
4478
4588
  const paths = analyzeJsonPaths(text3);
4479
4589
  return { paths, readable: paths.length > 0 || isJsonObject(text3) };
4480
4590
  }
4591
+ function scriptReadable(script, paths) {
4592
+ return !hasTopLevelSpread(script) && (paths.length > 0 || hasDefaultExportObject(script));
4593
+ }
4481
4594
  function fromScript(script) {
4482
4595
  const paths = analyzeStatePaths(script);
4483
- return { paths, readable: paths.length > 0 || isReadableStateScript(script) };
4596
+ return { paths, readable: scriptReadable(script, paths) };
4484
4597
  }
4485
4598
  function resolveElementPathsRaw(element2, html, fileReader) {
4486
4599
  let readable = false;
@@ -4503,19 +4616,23 @@ function resolveElementPathsRaw(element2, html, fileReader) {
4503
4616
  readable ||= resolved.readable;
4504
4617
  }
4505
4618
  if (element2.scriptBlocks.length > 0) {
4506
- const paths = element2.scriptBlocks.flatMap((block) => analyzeStatePaths(block.content));
4619
+ const blocks = element2.scriptBlocks.map((block) => ({ script: block.content, paths: analyzeStatePaths(block.content) }));
4507
4620
  return {
4508
- paths,
4509
- readable: paths.length > 0 || readable || element2.scriptBlocks.some((block) => isReadableStateScript(block.content))
4621
+ paths: blocks.flatMap((block) => block.paths),
4622
+ readable: readable || blocks.some((block) => scriptReadable(block.script, block.paths))
4510
4623
  };
4511
4624
  }
4512
4625
  return readable ? { paths: [], readable } : UNREADABLE;
4513
4626
  }
4514
4627
  function readStateScript(srcPath, fileReader) {
4515
- if (srcPath.endsWith(".js")) {
4516
- return fileReader(srcPath.replace(/\.js$/, ".ts")) || fileReader(srcPath) || void 0;
4628
+ return readStateScriptFile(srcPath, fileReader)?.text;
4629
+ }
4630
+ function readStateScriptFile(srcPath, fileReader) {
4631
+ const paths = srcPath.endsWith(".js") ? [srcPath.replace(/\.js$/, ".ts"), srcPath] : srcPath.endsWith(".ts") ? [srcPath] : [];
4632
+ for (const path of paths) {
4633
+ const text3 = fileReader(path);
4634
+ if (text3) return { path, text: text3 };
4517
4635
  }
4518
- if (srcPath.endsWith(".ts")) return fileReader(srcPath) || void 0;
4519
4636
  return void 0;
4520
4637
  }
4521
4638
  function resolveSrcAttribute(srcPath, fileReader) {
@@ -4548,10 +4665,6 @@ function isInsideForTemplate(html, offset2, bindAttrName = "data-wcs") {
4548
4665
  }
4549
4666
  return false;
4550
4667
  }
4551
- function getInnermostForPath(html, offset2, bindAttrName = "data-wcs") {
4552
- const chain = getEnclosingForPaths(html, offset2, bindAttrName);
4553
- return chain.length === 0 ? null : chain[chain.length - 1];
4554
- }
4555
4668
  var BINDING_SYNTAX_MARKER = `[${WcsDiagnosticCode.BindingSyntax}]`;
4556
4669
  function isForBindingRefused(bindText) {
4557
4670
  try {
@@ -4797,10 +4910,10 @@ function analyzeElementContexts(html, offsets, bindAttrName = "data-wcs", stateT
4797
4910
  }
4798
4911
  const match3 = bindAttr.exec(attrs);
4799
4912
  const value = match3 === null ? null : match3[1] ?? match3[2] ?? match3[3];
4800
- const names = value === null ? [] : propertyNamesOf(value);
4801
- const structural = name === "template" && names.length === 1 && STRUCTURAL_DIRECTIVES2.has(names[0]) && !value.slice(0, Math.max(0, indexOfOutsideQuotes2(value, ":"))).includes("#");
4913
+ const names2 = value === null ? [] : propertyNamesOf(value);
4914
+ const structural = name === "template" && names2.length === 1 && STRUCTURAL_DIRECTIVES2.has(names2[0]) && !value.slice(0, Math.max(0, indexOfOutsideQuotes2(value, ":"))).includes("#");
4802
4915
  const plainTemplate = name === "template" && !structural;
4803
- const blocks = plainTemplate && stack.some((e) => e.name === "template") || name !== "template" && names.some((n) => CONTENT_PROPERTIES.has(n));
4916
+ const blocks = plainTemplate && stack.some((e) => e.name === "template") || name !== "template" && names2.some((n) => CONTENT_PROPERTIES.has(n));
4804
4917
  const scope = plainTemplate ? { hasOwnState: false, id: extractAttribute(attrs, "id"), underRouter: stack.some((e) => e.name === ROUTER_TAG) } : null;
4805
4918
  stack.push({ name, structural, scope, blocks });
4806
4919
  }
@@ -6257,7 +6370,7 @@ pp$8.parseClassElement = function(constructorAllowsSuper) {
6257
6370
  }
6258
6371
  var ecmaVersion = this.options.ecmaVersion;
6259
6372
  var node = this.startNode();
6260
- var keyName = "";
6373
+ var keyName2 = "";
6261
6374
  var isGenerator = false;
6262
6375
  var isAsync = false;
6263
6376
  var kind = "method";
@@ -6270,34 +6383,34 @@ pp$8.parseClassElement = function(constructorAllowsSuper) {
6270
6383
  if (this.isClassElementNameStart() || this.type === types$1.star) {
6271
6384
  isStatic = true;
6272
6385
  } else {
6273
- keyName = "static";
6386
+ keyName2 = "static";
6274
6387
  }
6275
6388
  }
6276
6389
  node.static = isStatic;
6277
- if (!keyName && ecmaVersion >= 8 && this.eatContextual("async")) {
6390
+ if (!keyName2 && ecmaVersion >= 8 && this.eatContextual("async")) {
6278
6391
  if ((this.isClassElementNameStart() || this.type === types$1.star) && !this.canInsertSemicolon()) {
6279
6392
  isAsync = true;
6280
6393
  } else {
6281
- keyName = "async";
6394
+ keyName2 = "async";
6282
6395
  }
6283
6396
  }
6284
- if (!keyName && (ecmaVersion >= 9 || !isAsync) && this.eat(types$1.star)) {
6397
+ if (!keyName2 && (ecmaVersion >= 9 || !isAsync) && this.eat(types$1.star)) {
6285
6398
  isGenerator = true;
6286
6399
  }
6287
- if (!keyName && !isAsync && !isGenerator) {
6400
+ if (!keyName2 && !isAsync && !isGenerator) {
6288
6401
  var lastValue = this.value;
6289
6402
  if (this.eatContextual("get") || this.eatContextual("set")) {
6290
6403
  if (this.isClassElementNameStart()) {
6291
6404
  kind = lastValue;
6292
6405
  } else {
6293
- keyName = lastValue;
6406
+ keyName2 = lastValue;
6294
6407
  }
6295
6408
  }
6296
6409
  }
6297
- if (keyName) {
6410
+ if (keyName2) {
6298
6411
  node.computed = false;
6299
6412
  node.key = this.startNodeAt(this.lastTokStart, this.lastTokStartLoc);
6300
- node.key.name = keyName;
6413
+ node.key.name = keyName2;
6301
6414
  this.finishNode(node.key, "Identifier");
6302
6415
  } else {
6303
6416
  this.parseClassElementName(node);
@@ -6598,7 +6711,7 @@ pp$8.parseExportSpecifier = function(exports$1) {
6598
6711
  return this.finishNode(node, "ExportSpecifier");
6599
6712
  };
6600
6713
  pp$8.parseExportSpecifiers = function(exports$1) {
6601
- var nodes = [], first = true;
6714
+ var nodes2 = [], first = true;
6602
6715
  this.expect(types$1.braceL);
6603
6716
  while (!this.eat(types$1.braceR)) {
6604
6717
  if (!first) {
@@ -6609,9 +6722,9 @@ pp$8.parseExportSpecifiers = function(exports$1) {
6609
6722
  } else {
6610
6723
  first = false;
6611
6724
  }
6612
- nodes.push(this.parseExportSpecifier(exports$1));
6725
+ nodes2.push(this.parseExportSpecifier(exports$1));
6613
6726
  }
6614
- return nodes;
6727
+ return nodes2;
6615
6728
  };
6616
6729
  pp$8.parseImport = function(node) {
6617
6730
  this.next();
@@ -6656,16 +6769,16 @@ pp$8.parseImportNamespaceSpecifier = function() {
6656
6769
  return this.finishNode(node, "ImportNamespaceSpecifier");
6657
6770
  };
6658
6771
  pp$8.parseImportSpecifiers = function() {
6659
- var nodes = [], first = true;
6772
+ var nodes2 = [], first = true;
6660
6773
  if (this.type === types$1.name) {
6661
- nodes.push(this.parseImportDefaultSpecifier());
6774
+ nodes2.push(this.parseImportDefaultSpecifier());
6662
6775
  if (!this.eat(types$1.comma)) {
6663
- return nodes;
6776
+ return nodes2;
6664
6777
  }
6665
6778
  }
6666
6779
  if (this.type === types$1.star) {
6667
- nodes.push(this.parseImportNamespaceSpecifier());
6668
- return nodes;
6780
+ nodes2.push(this.parseImportNamespaceSpecifier());
6781
+ return nodes2;
6669
6782
  }
6670
6783
  this.expect(types$1.braceL);
6671
6784
  while (!this.eat(types$1.braceR)) {
@@ -6677,14 +6790,14 @@ pp$8.parseImportSpecifiers = function() {
6677
6790
  } else {
6678
6791
  first = false;
6679
6792
  }
6680
- nodes.push(this.parseImportSpecifier());
6793
+ nodes2.push(this.parseImportSpecifier());
6681
6794
  }
6682
- return nodes;
6795
+ return nodes2;
6683
6796
  };
6684
6797
  pp$8.parseWithClause = function() {
6685
- var nodes = [];
6798
+ var nodes2 = [];
6686
6799
  if (!this.eat(types$1._with)) {
6687
- return nodes;
6800
+ return nodes2;
6688
6801
  }
6689
6802
  this.expect(types$1.braceL);
6690
6803
  var attributeKeys = {};
@@ -6699,14 +6812,14 @@ pp$8.parseWithClause = function() {
6699
6812
  first = false;
6700
6813
  }
6701
6814
  var attr = this.parseImportAttribute();
6702
- var keyName = attr.key.type === "Identifier" ? attr.key.name : attr.key.value;
6703
- if (hasOwn(attributeKeys, keyName)) {
6704
- this.raiseRecoverable(attr.key.start, "Duplicate attribute key '" + keyName + "'");
6815
+ var keyName2 = attr.key.type === "Identifier" ? attr.key.name : attr.key.value;
6816
+ if (hasOwn(attributeKeys, keyName2)) {
6817
+ this.raiseRecoverable(attr.key.start, "Duplicate attribute key '" + keyName2 + "'");
6705
6818
  }
6706
- attributeKeys[keyName] = true;
6707
- nodes.push(attr);
6819
+ attributeKeys[keyName2] = true;
6820
+ nodes2.push(attr);
6708
6821
  }
6709
- return nodes;
6822
+ return nodes2;
6710
6823
  };
6711
6824
  pp$8.parseImportAttribute = function() {
6712
6825
  var node = this.startNode();
@@ -10855,7 +10968,7 @@ function visitDestructure(pattern, prefix, scope, out) {
10855
10968
  emit(out, segments, { form: "destructure", callee: false, written: false }, property.start, property.end);
10856
10969
  }
10857
10970
  }
10858
- function collectThisMemberRefs(body, names) {
10971
+ function collectThisMemberRefs(body, names2) {
10859
10972
  let program;
10860
10973
  try {
10861
10974
  program = parse3(PREFIX + body + SUFFIX, { ecmaVersion: "latest", sourceType: "module" });
@@ -10864,11 +10977,11 @@ function collectThisMemberRefs(body, names) {
10864
10977
  }
10865
10978
  const fn = unwrapWrapper(program);
10866
10979
  if (fn === null) return null;
10867
- return walkThisMembers(fn.body, names, PREFIX.length);
10980
+ return walkThisMembers(fn.body, names2, PREFIX.length);
10868
10981
  }
10869
10982
  var VALUE_PREFIX = "(async function* () {\n(";
10870
10983
  var VALUE_SUFFIX = ")\n})";
10871
- function collectThisMemberRefsInValue(value, names) {
10984
+ function collectThisMemberRefsInValue(value, names2) {
10872
10985
  let program;
10873
10986
  try {
10874
10987
  program = parse3(VALUE_PREFIX + value + VALUE_SUFFIX, { ecmaVersion: "latest", sourceType: "module" });
@@ -10881,9 +10994,9 @@ function collectThisMemberRefsInValue(value, names) {
10881
10994
  if (statement.type !== "ExpressionStatement") return null;
10882
10995
  const expression = statement.expression;
10883
10996
  if (expression.type !== "FunctionExpression") return [];
10884
- return walkThisMembers(expression.body, names, VALUE_PREFIX.length);
10997
+ return walkThisMembers(expression.body, names2, VALUE_PREFIX.length);
10885
10998
  }
10886
- function walkThisMembers(root, names, offsetShift) {
10999
+ function walkThisMembers(root, names2, offsetShift) {
10887
11000
  const out = [];
10888
11001
  const walk = (node, thisIsState) => {
10889
11002
  if (isClassNode(node)) return;
@@ -10894,7 +11007,7 @@ function walkThisMembers(root, names, offsetShift) {
10894
11007
  }
10895
11008
  if (thisIsState && node.type === "MemberExpression" && node.object.type === "ThisExpression") {
10896
11009
  const hit = thisMemberName(node);
10897
- if (hit !== null && names.has(hit.name)) {
11010
+ if (hit !== null && names2.has(hit.name)) {
10898
11011
  out.push({ name: hit.name, start: hit.start - offsetShift, end: hit.end - offsetShift });
10899
11012
  }
10900
11013
  }
@@ -11061,13 +11174,13 @@ function findInPlaceChanges(text3, kind, root) {
11061
11174
  const collect2 = (node) => {
11062
11175
  if (isFunctionNode(node)) {
11063
11176
  if (node.type === "FunctionDeclaration" && node.id !== null) bind(node.id.name);
11064
- const names = /* @__PURE__ */ new Set();
11065
- for (const param of node.params) bindingNames(param, names);
11066
- names.forEach(bind);
11177
+ const names2 = /* @__PURE__ */ new Set();
11178
+ for (const param of node.params) bindingNames(param, names2);
11179
+ names2.forEach(bind);
11067
11180
  } else if (node.type === "VariableDeclarator") {
11068
- const names = /* @__PURE__ */ new Set();
11069
- bindingNames(node.id, names);
11070
- names.forEach(bind);
11181
+ const names2 = /* @__PURE__ */ new Set();
11182
+ bindingNames(node.id, names2);
11183
+ names2.forEach(bind);
11071
11184
  const init = node.init ? unwrapChain(node.init) : null;
11072
11185
  if (init !== null && node.id.type === "Identifier" && init.type === "MemberExpression") {
11073
11186
  const chain = memberChain(init, source);
@@ -11085,9 +11198,9 @@ function findInPlaceChanges(text3, kind, root) {
11085
11198
  }
11086
11199
  }
11087
11200
  } else if (node.type === "CatchClause" && node.param) {
11088
- const names = /* @__PURE__ */ new Set();
11089
- bindingNames(node.param, names);
11090
- names.forEach(bind);
11201
+ const names2 = /* @__PURE__ */ new Set();
11202
+ bindingNames(node.param, names2);
11203
+ names2.forEach(bind);
11091
11204
  } else if (node.type === "ClassDeclaration" && node.id !== null) {
11092
11205
  bind(node.id.name);
11093
11206
  } else if (node.type === "AssignmentExpression" && node.left.type === "Identifier") {
@@ -11149,14 +11262,14 @@ function findLocationRead(body) {
11149
11262
  }
11150
11263
  const wrapper = unwrapWrapper(program);
11151
11264
  if (wrapper === null) return null;
11152
- const names = /* @__PURE__ */ new Set();
11265
+ const names2 = /* @__PURE__ */ new Set();
11153
11266
  const scan = (node) => {
11154
- if (isFunctionNode(node)) for (const param of node.params) bindingNames(param, names);
11155
- if (node.type === "VariableDeclarator") bindingNames(node.id, names);
11267
+ if (isFunctionNode(node)) for (const param of node.params) bindingNames(param, names2);
11268
+ if (node.type === "VariableDeclarator") bindingNames(node.id, names2);
11156
11269
  forEachChild(node, scan);
11157
11270
  };
11158
11271
  scan(wrapper.body);
11159
- if (names.has("location")) return null;
11272
+ if (names2.has("location")) return null;
11160
11273
  const isLocation = (node) => {
11161
11274
  const n = unwrapChain(node);
11162
11275
  if (n.type === "Identifier") return n.name === "location";
@@ -11233,6 +11346,13 @@ var ja = {
11233
11346
  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`,
11234
11347
  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`,
11235
11348
  getterReadsLocation: (read) => `\u3053\u306E getter \u306F ${read} \u3092\u8AAD\u3093\u3067\u3044\u307E\u3059\u304C\u3001location \u306F state \u3067\u306F\u306A\u3044\u306E\u3067\u3001\u6700\u521D\u306B\u8AAD\u3093\u3060 URL \u3092\u6301\u3061\u7D9A\u3051\u307E\u3059\uFF08\u30CA\u30D3\u30B2\u30FC\u30B7\u30E7\u30F3\u3067\u518D\u8A55\u4FA1\u3055\u308C\u307E\u305B\u3093\uFF09\u3002URL \u306F state \u3092\u901A\u3057\u3066\u8AAD\u3093\u3067\u304F\u3060\u3055\u3044 \u2014 <wcs-router> \u306E path / searchParams \u3092\u675F\u306D\u308B`,
11349
+ getterReadsClock: (read) => `\u3053\u306E getter \u306F ${read} \u3092\u8AAD\u3093\u3067\u3044\u307E\u3059\u304C\u3001\u6642\u523B\u306F state \u3067\u306F\u306A\u3044\u306E\u3067\u4F9D\u5B58\u3068\u3057\u3066\u767B\u9332\u3055\u308C\u305A\u3001getter \u306F\u30AD\u30E3\u30C3\u30B7\u30E5\u3057\u305F\u6700\u521D\u306E\u5024\u3092\u8FD4\u3057\u7D9A\u3051\u307E\u3059\uFF08\u30A4\u30D9\u30F3\u30C8\u30C8\u30FC\u30AF\u30F3\u3067\u6BCE\u30D5\u30EC\u30FC\u30E0\u300C\u63CF\u304D\u76F4\u3057\u300D\u3066\u3082\u5909\u308F\u308A\u307E\u305B\u3093\uFF09\u3002\u6642\u523B\u3092 state \u306B\u7F6E\u3044\u3066\u304F\u3060\u3055\u3044 \u2014 <wcs-raf> \u3084 <wcs-timer> \u304C\u66F8\u304F\u5024\u3092\u675F\u306D\u308B`,
11350
+ updatedCallbackUnknownPath: (p) => `"${p}" \u306F state \u306E\u30D1\u30B9\u3067\u306F\u306A\u3044\u306E\u3067 $renderedCallback \u306E paths \u306B\u73FE\u308C\u305A\u3001\u3053\u306E\u5206\u5C90\u306F\u4E00\u5EA6\u3082\u5B9F\u884C\u3055\u308C\u307E\u305B\u3093`,
11351
+ commandTokenUnbound: (t) => `\u30B3\u30DE\u30F3\u30C9\u30C8\u30FC\u30AF\u30F3 "${t}" \u3092 emit \u3057\u3066\u3044\u307E\u3059\u304C\u3001\u3053\u306E\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8\u306B\u305D\u308C\u3092\u53D7\u3051\u308B command.<\u30E1\u30BD\u30C3\u30C9>: ${t} \u306E\u675F\u7E1B\u304C\u3042\u308A\u307E\u305B\u3093\u3002emit \u306F\u8AB0\u306B\u3082\u5C4A\u304D\u307E\u305B\u3093\u3002\u30E1\u30BD\u30C3\u30C9\u3092\u547C\u3076\u8981\u7D20\u306B\u675F\u306D\u3066\u304F\u3060\u3055\u3044\uFF08command.focus: ${t}\uFF09`,
11352
+ writePathMissing: (k) => `"${k}" \u306F state \u304C\u5BA3\u8A00\u3057\u3066\u3044\u306A\u3044\u30AD\u30FC\u3067\u3059\u3002\u66F8\u304D\u8FBC\u307F\u306F\u65B0\u3057\u3044\u30AD\u30FC\u3092\u4F5C\u308B\u3060\u3051\u3067\u3001\u5BA3\u8A00\u3057\u305F\u30AD\u30FC\u306E\u675F\u7E1B\u306B\u306F\u5C4A\u304D\u307E\u305B\u3093`,
11353
+ readPathMissing: (p, top) => top ? `"${p}" \u306F state \u304C\u5BA3\u8A00\u3057\u3066\u3044\u306A\u3044\u30AD\u30FC\u3067\u3059\u3002\u8AAD\u3093\u3060\u6642\u70B9\u3067\u4F8B\u5916\u306B\u306A\u308A\u307E\u3059\uFF08#301\uFF09` : `\u30D1\u30B9 "${p}" \u306F\u72B6\u614B\u5B9A\u7FA9\u306B\u5B58\u5728\u3057\u307E\u305B\u3093\u3002\u8AAD\u307F\u306F undefined \u306B\u306A\u308A\u3001\u305D\u3053\u304B\u3089\u8A08\u7B97\u3057\u305F\u5024\u306F\u9ED9\u3063\u3066\u9055\u3044\u307E\u3059`,
11354
+ pathDynamicUnknownSpread: (sp) => `${sp} \u304C\u6301\u3061\u8FBC\u3080\u30AD\u30FC\u306F\u9759\u7684\u306B\u8AAD\u3081\u306A\u3044\u306E\u3067\u3001\u3053\u306E state \u306E\u30D1\u30B9\u306F\u691C\u67FB\u3057\u3066\u3044\u307E\u305B\u3093\uFF08\u675F\u7E1B\u30FBgetter \u306E\u4E2D\u306E\u8AAD\u307F\u30FB$watch \u306E\u30AD\u30FC\uFF09\u3002\u30AD\u30FC\u3092 wcstack.manifest.json \u306E stateSchema \u306B\u5BA3\u8A00\u3059\u308B\u3068\u691C\u67FB\u3055\u308C\u307E\u3059\u3002npx wcs-schema\uFF08@wcstack/typescript\uFF09\u304C state \u306E\u578B\uFF08JSDoc\u30FBTypeScript\uFF09\u304B\u3089\u4F5C\u308C\u307E\u3059`,
11355
+ pathReadonlyTwoWay: (p, prop) => `"${p}" \u306F setter \u306E\u7121\u3044 getter \u3067\u3059\u304C\u3001${prop}: \u306F\u8AAD\u8005\u306E\u5165\u529B\u3092\u66F8\u304D\u623B\u3059\u306E\u3067\u3001\u5165\u529B\u306E\u305F\u3073\u306B\u66F8\u304D\u8FBC\u307F\u304C\u5931\u6557\u3057\u307E\u3059\uFF08"${p}" is a getter without a setter\uFF09\u3002setter \u3092\u8DB3\u3059\uFF08set "${p}"(v) { \u2026 }\uFF09\u304B\u3001#ro \u3067\u4E00\u65B9\u5411\u306B\u3057\u3066\u304F\u3060\u3055\u3044\uFF08${prop}#ro: ${p}\uFF09`,
11236
11356
  submitWithoutPrevent: (h) => `onsubmit \u306B #prevent \u304C\u7121\u304F\u3001"${h}" \u3082 preventDefault \u3092\u547C\u3073\u307E\u305B\u3093\u3002\u30D6\u30E9\u30A6\u30B6\u306F\u30D5\u30A9\u30FC\u30E0\u3082\u9001\u308B\u306E\u3067\u3001\u30DA\u30FC\u30B8\u304C\u8AAD\u307F\u76F4\u3055\u308C\u308B\u304B\u3001router \u304C\u3042\u308C\u3070 GET \u304C\u6B04\u306E\u5024\uFF08\u30D1\u30B9\u30EF\u30FC\u30C9\u3082\uFF09\u3092 URL \u3068\u5C65\u6B74\u306B\u8F09\u305B\u307E\u3059\u3002onsubmit#prevent: ${h} \u3068\u66F8\u304F\u304B\u3001\u30CF\u30F3\u30C9\u30E9\u3067 event.preventDefault() \u3092\u547C\u3093\u3067\u304F\u3060\u3055\u3044`,
11237
11357
  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`,
11238
11358
  handlerFilterNotAllowed: (prop) => `\u30A4\u30D9\u30F3\u30C8\u30CF\u30F3\u30C9\u30E9 "${prop}" \u306B\u30D5\u30A3\u30EB\u30BF\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093`,
@@ -11253,15 +11373,15 @@ var ja = {
11253
11373
  watchKeyEmptySegment: (k) => `$watch \u306E\u30AD\u30FC "${k}" \u306B\u7A7A\u306E\u30D1\u30B9\u30BB\u30B0\u30E1\u30F3\u30C8\u304C\u3042\u308A\u307E\u3059`,
11254
11374
  watchHandlerNotFunction: (k) => `$watch \u306E\u30A8\u30F3\u30C8\u30EA "${k}" \u306E\u5024\u306F\u95A2\u6570\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059`,
11255
11375
  watchPathMissing: (k) => `$watch \u306E\u30AD\u30FC "${k}" \u306F\u72B6\u614B\u5B9A\u7FA9\u306B\u5B58\u5728\u3057\u307E\u305B\u3093\uFF08\u4E00\u5EA6\u3082\u767A\u706B\u3057\u307E\u305B\u3093\uFF09`,
11256
- scanRemoved: (mountPath) => mountPath === null ? `$scan \u306F 4.0 \u3067\u5916\u308C\u307E\u3057\u305F\uFF08\u30E9\u30F3\u30BF\u30A4\u30E0\u306F\u8AAD\u307F\u8FBC\u307F\u6642\u306B throw \u3057\u307E\u3059\uFF09\u3002\u30D1\u30B9\u306E\u5909\u5316\u3092\u7573\u3080\u306A\u3089 $watch\u3001\u30A4\u30D9\u30F3\u30C8\u3092\u7573\u3080\u306A\u3089 $on \u306E\u30CF\u30F3\u30C9\u30E9\u3067\u3001\u51FA\u529B\u306E\u30D7\u30ED\u30D1\u30C6\u30A3\u3078\u66F8\u3044\u3066\u304F\u3060\u3055\u3044` : `$scan \u306F 4.0 \u3067\u5916\u308C\u307E\u3057\u305F\u3002\u30DC\u30EA\u30E5\u30FC\u30E0\uFF08mount="${mountPath}"\uFF09\u3067\u306F\u3001\u30E9\u30F3\u30BF\u30A4\u30E0\u306F\u63A5\u304E\u6728\u3092\u62D2\u3093\u3067 console.error \u3067\u5831\u544A\u3057\u307E\u3059\uFF08\u3053\u306E state \u306F\u6728\u306B\u8F09\u308A\u307E\u305B\u3093\uFF09\u3002root \u306E state \u306E $watch \u304B $on \u306E\u30CF\u30F3\u30C9\u30E9\u3067\u7573\u3093\u3067\u304F\u3060\u3055\u3044`,
11376
+ scanRemoved: (mountPath) => mountPath === null ? `$scan \u306F 4.0 \u3067\u5916\u308C\u307E\u3057\u305F\uFF08diagnostics \u306E\u5F8C\u4ED8\u3051\u3092\u5165\u308C\u305F\u5165\u53E3 \u2014 /auto \u306A\u3069 \u2014 \u306F\u8AAD\u307F\u8FBC\u307F\u6642\u306B throw \u3057\u3001/core \u3060\u3051\u3067\u306F\u9ED9\u3063\u3066\u7121\u8996\u3057\u307E\u3059\uFF09\u3002\u30D1\u30B9\u306E\u5909\u5316\u3092\u7573\u3080\u306A\u3089 $watch\u3001\u30A4\u30D9\u30F3\u30C8\u3092\u7573\u3080\u306A\u3089 $on \u306E\u30CF\u30F3\u30C9\u30E9\u3067\u3001\u51FA\u529B\u306E\u30D7\u30ED\u30D1\u30C6\u30A3\u3078\u66F8\u3044\u3066\u304F\u3060\u3055\u3044` : `$scan \u306F 4.0 \u3067\u5916\u308C\u307E\u3057\u305F\u3002\u30DC\u30EA\u30E5\u30FC\u30E0\uFF08mount="${mountPath}"\uFF09\u3067\u306F\u3001\u30E9\u30F3\u30BF\u30A4\u30E0\u306F\u63A5\u304E\u6728\u3092\u62D2\u3093\u3067 console.error \u3067\u5831\u544A\u3057\u307E\u3059\uFF08\u3053\u306E state \u306F\u6728\u306B\u8F09\u308A\u307E\u305B\u3093\uFF09\u3002root \u306E state \u306E $watch \u304B $on \u306E\u30CF\u30F3\u30C9\u30E9\u3067\u7573\u3093\u3067\u304F\u3060\u3055\u3044`,
11257
11377
  typeAnnotationIncompatible: (vt, rt) => `\u578B "${vt}" \u306F @type {${rt}} \u3068\u4E92\u63DB\u6027\u304C\u3042\u308A\u307E\u305B\u3093`,
11258
11378
  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`,
11259
11379
  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`,
11260
11380
  inPlaceAlias: (a, src, t) => `"${a}" \u306F ${src}\uFF08state \u306E\u5024\u305D\u306E\u3082\u306E\uFF09\u3067\u3059\u3002\u305D\u308C\u3092\u901A\u3057\u305F\u5909\u66F4\u306F\u30EA\u30A2\u30AF\u30C6\u30A3\u30D6\u66F4\u65B0\u3092\u30C8\u30EA\u30AC\u30FC\u305B\u305A\u3001\u540C\u3058\u5024\u3092\u66F8\u304D\u623B\u3057\u3066\u3082\u4E00\u89A7\u306E\u884C\u306F\u8FFD\u52A0\u30FB\u524A\u9664\u30FB\u7F6E\u304D\u63DB\u3048\u3055\u308C\u307E\u305B\u3093\u3002\u65B0\u3057\u3044\u5024\u3092\u4F5C\u3063\u3066 ${t} \u306B\u4EE3\u5165\u3057\u3066\u304F\u3060\u3055\u3044\uFF08${a}.with(i, item) / [...${a}, item] / { ...${a}, key: value }\uFF09`,
11261
11381
  inPlaceChange: (src, t) => `${src} \u306F state \u306E\u5024\u3092\u305D\u306E\u5834\u3067\u5909\u3048\u308B\u306E\u3067\u3001\u30EA\u30A2\u30AF\u30C6\u30A3\u30D6\u66F4\u65B0\u3092\u30C8\u30EA\u30AC\u30FC\u3057\u307E\u305B\u3093\u3002\u65B0\u3057\u3044\u5024\u3092\u4F5C\u3063\u3066 ${t} \u306B\u4EE3\u5165\u3057\u3066\u304F\u3060\u3055\u3044`,
11262
- 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`,
11382
+ tagMemberUnknown: (prop, tag) => `"${prop}" \u306F <${tag}> \u306E wcBindable \u30E1\u30F3\u30D0\u30FC\u3067\u306F\u3042\u308A\u307E\u305B\u3093\uFF08\u30E9\u30F3\u30BF\u30A4\u30E0\u306F\u5BA3\u8A00\u306B\u7121\u3044\u30E1\u30F3\u30D0\u30FC\u3078\u306E\u675F\u7E1B\u3092 #38 \u3067\u62D2\u307F\u3001root \u3067\u306F state \u304C\u521D\u671F\u5316\u306B\u5931\u6557\u3057\u307E\u3059\uFF09`,
11263
11383
  nameAlias: (written, canonical) => `"${written}" \u306F 4.0 \u3067\u5916\u308C\u307E\u3057\u305F\uFF08"${canonical}" \u306E 3.x \u306E\u65E7\u540D\u3067\u3001\u30E9\u30F3\u30BF\u30A4\u30E0\u306F\u8AAD\u3093\u3060\u6642\u70B9\u3067 throw \u3057\u307E\u3059\uFF09\u3002"${canonical}" \u3068\u66F8\u3044\u3066\u304F\u3060\u3055\u3044`,
11264
- declarationAliasRead: (alias, canonical) => `"${alias}" \u306F 4.0 \u3067\u5916\u308C\u305F\u5BA3\u8A00\u30AD\u30FC\uFF08"${canonical}" \u306E 3.x \u306E\u65E7\u540D\uFF09\u306A\u306E\u3067\u3001this["${alias}"] \u306F undefined \u306B\u306A\u308A\u307E\u3059\u3002"${canonical}" \u3092\u8AAD\u3093\u3067\u304F\u3060\u3055\u3044`,
11384
+ declarationAliasRead: (alias, canonical) => `"${alias}" \u306F 4.0 \u3067\u5916\u308C\u305F\u5BA3\u8A00\u30AD\u30FC\uFF08"${canonical}" \u306E 3.x \u306E\u65E7\u540D\uFF09\u306A\u306E\u3067\u3001this["${alias}"] \u306F undefined \u306B\u306A\u308A\u307E\u3059\u3002\u5BA3\u8A00\u306F this \u3092\u901A\u3057\u3066\u8AAD\u3081\u307E\u305B\u3093 \u2014 "${canonical}" \u3092\u8AAD\u3093\u3067\u3082 undefined \u3067\u3059${canonical === "$stream" ? "\uFF08\u30B9\u30C8\u30EA\u30FC\u30E0\u306E\u72B6\u614B\u306F $streamStatus\u30FB$streamError \u3067\u8AAD\u307F\u307E\u3059\uFF09" : ""}`,
11265
11385
  declarationAlias: (alias, canonical) => `\u5BA3\u8A00\u30AD\u30FC "${alias}" \u306F 4.0 \u3067\u5916\u308C\u307E\u3057\u305F\uFF08"${canonical}" \u306E 3.x \u306E\u65E7\u540D\u3067\u3001\u30E9\u30F3\u30BF\u30A4\u30E0\u306F\u8AAD\u307F\u8FBC\u307F\u6642\u306B throw \u3057\u307E\u3059\uFF09\u3002"${canonical}" \u3068\u66F8\u3044\u3066\u304F\u3060\u3055\u3044`,
11266
11386
  declarationAliasInVolume: (alias, canonical, mountPath) => `\u5BA3\u8A00\u30AD\u30FC "${alias}" \u306F 4.0 \u3067\u5916\u308C\u307E\u3057\u305F\uFF08"${canonical}" \u306E 3.x \u306E\u65E7\u540D\uFF09\u3002\u30DC\u30EA\u30E5\u30FC\u30E0\uFF08mount="${mountPath}"\uFF09\u3067\u306F\u3001\u30E9\u30F3\u30BF\u30A4\u30E0\u306F\u63A5\u304E\u6728\u3092\u62D2\u3093\u3067 console.error \u3067\u5831\u544A\u3057\u307E\u3059\uFF08\u3053\u306E state \u306F\u6728\u306B\u8F09\u308A\u307E\u305B\u3093\uFF09\u3002"${canonical}" \u3082\u30DC\u30EA\u30E5\u30FC\u30E0\u3067\u306F\u5BA3\u8A00\u3067\u304D\u306A\u3044\u306E\u3067\u3001root \u306E state \u306B\u5BA3\u8A00\u3057\u3066\u304F\u3060\u3055\u3044`,
11267
11387
  behaviorNotObject: (keys) => `$behavior \u306F { ${keys.map((k) => `${k}?`).join(", ")} } \u306E\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\uFF08\u30E9\u30F3\u30BF\u30A4\u30E0\u306F\u8AAD\u307F\u8FBC\u307F\u6642\u306B throw \u3057\u307E\u3059\uFF09`,
@@ -11269,7 +11389,7 @@ var ja = {
11269
11389
  behaviorValueType: (key, type) => `$behavior \u306E "${key}" \u306F ${type === "boolean" ? "true \u304B false" : type} \u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\uFF08\u30E9\u30F3\u30BF\u30A4\u30E0\u306F\u8AAD\u307F\u8FBC\u307F\u6642\u306B throw \u3057\u307E\u3059\uFF09`,
11270
11390
  configInVolume: (key, mountPath) => `${key} \u306F\u30DC\u30EA\u30E5\u30FC\u30E0\uFF08mount="${mountPath}"\uFF09\u3067\u306F\u5BA3\u8A00\u3067\u304D\u307E\u305B\u3093\uFF08\u30E9\u30F3\u30BF\u30A4\u30E0\u306F\u63A5\u304E\u6728\u3092\u62D2\u307F\u3001console.error \u3067\u5831\u544A\u3057\u307E\u3059 \u2014 \u3053\u306E state \u306F\u6728\u306B\u8F09\u308A\u307E\u305B\u3093\uFF09\u3002root \u306E state \u306B\u5BA3\u8A00\u3057\u3066\u304F\u3060\u3055\u3044 \u2014 \u30DC\u30EA\u30E5\u30FC\u30E0\u306F root \u306E\u30A8\u30F3\u30B8\u30F3\u306B\u63A5\u304E\u6728\u3055\u308C\u307E\u3059`,
11271
11391
  featuresNotArray: () => `$features \u306F\u5F8C\u4ED8\u3051\u306E\u540D\u524D\u306E\u914D\u5217\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\uFF08\u4F8B: ["temporal", "formats"]\u3002\u30E9\u30F3\u30BF\u30A4\u30E0\u306F\u8AAD\u307F\u8FBC\u307F\u6642\u306B throw \u3057\u307E\u3059\uFF09`,
11272
- featureUnknown: (name, names, suggestion2) => `"${name}" \u306F\u5F8C\u4ED8\u3051\u306E\u540D\u524D\u3067\u306F\u3042\u308A\u307E\u305B\u3093\uFF08${names.join("\u30FB")}\uFF09${suggestion2}`,
11392
+ featureUnknown: (name, names2, suggestion2) => `"${name}" \u306F\u5F8C\u4ED8\u3051\u306E\u540D\u524D\u3067\u306F\u3042\u308A\u307E\u305B\u3093\uFF08${names2.join("\u30FB")}\uFF09${suggestion2}`,
11273
11393
  volumeDeclarationRejected: (key, mountPath) => `${key} \u306F\u30DC\u30EA\u30E5\u30FC\u30E0\uFF08mount="${mountPath}"\uFF09\u3067\u306F\u5B9F\u884C\u3055\u308C\u307E\u305B\u3093\u3002\u30E9\u30F3\u30BF\u30A4\u30E0\u306F\u63A5\u304E\u6728\u3092\u62D2\u3093\u3067 console.error \u3067\u5831\u544A\u3057\u307E\u3059\uFF08\u3053\u306E state \u306F\u6728\u306B\u8F09\u308A\u307E\u305B\u3093\uFF09\u3002root \u306E state \u306B\u5BA3\u8A00\u3057\u3066\u304F\u3060\u3055\u3044`,
11274
11394
  volumeDeclarationNotRun: (key, mountPath) => `${key} \u306F\u30DC\u30EA\u30E5\u30FC\u30E0\uFF08mount="${mountPath}"\uFF09\u3067\u306F\u5B9F\u884C\u3055\u308C\u307E\u305B\u3093\uFF08\u30E9\u30F3\u30BF\u30A4\u30E0\u306F console.warn \u3067\u77E5\u3089\u305B\u3001\u3053\u306E\u5BA3\u8A00\u3092\u7121\u8996\u3057\u307E\u3059 \u2014 root \u306E state \u306E\u3082\u306E\u3067\u3059\uFF09\u3002root \u306E state \u306B\u5BA3\u8A00\u3057\u3066\u304F\u3060\u3055\u3044`,
11275
11395
  secondRoot: () => '\u540C\u3058 root \u306B 2 \u3064\u76EE\u306E <wcs-state> \u304C\u3042\u308A\u307E\u3059\u3002state \u306E\u6728\u306F root \u3054\u3068\u306B 1 \u3064\u3067\u3059\uFF08\u30E9\u30F3\u30BF\u30A4\u30E0\u306F\u5F8C\u304B\u3089\u8AAD\u307F\u8FBC\u3093\u3060\u65B9\u3092\u62D2\u3093\u3067 console.error \u3067\u5831\u544A\u3057\u307E\u3059\uFF09\u3002\u90E8\u5206\u6728\u306F <wcs-state mount="path"> \u3067\u63A5\u304E\u6728\u3057\u3066\u304F\u3060\u3055\u3044',
@@ -11291,7 +11411,7 @@ var ja = {
11291
11411
  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`,
11292
11412
  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`,
11293
11413
  inputNestedWriteOneShot: (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\u305A\u3001<${tag}> \u306F\u8981\u6C42\u306E\u305F\u3073\u306B "${input}" \u3092 null \u306B\u623B\u3059\u306E\u3067\u3001\u6B21\u306E\u8981\u6C42\u306F "${input}" \u306A\u3057\u3067\u9001\u3089\u308C\u307E\u3059 \u2014 \u8981\u6C42\u3092\u59CB\u3081\u308B\u30CF\u30F3\u30C9\u30E9\u3067\u65B0\u3057\u3044\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u3092\u4F5C\u3063\u3066\u4EE3\u5165\u3057\uFF08\`this.submitBody = { \u2026 }\`\uFF09\u3001\u305D\u308C\u3092\u675F\u306D\u3066\u304F\u3060\u3055\u3044`,
11294
- devtoolsAfterState: () => `@wcstack/devtools/auto \u306F @wcstack/state/auto \u3088\u308A\u5148\u306B\u8AAD\u307F\u8FBC\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u5F8C\u3060\u3068\u914D\u7DDA\u53F0\u5E33\u304C\u30E9\u30A4\u30D6\u3067 captured \u3055\u308C\u307E\u305B\u3093\uFF09`,
11414
+ devtoolsAfterState: () => `@wcstack/devtools/auto \u306F @wcstack/state/auto \u3088\u308A\u5148\u306B\u8AAD\u307F\u8FBC\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u5F8C\u304B\u3089\u3060\u3068\u3001DevTools \u306E\u30BF\u30A4\u30E0\u30E9\u30A4\u30F3\u306F\u4ED8\u3044\u305F\u6642\u70B9\u304B\u3089\u59CB\u307E\u308A\u307E\u3059\u3002\u65E2\u306B\u3042\u308B\u914D\u7DDA\u306F 4.0 \u304C\u9001\u308A\u76F4\u3057\u307E\u3059\uFF09`,
11295
11415
  baseHrefMissing: () => `@wcstack/router \u3092\u4F7F\u3046 SPA \u306B\u306F <head> \u5185\u306E <base href="/"> \u304C\u5FC5\u8981\u3067\u3059\uFF08\u7121\u3044\u3068\u30C7\u30A3\u30FC\u30D7\u30EA\u30F3\u30AF\u3067 basename \u304C\u8AA4\u5C0E\u51FA\u3055\u308C\u307E\u3059\uFF09`,
11296
11416
  routerOutletMisplaced: () => `\u3053\u306E <wcs-outlet> \u306F <wcs-router> \u306E\u76F4\u5F8C\u306B\u7121\u3044\u306E\u3067\u3001\u3069\u306E router \u3082\u4F7F\u3044\u307E\u305B\u3093\u3002router \u306F\u81EA\u5206\u306E\u76F4\u5F8C\u306E\u8981\u7D20\u3060\u3051\u3092 outlet \u3068\u3057\u3066\u4F7F\u3044\u3001\u305D\u3053\u306B <wcs-outlet> \u304C\u7121\u3051\u308C\u3070\u81EA\u524D\u306E outlet \u3092\u4F5C\u308A\u307E\u3059\u3002\u30EB\u30FC\u30C8\u306F router \u306E\u76F4\u5F8C\u306B\u63CF\u304B\u308C\u3001\u3053\u306E outlet \u306F\u7A7A\u306E\u307E\u307E\u3067\u3059 \u2014 <wcs-router> \u306E\u76F4\u5F8C\u3078\u79FB\u3057\u3066\u304F\u3060\u3055\u3044`,
11297
11417
  signalsDualEntry: () => `@wcstack/signals \u3068 @wcstack/signals/dom \u304C\u540C\u4E00\u30DA\u30FC\u30B8\u304B\u3089 import \u3055\u308C\u3066\u3044\u307E\u3059\u3002CDN \u3067\u306F\u5404\u30A8\u30F3\u30C8\u30EA\u304C\u81EA\u5DF1\u5B8C\u7D50\u30D0\u30F3\u30C9\u30EB\u306E\u305F\u3081\u30EA\u30A2\u30AF\u30C6\u30A3\u30D6\u30B3\u30A2\u304C\u4E8C\u91CD\u5316\u3057\u3001\u5883\u754C\u3067\u53CD\u5FDC\u304C\u58CA\u308C\u307E\u3059 \u2014 \u3059\u3079\u3066 /dom \u30A8\u30F3\u30C8\u30EA\u304B\u3089 import \u3057\u3066\u304F\u3060\u3055\u3044`,
@@ -11303,13 +11423,15 @@ var ja = {
11303
11423
  mountPathInvalid: (problem, mountPath) => {
11304
11424
  switch (problem) {
11305
11425
  case "empty":
11306
- return `"mount" \u306B\u306F\u7A7A\u3067\u306A\u3044\u30C4\u30EA\u30FC\u30D1\u30B9\u304C\u5FC5\u8981\u3067\u3059\uFF08runtime: "mount" requires a non-empty tree path.\uFF09`;
11426
+ return `"mount" \u306B\u306F\u7A7A\u3067\u306A\u3044\u9759\u7684\u306A\u30D1\u30B9\u304C\u5FC5\u8981\u3067\u3059\uFF08\u30E9\u30F3\u30BF\u30A4\u30E0\u306F\u30DC\u30EA\u30E5\u30FC\u30E0\u3092\u62D2\u307F\u307E\u3059: has an invalid mount path\uFF09`;
11307
11427
  case "emptySegment":
11308
- return `"mount" \u30D1\u30B9 "${mountPath}" \u306B\u7A7A\u306E\u30BB\u30B0\u30E1\u30F3\u30C8\u304C\u3042\u308A\u307E\u3059\uFF08runtime: has an empty segment.\uFF09`;
11428
+ return `"mount" \u30D1\u30B9 "${mountPath}" \u306B\u7A7A\u306E\u6BB5\u304C\u3042\u308A\u307E\u3059\uFF08\u30E9\u30F3\u30BF\u30A4\u30E0\u306F\u30DC\u30EA\u30E5\u30FC\u30E0\u3092\u62D2\u307F\u307E\u3059: has an invalid mount path\uFF09`;
11309
11429
  case "wildcard":
11310
- return `"mount" \u30D1\u30B9 "${mountPath}" \u306F\u9759\u7684\u3067\u306A\u3051\u308C\u3070\u306A\u308A\u307E\u305B\u3093 \u2014 \u30EF\u30A4\u30EB\u30C9\u30AB\u30FC\u30C9\u306F\u4F7F\u3048\u307E\u305B\u3093\uFF08runtime: must be static.\uFF09`;
11430
+ return `"mount" \u30D1\u30B9 "${mountPath}" \u306F\u9759\u7684\u3067\u306A\u3051\u308C\u3070\u306A\u308A\u307E\u305B\u3093 \u2014 "*" \u306F\u4F7F\u3048\u307E\u305B\u3093\uFF08\u30E9\u30F3\u30BF\u30A4\u30E0\u306F\u30DC\u30EA\u30E5\u30FC\u30E0\u3092\u62D2\u307F\u307E\u3059: has an invalid mount path\uFF09`;
11431
+ case "whitespace":
11432
+ return `"mount" \u30D1\u30B9 "${mountPath}" \u306B\u7A7A\u767D\u306F\u4F7F\u3048\u307E\u305B\u3093\uFF08\u30E9\u30F3\u30BF\u30A4\u30E0\u306F\u30DC\u30EA\u30E5\u30FC\u30E0\u3092\u62D2\u307F\u307E\u3059: has an invalid mount path\uFF09`;
11311
11433
  default:
11312
- return `"mount" \u30D1\u30B9 "${mountPath}" \u306B\u4E88\u7D04\u6587\u5B57\uFF08$, #, @\uFF09\u306F\u4F7F\u3048\u307E\u305B\u3093\uFF08runtime: must not use reserved characters.\uFF09`;
11434
+ return `"mount" \u30D1\u30B9 "${mountPath}" \u306B\u4E88\u7D04\u6587\u5B57\uFF08$, #, @\uFF09\u306F\u4F7F\u3048\u307E\u305B\u3093\uFF08\u30E9\u30F3\u30BF\u30A4\u30E0\u306F\u30DC\u30EA\u30E5\u30FC\u30E0\u3092\u62D2\u307F\u307E\u3059: has an invalid mount path\uFF09`;
11313
11435
  }
11314
11436
  },
11315
11437
  recursionUnsupported: (p, where) => {
@@ -11331,7 +11453,7 @@ var ja = {
11331
11453
  case "listKeys":
11332
11454
  return `$listKeys \u306E\u30AD\u30FC "${p}" \u306B "**" \u306F\u4F7F\u3048\u307E\u305B\u3093\u3002\u30AD\u30FC\u4ED8\u304D\u30EA\u30B9\u30C8\u306F 1 \u672C\u306E\u5177\u4F53\u30EA\u30B9\u30C8\u30D1\u30B9\u3067\u3059 \u2014 \u6DF1\u3055\u3054\u3068\u306B\u5BA3\u8A00\u3057\u3066\u304F\u3060\u3055\u3044\uFF08\u4F8B: "nodes.*.children"\uFF09`;
11333
11455
  default:
11334
- return `"${p}" \u306F "**" \u3092\u542B\u307F\u307E\u3059\u304C\u3001\u3053\u306E state \u306B\u306F $recursion \u5BA3\u8A00\u304C\u3042\u308A\u307E\u305B\u3093\u3002$recursion = { "<anchor>": "<repeat>" }\uFF08\u4F8B: { "nodes.*": "children.*" }\uFF09\u3092\u5BA3\u8A00\u3057\u3066\u304F\u3060\u3055\u3044\uFF08\u5BA3\u8A00\u304C\u7121\u3044\u3068 "**" \u306E\u30AD\u30FC\u306F\u9ED9\u3063\u3066\u7121\u8996\u3055\u308C\u307E\u3059\uFF09`;
11456
+ return `"${p}" \u306F "**" \u3092\u542B\u307F\u307E\u3059\u304C\u3001\u3053\u306E state \u306B\u306F $recursion \u5BA3\u8A00\u304C\u3042\u308A\u307E\u305B\u3093\u3002$recursion = { "<anchor>": "<repeat>" }\uFF08\u4F8B: { "nodes.*": "children.*" }\uFF09\u3092\u5BA3\u8A00\u3057\u3066\u304F\u3060\u3055\u3044\uFF08\u5BA3\u8A00\u304C\u7121\u3044\u3068\u3001\u30E9\u30F3\u30BF\u30A4\u30E0\u306F\u8AAD\u307F\u8FBC\u307F\u6642\u306B #1101 \u3067 throw \u3057\u3001state \u306F\u521D\u671F\u5316\u306B\u5931\u6557\u3057\u307E\u3059\uFF09`;
11335
11457
  }
11336
11458
  },
11337
11459
  recursionAnchorMismatch: (p, anchor) => `"${p}" \u306F\u5BA3\u8A00\u6E08\u307F\u306E\u518D\u5E30\u30A2\u30F3\u30AB\u30FC "${anchor}" \u3068\u5408\u81F4\u3057\u307E\u305B\u3093\uFF08\u521D\u7248\u306F state \u3054\u3068\u306B 1 \u3064\u306E\u81EA\u5DF1\u518D\u5E30\u306E\u307F\u3002"**" \u306E\u5F8C\u308D\u306F\u6574\u5F62\u3055\u308C\u305F\u63A5\u5C3E\u8F9E \u2014 2 \u3064\u76EE\u306E "**"\u30FB\u7A7A\u30BB\u30B0\u30E1\u30F3\u30C8\u30FB"**" \u76F4\u5F8C\u306E\u7D20\u306E "*" \u306F\u7F6E\u3051\u307E\u305B\u3093\uFF09`,
@@ -11432,6 +11554,13 @@ var en = {
11432
11554
  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`,
11433
11555
  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`,
11434
11556
  getterReadsLocation: (read) => `This getter reads ${read}, which is not state: it keeps the URL it first read (a navigation does not re-evaluate it). Read the URL through state \u2014 bind <wcs-router>'s path / searchParams`,
11557
+ getterReadsClock: (read) => `This getter reads ${read}. The time is not state, so it is not a dependency: the getter is cached and keeps returning its first value (an event token "redrawing" every frame does not change it). Keep the time in state \u2014 bind the value <wcs-raf> or <wcs-timer> writes`,
11558
+ updatedCallbackUnknownPath: (p) => `"${p}" is not a path of this state, so it is never in $renderedCallback's paths and this branch never runs`,
11559
+ commandTokenUnbound: (t) => `The command token "${t}" is emitted, but no command.<method>: ${t} binding in this document receives it, so the emit reaches nothing. Bind it on the element whose method it should call (command.focus: ${t})`,
11560
+ writePathMissing: (k) => `"${k}" is not a key the state declares. The write creates a new key and reaches no binding of a declared one`,
11561
+ readPathMissing: (p, top) => top ? `"${p}" is not a key the state declares. Reading it throws (#301)` : `Path "${p}" does not exist in the state definition. The read gives undefined, and what is computed from it is wrong without a word`,
11562
+ pathDynamicUnknownSpread: (sp) => `The keys ${sp} brings in cannot be read statically, so this state's paths are not checked (bindings, reads in getters, $watch keys). Declare the keys in the stateSchema of wcstack.manifest.json to have them checked; npx wcs-schema (@wcstack/typescript) derives it from the state's types (JSDoc or TypeScript)`,
11563
+ pathReadonlyTwoWay: (p, prop) => `"${p}" is a getter without a setter, and ${prop}: writes back what the reader enters, so every edit fails ("${p}" is a getter without a setter). Add a setter (set "${p}"(v) { \u2026 }), or bind it one way with #ro (${prop}#ro: ${p})`,
11435
11564
  submitWithoutPrevent: (h) => `onsubmit has no #prevent and "${h}" does not call preventDefault, so the browser submits the form too: the page reloads, or with the router a GET puts the fields (a password too) in the URL and the history. Write onsubmit#prevent: ${h}, or call event.preventDefault() in the handler`,
11436
11565
  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`,
11437
11566
  handlerFilterNotAllowed: (prop) => `Filters cannot be applied to event handler "${prop}"`,
@@ -11452,15 +11581,15 @@ var en = {
11452
11581
  watchKeyEmptySegment: (k) => `$watch key "${k}" has an empty path segment`,
11453
11582
  watchHandlerNotFunction: (k) => `The value of $watch entry "${k}" must be a function`,
11454
11583
  watchPathMissing: (k) => `$watch key "${k}" does not exist in the state definition (it will never fire)`,
11455
- scanRemoved: (mountPath) => mountPath === null ? `$scan was removed in 4.0 (the runtime throws at load time). Fold a path's changes in a $watch handler, or events in an $on handler, and write the output property there` : `$scan was removed in 4.0. In a volume (mount="${mountPath}") the runtime refuses to graft it and reports that with console.error (this state is not on the tree). Fold in a $watch or $on handler on the root state`,
11584
+ scanRemoved: (mountPath) => mountPath === null ? `$scan was removed in 4.0 (the entries with the diagnostics add-on, such as /auto, throw at load; /core alone ignores it). Fold a path's changes in a $watch handler, or events in an $on handler, and write the output property there` : `$scan was removed in 4.0. In a volume (mount="${mountPath}") the runtime refuses to graft it and reports that with console.error (this state is not on the tree). Fold in a $watch or $on handler on the root state`,
11456
11585
  typeAnnotationIncompatible: (vt, rt) => `Type "${vt}" is not compatible with @type {${rt}}`,
11457
11586
  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}).`,
11458
11587
  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.`,
11459
11588
  inPlaceAlias: (a, src, t) => `"${a}" is ${src} \u2014 the state's own value. A change through it does not trigger a reactive update, and writing the same value back does not add, remove or replace a list's rows. Build a new value and assign it to ${t} (${a}.with(i, item), [...${a}, item], { ...${a}, key: value })`,
11460
11589
  inPlaceChange: (src, t) => `${src} changes the state's value in place, which does not trigger a reactive update. Build a new value and assign it to ${t}`,
11461
- tagMemberUnknown: (prop, tag) => `"${prop}" is not a wcBindable member of <${tag}> (bindings to unknown members are silently ignored)`,
11590
+ tagMemberUnknown: (prop, tag) => `"${prop}" is not a wcBindable member of <${tag}> (the runtime refuses a binding to an undeclared member with #38; at the root the state fails to initialize)`,
11462
11591
  nameAlias: (written, canonical) => `"${written}" was removed in 4.0 (the 3.x old name of "${canonical}"; the runtime throws when it is read) \u2014 write "${canonical}"`,
11463
- declarationAliasRead: (alias, canonical) => `"${alias}" is a declaration key 4.0 removed (the 3.x old name of "${canonical}"), so this["${alias}"] is undefined. Read "${canonical}" instead`,
11592
+ declarationAliasRead: (alias, canonical) => `"${alias}" is a declaration key 4.0 removed (the 3.x old name of "${canonical}"), so this["${alias}"] is undefined. A declaration cannot be read through this \u2014 reading "${canonical}" is undefined too${canonical === "$stream" ? " (read a stream's state from $streamStatus / $streamError)" : ""}`,
11464
11593
  declarationAlias: (alias, canonical) => `The declaration key "${alias}" was removed in 4.0 (the 3.x old name of "${canonical}"; the runtime throws at load time) \u2014 write "${canonical}"`,
11465
11594
  declarationAliasInVolume: (alias, canonical, mountPath) => `The declaration key "${alias}" was removed in 4.0 (the 3.x old name of "${canonical}"). In a volume (mount="${mountPath}") the runtime refuses to graft it and reports that with console.error (this state is not on the tree). "${canonical}" cannot be declared in a volume either \u2014 declare it on the root state`,
11466
11595
  behaviorNotObject: (keys) => `$behavior must be an object { ${keys.map((k) => `${k}?`).join(", ")} } (the runtime throws at load time)`,
@@ -11468,7 +11597,7 @@ var en = {
11468
11597
  behaviorValueType: (key, type) => `$behavior "${key}" must be ${type === "boolean" ? "true or false" : type} (the runtime throws at load time)`,
11469
11598
  configInVolume: (key, mountPath) => `${key} cannot be declared in a volume (mount="${mountPath}"): the runtime refuses to graft the volume and reports that with console.error (this state is not on the tree). Declare it on the root state \u2014 a volume is grafted onto the root's engine`,
11470
11599
  featuresNotArray: () => `$features must be an array of add-on names (for example ["temporal", "formats"]; the runtime throws at load time)`,
11471
- featureUnknown: (name, names, suggestion2) => `"${name}" is not an add-on (${names.join(", ")})${suggestion2}`,
11600
+ featureUnknown: (name, names2, suggestion2) => `"${name}" is not an add-on (${names2.join(", ")})${suggestion2}`,
11472
11601
  volumeDeclarationRejected: (key, mountPath) => `${key} is not run in a volume (mount="${mountPath}"): the runtime refuses to graft the volume and reports that with console.error (this state is not on the tree). Declare it on the root state`,
11473
11602
  volumeDeclarationNotRun: (key, mountPath) => `${key} is not run in a volume (mount="${mountPath}"): the runtime says so with console.warn and ignores this declaration \u2014 it belongs to the root state. Declare it there`,
11474
11603
  secondRoot: () => 'A second <wcs-state> on the same root: there is one state tree per root (the runtime refuses the one that loads second and reports it with console.error). Graft a subtree with <wcs-state mount="path">',
@@ -11490,7 +11619,7 @@ var en = {
11490
11619
  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}\`)`,
11491
11620
  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`,
11492
11621
  inputNestedWriteOneShot: (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, and <${tag}> resets "${input}" to null after every request, so the next request goes without it \u2014 build a new object in the handler that starts the request (\`this.submitBody = { \u2026 }\`) and bind that`,
11493
- devtoolsAfterState: () => `Load @wcstack/devtools/auto BEFORE @wcstack/state/auto (otherwise the wiring ledger is not captured live)`,
11622
+ devtoolsAfterState: () => `Load @wcstack/devtools/auto before @wcstack/state/auto (loaded later, the DevTools timeline starts when it attaches; 4.0 sends it the wiring that is there already)`,
11494
11623
  baseHrefMissing: () => `An SPA using @wcstack/router needs <base href="/"> in <head> (without it, deep links misderive the basename)`,
11495
11624
  routerOutletMisplaced: () => `This <wcs-outlet> is not right after a <wcs-router>, so no router uses it: a router uses only the element right after it as its outlet, and makes an outlet of its own there when that is not a <wcs-outlet>. The routes render right after the router and this outlet stays empty \u2014 move it right after the <wcs-router>`,
11496
11625
  signalsDualEntry: () => `Both @wcstack/signals and @wcstack/signals/dom are imported on this page. On a CDN each entry is a self-contained bundle, so the reactive core is duplicated and reactivity breaks at the seam \u2014 import everything from the single /dom entry`,
@@ -11502,13 +11631,15 @@ var en = {
11502
11631
  mountPathInvalid: (problem, mountPath) => {
11503
11632
  switch (problem) {
11504
11633
  case "empty":
11505
- return `"mount" requires a non-empty tree path.`;
11634
+ return `"mount" needs a non-empty static path (the runtime refuses the volume: "has an invalid mount path").`;
11506
11635
  case "emptySegment":
11507
- return `"mount" path "${mountPath}" has an empty segment.`;
11636
+ return `"mount" path "${mountPath}" has an empty segment (the runtime refuses the volume: "has an invalid mount path").`;
11508
11637
  case "wildcard":
11509
- return `"mount" path "${mountPath}" must be static (wildcards are not allowed).`;
11638
+ return `"mount" path "${mountPath}" must be static \u2014 no "*" (the runtime refuses the volume: "has an invalid mount path").`;
11639
+ case "whitespace":
11640
+ return `"mount" path "${mountPath}" must not contain whitespace (the runtime refuses the volume: "has an invalid mount path").`;
11510
11641
  default:
11511
- return `"mount" path "${mountPath}" must not use reserved characters ($, #, @).`;
11642
+ return `"mount" path "${mountPath}" must not use the reserved characters $, #, @ (the runtime refuses the volume: "has an invalid mount path").`;
11512
11643
  }
11513
11644
  },
11514
11645
  recursionUnsupported: (p, where) => {
@@ -11530,7 +11661,7 @@ var en = {
11530
11661
  case "listKeys":
11531
11662
  return `$listKeys key "${p}" cannot contain "**" \u2014 a keyed list is one concrete list path. Declare the key per depth instead (for example "nodes.*.children")`;
11532
11663
  default:
11533
- return `"${p}" contains "**" but this state declares no $recursion anchor. Declare $recursion = { "<anchor>": "<repeat>" } (for example { "nodes.*": "children.*" }) \u2014 without it a "**" key is silently ignored`;
11664
+ return `"${p}" contains "**" but this state declares no $recursion anchor. Declare $recursion = { "<anchor>": "<repeat>" } (for example { "nodes.*": "children.*" }) \u2014 without it the runtime throws #1101 at load and the state fails to initialize`;
11534
11665
  }
11535
11666
  },
11536
11667
  recursionAnchorMismatch: (p, anchor) => `"${p}" does not match the declared recursion anchor "${anchor}" (this version supports exactly one self-recursive anchor per state, and "**" must be followed by a well-formed suffix: no second "**", no empty segment, no bare "*" right after "**")`,
@@ -11718,11 +11849,11 @@ var DELEGATED_EVENTS = /* @__PURE__ */ new Set([
11718
11849
  ]);
11719
11850
  var CUSTOM_ELEMENT_OWN_EVENTS = /* @__PURE__ */ new Set(["input", "change", "submit"]);
11720
11851
  function collectCurrentTargetHandlers(elements, html, fileReader) {
11721
- const names = /* @__PURE__ */ new Set();
11852
+ const names2 = /* @__PURE__ */ new Set();
11722
11853
  forEachStateMethod(elements, html, fileReader, "currentTarget", (name, params, body) => {
11723
- if (readsEventCurrentTarget(params, body)) names.add(name);
11854
+ if (readsEventCurrentTarget(params, body)) names2.add(name);
11724
11855
  });
11725
- return names;
11856
+ return names2;
11726
11857
  }
11727
11858
  function collectPreventDefaultHandlers(elements, html, fileReader) {
11728
11859
  const handlers = /* @__PURE__ */ new Map();
@@ -11761,11 +11892,6 @@ function validateBindings(html, attrName, stateTagName = "wcs-state", locale2, f
11761
11892
  const pathIndex = getStatePathIndex(html, stateTagName, fileReader);
11762
11893
  const statePaths = mergeSchemaCandidates(pathIndex.paths, applicationSchema);
11763
11894
  const attrs = findAllBindAttributes(html, attrName);
11764
- let structuralTemplates = null;
11765
- const getStructuralTemplates = () => {
11766
- structuralTemplates ??= collectStructuralTemplates(html, attrName);
11767
- return structuralTemplates;
11768
- };
11769
11895
  const outerCandidates = [];
11770
11896
  const currentTargetCandidates = [];
11771
11897
  let currentTargetHandlers = null;
@@ -11925,7 +12051,8 @@ function validateBindings(html, attrName, stateTagName = "wcs-state", locale2, f
11925
12051
  start: pathStart,
11926
12052
  end: pathStart + tokenPath.length,
11927
12053
  message: msgs.commandRhsFormat(),
11928
- severity: "warning"
12054
+ // ランタイムは束縛の計画で #1201 として throw し、root では初期化が失敗する
12055
+ severity: "error"
11929
12056
  });
11930
12057
  } else if (commandNames.size > 0 && !commandNames.has(tokenPath)) {
11931
12058
  diagnostics.push({
@@ -11933,7 +12060,9 @@ function validateBindings(html, attrName, stateTagName = "wcs-state", locale2, f
11933
12060
  start: pathStart,
11934
12061
  end: pathStart + tokenPath.length,
11935
12062
  message: msgs.commandTokenUndeclared(tokenPath),
11936
- severity: "warning"
12063
+ // ランタイムは取り付けで #1302 として throw し、root では初期化が失敗する
12064
+ // (eventToken. と `on*: $command.x` はイベントのたびに #1301 を記録するだけなので warning のまま)
12065
+ severity: "error"
11937
12066
  });
11938
12067
  }
11939
12068
  }
@@ -11971,6 +12100,18 @@ function validateBindings(html, attrName, stateTagName = "wcs-state", locale2, f
11971
12100
  message: `${verdict.message}${pathTrimmed.startsWith(".") ? msgs.expansionSuffix(checkPath) : ""}`,
11972
12101
  severity: verdict.severity
11973
12102
  });
12103
+ } else if (writesBack(attr, propNoMod, parsed.property)) {
12104
+ const target = scopedPaths.find((p) => p.path === checkPath);
12105
+ if (target !== void 0 && target.kind === "computed" && target.settable !== true) {
12106
+ const pathStart = bindingStart + binding.indexOf(parsed.path);
12107
+ diagnostics.push({
12108
+ code: WcsDiagnosticCode.PathReadonly,
12109
+ start: pathStart,
12110
+ end: pathStart + pathTrimmed.length,
12111
+ message: msgs.pathReadonlyTwoWay(checkPath, propNoMod),
12112
+ severity: "error"
12113
+ });
12114
+ }
11974
12115
  }
11975
12116
  }
11976
12117
  }
@@ -12103,10 +12244,7 @@ function validateBindings(html, attrName, stateTagName = "wcs-state", locale2, f
12103
12244
  const typePath = candidateKeyOf(pathTrimmed, (c) => scopedPathSet.has(c));
12104
12245
  const resultType = resolveResultType(typePath, parsed.filters, scopedPaths);
12105
12246
  if (resultType !== null) {
12106
- const typeReq = getExpectedType(
12107
- parsed.property,
12108
- () => isNegatedByElseChain(getStructuralTemplates(), attr.valueStart)
12109
- );
12247
+ const typeReq = getExpectedType(parsed.property);
12110
12248
  if (typeReq && resultType !== typeReq.expected) {
12111
12249
  const pathOffset = binding.indexOf(parsed.path);
12112
12250
  const pathStart = bindingStart + pathOffset;
@@ -12160,6 +12298,19 @@ function openTagBefore(html, valueStart) {
12160
12298
  const lt2 = html.lastIndexOf("<", valueStart);
12161
12299
  return lt2 === -1 ? "" : html.slice(lt2, valueStart);
12162
12300
  }
12301
+ function writesBack(attr, prop, written) {
12302
+ if (written.split("#").slice(1).some((modifier) => modifier.trim() === "ro")) return false;
12303
+ if (prop === "radio" || prop === "checkbox") return true;
12304
+ const tag = attr.tagName;
12305
+ if (tag === void 0 || tag.includes("-")) return false;
12306
+ if (tag === "input") {
12307
+ const type = (attr.inputType || "text").toLowerCase();
12308
+ if (type === "button") return false;
12309
+ if ((type === "radio" || type === "checkbox") && prop === "checked") return true;
12310
+ return prop === "value" || prop === "valueAsNumber" || prop === "valueAsDate";
12311
+ }
12312
+ return (tag === "select" || tag === "textarea") && prop === "value";
12313
+ }
12163
12314
  function findAllBindAttributes(html, attrName) {
12164
12315
  const attrs = [];
12165
12316
  const escaped = attrName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -12173,7 +12324,8 @@ function findAllBindAttributes(html, attrName) {
12173
12324
  const valueStart = tag.start + match.index + match[0].length;
12174
12325
  const valueEnd = html.indexOf(quote, valueStart);
12175
12326
  if (valueEnd === -1 || valueEnd > tag.end) continue;
12176
- attrs.push({ value: html.slice(valueStart, valueEnd), valueStart, tagName: tag.tagName });
12327
+ const inputType = tag.tagName === "input" ? extractAttribute(attrsText, "type") ?? void 0 : void 0;
12328
+ attrs.push({ value: html.slice(valueStart, valueEnd), valueStart, tagName: tag.tagName, ...inputType !== void 0 ? { inputType } : {} });
12177
12329
  regex.lastIndex = valueEnd - tag.start;
12178
12330
  }
12179
12331
  }
@@ -12264,14 +12416,16 @@ function validateFilterUsage(filter, bindingStart, msgs) {
12264
12416
  for (let i = 0; i < Math.min(argCount, info.argTypes.length); i++) {
12265
12417
  const expectedArgType = info.argTypes[i];
12266
12418
  if (expectedArgType === "any") continue;
12267
- const actualArgType = inferArgType(filter.args[i]);
12268
- if (actualArgType !== expectedArgType) {
12419
+ const arg = filter.args[i];
12420
+ const numericFails = expectedArgType === "number" && !readsAsNumber(arg);
12421
+ const actualArgType = inferArgType(arg);
12422
+ if (expectedArgType === "number" ? numericFails : actualArgType !== expectedArgType) {
12269
12423
  diagnostics.push({
12270
12424
  code: WcsDiagnosticCode.FilterArgType,
12271
12425
  start: bindingStart + filter.argsOffset,
12272
12426
  end: bindingStart + filter.argsOffset + filter.name.length,
12273
- message: msgs.filterArgType(filter.name, i + 1, expectedArgType, filter.args[i], actualArgType),
12274
- severity: "warning"
12427
+ message: msgs.filterArgType(filter.name, i + 1, expectedArgType, arg, actualArgType),
12428
+ severity: numericFails ? "error" : "warning"
12275
12429
  });
12276
12430
  }
12277
12431
  }
@@ -12336,57 +12490,11 @@ function validateSchemaPathExistence(checkPath, displayPath, scopedPaths, scoped
12336
12490
  }
12337
12491
  return null;
12338
12492
  }
12339
- function collectStructuralTemplates(html, attrName) {
12340
- const escaped = attrName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
12341
- const attrRegex = new RegExp(`${escaped}\\s*=\\s*(["'])`, "i");
12342
- const tagRegex = /<template(?:\s[^>]*)?>|<\/template\s*>/gi;
12343
- const templates = [];
12344
- let depth = 0;
12345
- let match;
12346
- while ((match = tagRegex.exec(html)) !== null) {
12347
- if (match[0].startsWith("</")) {
12348
- depth = Math.max(0, depth - 1);
12349
- continue;
12350
- }
12351
- const attrMatch = attrRegex.exec(match[0]);
12352
- if (attrMatch) {
12353
- const quote = attrMatch[1];
12354
- const valueStart = match.index + attrMatch.index + attrMatch[0].length;
12355
- const valueEnd = html.indexOf(quote, valueStart);
12356
- if (valueEnd !== -1) {
12357
- const first = splitBindingExpressions(html.slice(valueStart, valueEnd))[0] ?? "";
12358
- const firstColon = indexOfOutsideQuotes2(first, ":");
12359
- const prop = (firstColon === -1 ? first : first.slice(0, firstColon)).replace(/#.*$/, "").trim();
12360
- const type = prop === "if" || prop === "elseif" || prop === "else" ? prop : "other";
12361
- templates.push({ valueStart, depth, type });
12362
- }
12363
- }
12364
- depth++;
12365
- }
12366
- return templates;
12367
- }
12368
- function isNegatedByElseChain(templates, valueStart) {
12369
- const index = templates.findIndex((t) => t.valueStart === valueStart);
12370
- if (index === -1) return false;
12371
- const selfDepth = templates[index].depth;
12372
- for (let i = index + 1; i < templates.length; i++) {
12373
- const next = templates[i];
12374
- if (next.depth > selfDepth) continue;
12375
- if (next.depth < selfDepth) return false;
12376
- if (next.type === "elseif" || next.type === "else") return true;
12377
- if (next.type === "if") return false;
12378
- }
12379
- return false;
12380
- }
12381
- function getExpectedType(property, isNegatedIf) {
12493
+ function getExpectedType(property) {
12382
12494
  const prop = property.replace(/#.*$/, "");
12383
12495
  if (prop === "for") {
12384
12496
  return { label: "for", expected: "array", severity: "error" };
12385
12497
  }
12386
- if (prop === "if" || prop === "elseif") {
12387
- if (!isNegatedIf()) return null;
12388
- return { label: prop, expected: "boolean", severity: "warning" };
12389
- }
12390
12498
  if (prop.startsWith("class.")) {
12391
12499
  return { label: prop, expected: "boolean", severity: "warning" };
12392
12500
  }
@@ -12442,6 +12550,10 @@ function inferArgType(arg) {
12442
12550
  if (/^-?\d+(\.\d+)?$/.test(v)) return "number";
12443
12551
  return "string";
12444
12552
  }
12553
+ function readsAsNumber(arg) {
12554
+ const v = arg.trim().replace(/^(["'])([\s\S]*)\1$/, "$2");
12555
+ return v !== "" && !Number.isNaN(Number(v));
12556
+ }
12445
12557
  function isLiteral(value) {
12446
12558
  return /^-?\d/.test(value) || /^["'`]/.test(value) || value === "true" || value === "false" || value === "null";
12447
12559
  }
@@ -14365,21 +14477,164 @@ var BUILTIN_TAGS = {
14365
14477
  }
14366
14478
  };
14367
14479
 
14480
+ // src/service/pageElements.ts
14481
+ var MAX_FILES = 32;
14482
+ var JS_TYPES = /* @__PURE__ */ new Set(["", "module", "text/javascript", "application/javascript", "text/ecmascript"]);
14483
+ function pageScripts(html) {
14484
+ const inline = [];
14485
+ const srcs = [];
14486
+ const re = /<script\b((?:"[^"]*"|'[^']*'|[^>"'])*)>([\s\S]*?)<\/script\s*>/gi;
14487
+ const text3 = html.replace(/<!--[\s\S]*?-->/g, (c) => " ".repeat(c.length));
14488
+ let m;
14489
+ while ((m = re.exec(text3)) !== null) {
14490
+ const attrs = m[1];
14491
+ const type = (extractAttribute(attrs, "type") ?? "").trim().toLowerCase();
14492
+ if (!JS_TYPES.has(type)) continue;
14493
+ const src = extractAttribute(attrs, "src");
14494
+ if (src !== null) srcs.push(src);
14495
+ else if (m[2].trim() !== "") inline.push(m[2]);
14496
+ }
14497
+ return { inline, srcs };
14498
+ }
14499
+ function joinRelative(from, spec) {
14500
+ if (!spec.startsWith("./") && !spec.startsWith("../")) return null;
14501
+ const dir = from.includes("/") ? from.slice(0, from.lastIndexOf("/") + 1) : "";
14502
+ const out = [];
14503
+ for (const seg of `${dir}${spec}`.split("/")) {
14504
+ if (seg === "" || seg === ".") continue;
14505
+ if (seg === ".." && out.length > 0 && out[out.length - 1] !== "..") out.pop();
14506
+ else out.push(seg);
14507
+ }
14508
+ return `./${out.join("/")}`;
14509
+ }
14510
+ function parseScript(source) {
14511
+ for (const sourceType of ["module", "script"]) {
14512
+ try {
14513
+ return parse3(source, { ecmaVersion: "latest", sourceType, allowHashBang: true });
14514
+ } catch {
14515
+ }
14516
+ }
14517
+ return null;
14518
+ }
14519
+ function* nodes(node) {
14520
+ yield node;
14521
+ for (const value of Object.values(node)) {
14522
+ if (Array.isArray(value)) {
14523
+ for (const v of value) if (v !== null && typeof v === "object" && typeof v.type === "string") yield* nodes(v);
14524
+ } else if (value !== null && typeof value === "object" && typeof value.type === "string") {
14525
+ yield* nodes(value);
14526
+ }
14527
+ }
14528
+ }
14529
+ var keyName = (key, computed) => computed ? null : key.type === "Identifier" ? key.name : key.type === "Literal" && typeof key.value === "string" ? key.value : null;
14530
+ function names(obj, key) {
14531
+ const prop = obj.properties.find((p) => p.type === "Property" && keyName(p.key, p.computed) === key);
14532
+ if (prop === void 0 || prop.type !== "Property") return void 0;
14533
+ if (prop.value.type !== "ArrayExpression") return null;
14534
+ const out = [];
14535
+ for (const el of prop.value.elements) {
14536
+ if (el === null || el.type !== "ObjectExpression" || el.properties.some((p) => p.type !== "Property")) return null;
14537
+ const name = el.properties.find((p) => p.type === "Property" && keyName(p.key, p.computed) === "name");
14538
+ if (name === void 0 || name.type !== "Property" || name.value.type !== "Literal" || typeof name.value.value !== "string") return null;
14539
+ out.push(name.value.value);
14540
+ }
14541
+ return out;
14542
+ }
14543
+ function contractOf(value) {
14544
+ if (value.type !== "ObjectExpression" || value.properties.some((p) => p.type !== "Property")) return "unknown";
14545
+ const properties = names(value, "properties");
14546
+ const inputs = names(value, "inputs");
14547
+ const commands = names(value, "commands");
14548
+ if (properties === null || inputs === null || commands === null) return "unknown";
14549
+ return {
14550
+ properties: properties ?? [],
14551
+ inputs: Object.fromEntries((inputs ?? []).map((n) => [n, null])),
14552
+ commands: commands ?? []
14553
+ };
14554
+ }
14555
+ function declaredBy(cls) {
14556
+ let declared = "none";
14557
+ for (const member of cls.body.body) {
14558
+ if (member.type !== "PropertyDefinition" && member.type !== "MethodDefinition" || !member.static) continue;
14559
+ if (keyName(member.key, member.computed) !== "wcBindable") continue;
14560
+ if (member.type === "PropertyDefinition") {
14561
+ declared = member.value === null || member.value === void 0 ? "unknown" : contractOf(member.value);
14562
+ } else {
14563
+ const body = member.kind === "get" ? member.value.body.body : [];
14564
+ const ret = body.length === 1 && body[0].type === "ReturnStatement" ? body[0].argument : null;
14565
+ declared = ret === null || ret === void 0 ? "unknown" : contractOf(ret);
14566
+ }
14567
+ }
14568
+ const sup = cls.superClass;
14569
+ return { declared, superName: sup !== null && sup !== void 0 && sup.type === "Identifier" ? sup.name : null };
14570
+ }
14571
+ function isDefine(callee) {
14572
+ if (callee.type !== "MemberExpression" || keyName(callee.property, callee.computed) !== "define") return false;
14573
+ const o = callee.object;
14574
+ return o.type === "Identifier" && o.name === "customElements" || o.type === "MemberExpression" && keyName(o.property, o.computed) === "customElements";
14575
+ }
14576
+ function collectPageElementContracts(html, fileReader) {
14577
+ const { inline, srcs } = pageScripts(html);
14578
+ const programs = [];
14579
+ const read = /* @__PURE__ */ new Set();
14580
+ const queue = srcs.map((spec) => ({ from: "", spec: spec.startsWith(".") ? spec : `./${spec}` }));
14581
+ const visit2 = (program, from) => {
14582
+ programs.push(program);
14583
+ for (const n of nodes(program)) {
14584
+ const source = n.type === "ImportDeclaration" || n.type === "ExportAllDeclaration" || n.type === "ExportNamedDeclaration" ? n.source : n.type === "ImportExpression" ? n.source : null;
14585
+ if (source !== null && source !== void 0 && source.type === "Literal" && typeof source.value === "string") queue.push({ from, spec: source.value });
14586
+ }
14587
+ };
14588
+ for (const source of inline) {
14589
+ const program = parseScript(source);
14590
+ if (program !== null) visit2(program, "");
14591
+ }
14592
+ while (queue.length > 0 && fileReader !== void 0 && read.size < MAX_FILES) {
14593
+ const { from, spec } = queue.shift();
14594
+ const path = joinRelative(from, spec);
14595
+ if (path === null || read.has(path) || !/\.m?js$/.test(path)) continue;
14596
+ read.add(path);
14597
+ const text3 = fileReader(path);
14598
+ const program = text3 === void 0 ? null : parseScript(text3);
14599
+ if (program !== null) visit2(program, path);
14600
+ }
14601
+ const classes = /* @__PURE__ */ new Map();
14602
+ const defines = [];
14603
+ for (const program of programs) {
14604
+ for (const n of nodes(program)) {
14605
+ if (n.type === "ClassDeclaration" && n.id !== null && !classes.has(n.id.name)) classes.set(n.id.name, declaredBy(n));
14606
+ else if (n.type === "VariableDeclarator" && n.id.type === "Identifier" && n.init?.type === "ClassExpression" && !classes.has(n.id.name)) {
14607
+ classes.set(n.id.name, declaredBy(n.init));
14608
+ } else if (n.type === "CallExpression" && isDefine(n.callee) && n.arguments.length >= 2) {
14609
+ const [tag, cls] = n.arguments;
14610
+ if (tag.type !== "Literal" || typeof tag.value !== "string") continue;
14611
+ if (cls.type === "ClassExpression") defines.push({ tag: tag.value, info: declaredBy(cls) });
14612
+ else if (cls.type === "Identifier") defines.push({ tag: tag.value, info: cls.name });
14613
+ }
14614
+ }
14615
+ }
14616
+ const resolve = (info, depth) => {
14617
+ if (info.declared === "unknown") return null;
14618
+ if (info.declared !== "none") return info.declared;
14619
+ const sup = info.superName === null ? void 0 : classes.get(info.superName);
14620
+ return sup === void 0 || depth > 16 ? null : resolve(sup, depth + 1);
14621
+ };
14622
+ const out = /* @__PURE__ */ new Map();
14623
+ for (const { tag, info } of defines) {
14624
+ const name = tag.toLowerCase();
14625
+ if (name.startsWith("wcs-") || out.has(name)) continue;
14626
+ const cls = typeof info === "string" ? classes.get(info) : info;
14627
+ const contract = cls === void 0 ? null : resolve(cls, 0);
14628
+ if (contract !== null) out.set(name, contract);
14629
+ }
14630
+ return out;
14631
+ }
14632
+ function mayDefineElements(html) {
14633
+ return /customElements|<script\b[^>]*\bsrc\s*=/i.test(html);
14634
+ }
14635
+
14368
14636
  // src/service/ioNodeValidator.ts
14369
- var DOM_COMMON_PROPERTIES = /* @__PURE__ */ new Set([
14370
- "textContent",
14371
- "innerHTML",
14372
- "innerText",
14373
- "hidden",
14374
- "title",
14375
- "id",
14376
- "slot",
14377
- "dir",
14378
- "lang",
14379
- "role",
14380
- "tabIndex",
14381
- "className"
14382
- ]);
14637
+ var HTML_SINK_PROPERTIES = /* @__PURE__ */ new Set(["html", "innerHTML", "outerHTML", "srcdoc"]);
14383
14638
  var STRUCTURAL_DIRECTIVES3 = /* @__PURE__ */ new Set(["for", "if", "elseif", "else"]);
14384
14639
  var EXPLICIT_PROPERTY_REJECTED_HEADS2 = /* @__PURE__ */ new Set([
14385
14640
  ...Object.values(getWcsManifest().syntax.bindingTypes.propNamespaces),
@@ -14392,7 +14647,6 @@ function validateIoNodes(html, bindAttribute = "data-wcs", stateTagName = "wcs-s
14392
14647
  const diagnostics = [];
14393
14648
  const msgs = getMessages(locale2);
14394
14649
  const occurrences = findBuiltinTagOccurrences(html);
14395
- if (occurrences.length === 0) return diagnostics;
14396
14650
  let statePaths = null;
14397
14651
  const getPaths = () => statePaths ??= getStatePathsFromHtml(html, stateTagName, fileReader);
14398
14652
  for (const occ of occurrences) {
@@ -14420,32 +14674,35 @@ function validateIoNodes(html, bindAttribute = "data-wcs", stateTagName = "wcs-s
14420
14674
  }
14421
14675
  if (contract.properties.length === 0 && contract.commands.length === 0 && Object.keys(contract.inputs).length === 0) continue;
14422
14676
  const hasManual = hasBooleanAttribute(occ.attrsText, "manual");
14423
- let exprOffset = 0;
14424
- for (const expr of splitBindingExpressions(bindAttr.value)) {
14425
- const exprStart = valueStart + exprOffset;
14426
- exprOffset += expr.length + 1;
14427
- const parsed = parseBindingExpression(expr);
14428
- const property = parsed.property;
14429
- if (!property) continue;
14430
- const propIndex = expr.indexOf(property);
14431
- const start = propIndex === -1 ? exprStart : exprStart + propIndex;
14432
- const end = propIndex === -1 ? exprStart + expr.length : start + property.length;
14433
- validateBindingAgainstContract(
14434
- occ.tagName,
14435
- contract,
14436
- parsed,
14437
- property,
14438
- start,
14439
- end,
14440
- hasManual,
14441
- getPaths,
14442
- diagnostics,
14443
- msgs
14444
- );
14677
+ checkBindings(occ.tagName, contract, bindAttr.value, valueStart, hasManual, getPaths, diagnostics, msgs);
14678
+ }
14679
+ if (mayDefineElements(html)) {
14680
+ const own2 = findPageTagOccurrences(html, bindAttribute);
14681
+ const contracts = own2.length > 0 ? collectPageElementContracts(html, fileReader) : null;
14682
+ for (const occ of own2) {
14683
+ const contract = contracts.get(occ.tagName);
14684
+ if (contract === void 0) continue;
14685
+ if (contract.properties.length === 0 && contract.commands.length === 0 && Object.keys(contract.inputs).length === 0) continue;
14686
+ const bindAttr = extractAttributeValue(occ.attrsText, bindAttribute);
14687
+ checkBindings(occ.tagName, contract, bindAttr.value, occ.attrsStart + bindAttr.valueOffsetInAttrs, false, getPaths, diagnostics, msgs);
14445
14688
  }
14446
14689
  }
14447
14690
  return diagnostics;
14448
14691
  }
14692
+ function checkBindings(tagName, contract, value, valueStart, hasManual, getPaths, diagnostics, msgs) {
14693
+ let exprOffset = 0;
14694
+ for (const expr of splitBindingExpressions(value)) {
14695
+ const exprStart = valueStart + exprOffset;
14696
+ exprOffset += expr.length + 1;
14697
+ const parsed = parseBindingExpression(expr);
14698
+ const property = parsed.property;
14699
+ if (!property) continue;
14700
+ const propIndex = expr.indexOf(property);
14701
+ const start = propIndex === -1 ? exprStart : exprStart + propIndex;
14702
+ const end = propIndex === -1 ? exprStart + expr.length : start + property.length;
14703
+ validateBindingAgainstContract(tagName, contract, parsed, property, start, end, hasManual, getPaths, diagnostics, msgs);
14704
+ }
14705
+ }
14449
14706
  function validateBindingAgainstContract(tagName, contract, parsed, property, start, end, hasManual, getPaths, diagnostics, msgs) {
14450
14707
  const hashIndex = property.indexOf("#");
14451
14708
  const modifiers = hashIndex === -1 ? "" : property.slice(hashIndex + 1);
@@ -14481,7 +14738,7 @@ function validateBindingAgainstContract(tagName, contract, parsed, property, sta
14481
14738
  code: WcsDiagnosticCode.TagMemberUnknown,
14482
14739
  start,
14483
14740
  end,
14484
- severity: "warning",
14741
+ severity: "error",
14485
14742
  tag: tagName,
14486
14743
  member: name,
14487
14744
  message: msgs.tagCommandUnknown(name, tagName, contract.commands.join(", ") || msgs.none()) + suggestion(name, contract.commands, msgs)
@@ -14496,7 +14753,7 @@ function validateBindingAgainstContract(tagName, contract, parsed, property, sta
14496
14753
  code: WcsDiagnosticCode.TagMemberUnknown,
14497
14754
  start,
14498
14755
  end,
14499
- severity: "warning",
14756
+ severity: "error",
14500
14757
  tag: tagName,
14501
14758
  member: name,
14502
14759
  message: msgs.tagEventTokenKeyUnknown(name, tagName, contract.properties.join(", ")) + suggestion(name, contract.properties, msgs)
@@ -14504,20 +14761,21 @@ function validateBindingAgainstContract(tagName, contract, parsed, property, sta
14504
14761
  }
14505
14762
  return;
14506
14763
  }
14507
- if (!contract.properties.includes(property) && !(property in contract.inputs) && !DOM_COMMON_PROPERTIES.has(property)) {
14764
+ if (!tagName.startsWith("wcs-") && property.includes(".")) return;
14765
+ if (!contract.properties.includes(property) && !(property in contract.inputs) && !HTML_SINK_PROPERTIES.has(property)) {
14508
14766
  const members = [...contract.properties, ...inputNames];
14509
14767
  diagnostics.push({
14510
14768
  code: WcsDiagnosticCode.TagMemberUnknown,
14511
14769
  start,
14512
14770
  end,
14513
- severity: "warning",
14771
+ severity: "error",
14514
14772
  tag: tagName,
14515
14773
  member: property,
14516
14774
  message: msgs.tagMemberUnknown(property, tagName) + suggestion(property, members, msgs)
14517
14775
  });
14518
14776
  return;
14519
14777
  }
14520
- if (property === "trigger" && "trigger" in contract.inputs && parsed.path) {
14778
+ if (tagName.startsWith("wcs-") && property === "trigger" && "trigger" in contract.inputs && parsed.path) {
14521
14779
  const cand = findDataSlot(getPaths(), parsed.path);
14522
14780
  if (cand?.rawInitial === "true") {
14523
14781
  diagnostics.push({
@@ -14594,6 +14852,17 @@ function findBuiltinTagOccurrences(html) {
14594
14852
  }
14595
14853
  return out;
14596
14854
  }
14855
+ function findPageTagOccurrences(html, bindAttribute) {
14856
+ const out = [];
14857
+ for (const region of findStartTagRegions(html)) {
14858
+ const tagName = region.tagName;
14859
+ if (!tagName.includes("-") || tagName.startsWith("wcs-")) continue;
14860
+ const attrsText = html.slice(region.start, region.end);
14861
+ if (extractAttributeValue(attrsText, bindAttribute) === null) continue;
14862
+ out.push({ tagName, tagStart: region.start - tagName.length - 1, attrsText, attrsStart: region.start });
14863
+ }
14864
+ return out;
14865
+ }
14597
14866
  function extractAttributeValue(attrsText, attrName) {
14598
14867
  const escaped = attrName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
14599
14868
  const regex = new RegExp(`(?:^|\\s)${escaped}\\s*=\\s*(["'])`, "i");
@@ -14715,7 +14984,7 @@ function validateDocumentEnv(html, locale2) {
14715
14984
  code: WcsDiagnosticCode.ScriptOrder,
14716
14985
  start: later.start,
14717
14986
  end: later.end,
14718
- severity: "warning",
14987
+ severity: "info",
14719
14988
  message: msgs.devtoolsAfterState()
14720
14989
  });
14721
14990
  }
@@ -15039,7 +15308,7 @@ function validateWatchDeclarations(html, stateTagName = "wcs-state", locale2, fi
15039
15308
  const scopes = {
15040
15309
  mounts: volumes?.scopes.mounts ?? [],
15041
15310
  unresolvedMounts: volumes?.scopes.unresolvedMounts ?? NO_MOUNTS,
15042
- rootUnresolved: own2.length === 0 && !isReadableStateScript(block.content)
15311
+ rootUnresolved: !scriptReadable(block.content, own2)
15043
15312
  };
15044
15313
  for (const entry of entries) {
15045
15314
  const diagnostic = validateEntry(entry, pathSet, paths, scopes, msgs);
@@ -15060,10 +15329,10 @@ var NO_MOUNTS = /* @__PURE__ */ new Set();
15060
15329
  function assignVolumes(elements, html) {
15061
15330
  const chainOf = createTemplateChain(html);
15062
15331
  const innermost = (chain) => chain.length > 0 ? chain[chain.length - 1] : -1;
15063
- const treeOf = (root) => innermost(chainOf(root.tagStart));
15332
+ const treeOf2 = (root) => innermost(chainOf(root.tagStart));
15064
15333
  const rootTrees = /* @__PURE__ */ new Set();
15065
15334
  for (const element2 of elements) {
15066
- if (element2.mountPath === null && !element2.bindComponent) rootTrees.add(treeOf(element2));
15335
+ if (element2.mountPath === null && !element2.bindComponent) rootTrees.add(treeOf2(element2));
15067
15336
  }
15068
15337
  const volumes = /* @__PURE__ */ new Map();
15069
15338
  for (const element2 of elements) {
@@ -15080,7 +15349,7 @@ function assignVolumes(elements, html) {
15080
15349
  if (list === void 0) volumes.set(tree, [element2]);
15081
15350
  else list.push(element2);
15082
15351
  }
15083
- return { treeOf, volumes };
15352
+ return { treeOf: treeOf2, volumes };
15084
15353
  }
15085
15354
  function validateEntry(entry, pathSet, paths, scopes, msgs) {
15086
15355
  const { key } = entry;
@@ -15411,7 +15680,7 @@ function validateRecursiveGetters(script, offset2, spec, undeclared, msgs, out)
15411
15680
  start,
15412
15681
  end,
15413
15682
  msgs.recursionUnsupported(span.name, "undeclared"),
15414
- "warning"
15683
+ "error"
15415
15684
  );
15416
15685
  }
15417
15686
  continue;
@@ -15935,7 +16204,8 @@ function findMountPathProblem(mountPath) {
15935
16204
  if (mountPath.length === 0) return "empty";
15936
16205
  for (const segment of mountPath.split(".")) {
15937
16206
  if (segment.length === 0) return "emptySegment";
15938
- if (segment === "*") return "wildcard";
16207
+ if (segment.includes("*")) return "wildcard";
16208
+ if (/\s/.test(segment)) return "whitespace";
15939
16209
  if (segment.includes("$") || segment.includes("#") || segment.includes("@")) return "reserved";
15940
16210
  }
15941
16211
  return null;
@@ -16067,8 +16337,8 @@ function validateVolumeBlock2(block, mountPath, msgs, out) {
16067
16337
  }
16068
16338
  function validateBindComponentSource(html, tagStart, tagEnd, hasInlineScript, msgs, out) {
16069
16339
  const tag = html.slice(tagStart, tagEnd);
16070
- const names = parseAttributeNames(tag);
16071
- const sources = BIND_COMPONENT_SOURCE_ATTRIBUTES.filter((name) => names.has(name));
16340
+ const names2 = parseAttributeNames(tag);
16341
+ const sources = BIND_COMPONENT_SOURCE_ATTRIBUTES.filter((name) => names2.has(name));
16072
16342
  if (hasInlineScript) sources.push('<script type="module">');
16073
16343
  if (sources.length === 0) return;
16074
16344
  const prop = /\sbind-component\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'<>`=]+))/i.exec(tag);
@@ -16196,7 +16466,7 @@ var OLD_DECLARATION_KEY = /(^|[{,;\s])(\$streams|\$updatedCallback)(?=\s*(?:[:(]
16196
16466
  function collectDeclarationAliasReads(script) {
16197
16467
  return collectStateThisReads(script, OLD_DECLARATION_MEMBER_NAMES);
16198
16468
  }
16199
- function collectStateThisReads(script, names) {
16469
+ function collectStateThisReads(script, names2) {
16200
16470
  if (!hasDefaultExportObject(script)) return null;
16201
16471
  const out = [];
16202
16472
  const take = (refs, base) => {
@@ -16205,10 +16475,10 @@ function collectStateThisReads(script, names) {
16205
16475
  return true;
16206
16476
  };
16207
16477
  for (const callable of analyzeCallableBodies(script)) {
16208
- if (!take(collectThisMemberRefs(callable.body, names), callable.bodyStart)) return null;
16478
+ if (!take(collectThisMemberRefs(callable.body, names2), callable.bodyStart)) return null;
16209
16479
  }
16210
16480
  for (const handler of analyzeWatchHandlerSources(script)) {
16211
- const refs = handler.kind === "body" ? collectThisMemberRefs(handler.text, names) : collectThisMemberRefsInValue(handler.text, names);
16481
+ const refs = handler.kind === "body" ? collectThisMemberRefs(handler.text, names2) : collectThisMemberRefsInValue(handler.text, names2);
16212
16482
  if (!take(refs, handler.start)) return null;
16213
16483
  }
16214
16484
  out.sort((a, b) => a.start - b.start);
@@ -16307,7 +16577,7 @@ function validateIndexArity(script, scriptStart, locale2) {
16307
16577
  start: scriptStart + parsed.starts[1] + leading,
16308
16578
  end: scriptStart + parsed.starts[1] + argText.trimEnd().length,
16309
16579
  message: msgs.indexArity(api, path, requirement, wildcardCount, actual),
16310
- severity: "warning"
16580
+ severity: "error"
16311
16581
  });
16312
16582
  }
16313
16583
  return out;
@@ -16363,7 +16633,7 @@ function validateGetterCycles(script, scriptStart, locale2) {
16363
16633
  start: scriptStart + getter.start,
16364
16634
  end: scriptStart + getter.end,
16365
16635
  message: msgs.getterCycle(cycle),
16366
- severity: "warning"
16636
+ severity: "error"
16367
16637
  });
16368
16638
  }
16369
16639
  return out;
@@ -16416,6 +16686,26 @@ function validateGetterLocationReads(script, scriptStart, locale2) {
16416
16686
  }
16417
16687
  return out;
16418
16688
  }
16689
+ var CLOCK_READ = /\bDate\s*\.\s*now\s*\(|\bnew\s+Date\s*\(\s*\)|\bperformance\s*\.\s*now\s*\(/;
16690
+ function validateGetterClockReads(script, scriptStart, locale2) {
16691
+ if (!/Date|performance/.test(script)) return [];
16692
+ const msgs = getMessages(locale2);
16693
+ const out = [];
16694
+ for (const getter of analyzeCallableBodies(script)) {
16695
+ if (getter.kind !== "getter" || getter.accessor !== "get") continue;
16696
+ const read = CLOCK_READ.exec(maskCommentsAndStrings(getter.body));
16697
+ if (read === null) continue;
16698
+ const text3 = read[0].startsWith("new") ? "new Date()" : read[0].startsWith("performance") ? "performance.now()" : "Date.now()";
16699
+ out.push({
16700
+ code: WcsDiagnosticCode.GetterUntrackedRead,
16701
+ start: scriptStart + getter.bodyStart + read.index,
16702
+ end: scriptStart + getter.bodyStart + read.index + read[0].length,
16703
+ message: msgs.getterReadsClock(text3),
16704
+ severity: "warning"
16705
+ });
16706
+ }
16707
+ return out;
16708
+ }
16419
16709
  function onHandlerStateParam(script, handler) {
16420
16710
  if (handler.kind === "body") {
16421
16711
  const head = script.slice(Math.max(0, handler.start - 400), handler.start);
@@ -16475,7 +16765,7 @@ function validateInputNestedWrites(html, stateTagName, bindAttrName, nestedWrite
16475
16765
  code: WcsDiagnosticCode.InputNestedWrite,
16476
16766
  start: occ.pathRange.start,
16477
16767
  end: occ.pathRange.end,
16478
- severity: "warning",
16768
+ severity: "error",
16479
16769
  tag: tag.tagName,
16480
16770
  statePath: occ.path,
16481
16771
  message
@@ -16613,15 +16903,22 @@ function validateUpdatedCallbackDemand(html, stateTagName, bindAttrName, locale2
16613
16903
  const reported = /* @__PURE__ */ new Set();
16614
16904
  while ((match = PATH_TEST_LITERAL.exec(body)) !== null) {
16615
16905
  const path = match[2];
16616
- if (path.length === 0 || !declared.has(path) || bound.has(path)) continue;
16617
- if (reported.has(path)) continue;
16906
+ if (path.length === 0 || bound.has(path) || reported.has(path)) continue;
16907
+ let message;
16908
+ if (declared.has(path)) {
16909
+ message = msgs.updatedCallbackUnbound(path);
16910
+ } else {
16911
+ const near = suggestion(path, [...declared, ...bound], msgs);
16912
+ if (near === "") continue;
16913
+ message = msgs.updatedCallbackUnknownPath(path) + near;
16914
+ }
16618
16915
  reported.add(path);
16619
16916
  const quoteAt = match.index + match[0].length - path.length - 1;
16620
16917
  out.push({
16621
16918
  code: WcsDiagnosticCode.UpdatedCallbackUnbound,
16622
16919
  start: block.contentStart + callback.bodyStart + quoteAt,
16623
16920
  end: block.contentStart + callback.bodyStart + quoteAt + path.length,
16624
- message: msgs.updatedCallbackUnbound(path),
16921
+ message,
16625
16922
  severity: "warning"
16626
16923
  });
16627
16924
  }
@@ -16634,8 +16931,8 @@ function collectBoundPaths(html, stateTagName, bindAttrName) {
16634
16931
  for (const occurrence of index.occurrences) {
16635
16932
  bound.add(occurrence.path);
16636
16933
  if (!occurrence.path.startsWith(".")) continue;
16637
- const forPath = getInnermostForPath(html, occurrence.pathRange.start, bindAttrName);
16638
- if (forPath === null || forPath.startsWith(".")) continue;
16934
+ const forPath = getResolvedForListPath(html, occurrence.pathRange.start, bindAttrName);
16935
+ if (forPath === null) continue;
16639
16936
  bound.add(
16640
16937
  occurrence.path === "." ? `${forPath}.*` : `${forPath}.*.${occurrence.path.slice(1)}`
16641
16938
  );
@@ -16708,6 +17005,7 @@ function validateSemantics(html, stateTagName = "wcs-state", locale2, bindAttrNa
16708
17005
  out.push(...validateGetterCycles(block.content, block.contentStart, locale2));
16709
17006
  out.push(...validateGetterUntrackedReads(block.content, block.contentStart, getNestedWriteRoots, locale2));
16710
17007
  out.push(...validateGetterLocationReads(block.content, block.contentStart, locale2));
17008
+ out.push(...validateGetterClockReads(block.content, block.contentStart, locale2));
16711
17009
  out.push(...validateOnHandlerThis(block.content, block.contentStart, locale2));
16712
17010
  out.push(...validateInPlaceChanges(block.content, block.contentStart, locale2));
16713
17011
  }
@@ -16716,6 +17014,169 @@ function validateSemantics(html, stateTagName = "wcs-state", locale2, bindAttrNa
16716
17014
  return out;
16717
17015
  }
16718
17016
 
17017
+ // src/service/scriptStateUseValidator.ts
17018
+ var COMMAND_USE = /\.\s*\$command\s*\.\s*([A-Za-z_$][\w$]*)/dg;
17019
+ var EMIT_AFTER = /^\s*\.\s*emit\s*\(/;
17020
+ var THIS_WRITE = /\bthis\s*\.\s*([A-Za-z_][\w$]*)\s*(?:=(?![=>])|[-+*/%&|^]=|\*\*=|<<=|>>>?=|&&=|\|\|=|\?\?=|\+\+|--)/dg;
17021
+ var PRE_THIS_WRITE = /(?:\+\+|--)\s*this\s*\.\s*([A-Za-z_][\w$]*)/dg;
17022
+ function validateScriptStateUses(html, stateTagName = "wcs-state", locale2, bindAttrName = "data-wcs") {
17023
+ const blocks = parseLoadedScriptBlocks(html, stateTagName).filter((block) => isReadableStateScript(block.content));
17024
+ if (blocks.length === 0) return [];
17025
+ const msgs = getMessages(locale2);
17026
+ const out = [];
17027
+ let receivers = null;
17028
+ let markupEmits = null;
17029
+ const bindings = () => {
17030
+ if (receivers !== null) return;
17031
+ receivers = /* @__PURE__ */ new Set();
17032
+ markupEmits = /* @__PURE__ */ new Map();
17033
+ for (const o of buildReferenceIndex(html, { bindAttribute: bindAttrName, stateTagName }).occurrences) {
17034
+ if (!o.path.startsWith("$command.")) continue;
17035
+ const name = o.path.slice("$command.".length);
17036
+ const prop = o.propName ?? "";
17037
+ if (prop.startsWith("command.")) receivers.add(name);
17038
+ else if (prop.startsWith("on") && !markupEmits.has(name)) markupEmits.set(name, o.pathRange);
17039
+ }
17040
+ };
17041
+ for (const block of blocks) {
17042
+ const paths = analyzeStatePaths(block.content);
17043
+ const masked = maskCommentsAndStrings(block.content);
17044
+ const declared = paths.filter((p) => p.kind === "command").map((p) => p.path.slice("$command.".length));
17045
+ if (block.mountPath === null && declared.length > 0) {
17046
+ const emitted = /* @__PURE__ */ new Map();
17047
+ COMMAND_USE.lastIndex = 0;
17048
+ let match;
17049
+ while ((match = COMMAND_USE.exec(masked)) !== null) {
17050
+ const name = match[1];
17051
+ const [start, end] = match.indices[1];
17052
+ if (!declared.includes(name)) {
17053
+ out.push({
17054
+ code: WcsDiagnosticCode.TokenUndeclared,
17055
+ start: block.contentStart + start,
17056
+ end: block.contentStart + end,
17057
+ // `$command` holds the declared tokens only: `.emit()` on what it lacks is a TypeError
17058
+ message: msgs.commandTokenUndeclared(`$command.${name}`) + suggestion(name, declared, msgs),
17059
+ severity: "error"
17060
+ });
17061
+ } else if (!emitted.has(name) && EMIT_AFTER.test(masked.slice(match.index + match[0].length))) {
17062
+ emitted.set(name, { start: block.contentStart + start, end: block.contentStart + end });
17063
+ }
17064
+ }
17065
+ bindings();
17066
+ for (const name of declared) {
17067
+ if (receivers.has(name)) continue;
17068
+ const at2 = emitted.get(name) ?? markupEmits.get(name);
17069
+ if (at2 === void 0) continue;
17070
+ out.push({
17071
+ code: WcsDiagnosticCode.CommandTokenUnbound,
17072
+ start: at2.start,
17073
+ end: at2.end,
17074
+ message: msgs.commandTokenUnbound(`$command.${name}`),
17075
+ severity: "warning"
17076
+ });
17077
+ }
17078
+ }
17079
+ const keys = [...new Set(paths.map((p) => p.path.split(".")[0]).filter((key) => key !== "" && !key.startsWith("$")))];
17080
+ const reported = /* @__PURE__ */ new Set();
17081
+ for (const pattern of [THIS_WRITE, PRE_THIS_WRITE]) {
17082
+ pattern.lastIndex = 0;
17083
+ let match;
17084
+ while ((match = pattern.exec(masked)) !== null) {
17085
+ const key = match[1];
17086
+ if (keys.includes(key) || reported.has(key)) continue;
17087
+ const near = suggestion(key, keys, msgs);
17088
+ if (near === "") continue;
17089
+ reported.add(key);
17090
+ const [start, end] = match.indices[1];
17091
+ out.push({
17092
+ code: WcsDiagnosticCode.WritePathMissing,
17093
+ start: block.contentStart + start,
17094
+ end: block.contentStart + end,
17095
+ message: msgs.writePathMissing(key) + near,
17096
+ severity: "warning"
17097
+ });
17098
+ }
17099
+ }
17100
+ }
17101
+ return out;
17102
+ }
17103
+
17104
+ // src/service/scriptReadValidator.ts
17105
+ function validateScriptReads(html, stateTagName = "wcs-state", locale2, fileReader, applicationSchema) {
17106
+ const blocks = parseLoadedScriptBlocks(html, stateTagName);
17107
+ if (blocks.length === 0) return [];
17108
+ const msgs = getMessages(locale2);
17109
+ const index = getStatePathIndex(html, stateTagName, fileReader);
17110
+ const candidates = mergeSchemaCandidates(index.paths, applicationSchema);
17111
+ const candidateSet = new Set(candidates.map((p) => p.path));
17112
+ let tree = null;
17113
+ const out = [];
17114
+ for (const block of blocks) {
17115
+ const spread = applicationSchema === void 0 ? findTopLevelSpread(block.content) : null;
17116
+ if (spread !== null) {
17117
+ out.push({
17118
+ code: WcsDiagnosticCode.PathDynamicUnknown,
17119
+ start: block.contentStart + spread.start,
17120
+ end: block.contentStart + spread.end,
17121
+ message: msgs.pathDynamicUnknownSpread(block.content.slice(spread.start, spread.end)),
17122
+ severity: "info"
17123
+ });
17124
+ }
17125
+ const prefix = block.mountPath === null || block.mountPath === "" ? "" : `${block.mountPath}.`;
17126
+ for (const callable of analyzeCallableBodies(block.content)) {
17127
+ for (const read of collectGetterReads(callable.body) ?? []) {
17128
+ if (read.written || read.path.split(".").some((s) => s === "" || s.startsWith("$")) || hasRecursionWildcard(read.path)) continue;
17129
+ const path = prefix + read.path;
17130
+ if (pathExistsInCandidates(path, candidates, candidateSet)) continue;
17131
+ if (applicationSchema !== void 0 ? resolveIndexedSchemaPath(applicationSchema, path).kind !== "nonexistent" : isUnresolvedPath(path, index.scopes)) continue;
17132
+ const near = nearName(path, tree ??= treeOf(candidates));
17133
+ if (near === null) continue;
17134
+ const said = suggestion(near.segment, near.names, msgs);
17135
+ if (said === "") continue;
17136
+ const at2 = block.contentStart + callable.bodyStart;
17137
+ out.push({
17138
+ code: WcsDiagnosticCode.ReadPathMissing,
17139
+ start: at2 + read.start,
17140
+ end: read.form === "member" ? at2 + read.start + statePart(callable.body.slice(read.start, read.end)) : at2 + read.end,
17141
+ message: msgs.readPathMissing(read.path, !read.path.includes(".")) + said,
17142
+ // a stateSchema says the path is not there, as for a binding's `wcs/path-nonexistent`
17143
+ severity: applicationSchema !== void 0 ? "error" : "warning"
17144
+ });
17145
+ }
17146
+ }
17147
+ }
17148
+ return out;
17149
+ }
17150
+ var THIS_PART = /^this\s*(?:\?\.\s*|\.\s*)(?:[A-Za-z_$][\w$]*)|^this\s*(?:\?\.)?\s*\[\s*(["'`])[^"'`]*\1\s*\]/;
17151
+ function statePart(text3) {
17152
+ return THIS_PART.exec(text3)?.[0].length ?? text3.length;
17153
+ }
17154
+ function treeOf(candidates) {
17155
+ const tree = /* @__PURE__ */ new Map();
17156
+ for (const c of candidates) {
17157
+ let parent = "";
17158
+ for (const segment of c.path.split(".")) {
17159
+ let names2 = tree.get(parent);
17160
+ if (names2 === void 0) tree.set(parent, names2 = /* @__PURE__ */ new Set());
17161
+ names2.add(segment);
17162
+ parent = parent === "" ? segment : `${parent}.${segment}`;
17163
+ }
17164
+ }
17165
+ return tree;
17166
+ }
17167
+ function nearName(path, tree) {
17168
+ let parent = "";
17169
+ for (const segment of (hasIndexSegment(path) ? toWildcardForm(path) : path).split(".")) {
17170
+ const names2 = tree.get(parent);
17171
+ if (names2?.has(segment)) {
17172
+ parent = parent === "" ? segment : `${parent}.${segment}`;
17173
+ continue;
17174
+ }
17175
+ return { segment, names: [...names2 ?? []].filter((name) => name !== "*" && !name.startsWith("$")) };
17176
+ }
17177
+ return null;
17178
+ }
17179
+
16719
17180
  // src/core/sidecar/discover.ts
16720
17181
  var APPLICATION_MANIFEST_FILENAME = "wcstack.manifest.json";
16721
17182
  var MAX_ASCEND = 16;
@@ -16740,13 +17201,129 @@ function applicationSchemaOf(loaded) {
16740
17201
  return void 0;
16741
17202
  }
16742
17203
 
17204
+ // src/core/offsetToPosition.ts
17205
+ function createPositionMapper(text3) {
17206
+ const lineStarts = [0];
17207
+ for (let i = 0; i < text3.length; i++) {
17208
+ const c = text3.charCodeAt(i);
17209
+ if (c === 10) {
17210
+ lineStarts.push(i + 1);
17211
+ } else if (c === 13) {
17212
+ if (text3.charCodeAt(i + 1) === 10) i++;
17213
+ lineStarts.push(i + 1);
17214
+ }
17215
+ }
17216
+ return (offset2) => {
17217
+ const clamped = Math.max(0, Math.min(offset2, text3.length));
17218
+ let lo = 0;
17219
+ let hi = lineStarts.length - 1;
17220
+ while (lo < hi) {
17221
+ const mid = lo + hi + 1 >> 1;
17222
+ if (lineStarts[mid] <= clamped) lo = mid;
17223
+ else hi = mid - 1;
17224
+ }
17225
+ return { line: lo + 1, column: clamped - lineStarts[lo] + 1 };
17226
+ };
17227
+ }
17228
+
17229
+ // src/core/externalState.ts
17230
+ var OPEN = '<script type="module">';
17231
+ var CLOSE = "</script>";
17232
+ function inlineExternalStates(html, stateTagName, fileReader) {
17233
+ let text3 = "";
17234
+ let from = 0;
17235
+ let shift = 0;
17236
+ const states = [];
17237
+ for (const element2 of parseWcsStateElements(html, stateTagName)) {
17238
+ const src = element2.srcSpan;
17239
+ if (src === void 0 || element2.srcAttr === void 0 || element2.stateAttr !== void 0 || element2.bindComponent) continue;
17240
+ const file = readStateScriptFile(element2.srcAttr, fileReader);
17241
+ if (file === void 0) continue;
17242
+ const blanks = [src];
17243
+ if (element2.jsonSpan !== void 0) blanks.push(element2.jsonSpan);
17244
+ blanks.sort((a, b) => a.start - b.start);
17245
+ for (const span of blanks) {
17246
+ text3 += html.slice(from, span.start) + " ".repeat(span.end - span.start);
17247
+ from = span.end;
17248
+ }
17249
+ text3 += html.slice(from, element2.tagEnd);
17250
+ from = element2.tagEnd;
17251
+ const content = file.text.replace(/<\/(script)/gi, "<\\$1");
17252
+ const at2 = element2.tagEnd + shift;
17253
+ const length = OPEN.length + content.length + CLOSE.length;
17254
+ text3 += OPEN + content + CLOSE;
17255
+ states.push({
17256
+ path: file.path,
17257
+ text: file.text,
17258
+ at: at2,
17259
+ contentAt: at2 + OPEN.length,
17260
+ length,
17261
+ valueStart: src.valueStart,
17262
+ valueEnd: src.valueEnd,
17263
+ position: createPositionMapper(file.text)
17264
+ });
17265
+ shift += length;
17266
+ }
17267
+ if (states.length === 0) return null;
17268
+ return { text: text3 + html.slice(from), states };
17269
+ }
17270
+ function locateInlined(page, offset2) {
17271
+ let shift = 0;
17272
+ for (const state of page.states) {
17273
+ if (offset2 < state.at) break;
17274
+ if (offset2 < state.at + state.length) {
17275
+ return { state, offset: Math.min(Math.max(offset2 - state.contentAt, 0), state.text.length) };
17276
+ }
17277
+ shift += state.length;
17278
+ }
17279
+ return { offset: offset2 - shift };
17280
+ }
17281
+
16743
17282
  // src/core/validateDocument.ts
16744
17283
  function validateDocument(text3, options = {}) {
17284
+ const stateTagName = options.stateTagName ?? "wcs-state";
17285
+ const fileReader = options.fileReader;
17286
+ const applicationSchema = options.applicationSchema ?? (fileReader !== void 0 ? discoverApplicationManifest(fileReader)?.schema : void 0);
17287
+ const found = validateText(text3, options, applicationSchema);
17288
+ const page = fileReader === void 0 ? null : inlineExternalStates(text3, stateTagName, fileReader);
17289
+ if (page === null) return found;
17290
+ const key = (d) => [d.code, d.start, d.end, d.message, d.origin?.path, d.origin?.start].join("\0");
17291
+ const seen2 = new Set(found.map(key));
17292
+ const out = [...found];
17293
+ for (const d of validateText(page.text, options, applicationSchema)) {
17294
+ const start = locateInlined(page, d.start);
17295
+ const end = locateInlined(page, d.end);
17296
+ let mapped;
17297
+ if (start.state !== void 0) {
17298
+ const state = start.state;
17299
+ const fileEnd = end.state === state ? Math.max(end.offset, start.offset) : start.offset;
17300
+ mapped = {
17301
+ ...d,
17302
+ start: state.valueStart,
17303
+ end: state.valueEnd,
17304
+ origin: {
17305
+ path: state.path,
17306
+ start: start.offset,
17307
+ end: fileEnd,
17308
+ startPosition: state.position(start.offset),
17309
+ endPosition: state.position(fileEnd)
17310
+ }
17311
+ };
17312
+ } else {
17313
+ mapped = { ...d, start: start.offset, end: end.state === void 0 ? Math.max(end.offset, start.offset) : start.offset };
17314
+ }
17315
+ const k = key(mapped);
17316
+ if (seen2.has(k)) continue;
17317
+ seen2.add(k);
17318
+ out.push(mapped);
17319
+ }
17320
+ return sortDiagnostics(out);
17321
+ }
17322
+ function validateText(text3, options, applicationSchema) {
16745
17323
  const bindAttribute = options.bindAttribute ?? "data-wcs";
16746
17324
  const stateTagName = options.stateTagName ?? "wcs-state";
16747
17325
  const locale2 = options.locale;
16748
17326
  const fileReader = options.fileReader;
16749
- const applicationSchema = options.applicationSchema ?? (fileReader !== void 0 ? discoverApplicationManifest(fileReader)?.schema : void 0);
16750
17327
  const out = [];
16751
17328
  out.push(...validateBindings(text3, bindAttribute, stateTagName, locale2, fileReader, applicationSchema));
16752
17329
  out.push(...validateTemplateSyntax(text3, stateTagName, bindAttribute, locale2, fileReader, applicationSchema));
@@ -16755,6 +17332,8 @@ function validateDocument(text3, options = {}) {
16755
17332
  out.push(...validateAriaAttributes(text3, bindAttribute, locale2));
16756
17333
  out.push(...validateDocumentEnv(text3, locale2));
16757
17334
  out.push(...validateSemantics(text3, stateTagName, locale2, bindAttribute));
17335
+ out.push(...validateScriptStateUses(text3, stateTagName, locale2, bindAttribute));
17336
+ out.push(...validateScriptReads(text3, stateTagName, locale2, fileReader, applicationSchema));
16758
17337
  out.push(...validateArrayMutations(text3, stateTagName, locale2));
16759
17338
  out.push(...validateWatchDeclarations(text3, stateTagName, locale2, fileReader));
16760
17339
  out.push(...validateScanDeclarations(text3, stateTagName, locale2));
@@ -16769,7 +17348,9 @@ function validateDocument(text3, options = {}) {
16769
17348
  for (const d of validateNestedAssigns(text3, stateTagName, locale2)) {
16770
17349
  out.push({ code: WcsDiagnosticCode.NestedAssign, start: d.start, end: d.end, message: d.message, severity: d.severity });
16771
17350
  }
16772
- return sortDiagnostics(out);
17351
+ const ignored = findIgnoredRanges(text3, bindAttribute);
17352
+ const kept = ignored.length === 0 ? out : out.filter((d) => !ignored.some(([start, end]) => d.start >= start && d.start < end));
17353
+ return sortDiagnostics(kept);
16773
17354
  }
16774
17355
  // Annotate the CommonJS export names for ESM import in node:
16775
17356
  0 && (module.exports = {