browser-debugger-cli 0.12.0 → 0.14.0
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/.claude/skills/bdg/SKILL.md +100 -186
- package/README.md +5 -4
- package/dist/commands/cdp.d.ts +22 -1
- package/dist/commands/cdp.js +100 -43
- package/dist/commands/console.d.ts +12 -0
- package/dist/commands/console.js +67 -13
- package/dist/commands/dom/DomElementResolver.d.ts +3 -1
- package/dist/commands/dom/DomElementResolver.js +10 -3
- package/dist/commands/dom/a11y.d.ts +1 -1
- package/dist/commands/dom/a11y.js +23 -22
- package/dist/commands/dom/eval.d.ts +4 -2
- package/dist/commands/dom/eval.js +31 -7
- package/dist/commands/dom/form.js +10 -9
- package/dist/commands/dom/formInteraction.js +9 -8
- package/dist/commands/dom/get.js +32 -14
- package/dist/commands/dom/helpers/index.d.ts +1 -1
- package/dist/commands/dom/helpers/index.js +1 -1
- package/dist/commands/dom/helpers/query.d.ts +27 -3
- package/dist/commands/dom/helpers/query.js +152 -64
- package/dist/commands/dom/helpers/screenshot.js +13 -13
- package/dist/commands/dom/index.js +10 -3
- package/dist/commands/dom/query.d.ts +20 -2
- package/dist/commands/dom/query.js +39 -6
- package/dist/commands/dom/screenshot.js +3 -1
- package/dist/commands/dom/semanticUtils.d.ts +3 -2
- package/dist/commands/dom/semanticUtils.js +40 -9
- package/dist/commands/helpJson.d.ts +82 -19
- package/dist/commands/helpJson.js +112 -41
- package/dist/commands/helpTopic.d.ts +16 -1
- package/dist/commands/helpTopic.js +59 -1
- package/dist/commands/installSkill.d.ts +15 -5
- package/dist/commands/installSkill.js +86 -16
- package/dist/commands/network/list.js +65 -12
- package/dist/commands/optionBehaviors.d.ts +25 -2
- package/dist/commands/optionBehaviors.js +81 -46
- package/dist/commands/peek.js +3 -0
- package/dist/commands/shared/CommandRunner.js +13 -13
- package/dist/commands/shared/daemonErrorHandler.d.ts +5 -2
- package/dist/commands/shared/daemonErrorHandler.js +21 -10
- package/dist/commands/shared/dataFetcher.d.ts +14 -4
- package/dist/commands/shared/dataFetcher.js +20 -4
- package/dist/commands/shared/followMode.d.ts +9 -1
- package/dist/commands/shared/followMode.js +22 -4
- package/dist/commands/shared/handleValidationError.js +3 -3
- package/dist/commands/shared/optionTypes.d.ts +17 -3
- package/dist/commands/shared/outputFile.js +6 -1
- package/dist/commands/shared/startHelpers.js +3 -3
- package/dist/commands/start.d.ts +7 -5
- package/dist/commands/start.js +65 -21
- package/dist/commands/stop.d.ts +11 -0
- package/dist/commands/stop.js +24 -1
- package/dist/commands.js +1 -1
- package/dist/connection/cdp.d.ts +7 -0
- package/dist/connection/cdp.js +9 -0
- package/dist/connection/chromeIdentity.d.ts +8 -2
- package/dist/connection/chromeIdentity.js +85 -13
- package/dist/connection/launcher.js +3 -2
- package/dist/constants.d.ts +29 -1
- package/dist/constants.js +35 -1
- package/dist/daemon/SessionController.js +8 -1
- package/dist/daemon/launcher.d.ts +3 -2
- package/dist/daemon/launcher.js +47 -3
- package/dist/daemon/session/Session.d.ts +5 -1
- package/dist/daemon/session/Session.js +42 -3
- package/dist/daemon/session/TelemetryStore.d.ts +15 -1
- package/dist/daemon/session/TelemetryStore.js +19 -1
- package/dist/daemon/session/commandRegistry.js +52 -18
- package/dist/daemon/session/interactions.d.ts +2 -1
- package/dist/daemon/session/interactions.js +13 -1
- package/dist/daemon/session/matchedStylesReset.d.ts +26 -0
- package/dist/daemon/session/matchedStylesReset.js +46 -0
- package/dist/daemon/session/plugins.js +17 -2
- package/dist/daemon/session/teardown.js +1 -1
- package/dist/daemon/session/triggeredRequests.d.ts +0 -5
- package/dist/daemon/session/triggeredRequests.js +13 -7
- package/dist/daemon.js +2385 -1229
- package/dist/errors/messages.d.ts +62 -11
- package/dist/errors/messages.js +119 -22
- package/dist/index.js +14995 -9866
- package/dist/ipc/client.d.ts +18 -2
- package/dist/ipc/client.js +26 -5
- package/dist/ipc/protocol/auditTypes.d.ts +8 -2
- package/dist/ipc/protocol/commands.d.ts +16 -0
- package/dist/ipc/protocol/domTypes.d.ts +12 -0
- package/dist/ipc/protocol/inspectTypes.d.ts +7 -2
- package/dist/ipc/session/types.d.ts +7 -1
- package/dist/program.d.ts +14 -0
- package/dist/program.js +53 -0
- package/dist/runtime/dom/actionEffects.d.ts +5 -1
- package/dist/runtime/dom/actionEffects.js +26 -14
- package/dist/runtime/dom/audit.js +3 -2
- package/dist/runtime/dom/auditModel.js +6 -1
- package/dist/runtime/dom/auditScripts.d.ts +9 -3
- package/dist/runtime/dom/auditScripts.js +41 -5
- package/dist/runtime/dom/elementGeometry.d.ts +33 -3
- package/dist/runtime/dom/elementGeometry.js +44 -19
- package/dist/runtime/dom/elementInfo.d.ts +76 -18
- package/dist/runtime/dom/elementInfo.js +190 -40
- package/dist/runtime/dom/evalHelpers.d.ts +12 -2
- package/dist/runtime/dom/evalHelpers.js +67 -7
- package/dist/runtime/dom/formDiscovery.d.ts +6 -2
- package/dist/runtime/dom/formDiscovery.js +20 -3
- package/dist/runtime/dom/formFillHelpers/fill.js +7 -11
- package/dist/runtime/dom/formFillHelpers/pressKey.js +2 -2
- package/dist/runtime/dom/formFillHelpers/shared.d.ts +16 -10
- package/dist/runtime/dom/formFillHelpers/shared.js +19 -52
- package/dist/runtime/dom/formSubmitHelpers.js +4 -3
- package/dist/runtime/dom/frameLayout.js +1 -0
- package/dist/runtime/dom/frameScopedConnection.d.ts +7 -0
- package/dist/runtime/dom/frameScopedConnection.js +2 -2
- package/dist/runtime/dom/inspect.d.ts +17 -3
- package/dist/runtime/dom/inspect.js +45 -32
- package/dist/runtime/dom/inspectAllStyles.js +1 -0
- package/dist/runtime/dom/inspectHints.d.ts +1 -1
- package/dist/runtime/dom/inspectModel.d.ts +5 -4
- package/dist/runtime/dom/inspectModel.js +7 -3
- package/dist/runtime/dom/inspectPaintModel.d.ts +2 -0
- package/dist/runtime/dom/inspectPaintModel.js +3 -1
- package/dist/runtime/dom/inspectRules.d.ts +29 -3
- package/dist/runtime/dom/inspectRules.js +205 -11
- package/dist/runtime/dom/inspectScripts.d.ts +29 -2
- package/dist/runtime/dom/inspectScripts.js +49 -10
- package/dist/runtime/dom/layout.d.ts +0 -2
- package/dist/runtime/dom/layout.js +10 -9
- package/dist/runtime/dom/reactEventHelpers.d.ts +17 -4
- package/dist/runtime/dom/reactEventHelpers.js +71 -28
- package/dist/runtime/dom/targetNode.d.ts +27 -10
- package/dist/runtime/dom/targetNode.js +283 -16
- package/dist/runtime/dom/wait.js +2 -1
- package/dist/runtime/page/bdgWorld.d.ts +57 -0
- package/dist/runtime/page/bdgWorld.js +180 -0
- package/dist/runtime/page/replacedBuiltins.d.ts +28 -0
- package/dist/runtime/page/replacedBuiltins.js +136 -0
- package/dist/session/QueryCacheManager.d.ts +4 -1
- package/dist/session/QueryCacheManager.js +5 -2
- package/dist/session/chrome.d.ts +4 -1
- package/dist/session/chrome.js +7 -1
- package/dist/session/cleanup/staleSession.d.ts +21 -4
- package/dist/session/cleanup/staleSession.js +79 -9
- package/dist/session/cleanup/userCommands.d.ts +4 -1
- package/dist/session/cleanup/userCommands.js +10 -5
- package/dist/session/daemonSocket.d.ts +10 -0
- package/dist/session/daemonSocket.js +22 -0
- package/dist/session/lastSession.d.ts +6 -3
- package/dist/session/lastSession.js +11 -5
- package/dist/session/paths.d.ts +3 -1
- package/dist/session/paths.js +5 -5
- package/dist/session/portClaims.js +4 -3
- package/dist/session/sessionList.d.ts +13 -5
- package/dist/session/sessionList.js +31 -7
- package/dist/telemetry/a11y.d.ts +15 -1
- package/dist/telemetry/a11y.js +85 -2
- package/dist/telemetry/console.d.ts +2 -1
- package/dist/telemetry/console.js +30 -21
- package/dist/telemetry/har/builder.js +1 -1
- package/dist/telemetry/network.d.ts +13 -16
- package/dist/telemetry/network.js +30 -52
- package/dist/telemetry/networkRetention.d.ts +83 -0
- package/dist/telemetry/networkRetention.js +117 -0
- package/dist/telemetry/pageCrash.d.ts +26 -0
- package/dist/telemetry/pageCrash.js +53 -0
- package/dist/types.d.ts +42 -0
- package/dist/ui/OutputBuilder.d.ts +10 -0
- package/dist/ui/OutputBuilder.js +12 -0
- package/dist/ui/formatters/a11y.d.ts +5 -7
- package/dist/ui/formatters/a11y.js +7 -61
- package/dist/ui/formatters/audit.js +14 -5
- package/dist/ui/formatters/cdp.d.ts +138 -0
- package/dist/ui/formatters/cdp.js +131 -0
- package/dist/ui/formatters/console/chronological.js +7 -5
- package/dist/ui/formatters/console/follow.d.ts +5 -2
- package/dist/ui/formatters/console/follow.js +7 -4
- package/dist/ui/formatters/console/json.d.ts +4 -7
- package/dist/ui/formatters/console/json.js +16 -14
- package/dist/ui/formatters/console/shared.d.ts +47 -2
- package/dist/ui/formatters/console/shared.js +33 -0
- package/dist/ui/formatters/console/summarize.d.ts +9 -2
- package/dist/ui/formatters/console/summarize.js +57 -11
- package/dist/ui/formatters/console.d.ts +3 -2
- package/dist/ui/formatters/console.js +8 -10
- package/dist/ui/formatters/details.js +4 -2
- package/dist/ui/formatters/dom.d.ts +14 -5
- package/dist/ui/formatters/dom.js +30 -13
- package/dist/ui/formatters/helpFormatters.js +1 -1
- package/dist/ui/formatters/inspect.js +9 -3
- package/dist/ui/formatters/installSkill.d.ts +9 -1
- package/dist/ui/formatters/installSkill.js +32 -6
- package/dist/ui/formatters/layout.js +4 -2
- package/dist/ui/formatters/longValues.d.ts +14 -0
- package/dist/ui/formatters/longValues.js +23 -0
- package/dist/ui/formatters/networkList.d.ts +8 -2
- package/dist/ui/formatters/networkList.js +11 -3
- package/dist/ui/formatters/preview.d.ts +6 -1
- package/dist/ui/formatters/preview.js +67 -15
- package/dist/ui/formatters/sessions.d.ts +2 -2
- package/dist/ui/formatters/sessions.js +9 -2
- package/dist/ui/formatters/status.js +7 -0
- package/dist/ui/formatters/triggeredRequests.js +2 -1
- package/dist/ui/logging/logger.d.ts +1 -1
- package/dist/ui/messages/chrome.d.ts +20 -1
- package/dist/ui/messages/chrome.js +29 -3
- package/dist/ui/messages/commands.d.ts +153 -12
- package/dist/ui/messages/commands.js +198 -15
- package/dist/ui/messages/consoleMessages.d.ts +24 -0
- package/dist/ui/messages/consoleMessages.js +32 -0
- package/dist/ui/messages/networkMessages.d.ts +24 -0
- package/dist/ui/messages/networkMessages.js +45 -0
- package/dist/ui/messages/preview.d.ts +6 -0
- package/dist/ui/messages/preview.js +9 -1
- package/dist/ui/messages/session.d.ts +13 -2
- package/dist/ui/messages/session.js +22 -3
- package/dist/utils/directories.d.ts +34 -0
- package/dist/utils/directories.js +88 -0
- package/dist/utils/display.d.ts +16 -0
- package/dist/utils/display.js +42 -0
- package/dist/utils/exitCodes.d.ts +1 -0
- package/dist/utils/exitCodes.js +6 -0
- package/dist/utils/http.d.ts +9 -2
- package/dist/utils/http.js +4 -3
- package/dist/utils/process.d.ts +12 -0
- package/dist/utils/process.js +25 -0
- package/dist/utils/strings.d.ts +19 -0
- package/dist/utils/strings.js +16 -0
- package/package.json +2 -2
package/dist/commands/cdp.js
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
+
import { Option } from 'commander';
|
|
1
2
|
import { normalizeMethod } from '../cdp/protocol.js';
|
|
2
3
|
import { getAllDomainSummaries, getDomainMethods, getProtocolCounts, getDomainSummary, getMethodSchema, } from '../cdp/schema.js';
|
|
3
4
|
import { runCommand } from './shared/CommandRunner.js';
|
|
4
5
|
import { jsonOption } from './shared/commonOptions.js';
|
|
5
6
|
import { CommandError } from '../errors/index.js';
|
|
7
|
+
import { emptyCdpSearchError, missingArgumentError, scriptExecutionError, } from '../errors/messages.js';
|
|
6
8
|
import { callCDP } from '../ipc/client.js';
|
|
7
9
|
import { validateIPCResponse } from '../ipc/index.js';
|
|
10
|
+
import { describeException } from '../runtime/dom/evalHelpers.js';
|
|
11
|
+
import { formatCdpDescription, formatCdpDomainMethods, formatCdpDomains, formatCdpResult, formatCdpSearch, isEmptyCdpResult, } from '../ui/formatters/cdp.js';
|
|
8
12
|
import { formatHint } from '../ui/messages/hints.js';
|
|
9
13
|
import { sessionCommand } from '../ui/messages/sessionCommand.js';
|
|
10
14
|
import { getErrorMessage } from '../utils/errors.js';
|
|
@@ -26,6 +30,8 @@ const DOMAIN_NOTES = {
|
|
|
26
30
|
Tracing: 'Performance tracing. Call Tracing.start, perform actions, then Tracing.end. ' +
|
|
27
31
|
'Data arrives via Tracing.dataCollected events.',
|
|
28
32
|
};
|
|
33
|
+
/** Usage of `bdg cdp`, suggested when it gets neither a method nor a flag */
|
|
34
|
+
const CDP_USAGE = 'Usage: bdg cdp [method] [--params <json>] [--list] [--describe] [--search <query>]';
|
|
29
35
|
/**
|
|
30
36
|
* Domain and method counts of the bundled protocol, for the help text.
|
|
31
37
|
*
|
|
@@ -44,18 +50,6 @@ const METHOD_NOTES = {
|
|
|
44
50
|
'Profiler.start': 'Starts CPU profiling. Returns empty. Call Profiler.stop to get the profile data.',
|
|
45
51
|
'Tracing.start': 'Starts tracing. Returns empty. Data arrives via events after Tracing.end.',
|
|
46
52
|
};
|
|
47
|
-
/**
|
|
48
|
-
* Check if a CDP result is empty (null, undefined, or empty object).
|
|
49
|
-
*/
|
|
50
|
-
function isEmptyResult(result) {
|
|
51
|
-
if (result === null || result === undefined) {
|
|
52
|
-
return true;
|
|
53
|
-
}
|
|
54
|
-
if (typeof result === 'object' && Object.keys(result).length === 0) {
|
|
55
|
-
return true;
|
|
56
|
-
}
|
|
57
|
-
return false;
|
|
58
|
-
}
|
|
59
53
|
/**
|
|
60
54
|
* Get contextual hint for a method based on domain notes and result.
|
|
61
55
|
*/
|
|
@@ -64,7 +58,7 @@ function getMethodHint(methodName, result) {
|
|
|
64
58
|
return METHOD_NOTES[methodName];
|
|
65
59
|
}
|
|
66
60
|
const domain = methodName.split('.')[0];
|
|
67
|
-
if (domain && DOMAIN_NOTES[domain] &&
|
|
61
|
+
if (domain && DOMAIN_NOTES[domain] && isEmptyCdpResult(result)) {
|
|
68
62
|
return DOMAIN_NOTES[domain];
|
|
69
63
|
}
|
|
70
64
|
return undefined;
|
|
@@ -90,35 +84,87 @@ export function registerCdpCommand(program) {
|
|
|
90
84
|
' Discovery: --list, --search, --describe\n' +
|
|
91
85
|
' Execution: case-insensitive (network.getcookies works)')
|
|
92
86
|
.argument('[method]', 'CDP method name (e.g., Network.getCookies, network.getcookies)')
|
|
93
|
-
.
|
|
94
|
-
.
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
87
|
+
.addOption(new Option('--params <json>', 'Method parameters as JSON'))
|
|
88
|
+
.addOption(new Option('--list', 'List all domains or methods in a domain').conflicts([
|
|
89
|
+
'describe',
|
|
90
|
+
'params',
|
|
91
|
+
]))
|
|
92
|
+
.addOption(new Option('--describe', 'Show method signature and parameters').conflicts('params'))
|
|
93
|
+
.addOption(new Option('--search <query>', 'Search methods by keyword').conflicts([
|
|
94
|
+
'list',
|
|
95
|
+
'describe',
|
|
96
|
+
'params',
|
|
97
|
+
]))
|
|
98
|
+
.addOption(jsonOption())
|
|
98
99
|
.addHelpText('after', () => `\nBundled protocol: ${cdpCountsText()}`)
|
|
99
100
|
.action(async (method, options) => {
|
|
100
|
-
await
|
|
101
|
-
if (opts.search) {
|
|
102
|
-
return await handleSearch(opts.search, method);
|
|
103
|
-
}
|
|
104
|
-
if (opts.list && !method) {
|
|
105
|
-
return handleListDomains();
|
|
106
|
-
}
|
|
107
|
-
if (opts.list && method) {
|
|
108
|
-
return handleListDomainMethods(method);
|
|
109
|
-
}
|
|
110
|
-
if (opts.describe && method) {
|
|
111
|
-
return handleDescribeMethod(method);
|
|
112
|
-
}
|
|
113
|
-
if (method) {
|
|
114
|
-
return await handleExecuteMethod(method, opts.params);
|
|
115
|
-
}
|
|
116
|
-
throw new CommandError('Missing required argument or flag', {
|
|
117
|
-
suggestion: 'Usage: bdg cdp [method] [--params <json>] [--list] [--describe] [--search <query>]',
|
|
118
|
-
}, EXIT_CODES.INVALID_ARGUMENTS);
|
|
119
|
-
}, { ...options, json: true });
|
|
101
|
+
await runCdpCommand(method, options);
|
|
120
102
|
});
|
|
121
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* Run the `bdg cdp` mode the options select, with its human-readable output.
|
|
106
|
+
*
|
|
107
|
+
* @param method - Method or domain argument
|
|
108
|
+
* @param options - Command options (exits 81 when neither a method nor a
|
|
109
|
+
* discovery flag is given)
|
|
110
|
+
*/
|
|
111
|
+
async function runCdpCommand(method, options) {
|
|
112
|
+
if (options.search !== undefined) {
|
|
113
|
+
const query = options.search;
|
|
114
|
+
return runCommand(async () => handleSearch(query, method), options, formatCdpSearch);
|
|
115
|
+
}
|
|
116
|
+
if (method && (options.list || isBareDomain(method, options))) {
|
|
117
|
+
return runCommand(async () => handleListDomainMethods(method), options, formatCdpDomainMethods);
|
|
118
|
+
}
|
|
119
|
+
if (options.list)
|
|
120
|
+
return runCommand(async () => handleListDomains(), options, formatCdpDomains);
|
|
121
|
+
if (options.describe && method) {
|
|
122
|
+
return runCommand(async () => handleDescribeMethod(method), options, formatCdpDescription);
|
|
123
|
+
}
|
|
124
|
+
if (method) {
|
|
125
|
+
return runCommand(async () => handleExecuteMethod(method, options.params), options, formatCdpResult);
|
|
126
|
+
}
|
|
127
|
+
return runCommand(async () => {
|
|
128
|
+
const err = missingArgumentError(CDP_USAGE);
|
|
129
|
+
throw new CommandError(err.message, { suggestion: err.suggestion }, EXIT_CODES.INVALID_ARGUMENTS);
|
|
130
|
+
}, options);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Whether the argument names a domain without a method and nothing asks to
|
|
134
|
+
* run it (`bdg cdp Network`): its methods are listed, as with `--list`.
|
|
135
|
+
*
|
|
136
|
+
* @param method - Method or domain argument
|
|
137
|
+
* @param options - Command options
|
|
138
|
+
* @returns True for a bare domain name
|
|
139
|
+
*/
|
|
140
|
+
export function isBareDomain(method, options) {
|
|
141
|
+
return (!method.includes('.') &&
|
|
142
|
+
options.params === undefined &&
|
|
143
|
+
!options.describe &&
|
|
144
|
+
getDomainSummary(method) !== undefined);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* The page exception a method reported in its result (`Runtime.evaluate`,
|
|
148
|
+
* `Runtime.callFunctionOn`, ... answer a script that threw with
|
|
149
|
+
* `exceptionDetails`), as an error result like `dom eval`'s (exit 91).
|
|
150
|
+
*
|
|
151
|
+
* @param result - Method result
|
|
152
|
+
* @returns Error result, or undefined when the result has no exception
|
|
153
|
+
*/
|
|
154
|
+
export function pageExceptionResult(result) {
|
|
155
|
+
if (typeof result !== 'object' || result === null || !('exceptionDetails' in result)) {
|
|
156
|
+
return undefined;
|
|
157
|
+
}
|
|
158
|
+
const details = result
|
|
159
|
+
.exceptionDetails;
|
|
160
|
+
const err = scriptExecutionError(describeException(details));
|
|
161
|
+
return {
|
|
162
|
+
success: false,
|
|
163
|
+
error: err.message,
|
|
164
|
+
exitCode: EXIT_CODES.SCRIPT_ERROR,
|
|
165
|
+
errorContext: { suggestion: err.suggestion },
|
|
166
|
+
};
|
|
167
|
+
}
|
|
122
168
|
/**
|
|
123
169
|
* Find similar methods to suggest when a method is not found.
|
|
124
170
|
* Returns up to 3 closest matches based on edit distance.
|
|
@@ -177,6 +223,15 @@ function blockedAlternative(methodName) {
|
|
|
177
223
|
* @returns Success result with matching methods
|
|
178
224
|
*/
|
|
179
225
|
async function handleSearch(query, domain) {
|
|
226
|
+
if (!query.trim()) {
|
|
227
|
+
const err = emptyCdpSearchError();
|
|
228
|
+
return {
|
|
229
|
+
success: false,
|
|
230
|
+
error: err.message,
|
|
231
|
+
exitCode: EXIT_CODES.INVALID_ARGUMENTS,
|
|
232
|
+
errorContext: { suggestion: err.suggestion },
|
|
233
|
+
};
|
|
234
|
+
}
|
|
180
235
|
if (domain !== undefined && !getDomainSummary(domain)) {
|
|
181
236
|
return {
|
|
182
237
|
success: false,
|
|
@@ -186,11 +241,11 @@ async function handleSearch(query, domain) {
|
|
|
186
241
|
};
|
|
187
242
|
}
|
|
188
243
|
const { searchMethods } = await import('../cdp/schema.js');
|
|
189
|
-
const results = searchMethods(query).filter((m) => domain === undefined || m.domain.toLowerCase() === domain.toLowerCase());
|
|
244
|
+
const results = searchMethods(query.trim()).filter((m) => domain === undefined || m.domain.toLowerCase() === domain.toLowerCase());
|
|
190
245
|
return {
|
|
191
246
|
success: true,
|
|
192
247
|
data: {
|
|
193
|
-
query,
|
|
248
|
+
query: query.trim(),
|
|
194
249
|
count: results.length,
|
|
195
250
|
methods: results.map((m) => ({
|
|
196
251
|
name: m.name,
|
|
@@ -338,6 +393,7 @@ function handleDescribeMethod(methodName) {
|
|
|
338
393
|
};
|
|
339
394
|
}
|
|
340
395
|
const methodNote = METHOD_NOTES[schema.name] ?? DOMAIN_NOTES[schema.domain];
|
|
396
|
+
const alternative = blockedAlternative(schema.name);
|
|
341
397
|
return {
|
|
342
398
|
success: true,
|
|
343
399
|
data: {
|
|
@@ -365,9 +421,7 @@ function handleDescribeMethod(methodName) {
|
|
|
365
421
|
description: r.description,
|
|
366
422
|
items: r.items,
|
|
367
423
|
})),
|
|
368
|
-
example:
|
|
369
|
-
? { command: blockedAlternative(schema.name) }
|
|
370
|
-
: schema.example,
|
|
424
|
+
example: alternative ? { command: alternative } : schema.example,
|
|
371
425
|
},
|
|
372
426
|
};
|
|
373
427
|
}
|
|
@@ -443,6 +497,9 @@ async function handleExecuteMethod(methodName, paramsJson) {
|
|
|
443
497
|
const response = await callCDP(normalized, params);
|
|
444
498
|
validateIPCResponse(response);
|
|
445
499
|
const cdpResult = response.data?.result;
|
|
500
|
+
const exception = pageExceptionResult(cdpResult);
|
|
501
|
+
if (exception)
|
|
502
|
+
return exception;
|
|
446
503
|
const result = {
|
|
447
504
|
success: true,
|
|
448
505
|
data: {
|
|
@@ -22,6 +22,18 @@ export declare function listsMessages(options: Pick<ConsoleCommandOptions, 'list
|
|
|
22
22
|
* @returns Messages of the current page (empty if it logged nothing)
|
|
23
23
|
*/
|
|
24
24
|
export declare function filterByCurrentNavigation(messages: ConsoleMessage[], currentNavigationId?: number): ConsoleMessage[];
|
|
25
|
+
/**
|
|
26
|
+
* Dropped messages that could have been in the view: all of them with
|
|
27
|
+
* `--history`; for the current page only while the oldest kept message is
|
|
28
|
+
* that page's (else every dropped one came from an earlier page).
|
|
29
|
+
*
|
|
30
|
+
* @param messages - All kept messages, oldest first
|
|
31
|
+
* @param dropped - Oldest messages the session dropped at its limit
|
|
32
|
+
* @param options - `--history`
|
|
33
|
+
* @param currentNavigationId - Navigation id of the current page, if known
|
|
34
|
+
* @returns Dropped count to warn about (0: none of the view's)
|
|
35
|
+
*/
|
|
36
|
+
export declare function droppedInView(messages: ConsoleMessage[], dropped: number, options: Pick<ConsoleCommandOptions, 'history'>, currentNavigationId?: number): number;
|
|
25
37
|
export declare function filterByLevel(messages: ConsoleMessage[], level: ConsoleLevel): ConsoleMessage[];
|
|
26
38
|
/**
|
|
27
39
|
* Messages the filters left out between the first and the last listed
|
package/dist/commands/console.js
CHANGED
|
@@ -6,11 +6,13 @@ import { runCommand } from './shared/CommandRunner.js';
|
|
|
6
6
|
import { jsonOption } from './shared/commonOptions.js';
|
|
7
7
|
import { noteFollowConnected } from './shared/daemonErrorHandler.js';
|
|
8
8
|
import { fetchConsoleMessages, createErrorResult } from './shared/dataFetcher.js';
|
|
9
|
-
import { followFetchFailure, setupFollowMode, } from './shared/followMode.js';
|
|
9
|
+
import { followFetchFailure, newPageCrashes, setupFollowMode, } from './shared/followMode.js';
|
|
10
10
|
import { handleValidationError } from './shared/handleValidationError.js';
|
|
11
11
|
import { consoleLevelOption, positiveIntRule } from './shared/validation.js';
|
|
12
|
+
import { MAX_CONSOLE_JSON_TEXT_LENGTH, MAX_CONSOLE_TEXT_LENGTH } from '../constants.js';
|
|
12
13
|
import { buildSuccessResponse } from '../ui/OutputBuilder.js';
|
|
13
14
|
import { buildConsoleJsonOutput, formatConsole, formatConsoleFollowLines, LEVEL_MAP, lastMessages, } from '../ui/formatters/console.js';
|
|
15
|
+
import { pageCrashedNote } from '../ui/messages/commands.js';
|
|
14
16
|
import { followingConsoleMessage, stoppedFollowingConsoleMessage, } from '../ui/messages/consoleMessages.js';
|
|
15
17
|
const MIN_LAST = 0;
|
|
16
18
|
const MAX_LAST = 10000;
|
|
@@ -37,9 +39,40 @@ export function listsMessages(options) {
|
|
|
37
39
|
export function filterByCurrentNavigation(messages, currentNavigationId) {
|
|
38
40
|
if (messages.length === 0)
|
|
39
41
|
return messages;
|
|
40
|
-
const navId =
|
|
42
|
+
const navId = shownNavigationId(messages, currentNavigationId);
|
|
41
43
|
return messages.filter((m) => (m.navigationId ?? 0) === navId);
|
|
42
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* Navigation id of the page whose messages are shown without `--history`.
|
|
47
|
+
*
|
|
48
|
+
* @param messages - All captured messages
|
|
49
|
+
* @param currentNavigationId - Navigation id of the current page, if known
|
|
50
|
+
* @returns That id, else the newest navigation id among the messages
|
|
51
|
+
*/
|
|
52
|
+
function shownNavigationId(messages, currentNavigationId) {
|
|
53
|
+
return currentNavigationId ?? Math.max(...messages.map((m) => m.navigationId ?? 0));
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Dropped messages that could have been in the view: all of them with
|
|
57
|
+
* `--history`; for the current page only while the oldest kept message is
|
|
58
|
+
* that page's (else every dropped one came from an earlier page).
|
|
59
|
+
*
|
|
60
|
+
* @param messages - All kept messages, oldest first
|
|
61
|
+
* @param dropped - Oldest messages the session dropped at its limit
|
|
62
|
+
* @param options - `--history`
|
|
63
|
+
* @param currentNavigationId - Navigation id of the current page, if known
|
|
64
|
+
* @returns Dropped count to warn about (0: none of the view's)
|
|
65
|
+
*/
|
|
66
|
+
export function droppedInView(messages, dropped, options, currentNavigationId) {
|
|
67
|
+
if (dropped === 0 || options.history)
|
|
68
|
+
return dropped;
|
|
69
|
+
const oldest = messages[0];
|
|
70
|
+
if (!oldest)
|
|
71
|
+
return dropped;
|
|
72
|
+
return (oldest.navigationId ?? 0) === shownNavigationId(messages, currentNavigationId)
|
|
73
|
+
? dropped
|
|
74
|
+
: 0;
|
|
75
|
+
}
|
|
43
76
|
export function filterByLevel(messages, level) {
|
|
44
77
|
return messages.filter((m) => LEVEL_MAP[m.type] === level);
|
|
45
78
|
}
|
|
@@ -84,28 +117,35 @@ export function skippedMessages(all, listed) {
|
|
|
84
117
|
* @param options - Command options
|
|
85
118
|
* @param lastN - `--last` value
|
|
86
119
|
* @param skipped - Messages the filters left out between the listed ones
|
|
120
|
+
* @param dropped - Oldest messages the session dropped at its limit
|
|
121
|
+
* @param pageCrashedAt - When the page crashed, while it is not loaded again
|
|
87
122
|
* @returns Formatting options
|
|
88
123
|
*/
|
|
89
|
-
function buildFormatOptions(options, lastN, skipped) {
|
|
124
|
+
function buildFormatOptions(options, lastN, skipped, dropped, pageCrashedAt) {
|
|
90
125
|
return {
|
|
91
|
-
|
|
126
|
+
...(options.last !== undefined && { groupLimit: lastN }),
|
|
127
|
+
...(dropped && { dropped }),
|
|
128
|
+
...(pageCrashedAt !== undefined && { pageCrashedAt }),
|
|
92
129
|
list: listsMessages(options),
|
|
93
130
|
follow: options.follow,
|
|
94
131
|
last: lastN,
|
|
95
132
|
history: options.history,
|
|
96
133
|
level: options.level,
|
|
134
|
+
full: options.full,
|
|
97
135
|
skipped,
|
|
98
136
|
};
|
|
99
137
|
}
|
|
100
138
|
/**
|
|
101
139
|
* Stream console messages: the last `lastN` at start, then each new message
|
|
102
|
-
* once (like `tail -f`), with a separator when the page navigates
|
|
140
|
+
* once (like `tail -f`), with a separator when the page navigates and a
|
|
141
|
+
* warning (JSON `pageCrashedAt`) once when the page crashes.
|
|
103
142
|
*
|
|
104
143
|
* @param options - Command options
|
|
105
144
|
* @param lastN - Messages to show at start (0 = all)
|
|
106
145
|
*/
|
|
107
146
|
async function runFollowMode(options, lastN) {
|
|
108
147
|
const shown = new Set();
|
|
148
|
+
const newCrash = newPageCrashes();
|
|
109
149
|
let navigationId;
|
|
110
150
|
let started = false;
|
|
111
151
|
const showConsole = async () => {
|
|
@@ -115,6 +155,7 @@ async function runFollowMode(options, lastN) {
|
|
|
115
155
|
}
|
|
116
156
|
noteFollowConnected();
|
|
117
157
|
const { messages, currentNavigationId } = result.data;
|
|
158
|
+
const crashedAt = newCrash(result.data.pageCrashedAt);
|
|
118
159
|
const matching = applyFilters(messages, options, currentNavigationId);
|
|
119
160
|
const keys = messageKeys(matching);
|
|
120
161
|
const fresh = matching.filter((_message, i) => !shown.has(keys[i]));
|
|
@@ -124,19 +165,27 @@ async function runFollowMode(options, lastN) {
|
|
|
124
165
|
const navigated = started && navigationId !== currentNavigationId;
|
|
125
166
|
navigationId = currentNavigationId;
|
|
126
167
|
if (options.json) {
|
|
127
|
-
if (!started || backlog.length > 0) {
|
|
128
|
-
const data = buildConsoleJsonOutput(backlog, {
|
|
129
|
-
|
|
168
|
+
if (!started || backlog.length > 0 || crashedAt !== undefined) {
|
|
169
|
+
const data = buildConsoleJsonOutput(backlog, {
|
|
170
|
+
list: true,
|
|
171
|
+
last: 0,
|
|
172
|
+
pageCrashedAt: crashedAt,
|
|
173
|
+
full: options.full,
|
|
174
|
+
});
|
|
175
|
+
console.log(JSON.stringify(buildSuccessResponse(data)));
|
|
130
176
|
}
|
|
131
177
|
}
|
|
132
178
|
else {
|
|
133
179
|
const text = formatConsoleFollowLines(backlog, {
|
|
134
180
|
header: !started,
|
|
181
|
+
full: options.full,
|
|
135
182
|
...(navigated &&
|
|
136
183
|
currentNavigationId !== undefined && { navigationId: currentNavigationId }),
|
|
137
184
|
});
|
|
138
185
|
if (text)
|
|
139
186
|
console.log(text);
|
|
187
|
+
if (crashedAt !== undefined)
|
|
188
|
+
console.log(pageCrashedNote(crashedAt));
|
|
140
189
|
}
|
|
141
190
|
started = true;
|
|
142
191
|
return undefined;
|
|
@@ -173,6 +222,7 @@ export function registerConsoleCommand(program) {
|
|
|
173
222
|
.addOption(new Option('-H, --history', 'Show messages from all page loads (default: current only)').default(false))
|
|
174
223
|
.addOption(new Option('--level <level>', 'Filter by message level: error, warning, info (includes log), debug; any case').argParser(consoleLevelOption))
|
|
175
224
|
.addOption(consoleLastOption)
|
|
225
|
+
.addOption(new Option('--full', `Print message texts whole (default: the first ${MAX_CONSOLE_TEXT_LENGTH} characters, ${MAX_CONSOLE_JSON_TEXT_LENGTH} in JSON)`).default(false))
|
|
176
226
|
.addOption(jsonOption())
|
|
177
227
|
.action(async (options) => {
|
|
178
228
|
let lastN;
|
|
@@ -196,19 +246,23 @@ export function registerConsoleCommand(program) {
|
|
|
196
246
|
if (!result.success) {
|
|
197
247
|
return createErrorResult(result.error, result.exitCode, result.suggestion);
|
|
198
248
|
}
|
|
199
|
-
const { messages, currentNavigationId } = result.data;
|
|
249
|
+
const { messages, currentNavigationId, dropped, pageCrashedAt } = result.data;
|
|
200
250
|
const filtered = applyFilters(messages, options, currentNavigationId);
|
|
201
251
|
if (options.json) {
|
|
202
252
|
return {
|
|
203
253
|
success: true,
|
|
204
|
-
data: buildConsoleJsonOutput(filtered, buildFormatOptions(options, lastN)),
|
|
254
|
+
data: buildConsoleJsonOutput(filtered, buildFormatOptions(options, lastN, undefined, dropped, pageCrashedAt)),
|
|
205
255
|
};
|
|
206
256
|
}
|
|
207
|
-
|
|
257
|
+
const droppedShown = droppedInView(messages, dropped, options, currentNavigationId);
|
|
258
|
+
return {
|
|
259
|
+
success: true,
|
|
260
|
+
data: { messages, filtered, dropped: droppedShown, pageCrashedAt },
|
|
261
|
+
};
|
|
208
262
|
}, options, (data) => {
|
|
209
|
-
const { messages, filtered } = data;
|
|
263
|
+
const { messages, filtered, dropped, pageCrashedAt } = data;
|
|
210
264
|
const skipped = skippedMessages(messages, lastMessages(filtered, lastN));
|
|
211
|
-
return formatConsole(filtered, buildFormatOptions(options, lastN, skipped));
|
|
265
|
+
return formatConsole(filtered, buildFormatOptions(options, lastN, skipped, dropped, pageCrashedAt));
|
|
212
266
|
});
|
|
213
267
|
});
|
|
214
268
|
}
|
|
@@ -109,7 +109,9 @@ export declare class DomElementResolver {
|
|
|
109
109
|
*
|
|
110
110
|
* @param index - Zero-based index
|
|
111
111
|
* @returns Cached node and the query's selector
|
|
112
|
-
* @throws CommandError (83) without a session, (81) without a usable cache,
|
|
112
|
+
* @throws CommandError (83) without a session, (81) without a usable cache,
|
|
113
|
+
* (87) for an index outside the cached results or of a page document
|
|
114
|
+
* that has since been replaced (another page's elements reuse its node ids)
|
|
113
115
|
*/
|
|
114
116
|
private lookup;
|
|
115
117
|
}
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
* // { success: true, selector: 'button.submit' }
|
|
19
19
|
* ```
|
|
20
20
|
*/
|
|
21
|
+
import { pageDocumentId } from './helpers/query.js';
|
|
21
22
|
import { noActiveSessionError } from '../shared/CommandRunner.js';
|
|
22
23
|
import { CommandError } from '../../errors/index.js';
|
|
23
24
|
import { cachedIndexOutOfRangeError, indexWithIndexOptionError, staleNodeError, } from '../../errors/messages.js';
|
|
@@ -136,7 +137,9 @@ export class DomElementResolver {
|
|
|
136
137
|
*
|
|
137
138
|
* @param index - Zero-based index
|
|
138
139
|
* @returns Cached node and the query's selector
|
|
139
|
-
* @throws CommandError (83) without a session, (81) without a usable cache,
|
|
140
|
+
* @throws CommandError (83) without a session, (81) without a usable cache,
|
|
141
|
+
* (87) for an index outside the cached results or of a page document
|
|
142
|
+
* that has since been replaced (another page's elements reuse its node ids)
|
|
140
143
|
*/
|
|
141
144
|
async lookup(index) {
|
|
142
145
|
const validation = await this.cacheManager.validate();
|
|
@@ -145,11 +148,15 @@ export class DomElementResolver {
|
|
|
145
148
|
throw noActiveSessionError();
|
|
146
149
|
throw new CommandError(validation.error ?? 'No cached query results found', validation.suggestion ? { suggestion: validation.suggestion } : {}, EXIT_CODES.INVALID_ARGUMENTS);
|
|
147
150
|
}
|
|
148
|
-
const { nodes, selector } = validation.cache;
|
|
151
|
+
const { nodes, selector, count, document } = validation.cache;
|
|
149
152
|
const source = indexSourceOf(index, selector);
|
|
153
|
+
if (document !== undefined && (await pageDocumentId()) !== document) {
|
|
154
|
+
const err = staleNodeError(index, source);
|
|
155
|
+
throw new CommandError(err.message, { suggestion: err.suggestion }, EXIT_CODES.STALE_CACHE);
|
|
156
|
+
}
|
|
150
157
|
const node = nodes.find((n) => n.index === index);
|
|
151
158
|
if (!node) {
|
|
152
|
-
const err = cachedIndexOutOfRangeError(source, nodes.length);
|
|
159
|
+
const err = cachedIndexOutOfRangeError(source, nodes.length, count);
|
|
153
160
|
throw new CommandError(err.message, { suggestion: err.suggestion }, EXIT_CODES.STALE_CACHE);
|
|
154
161
|
}
|
|
155
162
|
return { node, selector, source };
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Accessibility tree inspection commands for semantic element queries.
|
|
3
3
|
*
|
|
4
4
|
* Provides three core commands:
|
|
5
|
-
* - tree:
|
|
5
|
+
* - tree: List the accessibility tree (bounded by --limit / --depth)
|
|
6
6
|
* - query: Search by role/name/description patterns
|
|
7
7
|
* - describe: Get A11y properties for CSS selector
|
|
8
8
|
*
|
|
@@ -2,50 +2,48 @@
|
|
|
2
2
|
* Accessibility tree inspection commands for semantic element queries.
|
|
3
3
|
*
|
|
4
4
|
* Provides three core commands:
|
|
5
|
-
* - tree:
|
|
5
|
+
* - tree: List the accessibility tree (bounded by --limit / --depth)
|
|
6
6
|
* - query: Search by role/name/description patterns
|
|
7
7
|
* - describe: Get A11y properties for CSS selector
|
|
8
8
|
*
|
|
9
9
|
* Uses IPC/callCDP pattern for consistency with other DOM commands.
|
|
10
10
|
*/
|
|
11
11
|
import { DomElementResolver } from './DomElementResolver.js';
|
|
12
|
-
import { getDomContext, resolveBackendNodeIds } from './helpers/index.js';
|
|
12
|
+
import { getDomContext, pageDocumentId, resolveBackendNodeIds, } from './helpers/index.js';
|
|
13
13
|
import { withSecretMasked } from './semanticUtils.js';
|
|
14
14
|
import { runCommand, runJsonCommand } from '../shared/CommandRunner.js';
|
|
15
15
|
import { jsonOption } from '../shared/commonOptions.js';
|
|
16
16
|
import { integerOption } from '../shared/validation.js';
|
|
17
|
+
import { QUERY_JSON_LIST_LIMIT } from '../../constants.js';
|
|
17
18
|
import { CommandError } from '../../errors/index.js';
|
|
18
19
|
import { elementNotFoundError, invalidQueryPatternError, noA11yNodesFoundError, notInAccessibilityTreeError, } from '../../errors/messages.js';
|
|
19
20
|
import { A11Y_CACHE_SELECTOR_PREFIX, QueryCacheManager } from '../../session/QueryCacheManager.js';
|
|
20
|
-
import { a11yIgnoredReasons, collectA11yTree, queryA11yTree, parseQueryPattern, resolveA11yNode, } from '../../telemetry/a11y.js';
|
|
21
|
+
import { a11yIgnoredReasons, collectA11yTree, listA11yTree, queryA11yTree, parseQueryPattern, resolveA11yNode, } from '../../telemetry/a11y.js';
|
|
21
22
|
import { formatA11yTree, formatA11yQueryResult, formatA11yNodeWithContext, } from '../../ui/formatters/a11y.js';
|
|
22
23
|
import { EXIT_CODES } from '../../utils/exitCodes.js';
|
|
23
|
-
/** Matches `dom a11y query` lists by default in human output (a page can have hundreds of links
|
|
24
|
+
/** Matches `dom a11y query` lists by default in human output (a page can have hundreds of links) */
|
|
24
25
|
const A11Y_QUERY_LIMIT = 50;
|
|
26
|
+
/** Nodes `dom a11y tree` lists by default, in human and JSON output */
|
|
27
|
+
const A11Y_TREE_LIMIT = 50;
|
|
25
28
|
/**
|
|
26
29
|
* Handle bdg dom a11y tree command
|
|
27
30
|
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
31
|
+
* Lists the accessibility tree depth-first, the first `--limit` meaningful
|
|
32
|
+
* nodes (default {@link A11Y_TREE_LIMIT}, 0 = all) down to `--depth`, in
|
|
33
|
+
* human and JSON output; `count` is the whole tree, `omitted` the nodes cut
|
|
34
|
+
* and `skipped` the noise never listed.
|
|
30
35
|
*
|
|
31
|
-
* JSON output returns nodes as an array for
|
|
32
|
-
* bdg dom a11y tree --json | jq '.data.nodes[] | select(.role == "checkbox")'
|
|
33
|
-
* bdg dom a11y tree --json | jq '.data.nodes[0]'
|
|
36
|
+
* JSON output returns nodes as an array (each with its `depth`) for jq:
|
|
37
|
+
* bdg dom a11y tree --json --limit 0 | jq '.data.nodes[] | select(.role == "checkbox")'
|
|
34
38
|
*
|
|
35
39
|
* @param options - Command options
|
|
36
40
|
*/
|
|
37
41
|
async function handleA11yTree(options) {
|
|
42
|
+
const listTree = async () => listA11yTree(await collectA11yTree(), options.limit ?? A11Y_TREE_LIMIT, options.depth);
|
|
38
43
|
if (options.json) {
|
|
39
|
-
await runJsonCommand(
|
|
40
|
-
const tree = await collectA11yTree();
|
|
41
|
-
return {
|
|
42
|
-
root: tree.root,
|
|
43
|
-
nodes: Array.from(tree.nodes.values()),
|
|
44
|
-
count: tree.count,
|
|
45
|
-
};
|
|
46
|
-
});
|
|
44
|
+
await runJsonCommand(listTree);
|
|
47
45
|
}
|
|
48
|
-
await runCommand(async () => ({ success: true, data: await
|
|
46
|
+
await runCommand(async () => ({ success: true, data: await listTree() }), options, formatA11yTree);
|
|
49
47
|
}
|
|
50
48
|
/**
|
|
51
49
|
* Quote a search text for a query pattern, keeping the quotes it contains
|
|
@@ -85,6 +83,7 @@ async function handleA11yQuery(pattern, options) {
|
|
|
85
83
|
const err = invalidQueryPatternError(pattern);
|
|
86
84
|
throw new CommandError(err.message, { suggestion: err.suggestion }, EXIT_CODES.INVALID_ARGUMENTS);
|
|
87
85
|
}
|
|
86
|
+
const document = await pageDocumentId();
|
|
88
87
|
const tree = await collectA11yTree();
|
|
89
88
|
const result = queryA11yTree(tree, queryPattern);
|
|
90
89
|
if (result.count === 0) {
|
|
@@ -101,10 +100,10 @@ async function handleA11yQuery(pattern, options) {
|
|
|
101
100
|
tag: node.role,
|
|
102
101
|
...(node.name && { preview: node.name }),
|
|
103
102
|
})),
|
|
104
|
-
});
|
|
103
|
+
}, document);
|
|
105
104
|
return {
|
|
106
105
|
success: true,
|
|
107
|
-
data: limitMatches(indexed, options.limit ?? (options.json ?
|
|
106
|
+
data: limitMatches(indexed, options.limit ?? (options.json ? QUERY_JSON_LIST_LIMIT : A11Y_QUERY_LIMIT)),
|
|
108
107
|
};
|
|
109
108
|
}, options, formatA11yQueryResult);
|
|
110
109
|
}
|
|
@@ -206,7 +205,9 @@ export function registerA11yCommands(domCmd) {
|
|
|
206
205
|
});
|
|
207
206
|
a11y
|
|
208
207
|
.command('tree')
|
|
209
|
-
.description('
|
|
208
|
+
.description('List the accessibility tree depth-first (ignored nodes, text boxes, repeated text and nameless wrappers left out)')
|
|
209
|
+
.option('--limit <n>', `Nodes to list (default: ${A11Y_TREE_LIMIT}, also with --json; 0 = all listed nodes (text boxes and empty wrappers are always skipped))`, integerOption(0))
|
|
210
|
+
.option('--depth <n>', 'Levels below the root to list (0 = root only; default: all)', integerOption(0))
|
|
210
211
|
.addOption(jsonOption())
|
|
211
212
|
.action(async (options) => {
|
|
212
213
|
await handleA11yTree(options);
|
|
@@ -215,7 +216,7 @@ export function registerA11yCommands(domCmd) {
|
|
|
215
216
|
.command('query')
|
|
216
217
|
.description('Query elements by accessibility properties (e.g., "role:button", "name:Submit")')
|
|
217
218
|
.argument('<pattern>', "Fields role, name, description as key:value or key=value, separated by spaces or commas; * is a wildcard. A name or description runs to the next field or the end, so it may contain spaces and colons; quote the whole pattern (e.g. 'role=button name=Sign in', 'name=E-mail address:')")
|
|
218
|
-
.option('--limit <n>', `Matches to list (default: ${A11Y_QUERY_LIMIT},
|
|
219
|
+
.option('--limit <n>', `Matches to list (default: ${A11Y_QUERY_LIMIT}, ${QUERY_JSON_LIST_LIMIT} with --json; 0 = all); all are indexed`, integerOption(0))
|
|
219
220
|
.addOption(jsonOption())
|
|
220
221
|
.action(async (pattern, options) => {
|
|
221
222
|
await handleA11yQuery(pattern, options);
|
|
@@ -8,8 +8,10 @@
|
|
|
8
8
|
import type { DomEvalCommandOptions } from '../shared/optionTypes.js';
|
|
9
9
|
/**
|
|
10
10
|
* Handle `bdg dom eval <script> [--frame <frame>]`. With `--frame`, the
|
|
11
|
-
* frame the script ran in is a `Frame:` line on stderr (JSON: `frame`),
|
|
12
|
-
*
|
|
11
|
+
* frame the script ran in is a `Frame:` line on stderr (JSON: `frame`), and
|
|
12
|
+
* a warning about how the result was copied goes there too (JSON:
|
|
13
|
+
* `warning`), so stdout stays the bare value for pipes. Long values are cut
|
|
14
|
+
* (a string result in JSON with `truncatedFrom`) unless `--full`.
|
|
13
15
|
*/
|
|
14
16
|
export declare function handleDomEval(script: string, options: DomEvalCommandOptions): Promise<void>;
|
|
15
17
|
//# sourceMappingURL=eval.d.ts.map
|
|
@@ -7,15 +7,19 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { documentReadyState } from './helpers/query.js';
|
|
9
9
|
import { runCommand } from '../shared/CommandRunner.js';
|
|
10
|
+
import { MAX_VALUE_LENGTH } from '../../constants.js';
|
|
10
11
|
import { emptyScriptError, withLoadingHint } from '../../errors/messages.js';
|
|
11
12
|
import { domEval } from '../../ipc/client.js';
|
|
12
13
|
import { formatDomEval } from '../../ui/formatters/dom.js';
|
|
13
|
-
import { evalFrameLine } from '../../ui/messages/commands.js';
|
|
14
|
+
import { evalFrameLine, warningMessage } from '../../ui/messages/commands.js';
|
|
14
15
|
import { EXIT_CODES } from '../../utils/exitCodes.js';
|
|
16
|
+
import { capLength } from '../../utils/strings.js';
|
|
15
17
|
/**
|
|
16
18
|
* Handle `bdg dom eval <script> [--frame <frame>]`. With `--frame`, the
|
|
17
|
-
* frame the script ran in is a `Frame:` line on stderr (JSON: `frame`),
|
|
18
|
-
*
|
|
19
|
+
* frame the script ran in is a `Frame:` line on stderr (JSON: `frame`), and
|
|
20
|
+
* a warning about how the result was copied goes there too (JSON:
|
|
21
|
+
* `warning`), so stdout stays the bare value for pipes. Long values are cut
|
|
22
|
+
* (a string result in JSON with `truncatedFrom`) unless `--full`.
|
|
19
23
|
*/
|
|
20
24
|
export async function handleDomEval(script, options) {
|
|
21
25
|
await runCommand(async () => {
|
|
@@ -38,18 +42,38 @@ export async function handleDomEval(script, options) {
|
|
|
38
42
|
...(suggestion && { errorContext: { suggestion } }),
|
|
39
43
|
};
|
|
40
44
|
}
|
|
41
|
-
const { value, type, subtype, frame } = response.data;
|
|
45
|
+
const { value, type, subtype, frame, warning } = response.data;
|
|
46
|
+
const hint = [
|
|
47
|
+
...(frame !== undefined ? [evalFrameLine(frame)] : []),
|
|
48
|
+
...(warning ? [warningMessage(warning)] : []),
|
|
49
|
+
].join('\n');
|
|
42
50
|
return {
|
|
43
51
|
success: true,
|
|
44
52
|
data: {
|
|
45
|
-
|
|
53
|
+
...jsonResult(value, options),
|
|
46
54
|
type,
|
|
47
55
|
...(subtype && { subtype }),
|
|
48
56
|
...(frame !== undefined && { frame }),
|
|
57
|
+
...(warning && { warning }),
|
|
49
58
|
},
|
|
50
|
-
...(
|
|
59
|
+
...(hint && !options.json && { hint }),
|
|
51
60
|
};
|
|
52
|
-
}, options, formatDomEval);
|
|
61
|
+
}, options, (data) => formatDomEval(data, { full: options.full }));
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* The result field of the output: a string result in JSON cut to
|
|
65
|
+
* {@link MAX_VALUE_LENGTH} characters with `truncatedFrom`, unless `--full`
|
|
66
|
+
* (human output is cut when formatted).
|
|
67
|
+
*
|
|
68
|
+
* @param value - Evaluated value
|
|
69
|
+
* @param options - `--json`, `--full`
|
|
70
|
+
* @returns `result`, and `truncatedFrom` when cut
|
|
71
|
+
*/
|
|
72
|
+
function jsonResult(value, options) {
|
|
73
|
+
if (!options.json || options.full || typeof value !== 'string')
|
|
74
|
+
return { result: value };
|
|
75
|
+
const { text, truncatedFrom } = capLength(value, MAX_VALUE_LENGTH);
|
|
76
|
+
return { result: text, ...(truncatedFrom !== undefined && { truncatedFrom }) };
|
|
53
77
|
}
|
|
54
78
|
/**
|
|
55
79
|
* Suggestion of a failed eval; a frame not found (83) while the page is
|