@trebco/treb 29.3.4 → 29.4.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 +11 -11
- package/dist/treb-spreadsheet.mjs +11 -11
- package/dist/treb.d.ts +3 -25
- package/package.json +1 -1
- package/treb-base-types/src/area.ts +7 -0
- package/treb-base-types/src/cell.ts +2 -46
- package/treb-base-types/src/cells.ts +14 -8
- package/treb-base-types/src/import.ts +2 -2
- package/treb-calculator/src/calculator.ts +22 -12
- package/treb-calculator/src/dag/graph.ts +12 -3
- package/treb-calculator/src/expression-calculator.ts +66 -74
- package/treb-calculator/src/functions/base-functions.ts +2 -2
- package/treb-calculator/src/functions/statistics-functions.ts +31 -1
- package/treb-data-model/src/data-validation.ts +44 -0
- package/treb-data-model/src/data_model.ts +11 -7
- package/treb-data-model/src/index.ts +1 -1
- package/treb-data-model/src/named.ts +35 -10
- package/treb-data-model/src/sheet.ts +61 -0
- package/treb-data-model/src/sheet_types.ts +4 -0
- package/treb-embed/src/embedded-spreadsheet.ts +21 -15
- package/treb-embed/src/progress-dialog.ts +4 -1
- package/treb-export/src/export2.ts +27 -14
- package/treb-export/src/import2.ts +58 -12
- package/treb-grid/src/layout/base_layout.ts +2 -11
- package/treb-grid/src/types/grid.ts +29 -18
- package/treb-grid/src/types/grid_base.ts +83 -16
- package/treb-grid/src/types/grid_command.ts +2 -1
- package/treb-parser/src/parser.ts +22 -4
package/dist/treb.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! API v29.
|
|
1
|
+
/*! API v29.4. Copyright 2018-2024 trebco, llc. All rights reserved. LGPL: https://treb.app/license */
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* add our tag to the map
|
|
@@ -743,13 +743,13 @@ export declare class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
|
|
|
743
743
|
/**
|
|
744
744
|
* set or clear cell valiation.
|
|
745
745
|
*
|
|
746
|
-
* @param
|
|
746
|
+
* @param target - target cell/area
|
|
747
747
|
* @param validation - a spreadsheet range, list of data, or undefined. pass
|
|
748
748
|
* undefined to remove existing cell validation.
|
|
749
749
|
* @param error - setting an invalid value in the target cell is an error (and
|
|
750
750
|
* is blocked). defaults to false.
|
|
751
751
|
*/
|
|
752
|
-
SetValidation(
|
|
752
|
+
SetValidation(target: RangeReference, validation?: RangeReference | CellValue[], error?: boolean): void;
|
|
753
753
|
|
|
754
754
|
/**
|
|
755
755
|
* Delete a macro function.
|
|
@@ -1727,7 +1727,6 @@ export interface BaseCellData {
|
|
|
1727
1727
|
table?: Table;
|
|
1728
1728
|
area?: IArea;
|
|
1729
1729
|
merge_area?: IArea;
|
|
1730
|
-
validation?: DataValidation;
|
|
1731
1730
|
calculated_type?: SerializedValueType;
|
|
1732
1731
|
note?: string;
|
|
1733
1732
|
hyperlink?: string;
|
|
@@ -1817,27 +1816,6 @@ export interface Table {
|
|
|
1817
1816
|
*/
|
|
1818
1817
|
sort?: TableSortOptions;
|
|
1819
1818
|
}
|
|
1820
|
-
export type DataValidation = DataValidationList | DataValidationRange | DataValidationNumber | DataValidationDate | DataValidationBoolean;
|
|
1821
|
-
export interface DataValidationBase {
|
|
1822
|
-
error?: boolean;
|
|
1823
|
-
}
|
|
1824
|
-
export interface DataValidationRange extends DataValidationBase {
|
|
1825
|
-
type: 'range';
|
|
1826
|
-
area: IArea;
|
|
1827
|
-
}
|
|
1828
|
-
export interface DataValidationList extends DataValidationBase {
|
|
1829
|
-
type: 'list';
|
|
1830
|
-
list: CellValue[];
|
|
1831
|
-
}
|
|
1832
|
-
export interface DataValidationDate extends DataValidationBase {
|
|
1833
|
-
type: 'date';
|
|
1834
|
-
}
|
|
1835
|
-
export interface DataValidationNumber extends DataValidationBase {
|
|
1836
|
-
type: 'number';
|
|
1837
|
-
}
|
|
1838
|
-
export interface DataValidationBoolean extends DataValidationBase {
|
|
1839
|
-
type: 'boolean';
|
|
1840
|
-
}
|
|
1841
1819
|
|
|
1842
1820
|
/**
|
|
1843
1821
|
* string types for import/export
|
package/package.json
CHANGED
|
@@ -584,6 +584,13 @@ export class Area implements IArea {
|
|
|
584
584
|
&& area.end_.column === this.end_.column;
|
|
585
585
|
}
|
|
586
586
|
|
|
587
|
+
public Equals2(area: IArea): boolean {
|
|
588
|
+
return area.start.row === this.start_.row
|
|
589
|
+
&& area.start.column === this.start_.column
|
|
590
|
+
&& area.end.row === this.end_.row
|
|
591
|
+
&& area.end.column === this.end_.column;
|
|
592
|
+
}
|
|
593
|
+
|
|
587
594
|
public Clone(): Area {
|
|
588
595
|
return new Area(this.start, this.end); // ensure copies
|
|
589
596
|
}
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
|
|
22
22
|
// import { Parser } from 'treb-parser';
|
|
23
23
|
|
|
24
|
-
import type { Area
|
|
24
|
+
import type { Area } from './area';
|
|
25
25
|
import type { CellStyle } from './style';
|
|
26
26
|
import type { TextPart } from './text_part';
|
|
27
27
|
import type { Complex } from './value-type';
|
|
@@ -117,50 +117,6 @@ export type ClickFunction = (options: ClickFunctionOptions) => ClickFunctionResu
|
|
|
117
117
|
* - raw per-cell style information. this is in a separate array (object).
|
|
118
118
|
*/
|
|
119
119
|
|
|
120
|
-
/**
|
|
121
|
-
* validation TODO: date, number, boolean, &c
|
|
122
|
-
*/
|
|
123
|
-
export enum ValidationType {
|
|
124
|
-
List = 'list',
|
|
125
|
-
Date = 'date',
|
|
126
|
-
Range = 'range',
|
|
127
|
-
Number = 'number',
|
|
128
|
-
Boolean = 'boolean',
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
export interface DataValidationBase {
|
|
132
|
-
error?: boolean;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
export interface DataValidationRange extends DataValidationBase {
|
|
136
|
-
type: 'range'; // ValidationType.Range;
|
|
137
|
-
area: IArea;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
export interface DataValidationList extends DataValidationBase {
|
|
141
|
-
type: 'list'; // ValidationType.List;
|
|
142
|
-
list: CellValue[];
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
export interface DataValidationDate extends DataValidationBase {
|
|
146
|
-
type: 'date'; // ValidationType.Date;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
export interface DataValidationNumber extends DataValidationBase {
|
|
150
|
-
type: 'number'; // ValidationType.Number;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
export interface DataValidationBoolean extends DataValidationBase {
|
|
154
|
-
type: 'boolean'; // ValidationType.Boolean;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
export type DataValidation
|
|
158
|
-
= DataValidationList
|
|
159
|
-
| DataValidationRange
|
|
160
|
-
| DataValidationNumber
|
|
161
|
-
| DataValidationDate
|
|
162
|
-
| DataValidationBoolean;
|
|
163
|
-
|
|
164
120
|
export class Cell {
|
|
165
121
|
|
|
166
122
|
// --- static methods -------------------------------------------------------
|
|
@@ -342,7 +298,7 @@ export class Cell {
|
|
|
342
298
|
/** not editable */
|
|
343
299
|
// public locked?: boolean;
|
|
344
300
|
|
|
345
|
-
public validation?: DataValidation;
|
|
301
|
+
// public validation?: DataValidation;
|
|
346
302
|
|
|
347
303
|
// --- class methods --------------------------------------------------------
|
|
348
304
|
|
|
@@ -26,7 +26,9 @@
|
|
|
26
26
|
|
|
27
27
|
import type { IArea, ICellAddress} from './area';
|
|
28
28
|
import { Area, IsCellAddress } from './area';
|
|
29
|
-
|
|
29
|
+
|
|
30
|
+
// import type { DataValidation } from './cell';
|
|
31
|
+
|
|
30
32
|
import { Cell } from './cell';
|
|
31
33
|
import type { Table } from './table';
|
|
32
34
|
import { type SerializedValueType, ValueType, GetValueType, ValueTypeList } from './value-type';
|
|
@@ -79,7 +81,7 @@ export interface BaseCellData {
|
|
|
79
81
|
table?: Table;
|
|
80
82
|
area?: IArea;
|
|
81
83
|
merge_area?: IArea;
|
|
82
|
-
validation?: DataValidation;
|
|
84
|
+
// validation?: DataValidation;
|
|
83
85
|
calculated_type?: SerializedValueType; // ValueType;
|
|
84
86
|
note?: string;
|
|
85
87
|
hyperlink?: string;
|
|
@@ -404,7 +406,7 @@ export class Cells {
|
|
|
404
406
|
|
|
405
407
|
|
|
406
408
|
|
|
407
|
-
|
|
409
|
+
/* *
|
|
408
410
|
* this method is used for importing legacy data validation types. in those
|
|
409
411
|
* those we used a numeric enum. we're just dropping that altogether (c.f.
|
|
410
412
|
* ValueType, which we're keeping) so we need to translate for backcompat.
|
|
@@ -419,7 +421,8 @@ export class Cells {
|
|
|
419
421
|
* Boolean = 'boolean',
|
|
420
422
|
* }
|
|
421
423
|
*
|
|
422
|
-
|
|
424
|
+
* OK, removed
|
|
425
|
+
* /
|
|
423
426
|
public ImportDataValidation(value: DataValidation): DataValidation|undefined {
|
|
424
427
|
|
|
425
428
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -435,6 +438,7 @@ export class Cells {
|
|
|
435
438
|
|
|
436
439
|
return value;
|
|
437
440
|
}
|
|
441
|
+
*/
|
|
438
442
|
|
|
439
443
|
/**
|
|
440
444
|
* UPDATE: adding optional style refs, for export
|
|
@@ -572,6 +576,7 @@ export class Cells {
|
|
|
572
576
|
}
|
|
573
577
|
}
|
|
574
578
|
|
|
579
|
+
/*
|
|
575
580
|
if (obj.validation) {
|
|
576
581
|
|
|
577
582
|
// the old type used a numeric enum. we just dropped that in favor
|
|
@@ -581,6 +586,7 @@ export class Cells {
|
|
|
581
586
|
cell.validation = this.ImportDataValidation(obj.validation);
|
|
582
587
|
|
|
583
588
|
}
|
|
589
|
+
*/
|
|
584
590
|
|
|
585
591
|
}
|
|
586
592
|
|
|
@@ -678,7 +684,7 @@ export class Cells {
|
|
|
678
684
|
(merge_head || cell.type || (cell.calculated_type && options.expand_arrays) ||
|
|
679
685
|
(cell.calculated_type && options.calculated_value) ||
|
|
680
686
|
(cell.note) ||
|
|
681
|
-
(cell.validation) ||
|
|
687
|
+
// (cell.validation) ||
|
|
682
688
|
(options.decorated_cells && cell.style &&
|
|
683
689
|
( cell.style.fill || cell.style.border_bottom ||
|
|
684
690
|
cell.style.border_top || cell.style.border_left || cell.style.border_right)))){
|
|
@@ -715,9 +721,9 @@ export class Cells {
|
|
|
715
721
|
if (cell.merge_area) {
|
|
716
722
|
obj.merge_area = cell.merge_area.toJSON();
|
|
717
723
|
}
|
|
718
|
-
if (cell.validation) {
|
|
719
|
-
|
|
720
|
-
}
|
|
724
|
+
// if (cell.validation) {
|
|
725
|
+
// obj.validation = cell.validation; // safe?
|
|
726
|
+
// }
|
|
721
727
|
|
|
722
728
|
if (options.cell_style_refs &&
|
|
723
729
|
options.cell_style_refs[column] &&
|
|
@@ -23,9 +23,8 @@ import type { CellStyle } from './style';
|
|
|
23
23
|
import type { SerializedValueType } from './value-type';
|
|
24
24
|
import type { IArea } from './area';
|
|
25
25
|
import type { AnnotationLayout } from './layout';
|
|
26
|
-
import type { DataValidation } from './cell';
|
|
27
26
|
import type { Table } from './table';
|
|
28
|
-
import type { AnnotationType, ConditionalFormat } from 'treb-data-model';
|
|
27
|
+
import type { DataValidation, AnnotationType, ConditionalFormat } from 'treb-data-model';
|
|
29
28
|
|
|
30
29
|
export interface CellParseResult {
|
|
31
30
|
row: number,
|
|
@@ -60,6 +59,7 @@ export interface ImportedSheetData {
|
|
|
60
59
|
row_heights: number[];
|
|
61
60
|
styles: CellStyle[];
|
|
62
61
|
conditional_formats: ConditionalFormat[];
|
|
62
|
+
data_validations?: DataValidation[];
|
|
63
63
|
|
|
64
64
|
// optional, for backcompat
|
|
65
65
|
sheet_style?: number;
|
|
@@ -184,7 +184,7 @@ export class Calculator extends Graph {
|
|
|
184
184
|
|
|
185
185
|
super();
|
|
186
186
|
|
|
187
|
-
this.expression_calculator = new ExpressionCalculator(this.library, this.parser);
|
|
187
|
+
this.expression_calculator = new ExpressionCalculator(this.model, this.library, this.parser);
|
|
188
188
|
|
|
189
189
|
|
|
190
190
|
// at the moment options are only used here; in the future
|
|
@@ -208,6 +208,9 @@ export class Calculator extends Graph {
|
|
|
208
208
|
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
+
// FIXME: why is this called here, if model now owns it?
|
|
212
|
+
// TODO: move to model
|
|
213
|
+
|
|
211
214
|
this.UpdateLocale(); // for parser
|
|
212
215
|
|
|
213
216
|
// base functions
|
|
@@ -1391,6 +1394,11 @@ export class Calculator extends Graph {
|
|
|
1391
1394
|
};
|
|
1392
1395
|
});
|
|
1393
1396
|
|
|
1397
|
+
// FIXME: this doesn't need to be here, if it's owned by model.
|
|
1398
|
+
// we should have model responsible for retrieving these names
|
|
1399
|
+
// (along with named ranges/expressions). also, should macro
|
|
1400
|
+
// functions support scoping?
|
|
1401
|
+
|
|
1394
1402
|
for (const macro of this.model.macro_functions.values()) {
|
|
1395
1403
|
function_list.push({
|
|
1396
1404
|
name: macro.name,
|
|
@@ -1448,8 +1456,7 @@ export class Calculator extends Graph {
|
|
|
1448
1456
|
// that rely on it. which is a pretty far-fetched scenario, but we might
|
|
1449
1457
|
// as well protect against it.
|
|
1450
1458
|
|
|
1451
|
-
|
|
1452
|
-
descriptor.fn = (...args: any[]) => {
|
|
1459
|
+
descriptor.fn = (...args: unknown[]) => {
|
|
1453
1460
|
return original_function.apply({
|
|
1454
1461
|
address: { ...this.expression_calculator.context.address},
|
|
1455
1462
|
}, args);
|
|
@@ -1460,22 +1467,23 @@ export class Calculator extends Graph {
|
|
|
1460
1467
|
|
|
1461
1468
|
}
|
|
1462
1469
|
|
|
1463
|
-
|
|
1470
|
+
/* *
|
|
1464
1471
|
* wrap the attachdata function so we can update the expression calculator
|
|
1465
1472
|
* at the same time (we should unwind this a little bit, it's an artifact
|
|
1466
1473
|
* of graph being a separate class)
|
|
1467
|
-
|
|
1474
|
+
* /
|
|
1468
1475
|
public AttachModel(): void {
|
|
1469
1476
|
// this.RebuildMap();
|
|
1470
|
-
this.expression_calculator.SetModel(this.model);
|
|
1477
|
+
// this.expression_calculator.SetModel(this.model);
|
|
1471
1478
|
}
|
|
1479
|
+
*/
|
|
1472
1480
|
|
|
1473
1481
|
/**
|
|
1474
1482
|
* wrapper method for calculation
|
|
1475
1483
|
*/
|
|
1476
1484
|
public Calculate(subset?: Area): void {
|
|
1477
1485
|
|
|
1478
|
-
this.AttachModel();
|
|
1486
|
+
// this.AttachModel();
|
|
1479
1487
|
|
|
1480
1488
|
// this gets checked later, now... it would be better if we could
|
|
1481
1489
|
// check it here are skip the later check, but that field is optional
|
|
@@ -1539,7 +1547,7 @@ export class Calculator extends Graph {
|
|
|
1539
1547
|
public Reset(): void {
|
|
1540
1548
|
|
|
1541
1549
|
this.FlushTree();
|
|
1542
|
-
this.AttachModel();
|
|
1550
|
+
// this.AttachModel();
|
|
1543
1551
|
|
|
1544
1552
|
this.full_rebuild_required = true;
|
|
1545
1553
|
}
|
|
@@ -1572,7 +1580,10 @@ export class Calculator extends Graph {
|
|
|
1572
1580
|
return map;
|
|
1573
1581
|
}
|
|
1574
1582
|
|
|
1583
|
+
/** overload */
|
|
1575
1584
|
public Evaluate(expression: string, active_sheet?: Sheet, options?: EvaluateOptions, raw_result?: false): CellValue|CellValue[][];
|
|
1585
|
+
|
|
1586
|
+
/** overload */
|
|
1576
1587
|
public Evaluate(expression: string, active_sheet?: Sheet, options?: EvaluateOptions, raw_result?: true): UnionValue;
|
|
1577
1588
|
|
|
1578
1589
|
/** moved from embedded sheet */
|
|
@@ -1687,8 +1698,6 @@ export class Calculator extends Graph {
|
|
|
1687
1698
|
|
|
1688
1699
|
this.full_rebuild_required = false; // unset
|
|
1689
1700
|
|
|
1690
|
-
this.AttachModel();
|
|
1691
|
-
|
|
1692
1701
|
this.RebuildGraph();
|
|
1693
1702
|
|
|
1694
1703
|
// add leaf vertices for annotations
|
|
@@ -1955,7 +1964,7 @@ export class Calculator extends Graph {
|
|
|
1955
1964
|
}
|
|
1956
1965
|
|
|
1957
1966
|
/**
|
|
1958
|
-
*
|
|
1967
|
+
* FIXME: just add a quote option to the model method and we can drop this function
|
|
1959
1968
|
*/
|
|
1960
1969
|
public ResolveSheetName(id: number, quote = false): string | undefined {
|
|
1961
1970
|
const sheet = this.model.sheets.Find(id);
|
|
@@ -2792,10 +2801,11 @@ export class Calculator extends Graph {
|
|
|
2792
2801
|
|
|
2793
2802
|
}
|
|
2794
2803
|
|
|
2795
|
-
|
|
2804
|
+
/*
|
|
2796
2805
|
protected IsNativeOrTypedArray(val: unknown): boolean {
|
|
2797
2806
|
return Array.isArray(val) || (val instanceof Float64Array) || (val instanceof Float32Array);
|
|
2798
2807
|
}
|
|
2808
|
+
*/
|
|
2799
2809
|
|
|
2800
2810
|
/**
|
|
2801
2811
|
* check if a cell is volatile. normally this falls out of the calculation,
|
|
@@ -639,6 +639,8 @@ export abstract class Graph implements GraphCallbacks {
|
|
|
639
639
|
|
|
640
640
|
const map = this.vertices[u.start.sheet_id];
|
|
641
641
|
|
|
642
|
+
// console.info({u});
|
|
643
|
+
|
|
642
644
|
// this might happen on create, we can let it go because the
|
|
643
645
|
// references will be added when the relevant sheet is added
|
|
644
646
|
|
|
@@ -680,10 +682,17 @@ export abstract class Graph implements GraphCallbacks {
|
|
|
680
682
|
else {
|
|
681
683
|
for (let row = u.start.row; row <= u.end.row; row++) {
|
|
682
684
|
for (let column = u.start.column; column <= u.end.column; column++) {
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
685
|
+
if (map[column]) {
|
|
686
|
+
const vertex = map[column][row];
|
|
687
|
+
if (vertex) {
|
|
688
|
+
array_vertex.DependsOn(vertex);
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
/*
|
|
692
|
+
else {
|
|
693
|
+
console.info("HERE", column, row);
|
|
686
694
|
}
|
|
695
|
+
*/
|
|
687
696
|
}
|
|
688
697
|
}
|
|
689
698
|
}
|
|
@@ -27,7 +27,7 @@ import type { Cell, ICellAddress,
|
|
|
27
27
|
UndefinedUnion,
|
|
28
28
|
ComplexUnion,
|
|
29
29
|
DimensionedQuantityUnion} from 'treb-base-types';
|
|
30
|
-
import { ValueType, GetValueType } from 'treb-base-types';
|
|
30
|
+
import { ValueType, GetValueType, Area } from 'treb-base-types';
|
|
31
31
|
import type { Parser, ExpressionUnit, UnitBinary, UnitIdentifier,
|
|
32
32
|
UnitGroup, UnitUnary, UnitAddress, UnitRange, UnitCall, UnitDimensionedQuantity, UnitStructuredReference } from 'treb-parser';
|
|
33
33
|
import type { DataModel, MacroFunction, Sheet } from 'treb-data-model';
|
|
@@ -36,8 +36,26 @@ import { ReturnType } from './descriptors';
|
|
|
36
36
|
|
|
37
37
|
import * as Primitives from './primitives';
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
//////////
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* dynamically adding a user data field to the expression so we can
|
|
43
|
+
* cache a function call, avoiding type switching and function lookups.
|
|
44
|
+
*
|
|
45
|
+
* we use the generic type so we can cover the composite type as well
|
|
46
|
+
* before specifying
|
|
47
|
+
*/
|
|
48
|
+
type AttachCachedFunction<T> = (T & { fn: (arg0: T) => UnionValue });
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* expression unit with cached function
|
|
52
|
+
*/
|
|
53
|
+
type ExpressionWithCachedFunction<T extends ExpressionUnit> = T extends { type: T['type'] } ? AttachCachedFunction<T> : never;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* @internal
|
|
57
|
+
*/
|
|
58
|
+
export type ExtendedExpressionUnit = ExpressionWithCachedFunction<ExpressionUnit>;
|
|
41
59
|
|
|
42
60
|
// FIXME: move
|
|
43
61
|
export const UnionIsExpressionUnit = (test: UnionValue /*UnionOrArray*/): test is { type: ValueType.object, value: ExpressionUnit } => {
|
|
@@ -61,16 +79,18 @@ export const UnionIsMetadata = (test: UnionValue /*UnionOrArray*/): test is { ty
|
|
|
61
79
|
// FIXME: move
|
|
62
80
|
export interface ReferenceMetadata {
|
|
63
81
|
type: 'metadata';
|
|
82
|
+
|
|
83
|
+
// what's the context in which I was using the unit address (parse expression?)
|
|
64
84
|
address: UnitAddress; // ICellAddress;
|
|
85
|
+
|
|
65
86
|
value: CellValue;
|
|
66
87
|
format?: string;
|
|
67
88
|
}
|
|
68
89
|
|
|
69
90
|
export interface CalculationContext {
|
|
70
91
|
address: ICellAddress;
|
|
71
|
-
model?: DataModel;
|
|
92
|
+
// model?: DataModel;
|
|
72
93
|
volatile: boolean;
|
|
73
|
-
call_index: number;
|
|
74
94
|
}
|
|
75
95
|
|
|
76
96
|
export class ExpressionCalculator {
|
|
@@ -78,57 +98,30 @@ export class ExpressionCalculator {
|
|
|
78
98
|
public context: CalculationContext = {
|
|
79
99
|
address: { row: -1, column: -1 },
|
|
80
100
|
volatile: false,
|
|
81
|
-
call_index: 0,
|
|
82
101
|
};
|
|
83
102
|
|
|
84
|
-
/**
|
|
85
|
-
* this refers to the number of function call within a single cell.
|
|
86
|
-
* so if you have a function like
|
|
87
|
-
*
|
|
88
|
-
* =A(B())
|
|
89
|
-
*
|
|
90
|
-
* then when calculating A call index should be set to 1; and when
|
|
91
|
-
* calculating B, call index is 2. and so on.
|
|
92
|
-
*/
|
|
93
|
-
protected call_index = 0;
|
|
94
|
-
|
|
95
|
-
// local reference
|
|
96
|
-
// protected cells: Cells = new Cells();
|
|
97
|
-
// protected cells_map: {[index: number]: Cells} = {};
|
|
98
|
-
// protected sheet_name_map: {[index: string]: number} = {};
|
|
99
|
-
|
|
100
|
-
// local reference
|
|
101
|
-
// protected named_range_map: {[index: string]: Area} = {};
|
|
102
|
-
|
|
103
|
-
// protected bound_name_stack: Array<Record<string, ExpressionUnit>> = [];
|
|
104
|
-
|
|
105
103
|
//
|
|
106
|
-
protected data_model!: DataModel;
|
|
104
|
+
// protected data_model!: DataModel; // can we set in ctor? I think this is a legacy hack
|
|
107
105
|
|
|
108
106
|
|
|
109
107
|
// --- public API -----------------------------------------------------------
|
|
110
108
|
|
|
111
109
|
constructor(
|
|
110
|
+
protected readonly data_model: DataModel,
|
|
112
111
|
protected readonly library: FunctionLibrary,
|
|
113
112
|
protected readonly parser: Parser) {}
|
|
114
113
|
|
|
114
|
+
/*
|
|
115
115
|
public SetModel(model: DataModel): void {
|
|
116
116
|
|
|
117
|
-
// this
|
|
118
|
-
//
|
|
119
|
-
|
|
120
|
-
/*
|
|
121
|
-
for (const sheet of model.sheets.list) {
|
|
122
|
-
// this.cells_map[sheet.id] = sheet.cells;
|
|
123
|
-
// this.sheet_name_map[sheet.name.toLowerCase()] = sheet.id;
|
|
124
|
-
}
|
|
125
|
-
*/
|
|
117
|
+
// is this kept around for some side-effects or something? does
|
|
118
|
+
// the model ever change?
|
|
126
119
|
|
|
127
120
|
this.data_model = model;
|
|
128
|
-
// this.named_range_map = model.named_ranges.Map();
|
|
129
121
|
this.context.model = model;
|
|
130
122
|
|
|
131
123
|
}
|
|
124
|
+
*/
|
|
132
125
|
|
|
133
126
|
/**
|
|
134
127
|
* there's a case where we are calling this from within a function
|
|
@@ -141,10 +134,6 @@ export class ExpressionCalculator {
|
|
|
141
134
|
|
|
142
135
|
this.context.address = addr;
|
|
143
136
|
this.context.volatile = false;
|
|
144
|
-
this.context.call_index = 0;
|
|
145
|
-
|
|
146
|
-
// reset for this cell
|
|
147
|
-
this.call_index = 0; // why not in model? A: timing (nested)
|
|
148
137
|
|
|
149
138
|
}
|
|
150
139
|
|
|
@@ -218,8 +207,7 @@ export class ExpressionCalculator {
|
|
|
218
207
|
}
|
|
219
208
|
|
|
220
209
|
/** breaking this out to de-dupe */
|
|
221
|
-
|
|
222
|
-
protected GetMetadata(arg: ExpressionUnit, map_result: (cell_data: Cell, address: ICellAddress) => any): UnionValue /*UnionOrArray*/ {
|
|
210
|
+
protected GetMetadata<T>(arg: ExpressionUnit, transform: (cell_data: Cell, address: ICellAddress) => T): UnionValue {
|
|
223
211
|
|
|
224
212
|
// FIXME: we used to restrict this to non-cell functions, now
|
|
225
213
|
// we are using it for the cell function (we used to use address,
|
|
@@ -328,10 +316,24 @@ export class ExpressionCalculator {
|
|
|
328
316
|
|
|
329
317
|
const metadata: ReferenceMetadata = {
|
|
330
318
|
type: 'metadata',
|
|
331
|
-
|
|
319
|
+
|
|
320
|
+
// metadata is expecting a parse expression instead of an addresss.
|
|
321
|
+
// note we're not setting the label properly here, which could be
|
|
322
|
+
// an issue? not sure who's calling it in this case
|
|
323
|
+
|
|
324
|
+
// UPDATE: "Cell" is calling it, so it needs a label
|
|
325
|
+
|
|
326
|
+
address: {
|
|
327
|
+
...address,
|
|
328
|
+
position: 0,
|
|
329
|
+
id: 0,
|
|
330
|
+
type: 'address',
|
|
331
|
+
label: new Area(address).spreadsheet_label,
|
|
332
|
+
},
|
|
333
|
+
|
|
332
334
|
value,
|
|
333
335
|
format: cell_data.style ? cell_data.style.number_format : undefined,
|
|
334
|
-
...
|
|
336
|
+
...transform(cell_data, address),
|
|
335
337
|
};
|
|
336
338
|
|
|
337
339
|
return { type: ValueType.object, value: metadata, key: 'metadata' };
|
|
@@ -378,7 +380,7 @@ export class ExpressionCalculator {
|
|
|
378
380
|
address,
|
|
379
381
|
value,
|
|
380
382
|
format: cell_data.style ? cell_data.style.number_format : undefined,
|
|
381
|
-
...
|
|
383
|
+
...transform(cell_data, address),
|
|
382
384
|
};
|
|
383
385
|
|
|
384
386
|
column_result.push({
|
|
@@ -511,11 +513,6 @@ export class ExpressionCalculator {
|
|
|
511
513
|
|
|
512
514
|
return (expr: UnitCall) => {
|
|
513
515
|
|
|
514
|
-
// get an index we can use for this call (we may recurse when
|
|
515
|
-
// calculating arguments), then increment for the next call.
|
|
516
|
-
|
|
517
|
-
const call_index = this.call_index++;
|
|
518
|
-
|
|
519
516
|
// yeah so this is clear. just checking volatile.
|
|
520
517
|
|
|
521
518
|
// FIXME: should this be set later, at the same time as the
|
|
@@ -656,11 +653,6 @@ export class ExpressionCalculator {
|
|
|
656
653
|
return argument_error;
|
|
657
654
|
}
|
|
658
655
|
|
|
659
|
-
// if we have any nested calls, they may have updated the index so
|
|
660
|
-
// we use the captured value here.
|
|
661
|
-
|
|
662
|
-
this.context.call_index = call_index;
|
|
663
|
-
|
|
664
656
|
// I thought we were passing the model as this (...) ? actually
|
|
665
657
|
// now we bind functions that need this, so maybe we should pass
|
|
666
658
|
// null here.
|
|
@@ -988,7 +980,7 @@ export class ExpressionCalculator {
|
|
|
988
980
|
return (expr: UnitGroup) => this.CalculateExpression(expr.elements[0] as ExtendedExpressionUnit);
|
|
989
981
|
}
|
|
990
982
|
|
|
991
|
-
protected CalculateExpression(expr: ExtendedExpressionUnit, return_reference = false): UnionValue
|
|
983
|
+
protected CalculateExpression(expr: ExtendedExpressionUnit, return_reference = false): UnionValue {
|
|
992
984
|
|
|
993
985
|
// user data is a generated function for the expression, at least
|
|
994
986
|
// for the simple ones (atm). see BinaryExpression for more. the
|
|
@@ -996,8 +988,8 @@ export class ExpressionCalculator {
|
|
|
996
988
|
|
|
997
989
|
// may be over-optimizing here.
|
|
998
990
|
|
|
999
|
-
if (expr.
|
|
1000
|
-
return expr.
|
|
991
|
+
if ((expr as AttachCachedFunction<ExpressionUnit>).fn) {
|
|
992
|
+
return (expr as AttachCachedFunction<ExpressionUnit>).fn(expr);
|
|
1001
993
|
}
|
|
1002
994
|
|
|
1003
995
|
switch (expr.type){
|
|
@@ -1005,52 +997,52 @@ export class ExpressionCalculator {
|
|
|
1005
997
|
{
|
|
1006
998
|
const macro = this.data_model.macro_functions.get(expr.name.toUpperCase());
|
|
1007
999
|
if (macro) {
|
|
1008
|
-
return (expr.
|
|
1000
|
+
return (expr.fn = this.CallMacro(expr, macro))(expr);
|
|
1009
1001
|
}
|
|
1010
|
-
return (expr.
|
|
1002
|
+
return (expr.fn = this.CallExpression(expr, return_reference))(expr);
|
|
1011
1003
|
}
|
|
1012
1004
|
|
|
1013
1005
|
case 'address':
|
|
1014
|
-
return (expr.
|
|
1006
|
+
return (expr.fn = this.CellFunction2(expr))(); // check
|
|
1015
1007
|
|
|
1016
1008
|
case 'range':
|
|
1017
|
-
return (expr.
|
|
1009
|
+
return (expr.fn = (x: UnitRange) => this.CellFunction4(x.start, x.end))(expr); // check
|
|
1018
1010
|
|
|
1019
1011
|
case 'binary':
|
|
1020
|
-
return (expr.
|
|
1012
|
+
return (expr.fn = this.BinaryExpression(expr))(expr); // check
|
|
1021
1013
|
|
|
1022
1014
|
case 'unary':
|
|
1023
|
-
return (expr.
|
|
1015
|
+
return (expr.fn = this.UnaryExpression(expr))(expr); // check
|
|
1024
1016
|
|
|
1025
1017
|
case 'identifier':
|
|
1026
|
-
return (expr.
|
|
1018
|
+
return (expr.fn = this.Identifier(expr))(); // check
|
|
1027
1019
|
|
|
1028
1020
|
case 'missing':
|
|
1029
|
-
return (expr.
|
|
1021
|
+
return (expr.fn = () => { return { value: undefined, type: ValueType.undefined } as UndefinedUnion })(); // check
|
|
1030
1022
|
|
|
1031
1023
|
case 'dimensioned':
|
|
1032
|
-
return (expr.
|
|
1024
|
+
return (expr.fn = this.ResolveDimensionedQuantity())(expr);
|
|
1033
1025
|
|
|
1034
1026
|
case 'literal':
|
|
1035
1027
|
{
|
|
1036
1028
|
const literal = { value: expr.value, type: GetValueType(expr.value) } as UnionValue;
|
|
1037
|
-
return (expr.
|
|
1029
|
+
return (expr.fn = () => literal)(); // check
|
|
1038
1030
|
}
|
|
1039
1031
|
case 'group':
|
|
1040
|
-
return (expr.
|
|
1032
|
+
return (expr.fn = this.GroupExpression(expr))(expr); // check
|
|
1041
1033
|
|
|
1042
1034
|
case 'complex':
|
|
1043
1035
|
{
|
|
1044
1036
|
const literal = {value: {real: expr.real, imaginary: expr.imaginary}, type: ValueType.complex } as ComplexUnion;
|
|
1045
|
-
return (expr.
|
|
1037
|
+
return (expr.fn = () => literal)(); // check
|
|
1046
1038
|
}
|
|
1047
1039
|
|
|
1048
1040
|
case 'structured-reference':
|
|
1049
|
-
return (expr.
|
|
1041
|
+
return (expr.fn = this.ResolveStructuredReference(expr))();
|
|
1050
1042
|
|
|
1051
1043
|
case 'array':
|
|
1052
1044
|
{
|
|
1053
|
-
return (expr.
|
|
1045
|
+
return (expr.fn = () => {
|
|
1054
1046
|
return {
|
|
1055
1047
|
type: ValueType.array,
|
|
1056
1048
|
value: expr.values.map((row) => (Array.isArray(row) ? row : [row]).map((value) => {
|