@rickcedwhat/playwright-smart-table 3.2.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.
- package/README.md +140 -67
- package/dist/filterEngine.d.ts +11 -0
- package/dist/filterEngine.js +38 -0
- package/dist/smartRow.d.ts +7 -0
- package/dist/smartRow.js +155 -0
- package/dist/strategies/columns.d.ts +27 -5
- package/dist/strategies/columns.js +9 -8
- package/dist/strategies/headers.js +4 -4
- package/dist/strategies/index.d.ts +53 -0
- package/dist/strategies/index.js +22 -1
- package/dist/strategies/pagination.d.ts +1 -1
- package/dist/strategies/pagination.js +2 -2
- package/dist/strategies/resolution.d.ts +22 -0
- package/dist/strategies/resolution.js +30 -0
- package/dist/typeContext.d.ts +1 -1
- package/dist/typeContext.js +104 -44
- package/dist/types.d.ts +97 -51
- package/dist/useTable.d.ts +7 -4
- package/dist/useTable.js +93 -244
- package/package.json +1 -1
package/dist/useTable.js
CHANGED
|
@@ -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.ColumnStrategies = exports.HeaderStrategies = exports.FillStrategies = exports.SortingStrategies = exports.
|
|
12
|
+
exports.Strategies = exports.ResolutionStrategies = exports.ColumnStrategies = exports.CellNavigationStrategies = exports.HeaderStrategies = exports.FillStrategies = exports.SortingStrategies = exports.DeprecatedTableStrategies = exports.PaginationStrategies = exports.useTable = void 0;
|
|
13
13
|
const typeContext_1 = require("./typeContext");
|
|
14
14
|
const sorting_1 = require("./strategies/sorting");
|
|
15
15
|
const pagination_1 = require("./strategies/pagination");
|
|
@@ -18,14 +18,29 @@ Object.defineProperty(exports, "FillStrategies", { enumerable: true, get: functi
|
|
|
18
18
|
const headers_1 = require("./strategies/headers");
|
|
19
19
|
Object.defineProperty(exports, "HeaderStrategies", { enumerable: true, get: function () { return headers_1.HeaderStrategies; } });
|
|
20
20
|
const columns_1 = require("./strategies/columns");
|
|
21
|
+
Object.defineProperty(exports, "CellNavigationStrategies", { enumerable: true, get: function () { return columns_1.CellNavigationStrategies; } });
|
|
21
22
|
Object.defineProperty(exports, "ColumnStrategies", { enumerable: true, get: function () { return columns_1.ColumnStrategies; } });
|
|
23
|
+
const smartRow_1 = require("./smartRow");
|
|
24
|
+
const filterEngine_1 = require("./filterEngine");
|
|
25
|
+
const resolution_1 = require("./strategies/resolution");
|
|
26
|
+
Object.defineProperty(exports, "ResolutionStrategies", { enumerable: true, get: function () { return resolution_1.ResolutionStrategies; } });
|
|
27
|
+
const strategies_1 = require("./strategies");
|
|
28
|
+
Object.defineProperty(exports, "Strategies", { enumerable: true, get: function () { return strategies_1.Strategies; } });
|
|
22
29
|
/**
|
|
23
30
|
* Main hook to interact with a table.
|
|
24
31
|
*/
|
|
25
32
|
const useTable = (rootLocator, configOptions = {}) => {
|
|
33
|
+
var _a;
|
|
26
34
|
// Store whether pagination was explicitly provided in config
|
|
27
|
-
const hasPaginationInConfig = configOptions.pagination !== undefined;
|
|
28
|
-
|
|
35
|
+
const hasPaginationInConfig = ((_a = configOptions.strategies) === null || _a === void 0 ? void 0 : _a.pagination) !== undefined;
|
|
36
|
+
// Default strategies
|
|
37
|
+
const defaultStrategies = {
|
|
38
|
+
fill: fill_1.FillStrategies.default,
|
|
39
|
+
header: headers_1.HeaderStrategies.visible,
|
|
40
|
+
cellNavigation: columns_1.CellNavigationStrategies.default,
|
|
41
|
+
pagination: () => __awaiter(void 0, void 0, void 0, function* () { return false; }),
|
|
42
|
+
};
|
|
43
|
+
const config = Object.assign(Object.assign({ rowSelector: "tbody tr", headerSelector: "th", cellSelector: "td", maxPages: 1, headerTransformer: ({ text, index, locator }) => text, autoScroll: true, debug: false, onReset: () => __awaiter(void 0, void 0, void 0, function* () { }) }, configOptions), { strategies: Object.assign(Object.assign({}, defaultStrategies), configOptions.strategies) });
|
|
29
44
|
const resolve = (item, parent) => {
|
|
30
45
|
if (typeof item === 'string')
|
|
31
46
|
return parent.locator(item);
|
|
@@ -37,31 +52,28 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
37
52
|
let _headerMap = null;
|
|
38
53
|
let _hasPaginated = false;
|
|
39
54
|
let _isInitialized = false;
|
|
55
|
+
// Helpers
|
|
40
56
|
const logDebug = (msg) => {
|
|
41
57
|
if (config.debug)
|
|
42
58
|
console.log(`🔎 [SmartTable Debug] ${msg}`);
|
|
43
59
|
};
|
|
44
|
-
const
|
|
45
|
-
|
|
60
|
+
const _createColumnError = (colName, map, context) => {
|
|
61
|
+
const availableColumns = Array.from(map.keys());
|
|
62
|
+
// Use Suggestion Logic from ResolutionStrategy (if we had a fuzzy one, for now manual suggest)
|
|
46
63
|
const lowerCol = colName.toLowerCase();
|
|
47
64
|
const suggestions = availableColumns.filter(col => col.toLowerCase().includes(lowerCol) ||
|
|
48
65
|
lowerCol.includes(col.toLowerCase()) ||
|
|
49
66
|
col.toLowerCase().replace(/\s+/g, '') === lowerCol.replace(/\s+/g, ''));
|
|
67
|
+
let suggestion = '.';
|
|
50
68
|
if (suggestions.length > 0 && suggestions[0] !== colName) {
|
|
51
|
-
|
|
69
|
+
suggestion = `. Did you mean "${suggestions[0]}"?`;
|
|
52
70
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
return `. Available columns: ${availableColumns.map(c => `"${c}"`).join(', ')}`;
|
|
71
|
+
else if (availableColumns.length > 0 && availableColumns.length <= 10) {
|
|
72
|
+
suggestion = `. Available columns: ${availableColumns.map(c => `"${c}"`).join(', ')}`;
|
|
56
73
|
}
|
|
57
74
|
else if (availableColumns.length > 0) {
|
|
58
|
-
|
|
75
|
+
suggestion = `. Available columns (first 5): ${availableColumns.slice(0, 5).map(c => `"${c}"`).join(', ')}, ...`;
|
|
59
76
|
}
|
|
60
|
-
return '.';
|
|
61
|
-
};
|
|
62
|
-
const _createColumnError = (colName, map, context) => {
|
|
63
|
-
const availableColumns = Array.from(map.keys());
|
|
64
|
-
const suggestion = _suggestColumnName(colName, availableColumns);
|
|
65
77
|
const contextMsg = context ? ` (${context})` : '';
|
|
66
78
|
return new Error(`Column "${colName}" not found${contextMsg}${suggestion}`);
|
|
67
79
|
};
|
|
@@ -81,12 +93,7 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
81
93
|
yield headerLoc.first().waitFor({ state: 'visible', timeout: headerTimeout });
|
|
82
94
|
}
|
|
83
95
|
catch (e) { /* Ignore hydration */ }
|
|
84
|
-
|
|
85
|
-
const strategy = config.headerStrategy || headers_1.HeaderStrategies.visible;
|
|
86
|
-
// We need to construct context - but wait, HeaderStrategies definition I made imports StrategyContext
|
|
87
|
-
// We need to import HeaderStrategies in useTable.ts first (it was imported as HeaderStrategies?).
|
|
88
|
-
// Wait, useTable.ts imports `FillStrategies`.
|
|
89
|
-
// I need to import `HeaderStrategies`.
|
|
96
|
+
const strategy = config.strategies.header || headers_1.HeaderStrategies.visible;
|
|
90
97
|
const context = {
|
|
91
98
|
root: rootLocator,
|
|
92
99
|
config: config,
|
|
@@ -94,20 +101,13 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
94
101
|
resolve: resolve
|
|
95
102
|
};
|
|
96
103
|
const rawHeaders = yield strategy(context);
|
|
97
|
-
// 2. Map Headers (Async)
|
|
98
|
-
// Note: We lose locator access here for transformer unless strategy provides it.
|
|
99
|
-
// For now assuming transformer handles missing locator or we don't pass it if generic strategy.
|
|
100
104
|
const entries = yield Promise.all(rawHeaders.map((t, i) => __awaiter(void 0, void 0, void 0, function* () {
|
|
101
105
|
let text = t.trim() || `__col_${i}`;
|
|
102
106
|
if (config.headerTransformer) {
|
|
103
107
|
text = yield config.headerTransformer({
|
|
104
108
|
text,
|
|
105
109
|
index: i,
|
|
106
|
-
locator: rootLocator.locator(config.headerSelector).nth(i)
|
|
107
|
-
// Danger: scanning strategy implies nth(i) might not map to visual i if scrolled.
|
|
108
|
-
// But map index maps to logical index.
|
|
109
|
-
// If scanning returns 100 headers, nth(99) might not exist in DOM.
|
|
110
|
-
// Passing fallback locator or stub.
|
|
110
|
+
locator: rootLocator.locator(config.headerSelector).nth(i)
|
|
111
111
|
});
|
|
112
112
|
}
|
|
113
113
|
return [text, i];
|
|
@@ -116,89 +116,13 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
116
116
|
logDebug(`Mapped ${entries.length} columns: ${JSON.stringify(entries.map(e => e[0]))}`);
|
|
117
117
|
return _headerMap;
|
|
118
118
|
});
|
|
119
|
-
// Placeholder for the final table object
|
|
119
|
+
// Placeholder for the final table object
|
|
120
120
|
let finalTable = null;
|
|
121
|
+
const filterEngine = new filterEngine_1.FilterEngine(config, resolve);
|
|
122
|
+
// Helper factory
|
|
121
123
|
const _makeSmart = (rowLocator, map, rowIndex) => {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
smart.rowIndex = rowIndex;
|
|
125
|
-
smart.getCell = (colName) => {
|
|
126
|
-
const idx = map.get(colName);
|
|
127
|
-
if (idx === undefined) {
|
|
128
|
-
const availableColumns = Array.from(map.keys());
|
|
129
|
-
const suggestion = _suggestColumnName(colName, availableColumns);
|
|
130
|
-
throw new Error(`Column "${colName}" not found${suggestion}`);
|
|
131
|
-
}
|
|
132
|
-
if (config.cellResolver) {
|
|
133
|
-
return config.cellResolver({ row: rowLocator, columnName: colName, columnIndex: idx, rowIndex });
|
|
134
|
-
}
|
|
135
|
-
return resolve(config.cellSelector, rowLocator).nth(idx);
|
|
136
|
-
};
|
|
137
|
-
smart.toJSON = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
138
|
-
const result = {};
|
|
139
|
-
const cells = typeof config.cellSelector === 'string'
|
|
140
|
-
? rowLocator.locator(config.cellSelector)
|
|
141
|
-
: resolve(config.cellSelector, rowLocator);
|
|
142
|
-
const texts = yield cells.allInnerTexts();
|
|
143
|
-
for (const [col, idx] of map.entries()) {
|
|
144
|
-
result[col] = (texts[idx] || '').trim();
|
|
145
|
-
}
|
|
146
|
-
return result;
|
|
147
|
-
});
|
|
148
|
-
// @ts-ignore - Intentionally overriding Locator's fill method to accept object
|
|
149
|
-
smart.fill = (data, fillOptions) => __awaiter(void 0, void 0, void 0, function* () {
|
|
150
|
-
logDebug(`Filling row with data: ${JSON.stringify(data)}`);
|
|
151
|
-
// Fill each column
|
|
152
|
-
for (const [colName, value] of Object.entries(data)) {
|
|
153
|
-
const colIdx = map.get(colName);
|
|
154
|
-
if (colIdx === undefined) {
|
|
155
|
-
throw _createColumnError(colName, map, 'in fill data');
|
|
156
|
-
}
|
|
157
|
-
// Execute Column Strategy BEFORE filling
|
|
158
|
-
yield config.columnStrategy({
|
|
159
|
-
config: config,
|
|
160
|
-
root: rootLocator,
|
|
161
|
-
page: rootLocator.page(),
|
|
162
|
-
resolve,
|
|
163
|
-
column: colName,
|
|
164
|
-
index: colIdx,
|
|
165
|
-
rowLocator: rowLocator,
|
|
166
|
-
rowIndex: rowIndex
|
|
167
|
-
});
|
|
168
|
-
// Use configured strategy or default to internal DOM logic
|
|
169
|
-
const strategy = config.fillStrategy || fill_1.FillStrategies.default;
|
|
170
|
-
yield strategy({
|
|
171
|
-
row: smart,
|
|
172
|
-
columnName: colName,
|
|
173
|
-
value,
|
|
174
|
-
index: -1,
|
|
175
|
-
page: rootLocator.page(),
|
|
176
|
-
rootLocator,
|
|
177
|
-
table: finalTable,
|
|
178
|
-
fillOptions
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
logDebug('Fill operation completed');
|
|
182
|
-
});
|
|
183
|
-
// Alias for explicit usage avoiding Locator.fill conflict
|
|
184
|
-
smart.smartFill = smart.fill;
|
|
185
|
-
return smart;
|
|
186
|
-
};
|
|
187
|
-
const _applyFilters = (baseRows, filters, map, exact) => {
|
|
188
|
-
let filtered = baseRows;
|
|
189
|
-
const page = rootLocator.page();
|
|
190
|
-
for (const [colName, value] of Object.entries(filters)) {
|
|
191
|
-
const colIndex = map.get(colName);
|
|
192
|
-
if (colIndex === undefined) {
|
|
193
|
-
throw _createColumnError(colName, map, 'in filter');
|
|
194
|
-
}
|
|
195
|
-
const filterVal = typeof value === 'number' ? String(value) : value;
|
|
196
|
-
const cellTemplate = resolve(config.cellSelector, page);
|
|
197
|
-
filtered = filtered.filter({
|
|
198
|
-
has: cellTemplate.nth(colIndex).getByText(filterVal, { exact }),
|
|
199
|
-
});
|
|
200
|
-
}
|
|
201
|
-
return filtered;
|
|
124
|
+
// Use the wrapped SmartRow logic
|
|
125
|
+
return (0, smartRow_1.createSmartRow)(rowLocator, map, rowIndex, config, rootLocator, resolve, finalTable);
|
|
202
126
|
};
|
|
203
127
|
const _findRowLocator = (filters_1, ...args_1) => __awaiter(void 0, [filters_1, ...args_1], void 0, function* (filters, options = {}) {
|
|
204
128
|
var _a;
|
|
@@ -208,11 +132,12 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
208
132
|
logDebug(`Looking for row: ${JSON.stringify(filters)} (MaxPages: ${effectiveMaxPages})`);
|
|
209
133
|
while (true) {
|
|
210
134
|
const allRows = resolve(config.rowSelector, rootLocator);
|
|
211
|
-
|
|
135
|
+
// Use FilterEngine
|
|
136
|
+
const matchedRows = filterEngine.applyFilters(allRows, filters, map, options.exact || false, rootLocator.page());
|
|
212
137
|
const count = yield matchedRows.count();
|
|
213
138
|
logDebug(`Page ${currentPage}: Found ${count} matches.`);
|
|
214
139
|
if (count > 1) {
|
|
215
|
-
//
|
|
140
|
+
// Sample data logic (simplified for refactor, kept inline or moved to util if needed)
|
|
216
141
|
const sampleData = [];
|
|
217
142
|
try {
|
|
218
143
|
const firstFewRows = yield matchedRows.all();
|
|
@@ -222,12 +147,8 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
222
147
|
sampleData.push(JSON.stringify(rowData));
|
|
223
148
|
}
|
|
224
149
|
}
|
|
225
|
-
catch (e) {
|
|
226
|
-
|
|
227
|
-
}
|
|
228
|
-
const sampleMsg = sampleData.length > 0
|
|
229
|
-
? `\nSample matching rows:\n${sampleData.map((d, i) => ` ${i + 1}. ${d}`).join('\n')}`
|
|
230
|
-
: '';
|
|
150
|
+
catch (e) { }
|
|
151
|
+
const sampleMsg = sampleData.length > 0 ? `\nSample matching rows:\n${sampleData.map((d, i) => ` ${i + 1}. ${d}`).join('\n')}` : '';
|
|
231
152
|
throw new Error(`Strict Mode Violation: Found ${count} rows matching ${JSON.stringify(filters)} on page ${currentPage}. ` +
|
|
232
153
|
`Expected exactly one match. Try adding more filters to make your query unique.${sampleMsg}`);
|
|
233
154
|
}
|
|
@@ -241,7 +162,7 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
241
162
|
page: rootLocator.page(),
|
|
242
163
|
resolve: resolve
|
|
243
164
|
};
|
|
244
|
-
const didLoadMore = yield config.pagination(context);
|
|
165
|
+
const didLoadMore = yield config.strategies.pagination(context);
|
|
245
166
|
if (didLoadMore) {
|
|
246
167
|
_hasPaginated = true;
|
|
247
168
|
currentPage++;
|
|
@@ -258,33 +179,27 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
258
179
|
}
|
|
259
180
|
});
|
|
260
181
|
const _handlePrompt = (promptName_1, content_1, ...args_1) => __awaiter(void 0, [promptName_1, content_1, ...args_1], void 0, function* (promptName, content, options = {}) {
|
|
182
|
+
// ... same logic ...
|
|
261
183
|
const { output = 'console', includeTypes = true } = options;
|
|
262
184
|
let finalPrompt = content;
|
|
263
|
-
if (includeTypes)
|
|
185
|
+
if (includeTypes)
|
|
264
186
|
finalPrompt += `\n\n👇 Useful TypeScript Definitions 👇\n\`\`\`typescript\n${typeContext_1.TYPE_CONTEXT}\n\`\`\`\n`;
|
|
265
|
-
}
|
|
266
187
|
if (output === 'error') {
|
|
267
188
|
console.log(`⚠️ Throwing error to display [${promptName}] cleanly...`);
|
|
268
189
|
throw new Error(finalPrompt);
|
|
269
190
|
}
|
|
270
191
|
console.log(finalPrompt);
|
|
271
192
|
});
|
|
272
|
-
// Helper to extract clean HTML for prompts
|
|
273
193
|
const _getCleanHtml = (loc) => __awaiter(void 0, void 0, void 0, function* () {
|
|
274
194
|
return loc.evaluate((el) => {
|
|
275
195
|
const clone = el.cloneNode(true);
|
|
276
|
-
// 1. Remove Heavy/Useless Elements
|
|
277
196
|
const removeSelectors = 'script, style, svg, path, circle, rect, noscript, [hidden]';
|
|
278
197
|
clone.querySelectorAll(removeSelectors).forEach(n => n.remove());
|
|
279
|
-
// 2. Clean Attributes
|
|
280
198
|
const walker = document.createTreeWalker(clone, NodeFilter.SHOW_ELEMENT);
|
|
281
199
|
let currentNode = walker.currentNode;
|
|
282
200
|
while (currentNode) {
|
|
283
|
-
currentNode.removeAttribute('style');
|
|
201
|
+
currentNode.removeAttribute('style');
|
|
284
202
|
currentNode.removeAttribute('data-reactid');
|
|
285
|
-
// 3. Condense Tailwind Classes (Heuristic)
|
|
286
|
-
// If class string is very long (>50 chars), keep the first few tokens and truncate.
|
|
287
|
-
// This preserves "MuiRow" but cuts "text-sm p-4 hover:bg-gray-50 ..."
|
|
288
203
|
const cls = currentNode.getAttribute('class');
|
|
289
204
|
if (cls && cls.length > 80) {
|
|
290
205
|
const tokens = cls.split(' ');
|
|
@@ -297,7 +212,6 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
297
212
|
return clone.outerHTML;
|
|
298
213
|
});
|
|
299
214
|
});
|
|
300
|
-
// Helper to ensure initialization for async methods
|
|
301
215
|
const _ensureInitialized = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
302
216
|
if (!_isInitialized) {
|
|
303
217
|
yield _getMap();
|
|
@@ -306,9 +220,8 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
306
220
|
});
|
|
307
221
|
const result = {
|
|
308
222
|
init: (options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
309
|
-
if (_isInitialized && _headerMap)
|
|
223
|
+
if (_isInitialized && _headerMap)
|
|
310
224
|
return result;
|
|
311
|
-
}
|
|
312
225
|
yield _getMap(options === null || options === void 0 ? void 0 : options.timeout);
|
|
313
226
|
_isInitialized = true;
|
|
314
227
|
return result;
|
|
@@ -316,10 +229,9 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
316
229
|
scrollToColumn: (columnName) => __awaiter(void 0, void 0, void 0, function* () {
|
|
317
230
|
const map = yield _getMap();
|
|
318
231
|
const idx = map.get(columnName);
|
|
319
|
-
if (idx === undefined)
|
|
232
|
+
if (idx === undefined)
|
|
320
233
|
throw _createColumnError(columnName, map);
|
|
321
|
-
|
|
322
|
-
yield config.columnStrategy({
|
|
234
|
+
yield config.strategies.cellNavigation({
|
|
323
235
|
config: config,
|
|
324
236
|
root: rootLocator,
|
|
325
237
|
page: rootLocator.page(),
|
|
@@ -329,15 +241,13 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
329
241
|
});
|
|
330
242
|
}),
|
|
331
243
|
getHeaders: () => __awaiter(void 0, void 0, void 0, function* () {
|
|
332
|
-
if (!_isInitialized || !_headerMap)
|
|
244
|
+
if (!_isInitialized || !_headerMap)
|
|
333
245
|
throw new Error('Table not initialized. Call await table.init() first.');
|
|
334
|
-
}
|
|
335
246
|
return Array.from(_headerMap.keys());
|
|
336
247
|
}),
|
|
337
248
|
getHeaderCell: (columnName) => __awaiter(void 0, void 0, void 0, function* () {
|
|
338
|
-
if (!_isInitialized || !_headerMap)
|
|
249
|
+
if (!_isInitialized || !_headerMap)
|
|
339
250
|
throw new Error('Table not initialized. Call await table.init() first.');
|
|
340
|
-
}
|
|
341
251
|
const idx = _headerMap.get(columnName);
|
|
342
252
|
if (idx === undefined)
|
|
343
253
|
throw _createColumnError(columnName, _headerMap, 'header cell');
|
|
@@ -345,21 +255,21 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
345
255
|
}),
|
|
346
256
|
reset: () => __awaiter(void 0, void 0, void 0, function* () {
|
|
347
257
|
logDebug("Resetting table...");
|
|
348
|
-
const context = {
|
|
349
|
-
root: rootLocator,
|
|
350
|
-
config: config,
|
|
351
|
-
page: rootLocator.page(),
|
|
352
|
-
resolve: resolve
|
|
353
|
-
};
|
|
258
|
+
const context = { root: rootLocator, config, page: rootLocator.page(), resolve };
|
|
354
259
|
yield config.onReset(context);
|
|
355
260
|
_hasPaginated = false;
|
|
356
261
|
_headerMap = null;
|
|
357
262
|
_isInitialized = false;
|
|
358
263
|
logDebug("Table reset complete.");
|
|
359
264
|
}),
|
|
265
|
+
revalidate: () => __awaiter(void 0, void 0, void 0, function* () {
|
|
266
|
+
logDebug("Revalidating table structure...");
|
|
267
|
+
_headerMap = null; // Clear the map to force re-scanning
|
|
268
|
+
yield _getMap(); // Re-scan headers
|
|
269
|
+
logDebug("Table revalidated.");
|
|
270
|
+
}),
|
|
360
271
|
getColumnValues: (column, options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
361
272
|
var _a, _b;
|
|
362
|
-
// Auto-init if needed (async methods can auto-init)
|
|
363
273
|
yield _ensureInitialized();
|
|
364
274
|
const colIdx = _headerMap.get(column);
|
|
365
275
|
if (colIdx === undefined)
|
|
@@ -378,10 +288,8 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
378
288
|
results.push(yield mapper(cell));
|
|
379
289
|
}
|
|
380
290
|
if (currentPage < effectiveMaxPages) {
|
|
381
|
-
const context = {
|
|
382
|
-
|
|
383
|
-
};
|
|
384
|
-
if (yield config.pagination(context)) {
|
|
291
|
+
const context = { root: rootLocator, config, page: rootLocator.page(), resolve };
|
|
292
|
+
if (yield config.strategies.pagination(context)) {
|
|
385
293
|
_hasPaginated = true;
|
|
386
294
|
currentPage++;
|
|
387
295
|
continue;
|
|
@@ -391,32 +299,23 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
391
299
|
}
|
|
392
300
|
return results;
|
|
393
301
|
}),
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
// Throw error if not initialized
|
|
397
|
-
if (!_isInitialized || !_headerMap) {
|
|
302
|
+
getByRow: (filters, options = { exact: false }) => {
|
|
303
|
+
if (!_isInitialized || !_headerMap)
|
|
398
304
|
throw new Error('Table not initialized. Call await table.init() first.');
|
|
399
|
-
}
|
|
400
|
-
// Handle Index Overload (1-based index)
|
|
401
|
-
if (typeof filtersOrIndex === 'number') {
|
|
402
|
-
const rowIndex = filtersOrIndex - 1;
|
|
403
|
-
const rowLocator = resolve(config.rowSelector, rootLocator).nth(rowIndex);
|
|
404
|
-
return _makeSmart(rowLocator, _headerMap, rowIndex);
|
|
405
|
-
}
|
|
406
|
-
// Handle Filter Logic (Sync - lazy)
|
|
407
|
-
const filters = filtersOrIndex;
|
|
408
305
|
const allRows = resolve(config.rowSelector, rootLocator);
|
|
409
|
-
const matchedRows =
|
|
306
|
+
const matchedRows = filterEngine.applyFilters(allRows, filters, _headerMap, options.exact || false, rootLocator.page());
|
|
410
307
|
const rowLocator = matchedRows.first();
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
308
|
+
return _makeSmart(rowLocator, _headerMap, 0); // fallback index 0
|
|
309
|
+
},
|
|
310
|
+
getByRowIndex: (index, options = {}) => {
|
|
311
|
+
if (!_isInitialized || !_headerMap)
|
|
312
|
+
throw new Error('Table not initialized. Call await table.init() first.');
|
|
313
|
+
const rowIndex = index - 1; // Convert 1-based to 0-based
|
|
314
|
+
const rowLocator = resolve(config.rowSelector, rootLocator).nth(rowIndex);
|
|
315
|
+
return _makeSmart(rowLocator, _headerMap, rowIndex);
|
|
415
316
|
},
|
|
416
317
|
searchForRow: (filters, options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
417
|
-
// Auto-init if needed (async methods can auto-init)
|
|
418
318
|
yield _ensureInitialized();
|
|
419
|
-
// Full pagination logic (existing _findRowLocator logic)
|
|
420
319
|
let row = yield _findRowLocator(filters, options);
|
|
421
320
|
if (!row) {
|
|
422
321
|
row = resolve(config.rowSelector, rootLocator).filter({ hasText: "___SENTINEL_ROW_NOT_FOUND___" + Date.now() });
|
|
@@ -424,11 +323,10 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
424
323
|
return _makeSmart(row, _headerMap, 0);
|
|
425
324
|
}),
|
|
426
325
|
getAllCurrentRows: (options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
427
|
-
// Auto-init if needed (async methods can auto-init)
|
|
428
326
|
yield _ensureInitialized();
|
|
429
327
|
let rowLocators = resolve(config.rowSelector, rootLocator);
|
|
430
328
|
if (options === null || options === void 0 ? void 0 : options.filter) {
|
|
431
|
-
rowLocators =
|
|
329
|
+
rowLocators = filterEngine.applyFilters(rowLocators, options.filter, _headerMap, options.exact || false, rootLocator.page());
|
|
432
330
|
}
|
|
433
331
|
const rows = yield rowLocators.all();
|
|
434
332
|
const smartRows = rows.map((loc, i) => _makeSmart(loc, _headerMap, i));
|
|
@@ -437,9 +335,6 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
437
335
|
}
|
|
438
336
|
return smartRows;
|
|
439
337
|
}),
|
|
440
|
-
/**
|
|
441
|
-
* @deprecated Use getAllCurrentRows instead. This method will be removed in a future major version.
|
|
442
|
-
*/
|
|
443
338
|
getAllRows: (options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
444
339
|
console.warn("⚠️ [SmartTable] getAllRows is deprecated. Use getAllCurrentRows instead.");
|
|
445
340
|
return result.getAllCurrentRows(options);
|
|
@@ -458,82 +353,58 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
458
353
|
}),
|
|
459
354
|
sorting: {
|
|
460
355
|
apply: (columnName, direction) => __awaiter(void 0, void 0, void 0, function* () {
|
|
461
|
-
// Auto-init if needed (async methods can auto-init)
|
|
462
356
|
yield _ensureInitialized();
|
|
463
|
-
if (!config.sorting)
|
|
464
|
-
throw new Error('No sorting strategy has been configured.
|
|
465
|
-
}
|
|
357
|
+
if (!config.strategies.sorting)
|
|
358
|
+
throw new Error('No sorting strategy has been configured.');
|
|
466
359
|
logDebug(`Applying sort for column "${columnName}" (${direction})`);
|
|
467
|
-
const context = {
|
|
468
|
-
|
|
469
|
-
config: config,
|
|
470
|
-
page: rootLocator.page(),
|
|
471
|
-
resolve: resolve
|
|
472
|
-
};
|
|
473
|
-
yield config.sorting.doSort({ columnName, direction, context });
|
|
360
|
+
const context = { root: rootLocator, config, page: rootLocator.page(), resolve };
|
|
361
|
+
yield config.strategies.sorting.doSort({ columnName, direction, context });
|
|
474
362
|
}),
|
|
475
363
|
getState: (columnName) => __awaiter(void 0, void 0, void 0, function* () {
|
|
476
|
-
// Auto-init if needed (async methods can auto-init)
|
|
477
364
|
yield _ensureInitialized();
|
|
478
|
-
if (!config.sorting)
|
|
479
|
-
throw new Error('No sorting strategy has been configured.
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
const context = {
|
|
483
|
-
root: rootLocator,
|
|
484
|
-
config: config,
|
|
485
|
-
page: rootLocator.page(),
|
|
486
|
-
resolve: resolve
|
|
487
|
-
};
|
|
488
|
-
return config.sorting.getSortState({ columnName, context });
|
|
365
|
+
if (!config.strategies.sorting)
|
|
366
|
+
throw new Error('No sorting strategy has been configured.');
|
|
367
|
+
const context = { root: rootLocator, config, page: rootLocator.page(), resolve };
|
|
368
|
+
return config.strategies.sorting.getSortState({ columnName, context });
|
|
489
369
|
})
|
|
490
370
|
},
|
|
491
371
|
iterateThroughTable: (callback, options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
492
372
|
var _a, _b, _c, _d;
|
|
493
|
-
// Auto-init if needed (async methods can auto-init)
|
|
494
373
|
yield _ensureInitialized();
|
|
495
|
-
|
|
496
|
-
const paginationStrategy = (_a = options === null || options === void 0 ? void 0 : options.pagination) !== null && _a !== void 0 ? _a : config.pagination;
|
|
497
|
-
// Check if pagination was explicitly provided in options or config
|
|
374
|
+
const paginationStrategy = (_a = options === null || options === void 0 ? void 0 : options.pagination) !== null && _a !== void 0 ? _a : config.strategies.pagination;
|
|
498
375
|
const hasPaginationInOptions = (options === null || options === void 0 ? void 0 : options.pagination) !== undefined;
|
|
499
|
-
if (!hasPaginationInOptions && !hasPaginationInConfig)
|
|
500
|
-
throw new Error('No pagination strategy provided.
|
|
501
|
-
}
|
|
502
|
-
// Reset to initial page before starting
|
|
376
|
+
if (!hasPaginationInOptions && !hasPaginationInConfig)
|
|
377
|
+
throw new Error('No pagination strategy provided.');
|
|
503
378
|
yield result.reset();
|
|
504
379
|
yield result.init();
|
|
505
|
-
// Create restricted table instance (excludes problematic methods)
|
|
506
380
|
const restrictedTable = {
|
|
507
381
|
init: result.init,
|
|
508
382
|
getHeaders: result.getHeaders,
|
|
509
383
|
getHeaderCell: result.getHeaderCell,
|
|
510
384
|
getByRow: result.getByRow,
|
|
385
|
+
getByRowIndex: result.getByRowIndex,
|
|
511
386
|
getAllCurrentRows: result.getAllCurrentRows,
|
|
512
387
|
getColumnValues: result.getColumnValues,
|
|
513
388
|
generateConfigPrompt: result.generateConfigPrompt,
|
|
514
389
|
generateStrategyPrompt: result.generateStrategyPrompt,
|
|
515
390
|
sorting: result.sorting,
|
|
516
|
-
scrollToColumn: result.scrollToColumn,
|
|
391
|
+
scrollToColumn: result.scrollToColumn,
|
|
392
|
+
revalidate: result.revalidate,
|
|
517
393
|
};
|
|
518
|
-
// Default functions
|
|
519
394
|
const getIsFirst = (_b = options === null || options === void 0 ? void 0 : options.getIsFirst) !== null && _b !== void 0 ? _b : (({ index }) => index === 0);
|
|
520
395
|
const getIsLast = (_c = options === null || options === void 0 ? void 0 : options.getIsLast) !== null && _c !== void 0 ? _c : (() => false);
|
|
521
|
-
// Create allData array (persists across iterations)
|
|
522
396
|
const allData = [];
|
|
523
397
|
const effectiveMaxIterations = (_d = options === null || options === void 0 ? void 0 : options.maxIterations) !== null && _d !== void 0 ? _d : config.maxPages;
|
|
524
398
|
let index = 0;
|
|
525
|
-
let paginationResult = true;
|
|
526
|
-
let seenKeys = null;
|
|
399
|
+
let paginationResult = true;
|
|
400
|
+
let seenKeys = null;
|
|
527
401
|
logDebug(`Starting iterateThroughTable (maxIterations: ${effectiveMaxIterations})`);
|
|
528
402
|
while (index < effectiveMaxIterations) {
|
|
529
|
-
// Get current rows
|
|
530
403
|
const rowLocators = yield resolve(config.rowSelector, rootLocator).all();
|
|
531
404
|
let rows = rowLocators.map((loc, i) => _makeSmart(loc, _headerMap, i));
|
|
532
|
-
// Deduplicate if dedupeStrategy provided (across all iterations)
|
|
533
405
|
if ((options === null || options === void 0 ? void 0 : options.dedupeStrategy) && rows.length > 0) {
|
|
534
|
-
if (!seenKeys)
|
|
406
|
+
if (!seenKeys)
|
|
535
407
|
seenKeys = new Set();
|
|
536
|
-
}
|
|
537
408
|
const deduplicated = [];
|
|
538
409
|
for (const row of rows) {
|
|
539
410
|
const key = yield options.dedupeStrategy(row);
|
|
@@ -545,43 +416,20 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
545
416
|
rows = deduplicated;
|
|
546
417
|
logDebug(`Deduplicated ${rowLocators.length} rows to ${rows.length} unique rows (total seen: ${seenKeys.size})`);
|
|
547
418
|
}
|
|
548
|
-
// Determine flags (isLast will be checked after pagination attempt)
|
|
549
419
|
const isFirst = getIsFirst({ index });
|
|
550
420
|
let isLast = getIsLast({ index, paginationResult });
|
|
551
|
-
// Check if this is the last iteration due to maxIterations (before attempting pagination)
|
|
552
421
|
const isLastDueToMax = index === effectiveMaxIterations - 1;
|
|
553
|
-
|
|
554
|
-
if (isFirst && (options === null || options === void 0 ? void 0 : options.onFirst)) {
|
|
422
|
+
if (isFirst && (options === null || options === void 0 ? void 0 : options.onFirst))
|
|
555
423
|
yield options.onFirst({ index, rows, allData });
|
|
556
|
-
}
|
|
557
|
-
// Call main callback
|
|
558
|
-
const returnValue = yield callback({
|
|
559
|
-
index,
|
|
560
|
-
isFirst,
|
|
561
|
-
isLast,
|
|
562
|
-
rows,
|
|
563
|
-
allData,
|
|
564
|
-
table: restrictedTable,
|
|
565
|
-
});
|
|
566
|
-
// Append return value to allData
|
|
424
|
+
const returnValue = yield callback({ index, isFirst, isLast, rows, allData, table: restrictedTable });
|
|
567
425
|
allData.push(returnValue);
|
|
568
|
-
|
|
569
|
-
const context = {
|
|
570
|
-
root: rootLocator,
|
|
571
|
-
config: config,
|
|
572
|
-
page: rootLocator.page(),
|
|
573
|
-
resolve: resolve
|
|
574
|
-
};
|
|
426
|
+
const context = { root: rootLocator, config, page: rootLocator.page(), resolve };
|
|
575
427
|
paginationResult = yield paginationStrategy(context);
|
|
576
|
-
// Now check isLast with updated paginationResult
|
|
577
428
|
isLast = getIsLast({ index, paginationResult }) || isLastDueToMax;
|
|
578
|
-
|
|
579
|
-
if (isLast && (options === null || options === void 0 ? void 0 : options.onLast)) {
|
|
429
|
+
if (isLast && (options === null || options === void 0 ? void 0 : options.onLast))
|
|
580
430
|
yield options.onLast({ index, rows, allData });
|
|
581
|
-
}
|
|
582
|
-
// Check if we should continue
|
|
583
431
|
if (isLast || !paginationResult) {
|
|
584
|
-
logDebug(`Reached last iteration (index: ${index}, paginationResult: ${paginationResult}
|
|
432
|
+
logDebug(`Reached last iteration (index: ${index}, paginationResult: ${paginationResult})`);
|
|
585
433
|
break;
|
|
586
434
|
}
|
|
587
435
|
index++;
|
|
@@ -596,5 +444,6 @@ const useTable = (rootLocator, configOptions = {}) => {
|
|
|
596
444
|
};
|
|
597
445
|
exports.useTable = useTable;
|
|
598
446
|
exports.PaginationStrategies = pagination_1.PaginationStrategies;
|
|
599
|
-
|
|
447
|
+
/** @deprecated Use Strategies.Pagination instead */
|
|
448
|
+
exports.DeprecatedTableStrategies = pagination_1.DeprecatedPaginationStrategies;
|
|
600
449
|
exports.SortingStrategies = sorting_1.SortingStrategies;
|
package/package.json
CHANGED