@bilig/headless 0.2.0 → 0.3.1

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.
@@ -1,20 +1,37 @@
1
1
  import { indexToColumn } from '@bilig/formula';
2
- import { ValueTag } from '@bilig/protocol';
2
+ import { makeCellKey } from '@bilig/core';
3
+ import { ErrorCode, ValueTag } from '@bilig/protocol';
4
+ const COLUMN_LABEL_CACHE = [];
5
+ const DEFERRED_TRACKED_INDEX_CHANGES = new WeakMap();
6
+ const LAZY_PUBLIC_CHANGE_SOURCE_THRESHOLD = 256;
3
7
  export function materializeTrackedIndexChangesWithMetadata(engine, changedCellIndices, options = {}) {
4
8
  if (changedCellIndices.length === 0) {
5
9
  return { changes: [], ordered: true };
6
10
  }
7
11
  const workbook = engine.workbook;
8
12
  const cellStore = workbook.cellStore;
9
- const columnLabels = [];
10
13
  const formatAddressCached = (row, col) => {
11
- let label = columnLabels[col];
14
+ let label = COLUMN_LABEL_CACHE[col];
12
15
  if (label === undefined) {
13
16
  label = indexToColumn(col);
14
- columnLabels[col] = label;
17
+ COLUMN_LABEL_CACHE[col] = label;
15
18
  }
16
19
  return `${label}${row + 1}`;
17
20
  };
21
+ if (options.lazy && options.trustedPhysicalSheetId !== undefined) {
22
+ const sheet = workbook.getSheetById(options.trustedPhysicalSheetId);
23
+ if (!sheet || sheet.structureVersion === 1) {
24
+ const split = options.trustedSortedSliceSplit !== undefined &&
25
+ options.trustedSortedSliceSplit > 0 &&
26
+ options.trustedSortedSliceSplit < changedCellIndices.length
27
+ ? options.trustedSortedSliceSplit
28
+ : undefined;
29
+ return {
30
+ changes: createLazyPhysicalTrackedIndexChanges(options.trustedPhysicalSheetId, sheet?.name ?? workbook.getSheetNameById(options.trustedPhysicalSheetId), cellStore, engine, changedCellIndices, formatAddressCached, split),
31
+ ordered: true,
32
+ };
33
+ }
34
+ }
18
35
  let firstSheetId;
19
36
  for (let index = 0; index < changedCellIndices.length; index += 1) {
20
37
  const sheetId = cellStore.sheetIds[changedCellIndices[index]];
@@ -26,6 +43,14 @@ export function materializeTrackedIndexChangesWithMetadata(engine, changedCellIn
26
43
  if (firstSheetId === undefined) {
27
44
  return { changes: [], ordered: true };
28
45
  }
46
+ if (options.lazy) {
47
+ const lazyPhysicalChanges = tryCreateLazyPhysicalTrackedIndexChanges(engine, changedCellIndices, firstSheetId, formatAddressCached, {
48
+ sortedSliceSplit: options.explicitChangedCount,
49
+ });
50
+ if (lazyPhysicalChanges) {
51
+ return { changes: lazyPhysicalChanges, ordered: true };
52
+ }
53
+ }
29
54
  let isSingleSheetChangeSet = true;
30
55
  for (let index = 0; index < changedCellIndices.length; index += 1) {
31
56
  const sheetId = cellStore.sheetIds[changedCellIndices[index]];
@@ -46,6 +71,12 @@ export function materializeTrackedIndexChangesWithMetadata(engine, changedCellIn
46
71
  split < changedCellIndices.length &&
47
72
  isTrackedIndexSliceSorted(cellStore, changedCellIndices, 0, split) &&
48
73
  isTrackedIndexSliceSorted(cellStore, changedCellIndices, split, changedCellIndices.length)) {
74
+ if (options.lazy && trackedIndicesAllBelongToSheet(cellStore, changedCellIndices, firstSheetId)) {
75
+ return {
76
+ changes: createLazyPhysicalTrackedIndexChanges(firstSheetId, sheetName, cellStore, engine, changedCellIndices, formatAddressCached, split),
77
+ ordered: true,
78
+ };
79
+ }
49
80
  let explicitIndex = 0;
50
81
  let recalculatedIndex = split;
51
82
  while (explicitIndex < split && recalculatedIndex < changedCellIndices.length) {
@@ -70,6 +101,15 @@ export function materializeTrackedIndexChangesWithMetadata(engine, changedCellIn
70
101
  }
71
102
  return { changes, ordered: true };
72
103
  }
104
+ if (options.lazy &&
105
+ isPhysicalSheet &&
106
+ trackedIndicesAllBelongToSheet(cellStore, changedCellIndices, firstSheetId) &&
107
+ isTrackedIndexSliceSorted(cellStore, changedCellIndices, 0, changedCellIndices.length)) {
108
+ return {
109
+ changes: createLazyPhysicalTrackedIndexChanges(firstSheetId, sheetName, cellStore, engine, changedCellIndices, formatAddressCached),
110
+ ordered: true,
111
+ };
112
+ }
73
113
  let ordered = true;
74
114
  let previousRow = -1;
75
115
  let previousCol = -1;
@@ -169,6 +209,108 @@ export function materializeTrackedIndexChangesWithMetadata(engine, changedCellIn
169
209
  export function materializeTrackedIndexChanges(engine, changedCellIndices, options = {}) {
170
210
  return materializeTrackedIndexChangesWithMetadata(engine, changedCellIndices, options).changes;
171
211
  }
212
+ export function materializeTrackedIndexChangeSourcesWithMetadata(engine, sources, options = {}) {
213
+ if (sources.length === 0) {
214
+ return { changes: [], ordered: true, usedSortedDisjointFastPath: true };
215
+ }
216
+ for (const source of sources) {
217
+ if (source.invalidation === 'full' ||
218
+ (source.patches !== undefined && source.patches.length > 0) ||
219
+ source.hasInvalidatedRanges ||
220
+ source.hasInvalidatedRows ||
221
+ source.hasInvalidatedColumns) {
222
+ return null;
223
+ }
224
+ }
225
+ const lazySameSheetChanges = tryCreateLazySameSheetTrackedSourceChanges(engine, sources, {
226
+ deferLazyDetach: options.deferLazyDetach === true,
227
+ preferLazyPublicChanges: options.lazy === true,
228
+ });
229
+ if (lazySameSheetChanges) {
230
+ return lazySameSheetChanges;
231
+ }
232
+ if (sources.length === 1) {
233
+ const materialized = materializeTrackedIndexChangesWithMetadata(engine, sources[0].changedCellIndices, {
234
+ ...options,
235
+ explicitChangedCount: sources[0].explicitChangedCount,
236
+ });
237
+ return {
238
+ changes: materialized.changes,
239
+ ordered: materialized.ordered,
240
+ usedSortedDisjointFastPath: materialized.ordered && trackedSourceHasSortedDisjointIndices(sources[0]),
241
+ };
242
+ }
243
+ const materializedSources = Array.from({ length: sources.length }, () => undefined);
244
+ const sheetOrders = sheetOrderLookup(engine);
245
+ const fastChanges = [];
246
+ let previousNumericCellIndex = -1;
247
+ let previousPublicChange;
248
+ let canUseSortedDisjointFastPath = true;
249
+ for (let sourceIndex = 0; sourceIndex < sources.length; sourceIndex += 1) {
250
+ const source = sources[sourceIndex];
251
+ if (!trackedSourceHasSortedDisjointIndices(source)) {
252
+ canUseSortedDisjointFastPath = false;
253
+ break;
254
+ }
255
+ if (source.changedCellIndices.length > 0) {
256
+ const first = source.firstChangedCellIndex ?? source.changedCellIndices[0];
257
+ const last = source.lastChangedCellIndex ?? source.changedCellIndices[source.changedCellIndices.length - 1];
258
+ if (first <= previousNumericCellIndex) {
259
+ canUseSortedDisjointFastPath = false;
260
+ break;
261
+ }
262
+ previousNumericCellIndex = last;
263
+ }
264
+ const materialized = materializeTrackedIndexChangesWithMetadata(engine, source.changedCellIndices, {
265
+ ...options,
266
+ explicitChangedCount: source.explicitChangedCount,
267
+ });
268
+ materializedSources[sourceIndex] = materialized;
269
+ if (!materialized.ordered) {
270
+ canUseSortedDisjointFastPath = false;
271
+ break;
272
+ }
273
+ for (let changeIndex = 0; changeIndex < materialized.changes.length; changeIndex += 1) {
274
+ const change = materialized.changes[changeIndex];
275
+ if (previousPublicChange !== undefined) {
276
+ const comparison = compareTrackedCellChanges(previousPublicChange, change, sheetOrders);
277
+ if (comparison >= 0) {
278
+ canUseSortedDisjointFastPath = false;
279
+ break;
280
+ }
281
+ }
282
+ fastChanges.push(change);
283
+ previousPublicChange = change;
284
+ }
285
+ if (!canUseSortedDisjointFastPath) {
286
+ break;
287
+ }
288
+ }
289
+ if (canUseSortedDisjointFastPath) {
290
+ return { changes: fastChanges, ordered: true, usedSortedDisjointFastPath: true };
291
+ }
292
+ return materializeTrackedIndexChangeSourcesGeneric(engine, sources, materializedSources, options, sheetOrders);
293
+ }
294
+ export function forceMaterializeTrackedIndexChanges(changes) {
295
+ const deferred = DEFERRED_TRACKED_INDEX_CHANGES.get(changes);
296
+ if (deferred === undefined) {
297
+ return false;
298
+ }
299
+ deferred.forceMaterialize();
300
+ DEFERRED_TRACKED_INDEX_CHANGES.delete(changes);
301
+ return true;
302
+ }
303
+ export function detachTrackedIndexChanges(changes, options = {}) {
304
+ const deferred = DEFERRED_TRACKED_INDEX_CHANGES.get(changes);
305
+ if (deferred === undefined) {
306
+ return false;
307
+ }
308
+ deferred.detach(options);
309
+ return true;
310
+ }
311
+ export function hasDeferredTrackedIndexChanges(changes) {
312
+ return DEFERRED_TRACKED_INDEX_CHANGES.has(changes);
313
+ }
172
314
  function readTrackedCellValue(cellStore, cellIndex, engine) {
173
315
  const tag = cellStore.tags[cellIndex] ?? ValueTag.Empty;
174
316
  switch (tag) {
@@ -185,6 +327,183 @@ function readTrackedCellValue(cellStore, cellIndex, engine) {
185
327
  return { tag: ValueTag.Empty };
186
328
  }
187
329
  }
330
+ function materializeTrackedIndexChangeSourcesGeneric(engine, sources, materializedSources, options, sheetOrders) {
331
+ const latestChangesByKey = new Map();
332
+ for (let sourceIndex = 0; sourceIndex < sources.length; sourceIndex += 1) {
333
+ const source = sources[sourceIndex];
334
+ const materialized = materializedSources[sourceIndex] ??
335
+ materializeTrackedIndexChangesWithMetadata(engine, source.changedCellIndices, {
336
+ ...options,
337
+ explicitChangedCount: source.explicitChangedCount,
338
+ });
339
+ for (let changeIndex = 0; changeIndex < materialized.changes.length; changeIndex += 1) {
340
+ const change = materialized.changes[changeIndex];
341
+ const key = makeCellKey(change.address.sheet, change.address.row, change.address.col);
342
+ latestChangesByKey.delete(key);
343
+ latestChangesByKey.set(key, change);
344
+ }
345
+ }
346
+ return {
347
+ changes: orderTrackedCellChanges([...latestChangesByKey.values()], sheetOrders),
348
+ ordered: true,
349
+ usedSortedDisjointFastPath: false,
350
+ };
351
+ }
352
+ function tryCreateLazySameSheetTrackedSourceChanges(engine, sources, options) {
353
+ let totalLength = 0;
354
+ for (let sourceIndex = 0; sourceIndex < sources.length; sourceIndex += 1) {
355
+ totalLength += sources[sourceIndex].changedCellIndices.length;
356
+ }
357
+ if (!options.preferLazyPublicChanges && totalLength < LAZY_PUBLIC_CHANGE_SOURCE_THRESHOLD) {
358
+ return null;
359
+ }
360
+ const workbook = engine.workbook;
361
+ const cellStore = workbook.cellStore;
362
+ const orderedSources = [];
363
+ let sheetId;
364
+ let previousNumericCellIndex = -1;
365
+ let previousLastCellIndex;
366
+ for (let sourceIndex = 0; sourceIndex < sources.length; sourceIndex += 1) {
367
+ const source = sources[sourceIndex];
368
+ if (!trackedSourceHasSortedDisjointIndices(source)) {
369
+ return null;
370
+ }
371
+ if (source.changedCellIndices.length === 0) {
372
+ continue;
373
+ }
374
+ const firstNumericCellIndex = source.firstChangedCellIndex ?? source.changedCellIndices[0];
375
+ const lastNumericCellIndex = source.lastChangedCellIndex ?? source.changedCellIndices[source.changedCellIndices.length - 1];
376
+ if (firstNumericCellIndex <= previousNumericCellIndex) {
377
+ return null;
378
+ }
379
+ previousNumericCellIndex = lastNumericCellIndex;
380
+ const sourceSheetId = cellStore.sheetIds[source.changedCellIndices[0]];
381
+ if (sourceSheetId === undefined) {
382
+ return null;
383
+ }
384
+ if (sheetId === undefined) {
385
+ sheetId = sourceSheetId;
386
+ }
387
+ else if (sourceSheetId !== sheetId) {
388
+ return null;
389
+ }
390
+ const sheet = workbook.getSheetById(sourceSheetId);
391
+ if (sheet && sheet.structureVersion !== 1) {
392
+ return null;
393
+ }
394
+ if (!trackedIndicesAllBelongToSheet(cellStore, source.changedCellIndices, sourceSheetId)) {
395
+ return null;
396
+ }
397
+ const orderedSource = orderedTrackedIndexSource(cellStore, source);
398
+ if (orderedSource === null) {
399
+ return null;
400
+ }
401
+ if (previousLastCellIndex !== undefined &&
402
+ compareTrackedPhysicalCellIndices(cellStore, previousLastCellIndex, orderedSource.firstCellIndex) >= 0) {
403
+ return null;
404
+ }
405
+ previousLastCellIndex = orderedSource.lastCellIndex;
406
+ orderedSources.push(orderedSource);
407
+ }
408
+ if (sheetId === undefined) {
409
+ return { changes: [], ordered: true, usedSortedDisjointFastPath: true };
410
+ }
411
+ const orderedCellIndices = new Uint32Array(totalLength);
412
+ let offset = 0;
413
+ for (let sourceIndex = 0; sourceIndex < orderedSources.length; sourceIndex += 1) {
414
+ const source = orderedSources[sourceIndex];
415
+ offset = copyOrderedTrackedCellIndices(cellStore, source.changedCellIndices, orderedCellIndices, offset, source.sortedSliceSplit);
416
+ }
417
+ const sheet = workbook.getSheetById(sheetId);
418
+ const sheetName = sheet?.name ?? workbook.getSheetNameById(sheetId);
419
+ const changes = createLazyPhysicalTrackedIndexChanges(sheetId, sheetName, cellStore, engine, orderedCellIndices, formatTrackedAddress);
420
+ if (!options.deferLazyDetach) {
421
+ detachTrackedIndexChanges(changes);
422
+ }
423
+ return { changes, ordered: true, usedSortedDisjointFastPath: true };
424
+ }
425
+ function orderedTrackedIndexSource(cellStore, source) {
426
+ const length = source.changedCellIndices.length;
427
+ const split = source.explicitChangedCount;
428
+ if (split !== undefined && split > 0 && split < length) {
429
+ if (!isTrackedIndexSliceSorted(cellStore, source.changedCellIndices, 0, split) ||
430
+ !isTrackedIndexSliceSorted(cellStore, source.changedCellIndices, split, length)) {
431
+ return null;
432
+ }
433
+ const firstLeft = source.changedCellIndices[0];
434
+ const firstRight = source.changedCellIndices[split];
435
+ const lastLeft = source.changedCellIndices[split - 1];
436
+ const lastRight = source.changedCellIndices[length - 1];
437
+ return {
438
+ changedCellIndices: source.changedCellIndices,
439
+ sortedSliceSplit: split,
440
+ firstCellIndex: compareTrackedPhysicalCellIndices(cellStore, firstLeft, firstRight) <= 0 ? firstLeft : firstRight,
441
+ lastCellIndex: compareTrackedPhysicalCellIndices(cellStore, lastLeft, lastRight) >= 0 ? lastLeft : lastRight,
442
+ };
443
+ }
444
+ if (!isTrackedIndexSliceSorted(cellStore, source.changedCellIndices, 0, length)) {
445
+ return null;
446
+ }
447
+ return {
448
+ changedCellIndices: source.changedCellIndices,
449
+ firstCellIndex: source.changedCellIndices[0],
450
+ lastCellIndex: source.changedCellIndices[length - 1],
451
+ };
452
+ }
453
+ function trackedSourceHasSortedDisjointIndices(source) {
454
+ if (source.changedCellIndicesSortedDisjoint !== undefined) {
455
+ return source.changedCellIndicesSortedDisjoint;
456
+ }
457
+ let previous = -1;
458
+ for (let index = 0; index < source.changedCellIndices.length; index += 1) {
459
+ const cellIndex = source.changedCellIndices[index];
460
+ if (!Number.isInteger(cellIndex) || cellIndex < 0 || cellIndex <= previous) {
461
+ return false;
462
+ }
463
+ previous = cellIndex;
464
+ }
465
+ return true;
466
+ }
467
+ function sheetOrderLookup(engine) {
468
+ const sheetOrders = new Map();
469
+ engine.workbook.sheetsById.forEach((sheet, sheetId) => {
470
+ sheetOrders.set(sheetId, sheet.order);
471
+ });
472
+ return sheetOrders;
473
+ }
474
+ function compareTrackedCellChanges(left, right, sheetOrders) {
475
+ return ((sheetOrders.get(left.address.sheet) ?? 0) - (sheetOrders.get(right.address.sheet) ?? 0) ||
476
+ left.address.row - right.address.row ||
477
+ left.address.col - right.address.col);
478
+ }
479
+ function orderTrackedCellChanges(changes, sheetOrders) {
480
+ if (changes.length < 2) {
481
+ return changes;
482
+ }
483
+ if (isTrackedCellChangeSliceSorted(changes, sheetOrders, 0, changes.length)) {
484
+ return changes;
485
+ }
486
+ if (isTrackedCellChangeSliceReverseSorted(changes, sheetOrders, 0, changes.length)) {
487
+ return changes.toReversed();
488
+ }
489
+ return changes.toSorted((left, right) => compareTrackedCellChanges(left, right, sheetOrders));
490
+ }
491
+ function isTrackedCellChangeSliceSorted(changes, sheetOrders, start, end) {
492
+ for (let index = start + 1; index < end; index += 1) {
493
+ if (compareTrackedCellChanges(changes[index - 1], changes[index], sheetOrders) > 0) {
494
+ return false;
495
+ }
496
+ }
497
+ return true;
498
+ }
499
+ function isTrackedCellChangeSliceReverseSorted(changes, sheetOrders, start, end) {
500
+ for (let index = start + 1; index < end; index += 1) {
501
+ if (compareTrackedCellChanges(changes[index - 1], changes[index], sheetOrders) < 0) {
502
+ return false;
503
+ }
504
+ }
505
+ return true;
506
+ }
188
507
  function compareTrackedPhysicalCellIndices(cellStore, leftCellIndex, rightCellIndex) {
189
508
  return ((cellStore.rows[leftCellIndex] ?? 0) - (cellStore.rows[rightCellIndex] ?? 0) ||
190
509
  (cellStore.cols[leftCellIndex] ?? 0) - (cellStore.cols[rightCellIndex] ?? 0));
@@ -197,6 +516,14 @@ function isTrackedIndexSliceSorted(cellStore, changedCellIndices, start, end) {
197
516
  }
198
517
  return true;
199
518
  }
519
+ function formatTrackedAddress(row, col) {
520
+ let label = COLUMN_LABEL_CACHE[col];
521
+ if (label === undefined) {
522
+ label = indexToColumn(col);
523
+ COLUMN_LABEL_CACHE[col] = label;
524
+ }
525
+ return `${label}${row + 1}`;
526
+ }
200
527
  function readPhysicalTrackedIndexChange(cellIndex, sheetId, sheetName, cellStore, engine, formatAddressCached) {
201
528
  const row = cellStore.rows[cellIndex];
202
529
  const col = cellStore.cols[cellIndex];
@@ -208,4 +535,308 @@ function readPhysicalTrackedIndexChange(cellIndex, sheetId, sheetName, cellStore
208
535
  newValue: readTrackedCellValue(cellStore, cellIndex, engine),
209
536
  };
210
537
  }
538
+ function trackedIndicesAllBelongToSheet(cellStore, changedCellIndices, sheetId) {
539
+ for (let index = 0; index < changedCellIndices.length; index += 1) {
540
+ if (cellStore.sheetIds[changedCellIndices[index]] !== sheetId) {
541
+ return false;
542
+ }
543
+ }
544
+ return true;
545
+ }
546
+ function createLazyPhysicalTrackedIndexChanges(sheetId, sheetName, cellStore, engine, changedCellIndices, formatAddressCached, sortedSliceSplit) {
547
+ const changedCellIndicesForMaterialization = changedCellIndices instanceof Uint32Array ? changedCellIndices : copyTrackedCellIndices(changedCellIndices);
548
+ const length = changedCellIndicesForMaterialization.length;
549
+ const cache = [];
550
+ cache.length = length;
551
+ let detached;
552
+ let fullyMaterialized = false;
553
+ let orderedCellIndices;
554
+ const hasMaterializedIndex = (index) => Object.prototype.hasOwnProperty.call(cache, index);
555
+ const orderedCellIndexAt = (index) => {
556
+ if (sortedSliceSplit === undefined) {
557
+ return changedCellIndicesForMaterialization[index];
558
+ }
559
+ if (orderedCellIndices === undefined) {
560
+ orderedCellIndices = new Uint32Array(length);
561
+ copyOrderedTrackedCellIndices(cellStore, changedCellIndicesForMaterialization, orderedCellIndices, 0, sortedSliceSplit);
562
+ }
563
+ return orderedCellIndices[index];
564
+ };
565
+ const forEachOrderedCellIndex = (fn) => {
566
+ if (sortedSliceSplit === undefined) {
567
+ for (let index = 0; index < length; index += 1) {
568
+ fn(index, changedCellIndicesForMaterialization[index]);
569
+ }
570
+ return;
571
+ }
572
+ if (orderedCellIndices === undefined) {
573
+ orderedCellIndices = new Uint32Array(length);
574
+ copyOrderedTrackedCellIndices(cellStore, changedCellIndicesForMaterialization, orderedCellIndices, 0, sortedSliceSplit);
575
+ }
576
+ for (let index = 0; index < length; index += 1) {
577
+ fn(index, orderedCellIndices[index]);
578
+ }
579
+ };
580
+ const materialize = (index) => {
581
+ if (hasMaterializedIndex(index)) {
582
+ return cache[index];
583
+ }
584
+ if (detached) {
585
+ cache[index] = readDetachedPhysicalTrackedIndexChange(index, sheetId, sheetName, cellStore, detached, formatAddressCached);
586
+ return cache[index];
587
+ }
588
+ cache[index] = readPhysicalTrackedIndexChange(orderedCellIndexAt(index), sheetId, sheetName, cellStore, engine, formatAddressCached);
589
+ return cache[index];
590
+ };
591
+ const detach = (options = {}) => {
592
+ if (fullyMaterialized) {
593
+ return;
594
+ }
595
+ const preservePositions = options.preservePositions ?? true;
596
+ if (detached !== undefined) {
597
+ if (preservePositions && detached.rows === undefined) {
598
+ if (detached.cellIndices === undefined) {
599
+ return;
600
+ }
601
+ const rows = new Uint32Array(length);
602
+ const cols = new Uint32Array(length);
603
+ for (let index = 0; index < length; index += 1) {
604
+ const cellIndex = detached.cellIndices[index];
605
+ rows[index] = cellStore.rows[cellIndex] ?? 0;
606
+ cols[index] = cellStore.cols[cellIndex] ?? 0;
607
+ }
608
+ detached = { ...detached, rows, cols };
609
+ }
610
+ return;
611
+ }
612
+ const cellIndices = preservePositions ? undefined : new Uint32Array(length);
613
+ const rows = preservePositions ? new Uint32Array(length) : undefined;
614
+ const cols = preservePositions ? new Uint32Array(length) : undefined;
615
+ const numbers = new Float64Array(length);
616
+ let tags;
617
+ let constantTag;
618
+ let errors;
619
+ let stringIds;
620
+ let strings;
621
+ const ensureTags = (currentIndex) => {
622
+ if (tags !== undefined) {
623
+ return tags;
624
+ }
625
+ const nextTags = new Uint8Array(length);
626
+ nextTags.fill(constantTag ?? ValueTag.Empty, 0, currentIndex);
627
+ tags = nextTags;
628
+ return nextTags;
629
+ };
630
+ forEachOrderedCellIndex((index, cellIndex) => {
631
+ if (cellIndices !== undefined) {
632
+ cellIndices[index] = cellIndex;
633
+ }
634
+ if (rows !== undefined && cols !== undefined) {
635
+ rows[index] = cellStore.rows[cellIndex] ?? 0;
636
+ cols[index] = cellStore.cols[cellIndex] ?? 0;
637
+ }
638
+ const tag = cellStore.tags[cellIndex] ?? ValueTag.Empty;
639
+ if (tags !== undefined) {
640
+ tags[index] = tag;
641
+ }
642
+ else if (constantTag === undefined) {
643
+ constantTag = tag;
644
+ }
645
+ else if (tag !== constantTag) {
646
+ ensureTags(index)[index] = tag;
647
+ }
648
+ switch (tag) {
649
+ case ValueTag.Number:
650
+ case ValueTag.Boolean:
651
+ numbers[index] = cellStore.numbers[cellIndex] ?? 0;
652
+ break;
653
+ case ValueTag.String:
654
+ {
655
+ stringIds ??= new Int32Array(length);
656
+ strings ??= [];
657
+ stringIds[index] = cellStore.stringIds[cellIndex] ?? 0;
658
+ const value = cellStore.getValue(cellIndex, (stringId) => engine.strings.get(stringId));
659
+ strings[index] = value.tag === ValueTag.String ? value.value : '';
660
+ }
661
+ break;
662
+ case ValueTag.Error:
663
+ errors ??= new Int32Array(length);
664
+ errors[index] = cellStore.errors[cellIndex] ?? ErrorCode.None;
665
+ break;
666
+ case ValueTag.Empty:
667
+ default:
668
+ break;
669
+ }
670
+ });
671
+ detached = {
672
+ ...(cellIndices === undefined ? {} : { cellIndices }),
673
+ ...(rows !== undefined && cols !== undefined ? { rows, cols } : {}),
674
+ ...(tags !== undefined ? { tags } : { constantTag: constantTag ?? ValueTag.Empty }),
675
+ numbers,
676
+ ...(errors === undefined ? {} : { errors }),
677
+ ...(stringIds === undefined ? {} : { stringIds }),
678
+ ...(strings === undefined ? {} : { strings }),
679
+ };
680
+ };
681
+ const forceMaterialize = () => {
682
+ if (fullyMaterialized) {
683
+ return;
684
+ }
685
+ if (detached !== undefined) {
686
+ for (let index = 0; index < length; index += 1) {
687
+ if (!hasMaterializedIndex(index)) {
688
+ cache[index] = readDetachedPhysicalTrackedIndexChange(index, sheetId, sheetName, cellStore, detached, formatAddressCached);
689
+ }
690
+ }
691
+ fullyMaterialized = true;
692
+ return;
693
+ }
694
+ for (let index = 0; index < length; index += 1) {
695
+ if (!hasMaterializedIndex(index)) {
696
+ cache[index] = readPhysicalTrackedIndexChange(orderedCellIndexAt(index), sheetId, sheetName, cellStore, engine, formatAddressCached);
697
+ }
698
+ }
699
+ fullyMaterialized = true;
700
+ };
701
+ const numericIndexOf = (property) => {
702
+ if (typeof property !== 'string' || property.length === 0) {
703
+ return undefined;
704
+ }
705
+ const index = Number(property);
706
+ return Number.isInteger(index) && index >= 0 && index < length && String(index) === property ? index : undefined;
707
+ };
708
+ const proxy = new Proxy(cache, {
709
+ get(target, property, receiver) {
710
+ const index = numericIndexOf(property);
711
+ return index === undefined ? Reflect.get(target, property, receiver) : materialize(index);
712
+ },
713
+ getOwnPropertyDescriptor(target, property) {
714
+ const index = numericIndexOf(property);
715
+ if (index === undefined) {
716
+ return Reflect.getOwnPropertyDescriptor(target, property);
717
+ }
718
+ return {
719
+ configurable: true,
720
+ enumerable: true,
721
+ value: materialize(index),
722
+ writable: true,
723
+ };
724
+ },
725
+ has(target, property) {
726
+ return numericIndexOf(property) !== undefined || Reflect.has(target, property);
727
+ },
728
+ ownKeys(target) {
729
+ return [
730
+ ...Array.from({ length }, (_value, index) => String(index)),
731
+ ...Reflect.ownKeys(target).filter((key) => typeof key !== 'string' || numericIndexOf(key) === undefined),
732
+ ];
733
+ },
734
+ });
735
+ DEFERRED_TRACKED_INDEX_CHANGES.set(proxy, { forceMaterialize, detach });
736
+ return proxy;
737
+ }
738
+ function tryCreateLazyPhysicalTrackedIndexChanges(engine, changedCellIndices, sheetId, formatAddressCached, options = {}) {
739
+ const workbook = engine.workbook;
740
+ const sheet = workbook.getSheetById(sheetId);
741
+ if (sheet && sheet.structureVersion !== 1) {
742
+ return null;
743
+ }
744
+ const cellStore = workbook.cellStore;
745
+ const length = changedCellIndices.length;
746
+ const split = options.sortedSliceSplit;
747
+ const sortedSliceSplit = split !== undefined && split > 0 && split < length ? split : undefined;
748
+ let previousRow = -1;
749
+ let previousCol = -1;
750
+ let previousRightRow = -1;
751
+ let previousRightCol = -1;
752
+ for (let index = 0; index < length; index += 1) {
753
+ const cellIndex = changedCellIndices[index];
754
+ if (cellStore.sheetIds[cellIndex] !== sheetId) {
755
+ return null;
756
+ }
757
+ const row = cellStore.rows[cellIndex] ?? 0;
758
+ const col = cellStore.cols[cellIndex] ?? 0;
759
+ if (sortedSliceSplit !== undefined && index >= sortedSliceSplit) {
760
+ if (row < previousRightRow || (row === previousRightRow && col < previousRightCol)) {
761
+ return null;
762
+ }
763
+ previousRightRow = row;
764
+ previousRightCol = col;
765
+ continue;
766
+ }
767
+ if (row < previousRow || (row === previousRow && col < previousCol)) {
768
+ return null;
769
+ }
770
+ previousRow = row;
771
+ previousCol = col;
772
+ }
773
+ const sheetName = sheet?.name ?? workbook.getSheetNameById(sheetId);
774
+ return createLazyPhysicalTrackedIndexChanges(sheetId, sheetName, cellStore, engine, changedCellIndices, formatAddressCached, sortedSliceSplit);
775
+ }
776
+ function copyOrderedTrackedCellIndices(cellStore, changedCellIndices, target, offset, sortedSliceSplit) {
777
+ if (sortedSliceSplit === undefined) {
778
+ for (let index = 0; index < changedCellIndices.length; index += 1) {
779
+ target[offset + index] = changedCellIndices[index];
780
+ }
781
+ return offset + changedCellIndices.length;
782
+ }
783
+ let explicitIndex = 0;
784
+ let recalculatedIndex = sortedSliceSplit;
785
+ let outputIndex = offset;
786
+ while (explicitIndex < sortedSliceSplit && recalculatedIndex < changedCellIndices.length) {
787
+ const explicitCellIndex = changedCellIndices[explicitIndex];
788
+ const recalculatedCellIndex = changedCellIndices[recalculatedIndex];
789
+ if (compareTrackedPhysicalCellIndices(cellStore, explicitCellIndex, recalculatedCellIndex) <= 0) {
790
+ target[outputIndex] = explicitCellIndex;
791
+ explicitIndex += 1;
792
+ }
793
+ else {
794
+ target[outputIndex] = recalculatedCellIndex;
795
+ recalculatedIndex += 1;
796
+ }
797
+ outputIndex += 1;
798
+ }
799
+ while (explicitIndex < sortedSliceSplit) {
800
+ target[outputIndex] = changedCellIndices[explicitIndex];
801
+ explicitIndex += 1;
802
+ outputIndex += 1;
803
+ }
804
+ while (recalculatedIndex < changedCellIndices.length) {
805
+ target[outputIndex] = changedCellIndices[recalculatedIndex];
806
+ recalculatedIndex += 1;
807
+ outputIndex += 1;
808
+ }
809
+ return outputIndex;
810
+ }
811
+ function copyTrackedCellIndices(changedCellIndices) {
812
+ return Uint32Array.from(changedCellIndices);
813
+ }
814
+ function readDetachedPhysicalTrackedIndexChange(index, sheetId, sheetName, cellStore, detached, formatAddressCached) {
815
+ const cellIndex = detached.cellIndices?.[index];
816
+ const row = detached.rows?.[index] ?? (cellIndex === undefined ? 0 : (cellStore.rows[cellIndex] ?? 0));
817
+ const col = detached.cols?.[index] ?? (cellIndex === undefined ? 0 : (cellStore.cols[cellIndex] ?? 0));
818
+ return {
819
+ kind: 'cell',
820
+ address: { sheet: sheetId, row, col },
821
+ sheetName,
822
+ a1: formatAddressCached(row, col),
823
+ newValue: readDetachedCellValue(detached, index),
824
+ };
825
+ }
826
+ function readDetachedCellValue(detached, index) {
827
+ const tag = (detached.tags?.[index] ?? detached.constantTag ?? ValueTag.Empty);
828
+ switch (tag) {
829
+ case ValueTag.Number:
830
+ return { tag: ValueTag.Number, value: detached.numbers[index] ?? 0 };
831
+ case ValueTag.Boolean:
832
+ return { tag: ValueTag.Boolean, value: (detached.numbers[index] ?? 0) !== 0 };
833
+ case ValueTag.String:
834
+ return { tag: ValueTag.String, value: detached.strings?.[index] ?? '', stringId: detached.stringIds?.[index] ?? 0 };
835
+ case ValueTag.Error:
836
+ return { tag: ValueTag.Error, code: detached.errors?.[index] ?? ErrorCode.None };
837
+ case ValueTag.Empty:
838
+ default:
839
+ return { tag: ValueTag.Empty };
840
+ }
841
+ }
211
842
  //# sourceMappingURL=tracked-cell-index-changes.js.map