@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.
- 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/text_part.ts +7 -0
- 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 +18 -8
- package/treb-grid/src/types/grid.ts +96 -67
- 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
|
@@ -20,7 +20,6 @@
|
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
import type { RenderFunctionOptions, ClickFunctionOptions, ClickFunctionResult, RenderFunctionResult } from 'treb-base-types';
|
|
23
|
-
import { Style } from 'treb-base-types';
|
|
24
23
|
|
|
25
24
|
export const ClickCheckbox = (options: ClickFunctionOptions): ClickFunctionResult => {
|
|
26
25
|
const { x, y, width, height, cell } = options;
|
|
@@ -20,12 +20,14 @@
|
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
import type { FunctionMap } from '../descriptors';
|
|
23
|
-
import type { NumberUnion, UnionValue} from 'treb-base-types';
|
|
23
|
+
import type { CellValue, NumberUnion, UnionValue} from 'treb-base-types';
|
|
24
24
|
import { IsComplex, ValueType } from 'treb-base-types';
|
|
25
|
-
import * as Utils from '../utilities';
|
|
25
|
+
// import * as Utils from '../utilities';
|
|
26
26
|
import { ValueError } from '../function-error';
|
|
27
27
|
import { RectangularToPolar } from '../complex-math';
|
|
28
28
|
|
|
29
|
+
import { CoerceComplex } from './function-utilities';
|
|
30
|
+
|
|
29
31
|
export const ComplexFunctionLibrary: FunctionMap = {
|
|
30
32
|
|
|
31
33
|
IsComplex: {
|
|
@@ -33,22 +35,23 @@ export const ComplexFunctionLibrary: FunctionMap = {
|
|
|
33
35
|
arguments: [{
|
|
34
36
|
name: 'Reference',
|
|
35
37
|
metadata: true, /* OK with array metadata */
|
|
38
|
+
unroll: true,
|
|
36
39
|
}],
|
|
37
|
-
fn:
|
|
40
|
+
fn: (ref: UnionValue): UnionValue => {
|
|
38
41
|
return {
|
|
39
42
|
type: ValueType.boolean,
|
|
40
|
-
value: ref?.value && IsComplex(ref.value.value),
|
|
43
|
+
value: !!(ref?.value) && IsComplex((ref.value as {value?: CellValue}).value),
|
|
41
44
|
};
|
|
42
|
-
}
|
|
45
|
+
},
|
|
43
46
|
},
|
|
44
47
|
|
|
45
48
|
|
|
46
49
|
Real: {
|
|
47
50
|
description: 'Returns the real part of a complex number',
|
|
48
51
|
arguments: [
|
|
49
|
-
{ boxed: true },
|
|
52
|
+
{ boxed: true, unroll: true },
|
|
50
53
|
],
|
|
51
|
-
fn:
|
|
54
|
+
fn: (ref: UnionValue): UnionValue => {
|
|
52
55
|
if (ref.type === ValueType.number) {
|
|
53
56
|
return { ...ref };
|
|
54
57
|
}
|
|
@@ -65,15 +68,15 @@ export const ComplexFunctionLibrary: FunctionMap = {
|
|
|
65
68
|
};
|
|
66
69
|
}
|
|
67
70
|
return ValueError();
|
|
68
|
-
}
|
|
71
|
+
},
|
|
69
72
|
},
|
|
70
73
|
|
|
71
74
|
Imaginary: {
|
|
72
75
|
description: 'Returns the imaginary part of a complex number (as real)',
|
|
73
76
|
arguments: [
|
|
74
|
-
{ boxed: true },
|
|
77
|
+
{ boxed: true, unroll: true, },
|
|
75
78
|
],
|
|
76
|
-
fn:
|
|
79
|
+
fn: (ref: UnionValue): UnionValue => {
|
|
77
80
|
if (ref.type === ValueType.complex) {
|
|
78
81
|
return {
|
|
79
82
|
type: ValueType.number,
|
|
@@ -89,41 +92,46 @@ export const ComplexFunctionLibrary: FunctionMap = {
|
|
|
89
92
|
};
|
|
90
93
|
}
|
|
91
94
|
return ValueError();
|
|
92
|
-
}
|
|
95
|
+
},
|
|
93
96
|
},
|
|
94
97
|
|
|
95
98
|
Conjugate: {
|
|
96
99
|
description: 'Returns the conjugate of a complex number',
|
|
97
100
|
arguments: [
|
|
98
|
-
{ boxed: true },
|
|
101
|
+
{ boxed: true, unroll: true },
|
|
99
102
|
],
|
|
100
|
-
fn:
|
|
101
|
-
|
|
103
|
+
fn: (arg: UnionValue): UnionValue => {
|
|
104
|
+
|
|
105
|
+
const complex = CoerceComplex(arg);
|
|
106
|
+
|
|
107
|
+
if (!complex) {
|
|
108
|
+
return ValueError();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (complex.imaginary) {
|
|
102
112
|
return {
|
|
103
113
|
type: ValueType.complex,
|
|
104
114
|
value: {
|
|
105
|
-
real:
|
|
106
|
-
imaginary: -
|
|
115
|
+
real: complex.real,
|
|
116
|
+
imaginary: -complex.imaginary,
|
|
107
117
|
},
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
else if (arg.type === ValueType.number || arg.type === ValueType.undefined || !arg.value) {
|
|
111
|
-
return {
|
|
112
|
-
type: ValueType.number, value: arg.value || 0,
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
else {
|
|
116
|
-
return ValueError();
|
|
118
|
+
}
|
|
117
119
|
}
|
|
118
|
-
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
type: ValueType.number,
|
|
123
|
+
value: complex.real,
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
},
|
|
119
127
|
},
|
|
120
128
|
|
|
121
129
|
Arg: {
|
|
122
130
|
description: 'Returns the principal argument of a complex number (in radians)',
|
|
123
131
|
arguments: [
|
|
124
|
-
{ boxed: true },
|
|
132
|
+
{ boxed: true, unroll: true },
|
|
125
133
|
],
|
|
126
|
-
fn:
|
|
134
|
+
fn: (ref: UnionValue): UnionValue => {
|
|
127
135
|
|
|
128
136
|
if (ref.type === ValueType.complex) {
|
|
129
137
|
return {
|
|
@@ -142,7 +150,7 @@ export const ComplexFunctionLibrary: FunctionMap = {
|
|
|
142
150
|
}
|
|
143
151
|
|
|
144
152
|
return ValueError();
|
|
145
|
-
}
|
|
153
|
+
},
|
|
146
154
|
},
|
|
147
155
|
|
|
148
156
|
Rectangular: {
|
|
@@ -165,30 +173,24 @@ export const ComplexFunctionLibrary: FunctionMap = {
|
|
|
165
173
|
Complex: {
|
|
166
174
|
description: 'Ensures that the given value will be treated as a complex number',
|
|
167
175
|
arguments: [
|
|
168
|
-
{ boxed: true },
|
|
176
|
+
{ boxed: true, unroll: true },
|
|
169
177
|
],
|
|
170
178
|
|
|
171
179
|
// FIXME: this should use flatten? not sure
|
|
172
180
|
|
|
173
|
-
fn:
|
|
181
|
+
fn: (a: UnionValue): UnionValue => {
|
|
174
182
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
type: ValueType.complex,
|
|
182
|
-
value: {
|
|
183
|
-
imaginary: 0,
|
|
184
|
-
real: a.value || 0,
|
|
185
|
-
},
|
|
186
|
-
}
|
|
183
|
+
const complex = CoerceComplex(a);
|
|
184
|
+
if (complex) {
|
|
185
|
+
return {
|
|
186
|
+
type: ValueType.complex,
|
|
187
|
+
value: complex,
|
|
188
|
+
};
|
|
187
189
|
}
|
|
188
190
|
|
|
189
191
|
return ValueError();
|
|
190
192
|
|
|
191
|
-
}
|
|
193
|
+
},
|
|
192
194
|
},
|
|
193
195
|
|
|
194
196
|
/**
|
|
@@ -203,9 +205,9 @@ export const ComplexFunctionLibrary: FunctionMap = {
|
|
|
203
205
|
ComplexLog: {
|
|
204
206
|
description: 'Returns the principal value Log(z) of a complex number z',
|
|
205
207
|
arguments: [
|
|
206
|
-
{ boxed: true },
|
|
208
|
+
{ boxed: true, unroll: true },
|
|
207
209
|
],
|
|
208
|
-
fn:
|
|
210
|
+
fn: (a: UnionValue): UnionValue => {
|
|
209
211
|
|
|
210
212
|
// real -> complex
|
|
211
213
|
if (a.type === ValueType.number) {
|
|
@@ -247,7 +249,7 @@ export const ComplexFunctionLibrary: FunctionMap = {
|
|
|
247
249
|
|
|
248
250
|
return ValueError();
|
|
249
251
|
|
|
250
|
-
}
|
|
252
|
+
},
|
|
251
253
|
},
|
|
252
254
|
|
|
253
255
|
};
|
|
@@ -21,9 +21,9 @@
|
|
|
21
21
|
|
|
22
22
|
import type { FunctionMap } from '../descriptors';
|
|
23
23
|
import { type CellValue, type UnionValue, ValueType } from 'treb-base-types';
|
|
24
|
-
import {
|
|
24
|
+
import { FlattenCellValues } from '../utilities';
|
|
25
25
|
|
|
26
|
-
import { ArgumentError,
|
|
26
|
+
import { ArgumentError, ValueError } from '../function-error';
|
|
27
27
|
|
|
28
28
|
// use a single, static object for base functions
|
|
29
29
|
|
|
@@ -98,11 +98,11 @@ export const FinanceFunctionLibrary: FunctionMap = {
|
|
|
98
98
|
{ name: 'Rate' },
|
|
99
99
|
{ name: 'Cashflow' },
|
|
100
100
|
],
|
|
101
|
-
fn: (rate = 0, ...args:
|
|
101
|
+
fn: (rate = 0, ...args: CellValue[]): UnionValue => {
|
|
102
102
|
|
|
103
103
|
let result = 0;
|
|
104
104
|
|
|
105
|
-
const flat =
|
|
105
|
+
const flat = FlattenCellValues(args);
|
|
106
106
|
for (let i = 0; i < flat.length; i++) {
|
|
107
107
|
const arg = flat[i];
|
|
108
108
|
if (typeof arg === 'number') {
|
|
@@ -123,14 +123,14 @@ export const FinanceFunctionLibrary: FunctionMap = {
|
|
|
123
123
|
{ name: 'Values', },
|
|
124
124
|
{ name: 'Dates', },
|
|
125
125
|
],
|
|
126
|
-
fn: (rate:
|
|
126
|
+
fn: (rate: CellValue, input_values: CellValue[], input_dates: CellValue[]): UnionValue => {
|
|
127
127
|
|
|
128
128
|
if (typeof rate !== 'number') {
|
|
129
129
|
return ArgumentError();
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
-
input_values =
|
|
133
|
-
input_dates =
|
|
132
|
+
input_values = FlattenCellValues(input_values);
|
|
133
|
+
input_dates = FlattenCellValues(input_dates);
|
|
134
134
|
|
|
135
135
|
// some validation...
|
|
136
136
|
|
|
@@ -186,8 +186,8 @@ export const FinanceFunctionLibrary: FunctionMap = {
|
|
|
186
186
|
],
|
|
187
187
|
fn: (input_values: CellValue[], input_dates: CellValue[], guess = .1): UnionValue => {
|
|
188
188
|
|
|
189
|
-
input_values =
|
|
190
|
-
input_dates =
|
|
189
|
+
input_values = FlattenCellValues(input_values);
|
|
190
|
+
input_dates = FlattenCellValues(input_dates);
|
|
191
191
|
|
|
192
192
|
// some validation...
|
|
193
193
|
|
|
@@ -307,7 +307,7 @@ export const FinanceFunctionLibrary: FunctionMap = {
|
|
|
307
307
|
],
|
|
308
308
|
fn: (args: CellValue[], guess = .1): UnionValue => {
|
|
309
309
|
|
|
310
|
-
const flat =
|
|
310
|
+
const flat = FlattenCellValues(args).map(value => typeof value === 'number' ? value : 0);
|
|
311
311
|
|
|
312
312
|
const step = .1; // initial step
|
|
313
313
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
|
|
2
|
+
import type { UnionValue, Complex } from 'treb-base-types';
|
|
3
|
+
import { ValueType } from 'treb-base-types';
|
|
4
|
+
|
|
5
|
+
export const CoerceComplex = (value: UnionValue): Complex|false => {
|
|
6
|
+
|
|
7
|
+
switch (value.type) {
|
|
8
|
+
case ValueType.complex:
|
|
9
|
+
return value.value;
|
|
10
|
+
|
|
11
|
+
case ValueType.number:
|
|
12
|
+
return { real: value.value, imaginary: 0 };
|
|
13
|
+
|
|
14
|
+
case ValueType.boolean:
|
|
15
|
+
return { real: value.value ? 1 : 0, imaginary: 0 };
|
|
16
|
+
|
|
17
|
+
// controversial? ...
|
|
18
|
+
case ValueType.undefined:
|
|
19
|
+
return { real: 0, imaginary: 0 };
|
|
20
|
+
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return false;
|
|
24
|
+
|
|
25
|
+
};
|
|
26
|
+
|
|
@@ -21,64 +21,44 @@
|
|
|
21
21
|
|
|
22
22
|
import type { FunctionMap } from '../descriptors';
|
|
23
23
|
import { type UnionValue, ValueType } from 'treb-base-types';
|
|
24
|
-
|
|
24
|
+
|
|
25
|
+
const MatchType = (type: string, ref: UnionValue): UnionValue => {
|
|
26
|
+
return {
|
|
27
|
+
type: ValueType.boolean,
|
|
28
|
+
value: typeof (ref.value as {value?: unknown})?.value === type,
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const match_arguments = [{
|
|
33
|
+
name: 'Reference',
|
|
34
|
+
metadata: true,
|
|
35
|
+
unroll: true,
|
|
36
|
+
}];
|
|
25
37
|
|
|
26
38
|
export const InformationFunctionLibrary: FunctionMap = {
|
|
27
39
|
|
|
28
40
|
IsBlank: {
|
|
29
41
|
description: 'Returns true if the reference is blank',
|
|
30
|
-
arguments:
|
|
31
|
-
|
|
32
|
-
metadata: true,
|
|
33
|
-
}],
|
|
34
|
-
fn: Utils.ApplyAsArray((ref: UnionValue): UnionValue => {
|
|
35
|
-
return {
|
|
36
|
-
type: ValueType.boolean,
|
|
37
|
-
value: !ref?.value || typeof ref.value.value === 'undefined',
|
|
38
|
-
};
|
|
39
|
-
}),
|
|
42
|
+
arguments: match_arguments,
|
|
43
|
+
fn: MatchType.bind(0, 'undefined'),
|
|
40
44
|
},
|
|
41
45
|
|
|
42
46
|
IsNumber: {
|
|
43
47
|
description: 'Returns true if the reference is a number',
|
|
44
|
-
arguments:
|
|
45
|
-
|
|
46
|
-
metadata: true,
|
|
47
|
-
}],
|
|
48
|
-
fn: Utils.ApplyAsArray((ref: UnionValue): UnionValue => {
|
|
49
|
-
return {
|
|
50
|
-
type: ValueType.boolean,
|
|
51
|
-
value: ref?.value && typeof ref.value.value === 'number',
|
|
52
|
-
};
|
|
53
|
-
}),
|
|
48
|
+
arguments: match_arguments,
|
|
49
|
+
fn: MatchType.bind(0, 'number'),
|
|
54
50
|
},
|
|
55
51
|
|
|
56
52
|
IsLogical: {
|
|
57
53
|
description: 'Returns true if the reference is a logical TRUE or FALSE',
|
|
58
|
-
arguments:
|
|
59
|
-
|
|
60
|
-
metadata: true,
|
|
61
|
-
}],
|
|
62
|
-
fn: Utils.ApplyAsArray((ref: UnionValue): UnionValue => {
|
|
63
|
-
return {
|
|
64
|
-
type: ValueType.boolean,
|
|
65
|
-
value: ref?.value && typeof ref.value.value === 'boolean',
|
|
66
|
-
};
|
|
67
|
-
}),
|
|
54
|
+
arguments: match_arguments,
|
|
55
|
+
fn: MatchType.bind(0, 'boolean'),
|
|
68
56
|
},
|
|
69
57
|
|
|
70
58
|
IsText: {
|
|
71
59
|
description: 'Returns true if the reference is text',
|
|
72
|
-
arguments:
|
|
73
|
-
|
|
74
|
-
metadata: true,
|
|
75
|
-
}],
|
|
76
|
-
fn: Utils.ApplyAsArray((ref: UnionValue): UnionValue => {
|
|
77
|
-
return {
|
|
78
|
-
type: ValueType.boolean,
|
|
79
|
-
value: ref?.value && typeof ref.value.value === 'string'
|
|
80
|
-
};
|
|
81
|
-
}),
|
|
60
|
+
arguments: match_arguments,
|
|
61
|
+
fn: MatchType.bind(0, 'string'),
|
|
82
62
|
},
|
|
83
63
|
|
|
84
64
|
/* needs more data
|
|
@@ -37,11 +37,18 @@ const ComplexMatrix = (input: UnionValue): ComplexMatrixType => {
|
|
|
37
37
|
|
|
38
38
|
// ensure array
|
|
39
39
|
|
|
40
|
+
// hmmm... this is confusing. what is this doing? is this for scalars?
|
|
41
|
+
// if that were the case shouldn't it wrap up the outer value, and not
|
|
42
|
+
// the value property? ...
|
|
43
|
+
|
|
40
44
|
if (input.type === ValueType.array) {
|
|
41
45
|
a = input.value;
|
|
42
46
|
}
|
|
43
47
|
else {
|
|
44
|
-
|
|
48
|
+
|
|
49
|
+
// a = [[input.value]];
|
|
50
|
+
a = [[input]];
|
|
51
|
+
|
|
45
52
|
}
|
|
46
53
|
|
|
47
54
|
// if (!Array.isArray(a)) { a = [[a]]; }
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
*/
|
|
31
31
|
|
|
32
32
|
|
|
33
|
-
import type { Cell,
|
|
33
|
+
import type { Cell, CellStyle } from 'treb-base-types';
|
|
34
34
|
|
|
35
35
|
export interface SparklineRenderOptions {
|
|
36
36
|
context: CanvasRenderingContext2D;
|
|
@@ -62,7 +62,7 @@ export class Sparkline {
|
|
|
62
62
|
* representation (loading file); in that case it's an object with numeric
|
|
63
63
|
* indexes (sadly)
|
|
64
64
|
*/
|
|
65
|
-
protected static UnpackValues(underlying:
|
|
65
|
+
protected static UnpackValues(underlying: unknown): number[] {
|
|
66
66
|
|
|
67
67
|
if (Array.isArray(underlying)) {
|
|
68
68
|
const test = underlying[0];
|
|
@@ -85,7 +85,9 @@ export class Sparkline {
|
|
|
85
85
|
// if (keys.every(key => !isNaN(Number(key)))) {
|
|
86
86
|
|
|
87
87
|
// check first, last
|
|
88
|
-
if (typeof underlying['0'] !== 'undefined' &&
|
|
88
|
+
if (typeof ((underlying as Record<string, number>)['0']) !== 'undefined' &&
|
|
89
|
+
typeof (underlying as Record<string, number>)[(len - 1).toString()] !== 'undefined') {
|
|
90
|
+
|
|
89
91
|
const data: number[] = [];
|
|
90
92
|
|
|
91
93
|
// we probably don't have to explicitly use strings -- although it's not
|
|
@@ -93,7 +95,7 @@ export class Sparkline {
|
|
|
93
95
|
// conversion
|
|
94
96
|
|
|
95
97
|
for (let i = 0; i < len; i++) {
|
|
96
|
-
data[i] = underlying[i.toString()];
|
|
98
|
+
data[i] = (underlying as Record<string, number>)[i.toString()];
|
|
97
99
|
}
|
|
98
100
|
return data;
|
|
99
101
|
}
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
import type { FunctionMap } from '../descriptors';
|
|
23
23
|
import * as Utils from '../utilities';
|
|
24
24
|
import { ValueError, ArgumentError, NAError } from '../function-error';
|
|
25
|
-
import { type Complex, type UnionValue, ValueType } from 'treb-base-types';
|
|
25
|
+
import { type Complex, type UnionValue, ValueType, type CellValue } from 'treb-base-types';
|
|
26
26
|
import * as ComplexMath from '../complex-math';
|
|
27
27
|
|
|
28
28
|
export const Variance = (data: number[], sample = false) => {
|
|
@@ -58,32 +58,32 @@ export const StatisticsFunctionLibrary: FunctionMap = {
|
|
|
58
58
|
'StDev.P': {
|
|
59
59
|
description: 'Returns the standard deviation of a set of values, corresponding to a population',
|
|
60
60
|
arguments: [{ name: 'data', }],
|
|
61
|
-
fn: (...args:
|
|
62
|
-
return { type: ValueType.number, value: Math.sqrt(Variance(Utils.
|
|
61
|
+
fn: (...args: CellValue[]): UnionValue => {
|
|
62
|
+
return { type: ValueType.number, value: Math.sqrt(Variance(Utils.FlattenNumbers(args), false)) };
|
|
63
63
|
},
|
|
64
64
|
},
|
|
65
65
|
|
|
66
66
|
'StDev.S': {
|
|
67
67
|
description: 'Returns the standard deviation of a set of values, corresponding to a sample of a population',
|
|
68
68
|
arguments: [{ name: 'data', }],
|
|
69
|
-
fn: (...args:
|
|
70
|
-
return { type: ValueType.number, value: Math.sqrt(Variance(Utils.
|
|
69
|
+
fn: (...args: CellValue[]): UnionValue => {
|
|
70
|
+
return { type: ValueType.number, value: Math.sqrt(Variance(Utils.FlattenNumbers(args), true)) };
|
|
71
71
|
},
|
|
72
72
|
},
|
|
73
73
|
|
|
74
74
|
'Var.P': {
|
|
75
75
|
description: 'Returns the variance of a set of values, corresponding to a population',
|
|
76
76
|
arguments: [{ name: 'data', }],
|
|
77
|
-
fn: (...args:
|
|
78
|
-
return { type: ValueType.number, value: Variance(Utils.
|
|
77
|
+
fn: (...args: CellValue[]): UnionValue => {
|
|
78
|
+
return { type: ValueType.number, value: Variance(Utils.FlattenNumbers(args), false) };
|
|
79
79
|
},
|
|
80
80
|
},
|
|
81
81
|
|
|
82
82
|
'Var.S': {
|
|
83
83
|
description: 'Returns the variance of a set of values, corresponding to a sample of a population',
|
|
84
84
|
arguments: [{ name: 'data', }],
|
|
85
|
-
fn: (...args:
|
|
86
|
-
return { type: ValueType.number, value: Variance(Utils.
|
|
85
|
+
fn: (...args: CellValue[]): UnionValue => {
|
|
86
|
+
return { type: ValueType.number, value: Variance(Utils.FlattenNumbers(args), true) };
|
|
87
87
|
},
|
|
88
88
|
},
|
|
89
89
|
|
|
@@ -94,7 +94,7 @@ export const StatisticsFunctionLibrary: FunctionMap = {
|
|
|
94
94
|
}, {
|
|
95
95
|
name: 'B',
|
|
96
96
|
}],
|
|
97
|
-
fn: (x:
|
|
97
|
+
fn: (x: number[][], y: number[][]): UnionValue => {
|
|
98
98
|
|
|
99
99
|
// both must be 2d arrays, we're assuming the same or mostly similar shape
|
|
100
100
|
if (!Array.isArray(x) || !Array.isArray(y)) { return ValueError(); }
|
|
@@ -153,7 +153,7 @@ export const StatisticsFunctionLibrary: FunctionMap = {
|
|
|
153
153
|
}, {
|
|
154
154
|
name: 'B',
|
|
155
155
|
}],
|
|
156
|
-
fn: (x:
|
|
156
|
+
fn: (x: number[][], y: number[][]): UnionValue => {
|
|
157
157
|
|
|
158
158
|
// both must be 2d arrays, we're assuming the same or mostly similar shape
|
|
159
159
|
if (!Array.isArray(x) || !Array.isArray(y)) { return ValueError(); }
|
|
@@ -201,7 +201,7 @@ export const StatisticsFunctionLibrary: FunctionMap = {
|
|
|
201
201
|
description: 'Returns the geometric mean of all numeric arguments',
|
|
202
202
|
arguments: [{ boxed: true }],
|
|
203
203
|
|
|
204
|
-
fn: (...args:
|
|
204
|
+
fn: (...args: UnionValue[]): UnionValue => {
|
|
205
205
|
|
|
206
206
|
args = Utils.FlattenBoxed(args);
|
|
207
207
|
|
|
@@ -210,7 +210,7 @@ export const StatisticsFunctionLibrary: FunctionMap = {
|
|
|
210
210
|
let complex = false;
|
|
211
211
|
let negative = false;
|
|
212
212
|
|
|
213
|
-
for (const arg of args
|
|
213
|
+
for (const arg of args) {
|
|
214
214
|
|
|
215
215
|
if (arg.type === ValueType.complex) {
|
|
216
216
|
complex = true;
|
|
@@ -265,7 +265,7 @@ export const StatisticsFunctionLibrary: FunctionMap = {
|
|
|
265
265
|
description: 'Returns the arithmetic mean of all numeric arguments',
|
|
266
266
|
arguments: [{ boxed: true }],
|
|
267
267
|
|
|
268
|
-
fn: (...args:
|
|
268
|
+
fn: (...args: UnionValue[]): UnionValue => {
|
|
269
269
|
args = Utils.FlattenBoxed(args);
|
|
270
270
|
|
|
271
271
|
const result = { real: 0, imaginary: 0 };
|
|
@@ -305,7 +305,9 @@ export const StatisticsFunctionLibrary: FunctionMap = {
|
|
|
305
305
|
],
|
|
306
306
|
fn: (range: number[][], percentile: number): UnionValue => {
|
|
307
307
|
|
|
308
|
-
const flat = Utils.
|
|
308
|
+
// const flat = Utils.FlattenCellValues(range).filter((test): test is number => typeof test === 'number');
|
|
309
|
+
const flat = Utils.FlattenNumbers(range);
|
|
310
|
+
|
|
309
311
|
flat.sort((a, b) => a - b);
|
|
310
312
|
const n = flat.length;
|
|
311
313
|
|
|
@@ -326,9 +328,11 @@ export const StatisticsFunctionLibrary: FunctionMap = {
|
|
|
326
328
|
arguments: [
|
|
327
329
|
{ name: 'range' },
|
|
328
330
|
],
|
|
329
|
-
fn: (...args:
|
|
331
|
+
fn: (...args: number[]): UnionValue => {
|
|
332
|
+
|
|
333
|
+
// const flat = Utils.FlattenCellValues(args).filter((test): test is number => typeof test === 'number');
|
|
334
|
+
const flat = Utils.FlattenNumbers(args);
|
|
330
335
|
|
|
331
|
-
const flat = Utils.FlattenUnboxed(args).filter((test) => typeof test === 'number');
|
|
332
336
|
flat.sort((a, b) => a - b);
|
|
333
337
|
const n = flat.length;
|
|
334
338
|
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
*
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
import type { FunctionMap } from '../descriptors';
|
|
22
|
+
import type { FunctionMap, IntrinsicValue } from '../descriptors';
|
|
23
23
|
import { NumberFormatCache, ValueParser } from 'treb-format';
|
|
24
|
-
import type { UnionValue} from 'treb-base-types';
|
|
24
|
+
import type { CellValue, UnionValue} from 'treb-base-types';
|
|
25
25
|
import { Localization, ValueType } from 'treb-base-types';
|
|
26
26
|
import * as Utils from '../utilities';
|
|
27
27
|
import { ArgumentError, ValueError } from '../function-error';
|
|
@@ -78,15 +78,15 @@ export const TextFunctionLibrary: FunctionMap = {
|
|
|
78
78
|
WildcardMatch: {
|
|
79
79
|
visibility: 'internal',
|
|
80
80
|
arguments: [
|
|
81
|
-
{ name: 'text', },
|
|
82
|
-
{ name: 'text', },
|
|
81
|
+
{ name: 'text', unroll: true },
|
|
82
|
+
{ name: 'text', unroll: true },
|
|
83
83
|
|
|
84
84
|
// the invert parameter is optional, defaults to false. we add this
|
|
85
85
|
// so we can invert wirhout requiring an extra function call.
|
|
86
86
|
|
|
87
87
|
{ name: 'invert' },
|
|
88
88
|
],
|
|
89
|
-
fn:
|
|
89
|
+
fn: (a: IntrinsicValue, b: IntrinsicValue, invert = false) => {
|
|
90
90
|
|
|
91
91
|
if (typeof a === 'string' && typeof b === 'string') {
|
|
92
92
|
const pattern = Utils.ParseWildcards(b);
|
|
@@ -102,21 +102,22 @@ export const TextFunctionLibrary: FunctionMap = {
|
|
|
102
102
|
type: ValueType.boolean,
|
|
103
103
|
value: (a === b || a?.toString() === b?.toString()),
|
|
104
104
|
}
|
|
105
|
-
}
|
|
105
|
+
},
|
|
106
|
+
|
|
106
107
|
},
|
|
107
108
|
|
|
108
109
|
Exact: {
|
|
109
110
|
arguments: [
|
|
110
|
-
{ name: 'text', boxed: true, },
|
|
111
|
-
{ name: 'text', boxed: true, },
|
|
111
|
+
{ name: 'text', boxed: true, unroll: true },
|
|
112
|
+
{ name: 'text', boxed: true, unroll: true },
|
|
112
113
|
],
|
|
113
114
|
category: ['text'],
|
|
114
|
-
fn:
|
|
115
|
+
fn: (a: UnionValue, b: UnionValue): UnionValue => {
|
|
115
116
|
return {
|
|
116
117
|
type: ValueType.boolean,
|
|
117
118
|
value: (a?.value?.toString()) === (b?.value?.toString()),
|
|
118
119
|
};
|
|
119
|
-
}
|
|
120
|
+
},
|
|
120
121
|
},
|
|
121
122
|
|
|
122
123
|
Left: {
|
|
@@ -258,15 +259,15 @@ export const TextFunctionLibrary: FunctionMap = {
|
|
|
258
259
|
/** canonical should be CONCAT; concatenate can be an alias */
|
|
259
260
|
Concat: {
|
|
260
261
|
description: 'Pastes strings together',
|
|
261
|
-
fn: (...args:
|
|
262
|
+
fn: (...args: CellValue[]): UnionValue => {
|
|
262
263
|
|
|
263
|
-
const values = Utils.
|
|
264
|
+
const values = Utils.FlattenCellValues(args);
|
|
264
265
|
const value = values.map((arg) => {
|
|
265
266
|
|
|
266
267
|
// this is used when concatenating cells that contain numbers
|
|
267
268
|
// FIXME: get cell number format? we'd need to use metadata
|
|
268
269
|
|
|
269
|
-
const string_arg =
|
|
270
|
+
const string_arg = arg?.toString() || '';
|
|
270
271
|
|
|
271
272
|
if (typeof arg === 'number' && Localization.decimal_separator === ',') {
|
|
272
273
|
return string_arg.replace(/\./, ',');
|