diff --git a/package.json b/package.json index 84330004..afa6f2f1 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "release:beta": "bumpp -r && nr build && pnpm -r publish --access public --tag beta", "dep:up": "taze -I major -r", "prepare": "simple-git-hooks", - "test": "vitest", + "test": "vitest --environment jsdom", "play": "nr -C packages/playground dev", "play:webpack": "nr -C packages/webpack-playground dev", "docs": "pnpm -C docs run docs:dev", @@ -75,7 +75,8 @@ "@types/node": "^20.11.10", "@unocss/eslint-plugin": "^0.58.4", "@vue/devtools-core": "workspace:^", - "@vue/devtools-schema": "workspace:^", + "@vue/devtools-kit": "workspace:^", + "@vue/test-utils": "^2.4.4", "archiver": "^6.0.1", "bumpp": "^9.3.0", "cross-env": "^7.0.3", @@ -85,6 +86,7 @@ "eslint-ts-patch": "8.55.0-1", "fast-glob": "^3.3.2", "fs-extra": "^11.2.0", + "jsdom": "^24.0.0", "lint-staged": "^15.2.0", "npm-run-all2": "^5.0.2", "pnpm": "^8.15.0", diff --git a/packages/client/package.json b/packages/client/package.json index f96c894a..c9307966 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -28,7 +28,6 @@ "@unocss/runtime": "^0.58.4", "@vue/devtools-core": "workspace:^", "@vue/devtools-kit": "workspace:^", - "@vue/devtools-schema": "workspace:*", "@vue/devtools-shared": "workspace:^", "@vue/devtools-ui": "workspace:*", "@vueuse/core": "^10.7.2", diff --git a/packages/core/package.json b/packages/core/package.json index 9dd76828..e91cc197 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -27,7 +27,6 @@ }, "dependencies": { "@vue/devtools-kit": "workspace:^", - "@vue/devtools-schema": "workspace:^", "@vue/devtools-shared": "workspace:^", "birpc": "^0.2.15", "fast-glob": "^3.3.2", diff --git a/packages/core/src/bridge/core.ts b/packages/core/src/bridge/core.ts index 8368b985..47aab9aa 100644 --- a/packages/core/src/bridge/core.ts +++ b/packages/core/src/bridge/core.ts @@ -2,7 +2,7 @@ import { NOOP } from '@vue/devtools-shared' import type { Emitter, EventType, Handler } from 'mitt' import mitt from 'mitt' import { parse } from '@vue/devtools-kit' -import type { InspectorStateEditorPayload, ScrollToComponentOptions, ToggleComponentInspectorOptions } from '@vue/devtools-kit' +import type { ComponentHighLighterOptions, InspectorStateEditorPayload, ScrollToComponentOptions } from '@vue/devtools-kit' export interface BridgeAdapterOptions { tracker: (fn: Function) => void @@ -91,7 +91,7 @@ export const bridgeRpcEvents = { export type BridgeRpcEvents = typeof bridgeRpcEvents export type BridgeRpcEventName = BridgeRpcEvents[keyof BridgeRpcEvents] export interface BridgeRpcEventPayload { - [bridgeRpcEvents.toggleComponentInspector]: ToggleComponentInspectorOptions + [bridgeRpcEvents.toggleComponentInspector]: ComponentHighLighterOptions [bridgeRpcEvents.scrollToComponent]: ScrollToComponentOptions [bridgeRpcEvents.inspectComponentInspector]: string [bridgeRpcEvents.componentBoundingRect]: { diff --git a/packages/core/src/vue-plugin.ts b/packages/core/src/vue-plugin.ts index 582fa816..da47e234 100644 --- a/packages/core/src/vue-plugin.ts +++ b/packages/core/src/vue-plugin.ts @@ -1,7 +1,6 @@ import type { App, InjectionKey, Plugin, Ref } from 'vue' import { inject, ref } from 'vue' -import type { CustomCommand, CustomTab } from '@vue/devtools-kit' -import type { AppRecord } from '@vue/devtools-schema' +import type { AppRecord, CustomCommand, CustomTab } from '@vue/devtools-kit' import type { BridgeInstanceType } from './bridge/core' import { DevToolsRpc } from './bridge' diff --git a/packages/devtools-kit/src/core/component/state/__tests__/format.spec.ts b/packages/devtools-kit/__tests__/component/format.test.ts similarity index 96% rename from packages/devtools-kit/src/core/component/state/__tests__/format.spec.ts rename to packages/devtools-kit/__tests__/component/format.test.ts index af7d820b..e715a76d 100644 --- a/packages/devtools-kit/src/core/component/state/__tests__/format.spec.ts +++ b/packages/devtools-kit/__tests__/component/format.test.ts @@ -1,6 +1,7 @@ -import * as format from '../format' -import { customTypeEnums } from '../../types' -import { INFINITY, NAN, NEGATIVE_INFINITY, UNDEFINED } from '../constants' +import * as format from '../../src/core/component/state/format' +import { INFINITY, NAN, NEGATIVE_INFINITY, UNDEFINED } from '../../src/core/component/state/constants' + +import { customTypeEnums } from '../../src/core/component/types' describe('format: displayText and rawValue can be calculated by formatInspectorStateValue, getRaw', () => { describe('type: literals', () => { diff --git a/packages/devtools-kit/__tests__/fixtures/App.vue b/packages/devtools-kit/__tests__/fixtures/App.vue new file mode 100644 index 00000000..af51c014 --- /dev/null +++ b/packages/devtools-kit/__tests__/fixtures/App.vue @@ -0,0 +1,15 @@ + + + diff --git a/packages/devtools-kit/__tests__/fixtures/components/Name.vue b/packages/devtools-kit/__tests__/fixtures/components/Name.vue new file mode 100644 index 00000000..9bc3e2a6 --- /dev/null +++ b/packages/devtools-kit/__tests__/fixtures/components/Name.vue @@ -0,0 +1,11 @@ + + + diff --git a/packages/devtools-kit/__tests__/hook.test.ts b/packages/devtools-kit/__tests__/hook.test.ts new file mode 100644 index 00000000..f3eee720 --- /dev/null +++ b/packages/devtools-kit/__tests__/hook.test.ts @@ -0,0 +1,39 @@ +import { devtools } from '@vue/devtools-kit' +import { mount } from '@vue/test-utils' +import { resetDevToolsState } from '../src/state' +import App from './fixtures/App.vue' + +describe('hook', () => { + beforeAll(() => { + devtools.init() + }) + afterEach(() => { + resetDevToolsState() + }) + it('should work w/ app init hook', async () => { + await new Promise((resolve) => { + devtools.hook.on.vueAppInit((app, version) => { + expect(app).toBeTypeOf('object') + expect(version).toBeTypeOf('string') + resolve() + }) + mount(App, { + attachTo: document.body, + }) + }) + }) + + it('should work w/ component updated hook', async () => { + await new Promise((resolve) => { + devtools.hook.on.componentUpdated((_, __, ___, component) => { + expect(component.setupState.count).toBe(10) + resolve() + }) + + const app = mount<{}, { }, { count: number, visible: boolean }>(App, { + attachTo: document.body, + }) + app.vm.count = 10 + }) + }) +}) diff --git a/packages/devtools-kit/__tests__/state.test.ts b/packages/devtools-kit/__tests__/state.test.ts new file mode 100644 index 00000000..aebd065f --- /dev/null +++ b/packages/devtools-kit/__tests__/state.test.ts @@ -0,0 +1,26 @@ +import { devtools } from '@vue/devtools-kit' +import { mount } from '@vue/test-utils' +import { resetDevToolsState } from '../src/state' +import App from './fixtures/App.vue' + +describe('app record', () => { + beforeAll(() => { + devtools.init() + }) + afterEach(() => { + resetDevToolsState() + }) + it('should work', async () => { + await new Promise((resolve) => { + devtools.hook.on.vueAppInit(() => { + const records = devtools.state.appRecords + expect(records.length).toBe(1) + expect(devtools.state.connected).toBe(true) + resolve() + }) + mount(App, { + attachTo: document.body, + }) + }) + }) +}) diff --git a/packages/devtools-kit/global.d.ts b/packages/devtools-kit/global.d.ts new file mode 100644 index 00000000..bcc83fd3 --- /dev/null +++ b/packages/devtools-kit/global.d.ts @@ -0,0 +1,21 @@ +import type { DevToolsContext, DevToolsEnv, DevToolsHook, DevToolsState, Router, RouterInfo } from './src/types' + +/* eslint-disable vars-on-top, no-var */ +declare global { + var __VUE_DEVTOOLS_GLOBAL_HOOK__: DevToolsHook + var __VUE_DEVTOOLS_GLOBAL_STATE__: DevToolsState + var __VUE_DEVTOOLS_CONTEXT__: DevToolsContext + var __VUE_DEVTOOLS_APP_RECROD_INFO__: { + id: number + appIds: Set + } + var __VUE_DEVTOOLS_ROUTER__: Router | null + var __VUE_DEVTOOLS_ROUTER_INFO__: RouterInfo + var __VUE_DEVTOOLS_ENV__: DevToolsEnv + var __VUE_DEVTOOLS_COMPONENT_INSPECTOR_ENABLED__: boolean + var __VUE_DEVTOOLS_VITE_PLUGIN_DETECTED__: boolean + var __VUE_DEVTOOLS_VITE_PLUGIN_CLIENT_URL__: string + var __VUE_DEVTOOLS_BROWSER_EXTENSION_DETECTED__: boolean +} + +export { } diff --git a/packages/devtools-kit/package.json b/packages/devtools-kit/package.json index b59453b8..935ee219 100644 --- a/packages/devtools-kit/package.json +++ b/packages/devtools-kit/package.json @@ -12,7 +12,9 @@ }, "main": "./dist/index.cjs", "module": "./dist/index.js", + "types": "./types.d.ts", "files": [ + "**.d.ts", "dist" ], "scripts": { @@ -24,7 +26,6 @@ "vue": "^3.0.0" }, "dependencies": { - "@vue/devtools-schema": "workspace:^", "@vue/devtools-shared": "workspace:^", "hookable": "^5.5.3", "mitt": "^3.0.1", @@ -32,7 +33,8 @@ "speakingurl": "^14.0.1" }, "devDependencies": { - "vue": "^3.4.15", + "@types/speakingurl": "^13.0.6", + "vue": "^3.4.14", "vue-router": "^4.2.5" } } diff --git a/packages/devtools-kit/src/api/api.ts b/packages/devtools-kit/src/api/api.ts new file mode 100644 index 00000000..29e29f79 --- /dev/null +++ b/packages/devtools-kit/src/api/api.ts @@ -0,0 +1,230 @@ +import { TimelineLayerItem, addTimelineLayer } from '../core/timeline' +import { InspectorApiPayload, addInspector, getInspector, updateInspector } from '../core/inspector' +import { toggleActiveAppRecord } from '../core/app-record' +import type { VueAppInstance } from '../types' +import { highlight as highlightElement, inspectComponentHighLighter, scrollToComponent, toggleComponentHighLighter, unhighlight as unhighlightElement } from '../core/component-highlighter' +import { devtoolsContext } from '../state' +import { now as nowFn, parse, stringify } from '../shared' +import { StateEditor } from '../core/component/state/editor' +import type { InspectorStateEditorPayload } from '../core/component/types' +import { addCustomTab } from '../core/custom-tab' +import type { CustomTab } from '../core/custom-tab/types' +import { addCustomCommand, removeCustomCommand } from '../core/custom-command' +import type { CustomCommand } from '../core/custom-command' +import { getComponentInspector } from '../core/component-inspector' +import type { OpenInEditorOptions } from '../core/open-in-editor' +import { openInEditor } from '../core/open-in-editor' + +import { DevToolsEventParams, DevToolsEvents, apiHooks } from './hook' +import { on } from './on' +import { remove } from './off' + +export { collectDevToolsPlugin } from './plugin' + +export class DevToolsPluginApi { + public on: typeof on + public clear = remove + constructor() { + this.on = on + } + + // #region compatible with old devtools + + // timeline layer + addTimelineLayer(payload: TimelineLayerItem) { + addTimelineLayer(payload) + } + + // timeline event + addTimelineEvent(...params: DevToolsEventParams) { + apiHooks.callHook(DevToolsEvents.ADD_TIMELINE_EVENT, ...params) + } + + // add inspector + addInspector(payload: InspectorApiPayload) { + addInspector({ + id: payload.id, + nodeId: '', + filter: '', + treeFilterPlaceholder: payload.treeFilterPlaceholder || '', + }) + } + + highlightElement(instance: VueAppInstance) { + highlightElement(instance) + } + + unhighlightElement() { + unhighlightElement() + } + + // inspector + + async getInspectorTree(payload: DevToolsEventParams[0] = {}) { + const { inspectorId, filter = '', instanceId = '' } = payload + const _payload = { + app: devtoolsContext.appRecord?.app, + inspectorId, + instanceId, + filter, + rootNodes: [], + } + + updateInspector(inspectorId!, { + filter, + }) + + await new Promise((resolve) => { + // @ts-expect-error hookable + apiHooks.callHookWith(async (callbacks) => { + await Promise.all(callbacks.map(cb => cb(_payload))) + resolve() + }, DevToolsEvents.GET_INSPECTOR_TREE) + }) + + return stringify(_payload.rootNodes) as string + } + + getInspectorState(payload: { inspectorId?: string, nodeId?: string } = {}) { + const { inspectorId, nodeId } = payload + const _payload = { + app: devtoolsContext.appRecord?.app, + inspectorId, + nodeId, + } + + updateInspector(inspectorId!, { + nodeId, + }) + // @ts-expect-error hookable + apiHooks.callHookWith((callbacks) => { + callbacks.forEach(cb => cb(_payload)) + }, DevToolsEvents.GET_INSPECTOR_STATE) + + // @ts-expect-error TODO: types + const state = _payload.state + + delete state.instance + return stringify(state) as string + } + + async editInspectorState(payload: InspectorStateEditorPayload) { + const stateEditor = new StateEditor() + apiHooks.callHook(DevToolsEvents.EDIT_INSPECTOR_STATE, { + ...payload, + app: devtoolsContext.appRecord?.app, + set: (obj, path = payload.path, value = payload.state.value, cb) => { + stateEditor.set(obj, path, value, cb || stateEditor.createDefaultSetCallback(payload.state)) + }, + }) + } + + async sendInspectorTree(inspectorId: string) { + const inspector = getInspector(inspectorId) + if (inspector) { + const res = await this.getInspectorTree({ + inspectorId, + }) + apiHooks.callHook(DevToolsEvents.SEND_INSPECTOR_TREE, stringify({ + inspectorId, + data: parse(res), + }) as string) + } + } + + async sendInspectorState(inspectorId: string) { + const inspector = getInspector(inspectorId) + if (inspector && inspector.nodeId) { + const res = await this.getInspectorState({ + inspectorId, + nodeId: inspector.nodeId, + }) + apiHooks.callHook(DevToolsEvents.SEND_INSPECTOR_STATE, stringify({ ...parse(res), inspectorId }) as string) + } + } + + async getComponentInstances(app: VueAppInstance) { + const appRecord = app.__VUE_DEVTOOLS_APP_RECORD__ + const appId = appRecord.id.toString() + const instances = [...appRecord.instanceMap] + .filter(([key]) => key.split(':')[0] === appId) + .map(([,instance]) => instance) + return instances + } + + visitComponentTree(...params: DevToolsEventParams) { + apiHooks.callHook(DevToolsEvents.VISIT_COMPONENT_TREE, ...params) + } + + notifyComponentUpdate() {} + now() { + return nowFn() + } + + getSettings() { + return { + logStoreChanges: null, + } + } + + // #endregion compatible with old devtools + + // #region highlighter + toggleComponentInspector(...params: DevToolsEventParams) { + return toggleComponentHighLighter(...params) + } + + inspectComponentInspector() { + return inspectComponentHighLighter() + } + + scrollToComponent(...params: DevToolsEventParams) { + return scrollToComponent(...params) + } + + getComponentBoundingRect(...params: DevToolsEventParams) { + const { inspectorId, instanceId = '' } = params[0] + const _payload = { + app: devtoolsContext.appRecord?.app, + inspectorId, + instanceId, + rect: { + top: 0, + left: 0, + width: 0, + height: 0, + }, + } + // @ts-expect-error hookable + apiHooks.callHookWith((callbacks) => { + callbacks.map(cb => cb(_payload)) + }, DevToolsEvents.GET_COMPONENT_BOUNDING_RECT) + return stringify(_payload.rect) as string + } + + // #endregion highlighter + + toggleApp(id: string) { + return toggleActiveAppRecord(id) + } + + addCustomTab(tab: CustomTab) { + addCustomTab(tab) + } + + addCustomCommand(action: CustomCommand) { + addCustomCommand(action) + } + + removeCustomCommand(actionId: CustomCommand['id']) { + removeCustomCommand(actionId) + } + + openInEditor(payload: OpenInEditorOptions) { + openInEditor(payload) + } + + getVueInspector() { + return getComponentInspector() + } +} diff --git a/packages/devtools-kit/src/api/hook.ts b/packages/devtools-kit/src/api/hook.ts new file mode 100644 index 00000000..266dc512 --- /dev/null +++ b/packages/devtools-kit/src/api/hook.ts @@ -0,0 +1,67 @@ +import type { HookKeys, Hookable } from 'hookable' +import { target } from '@vue/devtools-shared' +import { createHooks } from 'hookable' +import type { TimelineEvent } from '../core/timeline' +import type { ComponentHighLighterOptions, ScrollToComponentOptions } from '../core/component-highlighter' +import type { ComponentBoundingRectApiPayload, ComponentTreeNode, InspectorStateApiPayload, InspectorStateEditorPayload, InspectorTreeApiPayload } from '../core/component/types' +import type { DevToolsState, RouterInfo, VueAppInstance } from '../types' +import type { CustomTab } from '../core/custom-tab/types' +import type { CustomCommand } from '../core/custom-command' + +export enum DevToolsEvents { + DEVTOOLS_STATE_UPDATED = 'devtools:state-updated', + DEVTOOLS_CONNECTED_UPDATED = 'devtools:connected-updated', + ROUTER_INFO_UPDATED = 'router-info:updated', + COMPONENT_STATE_INSPECT = 'component-state:inspect', + TOGGLE_COMPONENT_HIGHLIGHTER = 'component-highlighter:toggle', + GET_COMPONENT_BOUNDING_RECT = 'component-bounding-rect:get', + SCROLL_TO_COMPONENT = 'scroll-to-component', + GET_INSPECTOR_TREE = 'inspector-tree:get', + SEND_INSPECTOR_TREE = 'inspector-tree:send', + GET_INSPECTOR_STATE = 'inspector-state:get', + EDIT_INSPECTOR_STATE = 'inspector-state:edit', + SEND_INSPECTOR_STATE = 'inspector-state:send', + VISIT_COMPONENT_TREE = 'component-tree:visit', + ADD_TIMELINE_EVENT = 'timeline:add-event', + CUSTOM_TABS_UPDATED = 'custom-tabs:updated', + CUSTOM_COMMANDS_UPDATED = 'custom-commands:updated', +} + +export interface DevToolsEvent { + // timeline + [DevToolsEvents.ADD_TIMELINE_EVENT]: (payload: TimelineEvent) => void + // router + [DevToolsEvents.ROUTER_INFO_UPDATED]: (routerInfo: RouterInfo) => void + // highlighter + [DevToolsEvents.TOGGLE_COMPONENT_HIGHLIGHTER]: (payload: ComponentHighLighterOptions) => void + [DevToolsEvents.SCROLL_TO_COMPONENT]: (payload: ScrollToComponentOptions) => void + [DevToolsEvents.GET_COMPONENT_BOUNDING_RECT]: (payload: ComponentBoundingRectApiPayload) => void + // state + [DevToolsEvents.DEVTOOLS_STATE_UPDATED]: (state: DevToolsState, oldState: DevToolsState) => void + [DevToolsEvents.DEVTOOLS_CONNECTED_UPDATED]: (state: DevToolsState, oldState: DevToolsState) => void + // inspector + [DevToolsEvents.COMPONENT_STATE_INSPECT]: (payload: { + componentInstance: VueAppInstance | undefined + app: VueAppInstance | undefined + instanceData: InspectorStateApiPayload['state'] + }) => void + [DevToolsEvents.GET_INSPECTOR_TREE]: (payload: InspectorTreeApiPayload) => void + [DevToolsEvents.SEND_INSPECTOR_TREE]: (payload: string) => void + [DevToolsEvents.GET_INSPECTOR_STATE]: (payload: InspectorStateApiPayload) => void + [DevToolsEvents.EDIT_INSPECTOR_STATE]: (payload: InspectorStateEditorPayload) => void + [DevToolsEvents.SEND_INSPECTOR_STATE]: (payload: string) => void + [DevToolsEvents.VISIT_COMPONENT_TREE]: (payload: { + componentInstance: VueAppInstance | undefined + app: VueAppInstance | undefined + treeNode: ComponentTreeNode + filter: string + }) => void + // custom tabs + [DevToolsEvents.CUSTOM_TABS_UPDATED]: (payload: CustomTab[]) => void + // custom command + [DevToolsEvents.CUSTOM_COMMANDS_UPDATED]: (payload: CustomCommand[]) => void +} + +export type DevToolsEventParams = Parameters + +export const apiHooks: Hookable> = target.__VUE_DEVTOOLS_API_HOOK ??= createHooks() diff --git a/packages/devtools-kit/src/api/index.ts b/packages/devtools-kit/src/api/index.ts index 2dbcba52..be4f099c 100644 --- a/packages/devtools-kit/src/api/index.ts +++ b/packages/devtools-kit/src/api/index.ts @@ -1,221 +1,3 @@ -import { devtoolsContext } from '../core/general/state' -import { now as nowFn, parse, stringify } from '../shared' -import type { AddInspectorApiPayload, InspectorStateEditorPayload } from '../core/component/types' -import { addInspector, getInspector, updateInspector } from '../core/general/inspector' -import type { TimelineEvent } from '../core/timeline' -import { addTimelineLayer } from '../core/timeline' -import { StateEditor } from '../core/component/state/editor' -import { openInEditor } from '../core/open-in-editor' -import { toggleAppRecord } from '../core/general/app-record' -import type { OpenInEditorOptions } from '../core/open-in-editor' -import { addCustomTab } from '../core/custom-tab' -import type { CustomTab } from '../core/custom-tab/types' -import { addCustomCommand, removeCustomCommand } from '../core/custom-command' -import type { CustomCommand } from '../core/custom-command' - -import { getVueInspector } from '../core/vue-inspector' -import { highlight as highlightElement, inspectComponentInspector, scrollToComponent, toggleComponentInspector, unhighlight as unhighlightElement } from '../core/component-inspector' -import { clear } from './off' -import type { DevToolsEvent } from './on' -import { DevToolsEvents, apiHooks, on } from './on' - -export { DevToolsEvents, apiHooks } from './on' +export * from './api' export * from './plugin' - -export class DevToolsPluginApi { - public on: typeof on - public clear: typeof clear - constructor() { - this.on = on - this.clear = clear - } - - toggleApp(id: string) { - return toggleAppRecord(id) - } - - addTimelineEvent(payload: TimelineEvent) { - apiHooks.callHook(DevToolsEvents.ADD_TIMELINE_EVENT, payload) - } - - toggleComponentInspector(payload: Parameters[0]) { - return toggleComponentInspector(payload) - } - - inspectComponentInspector() { - return inspectComponentInspector() - } - - scrollToComponent(payload: Parameters[0]) { - return scrollToComponent(payload) - } - - getComponentBoundingRect(payload: Parameters[0]) { - const { inspectorId, instanceId = '' } = payload - const _payload = { - app: devtoolsContext.appRecord.app, - inspectorId, - instanceId, - rect: { - top: 0, - left: 0, - width: 0, - height: 0, - }, - } - // @ts-expect-error hookable - apiHooks.callHookWith((callbacks) => { - callbacks.map(cb => cb(_payload)) - }, DevToolsEvents.GET_COMPONENT_BOUNDING_RECT) - return stringify(_payload.rect) as string - } - - async getInspectorTree(payload: Parameters[0] = {}) { - const { inspectorId, filter = '', instanceId = '' } = payload - const _payload = { - app: devtoolsContext.appRecord.app, - inspectorId, - instanceId, - filter, - rootNodes: [], - } - - updateInspector(inspectorId!, { - filter, - }) - - await new Promise((resolve) => { - // @ts-expect-error hookable - apiHooks.callHookWith(async (callbacks) => { - await Promise.all(callbacks.map(cb => cb(_payload))) - resolve() - }, DevToolsEvents.GET_INSPECTOR_TREE) - }) - - return stringify(_payload.rootNodes) as string - } - - getInspectorState(payload: { inspectorId?: string, nodeId?: string } = {}) { - const { inspectorId, nodeId } = payload - const _payload = { - app: devtoolsContext.appRecord.app, - inspectorId, - nodeId, - } - - updateInspector(inspectorId!, { - nodeId, - }) - // @ts-expect-error hookable - apiHooks.callHookWith((callbacks) => { - callbacks.forEach(cb => cb(_payload)) - }, DevToolsEvents.GET_INSPECTOR_STATE) - - // @ts-expect-error TODO: types - const state = _payload.state - - delete state.instance - return stringify(state) as string - } - - async editInspectorState(payload: InspectorStateEditorPayload) { - const stateEditor = new StateEditor() - apiHooks.callHook(DevToolsEvents.EDIT_INSPECTOR_STATE, { - ...payload, - app: devtoolsContext.appRecord.app, - set: (obj, path = payload.path, value = payload.state.value, cb) => { - stateEditor.set(obj, path, value, cb || stateEditor.createDefaultSetCallback(payload.state)) - }, - }) - } - - async sendInspectorTree(inspectorId: string) { - const inspector = getInspector(inspectorId) - if (inspector) { - const res = await this.getInspectorTree({ - inspectorId, - }) - apiHooks.callHook(DevToolsEvents.SEND_INSPECTOR_TREE, stringify({ - inspectorId, - data: parse(res), - }) as string) - } - } - - async sendInspectorState(inspectorId: string) { - const inspector = getInspector(inspectorId) - if (inspector && inspector.nodeId) { - const res = await this.getInspectorState({ - inspectorId, - nodeId: inspector.nodeId, - }) - apiHooks.callHook(DevToolsEvents.SEND_INSPECTOR_STATE, stringify({ ...parse(res), inspectorId }) as string) - } - } - - addCustomTab(tab: CustomTab) { - addCustomTab(tab) - } - - addCustomCommand(action: CustomCommand) { - addCustomCommand(action) - } - - removeCustomCommand(actionId: CustomCommand['id']) { - removeCustomCommand(actionId) - } - - addInspector(payload: AddInspectorApiPayload) { - addInspector({ - id: payload.id, - nodeId: '', - filter: '', - treeFilterPlaceholder: payload.treeFilterPlaceholder ?? '', - }) - } - - openInEditor(payload: OpenInEditorOptions) { - openInEditor(payload) - } - - highlightElement(instance) { - highlightElement(instance) - } - - unhighlightElement() { - unhighlightElement() - } - - async getComponentInstances(app) { - const appRecord = app.__VUE_DEVTOOLS_APP_RECORD__ - const appId = appRecord.id.toString() - const instances = [...appRecord.instanceMap] - .filter(([key]) => key.split(':')[0] === appId) - .map(([,instance]) => instance) - return instances - } - - // Vite only - getVueInspector() { - return getVueInspector() - } - - visitComponentTree(payload: Parameters[0]) { - apiHooks.callHook(DevToolsEvents.VISIT_COMPONENT_TREE, payload) - } - - addTimelineLayer(payload: { id: string, label: string, color: number }) { - addTimelineLayer(payload) - } - - notifyComponentUpdate() {} - now() { - return nowFn() - } - - getSettings() { - return { - logStoreChanges: null, - } - } -} +export * from './hook' diff --git a/packages/devtools-kit/src/api/off.ts b/packages/devtools-kit/src/api/off.ts index 40d9a203..f10322f9 100644 --- a/packages/devtools-kit/src/api/off.ts +++ b/packages/devtools-kit/src/api/off.ts @@ -1,5 +1,5 @@ -import { apiHooks } from './on' +import { apiHooks } from './hook' -export function clear() { +export function remove() { apiHooks.removeAllHooks() } diff --git a/packages/devtools-kit/src/api/on.ts b/packages/devtools-kit/src/api/on.ts index 1e682336..a36a38c8 100644 --- a/packages/devtools-kit/src/api/on.ts +++ b/packages/devtools-kit/src/api/on.ts @@ -1,81 +1,11 @@ -import type { DevToolsState, VueAppInstance } from '@vue/devtools-schema' -import { target } from '@vue/devtools-shared' -import type { HookKeys, Hookable } from 'hookable' -import { createHooks } from 'hookable' -import type { ComponentBoundingRectApiPayload, ComponentTreeNode, InspectorState, InspectorStateApiPayload, InspectorStateEditorPayload, InspectorTreeApiPayload } from '../core/component/types' -import type { ScrollToComponentOptions, ToggleComponentInspectorOptions } from '../core/component-inspector/types' -import type { TimelineEvent } from '../core/timeline' -import type { RouterInfo } from '../core/router' -import type { CustomTab } from '../core/custom-tab/types' -import type { CustomCommand } from '../core/custom-command' - -export enum DevToolsEvents { - DEVTOOLS_STATE_UPDATED = 'devtools:state-updated', - DEVTOOLS_CONNECTED_UPDATED = 'devtools:connected-updated', - ROUTER_INFO_UPDATED = 'router-info:updated', - COMPONENT_STATE_INSPECT = 'component-state:inspect', - TOGGLE_COMPONENT_INSPECTOR = 'component-inspector:toggle', - GET_COMPONENT_BOUNDING_RECT = 'component-bounding-rect:get', - SCROLL_TO_COMPONENT = 'scroll-to-component', - GET_INSPECTOR_TREE = 'inspector-tree:get', - SEND_INSPECTOR_TREE = 'inspector-tree:send', - GET_INSPECTOR_STATE = 'inspector-state:get', - EDIT_INSPECTOR_STATE = 'inspector-state:edit', - SEND_INSPECTOR_STATE = 'inspector-state:send', - VISIT_COMPONENT_TREE = 'component-tree:visit', - ADD_TIMELINE_EVENT = 'timeline:add-event', - CUSTOM_TABS_UPDATED = 'custom-tabs:updated', - CUSTOM_COMMANDS_UPDATED = 'custom-commands:updated', -} - -export interface DevToolsEvent { - [DevToolsEvents.DEVTOOLS_STATE_UPDATED]: (state: DevToolsState, oldState: DevToolsState) => void - [DevToolsEvents.DEVTOOLS_CONNECTED_UPDATED]: (state: DevToolsState, oldState: DevToolsState) => void - [DevToolsEvents.ROUTER_INFO_UPDATED]: (routerInfo: RouterInfo) => void - [DevToolsEvents.COMPONENT_STATE_INSPECT]: (payload: { - componentInstance: VueAppInstance | undefined - app: VueAppInstance | undefined - instanceData: { - id: string - name: string - file: string | undefined - state: InspectorState[] - instance: VueAppInstance | undefined - } - }) => void - [DevToolsEvents.TOGGLE_COMPONENT_INSPECTOR]: (payload: ToggleComponentInspectorOptions) => void - [DevToolsEvents.GET_COMPONENT_BOUNDING_RECT]: (payload: ComponentBoundingRectApiPayload) => void - [DevToolsEvents.SCROLL_TO_COMPONENT]: (payload: ScrollToComponentOptions) => void - [DevToolsEvents.GET_INSPECTOR_TREE]: (payload: InspectorTreeApiPayload) => void - [DevToolsEvents.SEND_INSPECTOR_TREE]: (payload: string) => void - [DevToolsEvents.GET_INSPECTOR_STATE]: (payload: InspectorStateApiPayload) => void - [DevToolsEvents.EDIT_INSPECTOR_STATE]: (payload: InspectorStateEditorPayload) => void - [DevToolsEvents.SEND_INSPECTOR_STATE]: (payload: string) => void - [DevToolsEvents.VISIT_COMPONENT_TREE]: (payload: { - componentInstance: VueAppInstance | undefined - app: VueAppInstance | undefined - treeNode: ComponentTreeNode - filter: string - }) => void - [DevToolsEvents.ADD_TIMELINE_EVENT]: (payload: TimelineEvent) => void - [DevToolsEvents.CUSTOM_TABS_UPDATED]: (payload: CustomTab[]) => void - [DevToolsEvents.CUSTOM_COMMANDS_UPDATED]: (payload: CustomCommand[]) => void -} - -export const apiHooks: Hookable> = target.__VUE_DEVTOOLS_API_HOOK ??= createHooks() -// export const apiHooks: Hookable> = createHooks() +import { DevToolsEvents, apiHooks } from './hook' +import type { DevToolsEvent } from './hook' export const on = { - devtoolsStateUpdated(fn: DevToolsEvent[DevToolsEvents.DEVTOOLS_STATE_UPDATED]) { - apiHooks.hook(DevToolsEvents.DEVTOOLS_STATE_UPDATED, fn) - }, - routerInfoUpdated(fn: DevToolsEvent[DevToolsEvents.ROUTER_INFO_UPDATED]) { - apiHooks.hook(DevToolsEvents.ROUTER_INFO_UPDATED, fn) - }, - getComponentBoundingRect(fn: DevToolsEvent[DevToolsEvents.GET_COMPONENT_BOUNDING_RECT]) { - apiHooks.hook(DevToolsEvents.GET_COMPONENT_BOUNDING_RECT, fn) + // #region compatible with old devtools + addTimelineEvent(fn: DevToolsEvent[DevToolsEvents.ADD_TIMELINE_EVENT]) { + apiHooks.hook(DevToolsEvents.ADD_TIMELINE_EVENT, fn) }, - // compatible inspectComponent(fn: DevToolsEvent[DevToolsEvents.COMPONENT_STATE_INSPECT]) { apiHooks.hook(DevToolsEvents.COMPONENT_STATE_INSPECT, fn) }, @@ -88,24 +18,39 @@ export const on = { getInspectorState(fn: DevToolsEvent[DevToolsEvents.GET_INSPECTOR_STATE]) { apiHooks.hook(DevToolsEvents.GET_INSPECTOR_STATE, fn) }, - // private sendInspectorTree(fn: DevToolsEvent[DevToolsEvents.SEND_INSPECTOR_TREE]) { apiHooks.hook(DevToolsEvents.SEND_INSPECTOR_TREE, fn) }, sendInspectorState(fn: DevToolsEvent[DevToolsEvents.SEND_INSPECTOR_STATE]) { apiHooks.hook(DevToolsEvents.SEND_INSPECTOR_STATE, fn) }, - addTimelineEvent(fn: DevToolsEvent[DevToolsEvents.ADD_TIMELINE_EVENT]) { - apiHooks.hook(DevToolsEvents.ADD_TIMELINE_EVENT, fn) - }, editInspectorState(fn: DevToolsEvent[DevToolsEvents.EDIT_INSPECTOR_STATE]) { apiHooks.hook(DevToolsEvents.EDIT_INSPECTOR_STATE, fn) }, editComponentState() {}, + // #endregion compatible with old devtools + + // router + routerInfoUpdated(fn: DevToolsEvent[DevToolsEvents.ROUTER_INFO_UPDATED]) { + apiHooks.hook(DevToolsEvents.ROUTER_INFO_UPDATED, fn) + }, + + // component highlighter + getComponentBoundingRect(fn: DevToolsEvent[DevToolsEvents.GET_COMPONENT_BOUNDING_RECT]) { + apiHooks.hook(DevToolsEvents.GET_COMPONENT_BOUNDING_RECT, fn) + }, + + // custom tabs customTabsUpdated(fn: DevToolsEvent[DevToolsEvents.CUSTOM_TABS_UPDATED]) { apiHooks.hook(DevToolsEvents.CUSTOM_TABS_UPDATED, fn) }, + + // custom commands customCommandsUpdated(fn: DevToolsEvent[DevToolsEvents.CUSTOM_COMMANDS_UPDATED]) { apiHooks.hook(DevToolsEvents.CUSTOM_COMMANDS_UPDATED, fn) }, -} + + devtoolsStateUpdated(fn: DevToolsEvent[DevToolsEvents.DEVTOOLS_STATE_UPDATED]) { + apiHooks.hook(DevToolsEvents.DEVTOOLS_STATE_UPDATED, fn) + }, +} as const diff --git a/packages/devtools-kit/src/api/plugin.ts b/packages/devtools-kit/src/api/plugin.ts index e2540ebf..38fa335b 100644 --- a/packages/devtools-kit/src/api/plugin.ts +++ b/packages/devtools-kit/src/api/plugin.ts @@ -1,17 +1,18 @@ -import { DevToolsHooks } from '@vue/devtools-schema' -import type { PluginDescriptor, PluginSetupFunction, VueAppInstance } from '@vue/devtools-schema' -import { getAppRecord } from '../core/component/general' -import { devtoolsState } from '../core/general/state' -import { devtoolsHooks } from '../core/general/hook' +import { PluginDescriptor, PluginSetupFunction, VueAppInstance } from '../types' +import { devtoolsAppRecords, devtoolsState } from '../state' +import { hook } from '../hook' import { getRouterDevToolsId } from '../core/router' -import type { DevToolsPluginApi } from './index' +import type { DevToolsPluginApi } from './api' -export function collectRegisteredPlugin(pluginDescriptor: PluginDescriptor, setupFn: PluginSetupFunction) { +export function collectDevToolsPlugin(pluginDescriptor: PluginDescriptor, setupFn: PluginSetupFunction) { devtoolsState.pluginBuffer.push([pluginDescriptor, setupFn]) } -export async function registerPlugin(options: { app: VueAppInstance, api: DevToolsPluginApi }) { - const { app, api } = options +export function setupDevToolsPlugin(pluginDescriptor: PluginDescriptor, setupFn: PluginSetupFunction) { + return hook.setupDevToolsPlugin(pluginDescriptor, setupFn) +} + +export function registerPlugin(app: VueAppInstance, api: DevToolsPluginApi) { const plugins = devtoolsState.pluginBuffer.filter(([plugin]) => plugin.app === app) plugins.forEach(async ([plugin, setupFn]) => { if (plugin.packageName === 'vue-query') { @@ -23,12 +24,11 @@ export async function registerPlugin(options: { app: VueAppInstance, api: DevToo return } - const appRecord = await getAppRecord(plugin.app) // edge case for router plugin if (plugin.packageName === 'vue-router') { const id = getRouterDevToolsId(`${plugin.id}`) if (plugin.app === app) { - devtoolsState.appRecords = devtoolsState.appRecords.map(item => ({ + devtoolsAppRecords.value = devtoolsAppRecords.value.map(item => ({ ...item, routerId: id, })) @@ -37,7 +37,7 @@ export async function registerPlugin(options: { app: VueAppInstance, api: DevToo setupFn(api) }) - devtoolsState.appRecords = devtoolsState.appRecords.map((record) => { + devtoolsAppRecords.value = devtoolsAppRecords.value.map((record) => { const globalProperties = record.app?.config?.globalProperties if (!globalProperties) return record @@ -52,7 +52,3 @@ export async function registerPlugin(options: { app: VueAppInstance, api: DevToo } }) } - -export function setupDevToolsPlugin(pluginDescriptor: PluginDescriptor, setupFn: PluginSetupFunction) { - return devtoolsHooks.callHook(DevToolsHooks.SETUP_DEVTOOLS_PLUGIN, pluginDescriptor, setupFn) -} diff --git a/packages/devtools-kit/src/core/general/app.ts b/packages/devtools-kit/src/core/app-record/index.ts similarity index 55% rename from packages/devtools-kit/src/core/general/app.ts rename to packages/devtools-kit/src/core/app-record/index.ts index 81a12deb..1260aec5 100644 --- a/packages/devtools-kit/src/core/general/app.ts +++ b/packages/devtools-kit/src/core/app-record/index.ts @@ -1,11 +1,9 @@ -import type { AppRecord, VueAppInstance } from '@vue/devtools-schema' -import { target } from '@vue/devtools-shared' import slug from 'speakingurl' - -const appRecordInfo = target.__VUE_DEVTOOLS_APP_RECROD_INFO__ ??= { - id: 0, - appIds: new Set(), -} +import { AppRecord, VueAppInstance } from '../../types' +import { DevToolsPluginApi } from '../../api' +import { registerPlugin } from '../../api/plugin' +import { registerComponentDevToolsPlugin } from '../../plugins' +import { appRecordInfo, devtoolsAppRecords, devtoolsContext, devtoolsState } from '../../state' function getAppRecordName(app: VueAppInstance['appContext']['app'], fallbackName: string) { return app?._component?.name || `App ${fallbackName}` @@ -63,3 +61,29 @@ export function createAppRecord(app: VueAppInstance['appContext']['app']): AppRe return {} as AppRecord } } + +export async function setActiveAppRecord(appRecord: AppRecord) { + await registerComponentDevToolsPlugin(appRecord?.app as unknown as VueAppInstance) + devtoolsAppRecords.active = appRecord + devtoolsAppRecords.activeId = `${appRecord.id}` + registerPlugin(appRecord.app as unknown as VueAppInstance, appRecord.api!) +} + +export async function toggleActiveAppRecord(id: string) { + devtoolsContext.componentPluginHookBuffer.forEach(cleanup => cleanup()) + devtoolsContext.api.clear() + devtoolsContext.clear() + const appRecord = devtoolsAppRecords.value.find(record => record.id === id) + if (appRecord) { + devtoolsState.pluginBuffer = devtoolsState.pluginBuffer.filter(([plugin]) => plugin.id !== 'components') + const api = new DevToolsPluginApi() + appRecord.api = api + setActiveAppRecord(appRecord) + + // @TODO: find a better way to handle it + window.postMessage({ + event: 'toggle-app-record', + target: 'vue-devtools', + }) + } +} diff --git a/packages/devtools-kit/src/core/component-highlighter/index.ts b/packages/devtools-kit/src/core/component-highlighter/index.ts new file mode 100644 index 00000000..587b091a --- /dev/null +++ b/packages/devtools-kit/src/core/component-highlighter/index.ts @@ -0,0 +1,252 @@ +import type { VueAppInstance } from '../../types' +import { getComponentId, getComponentInstance, getInstanceName } from '../component/utils' +import { devtoolsContext } from '../../state' +import { getRootElementsFromComponentInstance } from '../component/tree/el' +import { getComponentBoundingRect } from '../component/state/bounding-rect' +import type { ComponentHighLighterOptions, ScrollToComponentOptions } from './types' + +export type * from './types' + +const CONTAINER_ELEMENT_ID = '__vue-devtools-component-inspector__' +const CARD_ELEMENT_ID = '__vue-devtools-component-inspector__card__' +const COMPONENT_NAME_ELEMENT_ID = '__vue-devtools-component-inspector__name__' +const INDICATOR_ELEMENT_ID = '__vue-devtools-component-inspector__indicator__' + +const containerStyles = { + display: 'block', + zIndex: 2147483640, + position: 'fixed', + backgroundColor: '#42b88325', + border: '1px solid #42b88350', + borderRadius: '5px', + transition: 'all 0.1s ease-in', + pointerEvents: 'none', +} + +const cardStyles = { + fontFamily: 'Arial, Helvetica, sans-serif', + padding: '5px 8px', + borderRadius: '4px', + textAlign: 'left', + position: 'absolute', + left: 0, + color: '#e9e9e9', + fontSize: '14px', + fontWeight: 600, + lineHeight: '24px', + backgroundColor: '#42b883', + boxShadow: '0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1)', +} + +const indicatorStyles = { + display: 'inline-block', + fontWeight: 400, + fontStyle: 'normal', + fontSize: '12px', + opacity: 0.7, +} + +function getContainerElement() { + return document.getElementById(CONTAINER_ELEMENT_ID) +} + +function getCardElement() { + return document.getElementById(CARD_ELEMENT_ID) +} + +function getIndicatorElement() { + return document.getElementById(INDICATOR_ELEMENT_ID) +} + +function getNameElement() { + return document.getElementById(COMPONENT_NAME_ELEMENT_ID) +} + +function getStyles(bounds: ComponentHighLighterOptions['bounds']) { + return { + left: `${Math.round(bounds.left * 100) / 100}px`, + top: `${Math.round(bounds.top * 100) / 100}px`, + width: `${Math.round(bounds.width * 100) / 100}px`, + height: `${Math.round(bounds.height * 100) / 100}px`, + } satisfies Partial +} + +function create(options: ComponentHighLighterOptions & { elementId?: string, style?: Partial }) { + // create container + const containerEl = document.createElement('div') + containerEl.id = options.elementId ?? CONTAINER_ELEMENT_ID + Object.assign(containerEl.style, { + ...containerStyles, + ...getStyles(options.bounds), + ...options.style, + }) + + // create card + const cardEl = document.createElement('span') + cardEl.id = CARD_ELEMENT_ID + Object.assign(cardEl.style, { + ...cardStyles, + top: options.bounds.top < 35 ? 0 : '-35px', + }) + + // create name + const nameEl = document.createElement('span') + nameEl.id = COMPONENT_NAME_ELEMENT_ID + nameEl.innerHTML = `<${options.name}>  ` + + // create indicator + const indicatorEl = document.createElement('i') + indicatorEl.id = INDICATOR_ELEMENT_ID + indicatorEl.innerHTML = `${Math.round(options.bounds.width * 100) / 100} x ${Math.round(options.bounds.height * 100) / 100}` + Object.assign(indicatorEl.style, indicatorStyles) + + // append + cardEl.appendChild(nameEl) + cardEl.appendChild(indicatorEl) + containerEl.appendChild(cardEl) + document.body.appendChild(containerEl) + return containerEl +} + +function update(options: ComponentHighLighterOptions) { + const containerEl = getContainerElement() + const cardEl = getCardElement()! + const nameEl = getNameElement()! + const indicatorEl = getIndicatorElement()! + + if (containerEl) { + Object.assign(containerEl.style, { + ...containerStyles, + ...getStyles(options.bounds), + }) + Object.assign(cardEl.style, { + top: options.bounds.top < 35 ? 0 : '-35px', + }) + nameEl.innerHTML = `<${options.name}>  ` + indicatorEl.innerHTML = `${Math.round(options.bounds.width * 100) / 100} x ${Math.round(options.bounds.height * 100) / 100}` + } +} + +export function toggleComponentHighLighter(options: ComponentHighLighterOptions) { + if (options.visible) { + const instance = getComponentInstance(devtoolsContext.appRecord!, options.id) + if (instance && (options.bounds.width || options.bounds.height)) { + const name = getInstanceName(instance) + const el = getContainerElement() + el ? update({ ...options, name }) : create({ ...options, name }) + } + } + else { + const el = getContainerElement() + if (el) + el.style.display = 'none' + } +} + +export function highlight(instance: VueAppInstance) { + const bounds = getComponentBoundingRect(instance) + const name = getInstanceName(instance) + const container = getContainerElement() + container ? update({ bounds, name }) : create({ bounds, name }) +} + +export function unhighlight() { + const el = getContainerElement() + if (el) + el.style.display = 'none' +} + +let inspectInstance: VueAppInstance = null! +function inspectFn(e: MouseEvent) { + const target = e.target as { __vueParentComponent?: VueAppInstance } + if (target) { + const instance = target.__vueParentComponent + if (instance) { + inspectInstance = instance + const el = instance.vnode.el as HTMLElement | undefined + if (el) { + const bounds = getComponentBoundingRect(instance) + const name = getInstanceName(instance) + const container = getContainerElement() + container ? update({ bounds, name }) : create({ bounds, name }) + } + } + } +} + +function selectComponentFn(e: MouseEvent, cb) { + e.preventDefault() + e.stopPropagation() + if (inspectInstance) { + const app = devtoolsContext.appRecord?.app as unknown as VueAppInstance + getComponentId({ + app, + uid: app.uid, + instance: inspectInstance, + }).then((id) => { + cb(id) + }) + } +} + +export function inspectComponentHighLighter() { + window.addEventListener('mouseover', inspectFn) + return new Promise((resolve) => { + function onSelect(e: MouseEvent) { + e.preventDefault() + e.stopPropagation() + selectComponentFn(e, (id: string) => { + window.removeEventListener('click', onSelect) + window.removeEventListener('mouseover', inspectFn) + const el = getContainerElement() + if (el) + el.style.display = 'none' + resolve(JSON.stringify({ id })) + }) + } + window.addEventListener('click', onSelect) + }) +} + +export function scrollToComponent(options: ScrollToComponentOptions) { + const instance = getComponentInstance(devtoolsContext.appRecord!, options.id) + if (instance) { + const [el] = getRootElementsFromComponentInstance(instance) + // @ts-expect-error type mismatch + if (typeof el.scrollIntoView === 'function') { + // @ts-expect-error type mismatch + el.scrollIntoView({ + behavior: 'smooth', + }) + } + else { + const bounds = getComponentBoundingRect(instance) + const scrollTarget = document.createElement('div') + const styles = { + ...getStyles(bounds), + position: 'absolute', + } + Object.assign(scrollTarget.style, styles) + document.body.appendChild(scrollTarget) + scrollTarget.scrollIntoView({ + behavior: 'smooth', + }) + setTimeout(() => { + document.body.removeChild(scrollTarget) + }, 2000) + } + + setTimeout(() => { + const bounds = getComponentBoundingRect(instance) + if (bounds.width || bounds.height) { + const name = getInstanceName(instance) + const el = getContainerElement() + el ? update({ ...options, name, bounds }) : create({ ...options, name, bounds }) + setTimeout(() => { + if (el) + el.style.display = 'none' + }, 1500) + } + }, 1200) + } +} diff --git a/packages/devtools-kit/src/core/component-inspector/types.ts b/packages/devtools-kit/src/core/component-highlighter/types.ts similarity index 80% rename from packages/devtools-kit/src/core/component-inspector/types.ts rename to packages/devtools-kit/src/core/component-highlighter/types.ts index b320cef7..f10139cd 100644 --- a/packages/devtools-kit/src/core/component-inspector/types.ts +++ b/packages/devtools-kit/src/core/component-highlighter/types.ts @@ -1,6 +1,6 @@ import type { ComponentBoundingRect } from '../component/types' -export interface ToggleComponentInspectorOptions { +export interface ComponentHighLighterOptions { bounds: ComponentBoundingRect name?: string id?: string diff --git a/packages/devtools-kit/src/core/component-inspector/index.ts b/packages/devtools-kit/src/core/component-inspector/index.ts index e27bb3c1..7a3cd344 100644 --- a/packages/devtools-kit/src/core/component-inspector/index.ts +++ b/packages/devtools-kit/src/core/component-inspector/index.ts @@ -1,251 +1,64 @@ -import type { VueAppInstance } from '@vue/devtools-schema' -import { getComponentInstance } from '../component/general' -import { devtoolsContext } from '../general/state' -import { getComponentId, getInstanceName } from '../component/general/util' -import { getRootElementsFromComponentInstance } from '../component/tree/el' -import { getComponentBoundingRect } from '../component/state/bounding-rect' -import type { ScrollToComponentOptions, ToggleComponentInspectorOptions } from './types' +import { target } from '@vue/devtools-shared' -const CONTAINER_ELEMENT_ID = '__vue-devtools-component-inspector__' -const CARD_ELEMENT_ID = '__vue-devtools-component-inspector__card__' -const COMPONENT_NAME_ELEMENT_ID = '__vue-devtools-component-inspector__name__' -const INDICATOR_ELEMENT_ID = '__vue-devtools-component-inspector__indicator__' - -const containerStyles = { - display: 'block', - zIndex: 2147483640, - position: 'fixed', - backgroundColor: '#42b88325', - border: '1px solid #42b88350', - borderRadius: '5px', - transition: 'all 0.1s ease-in', - pointerEvents: 'none', -} - -const cardStyles = { - fontFamily: 'Arial, Helvetica, sans-serif', - padding: '5px 8px', - borderRadius: '4px', - textAlign: 'left', - position: 'absolute', - left: 0, - color: '#e9e9e9', - fontSize: '14px', - fontWeight: 600, - lineHeight: '24px', - backgroundColor: '#42b883', - boxShadow: '0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1)', -} - -const indicatorStyles = { - display: 'inline-block', - fontWeight: 400, - fontStyle: 'normal', - fontSize: '12px', - opacity: 0.7, -} - -function getContainerElement() { - return document.getElementById(CONTAINER_ELEMENT_ID) -} - -function getCardElement() { - return document.getElementById(CARD_ELEMENT_ID) -} - -function getIndicatorElement() { - return document.getElementById(INDICATOR_ELEMENT_ID) -} - -function getNameElement() { - return document.getElementById(COMPONENT_NAME_ELEMENT_ID) -} - -function getStyles(bounds: ToggleComponentInspectorOptions['bounds']) { - return { - left: `${Math.round(bounds.left * 100) / 100}px`, - top: `${Math.round(bounds.top * 100) / 100}px`, - width: `${Math.round(bounds.width * 100) / 100}px`, - height: `${Math.round(bounds.height * 100) / 100}px`, - } satisfies Partial -} - -function create(options: ToggleComponentInspectorOptions & { elementId?: string, style?: Partial }) { - // create container - const containerEl = document.createElement('div') - containerEl.id = options.elementId ?? CONTAINER_ELEMENT_ID - Object.assign(containerEl.style, { - ...containerStyles, - ...getStyles(options.bounds), - ...options.style, - }) - - // create card - const cardEl = document.createElement('span') - cardEl.id = CARD_ELEMENT_ID - Object.assign(cardEl.style, { - ...cardStyles, - top: options.bounds.top < 35 ? 0 : '-35px', - }) - - // create name - const nameEl = document.createElement('span') - nameEl.id = COMPONENT_NAME_ELEMENT_ID - nameEl.innerHTML = `<${options.name}>  ` - - // create indicator - const indicatorEl = document.createElement('i') - indicatorEl.id = INDICATOR_ELEMENT_ID - indicatorEl.innerHTML = `${Math.round(options.bounds.width * 100) / 100} x ${Math.round(options.bounds.height * 100) / 100}` - Object.assign(indicatorEl.style, indicatorStyles) - - // append - cardEl.appendChild(nameEl) - cardEl.appendChild(indicatorEl) - containerEl.appendChild(cardEl) - document.body.appendChild(containerEl) - return containerEl -} - -function update(options: ToggleComponentInspectorOptions) { - const containerEl = getContainerElement() - const cardEl = getCardElement()! - const nameEl = getNameElement()! - const indicatorEl = getIndicatorElement()! - - if (containerEl) { - Object.assign(containerEl.style, { - ...containerStyles, - ...getStyles(options.bounds), - }) - Object.assign(cardEl.style, { - top: options.bounds.top < 35 ? 0 : '-35px', - }) - nameEl.innerHTML = `<${options.name}>  ` - indicatorEl.innerHTML = `${Math.round(options.bounds.width * 100) / 100} x ${Math.round(options.bounds.height * 100) / 100}` - } -} - -export function toggleComponentInspector(options: ToggleComponentInspectorOptions) { - if (options.visible) { - const instance = getComponentInstance(devtoolsContext.appRecord!, options.id) - if (instance && (options.bounds.width || options.bounds.height)) { - const name = getInstanceName(instance) - const el = getContainerElement() - el ? update({ ...options, name }) : create({ ...options, name }) - } +export interface ComponentInspector { + enabled: boolean + position: { + x: number + y: number } - else { - const el = getContainerElement() - if (el) - el.style.display = 'none' + linkParams: { + file: string + line: number + column: number } -} -export function highlight(instance: VueAppInstance) { - const bounds = getComponentBoundingRect(instance) - const name = getInstanceName(instance) - const container = getContainerElement() - container ? update({ bounds, name }) : create({ bounds, name }) + enable: () => void + disable: () => void + toggleEnabled: () => void + openInEditor: (baseUrl: string, file: string, line: number, column: number) => void + onUpdated: () => void } -export function unhighlight() { - const el = getContainerElement() - if (el) - el.style.display = 'none' +target.__VUE_DEVTOOLS_COMPONENT_INSPECTOR_ENABLED__ ??= true +export function toggleComponentInspectorEnabled(enabled: boolean) { + target.__VUE_DEVTOOLS_COMPONENT_INSPECTOR_ENABLED__ = enabled } -let inspectInstance: VueAppInstance = null! -function inspectFn(e: MouseEvent) { - const target = e.target as { __vueParentComponent?: VueAppInstance } - if (target) { - const instance = target.__vueParentComponent - if (instance) { - inspectInstance = instance - const el = instance.vnode.el as HTMLElement | undefined - if (el) { - const bounds = getComponentBoundingRect(instance) - const name = getInstanceName(instance) - const container = getContainerElement() - container ? update({ bounds, name }) : create({ bounds, name }) - } +function waitForInspectorInit(cb: () => void) { + let total = 0 + const timer = setInterval(() => { + if (target.__VUE_INSPECTOR__) { + clearInterval(timer) + total += 30 + cb() } - } + if (total >=/* 5s */ 5000) + clearInterval(timer) + }, 30) } -function selectComponentFn(e: MouseEvent, cb) { - e.preventDefault() - e.stopPropagation() - if (inspectInstance) { - const app = devtoolsContext.appRecord?.app as unknown as VueAppInstance - getComponentId({ - app, - uid: app.uid, - instance: inspectInstance, - }).then((id) => { - cb(id) - }) +function setupInspector() { + const inspector = target.__VUE_INSPECTOR__ + const _openInEditor = inspector.openInEditor + inspector.openInEditor = async (...params: Parameters) => { + inspector.disable() + _openInEditor(...params) } } -export function inspectComponentInspector() { - window.addEventListener('mouseover', inspectFn) - return new Promise((resolve) => { - function onSelect(e: MouseEvent) { - e.preventDefault() - e.stopPropagation() - selectComponentFn(e, (id: string) => { - window.removeEventListener('click', onSelect) - window.removeEventListener('mouseover', inspectFn) - const el = getContainerElement() - if (el) - el.style.display = 'none' - resolve(JSON.stringify({ id })) - }) +export function getComponentInspector(): Promise { + return new Promise((resolve) => { + function setup() { + setupInspector() + resolve(target.__VUE_INSPECTOR__) } - window.addEventListener('click', onSelect) - }) -} - -export function scrollToComponent(options: ScrollToComponentOptions) { - const instance = getComponentInstance(devtoolsContext.appRecord!, options.id) - if (instance) { - const [el] = getRootElementsFromComponentInstance(instance) - // @ts-expect-error type mismatch - if (typeof el.scrollIntoView === 'function') { - // @ts-expect-error type mismatch - el.scrollIntoView({ - behavior: 'smooth', + if (!target.__VUE_INSPECTOR__) { + waitForInspectorInit(() => { + setup() }) } else { - const bounds = getComponentBoundingRect(instance) - const scrollTarget = document.createElement('div') - const styles = { - ...getStyles(bounds), - position: 'absolute', - } - Object.assign(scrollTarget.style, styles) - document.body.appendChild(scrollTarget) - scrollTarget.scrollIntoView({ - behavior: 'smooth', - }) - setTimeout(() => { - document.body.removeChild(scrollTarget) - }, 2000) + setup() } - - setTimeout(() => { - const bounds = getComponentBoundingRect(instance) - if (bounds.width || bounds.height) { - const name = getInstanceName(instance) - const el = getContainerElement() - el ? update({ ...options, name, bounds }) : create({ ...options, name, bounds }) - setTimeout(() => { - if (el) - el.style.display = 'none' - }, 1500) - } - }, 1200) - } + }) } diff --git a/packages/devtools-kit/src/core/component/general/index.ts b/packages/devtools-kit/src/core/component/general/index.ts deleted file mode 100644 index 1871e743..00000000 --- a/packages/devtools-kit/src/core/component/general/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './util' diff --git a/packages/devtools-kit/src/core/component/state/bounding-rect.ts b/packages/devtools-kit/src/core/component/state/bounding-rect.ts index 71e180b4..1e020ce7 100644 --- a/packages/devtools-kit/src/core/component/state/bounding-rect.ts +++ b/packages/devtools-kit/src/core/component/state/bounding-rect.ts @@ -1,6 +1,6 @@ -import type { VueAppInstance } from '@vue/devtools-schema' +import type { VueAppInstance } from '../../../types' import type { ComponentBoundingRect } from '../types' -import { isFragment } from '../general/util' +import { isFragment } from '../utils' // #region rect util function createRect() { diff --git a/packages/devtools-kit/src/core/component/state/custom.ts b/packages/devtools-kit/src/core/component/state/custom.ts index b7b7cb8c..5ba7ab86 100644 --- a/packages/devtools-kit/src/core/component/state/custom.ts +++ b/packages/devtools-kit/src/core/component/state/custom.ts @@ -1,5 +1,5 @@ import type { InspectorState, customTypeEnums } from '../types' -import { getComponentName, getInstanceName } from '../general/util' +import { getComponentName, getInstanceName } from '../utils' import { processInstanceState } from './process' import { escape, getSetupStateType, toRaw } from './util' diff --git a/packages/devtools-kit/src/core/component/state/editor.ts b/packages/devtools-kit/src/core/component/state/editor.ts index 0816647b..5dd209cb 100644 --- a/packages/devtools-kit/src/core/component/state/editor.ts +++ b/packages/devtools-kit/src/core/component/state/editor.ts @@ -1,7 +1,7 @@ import type { MaybeRef, Ref } from 'vue' import { isReactive, isRef, toRaw } from 'vue' -import { getComponentInstance } from '../general' -import { devtoolsContext } from '../../general' +import { getComponentInstance } from '../utils' +import { devtoolsContext } from '../../../state' import type { InspectorStateEditorPayload, PropPath } from '../types' @@ -124,7 +124,7 @@ export async function editComponentState(payload: InspectorStateEditorPayload, s const { path, nodeId, state, type } = payload // assert data types, currently no... // if (!['data', 'props', 'computed', 'setup'].includes(dataType)) - const instance = getComponentInstance(devtoolsContext.appRecord, nodeId) + const instance = getComponentInstance(devtoolsContext.appRecord!, nodeId) if (!instance) return diff --git a/packages/devtools-kit/src/core/component/state/index.ts b/packages/devtools-kit/src/core/component/state/index.ts index f128c4b5..49ced730 100644 --- a/packages/devtools-kit/src/core/component/state/index.ts +++ b/packages/devtools-kit/src/core/component/state/index.ts @@ -1,10 +1,9 @@ -import { devtoolsContext } from '../../general/state' -import { getComponentInstance } from '../general' -import { getInstanceName, getUniqueComponentId } from '../general/util' +import { devtoolsContext } from '../../../state' +import { getComponentInstance, getInstanceName, getUniqueComponentId } from '../utils' import { processInstanceState } from './process' export function getInstanceState(params: { instanceId: string }) { - const instance = getComponentInstance(devtoolsContext.appRecord, params.instanceId) + const instance = getComponentInstance(devtoolsContext.appRecord!, params.instanceId) const id = getUniqueComponentId(instance!) const name = getInstanceName(instance!) const file = instance?.type?.__file diff --git a/packages/devtools-kit/src/core/component/state/process.ts b/packages/devtools-kit/src/core/component/state/process.ts index 63b04a54..e11bacbe 100644 --- a/packages/devtools-kit/src/core/component/state/process.ts +++ b/packages/devtools-kit/src/core/component/state/process.ts @@ -1,7 +1,7 @@ -import type { VueAppInstance } from '@vue/devtools-schema' import { camelize } from '@vue/devtools-shared' +import type { VueAppInstance } from '../../../types' import type { InspectorState } from '../types' -import { returnError } from '../general/util' +import { returnError } from '../utils' import { vueBuiltins } from './constants' import { getPropType, getSetupStateType, toRaw } from './util' diff --git a/packages/devtools-kit/src/core/component/state/reviver.ts b/packages/devtools-kit/src/core/component/state/reviver.ts index 5867f2d5..fdd7de89 100644 --- a/packages/devtools-kit/src/core/component/state/reviver.ts +++ b/packages/devtools-kit/src/core/component/state/reviver.ts @@ -1,5 +1,5 @@ import { target } from '@vue/devtools-shared' -import { devtoolsContext } from '../../general/state' +import { devtoolsContext } from '../../../state' import { INFINITY, NAN, NEGATIVE_INFINITY, UNDEFINED, specialTypeRE, symbolRE } from './constants' export function reviveSet(val) { diff --git a/packages/devtools-kit/src/core/component/tree/el.ts b/packages/devtools-kit/src/core/component/tree/el.ts index 9f33bd36..ceb4c31d 100644 --- a/packages/devtools-kit/src/core/component/tree/el.ts +++ b/packages/devtools-kit/src/core/component/tree/el.ts @@ -1,6 +1,6 @@ -import type { VueAppInstance } from '@vue/devtools-schema' import type { VNode } from 'vue' -import { isFragment } from '../general/util' +import type { VueAppInstance } from '../../../types' +import { isFragment } from '../utils' export function getRootElementsFromComponentInstance(instance: VueAppInstance): VNode[] { if (isFragment(instance)) diff --git a/packages/devtools-kit/src/core/component/tree/filter.ts b/packages/devtools-kit/src/core/component/tree/filter.ts index 9dd370e2..09d8bf1f 100644 --- a/packages/devtools-kit/src/core/component/tree/filter.ts +++ b/packages/devtools-kit/src/core/component/tree/filter.ts @@ -1,6 +1,6 @@ -import type { VueAppInstance } from '@vue/devtools-schema' import { classify, kebabize } from '@vue/devtools-shared' -import { getInstanceName } from '../general/util' +import type { VueAppInstance } from '../../../types' +import { getInstanceName } from '../utils' export class ComponentFilter { filter: string diff --git a/packages/devtools-kit/src/core/component/tree/index.ts b/packages/devtools-kit/src/core/component/tree/index.ts index 02930c0e..b31b5f90 100644 --- a/packages/devtools-kit/src/core/component/tree/index.ts +++ b/packages/devtools-kit/src/core/component/tree/index.ts @@ -1,6 +1,6 @@ -import type { AppRecord } from '@vue/devtools-schema' -import { devtoolsContext } from '../../general/state' -import { getComponentInstance } from '../general' +import type { AppRecord } from '../../../types' +import { devtoolsContext } from '../../../state' +import { getComponentInstance } from '../utils' import { ComponentWalker } from './walker' export async function getComponentTree(options: { appRecord?: AppRecord, instanceId?: string, filterText?: string, maxDepth?: number, recursively?: boolean }) { diff --git a/packages/devtools-kit/src/core/component/tree/walker.ts b/packages/devtools-kit/src/core/component/tree/walker.ts index 740d60e8..0f2dbfcc 100644 --- a/packages/devtools-kit/src/core/component/tree/walker.ts +++ b/packages/devtools-kit/src/core/component/tree/walker.ts @@ -1,8 +1,8 @@ -import type { VueAppInstance } from '@vue/devtools-schema' import type { SuspenseBoundary, VNode } from 'vue' +import type { VueAppInstance } from '../../../types' import type { ComponentTreeNode } from '../types' -import { getAppRecord, getInstanceName, getRenderKey, getUniqueComponentId, isBeingDestroyed, isFragment } from '../general/util' -import { devtoolsContext } from '../../general' +import { getAppRecord, getInstanceName, getRenderKey, getUniqueComponentId, isBeingDestroyed, isFragment } from '../utils' +import { devtoolsContext } from '../../../state' import { getRootElementsFromComponentInstance } from './el' import type { ComponentFilter } from './filter' import { createComponentFilter } from './filter' diff --git a/packages/devtools-kit/src/core/component/types/bounding-rect.ts b/packages/devtools-kit/src/core/component/types/bounding-rect.ts index 6820aefd..961411f9 100644 --- a/packages/devtools-kit/src/core/component/types/bounding-rect.ts +++ b/packages/devtools-kit/src/core/component/types/bounding-rect.ts @@ -1,4 +1,4 @@ -import type { VueAppInstance } from '@vue/devtools-schema' +import type { VueAppInstance } from '../../../types' export interface ComponentBoundingRect { left: number @@ -8,6 +8,7 @@ export interface ComponentBoundingRect { width: number height: number } + export interface ComponentBoundingRectApiPayload { app?: VueAppInstance inspectorId?: string diff --git a/packages/devtools-kit/src/core/component/types/editor.ts b/packages/devtools-kit/src/core/component/types/editor.ts index 17dd9272..22aaa1b8 100644 --- a/packages/devtools-kit/src/core/component/types/editor.ts +++ b/packages/devtools-kit/src/core/component/types/editor.ts @@ -1,4 +1,4 @@ -import type { AppRecord } from '@vue/devtools-schema' +import type { AppRecord } from '../../../types' import type { Recordable } from '../state/editor' export type PropPath = string | string[] diff --git a/packages/devtools-kit/src/core/component/types/index.ts b/packages/devtools-kit/src/core/component/types/index.ts index 3c7d5038..5d6d11ca 100644 --- a/packages/devtools-kit/src/core/component/types/index.ts +++ b/packages/devtools-kit/src/core/component/types/index.ts @@ -1,5 +1,5 @@ -export * from './state' export * from './tree' -export * from './editor' export * from './bounding-rect' +export * from './state' +export * from './editor' export * from './custom' diff --git a/packages/devtools-kit/src/core/component/types/state.ts b/packages/devtools-kit/src/core/component/types/state.ts index c261f990..7087f862 100644 --- a/packages/devtools-kit/src/core/component/types/state.ts +++ b/packages/devtools-kit/src/core/component/types/state.ts @@ -1,4 +1,4 @@ -import type { VueAppInstance } from '@vue/devtools-schema' +import type { VueAppInstance } from '../../../types' export interface InspectorCustomState { _custom?: { @@ -33,6 +33,13 @@ export interface InspectorStateApiPayload { app: VueAppInstance inspectorId: string nodeId: string + state: { + id: string + name: string + file: string | undefined + state: InspectorState[] + instance: VueAppInstance | undefined + } } export interface AddInspectorApiPayload { diff --git a/packages/devtools-kit/src/core/component/types/tree.ts b/packages/devtools-kit/src/core/component/types/tree.ts index 5a2101e6..d649a3c1 100644 --- a/packages/devtools-kit/src/core/component/types/tree.ts +++ b/packages/devtools-kit/src/core/component/types/tree.ts @@ -1,4 +1,4 @@ -import type { VueAppInstance } from '@vue/devtools-schema' +import type { VueAppInstance } from '../../../types' export interface InspectorNodeTag { label: string diff --git a/packages/devtools-kit/src/core/component/general/util.ts b/packages/devtools-kit/src/core/component/utils/index.ts similarity index 98% rename from packages/devtools-kit/src/core/component/general/util.ts rename to packages/devtools-kit/src/core/component/utils/index.ts index 12e3ed59..527eafd9 100644 --- a/packages/devtools-kit/src/core/component/general/util.ts +++ b/packages/devtools-kit/src/core/component/utils/index.ts @@ -1,6 +1,6 @@ -import type { AppRecord, VueAppInstance } from '@vue/devtools-schema' import { basename, classify } from '@vue/devtools-shared' import { Fragment } from 'vue' +import type { AppRecord, VueAppInstance } from '../../../types' function getComponentTypeName(options: VueAppInstance['type']) { return options.name || options._componentTag || options.__VUE_DEVTOOLS_COMPONENT_GUSSED_NAME__ || options.__name diff --git a/packages/devtools-kit/src/core/custom-command/index.ts b/packages/devtools-kit/src/core/custom-command/index.ts index d5f558ff..69d940d7 100644 --- a/packages/devtools-kit/src/core/custom-command/index.ts +++ b/packages/devtools-kit/src/core/custom-command/index.ts @@ -1,4 +1,4 @@ -import { devtoolsState } from '../general/state' +import { devtoolsState } from '../../state' export interface CustomCommandAction { type: 'url' @@ -36,14 +36,14 @@ export interface CustomCommand { } export function addCustomCommand(action: CustomCommand) { - if ((devtoolsState.commands as unknown as CustomCommand[]).some(t => t.id === action.id)) + if (devtoolsState.commands.some(t => t.id === action.id)) return devtoolsState.commands.push(action) } -export function removeCustomCommand(actionId: CustomCommand['id']) { - const index = (devtoolsState.commands as unknown as CustomCommand[]).findIndex(t => t.id === actionId) +export function removeCustomCommand(actionId: string) { + const index = devtoolsState.commands.findIndex(t => t.id === actionId) if (index === -1) return diff --git a/packages/devtools-kit/src/core/custom-tab/index.ts b/packages/devtools-kit/src/core/custom-tab/index.ts index ac68fc53..732c45e7 100644 --- a/packages/devtools-kit/src/core/custom-tab/index.ts +++ b/packages/devtools-kit/src/core/custom-tab/index.ts @@ -1,10 +1,10 @@ -import { devtoolsState } from '../general/state' +import { devtoolsState } from '../../state' import type { CustomTab } from './types' export type { CustomTab } from './types' export function addCustomTab(tab: CustomTab) { - if ((devtoolsState.tabs as unknown as CustomTab[]).some(t => t.name === tab.name)) + if (devtoolsState.tabs.some(t => t.name === tab.name)) return devtoolsState.tabs.push(tab) diff --git a/packages/devtools-kit/src/core/general/app-record.ts b/packages/devtools-kit/src/core/general/app-record.ts deleted file mode 100644 index 08d5c344..00000000 --- a/packages/devtools-kit/src/core/general/app-record.ts +++ /dev/null @@ -1,33 +0,0 @@ -import type { AppRecord, VueAppInstance } from '@vue/devtools-schema' -import { registerComponentsDevTools } from '../plugins' -import { DevToolsPluginApi, registerPlugin } from '../../api' -import { devtoolsContext, devtoolsState } from './state' - -export async function setActiveAppRecord(appRecord: AppRecord) { - await registerComponentsDevTools(appRecord!.app as unknown as VueAppInstance) - devtoolsState.activeAppRecord = appRecord - devtoolsState.activeAppRecordId = `${appRecord.id}` - registerPlugin({ - app: appRecord.app as unknown as VueAppInstance, - api: appRecord.api, - }) -} - -export async function toggleAppRecord(id: string) { - devtoolsContext.componentPluginHookBuffer.forEach(cleanup => cleanup()) - devtoolsContext.api.clear() - devtoolsContext.clear() - const appRecord = devtoolsState.appRecords.find(record => record.id === id) - if (appRecord) { - devtoolsState.pluginBuffer = devtoolsState.pluginBuffer.filter(([plugin]) => plugin.id !== 'components') - const api = new DevToolsPluginApi() - appRecord.api = api - setActiveAppRecord(appRecord) - - // @TODO: find a better way to handle it - window.postMessage({ - event: 'toggle-app-record', - target: 'vue-devtools', - }) - } -} diff --git a/packages/devtools-kit/src/core/general/inspector.ts b/packages/devtools-kit/src/core/general/inspector.ts deleted file mode 100644 index 446e58ce..00000000 --- a/packages/devtools-kit/src/core/general/inspector.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { DevToolsContext } from '@vue/devtools-schema' -import { devtoolsContext } from './state' - -export function addInspector(payload: DevToolsContext['inspector'][0]) { - devtoolsContext.inspector.push(payload) -} - -export function getInspector(inspectorId: string) { - return devtoolsContext.inspector.find(inspector => inspector.id === inspectorId) -} - -export function updateInspector(inspectorId: string, payload: Partial) { - const inspector = getInspector(inspectorId) - inspector && Object.assign(inspector, payload) -} diff --git a/packages/devtools-kit/src/core/general/state.ts b/packages/devtools-kit/src/core/general/state.ts deleted file mode 100644 index 3ab9de49..00000000 --- a/packages/devtools-kit/src/core/general/state.ts +++ /dev/null @@ -1,137 +0,0 @@ -import type { AppRecord, DevToolsState } from '@vue/devtools-schema' -import { deepClone, target as global } from '@vue/devtools-shared' -import { debounce } from 'perfect-debounce' -import type { DevToolsPluginApi } from '../../api' -import { DevToolsEvents, apiHooks } from '../../api' -import type { Router, RouterInfo } from '../router' -import { RouterKey, devtoolsRouterInfo, normalizeRouterInfo } from '../router' - -const StateKey = '__VUE_DEVTOOLS_GLOBAL_STATE__' -const ContextKey = '__VUE_DEVTOOLS_CONTEXT__' -const DefaultContext = { - appRecord: null, - api: null, - inspector: [], - timelineLayer: [], - routerInfo: {}, - router: null, - activeInspectorTreeId: '', - componentPluginHookBuffer: [], -} - -global[StateKey] ??= { - connected: false, - clientConnected: false, - appRecords: [], - activeAppRecord: null, - selectedComponentId: null, - pluginBuffer: [], - tabs: [], - commands: [], - vitePluginDetected: false, - activeAppRecordId: null, -} - -global[ContextKey] ??= deepClone(DefaultContext) - -const callStateUpdatedHook = debounce((state: DevToolsState, oldState: DevToolsState) => { - apiHooks.callHook(DevToolsEvents.DEVTOOLS_STATE_UPDATED, state, oldState) -}, 80) - -const callConnectedUpdatedHook = debounce((state: DevToolsState, oldState: DevToolsState) => { - apiHooks.callHook(DevToolsEvents.DEVTOOLS_CONNECTED_UPDATED, state, oldState) -}, 80) - -export const devtoolsState = new Proxy(global[StateKey], { - get(target, property) { - return global[StateKey][property] - }, - set(target, property, value) { - const oldState = { ...global[StateKey] } - - target[property] = value - // sync to global to ensure the state is consistent - global[StateKey][property] = value - if (property === 'activeAppRecord') { - // update context - global[ContextKey].appRecord = value - global[ContextKey].api = value.api - global[ContextKey].inspector = value.inspector ?? [] - normalizeRouterInfo(value) - global[ContextKey].routerInfo = devtoolsRouterInfo - } - - callStateUpdatedHook(global[StateKey], oldState) - if (['connected', 'clientConnected'].includes(property.toString()) && oldState[property] !== value) - callConnectedUpdatedHook(global[StateKey], oldState) - - return true - }, - deleteProperty(target, property) { - delete target[property] - return true - }, -}) - -Object.defineProperty(devtoolsState.tabs, 'push', { - configurable: true, - value(...items: unknown[]) { - const result = Array.prototype.push.apply(this, items) - devtoolsState.tabs = this - apiHooks.callHook(DevToolsEvents.CUSTOM_TABS_UPDATED, this) - return result - }, -}) - -;['push', 'splice'].forEach((method) => { - Object.defineProperty(devtoolsState.commands, method, { - configurable: true, - value(...args: unknown[]) { - const result = Array.prototype[method].apply(this, args) - devtoolsState.commands = this - apiHooks.callHook(DevToolsEvents.CUSTOM_COMMANDS_UPDATED, this) - return result - }, - }) -}) - -export const devtoolsContext = new Proxy(global[ContextKey], { - get(target, property) { - if (property === 'router') - return global[RouterKey] - - else if (property === 'clear') - return clearDevToolsContext - - return global[ContextKey][property] - }, - set(target, property, value) { - if (property === 'componentPluginHookBuffer') - global[ContextKey][property] = value - - return true - }, -}) as unknown as { - appRecord: AppRecord - api: DevToolsPluginApi - inspector: { - id: string - nodeId: string - filter: string - treeFilterPlaceholder: string - }[] - timelineLayer: { - id: string - label: string - color: number - }[] - routerInfo: RouterInfo - router: Router - activeInspectorTreeId: string - componentPluginHookBuffer: (() => void)[] - clear: () => void -} - -function clearDevToolsContext() { - global[ContextKey] = deepClone(DefaultContext) -} diff --git a/packages/devtools-kit/src/core/general/index.ts b/packages/devtools-kit/src/core/index.ts similarity index 59% rename from packages/devtools-kit/src/core/general/index.ts rename to packages/devtools-kit/src/core/index.ts index 3e97e607..cf936fdd 100644 --- a/packages/devtools-kit/src/core/general/index.ts +++ b/packages/devtools-kit/src/core/index.ts @@ -1,18 +1,17 @@ import { target } from '@vue/devtools-shared' -import { DevToolsHooks } from '@vue/devtools-schema' -import { DevToolsEvents, DevToolsPluginApi, apiHooks, collectRegisteredPlugin } from '../../api' -import { createAppRecord } from './app' -import { createDevToolsHook, devtoolsHooks, hook, subscribeDevToolsHook } from './hook' -import { devtoolsContext, devtoolsState } from './state' -import { setActiveAppRecord } from './app-record' +import { createDevToolsHook, devtoolsHooks, hook, subscribeDevToolsHook } from '../hook' +import { DevToolsHooks } from '../types' +import { devtoolsAppRecords, devtoolsState, getDevToolsEnv } from '../state' +import { DevToolsEvents, DevToolsPluginApi, apiHooks, collectDevToolsPlugin } from '../api' +import { createAppRecord, setActiveAppRecord } from './app-record' -// usage: inject to user application and call it before the vue app is created export function initDevTools() { - devtoolsState.vitePluginDetected = !!target.__VUE_DEVTOOLS_VITE_PLUGIN_DETECTED__ + devtoolsState.vitePluginDetected = getDevToolsEnv().vitePluginDetected + + const isDevToolsNext = target.__VUE_DEVTOOLS_GLOBAL_HOOK__?.id === 'vue-devtools-next' - const isNewDevTools = target.__VUE_DEVTOOLS_GLOBAL_HOOK__?.id === 'vue-devtools-next' // de-duplicate - if (target.__VUE_DEVTOOLS_GLOBAL_HOOK__ && isNewDevTools) + if (target.__VUE_DEVTOOLS_GLOBAL_HOOK__ && isDevToolsNext) return // compatible with old devtools @@ -22,17 +21,15 @@ export function initDevTools() { else target.__VUE_DEVTOOLS_GLOBAL_HOOK__ = createDevToolsHook() - target.__VUE_DEVTOOLS_APP_RECORDS__ ??= [] - - // devtools plugin setup hook - hook.on.setupDevtoolsPlugin(collectRegisteredPlugin) + // setup old devtools plugin (compatible with pinia, router, etc) + hook.on.setupDevtoolsPlugin(collectDevToolsPlugin) // create app record hook.on.vueAppInit(async (app, version) => { const record = createAppRecord(app) const api = new DevToolsPluginApi() - devtoolsState.appRecords = [ - ...(devtoolsState.appRecords ?? []), + devtoolsAppRecords.value = [ + ...devtoolsAppRecords.value, { ...record, app, @@ -41,8 +38,8 @@ export function initDevTools() { }, ] - if (devtoolsState.appRecords.length === 1) { - await setActiveAppRecord(devtoolsState.appRecords[0]) + if (devtoolsAppRecords.value.length === 1) { + await setActiveAppRecord(devtoolsAppRecords.value[0]) devtoolsState.connected = true devtoolsHooks.callHook(DevToolsHooks.APP_CONNECTED) } @@ -84,9 +81,3 @@ export function onDevToolsClientConnected(fn: () => void) { }) }) } - -export { - devtoolsContext, - devtoolsState, - hook, -} diff --git a/packages/devtools-kit/src/core/inspector/index.ts b/packages/devtools-kit/src/core/inspector/index.ts new file mode 100644 index 00000000..64bb2958 --- /dev/null +++ b/packages/devtools-kit/src/core/inspector/index.ts @@ -0,0 +1,33 @@ +import { devtoolsContext } from '../../state' + +export interface Inspector { + id: string + nodeId: string + filter: string + treeFilterPlaceholder: string +} + +export interface InspectorApiPayload { + id: string + label: string + icon?: string + treeFilterPlaceholder?: string + actions?: { + icon: string + tooltip: string + action: (payload: unknown) => void + }[] +} + +export function addInspector(payload: Inspector) { + devtoolsContext.inspector.push(payload) +} + +export function getInspector(inspectorId: string) { + return devtoolsContext.inspector.find(inspector => inspector.id === inspectorId) +} + +export function updateInspector(inspectorId: string, payload: Partial) { + const inspector = getInspector(inspectorId) + inspector && Object.assign(inspector, payload) +} diff --git a/packages/devtools-kit/src/core/open-in-editor/index.ts b/packages/devtools-kit/src/core/open-in-editor/index.ts index 70d4ca94..11477cf6 100644 --- a/packages/devtools-kit/src/core/open-in-editor/index.ts +++ b/packages/devtools-kit/src/core/open-in-editor/index.ts @@ -1,4 +1,5 @@ import { target } from '@vue/devtools-shared' +import { devtoolsState } from '../../state' export interface OpenInEditorOptions { file?: string @@ -10,7 +11,7 @@ export function openInEditor(options: OpenInEditorOptions = {}) { const { file, line = 0, column = 0 } = options if (file) { const baseUrl = window.location.origin - if (target.__VUE_DEVTOOLS_VITE_PLUGIN_DETECTED__) { + if (devtoolsState.vitePluginDetected) { target.__VUE_INSPECTOR__.openInEditor(baseUrl, file, line, column) } else { diff --git a/packages/devtools-kit/src/core/plugins/index.ts b/packages/devtools-kit/src/core/plugins/index.ts deleted file mode 100644 index cb64ac1b..00000000 --- a/packages/devtools-kit/src/core/plugins/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './components' diff --git a/packages/devtools-kit/src/core/router/index.ts b/packages/devtools-kit/src/core/router/index.ts index 0edecb63..96d79fde 100644 --- a/packages/devtools-kit/src/core/router/index.ts +++ b/packages/devtools-kit/src/core/router/index.ts @@ -1,79 +1,59 @@ -import type { RouteLocationNormalizedLoaded, RouteRecordNormalized, RouteRecordRaw, Router } from 'vue-router' -import type { AppRecord } from '@vue/devtools-schema' +import type { RouteLocationNormalizedLoaded, RouteRecordRaw, Router } from 'vue-router' import { deepClone, target as global } from '@vue/devtools-shared' import { debounce } from 'perfect-debounce' -import { DevToolsEvents, apiHooks } from '../../api' -import { hook } from '../general/hook' +import { ROUTER_INFO_KEY, ROUTER_KEY } from '../../state' +import type { AppRecord } from '../../types' +import { hook } from '../../hook' +import { DevToolsEvents, apiHooks } from '../../api/hook' -const RouterInfoKey = '__VUE_DEVTOOLS_ROUTER_INFO__' -export const RouterKey = '__VUE_DEVTOOLS_ROUTER__' - -export type { Router } from 'vue-router' -export interface RouterInfo { - currentRoute: RouteLocationNormalizedLoaded | null - routes: RouteRecordNormalized[] - router: Router | null +function getRoutes(router?: Router) { + const routesMap = new Map() + return (router?.getRoutes() || []).filter(i => !routesMap.has(i.path) && routesMap.set(i.path, 1)) } -global[RouterInfoKey] ??= { - currentRoute: null, - routes: [], - router: null, -} as RouterInfo - -global[RouterKey] ??= null as unknown as Router - -export const devtoolsRouterInfo: RouterInfo = new Proxy(global[RouterInfoKey], { - get(target, property) { - return global[RouterInfoKey][property] - }, -}) +function filterRoutes(routes: RouteRecordRaw[]) { + return routes.map((item) => { + let { path, name, children } = item + if (children?.length) + children = filterRoutes(children) -export function normalizeRouterInfo(appRecord: AppRecord) { - const getRoutes = (router?: Router) => { - const routesMap = new Map() - return (router?.getRoutes() || []).filter(i => !routesMap.has(i.path) && routesMap.set(i.path, 1)) - } - function filterRoutes(routes: RouteRecordRaw[]) { - return routes.map((item) => { - let { path, name, children } = item - if (children?.length) - children = filterRoutes(children) + return { + path, + name, + children, + } + }) +} - return { - path, - name, - children, - } - }) - } - function filterCurrentRoute(route: RouteLocationNormalizedLoaded & { href?: string } | undefined) { - if (route) { - const { fullPath, hash, href, path, name, matched, params, query } = route - return { - fullPath, - hash, - href, - path, - name, - params, - query, - matched: filterRoutes(matched), - } +function filterCurrentRoute(route: RouteLocationNormalizedLoaded & { href?: string } | undefined) { + if (route) { + const { fullPath, hash, href, path, name, matched, params, query } = route + return { + fullPath, + hash, + href, + path, + name, + params, + query, + matched: filterRoutes(matched), } - return route } + return route +} + +export function normalizeRouterInfo(appRecord: AppRecord) { function init() { const router = appRecord.app?.config.globalProperties.$router as Router | undefined const currentRoute = filterCurrentRoute(router?.currentRoute.value) const routes = filterRoutes(getRoutes(router)) const c = console.warn console.warn = () => {} - global[RouterInfoKey] = { + global[ROUTER_INFO_KEY] = { currentRoute: currentRoute ? deepClone(currentRoute) : {}, routes: deepClone(routes), } - global[RouterKey] = router + global[ROUTER_KEY] = router! console.warn = c } @@ -82,10 +62,9 @@ export function normalizeRouterInfo(appRecord: AppRecord) { // @TODO: use another way to watch router hook.on.componentUpdated(debounce(() => { init() - apiHooks.callHook(DevToolsEvents.ROUTER_INFO_UPDATED, global[RouterInfoKey]) + apiHooks.callHook(DevToolsEvents.ROUTER_INFO_UPDATED, global[ROUTER_INFO_KEY]) }, 200)) } - export function getRouterDevToolsId(id: string) { return id.replace(/\D/g, '') || '0' } diff --git a/packages/devtools-kit/src/core/timeline/index.ts b/packages/devtools-kit/src/core/timeline/index.ts index 394dcef3..2e9047ec 100644 --- a/packages/devtools-kit/src/core/timeline/index.ts +++ b/packages/devtools-kit/src/core/timeline/index.ts @@ -1,9 +1,24 @@ -import type { DevToolsContext } from '@vue/devtools-schema' -import { devtoolsContext } from '../general/state' +import { devtoolsContext } from '../../state' -export type * from './types' +export interface TimelineEvent { + event: { + groupId: number + time: number + title: string + subtitle: string + // @TODO: InspectorCustomState type + data: Record + } + layerId: string +} + +export interface TimelineLayerItem { + id: string + label: string + color: number +} -export function addTimelineLayer(payload: DevToolsContext['timelineLayer'][0]) { +export function addTimelineLayer(payload: TimelineLayerItem) { devtoolsContext.timelineLayer.push(payload) } diff --git a/packages/devtools-kit/src/core/timeline/types.ts b/packages/devtools-kit/src/core/timeline/types.ts deleted file mode 100644 index e402fd30..00000000 --- a/packages/devtools-kit/src/core/timeline/types.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { InspectorCustomState } from '../component/types' - -export interface TimelineEventData { - data: Record -} - -export interface TimelineEvent { - event: { - groupId: number - time: number - title: string - subtitle: string - data: TimelineEventData - } - layerId: string -} diff --git a/packages/devtools-kit/src/core/vue-inspector/index.ts b/packages/devtools-kit/src/core/vue-inspector/index.ts deleted file mode 100644 index c3cebb6d..00000000 --- a/packages/devtools-kit/src/core/vue-inspector/index.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { target } from '@vue/devtools-shared' - -export interface VueInspector { - enabled: boolean - position: { - x: number - y: number - } - linkParams: { - file: string - line: number - column: number - } - - enable: () => void - disable: () => void - toggleEnabled: () => void - openInEditor: (baseUrl: string, file: string, line: number, column: number) => void - onUpdated: () => void -} - -target.__VUE_DEVTOOLS_COMPONENT_INSPECTOR_ENABLED__ ??= true -export function toggleComponentInspectorEnabled(enabled: boolean) { - target.__VUE_DEVTOOLS_COMPONENT_INSPECTOR_ENABLED__ = enabled -} - -function waitForInspectorInit(cb: () => void) { - let total = 0 - const timer = setInterval(() => { - if (target.__VUE_INSPECTOR__) { - clearInterval(timer) - total += 30 - cb() - } - if (total >=/* 5s */ 5000) - clearInterval(timer) - }, 30) -} - -function setupInspector() { - const inspector = target.__VUE_INSPECTOR__ - const _openInEditor = inspector.openInEditor - inspector.openInEditor = async (...params: Parameters) => { - inspector.disable() - _openInEditor(...params) - } -} - -export function getVueInspector(): Promise { - return new Promise((resolve) => { - if (!target.__VUE_DEVTOOLS_COMPONENT_INSPECTOR_ENABLED__) - resolve(null) - - function setup() { - setupInspector() - resolve(target.__VUE_INSPECTOR__) - } - if (!target.__VUE_INSPECTOR__) { - waitForInspectorInit(() => { - setup() - }) - } - else { - setup() - } - }) -} diff --git a/packages/devtools-kit/src/core/general/hook.ts b/packages/devtools-kit/src/hook/index.ts similarity index 55% rename from packages/devtools-kit/src/core/general/hook.ts rename to packages/devtools-kit/src/hook/index.ts index 20f1da31..c42f113d 100644 --- a/packages/devtools-kit/src/core/general/hook.ts +++ b/packages/devtools-kit/src/hook/index.ts @@ -1,44 +1,34 @@ -import type { DevtoolsHook, PluginDescriptor, PluginSetupFunction, VueAppInstance } from '@vue/devtools-schema' -import { DevToolsHooks } from '@vue/devtools-schema' import { target } from '@vue/devtools-shared' import type { HookKeys, Hookable } from 'hookable' import { createHooks } from 'hookable' -import type { App } from 'vue' - -type HookAppInstance = App & VueAppInstance -interface DevToolsEvent { - [DevToolsHooks.APP_INIT]: (app: VueAppInstance['appContext']['app'], version: string) => void - [DevToolsHooks.APP_CONNECTED]: () => void - [DevToolsHooks.COMPONENT_ADDED]: (app: HookAppInstance, uid: number, parentUid: number, component: VueAppInstance) => void - [DevToolsHooks.COMPONENT_UPDATED]: DevToolsEvent['component:added'] - [DevToolsHooks.COMPONENT_REMOVED]: DevToolsEvent['component:added'] - [DevToolsHooks.SETUP_DEVTOOLS_PLUGIN]: (pluginDescriptor: PluginDescriptor, setupFn: PluginSetupFunction) => void -} +import { DevToolsEvent, DevToolsHook, DevToolsHooks, VueHooks } from '../types' + +export { VueHooks } from '../types' export const devtoolsHooks: Hookable> = target.__VUE_DEVTOOLS_HOOK ??= createHooks() -const on = { - vueAppInit(fn: DevToolsEvent[DevToolsHooks.APP_INIT]) { +const on: VueHooks['on'] = { + vueAppInit(fn) { devtoolsHooks.hook(DevToolsHooks.APP_INIT, fn) }, - vueAppConnected(fn: DevToolsEvent[DevToolsHooks.APP_CONNECTED]) { + vueAppConnected(fn) { devtoolsHooks.hook(DevToolsHooks.APP_CONNECTED, fn) }, - componentAdded(fn: DevToolsEvent[DevToolsHooks.COMPONENT_ADDED]) { + componentAdded(fn) { return devtoolsHooks.hook(DevToolsHooks.COMPONENT_ADDED, fn) }, - componentUpdated(fn: DevToolsEvent[DevToolsHooks.COMPONENT_UPDATED]) { + componentUpdated(fn) { return devtoolsHooks.hook(DevToolsHooks.COMPONENT_UPDATED, fn) }, - componentRemoved(fn: DevToolsEvent[DevToolsHooks.COMPONENT_REMOVED]) { + componentRemoved(fn) { return devtoolsHooks.hook(DevToolsHooks.COMPONENT_REMOVED, fn) }, - setupDevtoolsPlugin(fn: DevToolsEvent[DevToolsHooks.SETUP_DEVTOOLS_PLUGIN]) { + setupDevtoolsPlugin(fn) { devtoolsHooks.hook(DevToolsHooks.SETUP_DEVTOOLS_PLUGIN, fn) }, } -export function createDevToolsHook(): DevtoolsHook { +export function createDevToolsHook(): DevToolsHook { return { id: 'vue-devtools-next', enabled: false, @@ -78,24 +68,17 @@ export function createDevToolsHook(): DevtoolsHook { } export function subscribeDevToolsHook() { - const hook = target.__VUE_DEVTOOLS_GLOBAL_HOOK__ + const hook = target.__VUE_DEVTOOLS_GLOBAL_HOOK__ as DevToolsHook // app init hook - hook.on(DevToolsHooks.APP_INIT, (app: VueAppInstance['appContext']['app'], version: string) => { + hook.on(DevToolsHooks.APP_INIT, (app, version) => { if (app?._instance?.type?.devtools?.hide) return devtoolsHooks.callHook(DevToolsHooks.APP_INIT, app, version) - // const record = createAppRecord(app) - - // hook.appRecords.push({ - // ...record, - // app, - // version, - // }) }) // component added hook - hook.on(DevToolsHooks.COMPONENT_ADDED, async (app: HookAppInstance, uid: number, parentUid: number, component: VueAppInstance) => { + hook.on(DevToolsHooks.COMPONENT_ADDED, async (app, uid, parentUid, component) => { if (app?._instance?.type?.devtools?.hide) return @@ -106,7 +89,7 @@ export function subscribeDevToolsHook() { }) // component updated hook - hook.on(DevToolsHooks.COMPONENT_UPDATED, (app: HookAppInstance, uid: number, parentUid: number, component: VueAppInstance) => { + hook.on(DevToolsHooks.COMPONENT_UPDATED, (app, uid, parentUid, component) => { if (!app || (typeof uid !== 'number' && !uid) || !component) return @@ -114,7 +97,7 @@ export function subscribeDevToolsHook() { }) // component removed hook - hook.on(DevToolsHooks.COMPONENT_REMOVED, async (app: HookAppInstance, uid: number, parentUid: number, component: VueAppInstance) => { + hook.on(DevToolsHooks.COMPONENT_REMOVED, async (app, uid, parentUid, component) => { if (!app || (typeof uid !== 'number' && !uid) || !component) return @@ -122,11 +105,14 @@ export function subscribeDevToolsHook() { }) // devtools plugin setup - hook.on(DevToolsHooks.SETUP_DEVTOOLS_PLUGIN, (pluginDescriptor: PluginDescriptor, setupFn: PluginSetupFunction) => { + hook.on(DevToolsHooks.SETUP_DEVTOOLS_PLUGIN, (pluginDescriptor, setupFn) => { devtoolsHooks.callHook(DevToolsHooks.SETUP_DEVTOOLS_PLUGIN, pluginDescriptor, setupFn) }) } -export const hook = { +export const hook: VueHooks = { on, + setupDevToolsPlugin(pluginDescriptor, setupFn) { + return devtoolsHooks.callHook(DevToolsHooks.SETUP_DEVTOOLS_PLUGIN, pluginDescriptor, setupFn) + }, } diff --git a/packages/devtools-kit/src/index.ts b/packages/devtools-kit/src/index.ts index 17eeb891..1556b959 100644 --- a/packages/devtools-kit/src/index.ts +++ b/packages/devtools-kit/src/index.ts @@ -1,25 +1,30 @@ -import { devtoolsContext, devtoolsState, hook, initDevTools, onDevToolsClientConnected, onDevToolsConnected } from './core/general' +import { initDevTools, onDevToolsClientConnected, onDevToolsConnected } from './core' +import { hook } from './hook' +import { devtoolsContext, devtoolsState, setDevToolsEnv } from './state' +import { setupDevToolsPlugin } from './api' import { addCustomTab } from './core/custom-tab' import { addCustomCommand, removeCustomCommand } from './core/custom-command' -import { setupDevToolsPlugin } from './api/plugin' -import { toggleComponentInspectorEnabled } from './core/vue-inspector' +import { toggleComponentInspectorEnabled } from './core/component-inspector' -export type * from './core/component/types' -export type * from './core/timeline/types' -export type * from './core/router' -export type * from './core/open-in-editor' -export type * from './core/vue-inspector' -export type * from './core/component-inspector/types' -export type * from './core/custom-tab/types' +export type * from './core/custom-tab' export type * from './core/custom-command' +export type * from './core/timeline' +export type * from './core/open-in-editor' +export type * from './core/component-highlighter' +export type * from './core/component/types' +export type * from './core/component-inspector' +export type * from './core/inspector' +export type * from './types' -export * from './shared' +export { parse, stringify } from './shared' +export { formatInspectorStateValue, getInspectorStateValueType, getRaw, toEdit, toSubmit } from './core/component/state/format' +export { UNDEFINED } from './core/component/state/constants' export const devtools = { state: devtoolsState, context: devtoolsContext, - init: initDevTools, hook, + init: initDevTools, get api() { return devtoolsContext.api }, @@ -32,5 +37,6 @@ export { addCustomCommand, removeCustomCommand, setupDevToolsPlugin, + setDevToolsEnv, toggleComponentInspectorEnabled, } diff --git a/packages/devtools-kit/src/core/plugins/components.ts b/packages/devtools-kit/src/plugins/component.ts similarity index 89% rename from packages/devtools-kit/src/core/plugins/components.ts rename to packages/devtools-kit/src/plugins/component.ts index 79f8a100..f8f744e3 100644 --- a/packages/devtools-kit/src/core/plugins/components.ts +++ b/packages/devtools-kit/src/plugins/component.ts @@ -1,18 +1,17 @@ -import type { VueAppInstance } from '@vue/devtools-schema' import { debounce } from 'perfect-debounce' -import { setupDevToolsPlugin } from '../../api/plugin' -import { getAppRecord, getComponentId, getComponentInstance } from '../component/general' -import { devtoolsContext } from '../general/state' -import { ComponentWalker } from '../component/tree/walker' -import { getInstanceState } from '../component/state' -import { editState } from '../component/state/editor' -import { getComponentBoundingRect } from '../component/state/bounding-rect' -import { DevToolsEvents, apiHooks } from '../../api/on' -import { hook } from '../general/hook' +import { VueAppInstance } from '../types' +import { DevToolsEvents, apiHooks, setupDevToolsPlugin } from '../api' +import { devtoolsContext } from '../state' +import { hook } from '../hook' +import { getAppRecord, getComponentId, getComponentInstance } from '../core/component/utils' +import { getComponentBoundingRect } from '../core/component/state/bounding-rect' +import { ComponentWalker } from '../core/component/tree/walker' +import { editState } from '../core/component/state/editor' +import { getInstanceState } from '../core/component/state' const INSPECTOR_ID = 'components' -export function registerComponentsDevTools(app: VueAppInstance) { +export function registerComponentDevToolsPlugin(app: VueAppInstance) { setupDevToolsPlugin({ id: INSPECTOR_ID, label: 'Components', @@ -82,6 +81,7 @@ export function registerComponentsDevTools(app: VueAppInstance) { }) api.on.editInspectorState(async (payload) => { + // @ts-expect-error expected type if (payload.app === app && payload.inspectorId === INSPECTOR_ID) { editState(payload) await api.sendInspectorState('components') diff --git a/packages/devtools-kit/src/plugins/index.ts b/packages/devtools-kit/src/plugins/index.ts new file mode 100644 index 00000000..452e5c21 --- /dev/null +++ b/packages/devtools-kit/src/plugins/index.ts @@ -0,0 +1 @@ +export * from './component' diff --git a/packages/devtools-kit/src/state/app-record.ts b/packages/devtools-kit/src/state/app-record.ts new file mode 100644 index 00000000..7df39a1b --- /dev/null +++ b/packages/devtools-kit/src/state/app-record.ts @@ -0,0 +1,58 @@ +import { target } from '@vue/devtools-shared' +import { AppRecord } from '../types' +import { normalizeRouterInfo } from '../core/router' +import { callConnectedUpdatedHook, callStateUpdatedHook, devtoolsState } from './state' +import { devtoolsRouterInfo } from './router' +import { devtoolsContext } from './context' + +interface DevToolsAppRecords { + value: AppRecord[] + active: AppRecord + activeId: string +} + +export const devtoolsAppRecords = new Proxy(devtoolsState.appRecords as unknown as DevToolsAppRecords, { + get(_, property) { + if (property === 'value') + return devtoolsState.appRecords + else if (property === 'active') + return devtoolsState.activeAppRecord + else if (property === 'activeId') + return devtoolsState.activeAppRecordId + }, + set(target, property, value) { + const oldState = { ...devtoolsState } + + if (property === 'value') { + devtoolsState.appRecords = value + } + + else if (property === 'active') { + const _value = value as AppRecord + + // sync to context + devtoolsState.activeAppRecord = _value + devtoolsContext.appRecord = _value + devtoolsContext.api = _value.api! + // @ts-expect-error expected type + devtoolsContext.inspector = _value.inspector ?? [] + normalizeRouterInfo(value) + devtoolsContext.routerInfo = devtoolsRouterInfo + } + + else if (property === 'activeId') { + devtoolsState.activeAppRecordId = value + } + + callStateUpdatedHook(devtoolsState, oldState) + if (['connected', 'clientConnected'].includes(property.toString()) && oldState[property] !== value) + callConnectedUpdatedHook(devtoolsState, oldState) + + return true + }, +}) + +export const appRecordInfo = target.__VUE_DEVTOOLS_APP_RECROD_INFO__ ??= { + id: 0, + appIds: new Set(), +} diff --git a/packages/devtools-kit/src/state/context.ts b/packages/devtools-kit/src/state/context.ts new file mode 100644 index 00000000..e0ed2d3a --- /dev/null +++ b/packages/devtools-kit/src/state/context.ts @@ -0,0 +1,37 @@ +import { deepClone, target as global } from '@vue/devtools-shared' +import type { DevToolsContext } from '../types' +import { ROUTER_KEY } from './router' + +const CONTEXT_KEY = '__VUE_DEVTOOLS_CONTEXT__' +const INITIAL_CONTEXT = { + appRecord: null, + api: null, + inspector: [], + timelineLayer: [], + routerInfo: {}, + router: null, + activeInspectorTreeId: '', + componentPluginHookBuffer: [], +} as unknown as DevToolsContext + +global[CONTEXT_KEY] ??= deepClone(INITIAL_CONTEXT) + +function resetDevToolsContext() { + global[CONTEXT_KEY] = deepClone(INITIAL_CONTEXT) +} + +export const devtoolsContext = new Proxy(global[CONTEXT_KEY], { + get(target, property) { + if (property === 'router') + return global[ROUTER_KEY] + + else if (property === 'clear') + return resetDevToolsContext + + return global[CONTEXT_KEY][property] + }, + set(target, property, value) { + global[CONTEXT_KEY][property] = value + return true + }, +}) diff --git a/packages/devtools-kit/src/state/env.ts b/packages/devtools-kit/src/state/env.ts new file mode 100644 index 00000000..db3acc18 --- /dev/null +++ b/packages/devtools-kit/src/state/env.ts @@ -0,0 +1,17 @@ +import { target } from '@vue/devtools-shared' +import { DevToolsEnv } from '../types' + +target.__VUE_DEVTOOLS_ENV__ ??= { + vitePluginDetected: false, +} + +export function getDevToolsEnv() { + return target.__VUE_DEVTOOLS_ENV__ +} + +export function setDevToolsEnv(env: Partial) { + target.__VUE_DEVTOOLS_ENV__ = { + ...target.__VUE_DEVTOOLS_ENV__, + ...env, + } +} diff --git a/packages/devtools-kit/src/state/index.ts b/packages/devtools-kit/src/state/index.ts new file mode 100644 index 00000000..49120dee --- /dev/null +++ b/packages/devtools-kit/src/state/index.ts @@ -0,0 +1,5 @@ +export * from './state' +export * from './app-record' +export * from './context' +export * from './router' +export * from './env' diff --git a/packages/devtools-kit/src/state/router.ts b/packages/devtools-kit/src/state/router.ts new file mode 100644 index 00000000..a8549de3 --- /dev/null +++ b/packages/devtools-kit/src/state/router.ts @@ -0,0 +1,18 @@ +import { target as global } from '@vue/devtools-shared' +import { RouterInfo } from '../types' + +export const ROUTER_KEY = '__VUE_DEVTOOLS_ROUTER__' +export const ROUTER_INFO_KEY = '__VUE_DEVTOOLS_ROUTER_INFO__' + +global[ROUTER_INFO_KEY] ??= { + currentRoute: null, + routes: [], +} + +global[ROUTER_KEY] ??= null + +export const devtoolsRouterInfo: RouterInfo = new Proxy(global[ROUTER_INFO_KEY], { + get(target, property) { + return global[ROUTER_INFO_KEY][property] + }, +}) diff --git a/packages/devtools-kit/src/state/state.ts b/packages/devtools-kit/src/state/state.ts new file mode 100644 index 00000000..fe0480a4 --- /dev/null +++ b/packages/devtools-kit/src/state/state.ts @@ -0,0 +1,79 @@ +import { target as global } from '@vue/devtools-shared' +import { debounce } from 'perfect-debounce' +import type { DevToolsState } from '../types' +import { DevToolsEvents, apiHooks } from '../api' + +export type { DevToolsState } from '../types' + +const STATE_KEY = '__VUE_DEVTOOLS_GLOBAL_STATE__' +const INITIAL_STATE = { + connected: false, + clientConnected: false, + appRecords: [], + activeAppRecord: null, + selectedComponentId: null, + pluginBuffer: [], + tabs: [], + commands: [], + vitePluginDetected: false, + activeAppRecordId: null, +} + +global[STATE_KEY] ??= INITIAL_STATE + +export function resetDevToolsState() { + global[STATE_KEY] = INITIAL_STATE +} + +export const callStateUpdatedHook = debounce((state: DevToolsState, oldState: DevToolsState) => { + apiHooks.callHook(DevToolsEvents.DEVTOOLS_STATE_UPDATED, state, oldState) +}, 80) + +export const callConnectedUpdatedHook = debounce((state: DevToolsState, oldState: DevToolsState) => { + apiHooks.callHook(DevToolsEvents.DEVTOOLS_CONNECTED_UPDATED, state, oldState) +}, 80) + +export const devtoolsState: DevToolsState = new Proxy(global[STATE_KEY], { + get(target, property) { + return global[STATE_KEY][property] + }, + deleteProperty(target, property) { + delete target[property] + return true + }, + set(target, property, value) { + const oldState = { ...global[STATE_KEY] } + + target[property] = value + // sync to global to ensure the state is consistent + global[STATE_KEY][property] = value + + callStateUpdatedHook(global[STATE_KEY], oldState) + if (['connected', 'clientConnected'].includes(property.toString()) && oldState[property] !== value) + callConnectedUpdatedHook(global[STATE_KEY], oldState) + + return true + }, +}) + +Object.defineProperty(devtoolsState.tabs, 'push', { + configurable: true, + value(...items: unknown[]) { + const result = Array.prototype.push.apply(this, items) + devtoolsState.tabs = this + apiHooks.callHook(DevToolsEvents.CUSTOM_TABS_UPDATED, this) + return result + }, +}) + +;['push', 'splice'].forEach((method) => { + Object.defineProperty(devtoolsState.commands, method, { + configurable: true, + value(...args: unknown[]) { + const result = Array.prototype[method].apply(this, args) + devtoolsState.commands = this + apiHooks.callHook(DevToolsEvents.CUSTOM_COMMANDS_UPDATED, this) + return result + }, + }) +}) diff --git a/packages/devtools-kit/src/types/app.ts b/packages/devtools-kit/src/types/app.ts new file mode 100644 index 00000000..5f43caff --- /dev/null +++ b/packages/devtools-kit/src/types/app.ts @@ -0,0 +1,101 @@ +import type { App, ComponentInternalInstance, ComponentOptions, SuspenseBoundary } from 'vue' +import type { DevToolsPluginApi } from '../api' + +export type PluginApi = DevToolsPluginApi + +export declare type PluginSettingsItem = { + label: string + description?: string +} & ({ + type: 'boolean' + defaultValue: boolean +} | { + type: 'choice' + defaultValue: string | number + options: { + value: string | number + label: string + }[] + component?: 'select' | 'button-group' +} | { + type: 'text' + defaultValue: string +}) + +export interface PluginDescriptor { + id: string + label: string + app: VueAppInstance + packageName?: string + homepage?: string + componentStateTypes?: string[] + logo?: string + disableAppScope?: boolean + disablePluginScope?: boolean + /** + * Run the plugin setup and expose the api even if the devtools is not opened yet. + * Useful to record timeline events early. + */ + enableEarlyProxy?: boolean + settings?: Record +} + +export type PluginSetupFunction = (api: PluginApi) => void + +export type VueAppInstance = ComponentInternalInstance & { + type: { + _componentTag: string | undefined + components: Record + __VUE_DEVTOOLS_COMPONENT_GUSSED_NAME__: string + __isKeepAlive: boolean + devtools: { + hide: boolean + } + mixins: ComponentOptions[] + extends: ComponentOptions + vuex: { + getters: Record + } + computed: Record + } + __v_cache: Cache + __VUE_DEVTOOLS_UID__: string + _isBeingDestroyed: boolean + _instance: VueAppInstance + _container: { + _vnode: { + component: VueAppInstance + } + } + isUnmounted: boolean + parent: VueAppInstance + appContext: { + app: VueAppInstance & App & { + __VUE_DEVTOOLS_APP_RECORD_ID__: string + __VUE_DEVTOOLS_APP_RECORD__: AppRecord + } + } + __VUE_DEVTOOLS_APP_RECORD__: AppRecord + suspense: SuspenseBoundary & { suspenseKey: string } + renderContext: Record + devtoolsRawSetupState: Record + setupState: Record + provides: Record + ctx: Record +} +export interface AppRecord { + id: string | number + name: string + app?: App + version?: string + types?: Record + instanceMap: Map + rootInstance: VueAppInstance + api?: PluginApi + routerId?: string + moduleDetectives?: { + vueRouter: boolean + pinia: boolean + vueI18n: boolean + } +} diff --git a/packages/devtools-kit/src/types/context.ts b/packages/devtools-kit/src/types/context.ts new file mode 100644 index 00000000..503dc7ea --- /dev/null +++ b/packages/devtools-kit/src/types/context.ts @@ -0,0 +1,17 @@ +import type { TimelineLayerItem } from '../core/timeline' +import type { DevToolsPluginApi } from '../api' +import type { Inspector } from '../core/inspector' +import type { AppRecord } from './app' +import type { Router, RouterInfo } from './router' + +export interface DevToolsContext { + appRecord: AppRecord | null + api: DevToolsPluginApi + inspector: Inspector[] + timelineLayer: TimelineLayerItem[] + routerInfo: RouterInfo + router: Router | null + activeInspectorTreeId: string + componentPluginHookBuffer: (() => void)[] + clear: () => void +} diff --git a/packages/devtools-kit/src/types/env.ts b/packages/devtools-kit/src/types/env.ts new file mode 100644 index 00000000..2025a9de --- /dev/null +++ b/packages/devtools-kit/src/types/env.ts @@ -0,0 +1,3 @@ +export interface DevToolsEnv { + vitePluginDetected: boolean +} diff --git a/packages/devtools-kit/src/types/hook.ts b/packages/devtools-kit/src/types/hook.ts new file mode 100644 index 00000000..b9dc6383 --- /dev/null +++ b/packages/devtools-kit/src/types/hook.ts @@ -0,0 +1,55 @@ +import type { App } from 'vue' +import type { AppRecord, PluginDescriptor, PluginSetupFunction, VueAppInstance } from './app' + +type HookAppInstance = App & VueAppInstance +export enum DevToolsHooks { + // internal + APP_INIT = 'app:init', + APP_UNMOUNT = 'app:unmount', + COMPONENT_UPDATED = 'component:updated', + COMPONENT_ADDED = 'component:added', + COMPONENT_REMOVED = 'component:removed', + COMPONENT_EMIT = 'component:emit', + PERFORMANCE_START = 'perf:start', + PERFORMANCE_END = 'perf:end', + ADD_ROUTE = 'router:add-route', + REMOVE_ROUTE = 'router:remove-route', + RENDER_TRACKED = 'render:tracked', + RENDER_TRIGGERED = 'render:triggered', + APP_CONNECTED = 'app:connected', + SETUP_DEVTOOLS_PLUGIN = 'devtools-plugin:setup', +} + +export interface DevToolsEvent { + [DevToolsHooks.APP_INIT]: (app: VueAppInstance['appContext']['app'], version: string) => void + [DevToolsHooks.APP_CONNECTED]: () => void + [DevToolsHooks.COMPONENT_ADDED]: (app: HookAppInstance, uid: number, parentUid: number, component: VueAppInstance) => void + [DevToolsHooks.COMPONENT_UPDATED]: DevToolsEvent['component:added'] + [DevToolsHooks.COMPONENT_REMOVED]: DevToolsEvent['component:added'] + [DevToolsHooks.SETUP_DEVTOOLS_PLUGIN]: (pluginDescriptor: PluginDescriptor, setupFn: PluginSetupFunction) => void +} + +export interface DevToolsHook { + id: string + enabled?: boolean + events: Map + emit: (event: DevToolsHooks, ...payload: any[]) => void + on: (event: DevToolsHooks, handler: T) => () => void + once: (event: DevToolsHooks, handler: T) => void + off: (event: DevToolsHooks, handler: T) => void + appRecords: AppRecord[] + apps: Record + cleanupBuffer?: (matchArg: unknown) => boolean +} + +export interface VueHooks { + on: { + vueAppInit(fn: DevToolsEvent[DevToolsHooks.APP_INIT]): void + vueAppConnected(fn: DevToolsEvent[DevToolsHooks.APP_CONNECTED]): void + componentAdded(fn: DevToolsEvent[DevToolsHooks.COMPONENT_ADDED]): () => void + componentUpdated(fn: DevToolsEvent[DevToolsHooks.COMPONENT_UPDATED]): () => void + componentRemoved(fn: DevToolsEvent[DevToolsHooks.COMPONENT_REMOVED]): () => void + setupDevtoolsPlugin(fn: DevToolsEvent[DevToolsHooks.SETUP_DEVTOOLS_PLUGIN]): void + } + setupDevToolsPlugin(pluginDescriptor: PluginDescriptor, setupFn: PluginSetupFunction): void +} diff --git a/packages/devtools-kit/src/types/index.ts b/packages/devtools-kit/src/types/index.ts new file mode 100644 index 00000000..13c2de45 --- /dev/null +++ b/packages/devtools-kit/src/types/index.ts @@ -0,0 +1,6 @@ +export * from './app' +export * from './hook' +export * from './state' +export * from './context' +export * from './router' +export * from './env' diff --git a/packages/devtools-kit/src/types/router.ts b/packages/devtools-kit/src/types/router.ts new file mode 100644 index 00000000..ff8f1759 --- /dev/null +++ b/packages/devtools-kit/src/types/router.ts @@ -0,0 +1,8 @@ +import type { RouteLocationNormalizedLoaded, RouteRecordNormalized } from 'vue-router' + +export type { Router } from 'vue-router' +export interface RouterInfo { + currentRoute: RouteLocationNormalizedLoaded | null | {} + routes: RouteRecordNormalized[] + // router: Router | null +} diff --git a/packages/devtools-kit/src/types/state.ts b/packages/devtools-kit/src/types/state.ts new file mode 100644 index 00000000..9f5ea35f --- /dev/null +++ b/packages/devtools-kit/src/types/state.ts @@ -0,0 +1,16 @@ +import type { CustomCommand } from '../core/custom-command' +import type { CustomTab } from '../core/custom-tab' +import type { AppRecord, PluginDescriptor, PluginSetupFunction } from './app' + +export interface DevToolsState { + connected: boolean + clientConnected: boolean + vitePluginDetected: boolean + appRecords: AppRecord[] + activeAppRecord: AppRecord | null + selectedComponentId: string | null + pluginBuffer: [PluginDescriptor, PluginSetupFunction][] + tabs: CustomTab[] + commands: CustomCommand[] + activeAppRecordId: string | null +} diff --git a/packages/devtools-kit/types.d.ts b/packages/devtools-kit/types.d.ts new file mode 100644 index 00000000..e4001646 --- /dev/null +++ b/packages/devtools-kit/types.d.ts @@ -0,0 +1,2 @@ +/// +export * from './dist/index' diff --git a/packages/schema/global.d.ts b/packages/schema/global.d.ts deleted file mode 100644 index 0896c7c8..00000000 --- a/packages/schema/global.d.ts +++ /dev/null @@ -1,42 +0,0 @@ -import type { DevToolsContext } from './src/types/context' -import type { DevtoolsHook } from './src/types/hook' -import type { AppRecord, DevToolsState } from './src/types/vue' - -/* eslint-disable vars-on-top, no-var */ -declare global { - var __VUE_DEVTOOLS_GLOBAL_HOOK__: DevtoolsHook - var __VUE_DEVTOOLS_CLIENT_URL__: string - - // FIXME: the type should be BridgeInstanceType - var __VUE_DEVTOOLS_BRIDGE__: any - var __VUE_DEVTOOLS_OVERLAY_BRIDGE__: any - var __VUE_DEVTOOLS_PANEL_BRIDGE__: any - - var __VUE_DEVTOOLS_CLIENT_CONNECTED__: boolean - // app record info - var __VUE_DEVTOOLS_APP_RECORDS__: AppRecord[] - var __VUE_DEVTOOLS_ACTIVE_APP_RECORD__: AppRecord - var __VUE_DEVTOOLS_APP_RECROD_INFO__: { - id: number - appIds: Set - } - // devtools global state - var __VUE_DEVTOOLS_GLOBAL_STATE__: DevToolsState - // devtools context - var __VUE_DEVTOOLS_CONTEXT__: DevToolsContext - // router - var __VUE_DEVTOOLS_ROUTER__: unknown - // toggle overlay - var __VUE_DEVTOOLS_TOGGLE_OVERLAY__: (visible: boolean) => void - // is vite plugin detected - var __VUE_DEVTOOLS_VITE_PLUGIN_DETECTED__: boolean - // is browser extension detected - var __VUE_DEVTOOLS_BROWSER_EXTENSION_DETECTED__: boolean - // vite client url - var __VUE_DEVTOOLS_VITE_PLUGIN_CLIENT_URL__: string - // remote devtools option - var __VUE_DEVTOOLS_HOST__: string - var __VUE_DEVTOOLS_PORT__: number -} - -export { } diff --git a/packages/schema/types.d.ts b/packages/schema/types.d.ts index e4001646..9247c2a8 100644 --- a/packages/schema/types.d.ts +++ b/packages/schema/types.d.ts @@ -1,2 +1 @@ -/// export * from './dist/index' diff --git a/packages/vite/src/overlay.js b/packages/vite/src/overlay.js index 5337018e..9683342f 100644 --- a/packages/vite/src/overlay.js +++ b/packages/vite/src/overlay.js @@ -1,13 +1,15 @@ import vueDevToolsOptions from 'virtual:vue-devtools-options' import { Bridge, prepareInjection, setDevToolsClientUrl } from '@vue/devtools-core' import { BROADCAST_CHANNEL_NAME } from '@vue/devtools-shared' -import { addCustomTab, devtools, toggleComponentInspectorEnabled } from '@vue/devtools-kit' +import { addCustomTab, devtools, setDevToolsEnv, toggleComponentInspectorEnabled } from '@vue/devtools-kit' const overlayDir = `${vueDevToolsOptions.base || '/'}@id/virtual:vue-devtools-path:overlay` const body = document.getElementsByTagName('body')[0] const head = document.getElementsByTagName('head')[0] -window.__VUE_DEVTOOLS_VITE_PLUGIN_DETECTED__ = true +setDevToolsEnv({ + vitePluginDetected: true, +}) const devtoolsClientUrl = `${vueDevToolsOptions.clientHost || ''}${vueDevToolsOptions.base || '/'}__devtools__/` setDevToolsClientUrl(devtoolsClientUrl) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6470e480..93e67ebe 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -28,16 +28,19 @@ importers: version: 11.0.4 '@types/node': specifier: ^20.11.10 - version: 20.11.10 + version: 20.11.16 '@unocss/eslint-plugin': specifier: ^0.58.4 version: 0.58.4(eslint-ts-patch@8.55.0-1)(typescript@5.3.3) '@vue/devtools-core': specifier: workspace:^ version: link:packages/core - '@vue/devtools-schema': + '@vue/devtools-kit': specifier: workspace:^ - version: link:packages/schema + version: link:packages/devtools-kit + '@vue/test-utils': + specifier: ^2.4.4 + version: 2.4.4(vue@3.4.15) archiver: specifier: ^6.0.1 version: 6.0.1 @@ -65,6 +68,9 @@ importers: fs-extra: specifier: ^11.2.0 version: 11.2.0 + jsdom: + specifier: ^24.0.0 + version: 24.0.0 lint-staged: specifier: ^15.2.0 version: 15.2.0 @@ -73,7 +79,7 @@ importers: version: 5.0.2 pnpm: specifier: ^8.15.0 - version: 8.15.0 + version: 8.15.1 progress: specifier: ^2.0.3 version: 2.0.3 @@ -109,10 +115,10 @@ importers: version: 0.58.4(postcss@8.4.33)(rollup@3.28.1)(vite@5.0.12) vite: specifier: ^5.0.12 - version: 5.0.12(@types/node@20.11.10)(sass@1.70.0) + version: 5.0.12(@types/node@20.11.16)(sass@1.70.0) vitest: specifier: ^1.2.2 - version: 1.2.2(@types/node@20.11.10) + version: 1.2.2(@types/node@20.11.16)(jsdom@24.0.0) vue: specifier: ^3.4.15 version: 3.4.15(typescript@5.3.3) @@ -130,7 +136,7 @@ importers: version: 0.26.0(rollup@3.28.1)(vue@3.4.15) vitepress: specifier: 1.0.0-rc.40 - version: 1.0.0-rc.40(@algolia/client-search@4.22.0)(@types/node@20.11.10)(postcss@8.4.33)(search-insights@2.13.0)(typescript@5.3.3) + version: 1.0.0-rc.40(@algolia/client-search@4.22.0)(@types/node@20.11.16)(postcss@8.4.33)(search-insights@2.13.0)(typescript@5.3.3) vue: specifier: ^3.4.15 version: 3.4.15(typescript@5.3.3) @@ -165,9 +171,6 @@ importers: '@vue/devtools-kit': specifier: workspace:^ version: link:../devtools-kit - '@vue/devtools-schema': - specifier: workspace:* - version: link:../schema '@vue/devtools-shared': specifier: workspace:^ version: link:../shared @@ -210,10 +213,10 @@ importers: devDependencies: '@iconify/json': specifier: ^2.2.176 - version: 2.2.176 + version: 2.2.178 '@types/node': specifier: ^20.11.10 - version: 20.11.10 + version: 20.11.16 '@types/splitpanes': specifier: ^2.2.6 version: 2.2.6 @@ -261,7 +264,7 @@ importers: version: 0.26.0(rollup@3.28.1)(vue@3.4.15) vite: specifier: ^5.0.12 - version: 5.0.12(@types/node@20.11.10)(sass@1.70.0) + version: 5.0.12(@types/node@20.11.16)(sass@1.70.0) vue: specifier: ^3.4.15 version: 3.4.15(typescript@5.3.3) @@ -271,9 +274,6 @@ importers: '@vue/devtools-kit': specifier: workspace:^ version: link:../devtools-kit - '@vue/devtools-schema': - specifier: workspace:^ - version: link:../schema '@vue/devtools-shared': specifier: workspace:^ version: link:../shared @@ -326,9 +326,6 @@ importers: packages/devtools-kit: dependencies: - '@vue/devtools-schema': - specifier: workspace:^ - version: link:../schema '@vue/devtools-shared': specifier: workspace:^ version: link:../shared @@ -345,8 +342,11 @@ importers: specifier: ^14.0.1 version: 14.0.1 devDependencies: + '@types/speakingurl': + specifier: ^13.0.6 + version: 13.0.6 vue: - specifier: ^3.4.15 + specifier: ^3.4.14 version: 3.4.15(typescript@5.3.3) vue-router: specifier: ^4.2.5 @@ -415,10 +415,10 @@ importers: devDependencies: '@iconify/json': specifier: ^2.2.176 - version: 2.2.176 + version: 2.2.178 '@types/node': specifier: ^20.11.10 - version: 20.11.10 + version: 20.11.16 '@vitejs/plugin-vue': specifier: ^5.0.3 version: 5.0.3(vite@5.0.12)(vue@3.4.15) @@ -427,7 +427,7 @@ importers: version: 1.70.0 vite: specifier: ^5.0.12 - version: 5.0.12(@types/node@20.11.10)(sass@1.70.0) + version: 5.0.12(@types/node@20.11.16)(sass@1.70.0) vue: specifier: ^3.4.15 version: 3.4.15(typescript@5.3.3) @@ -473,7 +473,7 @@ importers: version: 5.3.3 vite: specifier: ^5.0.12 - version: 5.0.12(@types/node@20.11.10)(sass@1.70.0) + version: 5.0.12(@types/node@20.11.16)(sass@1.70.0) vite-plugin-inspect: specifier: ^0.8.3 version: 0.8.3(rollup@3.28.1)(vite@5.0.12) @@ -491,7 +491,7 @@ importers: devDependencies: '@types/node': specifier: ^20.11.10 - version: 20.11.10 + version: 20.11.16 packages/ui: dependencies: @@ -519,7 +519,7 @@ importers: version: 0.17.9(histoire@0.17.9)(vite@5.0.12)(vue@3.4.0) '@types/node': specifier: ^20.11.10 - version: 20.11.10 + version: 20.11.16 '@unocss/reset': specifier: ^0.58.4 version: 0.58.4 @@ -531,13 +531,13 @@ importers: version: 2.0.0(vue@3.4.0) histoire: specifier: ^0.17.9 - version: 0.17.9(@types/node@20.11.10)(vite@5.0.12) + version: 0.17.9(@types/node@20.11.16)(vite@5.0.12) unocss: specifier: ^0.58.4 version: 0.58.4(postcss@8.4.33)(rollup@3.28.1)(vite@5.0.12) vite-plugin-dts: specifier: ^3.7.2 - version: 3.7.2(@types/node@20.11.10)(rollup@3.28.1)(typescript@5.3.3)(vite@5.0.12) + version: 3.7.2(@types/node@20.11.16)(rollup@3.28.1)(typescript@5.3.3)(vite@5.0.12) packages/ui-playground: dependencies: @@ -565,7 +565,7 @@ importers: version: 5.3.3 vite: specifier: ^5.0.12 - version: 5.0.12(@types/node@20.11.10)(sass@1.70.0) + version: 5.0.12(@types/node@20.11.16)(sass@1.70.0) vue-tsc: specifier: ^1.8.27 version: 1.8.27(typescript@5.3.3) @@ -592,7 +592,7 @@ importers: version: 2.0.4 vite: specifier: ^3.1.0 || ^4.0.0-0 || ^5.0.0-0 - version: 5.0.10(@types/node@20.11.10) + version: 5.0.10(@types/node@20.11.16) vite-plugin-inspect: specifier: ^0.8.3 version: 0.8.3(rollup@3.28.1)(vite@5.0.10) @@ -602,7 +602,7 @@ importers: devDependencies: '@types/node': specifier: ^20.11.10 - version: 20.11.10 + version: 20.11.16 fast-glob: specifier: ^3.3.2 version: 3.3.2 @@ -630,13 +630,13 @@ importers: devDependencies: '@types/node': specifier: ^18.19.10 - version: 18.19.10 + version: 18.19.14 '@vitejs/plugin-vue': specifier: ^5.0.3 version: 5.0.3(vite@5.0.12)(vue@3.4.15) '@vue-termui/cli': specifier: '*' - version: 0.0.17(@types/node@18.19.10)(vite-plugin-vue-termui@0.0.12)(vite@5.0.12)(vue-termui@0.0.19) + version: 0.0.17(@types/node@18.19.14)(vite-plugin-vue-termui@0.0.12)(vite@5.0.12)(vue-termui@0.0.19) '@vue/compiler-sfc': specifier: ^3.4.15 version: 3.4.15 @@ -651,7 +651,7 @@ importers: version: 0.26.0(rollup@3.28.1)(vue@3.4.15) vite: specifier: ^5.0.12 - version: 5.0.12(@types/node@18.19.10) + version: 5.0.12(@types/node@18.19.14) vite-plugin-vue-termui: specifier: '*' version: 0.0.12(@vitejs/plugin-vue@5.0.3)(unplugin-auto-import@0.17.5)(unplugin-vue-components@0.26.0)(vue-termui@0.0.19)(vue@3.4.15) @@ -670,7 +670,7 @@ importers: version: 7.23.9 '@babel/eslint-parser': specifier: ^7.23.9 - version: 7.23.9(@babel/core@7.23.9)(eslint@8.56.0) + version: 7.23.10(@babel/core@7.23.9)(eslint@8.56.0) '@vue/cli-plugin-babel': specifier: ~5.0.8 version: 5.0.8(@vue/cli-service@5.0.8)(core-js@3.35.1)(esbuild@0.19.10)(vue@3.4.15) @@ -893,8 +893,8 @@ packages: '@eslint-types/typescript-eslint': 6.19.1 '@eslint-types/unicorn': 50.0.1 '@stylistic/eslint-plugin': 1.5.4(eslint-ts-patch@8.55.0-1)(typescript@5.3.3) - '@typescript-eslint/eslint-plugin': 6.19.1(@typescript-eslint/parser@6.19.1)(eslint-ts-patch@8.55.0-1)(typescript@5.3.3) - '@typescript-eslint/parser': 6.19.1(eslint-ts-patch@8.55.0-1)(typescript@5.3.3) + '@typescript-eslint/eslint-plugin': 6.20.0(@typescript-eslint/parser@6.20.0)(eslint-ts-patch@8.55.0-1)(typescript@5.3.3) + '@typescript-eslint/parser': 6.20.0(eslint-ts-patch@8.55.0-1)(typescript@5.3.3) '@unocss/eslint-plugin': 0.58.4(eslint-ts-patch@8.55.0-1)(typescript@5.3.3) eslint: /eslint-ts-patch@8.55.0-1 eslint-config-flat-gitignore: 0.1.2 @@ -902,7 +902,7 @@ packages: eslint-plugin-antfu: 2.1.2(eslint-ts-patch@8.55.0-1) eslint-plugin-eslint-comments: 3.2.0(eslint-ts-patch@8.55.0-1) eslint-plugin-format: 0.1.0(eslint-ts-patch@8.55.0-1) - eslint-plugin-i: 2.29.1(@typescript-eslint/parser@6.19.1)(eslint-ts-patch@8.55.0-1) + eslint-plugin-i: 2.29.1(@typescript-eslint/parser@6.20.0)(eslint-ts-patch@8.55.0-1) eslint-plugin-jsdoc: 48.0.4(eslint-ts-patch@8.55.0-1) eslint-plugin-jsonc: 2.13.0(eslint-ts-patch@8.55.0-1) eslint-plugin-markdown: 3.0.1(eslint-ts-patch@8.55.0-1) @@ -911,8 +911,8 @@ packages: eslint-plugin-perfectionist: 2.5.0(eslint-ts-patch@8.55.0-1)(typescript@5.3.3)(vue-eslint-parser@9.4.0) eslint-plugin-toml: 0.9.2(eslint-ts-patch@8.55.0-1) eslint-plugin-unicorn: 50.0.1(eslint-ts-patch@8.55.0-1) - eslint-plugin-unused-imports: 3.0.0(@typescript-eslint/eslint-plugin@6.19.1)(eslint-ts-patch@8.55.0-1) - eslint-plugin-vitest: 0.3.20(@typescript-eslint/eslint-plugin@6.19.1)(eslint-ts-patch@8.55.0-1)(typescript@5.3.3)(vitest@1.2.2) + eslint-plugin-unused-imports: 3.0.0(@typescript-eslint/eslint-plugin@6.20.0)(eslint-ts-patch@8.55.0-1) + eslint-plugin-vitest: 0.3.21(@typescript-eslint/eslint-plugin@6.20.0)(eslint-ts-patch@8.55.0-1)(typescript@5.3.3)(vitest@1.2.2) eslint-plugin-vue: 9.20.1(eslint-ts-patch@8.55.0-1) eslint-plugin-yml: 1.12.2(eslint-ts-patch@8.55.0-1) eslint-processor-vue-blocks: 0.1.1(@vue/compiler-sfc@3.4.15)(eslint-ts-patch@8.55.0-1) @@ -1008,10 +1008,10 @@ packages: '@babel/generator': 7.23.6 '@babel/helper-compilation-targets': 7.23.6 '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.6) - '@babel/helpers': 7.23.8 + '@babel/helpers': 7.23.6 '@babel/parser': 7.23.6 '@babel/template': 7.22.15 - '@babel/traverse': 7.23.7 + '@babel/traverse': 7.23.6 '@babel/types': 7.23.6 convert-source-map: 2.0.0 debug: 4.3.4 @@ -1043,8 +1043,8 @@ packages: transitivePeerDependencies: - supports-color - /@babel/eslint-parser@7.23.9(@babel/core@7.23.9)(eslint@8.56.0): - resolution: {integrity: sha512-xPndlO7qxiJbn0ATvfXQBjCS7qApc9xmKHArgI/FTEFxXas5dnjC/VqM37lfZun9dclRYcn+YQAr6uDFy0bB2g==} + /@babel/eslint-parser@7.23.10(@babel/core@7.23.9)(eslint@8.56.0): + resolution: {integrity: sha512-3wSYDPZVnhseRnxRJH6ZVTNknBz76AEnyC+AYYhasjP3Yy23qz0ERR7Fcd2SHmYuSFJ2kY9gaaDd3vyqU09eSw==} engines: {node: ^10.13.0 || ^12.13.0 || >=14.0.0} peerDependencies: '@babel/core': ^7.11.0 @@ -1061,7 +1061,7 @@ packages: resolution: {integrity: sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.9 + '@babel/types': 7.23.6 '@jridgewell/gen-mapping': 0.3.3 '@jridgewell/trace-mapping': 0.3.20 jsesc: 2.5.2 @@ -1158,14 +1158,14 @@ packages: resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/template': 7.23.9 - '@babel/types': 7.23.9 + '@babel/template': 7.22.15 + '@babel/types': 7.23.6 /@babel/helper-hoist-variables@7.22.5: resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.9 + '@babel/types': 7.23.6 /@babel/helper-member-expression-to-functions@7.23.0: resolution: {integrity: sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==} @@ -1253,7 +1253,7 @@ packages: resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.9 + '@babel/types': 7.23.6 /@babel/helper-skip-transparent-expression-wrappers@7.22.5: resolution: {integrity: sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==} @@ -1288,12 +1288,12 @@ packages: '@babel/types': 7.23.6 dev: true - /@babel/helpers@7.23.8: - resolution: {integrity: sha512-KDqYz4PiOWvDFrdHLPhKtCThtIcKVy6avWD2oG4GEvyQ+XDZwHD4YQd+H2vNMnq2rkdxsDkU82T+Vk8U/WXHRQ==} + /@babel/helpers@7.23.6: + resolution: {integrity: sha512-wCfsbN4nBidDRhpDhvcKlzHWCTlgJYUUdSJfzXb2NuBssDSIjc3xcb+znA7l+zYsFljAcGM0aFkN40cR3lXiGA==} engines: {node: '>=6.9.0'} dependencies: '@babel/template': 7.22.15 - '@babel/traverse': 7.23.7 + '@babel/traverse': 7.23.6 '@babel/types': 7.23.6 transitivePeerDependencies: - supports-color @@ -2376,8 +2376,8 @@ packages: '@babel/parser': 7.23.9 '@babel/types': 7.23.9 - /@babel/traverse@7.23.7: - resolution: {integrity: sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg==} + /@babel/traverse@7.23.6: + resolution: {integrity: sha512-czastdK1e8YByZqezMPFiZ8ahwVMh/ESl9vPgvgdB9AmFMGP5jfpFax74AQgl5zj4XHzqeYAg2l8PuUeRS1MgQ==} engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.23.5 @@ -3107,7 +3107,7 @@ packages: '@histoire/vendors': 0.17.8 change-case: 4.1.2 globby: 13.2.2 - histoire: 0.17.9(@types/node@20.11.10)(vite@5.0.12) + histoire: 0.17.9(@types/node@20.11.16)(vite@5.0.12) launch-editor: 2.6.1 pathe: 1.1.2 vue: 3.4.0(typescript@5.3.3) @@ -3126,7 +3126,7 @@ packages: chokidar: 3.5.3 pathe: 1.1.2 picocolors: 1.0.0 - vite: 5.0.12(@types/node@20.11.10)(sass@1.70.0) + vite: 5.0.12(@types/node@20.11.16)(sass@1.70.0) dev: true /@histoire/vendors@0.17.8: @@ -3153,8 +3153,8 @@ packages: resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==} dev: true - /@iconify/json@2.2.176: - resolution: {integrity: sha512-Pw1MA57OZdzyrJgGHzZXVnoht8vndv4aM6I3xj4SeimF14HA3e101Ignnlw2h/+Yjujf43jH7doPIVAhgCTFMw==} + /@iconify/json@2.2.178: + resolution: {integrity: sha512-AYw9z/Lu9Y0Q5V0DvyhysJA3ohwKMOgXxCJ1AzTnsZizbUqZ7zh5/wnBegv1ikBEISAY0tC/R46j0tJBjliHkw==} dependencies: '@iconify/types': 2.0.0 pathe: 1.1.2 @@ -3236,7 +3236,7 @@ packages: '@intlify/bundle-utils': 7.5.0(vue-i18n@9.9.0) '@intlify/shared': 9.9.0 '@rollup/pluginutils': 5.1.0(rollup@3.28.1) - '@vue/compiler-sfc': 3.4.4 + '@vue/compiler-sfc': 3.4.15 debug: 4.3.4 fast-glob: 3.3.2 js-yaml: 4.1.0 @@ -3339,24 +3339,24 @@ packages: '@lezer/common': 1.1.1 dev: true - /@microsoft/api-extractor-model@7.28.3(@types/node@20.11.10): + /@microsoft/api-extractor-model@7.28.3(@types/node@20.11.16): resolution: {integrity: sha512-wT/kB2oDbdZXITyDh2SQLzaWwTOFbV326fP0pUwNW00WeliARs0qjmXBWmGWardEzp2U3/axkO3Lboqun6vrig==} dependencies: '@microsoft/tsdoc': 0.14.2 '@microsoft/tsdoc-config': 0.16.2 - '@rushstack/node-core-library': 3.62.0(@types/node@20.11.10) + '@rushstack/node-core-library': 3.62.0(@types/node@20.11.16) transitivePeerDependencies: - '@types/node' dev: true - /@microsoft/api-extractor@7.39.0(@types/node@20.11.10): + /@microsoft/api-extractor@7.39.0(@types/node@20.11.16): resolution: {integrity: sha512-PuXxzadgnvp+wdeZFPonssRAj/EW4Gm4s75TXzPk09h3wJ8RS3x7typf95B4vwZRrPTQBGopdUl+/vHvlPdAcg==} hasBin: true dependencies: - '@microsoft/api-extractor-model': 7.28.3(@types/node@20.11.10) + '@microsoft/api-extractor-model': 7.28.3(@types/node@20.11.16) '@microsoft/tsdoc': 0.14.2 '@microsoft/tsdoc-config': 0.16.2 - '@rushstack/node-core-library': 3.62.0(@types/node@20.11.10) + '@rushstack/node-core-library': 3.62.0(@types/node@20.11.16) '@rushstack/rig-package': 0.5.1 '@rushstack/ts-command-line': 4.17.1 colors: 1.2.5 @@ -3512,6 +3512,10 @@ packages: - supports-color dev: true + /@one-ini/wasm@0.1.1: + resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==} + dev: true + /@pkgjs/parseargs@0.11.0: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -3708,7 +3712,7 @@ packages: requiresBuild: true optional: true - /@rushstack/node-core-library@3.62.0(@types/node@20.11.10): + /@rushstack/node-core-library@3.62.0(@types/node@20.11.16): resolution: {integrity: sha512-88aJn2h8UpSvdwuDXBv1/v1heM6GnBf3RjEy6ZPP7UnzHNCqOHA2Ut+ScYUbXcqIdfew9JlTAe3g+cnX9xQ/Aw==} peerDependencies: '@types/node': '*' @@ -3716,7 +3720,7 @@ packages: '@types/node': optional: true dependencies: - '@types/node': 20.11.10 + '@types/node': 20.11.16 colors: 1.2.5 fs-extra: 7.0.1 import-lazy: 4.0.0 @@ -3851,7 +3855,7 @@ packages: peerDependencies: eslint: '*' dependencies: - '@typescript-eslint/utils': 6.19.1(eslint-ts-patch@8.55.0-1)(typescript@5.3.3) + '@typescript-eslint/utils': 6.20.0(eslint-ts-patch@8.55.0-1)(typescript@5.3.3) eslint: /eslint-ts-patch@8.55.0-1 transitivePeerDependencies: - supports-color @@ -3865,7 +3869,7 @@ packages: eslint: '>=8.40.0' dependencies: '@stylistic/eslint-plugin-js': 1.5.4(eslint-ts-patch@8.55.0-1) - '@typescript-eslint/utils': 6.19.1(eslint-ts-patch@8.55.0-1)(typescript@5.3.3) + '@typescript-eslint/utils': 6.20.0(eslint-ts-patch@8.55.0-1)(typescript@5.3.3) eslint: /eslint-ts-patch@8.55.0-1 transitivePeerDependencies: - supports-color @@ -3926,13 +3930,13 @@ packages: resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} dependencies: '@types/connect': 3.4.38 - '@types/node': 20.11.10 + '@types/node': 20.11.16 dev: true /@types/bonjour@3.5.13: resolution: {integrity: sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==} dependencies: - '@types/node': 20.11.10 + '@types/node': 20.11.16 dev: true /@types/cacheable-request@6.0.3: @@ -3940,7 +3944,7 @@ packages: dependencies: '@types/http-cache-semantics': 4.0.4 '@types/keyv': 3.1.4 - '@types/node': 18.19.10 + '@types/node': 18.19.14 '@types/responselike': 1.0.3 dev: false @@ -3955,13 +3959,13 @@ packages: resolution: {integrity: sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==} dependencies: '@types/express-serve-static-core': 4.17.41 - '@types/node': 20.11.10 + '@types/node': 20.11.16 dev: true /@types/connect@3.4.38: resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} dependencies: - '@types/node': 20.11.10 + '@types/node': 20.11.16 dev: true /@types/cookie@0.4.1: @@ -3971,7 +3975,7 @@ packages: /@types/cors@2.8.17: resolution: {integrity: sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==} dependencies: - '@types/node': 20.11.10 + '@types/node': 20.11.16 dev: false /@types/degit@2.8.6: @@ -3998,7 +4002,7 @@ packages: /@types/express-serve-static-core@4.17.41: resolution: {integrity: sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==} dependencies: - '@types/node': 20.11.10 + '@types/node': 20.11.16 '@types/qs': 6.9.11 '@types/range-parser': 1.2.7 '@types/send': 0.17.4 @@ -4031,13 +4035,13 @@ packages: resolution: {integrity: sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==} dependencies: '@types/jsonfile': 6.1.4 - '@types/node': 20.11.10 + '@types/node': 20.11.16 dev: true /@types/fs-extra@9.0.13: resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} dependencies: - '@types/node': 20.11.10 + '@types/node': 20.11.16 dev: true /@types/hammerjs@2.0.45: @@ -4063,7 +4067,7 @@ packages: /@types/http-proxy@1.17.14: resolution: {integrity: sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==} dependencies: - '@types/node': 20.11.10 + '@types/node': 20.11.16 dev: true /@types/json-schema@7.0.15: @@ -4073,13 +4077,13 @@ packages: /@types/jsonfile@6.1.4: resolution: {integrity: sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==} dependencies: - '@types/node': 20.11.10 + '@types/node': 20.11.16 dev: true /@types/keyv@3.1.4: resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} dependencies: - '@types/node': 18.19.10 + '@types/node': 18.19.14 dev: false /@types/linkify-it@3.0.5: @@ -4125,16 +4129,16 @@ packages: /@types/node-forge@1.3.11: resolution: {integrity: sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==} dependencies: - '@types/node': 20.11.10 + '@types/node': 20.11.16 dev: true - /@types/node@18.19.10: - resolution: {integrity: sha512-IZD8kAM02AW1HRDTPOlz3npFava678pr8Ie9Vp8uRhBROXAv8MXT2pCnGZZAKYdromsNQLHQcfWQ6EOatVLtqA==} + /@types/node@18.19.14: + resolution: {integrity: sha512-EnQ4Us2rmOS64nHDWr0XqAD8DsO6f3XR6lf9UIIrZQpUzPVdN/oPuEzfDWNHSyXLvoGgjuEm/sPwFGSSs35Wtg==} dependencies: undici-types: 5.26.5 - /@types/node@20.11.10: - resolution: {integrity: sha512-rZEfe/hJSGYmdfX9tvcPMYeYPW2sNl50nsw4jZmRcaG0HIAb0WYEpsB05GOb53vjqpyE9GUhlDQ4jLSoB5q9kg==} + /@types/node@20.11.16: + resolution: {integrity: sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ==} dependencies: undici-types: 5.26.5 @@ -4161,7 +4165,7 @@ packages: /@types/responselike@1.0.3: resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} dependencies: - '@types/node': 18.19.10 + '@types/node': 18.19.14 dev: false /@types/retry@0.12.0: @@ -4176,7 +4180,7 @@ packages: resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==} dependencies: '@types/mime': 1.3.5 - '@types/node': 20.11.10 + '@types/node': 20.11.16 dev: true /@types/serve-index@1.9.4: @@ -4190,13 +4194,17 @@ packages: dependencies: '@types/http-errors': 2.0.4 '@types/mime': 3.0.4 - '@types/node': 20.11.10 + '@types/node': 20.11.16 dev: true /@types/sockjs@0.3.36: resolution: {integrity: sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==} dependencies: - '@types/node': 20.11.10 + '@types/node': 20.11.16 + dev: true + + /@types/speakingurl@13.0.6: + resolution: {integrity: sha512-ywkRHNHBwq0mFs/2HRgW6TEBAzH66G8f2Txzh1aGR0UC9ZoAUHfHxLZGDhwMpck4BpSnB61eNFIFmlV+TJ+KUA==} dev: true /@types/splitpanes@2.2.6: @@ -4215,22 +4223,22 @@ packages: /@types/ws@8.5.10: resolution: {integrity: sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==} dependencies: - '@types/node': 20.11.10 + '@types/node': 20.11.16 dev: true /@types/yauzl@2.10.3: resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} requiresBuild: true dependencies: - '@types/node': 18.19.10 + '@types/node': 18.19.14 dev: false optional: true /@types/yoga-layout@1.9.2: resolution: {integrity: sha512-S9q47ByT2pPvD65IvrWp7qppVMpk9WGMbVq9wbWZOHg6tnXSD4vyhao6nOSBwwfDdV2p3Kx9evA9vI+XWTfDvw==} - /@typescript-eslint/eslint-plugin@6.19.1(@typescript-eslint/parser@6.19.1)(eslint-ts-patch@8.55.0-1)(typescript@5.3.3): - resolution: {integrity: sha512-roQScUGFruWod9CEyoV5KlCYrubC/fvG8/1zXuT0WTcxX87GnMMmnksMwSg99lo1xiKrBzw2icsJPMAw1OtKxg==} + /@typescript-eslint/eslint-plugin@6.20.0(@typescript-eslint/parser@6.20.0)(eslint-ts-patch@8.55.0-1)(typescript@5.3.3): + resolution: {integrity: sha512-fTwGQUnjhoYHeSF6m5pWNkzmDDdsKELYrOBxhjMrofPqCkoC2k3B2wvGHFxa1CTIqkEn88nlW1HVMztjo2K8Hg==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha @@ -4241,11 +4249,11 @@ packages: optional: true dependencies: '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 6.19.1(eslint-ts-patch@8.55.0-1)(typescript@5.3.3) - '@typescript-eslint/scope-manager': 6.19.1 - '@typescript-eslint/type-utils': 6.19.1(eslint-ts-patch@8.55.0-1)(typescript@5.3.3) - '@typescript-eslint/utils': 6.19.1(eslint-ts-patch@8.55.0-1)(typescript@5.3.3) - '@typescript-eslint/visitor-keys': 6.19.1 + '@typescript-eslint/parser': 6.20.0(eslint-ts-patch@8.55.0-1)(typescript@5.3.3) + '@typescript-eslint/scope-manager': 6.20.0 + '@typescript-eslint/type-utils': 6.20.0(eslint-ts-patch@8.55.0-1)(typescript@5.3.3) + '@typescript-eslint/utils': 6.20.0(eslint-ts-patch@8.55.0-1)(typescript@5.3.3) + '@typescript-eslint/visitor-keys': 6.20.0 debug: 4.3.4 eslint: /eslint-ts-patch@8.55.0-1 graphemer: 1.4.0 @@ -4258,8 +4266,8 @@ packages: - supports-color dev: true - /@typescript-eslint/parser@6.19.1(eslint-ts-patch@8.55.0-1)(typescript@5.3.3): - resolution: {integrity: sha512-WEfX22ziAh6pRE9jnbkkLGp/4RhTpffr2ZK5bJ18M8mIfA8A+k97U9ZyaXCEJRlmMHh7R9MJZWXp/r73DzINVQ==} + /@typescript-eslint/parser@6.20.0(eslint-ts-patch@8.55.0-1)(typescript@5.3.3): + resolution: {integrity: sha512-bYerPDF/H5v6V76MdMYhjwmwgMA+jlPVqjSDq2cRqMi8bP5sR3Z+RLOiOMad3nsnmDVmn2gAFCyNgh/dIrfP/w==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -4268,10 +4276,10 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 6.19.1 - '@typescript-eslint/types': 6.19.1 - '@typescript-eslint/typescript-estree': 6.19.1(typescript@5.3.3) - '@typescript-eslint/visitor-keys': 6.19.1 + '@typescript-eslint/scope-manager': 6.20.0 + '@typescript-eslint/types': 6.20.0 + '@typescript-eslint/typescript-estree': 6.20.0(typescript@5.3.3) + '@typescript-eslint/visitor-keys': 6.20.0 debug: 4.3.4 eslint: /eslint-ts-patch@8.55.0-1 typescript: 5.3.3 @@ -4287,16 +4295,16 @@ packages: '@typescript-eslint/visitor-keys': 6.16.0 dev: true - /@typescript-eslint/scope-manager@6.19.1: - resolution: {integrity: sha512-4CdXYjKf6/6aKNMSly/BP4iCSOpvMmqtDzRtqFyyAae3z5kkqEjKndR5vDHL8rSuMIIWP8u4Mw4VxLyxZW6D5w==} + /@typescript-eslint/scope-manager@6.20.0: + resolution: {integrity: sha512-p4rvHQRDTI1tGGMDFQm+GtxP1ZHyAh64WANVoyEcNMpaTFn3ox/3CcgtIlELnRfKzSs/DwYlDccJEtr3O6qBvA==} engines: {node: ^16.0.0 || >=18.0.0} dependencies: - '@typescript-eslint/types': 6.19.1 - '@typescript-eslint/visitor-keys': 6.19.1 + '@typescript-eslint/types': 6.20.0 + '@typescript-eslint/visitor-keys': 6.20.0 dev: true - /@typescript-eslint/type-utils@6.19.1(eslint-ts-patch@8.55.0-1)(typescript@5.3.3): - resolution: {integrity: sha512-0vdyld3ecfxJuddDjACUvlAeYNrHP/pDeQk2pWBR2ESeEzQhg52DF53AbI9QCBkYE23lgkhLCZNkHn2hEXXYIg==} + /@typescript-eslint/type-utils@6.20.0(eslint-ts-patch@8.55.0-1)(typescript@5.3.3): + resolution: {integrity: sha512-qnSobiJQb1F5JjN0YDRPHruQTrX7ICsmltXhkV536mp4idGAYrIyr47zF/JmkJtEcAVnIz4gUYJ7gOZa6SmN4g==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -4305,8 +4313,8 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 6.19.1(typescript@5.3.3) - '@typescript-eslint/utils': 6.19.1(eslint-ts-patch@8.55.0-1)(typescript@5.3.3) + '@typescript-eslint/typescript-estree': 6.20.0(typescript@5.3.3) + '@typescript-eslint/utils': 6.20.0(eslint-ts-patch@8.55.0-1)(typescript@5.3.3) debug: 4.3.4 eslint: /eslint-ts-patch@8.55.0-1 ts-api-utils: 1.0.3(typescript@5.3.3) @@ -4320,8 +4328,8 @@ packages: engines: {node: ^16.0.0 || >=18.0.0} dev: true - /@typescript-eslint/types@6.19.1: - resolution: {integrity: sha512-6+bk6FEtBhvfYvpHsDgAL3uo4BfvnTnoge5LrrCj2eJN8g3IJdLTD4B/jK3Q6vo4Ql/Hoip9I8aB6fF+6RfDqg==} + /@typescript-eslint/types@6.20.0: + resolution: {integrity: sha512-MM9mfZMAhiN4cOEcUOEx+0HmuaW3WBfukBZPCfwSqFnQy0grXYtngKCqpQN339X3RrwtzspWJrpbrupKYUSBXQ==} engines: {node: ^16.0.0 || >=18.0.0} dev: true @@ -4347,8 +4355,8 @@ packages: - supports-color dev: true - /@typescript-eslint/typescript-estree@6.19.1(typescript@5.3.3): - resolution: {integrity: sha512-aFdAxuhzBFRWhy+H20nYu19+Km+gFfwNO4TEqyszkMcgBDYQjmPJ61erHxuT2ESJXhlhrO7I5EFIlZ+qGR8oVA==} + /@typescript-eslint/typescript-estree@6.20.0(typescript@5.3.3): + resolution: {integrity: sha512-RnRya9q5m6YYSpBN7IzKu9FmLcYtErkDkc8/dKv81I9QiLLtVBHrjz+Ev/crAqgMNW2FCsoZF4g2QUylMnJz+g==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: typescript: '*' @@ -4356,8 +4364,8 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/types': 6.19.1 - '@typescript-eslint/visitor-keys': 6.19.1 + '@typescript-eslint/types': 6.20.0 + '@typescript-eslint/visitor-keys': 6.20.0 debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 @@ -4388,8 +4396,8 @@ packages: - typescript dev: true - /@typescript-eslint/utils@6.19.1(eslint-ts-patch@8.55.0-1)(typescript@5.3.3): - resolution: {integrity: sha512-JvjfEZuP5WoMqwh9SPAPDSHSg9FBHHGhjPugSRxu5jMfjvBpq5/sGTD+9M9aQ5sh6iJ8AY/Kk/oUYVEMAPwi7w==} + /@typescript-eslint/utils@6.20.0(eslint-ts-patch@8.55.0-1)(typescript@5.3.3): + resolution: {integrity: sha512-/EKuw+kRu2vAqCoDwDCBtDRU6CTKbUmwwI7SH7AashZ+W+7o8eiyy6V2cdOqN49KsTcASWsC5QeghYuRDTyOOg==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -4397,9 +4405,9 @@ packages: '@eslint-community/eslint-utils': 4.4.0(eslint-ts-patch@8.55.0-1) '@types/json-schema': 7.0.15 '@types/semver': 7.5.6 - '@typescript-eslint/scope-manager': 6.19.1 - '@typescript-eslint/types': 6.19.1 - '@typescript-eslint/typescript-estree': 6.19.1(typescript@5.3.3) + '@typescript-eslint/scope-manager': 6.20.0 + '@typescript-eslint/types': 6.20.0 + '@typescript-eslint/typescript-estree': 6.20.0(typescript@5.3.3) eslint: /eslint-ts-patch@8.55.0-1 semver: 7.5.4 transitivePeerDependencies: @@ -4415,11 +4423,11 @@ packages: eslint-visitor-keys: 3.4.3 dev: true - /@typescript-eslint/visitor-keys@6.19.1: - resolution: {integrity: sha512-gkdtIO+xSO/SmI0W68DBg4u1KElmIUo3vXzgHyGPs6cxgB0sa3TlptRAAE0hUY1hM6FcDKEv7aIwiTGm76cXfQ==} + /@typescript-eslint/visitor-keys@6.20.0: + resolution: {integrity: sha512-E8Cp98kRe4gKHjJD4NExXKz/zOJ1A2hhZc+IMVD6i7w4yjIvh6VyuRI0gRtxAsXtoC35uGMaQ9rjI2zJaXDEAw==} engines: {node: ^16.0.0 || >=18.0.0} dependencies: - '@typescript-eslint/types': 6.19.1 + '@typescript-eslint/types': 6.20.0 eslint-visitor-keys: 3.4.3 dev: true @@ -4438,7 +4446,7 @@ packages: '@unocss/core': 0.58.4 '@unocss/reset': 0.58.4 '@unocss/vite': 0.58.4(rollup@3.28.1)(vite@5.0.12) - vite: 5.0.12(@types/node@20.11.10)(sass@1.70.0) + vite: 5.0.12(@types/node@20.11.16)(sass@1.70.0) transitivePeerDependencies: - rollup @@ -4477,7 +4485,7 @@ packages: resolution: {integrity: sha512-wWXqs4+MbgqVgkpSqenO9QRxxixL7dA3U/tVgz6q7CwhmKc0fczEpYd04TUR2oLYhl9fnj15UcYNGdG+GCNt0Q==} engines: {node: '>=14'} dependencies: - '@typescript-eslint/utils': 6.19.1(eslint-ts-patch@8.55.0-1)(typescript@5.3.3) + '@typescript-eslint/utils': 6.20.0(eslint-ts-patch@8.55.0-1)(typescript@5.3.3) '@unocss/config': 0.58.4 '@unocss/core': 0.58.4 magic-string: 0.30.5 @@ -4636,7 +4644,7 @@ packages: chokidar: 3.5.3 fast-glob: 3.3.2 magic-string: 0.30.5 - vite: 5.0.12(@types/node@20.11.10)(sass@1.70.0) + vite: 5.0.12(@types/node@20.11.16)(sass@1.70.0) transitivePeerDependencies: - rollup @@ -4650,7 +4658,7 @@ packages: '@babel/core': 7.23.6 '@babel/plugin-transform-typescript': 7.23.5(@babel/core@7.23.6) '@vue/babel-plugin-jsx': 1.1.5(@babel/core@7.23.6) - vite: 5.0.12(@types/node@20.11.10)(sass@1.70.0) + vite: 5.0.12(@types/node@20.11.16)(sass@1.70.0) vue: 3.4.15(typescript@5.3.3) transitivePeerDependencies: - supports-color @@ -4663,7 +4671,7 @@ packages: vite: ^5.0.0 vue: ^3.2.25 dependencies: - vite: 5.0.12(@types/node@20.11.10)(sass@1.70.0) + vite: 5.0.12(@types/node@20.11.16)(sass@1.70.0) vue: 3.4.0(typescript@5.3.3) dev: true @@ -4674,7 +4682,7 @@ packages: vite: ^5.0.0 vue: ^3.2.25 dependencies: - vite: 5.0.12(@types/node@20.11.10)(sass@1.70.0) + vite: 5.0.12(@types/node@20.11.16)(sass@1.70.0) vue: 3.4.15(typescript@5.3.3) dev: true @@ -4736,7 +4744,7 @@ packages: path-browserify: 1.0.1 dev: true - /@vue-termui/cli@0.0.17(@types/node@18.19.10)(vite-plugin-vue-termui@0.0.12)(vite@5.0.12)(vue-termui@0.0.19): + /@vue-termui/cli@0.0.17(@types/node@18.19.14)(vite-plugin-vue-termui@0.0.12)(vite@5.0.12)(vue-termui@0.0.19): resolution: {integrity: sha512-VkY7OVb/UVhHMP6exAwidnb+HgC1/PHdvXJxXrpTOparNI59sD6ByLv5F3MDcx6mCKbkMVAE5P1syTFF88vJNg==} engines: {node: '>=14.0.0'} hasBin: true @@ -4746,8 +4754,8 @@ packages: vue-termui: '>=0.0.14' dependencies: picocolors: 1.0.0 - vite: 5.0.12(@types/node@18.19.10) - vite-node: 0.24.5(@types/node@18.19.10) + vite: 5.0.12(@types/node@18.19.14) + vite-node: 0.24.5(@types/node@18.19.14) vite-plugin-vue-termui: 0.0.12(@vitejs/plugin-vue@5.0.3)(unplugin-auto-import@0.17.5)(unplugin-vue-components@0.26.0)(vue-termui@0.0.19)(vue@3.4.15) vue-termui: 0.0.19(@vue/runtime-core@3.4.15) ws: 8.14.2 @@ -4779,7 +4787,7 @@ packages: '@babel/helper-module-imports': 7.22.15 '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.23.6) '@babel/template': 7.22.15 - '@babel/traverse': 7.23.7 + '@babel/traverse': 7.23.6 '@babel/types': 7.23.6 '@vue/babel-helper-vue-transform-on': 1.1.5 camelcase: 6.3.0 @@ -4797,7 +4805,7 @@ packages: '@babel/helper-module-imports': 7.22.15 '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.23.9) '@babel/template': 7.22.15 - '@babel/traverse': 7.23.7 + '@babel/traverse': 7.23.6 '@babel/types': 7.23.6 '@vue/babel-helper-vue-transform-on': 1.1.5 camelcase: 6.3.0 @@ -5197,16 +5205,6 @@ packages: estree-walker: 2.0.2 source-map-js: 1.0.2 - /@vue/compiler-core@3.4.4: - resolution: {integrity: sha512-U5AdCN+6skzh2bSJrkMj2KZsVkUpgK8/XlxjSRYQZhNPcvt9/kmgIMpFEiTyK+Dz5E1J+8o8//BEIX+bakgVSw==} - dependencies: - '@babel/parser': 7.23.6 - '@vue/shared': 3.4.4 - entities: 4.5.0 - estree-walker: 2.0.2 - source-map-js: 1.0.2 - dev: true - /@vue/compiler-dom@3.4.0: resolution: {integrity: sha512-E957uOhpoE48YjZGWeAoLmNYd3UeU4oIP8kJi8Rcsb9l2tV8Z48Jn07Zgq1aW0v3vuhlmydEKkKKbhLpADHXEA==} dependencies: @@ -5219,13 +5217,6 @@ packages: '@vue/compiler-core': 3.4.15 '@vue/shared': 3.4.15 - /@vue/compiler-dom@3.4.4: - resolution: {integrity: sha512-iSwkdDULCN+Vr8z6uwdlL044GJ/nUmECxP9vu7MzEs4Qma0FwDLYvnvRcyO0ZITuu3Os4FptGUDnhi1kOLSaGw==} - dependencies: - '@vue/compiler-core': 3.4.4 - '@vue/shared': 3.4.4 - dev: true - /@vue/compiler-sfc@2.7.15: resolution: {integrity: sha512-FCvIEevPmgCgqFBH7wD+3B97y7u7oj/Wr69zADBf403Tui377bThTjBvekaZvlRr4IwUAu3M6hYZeULZFJbdYg==} dependencies: @@ -5244,7 +5235,7 @@ packages: '@vue/shared': 3.4.0 estree-walker: 2.0.2 magic-string: 0.30.5 - postcss: 8.4.33 + postcss: 8.4.32 source-map-js: 1.0.2 /@vue/compiler-sfc@3.4.15: @@ -5260,20 +5251,6 @@ packages: postcss: 8.4.33 source-map-js: 1.0.2 - /@vue/compiler-sfc@3.4.4: - resolution: {integrity: sha512-OTFcU6vUxUNHBcarzkp4g6d25nvcmDvFDzPRvSrIsByFFPRYN+y3b+j9HxYwt6nlWvGyFCe0roeJdJlfYxbCBg==} - dependencies: - '@babel/parser': 7.23.6 - '@vue/compiler-core': 3.4.4 - '@vue/compiler-dom': 3.4.4 - '@vue/compiler-ssr': 3.4.4 - '@vue/shared': 3.4.4 - estree-walker: 2.0.2 - magic-string: 0.30.5 - postcss: 8.4.33 - source-map-js: 1.0.2 - dev: true - /@vue/compiler-ssr@3.4.0: resolution: {integrity: sha512-+oXKy105g9DIYQKDi3Gwung0xqQX5gJHr0GR+Vf7yK/WkNDM6q61ummcKmKAB85EIst8y3vj2PA9z9YU5Oc4DQ==} dependencies: @@ -5286,13 +5263,6 @@ packages: '@vue/compiler-dom': 3.4.15 '@vue/shared': 3.4.15 - /@vue/compiler-ssr@3.4.4: - resolution: {integrity: sha512-1DU9DflSSQlx/M61GEBN+NbT/anUki2ooDo9IXfTckCeKA/2IKNhY8KbG3x6zkd3KGrxzteC7de6QL88vEb41Q==} - dependencies: - '@vue/compiler-dom': 3.4.4 - '@vue/shared': 3.4.4 - dev: true - /@vue/component-compiler-utils@3.3.0: resolution: {integrity: sha512-97sfH2mYNU+2PzGrmK2haqffDpVASuib9/w2/noxiFi31Z54hW+q3izKQXXQZSNhtiUpAI36uSuYepeBe4wpHQ==} dependencies: @@ -5445,8 +5415,18 @@ packages: /@vue/shared@3.4.15: resolution: {integrity: sha512-KzfPTxVaWfB+eGcGdbSf4CWdaXcGDqckoeXUh7SB3fZdEtzPCK2Vq9B/lRRL3yutax/LWITz+SwvgyOxz5V75g==} - /@vue/shared@3.4.4: - resolution: {integrity: sha512-abSgiVRhfjfl3JALR/cSuBl74hGJ3SePgf1mKzodf1eMWLwHZbfEGxT2cNJSsNiw44jEgrO7bNkhchaWA7RwNw==} + /@vue/test-utils@2.4.4(vue@3.4.15): + resolution: {integrity: sha512-8jkRxz8pNhClAf4Co4ZrpAoFISdvT3nuSkUlY6Ys6rmTpw3DMWG/X3mw3gQ7QJzgCZO9f+zuE2kW57fi09MW7Q==} + peerDependencies: + '@vue/server-renderer': ^3.0.1 + vue: ^3.0.1 + peerDependenciesMeta: + '@vue/server-renderer': + optional: true + dependencies: + js-beautify: 1.14.11 + vue: 3.4.15(typescript@5.3.3) + vue-component-type-helpers: 1.8.27 dev: true /@vue/web-component-wrapper@1.3.0: @@ -6894,6 +6874,13 @@ packages: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} dev: true + /config-chain@1.1.13: + resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} + dependencies: + ini: 1.3.8 + proto-list: 1.2.4 + dev: true + /connect-history-api-fallback@2.0.0: resolution: {integrity: sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==} engines: {node: '>=0.8'} @@ -7471,6 +7458,13 @@ packages: cssom: 0.3.8 dev: true + /cssstyle@4.0.1: + resolution: {integrity: sha512-8ZYiJ3A/3OkDd093CBT/0UKDWry7ak4BdPTFP2+QEP7cmhouyq/Up709ASSj2cK02BbZiMgk7kYjZNS4QP5qrQ==} + engines: {node: '>=18'} + dependencies: + rrweb-cssom: 0.6.0 + dev: true + /csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} @@ -7483,6 +7477,14 @@ packages: whatwg-url: 11.0.0 dev: true + /data-urls@5.0.0: + resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} + engines: {node: '>=18'} + dependencies: + whatwg-mimetype: 4.0.0 + whatwg-url: 14.0.0 + dev: true + /dayjs@1.11.10: resolution: {integrity: sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==} dev: true @@ -7767,6 +7769,17 @@ packages: engines: {node: '>=6.0.0'} dev: true + /editorconfig@1.0.4: + resolution: {integrity: sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==} + engines: {node: '>=14'} + hasBin: true + dependencies: + '@one-ini/wasm': 0.1.1 + commander: 10.0.1 + minimatch: 9.0.1 + semver: 7.5.4 + dev: true + /ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} dev: true @@ -7781,7 +7794,7 @@ packages: requiresBuild: true dependencies: '@electron/get': 2.0.3 - '@types/node': 18.19.10 + '@types/node': 18.19.14 extract-zip: 2.0.1 transitivePeerDependencies: - supports-color @@ -7850,7 +7863,7 @@ packages: dependencies: '@types/cookie': 0.4.1 '@types/cors': 2.8.17 - '@types/node': 20.11.10 + '@types/node': 20.11.16 accepts: 1.3.8 base64id: 2.0.0 cookie: 0.4.2 @@ -8268,7 +8281,7 @@ packages: eslint: /eslint-ts-patch@8.55.0-1 dev: true - /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.19.1)(eslint-import-resolver-node@0.3.9)(eslint-ts-patch@8.55.0-1): + /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.20.0)(eslint-import-resolver-node@0.3.9)(eslint-ts-patch@8.55.0-1): resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} engines: {node: '>=4'} peerDependencies: @@ -8289,7 +8302,7 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 6.19.1(eslint-ts-patch@8.55.0-1)(typescript@5.3.3) + '@typescript-eslint/parser': 6.20.0(eslint-ts-patch@8.55.0-1)(typescript@5.3.3) debug: 3.2.7 eslint: /eslint-ts-patch@8.55.0-1 eslint-import-resolver-node: 0.3.9 @@ -8347,7 +8360,7 @@ packages: synckit: 0.8.8 dev: true - /eslint-plugin-i@2.29.1(@typescript-eslint/parser@6.19.1)(eslint-ts-patch@8.55.0-1): + /eslint-plugin-i@2.29.1(@typescript-eslint/parser@6.20.0)(eslint-ts-patch@8.55.0-1): resolution: {integrity: sha512-ORizX37MelIWLbMyqI7hi8VJMf7A0CskMmYkB+lkCX3aF4pkGV7kwx5bSEb4qx7Yce2rAf9s34HqDRPjGRZPNQ==} engines: {node: '>=12'} peerDependencies: @@ -8357,7 +8370,7 @@ packages: doctrine: 3.0.0 eslint: /eslint-ts-patch@8.55.0-1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.19.1)(eslint-import-resolver-node@0.3.9)(eslint-ts-patch@8.55.0-1) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.20.0)(eslint-import-resolver-node@0.3.9)(eslint-ts-patch@8.55.0-1) get-tsconfig: 4.7.2 is-glob: 4.0.3 minimatch: 3.1.2 @@ -8512,7 +8525,7 @@ packages: - supports-color dev: true - /eslint-plugin-unused-imports@3.0.0(@typescript-eslint/eslint-plugin@6.19.1)(eslint-ts-patch@8.55.0-1): + /eslint-plugin-unused-imports@3.0.0(@typescript-eslint/eslint-plugin@6.20.0)(eslint-ts-patch@8.55.0-1): resolution: {integrity: sha512-sduiswLJfZHeeBJ+MQaG+xYzSWdRXoSw61DpU13mzWumCkR0ufD0HmO4kdNokjrkluMHpj/7PJeN35pgbhW3kw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -8522,13 +8535,13 @@ packages: '@typescript-eslint/eslint-plugin': optional: true dependencies: - '@typescript-eslint/eslint-plugin': 6.19.1(@typescript-eslint/parser@6.19.1)(eslint-ts-patch@8.55.0-1)(typescript@5.3.3) + '@typescript-eslint/eslint-plugin': 6.20.0(@typescript-eslint/parser@6.20.0)(eslint-ts-patch@8.55.0-1)(typescript@5.3.3) eslint: /eslint-ts-patch@8.55.0-1 eslint-rule-composer: 0.3.0 dev: true - /eslint-plugin-vitest@0.3.20(@typescript-eslint/eslint-plugin@6.19.1)(eslint-ts-patch@8.55.0-1)(typescript@5.3.3)(vitest@1.2.2): - resolution: {integrity: sha512-O05k4j9TGMOkkghj9dRgpeLDyOSiVIxQWgNDPfhYPm5ioJsehcYV/zkRLekQs+c8+RBCVXucSED3fYOyy2EoWA==} + /eslint-plugin-vitest@0.3.21(@typescript-eslint/eslint-plugin@6.20.0)(eslint-ts-patch@8.55.0-1)(typescript@5.3.3)(vitest@1.2.2): + resolution: {integrity: sha512-oYwR1MrwaBw/OG6CKU+SJYleAc442w6CWL1RTQl5WLwy8X3sh0bgHIQk5iEtmTak3Q+XAvZglr0bIoDOjFdkcw==} engines: {node: ^18.0.0 || >= 20.0.0} peerDependencies: '@typescript-eslint/eslint-plugin': '*' @@ -8540,10 +8553,10 @@ packages: vitest: optional: true dependencies: - '@typescript-eslint/eslint-plugin': 6.19.1(@typescript-eslint/parser@6.19.1)(eslint-ts-patch@8.55.0-1)(typescript@5.3.3) - '@typescript-eslint/utils': 6.16.0(eslint-ts-patch@8.55.0-1)(typescript@5.3.3) + '@typescript-eslint/eslint-plugin': 6.20.0(@typescript-eslint/parser@6.20.0)(eslint-ts-patch@8.55.0-1)(typescript@5.3.3) + '@typescript-eslint/utils': 6.20.0(eslint-ts-patch@8.55.0-1)(typescript@5.3.3) eslint: /eslint-ts-patch@8.55.0-1 - vitest: 1.2.2(@types/node@20.11.10) + vitest: 1.2.2(@types/node@20.11.16)(jsdom@24.0.0) transitivePeerDependencies: - supports-color - typescript @@ -9528,7 +9541,7 @@ packages: resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} dev: true - /histoire@0.17.9(@types/node@20.11.10)(vite@5.0.12): + /histoire@0.17.9(@types/node@20.11.16)(vite@5.0.12): resolution: {integrity: sha512-z5Jb9QwbOw0TKvpkU0v7+CxJG6hIljIKMhWXzOfteteRZGDFElpTEwbr5/8EdPI6VTdF/k76fqZ07nmS9YdUvA==} hasBin: true peerDependencies: @@ -9564,8 +9577,8 @@ packages: sade: 1.8.1 shiki-es: 0.2.0 sirv: 2.0.4 - vite: 5.0.12(@types/node@20.11.10)(sass@1.70.0) - vite-node: 0.34.6(@types/node@20.11.10) + vite: 5.0.12(@types/node@20.11.16)(sass@1.70.0) + vite-node: 0.34.6(@types/node@20.11.16) transitivePeerDependencies: - '@types/node' - bufferutil @@ -9610,6 +9623,13 @@ packages: whatwg-encoding: 2.0.0 dev: true + /html-encoding-sniffer@4.0.0: + resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} + engines: {node: '>=18'} + dependencies: + whatwg-encoding: 3.1.1 + dev: true + /html-entities@2.4.0: resolution: {integrity: sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ==} dev: true @@ -10142,7 +10162,7 @@ packages: resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} engines: {node: '>= 10.13.0'} dependencies: - '@types/node': 20.11.10 + '@types/node': 20.11.16 merge-stream: 2.0.0 supports-color: 8.1.1 dev: true @@ -10151,7 +10171,7 @@ packages: resolution: {integrity: sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} dependencies: - '@types/node': 20.11.10 + '@types/node': 20.11.16 merge-stream: 2.0.0 supports-color: 8.1.1 dev: true @@ -10179,6 +10199,17 @@ packages: engines: {node: '>=10'} dev: true + /js-beautify@1.14.11: + resolution: {integrity: sha512-rPogWqAfoYh1Ryqqh2agUpVfbxAhbjuN1SmU86dskQUKouRiggUTCO4+2ym9UPXllc2WAp0J+T5qxn7Um3lCdw==} + engines: {node: '>=14'} + hasBin: true + dependencies: + config-chain: 1.1.13 + editorconfig: 1.0.4 + glob: 10.3.10 + nopt: 7.2.0 + dev: true + /js-message@1.0.7: resolution: {integrity: sha512-efJLHhLjIyKRewNS9EGZ4UpI8NguuL6fKkhRxVuMmrGV2xN/0APGdQYwLFky5w9naebSZ0OwAGp0G6/2Cg90rA==} engines: {node: '>=0.6.0'} @@ -10240,7 +10271,7 @@ packages: whatwg-encoding: 2.0.0 whatwg-mimetype: 3.0.0 whatwg-url: 11.0.0 - ws: 8.14.2 + ws: 8.16.0 xml-name-validator: 4.0.0 transitivePeerDependencies: - bufferutil @@ -10248,6 +10279,42 @@ packages: - utf-8-validate dev: true + /jsdom@24.0.0: + resolution: {integrity: sha512-UDS2NayCvmXSXVP6mpTj+73JnNQadZlr9N68189xib2tx5Mls7swlTNao26IoHv46BZJFvXygyRtyXd1feAk1A==} + engines: {node: '>=18'} + peerDependencies: + canvas: ^2.11.2 + peerDependenciesMeta: + canvas: + optional: true + dependencies: + cssstyle: 4.0.1 + data-urls: 5.0.0 + decimal.js: 10.4.3 + form-data: 4.0.0 + html-encoding-sniffer: 4.0.0 + http-proxy-agent: 7.0.0 + https-proxy-agent: 7.0.2 + is-potential-custom-element-name: 1.0.1 + nwsapi: 2.2.7 + parse5: 7.1.2 + rrweb-cssom: 0.6.0 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 4.1.3 + w3c-xmlserializer: 5.0.0 + webidl-conversions: 7.0.0 + whatwg-encoding: 3.1.1 + whatwg-mimetype: 4.0.0 + whatwg-url: 14.0.0 + ws: 8.16.0 + xml-name-validator: 5.0.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: true + /jsesc@0.5.0: resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==} hasBin: true @@ -10889,6 +10956,13 @@ packages: brace-expansion: 2.0.1 dev: true + /minimatch@9.0.1: + resolution: {integrity: sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + brace-expansion: 2.0.1 + dev: true + /minimatch@9.0.3: resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} engines: {node: '>=16 || 14 >=14.17'} @@ -11788,8 +11862,8 @@ packages: engines: {node: '>=4'} dev: true - /pnpm@8.15.0: - resolution: {integrity: sha512-6kVRfVKF0SPqwCw3k1Bfof1tqQovxg0ejZ4MHpKSiG7Pr/UT8GK50cyAIbuGFQM7GsW+o7LuP8FlptcDS75rAw==} + /pnpm@8.15.1: + resolution: {integrity: sha512-gxz0xfi4N0r3FSHU0VPbSdcIbeYVwq98tenX64umMN2sRv6kldZD5VLvLmijqpmj5en77oaWcClnUE31xZyycw==} engines: {node: '>=16.14'} hasBin: true dev: true @@ -12578,6 +12652,10 @@ packages: sisteransi: 1.0.5 dev: true + /proto-list@1.2.4: + resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} + dev: true + /proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} @@ -13019,6 +13097,10 @@ packages: '@rollup/rollup-win32-x64-msvc': 4.7.0 fsevents: 2.3.3 + /rrweb-cssom@0.6.0: + resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==} + dev: true + /run-applescript@7.0.0: resolution: {integrity: sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==} engines: {node: '>=18'} @@ -14071,6 +14153,13 @@ packages: punycode: 2.3.1 dev: true + /tr46@5.0.0: + resolution: {integrity: sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==} + engines: {node: '>=18'} + dependencies: + punycode: 2.3.1 + dev: true + /tree-kill@1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true @@ -14403,7 +14492,7 @@ packages: '@unocss/transformer-directives': 0.58.4 '@unocss/transformer-variant-group': 0.58.4 '@unocss/vite': 0.58.4(rollup@3.28.1)(vite@5.0.12) - vite: 5.0.12(@types/node@20.11.10)(sass@1.70.0) + vite: 5.0.12(@types/node@20.11.16)(sass@1.70.0) transitivePeerDependencies: - postcss - rollup @@ -14625,7 +14714,7 @@ packages: vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 dependencies: birpc: 0.2.15 - vite: 5.0.12(@types/node@20.11.10)(sass@1.70.0) + vite: 5.0.12(@types/node@20.11.16)(sass@1.70.0) vite-hot-client: 0.2.3(vite@5.0.12) dev: false @@ -14634,10 +14723,10 @@ packages: peerDependencies: vite: ^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 dependencies: - vite: 5.0.12(@types/node@20.11.10)(sass@1.70.0) + vite: 5.0.12(@types/node@20.11.16)(sass@1.70.0) dev: false - /vite-node@0.24.5(@types/node@18.19.10): + /vite-node@0.24.5(@types/node@18.19.14): resolution: {integrity: sha512-+xnJaYu1i+2eCsycRO2QF1vxne13b2nL6nF+O8EzdF/X+ohPujysjwij3ZbX3AZ+j8HWYzjlRlKPdlHVyaNzwQ==} engines: {node: '>=v14.16.0'} hasBin: true @@ -14645,7 +14734,7 @@ packages: debug: 4.3.4 mlly: 0.5.17 pathe: 0.2.0 - vite: 3.2.7(@types/node@18.19.10) + vite: 3.2.7(@types/node@18.19.14) transitivePeerDependencies: - '@types/node' - less @@ -14656,7 +14745,7 @@ packages: - terser dev: true - /vite-node@0.34.6(@types/node@20.11.10): + /vite-node@0.34.6(@types/node@20.11.16): resolution: {integrity: sha512-nlBMJ9x6n7/Amaz6F3zJ97EBwR2FkzhBRxF5e+jE6LA3yi6Wtc2lyTij1OnDMIr34v5g/tVQtsVAzhT0jc5ygA==} engines: {node: '>=v14.18.0'} hasBin: true @@ -14666,7 +14755,7 @@ packages: mlly: 1.4.2 pathe: 1.1.2 picocolors: 1.0.0 - vite: 5.0.12(@types/node@20.11.10)(sass@1.70.0) + vite: 5.0.12(@types/node@20.11.16)(sass@1.70.0) transitivePeerDependencies: - '@types/node' - less @@ -14678,7 +14767,7 @@ packages: - terser dev: true - /vite-node@1.2.2(@types/node@20.11.10): + /vite-node@1.2.2(@types/node@20.11.16): resolution: {integrity: sha512-1as4rDTgVWJO3n1uHmUYqq7nsFgINQ9u+mRcXpjeOMJUmviqNKjcZB7UfRZrlM7MjYXMKpuWp5oGkjaFLnjawg==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -14687,7 +14776,7 @@ packages: debug: 4.3.4 pathe: 1.1.2 picocolors: 1.0.0 - vite: 5.0.12(@types/node@20.11.10)(sass@1.70.0) + vite: 5.0.12(@types/node@20.11.16)(sass@1.70.0) transitivePeerDependencies: - '@types/node' - less @@ -14699,7 +14788,7 @@ packages: - terser dev: true - /vite-plugin-dts@3.7.2(@types/node@20.11.10)(rollup@3.28.1)(typescript@5.3.3)(vite@5.0.12): + /vite-plugin-dts@3.7.2(@types/node@20.11.16)(rollup@3.28.1)(typescript@5.3.3)(vite@5.0.12): resolution: {integrity: sha512-kg//1nDA01b8rufJf4TsvYN8LMkdwv0oBYpiQi6nRwpHyue+wTlhrBiqgipdFpMnW1oOYv6ywmzE5B0vg6vSEA==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: @@ -14709,13 +14798,13 @@ packages: vite: optional: true dependencies: - '@microsoft/api-extractor': 7.39.0(@types/node@20.11.10) + '@microsoft/api-extractor': 7.39.0(@types/node@20.11.16) '@rollup/pluginutils': 5.1.0(rollup@3.28.1) '@vue/language-core': 1.8.27(typescript@5.3.3) debug: 4.3.4 kolorist: 1.8.0 typescript: 5.3.3 - vite: 5.0.12(@types/node@20.11.10)(sass@1.70.0) + vite: 5.0.12(@types/node@20.11.16)(sass@1.70.0) vue-tsc: 1.8.27(typescript@5.3.3) transitivePeerDependencies: - '@types/node' @@ -14742,7 +14831,7 @@ packages: perfect-debounce: 1.0.0 picocolors: 1.0.0 sirv: 2.0.4 - vite: 5.0.10(@types/node@20.11.10) + vite: 5.0.10(@types/node@20.11.16) transitivePeerDependencies: - rollup - supports-color @@ -14767,7 +14856,7 @@ packages: perfect-debounce: 1.0.0 picocolors: 1.0.0 sirv: 2.0.4 - vite: 5.0.12(@types/node@20.11.10)(sass@1.70.0) + vite: 5.0.12(@types/node@20.11.16)(sass@1.70.0) transitivePeerDependencies: - rollup - supports-color @@ -14786,7 +14875,7 @@ packages: '@vue/compiler-dom': 3.4.0 kolorist: 1.8.0 magic-string: 0.30.5 - vite: 5.0.10(@types/node@20.11.10) + vite: 5.0.10(@types/node@20.11.16) transitivePeerDependencies: - supports-color dev: false @@ -14807,7 +14896,7 @@ packages: vue-termui: 0.0.19(@vue/runtime-core@3.4.15) dev: true - /vite@3.2.7(@types/node@18.19.10): + /vite@3.2.7(@types/node@18.19.14): resolution: {integrity: sha512-29pdXjk49xAP0QBr0xXqu2s5jiQIXNvE/xwd0vUizYT2Hzqe4BksNNoWllFVXJf4eLZ+UlVQmXfB4lWrc+t18g==} engines: {node: ^14.18.0 || >=16.0.0} hasBin: true @@ -14832,7 +14921,7 @@ packages: terser: optional: true dependencies: - '@types/node': 18.19.10 + '@types/node': 18.19.14 esbuild: 0.15.18 postcss: 8.4.33 resolve: 1.22.8 @@ -14841,7 +14930,7 @@ packages: fsevents: 2.3.3 dev: true - /vite@5.0.10(@types/node@20.11.10): + /vite@5.0.10(@types/node@20.11.16): resolution: {integrity: sha512-2P8J7WWgmc355HUMlFrwofacvr98DAjoE52BfdbwQtyLH06XKwaL/FMnmKM2crF0iX4MpmMKoDlNCB1ok7zHCw==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -14869,7 +14958,7 @@ packages: terser: optional: true dependencies: - '@types/node': 20.11.10 + '@types/node': 20.11.16 esbuild: 0.19.10 postcss: 8.4.32 rollup: 4.7.0 @@ -14877,7 +14966,7 @@ packages: fsevents: 2.3.3 dev: false - /vite@5.0.12(@types/node@18.19.10): + /vite@5.0.12(@types/node@18.19.14): resolution: {integrity: sha512-4hsnEkG3q0N4Tzf1+t6NdN9dg/L3BM+q8SWgbSPnJvrgH2kgdyzfVJwbR1ic69/4uMJJ/3dqDZZE5/WwqW8U1w==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -14905,7 +14994,7 @@ packages: terser: optional: true dependencies: - '@types/node': 18.19.10 + '@types/node': 18.19.14 esbuild: 0.19.10 postcss: 8.4.33 rollup: 4.7.0 @@ -14913,7 +15002,7 @@ packages: fsevents: 2.3.3 dev: true - /vite@5.0.12(@types/node@20.11.10)(sass@1.70.0): + /vite@5.0.12(@types/node@20.11.16)(sass@1.70.0): resolution: {integrity: sha512-4hsnEkG3q0N4Tzf1+t6NdN9dg/L3BM+q8SWgbSPnJvrgH2kgdyzfVJwbR1ic69/4uMJJ/3dqDZZE5/WwqW8U1w==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -14941,7 +15030,7 @@ packages: terser: optional: true dependencies: - '@types/node': 20.11.10 + '@types/node': 20.11.16 esbuild: 0.19.10 postcss: 8.4.33 rollup: 4.7.0 @@ -14949,7 +15038,7 @@ packages: optionalDependencies: fsevents: 2.3.3 - /vitepress@1.0.0-rc.40(@algolia/client-search@4.22.0)(@types/node@20.11.10)(postcss@8.4.33)(search-insights@2.13.0)(typescript@5.3.3): + /vitepress@1.0.0-rc.40(@algolia/client-search@4.22.0)(@types/node@20.11.16)(postcss@8.4.33)(search-insights@2.13.0)(typescript@5.3.3): resolution: {integrity: sha512-1x9PCrcsJwqhpccyTR93uD6jpiPDeRC98CBCAQLLBb44a3VSXYBPzhCahi+2kwAYylu49p0XhseMPVM4IVcWcw==} hasBin: true peerDependencies: @@ -14975,7 +15064,7 @@ packages: shikiji: 0.10.2 shikiji-core: 0.10.2 shikiji-transformers: 0.10.2 - vite: 5.0.12(@types/node@20.11.10)(sass@1.70.0) + vite: 5.0.12(@types/node@20.11.16)(sass@1.70.0) vue: 3.4.15(typescript@5.3.3) transitivePeerDependencies: - '@algolia/client-search' @@ -15005,7 +15094,7 @@ packages: - universal-cookie dev: true - /vitest@1.2.2(@types/node@20.11.10): + /vitest@1.2.2(@types/node@20.11.16)(jsdom@24.0.0): resolution: {integrity: sha512-d5Ouvrnms3GD9USIK36KG8OZ5bEvKEkITFtnGv56HFaSlbItJuYr7hv2Lkn903+AvRAgSixiamozUVfORUekjw==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -15030,7 +15119,7 @@ packages: jsdom: optional: true dependencies: - '@types/node': 20.11.10 + '@types/node': 20.11.16 '@vitest/expect': 1.2.2 '@vitest/runner': 1.2.2 '@vitest/snapshot': 1.2.2 @@ -15041,6 +15130,7 @@ packages: chai: 4.3.10 debug: 4.3.4 execa: 8.0.1 + jsdom: 24.0.0 local-pkg: 0.5.0 magic-string: 0.30.5 pathe: 1.1.2 @@ -15049,8 +15139,8 @@ packages: strip-literal: 1.3.0 tinybench: 2.5.1 tinypool: 0.8.2 - vite: 5.0.12(@types/node@20.11.10)(sass@1.70.0) - vite-node: 1.2.2(@types/node@20.11.10) + vite: 5.0.12(@types/node@20.11.16)(sass@1.70.0) + vite-node: 1.2.2(@types/node@20.11.16) why-is-node-running: 2.2.2 transitivePeerDependencies: - less @@ -15062,6 +15152,10 @@ packages: - terser dev: true + /vue-component-type-helpers@1.8.27: + resolution: {integrity: sha512-0vOfAtI67UjeO1G6UiX5Kd76CqaQ67wrRZiOe7UAb9Jm6GzlUr/fC7CV90XfwapJRjpCMaZFhv1V0ajWRmE9Dg==} + dev: true + /vue-demi@0.14.6(vue@3.4.0): resolution: {integrity: sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==} engines: {node: '>=12'} @@ -15391,6 +15485,13 @@ packages: xml-name-validator: 4.0.0 dev: true + /w3c-xmlserializer@5.0.0: + resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} + engines: {node: '>=18'} + dependencies: + xml-name-validator: 5.0.0 + dev: true + /walk-up-path@3.0.1: resolution: {integrity: sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA==} dev: true @@ -15435,7 +15536,7 @@ packages: dependencies: '@discoveryjs/json-ext': 0.5.7 acorn: 8.11.2 - acorn-walk: 8.3.2 + acorn-walk: 8.3.0 commander: 7.2.0 debounce: 1.2.1 escape-string-regexp: 4.0.0 @@ -15608,6 +15709,13 @@ packages: iconv-lite: 0.6.3 dev: true + /whatwg-encoding@3.1.1: + resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} + engines: {node: '>=18'} + dependencies: + iconv-lite: 0.6.3 + dev: true + /whatwg-fetch@3.6.20: resolution: {integrity: sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==} dev: true @@ -15617,6 +15725,11 @@ packages: engines: {node: '>=12'} dev: true + /whatwg-mimetype@4.0.0: + resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} + engines: {node: '>=18'} + dev: true + /whatwg-url@11.0.0: resolution: {integrity: sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==} engines: {node: '>=12'} @@ -15625,6 +15738,14 @@ packages: webidl-conversions: 7.0.0 dev: true + /whatwg-url@14.0.0: + resolution: {integrity: sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==} + engines: {node: '>=18'} + dependencies: + tr46: 5.0.0 + webidl-conversions: 7.0.0 + dev: true + /whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} dependencies: @@ -15756,11 +15877,29 @@ packages: utf-8-validate: optional: true + /ws@8.16.0: + resolution: {integrity: sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: true + /xml-name-validator@4.0.0: resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} engines: {node: '>=12'} dev: true + /xml-name-validator@5.0.0: + resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} + engines: {node: '>=18'} + dev: true + /xmlchars@2.2.0: resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} dev: true diff --git a/tsconfig.json b/tsconfig.json index 5c65505c..94492949 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -18,8 +18,7 @@ "types": [ "chrome", "vite/client", - "vitest/globals", - "@vue/devtools-schema" + "vitest/globals" ], "allowJs": true, "strict": true, diff --git a/vitest.config.ts b/vitest.config.ts index 47cdb031..c881b9fb 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -1,6 +1,12 @@ import { defineConfig } from 'vitest/config' +import Vue from '@vitejs/plugin-vue' export default defineConfig({ + plugins: [Vue()], + define: { + __DEV__: true, + __FEATURE_PROD_DEVTOOLS__: true, + }, test: { globals: true, },