@sheetxl/primitives 0.7.28-beta.4 → 0.8.0-beta.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.
- package/browser/esm/index.mjs +101 -55
- package/node/esm/index.mjs +115 -67
- package/package.json +3 -4
- package/types/src/ErrorPolicy.d.ts +48 -57
- package/types/src/Flatten.d.ts +6 -3
- package/types/src/FormulaContext.d.ts +47 -7
- package/types/src/IFormulaContext.d.ts +223 -11
- package/types/src/IFunction.d.ts +368 -39
- package/types/src/IFunctionArguments.d.ts +214 -0
- package/types/src/IRange.d.ts +199 -40
- package/types/src/IRangeStats.d.ts +34 -3
- package/types/src/IRuntime.d.ts +24 -1
- package/types/src/Lazy.d.ts +76 -0
- package/types/src/NoFilter.d.ts +34 -0
- package/types/src/NoLift.d.ts +31 -0
- package/types/src/Repeating.d.ts +24 -4
- package/types/src/ReportType.d.ts +42 -0
- package/types/src/Scalar.d.ts +1 -1
- package/types/src/ValueKind.d.ts +43 -0
- package/types/src/Volatile.d.ts +12 -0
- package/types/src/WildCard.d.ts +13 -9
- package/types/src/index.d.ts +7 -0
- package/browser/cjs/index.cjs +0 -1
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { Scalar } from './Scalar';
|
|
2
|
+
import { ValueKind } from './ValueKind';
|
|
3
|
+
import { IRange } from './IRange';
|
|
4
|
+
import { Lambda } from './Lambda';
|
|
5
|
+
import { IFunction } from './IFunction';
|
|
6
|
+
/**
|
|
7
|
+
* The current call's arguments, as the body sees them — argument **reflection**.
|
|
8
|
+
*
|
|
9
|
+
* @remarks
|
|
10
|
+
* A declaration answers "what does this parameter mean?", and the marshaller coerces every
|
|
11
|
+
* argument to it. That is right for the overwhelming majority of parameters. What it cannot answer
|
|
12
|
+
* is anything about *this particular call*:
|
|
13
|
+
*
|
|
14
|
+
* - What did the caller write there — a value, a cell, an array, nothing at all?
|
|
15
|
+
* - What was the value BEFORE the parameter's type coerced it?
|
|
16
|
+
* - Was that empty slot an omission, or a blank cell the caller pointed at?
|
|
17
|
+
*
|
|
18
|
+
* Excel has behaviors that turn on exactly those questions, and they cluster at the
|
|
19
|
+
* parameters Excel declares `any` — where there is nothing to express as a type, because Excel
|
|
20
|
+
* declined to express one. `CUMIPMT` refuses a boolean at every slot while `FV` coerces one at
|
|
21
|
+
* every slot; the difference is not the values, it is that `CUMIPMT`'s slots are `any` and its
|
|
22
|
+
* body decides.
|
|
23
|
+
*
|
|
24
|
+
* It is REFLECTION and nothing else — two questions, and no third:
|
|
25
|
+
*
|
|
26
|
+
* | question | answers |
|
|
27
|
+
* | --- | --- |
|
|
28
|
+
* | *what was supplied* | {@link getLength}, {@link getKindAt} |
|
|
29
|
+
* | *what it is* | {@link getRawAt}, {@link getKindAt} |
|
|
30
|
+
*
|
|
31
|
+
* Coercion is deliberately absent. A body that wants a number calls
|
|
32
|
+
* {@link IFormulaContext.parseAsNumber} on the value this hands it — that already takes a value,
|
|
33
|
+
* already propagates an incoming error with its identity, and already answers `#VALUE!` for a
|
|
34
|
+
* boolean, which IS the rule an `any` slot needs. There is no coercion an index can do that a
|
|
35
|
+
* value cannot.
|
|
36
|
+
*
|
|
37
|
+
* Obtained from `FormulaContext.getArgs()`, and valid ONLY while the body that asked for it is
|
|
38
|
+
* running. A body must not retain it across an `await`, a callback, or a nested evaluation — the
|
|
39
|
+
* views are pooled by dispatch depth, so the one at your depth is handed to the next call at that
|
|
40
|
+
* depth.
|
|
41
|
+
*
|
|
42
|
+
* ```typescript
|
|
43
|
+
* export function CUMIPMT(rate: Scalar, nper: Scalar): number {
|
|
44
|
+
* const args = FormulaContext.getArgs();
|
|
45
|
+
* if (args.getKindAt(0) === ValueKind.Omitted) return FormulaError.BuiltIn.NA; // `CUMIPMT(,120,…)`
|
|
46
|
+
* const asNumber = FormulaContext.parseAsNumber(args.getRawAt(0) as Scalar); // TRUE is #VALUE!
|
|
47
|
+
* // …
|
|
48
|
+
* }
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
* @see {@link IFormulaContext.getArgs}
|
|
52
|
+
*/
|
|
53
|
+
export interface IFunctionArguments {
|
|
54
|
+
/**
|
|
55
|
+
* How many PARAMETERS the caller supplied.
|
|
56
|
+
*
|
|
57
|
+
* @remarks
|
|
58
|
+
* Indexing throughout matches the BODY's own signature, never the raw call positions
|
|
59
|
+
* (see {@link getRawAt}). `index >= getLength()` is an ABSENT argument — one the caller never
|
|
60
|
+
* wrote, whose own JS initializer supplied the value. That is a different thing from an OMITTED
|
|
61
|
+
* one; see {@link isOmittedAt}.
|
|
62
|
+
*/
|
|
63
|
+
getLength(): number;
|
|
64
|
+
/**
|
|
65
|
+
* This invocation's value at `index`, uncoerced.
|
|
66
|
+
*
|
|
67
|
+
* @param index The PARAMETER index — the position in the body's own signature.
|
|
68
|
+
*
|
|
69
|
+
* @remarks
|
|
70
|
+
* A `Scalar` means the argument IS a value; an {@link IRange} means a container whose members
|
|
71
|
+
* the body reads itself (a reference materializes on demand); a {@link Lambda} means a callable.
|
|
72
|
+
*
|
|
73
|
+
* At a REPEATING parameter (`Repeating<T>`, or a rest parameter) this is the ARRAY of that
|
|
74
|
+
* group's values — one entry per argument the caller wrote — and {@link getRepeatingArgsAt} is the
|
|
75
|
+
* per-argument view of the same thing. Indexing by parameter rather than by call position is
|
|
76
|
+
* what lets a body ask its questions in the vocabulary it declared:
|
|
77
|
+
*
|
|
78
|
+
* ```typescript
|
|
79
|
+
* // IFS(condition: Repeating<[logicalTest: boolean, logicalTrue: AcceptError<any>]>)
|
|
80
|
+
* args.getRawAt(0); // [test1, value1, test2, value2, …]
|
|
81
|
+
* args.getRepeatingArgsAt(0).getRawAt(0); // test1
|
|
82
|
+
* ```
|
|
83
|
+
*
|
|
84
|
+
* **Under a lift** the call broadcasts and the body runs once per output cell; this reports the
|
|
85
|
+
* value for THIS invocation — the member at the current broadcast position for a lifted argument,
|
|
86
|
+
* the whole argument for one that is not lifting. That is what every identified caller wants: a
|
|
87
|
+
* body checking for a boolean must see the member, not the array around it.
|
|
88
|
+
*
|
|
89
|
+
* One boundary is worth knowing: under a lift at a parameter that declares a CONCRETE scalar
|
|
90
|
+
* type, the member has already been converted by that declaration, so the raw and coerced answers
|
|
91
|
+
* coincide there. At the `Scalar` slots this interface exists for, nothing coerces and the value
|
|
92
|
+
* is the member exactly as the caller's range holds it.
|
|
93
|
+
*
|
|
94
|
+
* A reference UNION (`(A1:A3,C1:C3)`) is an array too — one `IReferenceRange` per area — which
|
|
95
|
+
* is how a body whose slot took the areas apart can still tell one argument's union from two
|
|
96
|
+
* arguments (`SUMPRODUCT` refuses the first and accepts the second).
|
|
97
|
+
*/
|
|
98
|
+
getRawAt(index: number): IFunctionArguments.RawArg | IFunctionArguments.RawArg[];
|
|
99
|
+
/**
|
|
100
|
+
* A nested view over one REPEATING parameter's arguments, so a body can ask the same questions
|
|
101
|
+
* one level down — `getRepeatingArgsAt(0).isOmittedAt(1)`.
|
|
102
|
+
*
|
|
103
|
+
* @param index The PARAMETER index of the repeating group (or rest parameter).
|
|
104
|
+
*
|
|
105
|
+
* @remarks
|
|
106
|
+
* The nested view is FLAT over the group's arguments: a period-2 group repeated three times reads
|
|
107
|
+
* as six, in call order. That is where "which one was omitted" has an answer at all — the group
|
|
108
|
+
* as a whole cannot be omitted, only one of its arguments can.
|
|
109
|
+
*
|
|
110
|
+
* At a non-repeating parameter this returns an EMPTY view (`getLength()` of 0) rather than
|
|
111
|
+
* throwing, so a body that folds over its groups needs no special case.
|
|
112
|
+
*/
|
|
113
|
+
getRepeatingArgsAt(index: number): IFunctionArguments;
|
|
114
|
+
/**
|
|
115
|
+
* The KIND of the argument at `index` — the total discriminator over {@link getRawAt}'s value.
|
|
116
|
+
*
|
|
117
|
+
* @param index The PARAMETER index — the position in the body's own signature.
|
|
118
|
+
*
|
|
119
|
+
* @remarks
|
|
120
|
+
* Every raw argument is exactly one of a closed set of kinds ({@link ValueKind}), and this
|
|
121
|
+
* answers without materializing anything — a reference stays coords underneath. The scalar
|
|
122
|
+
* kinds ARE `ScalarType` values, so `getKindAt(i) === ScalarType.Boolean` reads naturally.
|
|
123
|
+
*
|
|
124
|
+
* Under a lift this reports THIS invocation's value, like {@link getRawAt} — except the
|
|
125
|
+
* {@link ValueKind.Omitted} answer, which is a fact about the CALL (the caller wrote an empty
|
|
126
|
+
* comma) and does not change per broadcast position. At a REPEATING parameter it answers for
|
|
127
|
+
* the group's FIRST argument; per-argument kinds are one level down —
|
|
128
|
+
* `getRepeatingArgsAt(i).getKindAt(j)`.
|
|
129
|
+
*
|
|
130
|
+
* There are THREE argument positions:
|
|
131
|
+
*
|
|
132
|
+
* | form | position | answer |
|
|
133
|
+
* | --- | --- | --- |
|
|
134
|
+
* | `CUMIPMT(0.01,120,100000,13,24)` | never wrote a 6th | `Omitted` here — the POSITION fact is {@link getLength} (`index >= getLength()`), not a kind |
|
|
135
|
+
* | `CUMIPMT(,120,100000,13,24,0)` | the empty comma | {@link ValueKind.Omitted} |
|
|
136
|
+
* | `CUMIPMT(…,E1)`, E1 blank | a blank CELL | {@link ValueKind.Reference} — blankness is the cell's value, not the argument |
|
|
137
|
+
*
|
|
138
|
+
* The kind is the argument's own and it survives what it passes through:
|
|
139
|
+
* `VLOOKUP(10,10,1,TRUE)` is `#N/A` where `VLOOKUP(10,{10},1,TRUE)` is 10 — scalar vs 1x1
|
|
140
|
+
* array; `TYPE(IF(TRUE,10))` is 1 where `TYPE(IF(TRUE,{10}))` is 64 — a selector carries the
|
|
141
|
+
* kind through in both directions.
|
|
142
|
+
*/
|
|
143
|
+
getKindAt(index: number): ValueKind;
|
|
144
|
+
/**
|
|
145
|
+
* True when the argument at `index` is DIRECT — Excel's "typed into the list of arguments":
|
|
146
|
+
* the evaluated value IS a value, not a container or a callable.
|
|
147
|
+
*
|
|
148
|
+
* @param index The PARAMETER index — the position in the body's own signature.
|
|
149
|
+
*
|
|
150
|
+
* @remarks
|
|
151
|
+
* The derived predicate over {@link getKindAt}: true exactly when the kind is one of the
|
|
152
|
+
* `ScalarType` members. A blank (`ScalarType.Null`) IS a value and is direct; an omitted
|
|
153
|
+
* argument, a reference, an array and a callable are not. Directness is what the
|
|
154
|
+
* direct-vs-member coercion rules key on (`SUM(1,TRUE)` is 2 where `SUM({1,TRUE})` is 1), so
|
|
155
|
+
* a body speaking that vocabulary can ask in it.
|
|
156
|
+
*/
|
|
157
|
+
isDirectAt(index: number): boolean;
|
|
158
|
+
/**
|
|
159
|
+
* How many AREAS the argument at `index` covers — 1 for an ordinary reference, more for a
|
|
160
|
+
* union (`(A1:A5,B1:B2)`), and 0 for anything that is not a reference at all.
|
|
161
|
+
*
|
|
162
|
+
* @param index The PARAMETER index — the position in the body's own signature.
|
|
163
|
+
*
|
|
164
|
+
* @remarks
|
|
165
|
+
* {@link getKindAt} deliberately cannot answer this: a union IS a reference and reports
|
|
166
|
+
* {@link ValueKind.Reference}, the same as `A1:A5`. This is the question a body asks when the
|
|
167
|
+
* union is the thing it must decide about, and the three possible answers all come from asking
|
|
168
|
+
* it — flatten every area, refuse, or `#REF!`.
|
|
169
|
+
*
|
|
170
|
+
* Only a {@link IFunction.ParameterTypeJSON.reportType} slot can see a union at all; at every
|
|
171
|
+
* other slot the marshaller has already answered `#VALUE!`.
|
|
172
|
+
*/
|
|
173
|
+
getAreaCountAt(index: number): number;
|
|
174
|
+
/**
|
|
175
|
+
* The functions the argument at `index` holds, in row-major order — or `null` unless it holds
|
|
176
|
+
* nothing but functions.
|
|
177
|
+
*
|
|
178
|
+
* @param index The PARAMETER index — the position in the body's own signature.
|
|
179
|
+
*
|
|
180
|
+
* @remarks
|
|
181
|
+
* A formula can pass a function as a value: `LAMBDA(x, x * 2)`, or a built-in by name, as `SUM`
|
|
182
|
+
* is in `BYROW(A1:C3, SUM)`. A `Lambda` parameter takes ONE such value. This is for an untyped
|
|
183
|
+
* parameter that also takes an ARRAY of them, as `HSTACK(SUM, AVERAGE)` makes.
|
|
184
|
+
*
|
|
185
|
+
* The argument's shape is its own: {@link getKindAt} is `Lambda` for one function and `Array`
|
|
186
|
+
* for several, and {@link getRawAt} is that array. A function value IS an {@link IFunction}: a
|
|
187
|
+
* built-in by name answers as the registry's function does, and a `LAMBDA` is one whose
|
|
188
|
+
* {@link IFunction.isLambda} is `true`. A body whose untyped parameter holds the value reads the
|
|
189
|
+
* functions from it directly; this is reflection, for when the declaration does not hand it over.
|
|
190
|
+
*
|
|
191
|
+
* Nothing is collected until every member has proved to be a function, so a data range given by
|
|
192
|
+
* mistake costs one member.
|
|
193
|
+
*/
|
|
194
|
+
getFunctionsAt(index: number): readonly IFunction[] | null;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* {@inheritDoc IFunctionArguments}
|
|
198
|
+
*
|
|
199
|
+
* @see
|
|
200
|
+
* ### **Interface**
|
|
201
|
+
*
|
|
202
|
+
* {@link IFunctionArguments}
|
|
203
|
+
*/
|
|
204
|
+
export declare namespace IFunctionArguments {
|
|
205
|
+
/**
|
|
206
|
+
* One argument as the caller wrote it — a value, a container, a callable, or nothing.
|
|
207
|
+
*
|
|
208
|
+
* @remarks
|
|
209
|
+
* `undefined` is an OMITTED or ABSENT argument; `null` is a blank, which is a value. A reference
|
|
210
|
+
* union is delivered as `RawArg[]` — one reference per area (see {@link IFunctionArguments.getRawAt}).
|
|
211
|
+
*/
|
|
212
|
+
type RawArg = Scalar | IRange | Lambda | undefined;
|
|
213
|
+
}
|
|
214
|
+
//# sourceMappingURL=IFunctionArguments.d.ts.map
|
package/types/src/IRange.d.ts
CHANGED
|
@@ -69,11 +69,16 @@ export interface IRange<T extends Scalar = Scalar> {
|
|
|
69
69
|
uniqueIndices(axis?: IRange.Axis, exactlyOnce?: boolean): number[];
|
|
70
70
|
/**
|
|
71
71
|
* Applies a callback function to elements from this range and another range or a scalar,
|
|
72
|
-
* using
|
|
72
|
+
* using Excel's broadcasting rules. This is the two-operand special case of {@link zip}:
|
|
73
|
+
* `a.broadcast(b, f)` is `a.zip([b], ([x, y]) => f(x, y))`.
|
|
73
74
|
*
|
|
74
|
-
* **Broadcasting Rules
|
|
75
|
-
* -
|
|
76
|
-
* -
|
|
75
|
+
* **Broadcasting Rules** (the same as {@link zip}):
|
|
76
|
+
* - A scalar or a 1×1 range fills any shape: (1×1) + (3×4) → (3×4)
|
|
77
|
+
* - Same shapes pair position by position: (3×4) + (3×4) → (3×4)
|
|
78
|
+
* - A dimension of 1 tiles across the other operand's: (3×1) + (3×4) → (3×4)
|
|
79
|
+
* - Incompatible shapes (neither equal nor 1) throw, unless `misalignValue` is set, in which
|
|
80
|
+
* case the result is the union shape and every position outside the intersection holds
|
|
81
|
+
* `misalignValue`. Here the pad is a RESULT; in {@link zip} it is an ARGUMENT.
|
|
77
82
|
*
|
|
78
83
|
* @param other The other range or scalar to broadcast with.
|
|
79
84
|
* @param callbackFn The function to apply to corresponding elements.
|
|
@@ -82,11 +87,10 @@ export interface IRange<T extends Scalar = Scalar> {
|
|
|
82
87
|
* @returns A new range with the broadcasted results.
|
|
83
88
|
*
|
|
84
89
|
* @remarks
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
* - Incompatible shapes error: (3×4) + (2×3) → Error (unless misalignValue set)
|
|
90
|
+
* Iteration is sparse: the positions visited are the union of both operands' stored cells. A
|
|
91
|
+
* position empty on both sides has one answer, and a callback that reads only its two values
|
|
92
|
+
* (`callbackFn.length === 2`) receives that answer computed ONCE and written as runs; a callback
|
|
93
|
+
* that asks for `coords` or `range` is called per position instead.
|
|
90
94
|
*/
|
|
91
95
|
broadcast<TS extends Scalar = T>(other: IRange | TS, callbackFn: (a: TS, b: TS, coords: IRange.CellCoords, range: IRange<T>) => TS, options?: IRange.BroadcastOptions): this;
|
|
92
96
|
/**
|
|
@@ -244,11 +248,40 @@ export interface IRange<T extends Scalar = Scalar> {
|
|
|
244
248
|
*/
|
|
245
249
|
filter<TS extends Scalar = T>(callbackFn: (value: TS, coords: IRange.CellCoords, range: IRange<T>) => MaybeError<boolean>, options?: IRange.TraversalAxis | IRange.IteratorOptions): this;
|
|
246
250
|
/**
|
|
247
|
-
*
|
|
251
|
+
* The first error member in row-major order, or `null` when there is none — the identity that
|
|
252
|
+
* propagates when a body refuses a range with an error inside it:
|
|
253
|
+
* `if (range.hasError()) return range.firstError();`.
|
|
254
|
+
*
|
|
255
|
+
* @remarks
|
|
256
|
+
* Errors INSIDE a range are the body's to judge: the engine hands a valid range over whole and
|
|
257
|
+
* never looks inside, so a function whose answer depends on every member says so with this
|
|
258
|
+
* line, placed before its own validation where Excel's error outranks it. A reshaper or a
|
|
259
|
+
* lookup, whose members pass through or are never read, needs no line at all.
|
|
260
|
+
*/
|
|
261
|
+
firstError(): FormulaError.Known | null;
|
|
262
|
+
/**
|
|
263
|
+
* Linearizes the range into a single column by flattened ordinal — the member at ordinal `i`
|
|
264
|
+
* lands at row `i`, column 0.
|
|
248
265
|
*
|
|
249
266
|
* @param options {@link IRange.IteratorOptions}
|
|
267
|
+
*
|
|
268
|
+
* @remarks
|
|
269
|
+
* `options.axis` is the TRAVERSAL order feeding the ordinal, not the orientation of the result:
|
|
270
|
+
* the result is always Nx1, and a row is `flatten().transpose()`. The default is row-major,
|
|
271
|
+
* which is the order Excel pairs two range operands in.
|
|
272
|
+
*
|
|
273
|
+
* `options.type` carries a read type onto the result, so a member the type filters out becomes
|
|
274
|
+
* a HOLE at its ordinal rather than compacting the column. That is what lets two operands be
|
|
275
|
+
* paired position by position — see {@link alignValues}.
|
|
276
|
+
*
|
|
277
|
+
* `options.includeEmpty` has no meaning here and is ignored: a range is inherently sparse, so
|
|
278
|
+
* an empty position is simply absent. Sparsity is preserved and nothing is materialized.
|
|
279
|
+
*
|
|
280
|
+
* Equivalent to `reshape(rows * columns, 1)`, which is where the ordinal rule is stated.
|
|
281
|
+
*
|
|
282
|
+
* @see {@link getValuesFlat} for the same linearization as a JS array.
|
|
250
283
|
*/
|
|
251
|
-
flatten
|
|
284
|
+
flatten(options?: IRange.IteratorOptions): this;
|
|
252
285
|
/**
|
|
253
286
|
* Iterates over the cells within the range, applying the provided callback function to each cell.
|
|
254
287
|
*
|
|
@@ -326,6 +359,30 @@ export interface IRange<T extends Scalar = Scalar> {
|
|
|
326
359
|
* @param options {@link IRange.ValueOptions}
|
|
327
360
|
*/
|
|
328
361
|
getValueAt<TS extends Scalar = T>(rowIndex: number, colIndex: number, options?: IRange.ValueOptions): TS;
|
|
362
|
+
/**
|
|
363
|
+
* Returns the members as a flat JS array.
|
|
364
|
+
*
|
|
365
|
+
* @param options {@link IRange.IteratorOptions}
|
|
366
|
+
*
|
|
367
|
+
* @remarks
|
|
368
|
+
* The array form of {@link flatten}. Skips empty members unless `includeEmpty` is set, where
|
|
369
|
+
* `flatten` keeps them as holes in a range.
|
|
370
|
+
*/
|
|
371
|
+
getValuesFlat<TS extends Scalar = T>(options?: IRange.IteratorOptions): TS[];
|
|
372
|
+
/**
|
|
373
|
+
* Returns the position of the first member equal to `value`, or `-1` when there is none.
|
|
374
|
+
*
|
|
375
|
+
* @param value The value to find.
|
|
376
|
+
* @param options {@link IRange.IndexOfOptions}
|
|
377
|
+
*
|
|
378
|
+
* @remarks
|
|
379
|
+
* Equality is the `=` operator's: text is case-insensitive, and no value matches one of another
|
|
380
|
+
* type (`1` does not match `"1"`, nor `TRUE` `1`). Empty members, errors and rich data are never
|
|
381
|
+
* a match. The position is the offset along a row or column vector, and the row-major offset
|
|
382
|
+
* within a larger range. This is `MATCH(value, range, 0)` less one, and a range read by many
|
|
383
|
+
* lookups is indexed once rather than scanned per call.
|
|
384
|
+
*/
|
|
385
|
+
indexOf(value: Scalar, options?: IRange.IndexOfOptions): number;
|
|
329
386
|
/**
|
|
330
387
|
* Returns the number of columns of the range.
|
|
331
388
|
*/
|
|
@@ -345,7 +402,7 @@ export interface IRange<T extends Scalar = Scalar> {
|
|
|
345
402
|
* outputs and `map` cannot know what type they are. Use {@link IRange.toType} on the result if
|
|
346
403
|
* you do know. (`options.type` still applies to the values handed TO the callback.)
|
|
347
404
|
*/
|
|
348
|
-
map<TS extends Scalar = T>(callbackFn: (value: TS, coords: IRange.CellCoords, range: IRange<T>) => TS, options?: IRange.
|
|
405
|
+
map<TS extends Scalar = T>(callbackFn: (value: TS, coords: IRange.CellCoords, range: IRange<T>) => TS, options?: IRange.MapOptions): this;
|
|
349
406
|
/**
|
|
350
407
|
* Returns a new range where each cell is replaced with the value from `ifTrues`
|
|
351
408
|
* where the corresponding `conditions` value is strictly `true`.
|
|
@@ -602,40 +659,54 @@ export interface IRange<T extends Scalar = Scalar> {
|
|
|
602
659
|
*/
|
|
603
660
|
values<TS extends Scalar = T>(options?: IRange.IteratorOptions): IterableIterator<TS>;
|
|
604
661
|
/**
|
|
605
|
-
*
|
|
606
|
-
*
|
|
607
|
-
*
|
|
608
|
-
*
|
|
609
|
-
*
|
|
610
|
-
*
|
|
611
|
-
*
|
|
612
|
-
* -
|
|
662
|
+
* Aligns this range with any number of other ranges or scalars under Excel's broadcasting
|
|
663
|
+
* rules, calls `callbackFn` with the aligned values at each position, and returns the results as
|
|
664
|
+
* a new range of the broadcast shape. This is the N-ary form of {@link broadcast}, and the numpy
|
|
665
|
+
* idiom "align once, apply the kernel, never index"
|
|
666
|
+
* (`np.frompyfunc(f, n, 1)(*np.broadcast_arrays(...))`).
|
|
667
|
+
*
|
|
668
|
+
* **Broadcasting Rules** (Excel's; {@link broadcast} shares them):
|
|
669
|
+
* - A scalar or a 1×1 range FILLS: it is the same value at every position.
|
|
670
|
+
* - A dimension of 1 TILES across the largest extent in that dimension (`tile`, default on).
|
|
671
|
+
* - A shorter dimension PADS: past its extent the operand contributes `misalignValue`
|
|
672
|
+
* (default `#N/A`). The pad is an ARGUMENT, reaching the callback in that operand's slot for
|
|
673
|
+
* the callback to decide what it means; it is not a result written around the callback.
|
|
674
|
+
* - The output is `max(rows)` × `max(cols)` over the operands, anchored at this range's origin.
|
|
675
|
+
*
|
|
676
|
+
* **Iteration is sparse.** The positions visited are the UNION of the operands' stored cells
|
|
677
|
+
* after broadcast mapping; an operand with no cell at a visited position contributes its empty
|
|
678
|
+
* value (`null`, or the empty of `type`). Where EVERY shaped operand is blank the answer depends
|
|
679
|
+
* only on which operands are padded there, so those positions form REGIONS of equal padding,
|
|
680
|
+
* one per combination of operand extents, and `blankRegions` says how they are answered:
|
|
681
|
+
* `'each'` (default) calls the callback per position with its coordinates; `'once'` calls it once
|
|
682
|
+
* per region (the pandas `SparseArray` rule: the kernel runs once on `fill_value` and per stored
|
|
683
|
+
* entry otherwise) — the unpadded region's answer is what the result's empty positions read as,
|
|
684
|
+
* a padded region is written as runs. A region call carries `coords` of
|
|
685
|
+
* `{ rowIndex: -1, colIndex: -1 }`: it answers for many positions and no one of them. Under
|
|
686
|
+
* `'once'` a stretch of stored positions holding one value across every operand is one call too.
|
|
687
|
+
* An operand's own empty positions read as its empty value (a `fillEmpty`, an earlier
|
|
688
|
+
* elementwise result) and are never visited one by one.
|
|
689
|
+
*
|
|
690
|
+
* @param others Additional ranges or scalar values to align with this range, in argument order.
|
|
691
|
+
* @param callbackFn Called at each position with the aligned values (`values[0]` is this
|
|
692
|
+
* range's, `values[i + 1]` is `others[i]`'s), the position relative to the output, and this
|
|
693
|
+
* range. Returns the output value for that position. `values` is ONE buffer reused across
|
|
694
|
+
* calls (the ufunc inner-loop rule): read it, do not retain it.
|
|
695
|
+
* @param options {@link IRange.ZipOptions}. `type` reads EVERY operand's members, and the
|
|
696
|
+
* empty, through that type; it defaults to this range's own type, as {@link broadcast} does.
|
|
697
|
+
* Pass `type: null` to read every operand raw.
|
|
698
|
+
* @returns A new, untyped range of the broadcast shape (the values are the callback's, so this
|
|
699
|
+
* range's type does not describe them).
|
|
613
700
|
*
|
|
614
|
-
* @
|
|
615
|
-
*
|
|
616
|
-
*
|
|
617
|
-
* the current cell coordinates, and the original range. Returns the output value
|
|
618
|
-
* for that position.
|
|
619
|
-
* @param options {@link IRange.IteratorOptions}
|
|
620
|
-
* @returns A new range of the same shape as the broadcast result.
|
|
701
|
+
* @example
|
|
702
|
+
* // A 3×1 beside a 1×3 is 3×3: rows tile from the first, columns from the second.
|
|
703
|
+
* const sums = a.zip([b, 10], ([x, y, k]) => (x as number) + (y as number) + (k as number));
|
|
621
704
|
*/
|
|
622
|
-
zip(others: (IRange | Scalar)[], callbackFn: (values: Scalar[], coords: IRange.CellCoords, range: IRange<T>) => Scalar, options?: IRange.
|
|
705
|
+
zip(others: (IRange | Scalar)[], callbackFn: (values: Scalar[], coords: IRange.CellCoords, range: IRange<T>) => Scalar, options?: IRange.ZipOptions): this;
|
|
623
706
|
/**
|
|
624
707
|
* Returns a string representation of the range.
|
|
625
708
|
*/
|
|
626
709
|
toString(): string;
|
|
627
|
-
/**
|
|
628
|
-
* Returns `true` if the range is a literal range from a parameter.
|
|
629
|
-
*/
|
|
630
|
-
isLiteral(): boolean;
|
|
631
|
-
/**
|
|
632
|
-
* Returns `true` if the range is a scalar.
|
|
633
|
-
*/
|
|
634
|
-
isScalar(): boolean;
|
|
635
|
-
/**
|
|
636
|
-
* Returns `true` if the range is a vector (1D) either row or column.
|
|
637
|
-
*/
|
|
638
|
-
isVector(): boolean;
|
|
639
710
|
/**
|
|
640
711
|
* Returns `true` if the range is empty.
|
|
641
712
|
*/
|
|
@@ -668,6 +739,17 @@ export declare namespace IRange {
|
|
|
668
739
|
/**
|
|
669
740
|
* Options for controlling iteration behavior.
|
|
670
741
|
*/
|
|
742
|
+
/**
|
|
743
|
+
* Options for {@link IRange.indexOf}.
|
|
744
|
+
*/
|
|
745
|
+
interface IndexOfOptions {
|
|
746
|
+
/**
|
|
747
|
+
* Search from the last member back, answering the last match.
|
|
748
|
+
*
|
|
749
|
+
* @defaultValue `false`
|
|
750
|
+
*/
|
|
751
|
+
reverse?: boolean;
|
|
752
|
+
}
|
|
671
753
|
interface IteratorOptions extends IRange.ValueOptions {
|
|
672
754
|
/**
|
|
673
755
|
* The direction of the iteration.
|
|
@@ -705,6 +787,24 @@ export declare namespace IRange {
|
|
|
705
787
|
* If passing a large bound care must be taken.
|
|
706
788
|
*/
|
|
707
789
|
includeEmpty?: boolean;
|
|
790
|
+
/**
|
|
791
|
+
* Skips rows of the range: given the next row that would be read, answers the row to read
|
|
792
|
+
* instead - the same row when it is read, or the next one that is (the previous, when
|
|
793
|
+
* `reverse`).
|
|
794
|
+
*
|
|
795
|
+
* @param index The 0-based row about to be read.
|
|
796
|
+
* @param reverse Whether the read runs from the last row back.
|
|
797
|
+
* @returns The row to read, at or past `index`.
|
|
798
|
+
*
|
|
799
|
+
* @remarks
|
|
800
|
+
* A skipped cell is not visited, reads as empty and is left out of the statistics; the shape
|
|
801
|
+
* of the range is unchanged. `SUBTOTAL` reads a range this way when it skips hidden rows.
|
|
802
|
+
*/
|
|
803
|
+
processRowSkip?: (index: number, reverse?: boolean) => number;
|
|
804
|
+
/**
|
|
805
|
+
* Skips columns of the range, as {@link processRowSkip} skips rows.
|
|
806
|
+
*/
|
|
807
|
+
processColumnSkip?: (index: number, reverse?: boolean) => number;
|
|
708
808
|
/**
|
|
709
809
|
* Useful for callback functions that want a this.
|
|
710
810
|
*/
|
|
@@ -821,6 +921,8 @@ export declare namespace IRange {
|
|
|
821
921
|
* - It expands the result to the **union of both range sizes**.
|
|
822
922
|
* - Any cells that do not have valid corresponding values from the inputs
|
|
823
923
|
* will be filled with `misalignValue` instead of causing an error.
|
|
924
|
+
* - `zip()`, `mask()` and `choose()` always pad and default it to `#N/A`; in `zip()` the pad
|
|
925
|
+
* is delivered to the callback as that operand's value rather than written as the result.
|
|
824
926
|
*
|
|
825
927
|
* @example
|
|
826
928
|
* // Throws an error if A and B are not naturally broadcast-compatible
|
|
@@ -842,6 +944,53 @@ export declare namespace IRange {
|
|
|
842
944
|
*/
|
|
843
945
|
otherType?: ScalarType;
|
|
844
946
|
}
|
|
947
|
+
/**
|
|
948
|
+
* Options for {@link IRange.map}.
|
|
949
|
+
*/
|
|
950
|
+
interface MapOptions extends IRange.IteratorOptions {
|
|
951
|
+
/**
|
|
952
|
+
* How the positions the range does not store are answered.
|
|
953
|
+
*
|
|
954
|
+
* @defaultValue `'each'`
|
|
955
|
+
*
|
|
956
|
+
* @remarks
|
|
957
|
+
* `'each'` is the sparse walk: an empty position is not visited (or, with `includeEmpty`,
|
|
958
|
+
* visited with its coordinates). `'once'` calls the callback a single time for every empty
|
|
959
|
+
* position, with `coords` of `{ rowIndex: -1, colIndex: -1 }` and the value an empty reads
|
|
960
|
+
* as, and every one of them takes that answer — the {@link IRange.zip} rule. Under `'once'` a
|
|
961
|
+
* stretch of stored positions holding one value is also one call; a callback that reads only
|
|
962
|
+
* its value gets that on its own (it cannot tell), and one that reads `coords` opts in here.
|
|
963
|
+
*/
|
|
964
|
+
blankRegions?: 'each' | 'once';
|
|
965
|
+
}
|
|
966
|
+
/**
|
|
967
|
+
* Options for {@link IRange.zip}.
|
|
968
|
+
*/
|
|
969
|
+
interface ZipOptions extends IRange.ValuesOptions {
|
|
970
|
+
/**
|
|
971
|
+
* Whether a dimension of 1 tiles across the largest extent in that dimension.
|
|
972
|
+
*
|
|
973
|
+
* @defaultValue `true`
|
|
974
|
+
*
|
|
975
|
+
* @remarks
|
|
976
|
+
* Off, a dimension of 1 is a short dimension like any other and pads `misalignValue` past
|
|
977
|
+
* its one position: Excel's `MAP` rule, where a 1-row array is not stretched.
|
|
978
|
+
*/
|
|
979
|
+
tile?: boolean;
|
|
980
|
+
/**
|
|
981
|
+
* How the positions where EVERY shaped operand is blank are answered.
|
|
982
|
+
*
|
|
983
|
+
* @defaultValue `'each'`
|
|
984
|
+
*
|
|
985
|
+
* @remarks
|
|
986
|
+
* Such positions form regions of equal padding (see {@link IRange.zip}). `'each'` visits every
|
|
987
|
+
* one with its coordinates; `'once'` calls the callback a single time per region, with
|
|
988
|
+
* `coords` of `{ rowIndex: -1, colIndex: -1 }`, and writes the region as runs. An explicit
|
|
989
|
+
* option rather than a callback-arity gate, so a callback that reads `coords` for the positions
|
|
990
|
+
* it IS given can still have the blanks answered in one call.
|
|
991
|
+
*/
|
|
992
|
+
blankRegions?: 'each' | 'once';
|
|
993
|
+
}
|
|
845
994
|
/**
|
|
846
995
|
* Options used during masking.
|
|
847
996
|
*/
|
|
@@ -989,6 +1138,15 @@ export declare namespace IRange {
|
|
|
989
1138
|
rowEnd: number;
|
|
990
1139
|
/**
|
|
991
1140
|
* An optional identifier for the 2D space these coordinates are relative to.
|
|
1141
|
+
*
|
|
1142
|
+
* @remarks
|
|
1143
|
+
* `scope` was added after the coords reuse/scratch patterns were established, so it is the
|
|
1144
|
+
* field a reused object is most likely to carry STALE. The contract: a function that writes
|
|
1145
|
+
* its result into a caller-supplied reuse object must write `scope` unconditionally —
|
|
1146
|
+
* `null` when the result is unscoped, never left over from the previous occupant
|
|
1147
|
+
* (a leaked scope silently re-targets the coords at another sheet's grid). Writing it
|
|
1148
|
+
* conditionally is only safe on a freshly created object. Geometry-only helpers that
|
|
1149
|
+
* never read or write `scope` (CoordUtils) are exempt; their scope-aware wrappers own it.
|
|
992
1150
|
*/
|
|
993
1151
|
scope?: string | null;
|
|
994
1152
|
}
|
|
@@ -1006,6 +1164,7 @@ export declare namespace IRange {
|
|
|
1006
1164
|
rowIndex: number;
|
|
1007
1165
|
/**
|
|
1008
1166
|
* An optional identifier for the 2D space these coordinates are relative to.
|
|
1167
|
+
* See the remark on {@link Coords.scope} for the reuse-object contract.
|
|
1009
1168
|
*/
|
|
1010
1169
|
scope?: string | null;
|
|
1011
1170
|
}
|
|
@@ -19,6 +19,20 @@ import { FormulaError } from './FormulaError';
|
|
|
19
19
|
* 5. Quick introspection without triggering a full range scan
|
|
20
20
|
*/
|
|
21
21
|
export interface IRangeStats {
|
|
22
|
+
/**
|
|
23
|
+
* Returns the bounding box of the cells these stats cover, in the coordinates of the scanned
|
|
24
|
+
* grid.
|
|
25
|
+
*
|
|
26
|
+
* @returns The smallest rectangle containing every covered coordinate, or `null` when the
|
|
27
|
+
* stats cover nothing.
|
|
28
|
+
*
|
|
29
|
+
* @remarks
|
|
30
|
+
* Stats over several areas (a multi-area range, or a composite over several ranges) return the
|
|
31
|
+
* union box, which can include cells outside every area — and a composite's children may sit
|
|
32
|
+
* on different sheets, so its box is a shape, not an address. `getSize()` is the exact cell
|
|
33
|
+
* count; this is where those cells are.
|
|
34
|
+
*/
|
|
35
|
+
getCoords(): IRange.Coords | null;
|
|
22
36
|
/**
|
|
23
37
|
* Returns the total number of cells in the range, including empty cells.
|
|
24
38
|
*
|
|
@@ -146,7 +160,8 @@ export interface IRangeStats {
|
|
|
146
160
|
*
|
|
147
161
|
* - Every requested type (all types when omitted) is present with an explicit count —
|
|
148
162
|
* a `0` is a fact about the range, a missing key would be ambiguous.
|
|
149
|
-
* - Blanks report under {@link ScalarType.Null}: total cells minus non-empty values.
|
|
163
|
+
* - Blanks report under {@link ScalarType.Null}: total cells minus non-empty values. A cell the
|
|
164
|
+
* range skips ({@link IRange.IteratorOptions.processRowSkip}) is not a blank; it is not counted.
|
|
150
165
|
* - Never throws on error values — errors are population here, not faults — regardless of
|
|
151
166
|
* the `onError` iterator policy the stats were created with.
|
|
152
167
|
*/
|
|
@@ -242,7 +257,9 @@ export declare namespace IRangeStats {
|
|
|
242
257
|
/**
|
|
243
258
|
* Returns the k-th largest numeric value (1-based).
|
|
244
259
|
*
|
|
245
|
-
* @param k The rank of the value to return, where 1 is the largest value.
|
|
260
|
+
* @param k The rank of the value to return, where 1 is the largest value. A fractional rank
|
|
261
|
+
* becomes a 0-based index before it truncates — over five values `k = 2.5` is the
|
|
262
|
+
* THIRD largest, not the second.
|
|
246
263
|
* @returns `null` if k is out of range.
|
|
247
264
|
*
|
|
248
265
|
* @remarks
|
|
@@ -252,7 +269,8 @@ export declare namespace IRangeStats {
|
|
|
252
269
|
/**
|
|
253
270
|
* Returns the k-th smallest numeric value (1-based).
|
|
254
271
|
*
|
|
255
|
-
* @param k The rank of the value to return, where 1 is the smallest value.
|
|
272
|
+
* @param k The rank of the value to return, where 1 is the smallest value. A fractional rank
|
|
273
|
+
* becomes a 0-based index before it truncates.
|
|
256
274
|
* @returns `null` if k is out of range.
|
|
257
275
|
*
|
|
258
276
|
* @remarks
|
|
@@ -434,6 +452,19 @@ export declare namespace IRangeStats {
|
|
|
434
452
|
* This is a convenience method (visitedCount < totalCount)
|
|
435
453
|
*/
|
|
436
454
|
isTruncated(): boolean;
|
|
455
|
+
/**
|
|
456
|
+
* Returns the bounding box of a value's occurrences, in the coordinates of the scanned grid.
|
|
457
|
+
*
|
|
458
|
+
* @param value The value to look up
|
|
459
|
+
* @returns The smallest rectangle containing every occurrence, or `null` when the value was
|
|
460
|
+
* not found, is blank, or the frequencies were merged from several ranges (no single grid).
|
|
461
|
+
*
|
|
462
|
+
* @remarks
|
|
463
|
+
* Tracked by the same scan that counts, so it costs nothing extra. A box whose cell count
|
|
464
|
+
* equals {@link getFrequency} is a contiguous block — the value lives in exactly that
|
|
465
|
+
* rectangle; a larger box means the occurrences are scattered within it.
|
|
466
|
+
*/
|
|
467
|
+
getExtent(value: Scalar): IRange.Coords | null;
|
|
437
468
|
}
|
|
438
469
|
/**
|
|
439
470
|
* Options for finding top values in a range.
|
package/types/src/IRuntime.d.ts
CHANGED
|
@@ -54,9 +54,32 @@ export interface IRuntime {
|
|
|
54
54
|
*/
|
|
55
55
|
getOS(): string;
|
|
56
56
|
/**
|
|
57
|
-
* Returns the
|
|
57
|
+
* Returns the clock this runtime reads, as epoch milliseconds.
|
|
58
|
+
*
|
|
59
|
+
* @remarks
|
|
60
|
+
* A workbook's own runtime answers the current commit's timestamp, so every cell of a
|
|
61
|
+
* calculation pass agrees and collaborators on that commit agree with each other. A runtime
|
|
62
|
+
* built by a host answers whatever that host supplied — a pinned clock makes `NOW` and `TODAY`
|
|
63
|
+
* reproducible, and an unpinned one is the wall clock, which advances between reads.
|
|
58
64
|
*/
|
|
59
65
|
getNow: () => number;
|
|
66
|
+
/**
|
|
67
|
+
* Returns a random number in `[0, 1)` — one per calculation pass, as {@link getNow} is one
|
|
68
|
+
* clock reading per pass.
|
|
69
|
+
*
|
|
70
|
+
* @remarks
|
|
71
|
+
* This is not a cell's value. Each cell's draw is derived from this one, its position and which
|
|
72
|
+
* draw it is within that cell, so cells that do not depend on each other — which the engine is
|
|
73
|
+
* free to evaluate in any order — get the values their positions earn rather than the values
|
|
74
|
+
* their turn earned.
|
|
75
|
+
*
|
|
76
|
+
* Pinning it therefore pins `RAND`, `RANDBETWEEN` and `RANDARRAY`, exactly as pinning
|
|
77
|
+
* {@link getNow} pins `NOW` and `TODAY`. Left alone it is `Math.random`, drawn afresh each pass,
|
|
78
|
+
* so volatiles move on every recalculation.
|
|
79
|
+
*
|
|
80
|
+
* Values reproduce within one release, not across releases.
|
|
81
|
+
*/
|
|
82
|
+
getRandom: () => number;
|
|
60
83
|
/**
|
|
61
84
|
* Returns the current user or `null` if no user information is provided.
|
|
62
85
|
*/
|