@dimina-kit/devtools 0.4.0-dev.20260624040247 → 0.4.0-dev.20260624084417
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/index.bundle.js +265 -29
- package/dist/main/services/elements-forward/index.js +37 -3
- package/dist/main/services/render-inspect/index.js +182 -6
- package/dist/main/services/views/devtools-tabs.d.ts +4 -1
- package/dist/main/services/views/devtools-tabs.js +21 -3
- package/dist/main/services/views/view-manager.js +7 -6
- package/dist/preload/instrumentation/wxml-extract.js +53 -7
- package/dist/render-host/render-inspect.js +24 -23
- package/dist/renderer/assets/index-BMqriQNr.js +50 -0
- package/dist/renderer/entries/main/index.html +1 -1
- package/dist/shared/open-in-editor.d.ts +9 -2
- package/dist/shared/open-in-editor.js +140 -17
- package/dist/simulator/assets/device-shell-CPCnCp1L.js +2 -0
- package/dist/simulator/assets/{simulator-CtyXt_4V.js → simulator-gMBWKDeO.js} +3 -3
- package/dist/simulator/simulator.html +1 -1
- package/package.json +6 -6
- package/dist/renderer/assets/index-PtsdWlGu.js +0 -50
- package/dist/simulator/assets/device-shell-TtcSXwhb.js +0 -2
|
@@ -1138,10 +1138,15 @@ function projectAwareResourcePath(resourceUrl, context) {
|
|
|
1138
1138
|
const projectRoot = normalizeSlashPath(context.projectRoot).replace(/\/$/, "");
|
|
1139
1139
|
const raw = resourceUrl.trim();
|
|
1140
1140
|
if (!raw) return null;
|
|
1141
|
+
const excludeBuildChunk = (rel) => {
|
|
1142
|
+
if (!rel) return rel;
|
|
1143
|
+
const base2 = rel.split("/").pop();
|
|
1144
|
+
return base2 === "common.js" || base2 === "vendors.js" || base2 === "runtime.js" || base2 === "taro.js" || base2 === "babelHelpers.js" ? null : rel;
|
|
1145
|
+
};
|
|
1141
1146
|
const normalizedRaw = normalizeSlashPath(raw);
|
|
1142
1147
|
if (projectRoot && (normalizedRaw === projectRoot || normalizedRaw.startsWith(`${projectRoot}/`))) {
|
|
1143
1148
|
const relative = normalizedRaw.slice(projectRoot.length).replace(/^\/+/, "");
|
|
1144
|
-
return safeRelativePath(relative.split("/").filter(Boolean));
|
|
1149
|
+
return excludeBuildChunk(safeRelativePath(relative.split("/").filter(Boolean)));
|
|
1145
1150
|
}
|
|
1146
1151
|
if (/^\/(?:Volumes|Users|home|private|tmp|var|opt|Applications)\//.test(normalizedRaw)) {
|
|
1147
1152
|
return null;
|
|
@@ -1156,9 +1161,9 @@ function projectAwareResourcePath(resourceUrl, context) {
|
|
|
1156
1161
|
if (resource.protocol === "file:") {
|
|
1157
1162
|
const filePath = normalizeSlashPath(resource.pathname);
|
|
1158
1163
|
if (!projectRoot || filePath !== projectRoot && !filePath.startsWith(`${projectRoot}/`)) return null;
|
|
1159
|
-
return safeRelativePath(
|
|
1164
|
+
return excludeBuildChunk(safeRelativePath(
|
|
1160
1165
|
filePath.slice(projectRoot.length).replace(/^\/+/, "").split("/").filter(Boolean)
|
|
1161
|
-
);
|
|
1166
|
+
));
|
|
1162
1167
|
}
|
|
1163
1168
|
if (resource.protocol !== "http:" && resource.protocol !== "https:") return null;
|
|
1164
1169
|
if (resource.origin !== base.origin) return null;
|
|
@@ -1167,7 +1172,7 @@ function projectAwareResourcePath(resourceUrl, context) {
|
|
|
1167
1172
|
segments = segments.slice(1);
|
|
1168
1173
|
if (context.outputRoot && segments[0] === context.outputRoot) segments = segments.slice(1);
|
|
1169
1174
|
}
|
|
1170
|
-
return safeRelativePath(segments);
|
|
1175
|
+
return excludeBuildChunk(safeRelativePath(segments));
|
|
1171
1176
|
}
|
|
1172
1177
|
function projectSourceContextFromServiceHostUrl(serviceHostUrl, activeProjectRoot) {
|
|
1173
1178
|
let url;
|
|
@@ -1212,6 +1217,7 @@ function buildDevtoolsProjectSourceLinksScript(context) {
|
|
|
1212
1217
|
const safeRelativePath = ${safeRelativePath.toString()}
|
|
1213
1218
|
const observedRoots = new Set()
|
|
1214
1219
|
const observers = []
|
|
1220
|
+
const clickBindings = []
|
|
1215
1221
|
let timer = null
|
|
1216
1222
|
const state = {
|
|
1217
1223
|
dispose() {
|
|
@@ -1222,11 +1228,106 @@ function buildDevtoolsProjectSourceLinksScript(context) {
|
|
|
1222
1228
|
for (const observer of observers.splice(0)) {
|
|
1223
1229
|
try { observer.disconnect() } catch (_) {}
|
|
1224
1230
|
}
|
|
1231
|
+
for (const binding of clickBindings.splice(0)) {
|
|
1232
|
+
try { binding.target.removeEventListener('click', binding.fn, true) } catch (_) {}
|
|
1233
|
+
}
|
|
1225
1234
|
observedRoots.clear()
|
|
1226
1235
|
},
|
|
1227
1236
|
}
|
|
1228
1237
|
globalThis[stateKey] = state
|
|
1229
1238
|
|
|
1239
|
+
// The InspectorFrontendHost that owns openInNewTab. Across DevTools
|
|
1240
|
+
// versions it lives on the top-level \`InspectorFrontendHost\` global, the
|
|
1241
|
+
// legacy \`Host.InspectorFrontendHost\`, or \`DevToolsHost\`; resolve at call
|
|
1242
|
+
// time so a late-bootstrapped host is still found.
|
|
1243
|
+
function resolveOpenInNewTabHost() {
|
|
1244
|
+
const candidates = [
|
|
1245
|
+
globalThis.InspectorFrontendHost,
|
|
1246
|
+
globalThis.Host && globalThis.Host.InspectorFrontendHost,
|
|
1247
|
+
globalThis.DevToolsHost,
|
|
1248
|
+
]
|
|
1249
|
+
for (const host of candidates) {
|
|
1250
|
+
if (host && typeof host.openInNewTab === 'function') return host
|
|
1251
|
+
}
|
|
1252
|
+
return null
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
// Encode (url, 0-based line, 0-based column) as the sentinel the main
|
|
1256
|
+
// process decodes from \`devtools-open-url\` and routes to Monaco.
|
|
1257
|
+
function openInEditor(url, line, column) {
|
|
1258
|
+
const host = resolveOpenInNewTabHost()
|
|
1259
|
+
if (!host) return false
|
|
1260
|
+
const p = new URLSearchParams()
|
|
1261
|
+
p.set('u', String(url))
|
|
1262
|
+
if (typeof line === 'number' && isFinite(line)) p.set('l', String(line))
|
|
1263
|
+
if (typeof column === 'number' && isFinite(column)) p.set('c', String(column))
|
|
1264
|
+
try { host.openInNewTab(${scheme} + ':?' + p.toString()) } catch (_) { return false }
|
|
1265
|
+
return true
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
// Resolve a clicked link element to a project source location. Returns
|
|
1269
|
+
// the FULL resource url (the main process re-maps it against the active
|
|
1270
|
+
// project) plus its display line/column when present.
|
|
1271
|
+
function projectLocationForLink(link) {
|
|
1272
|
+
if (!link) return null
|
|
1273
|
+
const candidates = [
|
|
1274
|
+
link.getAttribute && link.getAttribute('data-url'),
|
|
1275
|
+
link.getAttribute && link.getAttribute('href'),
|
|
1276
|
+
link.getAttribute && link.getAttribute('title'),
|
|
1277
|
+
]
|
|
1278
|
+
for (const candidate of candidates) {
|
|
1279
|
+
if (!candidate) continue
|
|
1280
|
+
const location = splitLocation(candidate)
|
|
1281
|
+
if (!diminaProjectSourcePath(location.url, cfg)) continue
|
|
1282
|
+
const suffix = location.suffix
|
|
1283
|
+
|| ((String(link.textContent || '').match(/(:\\d+(?::\\d+)?)$/) || [])[1] || '')
|
|
1284
|
+
return { url: location.url, suffix }
|
|
1285
|
+
}
|
|
1286
|
+
return null
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
// DevTools shows 1-based line:column in link text; the main process
|
|
1290
|
+
// contract expects 0-based (it re-adds 1). Convert here.
|
|
1291
|
+
function parseSuffix(suffix) {
|
|
1292
|
+
const m = String(suffix || '').match(/^:(\\d+)(?::(\\d+))?$/)
|
|
1293
|
+
if (!m) return { line: undefined, column: undefined }
|
|
1294
|
+
const line = Math.max(0, parseInt(m[1], 10) - 1)
|
|
1295
|
+
const column = m[2] != null ? Math.max(0, parseInt(m[2], 10) - 1) : undefined
|
|
1296
|
+
return { line, column }
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
// Capture-phase click handler: route a project-source link click to
|
|
1300
|
+
// Monaco instead of the DevTools Sources panel. Plain primary clicks only
|
|
1301
|
+
// \u2014 modified clicks (cmd/ctrl/shift/alt, middle button) fall through to
|
|
1302
|
+
// DevTools so its own "open in new tab" / multi-select still work.
|
|
1303
|
+
function onLinkClick(event) {
|
|
1304
|
+
if (event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return
|
|
1305
|
+
const path = typeof event.composedPath === 'function' ? event.composedPath() : []
|
|
1306
|
+
let link = null
|
|
1307
|
+
for (const node of path) {
|
|
1308
|
+
if (node && node.nodeType === 1 && node.classList && node.classList.contains('devtools-link')) {
|
|
1309
|
+
link = node
|
|
1310
|
+
break
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
if (!link) return
|
|
1314
|
+
const location = projectLocationForLink(link)
|
|
1315
|
+
if (!location) return
|
|
1316
|
+
const { line, column } = parseSuffix(location.suffix)
|
|
1317
|
+
if (!openInEditor(location.url, line, column)) return
|
|
1318
|
+
event.preventDefault()
|
|
1319
|
+
event.stopImmediatePropagation()
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
function bindClicks(target) {
|
|
1323
|
+
if (!target || !target.addEventListener) return
|
|
1324
|
+
for (const binding of clickBindings) {
|
|
1325
|
+
if (binding.target === target) return
|
|
1326
|
+
}
|
|
1327
|
+
target.addEventListener('click', onLinkClick, true)
|
|
1328
|
+
clickBindings.push({ target, fn: onLinkClick })
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1230
1331
|
function splitLocation(value) {
|
|
1231
1332
|
const raw = String(value || '')
|
|
1232
1333
|
const match = raw.match(/^(.*?)(?::(\\d+))(?::(\\d+))?$/)
|
|
@@ -1257,6 +1358,7 @@ function buildDevtoolsProjectSourceLinksScript(context) {
|
|
|
1257
1358
|
function observeRoot(root) {
|
|
1258
1359
|
if (!root || !root.querySelectorAll || observedRoots.has(root)) return
|
|
1259
1360
|
observedRoots.add(root)
|
|
1361
|
+
bindClicks(root)
|
|
1260
1362
|
|
|
1261
1363
|
const observer = new MutationObserver((records) => {
|
|
1262
1364
|
for (const record of records) {
|
|
@@ -1291,23 +1393,25 @@ function buildDevtoolsProjectSourceLinksScript(context) {
|
|
|
1291
1393
|
|
|
1292
1394
|
observeRoot(document)
|
|
1293
1395
|
|
|
1396
|
+
// Fallback for older DevTools fronts that still expose the
|
|
1397
|
+
// setOpenResourceHandler hook. On current Chromium the method is gone,
|
|
1398
|
+
// so this poll simply times out and the capture-phase click interceptor
|
|
1399
|
+
// is the only live path. When the hook IS present the interceptor still
|
|
1400
|
+
// wins (it runs in capture and stops propagation), so the two never
|
|
1401
|
+
// double-open the same click.
|
|
1294
1402
|
let tries = 0
|
|
1295
1403
|
timer = setInterval(() => {
|
|
1296
1404
|
tries++
|
|
1297
1405
|
try {
|
|
1298
|
-
const
|
|
1299
|
-
|
|
1300
|
-
if (host && typeof host.setOpenResourceHandler === 'function'
|
|
1301
|
-
&& typeof host.openInNewTab === 'function') {
|
|
1406
|
+
const host = resolveOpenInNewTabHost()
|
|
1407
|
+
if (host && typeof host.setOpenResourceHandler === 'function') {
|
|
1302
1408
|
host.setOpenResourceHandler((url, lineNumber, columnNumber) => {
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
host.openInNewTab(${scheme} + ':?' + p.toString())
|
|
1310
|
-
} catch (_) {}
|
|
1409
|
+
if (!diminaProjectSourcePath(String(url), cfg)) return
|
|
1410
|
+
openInEditor(
|
|
1411
|
+
String(url),
|
|
1412
|
+
typeof lineNumber === 'number' ? lineNumber : undefined,
|
|
1413
|
+
typeof columnNumber === 'number' ? columnNumber : undefined,
|
|
1414
|
+
)
|
|
1311
1415
|
})
|
|
1312
1416
|
clearInterval(timer)
|
|
1313
1417
|
timer = null
|
|
@@ -1373,19 +1477,25 @@ function createSafeAreaController(options = {}) {
|
|
|
1373
1477
|
}
|
|
1374
1478
|
|
|
1375
1479
|
// src/main/services/views/devtools-tabs.ts
|
|
1376
|
-
var DEVTOOLS_KEPT_VIEW_IDS = ["elements", "console", "network"];
|
|
1480
|
+
var DEVTOOLS_KEPT_VIEW_IDS = ["elements", "console", "network", "sources"];
|
|
1377
1481
|
function buildCustomizeTabsScript(keptIds = DEVTOOLS_KEPT_VIEW_IDS) {
|
|
1378
1482
|
const NAME_MAP = {
|
|
1379
1483
|
elements: ["Elements", "\u5143\u7D20"],
|
|
1380
1484
|
console: ["Console", "\u63A7\u5236\u53F0"],
|
|
1381
|
-
network: ["Network", "\u7F51\u7EDC"]
|
|
1485
|
+
network: ["Network", "\u7F51\u7EDC"],
|
|
1486
|
+
sources: ["Sources", "\u6765\u6E90", "\u6E90\u4EE3\u7801"]
|
|
1382
1487
|
};
|
|
1383
1488
|
const keepNames = keptIds.flatMap((id) => NAME_MAP[id] ?? [id]);
|
|
1384
1489
|
const keepIdsJson = JSON.stringify(JSON.stringify([...keptIds]));
|
|
1385
1490
|
const keepNamesJson = JSON.stringify(JSON.stringify(keepNames));
|
|
1491
|
+
const srcNamesJson = JSON.stringify(JSON.stringify(NAME_MAP.sources));
|
|
1492
|
+
const netNamesJson = JSON.stringify(JSON.stringify(NAME_MAP.network));
|
|
1386
1493
|
return `(function(){try{
|
|
1387
1494
|
var KEEPID = new Set(JSON.parse(${keepIdsJson}));
|
|
1388
1495
|
var KEEPNAME = new Set(JSON.parse(${keepNamesJson}));
|
|
1496
|
+
var SRCNAME = new Set(JSON.parse(${srcNamesJson}));
|
|
1497
|
+
var NETNAME = new Set(JSON.parse(${netNamesJson}));
|
|
1498
|
+
var WANT_SOURCES_LAST = KEEPID.has('sources');
|
|
1389
1499
|
// (1) Locale infobar \u2014 official host-preference suppression (NOT localStorage).
|
|
1390
1500
|
try { var IFH=globalThis.InspectorFrontendHost; if(IFH&&typeof IFH.setPreference==='function'){ IFH.setPreference('disable-locale-info-bar','true'); } }catch(_){}
|
|
1391
1501
|
function deepCollect(sel,cap){ var out=[],seen=0,stack=[document]; while(stack.length&&seen<(cap||40000)){ var root=stack.pop(); try{var m=root.querySelectorAll?root.querySelectorAll(sel):[];for(var i=0;i<m.length;i++)out.push(m[i]);}catch(_){} try{var all=root.querySelectorAll?root.querySelectorAll('*'):[];for(var j=0;j<all.length;j++){seen++;if(all[j].shadowRoot)stack.push(all[j].shadowRoot);}}catch(_){} } return out; }
|
|
@@ -1413,9 +1523,18 @@ function buildCustomizeTabsScript(keptIds = DEVTOOLS_KEPT_VIEW_IDS) {
|
|
|
1413
1523
|
handled=true;
|
|
1414
1524
|
}catch(_){} }
|
|
1415
1525
|
// fallback: registrations not enumerable -> at least clear the bar by id
|
|
1416
|
-
if(!handled){ var FALL=['timeline','resources','heap-profiler','
|
|
1526
|
+
if(!handled){ var FALL=['timeline','resources','heap-profiler','security','lighthouse','chrome-recorder','coverage','linear-memory-inspector','sensors','rendering','animations','autofill-view','medias','issues-pane']; for(var fr=0;fr<FALL.length;fr++){ try{ if(!KEEPID.has(FALL[fr])) maybeRemove(FALL[fr]); }catch(_){} } }
|
|
1417
1527
|
} else { domFallback(); }
|
|
1418
1528
|
})();
|
|
1529
|
+
// Keep Sources LAST in the bar (after Network). Default DevTools order puts
|
|
1530
|
+
// Sources between Console and Network; nudge it to just after Network. Runs in
|
|
1531
|
+
// BOTH paths (registry removal leaves the kept tabs in default order). Self-
|
|
1532
|
+
// stable: once Sources follows Network the condition no longer holds.
|
|
1533
|
+
if(WANT_SOURCES_LAST){ var ro=0,rt=setInterval(function(){ ro++; try{
|
|
1534
|
+
var tabs=deepCollect('[role="tab"]'),src=null,net=null;
|
|
1535
|
+
for(var i=0;i<tabs.length;i++){ var n=txt(tabs[i]); if(SRCNAME.has(n))src=tabs[i]; else if(NETNAME.has(n))net=tabs[i]; }
|
|
1536
|
+
if(src&&net&&src.parentElement&&src.parentElement===net.parentElement&&(src.compareDocumentPosition(net)&Node.DOCUMENT_POSITION_FOLLOWING)){ net.parentElement.insertBefore(src,net.nextSibling); }
|
|
1537
|
+
}catch(_){} if(ro>120)clearInterval(rt); },60); }
|
|
1419
1538
|
// DOM fallback: only if the ESM module couldn't be resolved at all.
|
|
1420
1539
|
function domFallback(){ var cachedBar=null;
|
|
1421
1540
|
function findBar(){ if(cachedBar&&cachedBar.isConnected)return cachedBar; cachedBar=null; var tabs=deepCollect('[role="tab"]'); var a=null; for(var i=0;i<tabs.length;i++){if(KEEPNAME.has(txt(tabs[i]))){a=tabs[i];break;}} if(!a)return null; var p=a.parentElement; while(p){try{if(p.querySelectorAll('[role="tab"]').length>1){cachedBar=p;return p;}}catch(_){} p=p.parentElement;} cachedBar=a.parentElement; return cachedBar; }
|
|
@@ -1670,10 +1789,19 @@ function installElementsForward(deps) {
|
|
|
1670
1789
|
function primeGuest(wc) {
|
|
1671
1790
|
if (!ensureGuestDebugger(wc)) return;
|
|
1672
1791
|
wireGuestEvents(wc);
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1792
|
+
void enableGuestDomains(wc);
|
|
1793
|
+
}
|
|
1794
|
+
async function enableGuestDomains(wc) {
|
|
1795
|
+
wc.debugger.sendCommand("CSS.enable").catch(() => {
|
|
1796
|
+
});
|
|
1797
|
+
try {
|
|
1798
|
+
await wc.debugger.sendCommand("DOM.enable");
|
|
1799
|
+
} catch {
|
|
1800
|
+
return;
|
|
1676
1801
|
}
|
|
1802
|
+
if (disposed || !isActiveWcId(wc.id)) return;
|
|
1803
|
+
wc.debugger.sendCommand("Overlay.enable").catch(() => {
|
|
1804
|
+
});
|
|
1677
1805
|
}
|
|
1678
1806
|
function routeCommand(cmd) {
|
|
1679
1807
|
const wc = activeRenderWc();
|
|
@@ -1693,6 +1821,10 @@ function installElementsForward(deps) {
|
|
|
1693
1821
|
replyError(cmd, "stale render generation");
|
|
1694
1822
|
return;
|
|
1695
1823
|
}
|
|
1824
|
+
if (cmd.method === "Overlay.disable" && isActiveWcId(cmdWcId)) {
|
|
1825
|
+
wc.debugger.sendCommand("Overlay.enable").catch(() => {
|
|
1826
|
+
});
|
|
1827
|
+
}
|
|
1696
1828
|
replyResult(cmd, result);
|
|
1697
1829
|
}).catch((err) => {
|
|
1698
1830
|
if (disposed) return;
|
|
@@ -8489,10 +8621,35 @@ function setupSimulatorCurrentPage(host, options) {
|
|
|
8489
8621
|
import { readFileSync } from "node:fs";
|
|
8490
8622
|
import path17 from "node:path";
|
|
8491
8623
|
var DEFAULT_SOURCE_PATH = "dist/render-host/render-inspect.js";
|
|
8624
|
+
var HIGHLIGHT_CONFIG = {
|
|
8625
|
+
showInfo: true,
|
|
8626
|
+
showRulers: false,
|
|
8627
|
+
showExtensionLines: false,
|
|
8628
|
+
contentColor: { r: 111, g: 168, b: 220, a: 0.66 },
|
|
8629
|
+
paddingColor: { r: 147, g: 196, b: 125, a: 0.55 },
|
|
8630
|
+
borderColor: { r: 255, g: 229, b: 153, a: 0.66 },
|
|
8631
|
+
marginColor: { r: 246, g: 178, b: 107, a: 0.66 }
|
|
8632
|
+
};
|
|
8633
|
+
var HOVER_OBJECT_GROUP = "render-inspect-hover";
|
|
8634
|
+
var ENABLE_HANDSHAKE_TIMEOUT_MS = 500;
|
|
8635
|
+
function withTimeout(p, ms) {
|
|
8636
|
+
return new Promise((resolve) => {
|
|
8637
|
+
const timer = setTimeout(resolve, ms);
|
|
8638
|
+
p.then(() => {
|
|
8639
|
+
clearTimeout(timer);
|
|
8640
|
+
resolve();
|
|
8641
|
+
}, () => {
|
|
8642
|
+
clearTimeout(timer);
|
|
8643
|
+
resolve();
|
|
8644
|
+
});
|
|
8645
|
+
});
|
|
8646
|
+
}
|
|
8492
8647
|
function createRenderInspector(options = {}) {
|
|
8493
8648
|
const loadSource = options.loadSource ?? (() => readFileSync(path17.join(devtoolsPackageRoot, DEFAULT_SOURCE_PATH), "utf8"));
|
|
8494
8649
|
let cachedSource = null;
|
|
8495
8650
|
const injected = /* @__PURE__ */ new Set();
|
|
8651
|
+
const selfAttached = /* @__PURE__ */ new Set();
|
|
8652
|
+
const enablePromises = /* @__PURE__ */ new Map();
|
|
8496
8653
|
function source() {
|
|
8497
8654
|
if (cachedSource === null) cachedSource = loadSource();
|
|
8498
8655
|
return cachedSource;
|
|
@@ -8514,10 +8671,14 @@ function createRenderInspector(options = {}) {
|
|
|
8514
8671
|
return false;
|
|
8515
8672
|
}
|
|
8516
8673
|
injected.add(wc.id);
|
|
8674
|
+
const forget = () => {
|
|
8675
|
+
injected.delete(wc.id);
|
|
8676
|
+
enablePromises.delete(wc.id);
|
|
8677
|
+
};
|
|
8517
8678
|
if (options.connections) {
|
|
8518
|
-
options.connections.acquire(wc).own(
|
|
8679
|
+
options.connections.acquire(wc).own(forget);
|
|
8519
8680
|
} else {
|
|
8520
|
-
wc.once("destroyed",
|
|
8681
|
+
wc.once("destroyed", forget);
|
|
8521
8682
|
}
|
|
8522
8683
|
return true;
|
|
8523
8684
|
}
|
|
@@ -8536,22 +8697,97 @@ function createRenderInspector(options = {}) {
|
|
|
8536
8697
|
async function highlight(wc, sid) {
|
|
8537
8698
|
if (wc.isDestroyed()) return null;
|
|
8538
8699
|
if (!await ensureInjected(wc)) return null;
|
|
8700
|
+
let inspection;
|
|
8539
8701
|
try {
|
|
8540
8702
|
const result = await wc.executeJavaScript(
|
|
8541
8703
|
`window.__diminaRenderInspect ? window.__diminaRenderInspect.highlightElement(${JSON.stringify(sid)}) : null`
|
|
8542
8704
|
);
|
|
8543
|
-
|
|
8705
|
+
inspection = result ?? null;
|
|
8544
8706
|
} catch {
|
|
8545
8707
|
return null;
|
|
8546
8708
|
}
|
|
8709
|
+
if (!inspection) return null;
|
|
8710
|
+
await drawNativeHighlight(wc, sid).catch(() => {
|
|
8711
|
+
});
|
|
8712
|
+
return inspection;
|
|
8713
|
+
}
|
|
8714
|
+
async function drawNativeHighlight(wc, sid) {
|
|
8715
|
+
if (wc.isDestroyed()) return;
|
|
8716
|
+
if (!ensureGuestDebugger(wc)) return;
|
|
8717
|
+
await withTimeout(ensureDomainsEnabled(wc), ENABLE_HANDSHAKE_TIMEOUT_MS);
|
|
8718
|
+
if (wc.isDestroyed()) return;
|
|
8719
|
+
const expression = `window.__diminaRenderInspect && window.__diminaRenderInspect.elementFor(${JSON.stringify(sid)})`;
|
|
8720
|
+
try {
|
|
8721
|
+
const evaluated = await wc.debugger.sendCommand("Runtime.evaluate", {
|
|
8722
|
+
expression,
|
|
8723
|
+
returnByValue: false,
|
|
8724
|
+
objectGroup: HOVER_OBJECT_GROUP
|
|
8725
|
+
});
|
|
8726
|
+
const objectId = evaluated?.result?.objectId;
|
|
8727
|
+
if (!objectId) return;
|
|
8728
|
+
await wc.debugger.sendCommand("Overlay.highlightNode", {
|
|
8729
|
+
objectId,
|
|
8730
|
+
highlightConfig: HIGHLIGHT_CONFIG
|
|
8731
|
+
});
|
|
8732
|
+
} finally {
|
|
8733
|
+
wc.debugger.sendCommand("Runtime.releaseObjectGroup", { objectGroup: HOVER_OBJECT_GROUP }).catch(() => {
|
|
8734
|
+
});
|
|
8735
|
+
}
|
|
8736
|
+
}
|
|
8737
|
+
function ensureGuestDebugger(wc) {
|
|
8738
|
+
try {
|
|
8739
|
+
if (wc.debugger.isAttached()) return true;
|
|
8740
|
+
} catch {
|
|
8741
|
+
return false;
|
|
8742
|
+
}
|
|
8743
|
+
try {
|
|
8744
|
+
wc.debugger.attach("1.3");
|
|
8745
|
+
trackSelfAttached(wc);
|
|
8746
|
+
return true;
|
|
8747
|
+
} catch {
|
|
8748
|
+
try {
|
|
8749
|
+
return wc.debugger.isAttached();
|
|
8750
|
+
} catch {
|
|
8751
|
+
return false;
|
|
8752
|
+
}
|
|
8753
|
+
}
|
|
8754
|
+
}
|
|
8755
|
+
function trackSelfAttached(wc) {
|
|
8756
|
+
if (selfAttached.has(wc.id)) return;
|
|
8757
|
+
selfAttached.add(wc.id);
|
|
8758
|
+
const detach = () => {
|
|
8759
|
+
selfAttached.delete(wc.id);
|
|
8760
|
+
try {
|
|
8761
|
+
if (!wc.isDestroyed() && wc.debugger.isAttached()) wc.debugger.detach();
|
|
8762
|
+
} catch {
|
|
8763
|
+
}
|
|
8764
|
+
};
|
|
8765
|
+
if (options.connections) options.connections.acquire(wc).own(detach);
|
|
8766
|
+
else {
|
|
8767
|
+
try {
|
|
8768
|
+
wc.once("destroyed", () => selfAttached.delete(wc.id));
|
|
8769
|
+
} catch {
|
|
8770
|
+
}
|
|
8771
|
+
}
|
|
8772
|
+
}
|
|
8773
|
+
function ensureDomainsEnabled(wc) {
|
|
8774
|
+
const cached = enablePromises.get(wc.id);
|
|
8775
|
+
if (cached) return cached;
|
|
8776
|
+
wc.debugger.sendCommand("CSS.enable").catch(() => {
|
|
8777
|
+
});
|
|
8778
|
+
const handshake = wc.debugger.sendCommand("DOM.enable").then(() => {
|
|
8779
|
+
if (wc.isDestroyed()) return;
|
|
8780
|
+
return wc.debugger.sendCommand("Overlay.enable");
|
|
8781
|
+
}).then(() => void 0).catch(() => {
|
|
8782
|
+
enablePromises.delete(wc.id);
|
|
8783
|
+
});
|
|
8784
|
+
enablePromises.set(wc.id, handshake);
|
|
8785
|
+
return handshake;
|
|
8547
8786
|
}
|
|
8548
8787
|
async function unhighlight(wc) {
|
|
8549
8788
|
if (wc.isDestroyed()) return;
|
|
8550
|
-
if (!await ensureInjected(wc)) return;
|
|
8551
8789
|
try {
|
|
8552
|
-
await wc.
|
|
8553
|
-
"window.__diminaRenderInspect && window.__diminaRenderInspect.unhighlightElement && window.__diminaRenderInspect.unhighlightElement()"
|
|
8554
|
-
);
|
|
8790
|
+
await wc.debugger.sendCommand("Overlay.hideHighlight");
|
|
8555
8791
|
} catch {
|
|
8556
8792
|
}
|
|
8557
8793
|
}
|
|
@@ -430,14 +430,40 @@ export function installElementsForward(deps) {
|
|
|
430
430
|
catch { /* gone */ }
|
|
431
431
|
});
|
|
432
432
|
}
|
|
433
|
-
/**
|
|
433
|
+
/**
|
|
434
|
+
* enable DOM/CSS/Overlay + wire events on a guest. Best-effort (never throws).
|
|
435
|
+
*
|
|
436
|
+
* `Overlay.enable` is sent ONLY AFTER `DOM.enable` has resolved: Chromium rejects
|
|
437
|
+
* `Overlay.enable` with "DOM should be enabled first" when it arrives before the
|
|
438
|
+
* DOM domain is enabled, and a silently-dropped rejection leaves Overlay disabled
|
|
439
|
+
* so every later `Overlay.highlightNode` fails with "Overlay must be enabled" and
|
|
440
|
+
* the Elements-panel hover highlight never paints. Awaiting DOM.enable first
|
|
441
|
+
* guarantees the correct enable order. CSS.enable has no such dependency and is
|
|
442
|
+
* fire-and-forget alongside.
|
|
443
|
+
*/
|
|
434
444
|
function primeGuest(wc) {
|
|
435
445
|
if (!ensureGuestDebugger(wc))
|
|
436
446
|
return;
|
|
437
447
|
wireGuestEvents(wc);
|
|
438
|
-
|
|
439
|
-
|
|
448
|
+
void enableGuestDomains(wc);
|
|
449
|
+
}
|
|
450
|
+
/** Enable the render domains in dependency order. Resolves; never rejects. */
|
|
451
|
+
async function enableGuestDomains(wc) {
|
|
452
|
+
wc.debugger.sendCommand('CSS.enable').catch(() => { });
|
|
453
|
+
try {
|
|
454
|
+
await wc.debugger.sendCommand('DOM.enable');
|
|
440
455
|
}
|
|
456
|
+
catch {
|
|
457
|
+
// Guest mid-destroy or DOM domain unavailable; Overlay.enable would only
|
|
458
|
+
// re-reject, so stop here rather than firing it out of order.
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
// DOM.enable can settle after the guest was destroyed or the active page
|
|
462
|
+
// switched away (priming always targets the active guest). Re-check before
|
|
463
|
+
// arming Overlay so a stale/dead guest is left untouched.
|
|
464
|
+
if (disposed || !isActiveWcId(wc.id))
|
|
465
|
+
return;
|
|
466
|
+
wc.debugger.sendCommand('Overlay.enable').catch(() => { });
|
|
441
467
|
}
|
|
442
468
|
// ── front-end → render command routing ─────────────────────────────────────
|
|
443
469
|
function routeCommand(cmd) {
|
|
@@ -465,6 +491,14 @@ export function installElementsForward(deps) {
|
|
|
465
491
|
replyError(cmd, 'stale render generation');
|
|
466
492
|
return;
|
|
467
493
|
}
|
|
494
|
+
// The front-end emits `Overlay.disable` on Elements-panel state
|
|
495
|
+
// transitions. Forwarded verbatim it disables the guest's Overlay agent,
|
|
496
|
+
// after which every `Overlay.highlightNode` fails with "Overlay must be
|
|
497
|
+
// enabled" and the hover highlight stops painting. Re-arm it so the next
|
|
498
|
+
// hover paints — only while this guest is still the active one.
|
|
499
|
+
if (cmd.method === 'Overlay.disable' && isActiveWcId(cmdWcId)) {
|
|
500
|
+
wc.debugger.sendCommand('Overlay.enable').catch(() => { });
|
|
501
|
+
}
|
|
468
502
|
replyResult(cmd, result);
|
|
469
503
|
})
|
|
470
504
|
.catch((err) => {
|