@bilig/formula 0.1.0
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/LICENSE +21 -0
- package/README.md +16 -0
- package/dist/addressing.d.ts +66 -0
- package/dist/addressing.js +179 -0
- package/dist/addressing.js.map +1 -0
- package/dist/ast.d.ts +74 -0
- package/dist/ast.js +2 -0
- package/dist/ast.js.map +1 -0
- package/dist/binder.d.ts +13 -0
- package/dist/binder.js +1700 -0
- package/dist/binder.js.map +1 -0
- package/dist/builtin-capabilities.d.ts +19 -0
- package/dist/builtin-capabilities.js +861 -0
- package/dist/builtin-capabilities.js.map +1 -0
- package/dist/builtins/complex.d.ts +10 -0
- package/dist/builtins/complex.js +407 -0
- package/dist/builtins/complex.js.map +1 -0
- package/dist/builtins/convert.d.ts +3 -0
- package/dist/builtins/convert.js +362 -0
- package/dist/builtins/convert.js.map +1 -0
- package/dist/builtins/datetime.d.ts +23 -0
- package/dist/builtins/datetime.js +1096 -0
- package/dist/builtins/datetime.js.map +1 -0
- package/dist/builtins/distribution-builtins.d.ts +16 -0
- package/dist/builtins/distribution-builtins.js +517 -0
- package/dist/builtins/distribution-builtins.js.map +1 -0
- package/dist/builtins/distributions.d.ts +34 -0
- package/dist/builtins/distributions.js +722 -0
- package/dist/builtins/distributions.js.map +1 -0
- package/dist/builtins/financial-builtins.d.ts +16 -0
- package/dist/builtins/financial-builtins.js +324 -0
- package/dist/builtins/financial-builtins.js.map +1 -0
- package/dist/builtins/financial.d.ts +11 -0
- package/dist/builtins/financial.js +241 -0
- package/dist/builtins/financial.js.map +1 -0
- package/dist/builtins/fixed-income-builtins.d.ts +14 -0
- package/dist/builtins/fixed-income-builtins.js +598 -0
- package/dist/builtins/fixed-income-builtins.js.map +1 -0
- package/dist/builtins/fixed-income.d.ts +42 -0
- package/dist/builtins/fixed-income.js +668 -0
- package/dist/builtins/fixed-income.js.map +1 -0
- package/dist/builtins/formatting.d.ts +8 -0
- package/dist/builtins/formatting.js +53 -0
- package/dist/builtins/formatting.js.map +1 -0
- package/dist/builtins/logical.d.ts +4 -0
- package/dist/builtins/logical.js +258 -0
- package/dist/builtins/logical.js.map +1 -0
- package/dist/builtins/lookup-array-shape-builtins.d.ts +21 -0
- package/dist/builtins/lookup-array-shape-builtins.js +517 -0
- package/dist/builtins/lookup-array-shape-builtins.js.map +1 -0
- package/dist/builtins/lookup-criteria-builtins.d.ts +16 -0
- package/dist/builtins/lookup-criteria-builtins.js +216 -0
- package/dist/builtins/lookup-criteria-builtins.js.map +1 -0
- package/dist/builtins/lookup-database-builtins.d.ts +17 -0
- package/dist/builtins/lookup-database-builtins.js +294 -0
- package/dist/builtins/lookup-database-builtins.js.map +1 -0
- package/dist/builtins/lookup-financial-builtins.d.ts +11 -0
- package/dist/builtins/lookup-financial-builtins.js +291 -0
- package/dist/builtins/lookup-financial-builtins.js.map +1 -0
- package/dist/builtins/lookup-hypothesis-builtins.d.ts +11 -0
- package/dist/builtins/lookup-hypothesis-builtins.js +57 -0
- package/dist/builtins/lookup-hypothesis-builtins.js.map +1 -0
- package/dist/builtins/lookup-matrix-builtins.d.ts +17 -0
- package/dist/builtins/lookup-matrix-builtins.js +218 -0
- package/dist/builtins/lookup-matrix-builtins.js.map +1 -0
- package/dist/builtins/lookup-order-statistics-builtins.d.ts +18 -0
- package/dist/builtins/lookup-order-statistics-builtins.js +575 -0
- package/dist/builtins/lookup-order-statistics-builtins.js.map +1 -0
- package/dist/builtins/lookup-reference-builtins.d.ts +18 -0
- package/dist/builtins/lookup-reference-builtins.js +300 -0
- package/dist/builtins/lookup-reference-builtins.js.map +1 -0
- package/dist/builtins/lookup-regression-builtins.d.ts +12 -0
- package/dist/builtins/lookup-regression-builtins.js +511 -0
- package/dist/builtins/lookup-regression-builtins.js.map +1 -0
- package/dist/builtins/lookup-sort-filter-builtins.d.ts +20 -0
- package/dist/builtins/lookup-sort-filter-builtins.js +382 -0
- package/dist/builtins/lookup-sort-filter-builtins.js.map +1 -0
- package/dist/builtins/lookup.d.ts +13 -0
- package/dist/builtins/lookup.js +867 -0
- package/dist/builtins/lookup.js.map +1 -0
- package/dist/builtins/math-builtins.d.ts +31 -0
- package/dist/builtins/math-builtins.js +420 -0
- package/dist/builtins/math-builtins.js.map +1 -0
- package/dist/builtins/numeric.d.ts +30 -0
- package/dist/builtins/numeric.js +150 -0
- package/dist/builtins/numeric.js.map +1 -0
- package/dist/builtins/placeholder.d.ts +9 -0
- package/dist/builtins/placeholder.js +540 -0
- package/dist/builtins/placeholder.js.map +1 -0
- package/dist/builtins/radix.d.ts +12 -0
- package/dist/builtins/radix.js +220 -0
- package/dist/builtins/radix.js.map +1 -0
- package/dist/builtins/statistical-builtins.d.ts +13 -0
- package/dist/builtins/statistical-builtins.js +240 -0
- package/dist/builtins/statistical-builtins.js.map +1 -0
- package/dist/builtins/statistics.d.ts +8 -0
- package/dist/builtins/statistics.js +74 -0
- package/dist/builtins/statistics.js.map +1 -0
- package/dist/builtins/text.d.ts +5 -0
- package/dist/builtins/text.js +1879 -0
- package/dist/builtins/text.js.map +1 -0
- package/dist/builtins.d.ts +8 -0
- package/dist/builtins.js +695 -0
- package/dist/builtins.js.map +1 -0
- package/dist/compatibility.d.ts +25 -0
- package/dist/compatibility.js +498 -0
- package/dist/compatibility.js.map +1 -0
- package/dist/compiler.d.ts +29 -0
- package/dist/compiler.js +474 -0
- package/dist/compiler.js.map +1 -0
- package/dist/external-function-adapter.d.ts +32 -0
- package/dist/external-function-adapter.js +42 -0
- package/dist/external-function-adapter.js.map +1 -0
- package/dist/generated/formula-inventory.d.ts +6839 -0
- package/dist/generated/formula-inventory.js +7368 -0
- package/dist/generated/formula-inventory.js.map +1 -0
- package/dist/group-pivot-evaluator.d.ts +28 -0
- package/dist/group-pivot-evaluator.js +435 -0
- package/dist/group-pivot-evaluator.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/js-evaluator.d.ts +107 -0
- package/dist/js-evaluator.js +1651 -0
- package/dist/js-evaluator.js.map +1 -0
- package/dist/lexer.d.ts +6 -0
- package/dist/lexer.js +115 -0
- package/dist/lexer.js.map +1 -0
- package/dist/optimizer.d.ts +2 -0
- package/dist/optimizer.js +353 -0
- package/dist/optimizer.js.map +1 -0
- package/dist/parser.d.ts +2 -0
- package/dist/parser.js +352 -0
- package/dist/parser.js.map +1 -0
- package/dist/program-arena.d.ts +22 -0
- package/dist/program-arena.js +67 -0
- package/dist/program-arena.js.map +1 -0
- package/dist/runtime-values.d.ts +17 -0
- package/dist/runtime-values.js +11 -0
- package/dist/runtime-values.js.map +1 -0
- package/dist/special-call-rewrites.d.ts +2 -0
- package/dist/special-call-rewrites.js +74 -0
- package/dist/special-call-rewrites.js.map +1 -0
- package/dist/translation.d.ts +28 -0
- package/dist/translation.js +569 -0
- package/dist/translation.js.map +1 -0
- package/package.json +53 -0
package/dist/builtins.js
ADDED
|
@@ -0,0 +1,695 @@
|
|
|
1
|
+
import { BUILTINS, BuiltinId, ErrorCode, ValueTag } from "@bilig/protocol";
|
|
2
|
+
import { builtinJsSpecialNames } from "./builtin-capabilities.js";
|
|
3
|
+
import { createComplexBuiltins } from "./builtins/complex.js";
|
|
4
|
+
import { createDistributionBuiltins } from "./builtins/distribution-builtins.js";
|
|
5
|
+
import { createFinancialBuiltins } from "./builtins/financial-builtins.js";
|
|
6
|
+
import { createFixedIncomeBuiltins } from "./builtins/fixed-income-builtins.js";
|
|
7
|
+
import { countLeadingZeros, formatFixed, isValidDollarFraction, parseDollarDecimal, toColumnLabel, } from "./builtins/formatting.js";
|
|
8
|
+
import { buildIdentityMatrix, collectNumericArgs, createNumericBuiltinHelpers, doubleFactorialValue, evenValue, factorialValue, gcdPair, lcmPair, oddValue, roundDownToDigits, roundTowardZero, roundUpToDigits, } from "./builtins/numeric.js";
|
|
9
|
+
import { createMathBuiltins } from "./builtins/math-builtins.js";
|
|
10
|
+
import { createRadixBuiltins } from "./builtins/radix.js";
|
|
11
|
+
import { populationVariance, sampleVariance } from "./builtins/statistics.js";
|
|
12
|
+
import { createStatisticalBuiltins } from "./builtins/statistical-builtins.js";
|
|
13
|
+
import { datetimeBuiltins } from "./builtins/datetime.js";
|
|
14
|
+
import { convertBuiltin, euroconvertBuiltin } from "./builtins/convert.js";
|
|
15
|
+
import { logicalBuiltins } from "./builtins/logical.js";
|
|
16
|
+
import { lookupBuiltins } from "./builtins/lookup.js";
|
|
17
|
+
import { createBlockedBuiltinMap, scalarPlaceholderBuiltinNames } from "./builtins/placeholder.js";
|
|
18
|
+
import { getExternalScalarFunction, hasExternalFunction } from "./external-function-adapter.js";
|
|
19
|
+
import { textBuiltins } from "./builtins/text.js";
|
|
20
|
+
function toNumber(value) {
|
|
21
|
+
switch (value.tag) {
|
|
22
|
+
case ValueTag.Number:
|
|
23
|
+
return value.value;
|
|
24
|
+
case ValueTag.Boolean:
|
|
25
|
+
return value.value ? 1 : 0;
|
|
26
|
+
case ValueTag.Empty:
|
|
27
|
+
return 0;
|
|
28
|
+
case ValueTag.String:
|
|
29
|
+
case ValueTag.Error:
|
|
30
|
+
return undefined;
|
|
31
|
+
default:
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function toBitwiseUnsigned(value) {
|
|
36
|
+
if (value === undefined) {
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
const numeric = toNumber(value);
|
|
40
|
+
if (numeric === undefined || !Number.isFinite(numeric)) {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
const truncated = Math.trunc(numeric);
|
|
44
|
+
if (!Number.isSafeInteger(truncated)) {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
return truncated >>> 0;
|
|
48
|
+
}
|
|
49
|
+
function coerceShiftAmount(value) {
|
|
50
|
+
if (value === undefined) {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
const numeric = toNumber(value);
|
|
54
|
+
if (numeric === undefined || !Number.isFinite(numeric)) {
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
const truncated = Math.trunc(numeric);
|
|
58
|
+
return truncated >= 0 ? truncated : undefined;
|
|
59
|
+
}
|
|
60
|
+
function numberResult(value) {
|
|
61
|
+
return { tag: ValueTag.Number, value };
|
|
62
|
+
}
|
|
63
|
+
function valueError() {
|
|
64
|
+
return { tag: ValueTag.Error, code: ErrorCode.Value };
|
|
65
|
+
}
|
|
66
|
+
function blockedError() {
|
|
67
|
+
return { tag: ValueTag.Error, code: ErrorCode.Blocked };
|
|
68
|
+
}
|
|
69
|
+
function numError() {
|
|
70
|
+
return { tag: ValueTag.Error, code: ErrorCode.Value };
|
|
71
|
+
}
|
|
72
|
+
function numericResultOrError(value) {
|
|
73
|
+
return Number.isFinite(value) ? numberResult(value) : valueError();
|
|
74
|
+
}
|
|
75
|
+
function firstError(args) {
|
|
76
|
+
return args.find((arg) => arg.tag === ValueTag.Error);
|
|
77
|
+
}
|
|
78
|
+
function coercePositiveInteger(value, fallback) {
|
|
79
|
+
if (value === undefined) {
|
|
80
|
+
return fallback;
|
|
81
|
+
}
|
|
82
|
+
const numeric = toNumber(value);
|
|
83
|
+
if (numeric === undefined || !Number.isFinite(numeric)) {
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
const truncated = Math.trunc(numeric);
|
|
87
|
+
return truncated >= 1 ? truncated : undefined;
|
|
88
|
+
}
|
|
89
|
+
function coerceNumber(value, fallback) {
|
|
90
|
+
if (value === undefined) {
|
|
91
|
+
return fallback;
|
|
92
|
+
}
|
|
93
|
+
const numeric = toNumber(value);
|
|
94
|
+
return numeric !== undefined && Number.isFinite(numeric) ? numeric : undefined;
|
|
95
|
+
}
|
|
96
|
+
function integerValue(value, fallback) {
|
|
97
|
+
if (value === undefined) {
|
|
98
|
+
return fallback;
|
|
99
|
+
}
|
|
100
|
+
const numeric = toNumber(value);
|
|
101
|
+
if (numeric === undefined || !Number.isFinite(numeric)) {
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
return Math.trunc(numeric);
|
|
105
|
+
}
|
|
106
|
+
function toInteger(value, fallback) {
|
|
107
|
+
if (value === undefined) {
|
|
108
|
+
return fallback;
|
|
109
|
+
}
|
|
110
|
+
const numeric = toNumber(value);
|
|
111
|
+
if (numeric === undefined || !Number.isFinite(numeric)) {
|
|
112
|
+
return undefined;
|
|
113
|
+
}
|
|
114
|
+
const truncated = Math.trunc(numeric);
|
|
115
|
+
return Number.isSafeInteger(truncated) ? truncated : undefined;
|
|
116
|
+
}
|
|
117
|
+
function nonNegativeIntegerValue(value, fallback) {
|
|
118
|
+
const integer = integerValue(value, fallback);
|
|
119
|
+
return integer !== undefined && integer >= 0 ? integer : undefined;
|
|
120
|
+
}
|
|
121
|
+
function positiveIntegerValue(value, fallback) {
|
|
122
|
+
const integer = integerValue(value, fallback);
|
|
123
|
+
return integer !== undefined && integer >= 1 ? integer : undefined;
|
|
124
|
+
}
|
|
125
|
+
function sequenceResult(rowsArg, colsArg, startArg, stepArg) {
|
|
126
|
+
const rows = coercePositiveInteger(rowsArg, 1);
|
|
127
|
+
const cols = coercePositiveInteger(colsArg, 1);
|
|
128
|
+
const start = coerceNumber(startArg, 1);
|
|
129
|
+
const step = coerceNumber(stepArg, 1);
|
|
130
|
+
if (rows === undefined || cols === undefined || start === undefined || step === undefined) {
|
|
131
|
+
return valueError();
|
|
132
|
+
}
|
|
133
|
+
const values = [];
|
|
134
|
+
for (let index = 0; index < rows * cols; index += 1) {
|
|
135
|
+
values.push(numberResult(start + index * step));
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
kind: "array",
|
|
139
|
+
rows,
|
|
140
|
+
cols,
|
|
141
|
+
values,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
function coerceDateSerial(value) {
|
|
145
|
+
if (value === undefined) {
|
|
146
|
+
return undefined;
|
|
147
|
+
}
|
|
148
|
+
const serial = toNumber(value);
|
|
149
|
+
return serial !== undefined && Number.isFinite(serial) ? Math.trunc(serial) : undefined;
|
|
150
|
+
}
|
|
151
|
+
function coerceBoolean(value, fallback) {
|
|
152
|
+
if (value === undefined) {
|
|
153
|
+
return fallback;
|
|
154
|
+
}
|
|
155
|
+
if (value.tag === ValueTag.Boolean) {
|
|
156
|
+
return value.value;
|
|
157
|
+
}
|
|
158
|
+
const numeric = toNumber(value);
|
|
159
|
+
return numeric === undefined ? undefined : numeric !== 0;
|
|
160
|
+
}
|
|
161
|
+
const complexBuiltins = createComplexBuiltins({ toNumber, numberResult, valueError });
|
|
162
|
+
const numericBuiltinHelpers = createNumericBuiltinHelpers({
|
|
163
|
+
toNumber,
|
|
164
|
+
numberResult,
|
|
165
|
+
valueError,
|
|
166
|
+
numericResultOrError,
|
|
167
|
+
});
|
|
168
|
+
const { binaryMath, ceilingWith, floorWith, roundWith, unaryMath } = numericBuiltinHelpers;
|
|
169
|
+
const radixBuiltins = createRadixBuiltins({
|
|
170
|
+
toNumber,
|
|
171
|
+
integerValue,
|
|
172
|
+
nonNegativeIntegerValue,
|
|
173
|
+
valueError,
|
|
174
|
+
numberResult,
|
|
175
|
+
});
|
|
176
|
+
const fixedIncomeBuiltins = createFixedIncomeBuiltins({
|
|
177
|
+
toNumber,
|
|
178
|
+
coerceBoolean,
|
|
179
|
+
coerceDateSerial,
|
|
180
|
+
coerceNumber,
|
|
181
|
+
integerValue,
|
|
182
|
+
numberResult,
|
|
183
|
+
valueError,
|
|
184
|
+
});
|
|
185
|
+
const statisticalBuiltins = createStatisticalBuiltins({
|
|
186
|
+
toNumber,
|
|
187
|
+
coerceBoolean,
|
|
188
|
+
firstError,
|
|
189
|
+
numberResult,
|
|
190
|
+
numericResultOrError,
|
|
191
|
+
valueError,
|
|
192
|
+
});
|
|
193
|
+
const distributionBuiltins = createDistributionBuiltins({
|
|
194
|
+
toNumber,
|
|
195
|
+
coerceBoolean,
|
|
196
|
+
coerceNumber,
|
|
197
|
+
integerValue,
|
|
198
|
+
nonNegativeIntegerValue,
|
|
199
|
+
positiveIntegerValue,
|
|
200
|
+
numberResult,
|
|
201
|
+
numericResultOrError,
|
|
202
|
+
valueError,
|
|
203
|
+
});
|
|
204
|
+
const financialBuiltins = createFinancialBuiltins({
|
|
205
|
+
toNumber,
|
|
206
|
+
coerceBoolean,
|
|
207
|
+
coerceNumber,
|
|
208
|
+
coercePaymentType,
|
|
209
|
+
integerValue,
|
|
210
|
+
positiveIntegerValue,
|
|
211
|
+
numberResult,
|
|
212
|
+
numericResultOrError,
|
|
213
|
+
valueError,
|
|
214
|
+
});
|
|
215
|
+
const mathBuiltins = createMathBuiltins({
|
|
216
|
+
toNumber,
|
|
217
|
+
toBitwiseUnsigned,
|
|
218
|
+
coerceShiftAmount,
|
|
219
|
+
integerValue,
|
|
220
|
+
nonNegativeIntegerValue,
|
|
221
|
+
firstError,
|
|
222
|
+
numberResult,
|
|
223
|
+
valueError,
|
|
224
|
+
numError,
|
|
225
|
+
numericResultOrError,
|
|
226
|
+
unaryMath,
|
|
227
|
+
binaryMath,
|
|
228
|
+
ceilingWith,
|
|
229
|
+
floorWith,
|
|
230
|
+
roundWith,
|
|
231
|
+
roundUpToDigits,
|
|
232
|
+
roundDownToDigits,
|
|
233
|
+
roundTowardZero,
|
|
234
|
+
evenValue,
|
|
235
|
+
oddValue,
|
|
236
|
+
factorialValue,
|
|
237
|
+
doubleFactorialValue,
|
|
238
|
+
gcdPair,
|
|
239
|
+
lcmPair,
|
|
240
|
+
});
|
|
241
|
+
function coercePaymentType(value, fallback) {
|
|
242
|
+
const type = integerValue(value, fallback);
|
|
243
|
+
return type === 0 || type === 1 ? type : undefined;
|
|
244
|
+
}
|
|
245
|
+
function toZeroNumericValue(value) {
|
|
246
|
+
if (value.tag === ValueTag.String) {
|
|
247
|
+
return 0;
|
|
248
|
+
}
|
|
249
|
+
return toNumber(value);
|
|
250
|
+
}
|
|
251
|
+
function aggregateByCode(functionNum, values) {
|
|
252
|
+
const normalized = functionNum > 100 ? functionNum - 100 : functionNum;
|
|
253
|
+
const numericValues = collectNumericArgs(values, toNumber);
|
|
254
|
+
switch (normalized) {
|
|
255
|
+
case 1:
|
|
256
|
+
return numericValues.length === 0
|
|
257
|
+
? numberResult(0)
|
|
258
|
+
: numberResult(numericValues.reduce((sum, value) => sum + value, 0) / numericValues.length);
|
|
259
|
+
case 2:
|
|
260
|
+
return numberResult(values.filter((value) => value.tag === ValueTag.Number || value.tag === ValueTag.Boolean)
|
|
261
|
+
.length);
|
|
262
|
+
case 3:
|
|
263
|
+
return numberResult(values.filter((value) => value.tag !== ValueTag.Empty).length);
|
|
264
|
+
case 4:
|
|
265
|
+
return numberResult(numericValues.length === 0 ? 0 : Math.max(...numericValues));
|
|
266
|
+
case 5:
|
|
267
|
+
return numberResult(numericValues.length === 0 ? 0 : Math.min(...numericValues));
|
|
268
|
+
case 6:
|
|
269
|
+
return numberResult(numericValues.length === 0
|
|
270
|
+
? 0
|
|
271
|
+
: numericValues.reduce((product, value) => product * value, 1));
|
|
272
|
+
case 7:
|
|
273
|
+
return numberResult(Math.sqrt(sampleVariance(numericValues)));
|
|
274
|
+
case 8:
|
|
275
|
+
return numberResult(Math.sqrt(populationVariance(numericValues)));
|
|
276
|
+
case 9:
|
|
277
|
+
return numberResult(numericValues.reduce((sum, value) => sum + value, 0));
|
|
278
|
+
case 10:
|
|
279
|
+
return numberResult(sampleVariance(numericValues));
|
|
280
|
+
case 11:
|
|
281
|
+
return numberResult(populationVariance(numericValues));
|
|
282
|
+
default:
|
|
283
|
+
return valueError();
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
const scalarPlaceholderBuiltins = createBlockedBuiltinMap(scalarPlaceholderBuiltinNames);
|
|
287
|
+
const externalScalarBuiltinNames = [
|
|
288
|
+
"CALL",
|
|
289
|
+
"CUBEKPIMEMBER",
|
|
290
|
+
"CUBEMEMBER",
|
|
291
|
+
"CUBEMEMBERPROPERTY",
|
|
292
|
+
"CUBERANKEDMEMBER",
|
|
293
|
+
"CUBESET",
|
|
294
|
+
"CUBESETCOUNT",
|
|
295
|
+
"CUBEVALUE",
|
|
296
|
+
"DDE",
|
|
297
|
+
"DETECTLANGUAGE",
|
|
298
|
+
"HYPERLINK",
|
|
299
|
+
"IMAGE",
|
|
300
|
+
"INFO",
|
|
301
|
+
"REGISTER.ID",
|
|
302
|
+
"RTD",
|
|
303
|
+
"TRANSLATE",
|
|
304
|
+
"WEBSERVICE",
|
|
305
|
+
];
|
|
306
|
+
function createExternalScalarBuiltin(name) {
|
|
307
|
+
return (...args) => {
|
|
308
|
+
const existingError = firstError(args);
|
|
309
|
+
if (existingError) {
|
|
310
|
+
return existingError;
|
|
311
|
+
}
|
|
312
|
+
const external = getExternalScalarFunction(name);
|
|
313
|
+
return external ? external(...args) : blockedError();
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
const externalScalarBuiltins = Object.fromEntries(externalScalarBuiltinNames.map((name) => [name, createExternalScalarBuiltin(name)]));
|
|
317
|
+
const scalarBuiltins = {
|
|
318
|
+
SUM: (...args) => {
|
|
319
|
+
const error = firstError(args);
|
|
320
|
+
if (error)
|
|
321
|
+
return error;
|
|
322
|
+
return numberResult(args.reduce((sum, arg) => sum + (toNumber(arg) ?? 0), 0));
|
|
323
|
+
},
|
|
324
|
+
AVERAGEA: (...args) => {
|
|
325
|
+
const error = firstError(args);
|
|
326
|
+
if (error)
|
|
327
|
+
return error;
|
|
328
|
+
const numbers = args
|
|
329
|
+
.map((arg) => toZeroNumericValue(arg))
|
|
330
|
+
.filter((value) => value !== undefined);
|
|
331
|
+
return numberResult(numbers.length === 0 ? 0 : numbers.reduce((sum, value) => sum + value, 0) / numbers.length);
|
|
332
|
+
},
|
|
333
|
+
AVERAGE: (...args) => {
|
|
334
|
+
const error = firstError(args);
|
|
335
|
+
if (error)
|
|
336
|
+
return error;
|
|
337
|
+
const numbers = collectNumericArgs(args, toNumber);
|
|
338
|
+
if (numbers.length === 0)
|
|
339
|
+
return numberResult(0);
|
|
340
|
+
return numberResult(numbers.reduce((sum, value) => sum + value, 0) / numbers.length);
|
|
341
|
+
},
|
|
342
|
+
AVG: (...args) => {
|
|
343
|
+
const error = firstError(args);
|
|
344
|
+
if (error)
|
|
345
|
+
return error;
|
|
346
|
+
const numbers = collectNumericArgs(args, toNumber);
|
|
347
|
+
if (numbers.length === 0)
|
|
348
|
+
return numberResult(0);
|
|
349
|
+
return numberResult(numbers.reduce((sum, value) => sum + value, 0) / numbers.length);
|
|
350
|
+
},
|
|
351
|
+
CHOOSE: (indexValue, ...values) => {
|
|
352
|
+
const index = integerValue(indexValue);
|
|
353
|
+
if (index === undefined || index < 1 || index > values.length) {
|
|
354
|
+
return valueError();
|
|
355
|
+
}
|
|
356
|
+
const value = values[index - 1];
|
|
357
|
+
return value === undefined ? valueError() : value;
|
|
358
|
+
},
|
|
359
|
+
MIN: (...args) => numberResult(Math.min(...args.map((arg) => toNumber(arg) ?? Number.POSITIVE_INFINITY))),
|
|
360
|
+
MAX: (...args) => numberResult(Math.max(...args.map((arg) => toNumber(arg) ?? Number.NEGATIVE_INFINITY))),
|
|
361
|
+
MAXA: (...args) => {
|
|
362
|
+
const error = firstError(args);
|
|
363
|
+
if (error)
|
|
364
|
+
return error;
|
|
365
|
+
const values = args
|
|
366
|
+
.map((arg) => toZeroNumericValue(arg))
|
|
367
|
+
.filter((value) => value !== undefined);
|
|
368
|
+
return values.length === 0 ? numberResult(0) : numberResult(Math.max(...values));
|
|
369
|
+
},
|
|
370
|
+
MINA: (...args) => {
|
|
371
|
+
const error = firstError(args);
|
|
372
|
+
if (error)
|
|
373
|
+
return error;
|
|
374
|
+
const values = args
|
|
375
|
+
.map((arg) => toZeroNumericValue(arg))
|
|
376
|
+
.filter((value) => value !== undefined);
|
|
377
|
+
return values.length === 0 ? numberResult(0) : numberResult(Math.min(...values));
|
|
378
|
+
},
|
|
379
|
+
COUNT: (...args) => numberResult(args.filter((arg) => arg.tag === ValueTag.Number || arg.tag === ValueTag.Boolean).length),
|
|
380
|
+
COUNTA: (...args) => numberResult(args.filter((arg) => arg.tag !== ValueTag.Empty).length),
|
|
381
|
+
COUNTBLANK: (...args) => {
|
|
382
|
+
let blanks = 0;
|
|
383
|
+
for (const arg of args) {
|
|
384
|
+
if (arg.tag === ValueTag.Empty) {
|
|
385
|
+
blanks += 1;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
return numberResult(blanks);
|
|
389
|
+
},
|
|
390
|
+
ABS: (value) => numberResult(Math.abs(toNumber(value) ?? 0)),
|
|
391
|
+
ADDRESS: (rowArg, columnArg, absNumArg = { tag: ValueTag.Number, value: 1 }, refStyleArg = { tag: ValueTag.Number, value: 1 }, sheetTextArg) => {
|
|
392
|
+
const row = positiveIntegerValue(rowArg);
|
|
393
|
+
const column = positiveIntegerValue(columnArg);
|
|
394
|
+
const absNum = integerValue(absNumArg, 1);
|
|
395
|
+
const refStyle = integerValue(refStyleArg, 1);
|
|
396
|
+
if (row === undefined ||
|
|
397
|
+
column === undefined ||
|
|
398
|
+
absNum === undefined ||
|
|
399
|
+
refStyle === undefined) {
|
|
400
|
+
return valueError();
|
|
401
|
+
}
|
|
402
|
+
if (![1, 2, 3, 4].includes(absNum) || ![1, 2].includes(refStyle)) {
|
|
403
|
+
return valueError();
|
|
404
|
+
}
|
|
405
|
+
if (sheetTextArg !== undefined &&
|
|
406
|
+
sheetTextArg.tag !== ValueTag.String &&
|
|
407
|
+
sheetTextArg.tag !== ValueTag.Empty) {
|
|
408
|
+
return valueError();
|
|
409
|
+
}
|
|
410
|
+
if (sheetTextArg?.tag === ValueTag.Empty) {
|
|
411
|
+
return valueError();
|
|
412
|
+
}
|
|
413
|
+
const columnLabel = toColumnLabel(column);
|
|
414
|
+
if (columnLabel === undefined) {
|
|
415
|
+
return valueError();
|
|
416
|
+
}
|
|
417
|
+
const sheetPrefix = sheetTextArg?.tag === ValueTag.String ? `'${sheetTextArg.value.replace(/'/g, "''")}'!` : "";
|
|
418
|
+
if (refStyle === 2) {
|
|
419
|
+
const rowLabel = absNum === 1 || absNum === 2 ? String(row) : `[${row}]`;
|
|
420
|
+
const colLabel = absNum === 1 || absNum === 3 ? String(column) : `[${column}]`;
|
|
421
|
+
return {
|
|
422
|
+
tag: ValueTag.String,
|
|
423
|
+
value: `${sheetPrefix}R${rowLabel}C${colLabel}`,
|
|
424
|
+
stringId: 0,
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
const rowLabel = absNum === 1 || absNum === 2 ? `$${row}` : `${row}`;
|
|
428
|
+
const colLabel = absNum === 1 || absNum === 3 ? `$${columnLabel}` : columnLabel;
|
|
429
|
+
return {
|
|
430
|
+
tag: ValueTag.String,
|
|
431
|
+
value: `${sheetPrefix}${colLabel}${rowLabel}`,
|
|
432
|
+
stringId: 0,
|
|
433
|
+
};
|
|
434
|
+
},
|
|
435
|
+
DOLLAR: (valueArg, decimalsArg = { tag: ValueTag.Number, value: 2 }, noCommasArg) => {
|
|
436
|
+
const value = toNumber(valueArg);
|
|
437
|
+
const decimals = toInteger(decimalsArg, 2);
|
|
438
|
+
const noCommasValue = noCommasArg === undefined ? 0 : (toNumber(noCommasArg) ?? 0);
|
|
439
|
+
if (value === undefined || decimals === undefined) {
|
|
440
|
+
return valueError();
|
|
441
|
+
}
|
|
442
|
+
const text = formatFixed(value, decimals, noCommasValue === 0);
|
|
443
|
+
if (text === "") {
|
|
444
|
+
return valueError();
|
|
445
|
+
}
|
|
446
|
+
const normalizedText = text.startsWith("-") ? text.slice(1) : text;
|
|
447
|
+
return {
|
|
448
|
+
tag: ValueTag.String,
|
|
449
|
+
value: value < 0 ? `-$${normalizedText}` : `$${text}`,
|
|
450
|
+
stringId: 0,
|
|
451
|
+
};
|
|
452
|
+
},
|
|
453
|
+
FIXED: (valueArg, decimalsArg = { tag: ValueTag.Number, value: 2 }, noCommasArg) => {
|
|
454
|
+
const value = toNumber(valueArg);
|
|
455
|
+
const decimals = toInteger(decimalsArg, 2);
|
|
456
|
+
const noCommasValue = noCommasArg === undefined ? 0 : (toNumber(noCommasArg) ?? 0);
|
|
457
|
+
if (value === undefined || decimals === undefined) {
|
|
458
|
+
return valueError();
|
|
459
|
+
}
|
|
460
|
+
const text = formatFixed(value, decimals, noCommasValue === 0);
|
|
461
|
+
return text === "" ? valueError() : { tag: ValueTag.String, value: text, stringId: 0 };
|
|
462
|
+
},
|
|
463
|
+
DOLLARDE: (valueArg, fractionArg) => {
|
|
464
|
+
const value = toNumber(valueArg);
|
|
465
|
+
const fraction = toInteger(fractionArg);
|
|
466
|
+
if (value === undefined || fraction === undefined || !isValidDollarFraction(fraction)) {
|
|
467
|
+
return valueError();
|
|
468
|
+
}
|
|
469
|
+
const { integerPart, fractionalNumerator } = parseDollarDecimal(value);
|
|
470
|
+
if (fractionalNumerator >= fraction || !Number.isInteger(fractionalNumerator)) {
|
|
471
|
+
return valueError();
|
|
472
|
+
}
|
|
473
|
+
const sign = value < 0 ? -1 : 1;
|
|
474
|
+
return numberResult(sign * (integerPart + fractionalNumerator / fraction));
|
|
475
|
+
},
|
|
476
|
+
DOLLARFR: (valueArg, fractionArg) => {
|
|
477
|
+
const value = toNumber(valueArg);
|
|
478
|
+
const fraction = toInteger(fractionArg);
|
|
479
|
+
if (value === undefined || fraction === undefined || !isValidDollarFraction(fraction)) {
|
|
480
|
+
return valueError();
|
|
481
|
+
}
|
|
482
|
+
const sign = value < 0 ? -1 : 1;
|
|
483
|
+
const absolute = Math.abs(value);
|
|
484
|
+
const integerPart = Math.floor(absolute);
|
|
485
|
+
const fractional = absolute - integerPart;
|
|
486
|
+
const width = countLeadingZeros(fraction);
|
|
487
|
+
const scaledNumerator = Math.round(fractional * fraction);
|
|
488
|
+
const carry = Math.floor(scaledNumerator / fraction);
|
|
489
|
+
const numerator = scaledNumerator - carry * fraction;
|
|
490
|
+
const outputValue = `${integerPart + carry}.${String(numerator).padStart(width, "0")}`;
|
|
491
|
+
return numberResult(sign * Number(outputValue));
|
|
492
|
+
},
|
|
493
|
+
GEOMEAN: (...args) => {
|
|
494
|
+
const error = firstError(args);
|
|
495
|
+
if (error)
|
|
496
|
+
return error;
|
|
497
|
+
const numbers = collectNumericArgs(args, toNumber);
|
|
498
|
+
if (numbers.length === 0) {
|
|
499
|
+
return valueError();
|
|
500
|
+
}
|
|
501
|
+
if (numbers.some((value) => value < 0)) {
|
|
502
|
+
return valueError();
|
|
503
|
+
}
|
|
504
|
+
if (numbers.some((value) => value === 0)) {
|
|
505
|
+
return numberResult(0);
|
|
506
|
+
}
|
|
507
|
+
const logSum = numbers.reduce((sum, value) => sum + Math.log(value), 0);
|
|
508
|
+
return numberResult(Math.exp(logSum / numbers.length));
|
|
509
|
+
},
|
|
510
|
+
HARMEAN: (...args) => {
|
|
511
|
+
const error = firstError(args);
|
|
512
|
+
if (error)
|
|
513
|
+
return error;
|
|
514
|
+
const numbers = collectNumericArgs(args, toNumber);
|
|
515
|
+
if (numbers.length === 0 || numbers.some((value) => value <= 0)) {
|
|
516
|
+
return valueError();
|
|
517
|
+
}
|
|
518
|
+
return numberResult(numbers.length / numbers.reduce((sum, value) => sum + 1 / value, 0));
|
|
519
|
+
},
|
|
520
|
+
...mathBuiltins,
|
|
521
|
+
...fixedIncomeBuiltins,
|
|
522
|
+
RANDBETWEEN: (bottomArg, topArg) => {
|
|
523
|
+
const bottom = integerValue(bottomArg);
|
|
524
|
+
const top = integerValue(topArg);
|
|
525
|
+
if (bottom === undefined || top === undefined || top < bottom) {
|
|
526
|
+
return valueError();
|
|
527
|
+
}
|
|
528
|
+
return numberResult(Math.floor(Math.random() * (top - bottom + 1)) + bottom);
|
|
529
|
+
},
|
|
530
|
+
RANDARRAY: (rowsArg, colsArg, minArg, maxArg, wholeArg) => {
|
|
531
|
+
const rows = coercePositiveInteger(rowsArg, 1);
|
|
532
|
+
const cols = coercePositiveInteger(colsArg, 1);
|
|
533
|
+
const min = coerceNumber(minArg, 0);
|
|
534
|
+
const max = coerceNumber(maxArg, 1);
|
|
535
|
+
const whole = wholeArg === undefined ? false : (toNumber(wholeArg) ?? 0) !== 0;
|
|
536
|
+
if (rows === undefined ||
|
|
537
|
+
cols === undefined ||
|
|
538
|
+
min === undefined ||
|
|
539
|
+
max === undefined ||
|
|
540
|
+
max < min) {
|
|
541
|
+
return valueError();
|
|
542
|
+
}
|
|
543
|
+
const values = [];
|
|
544
|
+
for (let index = 0; index < rows * cols; index += 1) {
|
|
545
|
+
const value = whole
|
|
546
|
+
? Math.floor(Math.random() * (Math.trunc(max) - Math.trunc(min) + 1)) + Math.trunc(min)
|
|
547
|
+
: Math.random() * (max - min) + min;
|
|
548
|
+
values.push(numberResult(value));
|
|
549
|
+
}
|
|
550
|
+
return { kind: "array", rows, cols, values };
|
|
551
|
+
},
|
|
552
|
+
MUNIT: (sizeArg) => {
|
|
553
|
+
const size = positiveIntegerValue(sizeArg);
|
|
554
|
+
return size === undefined ? valueError() : buildIdentityMatrix(size, numberResult);
|
|
555
|
+
},
|
|
556
|
+
SERIESSUM: (xArg, nArg, mArg, ...coefficientArgs) => {
|
|
557
|
+
const x = toNumber(xArg);
|
|
558
|
+
const n = integerValue(nArg);
|
|
559
|
+
const m = integerValue(mArg);
|
|
560
|
+
if (x === undefined || n === undefined || m === undefined) {
|
|
561
|
+
return valueError();
|
|
562
|
+
}
|
|
563
|
+
let sum = 0;
|
|
564
|
+
coefficientArgs.forEach((coefficientArg, index) => {
|
|
565
|
+
const coefficient = toNumber(coefficientArg) ?? 0;
|
|
566
|
+
sum += coefficient * x ** (n + index * m);
|
|
567
|
+
});
|
|
568
|
+
return numberResult(sum);
|
|
569
|
+
},
|
|
570
|
+
SQRTPI: (value) => {
|
|
571
|
+
const numeric = toNumber(value);
|
|
572
|
+
return numeric === undefined
|
|
573
|
+
? valueError()
|
|
574
|
+
: numericResultOrError(Math.sqrt(numeric * Math.PI));
|
|
575
|
+
},
|
|
576
|
+
SUMSQ: (...args) => {
|
|
577
|
+
const error = firstError(args);
|
|
578
|
+
if (error)
|
|
579
|
+
return error;
|
|
580
|
+
return numberResult(collectNumericArgs(args, toNumber).reduce((sum, value) => sum + value ** 2, 0));
|
|
581
|
+
},
|
|
582
|
+
CONVERT: (numberArg, fromUnitArg, toUnitArg) => convertBuiltin(numberArg, fromUnitArg, toUnitArg),
|
|
583
|
+
EUROCONVERT: (numberArg, sourceArg, targetArg, fullPrecisionArg, triangulationPrecisionArg) => euroconvertBuiltin(numberArg, sourceArg, targetArg, fullPrecisionArg, triangulationPrecisionArg),
|
|
584
|
+
...radixBuiltins,
|
|
585
|
+
...complexBuiltins,
|
|
586
|
+
T: (value = { tag: ValueTag.Empty }) => {
|
|
587
|
+
if (value.tag === ValueTag.Error) {
|
|
588
|
+
return value;
|
|
589
|
+
}
|
|
590
|
+
return value.tag === ValueTag.String ? value : { tag: ValueTag.Empty };
|
|
591
|
+
},
|
|
592
|
+
ISOMITTED: (...args) => {
|
|
593
|
+
if (args.length !== 1) {
|
|
594
|
+
return valueError();
|
|
595
|
+
}
|
|
596
|
+
return { tag: ValueTag.Boolean, value: false };
|
|
597
|
+
},
|
|
598
|
+
N: (value = { tag: ValueTag.Empty }) => {
|
|
599
|
+
if (value.tag === ValueTag.Error) {
|
|
600
|
+
return value;
|
|
601
|
+
}
|
|
602
|
+
return numberResult(toNumber(value) ?? 0);
|
|
603
|
+
},
|
|
604
|
+
TYPE: (value = { tag: ValueTag.Empty }) => {
|
|
605
|
+
if (value.tag === ValueTag.Error) {
|
|
606
|
+
return numberResult(16);
|
|
607
|
+
}
|
|
608
|
+
if (value.kind === "array") {
|
|
609
|
+
return numberResult(64);
|
|
610
|
+
}
|
|
611
|
+
switch (value.tag) {
|
|
612
|
+
case ValueTag.Number:
|
|
613
|
+
case ValueTag.Empty:
|
|
614
|
+
return numberResult(1);
|
|
615
|
+
case ValueTag.String:
|
|
616
|
+
return numberResult(2);
|
|
617
|
+
case ValueTag.Boolean:
|
|
618
|
+
return numberResult(4);
|
|
619
|
+
}
|
|
620
|
+
},
|
|
621
|
+
DELTA: (leftArg, rightArg = { tag: ValueTag.Number, value: 0 }) => {
|
|
622
|
+
const left = toNumber(leftArg);
|
|
623
|
+
const right = toNumber(rightArg);
|
|
624
|
+
if (left === undefined || right === undefined) {
|
|
625
|
+
return valueError();
|
|
626
|
+
}
|
|
627
|
+
return numberResult(left === right ? 1 : 0);
|
|
628
|
+
},
|
|
629
|
+
GESTEP: (numberArg, stepArg = { tag: ValueTag.Number, value: 0 }) => {
|
|
630
|
+
const numberValue = toNumber(numberArg);
|
|
631
|
+
const stepValue = toNumber(stepArg);
|
|
632
|
+
if (numberValue === undefined || stepValue === undefined) {
|
|
633
|
+
return valueError();
|
|
634
|
+
}
|
|
635
|
+
return numberResult(numberValue >= stepValue ? 1 : 0);
|
|
636
|
+
},
|
|
637
|
+
...statisticalBuiltins,
|
|
638
|
+
...financialBuiltins,
|
|
639
|
+
PERMUT: (numberArg, chosenArg) => {
|
|
640
|
+
const numberValue = nonNegativeIntegerValue(numberArg);
|
|
641
|
+
const chosenValue = nonNegativeIntegerValue(chosenArg);
|
|
642
|
+
if (numberValue === undefined || chosenValue === undefined || chosenValue > numberValue) {
|
|
643
|
+
return valueError();
|
|
644
|
+
}
|
|
645
|
+
let result = 1;
|
|
646
|
+
for (let index = 0; index < chosenValue; index += 1) {
|
|
647
|
+
result *= numberValue - index;
|
|
648
|
+
}
|
|
649
|
+
return numberResult(result);
|
|
650
|
+
},
|
|
651
|
+
PERMUTATIONA: (numberArg, chosenArg) => {
|
|
652
|
+
const numberValue = nonNegativeIntegerValue(numberArg);
|
|
653
|
+
const chosenValue = nonNegativeIntegerValue(chosenArg);
|
|
654
|
+
if (numberValue === undefined || chosenValue === undefined) {
|
|
655
|
+
return valueError();
|
|
656
|
+
}
|
|
657
|
+
return numberResult(numberValue ** chosenValue);
|
|
658
|
+
},
|
|
659
|
+
...distributionBuiltins,
|
|
660
|
+
SUBTOTAL: (functionNumArg, ...args) => {
|
|
661
|
+
const functionNum = integerValue(functionNumArg);
|
|
662
|
+
return functionNum === undefined ? valueError() : aggregateByCode(functionNum, args);
|
|
663
|
+
},
|
|
664
|
+
AGGREGATE: (functionNumArg, _optionsArg, ...args) => {
|
|
665
|
+
const functionNum = integerValue(functionNumArg);
|
|
666
|
+
return functionNum === undefined ? valueError() : aggregateByCode(functionNum, args);
|
|
667
|
+
},
|
|
668
|
+
SEQUENCE: (...args) => sequenceResult(args[0], args[1], args[2], args[3]),
|
|
669
|
+
...externalScalarBuiltins,
|
|
670
|
+
...scalarPlaceholderBuiltins,
|
|
671
|
+
};
|
|
672
|
+
const builtins = {
|
|
673
|
+
...scalarBuiltins,
|
|
674
|
+
...logicalBuiltins,
|
|
675
|
+
...textBuiltins,
|
|
676
|
+
...datetimeBuiltins,
|
|
677
|
+
};
|
|
678
|
+
const builtinIdByName = new Map(BUILTINS.map((builtin) => [builtin.name.toUpperCase(), builtin.id]));
|
|
679
|
+
builtinIdByName.set("USE.THE.COUNTIF", BuiltinId.Countif);
|
|
680
|
+
builtinIdByName.set("FORECAST.LINEAR", BuiltinId.Forecast);
|
|
681
|
+
export function getBuiltin(name) {
|
|
682
|
+
return builtins[name.toUpperCase()] ?? getExternalScalarFunction(name);
|
|
683
|
+
}
|
|
684
|
+
export function hasBuiltin(name) {
|
|
685
|
+
const upper = name.toUpperCase();
|
|
686
|
+
return (builtins[upper] !== undefined ||
|
|
687
|
+
lookupBuiltins[upper] !== undefined ||
|
|
688
|
+
builtinIdByName.has(upper) ||
|
|
689
|
+
builtinJsSpecialNames.has(upper) ||
|
|
690
|
+
hasExternalFunction(upper));
|
|
691
|
+
}
|
|
692
|
+
export function getBuiltinId(name) {
|
|
693
|
+
return builtinIdByName.get(name.toUpperCase());
|
|
694
|
+
}
|
|
695
|
+
//# sourceMappingURL=builtins.js.map
|