@trebco/treb 32.11.0 → 32.13.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-export-worker.mjs +1 -1
- package/dist/treb-spreadsheet.mjs +7 -7
- package/dist/treb.d.ts +1 -1
- package/package.json +1 -1
- package/treb-calculator/src/functions/base-functions.ts +63 -6
- package/treb-calculator/src/functions/fp.ts +192 -2
- package/treb-grid/src/types/scale-control.ts +5 -1
package/dist/treb.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1757,8 +1757,10 @@ export const BaseFunctionLibrary: FunctionMap = {
|
|
|
1757
1757
|
//}
|
|
1758
1758
|
|
|
1759
1759
|
let rng: Area|undefined;
|
|
1760
|
+
let return_from_array = false;
|
|
1760
1761
|
|
|
1761
1762
|
if (return_array.type === ValueType.array) {
|
|
1763
|
+
|
|
1762
1764
|
// console.info({return_array});
|
|
1763
1765
|
|
|
1764
1766
|
const arr = return_array.value;
|
|
@@ -1772,9 +1774,16 @@ export const BaseFunctionLibrary: FunctionMap = {
|
|
|
1772
1774
|
rng = new Area(start.value.address, end.value.address);
|
|
1773
1775
|
}
|
|
1774
1776
|
|
|
1777
|
+
// we can allow a regular array here... perhaps we should
|
|
1778
|
+
// check the dimensions to ensure they match? TODO/FIXME
|
|
1779
|
+
|
|
1780
|
+
else {
|
|
1781
|
+
return_from_array = true;
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1775
1784
|
}
|
|
1776
1785
|
|
|
1777
|
-
if (!rng) {
|
|
1786
|
+
if (!rng && !return_from_array) {
|
|
1778
1787
|
console.info('invalid range');
|
|
1779
1788
|
return ReferenceError();
|
|
1780
1789
|
}
|
|
@@ -1848,7 +1857,55 @@ export const BaseFunctionLibrary: FunctionMap = {
|
|
|
1848
1857
|
// an array. we might prefer to return a scalar if there's only
|
|
1849
1858
|
// one value, not sure what's the intended behavior
|
|
1850
1859
|
//
|
|
1851
|
-
const ReturnIndex = (
|
|
1860
|
+
const ReturnIndex = (index: number): UnionValue => {
|
|
1861
|
+
|
|
1862
|
+
// FIXME: we could almost certainly merge these two paths
|
|
1863
|
+
|
|
1864
|
+
if (return_from_array && return_array.type === ValueType.array) {
|
|
1865
|
+
|
|
1866
|
+
// instead of a range, we're returning values from a static array
|
|
1867
|
+
|
|
1868
|
+
const src_columns = return_array.value.length;
|
|
1869
|
+
const src_rows = return_array.value[0]?.length || 0;
|
|
1870
|
+
const result: UnionValue[][] = [];
|
|
1871
|
+
|
|
1872
|
+
let start_row = 0;
|
|
1873
|
+
let end_row = src_rows - 1;
|
|
1874
|
+
|
|
1875
|
+
let start_column = 0;
|
|
1876
|
+
let end_column = src_columns - 1;
|
|
1877
|
+
|
|
1878
|
+
if (transpose) {
|
|
1879
|
+
if (search_mode < 0) {
|
|
1880
|
+
index = src_rows - 1 - index; // invert FIXME: test
|
|
1881
|
+
}
|
|
1882
|
+
start_row = end_row = index;
|
|
1883
|
+
}
|
|
1884
|
+
else {
|
|
1885
|
+
if (search_mode < 0) {
|
|
1886
|
+
index = src_columns - 1 - index; // invert FIXME: test
|
|
1887
|
+
}
|
|
1888
|
+
start_column = end_column = index;
|
|
1889
|
+
}
|
|
1890
|
+
|
|
1891
|
+
for (let c = start_column; c <= end_column; c++) {
|
|
1892
|
+
const column: UnionValue[] = [];
|
|
1893
|
+
for (let r = start_row; r <= end_row; r++) {
|
|
1894
|
+
column.push(return_array.value[c][r]);
|
|
1895
|
+
}
|
|
1896
|
+
result.push(column);
|
|
1897
|
+
}
|
|
1898
|
+
|
|
1899
|
+
return {
|
|
1900
|
+
type: ValueType.array,
|
|
1901
|
+
value: result,
|
|
1902
|
+
};
|
|
1903
|
+
|
|
1904
|
+
}
|
|
1905
|
+
|
|
1906
|
+
if (!rng) {
|
|
1907
|
+
throw new Error('invalid range');
|
|
1908
|
+
}
|
|
1852
1909
|
|
|
1853
1910
|
// console.info("transpose?", transpose, {rng}, 'shape', rng.rows, rng.columns);
|
|
1854
1911
|
|
|
@@ -1953,7 +2010,7 @@ export const BaseFunctionLibrary: FunctionMap = {
|
|
|
1953
2010
|
|
|
1954
2011
|
// check for exact match first, just in case
|
|
1955
2012
|
if (value === lookup_value) {
|
|
1956
|
-
return ReturnIndex(
|
|
2013
|
+
return ReturnIndex(i);
|
|
1957
2014
|
}
|
|
1958
2015
|
|
|
1959
2016
|
const delta = Math.abs(value - lookup_value);
|
|
@@ -1969,7 +2026,7 @@ export const BaseFunctionLibrary: FunctionMap = {
|
|
|
1969
2026
|
}
|
|
1970
2027
|
|
|
1971
2028
|
if (index >= 0) {
|
|
1972
|
-
return ReturnIndex(
|
|
2029
|
+
return ReturnIndex(index);
|
|
1973
2030
|
}
|
|
1974
2031
|
|
|
1975
2032
|
}
|
|
@@ -1987,7 +2044,7 @@ export const BaseFunctionLibrary: FunctionMap = {
|
|
|
1987
2044
|
for (let i = 0; i < lookup_array.length; i++) {
|
|
1988
2045
|
const value = lookup_array[i][0];
|
|
1989
2046
|
if (typeof value === 'string' && regex.exec(value)) {
|
|
1990
|
-
return ReturnIndex(
|
|
2047
|
+
return ReturnIndex(i);
|
|
1991
2048
|
}
|
|
1992
2049
|
}
|
|
1993
2050
|
|
|
@@ -2005,7 +2062,7 @@ export const BaseFunctionLibrary: FunctionMap = {
|
|
|
2005
2062
|
value = value.toLowerCase();
|
|
2006
2063
|
}
|
|
2007
2064
|
if (value === lookup_value) {
|
|
2008
|
-
return ReturnIndex(
|
|
2065
|
+
return ReturnIndex(i);
|
|
2009
2066
|
}
|
|
2010
2067
|
}
|
|
2011
2068
|
|
|
@@ -20,9 +20,10 @@
|
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
import type { FunctionMap } from '../descriptors';
|
|
23
|
-
import type { FunctionUnion, UnionValue} from 'treb-base-types';
|
|
24
|
-
import { ValueType } from 'treb-base-types';
|
|
23
|
+
import type { CellValue, FunctionUnion, UnionValue} from 'treb-base-types';
|
|
24
|
+
import { Box, ValueType } from 'treb-base-types';
|
|
25
25
|
import { ArgumentError, ValueError } from '../function-error';
|
|
26
|
+
import { FlattenCellValues } from '../utilities';
|
|
26
27
|
|
|
27
28
|
export const FPFunctionLibrary: FunctionMap = {
|
|
28
29
|
|
|
@@ -67,6 +68,195 @@ export const FPFunctionLibrary: FunctionMap = {
|
|
|
67
68
|
},
|
|
68
69
|
},
|
|
69
70
|
|
|
71
|
+
ChooseCols: {
|
|
72
|
+
description: 'Returns one or more columns from an array, by column index',
|
|
73
|
+
arguments: [{
|
|
74
|
+
name: 'array',
|
|
75
|
+
}, {
|
|
76
|
+
name: 'column',
|
|
77
|
+
repeat: true,
|
|
78
|
+
}],
|
|
79
|
+
fn: function(data: CellValue|CellValue[][], ...args: number[]) {
|
|
80
|
+
|
|
81
|
+
if (!Array.isArray(data)) {
|
|
82
|
+
data = [[data]];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const flat = FlattenCellValues(args);
|
|
86
|
+
// console.info({flat});
|
|
87
|
+
|
|
88
|
+
const columns = data.length;
|
|
89
|
+
const result: UnionValue[][] = [];
|
|
90
|
+
|
|
91
|
+
for (let arg of flat) {
|
|
92
|
+
if (typeof arg === 'number') {
|
|
93
|
+
|
|
94
|
+
if (arg < 0) {
|
|
95
|
+
arg = columns + arg;
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
arg--;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const col = data[arg];
|
|
102
|
+
if (col) {
|
|
103
|
+
const column: UnionValue[] = [];
|
|
104
|
+
for (const value of col) {
|
|
105
|
+
column.push(Box(value));
|
|
106
|
+
}
|
|
107
|
+
result.push(column);
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
return ArgumentError(); // invalid column
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (!result.length) {
|
|
116
|
+
result.push([]);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
type: ValueType.array,
|
|
121
|
+
value: result,
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
ChooseRows: {
|
|
128
|
+
description: 'Returns one or more rows from an array, by row index',
|
|
129
|
+
arguments: [{
|
|
130
|
+
name: 'array',
|
|
131
|
+
}, {
|
|
132
|
+
name: 'row',
|
|
133
|
+
repeat: true,
|
|
134
|
+
}],
|
|
135
|
+
fn: function(data: CellValue|CellValue[][], ...args: number[]) {
|
|
136
|
+
|
|
137
|
+
if (!Array.isArray(data)) {
|
|
138
|
+
data = [[data]];
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const flat = FlattenCellValues(args);
|
|
142
|
+
// console.info({flat});
|
|
143
|
+
|
|
144
|
+
const rows = data[0]?.length || 0;
|
|
145
|
+
const result: UnionValue[][] = [];
|
|
146
|
+
|
|
147
|
+
for (let arg of flat) {
|
|
148
|
+
if (typeof arg === 'number') {
|
|
149
|
+
|
|
150
|
+
if (arg < 0) {
|
|
151
|
+
arg = rows + arg;
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
arg--;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
for (const [column_index, col] of data.entries()) {
|
|
158
|
+
const column = result[column_index] || [];
|
|
159
|
+
if (arg < 0 || arg >= col.length) {
|
|
160
|
+
return ArgumentError();
|
|
161
|
+
}
|
|
162
|
+
column.push(Box(col[arg]));
|
|
163
|
+
result[column_index] = column;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (!result.length) {
|
|
170
|
+
result.push([]);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return {
|
|
174
|
+
type: ValueType.array,
|
|
175
|
+
value: result,
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
|
|
181
|
+
Take: {
|
|
182
|
+
description: 'Returns some number of rows/columns from the start or end of an array',
|
|
183
|
+
arguments: [{
|
|
184
|
+
name: 'array',
|
|
185
|
+
}, {
|
|
186
|
+
name: 'rows',
|
|
187
|
+
}, {
|
|
188
|
+
name: 'columns',
|
|
189
|
+
}],
|
|
190
|
+
fn: function(data: CellValue|CellValue[][], rows?: number, columns?: number) {
|
|
191
|
+
|
|
192
|
+
// we need one of rows, columns to be defined. neither can === 0.
|
|
193
|
+
|
|
194
|
+
if ((!rows && !columns) || rows === 0 || columns === 0 || (typeof rows !== 'number' && typeof rows !== 'undefined') || (typeof columns !== 'number' && typeof columns !== 'undefined')) {
|
|
195
|
+
return ArgumentError();
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (!Array.isArray(data)) {
|
|
199
|
+
data = [[data]];
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const data_columns = data.length;
|
|
203
|
+
const data_rows = data[0].length;
|
|
204
|
+
const result: UnionValue[][] = [];
|
|
205
|
+
|
|
206
|
+
// I guess we can compose?
|
|
207
|
+
|
|
208
|
+
// data is column-first
|
|
209
|
+
|
|
210
|
+
let start_column = 0;
|
|
211
|
+
let end_column = data_columns - 1;
|
|
212
|
+
|
|
213
|
+
let start_row = 0;
|
|
214
|
+
let end_row = data_rows - 1;
|
|
215
|
+
|
|
216
|
+
if (typeof columns === 'number') {
|
|
217
|
+
|
|
218
|
+
// clip data so it has the first (or last) X columns
|
|
219
|
+
|
|
220
|
+
if (columns > 0) {
|
|
221
|
+
end_column = Math.min(columns, data_columns) - 1;
|
|
222
|
+
}
|
|
223
|
+
else if (columns < 0) {
|
|
224
|
+
end_column = data_columns - 1;
|
|
225
|
+
start_column = Math.max(0, end_column + columns + 1);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (typeof rows === 'number') {
|
|
231
|
+
|
|
232
|
+
// clip data so it has the first (or last) X columns
|
|
233
|
+
|
|
234
|
+
if (rows > 0) {
|
|
235
|
+
end_row = Math.min(rows, data_rows) - 1;
|
|
236
|
+
}
|
|
237
|
+
else if (rows < 0) {
|
|
238
|
+
end_row = data_rows - 1;
|
|
239
|
+
start_row = Math.max(0, end_row + rows + 1);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
for (let c = start_column; c <= end_column; c++) {
|
|
245
|
+
const column: UnionValue[] = [];
|
|
246
|
+
for (let r = start_row; r <= end_row; r++) {
|
|
247
|
+
column.push(Box(data[c][r]));
|
|
248
|
+
}
|
|
249
|
+
result.push(column);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return {
|
|
253
|
+
type: ValueType.array,
|
|
254
|
+
value: result,
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
|
|
70
260
|
Reduce: {
|
|
71
261
|
description: 'Accumulates a value by applying a function to a set of values',
|
|
72
262
|
arguments: [
|
|
@@ -140,11 +140,15 @@ export class ScaleControl extends EventSource<ScaleEvent> {
|
|
|
140
140
|
}
|
|
141
141
|
});
|
|
142
142
|
|
|
143
|
+
// we're overriding scroll behavior here, but it's a tiny panel.
|
|
144
|
+
// if we explicitly mark passive:false we can avoid the console
|
|
145
|
+
// warning (I think)
|
|
146
|
+
|
|
143
147
|
container.addEventListener('wheel', (event: WheelEvent) => {
|
|
144
148
|
event.stopPropagation();
|
|
145
149
|
event.preventDefault();
|
|
146
150
|
this.Tick(event.deltaY)
|
|
147
|
-
});
|
|
151
|
+
}, { passive: false });
|
|
148
152
|
|
|
149
153
|
}
|
|
150
154
|
|