@trebco/treb 29.2.0 → 29.3.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 +7 -7
- package/dist/treb-spreadsheet.mjs +15 -15
- package/dist/treb.d.ts +13 -9
- package/package.json +1 -1
- package/treb-base-types/src/area.ts +7 -0
- package/treb-calculator/src/calculator.ts +10 -8
- package/treb-calculator/src/dag/array-vertex.ts +0 -2
- package/treb-calculator/src/dag/graph.ts +88 -2
- package/treb-calculator/src/dag/spreadsheet_vertex.ts +1 -60
- package/treb-calculator/src/expression-calculator.ts +3 -1
- package/treb-calculator/src/functions/base-functions.ts +6 -1
- package/treb-data-model/src/data_model.ts +59 -20
- package/treb-data-model/src/index.ts +1 -1
- package/treb-data-model/src/named.ts +11 -32
- package/treb-data-model/src/sheet.ts +14 -6
- package/treb-export/src/export2.ts +3 -82
- package/treb-export/src/workbook2.ts +2 -2
- package/treb-grid/src/types/grid.ts +3 -3
package/dist/treb.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! API v29.
|
|
1
|
+
/*! API v29.3. 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
|
|
@@ -1602,19 +1602,23 @@ export interface SerializedNamedExpression {
|
|
|
1602
1602
|
}
|
|
1603
1603
|
|
|
1604
1604
|
/**
|
|
1605
|
-
* serialized type
|
|
1605
|
+
* serialized type is a composite of expression/range. we determine
|
|
1606
|
+
* what it is when parsing the expression. this simplifies passing these
|
|
1607
|
+
* things around.
|
|
1608
|
+
*
|
|
1609
|
+
* (named expressions and ranges they have slightly different behavior,
|
|
1610
|
+
* which is why we have a distinction at all).
|
|
1611
|
+
*
|
|
1606
1612
|
*/
|
|
1607
1613
|
export interface SerializedNamed {
|
|
1608
1614
|
name: string;
|
|
1609
|
-
|
|
1610
|
-
expression
|
|
1615
|
+
|
|
1616
|
+
/** expression or address/area */
|
|
1617
|
+
expression: string;
|
|
1618
|
+
|
|
1619
|
+
/** scope is a sheet name (not ID) */
|
|
1611
1620
|
scope?: string;
|
|
1612
1621
|
}
|
|
1613
|
-
export type SerializedArea = IArea & {
|
|
1614
|
-
start: ICellAddress & {
|
|
1615
|
-
sheet: string;
|
|
1616
|
-
};
|
|
1617
|
-
};
|
|
1618
1622
|
export interface SerializedSheet {
|
|
1619
1623
|
|
|
1620
1624
|
/** cell data */
|
package/package.json
CHANGED
|
@@ -102,6 +102,9 @@ export interface Dimensions {
|
|
|
102
102
|
* start/end value for row/column/both, so watch out on loops. the
|
|
103
103
|
* sheet class has a method for reducing infinite ranges to actual
|
|
104
104
|
* populated ranges.
|
|
105
|
+
*
|
|
106
|
+
* infinitiy is turning into a headache because it doesn't serialize
|
|
107
|
+
* to json properly. should we switch to a flag, or -1, or something?
|
|
105
108
|
*/
|
|
106
109
|
export class Area implements IArea {
|
|
107
110
|
|
|
@@ -166,6 +169,10 @@ export class Area implements IArea {
|
|
|
166
169
|
|
|
167
170
|
public static CellAddressToLabel(address: ICellAddress, sheet_id = false): string {
|
|
168
171
|
|
|
172
|
+
if (address.row === Infinity || address.column === Infinity) {
|
|
173
|
+
throw new Error('this is going to break something');
|
|
174
|
+
}
|
|
175
|
+
|
|
169
176
|
const prefix = sheet_id ? `${address.sheet_id || 0}!` : '';
|
|
170
177
|
|
|
171
178
|
return prefix
|
|
@@ -1930,12 +1930,15 @@ export class Calculator extends Graph {
|
|
|
1930
1930
|
}
|
|
1931
1931
|
}
|
|
1932
1932
|
|
|
1933
|
+
/*
|
|
1933
1934
|
if (area.count > 1) {
|
|
1934
1935
|
range = Area.CellAddressToLabel(area.start) + ':' + Area.CellAddressToLabel(area.end);
|
|
1935
1936
|
}
|
|
1936
1937
|
else {
|
|
1937
1938
|
range = Area.CellAddressToLabel(area.start);
|
|
1938
1939
|
}
|
|
1940
|
+
*/
|
|
1941
|
+
range = area.spreadsheet_label;
|
|
1939
1942
|
|
|
1940
1943
|
if (!qualified) {
|
|
1941
1944
|
return range;
|
|
@@ -2514,21 +2517,20 @@ export class Calculator extends Graph {
|
|
|
2514
2517
|
const unit = dependencies.ranges[key];
|
|
2515
2518
|
const range = new Area(unit.start, unit.end);
|
|
2516
2519
|
|
|
2517
|
-
|
|
2518
|
-
this.AddLeafVertexEdge(
|
|
2520
|
+
if (range.entire_column || range.entire_row || range.count > 1) {
|
|
2521
|
+
// this.AddLeafVertexEdge(range.start, vertex);
|
|
2522
|
+
this.AddLeafVertexArrayEdge(range, vertex);
|
|
2523
|
+
}
|
|
2524
|
+
else {
|
|
2525
|
+
this.AddLeafVertexEdge(range.start, vertex);
|
|
2519
2526
|
}
|
|
2520
|
-
|
|
2521
|
-
/*
|
|
2522
|
-
range.Iterate((address: ICellAddress) => {
|
|
2523
|
-
this.AddLeafVertexEdge(address, vertex);
|
|
2524
|
-
});
|
|
2525
|
-
*/
|
|
2526
2527
|
|
|
2527
2528
|
/*
|
|
2528
2529
|
for (const address of range) {
|
|
2529
2530
|
this.AddLeafVertexEdge(address, vertex);
|
|
2530
2531
|
}
|
|
2531
2532
|
*/
|
|
2533
|
+
|
|
2532
2534
|
}
|
|
2533
2535
|
|
|
2534
2536
|
for (const key of Object.keys(dependencies.addresses)){
|
|
@@ -101,11 +101,9 @@ export class ArrayVertex extends SpreadsheetVertexBase {
|
|
|
101
101
|
* returns a list of arrays that contain this address
|
|
102
102
|
*/
|
|
103
103
|
public static GetContainingArrays(address: ICellAddress2): ArrayVertex[] {
|
|
104
|
-
// console.info('av2 get arrays:', address.row, address.column);
|
|
105
104
|
const list: ArrayVertex[] = [];
|
|
106
105
|
for (const entry of this.list) {
|
|
107
106
|
if ((entry.area.start.sheet_id === address.sheet_id) && entry.area.Contains(address)) {
|
|
108
|
-
// console.info("match", entry.area.spreadsheet_label);
|
|
109
107
|
list.push(entry);
|
|
110
108
|
}
|
|
111
109
|
}
|
|
@@ -613,9 +613,91 @@ export abstract class Graph implements GraphCallbacks {
|
|
|
613
613
|
/**
|
|
614
614
|
* new array vertices
|
|
615
615
|
*/
|
|
616
|
-
|
|
616
|
+
protected CompositeAddArrayEdge(u: Area, vertex: Vertex): void {
|
|
617
|
+
|
|
618
|
+
if (!u.start.sheet_id) {
|
|
619
|
+
throw new Error('AddArrayEdge called without sheet ID');
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
// create or use existing
|
|
623
|
+
const [array_vertex, created] = ArrayVertex.GetVertex(u);
|
|
624
|
+
|
|
625
|
+
// add an edge
|
|
626
|
+
vertex.DependsOn(array_vertex);
|
|
627
|
+
|
|
628
|
+
// force a check on next calculation pass
|
|
629
|
+
this.loop_check_required = true;
|
|
630
|
+
|
|
631
|
+
if (!created) {
|
|
632
|
+
// console.info('reusing, so not adding edges');
|
|
633
|
+
return;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
// now add edges from/to nodes THAT ALREADY EXIST
|
|
637
|
+
|
|
638
|
+
// range can't span sheets, so we only need one set to look up
|
|
639
|
+
|
|
640
|
+
const map = this.vertices[u.start.sheet_id];
|
|
641
|
+
|
|
642
|
+
// this might happen on create, we can let it go because the
|
|
643
|
+
// references will be added when the relevant sheet is added
|
|
644
|
+
|
|
645
|
+
if (!map) {
|
|
646
|
+
return;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
// ...
|
|
650
|
+
|
|
651
|
+
if (u.entire_row) {
|
|
652
|
+
// console.group('entire row(s)')
|
|
653
|
+
for (let column = 0; column < map.length; column++) {
|
|
654
|
+
if (map[column]) {
|
|
655
|
+
for (let row = u.start.row; row <= u.end.row; row++ ) {
|
|
656
|
+
const vertex = map[column][row];
|
|
657
|
+
if (vertex) {
|
|
658
|
+
// console.info('add', column, row);
|
|
659
|
+
array_vertex.DependsOn(vertex);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
// console.groupEnd();
|
|
665
|
+
}
|
|
666
|
+
else if (u.entire_column) {
|
|
667
|
+
// console.group('entire column(s)');
|
|
668
|
+
for (let column = u.start.column; column <= u.end.column; column++) {
|
|
669
|
+
if(map[column]) {
|
|
670
|
+
for (const vertex of map[column]) {
|
|
671
|
+
if (vertex?.address) {
|
|
672
|
+
// console.info('add', vertex.address);
|
|
673
|
+
array_vertex.DependsOn(vertex);
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
// console.groupEnd();
|
|
679
|
+
}
|
|
680
|
+
else {
|
|
681
|
+
for (let row = u.start.row; row <= u.end.row; row++) {
|
|
682
|
+
for (let column = u.start.column; column <= u.end.column; column++) {
|
|
683
|
+
const vertex = map[column][row];
|
|
684
|
+
if (vertex) {
|
|
685
|
+
array_vertex.DependsOn(vertex);
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
}
|
|
617
690
|
|
|
618
|
-
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
public AddLeafVertexArrayEdge(u: Area, vertex: LeafVertex) {
|
|
694
|
+
this.CompositeAddArrayEdge(u, vertex);
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
/**
|
|
698
|
+
* new array vertices
|
|
699
|
+
*/
|
|
700
|
+
public AddArrayEdge(u: Area, v: ICellAddress): void {
|
|
619
701
|
|
|
620
702
|
if (!u.start.sheet_id) {
|
|
621
703
|
throw new Error('AddArrayEdge called without sheet ID');
|
|
@@ -624,6 +706,9 @@ export abstract class Graph implements GraphCallbacks {
|
|
|
624
706
|
// this should have already been added...
|
|
625
707
|
const v_v = this.GetVertex(v, true);
|
|
626
708
|
|
|
709
|
+
this.CompositeAddArrayEdge(u, v_v);
|
|
710
|
+
|
|
711
|
+
/*
|
|
627
712
|
// create or use existing
|
|
628
713
|
const [array_vertex, created] = ArrayVertex.GetVertex(u);
|
|
629
714
|
|
|
@@ -692,6 +777,7 @@ export abstract class Graph implements GraphCallbacks {
|
|
|
692
777
|
}
|
|
693
778
|
}
|
|
694
779
|
}
|
|
780
|
+
*/
|
|
695
781
|
|
|
696
782
|
}
|
|
697
783
|
|
|
@@ -226,71 +226,13 @@ export class SpreadsheetVertex extends SpreadsheetVertexBase {
|
|
|
226
226
|
// handle it properly regardless.
|
|
227
227
|
|
|
228
228
|
const single = (this.result.type === ValueType.array) ? this.result.value[0][0] : this.result;
|
|
229
|
-
/*
|
|
230
|
-
if (single.type === ValueType.object) {
|
|
231
|
-
this.reference.SetCalculationError('OBJECT');
|
|
232
|
-
}
|
|
233
|
-
else */
|
|
234
229
|
|
|
235
230
|
// we are using object type in the returned value for sparklines...
|
|
236
231
|
// so we can't drop it here. we could change rendering though. or
|
|
237
232
|
// whitelist types. or blacklist types. or something.
|
|
238
233
|
|
|
239
|
-
|
|
240
|
-
this.reference.SetCalculatedValue(single.value as CellValue, single.type);
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
/*
|
|
244
|
-
console.info("T2", t2);
|
|
245
|
-
|
|
246
|
-
// because we let sloppy data filter through, it's possible
|
|
247
|
-
// that we get some random stuff at this point. generally this
|
|
248
|
-
// shoudl not happen but if you use (e.g.) one of the chart
|
|
249
|
-
// functions in a spreadsheet cell, you'll get a 1d array.
|
|
250
|
-
|
|
251
|
-
// so we need to validate that what we have is either a UnionValue
|
|
252
|
-
// or a 2d UnionValue[][] array.
|
|
253
|
-
|
|
254
|
-
// don't know the performance cost of this.
|
|
255
|
-
|
|
256
|
-
// FIXME: don't let sloppy data through.
|
|
257
|
-
|
|
258
|
-
let test: any = this.result;
|
|
259
|
-
|
|
260
|
-
if (Array.isArray(test)) {
|
|
261
|
-
if (test[0] && Array.isArray(test[0])) {
|
|
262
|
-
test = test[0][0];
|
|
263
|
-
}
|
|
264
|
-
else {
|
|
265
|
-
// console.warn('error 1');
|
|
266
|
-
test = undefined;
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
if (!test || typeof (test as any).type === undefined) {
|
|
271
|
-
// console.warn('error 2/3');
|
|
272
|
-
this.reference.SetCalculationError('UNK');
|
|
273
|
-
}
|
|
274
|
-
else {
|
|
275
|
-
this.reference.SetCalculatedValue((test as UnionValue).value, (test as UnionValue).type);
|
|
276
|
-
}
|
|
277
|
-
*/
|
|
278
|
-
|
|
279
|
-
/*
|
|
280
|
-
const single = Array.isArray(this.result) ? this.result[0][0] : this.result;
|
|
281
|
-
|
|
282
|
-
// error is implicit
|
|
283
|
-
this.reference.SetCalculatedValue(single.value, single.type);
|
|
284
|
-
*/
|
|
234
|
+
this.reference.SetCalculatedValue(single.value as CellValue, single.type);
|
|
285
235
|
|
|
286
|
-
/*
|
|
287
|
-
if (typeof this.result === 'object' && this.result.error) {
|
|
288
|
-
this.reference.SetCalculationError(this.result.error);
|
|
289
|
-
}
|
|
290
|
-
else {
|
|
291
|
-
this.reference.SetCalculatedValue(this.result);
|
|
292
|
-
}
|
|
293
|
-
*/
|
|
294
236
|
}
|
|
295
237
|
|
|
296
238
|
}
|
|
@@ -318,7 +260,6 @@ export class SpreadsheetVertex extends SpreadsheetVertexBase {
|
|
|
318
260
|
//
|
|
319
261
|
|
|
320
262
|
for (const edge of this.edges_out as Set<SpreadsheetVertexBase>){
|
|
321
|
-
// (edge as SpreadsheetVertex).Calculate(graph);
|
|
322
263
|
if (edge.dirty) {
|
|
323
264
|
graph.calculation_list.push(edge);
|
|
324
265
|
}
|
|
@@ -502,7 +502,9 @@ export class ExpressionCalculator {
|
|
|
502
502
|
|
|
503
503
|
if (!func) {
|
|
504
504
|
|
|
505
|
-
|
|
505
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
506
|
+
console.info('(dev) missing function', outer.name);
|
|
507
|
+
}
|
|
506
508
|
|
|
507
509
|
return () => NameError();
|
|
508
510
|
}
|
|
@@ -416,7 +416,12 @@ export const BaseFunctionLibrary: FunctionMap = {
|
|
|
416
416
|
case 1: // feb, special
|
|
417
417
|
{
|
|
418
418
|
const year = date.getUTCFullYear();
|
|
419
|
-
|
|
419
|
+
|
|
420
|
+
// it's a leap year if it is divisible by 4, unless it's also
|
|
421
|
+
// divisible by 100 AND NOT divisible by 400. 1900 is grand-
|
|
422
|
+
// fathered in via an error in Lotus.
|
|
423
|
+
|
|
424
|
+
if (year % 4 === 0 && (year === 1900 || (year % 400 === 0) || (year % 100 !== 0))) {
|
|
420
425
|
date.setUTCDate(29);
|
|
421
426
|
}
|
|
422
427
|
else {
|
|
@@ -25,7 +25,7 @@ import type { IArea, ICellAddress, Table, CellStyle } from 'treb-base-types';
|
|
|
25
25
|
import type { SerializedSheet } from './sheet_types';
|
|
26
26
|
import { type ExpressionUnit, type UnitAddress, type UnitStructuredReference, type UnitRange, Parser, QuotedSheetNameRegex, DecimalMarkType, ArgumentSeparatorType } from 'treb-parser';
|
|
27
27
|
import { Area, IsCellAddress, Style } from 'treb-base-types';
|
|
28
|
-
import type {
|
|
28
|
+
import type { SerializedNamed } from './named';
|
|
29
29
|
import { NamedRangeManager } from './named';
|
|
30
30
|
|
|
31
31
|
export interface ConnectedElementType {
|
|
@@ -132,36 +132,72 @@ export class DataModel {
|
|
|
132
132
|
* need to check if something is a range -- if so, it will just be
|
|
133
133
|
* a single address or range. in that case store it as a named range.
|
|
134
134
|
*/
|
|
135
|
-
public
|
|
135
|
+
public UnserializeNames(names: SerializedNamed[], active_sheet?: Sheet) {
|
|
136
136
|
|
|
137
137
|
this.parser.Save();
|
|
138
138
|
this.parser.SetLocaleSettings(DecimalMarkType.Period, ArgumentSeparatorType.Comma);
|
|
139
139
|
|
|
140
|
-
const sorted = names.map(named => {
|
|
140
|
+
//const sorted = names.map(named => {
|
|
141
|
+
for (const named of names) {
|
|
141
142
|
const parse_result = this.parser.Parse(named.expression);
|
|
142
143
|
if (parse_result.expression) {
|
|
144
|
+
|
|
145
|
+
const scope = (typeof named.scope === 'string') ? this.sheets.ID(named.scope) : undefined;
|
|
146
|
+
|
|
143
147
|
if (parse_result.expression.type === 'address' || parse_result.expression.type === 'range') {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
expression:
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
148
|
+
|
|
149
|
+
const [start, end] = parse_result.expression.type === 'range' ?
|
|
150
|
+
[ parse_result.expression.start, parse_result.expression.end, ] :
|
|
151
|
+
[ parse_result.expression, parse_result.expression ];
|
|
152
|
+
|
|
153
|
+
if (start.sheet) {
|
|
154
|
+
const area = new Area({...start, sheet_id: this.sheets.ID(start.sheet), }, end);
|
|
155
|
+
|
|
156
|
+
if (area.start.sheet_id) {
|
|
157
|
+
this.named.SetNamedRange(named.name, area, scope);
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
console.warn("missing sheet ID?", start);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
console.warn("missing sheet name?", start);
|
|
166
|
+
}
|
|
167
|
+
|
|
152
168
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
169
|
+
else {
|
|
170
|
+
this.parser.Walk(parse_result.expression, unit => {
|
|
171
|
+
if (unit.type === 'address' || unit.type === 'range') {
|
|
172
|
+
if (unit.type === 'range') {
|
|
173
|
+
unit = unit.start;
|
|
174
|
+
}
|
|
175
|
+
if (!unit.sheet_id) {
|
|
176
|
+
if (unit.sheet) {
|
|
177
|
+
unit.sheet_id = this.sheets.ID(unit.sheet);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (!unit.sheet_id) {
|
|
181
|
+
unit.sheet_id = active_sheet?.id;
|
|
182
|
+
}
|
|
183
|
+
return false; // don't continue in ranges
|
|
184
|
+
}
|
|
185
|
+
return true;
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
this.named.SetNamedExpression(named.name, parse_result.expression, scope);
|
|
189
|
+
}
|
|
190
|
+
|
|
156
191
|
}
|
|
157
192
|
return undefined;
|
|
158
|
-
}).filter((test): test is SerializedNamed => !!test);
|
|
193
|
+
} // ).filter((test): test is SerializedNamed => !!test);
|
|
159
194
|
|
|
160
195
|
this.parser.Restore();
|
|
161
|
-
this.UnserializeNames(sorted, active_sheet);
|
|
196
|
+
// this.UnserializeNames(sorted, active_sheet);
|
|
162
197
|
|
|
163
198
|
}
|
|
164
199
|
|
|
200
|
+
/*
|
|
165
201
|
public UnserializeNames(names: SerializedNamed[], active_sheet?: Sheet) {
|
|
166
202
|
|
|
167
203
|
for (const entry of names) {
|
|
@@ -218,6 +254,7 @@ export class DataModel {
|
|
|
218
254
|
}
|
|
219
255
|
|
|
220
256
|
}
|
|
257
|
+
*/
|
|
221
258
|
|
|
222
259
|
/**
|
|
223
260
|
* serialize names. ranges are easy, but make sure there's a sheet name
|
|
@@ -231,7 +268,7 @@ export class DataModel {
|
|
|
231
268
|
|
|
232
269
|
const named: SerializedNamed = {
|
|
233
270
|
name: entry.name,
|
|
234
|
-
|
|
271
|
+
expression: '',
|
|
235
272
|
};
|
|
236
273
|
|
|
237
274
|
if (entry.scope) {
|
|
@@ -278,11 +315,10 @@ export class DataModel {
|
|
|
278
315
|
|
|
279
316
|
}
|
|
280
317
|
else {
|
|
281
|
-
|
|
318
|
+
|
|
319
|
+
const area = {
|
|
282
320
|
start: {
|
|
283
321
|
...entry.area.start,
|
|
284
|
-
sheet: this.sheets.Name(entry.area.start.sheet_id || 0) || '',
|
|
285
|
-
sheet_id: undefined, // in favor of name
|
|
286
322
|
absolute_column: true,
|
|
287
323
|
absolute_row: true,
|
|
288
324
|
},
|
|
@@ -292,6 +328,9 @@ export class DataModel {
|
|
|
292
328
|
absolute_row: true,
|
|
293
329
|
},
|
|
294
330
|
};
|
|
331
|
+
|
|
332
|
+
named.expression = this.AddressToLabel(area);
|
|
333
|
+
|
|
295
334
|
}
|
|
296
335
|
|
|
297
336
|
list.push(named);
|
|
@@ -30,7 +30,7 @@ export type {
|
|
|
30
30
|
SerializedMacroFunction,
|
|
31
31
|
} from './data_model';
|
|
32
32
|
|
|
33
|
-
export type { SerializedNamed
|
|
33
|
+
export type { SerializedNamed } from './named';
|
|
34
34
|
|
|
35
35
|
export { Sheet } from './sheet';
|
|
36
36
|
export type { SerializedSheet, FreezePane, LegacySerializedSheet } from './sheet_types';
|
|
@@ -20,15 +20,15 @@
|
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
import { Area } from 'treb-base-types';
|
|
23
|
-
import type {
|
|
23
|
+
import type { IArea } from 'treb-base-types';
|
|
24
24
|
import type { ExpressionUnit } from 'treb-parser';
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
interface NamedExpression {
|
|
27
27
|
type: 'expression';
|
|
28
28
|
expression: ExpressionUnit;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
interface NamedRange {
|
|
32
32
|
type: 'range';
|
|
33
33
|
area: Area;
|
|
34
34
|
}
|
|
@@ -38,44 +38,23 @@ export type Named = (NamedExpression | NamedRange) & {
|
|
|
38
38
|
scope?: number; // scope to sheet by ID
|
|
39
39
|
};
|
|
40
40
|
|
|
41
|
-
/**
|
|
42
|
-
* serialized type
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* for the external type we switch on the presence of the area
|
|
47
|
-
* or the expression. area uses a type that includes sheet names
|
|
48
|
-
* (IArea should allow that?). expression here is a string.
|
|
41
|
+
/**
|
|
42
|
+
* serialized type is a composite of expression/range. we determine
|
|
43
|
+
* what it is when parsing the expression. this simplifies passing these
|
|
44
|
+
* things around.
|
|
49
45
|
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
46
|
+
* (named expressions and ranges they have slightly different behavior,
|
|
47
|
+
* which is why we have a distinction at all).
|
|
52
48
|
*
|
|
53
|
-
* when serialized, scope is either the sheet name or nothing
|
|
54
|
-
* (implicit global scope).
|
|
55
49
|
*/
|
|
56
50
|
export interface SerializedNamed {
|
|
57
|
-
name: string;
|
|
58
|
-
area?: SerializedArea;
|
|
59
|
-
expression?: string;
|
|
60
|
-
scope?: string;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* this is a type we're using in imports. it consolidates the
|
|
65
|
-
* two types. we should maybe switch as well, at least for
|
|
66
|
-
* serialized representation? something to think about.
|
|
67
|
-
*/
|
|
68
|
-
export interface CompositeNamed {
|
|
69
51
|
|
|
70
52
|
name: string;
|
|
71
53
|
|
|
72
|
-
/**
|
|
73
|
-
* could be a address/range or a function expression. we'll distinguish
|
|
74
|
-
* when we parse it.
|
|
75
|
-
*/
|
|
54
|
+
/** expression or address/area */
|
|
76
55
|
expression: string;
|
|
77
56
|
|
|
78
|
-
/**
|
|
57
|
+
/** scope is a sheet name (not ID) */
|
|
79
58
|
scope?: string;
|
|
80
59
|
|
|
81
60
|
}
|
|
@@ -3282,9 +3282,20 @@ export class Sheet {
|
|
|
3282
3282
|
// stop rule. if you go forwards, you need some sort of indicator
|
|
3283
3283
|
// or flag).
|
|
3284
3284
|
|
|
3285
|
+
const area = JSON.parse(JSON.stringify(format.area));
|
|
3286
|
+
|
|
3287
|
+
if (area.start.row === null || area.end.row === null) {
|
|
3288
|
+
area.start.row = 0;
|
|
3289
|
+
area.end.row = this.cells.rows - 1;
|
|
3290
|
+
}
|
|
3291
|
+
if (area.start.column === null || area.end.column === null) {
|
|
3292
|
+
area.start.column = 0;
|
|
3293
|
+
area.end.column = this.cells.columns - 1;
|
|
3294
|
+
}
|
|
3295
|
+
|
|
3296
|
+
const result = format.internal?.vertex?.result;
|
|
3297
|
+
|
|
3285
3298
|
if (format.type === 'gradient') {
|
|
3286
|
-
const area = JSON.parse(JSON.stringify(format.area));
|
|
3287
|
-
const result = format.internal?.vertex?.result;
|
|
3288
3299
|
|
|
3289
3300
|
if (result && format.internal?.gradient) {
|
|
3290
3301
|
const property: 'fill'|'text' = format.property ?? 'fill';
|
|
@@ -3322,16 +3333,13 @@ export class Sheet {
|
|
|
3322
3333
|
|
|
3323
3334
|
// handle types expression, cell-match and duplicate-values
|
|
3324
3335
|
|
|
3325
|
-
const area = JSON.parse(JSON.stringify(format.area));
|
|
3326
|
-
const result = format.internal?.vertex?.result;
|
|
3327
|
-
|
|
3328
3336
|
if (result) {
|
|
3329
3337
|
|
|
3330
3338
|
if (result.type === ValueType.array) {
|
|
3331
3339
|
for (let row = area.start.row; row <= area.end.row; row++) {
|
|
3332
3340
|
for (let column = area.start.column; column <= area.end.column; column++) {
|
|
3333
3341
|
const value = result.value[column - area.start.column][row - area.start.row];
|
|
3334
|
-
if ((value.type === ValueType.boolean || value.type === ValueType.number) && !!value.value) {
|
|
3342
|
+
if (value && (value.type === ValueType.boolean || value.type === ValueType.number) && !!value.value) {
|
|
3335
3343
|
if (!temp[row]) { temp[row] = []; }
|
|
3336
3344
|
if (!temp[row][column] ) { temp[row][column] = []; }
|
|
3337
3345
|
temp[row][column].push(format.style);
|