Skip to content

Commit ba5b62a

Browse files
authored
feat: Inspecting values in the console (#328)
* wip: Add inspect action for values * fix: Fix value rows highlighting styles * feat: inspecting props * refactor: update getValueActionInspect to accept Inspector.ValueItem and streamline action handling * chore: Cleanup * feat: Support value inspecting for overlay * Create lucky-rats-care.md
1 parent 0bee80d commit ba5b62a

File tree

15 files changed

+245
-133
lines changed

15 files changed

+245
-133
lines changed

.changeset/lucky-rats-care.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@solid-devtools/extension": minor
3+
"@solid-devtools/debugger": minor
4+
"@solid-devtools/frontend": minor
5+
---
6+
7+
New feature: inspecting values in the console. (Closes #166)

extension/src/panel.tsx

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44

55
import * as s from 'solid-js'
66
import * as web from 'solid-js/web'
7-
import {log} from '@solid-devtools/shared/utils'
7+
import {error, log} from '@solid-devtools/shared/utils'
88
import * as frontend from '@solid-devtools/frontend'
9+
import * as debug from '@solid-devtools/debugger/types'
910

1011
import {
1112
ConnectionName, Place_Name, port_on_message, port_post_message_obj,
@@ -62,8 +63,36 @@ function App() {
6263
}
6364
})
6465

65-
/* Devtools -> Client */
66-
devtools.output.listen(e => port_post_message_obj(port, e))
66+
devtools.output.listen(e => {
67+
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
68+
switch (e.name) {
69+
case 'ConsoleInspectValue': {
70+
/*
71+
`chrome.devtools.inspectedWindow.eval` runs in a devtools console
72+
so the value can be additionally inspected with `inspect()`
73+
*/
74+
let get_value = `window[${JSON.stringify(debug.GLOBAL_GET_VALUE)}]`
75+
let value_id = JSON.stringify(e.details)
76+
77+
chrome.devtools.inspectedWindow.eval(
78+
/*js*/`typeof ${get_value} === 'function' && (() => {
79+
let v = ${get_value}(${value_id})
80+
inspect(v)
81+
console.log(v)
82+
})()`,
83+
(_, err?: chrome.devtools.inspectedWindow.EvaluationExceptionInfo) => {
84+
if (err && (err.isError || err.isException)) {
85+
error(err.description)
86+
}
87+
})
88+
break
89+
}
90+
default:
91+
/* Devtools -> Client */
92+
port_post_message_obj(port, e)
93+
break
94+
}
95+
})
6796

6897
return (
6998
<div

packages/debugger/src/inspector/index.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {onOwnerDispose} from '../main/utils.ts'
99
import {type ObservedPropsMap, ValueNodeMap, clearOwnerObservers, collectOwnerDetails} from './inspector.ts'
1010
import {encodeValue} from './serialize.ts'
1111
import {type StoreNodeProperty, type StoreUpdateData, observeStoreNode, setOnStoreNodeUpdate} from './store.ts'
12-
import {type InspectorUpdate, type InspectorUpdateMap, PropGetterState} from './types.ts'
12+
import {GLOBAL_GET_VALUE, type InspectorUpdate, type InspectorUpdateMap, PropGetterState} from './types.ts'
1313

1414
export * from './types.ts'
1515

@@ -24,13 +24,22 @@ export function createInspector(props: {
2424
resetInspectedNode: VoidFunction
2525
emit: OutputEmit
2626
}) {
27+
2728
let lastDetails: Mapped.OwnerDetails | undefined
2829
let inspectedOwner: Solid.Owner | null
2930
let valueMap = new ValueNodeMap()
3031
const propsMap: ObservedPropsMap = new WeakMap()
3132
/** compare props object with the previous one to see whats changed */
3233
let checkProxyProps: (() => InspectorUpdateMap['propKeys'] | null) | null
3334

35+
/*
36+
For the extension for inspecting values through `inspect()`
37+
*/
38+
function getValue(id: ValueItemID): unknown {
39+
return valueMap.get(id)?.getValue?.()
40+
}
41+
window[GLOBAL_GET_VALUE] = getValue
42+
3443
// Batch and dedupe inspector updates
3544
// these will include updates to signals, stores, props, and node value
3645
const {pushPropState, pushValueUpdate, pushInspectToggle, triggerPropsCheck, clearUpdates} =
@@ -156,11 +165,12 @@ export function createInspector(props: {
156165
})
157166

158167
props.emit('InspectedNodeDetails', result.details)
159-
valueMap = result.valueMap
160-
lastDetails = result.details
168+
169+
valueMap = result.valueMap
170+
lastDetails = result.details
161171
checkProxyProps = result.checkProxyProps || null
162172
} else {
163-
lastDetails = undefined
173+
lastDetails = undefined
164174
checkProxyProps = null
165175
}
166176

@@ -186,5 +196,9 @@ export function createInspector(props: {
186196
node.setSelected(selected)
187197
pushInspectToggle(id, selected)
188198
},
199+
consoleLogValue(value_id: ValueItemID): void {
200+
// eslint-disable-next-line no-console
201+
console.log(getValue(value_id))
202+
}
189203
}
190204
}

packages/debugger/src/inspector/types.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,14 @@ export type InspectorUpdateMap = {
6868
export type InspectorUpdate = {
6969
[T in keyof InspectorUpdateMap]: [type: T, data: InspectorUpdateMap[T]]
7070
}[keyof InspectorUpdateMap]
71+
72+
/*
73+
For the extension for inspecting values through `inspect()`
74+
*/
75+
export const GLOBAL_GET_VALUE = '$SdtGetValue'
76+
77+
declare global {
78+
interface Window {
79+
[GLOBAL_GET_VALUE]?: (id: ValueItemID) => unknown
80+
}
81+
}

packages/debugger/src/main/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {createStructure, type StructureUpdates} from '../structure/index.ts'
1010
import {DebuggerModule, DEFAULT_MAIN_VIEW, DevtoolsMainView, TreeWalkerMode} from './constants.ts'
1111
import {getObjectById, getSdtId, ObjectType} from './id.ts'
1212
import setup from './setup.ts'
13-
import {type Mapped, type NodeID} from './types.ts'
13+
import {type Mapped, type NodeID, type ValueItemID} from './types.ts'
1414

1515
export type InspectedState = {
1616
readonly ownerId: NodeID | null
@@ -37,6 +37,7 @@ export type InputChannels = {
3737
ResetState: void
3838
InspectNode: {ownerId: NodeID | null; signalId: NodeID | null} | null
3939
InspectValue: ToggleInspectedValueData
40+
ConsoleInspectValue: ValueItemID
4041
HighlightElementChange: HighlightElementPayload
4142
OpenLocation: void
4243
TreeViewModeChange: TreeWalkerMode
@@ -280,6 +281,9 @@ function createDebugger() {
280281
case 'InspectValue':
281282
inspector.toggleValueNode(e.details)
282283
break
284+
case 'ConsoleInspectValue':
285+
inspector.consoleLogValue(e.details)
286+
break
283287
case 'OpenLocation':
284288
openInspectedNodeLocation()
285289
break

packages/frontend/src/App.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export const App: s.Component<{headerSubtitle?: s.JSX.Element}> = props => {
1616
>
1717
<header class="p-2 flex items-center gap-x-2 bg-panel-bg b-b b-solid b-panel-border text-text">
1818
<div class="flex items-center gap-x-2">
19-
<ui.Icon.SolidWhite class="w-4 h-4 text-disabled" />
19+
<ui.icon.SolidWhite class="w-4 h-4 text-disabled" />
2020
<div>
2121
<h3>Solid Developer Tools</h3>
2222
{props.headerSubtitle && (
@@ -80,7 +80,7 @@ const Options: s.Component = () => {
8080
}}>
8181
<summary
8282
class={`${ui.toggle_button} rounded-md ml-auto w-7 h-7`}>
83-
<ui.Icon.Options
83+
<ui.icon.Options
8484
class="w-4.5 h-4.5"
8585
/>
8686
</summary>
@@ -97,7 +97,7 @@ const Options: s.Component = () => {
9797
class='
9898
flex items-center gap-1 p-1 rounded-md outline-none
9999
text-text transition-colors hover:bg-orange-500/10 focus:bg-orange-500/10'>
100-
<ui.Icon.Bug class='w-3 h-3 mb-px text-orange-500 dark:text-orange-400' />
100+
<ui.icon.Bug class='w-3 h-3 mb-px text-orange-500 dark:text-orange-400' />
101101
Report a bug
102102
</a>
103103
<a
@@ -108,7 +108,7 @@ const Options: s.Component = () => {
108108
class='
109109
flex items-center gap-1 p-1 rounded-md outline-none
110110
text-text transition-colors hover:bg-pink-500/10 focus:bg-pink-500/10'>
111-
<ui.Icon.Heart class='w-3 h-3 mb-px text-pink-500 dark:text-pink-400' />
111+
<ui.icon.Heart class='w-3 h-3 mb-px text-pink-500 dark:text-pink-400' />
112112
Support the project
113113
</a>
114114
</div>
@@ -141,4 +141,4 @@ const Options: s.Component = () => {
141141
// View: {view.get().toUpperCase()}
142142
// </button>
143143
// )
144-
// }
144+
// }

packages/frontend/src/SidePanel.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,15 +77,15 @@ export function createSidePanel() {
7777
class={action_button}
7878
onClick={openComponentLocation}
7979
>
80-
<ui.Icon.Code class={action_icon} />
80+
<ui.icon.Code class={action_icon} />
8181
</button>
8282
)}
8383
<button
8484
title="Close inspector"
8585
class={action_button}
8686
onClick={() => setInspectedOwner(null)}
8787
>
88-
<ui.Icon.Close class={action_icon} />
88+
<ui.icon.Close class={action_icon} />
8989
</button>
9090
</div>
9191
<ui.ToggleTabs

packages/frontend/src/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
export {createDevtools} from './controller.tsx'
22
export type {OutputEventBus, InputEventBus, DevtoolsOptions as DevtoolsProps} from './controller.tsx'
3-
export {Icon, MountIcons} from './ui/index.ts'
3+
export {icon as Icon, MountIcons} from './ui/index.ts'
44
export type {IconComponent} from './ui/index.ts'

0 commit comments

Comments
 (0)