@flrande/bak-extension 0.6.11 → 0.6.13

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/src/content.ts CHANGED
@@ -11,11 +11,22 @@ import type {
11
11
  PageMetrics,
12
12
  PageTextChunk,
13
13
  TableColumn,
14
- TableHandle
14
+ TableExtractionMetadata,
15
+ TableHandle,
16
+ TableIntelligence
15
17
  } from '@flrande/bak-protocol';
16
- import { documentMetadata, isDocumentNode, isShadowRootNode } from './context-metadata.js';
18
+ import { documentMetadata, isDocumentNode, isShadowRootNode } from './context-metadata.js';
19
+ import {
20
+ buildExtractionMetadata,
21
+ buildTableIntelligence,
22
+ collectTimestampProbes,
23
+ estimateSampleSize,
24
+ inferSchemaHint,
25
+ sampleValue,
26
+ type InlineJsonInspectionSource
27
+ } from './dynamic-data-tools.js';
17
28
  import { inferSafeName, redactElementText, redactHtmlSnapshot, type RedactTextOptions } from './privacy.js';
18
- import { unsupportedLocatorHint } from './limitations.js';
29
+ import { unsupportedLocatorHint } from './limitations.js';
19
30
 
20
31
  type ActionName =
21
32
  | 'click'
@@ -1785,6 +1796,135 @@ function buildTableId(kind: TableHandle['kind'], index: number): string {
1785
1796
  return `${kind}:${index + 1}`;
1786
1797
  }
1787
1798
 
