@tontoko/fast-playwright-mcp 0.1.0 → 0.1.2

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.
@@ -20,7 +20,13 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
20
20
  // src/tools/snapshot.ts
21
21
  import { z } from "zod";
22
22
  import { expectationSchema } from "../schemas/expectation.js";
23
+ import { elementSelectorSchema } from "../types/selectors.js";
23
24
  import { formatObject } from "../utils/codegen.js";
25
+ import {
26
+ handleSnapshotExpectation,
27
+ resolveDragElements,
28
+ resolveFirstElement
29
+ } from "./shared-element-utils.js";
24
30
  import { defineTabTool, defineTool } from "./tool.js";
25
31
  import { generateLocator } from "./utils.js";
26
32
  var snapshot = defineTool({
@@ -28,9 +34,9 @@ var snapshot = defineTool({
28
34
  schema: {
29
35
  name: "browser_snapshot",
30
36
  title: "Page snapshot",
31
- description: `Capture accessibility snapshot of current page.AVOID calling directly - use expectation:{includeSnapshot:true} on other tools instead.USE CASES:Initial page inspection,debugging when other tools didn't capture needed info.snapshotOptions:{selector:"#content"} to focus on specific area.`,
37
+ description: "Capture accessibility snapshot of current page",
32
38
  inputSchema: z.object({
33
- expectation: expectationSchema
39
+ expectation: expectationSchema.describe("Page state config")
34
40
  }),
35
41
  type: "readOnly"
36
42
  },
@@ -45,26 +51,24 @@ var snapshot = defineTool({
45
51
  }
46
52
  }
47
53
  });
48
- var elementSchema = z.object({
49
- element: z.string().describe("Human-readable element description used to obtain permission to interact with the element"),
50
- ref: z.string().describe('System-generated element ID from previous tool results (e.g., "rNODE-45-1"). Never use custom values.')
51
- });
52
- var clickSchema = elementSchema.extend({
53
- doubleClick: z.boolean().optional().describe("Whether to perform a double click instead of a single click"),
54
- button: z.enum(["left", "right", "middle"]).optional().describe("Button to click, defaults to left"),
55
- expectation: expectationSchema
54
+ var selectorsSchema = z.array(elementSelectorSchema).min(1).max(5).describe("Array of element selectors (max 5). Selectors are tried in order until one succeeds (fallback mechanism). " + "Multiple matches trigger an error with candidate list. " + "Supports: ref (highest priority), CSS (#id, .class, tag), role (button, textbox, etc.), text content. " + 'Example: [{css: "#submit"}, {role: "button", text: "Submit"}] - tries ID first, falls back to role+text');
55
+ var clickSchema = z.object({
56
+ selectors: selectorsSchema,
57
+ doubleClick: z.boolean().optional().describe("Double-click if true"),
58
+ button: z.enum(["left", "right", "middle"]).optional().describe("Mouse button (default: left)"),
59
+ expectation: expectationSchema.describe("Page state capture config. Use batch_execute for multi-clicks")
56
60
  });
57
61
  var click = defineTabTool({
58
62
  capability: "core",
59
63
  schema: {
60
64
  name: "browser_click",
61
- title: "Click",
62
- description: `Perform click on web page.USE batch_execute for multi-click workflows.expectation:{includeSnapshot:false} when next action follows immediately,true to verify result.diffOptions:{enabled:true,format:"minimal"} shows only changes(saves 80% tokens).snapshotOptions:{selector:".result"} to focus on result area.doubleClick:true for double-click,button:"right" for context menu.`,
65
+ title: "Perform click on web page",
66
+ description: "Perform click on web page",
63
67
  inputSchema: clickSchema,
64
68
  type: "destructive"
65
69
  },
66
70
  handle: async (tab, params, response) => {
67
- const locator = await tab.refLocator(params);
71
+ const { locator } = await resolveFirstElement(tab, params.selectors, "Failed to resolve any element selectors");
68
72
  const button = params.button;
69
73
  const buttonAttr = button ? `{ button: '${button}' }` : "";
70
74
  if (params.doubleClick) {
@@ -79,10 +83,7 @@ var click = defineTabTool({
79
83
  await locator.click({ button });
80
84
  }
81
85
  });
82
- if (params.expectation?.includeSnapshot) {
83
- const newSnapshot = await tab.captureSnapshot();
84
- response.setTabSnapshot(newSnapshot);
85
- }
86
+ await handleSnapshotExpectation(tab, params.expectation, response);
86
87
  }
87
88
  });
88
89
  var drag = defineTabTool({
@@ -90,21 +91,16 @@ var drag = defineTabTool({
90
91
  schema: {
91
92
  name: "browser_drag",
92
93
  title: "Drag mouse",
93
- description: `Perform drag and drop between two elements.expectation:{includeSnapshot:true,snapshotOptions:{selector:".drop-zone"}} to verify drop result.diffOptions:{enabled:true} shows only what moved.CONSIDER batch_execute if part of larger workflow.`,
94
+ description: "Perform drag and drop between two elements",
94
95
  inputSchema: z.object({
95
- startElement: z.string().describe("Human-readable source element description used to obtain the permission to interact with the element"),
96
- startRef: z.string().describe('System-generated source element ID from previous tool results (e.g., "rNODE-45-1"). Never use custom values.'),
97
- endElement: z.string().describe("Human-readable target element description used to obtain the permission to interact with the element"),
98
- endRef: z.string().describe('System-generated target element ID from previous tool results (e.g., "rNODE-45-1"). Never use custom values.'),
99
- expectation: expectationSchema
96
+ startSelectors: selectorsSchema.describe("Source element selectors for drag start"),
97
+ endSelectors: selectorsSchema.describe("Target element selectors for drag end"),
98
+ expectation: expectationSchema.describe("Page state after drag. Use batch_execute for workflows")
100
99
  }),
101
100
  type: "destructive"
102
101
  },
103
102
  handle: async (tab, params, response) => {
104
- const [startLocator, endLocator] = await tab.refLocators([
105
- { ref: params.startRef, element: params.startElement },
106
- { ref: params.endRef, element: params.endElement }
107
- ]);
103
+ const { startLocator, endLocator } = await resolveDragElements(tab, params.startSelectors, params.endSelectors);
108
104
  await tab.waitForCompletion(async () => {
109
105
  await startLocator.dragTo(endLocator);
110
106
  });
@@ -116,35 +112,37 @@ var hover = defineTabTool({
116
112
  schema: {
117
113
  name: "browser_hover",
118
114
  title: "Hover mouse",
119
- description: `Hover over element on page.expectation:{includeSnapshot:true} to capture tooltips/dropdown menus,false for simple hover.snapshotOptions:{selector:".tooltip"} to focus on tooltip area.Often followed by click - use batch_execute for hover→click sequences.`,
120
- inputSchema: elementSchema.extend({
121
- expectation: expectationSchema
115
+ description: "Hover over element on page",
116
+ inputSchema: z.object({
117
+ selectors: selectorsSchema,
118
+ expectation: expectationSchema.describe("Page state after hover. Use batch_execute for hover→click")
122
119
  }),
123
120
  type: "readOnly"
124
121
  },
125
122
  handle: async (tab, params, response) => {
126
- const locator = await tab.refLocator(params);
123
+ const { locator } = await resolveFirstElement(tab, params.selectors);
127
124
  response.addCode(`await page.${await generateLocator(locator)}.hover();`);
128
125
  await tab.waitForCompletion(async () => {
129
126
  await locator.hover();
130
127
  });
131
128
  }
132
129
  });
133
- var selectOptionSchema = elementSchema.extend({
134
- values: z.array(z.string()).describe("Array of values to select in the dropdown. This can be a single value or multiple values."),
135
- expectation: expectationSchema
130
+ var selectOptionSchema = z.object({
131
+ selectors: selectorsSchema,
132
+ values: z.array(z.string()).describe("Values to select (array)"),
133
+ expectation: expectationSchema.describe("Page state after selection. Use batch_execute for forms")
136
134
  });
137
135
  var selectOption = defineTabTool({
138
136
  capability: "core",
139
137
  schema: {
140
138
  name: "browser_select_option",
141
139
  title: "Select option",
142
- description: `Select option in dropdown.values:["option1","option2"] for multi-select.expectation:{includeSnapshot:false} when part of form filling(use batch),true to verify selection.snapshotOptions:{selector:"form"} for form context.USE batch_execute for form workflows with multiple selects.`,
140
+ description: "Select option in dropdown",
143
141
  inputSchema: selectOptionSchema,
144
142
  type: "destructive"
145
143
  },
146
144
  handle: async (tab, params, response) => {
147
- const locator = await tab.refLocator(params);
145
+ const { locator } = await resolveFirstElement(tab, params.selectors);
148
146
  response.addCode(`await page.${await generateLocator(locator)}.selectOption(${formatObject(params.values)});`);
149
147
  await tab.waitForCompletion(async () => {
150
148
  await locator.selectOption(params.values);
@@ -153,6 +151,6 @@ var selectOption = defineTabTool({
153
151
  });
154
152
  var snapshot_default = [snapshot, click, drag, hover, selectOption];
155
153
  export {
156
- elementSchema,
154
+ selectorsSchema,
157
155
  snapshot_default as default
158
156
  };
package/lib/tools/tabs.js CHANGED
@@ -26,9 +26,9 @@ var listTabs = defineTool({
26
26
  schema: {
27
27
  name: "browser_tab_list",
28
28
  title: "List tabs",
29
- description: "List browser tabs.Always returns tab list with titles and URLs.expectation:{includeSnapshot:false} for just tab info,true to also see current tab content.USE before tab_select to find right tab.",
29
+ description: "List browser tabs with titles and URLs",
30
30
  inputSchema: z.object({
31
- expectation: expectationSchema
31
+ expectation: expectationSchema.describe("Page state config")
32
32
  }),
33
33
  type: "readOnly"
34
34
  },
@@ -42,10 +42,10 @@ var selectTab = defineTool({
42
42
  schema: {
43
43
  name: "browser_tab_select",
44
44
  title: "Select a tab",
45
- description: `Select a tab by index.expectation:{includeSnapshot:true} to see selected tab content,false if you know what's there.USE batch_execute for tab_select→interact workflows.`,
45
+ description: "Select a tab by index",
46
46
  inputSchema: z.object({
47
47
  index: z.number().describe("The index of the tab to select"),
48
- expectation: expectationSchema
48
+ expectation: expectationSchema.describe("Page state after tab switch")
49
49
  }),
50
50
  type: "readOnly"
51
51
  },
@@ -59,10 +59,10 @@ var newTab = defineTool({
59
59
  schema: {
60
60
  name: "browser_tab_new",
61
61
  title: "Open a new tab",
62
- description: `Open a new tab.url:"https://example.com" to navigate immediately,omit for blank tab.expectation:{includeSnapshot:true} to see new tab,false if opening for later use.CONSIDER batch_execute for new_tab→navigate→interact.`,
62
+ description: "Open a new tab",
63
63
  inputSchema: z.object({
64
- url: z.string().optional().describe("The URL to navigate to in the new tab. If not provided, the new tab will be blank."),
65
- expectation: expectationSchema
64
+ url: z.string().optional().describe("URL for new tab (optional)"),
65
+ expectation: expectationSchema.describe("Page state of new tab")
66
66
  }),
67
67
  type: "readOnly"
68
68
  },
@@ -79,10 +79,10 @@ var closeTab = defineTool({
79
79
  schema: {
80
80
  name: "browser_tab_close",
81
81
  title: "Close a tab",
82
- description: "Close a tab.index:N to close specific tab,omit to close current.expectation:{includeSnapshot:false} usually sufficient,true to verify remaining tabs.USE batch_execute for multi-tab cleanup.",
82
+ description: "Close a tab by index or close current tab",
83
83
  inputSchema: z.object({
84
- index: z.number().optional().describe("The index of the tab to close. Closes current tab if not provided."),
85
- expectation: expectationSchema
84
+ index: z.number().optional().describe("Tab index to close (omit for current)"),
85
+ expectation: expectationSchema.describe("Page state after close")
86
86
  }),
87
87
  type: "destructive"
88
88
  },
package/lib/tools/wait.js CHANGED
@@ -26,12 +26,12 @@ var wait = defineTool({
26
26
  schema: {
27
27
  name: "browser_wait_for",
28
28
  title: "Wait for",
29
- description: `Wait for text to appear/disappear or time to pass.PREFER text-based wait over time for reliability.For loading states:wait for text:"Loading..." textGone:true.For dynamic content:wait for specific text to appear.expectation:{includeSnapshot:true,snapshotOptions:{selector:"#status"},diffOptions:{enabled:true}} shows only what changed.AVOID:fixed time waits unless necessary.`,
29
+ description: "Wait for text to appear or disappear or a specified time to pass",
30
30
  inputSchema: z.object({
31
- time: z.number().optional().describe("The time to wait in seconds"),
32
- text: z.string().optional().describe("The text to wait for"),
33
- textGone: z.string().optional().describe("The text to wait for to disappear"),
34
- expectation: expectationSchema
31
+ time: z.number().optional().describe("Wait time in seconds"),
32
+ text: z.string().optional(),
33
+ textGone: z.string().optional(),
34
+ expectation: expectationSchema.describe("Page state after wait")
35
35
  }),
36
36
  type: "readOnly"
37
37
  },
package/lib/tools.js CHANGED
@@ -26,6 +26,7 @@ import dialogs from "./tools/dialogs.js";
26
26
  import evaluate from "./tools/evaluate.js";
27
27
  import files from "./tools/files.js";
28
28
  import { browserFindElements } from "./tools/find-elements.js";
29
+ import inspectHtml from "./tools/inspect-html.js";
29
30
  import install from "./tools/install.js";
30
31
  import keyboard from "./tools/keyboard.js";
31
32
  import mouse from "./tools/mouse.js";
@@ -43,6 +44,7 @@ var allTools = [
43
44
  ...evaluate,
44
45
  ...files,
45
46
  ...install,
47
+ ...inspectHtml,
46
48
  ...keyboard,
47
49
  ...navigate,
48
50
  ...network,
@@ -37,9 +37,9 @@ var batchStepSchema = z.object({
37
37
  expectation: expectationSchema.describe("Expected output configuration for this step")
38
38
  });
39
39
  var batchExecuteSchema = z.object({
40
- steps: z.array(batchStepSchema).min(1).describe("Array of steps to execute in sequence"),
40
+ steps: z.array(batchStepSchema).min(1).describe('Array of steps to execute in sequence. Recommended for form filling (multiple type→click), multi-step navigation, any workflow with 2+ known steps. Saves 90% tokens vs individual calls. Example: [{tool:"browser_navigate",arguments:{url:"https://example.com"}},{tool:"browser_type",arguments:{selectors:[{css:"#user"}],text:"john"}},{tool:"browser_click",arguments:{selectors:[{css:"#btn"}]}}]'),
41
41
  stopOnFirstError: z.boolean().optional().default(false).describe("Stop entire batch on first error"),
42
- globalExpectation: z.preprocess(parseJsonString, expectationSchema).optional().describe("Default expectation for all steps")
42
+ globalExpectation: z.preprocess(parseJsonString, expectationSchema).optional().describe('Default expectation for all steps. Recommended: {includeSnapshot:false,snapshotOptions:{selector:"#app"},diffOptions:{enabled:true}}. Per-step override with steps[].expectation')
43
43
  });
44
44
  export {
45
45
  batchStepSchema,
@@ -0,0 +1,106 @@
1
+ import { createRequire } from "node:module";
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __toESM = (mod, isNodeMode, target) => {
8
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
9
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
+ for (let key of __getOwnPropNames(mod))
11
+ if (!__hasOwnProp.call(to, key))
12
+ __defProp(to, key, {
13
+ get: () => mod[key],
14
+ enumerable: true
15
+ });
16
+ return to;
17
+ };
18
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
+
20
+ // src/types/html-inspection.ts
21
+ import { z } from "zod";
22
+ import { elementSelectorSchema } from "./selectors.js";
23
+ var htmlInspectionOptionsSchema = z.object({
24
+ selectors: z.array(elementSelectorSchema).min(1).describe("Array of element selectors to inspect"),
25
+ depth: z.number().min(1).max(10).optional().default(2).describe("Maximum hierarchy depth to extract"),
26
+ includeStyles: z.boolean().optional().default(false).describe("Include computed CSS styles"),
27
+ maxSize: z.number().min(1024).max(500000).optional().default(50000).describe("Maximum size in bytes (1KB-500KB)"),
28
+ format: z.enum(["html", "aria", "text"]).optional().default("html").describe("Output format"),
29
+ includeAttributes: z.boolean().optional().default(true).describe("Include element attributes"),
30
+ preserveWhitespace: z.boolean().optional().default(false).describe("Preserve whitespace in content"),
31
+ excludeSelector: z.string().optional().describe("CSS selector to exclude elements")
32
+ });
33
+ var HTMLInspectionError = {
34
+ SELECTOR_NOT_FOUND: "SELECTOR_NOT_FOUND",
35
+ SIZE_LIMIT_EXCEEDED: "SIZE_LIMIT_EXCEEDED",
36
+ EXTRACTION_TIMEOUT: "EXTRACTION_TIMEOUT",
37
+ INVALID_SELECTOR: "INVALID_SELECTOR",
38
+ DOM_ACCESS_ERROR: "DOM_ACCESS_ERROR"
39
+ };
40
+ function calculateHtmlSize(html) {
41
+ return new TextEncoder().encode(html).length;
42
+ }
43
+ function truncateHtml(html, maxSize) {
44
+ if (calculateHtmlSize(html) <= maxSize) {
45
+ return { html, truncated: false };
46
+ }
47
+ const truncated = html.substring(0, maxSize - 100);
48
+ const lastTag = truncated.lastIndexOf("<");
49
+ const safeHtml = lastTag > truncated.lastIndexOf(">") ? truncated.substring(0, lastTag) : truncated;
50
+ return { html: `${safeHtml}<!-- TRUNCATED -->`, truncated: true };
51
+ }
52
+ function validateHTMLInspectionOptions(options) {
53
+ return htmlInspectionOptionsSchema.parse(options);
54
+ }
55
+ function generateHTMLInspectionSuggestions(result) {
56
+ const suggestions = [];
57
+ if (result.truncated) {
58
+ suggestions.push("Content was truncated. Consider reducing depth or using more specific selectors.");
59
+ }
60
+ if (result.stats.selectorsNotFound > 0) {
61
+ suggestions.push("Some selectors did not match elements. Try using more specific or alternative selectors.");
62
+ }
63
+ if (result.timing.totalMs > 5000) {
64
+ suggestions.push("Inspection took longer than expected. Consider reducing scope or depth.");
65
+ }
66
+ if (result.stats.averageDepth > 5) {
67
+ suggestions.push("Deep element extraction detected. Consider limiting depth for better performance.");
68
+ }
69
+ return suggestions;
70
+ }
71
+ var HTMLInspectionUtils = {
72
+ calculateHtmlSize,
73
+ truncateHtml,
74
+ validateOptions: validateHTMLInspectionOptions,
75
+ generateSuggestions: generateHTMLInspectionSuggestions
76
+ };
77
+ var HTMLInspectionConstants = {
78
+ DEFAULT_MAX_SIZE: 50000,
79
+ DEFAULT_DEPTH: 2,
80
+ MAX_DEPTH: 10,
81
+ DEFAULT_TIMEOUT_MS: 1e4,
82
+ SIZE_THRESHOLDS: {
83
+ WARNING: 30000,
84
+ CRITICAL: 45000
85
+ },
86
+ COMMON_ARIA_PROPERTIES: [
87
+ "aria-label",
88
+ "aria-describedby",
89
+ "aria-hidden",
90
+ "aria-expanded",
91
+ "aria-selected",
92
+ "aria-checked",
93
+ "aria-disabled",
94
+ "aria-required"
95
+ ]
96
+ };
97
+ export {
98
+ validateHTMLInspectionOptions,
99
+ truncateHtml,
100
+ htmlInspectionOptionsSchema,
101
+ generateHTMLInspectionSuggestions,
102
+ calculateHtmlSize,
103
+ HTMLInspectionUtils,
104
+ HTMLInspectionError,
105
+ HTMLInspectionConstants
106
+ };
@@ -0,0 +1,126 @@
1
+ import { createRequire } from "node:module";
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __toESM = (mod, isNodeMode, target) => {
8
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
9
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
+ for (let key of __getOwnPropNames(mod))
11
+ if (!__hasOwnProp.call(to, key))
12
+ __defProp(to, key, {
13
+ get: () => mod[key],
14
+ enumerable: true
15
+ });
16
+ return to;
17
+ };
18
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
+
20
+ // src/types/selectors.ts
21
+ import { z } from "zod";
22
+ var refSelectorSchema = z.object({
23
+ ref: z.string().describe("System-generated element ID from previous tool results")
24
+ });
25
+ var roleSelectorSchema = z.object({
26
+ role: z.string().describe("ARIA role to match (e.g., button, textbox, link)"),
27
+ text: z.string().optional().describe("Optional text content to match within the role")
28
+ });
29
+ var cssSelectorSchema = z.object({
30
+ css: z.string().describe('CSS selector string (e.g., "#id", ".class", "button[type=submit]")')
31
+ });
32
+ var textSelectorSchema = z.object({
33
+ text: z.string().describe("Text content to search for"),
34
+ tag: z.string().optional().describe("Optional HTML tag to limit search scope")
35
+ });
36
+ var elementSelectorSchema = z.union([
37
+ refSelectorSchema,
38
+ roleSelectorSchema,
39
+ cssSelectorSchema,
40
+ textSelectorSchema
41
+ ]).describe("Element selector supporting ref, role, CSS, or text-based selection");
42
+ var SelectorConfidence = {
43
+ HIGH: 0.9,
44
+ MEDIUM: 0.7,
45
+ LOW: 0.5,
46
+ VERY_LOW: 0.3
47
+ };
48
+ var ResolutionStrategy = {
49
+ REF: "ref",
50
+ CSS_PARALLEL: "css_parallel",
51
+ ROLE_SEQUENTIAL: "role_sequential",
52
+ TEXT_FALLBACK: "text_fallback"
53
+ };
54
+ function isRefSelector(selector) {
55
+ return "ref" in selector;
56
+ }
57
+ function isRoleSelector(selector) {
58
+ return "role" in selector;
59
+ }
60
+ function isCSSSelector(selector) {
61
+ return "css" in selector;
62
+ }
63
+ function isTextSelector(selector) {
64
+ return "text" in selector && !("role" in selector);
65
+ }
66
+ function validateElementSelector(selector) {
67
+ return elementSelectorSchema.parse(selector);
68
+ }
69
+ function isValidSelector(selector) {
70
+ try {
71
+ elementSelectorSchema.parse(selector);
72
+ return true;
73
+ } catch {
74
+ return false;
75
+ }
76
+ }
77
+ var SelectorValidator = {
78
+ validateElementSelector,
79
+ isValidSelector
80
+ };
81
+ var SelectorPatterns = {
82
+ ARIA_ROLES: [
83
+ "button",
84
+ "textbox",
85
+ "link",
86
+ "checkbox",
87
+ "radio",
88
+ "combobox",
89
+ "listbox",
90
+ "option",
91
+ "tab",
92
+ "tabpanel",
93
+ "dialog",
94
+ "alert",
95
+ "menu",
96
+ "menuitem",
97
+ "table",
98
+ "row",
99
+ "cell",
100
+ "heading"
101
+ ],
102
+ CSS_PATTERNS: {
103
+ byId: (id) => `#${id}`,
104
+ byClass: (className) => `.${className}`,
105
+ byAttribute: (attr, value) => value ? `[${attr}="${value}"]` : `[${attr}]`,
106
+ byDataTestId: (testId) => `[data-testid="${testId}"]`,
107
+ byRole: (role) => `[role="${role}"]`
108
+ }
109
+ };
110
+ export {
111
+ validateElementSelector,
112
+ textSelectorSchema,
113
+ roleSelectorSchema,
114
+ refSelectorSchema,
115
+ isValidSelector,
116
+ isTextSelector,
117
+ isRoleSelector,
118
+ isRefSelector,
119
+ isCSSSelector,
120
+ elementSelectorSchema,
121
+ cssSelectorSchema,
122
+ SelectorValidator,
123
+ SelectorPatterns,
124
+ SelectorConfidence,
125
+ ResolutionStrategy
126
+ };