diff --git a/src/app.d.ts b/src/app.d.ts index e7fd4d4..093d066 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -34,7 +34,7 @@ declare global { }; type SvelteBlockDetail = { - id: number; + id: string; // crypto.randomUUID(); source: string; type: | 'anchor' diff --git a/src/client/index.js b/src/client/index.js index 9f7f069..6ab49f0 100644 --- a/src/client/index.js +++ b/src/client/index.js @@ -1,18 +1,19 @@ import { highlight } from './highlight.js'; import { addListener } from './listener.js'; // import { profiler } from './profiler.js'; -import { getNode } from './svelte.js'; - -// @ts-ignore - possibly find an alternative -window.__svelte_devtools_inject_state = function (id, key, value) { - const { detail: component } = getNode(id) || {}; - component && component.$inject_state({ [key]: value }); -}; - -// @ts-ignore - possibly find an alternative -window.__svelte_devtools_select_element = function (element) { - const node = getNode(element); - if (node) send('inspect', { node: serialize(node) }); +import { nodes } from './svelte.js'; + +// @ts-ignore - for the app to call with `eval` +window['#SvelteDevTools'] = { + /** + * @param {string} id + * @param {string} key + * @param {any} value + */ + inject(id, key, value) { + const { detail: component } = nodes.map.get(id) || {}; + component && component.$inject_state({ [key]: value }); + }, }; const previous = { @@ -56,7 +57,7 @@ const inspect = { click(event) { event.preventDefault(); document.removeEventListener('mousemove', inspect.handle, true); - const node = getNode(/** @type {Node} */ (event.target)); + const node = nodes.map.get(/** @type {Node} */ (event.target)); if (node) send('bridge::ext/inspect', { node: serialize(node) }); previous.clear(); }, @@ -67,11 +68,11 @@ window.addEventListener('message', ({ data, source }) => { if (source !== window || data?.source !== 'svelte-devtools') return; if (data.type === 'bridge::ext/select') { - const node = getNode(data.payload); + const node = nodes.map.get(data.payload); // @ts-expect-error - saved for `devtools.inspect()` if (node) window.$n = node.detail; } else if (data.type === 'bridge::ext/highlight') { - const node = getNode(data.payload); + const node = nodes.map.get(data.payload); return highlight(node); } else if (data.type === 'bridge::ext/inspect') { switch (data.payload) { @@ -202,8 +203,8 @@ addListener({ add(node, anchor) { send('bridge::courier/node->add', { node: serialize(node), - target: node.parent?.id ?? null, - anchor: anchor?.id ?? null, + target: node.parent?.id, + anchor: anchor?.id, }); }, diff --git a/src/client/svelte.js b/src/client/svelte.js index ee19f15..1fc485a 100644 --- a/src/client/svelte.js +++ b/src/client/svelte.js @@ -3,18 +3,9 @@ import { listeners } from './listener.js'; /** @type {undefined | SvelteBlockDetail} */ let current_block; -let pointer = 0; -/** @param {number | Node} id */ -export function getNode(id) { - return nodes.map.get(id); -} - -const nodes = { - /** @type {SvelteBlockDetail[]} */ - root: [], - - /** @type {Map} */ +export const nodes = { + /** @type {Map} */ map: new Map(), /** @param {{ node: SvelteBlockDetail; target?: Node; anchor?: Node }} opts */ @@ -28,13 +19,11 @@ const nodes = { } node.parent = target; - const sibling = this.map.get(anchor); + const sibling = anchor && this.map.get(anchor); if (target) { const index = target.children.findIndex((n) => n === sibling); if (index === -1) target.children.push(node); else target.children.splice(index, 0, node); - } else { - this.root.push(node); } listeners.add(node, sibling); @@ -81,7 +70,7 @@ document.addEventListener('SvelteRegisterComponent', ({ detail }) => { let last_promise; document.addEventListener('SvelteRegisterBlock', ({ detail }) => { const { type, id, block, ...rest } = detail; - const current_node_id = pointer++; + const current_node_id = crypto.randomUUID(); if (block.m) { const original = block.m; @@ -134,7 +123,7 @@ document.addEventListener('SvelteRegisterBlock', ({ detail }) => { // @ts-expect-error - each block fallback group = /** @type {SvelteBlockDetail} */ ({ version: '', - id: pointer++, + id: crypto.randomUUID(), type: 'block', tagName: 'each', container: parent, @@ -214,7 +203,7 @@ document.addEventListener('SvelteDOMInsert', ({ detail }) => { target, // @ts-expect-error - missing properties are irrelevant node: { - id: pointer++, + id: crypto.randomUUID(), type, detail: element, tagName: element.nodeName.toLowerCase(), diff --git a/src/lib/panel/PropertyList.svelte b/src/lib/panel/PropertyList.svelte index b4618d1..4e1717f 100644 --- a/src/lib/panel/PropertyList.svelte +++ b/src/lib/panel/PropertyList.svelte @@ -2,18 +2,17 @@ import Expandable from './Expandable.svelte'; export let entries: Array<{ key: string; value: any }> = []; - export let id: number; + export let id: string; export let readonly = false; const errors: Record = {}; function change(key: string, value: any) { chrome.devtools.inspectedWindow.eval( - `__svelte_devtools_inject_state(${id}, '${key}', ${value})`, + `window['#SvelteDevTools'].inject("${id}", "${key}", ${value})`, (_, error) => { - errors[key] = - error && error.isException - ? error.value.substring(0, error.value.indexOf('\n')) - : undefined; + errors[key] = error?.isException + ? error.value.slice(0, error.value.indexOf('\n')) + : undefined; }, ); } diff --git a/src/lib/runtime.ts b/src/lib/runtime.ts index bee6673..77df92b 100644 --- a/src/lib/runtime.ts +++ b/src/lib/runtime.ts @@ -11,7 +11,7 @@ export const background = { }, }; -const nodes = new Map(); +const nodes = {} as { [key: string]: DebugNode }; function resolveEventBubble(node: any) { if (!node.detail || !node.detail.listeners) return; @@ -42,20 +42,22 @@ port.onMessage.addListener(({ type, payload }) => { case 'bridge::ext/clear': { selected.set(undefined); hovered.set(undefined); - return root.set([]); + root.set([]); + break; } case 'bridge::ext/inspect': { - if (typeof payload === 'string') return; - const current = nodes.get(payload.node.id); - return selected.set(current); + if (typeof payload === 'string') break; + const current = nodes[payload.node.id]; + selected.set(current); + break; } case 'bridge::courier/node->add': { const { node, target, anchor } = payload as { node: DebugNode; - target: null | number; - anchor: null | number; + target: string; + anchor: string; }; node.children = []; @@ -63,37 +65,43 @@ port.onMessage.addListener(({ type, payload }) => { node.invalidate = () => {}; resolveEventBubble(node); - const parent = nodes.get(target); - nodes.set(node.id, node); - if (!parent) return root.update((n) => [...n, node]); + const parent = nodes[target]; + nodes[node.id] = node; + if (!parent) { + root.update((n) => [...n, node]); + break; + } const index = parent.children.findIndex((n) => n.id === anchor); if (index === -1) parent.children.push(node); else parent.children.splice(index, 0, node); - return (node.parent = parent).invalidate(); + (node.parent = parent).invalidate(); + break; } case 'bridge::courier/node->remove': { const node = payload.node as SvelteBlockDetail; - const current = nodes.get(node.id); - if (current) nodes.delete(current.id); - if (!current?.parent) return; + const current = nodes[node.id]; + if (current) delete nodes[current.id]; + if (!current?.parent) break; const index = current.parent.children.findIndex((o) => o.id === current.id); current.parent.children.splice(index, 1); - return current.parent.invalidate(); + current.parent.invalidate(); + break; } case 'bridge::courier/node->update': { const node = payload.node as SvelteBlockDetail; - const current = nodes.get(node.id); - if (!current) return; + const current = nodes[node.id]; + if (!current) break; Object.assign(current, payload.node); resolveEventBubble(current); selected.update((o) => o); - return current.invalidate(); + current.invalidate(); + break; } // case 'bridge::courier/profile->update': {