@trebco/treb 25.9.1 → 26.0.3

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.
@@ -100,7 +100,7 @@ export interface ClickFunctionResult {
100
100
  export type ClickFunction = (options: ClickFunctionOptions) => ClickFunctionResult;
101
101
 
102
102
 
103
- /**
103
+ /*
104
104
  * restructuring from the old system, which had lots of separate arrays for
105
105
  * things. for the most part I think having a single array (or object) with
106
106
  * objects will be more useful (if not necessarily more efficient). the
@@ -121,11 +121,11 @@ export type ClickFunction = (options: ClickFunctionOptions) => ClickFunctionResu
121
121
  * validation TODO: date, number, boolean, &c
122
122
  */
123
123
  export enum ValidationType {
124
- List,
125
- Date,
126
- Range,
127
- Number,
128
- Boolean,
124
+ List = 'list',
125
+ Date = 'date',
126
+ Range = 'range',
127
+ Number = 'number',
128
+ Boolean = 'boolean',
129
129
  }
130
130
 
131
131
  export interface DataValidationBase {
@@ -133,25 +133,25 @@ export interface DataValidationBase {
133
133
  }
134
134
 
135
135
  export interface DataValidationRange extends DataValidationBase {
136
- type: ValidationType.Range;
136
+ type: 'range'; // ValidationType.Range;
137
137
  area: IArea;
138
138
  }
139
139
 
140
140
  export interface DataValidationList extends DataValidationBase {
141
- type: ValidationType.List;
141
+ type: 'list'; // ValidationType.List;
142
142
  list: CellValue[];
143
143
  }
144
144
 
145
145
  export interface DataValidationDate extends DataValidationBase {
146
- type: ValidationType.Date;
146
+ type: 'date'; // ValidationType.Date;
147
147
  }
148
148
 
149
149
  export interface DataValidationNumber extends DataValidationBase {
150
- type: ValidationType.Number;
150
+ type: 'number'; // ValidationType.Number;
151
151
  }
152
152
 
153
153
  export interface DataValidationBoolean extends DataValidationBase {
154
- type: ValidationType.Boolean;
154
+ type: 'boolean'; // ValidationType.Boolean;
155
155
  }
156
156
 
157
157
  export type DataValidation
@@ -29,7 +29,7 @@ import { Area, IsCellAddress } from './area';
29
29
  import type { DataValidation } from './cell';
30
30
  import { Cell } from './cell';
31
31
  import type { Table } from './table';
32
- import { ValueType, GetValueType } from './value-type';
32
+ import { type SerializedValueType, ValueType, GetValueType, ValueTypeList } from './value-type';
33
33
  import type { CellValue, UnionValue } from './union';
34
34
  import type { Style } from './style';
35
35
 
@@ -80,10 +80,10 @@ export interface BaseCellData {
80
80
  area?: IArea;
81
81
  merge_area?: IArea;
82
82
  validation?: DataValidation;
83
- calculated_type?: ValueType;
83
+ calculated_type?: SerializedValueType; // ValueType;
84
84
  note?: string;
85
85
  hyperlink?: string;
86
- type?: ValueType;
86
+ type?: SerializedValueType; // ValueType;
87
87
  sheet_id?: number;
88
88
  // locked?: boolean;
89
89
  }
@@ -132,6 +132,17 @@ export const IsNestedRowArray = (test: NestedRowData[]|NestedColumnData[]): test
132
132
 
133
133
  // ...
134
134
 
135
+
136
+ /**
137
+ * this is the reverse map, i.e. type => number
138
+ * FIXME: why is this getting exported by the API generator?
139
+ * FIXME: I get why it's dynamic, but for practical purposes why not just
140
+ * create a static map?
141
+ */
142
+ const ValueTypeMap =
143
+ ValueTypeList.map((key, index) => ({ [key]: index })).reduce((set, value) => ({...set, ...value}), {}) as Record<SerializedValueType, ValueType>;
144
+
145
+
135
146
  /**
136
147
  * collection of cells, basically a wrapper around an
137
148
  * array, with some accessor and control methods.
@@ -357,6 +368,53 @@ export class Cells {
357
368
  this.columns_ = columns;
358
369
  }
359
370
 
371
+ public SerializedTypeToValueType(type?: SerializedValueType|ValueType): ValueType|undefined {
372
+
373
+ if (!type) {
374
+ return undefined;
375
+ }
376
+
377
+ if (typeof type === 'number') {
378
+ return type as ValueType;
379
+ }
380
+
381
+ return ValueTypeMap[type] || undefined;
382
+
383
+ }
384
+
385
+ public ValueTypeToSerializedType(type?: ValueType): SerializedValueType|undefined {
386
+ return type ? ValueTypeList[type] : undefined;
387
+ }
388
+
389
+ /**
390
+ * this method is used for importing legacy data validation types. in those
391
+ * those we used a numeric enum. we're just dropping that altogether (c.f.
392
+ * ValueType, which we're keeping) so we need to translate for backcompat.
393
+ * it's ugly, but it gets us to a better place. we can probably drop at some
394
+ * point in the future.
395
+ *
396
+ * export enum ValidationType {
397
+ * List = 'list',
398
+ * Date = 'date',
399
+ * Range = 'range',
400
+ * Number = 'number',
401
+ * Boolean = 'boolean',
402
+ * }
403
+ *
404
+ */
405
+ public ImportDataValidation(value: DataValidation): DataValidation|undefined {
406
+
407
+ if (typeof (value as any).type === 'number') {
408
+ const types = ['list', 'date', 'range', 'number', 'boolean'];
409
+ (value as any).type = types[(value as any).type];
410
+ if (!value.type) {
411
+ return undefined;
412
+ }
413
+ }
414
+
415
+ return value;
416
+ }
417
+
360
418
  /**
361
419
  * UPDATE: adding optional style refs, for export
362
420
  */
@@ -423,7 +481,7 @@ export class Cells {
423
481
  if (typeof obj.calculated !== 'undefined') {
424
482
  // cell.calculated = obj.calculated;
425
483
  // cell.calculated_type = obj.calculated_type;
426
- cell.SetCalculatedValue(obj.calculated, obj.calculated_type);
484
+ cell.SetCalculatedValue(obj.calculated, this.SerializedTypeToValueType(obj.calculated_type));
427
485
  }
428
486
 
429
487
  if (style_refs) {
@@ -494,7 +552,13 @@ export class Cells {
494
552
  }
495
553
 
496
554
  if (obj.validation) {
497
- cell.validation = obj.validation;
555
+
556
+ // the old type used a numeric enum. we just dropped that in favor
557
+ // of a string enum, so we can export it as a type. but for backwards
558
+ // compatibility we still need to think about the numeric enum.
559
+
560
+ cell.validation = this.ImportDataValidation(obj.validation);
561
+
498
562
  }
499
563
 
500
564
  }
@@ -606,7 +670,9 @@ export class Cells {
606
670
  obj.hyperlink = cell.hyperlink;
607
671
  }
608
672
 
609
- if (options.preserve_type) obj.type = cell.type;
673
+ if (options.preserve_type) {
674
+ obj.type = this.ValueTypeToSerializedType(cell.type);
675
+ }
610
676
  if (options.sheet_id) obj.sheet_id = options.sheet_id;
611
677
  if (options.calculated_value &&
612
678
  typeof cell.calculated !== 'undefined') { // && cell.calculated_type !== ValueType.error) {
@@ -614,7 +680,7 @@ export class Cells {
614
680
 
615
681
  // always preserve error type, because we can't infer
616
682
  if (options.preserve_type || cell.calculated_type === ValueType.error) {
617
- obj.calculated_type = cell.calculated_type;
683
+ obj.calculated_type = this.ValueTypeToSerializedType(cell.calculated_type);
618
684
  }
619
685
  }
620
686
  if (cell.table && table_head) {
@@ -20,7 +20,7 @@
20
20
  */
21
21
 
22
22
  import type { Style } from './style';
23
- import type { ValueType } from './value-type';
23
+ import type { SerializedValueType, ValueType } from './value-type';
24
24
  import type { IArea } from './area';
25
25
  import type { AnnotationLayout } from './layout';
26
26
  import type { DataValidation } from './cell';
@@ -30,10 +30,10 @@ import type { AnnotationType } from 'treb-grid';
30
30
  export interface CellParseResult {
31
31
  row: number,
32
32
  column: number,
33
- type: ValueType,
33
+ type: SerializedValueType; // ValueType,
34
34
  value: number|string|undefined|boolean,
35
35
  calculated?: number|string|undefined|boolean,
36
- calculated_type?: ValueType,
36
+ calculated_type?: SerializedValueType; // ValueType,
37
37
  style_ref?: number,
38
38
  hyperlink?: string,
39
39
  validation?: DataValidation,
@@ -84,12 +84,44 @@ export const IsDimensionedQuantity = (value: unknown): value is DimensionedQuant
84
84
  && (typeof (value as DimensionedQuantity).unit === 'string');
85
85
  };
86
86
 
87
+ /**
88
+ * this is the list of value types. internally, we use an enum. I don't
89
+ * want to change that, at least not at the moment, but that presents a
90
+ * problem for exporting types.
91
+ *
92
+ * we'll switch to string types for import/export, although we still support
93
+ * importing the old numeric enum types for backwards compatibility.
94
+ */
95
+ export const ValueTypeList = [
96
+ 'undefined',
97
+ 'formula',
98
+ 'string',
99
+ 'number',
100
+ 'boolean',
101
+ 'object',
102
+ 'error',
103
+ 'complex',
104
+ 'array',
105
+ 'dimensioned_quantity',
106
+ ] as const;
107
+
87
108
  /**
88
- * I _think_ using enums is faster. I'm not actually sure about that, though.
89
- * it stands to reason that a single int compare is faster than a string
90
- * compare, but you never know with javascript. undefined preferred over null.
91
- * formula implies a string.
92
- *
109
+ * string types for import/export
110
+ */
111
+ export type SerializedValueType = typeof ValueTypeList[number];
112
+
113
+ /**
114
+ * this enum goes back a long way and is pretty ingrained, so I don't
115
+ * want to change it (at least not right now). but if we're exporting types,
116
+ * using enums is a problem.
117
+ *
118
+ * what we will do is keep the enum internally but switch the exported type
119
+ * to a string. the problem then becomes keeping the types matched up
120
+ * properly. I can't arrive at a good way of doing that automatically.
121
+ *
122
+ * old comments:
123
+ * ---
124
+ *
93
125
  * undefined is 0 so we can test it as falsy.
94
126
  *
95
127
  * we're passing this type information out to calculators, so it needs
@@ -46,23 +46,61 @@ export enum SaveFileType {
46
46
  * I would like to do it, though, that `any` looks bad in the public API.
47
47
  */
48
48
  export interface TREBDocument {
49
+
50
+ /** app name, as identifier */
49
51
  app: string;
52
+
53
+ /** app version. we'll warn if you use a file from a newer version */
50
54
  version: string;
55
+
56
+ /**
57
+ * revision number. this is a value that increments on any document change,
58
+ * useful for checking if a document is "dirty".
59
+ */
51
60
  revision?: number;
61
+
62
+ /** document name */
52
63
  name?: string;
64
+
65
+ /**
66
+ * opaque user data. we don't read or parse this, but applications can
67
+ * use it to store arbitrary data.
68
+ */
53
69
  user_data?: any;
54
- sheet_data?: SerializedSheet|SerializedSheet[]; // NOTE: support old version, but it would be nice to drop
70
+
71
+ /**
72
+ * per-sheet data. this should be an array, but for historical reasons
73
+ * we still support a single sheet outside of an array.
74
+ */
75
+ sheet_data?: SerializedSheet|SerializedSheet[];
76
+
77
+ /** document decimal mark */
55
78
  decimal_mark?: '.' | ',';
79
+
80
+ /** active sheet. if unset we'll show the first un-hidden sheet */
56
81
  active_sheet?: number;
82
+
83
+ /**
84
+ * this document includes rendered calculated values. using this lets the
85
+ * app show a document faster, without requiring an initial calculation.
86
+ */
57
87
  rendered_values?: boolean;
58
88
 
59
- // named_ranges?: {[index: string]: IArea};
89
+ /** document named ranges */
60
90
  named_ranges?: Record<string, IArea>;
61
91
 
62
- macro_functions?: SerializedMacroFunction[];
92
+ /** document named expressions */
63
93
  named_expressions?: SerializedNamedExpression[];
94
+
95
+ /** document macro functions */
96
+ macro_functions?: SerializedMacroFunction[];
97
+
98
+ /** document tables */
64
99
  tables?: Table[];
100
+
101
+ /** document shared resources (usually images) */
65
102
  shared_resources?: Record<string, string>;
103
+
66
104
  }
67
105
 
68
106
  export interface ResizeEvent {
@@ -29,7 +29,7 @@ import { Parser } from 'treb-parser';
29
29
  import type { RangeType, AddressType, HyperlinkType } from './address-type';
30
30
  import { is_range, ShiftRange, InRange, is_address } from './address-type';
31
31
  import type { ImportedSheetData, AnchoredAnnotation, CellParseResult, AnnotationLayout, Corner as LayoutCorner, ICellAddress, DataValidation, IArea } from 'treb-base-types/src';
32
- import { ValueType, ValidationType } from 'treb-base-types/src';
32
+ import { type ValueType, ValidationType, type SerializedValueType } from 'treb-base-types/src';
33
33
  import type { Sheet} from './workbook-sheet2';
34
34
  import { VisibleState } from './workbook-sheet2';
35
35
  import type { CellAnchor } from './drawing2/drawing2';
@@ -119,11 +119,13 @@ export class Importer {
119
119
  // console.info(element);
120
120
 
121
121
  let value: undefined | number | boolean | string;
122
- let type: ValueType = ValueType.undefined;
122
+ // let type: ValueType = ValueType.undefined;
123
+ let type: SerializedValueType = 'undefined';
123
124
 
124
125
  let calculated_value: undefined | number | boolean | string;
125
- let calculated_type: ValueType = ValueType.undefined;
126
-
126
+ // let calculated_type: ValueType = ValueType.undefined;
127
+ let calculated_type: SerializedValueType = 'undefined';
128
+
127
129
  // QUESTIONS:
128
130
  //
129
131
  // 1. is v always a value, or can it be an object?
@@ -147,7 +149,7 @@ export class Importer {
147
149
  // console.info(address, 'e', element, 'm', mapped);
148
150
 
149
151
  if (element.a$?.t && element.a$.t === 's') {
150
- type = ValueType.string;
152
+ type = 'string'; // ValueType.string;
151
153
  if (typeof element.v !== undefined) {
152
154
  const index = Number(element.v);
153
155
  if (!isNaN(index) && sheet.shared_strings) {
@@ -158,7 +160,7 @@ export class Importer {
158
160
  }
159
161
  else {
160
162
  if (typeof element.f !== 'undefined') {
161
- type = ValueType.formula;
163
+ type = 'formula'; // ValueType.formula;
162
164
 
163
165
  const formula = (typeof element.f === 'string' ? element.f : element.f.t$) || '';
164
166
 
@@ -219,11 +221,11 @@ export class Importer {
219
221
  if (typeof element.v !== 'undefined') {
220
222
  const num = Number(element.v.toString());
221
223
  if (!isNaN(num)) {
222
- calculated_type = ValueType.number;
224
+ calculated_type = 'number'; // ValueType.number;
223
225
  calculated_value = num;
224
226
  }
225
227
  else {
226
- calculated_type = ValueType.string;
228
+ calculated_type = 'string'; // ValueType.string;
227
229
  calculated_value = element.v.toString();
228
230
  }
229
231
  }
@@ -232,11 +234,11 @@ export class Importer {
232
234
  else if (typeof element.v !== 'undefined') {
233
235
  const num = Number(element.v.toString());
234
236
  if (!isNaN(num)) {
235
- type = ValueType.number;
237
+ type = 'number'; // ValueType.number;
236
238
  value = num;
237
239
  }
238
240
  else {
239
- type = ValueType.string;
241
+ type = 'string'; // ValueType.string;
240
242
  value = element.v.toString();
241
243
  }
242
244
  }
@@ -254,7 +256,7 @@ export class Importer {
254
256
  calculated_type = type;
255
257
  calculated_value = value;
256
258
  value = undefined;
257
- type = ValueType.undefined;
259
+ type = 'undefined'; // ValueType.undefined;
258
260
  }
259
261
  }
260
262
 
@@ -833,11 +835,16 @@ export class Importer {
833
835
 
834
836
  if (is_address(translated)) {
835
837
 
836
- const result = {
838
+ const result: {
839
+ row: number;
840
+ column: number;
841
+ value: string;
842
+ type: SerializedValueType;
843
+ } = {
837
844
  row: translated.row - 1,
838
845
  column: translated.col - 1,
839
846
  value: constructed_function,
840
- type: ValueType.formula,
847
+ type: 'formula', // ValueType.formula,
841
848
  };
842
849
 
843
850
  let matched = false;
@@ -845,7 +852,7 @@ export class Importer {
845
852
  for (const element of data) {
846
853
  if (element.row === result.row && element.column === result.column) {
847
854
  matched = true;
848
- element.type = ValueType.formula;
855
+ element.type = 'formula'; // ValueType.formula;
849
856
  element.value = constructed_function;
850
857
  break;
851
858
  }
@@ -30,7 +30,6 @@ export interface SerializedMacroFunction {
30
30
  name: string;
31
31
  function_def: string;
32
32
  argument_names?: string[];
33
- // argument_default_values?: any[]; // <- new
34
33
  description?: string;
35
34
  }
36
35
 
@@ -805,7 +805,9 @@ export class Grid extends GridBase {
805
805
  * be wiped from the model.
806
806
  */
807
807
  public RemoveAnnotationNodes(): void {
808
- this.layout.RemoveAnnotationNodes();
808
+ if (!this.headless) {
809
+ this.layout.RemoveAnnotationNodes();
810
+ }
809
811
  }
810
812
 
811
813
  /**
@@ -44,47 +44,83 @@ export interface ScrollOffset {
44
44
 
45
45
  export interface SerializedSheet {
46
46
 
47
- // version: string;
48
- // data: any; // FIXME
47
+ /** cell data */
49
48
  data: SerializedCellData;
50
49
 
50
+ /** top-level sheet style, if any */
51
51
  sheet_style: Style.Properties;
52
+
53
+ /** row count */
52
54
  rows: number;
55
+
56
+ /** column count */
53
57
  columns: number;
58
+
59
+ /**
60
+ * cell styles is for empty cells that have styling
61
+ */
54
62
  cell_styles: Array<{row: number; column: number; ref: number, rows?: number}>;
55
63
 
56
- /** @deprecated */
64
+ /**
65
+ * @deprecated use `styles` instead
66
+ */
57
67
  cell_style_refs?: Style.Properties[]; // old
58
- styles?: Style.Properties[]; // new
59
68
 
69
+ /**
70
+ * new implementation
71
+ */
72
+ styles?: Style.Properties[];
73
+
74
+ /**
75
+ * per-row styles
76
+ */
60
77
  row_style: Record<number, Style.Properties|number>;
78
+
79
+ /**
80
+ * per-column styles
81
+ */
61
82
  column_style: Record<number, Style.Properties|number>;
62
83
 
63
84
  /**
64
- * @deprecated - no one uses this anymore and it's weird
85
+ * @deprecated no one uses this anymore and it's weird
65
86
  */
66
87
  row_pattern?: Style.Properties[];
67
88
 
89
+ /** default for new rows */
68
90
  default_row_height?: number;
91
+
92
+ /** default for new columns */
69
93
  default_column_width?: number;
70
94
 
95
+ /** list of row heights. we use a Record instead of an array because it's sparse */
71
96
  row_height?: Record<number, number>;
97
+
98
+ /** list of column widths. we use a Record instead of an array because it's sparse */
72
99
  column_width?: Record<number, number>;
73
- named_ranges?: Record<string, IArea>;
74
100
 
75
- // row_height?: {[index: number]: number};
76
- // column_width?: {[index: number]: number};
77
- // named_ranges?: {[index: string]: IArea};
101
+ /**
102
+ * @deprecated these were moved to the containing document
103
+ */
104
+ named_ranges?: Record<string, IArea>;
78
105
 
79
106
  freeze?: FreezePane;
80
107
 
108
+ /** sheet ID, for serializing references */
81
109
  id?: number;
110
+
111
+ /** sheet name */
82
112
  name?: string;
83
113
 
114
+ /** current active selection */
84
115
  selection: GridSelection;
116
+
117
+ /** */
85
118
  annotations?: Partial<AnnotationData>[]; // Partial<Annotation>[];
119
+
120
+ /** current scroll position */
86
121
  scroll?: ScrollOffset;
87
122
 
123
+ /** visible flag. we only support visible/hidden */
88
124
  visible?: boolean;
89
125
 
90
126
  /** testing */