@sheetxl/sdk 0.7.28-beta.2 → 0.7.28-beta.4
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/browser/cjs/{BREMLtxkQhtNSVra.cjs → BF14ZEAnaqxXroSj.cjs} +1 -1
- package/browser/cjs/{BG7YDVxiC4ErxvF1.cjs → BXtvdT1Z-MsB_o5F.cjs} +1 -1
- package/browser/cjs/Bc4JjVVZfFo3R4He.cjs +33 -0
- package/browser/cjs/{CQf4zxkBmheTVbjX.cjs → CD2RXdnfqSYNc6gX.cjs} +2 -2
- package/browser/cjs/DcLpXGexEtOxi-dD.cjs +1 -0
- package/browser/cjs/index.cjs +2 -2
- package/browser/esm/{DN4d5bDBkti28wuc.mjs → 0Mj5WKM362q6CECb.mjs} +213 -207
- package/browser/esm/{BxIOX1TojvA-1ZZP.mjs → CHSahmMFYNB0Ajkf.mjs} +2 -2
- package/browser/esm/{CZO1RubmqnJV96rq.mjs → CKk58ZLcrllMzfou.mjs} +2 -2
- package/browser/esm/{DRWu3TmcE9JFf78V.mjs → CPTtL2f6_4iblmFM.mjs} +2 -2
- package/browser/esm/{DPOelA1J3WHbMXyh.mjs → CoA-sUxjiIUIpTUF.mjs} +2 -2
- package/browser/esm/{vHWuKF-ftK7LM1uw.mjs → DBIu6NUHIcxOOBQp.mjs} +1 -1
- package/browser/esm/{CB_4gdPPPruwremH.mjs → Dy4Sdpju1T2icURu.mjs} +4748 -3883
- package/browser/esm/index.mjs +419 -411
- package/node/esm/{XQhP3dYwF_tEuswB.mjs → BtGxbEbBm79YvF_k.mjs} +303 -297
- package/node/esm/{B-tgcZihStNV9CbZ.mjs → DUYP6faJJHCaW1Xf.mjs} +1 -1
- package/node/esm/{C8tfYGL3wHy9IDDc.mjs → DqgWsVXROpSgKq6c.mjs} +2 -2
- package/node/esm/index.mjs +8686 -7802
- package/package.json +6 -6
- package/resources/locales/de/model.msg.json +12 -0
- package/resources/locales/en/model.msg.json +12 -0
- package/types/scripting-enums.json +2 -0
- package/types/scripting.d.ts +341 -15
- package/types/src/anchored/IAnchored.d.ts +27 -0
- package/types/src/calculation/Calculation.d.ts +21 -12
- package/types/src/calculation/ICalculation.d.ts +183 -0
- package/types/src/calculation/compiler/CompilerUtils.d.ts +20 -0
- package/types/src/calculation/compiler/FormulaParser.d.ts +32 -6
- package/types/src/calculation/executor/CalcExecutor.d.ts +204 -13
- package/types/src/calculation/executor/CalcExecutorUtils.d.ts +31 -0
- package/types/src/calculation/executor/CircularReference.d.ts +81 -0
- package/types/src/calculation/functions/Operators.d.ts +1 -1
- package/types/src/calculation/grid/CalcGrid.d.ts +5 -1
- package/types/src/calculation/grid/CalcGridUtils.d.ts +3 -2
- package/types/src/calculation/grid/ICalcGrid.d.ts +23 -1
- package/types/src/calculation/spatial/CircularEntry.d.ts +18 -0
- package/types/src/calculation/spatial/index.d.ts +1 -0
- package/types/src/calculation/state/CalcNode.d.ts +24 -17
- package/types/src/calculation/state/CalcState.d.ts +78 -15
- package/types/src/calculation/state/CalculationContext.d.ts +39 -0
- package/types/src/calculation/state/_ReadObservedGrid.d.ts +90 -0
- package/types/src/cell/ICell.d.ts +16 -0
- package/types/src/cellRange/ICellRange.d.ts +72 -6
- package/types/src/condition/AnchoredConditional.d.ts +26 -6
- package/types/src/conditionalFormat/ConditionalFormat.d.ts +8 -1
- package/types/src/conditionalFormat/IConditionalFormat.d.ts +4 -1
- package/types/src/conditionalFormat/IConditionalFormatCollection.d.ts +6 -2
- package/types/src/dataValidation/IDataValidationCollection.d.ts +6 -2
- package/types/src/hyperlink/IHyperlink.d.ts +3 -1
- package/types/src/hyperlink/_Hyperlink.d.ts +6 -0
- package/types/src/lib/utils/utils.browser.d.ts +5 -0
- package/types/src/license/LicenseDetails.d.ts +5 -0
- package/types/src/primitives/CalcSignal.d.ts +20 -0
- package/types/src/protectedRange/IProtectedRangeCollection.d.ts +7 -2
- package/types/src/scripting/_ScriptUtils.d.ts +13 -0
- package/types/src/sheet/Sheet.d.ts +33 -2
- package/types/src/sheet/SheetCell.d.ts +2 -0
- package/types/src/sheet/SheetRange.d.ts +12 -1
- package/types/src/sheet/_SheetStateTypes.d.ts +14 -1
- package/types/src/style/IStyle.d.ts +5 -0
- package/types/src/table/AnchoredTable.d.ts +17 -1
- package/types/src/text/TextUtils.d.ts +18 -0
- package/browser/cjs/DoemwsUQoGCk0vBK.cjs +0 -33
- package/browser/cjs/_c2uwwpr03Y7lzIj.cjs +0 -1
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { IRange } from '@sheetxl/primitives';
|
|
2
|
+
import { ICalculation } from '../ICalculation';
|
|
3
|
+
import { CalcNode } from '../state';
|
|
4
|
+
import { CircularEntry } from '../spatial';
|
|
5
|
+
import { CalcExecutor } from './CalcExecutor';
|
|
6
|
+
/**
|
|
7
|
+
* The two graph questions a {@link CircularReference} cannot answer on its own; built once by
|
|
8
|
+
* the executor, shared by every cycle.
|
|
9
|
+
*/
|
|
10
|
+
export interface CycleHost {
|
|
11
|
+
/** Whether `node` is still the node registered for its own cell (a deleted formula's is not). */
|
|
12
|
+
isLiveNode(node: CalcNode): boolean;
|
|
13
|
+
/** The sheet name for a grid id, or `undefined` for a virtual grid (a named formula's body). */
|
|
14
|
+
resolveScope(gridId: string): string | undefined;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* One reference cycle (DESIGN-CIRCULAR-CALC.md §7.3): the executor's record of it and its public
|
|
18
|
+
* face in one — the object a `Feature.Circular` region carries as its payload and
|
|
19
|
+
* `ICell.getCircularReference()` answers. It holds the nodes the sheet index currently shows as
|
|
20
|
+
* its members and as downstream of it, the interned index payloads, and how the sweep that
|
|
21
|
+
* settled it ended. It persists across passes — a node moves between cycles when a commit writes
|
|
22
|
+
* its delta (`_trackCircular`) — and is dropped when its last node leaves.
|
|
23
|
+
*
|
|
24
|
+
* @remarks
|
|
25
|
+
* Every read filters through {@link CycleHost.isLiveNode}: a pass that deletes the offending
|
|
26
|
+
* formula never plans, so the sets cannot clear themselves, and a member is counted only while
|
|
27
|
+
* its cell still holds the block the cycle was found in (design §7.3, trap 5).
|
|
28
|
+
*
|
|
29
|
+
* The iteration answers come from the sweep that settled the cycle (design §6.3). A cycle id is
|
|
30
|
+
* minted by the pass that finds it, so a cycle evaluated with iteration off is a different object
|
|
31
|
+
* with no record — `isIterative()` is exactly "a sweep settled this one".
|
|
32
|
+
*/
|
|
33
|
+
export declare class CircularReference implements ICalculation.ICircularReference {
|
|
34
|
+
protected readonly _host: CycleHost;
|
|
35
|
+
protected readonly _cycleId: number;
|
|
36
|
+
/** @internal The nodes the sheet index shows in the cycle; maintained by the executor. */
|
|
37
|
+
readonly members: Set<CalcNode>;
|
|
38
|
+
/** @internal The nodes the sheet index shows downstream of the cycle; maintained by the executor. */
|
|
39
|
+
readonly downstream: Set<CalcNode>;
|
|
40
|
+
/** One payload per kind, so equal payloads are one object and adjacent cells one region. */
|
|
41
|
+
protected _memberEntry: CircularEntry | null;
|
|
42
|
+
protected _downstreamEntry: CircularEntry | null;
|
|
43
|
+
protected _iteration: CalcExecutor.IterationResult | null;
|
|
44
|
+
constructor(host: CycleHost, cycleId: number);
|
|
45
|
+
/** @internal The executor's key for this cycle. */
|
|
46
|
+
getCycleId(): number;
|
|
47
|
+
/** @internal Whether the sheet index shows no cell in or downstream of the cycle any more. */
|
|
48
|
+
isEmpty(): boolean;
|
|
49
|
+
/** @internal The index payload for the cycle's members or for its downstream cells. */
|
|
50
|
+
getEntry(isMember: boolean): CircularEntry;
|
|
51
|
+
/** @internal How the sweep that settled this cycle ended; written by the executor. */
|
|
52
|
+
setIteration(result: CalcExecutor.IterationResult): void;
|
|
53
|
+
/** @inheritdoc ICalculation.ICircularReference.getRepresentative */
|
|
54
|
+
getRepresentative(): IRange.CellCoords | null;
|
|
55
|
+
/** @inheritdoc ICalculation.ICircularReference.getMembers */
|
|
56
|
+
getMembers(): readonly IRange.CellCoords[];
|
|
57
|
+
/** @inheritdoc ICalculation.ICircularReference.getMemberCount */
|
|
58
|
+
getMemberCount(): number;
|
|
59
|
+
/** @inheritdoc ICalculation.ICircularReference.getDownstreamCount */
|
|
60
|
+
getDownstreamCount(): number;
|
|
61
|
+
/** @inheritdoc ICalculation.ICircularReference.isMember */
|
|
62
|
+
isMember(coords: IRange.CellCoords): boolean;
|
|
63
|
+
/** @inheritdoc ICalculation.ICircularReference.getPath */
|
|
64
|
+
getPath(from: IRange.CellCoords): readonly IRange.CellCoords[];
|
|
65
|
+
/** The live member at `coords`, or `null`. */
|
|
66
|
+
protected _memberAt(coords: IRange.CellCoords): CalcNode | null;
|
|
67
|
+
/** @inheritdoc ICalculation.ICircularReference.isIterative */
|
|
68
|
+
isIterative(): boolean;
|
|
69
|
+
/** @inheritdoc ICalculation.ICircularReference.isConverged */
|
|
70
|
+
isConverged(): boolean;
|
|
71
|
+
/** @inheritdoc ICalculation.ICircularReference.getIterationCount */
|
|
72
|
+
getIterationCount(): number;
|
|
73
|
+
/** @inheritdoc ICalculation.ICircularReference.getLastChange */
|
|
74
|
+
getLastChange(): number;
|
|
75
|
+
/** The members still on the graph, in row-major order (virtual grids first, then by sheet). */
|
|
76
|
+
protected _liveMembers(): CalcNode[];
|
|
77
|
+
protected _countLive(nodes: Set<CalcNode>): number;
|
|
78
|
+
protected _scopeOf(node: CalcNode): string | null;
|
|
79
|
+
protected _toCoords(node: CalcNode): IRange.CellCoords;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=CircularReference.d.ts.map
|
|
@@ -25,6 +25,6 @@ export declare const Prefix: {
|
|
|
25
25
|
};
|
|
26
26
|
export declare const Postfix: {
|
|
27
27
|
'%': (context: IFormulaContext, value: any) => any;
|
|
28
|
-
'#': (context: IFormulaContext, value: any) => IReferenceRange;
|
|
28
|
+
'#': (context: IFormulaContext, value: any) => IReferenceRange | FormulaError.Known;
|
|
29
29
|
};
|
|
30
30
|
//# sourceMappingURL=Operators.d.ts.map
|
|
@@ -3,7 +3,7 @@ import { IListener } from '../../listener';
|
|
|
3
3
|
import { ListenerEmitter } from '../../listener/ListenerEmitter';
|
|
4
4
|
import { Tuple, ISpatialQuery, ISparseGrid, ISpatialMap, ISpatialMap3D } from '../../collections';
|
|
5
5
|
import { IContextContainer, CalcNode } from '../state';
|
|
6
|
-
import { SpillEntry, FormulaSpatialValue, ContentfulSpatialValue, PrecedentSpatialValue } from '../spatial';
|
|
6
|
+
import { SpillEntry, FormulaSpatialValue, ContentfulSpatialValue, PrecedentSpatialValue, CircularEntry } from '../spatial';
|
|
7
7
|
import { IFormulaBlock } from '../formula';
|
|
8
8
|
import { ReferenceCoords } from '../Types';
|
|
9
9
|
import { ICalculation } from '../ICalculation';
|
|
@@ -20,12 +20,14 @@ export declare class CalcGrid implements ICalcGrid {
|
|
|
20
20
|
_spillSpatial: ISpatialMap<SpillEntry>;
|
|
21
21
|
_errorSpatial: ISpatialMap<string>;
|
|
22
22
|
_pendingSpatial: ISpatialMap<boolean>;
|
|
23
|
+
_circularSpatial: ISpatialMap<CircularEntry>;
|
|
23
24
|
_contentfulSpatial: ISpatialMap<ContentfulSpatialValue>;
|
|
24
25
|
_notifyValues: ISpatialMap;
|
|
25
26
|
_notifySpillsInsert: ISpatialMap.Entry<SpillEntry>[];
|
|
26
27
|
_notifySpillsRemove: IRange.Coords[];
|
|
27
28
|
_notifyFormats: ISpatialMap;
|
|
28
29
|
_notifyPending: ISpatialMap<boolean>;
|
|
30
|
+
_notifyCircular: ISpatialMap<CircularEntry | false>;
|
|
29
31
|
_cloneKey?: CalcGrid;
|
|
30
32
|
_version: number;
|
|
31
33
|
_iterationId: number;
|
|
@@ -75,6 +77,8 @@ export declare class CalcGrid implements ICalcGrid {
|
|
|
75
77
|
getDirtyRegions(): ISpatialQuery;
|
|
76
78
|
/** {@inheritDoc ICalcGrid.getFormulas} */
|
|
77
79
|
getFormulas(): ISpatialQuery<IFormulaBlock>;
|
|
80
|
+
/** {@inheritDoc ICalcGrid.getSpills} */
|
|
81
|
+
getSpills(): ISpatialQuery<SpillEntry>;
|
|
78
82
|
/** {@inheritDoc ICalcGrid.getSnapshot} */
|
|
79
83
|
getSnapshot(options?: ICalcGrid.GetSnapshotOptions): ICalcGrid.ISnapshot;
|
|
80
84
|
/** {@inheritDoc ICalcGrid.getDirectDependentsAt} */
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { IRange, Scalar } from '@sheetxl/primitives';
|
|
2
2
|
import { Tuple, ISparseGrid, ISpatialMap, ISpatialMap3D } from '../../collections';
|
|
3
3
|
import { CalcNode } from '../state';
|
|
4
|
-
import { ContentfulSpatialValue, FormulaSpatialValue, SpillEntry, PrecedentSpatialValue, PrecedentKind } from '../spatial';
|
|
4
|
+
import { ContentfulSpatialValue, FormulaSpatialValue, SpillEntry, PrecedentSpatialValue, CircularEntry, PrecedentKind } from '../spatial';
|
|
5
5
|
import { ReferenceCoords } from '../Types';
|
|
6
6
|
export declare function anchorCompareValues(a: ISpatialMap.Entry<FormulaSpatialValue>, removing: ISpatialMap.Entry<FormulaSpatialValue>): boolean;
|
|
7
7
|
/**
|
|
@@ -19,7 +19,8 @@ export declare function isTopLeft(rowIndex: number, colIndex: number, range: IRa
|
|
|
19
19
|
* This code will inline spill errors but spill results are handled in calculations.
|
|
20
20
|
*/
|
|
21
21
|
export declare function applyContentful(cycleId: number, removes: readonly IRange.Coords[] | null | undefined, inserts: ISpatialMap.Entry[] | null | undefined, contentfulSpatial: ISpatialMap<ContentfulSpatialValue>, spillSpatial: ISpatialMap<SpillEntry>, values: ISparseGrid<Scalar>, addDirty?: (colStart: number, rowStart: number, colEnd: number, rowEnd: number) => void, notifyValuesSpatial?: ISpatialMap, notifySpills?: (insert: ISpatialMap.Entry<SpillEntry>, remove: ISpatialMap.Entry<SpillEntry>) => void, notifyPending?: ISpatialMap<boolean>, errorSpatial?: ISpatialMap<string>, // notifyErrorSpatial,
|
|
22
|
-
isColumn?: boolean, notifyCalc?: boolean
|
|
22
|
+
isColumn?: boolean, notifyCalc?: boolean, // should notify. this is to differentiate between user set values and calc set values
|
|
23
|
+
circularSpatial?: ISpatialMap<CircularEntry>): IRange.Coords | null;
|
|
23
24
|
/**
|
|
24
25
|
* Creates a map from tuples
|
|
25
26
|
*
|
|
@@ -5,7 +5,7 @@ import { IListener } from '../../listener';
|
|
|
5
5
|
import { IHistory } from '../../history';
|
|
6
6
|
import { ISpatialQuery, ISpatialMap, ISparseGrid, Tuple } from '../../collections';
|
|
7
7
|
import { IFormulaBlock } from '../formula';
|
|
8
|
-
import { ContentfulSpatialValue, SpillEntry } from '../spatial';
|
|
8
|
+
import { ContentfulSpatialValue, SpillEntry, CircularEntry } from '../spatial';
|
|
9
9
|
import { ReferenceCoords, NamedReference } from '../Types';
|
|
10
10
|
import { ICalculation } from '../ICalculation';
|
|
11
11
|
/**
|
|
@@ -66,6 +66,17 @@ export interface ICalcGrid {
|
|
|
66
66
|
* Used by sheet
|
|
67
67
|
*/
|
|
68
68
|
getFormulas(): ISpatialQuery<IFormulaBlock>;
|
|
69
|
+
/**
|
|
70
|
+
* Returns a queryable spatial index of the ARRAY EXTENTS on this grid — one entry per array
|
|
71
|
+
* formula, keyed by the cells it occupies: a dynamic array's spill, a legacy CSE block, or the
|
|
72
|
+
* single cell a blocked spill collapses to.
|
|
73
|
+
*
|
|
74
|
+
* @remark
|
|
75
|
+
* The same index a calculation pass writes through {@link ICalcGrid.IncrementalUpdates.spillSpatial}
|
|
76
|
+
* (`beginUpdates` hands out this very map), so a read answers identically inside and outside a
|
|
77
|
+
* pass — which is what lets a formula evaluated OUTSIDE one resolve a spill anchor.
|
|
78
|
+
*/
|
|
79
|
+
getSpills(): ISpatialQuery<SpillEntry>;
|
|
69
80
|
/**
|
|
70
81
|
* Returns the current values on the grid.
|
|
71
82
|
*/
|
|
@@ -300,6 +311,14 @@ export declare namespace ICalcGrid {
|
|
|
300
311
|
* These are guaranteed to not overlap.
|
|
301
312
|
*/
|
|
302
313
|
pendingUpdates?: ISpatialMap.Entry<boolean>[];
|
|
314
|
+
/**
|
|
315
|
+
* Cells that entered or left a reference cycle (or the set downstream of one). A `null`
|
|
316
|
+
* value is a removal.
|
|
317
|
+
*
|
|
318
|
+
* @remarks
|
|
319
|
+
* These are guaranteed to not overlap.
|
|
320
|
+
*/
|
|
321
|
+
circularUpdates?: ISpatialMap.Entry<CircularEntry | null>[];
|
|
303
322
|
}
|
|
304
323
|
/**
|
|
305
324
|
* Returns from `ICalcGrid.beginUpdates()`.
|
|
@@ -313,13 +332,16 @@ export declare namespace ICalcGrid {
|
|
|
313
332
|
spillSpatial: ISpatialMap<SpillEntry>;
|
|
314
333
|
errorSpatial: ISpatialMap<string>;
|
|
315
334
|
pendingSpatial: ISpatialMap<boolean>;
|
|
335
|
+
circularSpatial: ISpatialMap<CircularEntry>;
|
|
316
336
|
contentfulSpatial: ISpatialMap<ContentfulSpatialValue>;
|
|
317
337
|
notifyValues: ISpatialMap;
|
|
318
338
|
notifySpillsInsert: ISpatialMap.Entry<SpillEntry>[];
|
|
319
339
|
notifySpillsRemove: IRange.Coords[];
|
|
320
340
|
notifyFormats: ISpatialMap;
|
|
321
341
|
notifyPending: ISpatialMap<boolean>;
|
|
342
|
+
notifyCircular: ISpatialMap<CircularEntry | false>;
|
|
322
343
|
pendingConflating: ISpatialMap.IConflatingEntries<boolean> | null;
|
|
344
|
+
circularConflating: ISpatialMap.IConflatingEntries<CircularEntry | false> | null;
|
|
323
345
|
errorRemovesConflating: ISpatialMap.IConflatingEntries<null> | null;
|
|
324
346
|
errorInsertsConflating: ISpatialMap.IConflatingEntries<string> | null;
|
|
325
347
|
formatsConflating: ISpatialMap.IConflatingEntries | null;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ICalculation } from '../ICalculation';
|
|
2
|
+
/**
|
|
3
|
+
* What a sheet's circular index says about a cell (DESIGN-CIRCULAR-CALC.md §7.2): which
|
|
4
|
+
* reference cycle it belongs to, and whether it is in the cycle or merely downstream of it.
|
|
5
|
+
*
|
|
6
|
+
* @remarks
|
|
7
|
+
* The value stays what it is (`0`, Excel's answer with iterative calculation off); this is
|
|
8
|
+
* metadata beside it, the way `SpillEntry` marks a spill zone. Entries are interned per
|
|
9
|
+
* `(cycle, kind)` by the executor, so equal payloads are the same object and adjacent cells of
|
|
10
|
+
* one cycle coalesce into one region — and a region's payload IS the cycle, no id to look up.
|
|
11
|
+
*/
|
|
12
|
+
export interface CircularEntry {
|
|
13
|
+
/** The cycle; one live object per cycle, shared by every cell in it or downstream of it. */
|
|
14
|
+
readonly cycle: ICalculation.ICircularReference;
|
|
15
|
+
/** In the cycle, or a reader of it (transitively). Both evaluate to `0`. */
|
|
16
|
+
readonly kind: 'member' | 'downstream';
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=CircularEntry.d.ts.map
|
|
@@ -40,31 +40,38 @@ export interface CalcNode {
|
|
|
40
40
|
cachedValue: Scalar | IRange | undefined;
|
|
41
41
|
pendingPromise: Promise<any> | null;
|
|
42
42
|
/**
|
|
43
|
-
*
|
|
43
|
+
* The demand evaluation's result — finalized for the cell, or a pending promise — which
|
|
44
|
+
* `doEvaluate` consumes in place of an `evaluateAt` of its own. Cleared once consumed.
|
|
45
|
+
* Meaningful only while `CalcState.Circular` is set.
|
|
44
46
|
*/
|
|
45
|
-
|
|
47
|
+
demandValue: any;
|
|
46
48
|
/**
|
|
47
|
-
*
|
|
49
|
+
* Identifies the cycle a `CycleRole.Member` belongs to (and the one a `CycleRole.Downstream`
|
|
50
|
+
* node read). `0` for none. Slices that share a node share an id. Reset every mark phase.
|
|
48
51
|
*/
|
|
49
|
-
|
|
52
|
+
cycleGroup: number;
|
|
50
53
|
/**
|
|
51
|
-
*
|
|
54
|
+
* For a `CycleRole.Member`: the member this one READ that continues the cycle — the next step
|
|
55
|
+
* of the walk `ICircularReference.getPath` answers. A cycle of one points at itself. Written
|
|
56
|
+
* from the `Circular` slice (whose stack order is the read order) and rewritten whenever the
|
|
57
|
+
* cycle is detected again; stale otherwise, so a walk checks each step is still a live member.
|
|
52
58
|
*/
|
|
53
|
-
|
|
59
|
+
cycleNext: CalcNode | null;
|
|
54
60
|
/**
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
* @remarks
|
|
60
|
-
* Deliberately not folded into {@link state}: `state` carries the Skip/Pending transitions that
|
|
61
|
-
* `doEvaluate` reads and rewrites mid-pass, and this has to survive being set BEFORE that runs.
|
|
61
|
+
* The cycle the sheet's circular index currently shows this cell in (`0` none) — what the last
|
|
62
|
+
* commit wrote, so the next can write the delta. Persists across passes, unlike
|
|
63
|
+
* {@link cycleGroup}; the role it shows is the `CalcState.ShownRoleMask` field of {@link state}.
|
|
62
64
|
*/
|
|
63
|
-
|
|
65
|
+
shownGroup: number;
|
|
64
66
|
/**
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
67
|
+
* Bit mask, laid out by `CalcState`: the pending flags, `Skip`, `Circular`, and the
|
|
68
|
+
* `DemandState`/`CycleRole` fields of the current pass.
|
|
69
|
+
*
|
|
70
|
+
* @remarks
|
|
71
|
+
* The node is reused across passes, so a per-pass bit is only meaningful when {@link cycleId}
|
|
72
|
+
* and {@link markId} say the node is in the current pass; the mark phase resets them
|
|
73
|
+
* (`CalcState.PassMask`) as it visits each affected node. `Skip` and the shown role outlive a
|
|
74
|
+
* pass on purpose.
|
|
68
75
|
*/
|
|
69
76
|
state: number;
|
|
70
77
|
}
|
|
@@ -1,28 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The bit layout of `CalcNode.state`: single-bit flags in the low byte, then three 2-bit fields.
|
|
3
|
+
*
|
|
4
|
+
* @remarks
|
|
5
|
+
* Every bit is independent, so a phase touches only its own: the mark phase clears
|
|
6
|
+
* {@link PassMask} (what the last pass decided), `doEvaluate` consumes {@link Skip}, and the
|
|
7
|
+
* promise path flips the pending bits — none of them assigns the whole word.
|
|
8
|
+
*
|
|
9
|
+
* The 2-bit fields hold a {@link DemandState} and two {@link CycleRole}s. Their values are
|
|
10
|
+
* pre-shifted into place, so a read is `(state & Mask) === Value` and a write is
|
|
11
|
+
* `state = (state & ~Mask) | Value`. The `ShownRole` field sits two bits above `CycleRole`, so
|
|
12
|
+
* copying the role the pass decided into what the sheet shows is `(state & CycleRoleMask) << 2`.
|
|
13
|
+
*/
|
|
1
14
|
export declare const CalcState: {
|
|
15
|
+
/** Nothing set. */
|
|
16
|
+
readonly Idle: 0;
|
|
2
17
|
/**
|
|
3
|
-
*
|
|
18
|
+
* Evaluate-once guard for a dynamic dependency (a dynamic precedent or a spill output) that
|
|
19
|
+
* caused a recalc: the next pass skips the node instead of re-evaluating it.
|
|
4
20
|
*/
|
|
5
|
-
readonly
|
|
21
|
+
readonly Skip: number;
|
|
22
|
+
/** Reserved. */
|
|
23
|
+
readonly Removed: number;
|
|
24
|
+
/** The node is in the pending spatial (the user has been given a pending status). */
|
|
25
|
+
readonly Pending: number;
|
|
26
|
+
/** A precedent evaluated to a pending value this pass, so the node keeps its cached value. */
|
|
27
|
+
readonly PendingPrecedents: number;
|
|
28
|
+
/** The node's promise resolved; the result waits in `cachedValue` for the next pass. */
|
|
29
|
+
readonly PendingResolved: number;
|
|
6
30
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
31
|
+
* The topological sort could not order the node this pass — it is in a reference cycle, or
|
|
32
|
+
* downstream of one — so it was (or will be) evaluated by demand and `doEvaluate` takes its
|
|
33
|
+
* `demandValue` in place of an `evaluateAt`.
|
|
9
34
|
*/
|
|
10
|
-
readonly
|
|
11
|
-
readonly Removed: 2;
|
|
35
|
+
readonly Circular: number;
|
|
12
36
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
37
|
+
* A `Waiting` node the evaluation in progress has read under iterative calculation — it is in
|
|
38
|
+
* the executor's hit list already, so a second read of it in the same evaluation adds nothing.
|
|
39
|
+
* Cleared when the list is consumed.
|
|
15
40
|
*/
|
|
16
|
-
readonly
|
|
41
|
+
readonly IterHit: number;
|
|
42
|
+
/** Field: the {@link DemandState}. */
|
|
43
|
+
readonly DemandMask: number;
|
|
44
|
+
/** Field: the {@link CycleRole} this pass decided. */
|
|
45
|
+
readonly CycleRoleMask: number;
|
|
46
|
+
/** Field: the {@link CycleRole} the sheet's circular index currently shows (persists). */
|
|
47
|
+
readonly ShownRoleMask: number;
|
|
17
48
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
49
|
+
* In the executor's circular roster for the pass in progress. Outside {@link PassMask} on
|
|
50
|
+
* purpose: the roster outlives the re-marks a pass makes while it re-dirties, so the executor
|
|
51
|
+
* clears this when it empties the roster.
|
|
20
52
|
*/
|
|
21
|
-
readonly
|
|
53
|
+
readonly Rostered: number;
|
|
54
|
+
/** What the mark phase resets: everything a single pass decides. `Skip` and the shown role survive. */
|
|
55
|
+
readonly PassMask: number;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Where a node the topological sort could not order stands in the demand evaluation
|
|
59
|
+
* (DESIGN-CIRCULAR-CALC.md §4.3). Meaningful only while `CalcState.Circular` is set for the
|
|
60
|
+
* current pass. Values sit in the `CalcState.DemandMask` field.
|
|
61
|
+
*/
|
|
62
|
+
export declare const DemandState: {
|
|
63
|
+
/** Not yet evaluated; a read of it suspends the reader so it can go first. */
|
|
64
|
+
readonly Unevaluated: 0;
|
|
65
|
+
/** On the in-progress stack; a read of it is a reference cycle. */
|
|
66
|
+
readonly Waiting: number;
|
|
67
|
+
/** Evaluated (or written `0` as a cycle member); reads see its value. */
|
|
68
|
+
readonly Done: number;
|
|
69
|
+
/**
|
|
70
|
+
* Evaluated on the ordered path but not yet committed — its value is in the pending batch, so a
|
|
71
|
+
* lazy read of the grid would still see the previous one. Reads treat it as {@link Unevaluated}
|
|
72
|
+
* until the batch is flushed, which makes it {@link Done}.
|
|
73
|
+
*/
|
|
74
|
+
readonly Evaluated: number;
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* How a node relates to a reference cycle, decided by the demand evaluation's reads. Values sit
|
|
78
|
+
* in the `CalcState.CycleRoleMask` field.
|
|
79
|
+
*/
|
|
80
|
+
export declare const CycleRole: {
|
|
81
|
+
/** Not in a cycle and reads none — an unorderable node that simply computed. */
|
|
82
|
+
readonly None: 0;
|
|
83
|
+
/** Named by a `Circular` read: its evaluation needed its own value. Writes `0`. */
|
|
84
|
+
readonly Member: number;
|
|
22
85
|
/**
|
|
23
|
-
*
|
|
24
|
-
*
|
|
86
|
+
* Read a member (transitively). Writes `0` too — Excel gives every cell downstream of a cycle
|
|
87
|
+
* `0`, not a value computed from the members' `0` (design §2.1: `=A1+100` is `0`).
|
|
25
88
|
*/
|
|
26
|
-
readonly
|
|
89
|
+
readonly Downstream: number;
|
|
27
90
|
};
|
|
28
91
|
//# sourceMappingURL=CalcState.d.ts.map
|
|
@@ -5,6 +5,7 @@ import { IFunctionCollection } from '../../scripting';
|
|
|
5
5
|
import { Tuple } from '../../collections';
|
|
6
6
|
import { IContextContainer } from './IContextContainer';
|
|
7
7
|
import { CalcScope } from './CalcScope';
|
|
8
|
+
import { ReadHook } from './_ReadObservedGrid';
|
|
8
9
|
export declare class CalculationContext implements IFormulaContext {
|
|
9
10
|
protected _instanceScope: any;
|
|
10
11
|
protected _runtime: IRuntime;
|
|
@@ -14,9 +15,39 @@ export declare class CalculationContext implements IFormulaContext {
|
|
|
14
15
|
protected _axis: IRange.Axis;
|
|
15
16
|
protected _coerceToNumber: (value: Scalar, fromType: ScalarType, options?: IFormulaContext.ParseNumberOptions) => Scalar;
|
|
16
17
|
protected _functionProviders?: readonly FunctionProvider[];
|
|
18
|
+
/**
|
|
19
|
+
* Receives every value read while armed; `null` on the ordinary path.
|
|
20
|
+
*
|
|
21
|
+
* @remarks
|
|
22
|
+
* Two paths read the grid on a formula's behalf and both report here: a reference built by
|
|
23
|
+
* {@link _toReference} (its grid is wrapped in a {@link ReadObservedGrid}) and the direct
|
|
24
|
+
* single-cell read {@link getValueAt} falls back to. Constructing a reference is not a read.
|
|
25
|
+
*/
|
|
26
|
+
protected _onRead: ReadHook | null;
|
|
27
|
+
/**
|
|
28
|
+
* Receives the reads of references built on the DYNAMIC branch of {@link getReference} — the
|
|
29
|
+
* result of `OFFSET`/`INDIRECT`/`INDEX` — when {@link _onRead} is not armed. The executor arms
|
|
30
|
+
* it for the length of an ordinary pass so that a dynamic read landing on the evaluating cell
|
|
31
|
+
* is seen (DESIGN-CIRCULAR-CALC.md §5); `null` outside a pass.
|
|
32
|
+
*/
|
|
33
|
+
protected _dynamicRead: ReadHook | null;
|
|
17
34
|
constructor(container: IContextContainer, axis?: IRange.Axis, functionProviders?: readonly FunctionProvider[]);
|
|
18
35
|
/** @hidden */
|
|
19
36
|
_setInstanceScope(instanceScope: any): void;
|
|
37
|
+
/**
|
|
38
|
+
* @hidden
|
|
39
|
+
* Arms (or, with `null`, disarms) the read hook. While armed, every reference this context
|
|
40
|
+
* builds observes its reads and every direct cell read is reported — the funnel a demand
|
|
41
|
+
* evaluation decides circularity through. The ordinary evaluation path leaves it `null` and
|
|
42
|
+
* builds references exactly as before.
|
|
43
|
+
*/
|
|
44
|
+
_setReadHook(hook: ReadHook | null): void;
|
|
45
|
+
/**
|
|
46
|
+
* @hidden
|
|
47
|
+
* Arms (or, with `null`, disarms) the hook dynamic-branch references report to while no read
|
|
48
|
+
* hook is armed. See {@link _dynamicRead}.
|
|
49
|
+
*/
|
|
50
|
+
_setDynamicReadHook(hook: ReadHook | null): void;
|
|
20
51
|
/**
|
|
21
52
|
* @hidden
|
|
22
53
|
*
|
|
@@ -100,6 +131,14 @@ export declare class CalculationContext implements IFormulaContext {
|
|
|
100
131
|
* A caller that reads a WINDOW rather than returning a reference - `SUMIF`'s `sum_range`,
|
|
101
132
|
* `LOOKUP`'s `result_vector`, both anchor-plus-length - goes through
|
|
102
133
|
* {@link getResizedReference} instead: Excel reads the part that fits rather than failing.
|
|
134
|
+
*
|
|
135
|
+
* This is the one place a reference is built on a formula's behalf, so it is where the read
|
|
136
|
+
* hook attaches: while {@link _onRead} is armed the reference is built over a
|
|
137
|
+
* {@link ReadObservedGrid} and every value it (or a view derived from it) opens is reported.
|
|
138
|
+
* Unarmed, a static reference's grid is used as is — the ordinary path pays nothing, not even a
|
|
139
|
+
* branch per read — while a `dynamic` one (the result of `OFFSET`/`INDIRECT`/`INDEX`, the rare
|
|
140
|
+
* path) reports to {@link _dynamicRead} when that is armed: a dynamic read that lands on the
|
|
141
|
+
* evaluating cell is a cycle on any path (design §5).
|
|
103
142
|
*/
|
|
104
143
|
private _toReference;
|
|
105
144
|
/** @inheritdoc IFormulaContext.getAddress */
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { Scalar } from '@sheetxl/primitives';
|
|
2
|
+
import { Direction, RangeAxis, CellCoords, RangeCoords } from '@sheetxl/utils';
|
|
3
|
+
import { IGrid, ISparseGrid, Tuple } from '../../collections';
|
|
4
|
+
/**
|
|
5
|
+
* Receives every value read a formula makes while a read hook is armed.
|
|
6
|
+
*
|
|
7
|
+
* @remarks
|
|
8
|
+
* A single-cell read reports a 1x1 rectangle; a block read (iteration, runs, bounded tuples)
|
|
9
|
+
* reports the rectangle it was asked for — the cells it *may* open — because a sparse iterator
|
|
10
|
+
* cannot tell an empty cell from a formula cell whose value is not there yet, and the second is
|
|
11
|
+
* exactly the read a cycle check must see. Coordinates are absolute and closed.
|
|
12
|
+
*
|
|
13
|
+
* The hook may throw; the throw propagates through the reading function up to the evaluation
|
|
14
|
+
* that armed it. Nothing is reported for constructing a reference, for its coords or size, or for
|
|
15
|
+
* a copy made to hold derived values.
|
|
16
|
+
*/
|
|
17
|
+
export type ReadHook = (gridId: string, rowStart: number, colStart: number, rowEnd: number, colEnd: number) => void;
|
|
18
|
+
/**
|
|
19
|
+
* An `ISparseGrid` that reports every value access on an inner grid to a {@link ReadHook}.
|
|
20
|
+
*
|
|
21
|
+
* @remarks
|
|
22
|
+
* Every `ReferenceRange` a formula receives reads its cells through the grid it was built over
|
|
23
|
+
* and never touches the sheet directly, so wrapping that grid observes every value read the
|
|
24
|
+
* reference makes — through any `Range` view derived from it, since views share the grid.
|
|
25
|
+
*
|
|
26
|
+
* `clone`/`cloneEmpty` hand back the inner grid's copy UNWRAPPED. A `Range` operation clones
|
|
27
|
+
* its grid only as scratch space for a derived result (`fill`, `map`, a scalar broadcast) and
|
|
28
|
+
* overwrites what it later reads back; the coordinates in such a copy no longer name sheet
|
|
29
|
+
* cells (a broadcast writes its scalar at (0,0)), so reporting them would invent reads of A1.
|
|
30
|
+
*
|
|
31
|
+
* Writes are delegated verbatim; nothing on a reference's path writes to its grid.
|
|
32
|
+
*/
|
|
33
|
+
export declare class ReadObservedGrid implements ISparseGrid<Scalar> {
|
|
34
|
+
/**
|
|
35
|
+
* Number of wrappers constructed since module load.
|
|
36
|
+
*
|
|
37
|
+
* @remarks
|
|
38
|
+
* A pass that Kahn orders builds none; tests pin that the ordinary path stays unwrapped.
|
|
39
|
+
*/
|
|
40
|
+
static created: number;
|
|
41
|
+
protected readonly _inner: ISparseGrid<Scalar>;
|
|
42
|
+
protected readonly _gridId: string;
|
|
43
|
+
protected readonly _onRead: ReadHook;
|
|
44
|
+
constructor(inner: ISparseGrid<Scalar>, gridId: string, onRead: ReadHook);
|
|
45
|
+
/** The grid being observed. */
|
|
46
|
+
getInner(): ISparseGrid<Scalar>;
|
|
47
|
+
/**
|
|
48
|
+
* Reports a block read. Missing sides of a partial bound are taken from the grid's maximum
|
|
49
|
+
* extent, then from its data extent; a grid with neither has nothing to read.
|
|
50
|
+
*/
|
|
51
|
+
protected _reportBounds(bounds: Partial<RangeCoords> | null | undefined): void;
|
|
52
|
+
/** {@inheritDoc IGrid.getValueAt} */
|
|
53
|
+
getValueAt(row: number, column: number): Scalar;
|
|
54
|
+
/** {@inheritDoc ISparseGrid.getRuns} */
|
|
55
|
+
getRuns(options?: ISparseGrid.RunIteratorOptions): ISparseGrid.RunIterableIterator<Scalar>;
|
|
56
|
+
/** {@inheritDoc IGrid.entries} */
|
|
57
|
+
entries(options?: IGrid.IteratorOptions): IGrid.EntryIterator<Scalar>;
|
|
58
|
+
/** {@inheritDoc IGrid.values} */
|
|
59
|
+
values(options?: IGrid.IteratorOptions): IGrid.ValueIterator;
|
|
60
|
+
/** {@inheritDoc IGrid.keys} */
|
|
61
|
+
keys(options?: IGrid.IteratorOptions): IGrid.KeyIterator;
|
|
62
|
+
/** {@inheritDoc IGrid.getValues} */
|
|
63
|
+
getValues(coords?: RangeCoords): Tuple.BoundedTuples<Scalar> | null;
|
|
64
|
+
/** {@inheritDoc IGrid.copyTo} */
|
|
65
|
+
copyTo(destination: IGrid, topLeft: CellCoords, from: RangeCoords): void;
|
|
66
|
+
/** {@inheritDoc IGrid.getAxis} */
|
|
67
|
+
getAxis(): RangeAxis;
|
|
68
|
+
/** {@inheritDoc IGrid.getCount} */
|
|
69
|
+
getCount(): number;
|
|
70
|
+
/** {@inheritDoc IGrid.getCoords} */
|
|
71
|
+
getCoords(): RangeCoords | null;
|
|
72
|
+
/** {@inheritDoc IGrid.getMaxCoords} */
|
|
73
|
+
getMaxCoords(): RangeCoords | null;
|
|
74
|
+
/** {@inheritDoc IGrid.clone} */
|
|
75
|
+
clone(cloneKey?: any): this;
|
|
76
|
+
/** {@inheritDoc IGrid.cloneEmpty} */
|
|
77
|
+
cloneEmpty(cloneKey?: any): this;
|
|
78
|
+
/** {@inheritDoc IGrid.setValues} */
|
|
79
|
+
setValues(values: Tuple.GridTuple<Scalar>): this;
|
|
80
|
+
/** {@inheritDoc IGrid.setValueAt} */
|
|
81
|
+
setValueAt(row: number, column: number, value: Scalar): void;
|
|
82
|
+
/** {@inheritDoc IGrid.delete} */
|
|
83
|
+
delete(coords: RangeCoords | null): boolean;
|
|
84
|
+
/** {@inheritDoc IGrid.clear} */
|
|
85
|
+
clear(): void;
|
|
86
|
+
/** {@inheritDoc IGrid.shift} */
|
|
87
|
+
shift(coords: RangeCoords, direction: Direction): boolean;
|
|
88
|
+
get [Symbol.toStringTag](): string;
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=_ReadObservedGrid.d.ts.map
|
|
@@ -124,12 +124,28 @@ export interface ICell {
|
|
|
124
124
|
*
|
|
125
125
|
* @remarks
|
|
126
126
|
* Warnings differ from errors in that they may alter the display of the cell's value or type.
|
|
127
|
+
* A cell in a reference cycle, or downstream of one, carries one here — the text form of
|
|
128
|
+
* {@link getCircularReference}: the walk from this cell around the cycle and back
|
|
129
|
+
* ("Circular reference: A1 → B1 → A1"), or "Reads a circular reference at A1".
|
|
127
130
|
*/
|
|
128
131
|
getWarnings(): readonly string[];
|
|
129
132
|
/**
|
|
130
133
|
* Retrieves any errors attached to the cell.
|
|
131
134
|
*/
|
|
132
135
|
getErrors(): readonly string[];
|
|
136
|
+
/**
|
|
137
|
+
* The reference cycle this cell is in, or downstream of — or `null` when it is neither.
|
|
138
|
+
*
|
|
139
|
+
* @remarks
|
|
140
|
+
* Evaluated state, beside the value: a cell in a cycle, and every cell that reads one, is `0`
|
|
141
|
+
* (Excel, iterative calculation off), and this is the only thing that says why. Ask the cycle
|
|
142
|
+
* whether this cell is a member or a reader ({@link ICalculation.ICircularReference.isMember})
|
|
143
|
+
* and, under iterative calculation, whether it converged.
|
|
144
|
+
*
|
|
145
|
+
* The range-level view is `ICellRange.Feature.Circular` — `getCounts` for how many cells,
|
|
146
|
+
* `getRegions` for which, each region carrying this same object as its payload.
|
|
147
|
+
*/
|
|
148
|
+
getCircularReference(): ICalculation.ICircularReference | null;
|
|
133
149
|
/**
|
|
134
150
|
* Returns the style information applied to the cell.
|
|
135
151
|
*
|