vite-uni-dev-tool 1.1.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (195) hide show
  1. package/README.md +21 -1
  2. package/dist/const.cjs +1 -1
  3. package/dist/const.d.ts +2 -1
  4. package/dist/const.js +1 -1
  5. package/dist/core-shared.d.ts +2 -3
  6. package/dist/core.d.ts +8 -8
  7. package/dist/core.js +2 -2
  8. package/dist/i18n/index.d.ts +0 -1
  9. package/dist/i18n/instance.d.ts +0 -1
  10. package/dist/i18n/locales/en.cjs +1 -1
  11. package/dist/i18n/locales/en.d.ts +6 -1
  12. package/dist/i18n/locales/en.js +1 -1
  13. package/dist/i18n/locales/zh-Hans.cjs +1 -1
  14. package/dist/i18n/locales/zh-Hans.d.ts +6 -1
  15. package/dist/i18n/locales/zh-Hans.js +1 -1
  16. package/dist/index.d.ts +0 -1
  17. package/dist/modules/devConsole/index.cjs +4 -4
  18. package/dist/modules/devConsole/index.d.ts +6 -107
  19. package/dist/modules/devConsole/index.js +4 -4
  20. package/dist/modules/devEvent/index.cjs +3 -3
  21. package/dist/modules/devEvent/index.d.ts +2 -3
  22. package/dist/modules/devEvent/index.js +3 -3
  23. package/dist/modules/devIntercept/index.cjs +14 -14
  24. package/dist/modules/devIntercept/index.d.ts +34 -6
  25. package/dist/modules/devIntercept/index.js +14 -14
  26. package/dist/modules/devStore/index.cjs +1 -1
  27. package/dist/modules/devStore/index.d.ts +48 -40
  28. package/dist/modules/devStore/index.js +1 -1
  29. package/dist/modules/devToolInfo/index.cjs +1 -1
  30. package/dist/modules/devToolInfo/index.d.ts +6 -25
  31. package/dist/modules/devToolInfo/index.js +1 -1
  32. package/dist/plugins/uniDevTool/transform/transformApp.d.ts +0 -1
  33. package/dist/plugins/uniDevTool/transform/transformMain.cjs +3 -3
  34. package/dist/plugins/uniDevTool/transform/transformMain.d.ts +2 -2
  35. package/dist/plugins/uniDevTool/transform/transformMain.js +3 -3
  36. package/dist/plugins/uniDevTool/transform/transformVue.cjs +31 -25
  37. package/dist/plugins/uniDevTool/transform/transformVue.d.ts +2 -2
  38. package/dist/plugins/uniDevTool/transform/transformVue.js +30 -24
  39. package/dist/plugins/uniDevTool/uniDevTool.cjs +3 -3
  40. package/dist/plugins/uniDevTool/uniDevTool.d.ts +3 -2
  41. package/dist/plugins/uniDevTool/uniDevTool.js +3 -3
  42. package/dist/plugins/uniGlobalComponents/uniGlobalComponents.d.ts +0 -1
  43. package/dist/plugins/utils/index.d.ts +0 -1
  44. package/dist/shims-uni.d.ts +26 -22
  45. package/dist/type.d.ts +47 -43
  46. package/dist/utils/array.d.ts +0 -1
  47. package/dist/utils/date.d.ts +0 -1
  48. package/dist/utils/file.d.ts +0 -1
  49. package/dist/utils/function.d.ts +0 -1
  50. package/dist/utils/index.d.ts +0 -1
  51. package/dist/utils/ip.d.ts +0 -1
  52. package/dist/utils/language.d.ts +14 -15
  53. package/dist/utils/object.cjs +1 -1
  54. package/dist/utils/object.d.ts +7 -8
  55. package/dist/utils/object.js +1 -1
  56. package/dist/utils/openLink.d.ts +0 -1
  57. package/dist/utils/page.d.ts +0 -1
  58. package/dist/utils/platform.d.ts +0 -1
  59. package/dist/utils/string.d.ts +0 -1
  60. package/dist/utils/utils.d.ts +0 -1
  61. package/dist/v3/DevTool/components/BluetoothList/BluetoothItem.vue +199 -199
  62. package/dist/v3/DevTool/components/BluetoothList/BluetoothTool.vue +730 -730
  63. package/dist/v3/DevTool/components/BluetoothList/index.vue +167 -167
  64. package/dist/v3/DevTool/components/CaptureScreen/index.vue +109 -109
  65. package/dist/v3/DevTool/components/ConsoleList/ConsoleItem.vue +230 -225
  66. package/dist/v3/DevTool/components/ConsoleList/RunJSInput.vue +247 -247
  67. package/dist/v3/DevTool/components/ConsoleList/index.vue +171 -171
  68. package/dist/v3/DevTool/components/ConsoleList/staticTips.ts +1145 -1145
  69. package/dist/v3/DevTool/components/DevToolButton/index.vue +42 -6
  70. package/dist/v3/DevTool/components/DevToolTitle/index.vue +24 -24
  71. package/dist/v3/DevTool/components/DevToolWindow/DevToolOverlay.vue +197 -197
  72. package/dist/v3/DevTool/components/DevToolWindow/hooks/dataUtils.ts +48 -48
  73. package/dist/v3/DevTool/components/DevToolWindow/hooks/useDevToolData.ts +411 -387
  74. package/dist/v3/DevTool/components/DevToolWindow/hooks/useDevToolHandlers.ts +644 -629
  75. package/dist/v3/DevTool/components/DevToolWindow/hooks/useDevToolOverlay.ts +201 -197
  76. package/dist/v3/DevTool/components/DevToolWindow/index.vue +27 -64
  77. package/dist/v3/DevTool/components/ElEvent/ElEventItem.vue +105 -105
  78. package/dist/v3/DevTool/components/ElEvent/index.vue +106 -106
  79. package/dist/v3/DevTool/components/Instance/components/InstanceTreeNode.vue +265 -265
  80. package/dist/v3/DevTool/components/Instance/flatten.ts +226 -226
  81. package/dist/v3/DevTool/components/Instance/index.vue +94 -94
  82. package/dist/v3/DevTool/components/Instance/registry.ts +49 -49
  83. package/dist/v3/DevTool/components/Instance/transformTree.ts +393 -375
  84. package/dist/v3/DevTool/components/Instance/transformTreeCtx.ts +268 -268
  85. package/dist/v3/DevTool/components/Instance/typing.d.ts +43 -43
  86. package/dist/v3/DevTool/components/InstanceDetail/index.vue +485 -485
  87. package/dist/v3/DevTool/components/JsonDetail/index.vue +70 -70
  88. package/dist/v3/DevTool/components/NFCList/NFCItem.vue +112 -112
  89. package/dist/v3/DevTool/components/NFCList/NFCTool.vue +454 -454
  90. package/dist/v3/DevTool/components/NFCList/const.ts +56 -56
  91. package/dist/v3/DevTool/components/NFCList/index.vue +94 -94
  92. package/dist/v3/DevTool/components/NetworkList/InterceptConfig.vue +624 -624
  93. package/dist/v3/DevTool/components/NetworkList/InterceptItem.vue +140 -140
  94. package/dist/v3/DevTool/components/NetworkList/NetworkDetail.vue +287 -287
  95. package/dist/v3/DevTool/components/NetworkList/NetworkIntercept.vue +88 -88
  96. package/dist/v3/DevTool/components/NetworkList/NetworkItem.vue +163 -163
  97. package/dist/v3/DevTool/components/NetworkList/NetworkSend.vue +589 -589
  98. package/dist/v3/DevTool/components/NetworkList/const.ts +4 -4
  99. package/dist/v3/DevTool/components/NetworkList/hooks/useNetworkForm.ts +86 -86
  100. package/dist/v3/DevTool/components/NetworkList/index.vue +160 -160
  101. package/dist/v3/DevTool/components/NetworkList/utils.ts +101 -101
  102. package/dist/v3/DevTool/components/Performance/index.vue +498 -498
  103. package/dist/v3/DevTool/components/Performance/modules/PerformanceMetrics.vue +153 -153
  104. package/dist/v3/DevTool/components/Performance/modules/usePerformanceChart.ts +460 -460
  105. package/dist/v3/DevTool/components/Performance/modules/usePerformanceData.ts +258 -258
  106. package/dist/v3/DevTool/components/PiniaList/index.vue +93 -93
  107. package/dist/v3/DevTool/components/RunJS/index.vue +148 -148
  108. package/dist/v3/DevTool/components/ScanCodeList/ScanCodeItem.vue +97 -97
  109. package/dist/v3/DevTool/components/ScanCodeList/index.vue +100 -100
  110. package/dist/v3/DevTool/components/SettingButton/index.vue +45 -45
  111. package/dist/v3/DevTool/components/SettingList/index.vue +226 -218
  112. package/dist/v3/DevTool/components/SettingList/modules/SettingBarrage.vue +320 -304
  113. package/dist/v3/DevTool/components/SettingList/modules/SettingDevTool.vue +212 -212
  114. package/dist/v3/DevTool/components/SettingList/modules/SettingInfo.vue +157 -157
  115. package/dist/v3/DevTool/components/SettingList/modules/SettingLanguage.vue +74 -74
  116. package/dist/v3/DevTool/components/SettingList/modules/SettingLog.vue +230 -230
  117. package/dist/v3/DevTool/components/SettingList/typing.d.ts +2 -2
  118. package/dist/v3/DevTool/components/SourceCode/Line.vue +127 -127
  119. package/dist/v3/DevTool/components/SourceCode/parseCode.ts +609 -609
  120. package/dist/v3/DevTool/components/StorageList/index.vue +174 -174
  121. package/dist/v3/DevTool/components/TransferList/TransferDetail.vue +268 -268
  122. package/dist/v3/DevTool/components/VuexList/index.vue +84 -84
  123. package/dist/v3/DevTool/index.vue +85 -138
  124. package/dist/v3/components/AppTransition/index.vue +156 -176
  125. package/dist/v3/components/AutoSizer/index.vue +192 -192
  126. package/dist/v3/components/AutoSizer/index1.vue +184 -184
  127. package/dist/v3/components/AutoSizer/utils.ts +49 -49
  128. package/dist/v3/components/Barrage/BarrageItem.vue +194 -137
  129. package/dist/v3/components/Barrage/index.vue +205 -202
  130. package/dist/v3/components/CircularButton/index.vue +84 -84
  131. package/dist/v3/components/CustomSwiper/CustomSwiperItem.vue +49 -49
  132. package/dist/v3/components/CustomSwiper/index.vue +104 -104
  133. package/dist/v3/components/DevErrorBoundary/index.vue +388 -0
  134. package/dist/v3/components/DraggableContainer/index.vue +186 -73
  135. package/dist/v3/components/Empty/index.vue +29 -29
  136. package/dist/v3/components/FilterSelect/index.vue +179 -179
  137. package/dist/v3/components/JsonPretty/components/Brackets/index.vue +27 -27
  138. package/dist/v3/components/JsonPretty/components/Carets/index.vue +59 -59
  139. package/dist/v3/components/JsonPretty/components/CheckController/index.vue +136 -136
  140. package/dist/v3/components/JsonPretty/components/TreeNode/index.vue +387 -387
  141. package/dist/v3/components/JsonPretty/hooks/useClipboard.ts +21 -21
  142. package/dist/v3/components/JsonPretty/hooks/useError.ts +21 -21
  143. package/dist/v3/components/JsonPretty/type.ts +127 -127
  144. package/dist/v3/components/JsonPretty/utils/index.ts +169 -169
  145. package/dist/v3/components/MovableContainer/index.vue +10 -4
  146. package/dist/v3/components/Pick/index.vue +321 -322
  147. package/dist/v3/components/Tag/index.vue +113 -113
  148. package/dist/v3/components/VirtualList/AutoSize.vue +40 -40
  149. package/dist/v3/components/VirtualList/index.vue +416 -416
  150. package/dist/v3/hooks/useBluetooth/index.ts +561 -561
  151. package/dist/v3/hooks/useContainerStyle.ts +95 -153
  152. package/dist/v3/hooks/useNFC/index.ts +107 -107
  153. package/dist/v3/hooks/useNFC/typing.d.ts +396 -396
  154. package/dist/v3/hooks/useNFC/useNFCAndroid.ts +966 -966
  155. package/dist/v3/hooks/useNFC/useNFCMpWeiXin.ts +812 -812
  156. package/dist/v3/hooks/useNFC/utils.ts +754 -754
  157. package/dist/v3/hooks/useRequest/index.ts +586 -586
  158. package/dist/v3/hooks/useRequest/utils.ts +267 -267
  159. package/dist/v3/hooks/useScanCode/index.ts +206 -206
  160. package/dist/v3/hooks/useWebsocket/index.ts +253 -253
  161. package/dist/v3/styles/theme.ts +12 -12
  162. package/package.json +70 -59
  163. package/dist/const.d.ts.map +0 -1
  164. package/dist/core-shared.d.ts.map +0 -1
  165. package/dist/core.d.ts.map +0 -1
  166. package/dist/i18n/index.d.ts.map +0 -1
  167. package/dist/i18n/instance.d.ts.map +0 -1
  168. package/dist/i18n/locales/en.d.ts.map +0 -1
  169. package/dist/i18n/locales/zh-Hans.d.ts.map +0 -1
  170. package/dist/index.d.ts.map +0 -1
  171. package/dist/modules/devConsole/index.d.ts.map +0 -1
  172. package/dist/modules/devEvent/index.d.ts.map +0 -1
  173. package/dist/modules/devIntercept/index.d.ts.map +0 -1
  174. package/dist/modules/devStore/index.d.ts.map +0 -1
  175. package/dist/modules/devToolInfo/index.d.ts.map +0 -1
  176. package/dist/plugins/uniDevTool/transform/transformApp.d.ts.map +0 -1
  177. package/dist/plugins/uniDevTool/transform/transformMain.d.ts.map +0 -1
  178. package/dist/plugins/uniDevTool/transform/transformVue.d.ts.map +0 -1
  179. package/dist/plugins/uniDevTool/uniDevTool.d.ts.map +0 -1
  180. package/dist/plugins/uniGlobalComponents/uniGlobalComponents.d.ts.map +0 -1
  181. package/dist/plugins/utils/index.d.ts.map +0 -1
  182. package/dist/type.d.ts.map +0 -1
  183. package/dist/utils/array.d.ts.map +0 -1
  184. package/dist/utils/date.d.ts.map +0 -1
  185. package/dist/utils/file.d.ts.map +0 -1
  186. package/dist/utils/function.d.ts.map +0 -1
  187. package/dist/utils/index.d.ts.map +0 -1
  188. package/dist/utils/ip.d.ts.map +0 -1
  189. package/dist/utils/language.d.ts.map +0 -1
  190. package/dist/utils/object.d.ts.map +0 -1
  191. package/dist/utils/openLink.d.ts.map +0 -1
  192. package/dist/utils/page.d.ts.map +0 -1
  193. package/dist/utils/platform.d.ts.map +0 -1
  194. package/dist/utils/string.d.ts.map +0 -1
  195. package/dist/utils/utils.d.ts.map +0 -1
