@trebco/treb 28.17.5 → 29.1.2
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/dist/treb-spreadsheet-light.mjs +12 -12
- package/dist/treb-spreadsheet.mjs +12 -12
- package/dist/treb.d.ts +121 -82
- package/eslint.config.js +21 -0
- package/package.json +6 -6
- package/treb-base-types/src/area.ts +4 -2
- package/treb-base-types/src/cell.ts +1 -1
- package/treb-base-types/src/cells.ts +16 -7
- package/treb-base-types/src/dom-utilities.ts +4 -2
- package/treb-base-types/src/import.ts +2 -2
- package/treb-base-types/src/rectangle.ts +5 -5
- package/treb-base-types/src/union.ts +6 -1
- package/treb-base-types/src/value-type.ts +1 -1
- package/treb-calculator/src/calculator.ts +114 -165
- package/treb-calculator/src/dag/calculation_leaf_vertex.ts +1 -2
- package/treb-calculator/src/dag/graph.ts +3 -3
- package/treb-calculator/src/dag/spreadsheet_vertex.ts +2 -2
- package/treb-calculator/src/dag/state_leaf_vertex.ts +2 -4
- package/treb-calculator/src/descriptors.ts +28 -2
- package/treb-calculator/src/expression-calculator.ts +25 -34
- package/treb-calculator/src/function-error.ts +2 -2
- package/treb-calculator/src/function-library.ts +16 -0
- package/treb-calculator/src/functions/base-functions.ts +185 -211
- package/treb-calculator/src/functions/checkbox.ts +0 -1
- package/treb-calculator/src/functions/complex-functions.ts +49 -47
- package/treb-calculator/src/functions/finance-functions.ts +10 -10
- package/treb-calculator/src/functions/function-utilities.ts +26 -0
- package/treb-calculator/src/functions/information-functions.ts +21 -41
- package/treb-calculator/src/functions/matrix-functions.ts +8 -1
- package/treb-calculator/src/functions/sparkline.ts +6 -4
- package/treb-calculator/src/functions/statistics-functions.ts +21 -17
- package/treb-calculator/src/functions/text-functions.ts +14 -13
- package/treb-calculator/src/primitives.ts +48 -37
- package/treb-calculator/src/utilities.ts +117 -134
- package/treb-charts/src/chart-functions.ts +3 -3
- package/treb-charts/src/chart-types.ts +42 -1
- package/treb-charts/src/chart-utils.ts +155 -113
- package/treb-charts/src/chart.ts +6 -5
- package/treb-charts/src/default-chart-renderer.ts +6 -5
- package/treb-charts/src/renderer.ts +12 -11
- package/treb-charts/src/util.ts +25 -36
- package/treb-data-model/package.json +5 -0
- package/{treb-grid/src/types → treb-data-model/src}/annotation.ts +2 -2
- package/{treb-grid/src/types → treb-data-model/src}/conditional_format.ts +20 -0
- package/{treb-grid/src/types → treb-data-model/src}/data_model.ts +231 -133
- package/treb-data-model/src/index.ts +45 -0
- package/{treb-grid/src/types/named_range.ts → treb-data-model/src/named.ts} +459 -376
- package/{treb-grid/src/types → treb-data-model/src}/sheet.ts +13 -5
- package/treb-data-model/src/sheet_collection.ts +114 -0
- package/{treb-grid/src/types → treb-data-model/src}/sheet_types.ts +6 -3
- package/treb-embed/modern.tsconfig.json +1 -0
- package/treb-embed/src/custom-element/spreadsheet-constructor.ts +2 -2
- package/treb-embed/src/embedded-spreadsheet.ts +125 -270
- package/treb-embed/src/selection-state.ts +1 -1
- package/treb-embed/src/toolbar-message.ts +1 -1
- package/treb-embed/src/types.ts +13 -5
- package/treb-export/src/export-worker/export-worker.ts +22 -7
- package/treb-export/src/export2.ts +110 -41
- package/treb-export/src/import2.ts +6 -5
- package/treb-export/src/workbook2.ts +31 -13
- package/treb-export/src/xml-utils.ts +5 -1
- package/treb-format/src/format.ts +8 -6
- package/treb-grid/src/editors/autocomplete.ts +2 -2
- package/treb-grid/src/editors/autocomplete_matcher.ts +57 -19
- package/treb-grid/src/editors/editor.ts +27 -25
- package/treb-grid/src/editors/formula_bar.ts +5 -5
- package/treb-grid/src/editors/overlay_editor.ts +1 -2
- package/treb-grid/src/index.ts +0 -11
- package/treb-grid/src/layout/base_layout.ts +20 -8
- package/treb-grid/src/layout/grid_layout.ts +2 -2
- package/treb-grid/src/layout/mock-layout.ts +5 -6
- package/treb-grid/src/render/selection-renderer.ts +2 -3
- package/treb-grid/src/render/tile_renderer.ts +1 -1
- package/treb-grid/src/types/grid.ts +95 -66
- package/treb-grid/src/types/grid_base.ts +76 -60
- package/treb-grid/src/types/grid_command.ts +3 -2
- package/treb-grid/src/types/grid_events.ts +12 -6
- package/treb-grid/src/types/tab_bar.ts +1 -2
- package/treb-parser/src/parser-types.ts +2 -1
- package/treb-parser/src/parser.ts +7 -5
- package/treb-utils/src/event_source.ts +1 -1
- package/treb-utils/src/serialize_html.ts +31 -6
- package/.eslintignore +0 -8
- package/.eslintrc.cjs +0 -168
- package/treb-grid/src/layout/rectangle_cache.ts +0 -86
- /package/{treb-grid/src/types → treb-data-model/src}/serialize_options.ts +0 -0
- /package/{treb-grid/src/types/grid_selection.ts → treb-data-model/src/sheet_selection.ts} +0 -0
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
*
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
import type { Complex, UnionValue} from 'treb-base-types';
|
|
22
|
+
import type { Complex, ComplexUnion, UnionValue} from 'treb-base-types';
|
|
23
23
|
import { ValueType } from 'treb-base-types';
|
|
24
24
|
import { DivideByZeroError, ValueError } from './function-error';
|
|
25
25
|
|
|
@@ -30,7 +30,13 @@ import * as ComplexLib from './complex-math';
|
|
|
30
30
|
|
|
31
31
|
export type PrimitiveBinaryExpression = (a: UnionValue, b: UnionValue) => UnionValue;
|
|
32
32
|
|
|
33
|
-
type NumericTuple = [
|
|
33
|
+
type NumericTuple = [
|
|
34
|
+
number,
|
|
35
|
+
number,
|
|
36
|
+
UnionValue?, // FIXME: should be error type?
|
|
37
|
+
ComplexUnion?, // UnionValue?,
|
|
38
|
+
ComplexUnion?, // UnionValue?
|
|
39
|
+
];
|
|
34
40
|
|
|
35
41
|
/**
|
|
36
42
|
* a is either a complex union value or undefined. if it's defined,
|
|
@@ -282,31 +288,16 @@ export const Equals = (a: UnionValue, b: UnionValue): UnionValue => {
|
|
|
282
288
|
return { type: ValueType.boolean, value: true, };
|
|
283
289
|
}
|
|
284
290
|
|
|
285
|
-
if (a.type === ValueType.complex
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
let equals = false;
|
|
290
|
-
|
|
291
|
-
if (a.type === b.type) {
|
|
292
|
-
equals =
|
|
293
|
-
a.value.real == b.value.real && // == ?
|
|
294
|
-
a.value.imaginary == b.value.imaginary // == ?
|
|
295
|
-
;
|
|
296
|
-
}
|
|
297
|
-
else if (a.type === ValueType.number) {
|
|
298
|
-
equals =
|
|
299
|
-
b.value.real == a.value &&
|
|
300
|
-
!b.value.imaginary;
|
|
291
|
+
if (a.type === ValueType.complex) {
|
|
292
|
+
if (b.type === ValueType.complex) {
|
|
293
|
+
return { type: ValueType.boolean, value: ((a.value.imaginary === b.value.imaginary) && (a.value.real === b.value.real)) };
|
|
301
294
|
}
|
|
302
|
-
else
|
|
303
|
-
|
|
304
|
-
a.value.real == b.value &&
|
|
305
|
-
!a.value.imaginary;
|
|
295
|
+
else {
|
|
296
|
+
return { type: ValueType.boolean, value: ((!a.value.imaginary) && (a.value.real === b.value)) };
|
|
306
297
|
}
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
298
|
+
}
|
|
299
|
+
else if (b.type === ValueType.complex) {
|
|
300
|
+
return { type: ValueType.boolean, value: ((!b.value.imaginary) && (a.value === b.value.real)) };
|
|
310
301
|
}
|
|
311
302
|
|
|
312
303
|
// this is standard (icase) string equality. we might also need
|
|
@@ -380,37 +371,57 @@ export const GreaterThan = (a: UnionValue, b: UnionValue): UnionValue => {
|
|
|
380
371
|
return { type: ValueType.boolean, value: (a.value||0) > (b.value||0) };
|
|
381
372
|
};
|
|
382
373
|
|
|
374
|
+
const Comparable = (a: UnionValue, b: UnionValue) => {
|
|
375
|
+
|
|
376
|
+
if (a.type === ValueType.complex ||
|
|
377
|
+
a.type === ValueType.array ||
|
|
378
|
+
a.type === ValueType.dimensioned_quantity ||
|
|
379
|
+
a.type === ValueType.object ||
|
|
380
|
+
b.type === ValueType.complex ||
|
|
381
|
+
b.type === ValueType.array ||
|
|
382
|
+
b.type === ValueType.dimensioned_quantity ||
|
|
383
|
+
b.type === ValueType.object
|
|
384
|
+
) {
|
|
385
|
+
return false;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
return true;
|
|
389
|
+
}
|
|
390
|
+
|
|
383
391
|
export const GreaterThanEqual = (a: UnionValue, b: UnionValue): UnionValue => {
|
|
384
392
|
if (a.type === ValueType.error) { return a; }
|
|
385
393
|
if (b.type === ValueType.error) { return b; }
|
|
386
394
|
|
|
387
|
-
if (a
|
|
388
|
-
|
|
389
|
-
}
|
|
395
|
+
if (!Comparable(a, b)) { return ValueError(); }
|
|
396
|
+
|
|
397
|
+
return { type: ValueType.boolean, value: (a.value||0) >= (b.value||0) };
|
|
390
398
|
|
|
391
|
-
return { type: ValueType.boolean, value: a.value >= b.value };
|
|
392
399
|
};
|
|
393
400
|
|
|
394
401
|
export const LessThan = (a: UnionValue, b: UnionValue): UnionValue => {
|
|
395
402
|
if (a.type === ValueType.error) { return a; }
|
|
396
403
|
if (b.type === ValueType.error) { return b; }
|
|
397
404
|
|
|
398
|
-
if (a
|
|
399
|
-
|
|
400
|
-
|
|
405
|
+
if (!Comparable(a, b)) { return ValueError(); }
|
|
406
|
+
|
|
407
|
+
//if (a.type === ValueType.complex || b.type === ValueType.complex) {
|
|
408
|
+
// return ValueError();
|
|
409
|
+
//}
|
|
401
410
|
|
|
402
|
-
return { type: ValueType.boolean, value: a.value < b.value };
|
|
411
|
+
return { type: ValueType.boolean, value: (a.value||0) < (b.value||0) };
|
|
403
412
|
};
|
|
404
413
|
|
|
405
414
|
export const LessThanEqual = (a: UnionValue, b: UnionValue): UnionValue => {
|
|
406
415
|
if (a.type === ValueType.error) { return a; }
|
|
407
416
|
if (b.type === ValueType.error) { return b; }
|
|
408
417
|
|
|
409
|
-
if (a.type === ValueType.complex || b.type === ValueType.complex) {
|
|
410
|
-
|
|
411
|
-
}
|
|
418
|
+
//if (a.type === ValueType.complex || b.type === ValueType.complex) {
|
|
419
|
+
// return ValueError();
|
|
420
|
+
//}
|
|
421
|
+
|
|
422
|
+
if (!Comparable(a, b)) { return ValueError(); }
|
|
412
423
|
|
|
413
|
-
return { type: ValueType.boolean, value: a.value <= b.value };
|
|
424
|
+
return { type: ValueType.boolean, value: (a.value||0) <= (b.value||0) };
|
|
414
425
|
};
|
|
415
426
|
|
|
416
427
|
export const UseComplex = () => {
|
|
@@ -19,12 +19,12 @@
|
|
|
19
19
|
*
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
import type { ArrayUnion, UnionValue} from 'treb-base-types';
|
|
22
|
+
import type { ArrayUnion, CellValue, UnionValue} from 'treb-base-types';
|
|
23
23
|
import { ValueType } from 'treb-base-types';
|
|
24
24
|
|
|
25
25
|
export const DAY_MS = 1000 * 60 * 60 * 24;
|
|
26
26
|
|
|
27
|
-
export const IsArrayOrTypedArray = (test:
|
|
27
|
+
export const IsArrayOrTypedArray = (test: unknown): boolean => {
|
|
28
28
|
return Array.isArray(test) || (test instanceof Float64Array) || (test instanceof Float64Array);
|
|
29
29
|
};
|
|
30
30
|
|
|
@@ -45,19 +45,21 @@ export const Transpose2 = <T> (arr: T[][]): T[][] => {
|
|
|
45
45
|
|
|
46
46
|
};
|
|
47
47
|
|
|
48
|
-
export const TransposeArray = (arr:
|
|
48
|
+
export const TransposeArray = <T>(arr: T[][]): T[][] => {
|
|
49
49
|
|
|
50
50
|
if (!arr) return [];
|
|
51
51
|
if (typeof arr[0] === 'undefined') return [];
|
|
52
52
|
|
|
53
|
+
/*
|
|
53
54
|
if (!IsArrayOrTypedArray(arr[0])) {
|
|
54
55
|
if (arr instanceof Float32Array || arr instanceof Float64Array){
|
|
55
|
-
return Array.prototype.slice.call(arr).map((x:
|
|
56
|
+
return Array.prototype.slice.call(arr).map((x: T) => [x]);
|
|
56
57
|
}
|
|
57
58
|
return arr.map((x) => [x]);
|
|
58
59
|
}
|
|
60
|
+
*/
|
|
59
61
|
|
|
60
|
-
const tmp:
|
|
62
|
+
const tmp: T[][] = [];
|
|
61
63
|
const cols = arr.length;
|
|
62
64
|
const rows = arr[0].length;
|
|
63
65
|
for (let r = 0; r < rows; r++) {
|
|
@@ -66,6 +68,7 @@ export const TransposeArray = (arr: any[][]) => {
|
|
|
66
68
|
tmp[r][c] = arr[c][r];
|
|
67
69
|
}
|
|
68
70
|
}
|
|
71
|
+
|
|
69
72
|
return tmp;
|
|
70
73
|
|
|
71
74
|
};
|
|
@@ -101,7 +104,7 @@ export const ColumnToString = (column: number) => {
|
|
|
101
104
|
|
|
102
105
|
export const OffsetFormula = (formula: string, offset: {columns: number, rows: number}) => {
|
|
103
106
|
|
|
104
|
-
const cache:
|
|
107
|
+
const cache: Record<string, string> = {};
|
|
105
108
|
formula = formula.replace(/\b([A-Za-z]+)(\d+)\b/g, (m, p1, p2) => {
|
|
106
109
|
if (!cache[m]) {
|
|
107
110
|
const c = ColumnToString(StringToColumn(p1) + offset.columns);
|
|
@@ -145,21 +148,67 @@ export const FlattenBoxed = (args: UnionValue[]): UnionValue[] => {
|
|
|
145
148
|
|
|
146
149
|
};
|
|
147
150
|
|
|
148
|
-
|
|
151
|
+
/* *
|
|
149
152
|
* flatten a set of arguments
|
|
150
153
|
* UPDATE: we no longer accept the "arguments" object. must be an array.
|
|
151
154
|
* callers can use rest spread to collect arguments.
|
|
152
|
-
|
|
153
|
-
|
|
155
|
+
*
|
|
156
|
+
* @deprecated - use a better-typed version
|
|
157
|
+
* /
|
|
158
|
+
export const FlattenCellValues = (args: any[]): any[] => {
|
|
154
159
|
if (!Array.isArray(args)) { return [args]; } // special case
|
|
155
160
|
return args.reduce((a: any[], b: any) => {
|
|
156
161
|
if (typeof b === 'undefined') return a;
|
|
157
|
-
if (Array.isArray(b)) return a.concat(
|
|
162
|
+
if (Array.isArray(b)) return a.concat(FlattenCellValues(b));
|
|
158
163
|
if (b instanceof Float32Array) return a.concat(Array.from(b));
|
|
159
164
|
if (b instanceof Float64Array) return a.concat(Array.from(b));
|
|
160
165
|
return a.concat([b]);
|
|
161
166
|
}, []);
|
|
162
167
|
};
|
|
168
|
+
*/
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* specialization using the CellValue type. this should be preferable
|
|
172
|
+
* to using any, although we're still kind of hacking at it. also we
|
|
173
|
+
* need to allow typed arrays (I think we've mostly gotten those out?)
|
|
174
|
+
*/
|
|
175
|
+
export const FlattenCellValues = (args: (CellValue|CellValue[]|CellValue[][]|Float32Array|Float64Array)[]): CellValue[] => {
|
|
176
|
+
|
|
177
|
+
if (!Array.isArray(args)) { return [args]; } // special case
|
|
178
|
+
return args.reduce((a: CellValue[], b) => {
|
|
179
|
+
if (typeof b === 'undefined') return a;
|
|
180
|
+
if (Array.isArray(b)) return a.concat(FlattenCellValues(b));
|
|
181
|
+
if (b instanceof Float32Array) return a.concat(Array.from(b));
|
|
182
|
+
if (b instanceof Float64Array) return a.concat(Array.from(b));
|
|
183
|
+
return a.concat([b]);
|
|
184
|
+
}, []);
|
|
185
|
+
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* flatten cell values, and filter out any non-numbers. this version does
|
|
190
|
+
* not account for booleans (you might want TRUE = 1). we do this a lot so
|
|
191
|
+
* combining the two operations seems like a useful place to reuse code.
|
|
192
|
+
*/
|
|
193
|
+
export const FlattenNumbers = (args: Parameters<typeof FlattenCellValues>[0]) =>
|
|
194
|
+
(FlattenCellValues(args)).filter((value): value is number => typeof value === 'number');
|
|
195
|
+
|
|
196
|
+
export const FilterIntrinsics = (data: unknown[]): (string|number|boolean|undefined)[] => {
|
|
197
|
+
return data.filter((value): value is number|boolean|undefined|string => {
|
|
198
|
+
switch (typeof value) {
|
|
199
|
+
case 'number':
|
|
200
|
+
case 'undefined':
|
|
201
|
+
case 'string':
|
|
202
|
+
case 'boolean':
|
|
203
|
+
return true;
|
|
204
|
+
}
|
|
205
|
+
return false;
|
|
206
|
+
});
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
/*
|
|
210
|
+
|
|
211
|
+
// anyone using this? (...) removing
|
|
163
212
|
|
|
164
213
|
export const UndefinedToEmptyString = (args: any[]): any[] => {
|
|
165
214
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -172,150 +221,84 @@ export const UndefinedToEmptyString = (args: any[]): any[] => {
|
|
|
172
221
|
}
|
|
173
222
|
return args;
|
|
174
223
|
};
|
|
224
|
+
*/
|
|
225
|
+
|
|
226
|
+
/** type guard. FIXME: move */
|
|
227
|
+
const IsArrayUnion = (value: unknown): value is ArrayUnion => {
|
|
228
|
+
return (!!value && typeof value === 'object' && (value as { type: ValueType, value?: Array<unknown> }).type === ValueType.array);
|
|
229
|
+
};
|
|
175
230
|
|
|
176
231
|
/**
|
|
177
|
-
*
|
|
178
|
-
*
|
|
232
|
+
* this is an attempt at a generalized array application wrapper
|
|
233
|
+
* for functions. the rules are the same -- we apply functions pairwise
|
|
234
|
+
* (or tuple-wise), not combinatorially.
|
|
235
|
+
*
|
|
236
|
+
* we could simplify a bit if we require that functions used boxed
|
|
237
|
+
* values. we should do that anyway, and be consistent across functions.
|
|
238
|
+
* also we could get the `any`s out.
|
|
239
|
+
*
|
|
240
|
+
* (swapping param order, so we don't have hanging param after inline
|
|
241
|
+
* function definition -- shades of window.setTimeout)
|
|
242
|
+
*
|
|
243
|
+
* @param map - a list of parameters, by index, that can be unrolled. this
|
|
244
|
+
* allows us to support both out-of-order application and functions that take
|
|
245
|
+
* mixes of scalars and arrays.
|
|
246
|
+
*
|
|
247
|
+
* @param base - the underlying function. for any parameters that can
|
|
248
|
+
* be applied/unrolled, it should take a scalar.
|
|
249
|
+
*
|
|
179
250
|
*/
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
251
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
252
|
+
export const ApplyArrayX = <TFunc extends (...args: any[]) => UnionValue>(map: boolean[], base: TFunc): (...args: Parameters<TFunc>) => UnionValue => {
|
|
253
|
+
|
|
254
|
+
return (...args: Parameters<TFunc>) => {
|
|
255
|
+
|
|
256
|
+
// we need to look at the actual parameters passed, not the signature.
|
|
257
|
+
// spreadsheet language supports "extra" parameters. we usually just
|
|
258
|
+
// repeat the tail parameter, but in this case we will NOT repeat the
|
|
259
|
+
// application (why not?)
|
|
260
|
+
|
|
261
|
+
const arrays: unknown[][][] = [];
|
|
262
|
+
|
|
263
|
+
// the result needs to be the same shape as the input. so we use the
|
|
264
|
+
// first array we find to create this map.
|
|
265
|
+
|
|
266
|
+
let shape: unknown[][] = [];
|
|
267
|
+
|
|
268
|
+
for (const [i, arg] of args.entries()) {
|
|
269
|
+
if (arg && map[i]) {
|
|
270
|
+
const arr = Array.isArray(arg) ? arg : IsArrayUnion(arg) ? arg.value : undefined;
|
|
271
|
+
if (arr) {
|
|
272
|
+
arrays[i] = arr;
|
|
273
|
+
if (!shape.length) {
|
|
274
|
+
shape = arr;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
189
277
|
}
|
|
190
|
-
return tmp;
|
|
191
|
-
}
|
|
192
|
-
return base(a);
|
|
193
|
-
};
|
|
194
|
-
};
|
|
195
|
-
|
|
196
|
-
export const ApplyAsArraySwap = (base: (...args: any[]) => UnionValue) => {
|
|
197
|
-
return (...args: any[]): UnionValue => {
|
|
198
|
-
|
|
199
|
-
// swap here
|
|
200
|
-
args.reverse();
|
|
201
|
-
const [a, ...rest] = args;
|
|
202
|
-
|
|
203
|
-
if (Array.isArray(a)) {
|
|
204
|
-
return {
|
|
205
|
-
type: ValueType.array,
|
|
206
|
-
value: a.map(row => row.map((element: any) => {
|
|
207
|
-
|
|
208
|
-
// swap back
|
|
209
|
-
const swapped = [...rest, element];
|
|
210
|
-
return base(...swapped);
|
|
211
|
-
|
|
212
|
-
})),
|
|
213
|
-
};
|
|
214
278
|
}
|
|
215
|
-
else if (typeof a === 'object' && !!a && a.type === ValueType.array ) {
|
|
216
|
-
return {
|
|
217
|
-
type: ValueType.array,
|
|
218
|
-
value: (a as ArrayUnion).value.map(row => row.map((element: any) => {
|
|
219
279
|
|
|
220
|
-
|
|
221
|
-
return base(...swapped);
|
|
280
|
+
if (arrays.length) {
|
|
222
281
|
|
|
223
|
-
|
|
224
|
-
};
|
|
225
|
-
|
|
226
|
-
}
|
|
227
|
-
else {
|
|
228
|
-
return base(...rest, a);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
};
|
|
282
|
+
// this is pretty, but 3 functional loops? ouch
|
|
232
283
|
|
|
233
|
-
export const ApplyAsArray = (base: (a: any, ...rest: any[]) => UnionValue) => {
|
|
234
|
-
return (a: any, ...rest: any[]): UnionValue => {
|
|
235
|
-
if (Array.isArray(a)) {
|
|
236
284
|
return {
|
|
237
285
|
type: ValueType.array,
|
|
238
|
-
value:
|
|
239
|
-
|
|
286
|
+
value: shape.map((_, i) => _.map((_, j) => {
|
|
287
|
+
const apply = args.map((arg, index) => arrays[index] ? (arrays[index][i][j] || { type: ValueType.undefined }) : arg);
|
|
288
|
+
return base(...apply as Parameters<TFunc>);
|
|
240
289
|
})),
|
|
241
290
|
};
|
|
242
|
-
}
|
|
243
|
-
else if (typeof a === 'object' && !!a && a.type === ValueType.array ) {
|
|
244
|
-
return {
|
|
245
|
-
type: ValueType.array,
|
|
246
|
-
value: (a as ArrayUnion).value.map(row => row.map((element: any) => {
|
|
247
|
-
return base(element, ...rest);
|
|
248
|
-
})),
|
|
249
|
-
};
|
|
250
|
-
|
|
251
|
-
}
|
|
252
|
-
else {
|
|
253
|
-
return base(a, ...rest);
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
};
|
|
257
|
-
|
|
258
|
-
export const ApplyAsArray2 = (base: (a: any, b: any, ...rest: any[]) => UnionValue) => {
|
|
259
|
-
return (a: any, b: any, ...rest: any[]): UnionValue => {
|
|
260
291
|
|
|
261
|
-
// do we need to worry about unboxed values? probably
|
|
262
|
-
// what about combinations of boxed/unboxed (implying there are 4)
|
|
263
|
-
|
|
264
|
-
// we could simplify this by pulling out the lists...
|
|
265
|
-
|
|
266
|
-
let a_array = false;
|
|
267
|
-
let b_array = false;
|
|
268
|
-
|
|
269
|
-
if (!!a && typeof a === 'object' && a.type === ValueType.array) {
|
|
270
|
-
a = (a as ArrayUnion).value;
|
|
271
|
-
a_array = true; // don't test again
|
|
272
|
-
}
|
|
273
|
-
else {
|
|
274
|
-
a_array = Array.isArray(a);
|
|
275
292
|
}
|
|
276
293
|
|
|
277
|
-
|
|
278
|
-
b = (b as ArrayUnion).value;
|
|
279
|
-
b_array = true; // don't test again
|
|
280
|
-
}
|
|
281
|
-
else {
|
|
282
|
-
b_array = Array.isArray(b);
|
|
283
|
-
}
|
|
294
|
+
// scalar case
|
|
284
295
|
|
|
285
|
-
|
|
286
|
-
if (b_array) {
|
|
287
|
-
// a and b are arrays
|
|
288
|
-
return {
|
|
289
|
-
type: ValueType.array,
|
|
290
|
-
value: a.map((row: any[], i: number) => row.map((element: any, j: number) => {
|
|
291
|
-
return base(element, b[i][j], ...rest);
|
|
292
|
-
})),
|
|
293
|
-
};
|
|
294
|
-
}
|
|
295
|
-
// a is array, b is scalar
|
|
296
|
-
return {
|
|
297
|
-
type: ValueType.array,
|
|
298
|
-
value: a.map((row: any[]) => row.map((element: any) => {
|
|
299
|
-
return base(element, b, ...rest);
|
|
300
|
-
})),
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
|
-
else if (b_array) {
|
|
304
|
-
// a is scalar, b is array
|
|
305
|
-
return {
|
|
306
|
-
type: ValueType.array,
|
|
307
|
-
value: b.map((row: any[]) => row.map((element: any) => {
|
|
308
|
-
return base(a, element, ...rest);
|
|
309
|
-
})),
|
|
310
|
-
};
|
|
311
|
-
}
|
|
296
|
+
return base(...args);
|
|
312
297
|
|
|
313
|
-
|
|
298
|
+
};
|
|
314
299
|
|
|
315
|
-
}
|
|
316
300
|
};
|
|
317
301
|
|
|
318
|
-
|
|
319
302
|
/**
|
|
320
303
|
* parse a string with wildcards into a regex pattern
|
|
321
304
|
*
|
|
@@ -27,7 +27,7 @@ import type { FunctionMap } from 'treb-calculator/src/descriptors';
|
|
|
27
27
|
*
|
|
28
28
|
* UPDATE: box this properly as "extended" type
|
|
29
29
|
*/
|
|
30
|
-
const Identity = (...args:
|
|
30
|
+
const Identity = (...args: unknown[]): UnionValue => {
|
|
31
31
|
return {
|
|
32
32
|
type: ValueType.object,
|
|
33
33
|
value: args,
|
|
@@ -45,7 +45,7 @@ export const ChartFunctions: FunctionMap = {
|
|
|
45
45
|
arguments: [
|
|
46
46
|
{ name: 'Array...', metadata: true, },
|
|
47
47
|
],
|
|
48
|
-
fn: (...args:
|
|
48
|
+
fn: (...args: unknown[]) => {
|
|
49
49
|
return {
|
|
50
50
|
type: ValueType.object,
|
|
51
51
|
value: args,
|
|
@@ -75,7 +75,7 @@ export const ChartFunctions: FunctionMap = {
|
|
|
75
75
|
{ name: 'subtype', },
|
|
76
76
|
{ name: 'Labels', description: 'Labels for bubble charts only (atm)' },
|
|
77
77
|
],
|
|
78
|
-
fn: (...args:
|
|
78
|
+
fn: (...args: unknown[]) => {
|
|
79
79
|
return {
|
|
80
80
|
type: ValueType.object,
|
|
81
81
|
value: args,
|
|
@@ -21,6 +21,47 @@
|
|
|
21
21
|
|
|
22
22
|
import type { RangeScale } from 'treb-utils';
|
|
23
23
|
import type { Area } from './rectangle';
|
|
24
|
+
import type { UnitAddress } from 'treb-parser';
|
|
25
|
+
import { ValueType, type ArrayUnion, type CellValue, type ExtendedUnion, type UnionValue } from 'treb-base-types';
|
|
26
|
+
|
|
27
|
+
export interface ReferenceMetadata {
|
|
28
|
+
type: 'metadata';
|
|
29
|
+
address: UnitAddress;
|
|
30
|
+
value: CellValue;
|
|
31
|
+
format?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface ReferenceSeries extends ExtendedUnion {
|
|
35
|
+
key: 'series',
|
|
36
|
+
value: [
|
|
37
|
+
CellValue?, // { name: 'Label' }, // , metadata: true, },
|
|
38
|
+
UnionValue?, // { name: 'X', metadata: true, },
|
|
39
|
+
UnionValue?, // { name: 'Y', metadata: true, },
|
|
40
|
+
UnionValue?, // { name: 'Z', metadata: true, },
|
|
41
|
+
CellValue?, // { name: 'index', },
|
|
42
|
+
CellValue?, // { name: 'subtype', },
|
|
43
|
+
CellValue?, // { name: 'Labels', description: 'Labels for bubble charts only (atm)' },
|
|
44
|
+
];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export const IsMetadata = (value?: unknown): value is ExtendedUnion & { value: ReferenceMetadata } => {
|
|
48
|
+
return (!!value && (typeof value === 'object')
|
|
49
|
+
&& (value as ExtendedUnion).key === 'metadata'
|
|
50
|
+
&& !!(value as ExtendedUnion).value
|
|
51
|
+
&& (value as { value: ReferenceMetadata}).value.type === 'metadata');
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const IsSeries = (value?: unknown): value is ReferenceSeries => {
|
|
55
|
+
return (!!value && (typeof value === 'object')
|
|
56
|
+
&& (value as ReferenceSeries).key === 'series'
|
|
57
|
+
&& Array.isArray((value as ReferenceSeries).value));
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export const IsArrayUnion = (value?: unknown): value is ArrayUnion => {
|
|
61
|
+
return (!!value && (typeof value === 'object')
|
|
62
|
+
&& (value as UnionValue).type === ValueType.array
|
|
63
|
+
&& Array.isArray((value as ArrayUnion).value));
|
|
64
|
+
};
|
|
24
65
|
|
|
25
66
|
export type NumberOrUndefinedArray = Array<number|undefined>;
|
|
26
67
|
|
|
@@ -44,7 +85,7 @@ export interface CalloutType {
|
|
|
44
85
|
|
|
45
86
|
export interface CellData {
|
|
46
87
|
address: { row: number; column: number };
|
|
47
|
-
value?:
|
|
88
|
+
value?: unknown;
|
|
48
89
|
format?: string;
|
|
49
90
|
}
|
|
50
91
|
|