@wcstack/state 4.8.0 → 4.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +9 -8
- package/README.md +9 -8
- package/dist/auto.min.js +1 -1
- package/dist/auto.min.js.map +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/parser.esm.js +1 -1
- package/dist/split/auto.js +1 -1
- package/dist/split/chunks/chunk-47I6RYV3.js +2 -0
- package/dist/split/chunks/{chunk-XXVJ6J2N.js.map → chunk-47I6RYV3.js.map} +1 -1
- package/dist/split/chunks/{chunk-DRSAQE4E.js → chunk-EBIQH2HE.js} +2 -2
- package/dist/split/chunks/{chunk-P3EXTBXC.js → chunk-FQUDP3XK.js} +2 -2
- package/dist/split/chunks/{chunk-IBGHHABS.js → chunk-ISBASPV2.js} +2 -2
- package/dist/split/chunks/{chunk-GQTEYSRZ.js → chunk-J3PTKUWV.js} +2 -2
- package/dist/split/chunks/{chunk-QMOIMPIJ.js → chunk-LWRYFYOC.js} +2 -2
- package/dist/split/chunks/{chunk-PKEAYPFR.js → chunk-P3JKSHRN.js} +2 -2
- package/dist/split/chunks/{chunk-T3KW5DZD.js → chunk-SOFOV2OG.js} +2 -2
- package/dist/split/chunks/{chunk-NITPUCPA.js → chunk-TS2HEHBQ.js} +2 -2
- package/dist/split/chunks/chunk-YIDHPXYQ.js +2 -0
- package/dist/split/chunks/{chunk-M3BJN6SQ.js.map → chunk-YIDHPXYQ.js.map} +1 -1
- package/dist/split/core.js +1 -1
- package/dist/split/features/devtools.js +1 -1
- package/dist/split/features/diagnostics.js +1 -1
- package/dist/split/features/diagnostics.js.map +1 -1
- package/dist/split/features/formats.js +1 -1
- package/dist/split/features/list-keys.js +1 -1
- package/dist/split/features/native-commands.js +1 -1
- package/dist/split/features/recursion.js +1 -1
- package/dist/split/features/scopes.js +1 -1
- package/dist/split/features/ssr.js +1 -1
- package/dist/split/features/temporal.js +1 -1
- package/package.json +1 -1
- package/dist/split/chunks/chunk-M3BJN6SQ.js +0 -2
- package/dist/split/chunks/chunk-XXVJ6J2N.js +0 -2
- /package/dist/split/chunks/{chunk-DRSAQE4E.js.map → chunk-EBIQH2HE.js.map} +0 -0
- /package/dist/split/chunks/{chunk-P3EXTBXC.js.map → chunk-FQUDP3XK.js.map} +0 -0
- /package/dist/split/chunks/{chunk-IBGHHABS.js.map → chunk-ISBASPV2.js.map} +0 -0
- /package/dist/split/chunks/{chunk-GQTEYSRZ.js.map → chunk-J3PTKUWV.js.map} +0 -0
- /package/dist/split/chunks/{chunk-QMOIMPIJ.js.map → chunk-LWRYFYOC.js.map} +0 -0
- /package/dist/split/chunks/{chunk-PKEAYPFR.js.map → chunk-P3JKSHRN.js.map} +0 -0
- /package/dist/split/chunks/{chunk-T3KW5DZD.js.map → chunk-SOFOV2OG.js.map} +0 -0
- /package/dist/split/chunks/{chunk-NITPUCPA.js.map → chunk-TS2HEHBQ.js.map} +0 -0
package/README.ja.md
CHANGED
|
@@ -193,9 +193,9 @@
|
|
|
193
193
|
<script type="importmap">
|
|
194
194
|
{
|
|
195
195
|
"imports": {
|
|
196
|
-
"@wcstack/state/core": "https://cdn.jsdelivr.net/npm/@wcstack/state@4.
|
|
197
|
-
"@wcstack/state/features/temporal": "https://cdn.jsdelivr.net/npm/@wcstack/state@4.
|
|
198
|
-
"@wcstack/state/features/scopes": "https://cdn.jsdelivr.net/npm/@wcstack/state@4.
|
|
196
|
+
"@wcstack/state/core": "https://cdn.jsdelivr.net/npm/@wcstack/state@4.9.0/dist/split/core.js",
|
|
197
|
+
"@wcstack/state/features/temporal": "https://cdn.jsdelivr.net/npm/@wcstack/state@4.9.0/dist/split/features/temporal.js",
|
|
198
|
+
"@wcstack/state/features/scopes": "https://cdn.jsdelivr.net/npm/@wcstack/state@4.9.0/dist/split/features/scopes.js"
|
|
199
199
|
}
|
|
200
200
|
}
|
|
201
201
|
</script>
|
|
@@ -261,7 +261,7 @@
|
|
|
261
261
|
ページが名指したアドオンを、同じビルドから読み込みます。
|
|
262
262
|
|
|
263
263
|
```html
|
|
264
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@wcstack/state@4.
|
|
264
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@wcstack/state@4.9.0/dist/split/auto.js"></script>
|
|
265
265
|
<wcs-state features="scopes diagnostics">
|
|
266
266
|
<script type="module">
|
|
267
267
|
export default {
|
|
@@ -1235,7 +1235,7 @@ getter の例外は握り潰されません。評価された場所(バイン
|
|
|
1235
1235
|
| **setter の中の読み取りは追跡しない。** setter は命令的な代入であって派生ではないので、その中で読んだものは何の依存にもならない | 何を書くかを `this.a` を読んで決める setter は、`a` が変わっても再実行されない。再実行されるのは getter だけ |
|
|
1236
1236
|
| **同値ガードはプリミティブにだけ効く。** 現在値と `Object.is` で等しいプリミティブの書き込みはキューに入る前に落とされる。オブジェクト・配列の書き込みは同じ参照でも必ず通る | 同じ文字列を再代入しても何も起きない。同じオブジェクトを再代入するとバインディングと `$watch` が再発火する(`$behavior.sameValueGuard`。`semantics: "event"` のプロパティはどちらにせよ対象外)。一覧は例外で、行が配列の要素に合わせ直されるのは**新しい**配列を代入したときだけ。同じ配列の再代入や `$postUpdate` は、ある行の下を読み直すが、行を追加・削除・置き換えしない: `cards[i] = card; this.cards = cards` は古いカードを出し続ける。新しい配列を代入する(`this.cards = cards.with(i, card)`、`[...cards, x]`)。lint はその場の変更を報告する(`wcs/array-index-assign`、`wcs/array-mutation`) |
|
|
1237
1237
|
|
|
1238
|
-
規則 1 は静的解析で捕まえられる唯一の規則です。getter が `this.form.name` を読んでいて、ドキュメントのどこかで `form.name` を書いている(`value:` バインド・spread・`this["form.name"] = …`)と、`wcs-validate` と VS Code 拡張が `wcs/getter-untracked-read` を報告します。ルートを丸ごと置換するだけの設計(router の params・`$stream` の fold)には出ません。
|
|
1238
|
+
規則 1 は静的解析で捕まえられる唯一の規則です。getter が `this.form.name` を読んでいて、ドキュメントのどこかで `form.name` を書いている(`value:` バインド・spread・`this["form.name"] = …`)と、`wcs-validate` と VS Code 拡張が `wcs/getter-untracked-read` を報告します。ルートを丸ごと置換するだけの設計(router の params・`$stream` の fold)には出ません。4.9 から、getter が読むパスをページの束縛が書くとき — `<wcs-fetch data-wcs="...: monthFetch">` は `monthFetch.value` を書くので、`this.monthFetch.value` を読む getter は応答を見ない — は **error** で、スクリプトだけが書くときは warning のままです。
|
|
1239
1239
|
|
|
1240
1240
|
`$untracked(fn)` は setter の規則を getter に意図的に適用するもので、`fn` の中の読み取りは追跡されません。`$dependOn(path)` は最初の規則に対する逃げ道です。
|
|
1241
1241
|
|
|
@@ -2346,6 +2346,7 @@ $on: {
|
|
|
2346
2346
|
- `$on` のすべてのキーは `$eventTokens` で宣言済みであること(さもなくば初期化時に throw)
|
|
2347
2347
|
- 各値は関数であること
|
|
2348
2348
|
- シグネチャは `(state, event, ...listIndexes)` —— まず DOM の `Event`、続いて内包するループインデックス
|
|
2349
|
+
- ハンドラの中の `this` は undefined なので、`this` を使うハンドラはイベントが届いたときに throw します。4.9 から、`diagnostics` の後付けが、state の宣言のときにハンドラごとに 1 回、イベントより前にそう言います(`[wcs/on-handler-this]`)。lint は error として報告します
|
|
2349
2350
|
|
|
2350
2351
|
### `eventToken.<property>:` バインディング
|
|
2351
2352
|
|
|
@@ -2953,7 +2954,7 @@ li {
|
|
|
2953
2954
|
| 26 | | `filter <name> requires at least one option` |
|
|
2954
2955
|
| 27 | | `filter <name> requires a number as option` |
|
|
2955
2956
|
| 28 | | `filter <name> requires a number value, not <what it was>` (a string adds: `— put |number before |<name>, or convert it where it is read`) |
|
|
2956
|
-
| 29 | | `filter <name> requires a date value (a Date), not <what it was>` (a string or a number adds: `— make the Date where it is read: a getter returning new Date(…)`) |
|
|
2957
|
+
| 29 | | `filter <name> requires a date value (a Date), not <what it was>` (a string or a number adds: `— make the Date where it is read: a getter returning new Date(…)`。4.9 から、`"2026-10-01"` のような日付だけの文字列には、`new Date("2026-10-01")` は UTC の真夜中 — グリニッジより西では前の日 — で、`new Date(y, m - 1, d)` がページのある場所のその日だ、とも言う) |
|
|
2957
2958
|
| 30 | | `filter <name> requires an array value` |
|
|
2958
2959
|
| 31 | | `init=/sync= modifiers require enableDirectionalInitialSync.` |
|
|
2959
2960
|
| 32 | | `"<text>": the "@name" selector was removed in v2 — there is a single state tree. …` |
|
|
@@ -3109,7 +3110,7 @@ this.$getAll("matrix.*.*", [row]);
|
|
|
3109
3110
|
- 読めないソース([状態の初期化](#状態の初期化))。
|
|
3110
3111
|
- 不正な宣言: 削除された名前(`$scan`・`$streams`・`$updatedCallback`。`diagnostics` アドオンがあるとき)、形の誤った `$behavior` / `$features` / `$commandTokens` / `$eventTokens` / `$on`、アドオンが入っていない宣言(`[wcs/feature-not-installed]`)。
|
|
3111
3112
|
- ページのバインド中に見つかったマークアップの誤り: 構文エラー、未知のフィルタや誤った引数の個数、wildcard-rank のエラー、フィルタ付きの `for:`、テンプレートの中の `outerHTML:`、クラスが定義済みの要素での wc-bindable の設定ミス。走査はそのエラーで止まります: 文書順でそれより前はバインドされ、後はバインドされません。デプロイの前に `npx @wcstack/lint` を実行してください。
|
|
3112
|
-
- 別の `<wcs-state>` がすでにバインドしているルートの上の、2 つ目のルート `<wcs-state>`(`#47`)。state ツリーはルートごとに 1 本です。部分木は `mount=`
|
|
3113
|
+
- 別の `<wcs-state>` がすでにバインドしているルートの上の、2 つ目のルート `<wcs-state>`(`#47`)。state ツリーはルートごとに 1 本です。部分木は `mount=` で接ぎ木してください。バインドするのは、文書で先のものではなく、状態が先にそろったものです: `json=` の state はすぐにそろうので、文書で先の `src=` やインラインの state より先にルートを取り、拒まれるのは後者になり、ページは違う state でバインドされます。4.9 から、`diagnostics` の後付けが、先にバインドしたときに両方を名指しします(`[wcs/second-root]`)。
|
|
3113
3114
|
|
|
3114
3115
|
`for:` / `if:` の行の中で、バインディングの取り付け時に見つかったエラー(未宣言の token、要素が宣言していないメンバ)は、初期化の失敗ではなく、そのバインディングの失敗になります: `$errorCallback` に届き、行はそのまま構築されます。state にないトップレベルのキーへのバインディングは、初期化の失敗ではなく適用の失敗です。初期化に失敗した要素は再始動できません —— `setInitialState()` は throw します(`#14`)。取り除いて新しい要素を作ってください。
|
|
3115
3116
|
|
|
@@ -3336,7 +3337,7 @@ router 自身が `<html lang>` を読む案と、リンク単位の intercept
|
|
|
3336
3337
|
|
|
3337
3338
|
`<wcs-state>` で組んだページは素の DOM なので、[happy-dom](https://github.com/capricorn86/happy-dom) でヘッドレスにテストできます — ブラウザ不要・ビルド不要・テスト専用 API 不要。レシピは 3 つ、いずれも書いてあるとおりに動きます。
|
|
3338
3339
|
|
|
3339
|
-
1 import で済ませたいなら [`@wcstack/testing`](../testing/README.ja.md) がレシピ 1 を `mount()` / `settle()` / `fire()` にまとめています(`<wcs-router>`
|
|
3340
|
+
1 import で済ませたいなら [`@wcstack/testing`](../testing/README.ja.md) がレシピ 1 を `mount()` / `settle()` / `fire()` にまとめています(`<wcs-router>` も待ちます)。以下の素のレシピはそれ無しでも有効です。自分のファイルにある状態(`<wcs-state src="./state.js">`)は、4.9 から `mount()` の `resolveModule` オプションで読み込めます — happy-dom の下では `src` は `http:` の URL で、Node のモジュールローダはそれを読みません。インラインの状態は、Node の下では相対モジュールを `import` できません。
|
|
3340
3341
|
|
|
3341
3342
|
### 1. vitest + happy-dom
|
|
3342
3343
|
|
package/README.md
CHANGED
|
@@ -194,9 +194,9 @@ leaves features out, it can compose them instead:
|
|
|
194
194
|
<script type="importmap">
|
|
195
195
|
{
|
|
196
196
|
"imports": {
|
|
197
|
-
"@wcstack/state/core": "https://cdn.jsdelivr.net/npm/@wcstack/state@4.
|
|
198
|
-
"@wcstack/state/features/temporal": "https://cdn.jsdelivr.net/npm/@wcstack/state@4.
|
|
199
|
-
"@wcstack/state/features/scopes": "https://cdn.jsdelivr.net/npm/@wcstack/state@4.
|
|
197
|
+
"@wcstack/state/core": "https://cdn.jsdelivr.net/npm/@wcstack/state@4.9.0/dist/split/core.js",
|
|
198
|
+
"@wcstack/state/features/temporal": "https://cdn.jsdelivr.net/npm/@wcstack/state@4.9.0/dist/split/features/temporal.js",
|
|
199
|
+
"@wcstack/state/features/scopes": "https://cdn.jsdelivr.net/npm/@wcstack/state@4.9.0/dist/split/features/scopes.js"
|
|
200
200
|
}
|
|
201
201
|
}
|
|
202
202
|
</script>
|
|
@@ -263,7 +263,7 @@ receptacle the owning add-on fills on install).
|
|
|
263
263
|
core, and the add-ons the page names from the same build.
|
|
264
264
|
|
|
265
265
|
```html
|
|
266
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@wcstack/state@4.
|
|
266
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@wcstack/state@4.9.0/dist/split/auto.js"></script>
|
|
267
267
|
<wcs-state features="scopes diagnostics">
|
|
268
268
|
<script type="module">
|
|
269
269
|
export default {
|
|
@@ -1243,7 +1243,7 @@ Three rules decide what the dependency graph sees. None of them matters until yo
|
|
|
1243
1243
|
| **Reads inside a setter are not tracked.** A setter is an imperative assignment, not a derivation, so nothing it reads becomes a dependency of anything | A setter that reads `this.a` to decide what to write does not run again when `a` changes — only a getter re-runs |
|
|
1244
1244
|
| **The same-value guard applies to primitives only.** A primitive write `Object.is`-equal to the current value is dropped before anything is enqueued; an object or array write always passes, even the same reference | Assigning the same string again fires nothing; assigning the same object again re-fires its bindings and `$watch` (`$behavior.sameValueGuard`; a `semantics: "event"` property is exempt either way). A list is the exception: its rows follow the array's items only when a **new** array is assigned. The same array assigned again — or `$postUpdate` — re-reads what is below the rows it has, but adds, removes or replaces no row: `cards[i] = card; this.cards = cards` keeps showing the old card. Assign a new array (`this.cards = cards.with(i, card)`, `[...cards, x]`); lint reports the in-place change (`wcs/array-index-assign`, `wcs/array-mutation`) |
|
|
1245
1245
|
|
|
1246
|
-
The first rule is the one static analysis can catch: `wcs-validate` and the VS Code extension report `wcs/getter-untracked-read` when a getter reads `this.form.name` and the document writes `form.name` somewhere (a `value:` binding, a spread, `this["form.name"] = …`). A root that is only ever replaced wholesale — router params, a `$stream` fold — is left alone.
|
|
1246
|
+
The first rule is the one static analysis can catch: `wcs-validate` and the VS Code extension report `wcs/getter-untracked-read` when a getter reads `this.form.name` and the document writes `form.name` somewhere (a `value:` binding, a spread, `this["form.name"] = …`). A root that is only ever replaced wholesale — router params, a `$stream` fold — is left alone. Since 4.9 it is an **error** when a binding on the page writes the path the getter reads — `<wcs-fetch data-wcs="...: monthFetch">` writes `monthFetch.value`, so a getter reading `this.monthFetch.value` never sees the response — and stays a warning when only the script writes it.
|
|
1247
1247
|
|
|
1248
1248
|
`$untracked(fn)` applies the setter rule to a getter on purpose: reads inside `fn` are not tracked. `$dependOn(path)` is the escape hatch for the first rule.
|
|
1249
1249
|
|
|
@@ -2358,6 +2358,7 @@ $on: {
|
|
|
2358
2358
|
- Every `$on` key must be declared in `$eventTokens` (otherwise an error is thrown at initialization)
|
|
2359
2359
|
- Each value must be a function
|
|
2360
2360
|
- The signature is `(state, event, ...listIndexes)` — the DOM `Event` first, then any enclosing loop indexes
|
|
2361
|
+
- `this` is undefined in a handler, so a handler that uses it throws when the event arrives. Since 4.9 the `diagnostics` add-on says so once per handler when the state is declared, before any event (`[wcs/on-handler-this]`); lint reports it as an error
|
|
2361
2362
|
|
|
2362
2363
|
### `eventToken.<property>:` Binding
|
|
2363
2364
|
|
|
@@ -2965,7 +2966,7 @@ The first line is what `@wcstack/state` and `/auto` print, the second what `/cor
|
|
|
2965
2966
|
| 26 | | `filter <name> requires at least one option` |
|
|
2966
2967
|
| 27 | | `filter <name> requires a number as option` |
|
|
2967
2968
|
| 28 | | `filter <name> requires a number value, not <what it was>` (a string adds: `— put |number before |<name>, or convert it where it is read`) |
|
|
2968
|
-
| 29 | | `filter <name> requires a date value (a Date), not <what it was>` (a string or a number adds: `— make the Date where it is read: a getter returning new Date(…)`) |
|
|
2969
|
+
| 29 | | `filter <name> requires a date value (a Date), not <what it was>` (a string or a number adds: `— make the Date where it is read: a getter returning new Date(…)`; since 4.9, a date-only string such as `"2026-10-01"` also says that `new Date("2026-10-01")` is midnight UTC — the day before west of Greenwich — and `new Date(y, m - 1, d)` is that day where the page is) |
|
|
2969
2970
|
| 30 | | `filter <name> requires an array value` |
|
|
2970
2971
|
| 31 | | `init=/sync= modifiers require enableDirectionalInitialSync.` |
|
|
2971
2972
|
| 32 | | `"<text>": the "@name" selector was removed in v2 — there is a single state tree. …` |
|
|
@@ -3122,7 +3123,7 @@ What fails initialization:
|
|
|
3122
3123
|
- A source that cannot be read ([State Initialization](#state-initialization)).
|
|
3123
3124
|
- An invalid declaration: a removed name (`$scan`, `$streams`, `$updatedCallback`; with the `diagnostics` add-on), a `$behavior` / `$features` / `$commandTokens` / `$eventTokens` / `$on` of the wrong shape, a declaration whose add-on is not installed (`[wcs/feature-not-installed]`).
|
|
3124
3125
|
- A markup error found while the page is bound: a syntax error, an unknown filter or a wrong argument count, a wildcard-rank error, `for:` with filters, `outerHTML:` in a template, a wc-bindable misconfiguration on an element whose class is already defined. The walk stops at the error: what comes before it in document order is bound, what comes after it is not. Run `npx @wcstack/lint` before you deploy.
|
|
3125
|
-
- A second root `<wcs-state>` on a root that another one already binds (`#47`). There is one state tree per root; graft a subtree with `mount=`.
|
|
3126
|
+
- A second root `<wcs-state>` on a root that another one already binds (`#47`). There is one state tree per root; graft a subtree with `mount=`. The one that binds is the one whose state is ready first, not the first in the document: a `json=` state is ready at once, so it takes the root before an earlier `src=` or inline state, which is then the one refused, and the page binds against the wrong state. Since 4.9 the `diagnostics` add-on names both when the first binds (`[wcs/second-root]`).
|
|
3126
3127
|
|
|
3127
3128
|
Inside a `for:` / `if:` row, an error found while a binding is attached (an undeclared token, a member the element does not declare) is that binding's failure instead: it goes to `$errorCallback`, and the row is still built. A binding to a top-level key the state does not have is a failed apply, not an initialization failure. An element that failed to initialize cannot be re-armed — `setInitialState()` throws (`#14`); remove it and create a new one.
|
|
3128
3129
|
|
|
@@ -3353,7 +3354,7 @@ different shape; `examples/router-i18n` is the reference layout.
|
|
|
3353
3354
|
|
|
3354
3355
|
A page built on `<wcs-state>` is plain DOM, so it can be tested headlessly with [happy-dom](https://github.com/capricorn86/happy-dom) — no browser, no build step, no test-only API. Three recipes follow; every one of them runs as written.
|
|
3355
3356
|
|
|
3356
|
-
Want it as one import? [`@wcstack/testing`](../testing/README.md) packages recipe 1 as `mount()` / `settle()` / `fire()` (and waits for `<wcs-router>` too). The bare recipes below stay valid without it.
|
|
3357
|
+
Want it as one import? [`@wcstack/testing`](../testing/README.md) packages recipe 1 as `mount()` / `settle()` / `fire()` (and waits for `<wcs-router>` too). The bare recipes below stay valid without it. A state in its own file (`<wcs-state src="./state.js">`) loads under `mount()` with its `resolveModule` option, since 4.9 — under happy-dom the `src` is an `http:` URL, which Node's module loader does not read, and an inline state cannot `import` a relative module under Node.
|
|
3357
3358
|
|
|
3358
3359
|
### 1. vitest + happy-dom
|
|
3359
3360
|
|