@@ -1,375 +1,393 @@
1
- import { isArray, isObject, isString } from '../../../../utils';
2
- import {
3
- type ComponentInternalInstance,
4
- type VNode,
5
- isRef,
6
- isReactive,
7
- } from 'vue';
8
- import { getRecordedChildren } from './registry';
9
-
10
- // 类型守卫函数,检查是否为VNode类型
11
- function isVNode(child: any): child is VNode {
12
- return child != null && typeof child === 'object' && 'type' in child;
13
- }
14
-
15
- // 类型守卫函数,检查是否为包含component属性的对象
16
- function hasComponentProperty(
17
- child: any,
18
- ): child is VNode & { component?: ComponentInternalInstance } {
19
- return isVNode(child) && 'component' in child;
20
- }
21
-
22
- // 类型守卫函数,检查是否为Symbol类型且具有description属性
23
- function isSymbolWithDescription(
24
- value: any,
25
- ): value is symbol & { description?: string } {
26
- return typeof value === 'symbol';
27
- }
28
-
29
- interface SimpleTreeNode {
30
- type: string;
31
- uid: string | number;
32
- children?: SimpleTreeNode[];
33
- content?: string;
34
- hasChildren?: boolean;
35
- // 分类存储属性
36
- props?: Record<string, any>;
37
- styles?: Record<string, any>;
38
- other?: Record<string, any>;
39
- provides?: Record<string, any>;
40
- data?: Record<string, any>;
41
- functions?: Record<string, any>;
42
- emits?: Record<string, any>;
43
- }
44
-
45
- /**
46
- * 分类提取属性
47
- */
48
- function extractCategorizedData(vnode: any): {
49
- props: Record<string, any>;
50
- styles: Record<string, any>;
51
- other: Record<string, any>;
52
- provides: Record<string, any>;
53
- data: Record<string, any>;
54
- functions: Record<string, any>;
55
- emits: Record<string, any>;
56
- } {
57
- const styles: any = {};
58
- const props: any = {};
59
- const other: any = {};
60
- const provides: any = {};
61
- const data: any = {};
62
- const emits: any = {};
63
-
64
- const vnodeProps = vnode.props || {};
65
-
66
- // 1. 提取样式相关 (id, style)
67
- const styleKeys = ['id', 'style'];
68
-
69
- // 处理样式属性
70
- styleKeys.forEach((key) => {
71
- let val = vnodeProps[key];
72
- if (val !== undefined && val !== null && val !== '') {
73
- if (key === 'style' && isObject(val)) {
74
- val = Object.entries(val)
75
- .filter(([_, v]) => v !== undefined && v !== null && v !== '')
76
- .map(([k, v]) => `${k}: ${v}`)
77
- .join('; ');
78
- }
79
- if (val !== '') {
80
- styles[key] = val;
81
- }
82
- }
83
- });
84
-
85
- // 处理 Props 属性 (包括 class, data- 以及其他)
86
- Object.keys(vnodeProps).forEach((key) => {
87
- // 排除已处理的样式属性
88
- if (!styleKeys.includes(key)) {
89
- // 统一处理 className -> class
90
- const finalKey = key === 'className' ? 'class' : key;
91
- props[finalKey] = vnodeProps[key];
92
- }
93
- });
94
-
95
- // 3. 提取其他元数据
96
- other.uid = vnode.uid;
97
- if (vnode.type) {
98
- other.type = isString(vnode.type)
99
- ? vnode.type
100
- : isObject(vnode.type)
101
- ? (vnode.type as any).name || (vnode.type as any).__name || 'Component'
102
- : String(vnode.type);
103
-
104
- if (isObject(vnode.type) && (vnode.type as any).__file) {
105
- other.file = (vnode.type as any).__file;
106
- }
107
- }
108
-
109
- // 如果有 slots
110
- if (vnode.children && !isArray(vnode.children) && isObject(vnode.children)) {
111
- other.slots = Object.keys(vnode.children);
112
- }
113
-
114
- // 4. 提取 provides
115
- const currentProvides = vnode.provides;
116
-
117
- if (currentProvides) {
118
- Reflect.ownKeys(currentProvides).forEach((key) => {
119
- // 排除 Vue 内部属性
120
- if (typeof key === 'string' && key.startsWith('__v')) return;
121
-
122
- const value = currentProvides[key];
123
- const keyStr = typeof key === 'symbol' ? String(key) : key;
124
- provides[keyStr] = value;
125
- });
126
- }
127
-
128
- // 5. 提取 data (仅当 vnode.component 存在时)
129
- const functions: any = {};
130
- if (vnode.setupState || vnode.data) {
131
- // 优先取 setupState (Script Setup / Composition API), 其次取 data (Options API)
132
- // 注意:setupState 包含了响应式引用的解包值
133
- const allData: any = {};
134
-
135
- // 处理 setupState
136
- if (isObject(vnode.setupState)) {
137
- Object.assign(allData, vnode.setupState);
138
- }
139
-
140
- // 处理 Options API data
141
- if (isObject(vnode.data)) {
142
- Object.assign(allData, vnode.data);
143
- }
144
-
145
- if (isObject(allData)) {
146
- Reflect.ownKeys(allData).forEach((key) => {
147
- // 排除 Vue 内部属性
148
- if (
149
- typeof key === 'string' &&
150
- (key.startsWith('__v') || key.startsWith('$') || key.startsWith('_'))
151
- )
152
- return;
153
-
154
- const value = (allData as any)[key];
155
- let keyStr = typeof key === 'symbol' ? String(key) : key;
156
-
157
- // 标记 Ref Reactive
158
- // 优先检查 devtoolsRawSetupState 获取原始 Ref
159
- const rawSetupState = (vnode as any).devtoolsRawSetupState || {};
160
- const rawValue = rawSetupState[key];
161
-
162
- if (rawValue && isRef(rawValue)) {
163
- keyStr += ' (Ref)';
164
- } else if (isReactive(value)) {
165
- keyStr += ' (Reactive)';
166
- }
167
-
168
- if (typeof value === 'function') {
169
- functions[keyStr] = value;
170
- } else {
171
- // 尝试区分类型(Ref, Reactive, Computed 等在 setupState 中通常已被解包,难以直接判断原始类型,
172
- // 除非使用 devtools 专用钩子。这里暂只做基础值存储)
173
- data[keyStr] = value;
174
- }
175
- });
176
- }
177
- }
178
-
179
- // 6. 提取 emits
180
- // 优先从组件实例获取归一化的 emitsOptions, 其次从类型定义获取
181
- const emitsOptions = vnode?.emitsOptions || vnode.type?.emits;
182
- if (emitsOptions) {
183
- if (isArray(emitsOptions)) {
184
- emitsOptions.forEach((emit: string) => {
185
- emits[emit] = 'function(...args) {...}'; // 简单标记存在
186
- });
187
- } else if (isObject(emitsOptions)) {
188
- Reflect.ownKeys(emitsOptions).forEach((key) => {
189
- if (typeof key === 'string') {
190
- emits[key] = 'function(...args) {...}';
191
- }
192
- });
193
- }
194
- }
195
-
196
- return { props, styles, other, provides, data, functions, emits };
197
- }
198
-
199
- let uidCount = 0;
200
- // 导出重置函数,供外部调用
201
- export function resetUidCount() {
202
- uidCount = 0;
203
- }
204
-
205
- function getNextUid() {
206
- return `manual-${++uidCount}`;
207
- }
208
-
209
- function extractNameFromFile(file: string): string | undefined {
210
- if (!file) return undefined;
211
- const match = file.match(/([^/|\\]+)\.[^.]+$/);
212
- return match ? match[1] : undefined;
213
- }
214
-
215
- function getComponentName(type: any): string {
216
- if (!type) return 'Anonymous';
217
- if (typeof type === 'string') return type;
218
- if (typeof type === 'object') {
219
- return (
220
- type.name ||
221
- type.__name ||
222
- (type.__file ? extractNameFromFile(type.__file) : undefined) ||
223
- 'Anonymous'
224
- );
225
- }
226
- if (typeof type === 'function') {
227
- return type.name || type.__name || 'Anonymous';
228
- }
229
- return 'Anonymous';
230
- }
231
-
232
- // ... existing code ...
233
-
234
- // ... types ...
235
-
236
- export function simpleTree(vNode?: any, depth = 0): SimpleTreeNode | null {
237
- // ... check valid ...
238
- if (vNode === null || typeof vNode !== 'object' || depth > 40) {
239
- return null;
240
- }
241
- // ... rest of simpleTree func ...
242
-
243
- // 确保只使用必需的属性
244
- const simplifiedInstance: InstanceTree.SimplifiedComponentInternalInstance = {
245
- type: vNode.type,
246
- subTree: vNode.subTree,
247
- uid: vNode.uid,
248
- ...(vNode.component && { component: vNode.component }),
249
- ...(vNode.children && { children: vNode.children }),
250
- };
251
-
252
- const children: SimpleTreeNode[] = [];
253
-
254
- // 获取子节点
255
- if (simplifiedInstance.subTree) {
256
- if ('data-dev-tool' in (simplifiedInstance.subTree.props ?? {})) {
257
- return null;
258
- } else {
259
- children.push(
260
- ...getSimpleChildrenFromVNode(simplifiedInstance.subTree, depth),
261
- );
262
- }
263
- }
264
-
265
- // 插槽 fallback
266
- if (children.length === 0 && simplifiedInstance.children) {
267
- if (isArray(simplifiedInstance.children)) {
268
- const slotChildren = getSimpleChildrenFromVNode(
269
- {
270
- children: simplifiedInstance.children,
271
- },
272
- depth,
273
- );
274
- children.push(...slotChildren);
275
- }
276
- }
277
-
278
- // GLOBAL fallback
279
- if (children.length === 0 && vNode.uid !== undefined) {
280
- const recordedChildren = getRecordedChildren(vNode.uid);
281
- recordedChildren.forEach((childInst) => {
282
- const childTree = simpleTree(childInst, depth + 1);
283
- if (childTree) {
284
- children.push(childTree);
285
- }
286
- });
287
- }
288
-
289
- const hasChildrenFlag = children.length > 0;
290
- const uid = vNode.uid !== undefined ? vNode.uid : getNextUid();
291
- const typeName = getComponentName(simplifiedInstance.type);
292
-
293
- const nodeInfo: SimpleTreeNode = {
294
- type: typeName,
295
- uid,
296
- children,
297
- hasChildren: hasChildrenFlag,
298
- ...extractCategorizedData(vNode),
299
- };
300
-
301
- return nodeInfo;
302
- }
303
-
304
- /**
305
- * 从 VNode 获取简化的子节点 (仅保留组件节点)
306
- */
307
- function getSimpleChildrenFromVNode(
308
- vnode: any,
309
- depth: number = 0,
310
- ): SimpleTreeNode[] {
311
- const children: SimpleTreeNode[] = [];
312
- if (vnode.children) {
313
- // 统一转为数组处理,兼容单节点和多节点
314
- const rawChildren = isArray(vnode.children)
315
- ? vnode.children
316
- : isObject(vnode.children)
317
- ? [vnode.children]
318
- : isString(vnode.children)
319
- ? [vnode.children]
320
- : [];
321
-
322
- for (const child of rawChildren) {
323
- if (
324
- child &&
325
- typeof child === 'object' &&
326
- 'props' in child &&
327
- child.props &&
328
- 'data-dev-tool' in child.props
329
- ) {
330
- continue;
331
- }
332
-
333
- // 1. 如果是组件实例,直接处理
334
- if (hasComponentProperty(child) && child?.component) {
335
- const childTree = simpleTree(child.component, depth + 1);
336
- if (childTree) {
337
- children.push(childTree);
338
- }
339
- }
340
- // 2. 如果是函数式组件
341
- else if (isVNode(child) && typeof child.type === 'function') {
342
- const uid =
343
- (child as any).uid !== undefined ? (child as any).uid : getNextUid();
344
- const typeName = getComponentName(child.type);
345
- children.push({
346
- type: typeName,
347
- uid,
348
- children: [],
349
- hasChildren: false,
350
- ...extractCategorizedData(child),
351
- });
352
- }
353
- // 3. 如果是 VNode 且是 Fragmentation/Block (带 children 的非组件节点),需要深入查找内部的组件
354
- else if (isVNode(child)) {
355
- // 如果是 Fragment,递归查找子节点
356
- if (child.type && isSymbolWithDescription(child.type)) {
357
- const desc = child.type.description;
358
- const isFragment = desc === 'v-fgt' || desc === 'Fragment';
359
- if (isFragment) {
360
- const fragmentChildren = getSimpleChildrenFromVNode(child, depth);
361
- children.push(...fragmentChildren);
362
- }
363
- }
364
- // 如果是普通 HTML 元素或其他容器,也需要递归查找其 children 中的组件
365
- // 例如 <view><MyComponent /></view>,我们需要找到 MyComponent
366
- else if (isString(child.type) || isObject(child.type)) {
367
- // 递归查找子节点中的组件,但不把当前节点加入树中(因为我们只关心组件)
368
- const subChildren = getSimpleChildrenFromVNode(child, depth);
369
- children.push(...subChildren);
370
- }
371
- }
372
- }
373
- }
374
- return children;
375
- }
1
+ import { isArray, isObject, isString } from '../../../../utils';
2
+ import {
3
+ type ComponentInternalInstance,
4
+ type VNode,
5
+ isRef,
6
+ isReactive,
7
+ } from 'vue';
8
+ import { getRecordedChildren } from './registry';
9
+
10
+ // 类型守卫函数,检查是否为Vnode类型
11
+ function isVNode(child: unknown): child is VNode {
12
+ return (
13
+ child != null && typeof child === 'object' && 'type' in (child as object)
14
+ );
15
+ }
16
+
17
+ // 类型守卫函数,检查是否为包含component属性的对象
18
+ function hasComponentProperty(
19
+ child: unknown,
20
+ ): child is VNode & { component?: ComponentInternalInstance } {
21
+ return isVNode(child) && 'component' in (child as object);
22
+ }
23
+
24
+ // 类型守卫函数,检查是否为Symbol类型且具有description属性
25
+ function isSymbolWithDescription(
26
+ value: unknown,
27
+ ): value is symbol & { description?: string } {
28
+ return typeof value === 'symbol';
29
+ }
30
+
31
+ interface SimpleTreeNode {
32
+ type: string;
33
+ uid: string | number;
34
+ children?: SimpleTreeNode[];
35
+ content?: string;
36
+ hasChildren?: boolean;
37
+ // 分类存储属性
38
+ props?: Record<string, unknown>;
39
+ styles?: Record<string, unknown>;
40
+ other?: Record<string, unknown>;
41
+ provides?: Record<string, unknown>;
42
+ data?: Record<string, unknown>;
43
+ functions?: Record<string, unknown>;
44
+ emits?: Record<string, unknown>;
45
+ }
46
+
47
+ interface VNodeWithInternals extends Record<string, unknown> {
48
+ uid?: string | number;
49
+ type?: unknown;
50
+ props?: Record<string, unknown> | null;
51
+ children?: unknown;
52
+ component?: unknown;
53
+ subTree?: unknown;
54
+ provides?: Record<string | symbol, unknown>;
55
+ setupState?: Record<string, unknown>;
56
+ data?: Record<string, unknown>;
57
+ emitsOptions?: string[] | Record<string, unknown>;
58
+ devtoolsRawSetupState?: Record<string, unknown>;
59
+ }
60
+
61
+ /**
62
+ * 分类提取属性
63
+ */
64
+ function extractCategorizedData(vnode: VNodeWithInternals): {
65
+ props: Record<string, unknown>;
66
+ styles: Record<string, unknown>;
67
+ other: Record<string, unknown>;
68
+ provides: Record<string, unknown>;
69
+ data: Record<string, unknown>;
70
+ functions: Record<string, unknown>;
71
+ emits: Record<string, unknown>;
72
+ } {
73
+ const styles: Record<string, unknown> = {};
74
+ const props: Record<string, unknown> = {};
75
+ const other: Record<string, unknown> = {};
76
+ const provides: Record<string, unknown> = {};
77
+ const data: Record<string, unknown> = {};
78
+ const emits: Record<string, unknown> = {};
79
+
80
+ const vnodeProps = (vnode.props as Record<string, unknown>) || {};
81
+
82
+ // 1. 提取样式相关 (id, style)
83
+ const styleKeys = ['id', 'style'];
84
+
85
+ // 处理样式属性
86
+ styleKeys.forEach((key) => {
87
+ let val = vnodeProps[key];
88
+ if (val !== undefined && val !== null && val !== '') {
89
+ if (key === 'style' && isObject(val)) {
90
+ val = Object.entries(val as object)
91
+ .filter(([_, v]) => v !== undefined && v !== null && v !== '')
92
+ .map(([k, v]) => `${k}: ${v}`)
93
+ .join('; ');
94
+ }
95
+ if (val !== '') {
96
+ styles[key] = val;
97
+ }
98
+ }
99
+ });
100
+
101
+ // 处理 Props 属性 (包括 class, data- 以及其他)
102
+ Object.keys(vnodeProps).forEach((key) => {
103
+ // 排除已处理的样式属性
104
+ if (!styleKeys.includes(key)) {
105
+ // 统一处理 className -> class
106
+ const finalKey = key === 'className' ? 'class' : key;
107
+ props[finalKey] = vnodeProps[key];
108
+ }
109
+ });
110
+
111
+ // 3. 提取其他元数据
112
+ other.uid = vnode.uid;
113
+ if (vnode.type) {
114
+ const vType = vnode.type as Record<string, string>;
115
+ other.type = isString(vnode.type)
116
+ ? vnode.type
117
+ : isObject(vnode.type)
118
+ ? vType.name || vType.__name || 'Component'
119
+ : String(vnode.type);
120
+
121
+ if (isObject(vnode.type) && vType.__file) {
122
+ other.file = vType.__file;
123
+ }
124
+ }
125
+
126
+ // 如果有 slots
127
+ if (vnode.children && !isArray(vnode.children) && isObject(vnode.children)) {
128
+ other.slots = Object.keys(vnode.children as object);
129
+ }
130
+
131
+ // 4. 提取 provides
132
+ const currentProvides = vnode.provides as Record<string | symbol, unknown>;
133
+
134
+ if (currentProvides) {
135
+ Reflect.ownKeys(currentProvides).forEach((key) => {
136
+ // 排除 Vue 内部属性
137
+ if (typeof key === 'string' && key.startsWith('__v')) return;
138
+
139
+ const value = currentProvides[key];
140
+ const keyStr = typeof key === 'symbol' ? String(key) : key;
141
+ provides[keyStr] = value;
142
+ });
143
+ }
144
+
145
+ // 5. 提取 data (仅当 vnode.component 存在时)
146
+ const functions: Record<string, unknown> = {};
147
+ if (vnode.setupState || vnode.data) {
148
+ // 优先取 setupState (Script Setup / Composition API), 其次取 data (Options API)
149
+ // 注意:setupState 包含了响应式引用的解包值
150
+ const allData: Record<string, unknown> = {};
151
+
152
+ // 处理 setupState
153
+ if (isObject(vnode.setupState)) {
154
+ Object.assign(allData, vnode.setupState as object);
155
+ }
156
+
157
+ // 处理 Options API data
158
+ if (isObject(vnode.data)) {
159
+ Object.assign(allData, vnode.data as object);
160
+ }
161
+
162
+ if (isObject(allData)) {
163
+ Reflect.ownKeys(allData).forEach((key) => {
164
+ // 排除 Vue 内部属性
165
+ if (
166
+ typeof key === 'string' &&
167
+ (key.startsWith('__v') || key.startsWith('$') || key.startsWith('_'))
168
+ )
169
+ return;
170
+
171
+ const value = (allData as Record<string | symbol, unknown>)[key];
172
+ let keyStr = typeof key === 'symbol' ? String(key) : key;
173
+
174
+ // 标记 Ref 和 Reactive
175
+ // 优先检查 devtoolsRawSetupState 获取原始 Ref
176
+ const rawSetupState =
177
+ (vnode as Record<string, Record<string, unknown>>)
178
+ .devtoolsRawSetupState || {};
179
+ const rawValue = rawSetupState[key as string];
180
+
181
+ if (rawValue && isRef(rawValue)) {
182
+ keyStr += ' (Ref)';
183
+ } else if (isReactive(value)) {
184
+ keyStr += ' (Reactive)';
185
+ }
186
+
187
+ if (typeof value === 'function') {
188
+ functions[keyStr] = value;
189
+ } else {
190
+ // 尝试区分类型(Ref, Reactive, Computed 等在 setupState 中通常已被解包,难以直接判断原始类型,
191
+ // 除非使用 devtools 专用钩子。这里暂只做基础值存储)
192
+ data[keyStr] = value;
193
+ }
194
+ });
195
+ }
196
+ }
197
+
198
+ // 6. 提取 emits
199
+ // 优先从组件实例获取归一化的 emitsOptions, 其次从类型定义获取
200
+ const emitsOptions = (vnode?.emitsOptions ||
201
+ (vnode.type as Record<string, unknown>)?.emits) as
202
+ | string[]
203
+ | Record<string, unknown>;
204
+ if (emitsOptions) {
205
+ if (isArray(emitsOptions)) {
206
+ emitsOptions.forEach((emit: string) => {
207
+ emits[emit] = 'function(...args) {...}'; // 简单标记存在
208
+ });
209
+ } else if (isObject(emitsOptions)) {
210
+ Reflect.ownKeys(emitsOptions).forEach((key) => {
211
+ if (typeof key === 'string') {
212
+ emits[key] = 'function(...args) {...}';
213
+ }
214
+ });
215
+ }
216
+ }
217
+
218
+ return { props, styles, other, provides, data, functions, emits };
219
+ }
220
+
221
+ let uidCount = 0;
222
+ // 导出重置函数,供外部调用
223
+ export function resetUidCount() {
224
+ uidCount = 0;
225
+ }
226
+
227
+ function getNextUid() {
228
+ return `manual-${++uidCount}`;
229
+ }
230
+
231
+ function extractNameFromFile(file: string): string | undefined {
232
+ if (!file) return undefined;
233
+ const match = file.match(/([^/|\\]+)\.[^.]+$/);
234
+ return match ? match[1] : undefined;
235
+ }
236
+
237
+ function getComponentName(type: unknown): string {
238
+ if (!type) return 'Anonymous';
239
+ if (typeof type === 'string') return type;
240
+ if (typeof type === 'object') {
241
+ const t = type as Record<string, string>;
242
+ return (
243
+ t.name ||
244
+ t.__name ||
245
+ (t.__file ? extractNameFromFile(t.__file) : undefined) ||
246
+ 'Anonymous'
247
+ );
248
+ }
249
+ if (typeof type === 'function') {
250
+ const f = type as { name?: string; __name?: string };
251
+ return f.name || f.__name || 'Anonymous';
252
+ }
253
+ return 'Anonymous';
254
+ }
255
+
256
+ /**
257
+ * 从 Vnode 获取简化的子节点 (仅保留组件节点)
258
+ */
259
+ function getSimpleChildrenFromVNode(
260
+ vnode: VNodeWithInternals,
261
+ depth: number = 0,
262
+ ): SimpleTreeNode[] {
263
+ const children: SimpleTreeNode[] = [];
264
+ if (vnode.children) {
265
+ // 统一转为数组处理,兼容单节点和多节点
266
+ const rawChildren = isArray(vnode.children)
267
+ ? (vnode.children as unknown[])
268
+ : isObject(vnode.children)
269
+ ? [vnode.children]
270
+ : isString(vnode.children)
271
+ ? [vnode.children]
272
+ : [];
273
+
274
+ for (const child of rawChildren) {
275
+ if (!child || typeof child !== 'object') continue;
276
+
277
+ const childObj = child as unknown as VNodeWithInternals;
278
+ const childProps = (childObj.props as Record<string, unknown>) || {};
279
+
280
+ if (childProps['data-dev-tool']) {
281
+ continue;
282
+ }
283
+
284
+ // 1. 如果是组件实例,直接处理
285
+ if (hasComponentProperty(child) && child.component) {
286
+ const childTree = simpleTree(
287
+ child.component as unknown as Record<string, unknown>,
288
+ depth + 1,
289
+ );
290
+ if (childTree) {
291
+ children.push(childTree);
292
+ }
293
+ }
294
+ // 2. 如果是函数式组件
295
+ else if (isVNode(child) && typeof child.type === 'function') {
296
+ const uid =
297
+ childObj.uid !== undefined
298
+ ? (childObj.uid as string | number)
299
+ : getNextUid();
300
+ const typeName = getComponentName(child.type);
301
+ children.push({
302
+ type: typeName,
303
+ uid,
304
+ children: [],
305
+ hasChildren: false,
306
+ ...extractCategorizedData(childObj),
307
+ });
308
+ }
309
+ // 3. 如果是 VNode 且是 Fragmentation/Block (带 children 的非组件节点),需要深入查找内部的组件
310
+ else if (isVNode(child)) {
311
+ // 如果是 Fragment,递归查找子节点
312
+ if (child.type && isSymbolWithDescription(child.type)) {
313
+ const desc = (child.type as { description?: string }).description;
314
+ const isFragment = desc === 'v-fgt' || desc === 'Fragment';
315
+ if (isFragment) {
316
+ const fragmentChildren = getSimpleChildrenFromVNode(
317
+ childObj,
318
+ depth,
319
+ );
320
+ children.push(...fragmentChildren);
321
+ }
322
+ }
323
+ // 如果是普通 HTML 元素或其他容器,也需要递归查找其 children 中的组件
324
+ else if (isString(child.type) || isObject(child.type)) {
325
+ const subChildren = getSimpleChildrenFromVNode(childObj, depth);
326
+ children.push(...subChildren);
327
+ }
328
+ }
329
+ }
330
+ }
331
+ return children;
332
+ }
333
+
334
+ export function simpleTree(
335
+ vNode?: Record<string, unknown>,
336
+ depth = 0,
337
+ ): SimpleTreeNode | null {
338
+ if (!vNode || typeof vNode !== 'object' || depth > 40) {
339
+ return null;
340
+ }
341
+
342
+ const vNodeObj = vNode as unknown as VNodeWithInternals;
343
+ const children: SimpleTreeNode[] = [];
344
+
345
+ // 1. 获取子节点
346
+ const subTree = vNodeObj.subTree as VNodeWithInternals | undefined;
347
+ if (subTree) {
348
+ const subProps = (subTree.props as Record<string, unknown>) || {};
349
+ if (!subProps['data-dev-tool']) {
350
+ children.push(...getSimpleChildrenFromVNode(subTree, depth));
351
+ }
352
+ }
353
+
354
+ // 2. 插槽 fallback
355
+ if (children.length === 0 && vNodeObj.children) {
356
+ if (isArray(vNodeObj.children)) {
357
+ const slotChildren = getSimpleChildrenFromVNode(
358
+ { children: vNodeObj.children } as VNodeWithInternals,
359
+ depth,
360
+ );
361
+ children.push(...slotChildren);
362
+ }
363
+ }
364
+
365
+ // 3. GLOBAL fallback
366
+ if (children.length === 0 && typeof vNodeObj.uid === 'number') {
367
+ const recordedChildren = getRecordedChildren(vNodeObj.uid);
368
+ recordedChildren.forEach((childInst) => {
369
+ const childTree = simpleTree(
370
+ childInst as unknown as Record<string, unknown>,
371
+ depth + 1,
372
+ );
373
+ if (childTree) {
374
+ children.push(childTree);
375
+ }
376
+ });
377
+ }
378
+
379
+ const hasChildrenFlag = children.length > 0;
380
+ const uid =
381
+ vNodeObj.uid !== undefined
382
+ ? (vNodeObj.uid as string | number)
383
+ : getNextUid();
384
+ const typeName = getComponentName(vNodeObj.type);
385
+
386
+ return {
387
+ type: typeName,
388
+ uid,
389
+ children,
390
+ hasChildren: hasChildrenFlag,
391
+ ...extractCategorizedData(vNodeObj),
392
+ };
393
+ }