1799
+ function gridRowNodes(grid: Element): HTMLElement[] {
1800
+ return Array.from(grid.querySelectorAll<HTMLElement>('[role="row"]')).filter(
1801
+ (row) => row.querySelector('[role="gridcell"], [role="cell"]') !== null
1802
+ );
1803
+ }
1804
+
1805
+ function tableSchemaFromElement(element: Element): TableColumn[] {
1806
+ return element instanceof HTMLTableElement ? htmlTableSchema(element) : gridSchema(element);
1807
+ }
1808
+
1809
+ function tableRowsFromElement(element: Element, limit: number): Array<Record<string, unknown>> {
1810
+ return element instanceof HTMLTableElement ? htmlTableRows(element, limit) : gridRows(element, limit);
1811
+ }
1812
+
1813
+ function findScrollableTableContainer(element: Element): HTMLElement | null {
1814
+ const explicitCandidate =
1815
+ (isHtmlElement(element) && (element.matches('[data-bak-scroll-root], [data-virtual-scroll]') ? element : null)) ||
1816
+ ('querySelector' in element
1817
+ ? (element.querySelector<HTMLElement>('[data-bak-scroll-root], [data-virtual-scroll]') ?? null)
1818
+ : null);
1819
+ if (explicitCandidate) {
1820
+ return explicitCandidate;
1821
+ }
1822
+
1823
+ const candidates: HTMLElement[] = [];
1824
+ if (isHtmlElement(element)) {
1825
+ candidates.push(element);
1826
+ }
1827
+ if ('querySelectorAll' in element) {
1828
+ candidates.push(...Array.from(element.querySelectorAll<HTMLElement>('[role="rowgroup"], *')));
1829
+ }
1830
+ let current: HTMLElement | null = element.parentElement;
1831
+ while (current && candidates.length < 80) {
1832
+ candidates.push(current);
1833
+ current = current.parentElement;
1834
+ }
1835
+ const uniqueCandidates = [...new Set(candidates)];
1836
+ return (
1837
+ uniqueCandidates.find((candidate) => {
1838
+ const style = getComputedStyle(candidate);
1839
+ return (
1840
+ (style.overflowY === 'auto' || style.overflowY === 'scroll') &&
1841
+ candidate.scrollHeight > candidate.clientHeight + 4 &&
1842
+ candidate.clientHeight > 0
1843
+ );
1844
+ }) ?? null
1845
+ );
1846
+ }
1847
+
1848
+ function observedRowIndexes(rows: HTMLElement[]): number[] {
1849
+ return rows
1850
+ .map((row) => {
1851
+ const raw = row.getAttribute('aria-rowindex') || row.getAttribute('data-row-index') || row.dataset.rowIndex;
1852
+ const parsed = raw ? Number.parseInt(raw, 10) : Number.NaN;
1853
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
1854
+ })
1855
+ .filter((value): value is number => value !== null);
1856
+ }
1857
+
1858
+ function inferEstimatedTotalRows(element: Element, rows: HTMLElement[], scrollContainer: HTMLElement | null): number | undefined {
1859
+ const attrCandidates = [
1860
+ element.getAttribute('aria-rowcount'),
1861
+ (scrollContainer ?? undefined)?.getAttribute('aria-rowcount'),
1862
+ element.getAttribute('data-total-rows'),
1863
+ (scrollContainer ?? undefined)?.getAttribute('data-total-rows')
1864
+ ]
1865
+ .filter((candidate): candidate is string => typeof candidate === 'string' && candidate.trim().length > 0)
1866
+ .map((candidate) => Number.parseInt(candidate, 10))
1867
+ .filter((candidate) => Number.isFinite(candidate) && candidate > 0);
1868
+ if (attrCandidates.length > 0) {
1869
+ return Math.max(...attrCandidates);
1870
+ }
1871
+ const indexes = observedRowIndexes(rows);
1872
+ if (indexes.length > 0) {
1873
+ return Math.max(...indexes);
1874
+ }
1875
+ const rowHeight = rows[0]?.getBoundingClientRect().height ?? 0;
1876
+ if (scrollContainer && rowHeight > 0) {
1877
+ const estimate = Math.round(scrollContainer.scrollHeight / rowHeight);
1878
+ if (estimate > rows.length) {
1879
+ return estimate;
1880
+ }
1881
+ }
1882
+ return undefined;
1883
+ }
1884
+
1885
+ function tableIntelligenceForElement(table: TableHandle, element: Element): TableIntelligence {
1886
+ if (element instanceof HTMLTableElement) {
1887
+ return buildTableIntelligence({
1888
+ kind: table.kind,
1889
+ visibleRowCount: htmlTableRows(element, Number.MAX_SAFE_INTEGER).length,
1890
+ rowCount: table.rowCount,
1891
+ estimatedTotalRows: table.rowCount,
1892
+ hasScrollContainer: false,
1893
+ hasTranslatedRows: false,
1894
+ knownGridKind: false
1895
+ });
1896
+ }
1897
+ const rows = gridRowNodes(element);
1898
+ const scrollContainer = findScrollableTableContainer(element);
1899
+ const rowIndexes = observedRowIndexes(rows);
1900
+ const estimatedTotalRows = inferEstimatedTotalRows(element, rows, scrollContainer);
1901
+ const hasTranslatedRows = rows.some((row) => {
1902
+ const style = row.style.transform || getComputedStyle(row).transform;
1903
+ return typeof style === 'string' && style !== '' && style !== 'none';
1904
+ });
1905
+ return buildTableIntelligence({
1906
+ kind: table.kind,
1907
+ visibleRowCount: rows.length,
1908
+ rowCount: table.rowCount,
1909
+ estimatedTotalRows,
1910
+ hasScrollContainer: scrollContainer !== null,
1911
+ hasTranslatedRows,
1912
+ maxObservedRowIndex: rowIndexes.length > 0 ? Math.max(...rowIndexes) : undefined,
1913
+ minObservedRowIndex: rowIndexes.length > 0 ? Math.min(...rowIndexes) : undefined,
1914
+ knownGridKind: table.kind !== 'aria-grid'
1915
+ });
1916
+ }
1917
+
1918
+ function withTableIntelligence(table: TableHandle, element: Element | null): TableHandle {
1919
+ if (!(element instanceof Element)) {
1920
+ return table;
1921
+ }
1922
+ return {
1923
+ ...table,
1924
+ intelligence: tableIntelligenceForElement(table, element)
1925
+ };
1926
+ }
1927
+
1788
1928
  function describeTables(): TableHandle[] {
1789
1929
  const rootResult = resolveRootForLocator();
1790
1930
  if (!rootResult.ok) {
@@ -1794,26 +1934,28 @@ function describeTables(): TableHandle[] {
1794
1934
  const tables: TableHandle[] = [];
1795
1935
  const htmlTables = Array.from(root.querySelectorAll('table'));
1796
1936
  for (const [index, table] of htmlTables.entries()) {
1797
- tables.push({
1937
+ const handle: TableHandle = {
1798
1938
  id: buildTableId(table.closest('.dataTables_wrapper') ? 'dataTables' : 'html', index),
1799
1939
  name: (table.getAttribute('aria-label') || table.getAttribute('data-testid') || table.id || `table-${index + 1}`).trim(),
1800
1940
  kind: table.closest('.dataTables_wrapper') ? 'dataTables' : 'html',
1801
1941
  selector: table.id ? `#${table.id}` : undefined,
1802
1942
  rowCount: table.querySelectorAll('tbody tr').length || table.querySelectorAll('tr').length,
1803
1943
  columnCount: table.querySelectorAll('thead th').length || table.querySelectorAll('tr:first-child th, tr:first-child td').length
1804
- });
1944
+ };
1945
+ tables.push(withTableIntelligence(handle, table));
1805
1946
  }
1806
1947
  const gridRoots = Array.from(root.querySelectorAll<HTMLElement>('[role="grid"], [role="table"], .ag-root, .ag-root-wrapper'));
1807
1948
  for (const [index, grid] of gridRoots.entries()) {
1808
1949
  const kind: TableHandle['kind'] = grid.className.includes('ag-') ? 'ag-grid' : 'aria-grid';
1809
- tables.push({
1950
+ const handle: TableHandle = {
1810
1951
  id: buildTableId(kind, index),
1811
1952
  name: (grid.getAttribute('aria-label') || grid.getAttribute('data-testid') || grid.id || `grid-${index + 1}`).trim(),
1812
1953
  kind,
1813
1954
  selector: grid.id ? `#${grid.id}` : undefined,
1814
- rowCount: grid.querySelectorAll('[role="row"]').length,
1955
+ rowCount: gridRowNodes(grid).length,
1815
1956
  columnCount: grid.querySelectorAll('[role="columnheader"]').length
1816
- });
1957
+ };
1958
+ tables.push(withTableIntelligence(handle, grid));
1817
1959
  }
1818
1960
  return tables;
1819
1961
  }
@@ -1878,11 +2020,11 @@ function gridSchema(grid: Element): TableColumn[] {
1878
2020
 
1879
2021
  function gridRows(grid: Element, limit: number): Array<Record<string, unknown>> {
1880
2022
  const columns = gridSchema(grid);
1881
- return Array.from(grid.querySelectorAll('[role="row"]'))
2023
+ return gridRowNodes(grid)
1882
2024
  .slice(0, limit)
1883
2025
  .map((row) => {
1884
2026
  const record: Record<string, unknown> = {};
1885
- Array.from(row.querySelectorAll('[role="gridcell"], [role="cell"], [role="columnheader"]')).forEach((cell, index) => {
2027
+ Array.from(row.querySelectorAll('[role="gridcell"], [role="cell"]')).forEach((cell, index) => {
1886
2028
  const key = columns[index]?.label ?? `Column ${index + 1}`;
1887
2029
  record[key] = (cell.textContent ?? '').trim();
1888
2030
  });
@@ -1891,6 +2033,187 @@ function gridRows(grid: Element, limit: number): Array<Record<string, unknown>>
1891
2033
  .filter((row) => Object.values(row).some((value) => String(value).trim().length > 0));
1892
2034
  }
1893
2035
 
2036
+ function rowSignature(row: Record<string, unknown>): string {
2037
+ return JSON.stringify(
2038
+ Object.entries(row)
2039
+ .sort(([left], [right]) => left.localeCompare(right))
2040
+ .map(([key, value]) => [key, value === undefined ? null : value])
2041
+ );
2042
+ }
2043
+
2044
+ function mergeUniqueRows(target: Map<string, Record<string, unknown>>, rows: Array<Record<string, unknown>>, limit: number): number {
2045
+ let added = 0;
2046
+ for (const row of rows) {
2047
+ const signature = rowSignature(row);
2048
+ if (target.has(signature)) {
2049
+ continue;
2050
+ }
2051
+ target.set(signature, row);
2052
+ added += 1;
2053
+ if (target.size >= limit) {
2054
+ break;
2055
+ }
2056
+ }
2057
+ return added;
2058
+ }
2059
+
2060
+ function waitForPaint(frames = 2): Promise<void> {
2061
+ return new Promise((resolve) => {
2062
+ const schedule = (remaining: number): void => {
2063
+ if (remaining <= 0) {
2064
+ window.setTimeout(() => resolve(), 24);
2065
+ return;
2066
+ }
2067
+ requestAnimationFrame(() => schedule(remaining - 1));
2068
+ };
2069
+ schedule(frames);
2070
+ });
2071
+ }
2072
+
2073
+ function currentTableWindowSignature(element: Element): string {
2074
+ const rowIndexes = observedRowIndexes(gridRowNodes(element));
2075
+ if (rowIndexes.length > 0) {
2076
+ return `indexes:${rowIndexes.join(',')}`;
2077
+ }
2078
+ const visibleRows = tableRowsFromElement(element, 24);
2079
+ return `rows:${visibleRows.map((row) => rowSignature(row)).join('|')}`;
2080
+ }
2081
+
2082
+ async function waitForTableWindowChange(
2083
+ element: Element,
2084
+ previousSignature: string,
2085
+ timeoutMs = 200
2086
+ ): Promise<string> {
2087
+ const start = Date.now();
2088
+ let currentSignature = previousSignature;
2089
+ while (Date.now() - start < timeoutMs) {
2090
+ await waitForPaint(1);
2091
+ currentSignature = currentTableWindowSignature(element);
2092
+ if (currentSignature !== previousSignature) {
2093
+ return currentSignature;
2094
+ }
2095
+ await new Promise((resolve) => window.setTimeout(resolve, 16));
2096
+ }
2097
+ return currentSignature;
2098
+ }
2099
+
2100
+ async function scrollExtractRows(
2101
+ element: Element,
2102
+ limit: number,
2103
+ intelligence?: TableIntelligence
2104
+ ): Promise<{ rows: Array<Record<string, unknown>>; extraction: TableExtractionMetadata; extractionMode: TableExtractionMetadata['mode'] }> {
2105
+ const scrollContainer = findScrollableTableContainer(element);
2106
+ if (!scrollContainer) {
2107
+ const rows = tableRowsFromElement(element, limit);
2108
+ return {
2109
+ rows,
2110
+ extractionMode: 'visibleOnly',
2111
+ extraction: buildExtractionMetadata('visibleOnly', rows, intelligence, [
2112
+ 'Fell back to visible rows because no scroll container was detected.'
2113
+ ])
2114
+ };
2115
+ }
2116
+
2117
+ const originalScrollTop = scrollContainer.scrollTop;
2118
+ const collected = new Map<string, Record<string, unknown>>();
2119
+ const seenRowIndexes = new Set<number>();
2120
+ let stagnantPasses = 0;
2121
+ let reachedEnd = false;
2122
+ let limitApplied = false;
2123
+ const rowHeight = gridRowNodes(element)[0]?.getBoundingClientRect().height ?? 0;
2124
+ const step = Math.max(80, Math.round(scrollContainer.clientHeight * 0.8), rowHeight > 0 ? Math.round(rowHeight * 4) : 0);
2125
+ const initialMaxScrollTop = Math.max(0, scrollContainer.scrollHeight - scrollContainer.clientHeight);
2126
+ const maxIterations = Math.max(8, Math.min(80, Math.ceil(initialMaxScrollTop / Math.max(step, 1)) + 6, limit * 2));
2127
+
2128
+ try {
2129
+ scrollContainer.scrollTop = 0;
2130
+ scrollContainer.dispatchEvent(new Event('scroll'));
2131
+ await waitForPaint();
2132
+ let currentWindowSignature = currentTableWindowSignature(element);
2133
+ for (let iteration = 0; iteration < maxIterations; iteration += 1) {
2134
+ const currentRows = tableRowsFromElement(element, limit);
2135
+ const added = mergeUniqueRows(collected, currentRows, limit);
2136
+ observedRowIndexes(gridRowNodes(element)).forEach((rowIndex) => {
2137
+ seenRowIndexes.add(rowIndex);
2138
+ });
2139
+ const estimatedTotalRows = intelligence?.estimatedTotalRows;
2140
+ if (
2141
+ typeof estimatedTotalRows === 'number' &&
2142
+ (collected.size >= estimatedTotalRows || seenRowIndexes.size >= estimatedTotalRows)
2143
+ ) {
2144
+ reachedEnd = true;
2145
+ break;
2146
+ }
2147
+ if (collected.size >= limit) {
2148
+ limitApplied = true;
2149
+ break;
2150
+ }
2151
+ if (added === 0) {
2152
+ stagnantPasses += 1;
2153
+ } else {
2154
+ stagnantPasses = 0;
2155
+ }
2156
+ const maxScrollTop = Math.max(0, scrollContainer.scrollHeight - scrollContainer.clientHeight);
2157
+ if (scrollContainer.scrollTop >= maxScrollTop - 2) {
2158
+ reachedEnd = true;
2159
+ if (stagnantPasses >= 1) {
2160
+ break;
2161
+ }
2162
+ }
2163
+ if (stagnantPasses >= 2) {
2164
+ break;
2165
+ }
2166
+ const nextScrollTop = Math.min(maxScrollTop, scrollContainer.scrollTop + step);
2167
+ if (nextScrollTop === scrollContainer.scrollTop) {
2168
+ reachedEnd = true;
2169
+ break;
2170
+ }
2171
+ scrollContainer.scrollTop = nextScrollTop;
2172
+ scrollContainer.dispatchEvent(new Event('scroll'));
2173
+ currentWindowSignature = await waitForTableWindowChange(element, currentWindowSignature);
2174
+ }
2175
+ if (!reachedEnd) {
2176
+ const maxScrollTop = Math.max(0, scrollContainer.scrollHeight - scrollContainer.clientHeight);
2177
+ if (scrollContainer.scrollTop < maxScrollTop) {
2178
+ const previousWindowSignature = currentTableWindowSignature(element);
2179
+ scrollContainer.scrollTop = maxScrollTop;
2180
+ scrollContainer.dispatchEvent(new Event('scroll'));
2181
+ await waitForTableWindowChange(element, previousWindowSignature);
2182
+ mergeUniqueRows(collected, tableRowsFromElement(element, limit), limit);
2183
+ observedRowIndexes(gridRowNodes(element)).forEach((rowIndex) => {
2184
+ seenRowIndexes.add(rowIndex);
2185
+ });
2186
+ }
2187
+ }
2188
+ } finally {
2189
+ scrollContainer.scrollTop = originalScrollTop;
2190
+ await waitForPaint();
2191
+ }
2192
+
2193
+ const rows = [...collected.values()].slice(0, limit);
2194
+ if (
2195
+ typeof intelligence?.estimatedTotalRows === 'number' &&
2196
+ (rows.length >= intelligence.estimatedTotalRows || seenRowIndexes.size >= intelligence.estimatedTotalRows)
2197
+ ) {
2198
+ reachedEnd = true;
2199
+ }
2200
+ const warnings: string[] = [];
2201
+ if (limitApplied) {
2202
+ warnings.push('Stopped after reaching maxRows before confirming the end of the table.');
2203
+ }
2204
+ if (!reachedEnd && (intelligence?.estimatedTotalRows ?? rows.length) > rows.length) {
2205
+ warnings.push('Could not confirm the end of scrollable content; result may be partial.');
2206
+ }
2207
+ return {
2208
+ rows,
2209
+ extractionMode: 'scroll',
2210
+ extraction: buildExtractionMetadata('scroll', rows, intelligence, warnings, {
2211
+ reachedEnd,
2212
+ limitApplied
2213
+ })
2214
+ };
2215
+ }
2216
+
1894
2217
  function runPageWorldRequest<T>(action: string, payload: Record<string, unknown>): Promise<T> {
1895
2218
  const requestId = `bak_page_world_${Date.now()}_${Math.random().toString(16).slice(2)}`;
1896
2219
  return new Promise<T>((resolve, reject) => {
@@ -2284,6 +2607,34 @@ async function globalsPreview(): Promise<string[]> {
2284
2607
  .slice(0, 50);
2285
2608
  }
2286
2609
 
2610
+ function collectInlineJsonSources(root: ParentNode): InlineJsonInspectionSource[] {
2611
+ const scripts = Array.from(root.querySelectorAll<HTMLScriptElement>('script[type="application/json"], script[type="application/ld+json"]'));
2612
+ return scripts
2613
+ .map((script, index) => {
2614
+ const raw = script.textContent?.trim() ?? '';
2615
+ if (!raw) {
2616
+ return null;
2617
+ }
2618
+ try {
2619
+ const parsed = JSON.parse(raw);
2620
+ const path = script.id ? `#${script.id}` : `inline-json:${index + 1}`;
2621
+ const timestamps = collectTimestampProbes(parsed, path);
2622
+ return {
2623
+ label: script.id || script.getAttribute('data-testid') || script.type || `inline-json-${index + 1}`,
2624
+ path,
2625
+ sample: sampleValue(parsed),
2626
+ sampleSize: estimateSampleSize(parsed),
2627
+ schemaHint: inferSchemaHint(parsed),
2628
+ lastObservedAt: timestamps.length > 0 ? Math.max(...timestamps.map((item) => Date.parse(item.value)).filter(Number.isFinite)) : null,
2629
+ timestamps
2630
+ } satisfies InlineJsonInspectionSource;
2631
+ } catch {
2632
+ return null;
2633
+ }
2634
+ })
2635
+ .filter((item): item is InlineJsonInspectionSource => item !== null);
2636
+ }
2637
+
2287
2638
  async function collectInspectionState(params: Record<string, unknown> = {}): Promise<Record<string, unknown>> {
2288
2639
  const rootResult = resolveRootForLocator();
2289
2640
  if (!rootResult.ok) {
@@ -2304,6 +2655,7 @@ async function collectInspectionState(params: Record<string, unknown> = {}): Pro
2304
2655
  );
2305
2656
  const previewGlobals = await globalsPreview();
2306
2657
  const suspiciousGlobals = [...new Set(scripts.flatMap((script) => script.suspectedVars))].slice(0, 50);
2658
+ const inlineJsonSources = collectInlineJsonSources(root);
2307
2659
  return {
2308
2660
  url: metadata.url,
2309
2661
  title: metadata.title,
@@ -2322,6 +2674,7 @@ async function collectInspectionState(params: Record<string, unknown> = {}): Pro
2322
2674
  storage: storageMetadata(),
2323
2675
  cookies: cookieMetadata(),
2324
2676
  frames: collectFrames(),
2677
+ inlineJsonSources,
2325
2678
  tables: describeTables(),
2326
2679
  timers: {
2327
2680
  timeouts: 0,
@@ -3076,12 +3429,10 @@ async function dispatchRpc(method: string, params: Record<string, unknown> = {})
3076
3429
  if (!resolved || !(resolved.element instanceof Element)) {
3077
3430
  throw { code: 'E_NOT_FOUND', message: `table not found: ${String(params.table ?? '')}` } satisfies ActionError;
3078
3431
  }
3079
- const schema =
3080
- resolved.element instanceof HTMLTableElement
3081
- ? { columns: htmlTableSchema(resolved.element) }
3082
- : { columns: gridSchema(resolved.element) };
3432
+ const table = withTableIntelligence(resolved.table, resolved.element);
3433
+ const schema = { columns: tableSchemaFromElement(resolved.element) };
3083
3434
  return {
3084
- table: resolved.table,
3435
+ table,
3085
3436
  schema
3086
3437
  };
3087
3438
  }
@@ -3099,15 +3450,32 @@ async function dispatchRpc(method: string, params: Record<string, unknown> = {})
3099
3450
  : typeof params.limit === 'number'
3100
3451
  ? Math.max(1, Math.floor(params.limit))
3101
3452
  : 100;
3102
- const extractionMode =
3103
- resolved.table.kind === 'html' || resolved.table.kind === 'dataTables' ? 'dataSource' : 'visibleOnly';
3104
- const rows =
3105
- resolved.element instanceof HTMLTableElement
3106
- ? htmlTableRows(resolved.element, requestedLimit)
3107
- : gridRows(resolved.element, requestedLimit);
3453
+ const table = withTableIntelligence(resolved.table, resolved.element);
3454
+ let rows = tableRowsFromElement(resolved.element, requestedLimit);
3455
+ let extractionMode: TableExtractionMetadata['mode'] =
3456
+ table.intelligence?.preferredExtractionMode ?? (resolved.element instanceof HTMLTableElement ? 'dataSource' : 'visibleOnly');
3457
+ let extraction = buildExtractionMetadata(
3458
+ extractionMode,
3459
+ rows,
3460
+ table.intelligence,
3461
+ params.all === true && extractionMode === 'visibleOnly'
3462
+ ? ['Only visible rows could be read from this table region.']
3463
+ : [],
3464
+ {
3465
+ reachedEnd: extractionMode === 'dataSource',
3466
+ limitApplied: params.all === true && rows.length >= requestedLimit
3467
+ }
3468
+ );
3469
+ if (params.all === true && extractionMode === 'scroll') {
3470
+ const scrolled = await scrollExtractRows(resolved.element, requestedLimit, table.intelligence);
3471
+ rows = scrolled.rows;
3472
+ extractionMode = scrolled.extractionMode;
3473
+ extraction = scrolled.extraction;
3474
+ }
3108
3475
  return {
3109
- table: resolved.table,
3476
+ table,
3110
3477
  extractionMode,
3478
+ extraction,
3111
3479
  rows
3112
3480
  };
3113
3481
  }