@ricsam/formula-engine 0.2.9 → 0.2.10

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.
Files changed (41) hide show
  1. package/README.md +40 -0
  2. package/dist/cjs/core/engine.cjs +37 -1
  3. package/dist/cjs/core/engine.cjs.map +3 -3
  4. package/dist/cjs/core/managers/dependency-manager.cjs +151 -67
  5. package/dist/cjs/core/managers/dependency-manager.cjs.map +3 -3
  6. package/dist/cjs/core/managers/workbook-manager.cjs +197 -1
  7. package/dist/cjs/core/managers/workbook-manager.cjs.map +3 -3
  8. package/dist/cjs/core/types.cjs.map +2 -2
  9. package/dist/cjs/core/workbook-renamer.cjs.map +1 -1
  10. package/dist/cjs/evaluator/formula-evaluator.cjs +22 -48
  11. package/dist/cjs/evaluator/formula-evaluator.cjs.map +3 -3
  12. package/dist/cjs/functions/math/sum/summation-utils.cjs +2 -2
  13. package/dist/cjs/functions/math/sum/summation-utils.cjs.map +2 -2
  14. package/dist/cjs/package.json +1 -1
  15. package/dist/cjs/parser/formatter.cjs +3 -4
  16. package/dist/cjs/parser/formatter.cjs.map +3 -3
  17. package/dist/cjs/parser/parser.cjs +24 -216
  18. package/dist/cjs/parser/parser.cjs.map +3 -3
  19. package/dist/mjs/core/engine.mjs +37 -1
  20. package/dist/mjs/core/engine.mjs.map +3 -3
  21. package/dist/mjs/core/managers/dependency-manager.mjs +151 -67
  22. package/dist/mjs/core/managers/dependency-manager.mjs.map +3 -3
  23. package/dist/mjs/core/managers/workbook-manager.mjs +197 -1
  24. package/dist/mjs/core/managers/workbook-manager.mjs.map +3 -3
  25. package/dist/mjs/core/types.mjs.map +2 -2
  26. package/dist/mjs/core/workbook-renamer.mjs.map +1 -1
  27. package/dist/mjs/evaluator/formula-evaluator.mjs +22 -48
  28. package/dist/mjs/evaluator/formula-evaluator.mjs.map +3 -3
  29. package/dist/mjs/functions/math/sum/summation-utils.mjs +2 -2
  30. package/dist/mjs/functions/math/sum/summation-utils.mjs.map +2 -2
  31. package/dist/mjs/package.json +1 -1
  32. package/dist/mjs/parser/formatter.mjs +3 -4
  33. package/dist/mjs/parser/formatter.mjs.map +3 -3
  34. package/dist/mjs/parser/parser.mjs +24 -216
  35. package/dist/mjs/parser/parser.mjs.map +3 -3
  36. package/dist/types/core/engine.d.ts +15 -1
  37. package/dist/types/core/managers/dependency-manager.d.ts +4 -0
  38. package/dist/types/core/managers/workbook-manager.d.ts +23 -1
  39. package/dist/types/core/types.d.ts +35 -0
  40. package/dist/types/parser/parser.d.ts +4 -6
  41. package/package.json +1 -1
@@ -44,6 +44,49 @@ class DependencyManager {
44
44
  this.cacheManager = cacheManager;
45
45
  this.workbookManager = workbookManager;
46
46
  }
47
+ getSnapshotEligibilityState(node) {
48
+ if (node instanceof ResourceDependencyNode) {
49
+ return {
50
+ eligible: true,
51
+ reason: "resource nodes are always snapshot eligible"
52
+ };
53
+ }
54
+ if (node instanceof RangeEvaluationNode) {
55
+ return node.result.type === "awaiting-evaluation" ? {
56
+ eligible: false,
57
+ reason: "range result is still awaiting evaluation"
58
+ } : {
59
+ eligible: true,
60
+ reason: `range result type is ${node.result.type}`
61
+ };
62
+ }
63
+ return node.evaluationResult.type === "awaiting-evaluation" ? {
64
+ eligible: false,
65
+ reason: "evaluation result is still awaiting evaluation"
66
+ } : {
67
+ eligible: true,
68
+ reason: `evaluation result type is ${node.evaluationResult.type}`
69
+ };
70
+ }
71
+ logSnapshotRestoreWarning(message, payload) {
72
+ console.warn("[FormulaEngine snapshot]", message, payload);
73
+ }
74
+ getLogicalNodeSnapshotId(node) {
75
+ if (node instanceof AstEvaluationNode) {
76
+ return getAstNodeSnapshotId(node);
77
+ }
78
+ return node.key;
79
+ }
80
+ resetRestoredNodeToColdState(node) {
81
+ this.unregisterNode(node);
82
+ if (node instanceof ResourceDependencyNode) {
83
+ return;
84
+ }
85
+ if (node instanceof CellValueNode) {
86
+ node.clearSpillMetaNode();
87
+ }
88
+ node.invalidate();
89
+ }
47
90
  getSheetWatcherKey(address) {
48
91
  return `${address.workbookName}:${address.sheetName}`;
49
92
  }
