@trebco/treb 28.17.5 → 29.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/dist/treb-spreadsheet-light.mjs +12 -12
  2. package/dist/treb-spreadsheet.mjs +12 -12
  3. package/dist/treb.d.ts +121 -82
  4. package/eslint.config.js +21 -0
  5. package/package.json +6 -6
  6. package/treb-base-types/src/area.ts +4 -2
  7. package/treb-base-types/src/cell.ts +1 -1
  8. package/treb-base-types/src/cells.ts +16 -7
  9. package/treb-base-types/src/dom-utilities.ts +4 -2
  10. package/treb-base-types/src/import.ts +2 -2
  11. package/treb-base-types/src/rectangle.ts +5 -5
  12. package/treb-base-types/src/text_part.ts +7 -0
  13. package/treb-base-types/src/union.ts +6 -1
  14. package/treb-base-types/src/value-type.ts +1 -1
  15. package/treb-calculator/src/calculator.ts +114 -165
  16. package/treb-calculator/src/dag/calculation_leaf_vertex.ts +1 -2
  17. package/treb-calculator/src/dag/graph.ts +3 -3
  18. package/treb-calculator/src/dag/spreadsheet_vertex.ts +2 -2
  19. package/treb-calculator/src/dag/state_leaf_vertex.ts +2 -4
  20. package/treb-calculator/src/descriptors.ts +28 -2
  21. package/treb-calculator/src/expression-calculator.ts +25 -34
  22. package/treb-calculator/src/function-error.ts +2 -2
  23. package/treb-calculator/src/function-library.ts +16 -0
  24. package/treb-calculator/src/functions/base-functions.ts +185 -211
  25. package/treb-calculator/src/functions/checkbox.ts +0 -1
  26. package/treb-calculator/src/functions/complex-functions.ts +49 -47
  27. package/treb-calculator/src/functions/finance-functions.ts +10 -10
  28. package/treb-calculator/src/functions/function-utilities.ts +26 -0
  29. package/treb-calculator/src/functions/information-functions.ts +21 -41
  30. package/treb-calculator/src/functions/matrix-functions.ts +8 -1
  31. package/treb-calculator/src/functions/sparkline.ts +6 -4
  32. package/treb-calculator/src/functions/statistics-functions.ts +21 -17
  33. package/treb-calculator/src/functions/text-functions.ts +14 -13
  34. package/treb-calculator/src/primitives.ts +48 -37
  35. package/treb-calculator/src/utilities.ts +117 -134
  36. package/treb-charts/src/chart-functions.ts +3 -3
  37. package/treb-charts/src/chart-types.ts +42 -1
  38. package/treb-charts/src/chart-utils.ts +155 -113
  39. package/treb-charts/src/chart.ts +6 -5
  40. package/treb-charts/src/default-chart-renderer.ts +6 -5
  41. package/treb-charts/src/renderer.ts +12 -11
  42. package/treb-charts/src/util.ts +25 -36
  43. package/treb-data-model/package.json +5 -0
  44. package/{treb-grid/src/types → treb-data-model/src}/annotation.ts +2 -2
  45. package/{treb-grid/src/types → treb-data-model/src}/conditional_format.ts +20 -0
  46. package/{treb-grid/src/types → treb-data-model/src}/data_model.ts +231 -133
  47. package/treb-data-model/src/index.ts +45 -0
  48. package/{treb-grid/src/types/named_range.ts → treb-data-model/src/named.ts} +459 -376
  49. package/{treb-grid/src/types → treb-data-model/src}/sheet.ts +13 -5
  50. package/treb-data-model/src/sheet_collection.ts +114 -0
  51. package/{treb-grid/src/types → treb-data-model/src}/sheet_types.ts +6 -3
  52. package/treb-embed/modern.tsconfig.json +1 -0
  53. package/treb-embed/src/custom-element/spreadsheet-constructor.ts +2 -2
  54. package/treb-embed/src/embedded-spreadsheet.ts +125 -270
  55. package/treb-embed/src/selection-state.ts +1 -1
  56. package/treb-embed/src/toolbar-message.ts +1 -1
  57. package/treb-embed/src/types.ts +13 -5
  58. package/treb-export/src/export-worker/export-worker.ts +22 -7
  59. package/treb-export/src/export2.ts +110 -41
  60. package/treb-export/src/import2.ts +6 -5
  61. package/treb-export/src/workbook2.ts +31 -13
  62. package/treb-export/src/xml-utils.ts +5 -1
  63. package/treb-format/src/format.ts +8 -6
  64. package/treb-grid/src/editors/autocomplete.ts +2 -2
  65. package/treb-grid/src/editors/autocomplete_matcher.ts +57 -19
  66. package/treb-grid/src/editors/editor.ts +27 -25
  67. package/treb-grid/src/editors/formula_bar.ts +5 -5
  68. package/treb-grid/src/editors/overlay_editor.ts +1 -2
  69. package/treb-grid/src/index.ts +0 -11
  70. package/treb-grid/src/layout/base_layout.ts +20 -8
  71. package/treb-grid/src/layout/grid_layout.ts +2 -2
  72. package/treb-grid/src/layout/mock-layout.ts +5 -6
  73. package/treb-grid/src/render/selection-renderer.ts +2 -3
  74. package/treb-grid/src/render/tile_renderer.ts +18 -8
  75. package/treb-grid/src/types/grid.ts +96 -67
  76. package/treb-grid/src/types/grid_base.ts +76 -60
  77. package/treb-grid/src/types/grid_command.ts +3 -2
  78. package/treb-grid/src/types/grid_events.ts +12 -6
  79. package/treb-grid/src/types/tab_bar.ts +1 -2
  80. package/treb-parser/src/parser-types.ts +2 -1
  81. package/treb-parser/src/parser.ts +7 -5
  82. package/treb-utils/src/event_source.ts +1 -1
  83. package/treb-utils/src/serialize_html.ts +31 -6
  84. package/.eslintignore +0 -8
  85. package/.eslintrc.cjs +0 -168
  86. package/treb-grid/src/layout/rectangle_cache.ts +0 -86
  87. /package/{treb-grid/src/types → treb-data-model/src}/serialize_options.ts +0 -0
  88. /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 = [number, number, UnionValue?, UnionValue?, UnionValue?];
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 || b.type === ValueType.complex) {
286
-
287
- // complex can equal real or complex
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 if (b.type === ValueType.number) {
303
- equals =
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
- return { type: ValueType.boolean, value: equals };
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.type === ValueType.complex || b.type === ValueType.complex) {
388
- return ValueError();
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.type === ValueType.complex || b.type === ValueType.complex) {
399
- return ValueError();
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
- return ValueError();
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: any): boolean => {
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: any[][]) => {
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: any) => [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: any = [];
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: any = {};
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
- export const FlattenUnboxed = (args: any[]): any[] => {
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(FlattenUnboxed(b));
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
- * returns a function that applies the given function to a scalar or a matrix
178
- * @param base the underlying function
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
- export const ApplyArrayFunc = (base: (...args: any[]) => any) => {
181
- return (a: any) => {
182
- if (Array.isArray(a)) {
183
- const tmp: any[] = [];
184
- const rows = a[0].length;
185
- for (let c = 0; c < a.length; c++) {
186
- const col: any[] = [];
187
- for (let r = 0; r < rows; r++) col[r] = base(a[c][r]);
188
- tmp.push(col);
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
- const swapped = [...rest, element];
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: a.map(row => row.map((element: any) => {
239
- return base(element, ...rest);
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
- if (!!b && typeof b === 'object' && b.type === ValueType.array) {
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
- if (a_array){
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
- return base(a, b, ...rest);
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: any[]): UnionValue => {
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: any) => {
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: any) => {
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?: any;
88
+ value?: unknown;
48
89
  format?: string;
49
90
  }
50
91