@rickcedwhat/playwright-smart-table 3.1.0 → 4.0.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.
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.ColumnStrategies = exports.CellNavigationStrategies = void 0;
13
+ exports.CellNavigationStrategies = {
14
+ /**
15
+ * Default strategy: Assumes column is accessible or standard scrolling works.
16
+ * No specific action taken other than what Playwright's default locator handling does.
17
+ */
18
+ default: () => __awaiter(void 0, void 0, void 0, function* () {
19
+ // No-op
20
+ }),
21
+ /**
22
+ * Strategy that clicks into the table to establish focus and then uses the Right Arrow key
23
+ * to navigate to the target CELL (navigates down to the row, then right to the column).
24
+ *
25
+ * Useful for canvas-based grids like Glide where DOM scrolling might not be enough for interaction
26
+ * or where keyboard navigation is the primary way to move focus.
27
+ */
28
+ keyboard: (context) => __awaiter(void 0, void 0, void 0, function* () {
29
+ const { root, page, index, rowLocator, rowIndex } = context;
30
+ if (typeof rowIndex !== 'number') {
31
+ throw new Error('Row index is required for keyboard navigation');
32
+ }
33
+ yield root.focus();
34
+ yield page.waitForTimeout(100);
35
+ // Robust Navigation:
36
+ // 1. Jump to Top-Left (Reset) - Sequence for Cross-OS (Mac/Windows)
37
+ yield page.keyboard.press('Control+Home');
38
+ yield page.keyboard.press('Meta+ArrowUp'); // Mac Go-To-Top
39
+ yield page.keyboard.press('Home'); // Ensure start of row
40
+ yield page.waitForTimeout(150);
41
+ // 2. Move Down to Target Row
42
+ for (let i = 0; i < rowIndex; i++) {
43
+ yield page.keyboard.press('ArrowDown');
44
+ }
45
+ // 3. Move Right to Target Column
46
+ for (let i = 0; i < index; i++) {
47
+ yield page.keyboard.press('ArrowRight');
48
+ }
49
+ yield page.waitForTimeout(50);
50
+ })
51
+ };
52
+ // Backwards compatibility - deprecated
53
+ /** @deprecated Use CellNavigationStrategies instead */
54
+ exports.ColumnStrategies = exports.CellNavigationStrategies;
@@ -0,0 +1,7 @@
1
+ import type { FillStrategy } from '../types';
2
+ export declare const FillStrategies: {
3
+ /**
4
+ * Default strategy: Detects input type and fills accordingly (Text, Select, Checkbox, ContentEditable).
5
+ */
6
+ default: ({ row, columnName, value, fillOptions }: Parameters<FillStrategy>[0]) => Promise<void>;
7
+ };
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.FillStrategies = void 0;
13
+ exports.FillStrategies = {
14
+ /**
15
+ * Default strategy: Detects input type and fills accordingly (Text, Select, Checkbox, ContentEditable).
16
+ */
17
+ default: (_a) => __awaiter(void 0, [_a], void 0, function* ({ row, columnName, value, fillOptions }) {
18
+ var _b;
19
+ const cell = row.getCell(columnName);
20
+ // Use custom input mapper for this column if provided, otherwise auto-detect
21
+ let inputLocator;
22
+ if ((_b = fillOptions === null || fillOptions === void 0 ? void 0 : fillOptions.inputMappers) === null || _b === void 0 ? void 0 : _b[columnName]) {
23
+ inputLocator = fillOptions.inputMappers[columnName](cell);
24
+ }
25
+ else {
26
+ // Auto-detect input type
27
+ // Check for text input
28
+ const textInput = cell.locator('input[type="text"], input:not([type]), textarea').first();
29
+ const textInputCount = yield textInput.count().catch(() => 0);
30
+ // Check for select
31
+ const select = cell.locator('select').first();
32
+ const selectCount = yield select.count().catch(() => 0);
33
+ // Check for checkbox/radio
34
+ const checkbox = cell.locator('input[type="checkbox"], input[type="radio"], [role="checkbox"]').first();
35
+ const checkboxCount = yield checkbox.count().catch(() => 0);
36
+ // Check for contenteditable or div-based inputs
37
+ const contentEditable = cell.locator('[contenteditable="true"]').first();
38
+ const contentEditableCount = yield contentEditable.count().catch(() => 0);
39
+ // Determine which input to use (prioritize by commonality)
40
+ if (textInputCount > 0 && selectCount === 0 && checkboxCount === 0) {
41
+ inputLocator = textInput;
42
+ }
43
+ else if (selectCount > 0) {
44
+ inputLocator = select;
45
+ }
46
+ else if (checkboxCount > 0) {
47
+ inputLocator = checkbox;
48
+ }
49
+ else if (contentEditableCount > 0) {
50
+ inputLocator = contentEditable;
51
+ }
52
+ else if (textInputCount > 0) {
53
+ // Fallback to text input even if others exist
54
+ inputLocator = textInput;
55
+ }
56
+ else {
57
+ // No input found - try to click the cell itself (might trigger an editor)
58
+ inputLocator = cell;
59
+ }
60
+ }
61
+ // Fill based on value type and input type
62
+ const inputTag = yield inputLocator.evaluate((el) => el.tagName.toLowerCase()).catch(() => 'unknown');
63
+ const inputType = yield inputLocator.getAttribute('type').catch(() => null);
64
+ const isContentEditable = yield inputLocator.getAttribute('contenteditable').catch(() => null);
65
+ // console.log(`[SmartTable] Filling "${columnName}" with value "${value}" (input: ${inputTag}, type: ${inputType})`);
66
+ if (inputType === 'checkbox' || inputType === 'radio') {
67
+ // Boolean value for checkbox/radio
68
+ const shouldBeChecked = Boolean(value);
69
+ const isChecked = yield inputLocator.isChecked().catch(() => false);
70
+ if (isChecked !== shouldBeChecked) {
71
+ yield inputLocator.click();
72
+ }
73
+ }
74
+ else if (inputTag === 'select') {
75
+ // Select dropdown
76
+ yield inputLocator.selectOption(String(value));
77
+ }
78
+ else if (isContentEditable === 'true') {
79
+ // Contenteditable div
80
+ yield inputLocator.click();
81
+ yield inputLocator.fill(String(value));
82
+ }
83
+ else {
84
+ // Text input, textarea, or generic
85
+ yield inputLocator.fill(String(value));
86
+ }
87
+ })
88
+ };
@@ -0,0 +1,29 @@
1
+ import { StrategyContext } from '../types';
2
+ /**
3
+ * Defines the contract for a header retrieval strategy.
4
+ * Returns a list of unique header names found in the table.
5
+ */
6
+ export type HeaderStrategy = (context: StrategyContext) => Promise<string[]>;
7
+ export declare const HeaderStrategies: {
8
+ /**
9
+ * Default strategy: Returns only the headers currently visible in the DOM.
10
+ * This is fast but won't find virtualized columns off-screen.
11
+ */
12
+ visible: ({ config, resolve, root }: StrategyContext) => Promise<string[]>;
13
+ /**
14
+ * Scans for headers by finding a scrollable container and setting scrollLeft.
15
+ */
16
+ scrollRight: (context: StrategyContext, options?: {
17
+ limit?: number;
18
+ selector?: string;
19
+ scrollAmount?: number;
20
+ }) => Promise<string[]>;
21
+ /**
22
+ * Strategy that clicks into the table to establish focus and then uses the Right Arrow key
23
+ * to navigate cell-by-cell, collecting headers found along the way.
24
+ */
25
+ keyboard: (context: StrategyContext, options?: {
26
+ limit?: number;
27
+ maxSilentClicks?: number;
28
+ }) => Promise<string[]>;
29
+ };
@@ -0,0 +1,142 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.HeaderStrategies = void 0;
13
+ exports.HeaderStrategies = {
14
+ /**
15
+ * Default strategy: Returns only the headers currently visible in the DOM.
16
+ * This is fast but won't find virtualized columns off-screen.
17
+ */
18
+ visible: (_a) => __awaiter(void 0, [_a], void 0, function* ({ config, resolve, root }) {
19
+ const headerLoc = resolve(config.headerSelector, root);
20
+ try {
21
+ // Wait for at least one header to be visible
22
+ yield headerLoc.first().waitFor({ state: 'visible', timeout: 3000 });
23
+ }
24
+ catch (e) {
25
+ // Ignore hydration/timeout issues, return what we have
26
+ }
27
+ const texts = yield headerLoc.allInnerTexts();
28
+ return texts.map(t => t.trim());
29
+ }),
30
+ /**
31
+ * Scans for headers by finding a scrollable container and setting scrollLeft.
32
+ */
33
+ scrollRight: (context, options) => __awaiter(void 0, void 0, void 0, function* () {
34
+ var _a, _b;
35
+ const { resolve, config, root, page } = context;
36
+ const limit = (_a = options === null || options === void 0 ? void 0 : options.limit) !== null && _a !== void 0 ? _a : 20;
37
+ const scrollAmount = (_b = options === null || options === void 0 ? void 0 : options.scrollAmount) !== null && _b !== void 0 ? _b : 300;
38
+ const collectedHeaders = new Set();
39
+ const getVisible = () => __awaiter(void 0, void 0, void 0, function* () {
40
+ const headerLoc = resolve(config.headerSelector, root);
41
+ const texts = yield headerLoc.allInnerTexts();
42
+ return texts.map(t => t.trim());
43
+ });
44
+ // Initial capture
45
+ let currentHeaders = yield getVisible();
46
+ currentHeaders.forEach(h => collectedHeaders.add(h));
47
+ // Find scroller using JS for better iframe/shadow support
48
+ const scrollerHandle = yield root.evaluateHandle((el, selector) => {
49
+ if (selector && el.matches(selector))
50
+ return el;
51
+ const effectiveSelector = selector || '.dvn-scroller';
52
+ const ancestor = el.closest(effectiveSelector);
53
+ if (ancestor)
54
+ return ancestor;
55
+ return document.querySelector(effectiveSelector);
56
+ }, options === null || options === void 0 ? void 0 : options.selector);
57
+ const isScrollerFound = yield scrollerHandle.evaluate(el => !!el);
58
+ if (isScrollerFound) {
59
+ yield scrollerHandle.evaluate(el => el.scrollLeft = 0);
60
+ yield page.waitForTimeout(200);
61
+ for (let i = 0; i < limit; i++) {
62
+ const sizeBefore = collectedHeaders.size;
63
+ yield scrollerHandle.evaluate((el, amount) => el.scrollLeft += amount, scrollAmount);
64
+ yield page.waitForTimeout(300);
65
+ const newHeaders = yield getVisible();
66
+ newHeaders.forEach(h => collectedHeaders.add(h));
67
+ if (collectedHeaders.size === sizeBefore) {
68
+ yield scrollerHandle.evaluate((el, amount) => el.scrollLeft += amount, scrollAmount);
69
+ yield page.waitForTimeout(300);
70
+ const retryHeaders = yield getVisible();
71
+ retryHeaders.forEach(h => collectedHeaders.add(h));
72
+ if (collectedHeaders.size === sizeBefore)
73
+ break;
74
+ }
75
+ }
76
+ }
77
+ else {
78
+ console.warn("HeaderStrategies.scrollRight: Could not find scroller. Returning visible headers.");
79
+ }
80
+ // Scroll back to start
81
+ yield scrollerHandle.evaluate(el => el.scrollLeft = 0);
82
+ yield page.waitForTimeout(200);
83
+ return Array.from(collectedHeaders);
84
+ }),
85
+ /**
86
+ * Strategy that clicks into the table to establish focus and then uses the Right Arrow key
87
+ * to navigate cell-by-cell, collecting headers found along the way.
88
+ */
89
+ keyboard: (context, options) => __awaiter(void 0, void 0, void 0, function* () {
90
+ var _a, _b;
91
+ const { resolve, config, root, page } = context;
92
+ const limit = (_a = options === null || options === void 0 ? void 0 : options.limit) !== null && _a !== void 0 ? _a : 100;
93
+ const maxSilentClicks = (_b = options === null || options === void 0 ? void 0 : options.maxSilentClicks) !== null && _b !== void 0 ? _b : 10;
94
+ const collectedHeaders = new Set();
95
+ const getVisible = () => __awaiter(void 0, void 0, void 0, function* () {
96
+ const headerLoc = resolve(config.headerSelector, root);
97
+ const texts = yield headerLoc.allInnerTexts();
98
+ return texts.map(t => t.trim());
99
+ });
100
+ // 1. Initial capture
101
+ let currentHeaders = yield getVisible();
102
+ currentHeaders.forEach(h => collectedHeaders.add(h));
103
+ // 2. Click to focus
104
+ // Try to find the canvas sibling specifically for Glide, otherwise click root
105
+ const canvas = root.locator('xpath=ancestor::div').locator('canvas').first();
106
+ if ((yield canvas.count()) > 0) {
107
+ // Click lower in the canvas to hit a data cell instead of header
108
+ // Adjusted to y=60 to target Row 1
109
+ yield canvas.click({ position: { x: 50, y: 60 }, force: true }).catch(() => { });
110
+ }
111
+ else {
112
+ yield root.click({ position: { x: 10, y: 10 }, force: true }).catch(() => { });
113
+ }
114
+ // Reset to home
115
+ yield page.keyboard.press('Control+Home');
116
+ yield page.keyboard.press('Home');
117
+ // Wait for potential scroll/focus reset
118
+ yield page.evaluate(() => new Promise(requestAnimationFrame));
119
+ currentHeaders = yield getVisible();
120
+ currentHeaders.forEach(h => collectedHeaders.add(h));
121
+ // 3. Navigate right loop
122
+ let silentCounter = 0;
123
+ for (let i = 0; i < limit; i++) {
124
+ const sizeBefore = collectedHeaders.size;
125
+ yield page.keyboard.press('ArrowRight');
126
+ // Small breathing room for key press to register
127
+ yield page.evaluate(() => new Promise(requestAnimationFrame));
128
+ const newHeaders = yield getVisible();
129
+ newHeaders.forEach(h => collectedHeaders.add(h));
130
+ if (collectedHeaders.size === sizeBefore) {
131
+ silentCounter++;
132
+ }
133
+ else {
134
+ silentCounter = 0;
135
+ }
136
+ if (silentCounter >= maxSilentClicks) {
137
+ break;
138
+ }
139
+ }
140
+ return Array.from(collectedHeaders);
141
+ }),
142
+ };
@@ -1,2 +1,55 @@
1
1
  export * from './pagination';
