@dimina-kit/devtools 0.4.0-dev.20260710085051 → 0.4.0-dev.20260711062001
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.
- package/dist/main/services/render-inspect/index.d.ts +1 -1
- package/dist/preload/instrumentation/wxml.js +1 -1
- package/dist/preload/runtime/bridge.d.ts +3 -3
- package/dist/preload/runtime/bridge.js +2 -2
- package/dist/preload/windows/host-toolbar-runtime.cjs.map +2 -2
- package/dist/preload/windows/simulator.cjs +12 -4
- package/dist/preload/windows/simulator.cjs.map +3 -3
- package/dist/preload/windows/simulator.js +12 -4
- package/dist/render-host/render-inspect.js +189 -88
- package/dist/renderer/assets/index-WbvXdhWQ.js +49 -0
- package/dist/renderer/assets/{input-CTb_le7F.js → input-COtRON-n.js} +2 -2
- package/dist/renderer/assets/{ipc-transport-BPWIV5hA.css → ipc-transport-CNvORIEX.css} +1 -1
- package/dist/renderer/assets/{ipc-transport-Ck5Xa8Tu.js → ipc-transport-SuI2rOB_.js} +1 -1
- package/dist/renderer/assets/{popover-B1Zu2UQu.js → popover-B73T3z-m.js} +2 -2
- package/dist/renderer/assets/{select-ozSk5Pt6.js → select-Bwb8O0Mf.js} +2 -2
- package/dist/renderer/assets/{settings-CNwGOI22.js → settings-BispnvJU.js} +2 -2
- package/dist/renderer/assets/{settings-api-DMbMp1Eq.js → settings-api-HIBz8BFz.js} +2 -2
- package/dist/renderer/assets/{workbenchSettings-C6w5S2ZY.js → workbenchSettings-CtRBr7gS.js} +2 -2
- package/dist/renderer/entries/main/index.html +6 -6
- package/dist/renderer/entries/popover/index.html +5 -5
- package/dist/renderer/entries/settings/index.html +5 -5
- package/dist/renderer/entries/workbench-settings/index.html +4 -4
- package/dist/shared/ipc-channels.d.ts +2 -44
- package/package.json +5 -4
- package/dist/preload/instrumentation/wxml-extract.d.ts +0 -11
- package/dist/preload/instrumentation/wxml-extract.js +0 -382
- package/dist/preload/shared/sid-registry.d.ts +0 -11
- package/dist/preload/shared/sid-registry.js +0 -38
- package/dist/renderer/assets/index-BjCKGJDg.js +0 -49
package/dist/renderer/assets/{workbenchSettings-C6w5S2ZY.js → workbenchSettings-CtRBr7gS.js}
RENAMED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import{S as e,T as t,w as n,x as r}from"./ipc-transport-
|
|
1
|
+
import{S as e,T as t,w as n,x as r}from"./ipc-transport-SuI2rOB_.js";import{t as i}from"./constants-EAMiwL9_.js";import{a,c as o,i as s,r as c,s as l,u}from"./settings-api-HIBz8BFz.js";var d=t(e(),1),f=t(n(),1),p=r(),m=[{id:`general`,label:`通用`},{id:`debug`,label:`调试`},{id:`mcp`,label:`MCP`}],h={system:`跟随系统`,dark:`深色`,light:`浅色`};function g({checked:e,onClick:t}){return(0,p.jsx)(`button`,{type:`button`,onClick:t,className:`relative inline-flex h-5 w-9 shrink-0 rounded-full transition-colors`,style:{background:e?`var(--color-accent)`:`var(--color-surface-3)`},children:(0,p.jsx)(`span`,{className:`inline-block h-3.5 w-3.5 rounded-full bg-white transition-transform`,style:{marginTop:3,transform:e?`translateX(18px)`:`translateX(3px)`}})})}function _({activeTab:e,onSelect:t}){return(0,p.jsx)(`div`,{className:`flex items-center border-b border-border shrink-0`,children:m.map(n=>(0,p.jsx)(`button`,{className:`flex-1 py-2.5 text-[12px] text-center transition-colors ${e===n.id?`text-accent border-b-2 border-accent`:`text-text-secondary hover:text-text`}`,onClick:()=>t(n.id),children:n.label},n.id))})}function v({theme:e,onSelect:t}){return(0,p.jsx)(`div`,{className:`flex rounded overflow-hidden border border-border text-[11px]`,children:[`system`,`dark`,`light`].map((n,r)=>(0,p.jsx)(`button`,{onClick:()=>t(n),className:[`px-3 py-1 transition-colors`,r>0?`border-l border-border`:``,e===n?`bg-accent text-white`:`text-text-secondary hover:text-text hover:bg-surface-3`].join(` `),children:h[n]},n))})}function y({autoBuildEnabled:e,onAutoBuildChange:t,autoReloadEnabled:n,onAutoReloadChange:r,theme:i,onThemeChange:a,saved:o}){return(0,p.jsxs)(`div`,{className:`space-y-4`,children:[(0,p.jsxs)(`section`,{className:`rounded-lg border border-border p-4 space-y-4 bg-bg`,children:[(0,p.jsxs)(`div`,{children:[(0,p.jsx)(`h2`,{className:`text-[13px] font-medium mb-1`,children:`编译与预览`}),(0,p.jsx)(`p`,{className:`text-[11px] leading-relaxed text-text-secondary`,children:`开启「自动编译」后,打开项目时会监听源文件改动并自动重新编译。开启「自动刷新」后,每次编译完成会刷新模拟器;关闭它可保留当前页面栈与表单状态,仅手动刷新。配置在下次打开项目时生效。`})]}),(0,p.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,p.jsx)(`span`,{className:`text-[12px] text-text-secondary`,children:`监听文件变化自动编译`}),(0,p.jsx)(g,{checked:e,onClick:()=>t(!e)})]}),(0,p.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,p.jsx)(`span`,{className:`text-[12px] text-text-secondary`,children:`编译完成后自动刷新模拟器`}),(0,p.jsx)(g,{checked:n,onClick:()=>r(!n)})]})]}),(0,p.jsxs)(`section`,{className:`rounded-lg border border-border p-4 space-y-3 bg-bg`,children:[(0,p.jsx)(`div`,{children:(0,p.jsx)(`h2`,{className:`text-[13px] font-medium mb-1`,children:`外观`})}),(0,p.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,p.jsx)(`span`,{className:`text-[12px] text-text-secondary`,children:`颜色模式`}),(0,p.jsx)(v,{theme:i,onSelect:a})]})]}),o&&(0,p.jsx)(`div`,{className:`text-[11px] text-status-success`,children:`已保存`})]})}function b({cdpStatus:e}){return(0,p.jsxs)(`div`,{className:`rounded p-3 space-y-2 border border-border bg-surface`,children:[(0,p.jsx)(`div`,{className:`text-[11px] font-medium text-text-secondary`,children:`当前状态`}),(0,p.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,p.jsx)(`span`,{className:`inline-block w-2 h-2 rounded-full`,style:{background:e?.active?`var(--color-status-success)`:`var(--color-text-dim)`}}),(0,p.jsx)(`span`,{className:`text-[12px] text-text-secondary`,children:e?.active?`CDP 已激活 - 端口 ${e.activePort}`:`CDP 未激活`})]}),e?.implicitDevDefault&&(0,p.jsx)(`div`,{className:`text-[11px] text-text-dim`,children:`当前为开发模式默认端口`}),e?.active&&(0,p.jsxs)(`div`,{className:`text-[11px] text-text-dim font-mono`,children:[`调试地址: http://localhost:`,e.activePort]})]})}function x(e,t){return!e||e.implicitDevDefault?!1:t.enabled===e.active?t.enabled&&e.active&&t.port!==e.activePort:!0}function S({cdpEnabled:e,onToggleCdp:t,portInput:n,onPortInputChange:r,cdpStatus:a,needsRestart:o,onSave:s,saved:c}){return(0,p.jsxs)(`section`,{className:`rounded-lg border border-border p-4 space-y-4 bg-bg`,children:[(0,p.jsxs)(`div`,{children:[(0,p.jsx)(`h2`,{className:`text-[13px] font-medium mb-1`,children:`DevTools Protocol`}),(0,p.jsx)(`p`,{className:`text-[11px] leading-relaxed text-text-secondary`,children:`开启后可通过 DevTools Protocol 连接调试模拟器。配置变更需要重启应用后生效。`})]}),(0,p.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,p.jsx)(`span`,{className:`text-[12px] text-text-secondary`,children:`启用 DevTools Protocol`}),(0,p.jsx)(g,{checked:e,onClick:t})]}),(0,p.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,p.jsx)(`label`,{className:`text-[12px] shrink-0 w-16 text-text-secondary`,children:`调试端口`}),(0,p.jsx)(`input`,{type:`number`,min:1024,max:65535,value:n,onChange:e=>r(e.target.value),disabled:!e,className:`w-24 h-7 px-2 rounded text-[12px] outline-none bg-surface border border-border text-text`,style:{opacity:e?1:.4}}),(0,p.jsxs)(`span`,{className:`text-[11px] text-text-dim`,children:[`默认 `,i]})]}),(0,p.jsx)(b,{cdpStatus:a}),o&&(0,p.jsx)(`div`,{className:`rounded px-3 py-2 text-[12px] border bg-warn-bg text-[var(--color-status-warn)]`,children:`配置已变更,需要重启应用后生效`}),(0,p.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,p.jsx)(`button`,{onClick:s,className:`h-7 px-4 rounded text-[13px] font-medium text-white bg-accent hover:bg-accent-hover`,children:`保存`}),c&&(0,p.jsx)(`span`,{className:`text-[11px] text-status-success`,children:`已保存`})]})]})}function C({color:e,children:t}){return(0,p.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,p.jsx)(`span`,{className:`inline-block w-2 h-2 rounded-full`,style:{background:e}}),(0,p.jsx)(`span`,{className:`text-[12px] text-text-secondary`,children:t})]})}function w({mcpEnabled:e,mcpStatus:t}){return(0,p.jsxs)(`div`,{className:`rounded p-3 space-y-2 border border-border bg-surface`,children:[(0,p.jsx)(`div`,{className:`text-[11px] font-medium text-text-secondary`,children:`当前状态`}),e?t?.running?(0,p.jsxs)(C,{color:`var(--color-status-success)`,children:[`MCP 已运行 - 端口 `,t.activePort]}):(0,p.jsxs)(C,{color:`var(--color-status-error, #e54d4d)`,children:[`MCP 未运行`,t?.error===`port-in-use`?`(端口 ${t.configuredPort} 已被占用)`:t?.error?`(${t.error})`:``]}):(0,p.jsx)(C,{color:`var(--color-text-dim)`,children:`MCP 未启用`})]})}function T({mcpEnabled:e,onToggleMcp:t,mcpPortInput:n,onMcpPortInputChange:r,mcpStatus:i,mcpPort:a,onSave:o,saved:s}){return(0,p.jsxs)(`section`,{className:`rounded-lg border border-border p-4 space-y-4 bg-bg`,children:[(0,p.jsxs)(`div`,{children:[(0,p.jsx)(`h2`,{className:`text-[13px] font-medium mb-1`,children:`MCP 配置`}),(0,p.jsx)(`p`,{className:`text-[11px] leading-relaxed text-text-secondary`,children:`AI 助手可以通过 MCP 连接当前开发工具,读取 console、截图、执行 JS、查看 DOM / Storage / 网络请求。启用后开发工具启动时会自动监听 SSE 端点,并自动启用 CDP。`})]}),(0,p.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,p.jsx)(`span`,{className:`text-[12px] text-text-secondary`,children:`启用 MCP 服务`}),(0,p.jsx)(g,{checked:e,onClick:t})]}),(0,p.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,p.jsx)(`label`,{className:`text-[12px] shrink-0 w-16 text-text-secondary`,children:`SSE 端口`}),(0,p.jsx)(`input`,{type:`number`,min:1024,max:65535,value:n,onChange:e=>r(e.target.value),disabled:!e,className:`w-24 h-7 px-2 rounded text-[12px] outline-none bg-surface border border-border text-text`,style:{opacity:e?1:.4}}),(0,p.jsx)(`span`,{className:`text-[11px] text-text-dim`,children:`默认 7789`})]}),(0,p.jsx)(w,{mcpEnabled:e,mcpStatus:i}),(0,p.jsxs)(`div`,{className:`rounded p-3 border border-border bg-surface`,children:[(0,p.jsx)(`div`,{className:`text-[11px] font-medium mb-2 text-text-secondary`,children:"`.mcp.json` 示例(SSE 传输)"}),(0,p.jsx)(`pre`,{className:`text-[11px] whitespace-pre-wrap leading-relaxed text-[var(--color-code-blue)] font-mono`,children:`{
|
|
2
2
|
"mcpServers": {
|
|
3
3
|
"dimina-devtools": {
|
|
4
4
|
"url": "http://127.0.0.1:${a}/sse"
|
|
5
5
|
}
|
|
6
6
|
}
|
|
7
7
|
}`})]}),(0,p.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,p.jsx)(`button`,{onClick:o,className:`h-7 px-4 rounded text-[13px] font-medium text-white bg-accent hover:bg-accent-hover`,children:`保存`}),s&&(0,p.jsx)(`span`,{className:`text-[11px] text-status-success`,children:`已保存`})]})]})}function E(){let[e,t]=(0,f.useState)({cdp:{enabled:!1,port:i},mcp:{enabled:!1,port:7789},compile:{autoBuild:!0},preview:{autoReload:!0},theme:`system`,lastCreateBaseDir:null}),[n,r]=(0,f.useState)(null),[d,m]=(0,f.useState)(null),[h,g]=(0,f.useState)(`general`),[v,b]=(0,f.useState)(!1),[C,w]=(0,f.useState)(String(i)),[E,D]=(0,f.useState)(`7789`);(0,f.useEffect)(()=>{let e=l(e=>{t(e.settings),w(String(e.settings.cdp.port)),D(String(e.settings.mcp.port))});return a().then(e=>{t(e),w(String(e.cdp.port)),D(String(e.mcp.port))}),c().then(r),s().then(m),e},[]);function O(){b(!0),window.setTimeout(()=>b(!1),2e3)}function k(){t(e=>({...e,cdp:{...e.cdp,enabled:!e.cdp.enabled}}))}function A(){t(e=>({...e,mcp:{...e.mcp,enabled:!e.mcp.enabled}}))}function j(n){let r={...e,theme:n};t(r),u(n),o(r)}function M(e){t(e),o(e).then(O)}async function N(){let n=parseInt(C,10);if(Number.isNaN(n)||n<1024||n>65535)return;let i=parseInt(E,10);if(Number.isNaN(i)||i<1024||i>65535)return;let a={...e,cdp:{...e.cdp,port:n},mcp:{...e.mcp,port:i}};t(a),await o(a),r(await c()),m(await s()),O()}let P=x(n,e.cdp);return(0,p.jsxs)(`div`,{className:`flex flex-col h-screen bg-surface text-text`,children:[(0,p.jsx)(_,{activeTab:h,onSelect:g}),(0,p.jsxs)(`div`,{className:`flex-1 overflow-y-auto p-4`,children:[h===`general`&&(0,p.jsx)(y,{autoBuildEnabled:e.compile.autoBuild,onAutoBuildChange:t=>M({...e,compile:{...e.compile,autoBuild:t}}),autoReloadEnabled:e.preview.autoReload,onAutoReloadChange:t=>M({...e,preview:{...e.preview,autoReload:t}}),theme:e.theme,onThemeChange:j,saved:v}),h===`debug`&&(0,p.jsx)(S,{cdpEnabled:e.cdp.enabled,onToggleCdp:k,portInput:C,onPortInputChange:w,cdpStatus:n,needsRestart:P,onSave:N,saved:v}),h===`mcp`&&(0,p.jsx)(T,{mcpEnabled:e.mcp.enabled,onToggleMcp:A,mcpPortInput:E,onMcpPortInputChange:D,mcpStatus:d,mcpPort:e.mcp.port,onSave:N,saved:v})]})]})}d.createRoot(document.getElementById(`root`)).render((0,p.jsx)(E,{}));
|
|
8
|
-
//# sourceMappingURL=workbenchSettings-
|
|
8
|
+
//# sourceMappingURL=workbenchSettings-CtRBr7gS.js.map
|
|
@@ -26,13 +26,13 @@
|
|
|
26
26
|
overflow: hidden;
|
|
27
27
|
}
|
|
28
28
|
</style>
|
|
29
|
-
<script type="module" crossorigin src="../../assets/index-
|
|
30
|
-
<link rel="modulepreload" crossorigin href="../../assets/ipc-transport-
|
|
31
|
-
<link rel="modulepreload" crossorigin href="../../assets/input-
|
|
32
|
-
<link rel="modulepreload" crossorigin href="../../assets/select-
|
|
33
|
-
<link rel="modulepreload" crossorigin href="../../assets/settings-api-
|
|
29
|
+
<script type="module" crossorigin src="../../assets/index-WbvXdhWQ.js"></script>
|
|
30
|
+
<link rel="modulepreload" crossorigin href="../../assets/ipc-transport-SuI2rOB_.js">
|
|
31
|
+
<link rel="modulepreload" crossorigin href="../../assets/input-COtRON-n.js">
|
|
32
|
+
<link rel="modulepreload" crossorigin href="../../assets/select-Bwb8O0Mf.js">
|
|
33
|
+
<link rel="modulepreload" crossorigin href="../../assets/settings-api-HIBz8BFz.js">
|
|
34
34
|
<link rel="modulepreload" crossorigin href="../../assets/constants-EAMiwL9_.js">
|
|
35
|
-
<link rel="stylesheet" crossorigin href="../../assets/ipc-transport-
|
|
35
|
+
<link rel="stylesheet" crossorigin href="../../assets/ipc-transport-CNvORIEX.css">
|
|
36
36
|
</head>
|
|
37
37
|
<body>
|
|
38
38
|
<div id="root"></div>
|
|
@@ -8,12 +8,12 @@
|
|
|
8
8
|
<style>
|
|
9
9
|
html, body { margin: 0; padding: 0; width: 100%; height: 100%; overflow: hidden; background: transparent !important; }
|
|
10
10
|
</style>
|
|
11
|
-
<script type="module" crossorigin src="../../assets/popover-
|
|
12
|
-
<link rel="modulepreload" crossorigin href="../../assets/ipc-transport-
|
|
13
|
-
<link rel="modulepreload" crossorigin href="../../assets/input-
|
|
14
|
-
<link rel="modulepreload" crossorigin href="../../assets/select-
|
|
11
|
+
<script type="module" crossorigin src="../../assets/popover-B73T3z-m.js"></script>
|
|
12
|
+
<link rel="modulepreload" crossorigin href="../../assets/ipc-transport-SuI2rOB_.js">
|
|
13
|
+
<link rel="modulepreload" crossorigin href="../../assets/input-COtRON-n.js">
|
|
14
|
+
<link rel="modulepreload" crossorigin href="../../assets/select-Bwb8O0Mf.js">
|
|
15
15
|
<link rel="modulepreload" crossorigin href="../../assets/constants-EAMiwL9_.js">
|
|
16
|
-
<link rel="stylesheet" crossorigin href="../../assets/ipc-transport-
|
|
16
|
+
<link rel="stylesheet" crossorigin href="../../assets/ipc-transport-CNvORIEX.css">
|
|
17
17
|
</head>
|
|
18
18
|
<body>
|
|
19
19
|
<div id="root"></div>
|
|
@@ -11,11 +11,11 @@
|
|
|
11
11
|
closes the overlay — mirrors the popover entry. */
|
|
12
12
|
html, body { margin: 0; padding: 0; width: 100%; height: 100%; overflow: hidden; background: transparent !important; }
|
|
13
13
|
</style>
|
|
14
|
-
<script type="module" crossorigin src="../../assets/settings-
|
|
15
|
-
<link rel="modulepreload" crossorigin href="../../assets/ipc-transport-
|
|
16
|
-
<link rel="modulepreload" crossorigin href="../../assets/input-
|
|
17
|
-
<link rel="modulepreload" crossorigin href="../../assets/settings-api-
|
|
18
|
-
<link rel="stylesheet" crossorigin href="../../assets/ipc-transport-
|
|
14
|
+
<script type="module" crossorigin src="../../assets/settings-BispnvJU.js"></script>
|
|
15
|
+
<link rel="modulepreload" crossorigin href="../../assets/ipc-transport-SuI2rOB_.js">
|
|
16
|
+
<link rel="modulepreload" crossorigin href="../../assets/input-COtRON-n.js">
|
|
17
|
+
<link rel="modulepreload" crossorigin href="../../assets/settings-api-HIBz8BFz.js">
|
|
18
|
+
<link rel="stylesheet" crossorigin href="../../assets/ipc-transport-CNvORIEX.css">
|
|
19
19
|
</head>
|
|
20
20
|
<body>
|
|
21
21
|
<div id="root"></div>
|
|
@@ -6,11 +6,11 @@
|
|
|
6
6
|
<!-- See entries/main/index.html for CSP rationale. -->
|
|
7
7
|
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: http: https:; font-src 'self' data:; media-src 'self' blob: http: https:; connect-src 'self' http: https: ws: wss:;" />
|
|
8
8
|
<title>开发工具设置</title>
|
|
9
|
-
<script type="module" crossorigin src="../../assets/workbenchSettings-
|
|
10
|
-
<link rel="modulepreload" crossorigin href="../../assets/ipc-transport-
|
|
11
|
-
<link rel="modulepreload" crossorigin href="../../assets/settings-api-
|
|
9
|
+
<script type="module" crossorigin src="../../assets/workbenchSettings-CtRBr7gS.js"></script>
|
|
10
|
+
<link rel="modulepreload" crossorigin href="../../assets/ipc-transport-SuI2rOB_.js">
|
|
11
|
+
<link rel="modulepreload" crossorigin href="../../assets/settings-api-HIBz8BFz.js">
|
|
12
12
|
<link rel="modulepreload" crossorigin href="../../assets/constants-EAMiwL9_.js">
|
|
13
|
-
<link rel="stylesheet" crossorigin href="../../assets/ipc-transport-
|
|
13
|
+
<link rel="stylesheet" crossorigin href="../../assets/ipc-transport-CNvORIEX.css">
|
|
14
14
|
</head>
|
|
15
15
|
<body>
|
|
16
16
|
<div id="root"></div>
|
|
@@ -67,31 +67,7 @@ export declare const SimulatorStorageChannel: {
|
|
|
67
67
|
readonly ClearAll: "simulator:storage:clearAll";
|
|
68
68
|
readonly Event: "simulator:storage:event";
|
|
69
69
|
};
|
|
70
|
-
export
|
|
71
|
-
key: string;
|
|
72
|
-
value: string;
|
|
73
|
-
}
|
|
74
|
-
export type StorageEvent = {
|
|
75
|
-
type: 'added';
|
|
76
|
-
key: string;
|
|
77
|
-
newValue: string;
|
|
78
|
-
} | {
|
|
79
|
-
type: 'updated';
|
|
80
|
-
key: string;
|
|
81
|
-
oldValue: string;
|
|
82
|
-
newValue: string;
|
|
83
|
-
} | {
|
|
84
|
-
type: 'removed';
|
|
85
|
-
key: string;
|
|
86
|
-
} | {
|
|
87
|
-
type: 'cleared';
|
|
88
|
-
};
|
|
89
|
-
export type StorageWriteResult = {
|
|
90
|
-
ok: true;
|
|
91
|
-
} | {
|
|
92
|
-
ok: false;
|
|
93
|
-
error: string;
|
|
94
|
-
};
|
|
70
|
+
export type { StorageEvent, StorageItem, StorageWriteResult } from '@dimina-kit/inspect';
|
|
95
71
|
/**
|
|
96
72
|
* A storage mutation reported by the service-host's SYNC wx storage APIs
|
|
97
73
|
* (`setStorageSync`/`removeStorageSync`/`clearStorageSync`). Those run inside the
|
|
@@ -126,25 +102,7 @@ export declare const SimulatorAppDataChannel: {
|
|
|
126
102
|
readonly GetSnapshot: "simulator:appdata:snapshot";
|
|
127
103
|
readonly Event: "simulator:appdata:event";
|
|
128
104
|
};
|
|
129
|
-
export
|
|
130
|
-
sid: string;
|
|
131
|
-
rect: {
|
|
132
|
-
x: number;
|
|
133
|
-
y: number;
|
|
134
|
-
width: number;
|
|
135
|
-
height: number;
|
|
136
|
-
};
|
|
137
|
-
style: {
|
|
138
|
-
display: string;
|
|
139
|
-
position: string;
|
|
140
|
-
boxSizing: string;
|
|
141
|
-
margin: string;
|
|
142
|
-
padding: string;
|
|
143
|
-
color: string;
|
|
144
|
-
backgroundColor: string;
|
|
145
|
-
fontSize: string;
|
|
146
|
-
};
|
|
147
|
-
}
|
|
105
|
+
export type { ElementInspection } from '@dimina-kit/inspect';
|
|
148
106
|
export declare const WorkbenchSettingsChannel: {
|
|
149
107
|
readonly Get: "workbenchSettings:get";
|
|
150
108
|
readonly Save: "workbenchSettings:save";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dimina-kit/devtools",
|
|
3
|
-
"version": "0.4.0-dev.
|
|
3
|
+
"version": "0.4.0-dev.20260711062001",
|
|
4
4
|
"description": "Dimina DevTools - modular developer tools for mini app debugging",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dimina",
|
|
@@ -85,9 +85,10 @@
|
|
|
85
85
|
"chrome-remote-interface": "^0.34.0",
|
|
86
86
|
"ws": "^8.20.0",
|
|
87
87
|
"zod": "^4.3.6",
|
|
88
|
-
"@dimina-kit/devkit": "0.1.2-dev.
|
|
89
|
-
"@dimina-kit/
|
|
90
|
-
"@dimina-kit/
|
|
88
|
+
"@dimina-kit/devkit": "0.1.2-dev.20260711062001",
|
|
89
|
+
"@dimina-kit/view-anchor": "0.1.0-dev.20260711062001",
|
|
90
|
+
"@dimina-kit/electron-deck": "0.1.0-dev.20260711062001",
|
|
91
|
+
"@dimina-kit/inspect": "0.3.0"
|
|
91
92
|
},
|
|
92
93
|
"devDependencies": {
|
|
93
94
|
"@playwright/test": "^1.59.1",
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { type WxmlNode } from '../shared/sid-registry.js';
|
|
2
|
-
export interface ComponentInstance extends Record<string, unknown> {
|
|
3
|
-
type?: Record<string, unknown>;
|
|
4
|
-
props?: Record<string, unknown>;
|
|
5
|
-
attrs?: Record<string, unknown>;
|
|
6
|
-
parent?: Record<string, unknown>;
|
|
7
|
-
appContext?: Record<string, unknown>;
|
|
8
|
-
subTree?: Record<string, unknown>;
|
|
9
|
-
}
|
|
10
|
-
export declare function walkInstance(instance: ComponentInstance, depth: number): WxmlNode | WxmlNode[] | null;
|
|
11
|
-
//# sourceMappingURL=wxml-extract.d.ts.map
|
|
@@ -1,382 +0,0 @@
|
|
|
1
|
-
import { registerSyntheticSid } from '../shared/sid-registry.js';
|
|
2
|
-
const INTERNAL_CLASSES = new Set([
|
|
3
|
-
'dd-swiper-wrapper', 'dd-swiper-slides', 'dd-swiper-slide-frame', 'dd-swiper-dots',
|
|
4
|
-
'dd-picker-overlay', 'dd-picker-container', 'dd-picker-header', 'dd-picker-body',
|
|
5
|
-
]);
|
|
6
|
-
const FRAMEWORK_TEMPLATE_RE = /^(taro_tmpl|tmpl_\d+)/;
|
|
7
|
-
/**
|
|
8
|
-
* Strip the `dd-` registration prefix and the `tpl-` prefix dimina adds to
|
|
9
|
-
* compiled template components (`app.component('dd-tpl-taro_tmpl', …)`), so a
|
|
10
|
-
* framework template wrapper normalizes to its bare name (`taro_tmpl`,
|
|
11
|
-
* `tmpl_0_3`) and `FRAMEWORK_TEMPLATE_RE` recognizes it.
|
|
12
|
-
*/
|
|
13
|
-
function normalizeRegisteredName(regName) {
|
|
14
|
-
const base = regName.startsWith('dd-') ? regName.slice(3) : regName;
|
|
15
|
-
return base.startsWith('tpl-') ? base.slice(4) : base;
|
|
16
|
-
}
|
|
17
|
-
function resolveTemplateNameFromParent(instance) {
|
|
18
|
-
const parent = instance.parent;
|
|
19
|
-
const parentType = parent?.type;
|
|
20
|
-
const components = parentType?.components;
|
|
21
|
-
if (components) {
|
|
22
|
-
for (const [regName, comp] of Object.entries(components)) {
|
|
23
|
-
if (comp === instance.type)
|
|
24
|
-
return normalizeRegisteredName(regName);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
const appComponents = instance.appContext?.components;
|
|
28
|
-
if (!appComponents)
|
|
29
|
-
return null;
|
|
30
|
-
for (const [regName, comp] of Object.entries(appComponents)) {
|
|
31
|
-
if (comp === instance.type)
|
|
32
|
-
return normalizeRegisteredName(regName);
|
|
33
|
-
}
|
|
34
|
-
return null;
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Convert a PascalCase / camelCase identifier to kebab-case. Matches the
|
|
38
|
-
* upstream `camelCaseToUnderscore` (dimina/fe/packages/common) so a name
|
|
39
|
-
* already normalized by `withInstall` round-trips identically.
|
|
40
|
-
* `View` -> `view`, `ScrollView` -> `scroll-view`, `CoverImage` -> `cover-image`.
|
|
41
|
-
*/
|
|
42
|
-
function pascalToKebab(name) {
|
|
43
|
-
return name.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Read the page's source path off Vue's provide/inject. dimina runtime.js 在
|
|
47
|
-
* dd-page 的 setup() 里调用 `provide('path', path)`,Vue 把它存到
|
|
48
|
-
* `instance.provides`。我们利用这个把页面节点的 tagName 从硬编码 `page`
|
|
49
|
-
* 升级为页面全路径(如 `pages/index/index`),对齐微信开发者工具。
|
|
50
|
-
*/
|
|
51
|
-
function resolvePagePath(instance) {
|
|
52
|
-
// dimina runtime 在 dd-page 的 setup 里 `instance.proxy.__page__ = true` 并
|
|
53
|
-
// `provide('path', path)`。两个标记同时具备才视为页面层级,避免 dd-page
|
|
54
|
-
// 的子节点继承 provides.path 后被误判(Vue 用 Object.create 链式 provides)。
|
|
55
|
-
const proxy = instance.proxy;
|
|
56
|
-
if (proxy?.__page__ !== true)
|
|
57
|
-
return null;
|
|
58
|
-
const provides = instance.provides;
|
|
59
|
-
const path = provides?.path;
|
|
60
|
-
if (typeof path !== 'string' || !path)
|
|
61
|
-
return null;
|
|
62
|
-
return path.startsWith('/') ? path.slice(1) : path;
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* A NATIVE dimina custom component (a `usingComponents` entry) calls
|
|
66
|
-
* `provide('path', componentPath)` in its setup (render runtime), so its
|
|
67
|
-
* provided `path` DIFFERS from its parent's. A plain descendant inherits the
|
|
68
|
-
* same provides object (identical `path`) and is not a boundary; a Taro template
|
|
69
|
-
* wrapper (`dd-tpl-*`) never provides, so it never differs either. Comparing
|
|
70
|
-
* against the parent's provided path therefore isolates exactly the native
|
|
71
|
-
* component roots — matching WeChat, which shows each custom component as a node
|
|
72
|
-
* tagged with its full registered path (with a synthetic `#shadow-root` added by
|
|
73
|
-
* `wrapInShadowRoot` since the path contains `/`). Pages are handled earlier via
|
|
74
|
-
* their authoritative `__page__` marker, so this only fires for components.
|
|
75
|
-
*/
|
|
76
|
-
function resolveComponentPath(instance) {
|
|
77
|
-
const provides = instance.provides;
|
|
78
|
-
const path = provides?.path;
|
|
79
|
-
if (typeof path !== 'string' || !path)
|
|
80
|
-
return null;
|
|
81
|
-
const parent = instance.parent;
|
|
82
|
-
const parentProvides = parent?.provides;
|
|
83
|
-
if (path === parentProvides?.path)
|
|
84
|
-
return null;
|
|
85
|
-
return path.startsWith('/') ? path.slice(1) : path;
|
|
86
|
-
}
|
|
87
|
-
function resolveTagName(instance) {
|
|
88
|
-
const type = instance.type;
|
|
89
|
-
if (!type)
|
|
90
|
-
return 'unknown';
|
|
91
|
-
// 页面层级优先:dd-page 没有 __tagName/__name,且 home 页等无 usingComponents
|
|
92
|
-
// 的页面 type.components 为 undefined,会落到 resolveTemplateNameFromParent
|
|
93
|
-
// 回到 'page'。在那之前直接用 provide('path') 的路径升级 tag 名。
|
|
94
|
-
const pagePath = resolvePagePath(instance);
|
|
95
|
-
if (pagePath)
|
|
96
|
-
return pagePath;
|
|
97
|
-
// Native custom-component boundary → tag with its full registered path (WeChat
|
|
98
|
-
// parity). Must precede the __tagName/__name/dd- shortening below, which would
|
|
99
|
-
// otherwise collapse `dd-foo` to the bare `foo` and lose the path.
|
|
100
|
-
const componentPath = resolveComponentPath(instance);
|
|
101
|
-
if (componentPath)
|
|
102
|
-
return componentPath;
|
|
103
|
-
if (typeof type.__tagName === 'string')
|
|
104
|
-
return type.__tagName;
|
|
105
|
-
const name = (type.__name || type.name);
|
|
106
|
-
if (!name) {
|
|
107
|
-
// A nameless component carrying a `__scopeId` is a compiled page, custom
|
|
108
|
-
// component, or framework template wrapper. The page is already resolved
|
|
109
|
-
// above via its authoritative `__page__` marker, so by here it is NOT a
|
|
110
|
-
// page — recover the registered tag (e.g. a Taro `taro_tmpl`/`tmpl_0_3`
|
|
111
|
-
// wrapper) and fall back to `template`. Defaulting to `page` here would
|
|
112
|
-
// mislabel every such wrapper as a second page root.
|
|
113
|
-
if (type.__scopeId)
|
|
114
|
-
return resolveTemplateNameFromParent(instance) || 'template';
|
|
115
|
-
return 'unknown';
|
|
116
|
-
}
|
|
117
|
-
if (name === 'dd-page')
|
|
118
|
-
return 'page';
|
|
119
|
-
if (name.startsWith('dd-'))
|
|
120
|
-
return name.slice(3);
|
|
121
|
-
// Reverse-map Dimina component names back to their miniprogram tag names.
|
|
122
|
-
// The installer (`withInstall`) sets `__tagName = camelCaseToUnderscore(__name)`,
|
|
123
|
-
// but in dev builds, custom registrations, or when the installer hasn't run,
|
|
124
|
-
// we may only see the raw `__name`/`name` (e.g. `View`, `ScrollView`, `DdButton`).
|
|
125
|
-
// Without this fallback the WXML panel would surface the upstream Vue name
|
|
126
|
-
// verbatim, defeating the panel's purpose of showing source-level tags.
|
|
127
|
-
if (name.startsWith('Dd') && name.length > 2)
|
|
128
|
-
return pascalToKebab(name.slice(2));
|
|
129
|
-
if (/^[A-Z]/.test(name))
|
|
130
|
-
return pascalToKebab(name);
|
|
131
|
-
return name;
|
|
132
|
-
}
|
|
133
|
-
/** Props/attrs entries that never surface in the WXML panel (internal Vue plumbing, falsy booleans). */
|
|
134
|
-
function isSkippedProp(key, value) {
|
|
135
|
-
if (typeof value === 'function' || value === undefined)
|
|
136
|
-
return true;
|
|
137
|
-
if (key === 'data' || key.startsWith('__'))
|
|
138
|
-
return true;
|
|
139
|
-
return typeof value === 'boolean' && !value;
|
|
140
|
-
}
|
|
141
|
-
/** Drop the `dd-` internal-marker classes so the panel shows only user-authored classes. */
|
|
142
|
-
function cleanClassAttr(value) {
|
|
143
|
-
return value.split(/\s+/).filter((c) => !c.startsWith('dd-')).join(' ');
|
|
144
|
-
}
|
|
145
|
-
function stringifyPropValue(value) {
|
|
146
|
-
return typeof value === 'object' ? JSON.stringify(value) : String(value);
|
|
147
|
-
}
|
|
148
|
-
function assignProp(out, key, value) {
|
|
149
|
-
if (isSkippedProp(key, value))
|
|
150
|
-
return;
|
|
151
|
-
if (key === 'class' && typeof value === 'string') {
|
|
152
|
-
const cleaned = cleanClassAttr(value);
|
|
153
|
-
if (cleaned)
|
|
154
|
-
out[key] = cleaned;
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
out[key] = stringifyPropValue(value);
|
|
158
|
-
}
|
|
159
|
-
function extractProps(instance) {
|
|
160
|
-
const out = {};
|
|
161
|
-
for (const raw of [instance.props, instance.attrs]) {
|
|
162
|
-
if (!raw)
|
|
163
|
-
continue;
|
|
164
|
-
for (const [k, v] of Object.entries(raw)) {
|
|
165
|
-
assignProp(out, k, v);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
return out;
|
|
169
|
-
}
|
|
170
|
-
function isInternalElement(vnode) {
|
|
171
|
-
const props = vnode.props;
|
|
172
|
-
if (!props)
|
|
173
|
-
return false;
|
|
174
|
-
const cls = String(props.class || '');
|
|
175
|
-
return cls.split(/\s+/).some((c) => INTERNAL_CLASSES.has(c));
|
|
176
|
-
}
|
|
177
|
-
function getElementSid(instance) {
|
|
178
|
-
const subTree = instance.subTree;
|
|
179
|
-
const el = subTree?.el;
|
|
180
|
-
if (!el?.getAttribute)
|
|
181
|
-
return undefined;
|
|
182
|
-
const sid = el.getAttribute('data-sid');
|
|
183
|
-
if (sid)
|
|
184
|
-
return sid;
|
|
185
|
-
return registerSyntheticSid(el);
|
|
186
|
-
}
|
|
187
|
-
function isTransparentComponent(instance, tagName) {
|
|
188
|
-
if (tagName === 'unknown')
|
|
189
|
-
return true;
|
|
190
|
-
// A framework template wrapper (Taro `taro_tmpl` / `tmpl_0_3`, whether named
|
|
191
|
-
// via `props.is` or recovered from its registration) is compiler scaffolding,
|
|
192
|
-
// not user content — pass its children straight through.
|
|
193
|
-
if (FRAMEWORK_TEMPLATE_RE.test(tagName))
|
|
194
|
-
return true;
|
|
195
|
-
if (tagName === 'template') {
|
|
196
|
-
const props = instance.props;
|
|
197
|
-
const is = props?.is;
|
|
198
|
-
if (is && FRAMEWORK_TEMPLATE_RE.test(is))
|
|
199
|
-
return true;
|
|
200
|
-
if (!is) {
|
|
201
|
-
const type = instance.type;
|
|
202
|
-
if (type?.__scopeId && !type.components)
|
|
203
|
-
return true;
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
return false;
|
|
207
|
-
}
|
|
208
|
-
/**
|
|
209
|
-
* 检测 Vue 的 Comment vnode(`v-if`/`v-else`/`v-for` 占位锚点)。
|
|
210
|
-
* Vue 在条件不成立时会留下 `<!-- v-if -->` 这样的注释 vnode 用作 DOM 锚点。
|
|
211
|
-
* 这些 vnode 不是用户内容,必须从 wxml 树里剔除。
|
|
212
|
-
*
|
|
213
|
-
* - dev build:type 是 `Symbol('Comment')`,description = 'Comment' 或 'v-cmt'
|
|
214
|
-
* - prod build:description 可能丢失,但 children 一般是 'v-if'/'v-else' 等 marker
|
|
215
|
-
*/
|
|
216
|
-
function isCommentVNode(vnode) {
|
|
217
|
-
const type = vnode.type;
|
|
218
|
-
if (typeof type !== 'symbol')
|
|
219
|
-
return false;
|
|
220
|
-
const desc = type.description;
|
|
221
|
-
if (desc === 'Comment' || desc === 'v-cmt')
|
|
222
|
-
return true;
|
|
223
|
-
const children = typeof vnode.children === 'string' ? vnode.children : '';
|
|
224
|
-
return /^v-(if|else|else-if|for)$/.test(children);
|
|
225
|
-
}
|
|
226
|
-
function textNode(text) {
|
|
227
|
-
return { tagName: '#text', attrs: {}, children: [], text };
|
|
228
|
-
}
|
|
229
|
-
/** A component vnode's children come from walking its mounted instance, not `vnode.children`. */
|
|
230
|
-
function childrenFromComponentVNode(component, depth) {
|
|
231
|
-
const result = walkInstance(component, depth + 1);
|
|
232
|
-
if (!result)
|
|
233
|
-
return [];
|
|
234
|
-
return Array.isArray(result) ? result : [result];
|
|
235
|
-
}
|
|
236
|
-
/** A `<Suspense>` vnode's visible content is whichever branch is currently active. */
|
|
237
|
-
function childrenFromSuspenseVNode(suspense, depth) {
|
|
238
|
-
const activeBranch = suspense.activeBranch;
|
|
239
|
-
return activeBranch ? extractChildrenFromVNode(activeBranch, depth + 1) : [];
|
|
240
|
-
}
|
|
241
|
-
/**
|
|
242
|
-
* A vnode whose OWN `children` is a plain string only counts as a text node when
|
|
243
|
-
* its `type` is a symbol/string (a real element or fragment) — a component vnode
|
|
244
|
-
* with string `children` is slot content, not text, and is handled elsewhere.
|
|
245
|
-
* Returns null when this vnode is not (top-level) text, so the caller falls
|
|
246
|
-
* through to the array-children path.
|
|
247
|
-
*/
|
|
248
|
-
function directTextChild(vnode) {
|
|
249
|
-
if (typeof vnode.children !== 'string' || !vnode.children.trim())
|
|
250
|
-
return null;
|
|
251
|
-
const vnodeType = vnode.type;
|
|
252
|
-
if (typeof vnodeType !== 'symbol' && typeof vnodeType !== 'string')
|
|
253
|
-
return null;
|
|
254
|
-
return [textNode(vnode.children.trim())];
|
|
255
|
-
}
|
|
256
|
-
function textChildEntry(child) {
|
|
257
|
-
const trimmed = child.trim();
|
|
258
|
-
return trimmed ? [textNode(trimmed)] : [];
|
|
259
|
-
}
|
|
260
|
-
/** A DOM-typed child (`type` is its tag name string): text leaf, internal wrapper, or a normal subtree. */
|
|
261
|
-
function domTypedChildEntries(c, depth) {
|
|
262
|
-
if (isInternalElement(c))
|
|
263
|
-
return extractChildrenFromVNode(c, depth + 1);
|
|
264
|
-
if (typeof c.children === 'string' && c.children.trim())
|
|
265
|
-
return [textNode(c.children.trim())];
|
|
266
|
-
return extractChildrenFromVNode(c, depth + 1);
|
|
267
|
-
}
|
|
268
|
-
/** One entry from a vnode's `children` array, normalized to zero or more WXML nodes. */
|
|
269
|
-
function extractChildEntry(child, depth) {
|
|
270
|
-
if (!child)
|
|
271
|
-
return [];
|
|
272
|
-
if (typeof child === 'string')
|
|
273
|
-
return textChildEntry(child);
|
|
274
|
-
if (typeof child !== 'object')
|
|
275
|
-
return [];
|
|
276
|
-
const c = child;
|
|
277
|
-
if (c.component)
|
|
278
|
-
return childrenFromComponentVNode(c.component, depth);
|
|
279
|
-
if (typeof c.type === 'symbol')
|
|
280
|
-
return extractChildrenFromVNode(c, depth + 1);
|
|
281
|
-
if (typeof c.type === 'string')
|
|
282
|
-
return domTypedChildEntries(c, depth);
|
|
283
|
-
return extractChildrenFromVNode(c, depth + 1);
|
|
284
|
-
}
|
|
285
|
-
function extractChildrenFromVNode(vnode, depth) {
|
|
286
|
-
if (!vnode || depth > 50)
|
|
287
|
-
return [];
|
|
288
|
-
if (isCommentVNode(vnode))
|
|
289
|
-
return [];
|
|
290
|
-
if (vnode.component)
|
|
291
|
-
return childrenFromComponentVNode(vnode.component, depth);
|
|
292
|
-
if (vnode.suspense)
|
|
293
|
-
return childrenFromSuspenseVNode(vnode.suspense, depth);
|
|
294
|
-
const directText = directTextChild(vnode);
|
|
295
|
-
if (directText)
|
|
296
|
-
return directText;
|
|
297
|
-
const kids = vnode.children;
|
|
298
|
-
if (!Array.isArray(kids))
|
|
299
|
-
return [];
|
|
300
|
-
const result = [];
|
|
301
|
-
for (const child of kids) {
|
|
302
|
-
result.push(...extractChildEntry(child, depth));
|
|
303
|
-
}
|
|
304
|
-
return result;
|
|
305
|
-
}
|
|
306
|
-
/**
|
|
307
|
-
* Reverse-map Dimina's `<wrapper name="/components/foo/foo">` (used to host
|
|
308
|
-
* every user-defined component) back to the source-level tag the user wrote
|
|
309
|
-
* in WXML (e.g. `<foo>`).
|
|
310
|
-
*
|
|
311
|
-
* The wrapper carries the registered component path in its `name` Vue prop.
|
|
312
|
-
* By convention (also followed by miniprogram tooling), the registered key is
|
|
313
|
-
* the last path segment, optionally stripping a trailing `/index`. We can't
|
|
314
|
-
* see the page's `usingComponents` map from inside the Vue instance, so this
|
|
315
|
-
* convention-based recovery is best-effort: if the user picked a different
|
|
316
|
-
* registration key than the directory name (e.g. `usingComponents:
|
|
317
|
-
* { myCounter: '/components/counter/counter' }`), the panel will show
|
|
318
|
-
* `counter`, not `myCounter`.
|
|
319
|
-
*
|
|
320
|
-
* The path heuristic also resolves a name-collision risk: a user-written
|
|
321
|
-
* `<counter name="x">` would land in the same `attrs.name` slot as the
|
|
322
|
-
* wrapper-internal path. We only unwrap when the value looks like an absolute
|
|
323
|
-
* component path (leading `/`), which dimina always emits but a user would
|
|
324
|
-
* almost never type as a literal attr.
|
|
325
|
-
*/
|
|
326
|
-
function unwrapCustomComponent(node) {
|
|
327
|
-
if (node.tagName !== 'wrapper')
|
|
328
|
-
return node;
|
|
329
|
-
const path = node.attrs?.name;
|
|
330
|
-
if (typeof path !== 'string' || !path.startsWith('/'))
|
|
331
|
-
return node;
|
|
332
|
-
// 去掉前导 `/` 后保留原路径形式(保留所有斜杠,不做 kebab/dash 转换)。
|
|
333
|
-
// 仅当路径以 `/index` 结尾且剥离后仍至少剩一段时才剥(`/index` 单独存在则
|
|
334
|
-
// 退回 wrapper,避免出现空 tagName)。
|
|
335
|
-
const stripped = path.replace(/^\//, '');
|
|
336
|
-
const withoutIndex = stripped.endsWith('/index') ? stripped.slice(0, -'/index'.length) : stripped;
|
|
337
|
-
const recovered = withoutIndex || stripped;
|
|
338
|
-
if (!recovered || recovered === 'index')
|
|
339
|
-
return node;
|
|
340
|
-
const nextAttrs = {};
|
|
341
|
-
for (const [k, v] of Object.entries(node.attrs)) {
|
|
342
|
-
if (k === 'name')
|
|
343
|
-
continue;
|
|
344
|
-
nextAttrs[k] = v;
|
|
345
|
-
}
|
|
346
|
-
return { ...node, tagName: recovered, attrs: nextAttrs };
|
|
347
|
-
}
|
|
348
|
-
/**
|
|
349
|
-
* 把"用户授权"层级(页面 / 自定义组件,tagName 以路径形式呈现,含 `/`)
|
|
350
|
-
* 的 children 包一层合成 `#shadow-root`,对齐微信开发者工具:组件本身
|
|
351
|
-
* 与内部实现之间用 shadow-root 边界视觉分隔。
|
|
352
|
-
*
|
|
353
|
-
* 内置组件(view/text/button 等)和合成节点(#text/#fragment)tagName 都
|
|
354
|
-
* 不含 `/`,自然不会被包裹。children 为空也不插入(避免空壳)。重复调用
|
|
355
|
-
* 是幂等的:若 children[0] 已经是 #shadow-root 就跳过。
|
|
356
|
-
*/
|
|
357
|
-
function wrapInShadowRoot(node) {
|
|
358
|
-
if (!node.tagName.includes('/'))
|
|
359
|
-
return node;
|
|
360
|
-
if (node.children.length === 0)
|
|
361
|
-
return node;
|
|
362
|
-
if (node.children[0]?.tagName === '#shadow-root')
|
|
363
|
-
return node;
|
|
364
|
-
return {
|
|
365
|
-
...node,
|
|
366
|
-
children: [{ tagName: '#shadow-root', attrs: {}, children: node.children }],
|
|
367
|
-
};
|
|
368
|
-
}
|
|
369
|
-
export function walkInstance(instance, depth) {
|
|
370
|
-
if (depth > 50)
|
|
371
|
-
return null;
|
|
372
|
-
const tagName = resolveTagName(instance);
|
|
373
|
-
const children = extractChildrenFromVNode(instance.subTree, depth);
|
|
374
|
-
if (isTransparentComponent(instance, tagName))
|
|
375
|
-
return children.length > 0 ? children : null;
|
|
376
|
-
const node = { tagName, attrs: extractProps(instance), children };
|
|
377
|
-
const sid = getElementSid(instance);
|
|
378
|
-
if (sid)
|
|
379
|
-
node.sid = sid;
|
|
380
|
-
return wrapInShadowRoot(unwrapCustomComponent(node));
|
|
381
|
-
}
|
|
382
|
-
//# sourceMappingURL=wxml-extract.js.map
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export interface WxmlNode {
|
|
2
|
-
tagName: string;
|
|
3
|
-
attrs: Record<string, string>;
|
|
4
|
-
children: WxmlNode[];
|
|
5
|
-
text?: string;
|
|
6
|
-
sid?: string;
|
|
7
|
-
}
|
|
8
|
-
export declare const SYNTHETIC_SID_PREFIX = "devtools-";
|
|
9
|
-
export declare function registerSyntheticSid(el: HTMLElement): string;
|
|
10
|
-
export declare function findElementBySid(doc: Document, sid: string): HTMLElement | null;
|
|
11
|
-
//# sourceMappingURL=sid-registry.d.ts.map
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
// Stable-id registry for WXML nodes, shared by the iframe-path extractor
|
|
2
|
-
// (preload/instrumentation/wxml-extract + runtime/bridge) and the native-host
|
|
3
|
-
// render-guest inspector (render-host/render-inspect). It is dependency-free so
|
|
4
|
-
// the render-inspect bundle injected into the guest main world stays small and
|
|
5
|
-
// doesn't drag in the iframe/exposeOnMainWorld machinery from runtime/bridge.
|
|
6
|
-
// 合成 sid 注册表:用 WeakMap 把元素 ↔ sid 双向绑定,避免在源 DOM 上写
|
|
7
|
-
// `data-*` 属性(提取本应只读,且属性形式会污染用户的快照/选择器)。
|
|
8
|
-
// elBySyntheticSid 为反向查找用 WeakRef,元素被 GC 后下次 lookup 自动清理。
|
|
9
|
-
export const SYNTHETIC_SID_PREFIX = 'devtools-';
|
|
10
|
-
const syntheticSidByEl = new WeakMap();
|
|
11
|
-
const elBySyntheticSid = new Map();
|
|
12
|
-
let nextSyntheticSid = 1;
|
|
13
|
-
export function registerSyntheticSid(el) {
|
|
14
|
-
const existing = syntheticSidByEl.get(el);
|
|
15
|
-
if (existing)
|
|
16
|
-
return existing;
|
|
17
|
-
const synthetic = `${SYNTHETIC_SID_PREFIX}${nextSyntheticSid++}`;
|
|
18
|
-
syntheticSidByEl.set(el, synthetic);
|
|
19
|
-
elBySyntheticSid.set(synthetic, new WeakRef(el));
|
|
20
|
-
return synthetic;
|
|
21
|
-
}
|
|
22
|
-
export function findElementBySid(doc, sid) {
|
|
23
|
-
if (sid.startsWith(SYNTHETIC_SID_PREFIX)) {
|
|
24
|
-
const ref = elBySyntheticSid.get(sid);
|
|
25
|
-
if (!ref)
|
|
26
|
-
return null;
|
|
27
|
-
const el = ref.deref();
|
|
28
|
-
if (!el || !el.isConnected) {
|
|
29
|
-
elBySyntheticSid.delete(sid);
|
|
30
|
-
return null;
|
|
31
|
-
}
|
|
32
|
-
if (el.ownerDocument !== doc)
|
|
33
|
-
return null;
|
|
34
|
-
return el;
|
|
35
|
-
}
|
|
36
|
-
return doc.querySelector(`[data-sid="${CSS.escape(sid)}"]`);
|
|
37
|
-
}
|
|
38
|
-
//# sourceMappingURL=sid-registry.js.map
|