@trebco/treb 29.6.2 → 29.7.5
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 +10 -10
- package/dist/treb-spreadsheet.mjs +15 -15
- package/dist/treb.d.ts +93 -87
- package/package.json +1 -1
- package/treb-base-types/src/cells.ts +34 -0
- package/treb-base-types/src/evaluate-options.ts +22 -1
- package/treb-base-types/src/union.ts +0 -11
- package/treb-base-types/src/value-type.ts +3 -3
- package/treb-calculator/src/calculator.ts +34 -29
- package/treb-calculator/src/descriptors.ts +2 -0
- package/treb-calculator/src/expression-calculator.ts +31 -173
- package/treb-calculator/src/function-error.ts +16 -21
- package/treb-charts/src/util.ts +3 -36
- package/treb-data-model/src/sheet.ts +7 -3
- package/treb-embed/src/embedded-spreadsheet.ts +128 -267
- package/treb-export/src/xml-utils.ts +20 -8
- package/treb-grid/src/index.ts +1 -0
- package/treb-grid/src/types/clipboard_data2.ts +85 -0
- package/treb-grid/src/types/grid.ts +226 -6
- package/treb-parser/src/parser-types.ts +3 -0
- package/treb-parser/src/parser.ts +86 -2
|
@@ -58,6 +58,7 @@ type ExpressionWithCachedFunction<T extends ExpressionUnit> = T extends { type:
|
|
|
58
58
|
export type ExtendedExpressionUnit = ExpressionWithCachedFunction<ExpressionUnit>;
|
|
59
59
|
|
|
60
60
|
// FIXME: move
|
|
61
|
+
// FIXME: this is sloppy
|
|
61
62
|
export const UnionIsExpressionUnit = (test: UnionValue /*UnionOrArray*/): test is { type: ValueType.object, value: ExpressionUnit } => {
|
|
62
63
|
return !Array.isArray(test)
|
|
63
64
|
&& test.type === ValueType.object
|
|
@@ -65,15 +66,9 @@ export const UnionIsExpressionUnit = (test: UnionValue /*UnionOrArray*/): test i
|
|
|
65
66
|
};
|
|
66
67
|
|
|
67
68
|
// FIXME: move
|
|
69
|
+
// FIXME: this is sloppy
|
|
68
70
|
export const UnionIsMetadata = (test: UnionValue /*UnionOrArray*/): test is { type: ValueType.object, value: ReferenceMetadata } => {
|
|
69
|
-
|
|
70
71
|
return test.type === ValueType.object && test.key === 'metadata';
|
|
71
|
-
|
|
72
|
-
/*
|
|
73
|
-
return !Array.isArray(test)
|
|
74
|
-
&& test.type === ValueType.object
|
|
75
|
-
&& ((test.value as ReferenceMetadata).type === 'metadata');
|
|
76
|
-
*/
|
|
77
72
|
};
|
|
78
73
|
|
|
79
74
|
// FIXME: move
|
|
@@ -89,7 +84,6 @@ export interface ReferenceMetadata {
|
|
|
89
84
|
|
|
90
85
|
export interface CalculationContext {
|
|
91
86
|
address: ICellAddress;
|
|
92
|
-
// model?: DataModel;
|
|
93
87
|
volatile: boolean;
|
|
94
88
|
}
|
|
95
89
|
|
|
@@ -100,10 +94,6 @@ export class ExpressionCalculator {
|
|
|
100
94
|
volatile: false,
|
|
101
95
|
};
|
|
102
96
|
|
|
103
|
-
//
|
|
104
|
-
// protected data_model!: DataModel; // can we set in ctor? I think this is a legacy hack
|
|
105
|
-
|
|
106
|
-
|
|
107
97
|
// --- public API -----------------------------------------------------------
|
|
108
98
|
|
|
109
99
|
constructor(
|
|
@@ -111,18 +101,6 @@ export class ExpressionCalculator {
|
|
|
111
101
|
protected readonly library: FunctionLibrary,
|
|
112
102
|
protected readonly parser: Parser) {}
|
|
113
103
|
|
|
114
|
-
/*
|
|
115
|
-
public SetModel(model: DataModel): void {
|
|
116
|
-
|
|
117
|
-
// is this kept around for some side-effects or something? does
|
|
118
|
-
// the model ever change?
|
|
119
|
-
|
|
120
|
-
this.data_model = model;
|
|
121
|
-
this.context.model = model;
|
|
122
|
-
|
|
123
|
-
}
|
|
124
|
-
*/
|
|
125
|
-
|
|
126
104
|
/**
|
|
127
105
|
* there's a case where we are calling this from within a function
|
|
128
106
|
* (which is weird, but hey) and to do that we need to preserve flags.
|
|
@@ -131,10 +109,8 @@ export class ExpressionCalculator {
|
|
|
131
109
|
value: UnionValue /*UnionOrArray*/, volatile: boolean }{
|
|
132
110
|
|
|
133
111
|
if (!preserve_flags) {
|
|
134
|
-
|
|
135
112
|
this.context.address = addr;
|
|
136
113
|
this.context.volatile = false;
|
|
137
|
-
|
|
138
114
|
}
|
|
139
115
|
|
|
140
116
|
return {
|
|
@@ -154,8 +130,6 @@ export class ExpressionCalculator {
|
|
|
154
130
|
if (!expr.sheet_id) {
|
|
155
131
|
if (expr.sheet) {
|
|
156
132
|
expr.sheet_id = this.data_model.sheets.ID(expr.sheet) || 0;
|
|
157
|
-
|
|
158
|
-
// expr.sheet_id = this.sheet_name_map[expr.sheet.toLowerCase()];
|
|
159
133
|
}
|
|
160
134
|
else {
|
|
161
135
|
return () => ReferenceError();
|
|
@@ -178,7 +152,6 @@ export class ExpressionCalculator {
|
|
|
178
152
|
|
|
179
153
|
if (!cell) {
|
|
180
154
|
return () => {
|
|
181
|
-
// return { type: ValueType.undefined, value: undefined }
|
|
182
155
|
return { type: ValueType.number, value: 0 };
|
|
183
156
|
};
|
|
184
157
|
}
|
|
@@ -199,9 +172,7 @@ export class ExpressionCalculator {
|
|
|
199
172
|
// throw new Error('missing sheet id in CellFunction4');
|
|
200
173
|
}
|
|
201
174
|
|
|
202
|
-
//const cells = this.cells_map[start.sheet_id];
|
|
203
175
|
const cells = this.data_model.sheets.Find(start.sheet_id)?.cells;
|
|
204
|
-
|
|
205
176
|
return cells?.GetRange4(start, end, true) || ReferenceError();
|
|
206
177
|
|
|
207
178
|
}
|
|
@@ -241,7 +212,6 @@ export class ExpressionCalculator {
|
|
|
241
212
|
|
|
242
213
|
case 'identifier':
|
|
243
214
|
{
|
|
244
|
-
// const named_range = this.named_range_map[arg.name.toUpperCase()];
|
|
245
215
|
const named_range = this.data_model.GetName(arg.name, this.context.address.sheet_id || 0);
|
|
246
216
|
if (named_range?.type === 'range') {
|
|
247
217
|
if (named_range.area.count === 1) {
|
|
@@ -290,29 +260,18 @@ export class ExpressionCalculator {
|
|
|
290
260
|
|
|
291
261
|
// don't we have a map? [...] only for names?
|
|
292
262
|
|
|
293
|
-
let sheet: Sheet|undefined;
|
|
294
|
-
if (address.sheet_id) {
|
|
263
|
+
let sheet: Sheet|undefined;
|
|
264
|
+
if (address.sheet_id) {
|
|
295
265
|
sheet = this.data_model.sheets.Find(address.sheet_id);
|
|
296
|
-
|
|
297
|
-
/*
|
|
298
|
-
for (const test of this.data_model.sheets) {
|
|
299
|
-
if (test.id === address.sheet_id) {
|
|
300
|
-
sheet = test;
|
|
301
|
-
break;
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
*/
|
|
305
266
|
}
|
|
306
267
|
|
|
307
268
|
if (!sheet) {
|
|
308
|
-
// throw new Error('missing sheet [ac8]');
|
|
309
269
|
console.error('missing sheet [ac8]');
|
|
310
270
|
return ReferenceError();
|
|
311
271
|
}
|
|
312
272
|
|
|
313
273
|
const cell_data = sheet.CellData(address);
|
|
314
|
-
const value =
|
|
315
|
-
cell_data.calculated_type ? cell_data.calculated : cell_data.value;
|
|
274
|
+
const value = cell_data.calculated_type ? cell_data.calculated : cell_data.value;
|
|
316
275
|
|
|
317
276
|
const metadata: ReferenceMetadata = {
|
|
318
277
|
type: 'metadata',
|
|
@@ -345,22 +304,12 @@ export class ExpressionCalculator {
|
|
|
345
304
|
return ReferenceError();
|
|
346
305
|
}
|
|
347
306
|
|
|
348
|
-
let sheet: Sheet|undefined;
|
|
349
|
-
if (range.start.sheet_id) {
|
|
307
|
+
let sheet: Sheet|undefined;
|
|
308
|
+
if (range.start.sheet_id) {
|
|
350
309
|
sheet = this.data_model.sheets.Find(range.start.sheet_id);
|
|
351
|
-
/*
|
|
352
|
-
for (const test of this.data_model.sheets) {
|
|
353
|
-
if (test.id === range.start.sheet_id) {
|
|
354
|
-
sheet = test;
|
|
355
|
-
break;
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
*/
|
|
359
310
|
}
|
|
360
311
|
|
|
361
312
|
if (!sheet) {
|
|
362
|
-
// console.info({range, context: JSON.stringify(this.context.address)});
|
|
363
|
-
// console.info({arg});
|
|
364
313
|
throw new Error('missing sheet [ac9]');
|
|
365
314
|
}
|
|
366
315
|
|
|
@@ -372,8 +321,7 @@ export class ExpressionCalculator {
|
|
|
372
321
|
const cell_data = sheet.CellData({row, column});
|
|
373
322
|
address = {...range.start, row, column};
|
|
374
323
|
|
|
375
|
-
const value =
|
|
376
|
-
cell_data.calculated_type ? cell_data.calculated : cell_data.value;
|
|
324
|
+
const value = cell_data.calculated_type ? cell_data.calculated : cell_data.value;
|
|
377
325
|
|
|
378
326
|
const metadata = {
|
|
379
327
|
type: 'metadata',
|
|
@@ -464,35 +412,7 @@ export class ExpressionCalculator {
|
|
|
464
412
|
}
|
|
465
413
|
|
|
466
414
|
/**
|
|
467
|
-
*
|
|
468
|
-
*
|
|
469
|
-
* the return type of functions has never been locked down, and as a result
|
|
470
|
-
* there are a couple of things we need to handle.
|
|
471
|
-
*
|
|
472
|
-
* return type can be any value, essentially, or array, error object, or
|
|
473
|
-
* (in the case of some of the reference/lookup functions) an address or
|
|
474
|
-
* range expression. array must be 2d, I think? not sure that that is true.
|
|
475
|
-
*
|
|
476
|
-
* this wrapper function returns a function which returns one of those
|
|
477
|
-
* things, i.e. it returns (expr) => return type
|
|
478
|
-
*
|
|
479
|
-
* it will only return address/range if the parameter flag is set, so we
|
|
480
|
-
* could in theory lock it down a bit with overloads.
|
|
481
|
-
*
|
|
482
|
-
* ---
|
|
483
|
-
*
|
|
484
|
-
* UPDATE: that's no longer the case. we require that functions return
|
|
485
|
-
* a UnionValue type (union), which can itself contain an array.
|
|
486
|
-
*
|
|
487
|
-
* ---
|
|
488
|
-
*
|
|
489
|
-
* FIXME: there is far too much duplication between this and the MC version
|
|
490
|
-
* (in simulation-expression-calculator). we need to find a way to consolidate
|
|
491
|
-
* these.
|
|
492
|
-
*
|
|
493
|
-
* I think the problem is that we don't want a lot of switches, but the cost
|
|
494
|
-
* is an almost complete duplicate of this function in the subclass.
|
|
495
|
-
*
|
|
415
|
+
* excute a function call
|
|
496
416
|
*/
|
|
497
417
|
protected CallExpression(outer: UnitCall, return_reference = false): (expr: UnitCall) => UnionValue /*UnionOrArray*/ {
|
|
498
418
|
|
|
@@ -513,45 +433,18 @@ export class ExpressionCalculator {
|
|
|
513
433
|
|
|
514
434
|
return (expr: UnitCall) => {
|
|
515
435
|
|
|
516
|
-
//
|
|
517
|
-
|
|
518
|
-
//
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
// BEFORE YOU DO THAT, track down all references that read this field
|
|
522
|
-
|
|
523
|
-
// from what I can tell, the only place this is read is after the
|
|
524
|
-
// external (outer) Calculate() call. so we should move this assignment,
|
|
525
|
-
// and we should also be able to get it to fail:
|
|
526
|
-
//
|
|
527
|
-
// RandBetween() should be volatile, but if we have a nonvolatile function
|
|
528
|
-
// as an argument that should unset it, and remove the volatile flag.
|
|
529
|
-
// Check?
|
|
530
|
-
|
|
531
|
-
// actually this works, because it only sets the flag (does not unset).
|
|
532
|
-
// volatile applies to the _cell_, not just the function -- so as long
|
|
533
|
-
// as the outer function sets the flag, it's not material if an inner
|
|
534
|
-
// function is nonvolatile. similarly an inner volatile function will
|
|
535
|
-
// make the outer function volatile.
|
|
536
|
-
|
|
537
|
-
// this does mean that the nonvolatile function will be treated differently
|
|
538
|
-
// if it's an argument to a volatile function, but I think that's reasonable
|
|
539
|
-
// behavior; also it's symmetric with the opposite case (inner volatile.)
|
|
540
|
-
|
|
541
|
-
// so leave this as-is, or you can move it -- should be immaterial
|
|
542
|
-
|
|
436
|
+
// set context volatile if this function is volatile. it will bubble
|
|
437
|
+
// through nested function calls, so the entire cell will be volatile
|
|
438
|
+
// if there's a volatile function in there somewhere
|
|
439
|
+
|
|
543
440
|
this.context.volatile = this.context.volatile || (!!func.volatile);
|
|
544
441
|
|
|
545
|
-
//
|
|
546
|
-
//
|
|
547
|
-
//
|
|
548
|
-
|
|
549
|
-
// ok we can handle IF functions, at the expense of some tests...
|
|
550
|
-
// is it worth it?
|
|
551
|
-
|
|
442
|
+
// we recurse calculation, but in the specific case of IF functions
|
|
443
|
+
// we can short-circuit and skip the unused code path. doesn't apply
|
|
444
|
+
// anywhere else atm
|
|
445
|
+
|
|
552
446
|
const if_function = outer.name.toLowerCase() === 'if';
|
|
553
447
|
let skip_argument_index = -1;
|
|
554
|
-
|
|
555
448
|
let argument_error: UnionValue|undefined;
|
|
556
449
|
|
|
557
450
|
const argument_descriptors = func.arguments || []; // map
|
|
@@ -593,16 +486,12 @@ export class ExpressionCalculator {
|
|
|
593
486
|
} : this.parser.Render(arg).replace(/\$/g, '');
|
|
594
487
|
}
|
|
595
488
|
else if (descriptor.metadata) {
|
|
596
|
-
|
|
597
489
|
return this.GetMetadata(arg, () => { return {}}); // type is UnionOrArray
|
|
598
|
-
|
|
599
490
|
}
|
|
600
491
|
else {
|
|
601
492
|
|
|
602
493
|
const result = this.CalculateExpression(arg as ExtendedExpressionUnit);
|
|
603
494
|
|
|
604
|
-
// if (!Array.isArray(result) && result.type === ValueType.error) {
|
|
605
|
-
|
|
606
495
|
if (result.type === ValueType.error) { // array check is implicit since array is a type
|
|
607
496
|
if (descriptor.allow_error) {
|
|
608
497
|
return result; // always boxed
|
|
@@ -613,11 +502,9 @@ export class ExpressionCalculator {
|
|
|
613
502
|
|
|
614
503
|
// can't shortcut if you have an array (or we need to test all the values)
|
|
615
504
|
|
|
616
|
-
|
|
617
|
-
if (if_function && arg_index === 0 && result.type !== ValueType.array){ // !Array.isArray(result)) {
|
|
618
|
-
let result_truthy = false;
|
|
505
|
+
if (if_function && arg_index === 0 && result.type !== ValueType.array){
|
|
619
506
|
|
|
620
|
-
|
|
507
|
+
let result_truthy = false;
|
|
621
508
|
|
|
622
509
|
if (result.type === ValueType.string) {
|
|
623
510
|
const lowercase = (result.value as string).toLowerCase().trim();
|
|
@@ -626,6 +513,7 @@ export class ExpressionCalculator {
|
|
|
626
513
|
else {
|
|
627
514
|
result_truthy = !!result.value;
|
|
628
515
|
}
|
|
516
|
+
|
|
629
517
|
skip_argument_index = result_truthy ? 2 : 1;
|
|
630
518
|
}
|
|
631
519
|
|
|
@@ -633,11 +521,6 @@ export class ExpressionCalculator {
|
|
|
633
521
|
return result;
|
|
634
522
|
}
|
|
635
523
|
|
|
636
|
-
/*
|
|
637
|
-
if (Array.isArray(result)) {
|
|
638
|
-
return result.map(row => row.map(value => value.value));
|
|
639
|
-
}
|
|
640
|
-
*/
|
|
641
524
|
if (result.type === ValueType.array) {
|
|
642
525
|
return (result as ArrayUnion).value.map(row => row.map(value => value.value));
|
|
643
526
|
}
|
|
@@ -653,12 +536,6 @@ export class ExpressionCalculator {
|
|
|
653
536
|
return argument_error;
|
|
654
537
|
}
|
|
655
538
|
|
|
656
|
-
// I thought we were passing the model as this (...) ? actually
|
|
657
|
-
// now we bind functions that need this, so maybe we should pass
|
|
658
|
-
// null here.
|
|
659
|
-
|
|
660
|
-
// return func.fn.apply(null, mapped_args);
|
|
661
|
-
|
|
662
539
|
if (func.return_type === ReturnType.reference) {
|
|
663
540
|
|
|
664
541
|
const result = func.fn.apply(null, mapped_args);
|
|
@@ -757,11 +634,6 @@ export class ExpressionCalculator {
|
|
|
757
634
|
value: (operand as ArrayUnion).value.map(column => column.map(value => func(zero, value))),
|
|
758
635
|
};
|
|
759
636
|
}
|
|
760
|
-
/*
|
|
761
|
-
if (Array.isArray(operand)) {
|
|
762
|
-
return operand.map(column => column.map(value => func(zero, value)));
|
|
763
|
-
}
|
|
764
|
-
*/
|
|
765
637
|
return func(zero, operand);
|
|
766
638
|
};
|
|
767
639
|
|
|
@@ -929,31 +801,17 @@ export class ExpressionCalculator {
|
|
|
929
801
|
|
|
930
802
|
return () => {
|
|
931
803
|
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
const named_range = this.data_model.GetName(upper_case, this.context.address.sheet_id || 0);
|
|
944
|
-
|
|
945
|
-
if (named_range?.type === 'range') {
|
|
946
|
-
if (named_range.area.count === 1) {
|
|
947
|
-
return this.CellFunction4(named_range.area.start, named_range.area.start);
|
|
948
|
-
}
|
|
949
|
-
else {
|
|
950
|
-
return this.CellFunction4(named_range.area.start, named_range.area.end);
|
|
951
|
-
}
|
|
952
|
-
}
|
|
953
|
-
|
|
954
|
-
const named2 = this.data_model.GetName(identifier, this.context.address.sheet_id || 0);
|
|
955
|
-
if (named2 && named2.type === 'expression') {
|
|
956
|
-
return this.CalculateExpression(named2.expression as ExtendedExpressionUnit);
|
|
804
|
+
const named = this.data_model.GetName(upper_case, this.context.address.sheet_id || 0);
|
|
805
|
+
|
|
806
|
+
switch (named?.type) {
|
|
807
|
+
case 'range':
|
|
808
|
+
if (named.area.count === 1) {
|
|
809
|
+
return this.CellFunction4(named.area.start, named.area.start);
|
|
810
|
+
}
|
|
811
|
+
return this.CellFunction4(named.area.start, named.area.end);
|
|
812
|
+
|
|
813
|
+
case 'expression':
|
|
814
|
+
return this.CalculateExpression(named.expression as ExtendedExpressionUnit);
|
|
957
815
|
}
|
|
958
816
|
|
|
959
817
|
// console.info( '** identifier', {identifier, expr, context: this.context});
|
|
@@ -40,14 +40,6 @@ export interface FunctionError {
|
|
|
40
40
|
error: ErrorType;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
// export const ArgumentError: FunctionError = { error: ErrorType.Argument };
|
|
44
|
-
// export const ReferenceError: FunctionError = { error: ErrorType.Reference };
|
|
45
|
-
//export const ExpressionError: FunctionError = { error: ErrorType.Expression };
|
|
46
|
-
// export const NameError: FunctionError = { error: ErrorType.Name };
|
|
47
|
-
// export const ValueError: FunctionError = { error: ErrorType.Value };
|
|
48
|
-
// export const DataError: FunctionError = { error: ErrorType.Data };
|
|
49
|
-
// export const DivideByZeroError: FunctionError = { error: ErrorType.Div0 };
|
|
50
|
-
// export const UnknownError: FunctionError = { error: ErrorType.Unknown };
|
|
51
43
|
export const NotImplError: FunctionError = { error: ErrorType.NotImpl };
|
|
52
44
|
|
|
53
45
|
export const NAError = (): UnionValue => {
|
|
@@ -87,18 +79,21 @@ export const UnknownError = (): UnionValue => {
|
|
|
87
79
|
};
|
|
88
80
|
|
|
89
81
|
|
|
90
|
-
/**
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
test.error === ErrorType.
|
|
98
|
-
test.error === ErrorType.
|
|
99
|
-
test.error === ErrorType.
|
|
100
|
-
test.error === ErrorType.
|
|
101
|
-
test.error === ErrorType.
|
|
102
|
-
test.error === ErrorType.
|
|
82
|
+
/**
|
|
83
|
+
* type guard function
|
|
84
|
+
*
|
|
85
|
+
* ...this is maybe too precise?
|
|
86
|
+
*/
|
|
87
|
+
export const IsError = (test: unknown): test is FunctionError => {
|
|
88
|
+
return !!test && typeof test === 'object' && !!(test as FunctionError).error && (
|
|
89
|
+
(test as FunctionError).error === ErrorType.Argument ||
|
|
90
|
+
(test as FunctionError).error === ErrorType.Reference ||
|
|
91
|
+
(test as FunctionError).error === ErrorType.Name ||
|
|
92
|
+
(test as FunctionError).error === ErrorType.Expression ||
|
|
93
|
+
(test as FunctionError).error === ErrorType.Data ||
|
|
94
|
+
(test as FunctionError).error === ErrorType.Unknown ||
|
|
95
|
+
(test as FunctionError).error === ErrorType.NotImpl ||
|
|
96
|
+
(test as FunctionError).error === ErrorType.Value ||
|
|
97
|
+
(test as FunctionError).error === ErrorType.Div0
|
|
103
98
|
);
|
|
104
99
|
};
|
package/treb-charts/src/util.ts
CHANGED
|
@@ -23,16 +23,6 @@
|
|
|
23
23
|
import type { RangeScale} from 'treb-utils';
|
|
24
24
|
import { Scale } from 'treb-utils';
|
|
25
25
|
|
|
26
|
-
/* * calculated human-friendly scale for rendering axes * /
|
|
27
|
-
export interface RangeScale {
|
|
28
|
-
scale: number;
|
|
29
|
-
step: number;
|
|
30
|
-
count: number;
|
|
31
|
-
min: number;
|
|
32
|
-
max: number;
|
|
33
|
-
}
|
|
34
|
-
*/
|
|
35
|
-
|
|
36
26
|
export class Util {
|
|
37
27
|
|
|
38
28
|
/**
|
|
@@ -63,32 +53,9 @@ export class Util {
|
|
|
63
53
|
return range * (value - scale.min) / (scale.max - scale.min);
|
|
64
54
|
}
|
|
65
55
|
|
|
66
|
-
|
|
67
|
-
*
|
|
68
|
-
|
|
69
|
-
* that makes sense).
|
|
70
|
-
*
|
|
71
|
-
* @deprecated
|
|
72
|
-
* /
|
|
73
|
-
public static Flatten(args: any) {
|
|
74
|
-
let flat: any[] = [];
|
|
75
|
-
if (Array.isArray(args)) {
|
|
76
|
-
for (const element of args) {
|
|
77
|
-
if (Array.isArray(element)) {
|
|
78
|
-
flat = flat.concat(this.Flatten(element));
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
flat.push(element);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
else if (typeof args !== 'undefined') {
|
|
86
|
-
flat.push(args);
|
|
87
|
-
}
|
|
88
|
-
return flat;
|
|
89
|
-
}
|
|
90
|
-
*/
|
|
91
|
-
|
|
56
|
+
/**
|
|
57
|
+
* can we replace this with Array.flatMap?
|
|
58
|
+
*/
|
|
92
59
|
public static Flatten<T>(args?: T|T[]|T[][]) {
|
|
93
60
|
let flat: T[] = [];
|
|
94
61
|
if (Array.isArray(args)) {
|
|
@@ -2225,8 +2225,14 @@ export class Sheet {
|
|
|
2225
2225
|
return this.CompositeStyleForCell(area, true, false, apply_theme);
|
|
2226
2226
|
}
|
|
2227
2227
|
|
|
2228
|
+
// the contract says this should return an array, not a single value.
|
|
2229
|
+
//
|
|
2230
|
+
// I can fix it, but will anyone break? (...) check the indent buttons
|
|
2231
|
+
// (update: looks OK)
|
|
2232
|
+
//
|
|
2233
|
+
|
|
2228
2234
|
if (area.start.row === area.end.row && area.start.column === area.end.column) {
|
|
2229
|
-
return this.CompositeStyleForCell(area.start, true, false, apply_theme);
|
|
2235
|
+
return [[this.CompositeStyleForCell(area.start, true, false, apply_theme)]];
|
|
2230
2236
|
}
|
|
2231
2237
|
|
|
2232
2238
|
const result: CellStyle[][] = [];
|
|
@@ -2234,8 +2240,6 @@ export class Sheet {
|
|
|
2234
2240
|
for (let r = area.start.row; r <= area.end.row; r++) {
|
|
2235
2241
|
const row: CellStyle[] = [];
|
|
2236
2242
|
for (let c = area.start.column; c <= area.end.column; c++) {
|
|
2237
|
-
// const cell = this.CellData({row: r, column: c});
|
|
2238
|
-
// row.push(cell.style || {});
|
|
2239
2243
|
row.push(this.CompositeStyleForCell({row: r, column: c}, true, false, apply_theme));
|
|
2240
2244
|
}
|
|
2241
2245
|
result.push(row);
|