@rickcedwhat/playwright-smart-table 6.4.0 → 6.6.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/dist/useTable.js CHANGED
@@ -8,9 +8,23 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
9
  });
10
10
  };
11
+ var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
12
+ var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
13
+ if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
14
+ var g = generator.apply(thisArg, _arguments || []), i, q = [];
15
+ return i = Object.create((typeof AsyncIterator === "function" ? AsyncIterator : Object).prototype), verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;
16
+ function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }
17
+ function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }
18
+ function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
19
+ function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
20
+ function fulfill(value) { resume("next", value); }
21
+ function reject(value) { resume("throw", value); }
22
+ function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
23
+ };
11
24
  Object.defineProperty(exports, "__esModule", { value: true });
12
25
  exports.useTable = void 0;
13
26
  const minimalConfigContext_1 = require("./minimalConfigContext");
27
+ const validation_1 = require("./strategies/validation");
14
28
  const loading_1 = require("./strategies/loading");
15
29
  const fill_1 = require("./strategies/fill");
16
30
  const headers_1 = require("./strategies/headers");
@@ -75,10 +89,11 @@ const useTable = (rootLocator, configOptions = {}) => {
75
89
  // Placeholder for the final table object
76
90
  let finalTable = null;
77
91
  // Helper factory
78
- const _makeSmart = (rowLocator, map, rowIndex) => {
79
- return (0, smartRow_1.createSmartRow)(rowLocator, map, rowIndex, config, rootLocator, resolve, finalTable);
92
+ const _makeSmart = (rowLocator, map, rowIndex, tablePageIndex) => {
93
+ return (0, smartRow_1.createSmartRow)(rowLocator, map, rowIndex, config, rootLocator, resolve, finalTable, tablePageIndex);
80
94
  };
81
- const rowFinder = new rowFinder_1.RowFinder(rootLocator, config, resolve, filterEngine, tableMapper, _makeSmart);
95
+ const tableState = { currentPageIndex: 0 };
96
+ const rowFinder = new rowFinder_1.RowFinder(rootLocator, config, resolve, filterEngine, tableMapper, _makeSmart, tableState);
82
97
  const _getCleanHtml = (loc) => __awaiter(void 0, void 0, void 0, function* () {
83
98
  return loc.evaluate((el) => {
84
99
  const clone = el.cloneNode(true);
@@ -117,6 +132,8 @@ const useTable = (rootLocator, configOptions = {}) => {
117
132
  yield tableMapper.getMap();
118
133
  });
119
134
  const result = {
135
+ get currentPageIndex() { return tableState.currentPageIndex; },
136
+ set currentPageIndex(v) { tableState.currentPageIndex = v; },
120
137
  init: (options) => __awaiter(void 0, void 0, void 0, function* () {
121
138
  if (tableMapper.isInitialized())
122
139
  return result;
@@ -168,7 +185,7 @@ const useTable = (rootLocator, configOptions = {}) => {
168
185
  throw _createColumnError(column, map);
169
186
  const mapper = (_a = options === null || options === void 0 ? void 0 : options.mapper) !== null && _a !== void 0 ? _a : ((c) => c.innerText());
170
187
  const effectiveMaxPages = (_b = options === null || options === void 0 ? void 0 : options.maxPages) !== null && _b !== void 0 ? _b : config.maxPages;
171
- let currentPage = 1;
188
+ let pagesScanned = 1;
172
189
  const results = [];
173
190
  log(`Getting column values for '${column}' (Pages: ${effectiveMaxPages})`);
174
191
  while (true) {
@@ -179,11 +196,23 @@ const useTable = (rootLocator, configOptions = {}) => {
179
196
  : resolve(config.cellSelector, row).nth(colIdx);
180
197
  results.push(yield mapper(cell));
181
198
  }
182
- if (currentPage < effectiveMaxPages) {
199
+ if (pagesScanned < effectiveMaxPages) {
183
200
  const context = { root: rootLocator, config, page: rootLocator.page(), resolve };
184
- if (yield config.strategies.pagination(context)) {
201
+ let pageRes;
202
+ if (typeof config.strategies.pagination === 'function') {
203
+ pageRes = yield config.strategies.pagination(context);
204
+ }
205
+ else {
206
+ if (!config.strategies.pagination.goNext) {
207
+ log('Cannot paginate: no goNext primitive found.');
208
+ break;
209
+ }
210
+ pageRes = yield config.strategies.pagination.goNext(context);
211
+ }
212
+ if (yield (0, validation_1.validatePaginationResult)(pageRes, 'Pagination Strategy')) {
185
213
  _hasPaginated = true;
186
- currentPage++;
214
+ tableState.currentPageIndex++;
215
+ pagesScanned++;
187
216
  continue;
188
217
  }
189
218
  }
@@ -234,6 +263,219 @@ const useTable = (rootLocator, configOptions = {}) => {
234
263
  return config.strategies.sorting.getSortState({ columnName, context });
235
264
  })
236
265
  },
266
+ // ─── Shared async row iterator ───────────────────────────────────────────
267
+ [Symbol.asyncIterator]() {
268
+ return __asyncGenerator(this, arguments, function* _a() {
269
+ var _b;
270
+ yield __await(_ensureInitialized());
271
+ const map = tableMapper.getMapSync();
272
+ const effectiveMaxPages = config.maxPages;
273
+ let rowIndex = 0;
274
+ let pagesScanned = 1;
275
+ while (true) {
276
+ const pageRows = yield __await(resolve(config.rowSelector, rootLocator).all());
277
+ for (const rowLocator of pageRows) {
278
+ yield yield __await({ row: _makeSmart(rowLocator, map, rowIndex), rowIndex });
279
+ rowIndex++;
280
+ }
281
+ if (pagesScanned >= effectiveMaxPages)
282
+ break;
283
+ const context = { root: rootLocator, config, page: rootLocator.page(), resolve };
284
+ let advanced;
285
+ if (typeof config.strategies.pagination === 'function') {
286
+ advanced = !!(yield __await(config.strategies.pagination(context)));
287
+ }
288
+ else {
289
+ advanced = !!(((_b = config.strategies.pagination) === null || _b === void 0 ? void 0 : _b.goNext) && (yield __await(config.strategies.pagination.goNext(context))));
290
+ }
291
+ if (!advanced)
292
+ break;
293
+ tableState.currentPageIndex++;
294
+ pagesScanned++;
295
+ }
296
+ });
297
+ },
298
+ // ─── Private row-iteration engine ────────────────────────────────────────
299
+ forEach: (callback_1, ...args_1) => __awaiter(void 0, [callback_1, ...args_1], void 0, function* (callback, options = {}) {
300
+ var _a, _b, _c;
301
+ yield _ensureInitialized();
302
+ const map = tableMapper.getMapSync();
303
+ const effectiveMaxPages = (_a = options.maxPages) !== null && _a !== void 0 ? _a : config.maxPages;
304
+ const dedupeKeys = options.dedupe ? new Set() : null;
305
+ const parallel = (_b = options.parallel) !== null && _b !== void 0 ? _b : false;
306
+ let rowIndex = 0;
307
+ let stopped = false;
308
+ let pagesScanned = 1;
309
+ const stop = () => { stopped = true; };
310
+ while (!stopped) {
311
+ const pageRows = yield resolve(config.rowSelector, rootLocator).all();
312
+ const smartRows = pageRows.map((r, i) => _makeSmart(r, map, rowIndex + i));
313
+ if (parallel) {
314
+ yield Promise.all(smartRows.map((row) => __awaiter(void 0, void 0, void 0, function* () {
315
+ if (stopped)
316
+ return;
317
+ if (dedupeKeys) {
318
+ const key = yield options.dedupe(row);
319
+ if (dedupeKeys.has(key))
320
+ return;
321
+ dedupeKeys.add(key);
322
+ }
323
+ yield callback({ row, rowIndex: row.rowIndex, stop });
324
+ })));
325
+ }
326
+ else {
327
+ for (const row of smartRows) {
328
+ if (stopped)
329
+ break;
330
+ if (dedupeKeys) {
331
+ const key = yield options.dedupe(row);
332
+ if (dedupeKeys.has(key))
333
+ continue;
334
+ dedupeKeys.add(key);
335
+ }
336
+ yield callback({ row, rowIndex: row.rowIndex, stop });
337
+ }
338
+ }
339
+ rowIndex += smartRows.length;
340
+ if (stopped || pagesScanned >= effectiveMaxPages)
341
+ break;
342
+ const context = { root: rootLocator, config, page: rootLocator.page(), resolve };
343
+ let advanced;
344
+ if (typeof config.strategies.pagination === 'function') {
345
+ advanced = !!(yield config.strategies.pagination(context));
346
+ }
347
+ else {
348
+ advanced = !!(((_c = config.strategies.pagination) === null || _c === void 0 ? void 0 : _c.goNext) && (yield config.strategies.pagination.goNext(context)));
349
+ }
350
+ if (!advanced)
351
+ break;
352
+ tableState.currentPageIndex++;
353
+ pagesScanned++;
354
+ }
355
+ }),
356
+ map: (callback_1, ...args_1) => __awaiter(void 0, [callback_1, ...args_1], void 0, function* (callback, options = {}) {
357
+ var _a, _b, _c;
358
+ yield _ensureInitialized();
359
+ const map = tableMapper.getMapSync();
360
+ const effectiveMaxPages = (_a = options.maxPages) !== null && _a !== void 0 ? _a : config.maxPages;
361
+ const dedupeKeys = options.dedupe ? new Set() : null;
362
+ const parallel = (_b = options.parallel) !== null && _b !== void 0 ? _b : true;
363
+ const results = [];
364
+ let rowIndex = 0;
365
+ let stopped = false;
366
+ let pagesScanned = 1;
367
+ const stop = () => { stopped = true; };
368
+ while (!stopped) {
369
+ const pageRows = yield resolve(config.rowSelector, rootLocator).all();
370
+ const smartRows = pageRows.map((r, i) => _makeSmart(r, map, rowIndex + i));
371
+ if (parallel) {
372
+ const SKIP = Symbol('skip');
373
+ const pageResults = yield Promise.all(smartRows.map((row) => __awaiter(void 0, void 0, void 0, function* () {
374
+ if (dedupeKeys) {
375
+ const key = yield options.dedupe(row);
376
+ if (dedupeKeys.has(key))
377
+ return SKIP;
378
+ dedupeKeys.add(key);
379
+ }
380
+ return callback({ row, rowIndex: row.rowIndex, stop });
381
+ })));
382
+ for (const r of pageResults) {
383
+ if (r !== SKIP)
384
+ results.push(r);
385
+ }
386
+ }
387
+ else {
388
+ for (const row of smartRows) {
389
+ if (stopped)
390
+ break;
391
+ if (dedupeKeys) {
392
+ const key = yield options.dedupe(row);
393
+ if (dedupeKeys.has(key))
394
+ continue;
395
+ dedupeKeys.add(key);
396
+ }
397
+ results.push(yield callback({ row, rowIndex: row.rowIndex, stop }));
398
+ }
399
+ }
400
+ rowIndex += smartRows.length;
401
+ if (stopped || pagesScanned >= effectiveMaxPages)
402
+ break;
403
+ const context = { root: rootLocator, config, page: rootLocator.page(), resolve };
404
+ let advanced;
405
+ if (typeof config.strategies.pagination === 'function') {
406
+ advanced = !!(yield config.strategies.pagination(context));
407
+ }
408
+ else {
409
+ advanced = !!(((_c = config.strategies.pagination) === null || _c === void 0 ? void 0 : _c.goNext) && (yield config.strategies.pagination.goNext(context)));
410
+ }
411
+ if (!advanced)
412
+ break;
413
+ tableState.currentPageIndex++;
414
+ pagesScanned++;
415
+ }
416
+ return results;
417
+ }),
418
+ filter: (predicate_1, ...args_1) => __awaiter(void 0, [predicate_1, ...args_1], void 0, function* (predicate, options = {}) {
419
+ var _a, _b, _c;
420
+ yield _ensureInitialized();
421
+ const map = tableMapper.getMapSync();
422
+ const effectiveMaxPages = (_a = options.maxPages) !== null && _a !== void 0 ? _a : config.maxPages;
423
+ const dedupeKeys = options.dedupe ? new Set() : null;
424
+ const parallel = (_b = options.parallel) !== null && _b !== void 0 ? _b : false;
425
+ const matched = [];
426
+ let rowIndex = 0;
427
+ let stopped = false;
428
+ let pagesScanned = 1;
429
+ const stop = () => { stopped = true; };
430
+ while (!stopped) {
431
+ const pageRows = yield resolve(config.rowSelector, rootLocator).all();
432
+ const smartRows = pageRows.map((r, i) => _makeSmart(r, map, rowIndex + i, pagesScanned - 1));
433
+ if (parallel) {
434
+ const flags = yield Promise.all(smartRows.map((row) => __awaiter(void 0, void 0, void 0, function* () {
435
+ if (dedupeKeys) {
436
+ const key = yield options.dedupe(row);
437
+ if (dedupeKeys.has(key))
438
+ return false;
439
+ dedupeKeys.add(key);
440
+ }
441
+ return predicate({ row, rowIndex: row.rowIndex, stop });
442
+ })));
443
+ smartRows.forEach((row, i) => { if (flags[i])
444
+ matched.push(row); });
445
+ }
446
+ else {
447
+ for (const row of smartRows) {
448
+ if (stopped)
449
+ break;
450
+ if (dedupeKeys) {
451
+ const key = yield options.dedupe(row);
452
+ if (dedupeKeys.has(key))
453
+ continue;
454
+ dedupeKeys.add(key);
455
+ }
456
+ if (yield predicate({ row, rowIndex: row.rowIndex, stop })) {
457
+ matched.push(row);
458
+ }
459
+ }
460
+ }
461
+ rowIndex += smartRows.length;
462
+ if (stopped || pagesScanned >= effectiveMaxPages)
463
+ break;
464
+ const context = { root: rootLocator, config, page: rootLocator.page(), resolve };
465
+ let advanced;
466
+ if (typeof config.strategies.pagination === 'function') {
467
+ advanced = !!(yield config.strategies.pagination(context));
468
+ }
469
+ else {
470
+ advanced = !!(((_c = config.strategies.pagination) === null || _c === void 0 ? void 0 : _c.goNext) && (yield config.strategies.pagination.goNext(context)));
471
+ }
472
+ if (!advanced)
473
+ break;
474
+ tableState.currentPageIndex++;
475
+ pagesScanned++;
476
+ }
477
+ return (0, smartRowArray_1.createSmartRowArray)(matched);
478
+ }),
237
479
  iterateThroughTable: (callback, options) => __awaiter(void 0, void 0, void 0, function* () {
238
480
  var _a, _b, _c, _d, _e, _f, _g;
239
481
  yield _ensureInitialized();
@@ -245,6 +487,7 @@ const useTable = (rootLocator, configOptions = {}) => {
245
487
  yield result.init();
246
488
  const map = tableMapper.getMapSync();
247
489
  const restrictedTable = {
490
+ get currentPageIndex() { return tableState.currentPageIndex; },
248
491
  init: result.init,
249
492
  getHeaders: result.getHeaders,
250
493
  getHeaderCell: result.getHeaderCell,
@@ -258,6 +501,10 @@ const useTable = (rootLocator, configOptions = {}) => {
258
501
  scrollToColumn: result.scrollToColumn,
259
502
  revalidate: result.revalidate,
260
503
  generateConfigPrompt: result.generateConfigPrompt,
504
+ forEach: result.forEach,
505
+ map: result.map,
506
+ filter: result.filter,
507
+ [Symbol.asyncIterator]: result[Symbol.asyncIterator].bind(result),
261
508
  };
262
509
  const getIsFirst = (_b = options === null || options === void 0 ? void 0 : options.getIsFirst) !== null && _b !== void 0 ? _b : (({ index }) => index === 0);
263
510
  const getIsLast = (_c = options === null || options === void 0 ? void 0 : options.getIsLast) !== null && _c !== void 0 ? _c : (() => false);
@@ -339,10 +586,20 @@ const useTable = (rootLocator, configOptions = {}) => {
339
586
  let finalIsLast = isLastDueToMax;
340
587
  if (!isLastIteration) {
341
588
  const context = { root: rootLocator, config, page: rootLocator.page(), resolve };
342
- paginationResult = yield paginationStrategy(context);
589
+ if (typeof paginationStrategy === 'function') {
590
+ paginationResult = yield paginationStrategy(context);
591
+ }
592
+ else {
593
+ const pageObj = paginationStrategy;
594
+ if (!pageObj.goNext)
595
+ break;
596
+ paginationResult = yield pageObj.goNext(context);
597
+ }
343
598
  (0, debugUtils_1.logDebug)(config, 'info', `Pagination ${paginationResult ? 'succeeded' : 'failed'}`);
344
599
  yield (0, debugUtils_1.debugDelay)(config, 'pagination');
345
600
  finalIsLast = getIsLast({ index: callbackIndex, paginationResult }) || !paginationResult;
601
+ if (paginationResult)
602
+ tableState.currentPageIndex++;
346
603
  }
347
604
  if (finalIsLast && (options === null || options === void 0 ? void 0 : options.afterLast)) {
348
605
  yield options.afterLast({ index: callbackIndex, rows: (0, smartRowArray_1.createSmartRowArray)(callbackRows), allData });
@@ -360,9 +617,21 @@ const useTable = (rootLocator, configOptions = {}) => {
360
617
  else {
361
618
  // Continue paginating even when batching
362
619
  const context = { root: rootLocator, config, page: rootLocator.page(), resolve };
363
- paginationResult = yield paginationStrategy(context);
620
+ if (typeof paginationStrategy === 'function') {
621
+ paginationResult = yield paginationStrategy(context);
622
+ }
623
+ else {
624
+ const pageObj = paginationStrategy;
625
+ if (!pageObj.goNext) {
626
+ log(`Cannot paginate: no goNext primitive found.`);
627
+ break;
628
+ }
629
+ paginationResult = yield pageObj.goNext(context);
630
+ }
364
631
  (0, debugUtils_1.logDebug)(config, 'info', `Pagination ${paginationResult ? 'succeeded' : 'failed'} (batching mode)`);
365
632
  yield (0, debugUtils_1.debugDelay)(config, 'pagination');
633
+ if (paginationResult)
634
+ tableState.currentPageIndex++;
366
635
  if (!paginationResult) {
367
636
  // Pagination failed, invoke callback with current batch
368
637
  const callbackIndex = batchStartIndex;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rickcedwhat/playwright-smart-table",
3
- "version": "6.4.0",
3
+ "version": "6.6.0",
4
4
  "description": "Smart, column-aware table interactions for Playwright",
5
5
  "author": "Cedrick Catalan",
6
6
  "license": "MIT",