@@ -351,13 +394,7 @@ class DependencyManager {
351
394
  }
352
395
  toSnapshot(evaluationManager) {
353
396
  const isNodeSnapshotEligible = (node) => {
354
- if (node instanceof ResourceDependencyNode) {
355
- return true;
356
- }
357
- if (node instanceof RangeEvaluationNode) {
358
- return node.result.type !== "awaiting-evaluation";
359
- }
360
- return node.evaluationResult.type !== "awaiting-evaluation";
397
+ return this.getSnapshotEligibilityState(node).eligible;
361
398
  };
362
399
  const astNodes = new Set;
363
400
  for (const astEntries of this.asts.values()) {
@@ -395,15 +432,17 @@ class DependencyManager {
395
432
  }
396
433
  const resolvedNodes = Array.from(resolvedNodesSet);
397
434
  const allNodeSnapshotIds = new Map;
435
+ const availableSnapshotIds = new Set;
398
436
  for (const node of resolvedNodes) {
399
- if (node instanceof AstEvaluationNode) {
400
- allNodeSnapshotIds.set(node, getAstNodeSnapshotId(node));
401
- } else {
402
- allNodeSnapshotIds.set(node, node.key);
403
- }
404
- }
405
- const getAllNodeSnapshotId = (node) => {
406
- const snapshotId = allNodeSnapshotIds.get(node);
437
+ const snapshotId = this.getLogicalNodeSnapshotId(node);
438
+ allNodeSnapshotIds.set(node, snapshotId);
439
+ availableSnapshotIds.add(snapshotId);
440
+ }
441
+ const getAllNodeSnapshotId = (node, _context) => {
442
+ const snapshotId = allNodeSnapshotIds.get(node) ?? (() => {
443
+ const logicalSnapshotId = this.getLogicalNodeSnapshotId(node);
444
+ return availableSnapshotIds.has(logicalSnapshotId) ? logicalSnapshotId : undefined;
445
+ })();
407
446
  if (!snapshotId) {
408
447
  throw new Error(`Missing snapshot id for dependency node ${node.key}`);
409
448
  }
@@ -449,9 +488,25 @@ class DependencyManager {
449
488
  restoreFromSnapshot(snapshots, evaluationManager) {
450
489
  this.clearEvaluationCache();
451
490
  const nodesBySnapshotId = new Map;
491
+ let hadRestoreFailures = false;
452
492
  for (const snapshot of snapshots.dependency.nodes) {
453
- const node = this.createNodeFromSnapshot(snapshot);
454
- nodesBySnapshotId.set(snapshot.snapshotId, node);
493
+ try {
494
+ const node = this.createNodeFromSnapshot(snapshot);
495
+ nodesBySnapshotId.set(snapshot.snapshotId, node);
496
+ } catch (error) {
497
+ hadRestoreFailures = true;
498
+ this.logSnapshotRestoreWarning("Failed to create warm snapshot node; discarding warm dependency state", {
499
+ phase: "create-node",
500
+ snapshotId: snapshot.snapshotId,
501
+ kind: snapshot.kind,
502
+ key: snapshot.key,
503
+ error: error instanceof Error ? { name: error.name, message: error.message } : { message: String(error) }
504
+ });
505
+ }
506
+ }
507
+ if (hadRestoreFailures) {
508
+ this.clearEvaluationCache();
509
+ return;
455
510
  }
456
511
  const resolveNodeSnapshotId = (snapshotId) => nodesBySnapshotId.get(snapshotId);
457
512
  const resolveRequiredNodeSnapshotId = (snapshotId) => {
@@ -462,54 +517,71 @@ class DependencyManager {
462
517
  return node;
463
518
  };
464
519
  for (const snapshot of snapshots.dependency.nodes) {
465
- const dependencies = new Set(snapshot.dependencies.map(resolveNodeSnapshotId).filter((node2) => node2 !== undefined));
466
- if (snapshot.kind === "cell-value") {
467
- const node2 = nodesBySnapshotId.get(snapshot.snapshotId);
468
- node2.restoreResolvedSnapshot({
469
- dependencies,
470
- evaluationResult: evaluationManager.deserializeSingleEvaluationResultSnapshot(snapshot.evaluationResult, resolveRequiredNodeSnapshotId)
471
- });
472
- if (snapshot.spillMetaSnapshotId) {
473
- const spillMetaNode = resolveNodeSnapshotId(snapshot.spillMetaSnapshotId);
474
- if (spillMetaNode instanceof SpillMetaNode) {
475
- node2.setSpillMetaNode(spillMetaNode);
476
- }
477
- }
478
- continue;
479
- }
480
- if (snapshot.kind === "spill-meta") {
481
- const node2 = nodesBySnapshotId.get(snapshot.snapshotId);
482
- node2.restoreResolvedSnapshot({
483
- dependencies,
484
- evaluationResult: evaluationManager.deserializeSpillMetaEvaluationResultSnapshot(snapshot.evaluationResult, resolveRequiredNodeSnapshotId)
485
- });
520
+ const targetNode = nodesBySnapshotId.get(snapshot.snapshotId);
521
+ if (!targetNode) {
522
+ hadRestoreFailures = true;
486
523
  continue;
487
524
  }
488
- if (snapshot.kind === "empty") {
489
- const node2 = nodesBySnapshotId.get(snapshot.snapshotId);
490
- node2.restoreResolvedSnapshot({
525
+ const dependencies = new Set(snapshot.dependencies.map(resolveNodeSnapshotId).filter((node) => node !== undefined));
526
+ try {
527
+ if (snapshot.kind === "cell-value") {
528
+ const node2 = targetNode;
529
+ node2.restoreResolvedSnapshot({
530
+ dependencies,
531
+ evaluationResult: evaluationManager.deserializeSingleEvaluationResultSnapshot(snapshot.evaluationResult, resolveRequiredNodeSnapshotId)
532
+ });
533
+ if (snapshot.spillMetaSnapshotId) {
534
+ const spillMetaNode = resolveNodeSnapshotId(snapshot.spillMetaSnapshotId);
535
+ if (spillMetaNode instanceof SpillMetaNode) {
536
+ node2.setSpillMetaNode(spillMetaNode);
537
+ }
538
+ }
539
+ continue;
540
+ }
541
+ if (snapshot.kind === "spill-meta") {
542
+ const node2 = targetNode;
543
+ node2.restoreResolvedSnapshot({
544
+ dependencies,
545
+ evaluationResult: evaluationManager.deserializeSpillMetaEvaluationResultSnapshot(snapshot.evaluationResult, resolveRequiredNodeSnapshotId)
546
+ });
547
+ continue;
548
+ }
549
+ if (snapshot.kind === "empty") {
550
+ const node2 = targetNode;
551
+ node2.restoreResolvedSnapshot({
552
+ dependencies,
553
+ evaluationResult: evaluationManager.deserializeSingleEvaluationResultSnapshot(snapshot.evaluationResult, resolveRequiredNodeSnapshotId)
554
+ });
555
+ continue;
556
+ }
557
+ if (snapshot.kind === "range") {
558
+ const node2 = targetNode;
559
+ node2.restoreResolvedSnapshot({
560
+ dependencies,
561
+ result: evaluationManager.deserializeEvaluateAllCellsResultSnapshot(snapshot.result, resolveRequiredNodeSnapshotId)
562
+ });
563
+ continue;
564
+ }
565
+ if (snapshot.kind === "resource") {
566
+ continue;
567
+ }
568
+ const node = targetNode;
569
+ node.restoreResolvedSnapshot({
491
570
  dependencies,
492
- evaluationResult: evaluationManager.deserializeSingleEvaluationResultSnapshot(snapshot.evaluationResult, resolveRequiredNodeSnapshotId)
571
+ evaluationResult: evaluationManager.deserializeFunctionEvaluationResultSnapshot(snapshot.evaluationResult, resolveRequiredNodeSnapshotId)
493
572
  });
494
- continue;
495
- }
496
- if (snapshot.kind === "range") {
497
- const node2 = nodesBySnapshotId.get(snapshot.snapshotId);
498
- node2.restoreResolvedSnapshot({
499
- dependencies,
500
- result: evaluationManager.deserializeEvaluateAllCellsResultSnapshot(snapshot.result, resolveRequiredNodeSnapshotId)
573
+ this.saveAstNode(node, snapshot.contextDependency);
574
+ } catch (error) {
575
+ hadRestoreFailures = true;
576
+ this.resetRestoredNodeToColdState(targetNode);
577
+ this.logSnapshotRestoreWarning("Failed to deserialize warm snapshot node; discarding warm dependency state", {
578
+ phase: "restore-node",
579
+ snapshotId: snapshot.snapshotId,
580
+ kind: snapshot.kind,
581
+ key: snapshot.key,
582
+ error: error instanceof Error ? { name: error.name, message: error.message } : { message: String(error) }
501
583
  });
502
- continue;
503
584
  }
504
- if (snapshot.kind === "resource") {
505
- continue;
506
- }
507
- const node = nodesBySnapshotId.get(snapshot.snapshotId);
508
- node.restoreResolvedSnapshot({
509
- dependencies,
510
- evaluationResult: evaluationManager.deserializeFunctionEvaluationResultSnapshot(snapshot.evaluationResult, resolveRequiredNodeSnapshotId)
511
- });
512
- this.saveAstNode(node, snapshot.contextDependency);
513
585
  }
514
586
  this._spilledValues = new Map(snapshots.dependency.spilledValues);
515
587
  this.rebuildRuntimeIndexes();
@@ -517,20 +589,32 @@ class DependencyManager {
517
589
  }
518
590
  serializeNodeSnapshot(node, evaluationManager, getNodeSnapshotId, allNodeSnapshotIds) {
519
591
  const snapshotId = getNodeSnapshotId(node);
592
+ const getKnownSnapshotId = (dependency) => {
593
+ const directSnapshotId = allNodeSnapshotIds.get(dependency);
594
+ if (directSnapshotId) {
595
+ return directSnapshotId;
596
+ }
597
+ const logicalSnapshotId = this.getLogicalNodeSnapshotId(dependency);
598
+ return allNodeSnapshotIds.values().some((knownSnapshotId) => knownSnapshotId === logicalSnapshotId) ? logicalSnapshotId : undefined;
599
+ };
520
600
  const dependencies = [];
521
601
  for (const dependency of node.getDependencies()) {
522
- const dependencySnapshotId = allNodeSnapshotIds.get(dependency);
602
+ const dependencySnapshotId = getKnownSnapshotId(dependency);
523
603
  if (!dependencySnapshotId) {
524
604
  return;
525
605
  }
526
606
  dependencies.push(dependencySnapshotId);
527
607
  }
608
+ const getReferencedNodeSnapshotId = (dependency) => getNodeSnapshotId(dependency, {
609
+ sourceNode: node,
610
+ relation: "evaluation result errAddress"
611
+ });
528
612
  if (node instanceof CellValueNode) {
529
- const spillMetaSnapshotId = node.spillMeta ? allNodeSnapshotIds.get(node.spillMeta) : undefined;
613
+ const spillMetaSnapshotId = node.spillMeta ? getKnownSnapshotId(node.spillMeta) : undefined;
530
614
  if (node.spillMeta && !spillMetaSnapshotId) {
531
615
  return;
532
616
  }
533
- const evaluationResult2 = evaluationManager.serializeSingleEvaluationResultSnapshot(node.evaluationResult, getNodeSnapshotId);
617
+ const evaluationResult2 = evaluationManager.serializeSingleEvaluationResultSnapshot(node.evaluationResult, getReferencedNodeSnapshotId);
534
618
  if (!evaluationResult2) {
535
619
  return;
536
620
  }
@@ -546,7 +630,7 @@ class DependencyManager {
546
630
  if (node instanceof SpillMetaNode) {
547
631
  const evaluationResult2 = evaluationManager.serializeSpillMetaEvaluationResultSnapshot(node.evaluationResult, {
548
632
  sourceNode: node,
549
- getNodeSnapshotId
633
+ getNodeSnapshotId: getReferencedNodeSnapshotId
550
634
  });
551
635
  if (!evaluationResult2) {
552
636
  return;
@@ -560,7 +644,7 @@ class DependencyManager {
560
644
  };
561
645
  }
562
646
  if (node instanceof EmptyCellEvaluationNode) {
563
- const evaluationResult2 = evaluationManager.serializeSingleEvaluationResultSnapshot(node.evaluationResult, getNodeSnapshotId);
647
+ const evaluationResult2 = evaluationManager.serializeSingleEvaluationResultSnapshot(node.evaluationResult, getReferencedNodeSnapshotId);
564
648
  if (!evaluationResult2) {
565
649
  return;
566
650
  }
@@ -573,7 +657,7 @@ class DependencyManager {
573
657
  };
574
658
  }
575
659
  if (node instanceof RangeEvaluationNode) {
576
- const result = evaluationManager.serializeEvaluateAllCellsResultSnapshot(node.result, getNodeSnapshotId);
660
+ const result = evaluationManager.serializeEvaluateAllCellsResultSnapshot(node.result, getReferencedNodeSnapshotId);
577
661
  if (!result) {
578
662
  return;
579
663
  }
@@ -595,7 +679,7 @@ class DependencyManager {
595
679
  }
596
680
  const evaluationResult = evaluationManager.serializeFunctionEvaluationResultSnapshot(node.evaluationResult, {
597
681
  sourceNode: node,
598
- getNodeSnapshotId
682
+ getNodeSnapshotId: getReferencedNodeSnapshotId
599
683
  });
600
684
  if (!evaluationResult) {
601
685
  return;
@@ -1424,4 +1508,4 @@ export {
1424
1508
  DependencyManager
1425
1509
  };
1426
1510
 
1427
- //# debugId=FBEAE642404E13D464756E2164756E21
1511
+ //# debugId=3C6CF47C62ED503A64756E2164756E21