browser-debugger-cli 0.10.0 → 0.12.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 +268 -0
- package/README.md +148 -74
- package/dist/commands/css.d.ts +13 -0
- package/dist/commands/css.js +53 -0
- package/dist/commands/dom/audit.d.ts +14 -0
- package/dist/commands/dom/audit.js +87 -0
- package/dist/commands/dom/formInteraction.js +36 -6
- package/dist/commands/dom/helpers/keyAttributes.d.ts +3 -2
- package/dist/commands/dom/helpers/keyAttributes.js +6 -4
- package/dist/commands/dom/helpers/screenshot.d.ts +1 -0
- package/dist/commands/dom/helpers/screenshot.js +158 -38
- package/dist/commands/dom/index.js +4 -1
- package/dist/commands/dom/screenshot.js +10 -6
- package/dist/commands/dom/wait.js +5 -3
- package/dist/commands/helpJson.js +1 -1
- package/dist/commands/installSkill.d.ts +20 -0
- package/dist/commands/installSkill.js +87 -0
- package/dist/commands/optionBehaviors.js +21 -6
- package/dist/commands/page.js +7 -4
- package/dist/commands/peek.d.ts +7 -0
- package/dist/commands/peek.js +65 -23
- package/dist/commands/shared/optionTypes.d.ts +5 -1
- package/dist/commands/start.d.ts +13 -0
- package/dist/commands/start.js +19 -2
- package/dist/commands/tail.d.ts +7 -1
- package/dist/commands/tail.js +13 -62
- package/dist/commands.js +5 -0
- package/dist/daemon/session/commandRegistry.js +7 -1
- package/dist/daemon/session/plugins.js +4 -52
- package/dist/daemon.js +7986 -6848
- package/dist/errors/messages.d.ts +50 -4
- package/dist/errors/messages.js +94 -5
- package/dist/index.js +709 -190
- package/dist/ipc/client.d.ts +4 -0
- package/dist/ipc/client.js +8 -0
- package/dist/ipc/protocol/auditTypes.d.ts +129 -0
- package/dist/ipc/protocol/auditTypes.js +6 -0
- package/dist/ipc/protocol/commands.d.ts +23 -0
- package/dist/ipc/protocol/commands.js +2 -0
- package/dist/ipc/protocol/domTypes.d.ts +4 -0
- package/dist/ipc/protocol/inspectTypes.d.ts +71 -8
- package/dist/runtime/css/search.d.ts +39 -0
- package/dist/runtime/css/search.js +122 -0
- package/dist/runtime/dom/actionEffects.d.ts +4 -1
- package/dist/runtime/dom/actionEffects.js +8 -4
- package/dist/runtime/dom/audit.d.ts +19 -0
- package/dist/runtime/dom/audit.js +36 -0
- package/dist/runtime/dom/auditModel.d.ts +45 -0
- package/dist/runtime/dom/auditModel.js +215 -0
- package/dist/runtime/dom/auditScripts.d.ts +107 -0
- package/dist/runtime/dom/auditScripts.js +112 -0
- package/dist/runtime/dom/elementGeometry.d.ts +8 -2
- package/dist/runtime/dom/elementGeometry.js +24 -8
- package/dist/runtime/dom/elementInfo.d.ts +3 -2
- package/dist/runtime/dom/elementInfo.js +8 -2
- package/dist/runtime/dom/formFillHelpers/fill.js +2 -2
- package/dist/runtime/dom/inspect.d.ts +7 -0
- package/dist/runtime/dom/inspect.js +88 -23
- package/dist/runtime/dom/inspectAllStyles.d.ts +16 -4
- package/dist/runtime/dom/inspectAllStyles.js +89 -7
- package/dist/runtime/dom/inspectCascade.d.ts +19 -2
- package/dist/runtime/dom/inspectCascade.js +214 -44
- package/dist/runtime/dom/inspectCascadeModel.d.ts +8 -0
- package/dist/runtime/dom/inspectCascadeModel.js +108 -34
- package/dist/runtime/dom/inspectHints.d.ts +26 -3
- package/dist/runtime/dom/inspectHints.js +125 -9
- package/dist/runtime/dom/inspectModel.d.ts +3 -0
- package/dist/runtime/dom/inspectModel.js +30 -7
- package/dist/runtime/dom/inspectPaintModel.d.ts +48 -22
- package/dist/runtime/dom/inspectPaintModel.js +180 -68
- package/dist/runtime/dom/inspectRules.d.ts +19 -0
- package/dist/runtime/dom/inspectRules.js +21 -5
- package/dist/runtime/dom/inspectScripts.d.ts +85 -12
- package/dist/runtime/dom/inspectScripts.js +314 -28
- package/dist/runtime/dom/inspectTree.js +10 -2
- package/dist/runtime/dom/inspectWhyModel.d.ts +2 -1
- package/dist/runtime/dom/inspectWhyModel.js +52 -10
- package/dist/runtime/dom/layout.js +31 -9
- package/dist/runtime/dom/reactEventHelpers.d.ts +7 -0
- package/dist/runtime/dom/reactEventHelpers.js +27 -9
- package/dist/runtime/page/emulation.d.ts +13 -4
- package/dist/runtime/page/emulation.js +69 -4
- package/dist/runtime/page/userAgent.d.ts +17 -0
- package/dist/runtime/page/userAgent.js +57 -0
- package/dist/types.d.ts +12 -0
- package/dist/ui/formatters/audit.d.ts +19 -0
- package/dist/ui/formatters/audit.js +106 -0
- package/dist/ui/formatters/dom.d.ts +1 -1
- package/dist/ui/formatters/dom.js +6 -3
- package/dist/ui/formatters/inspect.js +42 -15
- package/dist/ui/formatters/installSkill.d.ts +11 -0
- package/dist/ui/formatters/installSkill.js +31 -0
- package/dist/ui/formatters/status.js +1 -1
- package/dist/ui/messages/commands.d.ts +44 -7
- package/dist/ui/messages/commands.js +83 -11
- package/dist/ui/messages/preview.d.ts +6 -0
- package/dist/ui/messages/preview.js +9 -1
- package/dist/utils/cssValues.js +36 -4
- package/dist/utils/decisionTrees.js +0 -5
- package/dist/utils/suggestions.d.ts +4 -2
- package/dist/utils/suggestions.js +7 -5
- package/dist/utils/taskMappings.js +1 -1
- package/package.json +4 -2
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
import { containerKind } from '../../runtime/dom/inspectLayoutModel.js';
|
|
18
18
|
import { joinLines } from '../formatting.js';
|
|
19
|
-
import { inspectCascadeNote, inspectAnimatingBadge, inspectMidTransitionNote, inspectDarkThemeBadge, inspectedMatchAction, inspectVisibilityBadges, multipleMatchesWarning, } from '../messages/commands.js';
|
|
19
|
+
import { inspectCascadeNote, inspectAnimatingBadge, inspectMidTransitionNote, inspectDarkThemeBadge, inspectPseudoOfNote, inspectedMatchAction, inspectVisibilityBadges, multipleMatchesWarning, } from '../messages/commands.js';
|
|
20
20
|
import { shadowText, sidesShorthand } from '../../utils/cssValues.js';
|
|
21
21
|
import { truncateByLength } from '../../utils/strings.js';
|
|
22
22
|
/** Longest parent label on the parent line (CSS-module class names run long) */
|
|
@@ -50,11 +50,12 @@ export function inspectHeader(data) {
|
|
|
50
50
|
data.element,
|
|
51
51
|
data.content !== undefined && `"${data.content}"`,
|
|
52
52
|
data.placeholder !== undefined && `placeholder "${data.placeholder}"`,
|
|
53
|
-
data.rect &&
|
|
53
|
+
data.rect &&
|
|
54
|
+
`${data.rect.w}x${data.rect.h}${data.rect.screen ? ` (${data.rect.screen.w}x${data.rect.screen.h} on screen)` : ''} @${data.rect.x},${data.rect.y}${data.rect.in ? ' (fixed: viewport position)' : ''}`,
|
|
54
55
|
kind && `[${kind}]`,
|
|
55
56
|
...inspectVisibilityBadges(data.visibility),
|
|
56
57
|
data.context && `in ${data.context}`,
|
|
57
|
-
data.theme === 'dark' && inspectDarkThemeBadge(),
|
|
58
|
+
data.theme === 'dark' && inspectDarkThemeBadge(data.themeFrom === 'emulation'),
|
|
58
59
|
data.animating && inspectAnimatingBadge(data.animating),
|
|
59
60
|
]
|
|
60
61
|
.filter(Boolean)
|
|
@@ -177,9 +178,9 @@ function parentLine(layout) {
|
|
|
177
178
|
]);
|
|
178
179
|
}
|
|
179
180
|
/**
|
|
180
|
-
* Font, weight and size as one phrase, e.g. `Inter (webfont) 600 italic 16/24
|
|
181
|
-
*
|
|
182
|
-
*
|
|
181
|
+
* Font, weight and size as one phrase, e.g. `Inter (webfont) 600 italic 16/24`,
|
|
182
|
+
* `Inter (rendered "Helvetica") 400 14/normal` when the text was drawn in a
|
|
183
|
+
* fallback, or `sans-serif (resolves to "Helvetica")`; for a container only
|
|
183
184
|
* the fields it has.
|
|
184
185
|
*
|
|
185
186
|
* @param text - Text group
|
|
@@ -188,6 +189,7 @@ function parentLine(layout) {
|
|
|
188
189
|
function fontParts(text) {
|
|
189
190
|
const loaded = [
|
|
190
191
|
text.rendered && `rendered "${text.rendered}"`,
|
|
192
|
+
text.resolved && `resolves to "${text.resolved}"`,
|
|
191
193
|
text.webfont && 'webfont loaded',
|
|
192
194
|
].filter(Boolean);
|
|
193
195
|
const family = text.family && [text.family, loaded.length > 0 && `(${loaded.join(', ')})`];
|
|
@@ -218,10 +220,13 @@ function contrastText(contrast) {
|
|
|
218
220
|
if (!contrast)
|
|
219
221
|
return undefined;
|
|
220
222
|
return [
|
|
221
|
-
|
|
222
|
-
|
|
223
|
+
contrast.approximate
|
|
224
|
+
? `contrast ≈${contrast.ratio} ${contrast.level}`
|
|
225
|
+
: `contrast ${contrast.ratio} ${contrast.level}`,
|
|
226
|
+
`on ${contrast.background}`,
|
|
223
227
|
contrast.overImage && '(over image)',
|
|
224
228
|
contrast.opacity !== undefined && `(faded: opacity ${contrast.opacity})`,
|
|
229
|
+
contrast.approximate && `(approximate: ${contrast.approximate.join(', ')})`,
|
|
225
230
|
]
|
|
226
231
|
.filter(Boolean)
|
|
227
232
|
.join(' ');
|
|
@@ -234,6 +239,7 @@ function contrastText(contrast) {
|
|
|
234
239
|
*/
|
|
235
240
|
function textLine(text) {
|
|
236
241
|
return groupLine('text', [
|
|
242
|
+
text.holder && `in ${text.holder}`,
|
|
237
243
|
...fontParts(text),
|
|
238
244
|
text.color && `color ${text.color}`,
|
|
239
245
|
contrastText(text.contrast),
|
|
@@ -244,6 +250,8 @@ function textLine(text) {
|
|
|
244
250
|
text.whiteSpace && `ws ${text.whiteSpace}`,
|
|
245
251
|
text.overflow && `text-overflow ${text.overflow}`,
|
|
246
252
|
text.clamp && `clamp ${text.clamp}`,
|
|
253
|
+
text.truncated && 'truncated',
|
|
254
|
+
text.gradientFill && 'filled by its background (background-clip: text; no contrast)',
|
|
247
255
|
text.shadow && `shadow ${text.shadow}`,
|
|
248
256
|
text.features && `features ${text.features}`,
|
|
249
257
|
]);
|
|
@@ -257,9 +265,13 @@ function textLine(text) {
|
|
|
257
265
|
function fillText(fill) {
|
|
258
266
|
if (fill.type === 'solid')
|
|
259
267
|
return `bg ${fill.color}`;
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
268
|
+
return [
|
|
269
|
+
`bg-image ${fill.value}`,
|
|
270
|
+
fill.size && `size ${fill.size}`,
|
|
271
|
+
fill.position && `at ${fill.position}`,
|
|
272
|
+
]
|
|
273
|
+
.filter(Boolean)
|
|
274
|
+
.join(' ');
|
|
263
275
|
}
|
|
264
276
|
/**
|
|
265
277
|
* The fill line: backgrounds, opacity and blend mode.
|
|
@@ -268,7 +280,11 @@ function fillText(fill) {
|
|
|
268
280
|
* @returns Line
|
|
269
281
|
*/
|
|
270
282
|
function fillLine(data) {
|
|
283
|
+
const paint = data.paint;
|
|
271
284
|
return groupLine('fill', [
|
|
285
|
+
paint && `fill ${paint.fill}`,
|
|
286
|
+
paint &&
|
|
287
|
+
`stroke ${paint.stroke}${paint.strokeWidth !== undefined ? ` ${paint.strokeWidth}` : ''}`,
|
|
272
288
|
...(data.fills ?? []).map(fillText),
|
|
273
289
|
data.opacity !== undefined && `opacity ${data.opacity}`,
|
|
274
290
|
data.blend && `blend ${data.blend}`,
|
|
@@ -337,6 +353,7 @@ function pseudoText(pseudo) {
|
|
|
337
353
|
pseudo.content !== undefined && `content ${pseudo.content}`,
|
|
338
354
|
pseudo.display,
|
|
339
355
|
pseudo.position,
|
|
356
|
+
pseudo.inset && `inset ${pseudo.inset}`,
|
|
340
357
|
pseudo.size && `${pseudo.size.w}x${pseudo.size.h}`,
|
|
341
358
|
pseudo.color && `color ${pseudo.color}`,
|
|
342
359
|
pseudo.fontStyle,
|
|
@@ -370,7 +387,9 @@ function treeRow(node) {
|
|
|
370
387
|
return [
|
|
371
388
|
node.element,
|
|
372
389
|
node.count !== undefined && `×${node.count}`,
|
|
373
|
-
`${node.w}x${node.h}`,
|
|
390
|
+
node.contents ? '(contents)' : `${node.w}x${node.h}`,
|
|
391
|
+
node.shadow && '(shadow root)',
|
|
392
|
+
node.via && `via ${node.via}`,
|
|
374
393
|
node.layout && `[${node.layout}]`,
|
|
375
394
|
node.text && `"${node.text}"`,
|
|
376
395
|
node.childCount !== undefined && `(${node.childCount})`,
|
|
@@ -422,7 +441,7 @@ function ruleScope(entry) {
|
|
|
422
441
|
* @returns Lines
|
|
423
442
|
*/
|
|
424
443
|
function cascadeBlock(data) {
|
|
425
|
-
const hints = (data.hints ?? []).map((hint) => `${hint.property}: ${hint.value} ${hint.kind === 'not-inherited' ? "is the browser's" : 'has no effect'}: ${hint.reason} → ${hint.fix} · in ${hint.source}`);
|
|
444
|
+
const hints = (data.hints ?? []).map((hint) => `${hint.property}: ${hint.value} ${hint.kind === 'not-inherited' ? "is the browser's" : hint.only ? `has no effect on ${hint.only.join(', ')}` : 'has no effect'}: ${hint.reason} → ${hint.fix} · in ${hint.source}`);
|
|
426
445
|
return [
|
|
427
446
|
...labelledLines('hints', data.hints?.length === 0 ? ['none'] : hints),
|
|
428
447
|
...labelledLines('rules', (data.rules ?? []).map(ruleLine)),
|
|
@@ -472,14 +491,19 @@ function whyLines(why, data) {
|
|
|
472
491
|
entry.important ? ' !important' : '',
|
|
473
492
|
` ${entry.source}${entry.specificity ? ` [${entry.specificity.join(',')}]` : ''}${ruleScope(entry)}`,
|
|
474
493
|
entry.status === 'inherited' ? ' (inherited)' : '',
|
|
494
|
+
entry.note ? ` (${entry.note})` : '',
|
|
475
495
|
].join('');
|
|
476
496
|
});
|
|
477
497
|
const variables = (why.variables ?? []).map((variable) => ` ${variable.name}: ${truncateByLength(variable.value, CASCADE_VALUE_WIDTH)} ${variable.source}${variable.inherited !== undefined ? ` (inherited from ${levelsUp(variable.inherited)})` : ''}`);
|
|
478
498
|
return [
|
|
479
499
|
`${why.property} = ${why.computed}${midTransition(why.property, data.animating) ? ` ${inspectMidTransitionNote()}` : ''}`,
|
|
480
500
|
...entries.slice(0, 1),
|
|
501
|
+
...(why.chain[0]?.rule
|
|
502
|
+
? [` in ${truncateByLength(why.chain[0].rule, RULE_LINE_WIDTH)}`]
|
|
503
|
+
: []),
|
|
481
504
|
...variables,
|
|
482
505
|
...entries.slice(1),
|
|
506
|
+
...(why.inactive ?? []).map((rule) => ` - ${truncateByLength(rule.value, CASCADE_VALUE_WIDTH)} ${rule.selector} ${rule.condition} (does not apply now)`),
|
|
483
507
|
...(why.chain.length === 0 ? [' no author declaration: the default or inherited value'] : []),
|
|
484
508
|
];
|
|
485
509
|
}
|
|
@@ -505,6 +529,8 @@ function midTransition(property, animating) {
|
|
|
505
529
|
function levelsUp(levels) {
|
|
506
530
|
return levels === 1 ? 'the parent' : `${levels} levels up`;
|
|
507
531
|
}
|
|
532
|
+
/** Longest rule text shown under the winner in `--why` (JSON has up to 300 characters) */
|
|
533
|
+
const RULE_LINE_WIDTH = 120;
|
|
508
534
|
/** Longest declared value shown in `--rules` and `--why` lines (font stacks run long) */
|
|
509
535
|
const CASCADE_VALUE_WIDTH = 60;
|
|
510
536
|
/**
|
|
@@ -589,8 +615,9 @@ export function formatInspect(data) {
|
|
|
589
615
|
const note = data.picked
|
|
590
616
|
? multipleMatchesWarning(data.count, inspectedMatchAction(data.picked, data.index))
|
|
591
617
|
: undefined;
|
|
618
|
+
const pseudoNote = data.pseudoOf && inspectPseudoOfNote(data.pseudoOf);
|
|
592
619
|
if (data.why)
|
|
593
|
-
return joinLines(inspectHeader(data), ...cascadeBlock(data), note);
|
|
594
|
-
return joinLines(inspectHeader(data), ...body, ...cascadeBlock(data), ...treeBlock(data), note);
|
|
620
|
+
return joinLines(inspectHeader(data), ...cascadeBlock(data), note, pseudoNote);
|
|
621
|
+
return joinLines(inspectHeader(data), ...body, ...cascadeBlock(data), ...treeBlock(data), note, pseudoNote);
|
|
595
622
|
}
|
|
596
623
|
//# sourceMappingURL=inspect.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { InstalledSkill } from '../../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Format where the skill was installed, one line per agent.
|
|
4
|
+
*
|
|
5
|
+
* @param data - Install results
|
|
6
|
+
* @returns Human-readable summary
|
|
7
|
+
*/
|
|
8
|
+
export declare function formatInstalledSkills(data: {
|
|
9
|
+
skills: InstalledSkill[];
|
|
10
|
+
}): string;
|
|
11
|
+
//# sourceMappingURL=installSkill.d.ts.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { homedir } from 'os';
|
|
2
|
+
import { OutputFormatter } from '../formatting.js';
|
|
3
|
+
/**
|
|
4
|
+
* Shorten a path under the home directory to `~/...`.
|
|
5
|
+
*
|
|
6
|
+
* @param path - Absolute path
|
|
7
|
+
* @returns Path as the user would type it
|
|
8
|
+
*/
|
|
9
|
+
function tildePath(path) {
|
|
10
|
+
const home = homedir();
|
|
11
|
+
return path.startsWith(`${home}/`) ? `~${path.slice(home.length)}` : path;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Format where the skill was installed, one line per agent.
|
|
15
|
+
*
|
|
16
|
+
* @param data - Install results
|
|
17
|
+
* @returns Human-readable summary
|
|
18
|
+
*/
|
|
19
|
+
export function formatInstalledSkills(data) {
|
|
20
|
+
const fmt = new OutputFormatter().text('bdg skill:');
|
|
21
|
+
for (const skill of data.skills) {
|
|
22
|
+
fmt.text(` ${skill.target.padEnd(6)} ${skill.status.padEnd(9)} ${tildePath(skill.path)}`);
|
|
23
|
+
}
|
|
24
|
+
return fmt
|
|
25
|
+
.hints('Next:', [
|
|
26
|
+
'Start a new agent session to load it (running sessions keep the old list)',
|
|
27
|
+
'After upgrading bdg, run bdg install-skill again',
|
|
28
|
+
])
|
|
29
|
+
.build();
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=installSkill.js.map
|
|
@@ -98,7 +98,7 @@ export function appearanceLines(metadata, pageState) {
|
|
|
98
98
|
? [
|
|
99
99
|
[
|
|
100
100
|
'Viewport',
|
|
101
|
-
`${viewport.width}×${viewport.height}${metadata.viewport ? ` (emulated ${metadata.viewport.width}x${metadata.viewport.height})` : ''}`,
|
|
101
|
+
`${viewport.width}×${viewport.height}${metadata.viewport ? ` (emulated ${metadata.viewport.width}x${metadata.viewport.height}${metadata.viewport.mobile ? ', phone' : ''})` : ''}`,
|
|
102
102
|
],
|
|
103
103
|
]
|
|
104
104
|
: []),
|
|
@@ -94,6 +94,17 @@ export declare function shownElementText(element: ShownElement): string;
|
|
|
94
94
|
* "URL changed to https://example.com/#/active (same document)"
|
|
95
95
|
*/
|
|
96
96
|
export declare function pageNavigationText(navigation: PageNavigation): string;
|
|
97
|
+
/**
|
|
98
|
+
* Last `New text:` row when an action made more messages appear than are listed.
|
|
99
|
+
*
|
|
100
|
+
* @param count - Messages not listed
|
|
101
|
+
* @returns e.g. `(+4 more)`
|
|
102
|
+
*/
|
|
103
|
+
export declare function moreMessagesText(count: number): string;
|
|
104
|
+
/** Result line of `bdg dom hover --off` */
|
|
105
|
+
export declare const HOVER_OFF_DONE = "\u2713 Mouse moved off the page (hover styles and menus that close on mouseleave are gone)";
|
|
106
|
+
/** How `bdg dom hover` is called */
|
|
107
|
+
export declare const HOVER_USAGE = "bdg dom hover <selector|index>, or bdg dom hover --off to move the mouse away";
|
|
97
108
|
/**
|
|
98
109
|
* A message an action made appear, for its `New text:` rows.
|
|
99
110
|
*
|
|
@@ -252,7 +263,7 @@ export declare function layoutHeadline(count: number, listed: number, selector:
|
|
|
252
263
|
*/
|
|
253
264
|
export declare function indexLayoutHeadline(target: string): string;
|
|
254
265
|
/** Help text explaining `bdg dom inspect`'s output notation */
|
|
255
|
-
export declare const INSPECT_OUTPUT_LEGEND = "\nOutput notation:\n WxH @x,y rendered border box size and page position (CSS px, no unit)\n m / p / b margin / padding / border widths, 1-4 values in CSS order (top right bottom left)\n in-parent distances to the parent's content edges (l t r b); sib: gaps to the sibling on each side\n scroll WxH the content (pseudo-elements too) is larger than the box\n 16/24 font size / line height; 'webfont loaded' = drawn with a downloaded font;\n (rendered \"X\") = drawn with another font than declared (a fallback)\n contrast 4.47 WCAG ratio, rounded down, against the background behind the text\n (+N not rendered) children with display: none (or not in the layout)\n hints declarations on this element that have no effect, why, the fix and where they are\n ('none': checked, nothing found)\n \u2190 sel (file:N) --rules: the declaration that sets the value (file:line, or file:line:column in\n minified files); 'over X': rules it beats; '= v': the value of a var() expression\n \u2713 / \u2717 --why: the winning declaration / ones it beats, highest precedence first;\n [0,2,0]: selector specificity (ids, classes, types); indented --name lines: where\n the winner's custom properties are set\nSessions follow the system color scheme; start with --color-scheme light|dark to choose.";
|
|
266
|
+
export declare const INSPECT_OUTPUT_LEGEND = "\nOutput notation:\n WxH @x,y rendered border box size and page position (CSS px, no unit)\n m / p / b margin / padding / border widths, 1-4 values in CSS order (top right bottom left)\n in-parent distances to the parent's content edges (l t r b); sib: gaps to the sibling on each side\n scroll WxH the content (pseudo-elements too) is larger than the box\n 16/24 font size / line height; 'webfont loaded' = drawn with a downloaded font;\n (rendered \"X\") = drawn with another font than declared (a fallback);\n (resolves to \"X\") = the font a generic family (sans-serif, system-ui) became\n contrast 4.47 WCAG ratio, rounded down, against the background behind the text\n text in X the text is drawn by descendant X (the one with most of it): its font, color, contrast\n truncated the text is cut off (overflow clip, ellipsis or line clamp); a \"\u2026\" in the header is\n only bdg shortening the text\n .a.b(+3) the first two classes and how many more the element has\n sizing content-box padding and border add to the CSS size (shown only then; border-box is not)\n (+N not rendered) children with display: none (or not in the layout)\n hints declarations on this element that have no effect, why, the fix and where they are\n ('none': checked, nothing found)\n \u2190 sel (file:N) --rules: the declaration that sets the value (file:line, or file:line:column in\n minified files); 'over X': rules it beats; '= v': the value of a var() expression\n \u2713 / \u2717 --why: the winning declaration / ones it beats, highest precedence first;\n [0,2,0]: selector specificity (ids, classes, types); indented --name lines: where\n the winner's custom properties are set\nSessions follow the system color scheme; start with --color-scheme light|dark to choose.";
|
|
256
267
|
/**
|
|
257
268
|
* What covers an element: a cover that paints nothing at that point (a
|
|
258
269
|
* transparent box over it) does not hide it, but takes its clicks.
|
|
@@ -270,14 +281,24 @@ export declare function coverText(cover: string, transparent: boolean | undefine
|
|
|
270
281
|
* @returns Note
|
|
271
282
|
*/
|
|
272
283
|
export declare function inspectCascadeNote(reason: 'timeout' | 'failed'): string;
|
|
284
|
+
/**
|
|
285
|
+
* Note of `bdg dom inspect` when the selector named a pseudo-element: its
|
|
286
|
+
* element is inspected and the pseudo-element is on the `pseudo` line.
|
|
287
|
+
*
|
|
288
|
+
* @param pseudo - `::before` or `::after`
|
|
289
|
+
* @returns Note
|
|
290
|
+
*/
|
|
291
|
+
export declare function inspectPseudoOfNote(pseudo: string): string;
|
|
273
292
|
/**
|
|
274
293
|
* Header badge of `bdg dom inspect` when the page is shown in its dark theme
|
|
275
|
-
* because the session follows the system's dark preference
|
|
276
|
-
* the dark theme's, not what a
|
|
294
|
+
* because the session follows the system's dark preference, or because
|
|
295
|
+
* `page emulate` asked for dark: the colors are the dark theme's, not what a
|
|
296
|
+
* light-mode visitor sees.
|
|
277
297
|
*
|
|
298
|
+
* @param emulated - The dark preference comes from `page emulate --color-scheme dark`
|
|
278
299
|
* @returns Badge
|
|
279
300
|
*/
|
|
280
|
-
export declare function inspectDarkThemeBadge(): string;
|
|
301
|
+
export declare function inspectDarkThemeBadge(emulated?: boolean): string;
|
|
281
302
|
/**
|
|
282
303
|
* Header badges of `bdg dom inspect` for what keeps an element from being seen.
|
|
283
304
|
*
|
|
@@ -538,13 +559,24 @@ export declare function elementTextLine(text: string): string;
|
|
|
538
559
|
* @returns e.g. `No text; holds 1 element: iframe (see its HTML with --raw)`
|
|
539
560
|
*/
|
|
540
561
|
export declare function emptyElementLine(children: string[], count: number): string;
|
|
562
|
+
/**
|
|
563
|
+
* Note on a screenshot scaled down to keep its image token cost bounded.
|
|
564
|
+
*
|
|
565
|
+
* @param originalWidth - Captured width (CSS px)
|
|
566
|
+
* @param originalHeight - Captured height
|
|
567
|
+
* @param width - Image width
|
|
568
|
+
* @param height - Image height
|
|
569
|
+
* @returns e.g. `scaled from 1920×993 to 1568×811; --no-resize for full size`
|
|
570
|
+
*/
|
|
571
|
+
export declare function screenshotScaledNote(originalWidth: number, originalHeight: number, width: number, height: number): string;
|
|
541
572
|
/**
|
|
542
573
|
* Note on an element screenshot that captured more than the element's border
|
|
543
|
-
* box, because content (floats, positioned children) overflows it.
|
|
574
|
+
* box, because content (floats, positioned children, text, shadows) overflows it.
|
|
544
575
|
*
|
|
545
576
|
* @param box - Border box
|
|
546
577
|
* @param captured - Area captured
|
|
547
|
-
* @
|
|
578
|
+
* @param padding - `--padding` (px), which is not the element's own
|
|
579
|
+
* @returns e.g. `grown from 940×37 to 940×285 to include what it paints outside its box (…)`
|
|
548
580
|
*/
|
|
549
581
|
export declare function screenshotGrownNote(box: {
|
|
550
582
|
width: number;
|
|
@@ -552,7 +584,7 @@ export declare function screenshotGrownNote(box: {
|
|
|
552
584
|
}, captured: {
|
|
553
585
|
width: number;
|
|
554
586
|
height: number;
|
|
555
|
-
}): string;
|
|
587
|
+
}, padding?: number): string;
|
|
556
588
|
/**
|
|
557
589
|
* Next commands after `bdg dom query`, by index so they reach matches in
|
|
558
590
|
* shadow roots and iframes too.
|
|
@@ -655,6 +687,7 @@ export declare function pageEmulationLines(result: {
|
|
|
655
687
|
viewport?: {
|
|
656
688
|
width: number;
|
|
657
689
|
height: number;
|
|
690
|
+
mobile?: boolean;
|
|
658
691
|
};
|
|
659
692
|
colorScheme?: string;
|
|
660
693
|
};
|
|
@@ -678,5 +711,9 @@ export declare function inspectAnimatingBadge(animating: readonly string[]): str
|
|
|
678
711
|
* @returns Note
|
|
679
712
|
*/
|
|
680
713
|
export declare function inspectMidTransitionNote(): string;
|
|
714
|
+
/** Examples under `bdg dom audit --help` */
|
|
715
|
+
export declare const AUDIT_HELP_EXAMPLES = "\nExamples:\n bdg dom audit All checks\n bdg dom audit contrast --level AAA Text below WCAG AAA, weakest first\n bdg dom audit overflow What scrolls sideways, cut-off text, scaled images\n bdg dom audit layers animations Fixed/sticky elements and running animations\n\nFollow up on a finding with bdg dom inspect <element> (e.g. --why color).";
|
|
716
|
+
/** Examples under `bdg css search --help` */
|
|
717
|
+
export declare const CSS_SEARCH_HELP_EXAMPLES = "\nExamples:\n bdg css search -- --brand Where a custom property is set and used (-- before a text\n that starts with -; options go before it:\n bdg css search --limit 50 -- --brand)\n bdg css search \"oklch(\" Rules that use oklch colors\n bdg css search \".btn-primary\" Rules of a class, in every stylesheet";
|
|
681
718
|
export {};
|
|
682
719
|
//# sourceMappingURL=commands.d.ts.map
|
|
@@ -136,6 +136,19 @@ export function pageNavigationText(navigation) {
|
|
|
136
136
|
const status = navigation.status === undefined ? '' : ` (${navigation.status})`;
|
|
137
137
|
return `navigated to ${navigation.url}${status}`;
|
|
138
138
|
}
|
|
139
|
+
/**
|
|
140
|
+
* Last `New text:` row when an action made more messages appear than are listed.
|
|
141
|
+
*
|
|
142
|
+
* @param count - Messages not listed
|
|
143
|
+
* @returns e.g. `(+4 more)`
|
|
144
|
+
*/
|
|
145
|
+
export function moreMessagesText(count) {
|
|
146
|
+
return `(+${count} more)`;
|
|
147
|
+
}
|
|
148
|
+
/** Result line of `bdg dom hover --off` */
|
|
149
|
+
export const HOVER_OFF_DONE = '✓ Mouse moved off the page (hover styles and menus that close on mouseleave are gone)';
|
|
150
|
+
/** How `bdg dom hover` is called */
|
|
151
|
+
export const HOVER_USAGE = 'bdg dom hover <selector|index>, or bdg dom hover --off to move the mouse away';
|
|
139
152
|
/**
|
|
140
153
|
* A message an action made appear, for its `New text:` rows.
|
|
141
154
|
*
|
|
@@ -432,8 +445,14 @@ Output notation:
|
|
|
432
445
|
in-parent distances to the parent's content edges (l t r b); sib: gaps to the sibling on each side
|
|
433
446
|
scroll WxH the content (pseudo-elements too) is larger than the box
|
|
434
447
|
16/24 font size / line height; 'webfont loaded' = drawn with a downloaded font;
|
|
435
|
-
(rendered "X") = drawn with another font than declared (a fallback)
|
|
448
|
+
(rendered "X") = drawn with another font than declared (a fallback);
|
|
449
|
+
(resolves to "X") = the font a generic family (sans-serif, system-ui) became
|
|
436
450
|
contrast 4.47 WCAG ratio, rounded down, against the background behind the text
|
|
451
|
+
text in X the text is drawn by descendant X (the one with most of it): its font, color, contrast
|
|
452
|
+
truncated the text is cut off (overflow clip, ellipsis or line clamp); a "…" in the header is
|
|
453
|
+
only bdg shortening the text
|
|
454
|
+
.a.b(+3) the first two classes and how many more the element has
|
|
455
|
+
sizing content-box padding and border add to the CSS size (shown only then; border-box is not)
|
|
437
456
|
(+N not rendered) children with display: none (or not in the layout)
|
|
438
457
|
hints declarations on this element that have no effect, why, the fix and where they are
|
|
439
458
|
('none': checked, nothing found)
|
|
@@ -466,15 +485,29 @@ export function inspectCascadeNote(reason) {
|
|
|
466
485
|
? "CSS rules not read: the page's stylesheets took too long (hints wait 1 s; --rules and --why 5 s)"
|
|
467
486
|
: 'CSS rules not read: Chrome could not report the rules matching this element';
|
|
468
487
|
}
|
|
488
|
+
/**
|
|
489
|
+
* Note of `bdg dom inspect` when the selector named a pseudo-element: its
|
|
490
|
+
* element is inspected and the pseudo-element is on the `pseudo` line.
|
|
491
|
+
*
|
|
492
|
+
* @param pseudo - `::before` or `::after`
|
|
493
|
+
* @returns Note
|
|
494
|
+
*/
|
|
495
|
+
export function inspectPseudoOfNote(pseudo) {
|
|
496
|
+
return `Inspected the element of ${pseudo}: pseudo-elements cannot be selected; ${pseudo} is on the pseudo line (content, size, position, inset, colors)`;
|
|
497
|
+
}
|
|
469
498
|
/**
|
|
470
499
|
* Header badge of `bdg dom inspect` when the page is shown in its dark theme
|
|
471
|
-
* because the session follows the system's dark preference
|
|
472
|
-
* the dark theme's, not what a
|
|
500
|
+
* because the session follows the system's dark preference, or because
|
|
501
|
+
* `page emulate` asked for dark: the colors are the dark theme's, not what a
|
|
502
|
+
* light-mode visitor sees.
|
|
473
503
|
*
|
|
504
|
+
* @param emulated - The dark preference comes from `page emulate --color-scheme dark`
|
|
474
505
|
* @returns Badge
|
|
475
506
|
*/
|
|
476
|
-
export function inspectDarkThemeBadge() {
|
|
477
|
-
return
|
|
507
|
+
export function inspectDarkThemeBadge(emulated = false) {
|
|
508
|
+
return emulated
|
|
509
|
+
? '[dark theme, emulated; bdg page emulate --color-scheme light for light]'
|
|
510
|
+
: '[dark theme from system; --color-scheme light for light]';
|
|
478
511
|
}
|
|
479
512
|
/**
|
|
480
513
|
* Header badges of `bdg dom inspect` for what keeps an element from being seen.
|
|
@@ -887,16 +920,35 @@ export function emptyElementLine(children, count) {
|
|
|
887
920
|
const more = count > children.length ? `, … ${count - children.length} more` : '';
|
|
888
921
|
return `No text; holds ${pluralize(count, 'element')}: ${children.join(', ')}${more} (see its HTML with --raw)`;
|
|
889
922
|
}
|
|
923
|
+
/**
|
|
924
|
+
* Note on a screenshot scaled down to keep its image token cost bounded.
|
|
925
|
+
*
|
|
926
|
+
* @param originalWidth - Captured width (CSS px)
|
|
927
|
+
* @param originalHeight - Captured height
|
|
928
|
+
* @param width - Image width
|
|
929
|
+
* @param height - Image height
|
|
930
|
+
* @returns e.g. `scaled from 1920×993 to 1568×811; --no-resize for full size`
|
|
931
|
+
*/
|
|
932
|
+
export function screenshotScaledNote(originalWidth, originalHeight, width, height) {
|
|
933
|
+
return `scaled from ${originalWidth}×${originalHeight} to ${width}×${height}; --no-resize for full size`;
|
|
934
|
+
}
|
|
890
935
|
/**
|
|
891
936
|
* Note on an element screenshot that captured more than the element's border
|
|
892
|
-
* box, because content (floats, positioned children) overflows it.
|
|
937
|
+
* box, because content (floats, positioned children, text, shadows) overflows it.
|
|
893
938
|
*
|
|
894
939
|
* @param box - Border box
|
|
895
940
|
* @param captured - Area captured
|
|
896
|
-
* @
|
|
941
|
+
* @param padding - `--padding` (px), which is not the element's own
|
|
942
|
+
* @returns e.g. `grown from 940×37 to 940×285 to include what it paints outside its box (…)`
|
|
897
943
|
*/
|
|
898
|
-
export function screenshotGrownNote(box, captured) {
|
|
899
|
-
|
|
944
|
+
export function screenshotGrownNote(box, captured, padding = 0) {
|
|
945
|
+
const painted = { width: captured.width - 2 * padding, height: captured.height - 2 * padding };
|
|
946
|
+
const grew = painted.width > box.width + 0.5 || painted.height > box.height + 0.5;
|
|
947
|
+
const ink = `grown from ${box.width}×${box.height} to ${painted.width}×${painted.height} to include what it paints outside its box (overflowing content, shadows, outline)`;
|
|
948
|
+
const pad = `${padding}px of page around it (--padding)`;
|
|
949
|
+
if (!padding)
|
|
950
|
+
return ink;
|
|
951
|
+
return grew ? `${ink}, plus ${pad}` : `with ${pad}: ${captured.width}×${captured.height}`;
|
|
900
952
|
}
|
|
901
953
|
/**
|
|
902
954
|
* Next commands after `bdg dom query`, by index so they reach matches in
|
|
@@ -1010,7 +1062,7 @@ export function startCommandHelpMessage() {
|
|
|
1010
1062
|
export function pageEmulateNothingError() {
|
|
1011
1063
|
return {
|
|
1012
1064
|
message: 'Nothing to emulate',
|
|
1013
|
-
suggestion: 'Give --viewport <WxH>, --color-scheme light|dark, or --reset, e.g. bdg page emulate --viewport 900x700',
|
|
1065
|
+
suggestion: 'Give --viewport <WxH>, --mobile, --color-scheme light|dark, or --reset, e.g. bdg page emulate --viewport 900x700',
|
|
1014
1066
|
};
|
|
1015
1067
|
}
|
|
1016
1068
|
/**
|
|
@@ -1022,8 +1074,11 @@ export function pageEmulateNothingError() {
|
|
|
1022
1074
|
export function pageEmulationLines(result) {
|
|
1023
1075
|
const size = (v) => `${v.width}x${v.height}`;
|
|
1024
1076
|
const { emulated } = result;
|
|
1077
|
+
const phone = emulated.viewport?.mobile
|
|
1078
|
+
? ' (phone: mobile layout, touch, mobile user agent)'
|
|
1079
|
+
: '';
|
|
1025
1080
|
return [
|
|
1026
|
-
['Viewport', emulated.viewport ? size(emulated.viewport) : 'the browser window'],
|
|
1081
|
+
['Viewport', emulated.viewport ? `${size(emulated.viewport)}${phone}` : 'the browser window'],
|
|
1027
1082
|
...(result.viewport
|
|
1028
1083
|
? [['Layout', `${size(result.viewport)} (without scrollbars)`]]
|
|
1029
1084
|
: []),
|
|
@@ -1052,4 +1107,21 @@ export function inspectAnimatingBadge(animating) {
|
|
|
1052
1107
|
export function inspectMidTransitionNote() {
|
|
1053
1108
|
return '(mid-transition: inspect again for the final value)';
|
|
1054
1109
|
}
|
|
1110
|
+
/** Examples under `bdg dom audit --help` */
|
|
1111
|
+
export const AUDIT_HELP_EXAMPLES = `
|
|
1112
|
+
Examples:
|
|
1113
|
+
bdg dom audit All checks
|
|
1114
|
+
bdg dom audit contrast --level AAA Text below WCAG AAA, weakest first
|
|
1115
|
+
bdg dom audit overflow What scrolls sideways, cut-off text, scaled images
|
|
1116
|
+
bdg dom audit layers animations Fixed/sticky elements and running animations
|
|
1117
|
+
|
|
1118
|
+
Follow up on a finding with bdg dom inspect <element> (e.g. --why color).`;
|
|
1119
|
+
/** Examples under `bdg css search --help` */
|
|
1120
|
+
export const CSS_SEARCH_HELP_EXAMPLES = `
|
|
1121
|
+
Examples:
|
|
1122
|
+
bdg css search -- --brand Where a custom property is set and used (-- before a text
|
|
1123
|
+
that starts with -; options go before it:
|
|
1124
|
+
bdg css search --limit 50 -- --brand)
|
|
1125
|
+
bdg css search "oklch(" Rules that use oklch colors
|
|
1126
|
+
bdg css search ".btn-primary" Rules of a class, in every stylesheet`;
|
|
1055
1127
|
//# sourceMappingURL=commands.js.map
|
|
@@ -61,4 +61,10 @@ export declare function connectionLostRetryMessage(timestamp: string, retryLabel
|
|
|
61
61
|
* @returns Message instructing the user how to stop follow mode
|
|
62
62
|
*/
|
|
63
63
|
export declare function connectionLostStopHintMessage(): string;
|
|
64
|
+
/**
|
|
65
|
+
* Notice that `bdg tail` is deprecated (it still runs).
|
|
66
|
+
*
|
|
67
|
+
* @returns Notice for stderr
|
|
68
|
+
*/
|
|
69
|
+
export declare function tailDeprecatedNotice(): string;
|
|
64
70
|
//# sourceMappingURL=preview.d.ts.map
|
|
@@ -30,7 +30,7 @@ export function verboseCommandsMessage() {
|
|
|
30
30
|
return [
|
|
31
31
|
'Commands:',
|
|
32
32
|
` Full preview: ${sessionCommand('bdg peek --last 50')}`,
|
|
33
|
-
` Watch live: ${sessionCommand('bdg
|
|
33
|
+
` Watch live: ${sessionCommand('bdg peek --follow')}`,
|
|
34
34
|
` End session: ${sessionCommand('bdg stop')}`,
|
|
35
35
|
].join('\n');
|
|
36
36
|
}
|
|
@@ -79,4 +79,12 @@ export function connectionLostRetryMessage(timestamp, retryLabel) {
|
|
|
79
79
|
export function connectionLostStopHintMessage() {
|
|
80
80
|
return 'Press Ctrl+C to stop';
|
|
81
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* Notice that `bdg tail` is deprecated (it still runs).
|
|
84
|
+
*
|
|
85
|
+
* @returns Notice for stderr
|
|
86
|
+
*/
|
|
87
|
+
export function tailDeprecatedNotice() {
|
|
88
|
+
return 'Note: "bdg tail" is deprecated and will be removed; use "bdg peek --follow" (same options: --last, --network, --console, --interval, --verbose)';
|
|
89
|
+
}
|
|
82
90
|
//# sourceMappingURL=preview.js.map
|
package/dist/utils/cssValues.js
CHANGED
|
@@ -44,11 +44,42 @@ export function cssLength(value) {
|
|
|
44
44
|
* @returns Normalized value
|
|
45
45
|
*/
|
|
46
46
|
export function normalizeCssValue(value) {
|
|
47
|
-
return hexColorsIn(value)
|
|
48
|
-
.replace(PX_IN_VALUE, (_match, number) => String(round1(Number(number))))
|
|
47
|
+
return mapOutsideFunctions(hexColorsIn(value), UNIT_KEEPING_FUNCTIONS, (part) => part.replace(PX_IN_VALUE, (_match, number) => String(round1(Number(number)))))
|
|
49
48
|
.replace(/\s+/g, ' ')
|
|
50
49
|
.trim();
|
|
51
50
|
}
|
|
51
|
+
/** Functions whose px stay written: math mixes units, URLs are names */
|
|
52
|
+
const UNIT_KEEPING_FUNCTIONS = new Set(['calc', 'min', 'max', 'clamp', 'url']);
|
|
53
|
+
/**
|
|
54
|
+
* Change the parts of a value that are not inside the given functions.
|
|
55
|
+
*
|
|
56
|
+
* @param value - CSS value
|
|
57
|
+
* @param functions - Function names whose arguments are kept as written
|
|
58
|
+
* @param change - Change for the other parts
|
|
59
|
+
* @returns Value
|
|
60
|
+
*/
|
|
61
|
+
function mapOutsideFunctions(value, functions, change) {
|
|
62
|
+
let result = '';
|
|
63
|
+
let start = 0;
|
|
64
|
+
let depth = 0;
|
|
65
|
+
for (let i = 0; i < value.length; i++) {
|
|
66
|
+
if (value[i] === '(') {
|
|
67
|
+
const name = /([\w-]+)$/.exec(value.slice(start, i))?.[1]?.toLowerCase() ?? '';
|
|
68
|
+
if (depth === 0 && functions.has(name)) {
|
|
69
|
+
result += change(value.slice(start, i));
|
|
70
|
+
start = i;
|
|
71
|
+
depth = 1;
|
|
72
|
+
}
|
|
73
|
+
else if (depth > 0)
|
|
74
|
+
depth++;
|
|
75
|
+
}
|
|
76
|
+
else if (value[i] === ')' && depth > 0 && --depth === 0) {
|
|
77
|
+
result += value.slice(start, i + 1);
|
|
78
|
+
start = i + 1;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return result + (depth > 0 ? value.slice(start) : change(value.slice(start)));
|
|
82
|
+
}
|
|
52
83
|
/**
|
|
53
84
|
* 1-4 values the way CSS shorthands write them (top, right, bottom, left).
|
|
54
85
|
*
|
|
@@ -190,9 +221,10 @@ function round3(value) {
|
|
|
190
221
|
function decomposeMatrix([a = 1, b = 0, c = 0, d = 1, e = 0, f = 0]) {
|
|
191
222
|
if (Math.abs(a * c + b * d) > 1e-6)
|
|
192
223
|
return undefined;
|
|
193
|
-
const
|
|
224
|
+
const mirrored = a * d - b * c < 0 && a < 0;
|
|
225
|
+
const scaleX = mirrored ? -Math.hypot(a, b) : Math.hypot(a, b);
|
|
194
226
|
const scaleY = scaleX === 0 ? 0 : (a * d - b * c) / scaleX;
|
|
195
|
-
const angle = round3((Math.atan2(b, a) * 180) / Math.PI);
|
|
227
|
+
const angle = round3((Math.atan2(mirrored ? -b : b, mirrored ? -a : a) * 180) / Math.PI);
|
|
196
228
|
const parts = [];
|
|
197
229
|
if (e !== 0 || f !== 0)
|
|
198
230
|
parts.push(`translate(${round1(e)},${round1(f)})`);
|
|
@@ -121,11 +121,6 @@ export const DECISION_TREES = {
|
|
|
121
121
|
yesCommand: 'peek --follow',
|
|
122
122
|
noAction: 'next',
|
|
123
123
|
},
|
|
124
|
-
{
|
|
125
|
-
question: 'Need continuous monitoring (like tail -f)?',
|
|
126
|
-
yesCommand: 'tail',
|
|
127
|
-
noAction: 'next',
|
|
128
|
-
},
|
|
129
124
|
{
|
|
130
125
|
question: 'Need quick preview of recent data?',
|
|
131
126
|
yesCommand: 'peek',
|
|
@@ -18,8 +18,10 @@ export declare function getSuggestion(input: string, candidates: readonly string
|
|
|
18
18
|
/**
|
|
19
19
|
* Names (ids or classes) similar to one that matched nothing, best first, at
|
|
20
20
|
* most three: near-typos first (Levenshtein distance up to a fifth of the
|
|
21
|
-
* length, at least 2), then names sharing a long end
|
|
22
|
-
*
|
|
21
|
+
* length, at least 2), then names sharing a long end (at least a third of
|
|
22
|
+
* the name, at least 4 characters), then names sharing a long start (at
|
|
23
|
+
* least half: `--color-btn-inset-shadow` and `--color-bg-discussions-…` share
|
|
24
|
+
* only a namespace). The end
|
|
23
25
|
* ranks before the start because ids tend to name an action before the item
|
|
24
26
|
* (`add-to-cart-backpack` becomes `remove-backpack` once clicked).
|
|
25
27
|
*
|
|
@@ -65,8 +65,10 @@ function commonSuffixLength(a, b) {
|
|
|
65
65
|
/**
|
|
66
66
|
* Names (ids or classes) similar to one that matched nothing, best first, at
|
|
67
67
|
* most three: near-typos first (Levenshtein distance up to a fifth of the
|
|
68
|
-
* length, at least 2), then names sharing a long end
|
|
69
|
-
*
|
|
68
|
+
* length, at least 2), then names sharing a long end (at least a third of
|
|
69
|
+
* the name, at least 4 characters), then names sharing a long start (at
|
|
70
|
+
* least half: `--color-btn-inset-shadow` and `--color-bg-discussions-…` share
|
|
71
|
+
* only a namespace). The end
|
|
70
72
|
* ranks before the start because ids tend to name an action before the item
|
|
71
73
|
* (`add-to-cart-backpack` becomes `remove-backpack` once clicked).
|
|
72
74
|
*
|
|
@@ -79,15 +81,15 @@ export function findSimilarNames(name, candidates) {
|
|
|
79
81
|
const maxDistance = Math.max(2, Math.floor(name.length / 5));
|
|
80
82
|
const minAffix = Math.max(4, Math.ceil(name.length / 3));
|
|
81
83
|
const typos = findMatches(name, others, maxDistance, false).map((match) => match.value);
|
|
82
|
-
const byAffix = (length) => others
|
|
84
|
+
const byAffix = (length, min = minAffix) => others
|
|
83
85
|
.map((candidate) => ({ candidate, length: length(candidate) }))
|
|
84
|
-
.filter((entry) => entry.length >=
|
|
86
|
+
.filter((entry) => entry.length >= min)
|
|
85
87
|
.sort((a, b) => b.length - a.length)
|
|
86
88
|
.map((entry) => entry.candidate);
|
|
87
89
|
const ranked = [
|
|
88
90
|
...typos,
|
|
89
91
|
...byAffix((candidate) => commonSuffixLength(name, candidate)),
|
|
90
|
-
...byAffix((candidate) => commonPrefixLength(name, candidate)),
|
|
92
|
+
...byAffix((candidate) => commonPrefixLength(name, candidate), Math.max(minAffix, Math.ceil(name.length / 2))),
|
|
91
93
|
];
|
|
92
94
|
return [...new Set(ranked)].slice(0, MAX_SIMILAR_NAMES);
|
|
93
95
|
}
|