@wcstack/devtools 3.5.4 → 4.0.0-rc.1
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 +3 -2
- package/README.md +3 -2
- package/dist/auto.min.js +1 -1
- package/dist/auto.min.js.map +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.esm.js +25 -1
- package/dist/index.esm.js.map +1 -1
- package/package.json +1 -1
package/README.ja.md
CHANGED
|
@@ -39,7 +39,7 @@ auto エントリは `<wcs-devtools>` を定義し、ページに無ければ `<
|
|
|
39
39
|
| ペイン | 内容 |
|
|
40
40
|
|---|---|
|
|
41
41
|
| **State** | 各ルート state ツリー(root node ごとに 1 本・ラベルはルート由来 — v2 に名前次元は無い)のトップレベルキー、配列/オブジェクトの展開、computed getter。値クリックでインライン編集 — 書き込みは通常のリアクティブパイプライン(set トラップ → 更新バッチ → DOM)を通るため、アプリコードが書いたのと同じようにページが反応する。**パス**クリックで束縛ノードをハイライト。ツリーの下には、マウント記録の **Overlays** と、`$eq` / `$eqPath` / `$eqIndex` の購読を path ごとに数えた **Keyed selection**(行・鍵・リスト単位の監視の数と最後の値)が出る。path が getter で、読む getter が全部再評価される形には `tracked` バッジが付く(`@wcstack/state` 3.0 以降)。 |
|
|
42
|
-
| **Wiring** | ライブ binding 台帳: binding ごとの `property ← path` 行と型バッジ(`text` / `prop` / `for` / …)。**⌖ pick**
|
|
42
|
+
| **Wiring** | ライブ binding 台帳: binding ごとの `property ← path` 行と型バッジ(`text` / `prop` / `for` / …)。**⌖ pick** でページ要素をクリックするとその要素の配線だけに絞れる。行クリックで束縛ノードをハイライト。**coverage** の切り替えは、state が宣言したものと、パネルが観測を始めてから起きたことを突き合わせる: `$watch` のキーごと(`fired` ×n / `never`)、command・event トークンごと(`emitted` ×n / `never` / `emitted-unheard` — どの発火も購読者ゼロ)、宣言したバインディングごと(`attached` / `never-attached`)。`@wcstack/state` 3.x では、リストに `for` のバインドも `$listKeys` の宣言も無いワイルドカードの行 watch は、`never` ではなく `prerequisite-missing` と出る(3.x ではリストへの書き込みがその watch に届かない)。4.0 の行 watch はどちらも要らないので、4.0 のページでは出ない。 |
|
|
43
43
|
| **Timeline** | ring buffer(既定 500 件): `write`(旧値が取れた場合は併記)、`batch`(drain ごとの dedup 済み更新アドレス)、`command` / `event` トークン発火(引数要約 + 購読者数 — **購読者ゼロの空撃ちには警告バッジ**。whenDefined 前配線レースの検出に効く)、state 要素の登録/解除。⏸ で一時停止、🗑 でクリア。 |
|
|
44
44
|
|
|
45
45
|
## 属性
|
|
@@ -78,8 +78,9 @@ import { DevtoolsCore, getOrCreateHookRegistry, formatValue, scanDeclaredBinding
|
|
|
78
78
|
|
|
79
79
|
const core = new DevtoolsCore({ timelineCapacity: 200 });
|
|
80
80
|
core.connect();
|
|
81
|
-
core.onChange((kind) => { /* "sources" | "roster" | "wiring" | "timeline" */ });
|
|
81
|
+
core.onChange((kind) => { /* "sources" | "roster" | "wiring" | "timeline" | "coverage" */ });
|
|
82
82
|
core.getRoster(); // 観測中の <wcs-state> 要素
|
|
83
|
+
core.getCoverageReport(); // 宣言 × 実測(coverage ビュー)
|
|
83
84
|
core.getTimeline(); // ring buffer スナップショット
|
|
84
85
|
```
|
|
85
86
|
|
package/README.md
CHANGED
|
@@ -41,7 +41,7 @@ yourself:
|
|
|
41
41
|
| Pane | What it shows |
|
|
42
42
|
|---|---|
|
|
43
43
|
| **State** | Every root state tree (one per root node, labelled by its root — v2 has no name dimension): top-level keys, expandable arrays/objects, computed getters. Click a value to edit it inline — the write goes through the normal reactive pipeline (set trap → update batch → DOM), so the page reacts exactly as if application code had written it. Click a **path** to highlight the DOM nodes bound to it. Below the tree, **Overlays** lists the mount records and **Keyed selection** the `$eq` / `$eqPath` / `$eqIndex` subscriptions per path — rows, keys, list watchers and the last value — with a `tracked` badge when the path is a getter, so every getter reading it re-evaluates (`@wcstack/state` 3.0+). |
|
|
44
|
-
| **Wiring** | The live binding ledger: `property ← path` rows per binding, with type badges (`text` / `prop` / `for` / …). Use **⌖ pick** to click a page element and see only its bindings. Rows highlight their bound nodes on click. |
|
|
44
|
+
| **Wiring** | The live binding ledger: `property ← path` rows per binding, with type badges (`text` / `prop` / `for` / …). Use **⌖ pick** to click a page element and see only its bindings. Rows highlight their bound nodes on click. The **coverage** toggle compares what the state declares with what has happened since the panel started observing: each `$watch` key (`fired` ×n / `never`), each command and event token (`emitted` ×n / `never` / `emitted-unheard` — every emit had zero subscribers) and each declared binding (`attached` / `never-attached`). With `@wcstack/state` 3.x, a wildcard row watch whose list has no `for` binding and no `$listKeys` declaration shows `prerequisite-missing` instead of `never` (3.x list writes do not reach such a watch); 4.0 row watches need neither, so a 4.0 page never shows it. |
|
|
45
45
|
| **Timeline** | A ring buffer (default 500) of `write` (with old value when available), `batch` (deduplicated update addresses per drain), `command` / `event` token emissions (with argument summaries and subscriber counts — **zero-subscriber emissions get a warning badge**, catching wired-before-`whenDefined` races), and state element registration. ⏸ pauses, 🗑 clears. |
|
|
46
46
|
|
|
47
47
|
## Attributes
|
|
@@ -80,8 +80,9 @@ import { DevtoolsCore, getOrCreateHookRegistry, formatValue, scanDeclaredBinding
|
|
|
80
80
|
|
|
81
81
|
const core = new DevtoolsCore({ timelineCapacity: 200 });
|
|
82
82
|
core.connect();
|
|
83
|
-
core.onChange((kind) => { /* "sources" | "roster" | "wiring" | "timeline" */ });
|
|
83
|
+
core.onChange((kind) => { /* "sources" | "roster" | "wiring" | "timeline" | "coverage" */ });
|
|
84
84
|
core.getRoster(); // observed <wcs-state> elements
|
|
85
|
+
core.getCoverageReport(); // declared × observed (the coverage view)
|
|
85
86
|
core.getTimeline(); // ring buffer snapshot
|
|
86
87
|
```
|
|
87
88
|
|
package/dist/auto.min.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e="__WCSTACK_DEVTOOLS_HOOK__";function t(){const t=globalThis,n=t[e];if(void 0!==n)return 2!==n.version&&console.warn(`[wcstack/devtools] hook registry version mismatch: found ${n.version}, expected 2. Keeping the existing registry (first-wins).`),n;const i=function(){const e=new Map,t=new Set,n=e=>{if(0===t.size)return void e._setSink(null);const n=e.id;e._setSink(e=>{for(const i of t)i.onEvent?.(n,e)})};return{version:2,sources:e,register(i){if(!e.has(i.id)){e.set(i.id,i),n(i);for(const e of t)e.onSourceRegistered?.(i)}},unregister(n){const i=e.get(n);if(void 0!==i){i._setSink(null),e.delete(n);for(const e of t)e.onSourceUnregistered?.(n)}},addListener(i){t.add(i);for(const t of e.values())n(t),i.onSourceRegistered?.(t);return()=>{if(t.delete(i))for(const t of e.values())n(t)}}}}();return t[e]=i,i}const n=80;function i(e){const t=e.constructor,n=t?.name;return"string"==typeof n&&n.length>0?n:"Object"}function o(e,t=2){switch(typeof e){case"string":return`"${e.length>n?e.slice(0,n)+"…":e}"`;case"number":case"boolean":case"bigint":return String(e);case"symbol":return e.toString();case"undefined":return"undefined";case"function":return"[[Function]]"}if(null===e)return"null";const s=e;if(Array.isArray(s)){if(t<=0)return`[[Array(${s.length})]]`;const e=s.slice(0,3).map(e=>o(e,t-1)),n=s.length>3?`, …(${s.length})`:"";return`[${e.join(", ")}${n}]`}if(function(e){const t=Object.getPrototypeOf(e);return t===Object.prototype||null===t}(s)){if(t<=0)return"[[Object]]";const e=Object.keys(s),n=e.slice(0,3).map(e=>`${e}: ${o(s[e],t-1)}`),i=e.length>3?`, …(${e.length})`:"";return`{${n.join(", ")}${i}}`}return`[[${i(s)}]]`}function s(e){if(null!==e&&"object"==typeof e){const{name:t,message:o}=e;if("string"==typeof o){const s="string"==typeof t&&t.length>0?t:i(e),r=o.length>n?o.slice(0,n)+"…":o;return r.length>0?`${s}: ${r}`:s}}return o(e,1)}function r(e){if(0===e.length)return"";const t=e.slice(0,3).map(e=>{const t=o(e,1);return t.length>n?t.slice(0,n)+"…":t}),i=e.length>3?`, …(${e.length})`:"";return`${t.join(", ")}${i}`}const a=String.fromCharCode(0);function c(e){return e}function l(e,t){return e+a+t}function d(e,t){return e+a+t}function h(e){return"undefined"!=typeof ShadowRoot&&e instanceof ShadowRoot?`<${e.host.tagName.toLowerCase()}>`:9===e.nodeType?"document":e.nodeName.toLowerCase()}function u(e,t,n){return void 0===n?{kind:e,name:t,status:"never",count:0,note:null}:n.zeroSubscriberCount===n.count?{kind:e,name:t,status:"emitted-unheard",count:n.count,note:`all ${n.count} emit(s) had 0 subscribers`}:{kind:e,name:t,status:"emitted",count:n.count,note:n.zeroSubscriberCount>0?`${n.zeroSubscriberCount}/${n.count} emit(s) had 0 subscribers`:null}}class p{_timelineCapacity;_removeListener=null;_sources=new Map;_roster=new Map;_wiringByPathKey=new Map;_wiringEntryByBinding=new WeakMap;_timeline=[];_seq=0;_paused=!1;_changeListeners=new Set;_observingSince=null;_watchFiredStats=new Map;_tokenEmitStats=new Map;_everAttachedKeys=new Set;constructor(e){this._timelineCapacity=e?.timelineCapacity??500}get connected(){return null!==this._removeListener}get paused(){return this._paused}set paused(e){this._paused=e}connect(){if(null!==this._removeListener)return;this._observingSince=performance.now();const e=t();this._removeListener=e.addListener({onSourceRegistered:e=>{this._sources.set(e.id,e),this._refreshRosterOf(e),this._notify("sources")},onSourceUnregistered:e=>{this._sources.delete(e),this._roster.delete(e),this._notify("sources"),this._notify("roster")},onEvent:(e,t)=>{this._ingest(e,t)}})}disconnect(){null!==this._removeListener&&(this._removeListener(),this._removeListener=null,this._sources.clear(),this._roster.clear(),this._wiringByPathKey.clear(),this._wiringEntryByBinding=new WeakMap,this._observingSince=null,this._watchFiredStats.clear(),this._tokenEmitStats.clear(),this._everAttachedKeys.clear(),this._notify("sources"),this._notify("roster"),this._notify("wiring"),this._notify("coverage"))}get observingSince(){return this._observingSince}onChange(e){return this._changeListeners.add(e),()=>{this._changeListeners.delete(e)}}getSources(){return[...this._sources.values()]}getRoster(){const e=[];for(const t of this._roster.values())e.push(...t);return e}refreshRoster(){for(const e of this._sources.values())this._refreshRosterOf(e);this._notify("roster")}getTimeline(){return this._timeline}clearTimeline(){this._timeline=[],this._notify("timeline")}getWiringForPath(e,t){const n=this._wiringByPathKey.get(e);if(void 0===n)return[];const i=this._collectAlive(n);return void 0===t?i:i.filter(e=>null===e.stateElementRef||e.stateElementRef.deref()===t)}getAllWiring(){const e=[];for(const t of this._wiringByPathKey.values())e.push(...this._collectAlive(t));return e}getWiringForNode(e){const t=[];for(const n of this._wiringByPathKey.values())for(const i of this._collectAlive(n)){const n=i.bindingRef.deref();(n.node===e||n.replaceNode===e||e.contains(n.node)||e.contains(n.replaceNode))&&t.push(i)}return t}getCanonicalDeclared(){let e=!1;const t=[],n=new Set;for(const[i,o]of this._sources){if("function"!=typeof o.getDeclaredBindings)continue;e=!0;const s=new Set;for(const e of this._roster.get(i)??[])s.add(e.rootNode);for(const e of s)for(const i of o.getDeclaredBindings(e)){const e=[i.statePathName,i.propName,i.bindingType,i.origin,i.raw].join(a);n.has(e)||(n.add(e),t.push(i))}}return e?t:null}getCoverageReport(e){const t=[];for(const n of this.getRoster()){const i=n.summary;if(void 0===e||i.element===e){for(const e of i.watchPaths??[]){const n=this._measuredFor(this._watchFiredStats,c(e),i.element)?.count??0;if(n>0){t.push({kind:"watch",name:e,status:"fired",count:n,note:null});continue}const o=void 0!==i.keyedListPaths;let s=null;for(let t=e.indexOf(".*");-1!==t;t=e.indexOf(".*",t+2)){const n=e.slice(0,t);if(!(i.paths.list.has(n)||(i.keyedListPaths?.has(n)??!1))){s=n;break}}null===s?t.push({kind:"watch",name:e,status:"never",count:0,note:null}):t.push({kind:"watch",name:e,status:"prerequisite-missing",count:0,note:o?`list "${s}" has no for binding and no $listKeys declaration — list writes never reach its rows (only explicit-index writes can fire this watch)`:`no for binding observed for list "${s}" (a $listKeys declaration would still let list writes fire it)`})}for(const e of i.commandTokenNames)t.push(u("command",e,this._measuredFor(this._tokenEmitStats,l("command",e),i.element)));for(const e of i.eventTokenNames)t.push(u("eventToken",e,this._measuredFor(this._tokenEmitStats,l("event",e),i.element)))}}const n=this.getCanonicalDeclared();if(null!==n){const e=new Set;for(const i of n){if("for"===i.bindingType||"if"===i.bindingType||"elseif"===i.bindingType||"else"===i.bindingType)continue;if(i.propName.startsWith("eventToken."))continue;const n=d(i.statePathName,i.propName);if(e.has(n))continue;e.add(n);const o=this._everAttachedKeys.has(n);t.push({kind:"binding",name:`${i.propName} ← ${i.statePathName}`,status:o?"attached":"never-attached",count:o?1:0,note:"fragment"===i.origin?"template interior (attaches when rows materialize)":null})}}return t}keysOf(e){const t=this._sources.get(e.sourceId);return void 0===t||"function"!=typeof t.keys?[]:t.keys(e.rootNode)}overlaysOf(e){const t=this._sources.get(e.sourceId);return void 0===t||"function"!=typeof t.overlays?null:t.overlays(e.rootNode)}keyedSubscriptionsOf(e){const t=this._sources.get(e.sourceId);return void 0===t||"function"!=typeof t.keyedSubscriptions?null:t.keyedSubscriptions(e.rootNode)}readValue(e,t,n){const i=this._sources.get(e.sourceId);if(void 0!==i)return i.read(e.rootNode,t,n)}writeValue(e,t,n,i){const o=this._sources.get(e.sourceId);void 0!==o&&o.write(e.rootNode,t,n,i)}_notify(e){for(const t of this._changeListeners)t(e)}_refreshRosterOf(e){const t=[],n=new Map;for(const i of e.getStateElements()){const o=h(i.rootNode),s=(n.get(o)??0)+1;n.set(o,s),t.push({sourceId:e.id,label:1===s?o:`${o}#${s}`,rootNode:i.rootNode,summary:i})}this._roster.set(e.id,t)}_statFor(e,t,n){let i=e.get(t);void 0===i&&(i=[],e.set(t,i));const o="object"==typeof n&&null!==n?n:null;for(const e of i)if(null===o?null===e.stateElementRef:e.stateElementRef?.deref()===o)return e;const s={stateElementRef:null===o?null:new WeakRef(o),count:0,zeroSubscriberCount:0};return i.push(s),s}_measuredFor(e,t,n){const i=e.get(t);if(void 0===i)return;let o=0,s=0;for(let e=i.length-1;e>=0;e--){const t=i[e].stateElementRef;null===t||void 0!==t.deref()?null!==t&&t.deref()!==n||(o+=i[e].count,s+=i[e].zeroSubscriberCount):i.splice(e,1)}return 0===i.length&&e.delete(t),0===o?void 0:{count:o,zeroSubscriberCount:s}}_collectAlive(e){const t=[];for(const n of e)void 0!==n.bindingRef.deref()?t.push(n):e.delete(n);return t}_appendTimeline(e){if(this._paused)return;this._timeline.push({...e,seq:this._seq++,time:performance.now()});const t=this._timeline.length-this._timelineCapacity;t>0&&this._timeline.splice(0,t),this._notify("timeline")}_labelOf(e){const t=e.listIndex?.indexes,n=e.absolutePathInfo.pathInfo.path;return void 0!==t?`${n}[${t.join(",")}]`:n}_ingest(e,t){switch(t.type){case"state:element-registered":{const n=this._sources.get(e);return void 0!==n&&(this._refreshRosterOf(n),this._notify("roster")),void this._appendTimeline({sourceId:e,kind:"element-registered",label:h(t.rootNode),detail:"",subscriberCount:null})}case"state:element-unregistered":{const n=this._sources.get(e);return void 0!==n&&(this._refreshRosterOf(n),this._notify("roster")),void this._appendTimeline({sourceId:e,kind:"element-unregistered",label:h(t.rootNode),detail:"",subscriberCount:null})}case"state:write":{const n=t.hasOldValue?`${o(t.value)} (was ${o(t.oldValue)})`:o(t.value);return void this._appendTimeline({sourceId:e,kind:"write",label:this._labelOf(t.absoluteAddress),detail:n,subscriberCount:null})}case"state:update-batch":{const n=[];let i=0;for(const e of t.addresses)i++,n.length<3&&n.push(this._labelOf(e));if(0===i)return;const o=i>n.length?`, …(${i})`:"";return void this._appendTimeline({sourceId:e,kind:"batch",label:`${i} address${1===i?"":"es"}`,detail:`${n.join(", ")}${o}`,subscriberCount:null})}case"state:binding-added":{const n=t.absoluteAddress.absolutePathInfo.pathInfo.path,i=n;let o=this._wiringByPathKey.get(i);void 0===o&&(o=new Set,this._wiringByPathKey.set(i,o));const s=t.absoluteAddress.absolutePathInfo.stateElement,r={sourceId:e,path:n,propName:t.binding.propName,bindingType:t.binding.bindingType,bindingRef:new WeakRef(t.binding),stateElementRef:"object"==typeof s&&null!==s?new WeakRef(s):null};return o.add(r),this._wiringEntryByBinding.set(t.binding,r),this._everAttachedKeys.add(d(n,t.binding.propName)),this._notify("wiring"),void this._notify("coverage")}case"state:binding-removed":{const e=this._wiringEntryByBinding.get(t.binding);if(void 0===e)return;this._wiringEntryByBinding.delete(t.binding);const n=e.path,i=this._wiringByPathKey.get(n);return void 0!==i&&(i.delete(e),0===i.size&&this._wiringByPathKey.delete(n)),void this._notify("wiring")}case"state:binding-cleared":{const e=t.absoluteAddress.absolutePathInfo.pathInfo.path;return void(this._wiringByPathKey.delete(e)&&this._notify("wiring"))}case"state:token-emit":{const n=this._statFor(this._tokenEmitStats,l(t.kind,t.tokenName),t.stateElement);return n.count+=1,0===t.subscriberCount&&(n.zeroSubscriberCount+=1),this._notify("coverage"),void this._appendTimeline({sourceId:e,kind:t.kind,label:t.tokenName,detail:r(t.args),subscriberCount:t.subscriberCount})}case"state:watch-fired":return this._statFor(this._watchFiredStats,t.path,t.stateElement).count+=1,void this._notify("coverage");case"state:watch-error":return void this._appendTimeline({sourceId:e,kind:"watch-error",label:t.path,detail:`${t.phase}: ${s(t.error)}`,subscriberCount:null});case"state:watch-chain-limit":return void this._appendTimeline({sourceId:e,kind:"watch-chain-limit",label:`depth > ${t.maxDepth}`,detail:t.paths.join(", "),subscriberCount:null});case"state:render-chain-limit":return void this._appendTimeline({sourceId:e,kind:"render-chain-limit",label:`depth > ${t.maxDepth}`,detail:t.paths.join(", "),subscriberCount:null});case"state:path-unresolved":return void this._appendTimeline({sourceId:e,kind:"path-unresolved",label:t.path,detail:`${t.source}: "${t.missingSegment}" is not declared`,subscriberCount:null});case"state:binding-apply-error":return void this._appendTimeline({sourceId:e,kind:"binding-apply-error",label:t.path,detail:`${t.bindingType}: ${s(t.error)}`,subscriberCount:null});case"propagation:suppressed":return void this._appendTimeline({sourceId:e,kind:"propagation-suppressed",label:t.member,detail:`${t.reason} (tx ${t.transactionId}, edge ${t.edgeId})`,subscriberCount:null});case"propagation:coalesced":return void this._appendTimeline({sourceId:e,kind:"propagation-coalesced",label:this._labelOf(t.absoluteAddress),detail:`tx ${t.droppedTransactionId} dropped (winner tx ${t.winnerTransactionId})`,subscriberCount:null});case"propagation:hop-limit":return void this._appendTimeline({sourceId:e,kind:"propagation-hop-limit",label:this._labelOf(t.absoluteAddress),detail:`hop ${t.hop} (tx ${t.transactionId})`,subscriberCount:null});case"contract:drift":{const n=void 0!==t.member?`: ${t.member}`:"",i="event-mismatch"===t.reason?` (sidecar ${t.sidecarEvent??"?"} / live ${t.liveEvent??"?"})`:"";return void this._appendTimeline({sourceId:e,kind:"contract-drift",label:t.tag,detail:`${t.reason}${n}${i}`,subscriberCount:null})}case"contract:manifest-read":case"contract:unsupported-extension":return}}}const m=["wcs-text","wcs-for","wcs-if","wcs-elseif","wcs-else"];function g(e,t,n){const i=t.trim();if(0===i.length)return null;const o=i.indexOf(":");if(o<0)return null;const s=i.slice(0,o).trim(),r=i.slice(o+1).trim();if(0===s.length||0===r.length)return null;const[a,...c]=r.split("|").map(e=>e.trim());return{element:e,propName:s,path:a,filters:c.filter(e=>e.length>0),origin:n,raw:i}}class f extends HTMLElement{static get observedAttributes(){return["open","dock","hotkey"]}_core=null;_removeCoreListener=null;_panel=null;_badge=null;_stateSelect=null;_paneElements={};_wiringView="wiring";_highlightLayer=null;_dirtyPanes=new Set;_renderScheduled=!1;_selectedRosterKey=null;_selectedPath=null;_pickedNode=null;_pickMode=!1;_expanded=new Set;_hotkeyHandler=null;_pickHandler=null;get core(){return this._core}connectedCallback(){if(document.documentElement.hasAttribute("data-wcs-server"))return;null===this.shadowRoot&&this._buildShadow();const e=Number(this.getAttribute("buffer")??"");this._core=new p({timelineCapacity:Number.isFinite(e)&&e>0?e:void 0}),this._removeCoreListener=this._core.onChange(e=>{"roster"===e||"sources"===e?(this._markDirty("state"),this._markDirty("wiring")):"wiring"===e?this._markDirty("wiring"):"coverage"===e?"coverage"===this._wiringView&&this._markDirty("wiring"):this._markDirty("timeline")}),this._core.connect(),this._applyDock(),this._applyOpen(),this._installHotkey(),this._markDirty("state"),this._markDirty("wiring"),this._markDirty("timeline")}disconnectedCallback(){this._removeCoreListener?.(),this._removeCoreListener=null,this._core?.disconnect(),this._core=null,this._uninstallHotkey(),this._exitPickMode()}attributeChangedCallback(e){null!==this.shadowRoot&&("open"===e?this._applyOpen():"dock"===e?this._applyDock():"hotkey"===e&&(this._uninstallHotkey(),this._installHotkey()))}__flushRenderForTest(){this._renderDirty()}_buildShadow(){const e=this.attachShadow({mode:"open"}),t=document.createElement("style");t.textContent='\n:host {\n all: initial;\n position: fixed;\n z-index: 2147483647;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 12px;\n inset: auto 0 0 auto;\n}\n* { box-sizing: border-box; }\n.badge {\n position: fixed;\n right: 12px;\n bottom: 12px;\n width: 40px;\n height: 40px;\n border-radius: 20px;\n border: 1px solid #2b4f78;\n background: #10263f;\n color: #9fd0ff;\n font-weight: 700;\n cursor: pointer;\n}\n.panel {\n position: fixed;\n display: flex;\n flex-direction: column;\n background: #0d1b2a;\n color: #d7e3f4;\n border: 1px solid #2b4f78;\n box-shadow: 0 0 24px rgba(0,0,0,.5);\n}\n.panel.dock-bottom { left: 0; right: 0; bottom: 0; height: 45vh; }\n.panel.dock-right { top: 0; right: 0; bottom: 0; width: 420px; }\n.panel[hidden] { display: none; }\nheader {\n display: flex;\n gap: 6px;\n align-items: center;\n padding: 6px 8px;\n border-bottom: 1px solid #2b4f78;\n background: #10263f;\n}\nheader .title { font-weight: 700; color: #9fd0ff; margin-right: 4px; }\nheader select, header button {\n font: inherit;\n background: #16324f;\n color: #d7e3f4;\n border: 1px solid #2b4f78;\n border-radius: 4px;\n padding: 2px 8px;\n cursor: pointer;\n}\nheader button[aria-pressed="true"] { background: #2b5d8f; }\nheader .spacer { flex: 1; }\n.panes { display: flex; flex: 1; min-height: 0; }\n.pane { flex: 1; min-width: 0; overflow: auto; padding: 6px 8px; border-right: 1px solid #1d3a5c; }\n.pane:last-child { border-right: none; }\n.pane h3 {\n margin: 0 0 6px;\n font-size: 11px;\n text-transform: uppercase;\n letter-spacing: .08em;\n color: #7ba7d4;\n}\n.tree-row { display: flex; gap: 6px; padding: 1px 0; align-items: baseline; white-space: nowrap; }\n.tree-row .toggle { width: 14px; cursor: pointer; color: #7ba7d4; user-select: none; }\n.tree-row .key { color: #9fd0ff; cursor: pointer; }\n.tree-row .value { color: #ffd9a0; overflow: hidden; text-overflow: ellipsis; }\n.tree-row .value.editable { cursor: pointer; }\n.tree-row input { font: inherit; background: #16324f; color: #ffd9a0; border: 1px solid #2b4f78; }\n.badge-tag {\n display: inline-block;\n padding: 0 4px;\n border-radius: 3px;\n font-size: 10px;\n background: #26456a;\n color: #a8c6e8;\n}\n.badge-tag.warn { background: #6a3326; color: #ffb3a0; }\n.badge-tag.declared { background: #4a4426; color: #efe3a0; }\n.wiring-row, .timeline-row { padding: 1px 0; white-space: nowrap; }\n.wiring-row .prop { color: #b7f0c0; }\n.wiring-row .path { color: #9fd0ff; }\n.timeline-row .t { color: #6f88a3; }\n.timeline-row .label { color: #9fd0ff; }\n.timeline-row .detail { color: #ffd9a0; }\n.timeline-row .kind { display: inline-block; min-width: 52px; text-align: center; }\n.empty { color: #6f88a3; font-style: italic; padding: 4px 0; }\n.notice { color: #efe3a0; padding: 2px 0 6px; }\n.notice button { font: inherit; margin-left: 6px; cursor: pointer; }\n.wiring-row .detail { color: #6f88a3; }\n.overlays-heading { margin-top: 10px; }\n.overlay-row { padding: 1px 0; white-space: nowrap; }\n.overlay-row .prop { color: #b7f0c0; }\n.overlay-row .path { color: #9fd0ff; }\n.overlay-row .detail { color: #6f88a3; }\n.keyed-row { padding: 1px 0; white-space: nowrap; }\n.keyed-row .path { color: #9fd0ff; }\n.keyed-row .detail { color: #6f88a3; }\n.wiring-tabs { padding: 0 0 4px; }\n.wiring-tabs button { font: inherit; cursor: pointer; margin-right: 4px; opacity: 0.6; }\n.wiring-tabs button.active { opacity: 1; font-weight: bold; }\n.hl-box {\n position: fixed;\n pointer-events: none;\n border: 1px solid #58c2ff;\n background: rgba(88,194,255,.18);\n}\n',e.append(t);const n=document.createElement("button");n.className="badge",n.title="wcstack DevTools",n.textContent="WCS",n.addEventListener("click",()=>this.toggle()),e.append(n),this._badge=n;const i=document.createElement("div");i.className="panel dock-bottom",i.hidden=!0;const o=document.createElement("header"),s=document.createElement("span");s.className="title",s.textContent="wcstack devtools",o.append(s);const r=document.createElement("select");r.title="state element",r.addEventListener("change",()=>{this._selectedRosterKey=r.value||null,this._selectedPath=null,this._expanded.clear(),this._markDirty("state"),this._markDirty("wiring")}),o.append(r),this._stateSelect=r;const a=this._headerButton(o,"⌖ pick","pick a page element");a.addEventListener("click",()=>{this._pickMode?this._exitPickMode():this._enterPickMode(),a.setAttribute("aria-pressed",String(this._pickMode))}),a.dataset.role="pick";const c=this._headerButton(o,"⏸","pause timeline");c.addEventListener("click",()=>{const e=this._core;null!==e&&(e.paused=!e.paused,c.setAttribute("aria-pressed",String(e.paused)))}),c.dataset.role="pause";const l=this._headerButton(o,"🗑","clear timeline");l.addEventListener("click",()=>{this._core?.clearTimeline()}),l.dataset.role="clear";const d=document.createElement("span");d.className="spacer",o.append(d);const h=this._headerButton(o,"dock","toggle dock position");h.addEventListener("click",()=>{const e="bottom"===(this.getAttribute("dock")??"bottom")?"right":"bottom";this.setAttribute("dock",e)}),h.dataset.role="dock";const u=this._headerButton(o,"×","close");u.addEventListener("click",()=>this.toggle(!1)),u.dataset.role="close",i.append(o);const p=document.createElement("div");p.className="panes";for(const[e,t]of[["state","State"],["wiring","Wiring"],["timeline","Timeline"]]){const n=document.createElement("section");n.className=`pane pane-${e}`;const i=document.createElement("h3");i.textContent=t;const o=document.createElement("div");o.className="pane-body",n.append(i,o),p.append(n),this._paneElements[e]=o}i.append(p),e.append(i),this._panel=i;const m=document.createElement("div");m.className="hl-layer",e.append(m),this._highlightLayer=m}_headerButton(e,t,n){const i=document.createElement("button");return i.textContent=t,i.title=n,i.setAttribute("aria-pressed","false"),e.append(i),i}get open(){return this.hasAttribute("open")}toggle(e){e??!this.open?this.setAttribute("open",""):this.removeAttribute("open")}_applyOpen(){this._panel.hidden=!this.open,this._badge.hidden=this.open,this.open&&(this._markDirty("state"),this._markDirty("wiring"),this._markDirty("timeline"))}_applyDock(){const e="right"===this.getAttribute("dock")?"right":"bottom";this._panel.classList.toggle("dock-right","right"===e),this._panel.classList.toggle("dock-bottom","bottom"===e)}_installHotkey(){const e=this.getAttribute("hotkey")??"Alt+Shift+D";if("none"===e)return;const t=e.split("+").map(e=>e.trim().toLowerCase()),n=t[t.length-1],i=t.includes("alt"),o=t.includes("shift"),s=t.includes("ctrl"),r=t.includes("meta");this._hotkeyHandler=e=>{e.key.toLowerCase()===n&&e.altKey===i&&e.shiftKey===o&&e.ctrlKey===s&&e.metaKey===r&&(e.preventDefault(),this.toggle())},window.addEventListener("keydown",this._hotkeyHandler)}_uninstallHotkey(){null!==this._hotkeyHandler&&(window.removeEventListener("keydown",this._hotkeyHandler),this._hotkeyHandler=null)}_enterPickMode(){this._pickMode=!0,this._pickHandler=e=>{const t=e.target;t.getRootNode()!==this.shadowRoot&&t!==this&&(e.preventDefault(),e.stopPropagation(),this._pickedNode=t,this._selectedPath=null,this._exitPickMode(),this._markDirty("wiring"))},document.addEventListener("click",this._pickHandler,{capture:!0})}_exitPickMode(){null!==this._pickHandler&&(document.removeEventListener("click",this._pickHandler,{capture:!0}),this._pickHandler=null),this._pickMode=!1;const e=this.shadowRoot?.querySelector('button[data-role="pick"]');e?.setAttribute("aria-pressed","false")}_markDirty(e){this._dirtyPanes.add(e),this._renderScheduled||(this._renderScheduled=!0,requestAnimationFrame(()=>{this._renderDirty()}))}_renderDirty(){if(this._renderScheduled=!1,null===this._core||null===this.shadowRoot)return void this._dirtyPanes.clear();const e=this._dirtyPanes;this._dirtyPanes=new Set,e.has("state")&&this._renderStatePane(),e.has("wiring")&&this._renderWiringPane(),e.has("timeline")&&this._renderTimelinePane()}_rosterKey(e){return`${e.sourceId}:${e.label}`}_selectedRoster(){const e=this._core.getRoster();if(0===e.length)return null;return e.find(e=>this._rosterKey(e)===this._selectedRosterKey)??e[0]}_renderStatePane(){const e=this._core,t=this._paneElements.state,n=this._stateSelect,i=e.getRoster(),o=this._selectedRoster();if(n.replaceChildren(...i.map(e=>{const t=document.createElement("option");return t.value=this._rosterKey(e),t.textContent=`${e.label} (${e.sourceId.slice(0,12)})`,t.selected=null!==o&&this._rosterKey(e)===this._rosterKey(o),t})),t.replaceChildren(),null===o)return void t.append(this._emptyRow("no <wcs-state> elements observed"));this._selectedRosterKey=this._rosterKey(o);const s=e.keysOf(o);if(0===s.length)return t.append(this._emptyRow("no readable keys (runtime without keys() API?)")),this._renderOverlaysSection(t,o),void this._renderKeyedSection(t,o);for(const e of s)this._renderTreeNode(t,o,{path:e,indexes:[]},e,0);this._renderOverlaysSection(t,o),this._renderKeyedSection(t,o)}_renderKeyedSection(e,t){const n=this._core.keyedSubscriptionsOf(t);if(null===n||0===n.length)return;const i=document.createElement("h3");i.className="overlays-heading",i.textContent=`Keyed selection (${n.length} path${1===n.length?"":"s"})`,e.append(i);for(const t of n)e.append(this._keyedRow(t))}_keyedRow(e){const t=document.createElement("div");t.className="keyed-row";const n=document.createElement("span");if(n.className="path",n.textContent=e.path,t.append(n),e.tracked){const e=document.createElement("span");e.className="badge-tag warn",e.textContent="tracked",e.title="the path is a getter or under one, so $eq cannot subscribe by key: every getter that reads it re-evaluates when it changes",t.append(document.createTextNode(" "),e)}const i=[];e.rows>0&&i.push(`rows ${e.rows} · keys ${e.keys}`),e.lists>0&&i.push(`list watchers ${e.lists}`),e.tracked||i.push(`last ${o(e.lastValue,1)}`);const s=document.createElement("span");return s.className="detail",s.textContent=i.length>0?` ${i.join(" · ")}`:"",t.append(s),t}_renderOverlaysSection(e,t){const n=this._core.overlaysOf(t);if(null===n||0===n.length)return;const i=document.createElement("h3");i.className="overlays-heading",i.textContent=`Overlays (${n.length} mount${1===n.length?"":"s"})`,e.append(i);for(const t of n)e.append(this._overlayRow(t))}_overlayRow(e){const t=document.createElement("div");t.className="overlay-row";const n=document.createElement("span");n.className="badge-tag",n.textContent=e.marker;const i=document.createElement("span");i.className="prop",i.textContent=`<${e.componentTag}>`;const o=document.createElement("span");o.className="path",o.textContent=e.stateProp,t.append(n,document.createTextNode(" "),i,document.createTextNode(" "),o);const s=[];for(const t of e.mountTable)s.push(`${""===t.inner?"(root)":t.inner} → ${t.outer}`);e.delta>0&&s.push(`Δ${e.delta}`),e.privateKeys.length>0&&s.push(`private: ${e.privateKeys.join(", ")}`);const r=e.exports??[];if(r.length>0&&s.push(`exports: ${r.join(", ")}`),e.getterKeys.length>0&&s.push(`getters: ${e.getterKeys.join(", ")}`),s.length>0){const e=document.createElement("span");e.className="detail",e.textContent=` ${s.join(" · ")}`,t.append(e)}return t}_renderTreeNode(e,t,n,i,s){const r=this._core;let a,c=!0;try{a=r.readValue(t,n.path,n.indexes)}catch{c=!1}const l=document.createElement("div");l.className="tree-row",l.style.paddingLeft=14*s+"px";const d=c&&function(e){if(Array.isArray(e))return!0;if(null===e||"object"!=typeof e)return!1;const t=Object.getPrototypeOf(e);return t===Object.prototype||null===t}(a),h=function(e){return`${e.path}#${e.indexes.join(",")}`}(n),u=d&&this._expanded.has(h),p=document.createElement("span");p.className="toggle",p.textContent=d?u?"▾":"▸":"",d&&p.addEventListener("click",()=>{this._expanded.has(h)?this._expanded.delete(h):this._expanded.add(h),this._markDirty("state")}),l.append(p);const m=document.createElement("span");m.className="key",m.textContent=`${i}:`,m.title=n.path,m.addEventListener("click",()=>{this._selectedPath=n.path,this._pickedNode=null,this._markDirty("wiring"),this._highlightPath(t,n.path)}),l.append(m);const g=document.createElement("span");if(g.className="value",c){g.textContent=o(a,1);(null===a||"object"!=typeof a)&&"function"!=typeof a&&(g.classList.add("editable"),g.title="click to edit",g.addEventListener("click",()=>{this._beginEdit(l,g,t,n,a)}))}else g.textContent="(unreadable getter)";if(l.append(g),e.append(l),u)if(Array.isArray(a)){const i=Math.min(a.length,20);for(let o=0;o<i;o++)this._renderTreeNode(e,t,{path:`${n.path}.*`,indexes:[...n.indexes,o]},`[${o}]`,s+1);if(a.length>i){const t=this._emptyRow(`…(${a.length} items)`);t.style.paddingLeft=14*(s+1)+"px",e.append(t)}}else for(const i of Object.keys(a))this._renderTreeNode(e,t,{path:`${n.path}.${i}`,indexes:n.indexes},i,s+1)}_beginEdit(e,t,n,i,o){const s=document.createElement("input");s.value="string"==typeof o?o:String(o);const r=()=>{this._core?.writeValue(n,i.path,function(e){const t=e.trim();try{return JSON.parse(t)}catch{return e}}(s.value),i.indexes),this._markDirty("state")};s.addEventListener("keydown",e=>{"Enter"===e.key?r():"Escape"===e.key&&this._markDirty("state")}),e.replaceChild(s,t),s.focus()}_renderWiringPane(){const e=this._core,t=this._paneElements.wiring;t.replaceChildren();const n=document.createElement("div");n.className="wiring-tabs";for(const[e,t]of[["wiring","wiring"],["coverage","coverage"]]){const i=document.createElement("button");i.textContent=t,this._wiringView===e&&i.classList.add("active"),i.addEventListener("click",()=>{this._wiringView=e,this._markDirty("wiring")}),n.append(i)}if(t.append(n),"coverage"===this._wiringView)return void this._renderCoverageView(t);let i,o;if(null!==this._pickedNode){i=e.getWiringForNode(this._pickedNode);const t=this._pickedNode;o=t instanceof Element?`<${t.tagName.toLowerCase()}>`:t.nodeName}else if(null!==this._selectedPath){const t=this._selectedRoster();i=null!==t?e.getWiringForPath(this._selectedPath,t.summary.element):[],o=this._selectedPath}else i=e.getAllWiring(),o="all";const s=document.createElement("div");if(s.textContent=`context: ${o} — ${i.length} live binding${1===i.length?"":"s"}`,t.append(s),i.length>0){for(const e of i)t.append(this._wiringRow(e));return}const r=e.getCanonicalDeclared(),a=this._selectedRoster(),c=null===r&&null!==a?function(e,t="data-wcs"){const n=[];for(const i of e.querySelectorAll(`[${t}]`)){const e=i.getAttribute(t);for(const t of e.split(";")){const e=g(i,t,"attribute");null!==e&&n.push(e)}}const i=(e.ownerDocument??e).createTreeWalker(e,NodeFilter.SHOW_COMMENT);let o=i.nextNode();for(;null!==o;){const e=o.textContent.trim(),t=m.find(t=>e===t||e.startsWith(t+":"));if(void 0!==t){const i=o.parentNode instanceof Element?o.parentNode:null;if(null!==i){const o=e===t?"":e.slice(t.length+1).trim();if(o.length>0){const e="wcs-text"===t?"textContent":t.slice(4);n.push(g(i,`${e}: ${o}`,"comment"))}}}o=i.nextNode()}return n}(this._scanRootOf(a)):[];if(0===(r?.length??0)&&0===c.length)return void t.append(this._emptyRow("no bindings observed"));const l=document.createElement("div");l.className="notice";const d=document.createElement("span");d.className="badge-tag declared",d.textContent=null!==r?"declared (canonical)":"declared",l.append(d,document.createTextNode(" attached late — reload to capture live bindings "));const h=document.createElement("button");if(h.textContent="reload",h.addEventListener("click",()=>{location.reload()}),l.append(h),t.append(l),null!==r)for(const e of r)t.append(this._canonicalDeclaredRow(e));else for(const e of c)t.append(this._declaredRow(e))}_renderCoverageView(e){const t=this._core,n=t.observingSince,i=document.createElement("div"),o=null===n?null:new Date(Date.now()-(performance.now()-n)).toLocaleTimeString();i.textContent=null===o?"not observing":`observing since ${o} (declared vs measured after this point)`,e.append(i);const s=this._selectedRoster(),r=t.getCoverageReport(s?.summary.element);if(0!==r.length)for(const t of r){const n=document.createElement("div");n.className="wiring-row";const i=document.createElement("span");i.className="badge-tag",i.textContent=t.kind;const o=document.createElement("span");o.className="badge-tag",o.textContent=t.count>1?`${t.status} ×${t.count}`:t.status,"never"===t.status||"never-attached"===t.status||"emitted-unheard"===t.status?o.classList.add("warn"):"prerequisite-missing"===t.status&&o.classList.add("declared");const s=document.createElement("span");if(s.className="path",s.textContent=` ${t.name} `,n.append(i,document.createTextNode(" "),s,o),null!==t.note){const e=document.createElement("span");e.className="detail",e.textContent=` ${t.note}`,n.append(e)}e.append(n)}else e.append(this._emptyRow("nothing declared to cover"))}_canonicalDeclaredRow(e){const t=document.createElement("div");t.className="wiring-row";const n=document.createElement("span");n.className="badge-tag declared",n.textContent=e.origin;const i=document.createElement("span");i.className="prop",i.textContent=e.propName;const o=document.createElement("span");o.className="path";const s=e.outFilters.map(e=>` | ${e.filterName}(${e.args.join(",")})`).join("");if(o.textContent=`${e.statePathName}${s}`,t.append(n,document.createTextNode(" "),i,document.createTextNode(" ← "),o),null!==e.node){const n=e.node;t.addEventListener("click",()=>{this._highlightNodes([n])})}return t}_scanRootOf(e){const t=e.rootNode;return t.nodeType===Node.DOCUMENT_NODE||t.nodeType===Node.DOCUMENT_FRAGMENT_NODE?t:document}_wiringRow(e){const t=document.createElement("div");t.className="wiring-row";const n=document.createElement("span");n.className="prop",n.textContent=e.propName;const i=document.createTextNode(" ← "),o=document.createElement("span");o.className="path",o.textContent=e.path;const s=document.createElement("span");return s.className="badge-tag",s.textContent=e.bindingType,t.append(s,document.createTextNode(" "),n,i,o),t.addEventListener("click",()=>{const t=e.bindingRef.deref();void 0!==t&&this._highlightNodes([t.node,t.replaceNode])}),t}_declaredRow(e){const t=document.createElement("div");t.className="wiring-row";const n=document.createElement("span");n.className="badge-tag declared",n.textContent=e.origin;const i=document.createElement("span");i.className="prop",i.textContent=e.propName;const o=document.createElement("span");return o.className="path",o.textContent=e.path,t.append(n,document.createTextNode(" "),i,document.createTextNode(" ← "),o),t.addEventListener("click",()=>{this._highlightNodes([e.element])}),t}_renderTimelinePane(){const e=this._core,t=this._paneElements.timeline,n=e.getTimeline(),i=Math.max(0,n.length-200),o=[];i>0&&o.push(this._emptyRow(`…(${i} earlier entries)`));for(let e=i;e<n.length;e++)o.push(this._timelineRow(n[e]));0===o.length&&o.push(this._emptyRow("no activity yet")),t.replaceChildren(...o),t.scrollTop=t.scrollHeight}_timelineRow(e){const t=document.createElement("div");t.className="timeline-row";const n=document.createElement("span");n.className="t",n.textContent=`${(e.time/1e3).toFixed(3)}s `;const i=document.createElement("span");i.className="badge-tag kind",i.textContent=e.kind,0===e.subscriberCount&&(i.classList.add("warn"),i.title="emitted with no subscribers"),"watch-error"!==e.kind&&"watch-chain-limit"!==e.kind||(i.classList.add("warn"),i.title="watch-error"===e.kind?"a $watch or $scan failure (read, handler, fold or write — see the phase in the detail); the runtime isolated it (console.error only)":"a $watch write chain hit the depth limit and was cut off"),"render-chain-limit"===e.kind&&(i.classList.add("warn"),i.title="writes made while rendering kept starting new batches; the chain hit the depth limit and this batch was not rendered"),"path-unresolved"!==e.kind&&"binding-apply-error"!==e.kind||(i.classList.add("warn"),i.title="path-unresolved"===e.kind?"a wired path does not resolve on the state; its updates are dropped":"a binding threw while applying; the runtime isolated it (console.error only)"),"propagation-hop-limit"!==e.kind&&"contract-drift"!==e.kind||(i.classList.add("warn"),i.title="propagation-hop-limit"===e.kind?"a two-way propagation chain hit the hop limit and was cut off":"sidecar manifest drifted from the live wcBindable declaration (live wins)");const o=document.createElement("span");o.className="label",o.textContent=` ${e.label} `;const s=document.createElement("span");return s.className="detail",s.textContent=e.detail,t.append(n,i,o,s),t}_emptyRow(e){const t=document.createElement("div");return t.className="empty",t.textContent=e,t}_highlightPath(e,t){const n=this._core,i=[];for(const o of n.getWiringForPath(t,e.summary.element)){const e=o.bindingRef.deref();void 0!==e&&i.push(e.node,e.replaceNode)}this._highlightNodes(i)}_highlightNodes(e){const t=this._highlightLayer;t.replaceChildren();const n=new Set;for(const i of e){const e=i instanceof Element?i:i.parentElement;if(null===e||n.has(e)||!e.isConnected)continue;n.add(e);const o=e.getBoundingClientRect(),s=document.createElement("div");s.className="hl-box",s.style.left=`${o.left}px`,s.style.top=`${o.top}px`,s.style.width=`${o.width}px`,s.style.height=`${o.height}px`,t.append(s)}setTimeout(()=>{t.replaceChildren()},2e3)}}const _="wcs-devtools";function b(){null===document.querySelector(_)&&document.body.appendChild(document.createElement(_))}document.documentElement.hasAttribute("data-wcs-server")||(customElements.get(_)||customElements.define(_,f),null!==document.body?b():document.addEventListener("DOMContentLoaded",b,{once:!0}));
|
|
1
|
+
const e="__WCSTACK_DEVTOOLS_HOOK__";function t(){const t=globalThis,n=t[e];if(void 0!==n)return 2!==n.version&&console.warn(`[wcstack/devtools] hook registry version mismatch: found ${n.version}, expected 2. Keeping the existing registry (first-wins).`),n;const i=function(){const e=new Map,t=new Set,n=e=>{if(0===t.size)return void e._setSink(null);const n=e.id;e._setSink(e=>{for(const i of t)i.onEvent?.(n,e)})};return{version:2,sources:e,register(i){if(!e.has(i.id)){e.set(i.id,i),n(i);for(const e of t)e.onSourceRegistered?.(i)}},unregister(n){const i=e.get(n);if(void 0!==i){i._setSink(null),e.delete(n);for(const e of t)e.onSourceUnregistered?.(n)}},addListener(i){t.add(i);for(const t of e.values())n(t),i.onSourceRegistered?.(t);return()=>{if(t.delete(i))for(const t of e.values())n(t)}}}}();return t[e]=i,i}const n=80;function i(e){const t=e.constructor,n=t?.name;return"string"==typeof n&&n.length>0?n:"Object"}function o(e,t=2){switch(typeof e){case"string":return`"${e.length>n?e.slice(0,n)+"…":e}"`;case"number":case"boolean":case"bigint":return String(e);case"symbol":return e.toString();case"undefined":return"undefined";case"function":return"[[Function]]"}if(null===e)return"null";const s=e;if(Array.isArray(s)){if(t<=0)return`[[Array(${s.length})]]`;const e=s.slice(0,3).map(e=>o(e,t-1)),n=s.length>3?`, …(${s.length})`:"";return`[${e.join(", ")}${n}]`}if(function(e){const t=Object.getPrototypeOf(e);return t===Object.prototype||null===t}(s)){if(t<=0)return"[[Object]]";const e=Object.keys(s),n=e.slice(0,3).map(e=>`${e}: ${o(s[e],t-1)}`),i=e.length>3?`, …(${e.length})`:"";return`{${n.join(", ")}${i}}`}return`[[${i(s)}]]`}function s(e){if(null!==e&&"object"==typeof e){const{name:t,message:o}=e;if("string"==typeof o){const s="string"==typeof t&&t.length>0?t:i(e),r=o.length>n?o.slice(0,n)+"…":o;return r.length>0?`${s}: ${r}`:s}}return o(e,1)}function r(e){if(0===e.length)return"";const t=e.slice(0,3).map(e=>{const t=o(e,1);return t.length>n?t.slice(0,n)+"…":t}),i=e.length>3?`, …(${e.length})`:"";return`${t.join(", ")}${i}`}const a=String.fromCharCode(0);function c(e){return e}function l(e,t){return e+a+t}function d(e,t){return e+a+t}function h(e){return"undefined"!=typeof ShadowRoot&&e instanceof ShadowRoot?`<${e.host.tagName.toLowerCase()}>`:9===e.nodeType?"document":e.nodeName.toLowerCase()}function u(e){return!(Number.parseInt(String(e),10)>=4)}function p(e,t,n){return void 0===n?{kind:e,name:t,status:"never",count:0,note:null}:n.zeroSubscriberCount===n.count?{kind:e,name:t,status:"emitted-unheard",count:n.count,note:`all ${n.count} emit(s) had 0 subscribers`}:{kind:e,name:t,status:"emitted",count:n.count,note:n.zeroSubscriberCount>0?`${n.zeroSubscriberCount}/${n.count} emit(s) had 0 subscribers`:null}}class m{_timelineCapacity;_removeListener=null;_sources=new Map;_roster=new Map;_wiringByPathKey=new Map;_wiringEntryByBinding=new WeakMap;_timeline=[];_seq=0;_paused=!1;_changeListeners=new Set;_observingSince=null;_watchFiredStats=new Map;_tokenEmitStats=new Map;_everAttachedKeys=new Set;constructor(e){this._timelineCapacity=e?.timelineCapacity??500}get connected(){return null!==this._removeListener}get paused(){return this._paused}set paused(e){this._paused=e}connect(){if(null!==this._removeListener)return;this._observingSince=performance.now();const e=t();this._removeListener=e.addListener({onSourceRegistered:e=>{this._sources.set(e.id,e),this._refreshRosterOf(e),this._notify("sources")},onSourceUnregistered:e=>{this._sources.delete(e),this._roster.delete(e),this._notify("sources"),this._notify("roster")},onEvent:(e,t)=>{this._ingest(e,t)}})}disconnect(){null!==this._removeListener&&(this._removeListener(),this._removeListener=null,this._sources.clear(),this._roster.clear(),this._wiringByPathKey.clear(),this._wiringEntryByBinding=new WeakMap,this._observingSince=null,this._watchFiredStats.clear(),this._tokenEmitStats.clear(),this._everAttachedKeys.clear(),this._notify("sources"),this._notify("roster"),this._notify("wiring"),this._notify("coverage"))}get observingSince(){return this._observingSince}onChange(e){return this._changeListeners.add(e),()=>{this._changeListeners.delete(e)}}getSources(){return[...this._sources.values()]}getRoster(){const e=[];for(const t of this._roster.values())e.push(...t);return e}refreshRoster(){for(const e of this._sources.values())this._refreshRosterOf(e);this._notify("roster")}getTimeline(){return this._timeline}clearTimeline(){this._timeline=[],this._notify("timeline")}getWiringForPath(e,t){const n=this._wiringByPathKey.get(e);if(void 0===n)return[];const i=this._collectAlive(n);return void 0===t?i:i.filter(e=>null===e.stateElementRef||e.stateElementRef.deref()===t)}getAllWiring(){const e=[];for(const t of this._wiringByPathKey.values())e.push(...this._collectAlive(t));return e}getWiringForNode(e){const t=[];for(const n of this._wiringByPathKey.values())for(const i of this._collectAlive(n)){const n=i.bindingRef.deref();(n.node===e||n.replaceNode===e||e.contains(n.node)||e.contains(n.replaceNode))&&t.push(i)}return t}getCanonicalDeclared(){let e=!1;const t=[],n=new Set;for(const[i,o]of this._sources){if("function"!=typeof o.getDeclaredBindings)continue;e=!0;const s=new Set;for(const e of this._roster.get(i)??[])s.add(e.rootNode);for(const e of s)for(const i of o.getDeclaredBindings(e)){const e=[i.statePathName,i.propName,i.bindingType,i.origin,i.raw].join(a);n.has(e)||(n.add(e),t.push(i))}}return e?t:null}getCoverageReport(e){const t=[];for(const n of this.getRoster()){const i=n.summary;if(void 0!==e&&i.element!==e)continue;const o=u(this._sources.get(n.sourceId).packageVersion);for(const e of i.watchPaths??[]){const n=this._measuredFor(this._watchFiredStats,c(e),i.element)?.count??0;if(n>0){t.push({kind:"watch",name:e,status:"fired",count:n,note:null});continue}if(!o){t.push({kind:"watch",name:e,status:"never",count:0,note:null});continue}const s=void 0!==i.keyedListPaths;let r=null;for(let t=e.indexOf(".*");-1!==t;t=e.indexOf(".*",t+2)){const n=e.slice(0,t);if(!(i.paths.list.has(n)||(i.keyedListPaths?.has(n)??!1))){r=n;break}}null===r?t.push({kind:"watch",name:e,status:"never",count:0,note:null}):t.push({kind:"watch",name:e,status:"prerequisite-missing",count:0,note:s?`list "${r}" has no for binding and no $listKeys declaration — list writes never reach its rows (only explicit-index writes can fire this watch)`:`no for binding observed for list "${r}" (a $listKeys declaration would still let list writes fire it)`})}for(const e of i.commandTokenNames)t.push(p("command",e,this._measuredFor(this._tokenEmitStats,l("command",e),i.element)));for(const e of i.eventTokenNames)t.push(p("eventToken",e,this._measuredFor(this._tokenEmitStats,l("event",e),i.element)))}const n=this.getCanonicalDeclared();if(null!==n){const e=new Set;for(const i of n){if("for"===i.bindingType||"if"===i.bindingType||"elseif"===i.bindingType||"else"===i.bindingType)continue;if(i.propName.startsWith("eventToken."))continue;const n=d(i.statePathName,i.propName);if(e.has(n))continue;e.add(n);const o=this._everAttachedKeys.has(n);t.push({kind:"binding",name:`${i.propName} ← ${i.statePathName}`,status:o?"attached":"never-attached",count:o?1:0,note:"fragment"===i.origin?"template interior (attaches when rows materialize)":null})}}return t}keysOf(e){const t=this._sources.get(e.sourceId);return void 0===t||"function"!=typeof t.keys?[]:t.keys(e.rootNode)}overlaysOf(e){const t=this._sources.get(e.sourceId);return void 0===t||"function"!=typeof t.overlays?null:t.overlays(e.rootNode)}keyedSubscriptionsOf(e){const t=this._sources.get(e.sourceId);return void 0===t||"function"!=typeof t.keyedSubscriptions?null:t.keyedSubscriptions(e.rootNode)}readValue(e,t,n){const i=this._sources.get(e.sourceId);if(void 0!==i)return i.read(e.rootNode,t,n)}writeValue(e,t,n,i){const o=this._sources.get(e.sourceId);void 0!==o&&o.write(e.rootNode,t,n,i)}_notify(e){for(const t of this._changeListeners)t(e)}_refreshRosterOf(e){const t=[],n=new Map;for(const i of e.getStateElements()){const o=h(i.rootNode),s=(n.get(o)??0)+1;n.set(o,s),t.push({sourceId:e.id,label:1===s?o:`${o}#${s}`,rootNode:i.rootNode,summary:i})}this._roster.set(e.id,t)}_statFor(e,t,n){let i=e.get(t);void 0===i&&(i=[],e.set(t,i));const o="object"==typeof n&&null!==n?n:null;for(const e of i)if(null===o?null===e.stateElementRef:e.stateElementRef?.deref()===o)return e;const s={stateElementRef:null===o?null:new WeakRef(o),count:0,zeroSubscriberCount:0};return i.push(s),s}_measuredFor(e,t,n){const i=e.get(t);if(void 0===i)return;let o=0,s=0;for(let e=i.length-1;e>=0;e--){const t=i[e].stateElementRef;null===t||void 0!==t.deref()?null!==t&&t.deref()!==n||(o+=i[e].count,s+=i[e].zeroSubscriberCount):i.splice(e,1)}return 0===i.length&&e.delete(t),0===o?void 0:{count:o,zeroSubscriberCount:s}}_collectAlive(e){const t=[];for(const n of e)void 0!==n.bindingRef.deref()?t.push(n):e.delete(n);return t}_appendTimeline(e){if(this._paused)return;this._timeline.push({...e,seq:this._seq++,time:performance.now()});const t=this._timeline.length-this._timelineCapacity;t>0&&this._timeline.splice(0,t),this._notify("timeline")}_labelOf(e){const t=e.listIndex?.indexes,n=e.absolutePathInfo.pathInfo.path;return void 0!==t?`${n}[${t.join(",")}]`:n}_ingest(e,t){switch(t.type){case"state:element-registered":{const n=this._sources.get(e);return void 0!==n&&(this._refreshRosterOf(n),this._notify("roster")),void this._appendTimeline({sourceId:e,kind:"element-registered",label:h(t.rootNode),detail:"",subscriberCount:null})}case"state:element-unregistered":{const n=this._sources.get(e);return void 0!==n&&(this._refreshRosterOf(n),this._notify("roster")),void this._appendTimeline({sourceId:e,kind:"element-unregistered",label:h(t.rootNode),detail:"",subscriberCount:null})}case"state:write":{const n=t.hasOldValue?`${o(t.value)} (was ${o(t.oldValue)})`:o(t.value);return void this._appendTimeline({sourceId:e,kind:"write",label:this._labelOf(t.absoluteAddress),detail:n,subscriberCount:null})}case"state:update-batch":{const n=[];let i=0;for(const e of t.addresses)i++,n.length<3&&n.push(this._labelOf(e));if(0===i)return;const o=i>n.length?`, …(${i})`:"";return void this._appendTimeline({sourceId:e,kind:"batch",label:`${i} address${1===i?"":"es"}`,detail:`${n.join(", ")}${o}`,subscriberCount:null})}case"state:binding-added":{const n=t.absoluteAddress.absolutePathInfo.pathInfo.path,i=n;let o=this._wiringByPathKey.get(i);void 0===o&&(o=new Set,this._wiringByPathKey.set(i,o));const s=t.absoluteAddress.absolutePathInfo.stateElement,r={sourceId:e,path:n,propName:t.binding.propName,bindingType:t.binding.bindingType,bindingRef:new WeakRef(t.binding),stateElementRef:"object"==typeof s&&null!==s?new WeakRef(s):null};return o.add(r),this._wiringEntryByBinding.set(t.binding,r),this._everAttachedKeys.add(d(n,t.binding.propName)),this._notify("wiring"),void this._notify("coverage")}case"state:binding-removed":{const e=this._wiringEntryByBinding.get(t.binding);if(void 0===e)return;this._wiringEntryByBinding.delete(t.binding);const n=e.path,i=this._wiringByPathKey.get(n);return void 0!==i&&(i.delete(e),0===i.size&&this._wiringByPathKey.delete(n)),void this._notify("wiring")}case"state:binding-cleared":{const e=t.absoluteAddress.absolutePathInfo.pathInfo.path;return void(this._wiringByPathKey.delete(e)&&this._notify("wiring"))}case"state:token-emit":{const n=this._statFor(this._tokenEmitStats,l(t.kind,t.tokenName),t.stateElement);return n.count+=1,0===t.subscriberCount&&(n.zeroSubscriberCount+=1),this._notify("coverage"),void this._appendTimeline({sourceId:e,kind:t.kind,label:t.tokenName,detail:r(t.args),subscriberCount:t.subscriberCount})}case"state:watch-fired":return this._statFor(this._watchFiredStats,t.path,t.stateElement).count+=1,void this._notify("coverage");case"state:watch-error":return void this._appendTimeline({sourceId:e,kind:"watch-error",label:t.path,detail:`${t.phase}: ${s(t.error)}`,subscriberCount:null});case"state:watch-chain-limit":return void this._appendTimeline({sourceId:e,kind:"watch-chain-limit",label:`depth > ${t.maxDepth}`,detail:t.paths.join(", "),subscriberCount:null});case"state:render-chain-limit":return void this._appendTimeline({sourceId:e,kind:"render-chain-limit",label:`depth > ${t.maxDepth}`,detail:t.paths.join(", "),subscriberCount:null});case"state:path-unresolved":return void this._appendTimeline({sourceId:e,kind:"path-unresolved",label:t.path,detail:`${t.source}: "${t.missingSegment}" is not declared`,subscriberCount:null});case"state:binding-apply-error":return void this._appendTimeline({sourceId:e,kind:"binding-apply-error",label:t.path,detail:`${t.bindingType}: ${s(t.error)}`,subscriberCount:null});case"propagation:suppressed":return void this._appendTimeline({sourceId:e,kind:"propagation-suppressed",label:t.member,detail:`${t.reason} (tx ${t.transactionId}, edge ${t.edgeId})`,subscriberCount:null});case"propagation:coalesced":return void this._appendTimeline({sourceId:e,kind:"propagation-coalesced",label:this._labelOf(t.absoluteAddress),detail:`tx ${t.droppedTransactionId} dropped (winner tx ${t.winnerTransactionId})`,subscriberCount:null});case"propagation:hop-limit":return void this._appendTimeline({sourceId:e,kind:"propagation-hop-limit",label:this._labelOf(t.absoluteAddress),detail:`hop ${t.hop} (tx ${t.transactionId})`,subscriberCount:null});case"contract:drift":{const n=void 0!==t.member?`: ${t.member}`:"",i="event-mismatch"===t.reason?` (sidecar ${t.sidecarEvent??"?"} / live ${t.liveEvent??"?"})`:"";return void this._appendTimeline({sourceId:e,kind:"contract-drift",label:t.tag,detail:`${t.reason}${n}${i}`,subscriberCount:null})}case"contract:manifest-read":case"contract:unsupported-extension":return}}}const g=["wcs-text","wcs-for","wcs-if","wcs-elseif","wcs-else"];function f(e,t,n){const i=t.trim();if(0===i.length)return null;const o=i.indexOf(":");if(o<0)return null;const s=i.slice(0,o).trim(),r=i.slice(o+1).trim();if(0===s.length||0===r.length)return null;const[a,...c]=r.split("|").map(e=>e.trim());return{element:e,propName:s,path:a,filters:c.filter(e=>e.length>0),origin:n,raw:i}}class _ extends HTMLElement{static get observedAttributes(){return["open","dock","hotkey"]}_core=null;_removeCoreListener=null;_panel=null;_badge=null;_stateSelect=null;_paneElements={};_wiringView="wiring";_highlightLayer=null;_dirtyPanes=new Set;_renderScheduled=!1;_selectedRosterKey=null;_selectedPath=null;_pickedNode=null;_pickMode=!1;_expanded=new Set;_hotkeyHandler=null;_pickHandler=null;get core(){return this._core}connectedCallback(){if(document.documentElement.hasAttribute("data-wcs-server"))return;null===this.shadowRoot&&this._buildShadow();const e=Number(this.getAttribute("buffer")??"");this._core=new m({timelineCapacity:Number.isFinite(e)&&e>0?e:void 0}),this._removeCoreListener=this._core.onChange(e=>{"roster"===e||"sources"===e?(this._markDirty("state"),this._markDirty("wiring")):"wiring"===e?this._markDirty("wiring"):"coverage"===e?"coverage"===this._wiringView&&this._markDirty("wiring"):this._markDirty("timeline")}),this._core.connect(),this._applyDock(),this._applyOpen(),this._installHotkey(),this._markDirty("state"),this._markDirty("wiring"),this._markDirty("timeline")}disconnectedCallback(){this._removeCoreListener?.(),this._removeCoreListener=null,this._core?.disconnect(),this._core=null,this._uninstallHotkey(),this._exitPickMode()}attributeChangedCallback(e){null!==this.shadowRoot&&("open"===e?this._applyOpen():"dock"===e?this._applyDock():"hotkey"===e&&(this._uninstallHotkey(),this._installHotkey()))}__flushRenderForTest(){this._renderDirty()}_buildShadow(){const e=this.attachShadow({mode:"open"}),t=document.createElement("style");t.textContent='\n:host {\n all: initial;\n position: fixed;\n z-index: 2147483647;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 12px;\n inset: auto 0 0 auto;\n}\n* { box-sizing: border-box; }\n.badge {\n position: fixed;\n right: 12px;\n bottom: 12px;\n width: 40px;\n height: 40px;\n border-radius: 20px;\n border: 1px solid #2b4f78;\n background: #10263f;\n color: #9fd0ff;\n font-weight: 700;\n cursor: pointer;\n}\n.panel {\n position: fixed;\n display: flex;\n flex-direction: column;\n background: #0d1b2a;\n color: #d7e3f4;\n border: 1px solid #2b4f78;\n box-shadow: 0 0 24px rgba(0,0,0,.5);\n}\n.panel.dock-bottom { left: 0; right: 0; bottom: 0; height: 45vh; }\n.panel.dock-right { top: 0; right: 0; bottom: 0; width: 420px; }\n.panel[hidden] { display: none; }\nheader {\n display: flex;\n gap: 6px;\n align-items: center;\n padding: 6px 8px;\n border-bottom: 1px solid #2b4f78;\n background: #10263f;\n}\nheader .title { font-weight: 700; color: #9fd0ff; margin-right: 4px; }\nheader select, header button {\n font: inherit;\n background: #16324f;\n color: #d7e3f4;\n border: 1px solid #2b4f78;\n border-radius: 4px;\n padding: 2px 8px;\n cursor: pointer;\n}\nheader button[aria-pressed="true"] { background: #2b5d8f; }\nheader .spacer { flex: 1; }\n.panes { display: flex; flex: 1; min-height: 0; }\n.pane { flex: 1; min-width: 0; overflow: auto; padding: 6px 8px; border-right: 1px solid #1d3a5c; }\n.pane:last-child { border-right: none; }\n.pane h3 {\n margin: 0 0 6px;\n font-size: 11px;\n text-transform: uppercase;\n letter-spacing: .08em;\n color: #7ba7d4;\n}\n.tree-row { display: flex; gap: 6px; padding: 1px 0; align-items: baseline; white-space: nowrap; }\n.tree-row .toggle { width: 14px; cursor: pointer; color: #7ba7d4; user-select: none; }\n.tree-row .key { color: #9fd0ff; cursor: pointer; }\n.tree-row .value { color: #ffd9a0; overflow: hidden; text-overflow: ellipsis; }\n.tree-row .value.editable { cursor: pointer; }\n.tree-row input { font: inherit; background: #16324f; color: #ffd9a0; border: 1px solid #2b4f78; }\n.badge-tag {\n display: inline-block;\n padding: 0 4px;\n border-radius: 3px;\n font-size: 10px;\n background: #26456a;\n color: #a8c6e8;\n}\n.badge-tag.warn { background: #6a3326; color: #ffb3a0; }\n.badge-tag.declared { background: #4a4426; color: #efe3a0; }\n.wiring-row, .timeline-row { padding: 1px 0; white-space: nowrap; }\n.wiring-row .prop { color: #b7f0c0; }\n.wiring-row .path { color: #9fd0ff; }\n.timeline-row .t { color: #6f88a3; }\n.timeline-row .label { color: #9fd0ff; }\n.timeline-row .detail { color: #ffd9a0; }\n.timeline-row .kind { display: inline-block; min-width: 52px; text-align: center; }\n.empty { color: #6f88a3; font-style: italic; padding: 4px 0; }\n.notice { color: #efe3a0; padding: 2px 0 6px; }\n.notice button { font: inherit; margin-left: 6px; cursor: pointer; }\n.wiring-row .detail { color: #6f88a3; }\n.overlays-heading { margin-top: 10px; }\n.overlay-row { padding: 1px 0; white-space: nowrap; }\n.overlay-row .prop { color: #b7f0c0; }\n.overlay-row .path { color: #9fd0ff; }\n.overlay-row .detail { color: #6f88a3; }\n.keyed-row { padding: 1px 0; white-space: nowrap; }\n.keyed-row .path { color: #9fd0ff; }\n.keyed-row .detail { color: #6f88a3; }\n.wiring-tabs { padding: 0 0 4px; }\n.wiring-tabs button { font: inherit; cursor: pointer; margin-right: 4px; opacity: 0.6; }\n.wiring-tabs button.active { opacity: 1; font-weight: bold; }\n.hl-box {\n position: fixed;\n pointer-events: none;\n border: 1px solid #58c2ff;\n background: rgba(88,194,255,.18);\n}\n',e.append(t);const n=document.createElement("button");n.className="badge",n.title="wcstack DevTools",n.textContent="WCS",n.addEventListener("click",()=>this.toggle()),e.append(n),this._badge=n;const i=document.createElement("div");i.className="panel dock-bottom",i.hidden=!0;const o=document.createElement("header"),s=document.createElement("span");s.className="title",s.textContent="wcstack devtools",o.append(s);const r=document.createElement("select");r.title="state element",r.addEventListener("change",()=>{this._selectedRosterKey=r.value||null,this._selectedPath=null,this._expanded.clear(),this._markDirty("state"),this._markDirty("wiring")}),o.append(r),this._stateSelect=r;const a=this._headerButton(o,"⌖ pick","pick a page element");a.addEventListener("click",()=>{this._pickMode?this._exitPickMode():this._enterPickMode(),a.setAttribute("aria-pressed",String(this._pickMode))}),a.dataset.role="pick";const c=this._headerButton(o,"⏸","pause timeline");c.addEventListener("click",()=>{const e=this._core;null!==e&&(e.paused=!e.paused,c.setAttribute("aria-pressed",String(e.paused)))}),c.dataset.role="pause";const l=this._headerButton(o,"🗑","clear timeline");l.addEventListener("click",()=>{this._core?.clearTimeline()}),l.dataset.role="clear";const d=document.createElement("span");d.className="spacer",o.append(d);const h=this._headerButton(o,"dock","toggle dock position");h.addEventListener("click",()=>{const e="bottom"===(this.getAttribute("dock")??"bottom")?"right":"bottom";this.setAttribute("dock",e)}),h.dataset.role="dock";const u=this._headerButton(o,"×","close");u.addEventListener("click",()=>this.toggle(!1)),u.dataset.role="close",i.append(o);const p=document.createElement("div");p.className="panes";for(const[e,t]of[["state","State"],["wiring","Wiring"],["timeline","Timeline"]]){const n=document.createElement("section");n.className=`pane pane-${e}`;const i=document.createElement("h3");i.textContent=t;const o=document.createElement("div");o.className="pane-body",n.append(i,o),p.append(n),this._paneElements[e]=o}i.append(p),e.append(i),this._panel=i;const m=document.createElement("div");m.className="hl-layer",e.append(m),this._highlightLayer=m}_headerButton(e,t,n){const i=document.createElement("button");return i.textContent=t,i.title=n,i.setAttribute("aria-pressed","false"),e.append(i),i}get open(){return this.hasAttribute("open")}toggle(e){e??!this.open?this.setAttribute("open",""):this.removeAttribute("open")}_applyOpen(){this._panel.hidden=!this.open,this._badge.hidden=this.open,this.open&&(this._markDirty("state"),this._markDirty("wiring"),this._markDirty("timeline"))}_applyDock(){const e="right"===this.getAttribute("dock")?"right":"bottom";this._panel.classList.toggle("dock-right","right"===e),this._panel.classList.toggle("dock-bottom","bottom"===e)}_installHotkey(){const e=this.getAttribute("hotkey")??"Alt+Shift+D";if("none"===e)return;const t=e.split("+").map(e=>e.trim().toLowerCase()),n=t[t.length-1],i=t.includes("alt"),o=t.includes("shift"),s=t.includes("ctrl"),r=t.includes("meta");this._hotkeyHandler=e=>{e.key.toLowerCase()===n&&e.altKey===i&&e.shiftKey===o&&e.ctrlKey===s&&e.metaKey===r&&(e.preventDefault(),this.toggle())},window.addEventListener("keydown",this._hotkeyHandler)}_uninstallHotkey(){null!==this._hotkeyHandler&&(window.removeEventListener("keydown",this._hotkeyHandler),this._hotkeyHandler=null)}_enterPickMode(){this._pickMode=!0,this._pickHandler=e=>{const t=e.target;t.getRootNode()!==this.shadowRoot&&t!==this&&(e.preventDefault(),e.stopPropagation(),this._pickedNode=t,this._selectedPath=null,this._exitPickMode(),this._markDirty("wiring"))},document.addEventListener("click",this._pickHandler,{capture:!0})}_exitPickMode(){null!==this._pickHandler&&(document.removeEventListener("click",this._pickHandler,{capture:!0}),this._pickHandler=null),this._pickMode=!1;const e=this.shadowRoot?.querySelector('button[data-role="pick"]');e?.setAttribute("aria-pressed","false")}_markDirty(e){this._dirtyPanes.add(e),this._renderScheduled||(this._renderScheduled=!0,requestAnimationFrame(()=>{this._renderDirty()}))}_renderDirty(){if(this._renderScheduled=!1,null===this._core||null===this.shadowRoot)return void this._dirtyPanes.clear();const e=this._dirtyPanes;this._dirtyPanes=new Set,e.has("state")&&this._renderStatePane(),e.has("wiring")&&this._renderWiringPane(),e.has("timeline")&&this._renderTimelinePane()}_rosterKey(e){return`${e.sourceId}:${e.label}`}_selectedRoster(){const e=this._core.getRoster();if(0===e.length)return null;return e.find(e=>this._rosterKey(e)===this._selectedRosterKey)??e[0]}_renderStatePane(){const e=this._core,t=this._paneElements.state,n=this._stateSelect,i=e.getRoster(),o=this._selectedRoster();if(n.replaceChildren(...i.map(e=>{const t=document.createElement("option");return t.value=this._rosterKey(e),t.textContent=`${e.label} (${e.sourceId.slice(0,12)})`,t.selected=null!==o&&this._rosterKey(e)===this._rosterKey(o),t})),t.replaceChildren(),null===o)return void t.append(this._emptyRow("no <wcs-state> elements observed"));this._selectedRosterKey=this._rosterKey(o);const s=e.keysOf(o);if(0===s.length)return t.append(this._emptyRow("no readable keys (runtime without keys() API?)")),this._renderOverlaysSection(t,o),void this._renderKeyedSection(t,o);for(const e of s)this._renderTreeNode(t,o,{path:e,indexes:[]},e,0);this._renderOverlaysSection(t,o),this._renderKeyedSection(t,o)}_renderKeyedSection(e,t){const n=this._core.keyedSubscriptionsOf(t);if(null===n||0===n.length)return;const i=document.createElement("h3");i.className="overlays-heading",i.textContent=`Keyed selection (${n.length} path${1===n.length?"":"s"})`,e.append(i);for(const t of n)e.append(this._keyedRow(t))}_keyedRow(e){const t=document.createElement("div");t.className="keyed-row";const n=document.createElement("span");if(n.className="path",n.textContent=e.path,t.append(n),e.tracked){const e=document.createElement("span");e.className="badge-tag warn",e.textContent="tracked",e.title="the path is a getter or under one, so $eq cannot subscribe by key: every getter that reads it re-evaluates when it changes",t.append(document.createTextNode(" "),e)}const i=[];e.rows>0&&i.push(`rows ${e.rows} · keys ${e.keys}`),e.lists>0&&i.push(`list watchers ${e.lists}`),e.tracked||i.push(`last ${o(e.lastValue,1)}`);const s=document.createElement("span");return s.className="detail",s.textContent=i.length>0?` ${i.join(" · ")}`:"",t.append(s),t}_renderOverlaysSection(e,t){const n=this._core.overlaysOf(t);if(null===n||0===n.length)return;const i=document.createElement("h3");i.className="overlays-heading",i.textContent=`Overlays (${n.length} mount${1===n.length?"":"s"})`,e.append(i);for(const t of n)e.append(this._overlayRow(t))}_overlayRow(e){const t=document.createElement("div");t.className="overlay-row";const n=document.createElement("span");n.className="badge-tag",n.textContent=e.marker;const i=document.createElement("span");i.className="prop",i.textContent=`<${e.componentTag}>`;const o=document.createElement("span");o.className="path",o.textContent=e.stateProp,t.append(n,document.createTextNode(" "),i,document.createTextNode(" "),o);const s=[];for(const t of e.mountTable)s.push(`${""===t.inner?"(root)":t.inner} → ${t.outer}`);e.delta>0&&s.push(`Δ${e.delta}`),e.privateKeys.length>0&&s.push(`private: ${e.privateKeys.join(", ")}`);const r=e.exports??[];if(r.length>0&&s.push(`exports: ${r.join(", ")}`),e.getterKeys.length>0&&s.push(`getters: ${e.getterKeys.join(", ")}`),s.length>0){const e=document.createElement("span");e.className="detail",e.textContent=` ${s.join(" · ")}`,t.append(e)}return t}_renderTreeNode(e,t,n,i,s){const r=this._core;let a,c=!0;try{a=r.readValue(t,n.path,n.indexes)}catch{c=!1}const l=document.createElement("div");l.className="tree-row",l.style.paddingLeft=14*s+"px";const d=c&&function(e){if(Array.isArray(e))return!0;if(null===e||"object"!=typeof e)return!1;const t=Object.getPrototypeOf(e);return t===Object.prototype||null===t}(a),h=function(e){return`${e.path}#${e.indexes.join(",")}`}(n),u=d&&this._expanded.has(h),p=document.createElement("span");p.className="toggle",p.textContent=d?u?"▾":"▸":"",d&&p.addEventListener("click",()=>{this._expanded.has(h)?this._expanded.delete(h):this._expanded.add(h),this._markDirty("state")}),l.append(p);const m=document.createElement("span");m.className="key",m.textContent=`${i}:`,m.title=n.path,m.addEventListener("click",()=>{this._selectedPath=n.path,this._pickedNode=null,this._markDirty("wiring"),this._highlightPath(t,n.path)}),l.append(m);const g=document.createElement("span");if(g.className="value",c){g.textContent=o(a,1);(null===a||"object"!=typeof a)&&"function"!=typeof a&&(g.classList.add("editable"),g.title="click to edit",g.addEventListener("click",()=>{this._beginEdit(l,g,t,n,a)}))}else g.textContent="(unreadable getter)";if(l.append(g),e.append(l),u)if(Array.isArray(a)){const i=Math.min(a.length,20);for(let o=0;o<i;o++)this._renderTreeNode(e,t,{path:`${n.path}.*`,indexes:[...n.indexes,o]},`[${o}]`,s+1);if(a.length>i){const t=this._emptyRow(`…(${a.length} items)`);t.style.paddingLeft=14*(s+1)+"px",e.append(t)}}else for(const i of Object.keys(a))this._renderTreeNode(e,t,{path:`${n.path}.${i}`,indexes:n.indexes},i,s+1)}_beginEdit(e,t,n,i,o){const s=document.createElement("input");s.value="string"==typeof o?o:String(o);const r=()=>{this._core?.writeValue(n,i.path,function(e){const t=e.trim();try{return JSON.parse(t)}catch{return e}}(s.value),i.indexes),this._markDirty("state")};s.addEventListener("keydown",e=>{"Enter"===e.key?r():"Escape"===e.key&&this._markDirty("state")}),e.replaceChild(s,t),s.focus()}_renderWiringPane(){const e=this._core,t=this._paneElements.wiring;t.replaceChildren();const n=document.createElement("div");n.className="wiring-tabs";for(const[e,t]of[["wiring","wiring"],["coverage","coverage"]]){const i=document.createElement("button");i.textContent=t,this._wiringView===e&&i.classList.add("active"),i.addEventListener("click",()=>{this._wiringView=e,this._markDirty("wiring")}),n.append(i)}if(t.append(n),"coverage"===this._wiringView)return void this._renderCoverageView(t);let i,o;if(null!==this._pickedNode){i=e.getWiringForNode(this._pickedNode);const t=this._pickedNode;o=t instanceof Element?`<${t.tagName.toLowerCase()}>`:t.nodeName}else if(null!==this._selectedPath){const t=this._selectedRoster();i=null!==t?e.getWiringForPath(this._selectedPath,t.summary.element):[],o=this._selectedPath}else i=e.getAllWiring(),o="all";const s=document.createElement("div");if(s.textContent=`context: ${o} — ${i.length} live binding${1===i.length?"":"s"}`,t.append(s),i.length>0){for(const e of i)t.append(this._wiringRow(e));return}const r=e.getCanonicalDeclared(),a=this._selectedRoster(),c=null===r&&null!==a?function(e,t="data-wcs"){const n=[];for(const i of e.querySelectorAll(`[${t}]`)){const e=i.getAttribute(t);for(const t of e.split(";")){const e=f(i,t,"attribute");null!==e&&n.push(e)}}const i=(e.ownerDocument??e).createTreeWalker(e,NodeFilter.SHOW_COMMENT);let o=i.nextNode();for(;null!==o;){const e=o.textContent.trim(),t=g.find(t=>e===t||e.startsWith(t+":"));if(void 0!==t){const i=o.parentNode instanceof Element?o.parentNode:null;if(null!==i){const o=e===t?"":e.slice(t.length+1).trim();if(o.length>0){const e="wcs-text"===t?"textContent":t.slice(4);n.push(f(i,`${e}: ${o}`,"comment"))}}}o=i.nextNode()}return n}(this._scanRootOf(a)):[];if(0===(r?.length??0)&&0===c.length)return void t.append(this._emptyRow("no bindings observed"));const l=document.createElement("div");l.className="notice";const d=document.createElement("span");d.className="badge-tag declared",d.textContent=null!==r?"declared (canonical)":"declared",l.append(d,document.createTextNode(" attached late — reload to capture live bindings "));const h=document.createElement("button");if(h.textContent="reload",h.addEventListener("click",()=>{location.reload()}),l.append(h),t.append(l),null!==r)for(const e of r)t.append(this._canonicalDeclaredRow(e));else for(const e of c)t.append(this._declaredRow(e))}_renderCoverageView(e){const t=this._core,n=t.observingSince,i=document.createElement("div"),o=null===n?null:new Date(Date.now()-(performance.now()-n)).toLocaleTimeString();i.textContent=null===o?"not observing":`observing since ${o} (declared vs measured after this point)`,e.append(i);const s=this._selectedRoster(),r=t.getCoverageReport(s?.summary.element);if(0!==r.length)for(const t of r){const n=document.createElement("div");n.className="wiring-row";const i=document.createElement("span");i.className="badge-tag",i.textContent=t.kind;const o=document.createElement("span");o.className="badge-tag",o.textContent=t.count>1?`${t.status} ×${t.count}`:t.status,"never"===t.status||"never-attached"===t.status||"emitted-unheard"===t.status?o.classList.add("warn"):"prerequisite-missing"===t.status&&o.classList.add("declared");const s=document.createElement("span");if(s.className="path",s.textContent=` ${t.name} `,n.append(i,document.createTextNode(" "),s,o),null!==t.note){const e=document.createElement("span");e.className="detail",e.textContent=` ${t.note}`,n.append(e)}e.append(n)}else e.append(this._emptyRow("nothing declared to cover"))}_canonicalDeclaredRow(e){const t=document.createElement("div");t.className="wiring-row";const n=document.createElement("span");n.className="badge-tag declared",n.textContent=e.origin;const i=document.createElement("span");i.className="prop",i.textContent=e.propName;const o=document.createElement("span");o.className="path";const s=e.outFilters.map(e=>` | ${e.filterName}(${e.args.join(",")})`).join("");if(o.textContent=`${e.statePathName}${s}`,t.append(n,document.createTextNode(" "),i,document.createTextNode(" ← "),o),null!==e.node){const n=e.node;t.addEventListener("click",()=>{this._highlightNodes([n])})}return t}_scanRootOf(e){const t=e.rootNode;return t.nodeType===Node.DOCUMENT_NODE||t.nodeType===Node.DOCUMENT_FRAGMENT_NODE?t:document}_wiringRow(e){const t=document.createElement("div");t.className="wiring-row";const n=document.createElement("span");n.className="prop",n.textContent=e.propName;const i=document.createTextNode(" ← "),o=document.createElement("span");o.className="path",o.textContent=e.path;const s=document.createElement("span");return s.className="badge-tag",s.textContent=e.bindingType,t.append(s,document.createTextNode(" "),n,i,o),t.addEventListener("click",()=>{const t=e.bindingRef.deref();void 0!==t&&this._highlightNodes([t.node,t.replaceNode])}),t}_declaredRow(e){const t=document.createElement("div");t.className="wiring-row";const n=document.createElement("span");n.className="badge-tag declared",n.textContent=e.origin;const i=document.createElement("span");i.className="prop",i.textContent=e.propName;const o=document.createElement("span");return o.className="path",o.textContent=e.path,t.append(n,document.createTextNode(" "),i,document.createTextNode(" ← "),o),t.addEventListener("click",()=>{this._highlightNodes([e.element])}),t}_renderTimelinePane(){const e=this._core,t=this._paneElements.timeline,n=e.getTimeline(),i=Math.max(0,n.length-200),o=[];i>0&&o.push(this._emptyRow(`…(${i} earlier entries)`));for(let e=i;e<n.length;e++)o.push(this._timelineRow(n[e]));0===o.length&&o.push(this._emptyRow("no activity yet")),t.replaceChildren(...o),t.scrollTop=t.scrollHeight}_timelineRow(e){const t=document.createElement("div");t.className="timeline-row";const n=document.createElement("span");n.className="t",n.textContent=`${(e.time/1e3).toFixed(3)}s `;const i=document.createElement("span");i.className="badge-tag kind",i.textContent=e.kind,0===e.subscriberCount&&(i.classList.add("warn"),i.title="emitted with no subscribers"),"watch-error"!==e.kind&&"watch-chain-limit"!==e.kind||(i.classList.add("warn"),i.title="watch-error"===e.kind?"a $watch or $scan failure (read, handler, fold or write — see the phase in the detail); the runtime isolated it (console.error only)":"a $watch write chain hit the depth limit and was cut off"),"render-chain-limit"===e.kind&&(i.classList.add("warn"),i.title="writes made while rendering kept starting new batches; the chain hit the depth limit and this batch was not rendered"),"path-unresolved"!==e.kind&&"binding-apply-error"!==e.kind||(i.classList.add("warn"),i.title="path-unresolved"===e.kind?"a wired path does not resolve on the state; its updates are dropped":"a binding threw while applying; the runtime isolated it (console.error only)"),"propagation-hop-limit"!==e.kind&&"contract-drift"!==e.kind||(i.classList.add("warn"),i.title="propagation-hop-limit"===e.kind?"a two-way propagation chain hit the hop limit and was cut off":"sidecar manifest drifted from the live wcBindable declaration (live wins)");const o=document.createElement("span");o.className="label",o.textContent=` ${e.label} `;const s=document.createElement("span");return s.className="detail",s.textContent=e.detail,t.append(n,i,o,s),t}_emptyRow(e){const t=document.createElement("div");return t.className="empty",t.textContent=e,t}_highlightPath(e,t){const n=this._core,i=[];for(const o of n.getWiringForPath(t,e.summary.element)){const e=o.bindingRef.deref();void 0!==e&&i.push(e.node,e.replaceNode)}this._highlightNodes(i)}_highlightNodes(e){const t=this._highlightLayer;t.replaceChildren();const n=new Set;for(const i of e){const e=i instanceof Element?i:i.parentElement;if(null===e||n.has(e)||!e.isConnected)continue;n.add(e);const o=e.getBoundingClientRect(),s=document.createElement("div");s.className="hl-box",s.style.left=`${o.left}px`,s.style.top=`${o.top}px`,s.style.width=`${o.width}px`,s.style.height=`${o.height}px`,t.append(s)}setTimeout(()=>{t.replaceChildren()},2e3)}}const b="wcs-devtools";function y(){null===document.querySelector(b)&&document.body.appendChild(document.createElement(b))}document.documentElement.hasAttribute("data-wcs-server")||(customElements.get(b)||customElements.define(b,_),null!==document.body?y():document.addEventListener("DOMContentLoaded",y,{once:!0}));
|
|
2
2
|
//# sourceMappingURL=auto.min.js.map
|