@trebco/treb 28.15.0 → 28.15.1
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 +9 -9
- package/dist/treb-spreadsheet.mjs +15 -15
- package/package.json +1 -1
- package/treb-calculator/src/functions/base-functions.ts +71 -0
- package/treb-calculator/src/utilities.ts +37 -24
- package/treb-export/src/import2.ts +5 -16
- package/treb-export/src/workbook-style2.ts +15 -27
- package/treb-grid/src/render/tile_renderer.ts +14 -12
- package/treb-grid/src/types/grid.ts +1 -1
package/package.json
CHANGED
|
@@ -729,6 +729,77 @@ export const BaseFunctionLibrary: FunctionMap = {
|
|
|
729
729
|
})
|
|
730
730
|
},
|
|
731
731
|
|
|
732
|
+
Large: {
|
|
733
|
+
description: 'Returns the nth numeric value from the data, in descending order',
|
|
734
|
+
arguments: [
|
|
735
|
+
{
|
|
736
|
+
name: 'values',
|
|
737
|
+
},
|
|
738
|
+
{
|
|
739
|
+
name: 'index',
|
|
740
|
+
}
|
|
741
|
+
],
|
|
742
|
+
|
|
743
|
+
// OK a little tricky here -- we're going to reverse the arguments
|
|
744
|
+
// so we can call apply as array, but applying against the trailing
|
|
745
|
+
// arguments.
|
|
746
|
+
|
|
747
|
+
fn: Utils.ApplyAsArraySwap((data: any, index: number) => {
|
|
748
|
+
|
|
749
|
+
if (index <= 0) {
|
|
750
|
+
return ArgumentError();
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
const flat = Utils.FlattenUnboxed(data);
|
|
754
|
+
const numeric: number[] = flat.filter(test => typeof test === 'number');
|
|
755
|
+
numeric.sort((a, b) => b - a);
|
|
756
|
+
|
|
757
|
+
if (index <= numeric.length) {
|
|
758
|
+
return {
|
|
759
|
+
type: ValueType.number,
|
|
760
|
+
value: numeric[index - 1],
|
|
761
|
+
};
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
return ArgumentError();
|
|
765
|
+
}),
|
|
766
|
+
},
|
|
767
|
+
|
|
768
|
+
Small: {
|
|
769
|
+
description: 'Returns the nth numeric value from the data, in ascending order',
|
|
770
|
+
arguments: [
|
|
771
|
+
{
|
|
772
|
+
name: 'values',
|
|
773
|
+
},
|
|
774
|
+
{
|
|
775
|
+
name: 'index',
|
|
776
|
+
}
|
|
777
|
+
],
|
|
778
|
+
|
|
779
|
+
// see large, above
|
|
780
|
+
|
|
781
|
+
fn: Utils.ApplyAsArraySwap((data: any, index: number) => {
|
|
782
|
+
|
|
783
|
+
if (index <= 0) {
|
|
784
|
+
return ArgumentError();
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
const flat = Utils.FlattenUnboxed(data);
|
|
788
|
+
const numeric: number[] = flat.filter(test => typeof test === 'number');
|
|
789
|
+
numeric.sort((a, b) => a - b);
|
|
790
|
+
|
|
791
|
+
if (index <= numeric.length) {
|
|
792
|
+
return {
|
|
793
|
+
type: ValueType.number,
|
|
794
|
+
value: numeric[index - 1],
|
|
795
|
+
};
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
return ArgumentError();
|
|
799
|
+
|
|
800
|
+
}),
|
|
801
|
+
},
|
|
802
|
+
|
|
732
803
|
/**
|
|
733
804
|
* sort arguments, but ensure we return empty strings to
|
|
734
805
|
* fill up the result array
|
|
@@ -193,22 +193,52 @@ export const ApplyArrayFunc = (base: (...args: any[]) => any) => {
|
|
|
193
193
|
};
|
|
194
194
|
};
|
|
195
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
|
+
}
|
|
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
|
+
|
|
220
|
+
const swapped = [...rest, element];
|
|
221
|
+
return base(...swapped);
|
|
222
|
+
|
|
223
|
+
})),
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
return base(...rest, a);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
|
|
196
233
|
export const ApplyAsArray = (base: (a: any, ...rest: any[]) => UnionValue) => {
|
|
197
234
|
return (a: any, ...rest: any[]): UnionValue => {
|
|
198
235
|
if (Array.isArray(a)) {
|
|
199
|
-
|
|
200
236
|
return {
|
|
201
237
|
type: ValueType.array,
|
|
202
238
|
value: a.map(row => row.map((element: any) => {
|
|
203
239
|
return base(element, ...rest);
|
|
204
240
|
})),
|
|
205
241
|
};
|
|
206
|
-
|
|
207
|
-
/*
|
|
208
|
-
return a.map(row => row.map((element: any) => {
|
|
209
|
-
return base(element, ...rest);
|
|
210
|
-
}));
|
|
211
|
-
*/
|
|
212
242
|
}
|
|
213
243
|
else if (typeof a === 'object' && !!a && a.type === ValueType.array ) {
|
|
214
244
|
return {
|
|
@@ -280,23 +310,6 @@ export const ApplyAsArray2 = (base: (a: any, b: any, ...rest: any[]) => UnionVal
|
|
|
280
310
|
};
|
|
281
311
|
}
|
|
282
312
|
|
|
283
|
-
/*
|
|
284
|
-
if (Array.isArray(a)) {
|
|
285
|
-
if (Array.isArray(b)) {
|
|
286
|
-
return a.map((row, i: number) => row.map((element: any, j: number) => {
|
|
287
|
-
return base(element, b[i][j], ...rest);
|
|
288
|
-
}));
|
|
289
|
-
}
|
|
290
|
-
else {
|
|
291
|
-
return a.map(row => row.map((element: any) => {
|
|
292
|
-
return base(element, b, ...rest);
|
|
293
|
-
}));
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
else {
|
|
297
|
-
return base(a, b, ...rest);
|
|
298
|
-
}
|
|
299
|
-
*/
|
|
300
313
|
return base(a, b, ...rest);
|
|
301
314
|
|
|
302
315
|
}
|
|
@@ -93,7 +93,7 @@ export class Importer {
|
|
|
93
93
|
ref?: string;
|
|
94
94
|
},
|
|
95
95
|
};
|
|
96
|
-
},
|
|
96
|
+
},
|
|
97
97
|
shared_formulae: SharedFormulaMap,
|
|
98
98
|
arrays: RangeType[],
|
|
99
99
|
merges: RangeType[],
|
|
@@ -117,11 +117,9 @@ export class Importer {
|
|
|
117
117
|
// console.info(element);
|
|
118
118
|
|
|
119
119
|
let value: undefined | number | boolean | string;
|
|
120
|
-
// let type: ValueType = ValueType.undefined;
|
|
121
120
|
let type: SerializedValueType = 'undefined';
|
|
122
121
|
|
|
123
122
|
let calculated_value: undefined | number | boolean | string;
|
|
124
|
-
// let calculated_type: ValueType = ValueType.undefined;
|
|
125
123
|
let calculated_type: SerializedValueType = 'undefined';
|
|
126
124
|
|
|
127
125
|
// QUESTIONS:
|
|
@@ -397,7 +395,6 @@ export class Importer {
|
|
|
397
395
|
if (rule.formula) {
|
|
398
396
|
|
|
399
397
|
if (typeof rule.formula !== 'string') {
|
|
400
|
-
console.info("conditional expression", {rule});
|
|
401
398
|
if (rule.formula.t$) {
|
|
402
399
|
|
|
403
400
|
// the only case (to date) we've seen here is that the attribute
|
|
@@ -407,6 +404,10 @@ export class Importer {
|
|
|
407
404
|
rule.formula = rule.formula.t$;
|
|
408
405
|
|
|
409
406
|
}
|
|
407
|
+
else {
|
|
408
|
+
console.info("unexpected conditional expression", {rule});
|
|
409
|
+
|
|
410
|
+
}
|
|
410
411
|
}
|
|
411
412
|
|
|
412
413
|
let style = {};
|
|
@@ -536,18 +537,6 @@ export class Importer {
|
|
|
536
537
|
}
|
|
537
538
|
}
|
|
538
539
|
|
|
539
|
-
/*
|
|
540
|
-
const area = sheet.TranslateAddress(element.a$.sqref);
|
|
541
|
-
if (element.cfRule) {
|
|
542
|
-
const rules = Array.isArray(element.cfRule) ? element.cfRule : [element.cfRule];
|
|
543
|
-
for (const rule of rules) {
|
|
544
|
-
const format = this.ParseConditionalFormat(area, rule);
|
|
545
|
-
if (format) {
|
|
546
|
-
conditional_formats.push(format);
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
*/
|
|
551
540
|
}
|
|
552
541
|
}
|
|
553
542
|
|
|
@@ -669,7 +669,7 @@ export class StyleCache {
|
|
|
669
669
|
|
|
670
670
|
// indent
|
|
671
671
|
|
|
672
|
-
props.indent = xf.indent;
|
|
672
|
+
props.indent = (typeof xf.indent === 'string') ? Number(xf.indent) : xf.indent;
|
|
673
673
|
|
|
674
674
|
// wrap
|
|
675
675
|
|
|
@@ -722,6 +722,19 @@ export class StyleCache {
|
|
|
722
722
|
|
|
723
723
|
/** map all cell xfs to styles; retain order */
|
|
724
724
|
public CellXfToStyles(): CellStyle[] {
|
|
725
|
+
|
|
726
|
+
/*
|
|
727
|
+
const mapped = this.cell_xfs.map((xf, index) => {
|
|
728
|
+
const style = this.CellXfToStyle(xf);
|
|
729
|
+
if (style.font_size?.value && style.font_size.value > 200) {
|
|
730
|
+
console.info({index, fs: JSON.stringify(style.font_size), style, xf});
|
|
731
|
+
console.info(this);
|
|
732
|
+
}
|
|
733
|
+
return style;
|
|
734
|
+
});
|
|
735
|
+
return mapped;
|
|
736
|
+
*/
|
|
737
|
+
|
|
725
738
|
return this.cell_xfs.map((xf) => this.CellXfToStyle(xf));
|
|
726
739
|
}
|
|
727
740
|
|
|
@@ -1174,40 +1187,14 @@ export class StyleCache {
|
|
|
1174
1187
|
|
|
1175
1188
|
|
|
1176
1189
|
this.borders = composite.map(element => {
|
|
1177
|
-
|
|
1178
1190
|
const border: BorderStyle = JSON.parse(JSON.stringify(default_border));
|
|
1179
1191
|
|
|
1180
|
-
/*
|
|
1181
|
-
// we're relying on these being empty strings -> falsy, not a good look
|
|
1182
|
-
|
|
1183
|
-
if (element.left) {
|
|
1184
|
-
// border.left.style = element.left.a$.style;
|
|
1185
|
-
// border.left.color = Number(element.left.color?.a$?.indexed);
|
|
1186
|
-
}
|
|
1187
|
-
|
|
1188
|
-
if (element.right) {
|
|
1189
|
-
// border.right.style = element.right.a$.style;
|
|
1190
|
-
// border.right.color = Number(element.right.color?.a$?.indexed);
|
|
1191
|
-
}
|
|
1192
|
-
|
|
1193
|
-
if (element.top) {
|
|
1194
|
-
// border.top.style = element.top.a$.style;
|
|
1195
|
-
// border.top.color = Number(element.top.color?.a$?.indexed);
|
|
1196
|
-
}
|
|
1197
|
-
|
|
1198
|
-
if (element.bottom) {
|
|
1199
|
-
// border.bottom.style = element.bottom.a$.style;
|
|
1200
|
-
// border.bottom.color = Number(element.bottom.color?.a$?.indexed);
|
|
1201
|
-
}
|
|
1202
|
-
*/
|
|
1203
|
-
|
|
1204
1192
|
ElementToBorderEdge(element.left, border.left);
|
|
1205
1193
|
ElementToBorderEdge(element.right, border.right);
|
|
1206
1194
|
ElementToBorderEdge(element.top, border.top);
|
|
1207
1195
|
ElementToBorderEdge(element.bottom, border.bottom);
|
|
1208
1196
|
|
|
1209
1197
|
return border;
|
|
1210
|
-
|
|
1211
1198
|
});
|
|
1212
1199
|
|
|
1213
1200
|
// ---
|
|
@@ -1313,6 +1300,7 @@ export class StyleCache {
|
|
|
1313
1300
|
if (element.color.a$?.rgb) {
|
|
1314
1301
|
font.color_argb = element.color.a$.rgb;
|
|
1315
1302
|
}
|
|
1303
|
+
|
|
1316
1304
|
}
|
|
1317
1305
|
|
|
1318
1306
|
return font;
|
|
@@ -744,12 +744,12 @@ export class TileRenderer {
|
|
|
744
744
|
// this is a single line, with number formatting
|
|
745
745
|
|
|
746
746
|
if (indent) {
|
|
747
|
-
if (style.horizontal_align === '
|
|
748
|
-
formatted.unshift({ text: indent });
|
|
749
|
-
}
|
|
750
|
-
else if (style.horizontal_align === 'right') {
|
|
747
|
+
if (style.horizontal_align === 'right') {
|
|
751
748
|
formatted.push({ text: indent });
|
|
752
749
|
}
|
|
750
|
+
else if (style.horizontal_align !== 'center') {
|
|
751
|
+
formatted.unshift({ text: indent });
|
|
752
|
+
}
|
|
753
753
|
}
|
|
754
754
|
|
|
755
755
|
for (const part of formatted) {
|
|
@@ -953,12 +953,13 @@ export class TileRenderer {
|
|
|
953
953
|
});
|
|
954
954
|
|
|
955
955
|
if (style.indent) {
|
|
956
|
-
if (style.horizontal_align === '
|
|
957
|
-
line_string.unshift({ text: indent, hidden: false, width: indent_width });
|
|
958
|
-
}
|
|
959
|
-
else if (style.horizontal_align === 'right') {
|
|
956
|
+
if (style.horizontal_align === 'right') {
|
|
960
957
|
line_string.push({ text: indent, hidden: false, width: indent_width });
|
|
961
958
|
}
|
|
959
|
+
else if (style.horizontal_align !== 'center') {
|
|
960
|
+
line_string.unshift({ text: indent, hidden: false, width: indent_width });
|
|
961
|
+
}
|
|
962
|
+
|
|
962
963
|
}
|
|
963
964
|
|
|
964
965
|
strings.push(line_string);
|
|
@@ -977,12 +978,13 @@ export class TileRenderer {
|
|
|
977
978
|
const parts: RenderTextPart[] = [];
|
|
978
979
|
|
|
979
980
|
if (style.indent) {
|
|
980
|
-
if (style.horizontal_align === '
|
|
981
|
-
line.unshift({ text: indent });
|
|
982
|
-
}
|
|
983
|
-
else if (style.horizontal_align === 'right') {
|
|
981
|
+
if (style.horizontal_align === 'right') {
|
|
984
982
|
line.push({ text: indent });
|
|
985
983
|
}
|
|
984
|
+
else if (style.horizontal_align !== 'center') {
|
|
985
|
+
line.unshift({ text: indent });
|
|
986
|
+
}
|
|
987
|
+
|
|
986
988
|
}
|
|
987
989
|
|
|
988
990
|
let line_width = 0;
|
|
@@ -978,7 +978,7 @@ export class Grid extends GridBase {
|
|
|
978
978
|
|
|
979
979
|
const validated = this.model.named_ranges.ValidateNamed(name);
|
|
980
980
|
if (!validated) {
|
|
981
|
-
console.warn(`invalid name: ${name}
|
|
981
|
+
console.warn(`invalid name: ${name}`, import_data.names[name]);
|
|
982
982
|
continue;
|
|
983
983
|
}
|
|
984
984
|
|