explorbot 0.4.1 → 0.4.3
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/bin/explorbot-cli.ts +14 -4
- package/boat/api-tester/src/ai/curler-tools.ts +1 -1
- package/boat/api-tester/src/cli.ts +3 -0
- package/boat/doc-collector/src/ai/documentarian.ts +57 -5
- package/boat/doc-collector/src/ai/tools.ts +1 -1
- package/boat/doc-collector/src/cli.ts +18 -2
- package/boat/doc-collector/src/config.ts +3 -0
- package/boat/doc-collector/src/docbot.ts +56 -11
- package/boat/doc-collector/src/docs-renderer.ts +79 -55
- package/boat/doc-collector/src/interaction-screenshots.ts +19 -10
- package/boat/doc-collector/src/screenshots.ts +106 -3
- package/boat/doc-collector/src/template-dedup.ts +31 -0
- package/boat/prima/src/cli.ts +3 -0
- package/boat/prima/src/prima.ts +3 -4
- package/dist/bin/explorbot-cli.js +14 -4
- package/dist/boat/api-tester/src/ai/curler-tools.js +1 -1
- package/dist/boat/api-tester/src/cli.js +2 -0
- package/dist/boat/doc-collector/src/ai/documentarian.js +62 -4
- package/dist/boat/doc-collector/src/ai/tools.js +1 -1
- package/dist/boat/doc-collector/src/cli.js +15 -2
- package/dist/boat/doc-collector/src/config.js +1 -0
- package/dist/boat/doc-collector/src/docbot.js +52 -10
- package/dist/boat/doc-collector/src/docs-renderer.js +69 -46
- package/dist/boat/doc-collector/src/interaction-screenshots.js +18 -11
- package/dist/boat/doc-collector/src/screenshots.js +104 -1
- package/dist/boat/doc-collector/src/template-dedup.js +27 -0
- package/dist/boat/prima/src/cli.js +2 -0
- package/dist/boat/prima/src/prima.js +3 -4
- package/dist/package.json +1 -1
- package/dist/src/action-result.d.ts +2 -2
- package/dist/src/action-result.js +15 -17
- package/dist/src/action.d.ts +1 -1
- package/dist/src/action.js +15 -15
- package/dist/src/ai/fisherman/request-haul.d.ts +12 -0
- package/dist/src/ai/fisherman/request-haul.js +31 -0
- package/dist/src/ai/fisherman/tools.d.ts +50 -0
- package/dist/src/ai/{fisherman-tools.js → fisherman/tools.js} +109 -40
- package/dist/src/ai/fisherman.d.ts +14 -4
- package/dist/src/ai/fisherman.js +96 -18
- package/dist/src/ai/pilot.d.ts +13 -1
- package/dist/src/ai/pilot.js +40 -22
- package/dist/src/ai/provider.js +8 -14
- package/dist/src/ai/researcher/coordinates.d.ts +2 -0
- package/dist/src/ai/researcher/coordinates.js +13 -1
- package/dist/src/ai/researcher/deep-analysis.js +9 -9
- package/dist/src/ai/researcher/fingerprint-worker.js +1 -11
- package/dist/src/ai/researcher.js +1 -1
- package/dist/src/ai/rules.js +10 -0
- package/dist/src/ai/tester.js +20 -20
- package/dist/src/ai/tools.d.ts +1 -1
- package/dist/src/ai/tools.js +18 -74
- package/dist/src/api/request-result.js +3 -1
- package/dist/src/api/request-store.d.ts +7 -6
- package/dist/src/api/request-store.js +65 -37
- package/dist/src/api/xhr-capture.d.ts +2 -0
- package/dist/src/api/xhr-capture.js +35 -10
- package/dist/src/commands/config-command.js +2 -9
- package/dist/src/commands/help-json-command.d.ts +31 -0
- package/dist/src/commands/help-json-command.js +58 -0
- package/dist/src/commands/index.js +2 -0
- package/dist/src/commands/init-command.js +3 -7
- package/dist/src/commands/plans-command.d.ts +4 -1
- package/dist/src/commands/plans-command.js +4 -4
- package/dist/src/commands/recommended-models-command.d.ts +9 -0
- package/dist/src/commands/recommended-models-command.js +85 -0
- package/dist/src/config.d.ts +2 -0
- package/dist/src/config.js +7 -2
- package/dist/src/experience-tracker.js +1 -1
- package/dist/src/explorbot.js +3 -3
- package/dist/src/global-config.d.ts +2 -0
- package/dist/src/global-config.js +6 -0
- package/dist/src/state-manager.d.ts +3 -3
- package/dist/src/state-manager.js +8 -8
- package/dist/src/test-plan.d.ts +1 -0
- package/dist/src/test-plan.js +13 -9
- package/dist/src/utils/aria.d.ts +1 -1
- package/dist/src/utils/aria.js +23 -2
- package/dist/src/utils/cli-section.d.ts +1 -0
- package/dist/src/utils/cli-section.js +12 -0
- package/dist/src/utils/html-diff.d.ts +1 -0
- package/dist/src/utils/html-diff.js +5 -5
- package/dist/src/utils/html.d.ts +2 -0
- package/dist/src/utils/html.js +5 -4
- package/dist/src/utils/overlay.d.ts +19 -55
- package/dist/src/utils/overlay.js +94 -148
- package/dist/src/utils/region.d.ts +41 -0
- package/dist/src/utils/region.js +99 -0
- package/dist/src/utils/similarity.d.ts +1 -0
- package/dist/src/utils/similarity.js +11 -0
- package/dist/src/utils/url-matcher.d.ts +1 -1
- package/dist/src/utils/url-matcher.js +4 -4
- package/docs/doc-collection/basics.md +11 -5
- package/docs/doc-collection/crawling.md +21 -1
- package/docs/reference/commands.md +4 -0
- package/docs/reference/configuration.md +4 -0
- package/docs/superpowers/plans/2026-09-03-fisherman-query-api.md +1361 -0
- package/docs/superpowers/plans/2026-09-03-model-resolves-click-ambiguity.md +509 -0
- package/docs/workflow/agentic-usage.md +12 -0
- package/docs/workflow/application-spec.md +4 -0
- package/package.json +1 -1
- package/src/action-result.ts +15 -16
- package/src/action.ts +16 -15
- package/src/ai/fisherman/request-haul.ts +36 -0
- package/src/ai/{fisherman-tools.ts → fisherman/tools.ts} +125 -46
- package/src/ai/fisherman.ts +110 -20
- package/src/ai/pilot.ts +38 -20
- package/src/ai/provider.ts +8 -12
- package/src/ai/researcher/coordinates.ts +13 -1
- package/src/ai/researcher/deep-analysis.ts +9 -9
- package/src/ai/researcher/fingerprint-worker.ts +1 -10
- package/src/ai/researcher.ts +1 -1
- package/src/ai/rules.ts +10 -0
- package/src/ai/tester.ts +18 -18
- package/src/ai/tools.ts +18 -86
- package/src/api/request-result.ts +2 -1
- package/src/api/request-store.ts +68 -42
- package/src/api/xhr-capture.ts +39 -11
- package/src/commands/config-command.ts +2 -7
- package/src/commands/help-json-command.ts +74 -0
- package/src/commands/index.ts +2 -0
- package/src/commands/init-command.ts +4 -11
- package/src/commands/plans-command.ts +5 -5
- package/src/commands/recommended-models-command.ts +92 -0
- package/src/config.ts +9 -2
- package/src/experience-tracker.ts +1 -1
- package/src/explorbot.ts +3 -3
- package/src/global-config.ts +8 -0
- package/src/state-manager.ts +10 -9
- package/src/test-plan.ts +12 -10
- package/src/utils/aria.ts +26 -3
- package/src/utils/cli-section.ts +12 -0
- package/src/utils/html-diff.ts +6 -6
- package/src/utils/html.ts +6 -4
- package/src/utils/overlay.ts +105 -192
- package/src/utils/region.ts +132 -0
- package/src/utils/similarity.ts +9 -0
- package/src/utils/url-matcher.ts +3 -3
- package/dist/src/ai/fisherman-tools.d.ts +0 -138
- package/dist/src/utils/request-map.d.ts +0 -7
- package/dist/src/utils/request-map.js +0 -16
- package/src/utils/request-map.ts +0 -19
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ActionResult, type FocusedElement } from './action-result.js';
|
|
2
2
|
import type { ExperienceTracker } from './experience-tracker.js';
|
|
3
3
|
import type { Knowledge, KnowledgeTracker } from './knowledge-tracker.js';
|
|
4
|
-
import {
|
|
4
|
+
import type { Region } from './utils/region.js';
|
|
5
5
|
export interface Link {
|
|
6
6
|
title: string;
|
|
7
7
|
url: string;
|
|
@@ -41,7 +41,7 @@ export interface WebPageState {
|
|
|
41
41
|
focusedElement?: FocusedElement | null;
|
|
42
42
|
links?: Link[];
|
|
43
43
|
verifications?: Record<string, boolean>;
|
|
44
|
-
overlay?:
|
|
44
|
+
overlay?: Region;
|
|
45
45
|
/** Region name, the persisted scalar form of overlay.name used in experience frontmatter */
|
|
46
46
|
region?: string;
|
|
47
47
|
/** Region root selector, the persisted scalar form of overlay.root used in experience frontmatter */
|
|
@@ -95,7 +95,7 @@ export declare class StateManager {
|
|
|
95
95
|
* Update state from basic data (for navigation events)
|
|
96
96
|
*/
|
|
97
97
|
updateStateFromBasic(url: string, title?: string, trigger?: 'manual' | 'navigation' | 'automatic'): WebPageState;
|
|
98
|
-
|
|
98
|
+
regionOpened(previousState: WebPageState | null, newState: WebPageState): boolean;
|
|
99
99
|
/**
|
|
100
100
|
* Generate a basic hash for state comparison
|
|
101
101
|
*/
|
|
@@ -42,7 +42,7 @@ export class StateManager {
|
|
|
42
42
|
emitStateChange(event) {
|
|
43
43
|
const state = event.toState;
|
|
44
44
|
const payload = { url: state.fullUrl || state.url, path: state.url, title: state.title, h1: state.h1 };
|
|
45
|
-
if (state.overlay?.
|
|
45
|
+
if (state.overlay?.isOpen)
|
|
46
46
|
payload.region = state.overlay.name || state.overlay.type;
|
|
47
47
|
tag('data').log('state', payload);
|
|
48
48
|
this.stateChangeListeners.forEach((listener) => {
|
|
@@ -66,8 +66,8 @@ export class StateManager {
|
|
|
66
66
|
if (newState.url)
|
|
67
67
|
this.allVisitedUrls.add(normalizeUrl(newState.url));
|
|
68
68
|
const hashChanged = actionResult.hash !== previousHash;
|
|
69
|
-
const
|
|
70
|
-
if (hashChanged ||
|
|
69
|
+
const regionOpened = !hashChanged && this.regionOpened(previousState, newState);
|
|
70
|
+
if (hashChanged || regionOpened) {
|
|
71
71
|
const transition = {
|
|
72
72
|
fromState: previousState,
|
|
73
73
|
toState: newState,
|
|
@@ -77,7 +77,7 @@ export class StateManager {
|
|
|
77
77
|
};
|
|
78
78
|
this.stateHistory.push(transition);
|
|
79
79
|
this.emitStateChange(transition);
|
|
80
|
-
if (
|
|
80
|
+
if (regionOpened) {
|
|
81
81
|
debugLog('State change detected: region of interest appeared');
|
|
82
82
|
}
|
|
83
83
|
}
|
|
@@ -116,10 +116,10 @@ export class StateManager {
|
|
|
116
116
|
debugLog(`State updated from navigation: ${this.currentState.url} (${this.currentState.hash})`);
|
|
117
117
|
return newState;
|
|
118
118
|
}
|
|
119
|
-
|
|
120
|
-
const
|
|
121
|
-
const
|
|
122
|
-
return !
|
|
119
|
+
regionOpened(previousState, newState) {
|
|
120
|
+
const previous = Overlay.resolve(previousState ?? {});
|
|
121
|
+
const current = Overlay.resolve(newState);
|
|
122
|
+
return !previous.isOpen && current.isOpen;
|
|
123
123
|
}
|
|
124
124
|
/**
|
|
125
125
|
* Generate a basic hash for state comparison
|
package/dist/src/test-plan.d.ts
CHANGED
|
@@ -147,6 +147,7 @@ export declare class Plan {
|
|
|
147
147
|
get allSuccessful(): boolean;
|
|
148
148
|
get allFailed(): boolean;
|
|
149
149
|
updateStatus(): void;
|
|
150
|
+
static resolveFile(file: string, plansDir?: string): string | null;
|
|
150
151
|
static loadFromFile(file: string, plansDir?: string): Plan | null;
|
|
151
152
|
static fromMarkdown(filePath: string): Plan;
|
|
152
153
|
saveToMarkdown(filePath: string): void;
|
package/dist/src/test-plan.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
2
|
import { existsSync } from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
-
import {
|
|
4
|
+
import { listSitePlanDirs } from "./global-config.js";
|
|
5
5
|
import { tag } from "./utils/logger.js";
|
|
6
6
|
import { parsePlanFromMarkdown, planToAiContext, savePlanToMarkdown, savePlansToMarkdown } from "./utils/test-plan-markdown.js";
|
|
7
7
|
import { uniqSessionName } from "./utils/unique-names.js";
|
|
@@ -323,7 +323,6 @@ export class Test extends Task {
|
|
|
323
323
|
.sort((a, b) => a.timestamp - b.timestamp);
|
|
324
324
|
}
|
|
325
325
|
}
|
|
326
|
-
const SITE_PLANS_DIR = ['output', 'plans'];
|
|
327
326
|
export class Plan {
|
|
328
327
|
title;
|
|
329
328
|
tests = [];
|
|
@@ -398,7 +397,7 @@ export class Plan {
|
|
|
398
397
|
return this.tests.length > 0 && this.tests.every((test) => test.hasFailed);
|
|
399
398
|
}
|
|
400
399
|
updateStatus() { }
|
|
401
|
-
static
|
|
400
|
+
static resolveFile(file, plansDir) {
|
|
402
401
|
const names = [file];
|
|
403
402
|
if (!file.endsWith('.md'))
|
|
404
403
|
names.push(`${file}.md`);
|
|
@@ -406,17 +405,22 @@ export class Plan {
|
|
|
406
405
|
if (plansDir)
|
|
407
406
|
dirs.push(plansDir);
|
|
408
407
|
if (!plansDir)
|
|
409
|
-
dirs.push(...
|
|
408
|
+
dirs.push(...listSitePlanDirs());
|
|
410
409
|
for (const dir of dirs) {
|
|
411
410
|
const filePath = names.map((name) => path.resolve(dir, name)).find(existsSync);
|
|
412
|
-
if (
|
|
413
|
-
|
|
414
|
-
const loaded = parsePlanFromMarkdown(filePath);
|
|
415
|
-
loaded.filePath = filePath;
|
|
416
|
-
return loaded;
|
|
411
|
+
if (filePath)
|
|
412
|
+
return filePath;
|
|
417
413
|
}
|
|
418
414
|
return null;
|
|
419
415
|
}
|
|
416
|
+
static loadFromFile(file, plansDir) {
|
|
417
|
+
const filePath = Plan.resolveFile(file, plansDir);
|
|
418
|
+
if (!filePath)
|
|
419
|
+
return null;
|
|
420
|
+
const loaded = parsePlanFromMarkdown(filePath);
|
|
421
|
+
loaded.filePath = filePath;
|
|
422
|
+
return loaded;
|
|
423
|
+
}
|
|
420
424
|
static fromMarkdown(filePath) {
|
|
421
425
|
return parsePlanFromMarkdown(filePath);
|
|
422
426
|
}
|
package/dist/src/utils/aria.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
export interface FocusAreaResult {
|
|
2
|
-
detected: boolean;
|
|
3
2
|
type: 'modal' | null;
|
|
4
3
|
name: string | null;
|
|
5
4
|
}
|
|
@@ -8,6 +7,7 @@ export declare const compactAriaSnapshot: (snapshot: string | null, keepNamed?:
|
|
|
8
7
|
export declare const diffAriaSnapshots: (previous: string | null, current: string | null) => AriaDiff;
|
|
9
8
|
export declare const detectFocusArea: (snapshot: string | null) => FocusAreaResult;
|
|
10
9
|
export declare const collectInteractiveNodes: (snapshot: string | null) => Array<Record<string, unknown>>;
|
|
10
|
+
export declare const ariaTemplateSignature: (snapshot: string | null) => Set<string>;
|
|
11
11
|
export declare function parseAriaLocator(ariaStr: string): {
|
|
12
12
|
role: string;
|
|
13
13
|
text: string;
|
package/dist/src/utils/aria.js
CHANGED
|
@@ -473,7 +473,7 @@ const findDialogOrModal = (nodes) => {
|
|
|
473
473
|
let topmost = null;
|
|
474
474
|
for (const node of nodes) {
|
|
475
475
|
if (node.role === 'dialog' || node.role === 'alertdialog' || node.attributes.modal === true || node.attributes.modal === 'true') {
|
|
476
|
-
topmost = {
|
|
476
|
+
topmost = { type: 'modal', name: node.name || null };
|
|
477
477
|
}
|
|
478
478
|
const child = findDialogOrModal(node.children);
|
|
479
479
|
if (child)
|
|
@@ -517,7 +517,7 @@ export const detectFocusArea = (snapshot) => {
|
|
|
517
517
|
let tree = parseSnapshot(snapshot);
|
|
518
518
|
tree = unwrapIgnored(tree);
|
|
519
519
|
tree = dropEmpty(tree, { keepNamed: true });
|
|
520
|
-
return findDialogOrModal(tree) ?? {
|
|
520
|
+
return findDialogOrModal(tree) ?? { type: null, name: null };
|
|
521
521
|
};
|
|
522
522
|
export const collectInteractiveNodes = (snapshot) => {
|
|
523
523
|
let tree = parseSnapshot(snapshot);
|
|
@@ -526,6 +526,27 @@ export const collectInteractiveNodes = (snapshot) => {
|
|
|
526
526
|
tree = dropEmpty(tree);
|
|
527
527
|
return flatten(tree).map((e) => e.entry);
|
|
528
528
|
};
|
|
529
|
+
const TEMPLATE_CHROME_ROLES = new Set(['banner', 'navigation', 'contentinfo', 'complementary']);
|
|
530
|
+
const TEMPLATE_PROSE_ROLE = 'text';
|
|
531
|
+
const dropChrome = (nodes) => nodes.flatMap((node) => {
|
|
532
|
+
if (TEMPLATE_CHROME_ROLES.has(node.role))
|
|
533
|
+
return [];
|
|
534
|
+
return [{ ...node, children: dropChrome(node.children) }];
|
|
535
|
+
});
|
|
536
|
+
const collectRolePaths = (nodes, prefix, into) => {
|
|
537
|
+
for (const node of nodes) {
|
|
538
|
+
if (node.role === TEMPLATE_PROSE_ROLE)
|
|
539
|
+
continue;
|
|
540
|
+
const path = prefix ? `${prefix}/${node.role}` : node.role;
|
|
541
|
+
into.add(path);
|
|
542
|
+
collectRolePaths(node.children, path, into);
|
|
543
|
+
}
|
|
544
|
+
};
|
|
545
|
+
export const ariaTemplateSignature = (snapshot) => {
|
|
546
|
+
const paths = new Set();
|
|
547
|
+
collectRolePaths(dropChrome(parseSnapshot(snapshot)), '', paths);
|
|
548
|
+
return paths;
|
|
549
|
+
};
|
|
529
550
|
// ─────────────────────────────────────────────────────────────────
|
|
530
551
|
// Standalone helpers (regex on raw strings — not part of the pipeline)
|
|
531
552
|
// ─────────────────────────────────────────────────────────────────
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function renderSection(title: string, entries: [string, string][], indent?: number): string[];
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
export function renderSection(title, entries, indent = 0) {
|
|
3
|
+
if (!entries.length)
|
|
4
|
+
return [];
|
|
5
|
+
const pad = ' '.repeat(indent);
|
|
6
|
+
const width = Math.max(...entries.map(([label]) => label.length));
|
|
7
|
+
const lines = [`${pad}${chalk.bold(title)}`];
|
|
8
|
+
for (const [label, value] of entries)
|
|
9
|
+
lines.push(`${pad} ${chalk.dim(label.padEnd(width))} ${value}`);
|
|
10
|
+
lines.push('');
|
|
11
|
+
return lines;
|
|
12
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { parse, serialize } from 'parse5';
|
|
2
|
-
import {
|
|
2
|
+
import { isTailwindClass, isTrashClass, minifyHtml } from "./html.js";
|
|
3
3
|
import { isDynamicId, isGenericClass } from "./xpath.js";
|
|
4
4
|
const IGNORED_PATHS = new Set(['html[1]', 'html[1]/head[1]', 'html[1]/body[1]']);
|
|
5
5
|
const SHELL_RATIO = 0.8;
|
|
@@ -364,14 +364,13 @@ const directTextDiffer = (current, previous) => {
|
|
|
364
364
|
}
|
|
365
365
|
return false;
|
|
366
366
|
};
|
|
367
|
-
const trashHtmlClasses = TRASH_HTML_CLASSES;
|
|
368
367
|
function filterContainerClasses(classes) {
|
|
369
368
|
return classes
|
|
370
369
|
.filter((cls) => !/\d/.test(cls))
|
|
371
370
|
.filter((cls) => !isGenericClass(cls))
|
|
372
|
-
.filter((cls) => !
|
|
371
|
+
.filter((cls) => !isTrashClass(cls))
|
|
373
372
|
.filter((cls) => !/(:|__)/.test(cls))
|
|
374
|
-
.filter((cls) => !
|
|
373
|
+
.filter((cls) => !isTailwindClass(cls));
|
|
375
374
|
}
|
|
376
375
|
function buildContainerSelector(element, allElements) {
|
|
377
376
|
const tag = element.tagName?.toLowerCase();
|
|
@@ -529,7 +528,8 @@ async function buildDiffParts(originalMap, modifiedMap, pageSize) {
|
|
|
529
528
|
appearedPaths.sort((a, b) => sizeOf(b) - sizeOf(a));
|
|
530
529
|
const addedLines = appearedPaths.map((p) => `ELEMENT:${p}`);
|
|
531
530
|
const removedLines = [];
|
|
532
|
-
const
|
|
531
|
+
const heldContentBefore = (originalMap.get(containerPath)?.childNodes ?? []).some((child) => 'tagName' in child && !!child.tagName);
|
|
532
|
+
const part = { container: selector, subtree, rawSize: serialized.length, added: addedLines, removed: removedLines, containerWasEmpty: !heldContentBefore };
|
|
533
533
|
const appearedPath = appearedPaths[0];
|
|
534
534
|
if (appearedPath) {
|
|
535
535
|
const appearedElement = modifiedMap.get(appearedPath);
|
package/dist/src/utils/html.d.ts
CHANGED
|
@@ -76,6 +76,8 @@ export declare function extractComponentScopeHtml(eidx: string, config: Componen
|
|
|
76
76
|
export declare function getComponentScopeHtmlExtractorSource(): string;
|
|
77
77
|
export declare const TRASH_HTML_CLASSES: RegExp;
|
|
78
78
|
export declare const TAILWIND_CLASS_PATTERNS: RegExp[];
|
|
79
|
+
export declare const isTailwindClass: (cls: string) => boolean;
|
|
80
|
+
export declare const isTrashClass: (cls: string) => boolean;
|
|
79
81
|
export declare function sanitizeHtmlDocument(html: string, htmlConfig?: HtmlConfig): parse5TreeAdapter.Document;
|
|
80
82
|
export declare function sanitizeHtmlString(html: string, htmlConfig?: HtmlConfig): string;
|
|
81
83
|
/**
|
package/dist/src/utils/html.js
CHANGED
|
@@ -509,6 +509,8 @@ export const TAILWIND_CLASS_PATTERNS = [
|
|
|
509
509
|
/^aspect-/i,
|
|
510
510
|
/^prose$/i,
|
|
511
511
|
];
|
|
512
|
+
export const isTailwindClass = (cls) => TAILWIND_CLASS_PATTERNS.some((pattern) => pattern.test(cls));
|
|
513
|
+
export const isTrashClass = (cls) => TRASH_HTML_CLASSES.test(cls);
|
|
512
514
|
const NON_SEMANTIC_TAGS = new Set([
|
|
513
515
|
'style',
|
|
514
516
|
'script',
|
|
@@ -688,7 +690,6 @@ export function sanitizeHtmlString(html, htmlConfig) {
|
|
|
688
690
|
*/
|
|
689
691
|
export function htmlMinimalUISnapshot(html, htmlConfig) {
|
|
690
692
|
const document = parse(html);
|
|
691
|
-
const trashHtmlClasses = TRASH_HTML_CLASSES;
|
|
692
693
|
const removeElements = ['path', 'script'];
|
|
693
694
|
function isFilteredOut(node) {
|
|
694
695
|
// Check exclude selectors first
|
|
@@ -790,9 +791,9 @@ export function htmlMinimalUISnapshot(html, htmlConfig) {
|
|
|
790
791
|
attr.value = value
|
|
791
792
|
.split(' ')
|
|
792
793
|
.filter((className) => !/\d/.test(className))
|
|
793
|
-
.filter((className) => !className
|
|
794
|
+
.filter((className) => !isTrashClass(className))
|
|
794
795
|
.filter((className) => !className.match(/(:|__)/))
|
|
795
|
-
.filter((className) => !
|
|
796
|
+
.filter((className) => !isTailwindClass(className))
|
|
796
797
|
.join(' ');
|
|
797
798
|
if (attr.value === '')
|
|
798
799
|
return false;
|
|
@@ -1312,7 +1313,7 @@ function cleanElement(element) {
|
|
|
1312
1313
|
.filter(Boolean)
|
|
1313
1314
|
.filter((className) => !/\d/.test(className))
|
|
1314
1315
|
.filter((className) => !className.includes(':'))
|
|
1315
|
-
.filter((className) => !
|
|
1316
|
+
.filter((className) => !isTailwindClass(className))
|
|
1316
1317
|
.join(' ');
|
|
1317
1318
|
if (!attr.value) {
|
|
1318
1319
|
element.attrs = element.attrs.filter((a) => a.name !== 'class');
|
|
@@ -1,31 +1,13 @@
|
|
|
1
|
-
import type
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
html?: string | null;
|
|
8
|
-
xpath?: string | null;
|
|
9
|
-
parent?: OverlayData | null;
|
|
10
|
-
};
|
|
11
|
-
export declare class Overlay {
|
|
12
|
-
readonly type: OverlayType | null;
|
|
13
|
-
readonly name: string | null;
|
|
14
|
-
readonly root: string | null;
|
|
15
|
-
readonly html: string | null;
|
|
16
|
-
readonly xpath: string | null;
|
|
17
|
-
readonly parent: OverlayData | null;
|
|
18
|
-
constructor(data?: OverlayData);
|
|
19
|
-
get detected(): boolean;
|
|
20
|
-
get present(): boolean;
|
|
21
|
-
describe(): string;
|
|
22
|
-
withGeometry(geometry: Overlay): Overlay;
|
|
23
|
-
withParent(parent: Overlay): Overlay;
|
|
24
|
-
static fromAria(snapshot: string | null): Overlay;
|
|
1
|
+
import { Region, type RegionData, type RegionDiff } from './region.js';
|
|
2
|
+
export declare class Overlay extends Region {
|
|
3
|
+
constructor(data?: RegionData);
|
|
4
|
+
get isModal(): boolean;
|
|
5
|
+
withGeometry(geometry: Region): Overlay;
|
|
6
|
+
static fromAria(snapshot: string | null): Region;
|
|
25
7
|
static resolve(data: {
|
|
26
|
-
overlay?:
|
|
8
|
+
overlay?: RegionData | null;
|
|
27
9
|
ariaSnapshot?: string | null;
|
|
28
|
-
}):
|
|
10
|
+
}): Region;
|
|
29
11
|
}
|
|
30
12
|
export declare class OverlayPage {
|
|
31
13
|
page: {
|
|
@@ -34,36 +16,18 @@ export declare class OverlayPage {
|
|
|
34
16
|
constructor(page: {
|
|
35
17
|
evaluate(fn: any, arg: any): Promise<any>;
|
|
36
18
|
} | null);
|
|
37
|
-
detectRegion(diff: RegionDiff): Promise<
|
|
38
|
-
isStillOpen(
|
|
39
|
-
|
|
40
|
-
probe(xpath: string): Promise<RegionProbe | null>;
|
|
41
|
-
toOverlay(subRoot: AppearedSubRoot, probe: RegionProbe | null, previousHtml: string): Overlay;
|
|
42
|
-
nameFrom(html: string, previousHtml: string): string | null;
|
|
43
|
-
freshHeading(html: string, previousHtml: string): string | null;
|
|
44
|
-
headingsOf(html: string): string[];
|
|
19
|
+
detectRegion(diff: RegionDiff): Promise<Region | null>;
|
|
20
|
+
isStillOpen(region: Region): Promise<boolean>;
|
|
21
|
+
measure(xpath: string): Promise<RegionLayout | null>;
|
|
45
22
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
sameUrl: boolean;
|
|
51
|
-
previousHtml: string;
|
|
52
|
-
}
|
|
53
|
-
interface AppearedSubRoot {
|
|
54
|
-
container: string;
|
|
55
|
-
elementXPath: string;
|
|
56
|
-
subtree: string;
|
|
57
|
-
size: number;
|
|
58
|
-
rawSize: number;
|
|
59
|
-
appearedSelector?: string;
|
|
60
|
-
fresh: boolean;
|
|
61
|
-
}
|
|
62
|
-
interface RegionProbe {
|
|
63
|
-
found: boolean;
|
|
64
|
-
onScreen: boolean;
|
|
65
|
-
floating: boolean;
|
|
23
|
+
interface RegionLayout {
|
|
24
|
+
rendered: boolean;
|
|
25
|
+
inViewport: boolean;
|
|
26
|
+
outOfFlow: boolean;
|
|
66
27
|
centerBelongs: boolean;
|
|
67
|
-
|
|
28
|
+
coveredOutOfFlow: boolean;
|
|
29
|
+
holdsViewportCenter: boolean;
|
|
30
|
+
viewportCoverage: number;
|
|
31
|
+
controls: number;
|
|
68
32
|
}
|
|
69
33
|
export {};
|