2
2
  export * from './sorting';
3
+ export * from './columns';
4
+ export * from './headers';
5
+ export * from './fill';
6
+ export * from './resolution';
7
+ export declare const Strategies: {
8
+ Pagination: {
9
+ clickNext: (nextButtonSelector: import("..").Selector, timeout?: number) => import("..").PaginationStrategy;
10
+ clickLoadMore: (buttonSelector: import("..").Selector, timeout?: number) => import("..").PaginationStrategy;
11
+ infiniteScroll: (timeout?: number) => import("..").PaginationStrategy;
12
+ };
13
+ Sorting: {
14
+ AriaSort: () => import("..").SortingStrategy;
15
+ };
16
+ Column: {
17
+ default: () => Promise<void>;
18
+ keyboard: (context: import("..").StrategyContext & {
19
+ column: string;
20
+ index: number;
21
+ rowIndex?: number;
22
+ }) => Promise<void>;
23
+ };
24
+ CellNavigation: {
25
+ default: () => Promise<void>;
26
+ keyboard: (context: import("..").StrategyContext & {
27
+ column: string;
28
+ index: number;
29
+ rowIndex?: number;
30
+ }) => Promise<void>;
31
+ };
32
+ Header: {
33
+ visible: ({ config, resolve, root }: import("..").StrategyContext) => Promise<string[]>;
34
+ scrollRight: (context: import("..").StrategyContext, options?: {
35
+ limit?: number;
36
+ selector?: string;
37
+ scrollAmount?: number;
38
+ }) => Promise<string[]>;
39
+ keyboard: (context: import("..").StrategyContext, options?: {
40
+ limit?: number;
41
+ maxSilentClicks?: number;
42
+ }) => Promise<string[]>;
43
+ };
44
+ Fill: {
45
+ default: ({ row, columnName, value, fillOptions }: Parameters<import("..").FillStrategy>[0]) => Promise<void>;
46
+ };
47
+ Resolution: {
48
+ default: import("./resolution").ColumnResolutionStrategy;
49
+ };
50
+ DeprecatedPagination: {
51
+ clickNext: (nextButtonSelector: import("..").Selector, timeout?: number) => import("..").PaginationStrategy;
52
+ clickLoadMore: (buttonSelector: import("..").Selector, timeout?: number) => import("..").PaginationStrategy;
53
+ infiniteScroll: (timeout?: number) => import("..").PaginationStrategy;
54
+ };
55
+ };
@@ -14,6 +14,27 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- // src/strategies/index.ts
17
+ exports.Strategies = void 0;
18
+ const pagination_1 = require("./pagination");
19
+ const sorting_1 = require("./sorting");
20
+ const columns_1 = require("./columns");
21
+ const headers_1 = require("./headers");
22
+ const fill_1 = require("./fill");
23
+ const resolution_1 = require("./resolution");
18
24
  __exportStar(require("./pagination"), exports);
