@solid-devtools/debugger
Advanced tools
| // src/roots.ts | ||
| import { createEffect as createEffect2, onCleanup, untrack as untrack2 } from "solid-js"; | ||
| import { throttle as throttle3 } from "@solid-primitives/scheduled"; | ||
| import { | ||
| getOwner as getOwner2, | ||
| NodeType as NodeType4 | ||
| } from "@solid-devtools/shared/graph"; | ||
| import { INTERNAL as INTERNAL2 } from "@solid-devtools/shared/variables"; | ||
| import { untrackedCallback as untrackedCallback2 } from "@solid-devtools/shared/primitives"; | ||
| import { warn as warn2 } from "@solid-devtools/shared/utils"; | ||
| // src/walker.ts | ||
| import { resolveElements } from "@solid-primitives/refs"; | ||
| import { NodeType as NodeType2 } from "@solid-devtools/shared/graph"; | ||
| // src/utils.ts | ||
| import { createComputed, createRoot, runWithOwner } from "solid-js"; | ||
| import { noop, warn } from "@solid-primitives/utils"; | ||
| import { | ||
| NodeType, | ||
| getOwner | ||
| } from "@solid-devtools/shared/graph"; | ||
| import { INTERNAL, UNNAMED } from "@solid-devtools/shared/variables"; | ||
| import { trimString } from "@solid-devtools/shared/utils"; | ||
| import { createSimpleEmitter } from "@solid-primitives/event-bus"; | ||
| import { throttle } from "@solid-primitives/scheduled"; | ||
| var isSolidComputation = (o) => "fn" in o; | ||
| var isSolidMemo = (o) => "sdtType" in o ? o.sdtType === NodeType.Memo : _isMemo(o) && !fnMatchesRefresh(o.fn); | ||
| var isSolidOwner = (o) => "owned" in o; | ||
| var isSolidRoot = (o) => o.sdtType === NodeType.Root || !isSolidComputation(o); | ||
| var isSolidComponent = (o) => "componentName" in o; | ||
| var _isMemo = (o) => "value" in o && "comparator" in o && o.pure === true; | ||
| var fnMatchesRefresh = (fn) => (fn + "").replace(/[\n\t]/g, "").replace(/ +/g, " ") === "() => { const c = source(); if (c) { return untrack(() => c(props)); } return undefined; }"; | ||
| function getOwnerName(owner) { | ||
| const { name, componentName: component } = owner; | ||
| if (component && typeof component === "string") | ||
| return component.startsWith("_Hot$$") ? component.slice(6) : component; | ||
| return name || UNNAMED; | ||
| } | ||
| function getSignalName(signal) { | ||
| return signal.name || UNNAMED; | ||
| } | ||
| function getNodeName(o) { | ||
| const name = isSolidOwner(o) ? getOwnerName(o) : getSignalName(o); | ||
| return trimString(name, 16); | ||
| } | ||
| function getNodeType(o) { | ||
| if (isSolidOwner(o)) | ||
| return getOwnerType(o); | ||
| return NodeType.Signal; | ||
| } | ||
| var getOwnerType = (o) => { | ||
| if (typeof o.sdtType !== "undefined") | ||
| return o.sdtType; | ||
| if (!isSolidComputation(o)) | ||
| return NodeType.Root; | ||
| if (isSolidComponent(o)) | ||
| return NodeType.Component; | ||
| if (_isMemo(o)) { | ||
| if (fnMatchesRefresh(o.fn)) | ||
| return NodeType.Refresh; | ||
| return NodeType.Memo; | ||
| } | ||
| if (o.pure === false) { | ||
| if (o.user === true) | ||
| return NodeType.Effect; | ||
| return NodeType.Render; | ||
| } | ||
| return NodeType.Computation; | ||
| }; | ||
| function lookupOwner(owner, predicate) { | ||
| do { | ||
| if (predicate(owner)) | ||
| return owner; | ||
| owner = owner.owner; | ||
| } while (owner.owner); | ||
| return null; | ||
| } | ||
| function setDebuggerContext(owner, ctx) { | ||
| owner.sdtContext = ctx; | ||
| } | ||
| function getDebuggerContext(owner) { | ||
| while (!owner.sdtContext && owner.owner) | ||
| owner = owner.owner; | ||
| return owner.sdtContext; | ||
| } | ||
| function removeDebuggerContext(owner) { | ||
| delete owner.sdtContext; | ||
| } | ||
| function onOwnerCleanup(owner, fn, prepend = false) { | ||
| if (owner.cleanups === null) | ||
| owner.cleanups = [fn]; | ||
| else if (prepend) | ||
| owner.cleanups.splice(0, 0, fn); | ||
| else | ||
| owner.cleanups.push(fn); | ||
| return () => { | ||
| var _a; | ||
| return (_a = owner.cleanups) == null ? void 0 : _a.splice(owner.cleanups.indexOf(fn), 1); | ||
| }; | ||
| } | ||
| function onParentCleanup(owner, fn, prepend = false) { | ||
| if (owner.owner) | ||
| return onOwnerCleanup(owner.owner, fn, prepend); | ||
| return noop; | ||
| } | ||
| var DISPOSE_ID = Symbol("Dispose ID"); | ||
| function createUnownedRoot(fn) { | ||
| return runWithOwner(null, () => createRoot(fn)); | ||
| } | ||
| function getFunctionSources(fn) { | ||
| let nodes; | ||
| let init = true; | ||
| runWithOwner( | ||
| null, | ||
| () => createRoot( | ||
| (dispose) => createComputed(() => { | ||
| if (!init) | ||
| return; | ||
| init = false; | ||
| fn(); | ||
| const sources = getOwner().sources; | ||
| if (sources) | ||
| nodes = [...sources]; | ||
| dispose(); | ||
| }) | ||
| ) | ||
| ); | ||
| return nodes ?? []; | ||
| } | ||
| var LAST_ID = 0; | ||
| var getNewSdtId = () => (LAST_ID++).toString(36); | ||
| function markOwnerName(o) { | ||
| if (o.sdtName !== void 0) | ||
| return o.sdtName; | ||
| return o.sdtName = getNodeName(o); | ||
| } | ||
| function markOwnerType(o, type) { | ||
| if (o.sdtType !== void 0) | ||
| return o.sdtType; | ||
| return o.sdtType = type ?? getOwnerType(o); | ||
| } | ||
| function markNodeID(o) { | ||
| if (o.sdtId !== void 0) | ||
| return o.sdtId; | ||
| return o.sdtId = getNewSdtId(); | ||
| } | ||
| function markNodesID(nodes) { | ||
| if (!nodes || !nodes.length) | ||
| return []; | ||
| return nodes.map(markNodeID); | ||
| } | ||
| var SkipInternalRoot = null; | ||
| var createInternalRoot = (fn, detachedOwner) => { | ||
| SkipInternalRoot = fn; | ||
| const v = createRoot((dispose) => { | ||
| const owner = getOwner(); | ||
| setDebuggerContext(owner, INTERNAL); | ||
| return fn(dispose); | ||
| }, detachedOwner); | ||
| if (SkipInternalRoot === fn) | ||
| SkipInternalRoot = null; | ||
| return v; | ||
| }; | ||
| var skipInternalRoot = () => { | ||
| const skip = !!SkipInternalRoot; | ||
| if (skip) | ||
| SkipInternalRoot = null; | ||
| return skip; | ||
| }; | ||
| function createBatchedUpdateEmitter() { | ||
| const [handleUpdates, emitUpdates] = createSimpleEmitter(); | ||
| const updates = []; | ||
| const triggerUpdateEmit = throttle(() => { | ||
| const ids = /* @__PURE__ */ new Set(); | ||
| const deduped = []; | ||
| for (let i = updates.length - 1; i >= 0; i--) { | ||
| const update = updates[i]; | ||
| if (ids.has(update.id)) | ||
| continue; | ||
| ids.add(update.id); | ||
| deduped.push(update); | ||
| } | ||
| updates.length = 0; | ||
| emitUpdates(deduped); | ||
| }); | ||
| const pushUpdate = (update) => { | ||
| updates.push(update); | ||
| triggerUpdateEmit(); | ||
| }; | ||
| return [handleUpdates, pushUpdate]; | ||
| } | ||
| // src/update.ts | ||
| import { untrack } from "solid-js"; | ||
| import { noop as noop2, onRootCleanup } from "@solid-primitives/utils"; | ||
| import { Observable } from "object-observer"; | ||
| import { WINDOW_WRAP_STORE_PROPERTY } from "@solid-devtools/shared/variables"; | ||
| var GraphUpdateListeners = /* @__PURE__ */ new Set(); | ||
| { | ||
| const runListeners = () => GraphUpdateListeners.forEach((f) => f()); | ||
| if (typeof window._$afterUpdate === "function") { | ||
| GraphUpdateListeners.add(window._$afterUpdate); | ||
| } | ||
| window._$afterUpdate = runListeners; | ||
| } | ||
| function makeSolidUpdateListener(onUpdate2) { | ||
| GraphUpdateListeners.add(onUpdate2); | ||
| return onRootCleanup(() => { | ||
| GraphUpdateListeners.delete(onUpdate2); | ||
| }); | ||
| } | ||
| var CreateRootListeners = /* @__PURE__ */ new Set(); | ||
| { | ||
| const runListeners = (root) => { | ||
| if (skipInternalRoot()) | ||
| return; | ||
| CreateRootListeners.forEach((f) => f(root)); | ||
| }; | ||
| if (typeof window._$afterCreateRoot === "function") { | ||
| CreateRootListeners.add(window._$afterCreateRoot); | ||
| } | ||
| window._$afterCreateRoot = runListeners; | ||
| } | ||
| function makeCreateRootListener(onUpdate2) { | ||
| CreateRootListeners.add(onUpdate2); | ||
| return onRootCleanup(() => CreateRootListeners.delete(onUpdate2)); | ||
| } | ||
| window[WINDOW_WRAP_STORE_PROPERTY] = (init) => { | ||
| return Observable.from(init); | ||
| }; | ||
| function makeStoreObserver(state, onUpdate2) { | ||
| if (!Observable.isObservable(state)) { | ||
| console.warn(`Object ${state} is not wrapped`); | ||
| return noop2; | ||
| } | ||
| Observable.observe(state, onUpdate2); | ||
| return onRootCleanup(() => Observable.unobserve(state, onUpdate2)); | ||
| } | ||
| function observeComputationUpdate(owner, onRun) { | ||
| if (owner.onComputationUpdate) | ||
| return void (owner.onComputationUpdate = onRun); | ||
| owner.onComputationUpdate = onRun; | ||
| interceptComputationRerun(owner, (fn) => { | ||
| untrack(owner.onComputationUpdate); | ||
| fn(); | ||
| }); | ||
| } | ||
| function interceptComputationRerun(owner, onRun) { | ||
| const _fn = owner.fn; | ||
| let v; | ||
| let prev; | ||
| const fn = () => v = _fn(prev); | ||
| owner.fn = !!owner.fn.length ? (p) => { | ||
| onRun(fn, prev = p); | ||
| return v; | ||
| } : () => { | ||
| onRun(fn, void 0); | ||
| return v; | ||
| }; | ||
| } | ||
| function observeValueUpdate(node, onUpdate2, symbol) { | ||
| if (node.onValueUpdate) { | ||
| node.onValueUpdate[symbol] = onUpdate2; | ||
| return; | ||
| } | ||
| const map = node.onValueUpdate = { [symbol]: onUpdate2 }; | ||
| let value = node.value; | ||
| Object.defineProperty(node, "value", { | ||
| get: () => value, | ||
| set: (newValue) => { | ||
| for (let sym of Object.getOwnPropertySymbols(map)) | ||
| map[sym](newValue, value); | ||
| value = newValue; | ||
| } | ||
| }); | ||
| } | ||
| function removeValueUpdateObserver(node, symbol) { | ||
| if (node.onValueUpdate) | ||
| delete node.onValueUpdate[symbol]; | ||
| } | ||
| function makeValueUpdateListener(node, onUpdate2, symbol) { | ||
| observeValueUpdate(node, onUpdate2, symbol); | ||
| onRootCleanup(() => removeValueUpdateObserver(node, symbol)); | ||
| } | ||
| // src/walker.ts | ||
| var $inspectedId; | ||
| var $rootId; | ||
| var $onComputationUpdate; | ||
| var $gatherComponents; | ||
| var $components = []; | ||
| var $inspectedOwner; | ||
| function mapChildren(owner) { | ||
| const { owned } = owner; | ||
| if (!owned || !owned.length) | ||
| return; | ||
| const children = Array(owned.length); | ||
| for (let i = 0; i < children.length; i++) | ||
| children[i] = mapOwner(owned[i]); | ||
| return children; | ||
| } | ||
| function mapOwner(owner) { | ||
| const type = markOwnerType(owner); | ||
| const id = markNodeID(owner); | ||
| const name = markOwnerName(owner); | ||
| const mapped = { id, name, type }; | ||
| if (id === $inspectedId) | ||
| $inspectedOwner = owner; | ||
| if (type === NodeType2.Component) { | ||
| if ($gatherComponents) { | ||
| const element = resolveElements(owner.value); | ||
| if (element) | ||
| $components.push({ id, name, element }); | ||
| } | ||
| const { owned } = owner; | ||
| let refresh; | ||
| let hmr = false; | ||
| if (owned && owned.length === 1 && markOwnerType(refresh = owned[0]) === NodeType2.Refresh) { | ||
| owner = refresh; | ||
| hmr = true; | ||
| } | ||
| ; | ||
| mapped.hmr = hmr; | ||
| } else { | ||
| observeComputationUpdate( | ||
| owner, | ||
| $onComputationUpdate.bind(void 0, $rootId, id) | ||
| ); | ||
| if (!owner.sources || owner.sources.length === 0) { | ||
| ; | ||
| mapped.frozen = true; | ||
| } | ||
| } | ||
| const children = mapChildren(owner); | ||
| if (children) | ||
| mapped.children = children; | ||
| return mapped; | ||
| } | ||
| function mapRoot(root, id, attached) { | ||
| if (id === $inspectedId) | ||
| $inspectedOwner = root; | ||
| const mapped = { id, type: NodeType2.Root }; | ||
| const children = mapChildren(root); | ||
| if (children) | ||
| mapped.children = children; | ||
| if (attached) | ||
| mapped.attached = markNodeID(attached); | ||
| return mapped; | ||
| } | ||
| function walkSolidTree(owner, config) { | ||
| $inspectedId = config.inspectedId; | ||
| $rootId = config.rootId; | ||
| $onComputationUpdate = config.onComputationUpdate; | ||
| $gatherComponents = !!config.gatherComponents; | ||
| $inspectedOwner = null; | ||
| $components = []; | ||
| const root = mapRoot(owner, $rootId, owner.sdtAttached); | ||
| return { root, inspectedOwner: $inspectedOwner, components: $components }; | ||
| } | ||
| // src/plugin.ts | ||
| import { createEffect, createSignal } from "solid-js"; | ||
| import { createSimpleEmitter as createSimpleEmitter2 } from "@solid-primitives/event-bus"; | ||
| import { createStaticStore } from "@solid-primitives/utils"; | ||
| import { throttle as throttle2 } from "@solid-primitives/scheduled"; | ||
| import { encodeValue as encodeValue2, ElementMap as ElementMap2 } from "@solid-devtools/shared/serialize"; | ||
| import { createConsumers, untrackedCallback } from "@solid-devtools/shared/primitives"; | ||
| // src/inspect.ts | ||
| import { NodeType as NodeType3 } from "@solid-devtools/shared/graph"; | ||
| import { encodeValue, ValueType } from "@solid-devtools/shared/serialize"; | ||
| import { $PROXY } from "solid-js"; | ||
| var $elementMap; | ||
| var $signalMap; | ||
| var INSPECTOR = Symbol("inspector"); | ||
| function mapSignalNode(node, handler) { | ||
| const id = markNodeID(node); | ||
| $signalMap[id] = node; | ||
| observeValueUpdate(node, (value) => handler(id, value), INSPECTOR); | ||
| return { | ||
| type: getNodeType(node), | ||
| name: getNodeName(node), | ||
| id, | ||
| observers: markNodesID(node.observers), | ||
| value: encodeValue(node.value, false, $elementMap) | ||
| }; | ||
| } | ||
| function clearOwnerObservers(owner) { | ||
| if (owner.sourceMap) { | ||
| for (const node of Object.values(owner.sourceMap)) | ||
| removeValueUpdateObserver(node, INSPECTOR); | ||
| } | ||
| if (owner.owned) { | ||
| for (const node of owner.owned) | ||
| removeValueUpdateObserver(node, INSPECTOR); | ||
| } | ||
| } | ||
| function encodeComponentProps(owner, config) { | ||
| if (!isSolidComponent(owner)) | ||
| return null; | ||
| const { elementMap, inspectedProps } = config; | ||
| const { props } = owner; | ||
| const proxy = !!props[$PROXY]; | ||
| const record = Object.entries(Object.getOwnPropertyDescriptors(props)).reduce( | ||
| (record2, [key, descriptor]) => { | ||
| record2[key] = "get" in descriptor ? { type: ValueType.Getter, value: key } : encodeValue(descriptor.value, inspectedProps.has(key), elementMap); | ||
| return record2; | ||
| }, | ||
| {} | ||
| ); | ||
| return { proxy, record }; | ||
| } | ||
| function collectOwnerDetails(owner, config) { | ||
| const { elementMap, signalUpdateHandler, inspectedProps } = config; | ||
| const signalMap = {}; | ||
| $elementMap = elementMap; | ||
| $signalMap = signalMap; | ||
| let { sourceMap, owned } = owner; | ||
| let refresh; | ||
| if (owned && owned.length === 1 && markOwnerType(refresh = owned[0]) === NodeType3.Refresh) { | ||
| sourceMap = refresh.sourceMap; | ||
| owned = refresh.owned; | ||
| } | ||
| let signals; | ||
| if (sourceMap) { | ||
| const signalNodes = Object.values(sourceMap); | ||
| signals = Array(signalNodes.length); | ||
| for (let i = 0; i < signalNodes.length; i++) { | ||
| signals[i] = mapSignalNode(signalNodes[i], signalUpdateHandler); | ||
| } | ||
| } else | ||
| signals = []; | ||
| if (owned) { | ||
| for (const node of owned) { | ||
| if (isSolidMemo(node)) | ||
| signals.push(mapSignalNode(node, signalUpdateHandler)); | ||
| } | ||
| } | ||
| const details = { | ||
| id: markNodeID(owner), | ||
| name: markOwnerName(owner), | ||
| type: markOwnerType(owner), | ||
| signals | ||
| }; | ||
| if (isSolidComputation(owner)) { | ||
| details.value = encodeValue(owner.value, false, elementMap); | ||
| details.sources = markNodesID(owner.sources); | ||
| if (isSolidMemo(owner)) { | ||
| details.observers = markNodesID(owner.observers); | ||
| } | ||
| const props = encodeComponentProps(owner, { inspectedProps, elementMap }); | ||
| if (props) | ||
| details.props = props; | ||
| } | ||
| return { details, signalMap }; | ||
| } | ||
| // src/plugin.ts | ||
| var getNullInspected = () => ({ | ||
| id: null, | ||
| rootId: null, | ||
| owner: null, | ||
| details: null, | ||
| signalMap: {}, | ||
| elementMap: new ElementMap2() | ||
| }); | ||
| var [handleStructureUpdates, pushStructureUpdate] = (() => { | ||
| const [handleStructureUpdate, emitStructureUpdate] = createSimpleEmitter2(); | ||
| const updates = []; | ||
| const removedIds = /* @__PURE__ */ new Set(); | ||
| const trigger = throttle2(() => { | ||
| const updated = {}; | ||
| for (let i = updates.length - 1; i >= 0; i--) { | ||
| const update = updates[i]; | ||
| const { id } = update; | ||
| if (!removedIds.has(id) && !updated[id]) | ||
| updated[id] = update; | ||
| } | ||
| emitStructureUpdate({ updated, removed: [...removedIds] }); | ||
| updates.length = 0; | ||
| removedIds.clear(); | ||
| }, 50); | ||
| const pushStructureUpdate2 = (update) => { | ||
| if ("removed" in update) | ||
| removedIds.add(update.removed); | ||
| else if (removedIds.has(update.updated.id)) | ||
| return; | ||
| else | ||
| updates.push(update.updated); | ||
| trigger(); | ||
| }; | ||
| return [handleStructureUpdate, pushStructureUpdate2]; | ||
| })(); | ||
| var debuggerConfig = { | ||
| gatherComponents: false | ||
| }; | ||
| var exported = createInternalRoot(() => { | ||
| const [onUpdate2, triggerUpdate] = createSimpleEmitter2(); | ||
| const [onForceUpdate2, forceTriggerUpdate] = createSimpleEmitter2(); | ||
| const [enabled2, addDebuggerConsumer] = createConsumers(); | ||
| const [components, setComponents] = createSignal({}); | ||
| const findComponent = (rootId, nodeId) => { | ||
| const componentsList = components()[rootId]; | ||
| if (!componentsList) | ||
| return; | ||
| for (const c of componentsList) { | ||
| if (c.id === nodeId) | ||
| return c; | ||
| } | ||
| }; | ||
| function removeRoot2(rootId) { | ||
| setComponents((prev) => { | ||
| const copy = Object.assign({}, prev); | ||
| delete copy[rootId]; | ||
| return copy; | ||
| }); | ||
| pushStructureUpdate({ removed: rootId }); | ||
| } | ||
| function updateRoot2(newRoot, newComponents) { | ||
| setComponents((prev) => Object.assign(prev, { [newRoot.id]: newComponents })); | ||
| pushStructureUpdate({ updated: newRoot }); | ||
| } | ||
| const [inspected, setInspected] = createStaticStore(getNullInspected()); | ||
| let lastInspectedOwner = null; | ||
| const inspectedSignals = /* @__PURE__ */ new Set(); | ||
| const inspectedProps = /* @__PURE__ */ new Set(); | ||
| const [handleSignalUpdates, pushSignalUpdate] = createBatchedUpdateEmitter(); | ||
| const signalUpdateHandler = untrackedCallback((id, value) => { | ||
| if (!enabled2() || !inspected.id) | ||
| return; | ||
| const isSelected = inspectedSignals.has(id); | ||
| pushSignalUpdate({ id, value: encodeValue2(value, isSelected, inspected.elementMap) }); | ||
| }); | ||
| const [handlePropsUpdate, emitPropsUpdate] = createSimpleEmitter2(); | ||
| const updateInspectedDetails = untrackedCallback(() => { | ||
| const { owner, elementMap } = inspected; | ||
| if (!owner) | ||
| return; | ||
| const { details, signalMap } = collectOwnerDetails(owner, { | ||
| elementMap, | ||
| signalUpdateHandler, | ||
| inspectedProps | ||
| }); | ||
| setInspected({ details, signalMap }); | ||
| }); | ||
| const updateInspectedProps = untrackedCallback(() => { | ||
| const { owner, elementMap } = inspected; | ||
| if (!owner) | ||
| return; | ||
| const props = encodeComponentProps(owner, { inspectedProps, elementMap }); | ||
| props && emitPropsUpdate(props); | ||
| }); | ||
| createEffect(() => { | ||
| if (!enabled2()) | ||
| lastInspectedOwner && clearOwnerObservers(lastInspectedOwner); | ||
| else | ||
| updateInspectedDetails(); | ||
| createEffect(() => { | ||
| const owner = inspected.owner; | ||
| if (lastInspectedOwner && lastInspectedOwner !== owner) | ||
| clearOwnerObservers(lastInspectedOwner); | ||
| lastInspectedOwner = owner; | ||
| makeSolidUpdateListener(throttle2(updateInspectedProps, 150)); | ||
| }); | ||
| }); | ||
| const setInspectedOwner = untrackedCallback((payload) => { | ||
| if (!payload) | ||
| return setInspected(getNullInspected()); | ||
| const { rootId, nodeId } = payload; | ||
| if (inspected.id === nodeId) | ||
| return; | ||
| const result = walkSolidRoot(rootId, nodeId); | ||
| if (!result || !result.inspectedOwner) | ||
| return setInspected(getNullInspected()); | ||
| const owner = result.inspectedOwner; | ||
| const elementMap = new ElementMap2(); | ||
| inspectedProps.clear(); | ||
| inspectedSignals.clear(); | ||
| const { details, signalMap } = collectOwnerDetails(owner, { | ||
| elementMap, | ||
| signalUpdateHandler, | ||
| inspectedProps | ||
| }); | ||
| setInspected({ id: nodeId, rootId, owner, details, signalMap, elementMap }); | ||
| }); | ||
| const setInspectedSignal = untrackedCallback((id, selected) => { | ||
| const { signalMap, elementMap } = inspected; | ||
| const signal = signalMap[id]; | ||
| if (!signal) | ||
| return null; | ||
| if (selected) | ||
| inspectedSignals.add(id); | ||
| else | ||
| inspectedSignals.delete(id); | ||
| return encodeValue2(signal.value, selected, elementMap); | ||
| }); | ||
| const setInspectedProp = untrackedCallback((key, selected) => { | ||
| if (selected) | ||
| inspectedProps.add(key); | ||
| else | ||
| inspectedProps.delete(key); | ||
| updateInspectedProps(); | ||
| }); | ||
| const [handleComputationUpdates, _pushComputationUpdate] = createBatchedUpdateEmitter(); | ||
| const pushComputationUpdate2 = (rootId, id) => { | ||
| _pushComputationUpdate({ rootId, id }); | ||
| }; | ||
| const pluginData = { | ||
| handleComputationUpdates, | ||
| handleSignalUpdates, | ||
| handlePropsUpdate, | ||
| handleStructureUpdates, | ||
| components, | ||
| findComponent, | ||
| triggerUpdate, | ||
| forceTriggerUpdate, | ||
| setInspectedOwner, | ||
| inspected, | ||
| setInspectedSignal, | ||
| setInspectedProp | ||
| }; | ||
| function useDebugger2(options) { | ||
| const { enabled: enabled3, gatherComponents } = options; | ||
| enabled3 && addDebuggerConsumer(enabled3); | ||
| if (gatherComponents) | ||
| debuggerConfig.gatherComponents = true; | ||
| return pluginData; | ||
| } | ||
| return { | ||
| onUpdate: onUpdate2, | ||
| onForceUpdate: onForceUpdate2, | ||
| enabled: enabled2, | ||
| useDebugger: useDebugger2, | ||
| updateRoot: updateRoot2, | ||
| removeRoot: removeRoot2, | ||
| pushComputationUpdate: pushComputationUpdate2 | ||
| }; | ||
| }); | ||
| var { | ||
| onUpdate, | ||
| onForceUpdate, | ||
| enabled, | ||
| useDebugger, | ||
| updateRoot, | ||
| removeRoot, | ||
| pushComputationUpdate | ||
| } = exported; | ||
| // src/roots.ts | ||
| var RootMap = {}; | ||
| var walkSolidRoot = (rootId, inspectedId) => { | ||
| const walk = RootMap[rootId]; | ||
| return walk ? walk(inspectedId) : null; | ||
| }; | ||
| function createGraphRoot(owner) { | ||
| createInternalRoot((dispose) => { | ||
| onOwnerCleanup(owner, dispose); | ||
| const rootId = markNodeID(owner); | ||
| const onComputationUpdate = (rootId2, nodeId) => { | ||
| if (owner.isDisposed) | ||
| return; | ||
| if (untrack2(enabled)) | ||
| triggerRootUpdate(); | ||
| pushComputationUpdate(rootId2, nodeId); | ||
| }; | ||
| const forceRootUpdate = untrackedCallback2((inspectedId) => { | ||
| if (owner.isDisposed) | ||
| return null; | ||
| const result = walkSolidTree(owner, { | ||
| ...debuggerConfig, | ||
| onComputationUpdate, | ||
| rootId, | ||
| inspectedId: inspectedId ?? null | ||
| }); | ||
| updateRoot(result.root, result.components); | ||
| return result; | ||
| }); | ||
| const triggerRootUpdate = throttle3(forceRootUpdate, 300); | ||
| RootMap[rootId] = forceRootUpdate; | ||
| onUpdate(triggerRootUpdate); | ||
| onForceUpdate(forceRootUpdate); | ||
| createEffect2(() => { | ||
| enabled() && forceRootUpdate(); | ||
| }); | ||
| setDebuggerContext(owner, { rootId, triggerRootUpdate, forceRootUpdate }); | ||
| onCleanup(() => { | ||
| removeDebuggerContext(owner); | ||
| removeRoot(rootId); | ||
| owner.isDisposed = true; | ||
| delete RootMap[rootId]; | ||
| }); | ||
| }); | ||
| } | ||
| function attachDebugger(_owner = getOwner2()) { | ||
| let owner = _owner; | ||
| if (!owner) | ||
| return warn2("reatachOwner helper should be called synchronously in a reactive owner."); | ||
| forEachLookupRoot(owner, (root, ctx) => { | ||
| if (ctx === INTERNAL2) | ||
| return; | ||
| root.sdtAttached = null; | ||
| markOwnerType(root, NodeType4.Root); | ||
| createGraphRoot(root); | ||
| if (ctx) { | ||
| ctx.triggerRootUpdate(); | ||
| let parent = findClosestAliveParent(root); | ||
| if (!parent.owner) | ||
| return warn2("PARENT_SHOULD_BE_ALIVE"); | ||
| root.sdtAttached = parent.owner; | ||
| const onParentCleanup2 = () => { | ||
| const newParent = findClosestAliveParent(root); | ||
| if (newParent.owner) { | ||
| parent = newParent; | ||
| root.sdtAttached = parent.owner; | ||
| onOwnerCleanup(parent.root, onParentCleanup2); | ||
| } else { | ||
| root.sdtAttached = null; | ||
| removeOwnCleanup(); | ||
| } | ||
| }; | ||
| const removeParentCleanup = onOwnerCleanup(parent.root, onParentCleanup2); | ||
| const removeOwnCleanup = onOwnerCleanup(root, () => { | ||
| root.isDisposed = true; | ||
| root.sdtAttached = null; | ||
| removeParentCleanup(); | ||
| ctx.triggerRootUpdate(); | ||
| }); | ||
| } | ||
| }); | ||
| } | ||
| function findClosestAliveParent(owner) { | ||
| let disposed = null; | ||
| let closestAliveRoot = null; | ||
| let current = owner; | ||
| while (current.owner && !closestAliveRoot) { | ||
| current = current.owner; | ||
| if (isSolidRoot(current)) { | ||
| if (current.isDisposed) | ||
| disposed = current; | ||
| else | ||
| closestAliveRoot = current; | ||
| } | ||
| } | ||
| if (!closestAliveRoot) | ||
| return { owner: null, root: null }; | ||
| return { owner: (disposed == null ? void 0 : disposed.owner) ?? owner.owner, root: closestAliveRoot }; | ||
| } | ||
| function forEachLookupRoot(owner, callback) { | ||
| const roots = []; | ||
| let ctx; | ||
| do { | ||
| if (isSolidRoot(owner)) { | ||
| if ("sdtAttached" in owner) { | ||
| if (!ctx) | ||
| ctx = getDebuggerContext(owner); | ||
| break; | ||
| } | ||
| if (owner.sdtContext === INTERNAL2) { | ||
| ctx = INTERNAL2; | ||
| break; | ||
| } | ||
| roots.push(owner); | ||
| } | ||
| owner = owner.owner; | ||
| } while (owner); | ||
| for (let i = roots.length - 1; i >= 0; i--) { | ||
| const root = roots[i]; | ||
| callback(root, ctx); | ||
| if (root.sdtContext) | ||
| ctx = root.sdtContext; | ||
| } | ||
| } | ||
| // src/index.ts | ||
| var Debugger = (props) => { | ||
| attachDebugger(); | ||
| return props.children; | ||
| }; | ||
| export { | ||
| isSolidComputation, | ||
| isSolidMemo, | ||
| isSolidOwner, | ||
| isSolidRoot, | ||
| getNodeName, | ||
| getNodeType, | ||
| getOwnerType, | ||
| lookupOwner, | ||
| onOwnerCleanup, | ||
| onParentCleanup, | ||
| createUnownedRoot, | ||
| getFunctionSources, | ||
| createInternalRoot, | ||
| makeSolidUpdateListener, | ||
| makeCreateRootListener, | ||
| makeStoreObserver, | ||
| observeComputationUpdate, | ||
| interceptComputationRerun, | ||
| observeValueUpdate, | ||
| removeValueUpdateObserver, | ||
| makeValueUpdateListener, | ||
| useDebugger, | ||
| attachDebugger, | ||
| Debugger | ||
| }; |
+33
-14
@@ -175,3 +175,3 @@ "use strict"; | ||
| var LAST_ID = 0; | ||
| var getNewSdtId = () => (LAST_ID++).toString(16); | ||
| var getNewSdtId = () => (LAST_ID++).toString(36); | ||
| function markOwnerName(o) { | ||
@@ -352,7 +352,4 @@ if (o.sdtName !== void 0) | ||
| const mapped = { id, name, type }; | ||
| const { owned } = owner; | ||
| if (id === $inspectedId) | ||
| $inspectedOwner = owner; | ||
| if (isSolidComputation(owner)) | ||
| observeComputationUpdate(owner, $onComputationUpdate.bind(void 0, $rootId, id)); | ||
| if (type === import_graph2.NodeType.Component) { | ||
@@ -364,7 +361,20 @@ if ($gatherComponents) { | ||
| } | ||
| const { owned } = owner; | ||
| let refresh; | ||
| let hmr = false; | ||
| if (owned && owned.length === 1 && markOwnerType(refresh = owned[0]) === import_graph2.NodeType.Refresh) { | ||
| owner = refresh; | ||
| mapped.hmr = true; | ||
| hmr = true; | ||
| } | ||
| ; | ||
| mapped.hmr = hmr; | ||
| } else { | ||
| observeComputationUpdate( | ||
| owner, | ||
| $onComputationUpdate.bind(void 0, $rootId, id) | ||
| ); | ||
| if (!owner.sources || owner.sources.length === 0) { | ||
| ; | ||
| mapped.frozen = true; | ||
| } | ||
| } | ||
@@ -376,2 +386,13 @@ const children = mapChildren(owner); | ||
| } | ||
| function mapRoot(root, id, attached) { | ||
| if (id === $inspectedId) | ||
| $inspectedOwner = root; | ||
| const mapped = { id, type: import_graph2.NodeType.Root }; | ||
| const children = mapChildren(root); | ||
| if (children) | ||
| mapped.children = children; | ||
| if (attached) | ||
| mapped.attached = markNodeID(attached); | ||
| return mapped; | ||
| } | ||
| function walkSolidTree(owner, config) { | ||
@@ -384,5 +405,3 @@ $inspectedId = config.inspectedId; | ||
| $components = []; | ||
| const root = { id: $rootId, tree: mapOwner(owner) }; | ||
| if (owner.sdtAttachedTo) | ||
| root.attachedTo = markNodeID(owner.sdtAttachedTo); | ||
| const root = mapRoot(owner, $rootId, owner.sdtAttached); | ||
| return { root, inspectedOwner: $inspectedOwner, components: $components }; | ||
@@ -731,3 +750,3 @@ } | ||
| return; | ||
| root.sdtAttachedTo = null; | ||
| root.sdtAttached = null; | ||
| markOwnerType(root, import_graph4.NodeType.Root); | ||
@@ -740,3 +759,3 @@ createGraphRoot(root); | ||
| return (0, import_utils9.warn)("PARENT_SHOULD_BE_ALIVE"); | ||
| root.sdtAttachedTo = parent.owner; | ||
| root.sdtAttached = parent.owner; | ||
| const onParentCleanup2 = () => { | ||
@@ -746,6 +765,6 @@ const newParent = findClosestAliveParent(root); | ||
| parent = newParent; | ||
| root.sdtAttachedTo = parent.owner; | ||
| root.sdtAttached = parent.owner; | ||
| onOwnerCleanup(parent.root, onParentCleanup2); | ||
| } else { | ||
| root.sdtAttachedTo = null; | ||
| root.sdtAttached = null; | ||
| removeOwnCleanup(); | ||
@@ -757,3 +776,3 @@ } | ||
| root.isDisposed = true; | ||
| root.sdtAttachedTo = null; | ||
| root.sdtAttached = null; | ||
| removeParentCleanup(); | ||
@@ -787,3 +806,3 @@ ctx.triggerRootUpdate(); | ||
| if (isSolidRoot(owner)) { | ||
| if ("sdtAttachedTo" in owner) { | ||
| if ("sdtAttached" in owner) { | ||
| if (!ctx) | ||
@@ -790,0 +809,0 @@ ctx = getDebuggerContext(owner); |
+2
-2
@@ -32,4 +32,4 @@ import { Accessor, createRoot, ParentComponent } from 'solid-js'; | ||
| readonly handleStructureUpdates: Listen<RootsUpdates>; | ||
| readonly components: Accessor<Record<NodeID, Mapped.Component[]>>; | ||
| readonly findComponent: (rootId: NodeID, nodeId: NodeID) => Mapped.Component | undefined; | ||
| readonly components: Accessor<Record<NodeID, Mapped.ResolvedComponent[]>>; | ||
| readonly findComponent: (rootId: NodeID, nodeId: NodeID) => Mapped.ResolvedComponent | undefined; | ||
| readonly setInspectedOwner: (payload: { | ||
@@ -36,0 +36,0 @@ rootId: NodeID; |
+1
-1
@@ -26,3 +26,3 @@ import { | ||
| useDebugger | ||
| } from "./chunk-OV2GPZ42.js"; | ||
| } from "./chunk-QXDVWUIQ.js"; | ||
| export { | ||
@@ -29,0 +29,0 @@ Debugger, |
+1
-1
| import { | ||
| createUnownedRoot | ||
| } from "./chunk-OV2GPZ42.js"; | ||
| } from "./chunk-QXDVWUIQ.js"; | ||
@@ -5,0 +5,0 @@ // src/server.ts |
+2
-2
| { | ||
| "name": "@solid-devtools/debugger", | ||
| "version": "0.9.2", | ||
| "version": "0.10.0", | ||
| "description": "Debugger of the Solid's reactivity graph — a cornerstone of all solid-devtools.", | ||
@@ -61,3 +61,3 @@ "license": "MIT", | ||
| "dependencies": { | ||
| "@solid-devtools/shared": "^0.8.2", | ||
| "@solid-devtools/shared": "^0.8.3", | ||
| "@solid-primitives/event-bus": "^0.1.2", | ||
@@ -64,0 +64,0 @@ "@solid-primitives/refs": "^0.3.2", |
| // src/roots.ts | ||
| import { createEffect as createEffect2, onCleanup, untrack as untrack2 } from "solid-js"; | ||
| import { throttle as throttle3 } from "@solid-primitives/scheduled"; | ||
| import { | ||
| getOwner as getOwner2, | ||
| NodeType as NodeType4 | ||
| } from "@solid-devtools/shared/graph"; | ||
| import { INTERNAL as INTERNAL2 } from "@solid-devtools/shared/variables"; | ||
| import { untrackedCallback as untrackedCallback2 } from "@solid-devtools/shared/primitives"; | ||
| import { warn as warn2 } from "@solid-devtools/shared/utils"; | ||
| // src/walker.ts | ||
| import { resolveElements } from "@solid-primitives/refs"; | ||
| import { NodeType as NodeType2 } from "@solid-devtools/shared/graph"; | ||
| // src/utils.ts | ||
| import { createComputed, createRoot, runWithOwner } from "solid-js"; | ||
| import { noop, warn } from "@solid-primitives/utils"; | ||
| import { | ||
| NodeType, | ||
| getOwner | ||
| } from "@solid-devtools/shared/graph"; | ||
| import { INTERNAL, UNNAMED } from "@solid-devtools/shared/variables"; | ||
| import { trimString } from "@solid-devtools/shared/utils"; | ||
| import { createSimpleEmitter } from "@solid-primitives/event-bus"; | ||
| import { throttle } from "@solid-primitives/scheduled"; | ||
| var isSolidComputation = (o) => "fn" in o; | ||
| var isSolidMemo = (o) => "sdtType" in o ? o.sdtType === NodeType.Memo : _isMemo(o) && !fnMatchesRefresh(o.fn); | ||
| var isSolidOwner = (o) => "owned" in o; | ||
| var isSolidRoot = (o) => o.sdtType === NodeType.Root || !isSolidComputation(o); | ||
| var isSolidComponent = (o) => "componentName" in o; | ||
| var _isMemo = (o) => "value" in o && "comparator" in o && o.pure === true; | ||
| var fnMatchesRefresh = (fn) => (fn + "").replace(/[\n\t]/g, "").replace(/ +/g, " ") === "() => { const c = source(); if (c) { return untrack(() => c(props)); } return undefined; }"; | ||
| function getOwnerName(owner) { | ||
| const { name, componentName: component } = owner; | ||
| if (component && typeof component === "string") | ||
| return component.startsWith("_Hot$$") ? component.slice(6) : component; | ||
| return name || UNNAMED; | ||
| } | ||
| function getSignalName(signal) { | ||
| return signal.name || UNNAMED; | ||
| } | ||
| function getNodeName(o) { | ||
| const name = isSolidOwner(o) ? getOwnerName(o) : getSignalName(o); | ||
| return trimString(name, 16); | ||
| } | ||
| function getNodeType(o) { | ||
| if (isSolidOwner(o)) | ||
| return getOwnerType(o); | ||
| return NodeType.Signal; | ||
| } | ||
| var getOwnerType = (o) => { | ||
| if (typeof o.sdtType !== "undefined") | ||
| return o.sdtType; | ||
| if (!isSolidComputation(o)) | ||
| return NodeType.Root; | ||
| if (isSolidComponent(o)) | ||
| return NodeType.Component; | ||
| if (_isMemo(o)) { | ||
| if (fnMatchesRefresh(o.fn)) | ||
| return NodeType.Refresh; | ||
| return NodeType.Memo; | ||
| } | ||
| if (o.pure === false) { | ||
| if (o.user === true) | ||
| return NodeType.Effect; | ||
| return NodeType.Render; | ||
| } | ||
| return NodeType.Computation; | ||
| }; | ||
| function lookupOwner(owner, predicate) { | ||
| do { | ||
| if (predicate(owner)) | ||
| return owner; | ||
| owner = owner.owner; | ||
| } while (owner.owner); | ||
| return null; | ||
| } | ||
| function setDebuggerContext(owner, ctx) { | ||
| owner.sdtContext = ctx; | ||
| } | ||
| function getDebuggerContext(owner) { | ||
| while (!owner.sdtContext && owner.owner) | ||
| owner = owner.owner; | ||
| return owner.sdtContext; | ||
| } | ||
| function removeDebuggerContext(owner) { | ||
| delete owner.sdtContext; | ||
| } | ||
| function onOwnerCleanup(owner, fn, prepend = false) { | ||
| if (owner.cleanups === null) | ||
| owner.cleanups = [fn]; | ||
| else if (prepend) | ||
| owner.cleanups.splice(0, 0, fn); | ||
| else | ||
| owner.cleanups.push(fn); | ||
| return () => { | ||
| var _a; | ||
| return (_a = owner.cleanups) == null ? void 0 : _a.splice(owner.cleanups.indexOf(fn), 1); | ||
| }; | ||
| } | ||
| function onParentCleanup(owner, fn, prepend = false) { | ||
| if (owner.owner) | ||
| return onOwnerCleanup(owner.owner, fn, prepend); | ||
| return noop; | ||
| } | ||
| var DISPOSE_ID = Symbol("Dispose ID"); | ||
| function createUnownedRoot(fn) { | ||
| return runWithOwner(null, () => createRoot(fn)); | ||
| } | ||
| function getFunctionSources(fn) { | ||
| let nodes; | ||
| let init = true; | ||
| runWithOwner( | ||
| null, | ||
| () => createRoot( | ||
| (dispose) => createComputed(() => { | ||
| if (!init) | ||
| return; | ||
| init = false; | ||
| fn(); | ||
| const sources = getOwner().sources; | ||
| if (sources) | ||
| nodes = [...sources]; | ||
| dispose(); | ||
| }) | ||
| ) | ||
| ); | ||
| return nodes ?? []; | ||
| } | ||
| var LAST_ID = 0; | ||
| var getNewSdtId = () => (LAST_ID++).toString(16); | ||
| function markOwnerName(o) { | ||
| if (o.sdtName !== void 0) | ||
| return o.sdtName; | ||
| return o.sdtName = getNodeName(o); | ||
| } | ||
| function markOwnerType(o, type) { | ||
| if (o.sdtType !== void 0) | ||
| return o.sdtType; | ||
| return o.sdtType = type ?? getOwnerType(o); | ||
| } | ||
| function markNodeID(o) { | ||
| if (o.sdtId !== void 0) | ||
| return o.sdtId; | ||
| return o.sdtId = getNewSdtId(); | ||
| } | ||
| function markNodesID(nodes) { | ||
| if (!nodes || !nodes.length) | ||
| return []; | ||
| return nodes.map(markNodeID); | ||
| } | ||
| var SkipInternalRoot = null; | ||
| var createInternalRoot = (fn, detachedOwner) => { | ||
| SkipInternalRoot = fn; | ||
| const v = createRoot((dispose) => { | ||
| const owner = getOwner(); | ||
| setDebuggerContext(owner, INTERNAL); | ||
| return fn(dispose); | ||
| }, detachedOwner); | ||
| if (SkipInternalRoot === fn) | ||
| SkipInternalRoot = null; | ||
| return v; | ||
| }; | ||
| var skipInternalRoot = () => { | ||
| const skip = !!SkipInternalRoot; | ||
| if (skip) | ||
| SkipInternalRoot = null; | ||
| return skip; | ||
| }; | ||
| function createBatchedUpdateEmitter() { | ||
| const [handleUpdates, emitUpdates] = createSimpleEmitter(); | ||
| const updates = []; | ||
| const triggerUpdateEmit = throttle(() => { | ||
| const ids = /* @__PURE__ */ new Set(); | ||
| const deduped = []; | ||
| for (let i = updates.length - 1; i >= 0; i--) { | ||
| const update = updates[i]; | ||
| if (ids.has(update.id)) | ||
| continue; | ||
| ids.add(update.id); | ||
| deduped.push(update); | ||
| } | ||
| updates.length = 0; | ||
| emitUpdates(deduped); | ||
| }); | ||
| const pushUpdate = (update) => { | ||
| updates.push(update); | ||
| triggerUpdateEmit(); | ||
| }; | ||
| return [handleUpdates, pushUpdate]; | ||
| } | ||
| // src/update.ts | ||
| import { untrack } from "solid-js"; | ||
| import { noop as noop2, onRootCleanup } from "@solid-primitives/utils"; | ||
| import { Observable } from "object-observer"; | ||
| import { WINDOW_WRAP_STORE_PROPERTY } from "@solid-devtools/shared/variables"; | ||
| var GraphUpdateListeners = /* @__PURE__ */ new Set(); | ||
| { | ||
| const runListeners = () => GraphUpdateListeners.forEach((f) => f()); | ||
| if (typeof window._$afterUpdate === "function") { | ||
| GraphUpdateListeners.add(window._$afterUpdate); | ||
| } | ||
| window._$afterUpdate = runListeners; | ||
| } | ||
| function makeSolidUpdateListener(onUpdate2) { | ||
| GraphUpdateListeners.add(onUpdate2); | ||
| return onRootCleanup(() => { | ||
| GraphUpdateListeners.delete(onUpdate2); | ||
| }); | ||
| } | ||
| var CreateRootListeners = /* @__PURE__ */ new Set(); | ||
| { | ||
| const runListeners = (root) => { | ||
| if (skipInternalRoot()) | ||
| return; | ||
| CreateRootListeners.forEach((f) => f(root)); | ||
| }; | ||
| if (typeof window._$afterCreateRoot === "function") { | ||
| CreateRootListeners.add(window._$afterCreateRoot); | ||
| } | ||
| window._$afterCreateRoot = runListeners; | ||
| } | ||
| function makeCreateRootListener(onUpdate2) { | ||
| CreateRootListeners.add(onUpdate2); | ||
| return onRootCleanup(() => CreateRootListeners.delete(onUpdate2)); | ||
| } | ||
| window[WINDOW_WRAP_STORE_PROPERTY] = (init) => { | ||
| return Observable.from(init); | ||
| }; | ||
| function makeStoreObserver(state, onUpdate2) { | ||
| if (!Observable.isObservable(state)) { | ||
| console.warn(`Object ${state} is not wrapped`); | ||
| return noop2; | ||
| } | ||
| Observable.observe(state, onUpdate2); | ||
| return onRootCleanup(() => Observable.unobserve(state, onUpdate2)); | ||
| } | ||
| function observeComputationUpdate(owner, onRun) { | ||
| if (owner.onComputationUpdate) | ||
| return void (owner.onComputationUpdate = onRun); | ||
| owner.onComputationUpdate = onRun; | ||
| interceptComputationRerun(owner, (fn) => { | ||
| untrack(owner.onComputationUpdate); | ||
| fn(); | ||
| }); | ||
| } | ||
| function interceptComputationRerun(owner, onRun) { | ||
| const _fn = owner.fn; | ||
| let v; | ||
| let prev; | ||
| const fn = () => v = _fn(prev); | ||
| owner.fn = !!owner.fn.length ? (p) => { | ||
| onRun(fn, prev = p); | ||
| return v; | ||
| } : () => { | ||
| onRun(fn, void 0); | ||
| return v; | ||
| }; | ||
| } | ||
| function observeValueUpdate(node, onUpdate2, symbol) { | ||
| if (node.onValueUpdate) { | ||
| node.onValueUpdate[symbol] = onUpdate2; | ||
| return; | ||
| } | ||
| const map = node.onValueUpdate = { [symbol]: onUpdate2 }; | ||
| let value = node.value; | ||
| Object.defineProperty(node, "value", { | ||
| get: () => value, | ||
| set: (newValue) => { | ||
| for (let sym of Object.getOwnPropertySymbols(map)) | ||
| map[sym](newValue, value); | ||
| value = newValue; | ||
| } | ||
| }); | ||
| } | ||
| function removeValueUpdateObserver(node, symbol) { | ||
| if (node.onValueUpdate) | ||
| delete node.onValueUpdate[symbol]; | ||
| } | ||
| function makeValueUpdateListener(node, onUpdate2, symbol) { | ||
| observeValueUpdate(node, onUpdate2, symbol); | ||
| onRootCleanup(() => removeValueUpdateObserver(node, symbol)); | ||
| } | ||
| // src/walker.ts | ||
| var $inspectedId; | ||
| var $rootId; | ||
| var $onComputationUpdate; | ||
| var $gatherComponents; | ||
| var $components = []; | ||
| var $inspectedOwner; | ||
| function mapChildren(owner) { | ||
| const { owned } = owner; | ||
| if (!owned || !owned.length) | ||
| return; | ||
| const children = Array(owned.length); | ||
| for (let i = 0; i < children.length; i++) | ||
| children[i] = mapOwner(owned[i]); | ||
| return children; | ||
| } | ||
| function mapOwner(owner) { | ||
| const type = markOwnerType(owner); | ||
| const id = markNodeID(owner); | ||
| const name = markOwnerName(owner); | ||
| const mapped = { id, name, type }; | ||
| const { owned } = owner; | ||
| if (id === $inspectedId) | ||
| $inspectedOwner = owner; | ||
| if (isSolidComputation(owner)) | ||
| observeComputationUpdate(owner, $onComputationUpdate.bind(void 0, $rootId, id)); | ||
| if (type === NodeType2.Component) { | ||
| if ($gatherComponents) { | ||
| const element = resolveElements(owner.value); | ||
| if (element) | ||
| $components.push({ id, name, element }); | ||
| } | ||
| let refresh; | ||
| if (owned && owned.length === 1 && markOwnerType(refresh = owned[0]) === NodeType2.Refresh) { | ||
| owner = refresh; | ||
| mapped.hmr = true; | ||
| } | ||
| } | ||
| const children = mapChildren(owner); | ||
| if (children) | ||
| mapped.children = children; | ||
| return mapped; | ||
| } | ||
| function walkSolidTree(owner, config) { | ||
| $inspectedId = config.inspectedId; | ||
| $rootId = config.rootId; | ||
| $onComputationUpdate = config.onComputationUpdate; | ||
| $gatherComponents = !!config.gatherComponents; | ||
| $inspectedOwner = null; | ||
| $components = []; | ||
| const root = { id: $rootId, tree: mapOwner(owner) }; | ||
| if (owner.sdtAttachedTo) | ||
| root.attachedTo = markNodeID(owner.sdtAttachedTo); | ||
| return { root, inspectedOwner: $inspectedOwner, components: $components }; | ||
| } | ||
| // src/plugin.ts | ||
| import { createEffect, createSignal } from "solid-js"; | ||
| import { createSimpleEmitter as createSimpleEmitter2 } from "@solid-primitives/event-bus"; | ||
| import { createStaticStore } from "@solid-primitives/utils"; | ||
| import { throttle as throttle2 } from "@solid-primitives/scheduled"; | ||
| import { encodeValue as encodeValue2, ElementMap as ElementMap2 } from "@solid-devtools/shared/serialize"; | ||
| import { createConsumers, untrackedCallback } from "@solid-devtools/shared/primitives"; | ||
| // src/inspect.ts | ||
| import { NodeType as NodeType3 } from "@solid-devtools/shared/graph"; | ||
| import { encodeValue, ValueType } from "@solid-devtools/shared/serialize"; | ||
| import { $PROXY } from "solid-js"; | ||
| var $elementMap; | ||
| var $signalMap; | ||
| var INSPECTOR = Symbol("inspector"); | ||
| function mapSignalNode(node, handler) { | ||
| const id = markNodeID(node); | ||
| $signalMap[id] = node; | ||
| observeValueUpdate(node, (value) => handler(id, value), INSPECTOR); | ||
| return { | ||
| type: getNodeType(node), | ||
| name: getNodeName(node), | ||
| id, | ||
| observers: markNodesID(node.observers), | ||
| value: encodeValue(node.value, false, $elementMap) | ||
| }; | ||
| } | ||
| function clearOwnerObservers(owner) { | ||
| if (owner.sourceMap) { | ||
| for (const node of Object.values(owner.sourceMap)) | ||
| removeValueUpdateObserver(node, INSPECTOR); | ||
| } | ||
| if (owner.owned) { | ||
| for (const node of owner.owned) | ||
| removeValueUpdateObserver(node, INSPECTOR); | ||
| } | ||
| } | ||
| function encodeComponentProps(owner, config) { | ||
| if (!isSolidComponent(owner)) | ||
| return null; | ||
| const { elementMap, inspectedProps } = config; | ||
| const { props } = owner; | ||
| const proxy = !!props[$PROXY]; | ||
| const record = Object.entries(Object.getOwnPropertyDescriptors(props)).reduce( | ||
| (record2, [key, descriptor]) => { | ||
| record2[key] = "get" in descriptor ? { type: ValueType.Getter, value: key } : encodeValue(descriptor.value, inspectedProps.has(key), elementMap); | ||
| return record2; | ||
| }, | ||
| {} | ||
| ); | ||
| return { proxy, record }; | ||
| } | ||
| function collectOwnerDetails(owner, config) { | ||
| const { elementMap, signalUpdateHandler, inspectedProps } = config; | ||
| const signalMap = {}; | ||
| $elementMap = elementMap; | ||
| $signalMap = signalMap; | ||
| let { sourceMap, owned } = owner; | ||
| let refresh; | ||
| if (owned && owned.length === 1 && markOwnerType(refresh = owned[0]) === NodeType3.Refresh) { | ||
| sourceMap = refresh.sourceMap; | ||
| owned = refresh.owned; | ||
| } | ||
| let signals; | ||
| if (sourceMap) { | ||
| const signalNodes = Object.values(sourceMap); | ||
| signals = Array(signalNodes.length); | ||
| for (let i = 0; i < signalNodes.length; i++) { | ||
| signals[i] = mapSignalNode(signalNodes[i], signalUpdateHandler); | ||
| } | ||
| } else | ||
| signals = []; | ||
| if (owned) { | ||
| for (const node of owned) { | ||
| if (isSolidMemo(node)) | ||
| signals.push(mapSignalNode(node, signalUpdateHandler)); | ||
| } | ||
| } | ||
| const details = { | ||
| id: markNodeID(owner), | ||
| name: markOwnerName(owner), | ||
| type: markOwnerType(owner), | ||
| signals | ||
| }; | ||
| if (isSolidComputation(owner)) { | ||
| details.value = encodeValue(owner.value, false, elementMap); | ||
| details.sources = markNodesID(owner.sources); | ||
| if (isSolidMemo(owner)) { | ||
| details.observers = markNodesID(owner.observers); | ||
| } | ||
| const props = encodeComponentProps(owner, { inspectedProps, elementMap }); | ||
| if (props) | ||
| details.props = props; | ||
| } | ||
| return { details, signalMap }; | ||
| } | ||
| // src/plugin.ts | ||
| var getNullInspected = () => ({ | ||
| id: null, | ||
| rootId: null, | ||
| owner: null, | ||
| details: null, | ||
| signalMap: {}, | ||
| elementMap: new ElementMap2() | ||
| }); | ||
| var [handleStructureUpdates, pushStructureUpdate] = (() => { | ||
| const [handleStructureUpdate, emitStructureUpdate] = createSimpleEmitter2(); | ||
| const updates = []; | ||
| const removedIds = /* @__PURE__ */ new Set(); | ||
| const trigger = throttle2(() => { | ||
| const updated = {}; | ||
| for (let i = updates.length - 1; i >= 0; i--) { | ||
| const update = updates[i]; | ||
| const { id } = update; | ||
| if (!removedIds.has(id) && !updated[id]) | ||
| updated[id] = update; | ||
| } | ||
| emitStructureUpdate({ updated, removed: [...removedIds] }); | ||
| updates.length = 0; | ||
| removedIds.clear(); | ||
| }, 50); | ||
| const pushStructureUpdate2 = (update) => { | ||
| if ("removed" in update) | ||
| removedIds.add(update.removed); | ||
| else if (removedIds.has(update.updated.id)) | ||
| return; | ||
| else | ||
| updates.push(update.updated); | ||
| trigger(); | ||
| }; | ||
| return [handleStructureUpdate, pushStructureUpdate2]; | ||
| })(); | ||
| var debuggerConfig = { | ||
| gatherComponents: false | ||
| }; | ||
| var exported = createInternalRoot(() => { | ||
| const [onUpdate2, triggerUpdate] = createSimpleEmitter2(); | ||
| const [onForceUpdate2, forceTriggerUpdate] = createSimpleEmitter2(); | ||
| const [enabled2, addDebuggerConsumer] = createConsumers(); | ||
| const [components, setComponents] = createSignal({}); | ||
| const findComponent = (rootId, nodeId) => { | ||
| const componentsList = components()[rootId]; | ||
| if (!componentsList) | ||
| return; | ||
| for (const c of componentsList) { | ||
| if (c.id === nodeId) | ||
| return c; | ||
| } | ||
| }; | ||
| function removeRoot2(rootId) { | ||
| setComponents((prev) => { | ||
| const copy = Object.assign({}, prev); | ||
| delete copy[rootId]; | ||
| return copy; | ||
| }); | ||
| pushStructureUpdate({ removed: rootId }); | ||
| } | ||
| function updateRoot2(newRoot, newComponents) { | ||
| setComponents((prev) => Object.assign(prev, { [newRoot.id]: newComponents })); | ||
| pushStructureUpdate({ updated: newRoot }); | ||
| } | ||
| const [inspected, setInspected] = createStaticStore(getNullInspected()); | ||
| let lastInspectedOwner = null; | ||
| const inspectedSignals = /* @__PURE__ */ new Set(); | ||
| const inspectedProps = /* @__PURE__ */ new Set(); | ||
| const [handleSignalUpdates, pushSignalUpdate] = createBatchedUpdateEmitter(); | ||
| const signalUpdateHandler = untrackedCallback((id, value) => { | ||
| if (!enabled2() || !inspected.id) | ||
| return; | ||
| const isSelected = inspectedSignals.has(id); | ||
| pushSignalUpdate({ id, value: encodeValue2(value, isSelected, inspected.elementMap) }); | ||
| }); | ||
| const [handlePropsUpdate, emitPropsUpdate] = createSimpleEmitter2(); | ||
| const updateInspectedDetails = untrackedCallback(() => { | ||
| const { owner, elementMap } = inspected; | ||
| if (!owner) | ||
| return; | ||
| const { details, signalMap } = collectOwnerDetails(owner, { | ||
| elementMap, | ||
| signalUpdateHandler, | ||
| inspectedProps | ||
| }); | ||
| setInspected({ details, signalMap }); | ||
| }); | ||
| const updateInspectedProps = untrackedCallback(() => { | ||
| const { owner, elementMap } = inspected; | ||
| if (!owner) | ||
| return; | ||
| const props = encodeComponentProps(owner, { inspectedProps, elementMap }); | ||
| props && emitPropsUpdate(props); | ||
| }); | ||
| createEffect(() => { | ||
| if (!enabled2()) | ||
| lastInspectedOwner && clearOwnerObservers(lastInspectedOwner); | ||
| else | ||
| updateInspectedDetails(); | ||
| createEffect(() => { | ||
| const owner = inspected.owner; | ||
| if (lastInspectedOwner && lastInspectedOwner !== owner) | ||
| clearOwnerObservers(lastInspectedOwner); | ||
| lastInspectedOwner = owner; | ||
| makeSolidUpdateListener(throttle2(updateInspectedProps, 150)); | ||
| }); | ||
| }); | ||
| const setInspectedOwner = untrackedCallback((payload) => { | ||
| if (!payload) | ||
| return setInspected(getNullInspected()); | ||
| const { rootId, nodeId } = payload; | ||
| if (inspected.id === nodeId) | ||
| return; | ||
| const result = walkSolidRoot(rootId, nodeId); | ||
| if (!result || !result.inspectedOwner) | ||
| return setInspected(getNullInspected()); | ||
| const owner = result.inspectedOwner; | ||
| const elementMap = new ElementMap2(); | ||
| inspectedProps.clear(); | ||
| inspectedSignals.clear(); | ||
| const { details, signalMap } = collectOwnerDetails(owner, { | ||
| elementMap, | ||
| signalUpdateHandler, | ||
| inspectedProps | ||
| }); | ||
| setInspected({ id: nodeId, rootId, owner, details, signalMap, elementMap }); | ||
| }); | ||
| const setInspectedSignal = untrackedCallback((id, selected) => { | ||
| const { signalMap, elementMap } = inspected; | ||
| const signal = signalMap[id]; | ||
| if (!signal) | ||
| return null; | ||
| if (selected) | ||
| inspectedSignals.add(id); | ||
| else | ||
| inspectedSignals.delete(id); | ||
| return encodeValue2(signal.value, selected, elementMap); | ||
| }); | ||
| const setInspectedProp = untrackedCallback((key, selected) => { | ||
| if (selected) | ||
| inspectedProps.add(key); | ||
| else | ||
| inspectedProps.delete(key); | ||
| updateInspectedProps(); | ||
| }); | ||
| const [handleComputationUpdates, _pushComputationUpdate] = createBatchedUpdateEmitter(); | ||
| const pushComputationUpdate2 = (rootId, id) => { | ||
| _pushComputationUpdate({ rootId, id }); | ||
| }; | ||
| const pluginData = { | ||
| handleComputationUpdates, | ||
| handleSignalUpdates, | ||
| handlePropsUpdate, | ||
| handleStructureUpdates, | ||
| components, | ||
| findComponent, | ||
| triggerUpdate, | ||
| forceTriggerUpdate, | ||
| setInspectedOwner, | ||
| inspected, | ||
| setInspectedSignal, | ||
| setInspectedProp | ||
| }; | ||
| function useDebugger2(options) { | ||
| const { enabled: enabled3, gatherComponents } = options; | ||
| enabled3 && addDebuggerConsumer(enabled3); | ||
| if (gatherComponents) | ||
| debuggerConfig.gatherComponents = true; | ||
| return pluginData; | ||
| } | ||
| return { | ||
| onUpdate: onUpdate2, | ||
| onForceUpdate: onForceUpdate2, | ||
| enabled: enabled2, | ||
| useDebugger: useDebugger2, | ||
| updateRoot: updateRoot2, | ||
| removeRoot: removeRoot2, | ||
| pushComputationUpdate: pushComputationUpdate2 | ||
| }; | ||
| }); | ||
| var { | ||
| onUpdate, | ||
| onForceUpdate, | ||
| enabled, | ||
| useDebugger, | ||
| updateRoot, | ||
| removeRoot, | ||
| pushComputationUpdate | ||
| } = exported; | ||
| // src/roots.ts | ||
| var RootMap = {}; | ||
| var walkSolidRoot = (rootId, inspectedId) => { | ||
| const walk = RootMap[rootId]; | ||
| return walk ? walk(inspectedId) : null; | ||
| }; | ||
| function createGraphRoot(owner) { | ||
| createInternalRoot((dispose) => { | ||
| onOwnerCleanup(owner, dispose); | ||
| const rootId = markNodeID(owner); | ||
| const onComputationUpdate = (rootId2, nodeId) => { | ||
| if (owner.isDisposed) | ||
| return; | ||
| if (untrack2(enabled)) | ||
| triggerRootUpdate(); | ||
| pushComputationUpdate(rootId2, nodeId); | ||
| }; | ||
| const forceRootUpdate = untrackedCallback2((inspectedId) => { | ||
| if (owner.isDisposed) | ||
| return null; | ||
| const result = walkSolidTree(owner, { | ||
| ...debuggerConfig, | ||
| onComputationUpdate, | ||
| rootId, | ||
| inspectedId: inspectedId ?? null | ||
| }); | ||
| updateRoot(result.root, result.components); | ||
| return result; | ||
| }); | ||
| const triggerRootUpdate = throttle3(forceRootUpdate, 300); | ||
| RootMap[rootId] = forceRootUpdate; | ||
| onUpdate(triggerRootUpdate); | ||
| onForceUpdate(forceRootUpdate); | ||
| createEffect2(() => { | ||
| enabled() && forceRootUpdate(); | ||
| }); | ||
| setDebuggerContext(owner, { rootId, triggerRootUpdate, forceRootUpdate }); | ||
| onCleanup(() => { | ||
| removeDebuggerContext(owner); | ||
| removeRoot(rootId); | ||
| owner.isDisposed = true; | ||
| delete RootMap[rootId]; | ||
| }); | ||
| }); | ||
| } | ||
| function attachDebugger(_owner = getOwner2()) { | ||
| let owner = _owner; | ||
| if (!owner) | ||
| return warn2("reatachOwner helper should be called synchronously in a reactive owner."); | ||
| forEachLookupRoot(owner, (root, ctx) => { | ||
| if (ctx === INTERNAL2) | ||
| return; | ||
| root.sdtAttachedTo = null; | ||
| markOwnerType(root, NodeType4.Root); | ||
| createGraphRoot(root); | ||
| if (ctx) { | ||
| ctx.triggerRootUpdate(); | ||
| let parent = findClosestAliveParent(root); | ||
| if (!parent.owner) | ||
| return warn2("PARENT_SHOULD_BE_ALIVE"); | ||
| root.sdtAttachedTo = parent.owner; | ||
| const onParentCleanup2 = () => { | ||
| const newParent = findClosestAliveParent(root); | ||
| if (newParent.owner) { | ||
| parent = newParent; | ||
| root.sdtAttachedTo = parent.owner; | ||
| onOwnerCleanup(parent.root, onParentCleanup2); | ||
| } else { | ||
| root.sdtAttachedTo = null; | ||
| removeOwnCleanup(); | ||
| } | ||
| }; | ||
| const removeParentCleanup = onOwnerCleanup(parent.root, onParentCleanup2); | ||
| const removeOwnCleanup = onOwnerCleanup(root, () => { | ||
| root.isDisposed = true; | ||
| root.sdtAttachedTo = null; | ||
| removeParentCleanup(); | ||
| ctx.triggerRootUpdate(); | ||
| }); | ||
| } | ||
| }); | ||
| } | ||
| function findClosestAliveParent(owner) { | ||
| let disposed = null; | ||
| let closestAliveRoot = null; | ||
| let current = owner; | ||
| while (current.owner && !closestAliveRoot) { | ||
| current = current.owner; | ||
| if (isSolidRoot(current)) { | ||
| if (current.isDisposed) | ||
| disposed = current; | ||
| else | ||
| closestAliveRoot = current; | ||
| } | ||
| } | ||
| if (!closestAliveRoot) | ||
| return { owner: null, root: null }; | ||
| return { owner: (disposed == null ? void 0 : disposed.owner) ?? owner.owner, root: closestAliveRoot }; | ||
| } | ||
| function forEachLookupRoot(owner, callback) { | ||
| const roots = []; | ||
| let ctx; | ||
| do { | ||
| if (isSolidRoot(owner)) { | ||
| if ("sdtAttachedTo" in owner) { | ||
| if (!ctx) | ||
| ctx = getDebuggerContext(owner); | ||
| break; | ||
| } | ||
| if (owner.sdtContext === INTERNAL2) { | ||
| ctx = INTERNAL2; | ||
| break; | ||
| } | ||
| roots.push(owner); | ||
| } | ||
| owner = owner.owner; | ||
| } while (owner); | ||
| for (let i = roots.length - 1; i >= 0; i--) { | ||
| const root = roots[i]; | ||
| callback(root, ctx); | ||
| if (root.sdtContext) | ||
| ctx = root.sdtContext; | ||
| } | ||
| } | ||
| // src/index.ts | ||
| var Debugger = (props) => { | ||
| attachDebugger(); | ||
| return props.children; | ||
| }; | ||
| export { | ||
| isSolidComputation, | ||
| isSolidMemo, | ||
| isSolidOwner, | ||
| isSolidRoot, | ||
| getNodeName, | ||
| getNodeType, | ||
| getOwnerType, | ||
| lookupOwner, | ||
| onOwnerCleanup, | ||
| onParentCleanup, | ||
| createUnownedRoot, | ||
| getFunctionSources, | ||
| createInternalRoot, | ||
| makeSolidUpdateListener, | ||
| makeCreateRootListener, | ||
| makeStoreObserver, | ||
| observeComputationUpdate, | ||
| interceptComputationRerun, | ||
| observeValueUpdate, | ||
| removeValueUpdateObserver, | ||
| makeValueUpdateListener, | ||
| useDebugger, | ||
| attachDebugger, | ||
| Debugger | ||
| }; |
73948
1.01%2031
1.91%