Skip to content

Commit c810e88

Browse files
committed
feat: format reactive/ref/computed in nested values
1 parent 83fa90e commit c810e88

File tree

9 files changed

+64
-13
lines changed

9 files changed

+64
-13
lines changed

packages/api/src/api/component.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ export interface ComponentCustomState extends ComponentStateBase {
5858
export type CustomState = {
5959
_custom: {
6060
type: ComponentBuiltinCustomStateTypes | string
61+
objectType?: string
6162
display?: string
6263
tooltip?: string
6364
value?: any

packages/app-backend-vue2/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ export const backend = defineBackend({
9797
// @TODO refactor
9898
function injectToUtils () {
9999
backendInjections.getCustomInstanceDetails = getCustomInstanceDetails
100+
backendInjections.getCustomObjectDetails = () => undefined
100101
backendInjections.instanceMap = instanceMap
101102
backendInjections.isVueInstance = val => val._isVue
102103
}

packages/app-backend-vue3/src/components/data.ts

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { BackendContext } from '@vue-devtools/app-backend-api'
22
import { getInstanceName, getUniqueComponentId } from './util'
3-
import { camelize, StateEditor, SharedData } from '@vue-devtools/shared-utils'
4-
import { ComponentInstance, HookPayloads, Hooks, InspectedComponentData } from '@vue/devtools-api'
3+
import { camelize, StateEditor, SharedData, formattedValue } from '@vue-devtools/shared-utils'
4+
import { ComponentInstance, CustomState, HookPayloads, Hooks, InspectedComponentData } from '@vue/devtools-api'
55
import { returnError } from '../util'
66

77
/**
@@ -124,7 +124,7 @@ function processSetupState (instance) {
124124
const raw = instance.devtoolsRawSetupState || {}
125125
return Object.keys(instance.setupState)
126126
.map(key => {
127-
const value = returnError(() => instance.setupState[key])
127+
const value = returnError(() => toRaw(instance.setupState[key]))
128128

129129
const rawData = raw[key]
130130

@@ -174,6 +174,13 @@ function isReadOnly (raw: any): boolean {
174174
return !!raw.__v_isReadonly
175175
}
176176

177+
function toRaw (value: any) {
178+
if (value?.__v_raw) {
179+
return value.__v_raw
180+
}
181+
return value
182+
}
183+
177184
function getSetupStateInfo (raw: any) {
178185
return {
179186
ref: isRef(raw),
@@ -183,6 +190,26 @@ function getSetupStateInfo (raw: any) {
183190
}
184191
}
185192

193+
export function getCustomObjectDetails (object: any, proto: string): CustomState | undefined {
194+
const info = getSetupStateInfo(object)
195+
196+
const isState = info.ref || info.computed || info.reactive
197+
if (isState) {
198+
const objectType = info.computed ? 'Computed' : info.ref ? 'Ref' : info.reactive ? 'Reactive' : null
199+
const value = toRaw(info.reactive ? object : object._value)
200+
const raw = object.effect?.raw?.toString() || object.effect?.fn?.toString()
201+
return {
202+
_custom: {
203+
type: objectType.toLowerCase(),
204+
objectType,
205+
readOnly: true,
206+
value,
207+
...raw ? { tooltip: `<span class="font-mono">${raw}</span>` } : {},
208+
},
209+
}
210+
}
211+
}
212+
186213
/**
187214
* Process the computed properties of an instance.
188215
*

packages/app-backend-vue3/src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { defineBackend } from '@vue-devtools/app-backend-api'
22
import { ComponentWalker } from './components/tree'
3-
import { editState, getInstanceDetails, getCustomInstanceDetails } from './components/data'
3+
import { editState, getInstanceDetails, getCustomInstanceDetails, getCustomObjectDetails } from './components/data'
44
import { getInstanceName, getComponentInstances } from './components/util'
55
import { getComponentInstanceFromElement, getInstanceOrVnodeRect, getRootElementsFromComponentInstance } from './components/el'
66
import { backendInjections, HookEvents } from '@vue-devtools/shared-utils'
@@ -38,6 +38,7 @@ export const backend = defineBackend({
3838
api.on.inspectComponent((payload, ctx) => {
3939
// @TODO refactor
4040
backendInjections.getCustomInstanceDetails = getCustomInstanceDetails
41+
backendInjections.getCustomObjectDetails = getCustomObjectDetails
4142
backendInjections.instanceMap = ctx.currentAppRecord.instanceMap
4243
backendInjections.isVueInstance = val => val._ && Object.keys(val._).includes('vnode')
4344
payload.instanceData = getInstanceDetails(payload.componentInstance, ctx)

packages/app-frontend/src/features/inspector/DataField.vue

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,14 +96,15 @@ export default defineComponent({
9696
9797
formattedValue (): string {
9898
const value = this.field.value
99-
if (this.field.objectType === 'Reactive') {
99+
const objectType = value?._custom?.objectType || this.field.objectType
100+
if (objectType === 'Reactive') {
100101
return 'Reactive'
101102
} else if (this.fieldOptions.abstract) {
102103
return ''
103104
} else {
104105
let result = `<span class="value-formatted-ouput">${formattedValue(value)}</span>`
105-
if (this.field.objectType) {
106-
result += ` <span class="text-gray-500">(${this.field.objectType})</span>`
106+
if (objectType) {
107+
result += ` <span class="text-gray-500">(${objectType})</span>`
107108
}
108109
return result
109110
}

packages/app-frontend/src/util/format/value.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
const rawTypeRE = /^\[object (\w+)]$/
1212
const specialTypeRE = /^\[native (\w+) (.*?)(<>((.|\s)*))?\]$/
1313

14-
export function valueType (value) {
14+
export function valueType (value, raw = true) {
1515
const type = typeof value
1616
if (value == null || value === UNDEFINED) {
1717
return 'null'
@@ -23,8 +23,12 @@ export function valueType (value) {
2323
value === NAN
2424
) {
2525
return 'literal'
26-
} else if (value && value._custom) {
27-
return 'custom'
26+
} else if (value?._custom) {
27+
if ((raw || value._custom.display != null)) {
28+
return 'custom'
29+
} else {
30+
return valueType(value._custom.value)
31+
}
2832
} else if (type === 'string') {
2933
const typeMatch = specialTypeRE.exec(value)
3034
if (typeMatch) {
@@ -33,7 +37,7 @@ export function valueType (value) {
3337
} else {
3438
return 'string'
3539
}
36-
} else if (Array.isArray(value) || (value && value._isArray)) {
40+
} else if (Array.isArray(value) || (value?._isArray)) {
3741
return 'array'
3842
} else if (isPlainObject(value)) {
3943
return 'plain-object'
@@ -44,7 +48,10 @@ export function valueType (value) {
4448

4549
export function formattedValue (value, quotes = true) {
4650
let result
47-
const type = valueType(value)
51+
const type = valueType(value, false)
52+
if (type !== 'custom' && value?._custom) {
53+
value = value._custom.value
54+
}
4855
if ((result = specialTokenToString(value))) {
4956
return result
5057
} else if (type === 'custom') {

packages/shared-utils/src/backend.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export const backendInjections = {
22
instanceMap: new Map(),
33
isVueInstance: (() => false) as ((value: any) => boolean),
44
getCustomInstanceDetails: (() => ({})) as ((instance: any) => any),
5+
getCustomObjectDetails: (() => undefined) as (value: any, proto: string) => any,
56
}
67

78
export function getInstanceMap () {
@@ -12,6 +13,10 @@ export function getCustomInstanceDetails (instance) {
1213
return backendInjections.getCustomInstanceDetails(instance)
1314
}
1415

16+
export function getCustomObjectDetails (value, proto: string) {
17+
return backendInjections.getCustomObjectDetails(value, proto)
18+
}
19+
1520
export function isVueInstance (value) {
1621
return backendInjections.isVueInstance(value)
1722
}

packages/shared-utils/src/util.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
getCustomRouterDetails,
88
getCustomStoreDetails,
99
isVueInstance,
10+
getCustomObjectDetails,
1011
} from './backend'
1112
import { SharedData } from './shared-data'
1213
import { isChrome, target } from './env'
@@ -235,6 +236,8 @@ function replacer (key) {
235236
} else if (val instanceof HTMLElement) {
236237
return encodeCache.cache(val, () => getCustomHTMLElementDetails(val))
237238
}
239+
const customDetails = getCustomObjectDetails(val, proto)
240+
if (customDetails != null) return customDetails
238241
} else if (Number.isNaN(val)) {
239242
return NAN
240243
}

packages/shell-dev-vue3/src/Child.vue

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,13 @@ export default {
1515
world: 1,
1616
},
1717
nil: undefined,
18+
nestedRef: ref('meow'),
19+
nestedComputed: computed(() => answer.value * 4),
20+
map: new Map(),
1821
})
1922
23+
reactiveObject.map.set('foo', ref('bar'))
24+
2025
function myMethodFromSetup () {
2126
console.log('foobar')
2227
}
@@ -68,7 +73,7 @@ export default {
6873

6974
<template>
7075
<div>
71-
Child: {{ answer }} x2: {{ doubleAnswer }}
76+
Child: {{ answer }} x2: {{ doubleAnswer }} x4: {{ reactiveObject.nestedComputed }}
7277
<button @click="answer *= 2">
7378
double it
7479
</button>

0 commit comments

Comments
 (0)