19
25
  __exportStar(require("./sorting"), exports);
26
+ __exportStar(require("./columns"), exports);
27
+ __exportStar(require("./headers"), exports);
28
+ __exportStar(require("./fill"), exports);
29
+ __exportStar(require("./resolution"), exports);
30
+ exports.Strategies = {
31
+ Pagination: pagination_1.PaginationStrategies,
32
+ Sorting: sorting_1.SortingStrategies,
33
+ Column: columns_1.ColumnStrategies,
34
+ CellNavigation: columns_1.CellNavigationStrategies,
35
+ Header: headers_1.HeaderStrategies,
36
+ Fill: fill_1.FillStrategies,
37
+ Resolution: resolution_1.ResolutionStrategies,
38
+ // Alias for backward compatibility if needed, though we are encouraging the new structure
39
+ DeprecatedPagination: pagination_1.DeprecatedPaginationStrategies
40
+ };
@@ -16,7 +16,7 @@ export declare const PaginationStrategies: {
16
16
  /**
17
17
  * @deprecated Use `PaginationStrategies` instead. This alias will be removed in a future major version.
18
18
  */
19
- export declare const TableStrategies: {
19
+ export declare const DeprecatedPaginationStrategies: {
20
20
  /**
21
21
  * Strategy: Clicks a "Next" button and waits for the first row of data to change.
22
22
  */
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.TableStrategies = exports.PaginationStrategies = void 0;
12
+ exports.DeprecatedPaginationStrategies = exports.PaginationStrategies = void 0;
13
13
  const utils_1 = require("../utils");
14
14
  exports.PaginationStrategies = {
15
15
  /**
@@ -69,4 +69,4 @@ exports.PaginationStrategies = {
69
69
  /**
70
70
  * @deprecated Use `PaginationStrategies` instead. This alias will be removed in a future major version.
71
71
  */
72
- exports.TableStrategies = exports.PaginationStrategies;
72
+ exports.DeprecatedPaginationStrategies = exports.PaginationStrategies;
@@ -0,0 +1,22 @@
1
+ import { StrategyContext } from '../types';
2
+ export interface ColumnResolutionStrategy {
3
+ /**
4
+ * Resolves a column name (string or Regex) to a column index.
5
+ * Returns undefined if not found.
6
+ */
7
+ resolveIndex(options: {
8
+ query: string | RegExp;
9
+ headerMap: Map<string, number>;
10
+ context: StrategyContext;
11
+ }): number | undefined;
12
+ /**
13
+ * Resolves a column name to a clean string name (for error messages or debugging).
14
+ */
15
+ resolveName(options: {
16
+ query: string | RegExp;
17
+ headerMap: Map<string, number>;
18
+ }): string;
19
+ }
20
+ export declare const ResolutionStrategies: {
21
+ default: ColumnResolutionStrategy;
22
+ };
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ResolutionStrategies = void 0;
4
+ exports.ResolutionStrategies = {
5
+ default: {
6
+ resolveIndex: ({ query, headerMap }) => {
7
+ // 1. Exact / String Match
8
+ if (typeof query === 'string') {
9
+ if (headerMap.has(query))
10
+ return headerMap.get(query);
11
+ }
12
+ // 2. Regex Match
13
+ if (query instanceof RegExp) {
14
+ for (const [colName, idx] of headerMap.entries()) {
15
+ if (query.test(colName))
16
+ return idx;
17
+ }
18
+ return undefined;
19
+ }
20
+ // 3. (Optional) Fuzzy String Match fallback could go here
21
+ // But for strict default strategy, we might want to keep it simple first
22
+ // The original code didn't do fuzzy *resolution* logic inside the get(), it just did strict get().
23
+ // The fuzzy logic was only for *suggestions* on error.
24
+ return undefined;
25
+ },
26
+ resolveName: ({ query }) => {
27
+ return query.toString();
28
+ }
29
+ }
30
+ };
@@ -3,4 +3,4 @@
3
3
  * This file is generated by scripts/embed-types.js
4
4
  * It contains the raw text of types.ts to provide context for LLM prompts.
5
5
  */
6
- export declare const TYPE_CONTEXT = "\nexport type Selector = string | ((root: Locator | Page) => Locator);\n\nexport type SmartRow = Locator & {\n getCell(column: string): Locator;\n toJSON(): Promise<Record<string, string>>;\n /**\n * Fills the row with data. Automatically detects input types (text input, select, checkbox, etc.).\n */\n smartFill: (data: Record<string, any>, options?: FillOptions) => Promise<void>;\n};\n\nexport type StrategyContext = TableContext;\n\n/**\n * Defines the contract for a sorting strategy.\n */\nexport interface SortingStrategy {\n /**\n * Performs the sort action on a column.\n */\n doSort(options: {\n columnName: string;\n direction: 'asc' | 'desc';\n context: StrategyContext;\n }): Promise<void>;\n\n /**\n * Retrieves the current sort state of a column.\n */\n getSortState(options: {\n columnName: string;\n context: StrategyContext;\n }): Promise<'asc' | 'desc' | 'none'>;\n}\n\nexport interface TableContext {\n root: Locator;\n config: FinalTableConfig;\n page: Page;\n resolve: (selector: Selector, parent: Locator | Page) => Locator;\n}\n\nexport type PaginationStrategy = (context: TableContext) => Promise<boolean>;\n\nexport type DedupeStrategy = (row: SmartRow) => string | number | Promise<string | number>;\n\nexport interface PromptOptions {\n /**\n * Output Strategy:\n * - 'error': Throws an error with the prompt (useful for platforms that capture error output cleanly).\n * - 'console': Standard console logs (Default).\n */\n output?: 'console' | 'error';\n includeTypes?: boolean;\n}\n\nexport interface TableConfig {\n rowSelector?: Selector;\n headerSelector?: Selector;\n cellSelector?: Selector;\n pagination?: PaginationStrategy;\n sorting?: SortingStrategy;\n maxPages?: number;\n /**\n * Hook to rename columns dynamically.\n * * @param args.text - The default innerText of the header.\n * @param args.index - The column index.\n * @param args.locator - The specific header cell locator.\n */\n headerTransformer?: (args: { text: string, index: number, locator: Locator }) => string | Promise<string>;\n autoScroll?: boolean;\n /**\n * Enable debug mode to log internal state to console.\n */\n debug?: boolean;\n /**\n * Strategy to reset the table to the initial page.\n * Called when table.reset() is invoked.\n */\n onReset?: (context: TableContext) => Promise<void>;\n}\n\n/**\n * Represents the final, resolved table configuration after default values have been applied.\n * All optional properties from TableConfig are now required, except for `sorting`.\n */\nexport type FinalTableConfig = Required<Omit<TableConfig, 'sorting'>> & {\n sorting?: SortingStrategy;\n};\n\nexport interface FillOptions {\n /**\n * Custom input mappers for specific columns.\n * Maps column names to functions that return the input locator for that cell.\n * Columns not specified here will use auto-detection.\n */\n inputMappers?: Record<string, (cell: Locator) => Locator>;\n}\n\nexport interface TableResult {\n /**\n * Initializes the table by resolving headers. Must be called before using sync methods.\n * @param options Optional timeout for header resolution (default: 3000ms)\n */\n init(options?: { timeout?: number }): Promise<TableResult>;\n\n getHeaders: () => Promise<string[]>;\n getHeaderCell: (columnName: string) => Promise<Locator>;\n\n /**\n * Finds a row on the current page only. Returns immediately (sync).\n * Throws error if table is not initialized.\n */\n getByRow: (\n filters: Record<string, string | RegExp | number>, \n options?: { exact?: boolean }\n ) => SmartRow;\n\n /**\n * Searches for a row across all available data using the configured strategy (pagination, scroll, etc.).\n * Auto-initializes if needed.\n */\n searchForRow: (\n filters: Record<string, string | RegExp | number>, \n options?: { exact?: boolean, maxPages?: number }\n ) => Promise<SmartRow>;\n\n getAllRows: <T extends { asJSON?: boolean }>(\n options?: { filter?: Record<string, any>, exact?: boolean } & T\n ) => Promise<T['asJSON'] extends true ? Record<string, string>[] : SmartRow[]>;\n\n generateConfigPrompt: (options?: PromptOptions) => Promise<void>;\n generateStrategyPrompt: (options?: PromptOptions) => Promise<void>;\n\n /**\n * Resets the table state (clears cache, flags) and invokes the onReset strategy.\n */\n reset: () => Promise<void>;\n\n /**\n * Scans a specific column across all pages and returns the values.\n */\n getColumnValues: <V = string>(column: string, options?: { mapper?: (cell: Locator) => Promise<V> | V, maxPages?: number }) => Promise<V[]>;\n\n /**\n * Provides access to sorting actions and assertions.\n */\n sorting: {\n /**\n * Applies the configured sorting strategy to the specified column.\n * @param columnName The name of the column to sort.\n * @param direction The direction to sort ('asc' or 'desc').\n */\n apply(columnName: string, direction: 'asc' | 'desc'): Promise<void>;\n /**\n * Gets the current sort state of a column using the configured sorting strategy.\n * @param columnName The name of the column to check.\n * @returns A promise that resolves to 'asc', 'desc', or 'none'.\n */\n getState(columnName: string): Promise<'asc' | 'desc' | 'none'>;\n };\n\n /**\n * Iterates through paginated table data, calling the callback for each iteration.\n * Callback return values are automatically appended to allData, which is returned.\n */\n iterateThroughTable: <T = any>(\n callback: (context: {\n index: number;\n isFirst: boolean;\n isLast: boolean;\n rows: SmartRow[];\n allData: T[];\n table: RestrictedTableResult;\n }) => T | Promise<T>,\n options?: {\n pagination?: PaginationStrategy;\n dedupeStrategy?: DedupeStrategy;\n maxIterations?: number;\n getIsFirst?: (context: { index: number }) => boolean;\n getIsLast?: (context: { index: number, paginationResult: boolean }) => boolean;\n onFirst?: (context: { index: number, rows: SmartRow[], allData: any[] }) => void | Promise<void>;\n onLast?: (context: { index: number, rows: SmartRow[], allData: any[] }) => void | Promise<void>;\n }\n ) => Promise<T[]>;\n}\n\n/**\n * Restricted table result that excludes methods that shouldn't be called during iteration.\n */\nexport type RestrictedTableResult = Omit<TableResult, 'searchForRow' | 'iterateThroughTable' | 'reset'>;\n";
6
+ export declare const TYPE_CONTEXT = "\nexport type Selector = string | ((root: Locator | Page) => Locator);\n\n/**\n * Function to get a cell locator given row, column info.\n * Replaces the old cellResolver.\n */\nexport type GetCellLocatorFn = (args: {\n row: Locator;\n columnName: string;\n columnIndex: number;\n rowIndex?: number;\n page: Page;\n}) => Locator;\n\n/**\n * Function to get the currently active/focused cell.\n * Returns null if no cell is active.\n */\nexport type GetActiveCellFn = (args: TableContext) => Promise<{\n rowIndex: number;\n columnIndex: number;\n columnName?: string;\n locator: Locator;\n} | null>;\n\n\nexport type SmartRow<T = any> = Locator & {\n getRequestIndex(): number | undefined;\n rowIndex?: number;\n getCell(column: string): Locator;\n toJSON(options?: { columns?: string[] }): Promise<T>;\n /**\n * Scrolls/paginates to bring this row into view.\n * Only works if rowIndex is known.\n */\n bringIntoView(): Promise<void>;\n /**\n * Fills the row with data. Automatically detects input types.\n */\n fill: (data: Partial<T> | Record<string, any>, options?: FillOptions) => Promise<void>;\n /**\n * Alias for fill() to avoid conflict with Locator.fill()\n */\n smartFill: (data: Partial<T> | Record<string, any>, options?: FillOptions) => Promise<void>;\n};\n\nexport type StrategyContext = TableContext & { rowLocator?: Locator; rowIndex?: number };\n\n/**\n * Defines the contract for a sorting strategy.\n */\nexport interface SortingStrategy {\n /**\n * Performs the sort action on a column.\n */\n doSort(options: {\n columnName: string;\n direction: 'asc' | 'desc';\n context: StrategyContext;\n }): Promise<void>;\n\n /**\n * Retrieves the current sort state of a column.\n */\n getSortState(options: {\n columnName: string;\n context: StrategyContext;\n }): Promise<'asc' | 'desc' | 'none'>;\n}\n\nexport interface TableContext {\n root: Locator;\n config: FinalTableConfig;\n page: Page;\n resolve: (selector: Selector, parent: Locator | Page) => Locator;\n}\n\nexport type PaginationStrategy = (context: TableContext) => Promise<boolean>;\n\nexport type DedupeStrategy = (row: SmartRow) => string | number | Promise<string | number>;\n\nexport interface PromptOptions {\n /**\n * Output Strategy:\n * - 'error': Throws an error with the prompt (useful for platforms that capture error output cleanly).\n * - 'console': Standard console logs (Default).\n */\n output?: 'console' | 'error';\n includeTypes?: boolean;\n}\n\nexport type FillStrategy = (options: {\n row: SmartRow;\n columnName: string;\n value: any;\n index: number;\n page: Page;\n rootLocator: Locator;\n table: TableResult; // The parent table instance\n fillOptions?: FillOptions;\n}) => Promise<void>;\n\nexport type { HeaderStrategy } from './strategies/headers';\nexport type { CellNavigationStrategy } from './strategies/columns';\n\n/**\n * Strategy to resolve column names (string or regex) to their index.\n */\nexport type { ColumnResolutionStrategy } from './strategies/resolution';\n\n/**\n * Strategy to filter rows based on criteria.\n */\nexport interface FilterStrategy {\n apply(options: {\n rows: Locator;\n filter: { column: string, value: string | RegExp | number };\n colIndex: number;\n tableContext: TableContext;\n }): Locator;\n}\n\n/**\n * Organized container for all table interaction strategies.\n */\nexport interface TableStrategies {\n /** Strategy for discovering/scanning headers */\n header?: HeaderStrategy;\n /** Strategy for navigating to specific cells (row + column) */\n cellNavigation?: CellNavigationStrategy;\n /** Strategy for filling form inputs */\n fill?: FillStrategy;\n /** Strategy for paginating through data */\n pagination?: PaginationStrategy;\n /** Strategy for sorting columns */\n sorting?: SortingStrategy;\n /** Function to get a cell locator */\n getCellLocator?: GetCellLocatorFn;\n /** Function to get the currently active/focused cell */\n getActiveCell?: GetActiveCellFn;\n}\n\n/**\n * Configuration options for useTable.\n */\nexport interface TableConfig {\n /** Selector for the table headers */\n headerSelector?: string;\n /** Selector for the table rows */\n rowSelector?: string;\n /** Selector for the cells within a row */\n cellSelector?: string;\n /** Number of pages to scan for verification */\n maxPages?: number;\n /** Hook to rename columns dynamically */\n headerTransformer?: (args: { text: string, index: number, locator: Locator }) => string | Promise<string>;\n /** Automatically scroll to table on init */\n autoScroll?: boolean;\n /** Enable debug logs */\n debug?: boolean;\n /** Reset hook */\n onReset?: (context: TableContext) => Promise<void>;\n /** All interaction strategies */\n strategies?: TableStrategies;\n}\n\nexport interface FinalTableConfig extends TableConfig {\n headerSelector: string;\n rowSelector: string;\n cellSelector: string;\n maxPages: number;\n autoScroll: boolean;\n debug: boolean;\n headerTransformer: (args: { text: string, index: number, locator: Locator }) => string | Promise<string>;\n onReset: (context: TableContext) => Promise<void>;\n strategies: TableStrategies;\n}\n\n\nexport interface FillOptions {\n /**\n * Custom input mappers for specific columns.\n * Maps column names to functions that return the input locator for that cell.\n */\n inputMappers?: Record<string, (cell: Locator) => Locator>;\n}\n\nexport interface TableResult<T = any> {\n /**\n * Initializes the table by resolving headers. Must be called before using sync methods.\n * @param options Optional timeout for header resolution (default: 3000ms)\n */\n init(options?: { timeout?: number }): Promise<TableResult>;\n\n getHeaders: () => Promise<string[]>;\n getHeaderCell: (columnName: string) => Promise<Locator>;\n\n /**\n * Finds a row by filters on the current page only. Returns immediately (sync).\n * Throws error if table is not initialized.\n */\n getByRow: (\n filters: Record<string, string | RegExp | number>,\n options?: { exact?: boolean }\n ) => SmartRow;\n\n /**\n * Gets a row by 1-based index on the current page.\n * Throws error if table is not initialized.\n * @param index 1-based row index\n * @param options Optional settings including bringIntoView\n */\n getByRowIndex: (\n index: number,\n options?: { bringIntoView?: boolean }\n ) => SmartRow;\n\n /**\n * Searches for a row across all available data using the configured strategy (pagination, scroll, etc.).\n * Auto-initializes if needed.\n */\n searchForRow: (\n filters: Record<string, string | RegExp | number>,\n options?: { exact?: boolean, maxPages?: number }\n ) => Promise<SmartRow>;\n\n /**\n * Navigates to a specific column using the configured CellNavigationStrategy.\n */\n scrollToColumn: (columnName: string) => Promise<void>;\n\n getAllCurrentRows: <T extends { asJSON?: boolean }>(\n options?: { filter?: Record<string, any>, exact?: boolean } & T\n ) => Promise<T['asJSON'] extends true ? Record<string, string>[] : SmartRow[]>;\n\n /**\n * @deprecated Use getAllCurrentRows instead. This method will be removed in a future major version.\n */\n getAllRows: <T extends { asJSON?: boolean }>(\n options?: { filter?: Record<string, any>, exact?: boolean } & T\n ) => Promise<T['asJSON'] extends true ? Record<string, string>[] : SmartRow[]>;\n\n generateConfigPrompt: (options?: PromptOptions) => Promise<void>;\n generateStrategyPrompt: (options?: PromptOptions) => Promise<void>;\n\n /**\n * Resets the table state (clears cache, flags) and invokes the onReset strategy.\n */\n reset: () => Promise<void>;\n\n /**\n * Revalidates the table's structure (headers, columns) without resetting pagination or state.\n * Useful when columns change visibility or order dynamically.\n */\n revalidate: () => Promise<void>;\n\n /**\n * Scans a specific column across all pages and returns the values.\n */\n getColumnValues: <V = string>(column: string, options?: { mapper?: (cell: Locator) => Promise<V> | V, maxPages?: number }) => Promise<V[]>;\n\n /**\n * Provides access to sorting actions and assertions.\n */\n sorting: {\n /**\n * Applies the configured sorting strategy to the specified column.\n * @param columnName The name of the column to sort.\n * @param direction The direction to sort ('asc' or 'desc').\n */\n apply(columnName: string, direction: 'asc' | 'desc'): Promise<void>;\n /**\n * Gets the current sort state of a column using the configured sorting strategy.\n * @param columnName The name of the column to check.\n * @returns A promise that resolves to 'asc', 'desc', or 'none'.\n */\n getState(columnName: string): Promise<'asc' | 'desc' | 'none'>;\n };\n\n /**\n * Iterates through paginated table data, calling the callback for each iteration.\n * Callback return values are automatically appended to allData, which is returned.\n */\n iterateThroughTable: <T = any>(\n callback: (context: {\n index: number;\n isFirst: boolean;\n isLast: boolean;\n rows: SmartRow[];\n allData: T[];\n table: RestrictedTableResult;\n }) => T | Promise<T>,\n options?: {\n pagination?: PaginationStrategy;\n dedupeStrategy?: DedupeStrategy;\n maxIterations?: number;\n getIsFirst?: (context: { index: number }) => boolean;\n getIsLast?: (context: { index: number, paginationResult: boolean }) => boolean;\n onFirst?: (context: { index: number, rows: SmartRow[], allData: any[] }) => void | Promise<void>;\n onLast?: (context: { index: number, rows: SmartRow[], allData: any[] }) => void | Promise<void>;\n }\n ) => Promise<T[]>;\n}\n\n/**\n * Restricted table result that excludes methods that shouldn't be called during iteration.\n */\nexport type RestrictedTableResult<T = any> = Omit<TableResult<T>, 'searchForRow' | 'iterateThroughTable' | 'reset' | 'getAllRows'>;\n";