@wcstack/typescript 4.1.1 → 4.3.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.
@@ -68,12 +68,15 @@ var WcsDiagnosticCode = {
68
68
  NestedAssign: "wcs/nested-assign",
69
69
  // --- 意味論(構文・存在検査では捕まらない取り違え。service/semanticValidator.ts) ---
70
70
  // `$getAll` / `$setAll` / `$resolve` の添字の本数がパスの `*` の本数と噛み合わない。
71
- // ランタイムは同じ code で raiseError する(超過は以前は黙って無視されていた)。
71
+ // ランタイムは #901 / #902 で throw する(diagnostics の後付けがあれば同じ code の文面。超過は 3.x では
72
+ // 黙って無視されていた)。error。
72
73
  IndexArity: "wcs/index-arity",
73
74
  // ワイルドカードの階数がスコープの段数を超える(`matrix.*.*` を 1 段の for で読む、
74
75
  // `$2` を 1 段のループで読む。ランタイムの #1401)。既存の「for の外」検査の深さ方向の一般化。
75
76
  // 4.0 は各段の `*` が**その段で囲む for のリスト**の行であることも確かめる(#1403・F32 — `for: a`
76
- // の行の中の `b.*.y` は投げる)。静的側も囲む for の一覧と段ごとに比べて同じ code で報告する。
77
+ // の行の中の `b.*.y` は投げる)。静的側も囲む for の一覧と段ごとに比べて同じ code で報告する
78
+ // (ランタイムの文面に code が付くのは diagnostics の後付けがあるとき)。for のスコープを組み直しきれない
79
+ // ので、ランタイムは初期化を失敗させるが warning のまま(vscode-wcs の README の重大度の例外)。
77
80
  WildcardRank: "wcs/wildcard-rank",
78
81
  // ループの添字の範囲(`$1`〜`$128`。上限は manifest の `syntax.indexParam.maxDepth`)の外。ランタイムと同じ code:
79
82
  // for の中のマークアップの `$129`(バインディングが失敗する)と、スクリプトの `this.$0` / `this.$129` / `this.$1000`
@@ -81,7 +84,8 @@ var WcsDiagnosticCode = {
81
84
  // `wcs/binding-path-missing`(ただしけっして動かないので error)。for の外の `$129` はランタイムでは #1401 なので
82
85
  // 従来どおり「for の外のループ添字」(`wcs/template-syntax`)で報告する。
83
86
  IndexParamRange: "wcs/index-param-range",
84
- // パス getter どうしの循環参照。ランタイムはアドレススタック上限まで再帰してから落ちる。
87
+ // パス getter どうしの循環参照。4.0 のランタイムは評価の時点で #701 として throw し、その getter を読む
88
+ // 束縛はすべて失敗する(3.x はアドレススタック上限まで再帰してから落ちた)。error。
85
89
  GetterCycle: "wcs/getter-cycle",
86
90
  // `$renderedCallback`(3.x の旧名 `$updatedCallback`)が、どのバインディングにも現れないパスを判定に使っている。
87
91
  // 同コールバックは **binding 駆動**(live binding が適用された path しか報告しない)
@@ -96,8 +100,9 @@ var WcsDiagnosticCode = {
96
100
  GetterUntrackedRead: "wcs/getter-untracked-read",
97
101
  OnHandlerThis: "wcs/on-handler-this",
98
102
  // --- <wcs-state> script: $watch declaration ---
99
- // ランタイム(watch/processWatchDeclaration.ts)が raiseError で落とす宣言。
100
- // 越境 `@` / `$` 始まり / 空キー・空セグメント / 明らかな非関数ハンドラ。
103
+ // temporal の後付け(state の temporal/watch.ts)が読み込みで throw する宣言: 越境 `@` / `$` 始まり /
104
+ // 空キー / 明らかな非関数ハンドラ。空の段(`a..b`)はランタイムが調べず、その watch は黙って発火しない
105
+ // (lint だけが知らせる — docs/mistake-catalogue.md)。
101
106
  WatchDeclarationInvalid: "wcs/watch-declaration-invalid",
102
107
  // `$watch` のキーが状態定義に存在しない。バインディング側と違い黙って発火しない
103
108
  // だけなので気づけない。severity は binding-path-missing に揃える(warning)。
@@ -116,8 +121,8 @@ var WcsDiagnosticCode = {
116
121
  //
117
122
  // `**` を解釈しない場所へ `**` が渡った(data-wcs / mustache / $watch キー / $listKeys
118
123
  // キー / $resolve / $postUpdate / $dependOn(旧名 $trackDependency) / 代入)、または `$recursion` 宣言が
119
- // 無いのに `**` を使った。runtime は PathInfo の不変条件として raiseError するか
120
- //(API 経由)、getter を黙って無視する(宣言なしの `**` getter)。
124
+ // 無いのに `**` を使った。4.0 の runtime はどれも #1101 で throw する — 宣言なしの `**` getter も、
125
+ // アクセサを登録する時点で(3.x は黙って無視した)。error。
121
126
  RecursionUnsupported: "wcs/recursion-unsupported",
122
127
  // 宣言済みアンカーと合致しない `**`(綴り違い・2 つ目の `**`)、または `**` の後ろが
123
128
  // 整形されていない(空セグメント・`**` 直後の素の `*`)。
@@ -155,7 +160,8 @@ var WcsDiagnosticCode = {
155
160
  // ドットアクセスを含むチェーン代入は NestedAssign の担当(相補・二重報告なし)。
156
161
  ArrayIndexAssign: "wcs/array-index-assign",
157
162
  // --- built-in wcs-* tag contract (generated/builtinTags.generated.ts が正本) ---
158
- // 未知メンバーへのバインド(プロパティ / command. / eventToken. キー)。黙って無視される。
163
+ // 未知メンバーへのバインド(プロパティ / command. / eventToken. キー)。4.0 のランタイムは #38 / #1203 /
164
+ // #1204 で拒み、root では初期化が、行では束縛が失敗する(3.x の「黙って無視」ではない)。error。
159
165
  TagMemberUnknown: "wcs/tag-member-unknown",
160
166
  // タグのメンバー名が "on" で始まる(`once` 等)のに先頭ドット無しで束縛した: ランタイムはイベント束縛にして
161
167
  // "ce" イベントを待ち、値は届かない。明示のプロパティ形 `.once:` を提案する(@wcstack/state 3.1・要件 B5 / 3.x 計画 D36)
@@ -166,6 +172,10 @@ var WcsDiagnosticCode = {
166
172
  // ランタイムは何も報告しない(root は正しい値)ので lint の code。`#direct` か `event.target.closest(...)` を
167
173
  // 案内する。読みが実行されない分岐にあることもあるので warning。
168
174
  DelegatedCurrentTarget: "wcs/delegated-current-target",
175
+ // `<form data-wcs="onsubmit: login">` の `#prevent` 忘れ(ハンドラも preventDefault を呼ばない)。ブラウザが
176
+ // フォームも送る — ページが読み直されるか、router があれば GET が欄(パスワードも)を URL と履歴に載せる
177
+ // (docs/seam-apps.md、router-auth)。warning(action 付きのフォームと、読めないハンドラでは黙る)。
178
+ SubmitWithoutPrevent: "wcs/submit-without-prevent",
169
179
  // 4.0 で外れた API の旧名(`this.$trackDependency` → `$dependOn`、`$untrackDependency` → `$untracked`)。
170
180
  // ランタイムは読んだ時点で同じ code(#1701)で throw するので error。3.x(3.2〜3.3)では「動くが 4.0 で
171
181
  // 外れる」info だった。フィルタの旧名(`uc` など)は 4.0 のランタイムと同じく `wcs/filter-unknown` で、
@@ -213,7 +223,8 @@ var WcsDiagnosticCode = {
213
223
  // (error 昇格時は packages/lint/scripts/smoke-test.mjs の対ケース更新が必須)。
214
224
  AriaAttrUnknown: "wcs/aria-attr-unknown",
215
225
  // --- document-level load configuration ---
216
- // @wcstack/state/auto より後に他 wcstack /auto が読まれている。
226
+ // @wcstack/state/auto より後に @wcstack/devtools/auto が読まれている。info: 4.0 は後から付いた DevTools に
227
+ // 既存の束縛を送り直すので、欠けるのは付く前のタイムラインだけ。
217
228
  ScriptOrder: "wcs/script-order",
218
229
  // router/auto があるのに <base href> がない(SPA の basename 誤導出)。
219
230
  BaseHrefMissing: "wcs/base-href-missing",
@@ -223,6 +234,13 @@ var WcsDiagnosticCode = {
223
234
  RouterOutletMisplaced: "wcs/router-outlet-misplaced",
224
235
  // @wcstack/signals と /dom エントリの同一ページ混在(リアクティブコア二重化)。
225
236
  SignalsDualEntry: "wcs/signals-dual-entry",
237
+ // `<wcs-route>`(またはレイアウトのテンプレート)の直下のテキストの `{{ }}`。最初に着いたルートでしか束ねられず、
238
+ // 遷移で入ったルートでは書いたままの文字が出る(router の README「Where route content lives」— docs/seam-apps.md、
239
+ // router-admin)。warning。
240
+ RouteBareMustache: "wcs/route-bare-mustache",
241
+ // 既定の `<slot>` の無いレイアウトのテンプレートに、名前付きスロットの外の中身(入れ子のルート)を渡している。
242
+ // 中身は表示されない。ランタイムも同じ code で警告する(docs/seam-apps.md、router-admin)。warning。
243
+ LayoutSlotMissing: "wcs/layout-slot-missing",
226
244
  // --- deprecations ---
227
245
  // 名前付き State(`<wcs-state name>` / `path@name`)。v2 でマウント(`mount=` と接頭辞付きパス)に
228
246
  // 置き換わる(docs/state-mount-design.md D16)。1.x では warning、v2 では parse error と同時に error。
@@ -821,7 +839,8 @@ var FORMATS_FILTER_NAMES = [
821
839
  "coalesce",
822
840
  "number",
823
841
  "string",
824
- "nullIfEmpty"
842
+ "nullIfEmpty",
843
+ "currency"
825
844
  ];
826
845
  var definitions = /* @__PURE__ */ new Map();
827
846
  function hasFilter(name) {
@@ -1038,6 +1057,8 @@ var codeOf = (id) => {
1038
1057
  return c ? `[wcs/${c}] ` : "";
1039
1058
  };
1040
1059
  var MOVED = ["enableMustache", "sameValueGuard", "enableDirectionalInitialSync"];
1060
+ var was = (v) => v == null ? String(v) : v instanceof Date ? "a Date" : Array.isArray(v) ? "an array" : typeof v === "string" ? `a string (${JSON.stringify(v.length > 32 ? v.slice(0, 32) + "\u2026" : v)})` : typeof v === "object" ? "an object" : `a ${typeof v} (${String(v)})`;
1061
+ var NAMESPACES = ["", "", "class.", "attr.", "style."];
1041
1062
  var element = (tag, at2) => `<${tag}${at2.map((a, i) => i % 2 ? `="${a}"` : ` ${a}`).join("")}>`;
1042
1063
  var CSP_GUIDE = "https://github.com/wcstack/wcstack/blob/main/docs/csp.md";
1043
1064
  var SENTENCES = {
@@ -1089,10 +1110,11 @@ var SENTENCES = {
1089
1110
  41
1090
1111
  /* RenderChain */
1091
1112
  ]: () => `render chain depth limit exceeded (${MAX_RENDER_CHAIN} drains that rendering itself started); bindings for this batch were not applied.`,
1113
+ // (named as written — `textContent: iso`, `class.active: x` — when the binding has a member; else its type)
1092
1114
  [
1093
1115
  12
1094
1116
  /* BindingFailed */
1095
- ]: (type, p) => `binding "${type}: ${p}" failed to apply.`,
1117
+ ]: (type, p, name, kind) => `binding "${name ? (NAMESPACES[kind] ?? "") + name : type}: ${p}" failed to apply.`,
1096
1118
  [
1097
1119
  13
1098
1120
  /* LoadFailed */
@@ -1164,11 +1186,19 @@ var SENTENCES = {
1164
1186
  [
1165
1187
  28
1166
1188
  /* FilterValueNotNumber */
1167
- ]: (fn) => `filter ${fn} requires a number value`,
1189
+ ]: (fn, v) => `filter ${fn} requires a number value, not ${was(v)}${typeof v === "string" ? ` \u2014 put |number before |${fn}, or convert it where it is read` : ""}`,
1168
1190
  [
1169
1191
  29
1170
1192
  /* FilterValueNotDate */
1171
- ]: (fn) => `filter ${fn} requires a date value`,
1193
+ ]: (fn, v) => `filter ${fn} requires a date value (a Date), not ${was(v)}${typeof v === "string" || typeof v === "number" ? " \u2014 make the Date where it is read: a getter returning new Date(\u2026)" : ""}`,
1194
+ [
1195
+ 52
1196
+ /* FilterStyleInvalid */
1197
+ ]: (fn, v) => `filter ${fn} takes a style of full, long, medium or short, not "${v}"`,
1198
+ [
1199
+ 53
1200
+ /* FilterCurrencyInvalid */
1201
+ ]: (v) => `filter currency takes an ISO 4217 currency code (JPY, USD, EUR), not "${v}"`,
1172
1202
  [
1173
1203
  30
1174
1204
  /* FilterValueNotArray */
@@ -2033,6 +2063,61 @@ function extractAttribute(tagContent, attrName) {
2033
2063
  if (!match) return null;
2034
2064
  return match[1] ?? match[2] ?? match[3] ?? null;
2035
2065
  }
2066
+ var IGNORE_VOID_ELEMENTS = /* @__PURE__ */ new Set([
2067
+ "area",
2068
+ "base",
2069
+ "br",
2070
+ "col",
2071
+ "embed",
2072
+ "hr",
2073
+ "img",
2074
+ "input",
2075
+ "link",
2076
+ "meta",
2077
+ "param",
2078
+ "source",
2079
+ "track",
2080
+ "wbr"
2081
+ ]);
2082
+ function findIgnoredRanges(html, bindAttribute) {
2083
+ const marker = asciiLowerCase(`${bindAttribute}-ignore`);
2084
+ const lower2 = asciiLowerCase(html);
2085
+ if (!lower2.includes(marker)) return [];
2086
+ const out = [];
2087
+ const stack = [];
2088
+ const tag = /<!--[\s\S]*?(?:-->|$)|<(\/?)([a-zA-Z][^\s/>]*)((?:[^>"']|"[^"]*"|'[^']*')*)>/g;
2089
+ let match;
2090
+ while ((match = tag.exec(html)) !== null) {
2091
+ if (match[2] === void 0) continue;
2092
+ const name = asciiLowerCase(match[2]);
2093
+ const end = match.index + match[0].length;
2094
+ if (match[1] === "/") {
2095
+ for (let i = stack.length - 1; i >= 0; i--) {
2096
+ if (stack[i].name !== name) continue;
2097
+ for (const open of stack.slice(i)) if (open.start !== null) out.push([open.start, end]);
2098
+ stack.length = i;
2099
+ break;
2100
+ }
2101
+ continue;
2102
+ }
2103
+ const ignored = parseAttributeNames(match[3]).has(marker) ? match.index : null;
2104
+ if (IGNORE_VOID_ELEMENTS.has(name)) {
2105
+ if (ignored !== null) out.push([ignored, end]);
2106
+ continue;
2107
+ }
2108
+ if (RAW_TEXT_ELEMENTS.has(name)) {
2109
+ const close = name === "plaintext" ? -1 : lower2.indexOf(`</${name}`, end);
2110
+ const closeEnd = close === -1 ? html.length : html.indexOf(">", close) + 1 || html.length;
2111
+ if (ignored !== null) out.push([ignored, closeEnd]);
2112
+ if (close === -1) break;
2113
+ tag.lastIndex = closeEnd;
2114
+ continue;
2115
+ }
2116
+ stack.push({ name, start: ignored });
2117
+ }
2118
+ for (const open of stack) if (open.start !== null) out.push([open.start, html.length]);
2119
+ return out;
2120
+ }
2036
2121
 
2037
2122
  // src/core/parser/quoteAware.ts
2038
2123
  var isQuote = (c) => c === "'" || c === '"';
@@ -2108,11 +2193,17 @@ function optionsRequired(fnName) {
2108
2193
  function optionMustBeNumber(fnName) {
2109
2194
  raise2(27, [fnName]);
2110
2195
  }
2111
- function valueMustBeNumber(fnName) {
2112
- raise2(28, [fnName]);
2196
+ function styleInvalid(fnName, value) {
2197
+ raise2(52, [fnName, value]);
2198
+ }
2199
+ function currencyInvalid(value) {
2200
+ raise2(53, [value]);
2113
2201
  }
2114
- function valueMustBeDate(fnName) {
2115
- raise2(29, [fnName]);
2202
+ function valueMustBeNumber(fnName, value) {
2203
+ raise2(28, [fnName, value]);
2204
+ }
2205
+ function valueMustBeDate(fnName, value) {
2206
+ raise2(29, [fnName, value]);
2116
2207
  }
2117
2208
  function valueMustBeArray(fnName) {
2118
2209
  raise2(30, [fnName]);
@@ -2179,7 +2270,7 @@ var numeric = (name, op) => ({
2179
2270
  const opt = requiredNumberOption(options, 0, name);
2180
2271
  return (value) => {
2181
2272
  if (typeof value !== "number") {
2182
- valueMustBeNumber(name);
2273
+ valueMustBeNumber(name, value);
2183
2274
  }
2184
2275
  return op(value, opt);
2185
2276
  };
@@ -2209,7 +2300,7 @@ var toFixed = (options) => {
2209
2300
  const opt = numberOption(options?.[0] ?? "0", "toFixed");
2210
2301
  return (value) => {
2211
2302
  if (typeof value !== "number") {
2212
- valueMustBeNumber("toFixed");
2303
+ valueMustBeNumber("toFixed", value);
2213
2304
  }
2214
2305
  return value.toFixed(opt);
2215
2306
  };
@@ -2218,7 +2309,7 @@ var round = (options) => {
2218
2309
  const optValue = Math.pow(10, numberOption(options?.[0] ?? "0", "round"));
2219
2310
  return (value) => {
2220
2311
  if (typeof value !== "number") {
2221
- valueMustBeNumber("round");
2312
+ valueMustBeNumber("round", value);
2222
2313
  }
2223
2314
  return Math.round(value * optValue) / optValue;
2224
2315
  };
@@ -2227,7 +2318,7 @@ var floor = (options) => {
2227
2318
  const optValue = Math.pow(10, numberOption(options?.[0] ?? "0", "floor"));
2228
2319
  return (value) => {
2229
2320
  if (typeof value !== "number") {
2230
- valueMustBeNumber("floor");
2321
+ valueMustBeNumber("floor", value);
2231
2322
  }
2232
2323
  return Math.floor(value * optValue) / optValue;
2233
2324
  };
@@ -2236,7 +2327,7 @@ var ceil = (options) => {
2236
2327
  const optValue = Math.pow(10, numberOption(options?.[0] ?? "0", "ceil"));
2237
2328
  return (value) => {
2238
2329
  if (typeof value !== "number") {
2239
- valueMustBeNumber("ceil");
2330
+ valueMustBeNumber("ceil", value);
2240
2331
  }
2241
2332
  return Math.ceil(value * optValue) / optValue;
2242
2333
  };
@@ -2245,7 +2336,7 @@ var percent = (options) => {
2245
2336
  const opt = numberOption(options?.[0] ?? "0", "percent");
2246
2337
  return (value) => {
2247
2338
  if (typeof value !== "number") {
2248
- valueMustBeNumber("percent");
2339
+ valueMustBeNumber("percent", value);
2249
2340
  }
2250
2341
  return `${(value * 100).toFixed(opt)}%`;
2251
2342
  };
@@ -2272,11 +2363,29 @@ var locale = (options) => {
2272
2363
  const explicit = options?.[0];
2273
2364
  return (value) => {
2274
2365
  if (typeof value !== "number") {
2275
- valueMustBeNumber("locale");
2366
+ valueMustBeNumber("locale", value);
2276
2367
  }
2277
2368
  return value.toLocaleString(explicit ?? defaultLocale());
2278
2369
  };
2279
2370
  };
2371
+ var currency = (options) => {
2372
+ const code = options?.[0] ?? optionsRequired("currency");
2373
+ const explicit = options?.[1];
2374
+ const format = { style: "currency", currency: code };
2375
+ try {
2376
+ new Intl.NumberFormat("en", format);
2377
+ const known = Intl.supportedValuesOf?.("currency");
2378
+ if (known && !known.includes(code.toUpperCase())) throw 0;
2379
+ } catch {
2380
+ currencyInvalid(code);
2381
+ }
2382
+ return (value) => {
2383
+ if (typeof value !== "number") {
2384
+ valueMustBeNumber("currency", value);
2385
+ }
2386
+ return value.toLocaleString(explicit ?? defaultLocale(), format);
2387
+ };
2388
+ };
2280
2389
  var upper = () => (value) => String(value).toUpperCase();
2281
2390
  var lower = () => (value) => String(value).toLowerCase();
2282
2391
  var capitalize = () => (value) => {
@@ -2333,38 +2442,48 @@ var join = (options) => {
2333
2442
  return value.join(opt);
2334
2443
  };
2335
2444
  };
2445
+ var STYLES = ["full", "long", "medium", "short"];
2446
+ function dateOptions(options, fn) {
2447
+ let [loc, style] = options ?? [];
2448
+ if (style === void 0 && loc !== void 0 && STYLES.includes(loc)) [loc, style] = [void 0, loc];
2449
+ if (style !== void 0 && !STYLES.includes(style)) styleInvalid(fn, style);
2450
+ return [loc, style];
2451
+ }
2336
2452
  var date = (options) => {
2337
- const explicit = options?.[0];
2453
+ const [explicit, style] = dateOptions(options, "date");
2454
+ const format = style && { dateStyle: style };
2338
2455
  return (value) => {
2339
2456
  if (!(value instanceof Date)) {
2340
- valueMustBeDate("date");
2457
+ valueMustBeDate("date", value);
2341
2458
  }
2342
- return value.toLocaleDateString(explicit ?? defaultLocale());
2459
+ return value.toLocaleDateString(explicit ?? defaultLocale(), format);
2343
2460
  };
2344
2461
  };
2345
2462
  var time = (options) => {
2346
- const explicit = options?.[0];
2463
+ const [explicit, style] = dateOptions(options, "time");
2464
+ const format = style && { timeStyle: style };
2347
2465
  return (value) => {
2348
2466
  if (!(value instanceof Date)) {
2349
- valueMustBeDate("time");
2467
+ valueMustBeDate("time", value);
2350
2468
  }
2351
- return value.toLocaleTimeString(explicit ?? defaultLocale());
2469
+ return value.toLocaleTimeString(explicit ?? defaultLocale(), format);
2352
2470
  };
2353
2471
  };
2354
2472
  var datetime = (options) => {
2355
- const explicit = options?.[0];
2473
+ const [explicit, style] = dateOptions(options, "datetime");
2474
+ const format = style && { dateStyle: style, timeStyle: style };
2356
2475
  return (value) => {
2357
2476
  if (!(value instanceof Date)) {
2358
- valueMustBeDate("datetime");
2477
+ valueMustBeDate("datetime", value);
2359
2478
  }
2360
- return value.toLocaleString(explicit ?? defaultLocale());
2479
+ return value.toLocaleString(explicit ?? defaultLocale(), format);
2361
2480
  };
2362
2481
  };
2363
2482
  var ymd = (options) => {
2364
2483
  const opt = options?.[0] ?? "-";
2365
2484
  return (value) => {
2366
2485
  if (!(value instanceof Date)) {
2367
- valueMustBeDate("ymd");
2486
+ valueMustBeDate("ymd", value);
2368
2487
  }
2369
2488
  const year = value.getFullYear().toString();
2370
2489
  const month = (value.getMonth() + 1).toString().padStart(2, "0");
@@ -2376,7 +2495,7 @@ var hms = (options) => {
2376
2495
  const opt = options?.[0] ?? ":";
2377
2496
  return (value) => {
2378
2497
  if (!(value instanceof Date)) {
2379
- valueMustBeDate("hms");
2498
+ valueMustBeDate("hms", value);
2380
2499
  }
2381
2500
  const hours = value.getHours().toString().padStart(2, "0");
2382
2501
  const minutes = value.getMinutes().toString().padStart(2, "0");
@@ -2386,7 +2505,7 @@ var hms = (options) => {
2386
2505
  };
2387
2506
  var abs = () => (value) => {
2388
2507
  if (typeof value !== "number") {
2389
- valueMustBeNumber("abs");
2508
+ valueMustBeNumber("abs", value);
2390
2509
  }
2391
2510
  return Math.abs(value);
2392
2511
  };
@@ -2395,7 +2514,7 @@ var clamp = (options) => {
2395
2514
  const max = requiredNumberOption(options, 1, "clamp");
2396
2515
  return (value) => {
2397
2516
  if (typeof value !== "number") {
2398
- valueMustBeNumber("clamp");
2517
+ valueMustBeNumber("clamp", value);
2399
2518
  }
2400
2519
  return Math.min(Math.max(value, min), max);
2401
2520
  };
@@ -2442,10 +2561,10 @@ var registered = {
2442
2561
  ceil: { factory: ceil, arity: [0, 1] },
2443
2562
  percent: { factory: percent, arity: [0, 1] },
2444
2563
  unit: { factory: nullishPassthrough(unit), arity: [1, 1] },
2445
- // The locale-dependent three take a locale like `locale` does (`date(ja-JP)`)
2446
- date: { factory: date, arity: [0, 1] },
2447
- time: { factory: time, arity: [0, 1] },
2448
- datetime: { factory: datetime, arity: [0, 1] },
2564
+ // The locale-dependent three take a locale like `locale` does (`date(ja-JP)`), and a style (`date(ja-JP,long)`)
2565
+ date: { factory: date, arity: [0, 2] },
2566
+ time: { factory: time, arity: [0, 2] },
2567
+ datetime: { factory: datetime, arity: [0, 2] },
2449
2568
  ymd: { factory: ymd, arity: [0, 1] },
2450
2569
  hms: { factory: hms, arity: [0, 1] },
2451
2570
  // the core set of 4.0.0-rc.3 (the core's own: eq ne not lt le gt ge falsy truthy boolean)
@@ -2472,7 +2591,9 @@ var registered = {
2472
2591
  boolean: boolean2,
2473
2592
  number: { factory: number, arity: [0, 0] },
2474
2593
  string: { factory: string, arity: [0, 0] },
2475
- nullIfEmpty: { factory: nullIfEmpty, arity: [0, 0] }
2594
+ nullIfEmpty: { factory: nullIfEmpty, arity: [0, 0] },
2595
+ // (added in 4.2: last, so the order of the others is unchanged)
2596
+ currency: { factory: currency, arity: [1, 2] }
2476
2597
  };
2477
2598
  var formatFilters = /* @__PURE__ */ Object.fromEntries(
2478
2599
  /* @__PURE__ */ Object.entries(registered).filter(([name]) => !(name in coreFilters))
@@ -2504,10 +2625,11 @@ var builtinFilterMeta = {
2504
2625
  // `not` は真偽性(truthy / falsy)の反転。`if:` が `Boolean()` で寄せるのと同じ規則で、
2505
2626
  // `else:` はこのフィルタを足した束縛として組み立てられる(structural/createNotFilter.ts)
2506
2627
  not: { description: "\u771F\u507D\u6027\u3092\u53CD\u8EE2\uFF08falsy \u2192 true\uFF09", hasArgs: false, resultType: "boolean", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
2507
- lt: { description: "\u3088\u308A\u5C0F\u3055\u3044\u304B", hasArgs: true, resultType: "boolean", acceptTypes: ["number", "string"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
2508
- le: { description: "\u4EE5\u4E0B\u304B", hasArgs: true, resultType: "boolean", acceptTypes: ["number", "string"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
2509
- gt: { description: "\u3088\u308A\u5927\u304D\u3044\u304B", hasArgs: true, resultType: "boolean", acceptTypes: ["number", "string"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
2510
- ge: { description: "\u4EE5\u4E0A\u304B", hasArgs: true, resultType: "boolean", acceptTypes: ["number", "string"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
2628
+ // 比較は数値だけを受ける(filters/core.ts の `numeric` は数値以外の値で #28。3.x も同じで、"string" は誤りだった)
2629
+ lt: { description: "\u3088\u308A\u5C0F\u3055\u3044\u304B", hasArgs: true, resultType: "boolean", acceptTypes: ["number"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
2630
+ le: { description: "\u4EE5\u4E0B\u304B", hasArgs: true, resultType: "boolean", acceptTypes: ["number"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
2631
+ gt: { description: "\u3088\u308A\u5927\u304D\u3044\u304B", hasArgs: true, resultType: "boolean", acceptTypes: ["number"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
2632
+ ge: { description: "\u4EE5\u4E0A\u304B", hasArgs: true, resultType: "boolean", acceptTypes: ["number"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
2511
2633
  // 算術
2512
2634
  add: { description: "\u52A0\u7B97", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
2513
2635
  sub: { description: "\u6E1B\u7B97", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
@@ -2543,10 +2665,11 @@ var builtinFilterMeta = {
2543
2665
  unit: { description: "\u5358\u4F4D\uFF08\u63A5\u5C3E\u8F9E\uFF09\u3092\u4ED8\u52A0", hasArgs: true, resultType: "string", acceptTypes: ["number", "string"], minArgs: 1, maxArgs: 1, argTypes: ["string"] },
2544
2666
  // 日付・時刻
2545
2667
  // `locale` と同じくロケールを 1 つ受ける(`date(ja-JP)`)。実装は最初からこれを読んでいたが、
2546
- // メタデータ側が maxArgs: 0 だったため lint と補完が正しい書き方を誤りとして報告していた
2547
- date: { description: "\u30ED\u30B1\u30FC\u30EB\u5F62\u5F0F\u306E\u65E5\u4ED8 ([locale]\u3002\u65E2\u5B9A\u306F config.locale)", hasArgs: true, resultType: "string", acceptTypes: "any", minArgs: 0, maxArgs: 1, argTypes: ["string"] },
2548
- time: { description: "\u30ED\u30B1\u30FC\u30EB\u5F62\u5F0F\u306E\u6642\u523B ([locale]\u3002\u65E2\u5B9A\u306F config.locale)", hasArgs: true, resultType: "string", acceptTypes: "any", minArgs: 0, maxArgs: 1, argTypes: ["string"] },
2549
- datetime: { description: "\u30ED\u30B1\u30FC\u30EB\u5F62\u5F0F\u306E\u65E5\u6642 ([locale]\u3002\u65E2\u5B9A\u306F config.locale)", hasArgs: true, resultType: "string", acceptTypes: "any", minArgs: 0, maxArgs: 1, argTypes: ["string"] },
2668
+ // メタデータ側が maxArgs: 0 だったため lint と補完が正しい書き方を誤りとして報告していた。
2669
+ // 4.2: 2 つ目は書式(full / long / medium / short — Intl の dateStyle / timeStyle)。書式だけなら既定のロケール
2670
+ date: { description: "\u30ED\u30B1\u30FC\u30EB\u5F62\u5F0F\u306E\u65E5\u4ED8 ([locale][, style]\u3002style \u306F full / long / medium / short\u3001\u65E2\u5B9A\u306E\u30ED\u30B1\u30FC\u30EB\u306F config.locale)", hasArgs: true, resultType: "string", acceptTypes: "any", minArgs: 0, maxArgs: 2, argTypes: ["string", "string"] },
2671
+ time: { description: "\u30ED\u30B1\u30FC\u30EB\u5F62\u5F0F\u306E\u6642\u523B ([locale][, style]\u3002style \u306F full / long / medium / short\u3001\u65E2\u5B9A\u306E\u30ED\u30B1\u30FC\u30EB\u306F config.locale)", hasArgs: true, resultType: "string", acceptTypes: "any", minArgs: 0, maxArgs: 2, argTypes: ["string", "string"] },
2672
+ datetime: { description: "\u30ED\u30B1\u30FC\u30EB\u5F62\u5F0F\u306E\u65E5\u6642 ([locale][, style]\u3002style \u306F full / long / medium / short\u3001\u65E2\u5B9A\u306E\u30ED\u30B1\u30FC\u30EB\u306F config.locale)", hasArgs: true, resultType: "string", acceptTypes: "any", minArgs: 0, maxArgs: 2, argTypes: ["string", "string"] },
2550
2673
  ymd: { description: "YYYY-MM-DD \u5F62\u5F0F ([separator]\u3002\u65E2\u5B9A\u306F -)", hasArgs: true, resultType: "string", acceptTypes: "any", minArgs: 0, maxArgs: 1, argTypes: ["string"] },
2551
2674
  hms: { description: "HH:MM:SS \u5F62\u5F0F ([separator]\u3002\u65E2\u5B9A\u306F :)", hasArgs: true, resultType: "string", acceptTypes: "any", minArgs: 0, maxArgs: 1, argTypes: ["string"] },
2552
2675
  // 真偽値・変換
@@ -2557,7 +2680,9 @@ var builtinFilterMeta = {
2557
2680
  boolean: { description: "\u30D6\u30FC\u30EB\u5024\u306B\u5909\u63DB", hasArgs: false, resultType: "boolean", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
2558
2681
  number: { description: "\u6570\u5024\u306B\u5909\u63DB", hasArgs: false, resultType: "number", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
2559
2682
  string: { description: "\u6587\u5B57\u5217\u306B\u5909\u63DB", hasArgs: false, resultType: "string", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
2560
- nullIfEmpty: { description: "\u7A7A\u6587\u5B57\u5217\u3092null\u306B\u5909\u63DB", hasArgs: false, resultType: "passthrough", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 }
2683
+ nullIfEmpty: { description: "\u7A7A\u6587\u5B57\u5217\u3092null\u306B\u5909\u63DB", hasArgs: false, resultType: "passthrough", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 },
2684
+ // 4.2(formats の最後に登録)
2685
+ currency: { description: "\u901A\u8CA8\u306E\u66F8\u5F0F (code[, locale]\u3002code \u306F ISO 4217 \u2014 JPY / USD / EUR\u3001\u65E2\u5B9A\u306E\u30ED\u30B1\u30FC\u30EB\u306F config.locale)", hasArgs: true, resultType: "string", acceptTypes: ["number"], minArgs: 1, maxArgs: 2, argTypes: ["string", "string"] }
2561
2686
  };
2562
2687
  var WCS_MANIFEST_VERSION = 2;
2563
2688
  var builtinFilterAliases = Object.freeze({});
@@ -10943,6 +11068,193 @@ function findOwnThis(text3, kind) {
10943
11068
  forEachChild(root, walk);
10944
11069
  return found;
10945
11070
  }
11071
+ var DESTRUCTIVE_ARRAY_METHODS = /* @__PURE__ */ new Set(["push", "pop", "shift", "unshift", "splice", "sort", "reverse", "fill", "copyWithin"]);
11072
+ function memberChain(node, source) {
11073
+ const segments = [];
11074
+ let cur = unwrapChain(node);
11075
+ while (cur.type === "MemberExpression") {
11076
+ const property = cur.property;
11077
+ let name = null;
11078
+ if (!cur.computed && property.type === "Identifier") name = property.name;
11079
+ else if (property.type === "Literal" && (typeof property.value === "string" || typeof property.value === "number")) name = String(property.value);
11080
+ segments.unshift({ name, raw: source(property), computed: cur.computed });
11081
+ cur = unwrapChain(cur.object);
11082
+ }
11083
+ return { base: cur, segments };
11084
+ }
11085
+ function assignTarget(root, segments) {
11086
+ if (segments.every((s) => s.name !== null)) {
11087
+ const path = segments.map((s) => s.name).join(".");
11088
+ return segments.length === 1 && /^[A-Za-z_$][\w$]*$/.test(path) ? `${root}.${path}` : `${root}["${path}"]`;
11089
+ }
11090
+ return `${root}[\`${segments.map((s) => s.name ?? `\${${s.raw}}`).join(".")}\`]`;
11091
+ }
11092
+ function findInPlaceChanges(text3, kind, root) {
11093
+ const prefix = kind === "body" ? PREFIX : VALUE_PREFIX;
11094
+ let program;
11095
+ try {
11096
+ program = parse3(prefix + text3 + (kind === "body" ? SUFFIX : VALUE_SUFFIX), { ecmaVersion: "latest", sourceType: "module" });
11097
+ } catch {
11098
+ return [];
11099
+ }
11100
+ const wrapper = unwrapWrapper(program);
11101
+ if (wrapper === null) return [];
11102
+ let body = wrapper.body;
11103
+ if (kind === "value") {
11104
+ const statement = wrapper.body.body.length === 1 ? wrapper.body.body[0] : null;
11105
+ const fn = statement?.type === "ExpressionStatement" ? statement.expression : null;
11106
+ if (fn === null || fn.type !== "FunctionExpression" && fn.type !== "ArrowFunctionExpression") return [];
11107
+ if (root === null) {
11108
+ const first = fn.params[0];
11109
+ if (first === void 0 || first.type !== "Identifier") return [];
11110
+ root = first.name;
11111
+ }
11112
+ body = fn.body;
11113
+ }
11114
+ if (root === null) return [];
11115
+ const stateRoot = root;
11116
+ const shift = prefix.length;
11117
+ const source = (n) => (prefix + text3).slice(n.start, n.end);
11118
+ const isRoot = (n) => stateRoot === "this" ? n.type === "ThisExpression" : n.type === "Identifier" && n.name === stateRoot;
11119
+ const bound = /* @__PURE__ */ new Map();
11120
+ const bind = (name) => {
11121
+ bound.set(name, (bound.get(name) ?? 0) + 1);
11122
+ };
11123
+ const aliases = /* @__PURE__ */ new Map();
11124
+ const collect2 = (node) => {
11125
+ if (isFunctionNode(node)) {
11126
+ if (node.type === "FunctionDeclaration" && node.id !== null) bind(node.id.name);
11127
+ const names = /* @__PURE__ */ new Set();
11128
+ for (const param of node.params) bindingNames(param, names);
11129
+ names.forEach(bind);
11130
+ } else if (node.type === "VariableDeclarator") {
11131
+ const names = /* @__PURE__ */ new Set();
11132
+ bindingNames(node.id, names);
11133
+ names.forEach(bind);
11134
+ const init = node.init ? unwrapChain(node.init) : null;
11135
+ if (init !== null && node.id.type === "Identifier" && init.type === "MemberExpression") {
11136
+ const chain = memberChain(init, source);
11137
+ if (isRoot(chain.base) && chain.segments.length > 0 && !chain.segments[0].name?.startsWith("$")) {
11138
+ aliases.set(node.id.name, { source: source(init), segments: chain.segments });
11139
+ }
11140
+ } else if (init !== null && node.id.type === "ObjectPattern" && isRoot(init)) {
11141
+ for (const property of node.id.properties) {
11142
+ if (property.type !== "Property" || property.computed) continue;
11143
+ const key = property.key.type === "Identifier" ? property.key.name : property.key.type === "Literal" ? String(property.key.value) : null;
11144
+ const value = property.value.type === "AssignmentPattern" ? property.value.left : property.value;
11145
+ if (key === null || key.startsWith("$") || value.type !== "Identifier") continue;
11146
+ const segment = { name: key, raw: key, computed: false };
11147
+ aliases.set(value.name, { source: `${stateRoot}.${key}`, segments: [segment] });
11148
+ }
11149
+ }
11150
+ } else if (node.type === "CatchClause" && node.param) {
11151
+ const names = /* @__PURE__ */ new Set();
11152
+ bindingNames(node.param, names);
11153
+ names.forEach(bind);
11154
+ } else if (node.type === "ClassDeclaration" && node.id !== null) {
11155
+ bind(node.id.name);
11156
+ } else if (node.type === "AssignmentExpression" && node.left.type === "Identifier") {
11157
+ bind(node.left.name);
11158
+ }
11159
+ forEachChild(node, collect2);
11160
+ };
11161
+ collect2(body);
11162
+ const alias = (name) => bound.get(name) === 1 ? aliases.get(name) : void 0;
11163
+ const out = [];
11164
+ const report = (target, at2, form, directMin) => {
11165
+ const chain = memberChain(target, source);
11166
+ const base = chain.base;
11167
+ const range = { start: at2.start - shift, end: at2.end - shift };
11168
+ const pick = (segments) => form ?? (segments.length > 0 && segments.every((s) => s.computed) ? "index" : "property");
11169
+ if (base.type === "Identifier" && base.name !== stateRoot) {
11170
+ const a = alias(base.name);
11171
+ if (a === void 0) return;
11172
+ out.push({ form: pick(chain.segments), alias: base.name, source: a.source, target: assignTarget(stateRoot, a.segments), ...range });
11173
+ return;
11174
+ }
11175
+ if (!isRoot(base) || chain.segments.length < directMin || chain.segments[0].name?.startsWith("$")) return;
11176
+ out.push({ form: pick(chain.segments.slice(1)), alias: null, source: source(at2), target: assignTarget(stateRoot, chain.segments), ...range });
11177
+ };
11178
+ const direct = stateRoot === "this" ? Infinity : 2;
11179
+ const visitChanges = (node) => {
11180
+ if (node.type === "AssignmentExpression" && unwrapChain(node.left).type === "MemberExpression") {
11181
+ report(node.left, node.left, null, direct);
11182
+ } else if (node.type === "UpdateExpression" && unwrapChain(node.argument).type === "MemberExpression") {
11183
+ report(node.argument, node.argument, null, direct);
11184
+ } else if (node.type === "UnaryExpression" && node.operator === "delete" && unwrapChain(node.argument).type === "MemberExpression") {
11185
+ report(node.argument, node.argument, "property", direct);
11186
+ } else if (node.type === "CallExpression") {
11187
+ const callee = unwrapChain(node.callee);
11188
+ if (callee.type === "MemberExpression") {
11189
+ const method = !callee.computed && callee.property.type === "Identifier" ? callee.property.name : null;
11190
+ const object = unwrapChain(callee.object);
11191
+ if (method === "assign" && object.type === "Identifier" && object.name === "Object" && node.arguments.length > 0) {
11192
+ const first = node.arguments[0];
11193
+ if (first.type === "Identifier" || unwrapChain(first).type === "MemberExpression") report(first, node, "property", 1);
11194
+ } else if (method !== null && DESTRUCTIVE_ARRAY_METHODS.has(method)) {
11195
+ report(callee.object, node, "method", stateRoot === "this" ? Infinity : 1);
11196
+ }
11197
+ }
11198
+ }
11199
+ forEachChild(node, visitChanges);
11200
+ };
11201
+ visitChanges(body);
11202
+ return out;
11203
+ }
11204
+ var LOCATION_HOLDERS = /* @__PURE__ */ new Set(["window", "document", "globalThis", "self"]);
11205
+ var LOCATION_VARYING = /* @__PURE__ */ new Set(["pathname", "search", "hash", "href"]);
11206
+ function findLocationRead(body) {
11207
+ let program;
11208
+ try {
11209
+ program = parse3(PREFIX + body + SUFFIX, { ecmaVersion: "latest", sourceType: "module" });
11210
+ } catch {
11211
+ return null;
11212
+ }
11213
+ const wrapper = unwrapWrapper(program);
11214
+ if (wrapper === null) return null;
11215
+ const names = /* @__PURE__ */ new Set();
11216
+ const scan = (node) => {
11217
+ if (isFunctionNode(node)) for (const param of node.params) bindingNames(param, names);
11218
+ if (node.type === "VariableDeclarator") bindingNames(node.id, names);
11219
+ forEachChild(node, scan);
11220
+ };
11221
+ scan(wrapper.body);
11222
+ if (names.has("location")) return null;
11223
+ const isLocation = (node) => {
11224
+ const n = unwrapChain(node);
11225
+ if (n.type === "Identifier") return n.name === "location";
11226
+ return n.type === "MemberExpression" && !n.computed && n.property.type === "Identifier" && n.property.name === "location" && n.object.type === "Identifier" && LOCATION_HOLDERS.has(n.object.name);
11227
+ };
11228
+ let found = null;
11229
+ const at2 = (node) => {
11230
+ found = { start: node.start - PREFIX.length, end: node.end - PREFIX.length, text: (PREFIX + body).slice(node.start, node.end) };
11231
+ };
11232
+ const walk = (node) => {
11233
+ if (found !== null) return;
11234
+ if (node.type === "MemberExpression" && isLocation(node.object)) {
11235
+ const part = !node.computed && node.property.type === "Identifier" ? node.property.name : null;
11236
+ if (part === null || LOCATION_VARYING.has(part)) at2(node);
11237
+ return;
11238
+ }
11239
+ if (isLocation(node)) {
11240
+ at2(node);
11241
+ return;
11242
+ }
11243
+ if (node.type === "MemberExpression") {
11244
+ walk(node.object);
11245
+ if (node.computed) walk(node.property);
11246
+ return;
11247
+ }
11248
+ if (node.type === "Property") {
11249
+ if (node.computed) walk(node.key);
11250
+ walk(node.value);
11251
+ return;
11252
+ }
11253
+ forEachChild(node, walk);
11254
+ };
11255
+ walk(wrapper.body);
11256
+ return found;
11257
+ }
10946
11258
 
10947
11259
  // src/core/messages.ts
10948
11260
  function resolveLocale(locale2) {
@@ -10983,6 +11295,8 @@ var ja = {
10983
11295
  getterCycle: (cycle) => `\u30D1\u30B9 getter \u304C\u5FAA\u74B0\u53C2\u7167\u3057\u3066\u3044\u307E\u3059: ${cycle}`,
10984
11296
  updatedCallbackUnbound: (p) => `$renderedCallback \u306F binding \u99C6\u52D5\u3067\u3059\u3002"${p}" \u306F\u3053\u306E\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8\u306E\u3069\u306E\u30D0\u30A4\u30F3\u30C7\u30A3\u30F3\u30B0\u306B\u3082\u73FE\u308C\u306A\u3044\u305F\u3081\u3001\u3053\u306E\u5206\u5C90\u306F\u4E00\u5EA6\u3082\u5B9F\u884C\u3055\u308C\u307E\u305B\u3093\u3002\u63CF\u753B\u306B\u4F9D\u5B58\u305B\u305A\u53CD\u5FDC\u3059\u308B\u306A\u3089 $watch \u3092\u4F7F\u3063\u3066\u304F\u3060\u3055\u3044`,
10985
11297
  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`,
11298
+ 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`,
11299
+ 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`,
10986
11300
  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`,
10987
11301
  handlerFilterNotAllowed: (prop) => `\u30A4\u30D9\u30F3\u30C8\u30CF\u30F3\u30C9\u30E9 "${prop}" \u306B\u30D5\u30A3\u30EB\u30BF\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093`,
10988
11302
  typeExpectation: (label, expected, resultType) => `"${label}" \u306B\u306F${JA_EXPECTED_LABEL[expected]}\u304C\u5FC5\u8981\u3067\u3059\uFF08\u73FE\u5728\u306E\u578B: ${resultType}\uFF09`,
@@ -11002,13 +11316,15 @@ var ja = {
11002
11316
  watchKeyEmptySegment: (k) => `$watch \u306E\u30AD\u30FC "${k}" \u306B\u7A7A\u306E\u30D1\u30B9\u30BB\u30B0\u30E1\u30F3\u30C8\u304C\u3042\u308A\u307E\u3059`,
11003
11317
  watchHandlerNotFunction: (k) => `$watch \u306E\u30A8\u30F3\u30C8\u30EA "${k}" \u306E\u5024\u306F\u95A2\u6570\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059`,
11004
11318
  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`,
11005
- 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`,
11319
+ 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`,
11006
11320
  typeAnnotationIncompatible: (vt, rt) => `\u578B "${vt}" \u306F @type {${rt}} \u3068\u4E92\u63DB\u6027\u304C\u3042\u308A\u307E\u305B\u3093`,
11007
11321
  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`,
11008
11322
  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`,
11009
- 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`,
11323
+ 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`,
11324
+ 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`,
11325
+ 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`,
11010
11326
  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`,
11011
- 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`,
11327
+ 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" : ""}`,
11012
11328
  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`,
11013
11329
  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`,
11014
11330
  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`,
@@ -11038,22 +11354,27 @@ var ja = {
11038
11354
  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`,
11039
11355
  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`,
11040
11356
  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`,
11041
- 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`,
11357
+ 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`,
11042
11358
  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`,
11043
11359
  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`,
11044
11360
  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`,
11361
+ signalsImportMapBoth: () => `\u3053\u306E import map \u306F @wcstack/signals \u3068 @wcstack/signals/dom \u306E\u4E21\u65B9\u3092\u5272\u308A\u5F53\u3066\u3066\u3044\u307E\u3059\u3002CDN \u3067\u306F\u5404\u30A8\u30F3\u30C8\u30EA\u304C\u30EA\u30A2\u30AF\u30C6\u30A3\u30D6\u30B3\u30A2\u3092\u6301\u3064\u306E\u3067\u3001@wcstack/signals \u3092 import \u3059\u308B\u30E2\u30B8\u30E5\u30FC\u30EB\uFF08\u3053\u306E\u30DA\u30FC\u30B8\u306E\u3082\u306E\u3067\u3082\u3001\u8AAD\u307F\u8FBC\u3080 .js \u3067\u3082\uFF09\u304C 2 \u3064\u76EE\u306E\u30B3\u30A2\u3092\u6301\u3061\u3001\u5883\u754C\u3067\u53CD\u5FDC\u304C\u58CA\u308C\u307E\u3059\u3002@wcstack/signals/dom \u3060\u3051\u3092\u5272\u308A\u5F53\u3066\u3066\u304F\u3060\u3055\u3044\uFF08\u30B3\u30A2\u306E\u5168\u90E8\u3092 export \u3057\u307E\u3059\uFF09`,
11362
+ routeBareMustache: (inLayout) => inLayout ? `\u30EC\u30A4\u30A2\u30A6\u30C8\u306E\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u306E\u76F4\u4E0B\u306E\u30C6\u30AD\u30B9\u30C8\u306E {{ }} \u306F\u3001\u9077\u79FB\u3067\u306F\u675F\u306D\u3089\u308C\u307E\u305B\u3093 \u2014 \u8981\u7D20\u3067\u5305\u3093\u3067\u304F\u3060\u3055\u3044\uFF08<span>{{ \u2026 }}</span>\uFF09` : `<wcs-route> \u306E\u76F4\u4E0B\u306E\u30C6\u30AD\u30B9\u30C8\u306E {{ }} \u306F\u3001\u6700\u521D\u306B\u7740\u3044\u305F\u30EB\u30FC\u30C8\u3067\u3057\u304B\u675F\u306D\u3089\u308C\u307E\u305B\u3093\u3002\u9077\u79FB\u3067\u5165\u3063\u305F\u30EB\u30FC\u30C8\u3067\u306F\u66F8\u3044\u305F\u307E\u307E\u306E\u6587\u5B57\u304C\u51FA\u307E\u3059 \u2014 \u8981\u7D20\u3067\u5305\u3093\u3067\u304F\u3060\u3055\u3044\uFF08<h1>{{ \u2026 }}</h1>\uFF09`,
11363
+ layoutSlotMissing: (l) => `\u30EC\u30A4\u30A2\u30A6\u30C8 "${l}" \u306E\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u306B\u65E2\u5B9A\u306E <slot>\uFF08name \u306E\u7121\u3044\u3082\u306E\uFF09\u304C\u3042\u308A\u307E\u305B\u3093\u3002\u3053\u306E <wcs-layout> \u306E\u540D\u524D\u4ED8\u304D\u30B9\u30ED\u30C3\u30C8\u306E\u5916\u306E\u4E2D\u8EAB\uFF08\u5165\u308C\u5B50\u306E\u30EB\u30FC\u30C8\u3068\u305D\u306E\u30DA\u30FC\u30B8\uFF09\u306F\u8868\u793A\u3055\u308C\u307E\u305B\u3093 \u2014 \u30DA\u30FC\u30B8\u3092\u7F6E\u304F\u5834\u6240\u306B <slot></slot> \u3092\u66F8\u3044\u3066\u304F\u3060\u3055\u3044`,
11045
11364
  namedStateAttrDeprecated: (name) => `name \u5C5E\u6027\u306F v2 \u3067\u64A4\u53BB\u3055\u308C\u307E\u3057\u305F\uFF081 root 1 \u30C4\u30EA\u30FC\uFF09\u3002\u30EB\u30FC\u30C8\u30C4\u30EA\u30FC\u3078\u306E\u30DE\u30A6\u30F3\u30C8 <wcs-state mount="${name}"> \u306B\u7F6E\u304D\u63DB\u3048\u3001\u30D1\u30B9\u306F "${name}.<path>" \u3067\u53C2\u7167\u3057\u3066\u304F\u3060\u3055\u3044\uFF08docs/state-mount-design.md \xA79\uFF09`,
11046
11365
  namedStatePathDeprecated: (name) => name === "default" ? `"@default" \u30BB\u30EC\u30AF\u30BF\u306F v2 \u3067\u64A4\u53BB\u3055\u308C\u307E\u3057\u305F\u3002"@default" \u3092\u5916\u3057\u3066\u304F\u3060\u3055\u3044\uFF08docs/state-mount-design.md \xA79\uFF09` : `"@name" \u30BB\u30EC\u30AF\u30BF\u306F v2 \u3067\u64A4\u53BB\u3055\u308C\u307E\u3057\u305F\uFF081 root 1 \u30C4\u30EA\u30FC\uFF09\u3002\u30DE\u30A6\u30F3\u30C8\u3057\u305F\u30C4\u30EA\u30FC\u3092 "${name}.<path>" \u3067\u53C2\u7167\u3057\u3066\u304F\u3060\u3055\u3044\uFF08docs/state-mount-design.md \xA79\uFF09`,
11047
11366
  mountPathInvalid: (problem, mountPath) => {
11048
11367
  switch (problem) {
11049
11368
  case "empty":
11050
- 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`;
11369
+ 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`;
11051
11370
  case "emptySegment":
11052
- return `"mount" \u30D1\u30B9 "${mountPath}" \u306B\u7A7A\u306E\u30BB\u30B0\u30E1\u30F3\u30C8\u304C\u3042\u308A\u307E\u3059\uFF08runtime: has an empty segment.\uFF09`;
11371
+ 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`;
11053
11372
  case "wildcard":
11054
- 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`;
11373
+ 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`;
11374
+ case "whitespace":
11375
+ 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`;
11055
11376
  default:
11056
- 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`;
11377
+ 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`;
11057
11378
  }
11058
11379
  },
11059
11380
  recursionUnsupported: (p, where) => {
@@ -11075,7 +11396,7 @@ var ja = {
11075
11396
  case "listKeys":
11076
11397
  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`;
11077
11398
  default:
11078
- 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`;
11399
+ 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`;
11079
11400
  }
11080
11401
  },
11081
11402
  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`,
@@ -11175,6 +11496,8 @@ var en = {
11175
11496
  getterCycle: (cycle) => `Path getters form a dependency cycle: ${cycle}`,
11176
11497
  updatedCallbackUnbound: (p) => `$renderedCallback is binding-driven. "${p}" is not bound anywhere in this document, so this branch never runs. Use $watch to react without depending on what is rendered`,
11177
11498
  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`,
11499
+ 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`,
11500
+ 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`,
11178
11501
  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`,
11179
11502
  handlerFilterNotAllowed: (prop) => `Filters cannot be applied to event handler "${prop}"`,
11180
11503
  typeExpectation: (label, expected, resultType) => `"${label}" requires ${EN_EXPECTED_LABEL[expected]} (current type: ${resultType})`,
@@ -11194,13 +11517,15 @@ var en = {
11194
11517
  watchKeyEmptySegment: (k) => `$watch key "${k}" has an empty path segment`,
11195
11518
  watchHandlerNotFunction: (k) => `The value of $watch entry "${k}" must be a function`,
11196
11519
  watchPathMissing: (k) => `$watch key "${k}" does not exist in the state definition (it will never fire)`,
11197
- 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`,
11520
+ 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`,
11198
11521
  typeAnnotationIncompatible: (vt, rt) => `Type "${vt}" is not compatible with @type {${rt}}`,
11199
11522
  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}).`,
11200
11523
  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.`,
11201
- tagMemberUnknown: (prop, tag) => `"${prop}" is not a wcBindable member of <${tag}> (bindings to unknown members are silently ignored)`,
11524
+ 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 })`,
11525
+ 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}`,
11526
+ 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)`,
11202
11527
  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}"`,
11203
- 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`,
11528
+ 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)" : ""}`,
11204
11529
  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}"`,
11205
11530
  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`,
11206
11531
  behaviorNotObject: (keys) => `$behavior must be an object { ${keys.map((k) => `${k}?`).join(", ")} } (the runtime throws at load time)`,
@@ -11230,22 +11555,27 @@ var en = {
11230
11555
  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}\`)`,
11231
11556
  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`,
11232
11557
  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`,
11233
- devtoolsAfterState: () => `Load @wcstack/devtools/auto BEFORE @wcstack/state/auto (otherwise the wiring ledger is not captured live)`,
11558
+ 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)`,
11234
11559
  baseHrefMissing: () => `An SPA using @wcstack/router needs <base href="/"> in <head> (without it, deep links misderive the basename)`,
11235
11560
  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>`,
11236
11561
  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`,
11562
+ signalsImportMapBoth: () => `This import map maps both @wcstack/signals and @wcstack/signals/dom. On a CDN each entry carries its own reactive core, so a module that imports @wcstack/signals \u2014 this page's, or a .js file it loads \u2014 gets a second core and reactivity breaks at the seam. Map only @wcstack/signals/dom (it exports the whole core)`,
11563
+ routeBareMustache: (inLayout) => inLayout ? `{{ }} in text directly under a layout template is not bound on a navigation. Wrap it in an element (<span>{{ \u2026 }}</span>)` : `{{ }} in text directly under <wcs-route> is bound only on the landing route: a route entered by navigation shows it as written. Wrap it in an element (<h1>{{ \u2026 }}</h1>)`,
11564
+ layoutSlotMissing: (l) => `The template of layout "${l}" has no default <slot> (one without a name), so what this <wcs-layout> holds outside the named slots \u2014 the nested routes and their pages \u2014 is not shown. Put a <slot></slot> where the page goes`,
11237
11565
  namedStateAttrDeprecated: (name) => `The "name" attribute was removed in v2 \u2014 there is a single state tree per root. Mount this state onto the tree instead: <wcs-state mount="${name}"> and read it as "${name}.<path>" (docs/state-mount-design.md \xA79)`,
11238
11566
  namedStatePathDeprecated: (name) => name === "default" ? `The "@default" selector was removed in v2 \u2014 drop it (docs/state-mount-design.md \xA79)` : `The "@name" selector was removed in v2 \u2014 there is a single state tree. Mount the named state onto the tree (<wcs-state mount="...">) and read it as "${name}.<path>" (docs/state-mount-design.md \xA79)`,
11239
11567
  mountPathInvalid: (problem, mountPath) => {
11240
11568
  switch (problem) {
11241
11569
  case "empty":
11242
- return `"mount" requires a non-empty tree path.`;
11570
+ return `"mount" needs a non-empty static path (the runtime refuses the volume: "has an invalid mount path").`;
11243
11571
  case "emptySegment":
11244
- return `"mount" path "${mountPath}" has an empty segment.`;
11572
+ return `"mount" path "${mountPath}" has an empty segment (the runtime refuses the volume: "has an invalid mount path").`;
11245
11573
  case "wildcard":
11246
- return `"mount" path "${mountPath}" must be static (wildcards are not allowed).`;
11574
+ return `"mount" path "${mountPath}" must be static \u2014 no "*" (the runtime refuses the volume: "has an invalid mount path").`;
11575
+ case "whitespace":
11576
+ return `"mount" path "${mountPath}" must not contain whitespace (the runtime refuses the volume: "has an invalid mount path").`;
11247
11577
  default:
11248
- return `"mount" path "${mountPath}" must not use reserved characters ($, #, @).`;
11578
+ return `"mount" path "${mountPath}" must not use the reserved characters $, #, @ (the runtime refuses the volume: "has an invalid mount path").`;
11249
11579
  }
11250
11580
  },
11251
11581
  recursionUnsupported: (p, where) => {
@@ -11267,7 +11597,7 @@ var en = {
11267
11597
  case "listKeys":
11268
11598
  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")`;
11269
11599
  default:
11270
- 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`;
11600
+ 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`;
11271
11601
  }
11272
11602
  },
11273
11603
  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 "**")`,
@@ -11456,6 +11786,19 @@ var DELEGATED_EVENTS = /* @__PURE__ */ new Set([
11456
11786
  var CUSTOM_ELEMENT_OWN_EVENTS = /* @__PURE__ */ new Set(["input", "change", "submit"]);
11457
11787
  function collectCurrentTargetHandlers(elements, html, fileReader) {
11458
11788
  const names = /* @__PURE__ */ new Set();
11789
+ forEachStateMethod(elements, html, fileReader, "currentTarget", (name, params, body) => {
11790
+ if (readsEventCurrentTarget(params, body)) names.add(name);
11791
+ });
11792
+ return names;
11793
+ }
11794
+ function collectPreventDefaultHandlers(elements, html, fileReader) {
11795
+ const handlers = /* @__PURE__ */ new Map();
11796
+ forEachStateMethod(elements, html, fileReader, null, (name, _params, body) => {
11797
+ handlers.set(name, /\bpreventDefault\b/.test(body));
11798
+ });
11799
+ return handlers;
11800
+ }
11801
+ function forEachStateMethod(elements, html, fileReader, spelling, fn) {
11459
11802
  let insideTemplate = null;
11460
11803
  for (const element2 of elements) {
11461
11804
  if (element2.bindComponent) continue;
@@ -11465,20 +11808,19 @@ function collectCurrentTargetHandlers(elements, html, fileReader) {
11465
11808
  const script = readStateScript(element2.srcAttr, fileReader);
11466
11809
  if (script !== void 0) scripts = [script];
11467
11810
  }
11468
- scripts = scripts.filter((script) => script.includes("currentTarget"));
11811
+ if (spelling !== null) scripts = scripts.filter((script) => script.includes(spelling));
11469
11812
  if (scripts.length === 0) continue;
11470
11813
  if ((insideTemplate ??= createTemplateTester(html))(element2.tagStart)) continue;
11471
11814
  for (const script of scripts) {
11472
11815
  for (const callable of analyzeCallableBodies(script)) {
11473
- if (callable.kind !== "method" || !callable.body.includes("currentTarget")) continue;
11816
+ if (callable.kind !== "method" || spelling !== null && !callable.body.includes(spelling)) continue;
11474
11817
  const head = script.slice(callable.end, callable.bodyStart - 1);
11475
11818
  const params = /\(([^)]*)\)\s*$/.exec(head);
11476
11819
  if (params === null) continue;
11477
- if (readsEventCurrentTarget(params[1], callable.body)) names.add(volume === null ? callable.name : `${volume}.${callable.name}`);
11820
+ fn(volume === null ? callable.name : `${volume}.${callable.name}`, params[1], callable.body);
11478
11821
  }
11479
11822
  }
11480
11823
  }
11481
- return names;
11482
11824
  }
11483
11825
  function validateBindings(html, attrName, stateTagName = "wcs-state", locale2, fileReader, applicationSchema) {
11484
11826
  const diagnostics = [];
@@ -11486,11 +11828,6 @@ function validateBindings(html, attrName, stateTagName = "wcs-state", locale2, f
11486
11828
  const pathIndex = getStatePathIndex(html, stateTagName, fileReader);
11487
11829
  const statePaths = mergeSchemaCandidates(pathIndex.paths, applicationSchema);
11488
11830
  const attrs = findAllBindAttributes(html, attrName);
11489
- let structuralTemplates = null;
11490
- const getStructuralTemplates = () => {
11491
- structuralTemplates ??= collectStructuralTemplates(html, attrName);
11492
- return structuralTemplates;
11493
- };
11494
11831
  const outerCandidates = [];
11495
11832
  const currentTargetCandidates = [];
11496
11833
  let currentTargetHandlers = null;
@@ -11498,6 +11835,11 @@ function validateBindings(html, attrName, stateTagName = "wcs-state", locale2, f
11498
11835
  currentTargetHandlers ??= collectCurrentTargetHandlers(pathIndex.elements, html, fileReader);
11499
11836
  return currentTargetHandlers;
11500
11837
  };
11838
+ let preventDefaultHandlers = null;
11839
+ const getPreventDefaultHandlers = () => {
11840
+ preventDefaultHandlers ??= collectPreventDefaultHandlers(pathIndex.elements, html, fileReader);
11841
+ return preventDefaultHandlers;
11842
+ };
11501
11843
  for (const attr of attrs) {
11502
11844
  const bindings = splitBindingExpressions(attr.value);
11503
11845
  const nonEmptyCount = bindings.filter((b) => b.trim().length > 0).length;
@@ -11559,6 +11901,15 @@ function validateBindings(html, attrName, stateTagName = "wcs-state", locale2, f
11559
11901
  const eventName = propNoMod.slice(2);
11560
11902
  const handler = parsed.path.trim();
11561
11903
  const modifiers = modifiersOf(parsed.property);
11904
+ if (eventName === "submit" && attr.tagName === "form" && !modifiers.includes("prevent") && getPreventDefaultHandlers().get(handler) === false && !/\saction\s*=/i.test(openTagBefore(html, attr.valueStart))) {
11905
+ diagnostics.push({
11906
+ code: WcsDiagnosticCode.SubmitWithoutPrevent,
11907
+ start: bindingStart + leadingSpace,
11908
+ end: bindingStart + leadingSpace + propNoMod.length,
11909
+ message: msgs.submitWithoutPrevent(handler),
11910
+ severity: "warning"
11911
+ });
11912
+ }
11562
11913
  if (DELEGATED_EVENTS.has(eventName) && !modifiers.includes(DIRECT_MODIFIER) && attr.tagName !== void 0 && !(attr.tagName.includes("-") && CUSTOM_ELEMENT_OWN_EVENTS.has(eventName)) && /^[A-Za-z_][\w$]*(?:\.[A-Za-z_][\w$]*)*$/.test(handler) && getCurrentTargetHandlers().has(handler)) {
11563
11914
  currentTargetCandidates.push({
11564
11915
  offset: attr.valueStart,
@@ -11636,7 +11987,8 @@ function validateBindings(html, attrName, stateTagName = "wcs-state", locale2, f
11636
11987
  start: pathStart,
11637
11988
  end: pathStart + tokenPath.length,
11638
11989
  message: msgs.commandRhsFormat(),
11639
- severity: "warning"
11990
+ // ランタイムは束縛の計画で #1201 として throw し、root では初期化が失敗する
11991
+ severity: "error"
11640
11992
  });
11641
11993
  } else if (commandNames.size > 0 && !commandNames.has(tokenPath)) {
11642
11994
  diagnostics.push({
@@ -11644,7 +11996,9 @@ function validateBindings(html, attrName, stateTagName = "wcs-state", locale2, f
11644
11996
  start: pathStart,
11645
11997
  end: pathStart + tokenPath.length,
11646
11998
  message: msgs.commandTokenUndeclared(tokenPath),
11647
- severity: "warning"
11999
+ // ランタイムは取り付けで #1302 として throw し、root では初期化が失敗する
12000
+ // (eventToken. と `on*: $command.x` はイベントのたびに #1301 を記録するだけなので warning のまま)
12001
+ severity: "error"
11648
12002
  });
11649
12003
  }
11650
12004
  }
@@ -11814,10 +12168,7 @@ function validateBindings(html, attrName, stateTagName = "wcs-state", locale2, f
11814
12168
  const typePath = candidateKeyOf(pathTrimmed, (c) => scopedPathSet.has(c));
11815
12169
  const resultType = resolveResultType(typePath, parsed.filters, scopedPaths);
11816
12170
  if (resultType !== null) {
11817
- const typeReq = getExpectedType(
11818
- parsed.property,
11819
- () => isNegatedByElseChain(getStructuralTemplates(), attr.valueStart)
11820
- );
12171
+ const typeReq = getExpectedType(parsed.property);
11821
12172
  if (typeReq && resultType !== typeReq.expected) {
11822
12173
  const pathOffset = binding.indexOf(parsed.path);
11823
12174
  const pathStart = bindingStart + pathOffset;
@@ -11867,6 +12218,10 @@ function validateBindings(html, attrName, stateTagName = "wcs-state", locale2, f
11867
12218
  }
11868
12219
  return diagnostics;
11869
12220
  }
12221
+ function openTagBefore(html, valueStart) {
12222
+ const lt2 = html.lastIndexOf("<", valueStart);
12223
+ return lt2 === -1 ? "" : html.slice(lt2, valueStart);
12224
+ }
11870
12225
  function findAllBindAttributes(html, attrName) {
11871
12226
  const attrs = [];
11872
12227
  const escaped = attrName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -11971,14 +12326,16 @@ function validateFilterUsage(filter, bindingStart, msgs) {
11971
12326
  for (let i = 0; i < Math.min(argCount, info.argTypes.length); i++) {
11972
12327
  const expectedArgType = info.argTypes[i];
11973
12328
  if (expectedArgType === "any") continue;
11974
- const actualArgType = inferArgType(filter.args[i]);
11975
- if (actualArgType !== expectedArgType) {
12329
+ const arg = filter.args[i];
12330
+ const numericFails = expectedArgType === "number" && !readsAsNumber(arg);
12331
+ const actualArgType = inferArgType(arg);
12332
+ if (expectedArgType === "number" ? numericFails : actualArgType !== expectedArgType) {
11976
12333
  diagnostics.push({
11977
12334
  code: WcsDiagnosticCode.FilterArgType,
11978
12335
  start: bindingStart + filter.argsOffset,
11979
12336
  end: bindingStart + filter.argsOffset + filter.name.length,
11980
- message: msgs.filterArgType(filter.name, i + 1, expectedArgType, filter.args[i], actualArgType),
11981
- severity: "warning"
12337
+ message: msgs.filterArgType(filter.name, i + 1, expectedArgType, arg, actualArgType),
12338
+ severity: numericFails ? "error" : "warning"
11982
12339
  });
11983
12340
  }
11984
12341
  }
@@ -12043,57 +12400,11 @@ function validateSchemaPathExistence(checkPath, displayPath, scopedPaths, scoped
12043
12400
  }
12044
12401
  return null;
12045
12402
  }
12046
- function collectStructuralTemplates(html, attrName) {
12047
- const escaped = attrName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
12048
- const attrRegex = new RegExp(`${escaped}\\s*=\\s*(["'])`, "i");
12049
- const tagRegex = /<template(?:\s[^>]*)?>|<\/template\s*>/gi;
12050
- const templates = [];
12051
- let depth = 0;
12052
- let match;
12053
- while ((match = tagRegex.exec(html)) !== null) {
12054
- if (match[0].startsWith("</")) {
12055
- depth = Math.max(0, depth - 1);
12056
- continue;
12057
- }
12058
- const attrMatch = attrRegex.exec(match[0]);
12059
- if (attrMatch) {
12060
- const quote = attrMatch[1];
12061
- const valueStart = match.index + attrMatch.index + attrMatch[0].length;
12062
- const valueEnd = html.indexOf(quote, valueStart);
12063
- if (valueEnd !== -1) {
12064
- const first = splitBindingExpressions(html.slice(valueStart, valueEnd))[0] ?? "";
12065
- const firstColon = indexOfOutsideQuotes2(first, ":");
12066
- const prop = (firstColon === -1 ? first : first.slice(0, firstColon)).replace(/#.*$/, "").trim();
12067
- const type = prop === "if" || prop === "elseif" || prop === "else" ? prop : "other";
12068
- templates.push({ valueStart, depth, type });
12069
- }
12070
- }
12071
- depth++;
12072
- }
12073
- return templates;
12074
- }
12075
- function isNegatedByElseChain(templates, valueStart) {
12076
- const index = templates.findIndex((t) => t.valueStart === valueStart);
12077
- if (index === -1) return false;
12078
- const selfDepth = templates[index].depth;
12079
- for (let i = index + 1; i < templates.length; i++) {
12080
- const next = templates[i];
12081
- if (next.depth > selfDepth) continue;
12082
- if (next.depth < selfDepth) return false;
12083
- if (next.type === "elseif" || next.type === "else") return true;
12084
- if (next.type === "if") return false;
12085
- }
12086
- return false;
12087
- }
12088
- function getExpectedType(property, isNegatedIf) {
12403
+ function getExpectedType(property) {
12089
12404
  const prop = property.replace(/#.*$/, "");
12090
12405
  if (prop === "for") {
12091
12406
  return { label: "for", expected: "array", severity: "error" };
12092
12407
  }
12093
- if (prop === "if" || prop === "elseif") {
12094
- if (!isNegatedIf()) return null;
12095
- return { label: prop, expected: "boolean", severity: "warning" };
12096
- }
12097
12408
  if (prop.startsWith("class.")) {
12098
12409
  return { label: prop, expected: "boolean", severity: "warning" };
12099
12410
  }
@@ -12149,6 +12460,10 @@ function inferArgType(arg) {
12149
12460
  if (/^-?\d+(\.\d+)?$/.test(v)) return "number";
12150
12461
  return "string";
12151
12462
  }
12463
+ function readsAsNumber(arg) {
12464
+ const v = arg.trim().replace(/^(["'])([\s\S]*)\1$/, "$2");
12465
+ return v !== "" && !Number.isNaN(Number(v));
12466
+ }
12152
12467
  function isLiteral(value) {
12153
12468
  return /^-?\d/.test(value) || /^["'`]/.test(value) || value === "true" || value === "false" || value === "null";
12154
12469
  }
@@ -14073,20 +14388,7 @@ var BUILTIN_TAGS = {
14073
14388
  };
14074
14389
 
14075
14390
  // src/service/ioNodeValidator.ts
14076
- var DOM_COMMON_PROPERTIES = /* @__PURE__ */ new Set([
14077
- "textContent",
14078
- "innerHTML",
14079
- "innerText",
14080
- "hidden",
14081
- "title",
14082
- "id",
14083
- "slot",
14084
- "dir",
14085
- "lang",
14086
- "role",
14087
- "tabIndex",
14088
- "className"
14089
- ]);
14391
+ var HTML_SINK_PROPERTIES = /* @__PURE__ */ new Set(["html", "innerHTML", "outerHTML", "srcdoc"]);
14090
14392
  var STRUCTURAL_DIRECTIVES3 = /* @__PURE__ */ new Set(["for", "if", "elseif", "else"]);
14091
14393
  var EXPLICIT_PROPERTY_REJECTED_HEADS2 = /* @__PURE__ */ new Set([
14092
14394
  ...Object.values(getWcsManifest().syntax.bindingTypes.propNamespaces),
@@ -14188,7 +14490,7 @@ function validateBindingAgainstContract(tagName, contract, parsed, property, sta
14188
14490
  code: WcsDiagnosticCode.TagMemberUnknown,
14189
14491
  start,
14190
14492
  end,
14191
- severity: "warning",
14493
+ severity: "error",
14192
14494
  tag: tagName,
14193
14495
  member: name,
14194
14496
  message: msgs.tagCommandUnknown(name, tagName, contract.commands.join(", ") || msgs.none()) + suggestion(name, contract.commands, msgs)
@@ -14203,7 +14505,7 @@ function validateBindingAgainstContract(tagName, contract, parsed, property, sta
14203
14505
  code: WcsDiagnosticCode.TagMemberUnknown,
14204
14506
  start,
14205
14507
  end,
14206
- severity: "warning",
14508
+ severity: "error",
14207
14509
  tag: tagName,
14208
14510
  member: name,
14209
14511
  message: msgs.tagEventTokenKeyUnknown(name, tagName, contract.properties.join(", ")) + suggestion(name, contract.properties, msgs)
@@ -14211,13 +14513,13 @@ function validateBindingAgainstContract(tagName, contract, parsed, property, sta
14211
14513
  }
14212
14514
  return;
14213
14515
  }
14214
- if (!contract.properties.includes(property) && !(property in contract.inputs) && !DOM_COMMON_PROPERTIES.has(property)) {
14516
+ if (!contract.properties.includes(property) && !(property in contract.inputs) && !HTML_SINK_PROPERTIES.has(property)) {
14215
14517
  const members = [...contract.properties, ...inputNames];
14216
14518
  diagnostics.push({
14217
14519
  code: WcsDiagnosticCode.TagMemberUnknown,
14218
14520
  start,
14219
14521
  end,
14220
- severity: "warning",
14522
+ severity: "error",
14221
14523
  tag: tagName,
14222
14524
  member: property,
14223
14525
  message: msgs.tagMemberUnknown(property, tagName) + suggestion(property, members, msgs)
@@ -14422,7 +14724,7 @@ function validateDocumentEnv(html, locale2) {
14422
14724
  code: WcsDiagnosticCode.ScriptOrder,
14423
14725
  start: later.start,
14424
14726
  end: later.end,
14425
- severity: "warning",
14727
+ severity: "info",
14426
14728
  message: msgs.devtoolsAfterState()
14427
14729
  });
14428
14730
  }
@@ -14459,9 +14761,63 @@ function validateDocumentEnv(html, locale2) {
14459
14761
  severity: "error",
14460
14762
  message: msgs.signalsDualEntry()
14461
14763
  });
14764
+ } else {
14765
+ const both = findSignalsImportMapBoth(scanText);
14766
+ if (both) {
14767
+ diagnostics.push({
14768
+ code: WcsDiagnosticCode.SignalsDualEntry,
14769
+ start: both.start,
14770
+ end: both.end,
14771
+ severity: "warning",
14772
+ message: msgs.signalsImportMapBoth()
14773
+ });
14774
+ }
14775
+ }
14776
+ const structure = scanStructure(scanText);
14777
+ for (const at2 of structure.bareMustaches) {
14778
+ diagnostics.push({
14779
+ code: WcsDiagnosticCode.RouteBareMustache,
14780
+ start: at2.start,
14781
+ end: at2.end,
14782
+ severity: "warning",
14783
+ message: msgs.routeBareMustache(at2.inLayout)
14784
+ });
14785
+ }
14786
+ for (const layout of structure.layoutsWithoutDefaultSlot) {
14787
+ diagnostics.push({
14788
+ code: WcsDiagnosticCode.LayoutSlotMissing,
14789
+ start: layout.start,
14790
+ end: layout.end,
14791
+ severity: "warning",
14792
+ message: msgs.layoutSlotMissing(layout.id)
14793
+ });
14462
14794
  }
14463
14795
  return diagnostics;
14464
14796
  }
14797
+ function findSignalsImportMapBoth(html) {
14798
+ const mapRegex = /<script\b((?:"[^"]*"|'[^']*'|[^>"'])*)>([\s\S]*?)<\/script\s*>/gi;
14799
+ let match;
14800
+ while ((match = mapRegex.exec(html)) !== null) {
14801
+ if (!/\btype\s*=\s*(["'])importmap\1/i.test(match[1])) continue;
14802
+ let imports;
14803
+ try {
14804
+ imports = JSON.parse(match[2]).imports;
14805
+ } catch {
14806
+ continue;
14807
+ }
14808
+ if (imports === null || typeof imports !== "object") continue;
14809
+ const core = imports["@wcstack/signals"];
14810
+ const dom = imports["@wcstack/signals/dom"] ?? imports["@wcstack/signals/"];
14811
+ if (typeof core !== "string" || typeof dom !== "string") continue;
14812
+ if (core.includes("/dist/") && dom.includes("/dist/")) continue;
14813
+ const key = '"@wcstack/signals"';
14814
+ const at2 = match[2].indexOf(key);
14815
+ const bodyStart = match.index + match[0].indexOf(">") + 1;
14816
+ const start = bodyStart + (at2 === -1 ? 0 : at2 + 1);
14817
+ return { start, end: start + key.length - 2 };
14818
+ }
14819
+ return null;
14820
+ }
14465
14821
  var SCOPED_AUTO = /@wcstack\/([a-z0-9-]+)(?:@[^/"'\s]+)?\/(?:auto\b|dist\/(?:split\/)?auto(?:\.min)?\.js\b)/;
14466
14822
  var BUNDLE_AUTO = /(?:^|\/)wcstack(?:@[^/"'\s]+)?\/(?:auto\b|dist\/auto\.min\.js\b)/;
14467
14823
  var BUNDLE_PACKAGES = ["state", "router", "fetch", "storage", "autoloader"];
@@ -14540,6 +14896,88 @@ function blankHtmlComments(html) {
14540
14896
  function blankJsComments(code) {
14541
14897
  return code.replace(/\/\*[\s\S]*?\*\//g, (m) => " ".repeat(m.length)).replace(/(^|[^:])\/\/[^\n]*/g, (m, pre) => pre + " ".repeat(m.length - pre.length));
14542
14898
  }
14899
+ var VOID_TAGS = /* @__PURE__ */ new Set(["area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "source", "track", "wbr"]);
14900
+ var ROUTE_TAG = "wcs-route";
14901
+ var LAYOUT_TAG2 = "wcs-layout";
14902
+ function attrValue(attrs, name) {
14903
+ const m = new RegExp(`(?:^|\\s)${name}\\s*=\\s*(?:"([^"]*)"|'([^']*)'|([^\\s>]+))`, "i").exec(attrs);
14904
+ return m === null ? null : m[1] ?? m[2] ?? m[3] ?? "";
14905
+ }
14906
+ function scanStructure(html) {
14907
+ const scan = html.replace(
14908
+ /(<(script|style)\b[^>]*>)([\s\S]*?)(<\/\2\s*>)/gi,
14909
+ (_m, open, _name, body, close) => open + " ".repeat(body.length) + close
14910
+ );
14911
+ const tagRegex = /<(\/?)([a-zA-Z][\w-]*)((?:"[^"]*"|'[^']*'|[^>"'])*)>/g;
14912
+ const layoutIds = /* @__PURE__ */ new Set();
14913
+ for (const m of scan.matchAll(/<wcs-layout\b((?:"[^"]*"|'[^']*'|[^>"'])*)>/gi)) {
14914
+ const id = attrValue(m[1], "layout");
14915
+ if (id !== null && id !== "") layoutIds.add(id);
14916
+ }
14917
+ const bareMustaches = [];
14918
+ const layouts = [];
14919
+ const templateHasDefaultSlot = /* @__PURE__ */ new Map();
14920
+ const stack = [];
14921
+ let last = 0;
14922
+ let match;
14923
+ const text3 = (from, to) => {
14924
+ const top = stack[stack.length - 1];
14925
+ if (top === void 0 || to <= from) return;
14926
+ const chunk = scan.slice(from, to);
14927
+ if (top.name === LAYOUT_TAG2 && chunk.trim() !== "") top.unslotted = true;
14928
+ if (top.name !== ROUTE_TAG && !top.layoutTemplate) return;
14929
+ for (const m of chunk.matchAll(/\{\{[\s\S]*?\}\}/g)) {
14930
+ bareMustaches.push({ start: from + m.index, end: from + m.index + m[0].length, inLayout: top.layoutTemplate });
14931
+ }
14932
+ };
14933
+ while ((match = tagRegex.exec(scan)) !== null) {
14934
+ text3(last, match.index);
14935
+ last = match.index + match[0].length;
14936
+ const name = match[2].toLowerCase();
14937
+ const nameStart = match.index + 1 + match[1].length;
14938
+ if (match[1] === "/") {
14939
+ const at2 = stack.map((e) => e.name).lastIndexOf(name);
14940
+ if (at2 === -1) continue;
14941
+ for (const closed of stack.splice(at2)) {
14942
+ if (closed.name === LAYOUT_TAG2 && closed.unslotted && closed.layoutId !== void 0) {
14943
+ layouts.push({ start: closed.nameStart, end: closed.nameEnd, id: closed.layoutId });
14944
+ }
14945
+ }
14946
+ continue;
14947
+ }
14948
+ const attrs = match[3];
14949
+ const parent = stack[stack.length - 1];
14950
+ if (parent?.name === LAYOUT_TAG2 && !attrValue(attrs, "slot")) parent.unslotted = true;
14951
+ for (const open of stack) {
14952
+ if (open.layoutTemplate && name === "slot" && !attrValue(attrs, "name")) templateHasDefaultSlot.set(open.layoutId, true);
14953
+ }
14954
+ if (VOID_TAGS.has(name) || /\/\s*$/.test(attrs)) continue;
14955
+ const id = name === "template" ? attrValue(attrs, "id") : null;
14956
+ const element2 = {
14957
+ name,
14958
+ layoutTemplate: id !== null && layoutIds.has(id),
14959
+ nameStart,
14960
+ nameEnd: nameStart + match[2].length
14961
+ };
14962
+ if (element2.layoutTemplate) {
14963
+ element2.layoutId = id;
14964
+ if (!templateHasDefaultSlot.has(id)) templateHasDefaultSlot.set(id, false);
14965
+ }
14966
+ if (name === LAYOUT_TAG2 && attrValue(attrs, "src") === null) {
14967
+ const layoutId = attrValue(attrs, "layout");
14968
+ if (layoutId !== null && layoutId !== "") element2.layoutId = layoutId;
14969
+ }
14970
+ stack.push(element2);
14971
+ }
14972
+ text3(last, scan.length);
14973
+ for (const closed of stack) {
14974
+ if (closed.name === LAYOUT_TAG2 && closed.unslotted && closed.layoutId !== void 0) {
14975
+ layouts.push({ start: closed.nameStart, end: closed.nameEnd, id: closed.layoutId });
14976
+ }
14977
+ }
14978
+ const layoutsWithoutDefaultSlot = layouts.filter((l) => templateHasDefaultSlot.get(l.id) === false);
14979
+ return { bareMustaches, layoutsWithoutDefaultSlot };
14980
+ }
14543
14981
  var ROUTER_TAG2 = "wcs-router";
14544
14982
  var OUTLET_TAG = "wcs-outlet";
14545
14983
  function findMisplacedOutlets(html) {
@@ -14982,7 +15420,7 @@ function validateRecursiveGetters(script, offset2, spec, undeclared, msgs, out)
14982
15420
  start,
14983
15421
  end,
14984
15422
  msgs.recursionUnsupported(span.name, "undeclared"),
14985
- "warning"
15423
+ "error"
14986
15424
  );
14987
15425
  }
14988
15426
  continue;
@@ -15506,7 +15944,8 @@ function findMountPathProblem(mountPath) {
15506
15944
  if (mountPath.length === 0) return "empty";
15507
15945
  for (const segment of mountPath.split(".")) {
15508
15946
  if (segment.length === 0) return "emptySegment";
15509
- if (segment === "*") return "wildcard";
15947
+ if (segment.includes("*")) return "wildcard";
15948
+ if (/\s/.test(segment)) return "whitespace";
15510
15949
  if (segment.includes("$") || segment.includes("#") || segment.includes("@")) return "reserved";
15511
15950
  }
15512
15951
  return null;
@@ -15878,7 +16317,7 @@ function validateIndexArity(script, scriptStart, locale2) {
15878
16317
  start: scriptStart + parsed.starts[1] + leading,
15879
16318
  end: scriptStart + parsed.starts[1] + argText.trimEnd().length,
15880
16319
  message: msgs.indexArity(api, path, requirement, wildcardCount, actual),
15881
- severity: "warning"
16320
+ severity: "error"
15882
16321
  });
15883
16322
  }
15884
16323
  return out;
@@ -15934,7 +16373,7 @@ function validateGetterCycles(script, scriptStart, locale2) {
15934
16373
  start: scriptStart + getter.start,
15935
16374
  end: scriptStart + getter.end,
15936
16375
  message: msgs.getterCycle(cycle),
15937
- severity: "warning"
16376
+ severity: "error"
15938
16377
  });
15939
16378
  }
15940
16379
  return out;
@@ -15969,6 +16408,54 @@ function validateGetterUntrackedReads(script, scriptStart, nestedWriteRoots, loc
15969
16408
  }
15970
16409
  return out;
15971
16410
  }
16411
+ function validateGetterLocationReads(script, scriptStart, locale2) {
16412
+ if (!script.includes("location")) return [];
16413
+ const msgs = getMessages(locale2);
16414
+ const out = [];
16415
+ for (const getter of analyzeCallableBodies(script)) {
16416
+ if (getter.kind !== "getter" || getter.accessor !== "get" || !getter.body.includes("location")) continue;
16417
+ const read = findLocationRead(getter.body);
16418
+ if (read === null) continue;
16419
+ out.push({
16420
+ code: WcsDiagnosticCode.GetterUntrackedRead,
16421
+ start: scriptStart + getter.bodyStart + read.start,
16422
+ end: scriptStart + getter.bodyStart + read.end,
16423
+ message: msgs.getterReadsLocation(read.text),
16424
+ severity: "warning"
16425
+ });
16426
+ }
16427
+ return out;
16428
+ }
16429
+ function onHandlerStateParam(script, handler) {
16430
+ if (handler.kind === "body") {
16431
+ const head = script.slice(Math.max(0, handler.start - 400), handler.start);
16432
+ return /\(\s*([A-Za-z_$][\w$]*)[^()]*\)\s*\{\s*$/.exec(head)?.[1] ?? null;
16433
+ }
16434
+ return /^\s*(?:async\s+)?(?:function\b[^(]*\(\s*([A-Za-z_$][\w$]*)|\(\s*([A-Za-z_$][\w$]*)|([A-Za-z_$][\w$]*)\s*=>)/.exec(handler.text)?.slice(1).find((name) => name !== void 0) ?? null;
16435
+ }
16436
+ function validateInPlaceChanges(script, scriptStart, locale2) {
16437
+ const msgs = getMessages(locale2);
16438
+ const out = [];
16439
+ const push3 = (text3, kind, textStart, root) => {
16440
+ for (const change of findInPlaceChanges(text3, kind, root)) {
16441
+ out.push({
16442
+ code: change.form === "method" ? WcsDiagnosticCode.ArrayMutation : change.form === "index" ? WcsDiagnosticCode.ArrayIndexAssign : WcsDiagnosticCode.NestedAssign,
16443
+ start: scriptStart + textStart + change.start,
16444
+ end: scriptStart + textStart + change.end,
16445
+ severity: "error",
16446
+ message: change.alias !== null ? msgs.inPlaceAlias(change.alias, change.source, change.target) : msgs.inPlaceChange(change.source, change.target)
16447
+ });
16448
+ }
16449
+ };
16450
+ for (const callable of analyzeCallableBodies(script)) push3(callable.body, "body", callable.bodyStart, "this");
16451
+ for (const handler of analyzeWatchHandlerSources(script)) push3(handler.text, handler.kind, handler.start, "this");
16452
+ for (const handler of analyzeOnHandlerSources(script)) {
16453
+ const root = handler.kind === "body" ? onHandlerStateParam(script, handler) : null;
16454
+ if (handler.kind === "body" && root === null) continue;
16455
+ push3(handler.text, handler.kind, handler.start, root);
16456
+ }
16457
+ return out;
16458
+ }
15972
16459
  var NESTED_WRITE_INPUTS = {
15973
16460
  "wcs-storage": { inputs: ["value"], exemptWhenManual: true },
15974
16461
  "wcs-fetch": { inputs: ["body"], exemptWhenManual: false, oneShot: true }
@@ -15998,7 +16485,7 @@ function validateInputNestedWrites(html, stateTagName, bindAttrName, nestedWrite
15998
16485
  code: WcsDiagnosticCode.InputNestedWrite,
15999
16486
  start: occ.pathRange.start,
16000
16487
  end: occ.pathRange.end,
16001
- severity: "warning",
16488
+ severity: "error",
16002
16489
  tag: tag.tagName,
16003
16490
  statePath: occ.path,
16004
16491
  message
@@ -16080,6 +16567,26 @@ function collectNestedWriteRoots(html, stateTagName, bindAttrName, blocks) {
16080
16567
  if (path !== null) addPrefixes(path, false);
16081
16568
  }
16082
16569
  }
16570
+ for (const handler of analyzeOnHandlerSources(block.content)) {
16571
+ const param = onHandlerStateParam(block.content, handler);
16572
+ if (param === null) continue;
16573
+ const name = param.replace(/\$/g, "\\$");
16574
+ const region = { start: handler.start, end: handler.start + handler.text.length };
16575
+ const bracket = `\\b${name}\\s*(?:\\?\\.)?\\s*\\[\\s*["']([^"']+)["']\\s*\\]`;
16576
+ const template = `\\b${name}\\s*(?:\\?\\.)?\\s*\\[\\s*\`([^\`]*)\`` + String.raw`\s*\]`;
16577
+ for (const [pattern, quote] of [[bracket, /["']/], [template, /`/]]) {
16578
+ for (const regex of [new RegExp(`${pattern}${ASSIGN_TAIL}`, "g"), new RegExp(`${PRE_INCDEC}${pattern}`, "g")]) {
16579
+ let match;
16580
+ const part = scan.slice(region.start, region.end);
16581
+ while ((match = regex.exec(part)) !== null) {
16582
+ const keyStart = region.start + match.index + match[0].search(quote) + 1;
16583
+ const raw = block.content.slice(keyStart, keyStart + match[1].length);
16584
+ const path = quote.source === "`" ? templateKeyPath(raw) : raw;
16585
+ if (path !== null) addPrefixes(path, false);
16586
+ }
16587
+ }
16588
+ }
16589
+ }
16083
16590
  API_CALL.lastIndex = 0;
16084
16591
  let call;
16085
16592
  while ((call = API_CALL.exec(scan)) !== null) {
@@ -16210,7 +16717,9 @@ function validateSemantics(html, stateTagName = "wcs-state", locale2, bindAttrNa
16210
16717
  out.push(...validateIndexParamReads(block.content, block.contentStart, locale2));
16211
16718
  out.push(...validateGetterCycles(block.content, block.contentStart, locale2));
16212
16719
  out.push(...validateGetterUntrackedReads(block.content, block.contentStart, getNestedWriteRoots, locale2));
16720
+ out.push(...validateGetterLocationReads(block.content, block.contentStart, locale2));
16213
16721
  out.push(...validateOnHandlerThis(block.content, block.contentStart, locale2));
16722
+ out.push(...validateInPlaceChanges(block.content, block.contentStart, locale2));
16214
16723
  }
16215
16724
  out.push(...validateInputNestedWrites(html, stateTagName, bindAttrName, getNestedWriteRoots, locale2));
16216
16725
  out.push(...validateUpdatedCallbackDemand(html, stateTagName, bindAttrName, locale2));
@@ -16270,7 +16779,9 @@ function validateDocument(text3, options = {}) {
16270
16779
  for (const d of validateNestedAssigns(text3, stateTagName, locale2)) {
16271
16780
  out.push({ code: WcsDiagnosticCode.NestedAssign, start: d.start, end: d.end, message: d.message, severity: d.severity });
16272
16781
  }
16273
- return sortDiagnostics(out);
16782
+ const ignored = findIgnoredRanges(text3, bindAttribute);
16783
+ const kept = ignored.length === 0 ? out : out.filter((d) => !ignored.some(([start, end]) => d.start >= start && d.start < end));
16784
+ return sortDiagnostics(kept);
16274
16785
  }
16275
16786
  // Annotate the CommonJS export names for ESM import in node:
16276
16787
  0 && (module.exports = {