@wcstack/devtools 1.29.0 → 1.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auto.min.js +1 -1
- package/dist/auto.min.js.map +1 -1
- package/dist/index.d.ts +23 -3
- package/dist/index.esm.js +55 -6
- package/dist/index.esm.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -65,6 +65,14 @@ interface IStateElementSummaryLike {
|
|
|
65
65
|
* 旧ランタイムにはフィールド自体が無いため optional。宣言なしは null。
|
|
66
66
|
*/
|
|
67
67
|
readonly watchPaths?: ReadonlySet<string> | null;
|
|
68
|
+
/**
|
|
69
|
+
* `$listKeys` で宣言されたリストパス集合(protocol v1 追補)。ワイルドカード行
|
|
70
|
+
* watch に**リスト書き込み**が届く前提は「for バインド(paths.list)or
|
|
71
|
+
* $listKeys 宣言」なので、前提判定の正確化に paths.list と対で使う
|
|
72
|
+
*(明示 index 書き込みは前提に依らず発火し得る)。旧ランタイムにはフィールド自体が
|
|
73
|
+
* 無いため optional(undefined = $listKeys 側が観測不能)。宣言なしは null。
|
|
74
|
+
*/
|
|
75
|
+
readonly keyedListPaths?: ReadonlySet<string> | null;
|
|
68
76
|
}
|
|
69
77
|
/**
|
|
70
78
|
* 宣言レベルのバインディング 1 件(getDeclaredBindings の要素・protocol v1 追補)。
|
|
@@ -140,6 +148,18 @@ type DevtoolsEventLike = {
|
|
|
140
148
|
readonly type: "state:watch-fired";
|
|
141
149
|
readonly stateName: string;
|
|
142
150
|
readonly path: string;
|
|
151
|
+
} | {
|
|
152
|
+
readonly type: "state:path-unresolved";
|
|
153
|
+
readonly source: "binding" | "watch";
|
|
154
|
+
readonly stateName: string;
|
|
155
|
+
readonly path: string;
|
|
156
|
+
readonly missingSegment: string;
|
|
157
|
+
} | {
|
|
158
|
+
readonly type: "state:binding-apply-error";
|
|
159
|
+
readonly stateName: string;
|
|
160
|
+
readonly path: string;
|
|
161
|
+
readonly bindingType: string;
|
|
162
|
+
readonly error: unknown;
|
|
143
163
|
} | {
|
|
144
164
|
readonly type: "propagation:suppressed";
|
|
145
165
|
readonly reason: "confirmation" | "visited-edge";
|
|
@@ -219,7 +239,7 @@ interface IDevtoolsHookRegistryLike {
|
|
|
219
239
|
|
|
220
240
|
/** 予約 state 名 prefix(protocol §5)。この prefix の要素・イベントは常に除外 */
|
|
221
241
|
declare const RESERVED_STATE_NAME_PREFIX = "wcs-devtools";
|
|
222
|
-
type TimelineKind = "write" | "batch" | "command" | "event" | "element-registered" | "element-unregistered" | "watch-error" | "watch-chain-limit" | "propagation-suppressed" | "propagation-coalesced" | "propagation-hop-limit" | "contract-drift";
|
|
242
|
+
type TimelineKind = "write" | "batch" | "command" | "event" | "element-registered" | "element-unregistered" | "watch-error" | "watch-chain-limit" | "path-unresolved" | "binding-apply-error" | "propagation-suppressed" | "propagation-coalesced" | "propagation-hop-limit" | "contract-drift";
|
|
223
243
|
interface ITimelineEntry {
|
|
224
244
|
readonly seq: number;
|
|
225
245
|
readonly time: number;
|
|
@@ -249,8 +269,8 @@ type CoreChangeListener = (kind: CoreChangeKind) => void;
|
|
|
249
269
|
/**
|
|
250
270
|
* 配線カバレッジ 1 行(static-wiring-dx-design.md §4 — 宣言 × 実測の突合)。
|
|
251
271
|
* - watch: `fired`(count 回)/ `never` / `prerequisite-missing`
|
|
252
|
-
* (ワイルドカード行 watch
|
|
253
|
-
*
|
|
272
|
+
* (ワイルドカード行 watch は「for バインド or $listKeys 宣言」が無いと
|
|
273
|
+
* リスト書き込みが行へ届かない — 「未発火」と区別しないと誤警告になる)
|
|
254
274
|
* - command / eventToken: `emitted`(count 回)/ `never` /
|
|
255
275
|
* `emitted-unheard`(全 emit が subscriberCount 0 = 空撃ち。§4 の突合対象)
|
|
256
276
|
* - binding: canonical declared がある場合のみ。`attached` / `never-attached`
|
package/dist/index.esm.js
CHANGED
|
@@ -452,14 +452,21 @@ class DevtoolsCore {
|
|
|
452
452
|
out.push({ stateName: entry.name, kind: "watch", name: path, status: "fired", count, note: null });
|
|
453
453
|
continue;
|
|
454
454
|
}
|
|
455
|
-
// ワイルドカード行 watch
|
|
456
|
-
//
|
|
457
|
-
//
|
|
458
|
-
//
|
|
455
|
+
// ワイルドカード行 watch に**リスト書き込み**が届く前提 = 各 `.*` 階層の
|
|
456
|
+
// リストが「for バインド(paths.list)or `$listKeys` 宣言(keyedListPaths)」
|
|
457
|
+
// されていること(watch 設計 §6-3)。未成立は「未発火」と区別する。
|
|
458
|
+
// 前提はリスト置換経路に限る主張 — 明示 index 書き込み(`$resolve` /
|
|
459
|
+
// `items.0.price` 代入。$getAll で listIndex 台帳が生えた後)は前提に
|
|
460
|
+
// 依らず発火し得るため、「一度も発火しない」とは断定できない(実測済み)。
|
|
461
|
+
// keyedListPaths は protocol v1 追補 — フィールドを持たない旧ランタイム
|
|
462
|
+
// では $listKeys 側が観測できないため、note はさらに観測形に落とす 2 段。
|
|
463
|
+
const keyedKnown = summary.keyedListPaths !== undefined;
|
|
459
464
|
let missingList = null;
|
|
460
465
|
for (let star = path.indexOf(".*"); star !== -1; star = path.indexOf(".*", star + 2)) {
|
|
461
466
|
const listPath = path.slice(0, star);
|
|
462
|
-
|
|
467
|
+
const satisfied = summary.paths.list.has(listPath)
|
|
468
|
+
|| (summary.keyedListPaths?.has(listPath) ?? false);
|
|
469
|
+
if (!satisfied) {
|
|
463
470
|
missingList = listPath;
|
|
464
471
|
break;
|
|
465
472
|
}
|
|
@@ -467,7 +474,9 @@ class DevtoolsCore {
|
|
|
467
474
|
if (missingList !== null) {
|
|
468
475
|
out.push({
|
|
469
476
|
stateName: entry.name, kind: "watch", name: path, status: "prerequisite-missing", count: 0,
|
|
470
|
-
note:
|
|
477
|
+
note: keyedKnown
|
|
478
|
+
? `list "${missingList}" has no for binding and no $listKeys declaration — list writes never reach its rows (only explicit-index writes can fire this watch)`
|
|
479
|
+
: `no for binding observed for list "${missingList}" (a $listKeys declaration would still let list writes fire it)`,
|
|
471
480
|
});
|
|
472
481
|
continue;
|
|
473
482
|
}
|
|
@@ -799,6 +808,38 @@ class DevtoolsCore {
|
|
|
799
808
|
});
|
|
800
809
|
return;
|
|
801
810
|
}
|
|
811
|
+
case "state:path-unresolved": {
|
|
812
|
+
if (this.isHiddenStateName(event.stateName)) {
|
|
813
|
+
return;
|
|
814
|
+
}
|
|
815
|
+
// ランタイムは warn で続行する(既存ページを止めないため)。lint を
|
|
816
|
+
// 走らせていない相手には、ここが「配線が死んでいる」唯一の可視面になる。
|
|
817
|
+
this._appendTimeline({
|
|
818
|
+
sourceId,
|
|
819
|
+
kind: "path-unresolved",
|
|
820
|
+
stateName: event.stateName,
|
|
821
|
+
label: event.path,
|
|
822
|
+
detail: `${event.source}: "${event.missingSegment}" is not declared`,
|
|
823
|
+
subscriberCount: null,
|
|
824
|
+
});
|
|
825
|
+
return;
|
|
826
|
+
}
|
|
827
|
+
case "state:binding-apply-error": {
|
|
828
|
+
if (this.isHiddenStateName(event.stateName)) {
|
|
829
|
+
return;
|
|
830
|
+
}
|
|
831
|
+
// 隔離された適用失敗。bindingType を detail 先頭に置くのは、構造
|
|
832
|
+
// (for / if)の失敗と値の失敗で影響範囲が違うため。
|
|
833
|
+
this._appendTimeline({
|
|
834
|
+
sourceId,
|
|
835
|
+
kind: "binding-apply-error",
|
|
836
|
+
stateName: event.stateName,
|
|
837
|
+
label: event.path,
|
|
838
|
+
detail: `${event.bindingType}: ${formatError(event.error)}`,
|
|
839
|
+
subscriberCount: null,
|
|
840
|
+
});
|
|
841
|
+
return;
|
|
842
|
+
}
|
|
802
843
|
case "propagation:suppressed": {
|
|
803
844
|
// two-way エコーの辺単位抑止。state 名を持たない(node+member が主語)
|
|
804
845
|
// ため hidden 判定はここでは行わない。
|
|
@@ -1811,6 +1852,14 @@ class WcsDevtools extends HTMLElement {
|
|
|
1811
1852
|
? "a $watch threw; the runtime isolated it (console.error only)"
|
|
1812
1853
|
: "a $watch write chain hit the depth limit and was cut off";
|
|
1813
1854
|
}
|
|
1855
|
+
// 配線の死(解決しないパス)と隔離された適用失敗も、ランタイムが console に
|
|
1856
|
+
// 出すだけで続行する = 見ていなければ気づけない種類なので warn に乗せる。
|
|
1857
|
+
if (entry.kind === "path-unresolved" || entry.kind === "binding-apply-error") {
|
|
1858
|
+
kind.classList.add("warn");
|
|
1859
|
+
kind.title = entry.kind === "path-unresolved"
|
|
1860
|
+
? "a wired path does not resolve on the state; its updates are dropped"
|
|
1861
|
+
: "a binding threw while applying; the runtime isolated it (console.error only)";
|
|
1862
|
+
}
|
|
1814
1863
|
// 伝播の打ち切りと契約 drift も「黙って起きる異常」なので warn に乗せる。
|
|
1815
1864
|
// suppressed / coalesced は定常動作(エコー抑止・合流)のため通常表示。
|
|
1816
1865
|
if (entry.kind === "propagation-hop-limit" || entry.kind === "contract-drift") {
|