@dyyz1993/agent-browser 0.28.0 → 0.29.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions/context.d.ts +4 -0
- package/dist/actions/context.d.ts.map +1 -1
- package/dist/actions/context.js +41 -1
- package/dist/actions/context.js.map +1 -1
- package/dist/actions/index.d.ts.map +1 -1
- package/dist/actions/index.js +164 -297
- package/dist/actions/index.js.map +1 -1
- package/dist/actions/interaction.d.ts.map +1 -1
- package/dist/actions/interaction.js +96 -30
- package/dist/actions/interaction.js.map +1 -1
- package/dist/actions/touch.d.ts +25 -0
- package/dist/actions/touch.d.ts.map +1 -0
- package/dist/actions/touch.js +114 -0
- package/dist/actions/touch.js.map +1 -0
- package/dist/browser/browser-manager.d.ts +15 -0
- package/dist/browser/browser-manager.d.ts.map +1 -1
- package/dist/browser/browser-manager.js +75 -7
- package/dist/browser/browser-manager.js.map +1 -1
- package/dist/browser/network-analysis.d.ts +65 -0
- package/dist/browser/network-analysis.d.ts.map +1 -0
- package/dist/browser/network-analysis.js +359 -0
- package/dist/browser/network-analysis.js.map +1 -0
- package/dist/browser/network-tracker.d.ts +4 -0
- package/dist/browser/network-tracker.d.ts.map +1 -1
- package/dist/browser/network-tracker.js +41 -0
- package/dist/browser/network-tracker.js.map +1 -1
- package/dist/browser/popup-detector.d.ts +22 -0
- package/dist/browser/popup-detector.d.ts.map +1 -0
- package/dist/browser/popup-detector.js +138 -0
- package/dist/browser/popup-detector.js.map +1 -0
- package/dist/cli/commands/index.d.ts +5 -0
- package/dist/cli/commands/index.d.ts.map +1 -0
- package/dist/cli/commands/index.js +219 -0
- package/dist/cli/commands/index.js.map +1 -0
- package/dist/cli/commands/interact.d.ts +7 -0
- package/dist/cli/commands/interact.d.ts.map +1 -0
- package/dist/cli/commands/interact.js +371 -0
- package/dist/cli/commands/interact.js.map +1 -0
- package/dist/cli/commands/navigate.d.ts +4 -0
- package/dist/cli/commands/navigate.d.ts.map +1 -0
- package/dist/cli/commands/navigate.js +46 -0
- package/dist/cli/commands/navigate.js.map +1 -0
- package/dist/cli/commands/network.d.ts +3 -0
- package/dist/cli/commands/network.d.ts.map +1 -0
- package/dist/cli/commands/network.js +292 -0
- package/dist/cli/commands/network.js.map +1 -0
- package/dist/cli/commands/plugin.d.ts +3 -0
- package/dist/cli/commands/plugin.d.ts.map +1 -0
- package/dist/cli/commands/plugin.js +84 -0
- package/dist/cli/commands/plugin.js.map +1 -0
- package/dist/cli/commands/query.d.ts +7 -0
- package/dist/cli/commands/query.d.ts.map +1 -0
- package/dist/cli/commands/query.js +333 -0
- package/dist/cli/commands/query.js.map +1 -0
- package/dist/cli/commands/session.d.ts +3 -0
- package/dist/cli/commands/session.d.ts.map +1 -0
- package/dist/cli/commands/session.js +372 -0
- package/dist/cli/commands/session.js.map +1 -0
- package/dist/cli/commands/shared.d.ts +24 -0
- package/dist/cli/commands/shared.d.ts.map +1 -0
- package/dist/cli/commands/shared.js +113 -0
- package/dist/cli/commands/shared.js.map +1 -0
- package/dist/cli/commands.d.ts +1 -7
- package/dist/cli/commands.d.ts.map +1 -1
- package/dist/cli/commands.js +1 -1684
- package/dist/cli/commands.js.map +1 -1
- package/dist/cli/connection.d.ts.map +1 -1
- package/dist/cli/connection.js +9 -1
- package/dist/cli/connection.js.map +1 -1
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/help.js +1 -24
- package/dist/cli/help.js.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/cli.js.map +1 -1
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +21 -1
- package/dist/daemon.js.map +1 -1
- package/dist/diff.d.ts +4 -0
- package/dist/diff.d.ts.map +1 -1
- package/dist/diff.js +16 -0
- package/dist/diff.js.map +1 -1
- package/dist/flow/exporters/cypress.js +1 -1
- package/dist/flow/exporters/cypress.js.map +1 -1
- package/dist/flow/exporters/selenium.js +1 -1
- package/dist/flow/exporters/selenium.js.map +1 -1
- package/dist/openapi.d.ts.map +1 -1
- package/dist/openapi.js +2 -1
- package/dist/openapi.js.map +1 -1
- package/dist/plugins/registry.d.ts.map +1 -1
- package/dist/plugins/registry.js +4 -1
- package/dist/plugins/registry.js.map +1 -1
- package/dist/plugins/types.d.ts +4 -4
- package/dist/plugins/types.d.ts.map +1 -1
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +30 -7
- package/dist/protocol.js.map +1 -1
- package/dist/snapshot/constants.d.ts +6 -0
- package/dist/snapshot/constants.d.ts.map +1 -0
- package/dist/snapshot/constants.js +77 -0
- package/dist/snapshot/constants.js.map +1 -0
- package/dist/snapshot/dom-scripts.d.ts +12 -0
- package/dist/snapshot/dom-scripts.d.ts.map +1 -0
- package/dist/snapshot/dom-scripts.js +438 -0
- package/dist/snapshot/dom-scripts.js.map +1 -0
- package/dist/snapshot/format.d.ts +13 -0
- package/dist/snapshot/format.d.ts.map +1 -0
- package/dist/snapshot/format.js +175 -0
- package/dist/snapshot/format.js.map +1 -0
- package/dist/snapshot/index.d.ts +6 -0
- package/dist/snapshot/index.d.ts.map +1 -0
- package/dist/snapshot/index.js +5 -0
- package/dist/snapshot/index.js.map +1 -0
- package/dist/snapshot/refs.d.ts +3 -0
- package/dist/snapshot/refs.d.ts.map +1 -0
- package/dist/snapshot/refs.js +8 -0
- package/dist/snapshot/refs.js.map +1 -0
- package/dist/snapshot/selectors.d.ts +17 -0
- package/dist/snapshot/selectors.d.ts.map +1 -0
- package/dist/snapshot/selectors.js +619 -0
- package/dist/snapshot/selectors.js.map +1 -0
- package/dist/snapshot/snapshot.d.ts +12 -0
- package/dist/snapshot/snapshot.d.ts.map +1 -0
- package/dist/snapshot/snapshot.js +104 -0
- package/dist/snapshot/snapshot.js.map +1 -0
- package/dist/snapshot/types.d.ts +27 -0
- package/dist/snapshot/types.d.ts.map +1 -0
- package/dist/snapshot/types.js +2 -0
- package/dist/snapshot/types.js.map +1 -0
- package/dist/snapshot.d.ts +1 -79
- package/dist/snapshot.d.ts.map +1 -1
- package/dist/snapshot.js +1 -1800
- package/dist/snapshot.js.map +1 -1
- package/dist/stream/client-state.d.ts +13 -0
- package/dist/stream/client-state.d.ts.map +1 -0
- package/dist/stream/client-state.js +2 -0
- package/dist/stream/client-state.js.map +1 -0
- package/dist/stream/element-utils.d.ts +8 -0
- package/dist/stream/element-utils.d.ts.map +1 -0
- package/dist/stream/element-utils.js +25 -0
- package/dist/stream/element-utils.js.map +1 -0
- package/dist/stream/frame-processor.d.ts +63 -0
- package/dist/stream/frame-processor.d.ts.map +1 -0
- package/dist/stream/frame-processor.js +178 -0
- package/dist/stream/frame-processor.js.map +1 -0
- package/dist/stream/index.d.ts +10 -0
- package/dist/stream/index.d.ts.map +1 -0
- package/dist/stream/index.js +5 -0
- package/dist/stream/index.js.map +1 -0
- package/dist/stream/input-handler.d.ts +10 -0
- package/dist/stream/input-handler.d.ts.map +1 -0
- package/dist/stream/input-handler.js +81 -0
- package/dist/stream/input-handler.js.map +1 -0
- package/dist/stream/messages.d.ts +144 -0
- package/dist/stream/messages.d.ts.map +1 -0
- package/dist/stream/messages.js +46 -0
- package/dist/stream/messages.js.map +1 -0
- package/dist/stream-server-standalone.d.ts +0 -3
- package/dist/stream-server-standalone.d.ts.map +1 -1
- package/dist/stream-server-standalone.js +22 -82
- package/dist/stream-server-standalone.js.map +1 -1
- package/dist/stream-server.d.ts +8 -212
- package/dist/stream-server.d.ts.map +1 -1
- package/dist/stream-server.js +35 -389
- package/dist/stream-server.js.map +1 -1
- package/dist/types/base.d.ts +11 -0
- package/dist/types/base.d.ts.map +1 -0
- package/dist/types/base.js +2 -0
- package/dist/types/base.js.map +1 -0
- package/dist/types/browser.d.ts +26 -0
- package/dist/types/browser.d.ts.map +1 -0
- package/dist/types/browser.js +2 -0
- package/dist/types/browser.js.map +1 -0
- package/dist/types/commands.d.ts +768 -0
- package/dist/types/commands.d.ts.map +1 -0
- package/dist/types/commands.js +2 -0
- package/dist/types/commands.js.map +1 -0
- package/dist/types/crawl.d.ts +89 -0
- package/dist/types/crawl.d.ts.map +1 -0
- package/dist/types/crawl.js +2 -0
- package/dist/types/crawl.js.map +1 -0
- package/dist/types/index.d.ts +9 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +9 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/interact.d.ts +61 -0
- package/dist/types/interact.d.ts.map +1 -0
- package/dist/types/interact.js +2 -0
- package/dist/types/interact.js.map +1 -0
- package/dist/types/plugins.d.ts +39 -0
- package/dist/types/plugins.d.ts.map +1 -0
- package/dist/types/plugins.js +2 -0
- package/dist/types/plugins.js.map +1 -0
- package/dist/types/responses.d.ts +140 -0
- package/dist/types/responses.d.ts.map +1 -0
- package/dist/types/responses.js +4 -0
- package/dist/types/responses.js.map +1 -0
- package/dist/types/utils.d.ts +12 -0
- package/dist/types/utils.d.ts.map +1 -0
- package/dist/types/utils.js +2 -0
- package/dist/types/utils.js.map +1 -0
- package/dist/types.d.ts +1 -1125
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -3
- package/dist/types.js.map +1 -1
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +31 -0
- package/dist/version.js.map +1 -0
- package/package.json +11 -11
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/snapshot/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,MAAM,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC5E,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,mBAAmB,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAChF,OAAO,EACL,uBAAuB,EACvB,gBAAgB,EAChB,aAAa,EACb,eAAe,EACf,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,iBAAiB,EACjB,aAAa,EACb,gBAAgB,EAChB,oBAAoB,EACpB,aAAa,GACd,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { resetRefs } from './refs.js';
|
|
2
|
+
export { getEnhancedSnapshot, parseRef, getSnapshotStats } from './snapshot.js';
|
|
3
|
+
export { generateStableSelectors, getSemanticClass, generateXPath, generateCSSPath, collectAttributes, } from './selectors.js';
|
|
4
|
+
export { INTERACTIVE_ROLES, CONTENT_ROLES, STRUCTURAL_ROLES, STYLE_CLASS_PATTERNS, SEMANTIC_TAGS, } from './constants.js';
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/snapshot/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,mBAAmB,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAChF,OAAO,EACL,uBAAuB,EACvB,gBAAgB,EAChB,aAAa,EACb,eAAe,EACf,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,iBAAiB,EACjB,aAAa,EACb,gBAAgB,EAChB,oBAAoB,EACpB,aAAa,GACd,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refs.d.ts","sourceRoot":"","sources":["../../src/snapshot/refs.ts"],"names":[],"mappings":"AAEA,wBAAgB,SAAS,IAAI,IAAI,CAEhC;AAED,wBAAgB,OAAO,IAAI,MAAM,CAEhC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refs.js","sourceRoot":"","sources":["../../src/snapshot/refs.ts"],"names":[],"mappings":"AAAA,IAAI,UAAU,GAAG,CAAC,CAAC;AAEnB,MAAM,UAAU,SAAS;IACvB,UAAU,GAAG,CAAC,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,OAAO;IACrB,OAAO,IAAI,EAAE,UAAU,EAAE,CAAC;AAC5B,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Page, Frame } from 'playwright-core';
|
|
2
|
+
import type { RefMap } from './types.js';
|
|
3
|
+
export declare function buildSelector(role: string, name?: string): string;
|
|
4
|
+
export declare function suggestSelectors(page: Page | Frame): Promise<string[]>;
|
|
5
|
+
export declare function generateStableSelectors(page: Page | Frame, refs: RefMap): Promise<Record<string, {
|
|
6
|
+
cssSelector: string;
|
|
7
|
+
xpath: string;
|
|
8
|
+
}>>;
|
|
9
|
+
declare function buildCompactSelectors(page: Page | Frame, refs: RefMap, options?: {
|
|
10
|
+
all?: boolean;
|
|
11
|
+
}): Promise<string>;
|
|
12
|
+
export { buildCompactSelectors };
|
|
13
|
+
export declare function getSemanticClass(element: Element): string | null;
|
|
14
|
+
export declare function generateXPath(element: Element, maxDepth?: number): string;
|
|
15
|
+
export declare function generateCSSPath(element: Element, maxDepth?: number): string;
|
|
16
|
+
export declare function collectAttributes(element: Element): Record<string, string>;
|
|
17
|
+
//# sourceMappingURL=selectors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selectors.d.ts","sourceRoot":"","sources":["../../src/snapshot/selectors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,KAAK,EAAgB,MAAM,iBAAiB,CAAC;AACjE,OAAO,KAAK,EAAE,MAAM,EAAmB,MAAM,YAAY,CAAC;AAG1D,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAMjE;AAED,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,IAAI,GAAG,KAAK,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAoC5E;AAED,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,IAAI,GAAG,KAAK,EAClB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,CAuWjE;AAED,iBAAe,qBAAqB,CAClC,IAAI,EAAE,IAAI,GAAG,KAAK,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,OAAO,CAAA;CAAE,GAC1B,OAAO,CAAC,MAAM,CAAC,CAkEjB;AAED,OAAO,EAAE,qBAAqB,EAAE,CAAC;AAEjC,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAYhE;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,GAAE,MAAU,GAAG,MAAM,CAsB5E;AAmDD,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,GAAE,MAAU,GAAG,MAAM,CA2C9E;AAyBD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAS1E"}
|
|
@@ -0,0 +1,619 @@
|
|
|
1
|
+
import { STYLE_CLASS_PATTERNS, SEMANTIC_TAGS } from './constants.js';
|
|
2
|
+
export function buildSelector(role, name) {
|
|
3
|
+
if (name) {
|
|
4
|
+
const escapedName = name.replace(/"/g, '\\"');
|
|
5
|
+
return `getByRole('${role}', { name: "${escapedName}", exact: true })`;
|
|
6
|
+
}
|
|
7
|
+
return `getByRole('${role}')`;
|
|
8
|
+
}
|
|
9
|
+
export async function suggestSelectors(page) {
|
|
10
|
+
const selectors = [];
|
|
11
|
+
try {
|
|
12
|
+
const commonSelectors = [
|
|
13
|
+
'body',
|
|
14
|
+
'main',
|
|
15
|
+
'#main',
|
|
16
|
+
'#content',
|
|
17
|
+
'.content',
|
|
18
|
+
'article',
|
|
19
|
+
'form',
|
|
20
|
+
'#app',
|
|
21
|
+
'.app',
|
|
22
|
+
];
|
|
23
|
+
for (const selector of commonSelectors) {
|
|
24
|
+
try {
|
|
25
|
+
const locator = page.locator(selector);
|
|
26
|
+
const count = await locator.count();
|
|
27
|
+
if (count > 0) {
|
|
28
|
+
selectors.push(selector);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
/* ignored */
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (selectors.length === 0) {
|
|
36
|
+
selectors.push('body');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
selectors.push('body');
|
|
41
|
+
}
|
|
42
|
+
return selectors;
|
|
43
|
+
}
|
|
44
|
+
export async function generateStableSelectors(page, refs) {
|
|
45
|
+
const result = {};
|
|
46
|
+
for (const [ref, data] of Object.entries(refs)) {
|
|
47
|
+
if (data.role === 'clickable' || data.role === 'focusable') {
|
|
48
|
+
if (data.selector && !data.selector.startsWith('getByRole')) {
|
|
49
|
+
result[ref] = { cssSelector: data.selector, xpath: '' };
|
|
50
|
+
}
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
let locator;
|
|
55
|
+
if (data.name) {
|
|
56
|
+
locator = page.getByRole(data.role, {
|
|
57
|
+
name: data.name,
|
|
58
|
+
exact: true,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
locator = page.getByRole(data.role);
|
|
63
|
+
}
|
|
64
|
+
if (data.nth !== undefined) {
|
|
65
|
+
locator = locator.nth(data.nth);
|
|
66
|
+
}
|
|
67
|
+
const elementCount = await locator.count();
|
|
68
|
+
if (elementCount === 0)
|
|
69
|
+
continue;
|
|
70
|
+
const selectorData = await locator
|
|
71
|
+
.evaluate((el) => {
|
|
72
|
+
const UTILITY_CLASS_PATTERNS = [
|
|
73
|
+
/^_/,
|
|
74
|
+
/^css-/,
|
|
75
|
+
/^[a-z]{1,2}$/,
|
|
76
|
+
/^(active|disabled|hidden|visible|selected|hover|focus|current|open|closed)$/i,
|
|
77
|
+
/^(text-|font-|bg-|p-|m-|w-|h-|flex|grid|border|rounded|shadow|opacity|z-)/,
|
|
78
|
+
/^(sm:|md:|lg:|xl:|2xl:)/,
|
|
79
|
+
];
|
|
80
|
+
const SEMANTIC_ATTRS = [
|
|
81
|
+
'data-testid',
|
|
82
|
+
'data-test',
|
|
83
|
+
'data-cy',
|
|
84
|
+
'name',
|
|
85
|
+
'aria-label',
|
|
86
|
+
'aria-labelledby',
|
|
87
|
+
'role',
|
|
88
|
+
'type',
|
|
89
|
+
'placeholder',
|
|
90
|
+
'title',
|
|
91
|
+
'alt',
|
|
92
|
+
];
|
|
93
|
+
function isHighEntropyClassName(className) {
|
|
94
|
+
if (!className || className.length < 4 || className.length > 15)
|
|
95
|
+
return false;
|
|
96
|
+
if (/^[a-zA-Z]+_[a-zA-Z]+_{2}[a-zA-Z0-9]+$/.test(className))
|
|
97
|
+
return true;
|
|
98
|
+
if (/^sc-[a-zA-Z0-9]+$/.test(className))
|
|
99
|
+
return true;
|
|
100
|
+
const hasUpper = /[A-Z]/.test(className);
|
|
101
|
+
const hasLower = /[a-z]/.test(className);
|
|
102
|
+
const hasDigit = /[0-9]/.test(className);
|
|
103
|
+
const hasSeparator = /[-_]/.test(className);
|
|
104
|
+
if (hasSeparator)
|
|
105
|
+
return false;
|
|
106
|
+
if (hasUpper && hasLower && hasDigit)
|
|
107
|
+
return true;
|
|
108
|
+
if (/^[A-Z][a-z0-9]+[A-Z]/.test(className) && className.length <= 12)
|
|
109
|
+
return true;
|
|
110
|
+
if (/^[a-z]/.test(className) && /[a-z][A-Z][a-z][A-Z]/.test(className))
|
|
111
|
+
return true;
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
function isUniqueSelector(selector) {
|
|
115
|
+
try {
|
|
116
|
+
return document.querySelectorAll(selector).length === 1;
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function filterUsefulClasses(element) {
|
|
123
|
+
const htmlEl = element;
|
|
124
|
+
if (!htmlEl.className || typeof htmlEl.className !== 'string')
|
|
125
|
+
return [];
|
|
126
|
+
return htmlEl.className
|
|
127
|
+
.trim()
|
|
128
|
+
.split(/\s+/)
|
|
129
|
+
.filter((c) => {
|
|
130
|
+
if (!c)
|
|
131
|
+
return false;
|
|
132
|
+
if (UTILITY_CLASS_PATTERNS.some((p) => p.test(c)))
|
|
133
|
+
return false;
|
|
134
|
+
if (isHighEntropyClassName(c))
|
|
135
|
+
return false;
|
|
136
|
+
return true;
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
function tryIdSelector(element) {
|
|
140
|
+
const htmlEl = element;
|
|
141
|
+
if (htmlEl.id) {
|
|
142
|
+
const sel = '#' + CSS.escape(htmlEl.id);
|
|
143
|
+
if (isUniqueSelector(sel))
|
|
144
|
+
return sel;
|
|
145
|
+
}
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
function getMultiAttributeSelector(element) {
|
|
149
|
+
const tag = element.tagName.toLowerCase();
|
|
150
|
+
const attrs = [];
|
|
151
|
+
for (const attr of SEMANTIC_ATTRS) {
|
|
152
|
+
const value = element.getAttribute(attr);
|
|
153
|
+
if (value)
|
|
154
|
+
attrs.push({ attr, value });
|
|
155
|
+
}
|
|
156
|
+
if (attrs.length === 0)
|
|
157
|
+
return null;
|
|
158
|
+
for (const { attr, value } of attrs) {
|
|
159
|
+
const sel = tag + '[' + attr + '="' + CSS.escape(value) + '"]';
|
|
160
|
+
if (isUniqueSelector(sel))
|
|
161
|
+
return sel;
|
|
162
|
+
}
|
|
163
|
+
if (attrs.length >= 2) {
|
|
164
|
+
for (let i = 0; i < attrs.length; i++) {
|
|
165
|
+
for (let j = i + 1; j < attrs.length; j++) {
|
|
166
|
+
const sel = tag +
|
|
167
|
+
'[' +
|
|
168
|
+
attrs[i].attr +
|
|
169
|
+
'="' +
|
|
170
|
+
CSS.escape(attrs[i].value) +
|
|
171
|
+
'"]' +
|
|
172
|
+
'[' +
|
|
173
|
+
attrs[j].attr +
|
|
174
|
+
'="' +
|
|
175
|
+
CSS.escape(attrs[j].value) +
|
|
176
|
+
'"]';
|
|
177
|
+
if (isUniqueSelector(sel))
|
|
178
|
+
return sel;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
function getAttributeClassComboSelector(element) {
|
|
185
|
+
const tag = element.tagName.toLowerCase();
|
|
186
|
+
const classes = filterUsefulClasses(element);
|
|
187
|
+
if (classes.length === 0)
|
|
188
|
+
return null;
|
|
189
|
+
classes.sort((a, b) => b.length - a.length);
|
|
190
|
+
const bestClass = classes[0];
|
|
191
|
+
for (const attr of SEMANTIC_ATTRS) {
|
|
192
|
+
const value = element.getAttribute(attr);
|
|
193
|
+
if (value) {
|
|
194
|
+
const sel = tag + '.' + CSS.escape(bestClass) + '[' + attr + '="' + CSS.escape(value) + '"]';
|
|
195
|
+
if (isUniqueSelector(sel))
|
|
196
|
+
return sel;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
function getBestClassSelector(element) {
|
|
202
|
+
const classes = filterUsefulClasses(element);
|
|
203
|
+
if (classes.length === 0)
|
|
204
|
+
return null;
|
|
205
|
+
classes.sort((a, b) => b.length - a.length);
|
|
206
|
+
const tag = element.tagName.toLowerCase();
|
|
207
|
+
for (const cls of classes) {
|
|
208
|
+
const sel = tag + '.' + CSS.escape(cls);
|
|
209
|
+
if (isUniqueSelector(sel))
|
|
210
|
+
return sel;
|
|
211
|
+
}
|
|
212
|
+
for (let i = 2; i <= Math.min(3, classes.length); i++) {
|
|
213
|
+
const sel = tag +
|
|
214
|
+
'.' +
|
|
215
|
+
classes
|
|
216
|
+
.slice(0, i)
|
|
217
|
+
.map((c) => CSS.escape(c))
|
|
218
|
+
.join('.');
|
|
219
|
+
if (isUniqueSelector(sel))
|
|
220
|
+
return sel;
|
|
221
|
+
}
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
function getFeatureSelector(element) {
|
|
225
|
+
if (!element || element === document.body)
|
|
226
|
+
return null;
|
|
227
|
+
const htmlEl = element;
|
|
228
|
+
if (htmlEl.id)
|
|
229
|
+
return '#' + CSS.escape(htmlEl.id);
|
|
230
|
+
for (const attr of ['data-testid', 'data-test', 'name', 'role', 'aria-label']) {
|
|
231
|
+
const value = element.getAttribute(attr);
|
|
232
|
+
if (value)
|
|
233
|
+
return element.tagName.toLowerCase() + '[' + attr + '="' + CSS.escape(value) + '"]';
|
|
234
|
+
}
|
|
235
|
+
const classes = filterUsefulClasses(element);
|
|
236
|
+
if (classes.length > 0) {
|
|
237
|
+
classes.sort((a, b) => b.length - a.length);
|
|
238
|
+
const sel = element.tagName.toLowerCase() + '.' + CSS.escape(classes[0]);
|
|
239
|
+
if (isUniqueSelector(sel))
|
|
240
|
+
return sel;
|
|
241
|
+
}
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
function getBaseSelector(element) {
|
|
245
|
+
let sel = element.tagName.toLowerCase();
|
|
246
|
+
const classes = filterUsefulClasses(element);
|
|
247
|
+
if (classes.length > 0) {
|
|
248
|
+
classes.sort((a, b) => b.length - a.length);
|
|
249
|
+
sel +=
|
|
250
|
+
'.' +
|
|
251
|
+
classes
|
|
252
|
+
.slice(0, 2)
|
|
253
|
+
.map((c) => CSS.escape(c))
|
|
254
|
+
.join('.');
|
|
255
|
+
}
|
|
256
|
+
return sel;
|
|
257
|
+
}
|
|
258
|
+
function makeUniqueWithNth(element, baseSelector) {
|
|
259
|
+
const parent = element.parentElement;
|
|
260
|
+
if (!parent)
|
|
261
|
+
return baseSelector;
|
|
262
|
+
const siblings = Array.from(parent.children);
|
|
263
|
+
const sameTagSiblings = siblings.filter((s) => s.tagName === element.tagName);
|
|
264
|
+
if (sameTagSiblings.length === 1)
|
|
265
|
+
return baseSelector;
|
|
266
|
+
const index = siblings.indexOf(element) + 1;
|
|
267
|
+
return baseSelector + ':nth-child(' + index + ')';
|
|
268
|
+
}
|
|
269
|
+
function getSiblingBasedSelector(element) {
|
|
270
|
+
let prevSibling = element.previousElementSibling;
|
|
271
|
+
let attempts = 0;
|
|
272
|
+
while (prevSibling && attempts < 3) {
|
|
273
|
+
const siblingSelector = getFeatureSelector(prevSibling);
|
|
274
|
+
if (siblingSelector && isUniqueSelector(siblingSelector)) {
|
|
275
|
+
const elementSelector = getBaseSelector(element);
|
|
276
|
+
const combined = siblingSelector + ' + ' + elementSelector;
|
|
277
|
+
if (isUniqueSelector(combined))
|
|
278
|
+
return combined;
|
|
279
|
+
}
|
|
280
|
+
prevSibling = prevSibling.previousElementSibling;
|
|
281
|
+
attempts++;
|
|
282
|
+
}
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
285
|
+
function buildComposedSelector(element) {
|
|
286
|
+
const selfSelector = getBestClassSelector(element);
|
|
287
|
+
if (selfSelector && isUniqueSelector(selfSelector))
|
|
288
|
+
return selfSelector;
|
|
289
|
+
const parts = [];
|
|
290
|
+
let current = element;
|
|
291
|
+
let depth = 0;
|
|
292
|
+
const maxDepth = 3;
|
|
293
|
+
while (current && current !== document.body && depth < maxDepth) {
|
|
294
|
+
const featureSelector = getFeatureSelector(current);
|
|
295
|
+
if (featureSelector) {
|
|
296
|
+
parts.unshift(featureSelector);
|
|
297
|
+
const elementSelector = depth === 0 ? getBaseSelector(element) : getBaseSelector(current);
|
|
298
|
+
const fullSelector = parts.join(' > ') + (depth > 0 ? '' : ' > ' + elementSelector);
|
|
299
|
+
if (isUniqueSelector(fullSelector))
|
|
300
|
+
return fullSelector;
|
|
301
|
+
}
|
|
302
|
+
else {
|
|
303
|
+
const baseSelector = getBaseSelector(current);
|
|
304
|
+
const selector = makeUniqueWithNth(current, baseSelector);
|
|
305
|
+
parts.unshift(selector);
|
|
306
|
+
const fullSelector = parts.join(' > ');
|
|
307
|
+
if (isUniqueSelector(fullSelector))
|
|
308
|
+
return fullSelector;
|
|
309
|
+
}
|
|
310
|
+
current = current.parentElement;
|
|
311
|
+
depth++;
|
|
312
|
+
}
|
|
313
|
+
return parts.length > 0 ? parts.join(' > ') : null;
|
|
314
|
+
}
|
|
315
|
+
function tryNthChild(element) {
|
|
316
|
+
const baseSelector = getBaseSelector(element);
|
|
317
|
+
const uniqueSelector = makeUniqueWithNth(element, baseSelector);
|
|
318
|
+
try {
|
|
319
|
+
if (document.querySelectorAll(uniqueSelector).length === 1)
|
|
320
|
+
return uniqueSelector;
|
|
321
|
+
}
|
|
322
|
+
catch {
|
|
323
|
+
/* ignored */
|
|
324
|
+
}
|
|
325
|
+
return null;
|
|
326
|
+
}
|
|
327
|
+
function buildUniquePath(element) {
|
|
328
|
+
const parts = [];
|
|
329
|
+
let current = element;
|
|
330
|
+
let depth = 0;
|
|
331
|
+
while (current && current !== document.body && depth < 5) {
|
|
332
|
+
const baseSelector = getBaseSelector(current);
|
|
333
|
+
const selector = makeUniqueWithNth(current, baseSelector);
|
|
334
|
+
parts.unshift(selector);
|
|
335
|
+
const fullSelector = parts.join(' > ');
|
|
336
|
+
if (isUniqueSelector(fullSelector))
|
|
337
|
+
return fullSelector;
|
|
338
|
+
current = current.parentElement;
|
|
339
|
+
depth++;
|
|
340
|
+
}
|
|
341
|
+
return parts.length > 0 ? parts.join(' > ') : null;
|
|
342
|
+
}
|
|
343
|
+
function generateXPath(element) {
|
|
344
|
+
const htmlEl = element;
|
|
345
|
+
if (htmlEl.id)
|
|
346
|
+
return '//*[@id="' + htmlEl.id + '"]';
|
|
347
|
+
const testId = element.getAttribute('data-testid');
|
|
348
|
+
if (testId)
|
|
349
|
+
return '//*[@data-testid="' + testId + '"]';
|
|
350
|
+
const nameAttr = element.getAttribute('name');
|
|
351
|
+
if (nameAttr)
|
|
352
|
+
return '//' + element.tagName.toLowerCase() + '[@name="' + nameAttr + '"]';
|
|
353
|
+
const parts = [];
|
|
354
|
+
let current = element;
|
|
355
|
+
let depth = 0;
|
|
356
|
+
while (current && depth < 5) {
|
|
357
|
+
const curHtml = current;
|
|
358
|
+
if (curHtml.id) {
|
|
359
|
+
parts.unshift('//*[@id="' + curHtml.id + '"]');
|
|
360
|
+
break;
|
|
361
|
+
}
|
|
362
|
+
const testId = current.getAttribute('data-testid');
|
|
363
|
+
if (testId) {
|
|
364
|
+
parts.unshift('//*[@data-testid="' + testId + '"]');
|
|
365
|
+
break;
|
|
366
|
+
}
|
|
367
|
+
const tagName = current.tagName.toLowerCase();
|
|
368
|
+
const parent = current.parentElement;
|
|
369
|
+
if (parent) {
|
|
370
|
+
const siblings = Array.from(parent.children).filter((c) => c.tagName === current.tagName);
|
|
371
|
+
const index = siblings.indexOf(current) + 1;
|
|
372
|
+
parts.unshift(tagName + '[' + index + ']');
|
|
373
|
+
}
|
|
374
|
+
else {
|
|
375
|
+
parts.unshift(tagName);
|
|
376
|
+
}
|
|
377
|
+
current = current.parentElement;
|
|
378
|
+
depth++;
|
|
379
|
+
}
|
|
380
|
+
if (parts.length > 0 && !parts[0].startsWith('//'))
|
|
381
|
+
parts.unshift('//');
|
|
382
|
+
return parts.join('/');
|
|
383
|
+
}
|
|
384
|
+
let cssSelector = null;
|
|
385
|
+
cssSelector = tryIdSelector(el);
|
|
386
|
+
if (!cssSelector)
|
|
387
|
+
cssSelector = getMultiAttributeSelector(el);
|
|
388
|
+
if (!cssSelector)
|
|
389
|
+
cssSelector = getAttributeClassComboSelector(el);
|
|
390
|
+
if (!cssSelector)
|
|
391
|
+
cssSelector = getBestClassSelector(el);
|
|
392
|
+
if (!cssSelector)
|
|
393
|
+
cssSelector = getSiblingBasedSelector(el);
|
|
394
|
+
if (!cssSelector)
|
|
395
|
+
cssSelector = buildComposedSelector(el);
|
|
396
|
+
if (!cssSelector)
|
|
397
|
+
cssSelector = tryNthChild(el);
|
|
398
|
+
if (!cssSelector)
|
|
399
|
+
cssSelector = buildUniquePath(el);
|
|
400
|
+
if (!cssSelector)
|
|
401
|
+
cssSelector = el.tagName.toLowerCase();
|
|
402
|
+
const xpath = generateXPath(el);
|
|
403
|
+
return { cssSelector, xpath };
|
|
404
|
+
})
|
|
405
|
+
.catch(() => null);
|
|
406
|
+
if (selectorData) {
|
|
407
|
+
result[ref] = {
|
|
408
|
+
cssSelector: selectorData.cssSelector,
|
|
409
|
+
xpath: selectorData.xpath,
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
catch {
|
|
414
|
+
/* ignored */
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
return result;
|
|
418
|
+
}
|
|
419
|
+
async function buildCompactSelectors(page, refs, options) {
|
|
420
|
+
const entries = Object.entries(refs);
|
|
421
|
+
const parts = [];
|
|
422
|
+
const includeAll = options?.all ?? false;
|
|
423
|
+
for (const [ref, data] of entries) {
|
|
424
|
+
if (data.role === 'clickable' || data.role === 'focusable')
|
|
425
|
+
continue;
|
|
426
|
+
try {
|
|
427
|
+
let locator;
|
|
428
|
+
if (data.name) {
|
|
429
|
+
locator = page.getByRole(data.role, {
|
|
430
|
+
name: data.name,
|
|
431
|
+
exact: true,
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
else {
|
|
435
|
+
locator = page.getByRole(data.role);
|
|
436
|
+
}
|
|
437
|
+
if (data.nth !== undefined)
|
|
438
|
+
locator = locator.nth(data.nth);
|
|
439
|
+
if (!includeAll) {
|
|
440
|
+
const isReallyVisible = await locator
|
|
441
|
+
.evaluate((el) => {
|
|
442
|
+
const style = getComputedStyle(el);
|
|
443
|
+
const rect = el.getBoundingClientRect();
|
|
444
|
+
return !(style.display === 'none' ||
|
|
445
|
+
style.visibility === 'hidden' ||
|
|
446
|
+
parseFloat(style.opacity) === 0 ||
|
|
447
|
+
(rect.width === 0 && rect.height === 0) ||
|
|
448
|
+
rect.x + rect.width < 0 ||
|
|
449
|
+
rect.y + rect.height < 0);
|
|
450
|
+
})
|
|
451
|
+
.catch(() => false);
|
|
452
|
+
if (!isReallyVisible)
|
|
453
|
+
continue;
|
|
454
|
+
}
|
|
455
|
+
const attrs = await locator
|
|
456
|
+
.evaluate((el) => {
|
|
457
|
+
const htmlEl = el;
|
|
458
|
+
const r = {};
|
|
459
|
+
if (htmlEl.dataset.testid)
|
|
460
|
+
r['testid'] = `[data-testid="${htmlEl.dataset.testid}"]`;
|
|
461
|
+
if (htmlEl.id && !htmlEl.id.match(/^[:]/))
|
|
462
|
+
r['id'] = '#' + CSS.escape(htmlEl.id);
|
|
463
|
+
const nameAttr = htmlEl.getAttribute('name');
|
|
464
|
+
if (nameAttr)
|
|
465
|
+
r['name'] = `${htmlEl.tagName.toLowerCase()}[name="${nameAttr}"]`;
|
|
466
|
+
return r;
|
|
467
|
+
})
|
|
468
|
+
.catch(() => null);
|
|
469
|
+
if (!attrs)
|
|
470
|
+
continue;
|
|
471
|
+
let bestSelector = '';
|
|
472
|
+
if (attrs.testid)
|
|
473
|
+
bestSelector = attrs.testid;
|
|
474
|
+
else if (attrs.id)
|
|
475
|
+
bestSelector = attrs.id;
|
|
476
|
+
else if (attrs.name)
|
|
477
|
+
bestSelector = attrs.name;
|
|
478
|
+
if (bestSelector) {
|
|
479
|
+
parts.push(`${ref}: ${bestSelector}`);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
catch {
|
|
483
|
+
/* ignored */
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
return parts.join(' | ');
|
|
487
|
+
}
|
|
488
|
+
export { buildCompactSelectors };
|
|
489
|
+
export function getSemanticClass(element) {
|
|
490
|
+
const className = element.getAttribute('class');
|
|
491
|
+
if (!className)
|
|
492
|
+
return null;
|
|
493
|
+
const classes = className.split(/\s+/).filter((cls) => {
|
|
494
|
+
return !STYLE_CLASS_PATTERNS.some((p) => p.test(cls));
|
|
495
|
+
});
|
|
496
|
+
if (classes.length === 0)
|
|
497
|
+
return null;
|
|
498
|
+
const selectedClasses = classes.slice(0, 2);
|
|
499
|
+
return selectedClasses.map((cls) => `contains(@class, "${cls}")`).join(' and ');
|
|
500
|
+
}
|
|
501
|
+
export function generateXPath(element, maxDepth = 5) {
|
|
502
|
+
const elemId = element.id;
|
|
503
|
+
if (elemId) {
|
|
504
|
+
return `//*[@id="${elemId}"]`;
|
|
505
|
+
}
|
|
506
|
+
const testId = element.getAttribute('data-testid');
|
|
507
|
+
if (testId) {
|
|
508
|
+
return `//*[@data-testid="${testId}"]`;
|
|
509
|
+
}
|
|
510
|
+
const dataId = element.getAttribute('data-id');
|
|
511
|
+
if (dataId) {
|
|
512
|
+
return `//*[@data-id="${dataId}"]`;
|
|
513
|
+
}
|
|
514
|
+
const semanticClass = getSemanticClass(element);
|
|
515
|
+
if (semanticClass) {
|
|
516
|
+
return `//${element.tagName.toLowerCase()}[${semanticClass}]`;
|
|
517
|
+
}
|
|
518
|
+
return buildRelativeXPath(element, maxDepth);
|
|
519
|
+
}
|
|
520
|
+
function buildRelativeXPath(element, maxDepth) {
|
|
521
|
+
const path = [];
|
|
522
|
+
let current = element;
|
|
523
|
+
let depth = 0;
|
|
524
|
+
while (current && depth < maxDepth) {
|
|
525
|
+
const currentId = current.id;
|
|
526
|
+
if (currentId) {
|
|
527
|
+
path.unshift(`//*[@id="${currentId}"]`);
|
|
528
|
+
break;
|
|
529
|
+
}
|
|
530
|
+
const testId = current.getAttribute('data-testid');
|
|
531
|
+
if (testId) {
|
|
532
|
+
path.unshift(`//*[@data-testid="${testId}"]`);
|
|
533
|
+
break;
|
|
534
|
+
}
|
|
535
|
+
const tagName = current.tagName.toLowerCase();
|
|
536
|
+
if (SEMANTIC_TAGS.has(tagName)) {
|
|
537
|
+
const index = getElementIndex(current);
|
|
538
|
+
path.unshift(`//${tagName}[${index}]`);
|
|
539
|
+
break;
|
|
540
|
+
}
|
|
541
|
+
const index = getElementIndex(current);
|
|
542
|
+
path.unshift(`${tagName}[${index}]`);
|
|
543
|
+
current = current.parentElement;
|
|
544
|
+
depth++;
|
|
545
|
+
}
|
|
546
|
+
if (path.length > 0 && !path[0].startsWith('//')) {
|
|
547
|
+
path.unshift('//');
|
|
548
|
+
}
|
|
549
|
+
return path.join('/');
|
|
550
|
+
}
|
|
551
|
+
function getElementIndex(element) {
|
|
552
|
+
const parent = element.parentElement;
|
|
553
|
+
if (!parent)
|
|
554
|
+
return 1;
|
|
555
|
+
const siblings = Array.from(parent.children).filter((child) => child.tagName === element.tagName);
|
|
556
|
+
return siblings.indexOf(element) + 1;
|
|
557
|
+
}
|
|
558
|
+
export function generateCSSPath(element, maxDepth = 5) {
|
|
559
|
+
const elemId = element.id;
|
|
560
|
+
if (elemId) {
|
|
561
|
+
return `#${elemId}`;
|
|
562
|
+
}
|
|
563
|
+
const testId = element.getAttribute('data-testid');
|
|
564
|
+
if (testId) {
|
|
565
|
+
return `[data-testid="${testId}"]`;
|
|
566
|
+
}
|
|
567
|
+
const path = [];
|
|
568
|
+
let current = element;
|
|
569
|
+
let depth = 0;
|
|
570
|
+
while (current && depth < maxDepth) {
|
|
571
|
+
const currentId = current.id;
|
|
572
|
+
if (currentId) {
|
|
573
|
+
path.unshift(`#${currentId}`);
|
|
574
|
+
break;
|
|
575
|
+
}
|
|
576
|
+
const testId = current.getAttribute('data-testid');
|
|
577
|
+
if (testId) {
|
|
578
|
+
path.unshift(`[data-testid="${testId}"]`);
|
|
579
|
+
break;
|
|
580
|
+
}
|
|
581
|
+
const tagName = current.tagName.toLowerCase();
|
|
582
|
+
if (SEMANTIC_TAGS.has(tagName)) {
|
|
583
|
+
path.unshift(tagName);
|
|
584
|
+
break;
|
|
585
|
+
}
|
|
586
|
+
const selector = buildElementSelector(current);
|
|
587
|
+
path.unshift(selector);
|
|
588
|
+
current = current.parentElement;
|
|
589
|
+
depth++;
|
|
590
|
+
}
|
|
591
|
+
return path.join(' > ');
|
|
592
|
+
}
|
|
593
|
+
function buildElementSelector(element) {
|
|
594
|
+
const tagName = element.tagName.toLowerCase();
|
|
595
|
+
const className = element.getAttribute('class');
|
|
596
|
+
if (className) {
|
|
597
|
+
const classes = className.split(/\s+/).filter((cls) => {
|
|
598
|
+
return !STYLE_CLASS_PATTERNS.some((p) => p.test(cls));
|
|
599
|
+
});
|
|
600
|
+
if (classes.length > 0) {
|
|
601
|
+
return `${tagName}.${classes.slice(0, 2).join('.')}`;
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
const parent = element.parentElement;
|
|
605
|
+
if (parent) {
|
|
606
|
+
const index = Array.from(parent.children).indexOf(element) + 1;
|
|
607
|
+
return `${tagName}:nth-child(${index})`;
|
|
608
|
+
}
|
|
609
|
+
return tagName;
|
|
610
|
+
}
|
|
611
|
+
export function collectAttributes(element) {
|
|
612
|
+
const attrs = {};
|
|
613
|
+
for (let i = 0; i < element.attributes.length; i++) {
|
|
614
|
+
const attr = element.attributes[i];
|
|
615
|
+
attrs[attr.name] = attr.value;
|
|
616
|
+
}
|
|
617
|
+
return attrs;
|
|
618
|
+
}
|
|
619
|
+
//# sourceMappingURL=selectors.js.map
|