@trebco/treb 28.17.5 → 29.1.4

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.
Files changed (88) hide show
  1. package/dist/treb-spreadsheet-light.mjs +12 -12
  2. package/dist/treb-spreadsheet.mjs +12 -12
  3. package/dist/treb.d.ts +121 -82
  4. package/eslint.config.js +21 -0
  5. package/package.json +6 -6
  6. package/treb-base-types/src/area.ts +4 -2
  7. package/treb-base-types/src/cell.ts +1 -1
  8. package/treb-base-types/src/cells.ts +16 -7
  9. package/treb-base-types/src/dom-utilities.ts +4 -2
  10. package/treb-base-types/src/import.ts +2 -2
  11. package/treb-base-types/src/rectangle.ts +5 -5
  12. package/treb-base-types/src/text_part.ts +7 -0
  13. package/treb-base-types/src/union.ts +6 -1
  14. package/treb-base-types/src/value-type.ts +1 -1
  15. package/treb-calculator/src/calculator.ts +114 -165
  16. package/treb-calculator/src/dag/calculation_leaf_vertex.ts +1 -2
  17. package/treb-calculator/src/dag/graph.ts +3 -3
  18. package/treb-calculator/src/dag/spreadsheet_vertex.ts +2 -2
  19. package/treb-calculator/src/dag/state_leaf_vertex.ts +2 -4
  20. package/treb-calculator/src/descriptors.ts +28 -2
  21. package/treb-calculator/src/expression-calculator.ts +25 -34
  22. package/treb-calculator/src/function-error.ts +2 -2
  23. package/treb-calculator/src/function-library.ts +16 -0
  24. package/treb-calculator/src/functions/base-functions.ts +185 -211
  25. package/treb-calculator/src/functions/checkbox.ts +0 -1
  26. package/treb-calculator/src/functions/complex-functions.ts +49 -47
  27. package/treb-calculator/src/functions/finance-functions.ts +10 -10
  28. package/treb-calculator/src/functions/function-utilities.ts +26 -0
  29. package/treb-calculator/src/functions/information-functions.ts +21 -41
  30. package/treb-calculator/src/functions/matrix-functions.ts +8 -1
  31. package/treb-calculator/src/functions/sparkline.ts +6 -4
  32. package/treb-calculator/src/functions/statistics-functions.ts +21 -17
  33. package/treb-calculator/src/functions/text-functions.ts +14 -13
  34. package/treb-calculator/src/primitives.ts +48 -37
  35. package/treb-calculator/src/utilities.ts +117 -134
  36. package/treb-charts/src/chart-functions.ts +3 -3
  37. package/treb-charts/src/chart-types.ts +42 -1
  38. package/treb-charts/src/chart-utils.ts +155 -113
  39. package/treb-charts/src/chart.ts +6 -5
  40. package/treb-charts/src/default-chart-renderer.ts +6 -5
  41. package/treb-charts/src/renderer.ts +12 -11
  42. package/treb-charts/src/util.ts +25 -36
  43. package/treb-data-model/package.json +5 -0
  44. package/{treb-grid/src/types → treb-data-model/src}/annotation.ts +2 -2
  45. package/{treb-grid/src/types → treb-data-model/src}/conditional_format.ts +20 -0
  46. package/{treb-grid/src/types → treb-data-model/src}/data_model.ts +231 -133
  47. package/treb-data-model/src/index.ts +45 -0
  48. package/{treb-grid/src/types/named_range.ts → treb-data-model/src/named.ts} +459 -376
  49. package/{treb-grid/src/types → treb-data-model/src}/sheet.ts +13 -5
  50. package/treb-data-model/src/sheet_collection.ts +114 -0
  51. package/{treb-grid/src/types → treb-data-model/src}/sheet_types.ts +6 -3
  52. package/treb-embed/modern.tsconfig.json +1 -0
  53. package/treb-embed/src/custom-element/spreadsheet-constructor.ts +2 -2
  54. package/treb-embed/src/embedded-spreadsheet.ts +125 -270
  55. package/treb-embed/src/selection-state.ts +1 -1
  56. package/treb-embed/src/toolbar-message.ts +1 -1
  57. package/treb-embed/src/types.ts +13 -5
  58. package/treb-export/src/export-worker/export-worker.ts +22 -7
  59. package/treb-export/src/export2.ts +110 -41
  60. package/treb-export/src/import2.ts +6 -5
  61. package/treb-export/src/workbook2.ts +31 -13
  62. package/treb-export/src/xml-utils.ts +5 -1
  63. package/treb-format/src/format.ts +8 -6
  64. package/treb-grid/src/editors/autocomplete.ts +2 -2
  65. package/treb-grid/src/editors/autocomplete_matcher.ts +57 -19
  66. package/treb-grid/src/editors/editor.ts +27 -25
  67. package/treb-grid/src/editors/formula_bar.ts +5 -5
  68. package/treb-grid/src/editors/overlay_editor.ts +1 -2
  69. package/treb-grid/src/index.ts +0 -11
  70. package/treb-grid/src/layout/base_layout.ts +20 -8
  71. package/treb-grid/src/layout/grid_layout.ts +2 -2
  72. package/treb-grid/src/layout/mock-layout.ts +5 -6
  73. package/treb-grid/src/render/selection-renderer.ts +2 -3
  74. package/treb-grid/src/render/tile_renderer.ts +18 -8
  75. package/treb-grid/src/types/grid.ts +96 -67
  76. package/treb-grid/src/types/grid_base.ts +76 -60
  77. package/treb-grid/src/types/grid_command.ts +3 -2
  78. package/treb-grid/src/types/grid_events.ts +12 -6
  79. package/treb-grid/src/types/tab_bar.ts +1 -2
  80. package/treb-parser/src/parser-types.ts +2 -1
  81. package/treb-parser/src/parser.ts +7 -5
  82. package/treb-utils/src/event_source.ts +1 -1
  83. package/treb-utils/src/serialize_html.ts +31 -6
  84. package/.eslintignore +0 -8
  85. package/.eslintrc.cjs +0 -168
  86. package/treb-grid/src/layout/rectangle_cache.ts +0 -86
  87. /package/{treb-grid/src/types → treb-data-model/src}/serialize_options.ts +0 -0
  88. /package/{treb-grid/src/types/grid_selection.ts → treb-data-model/src/sheet_selection.ts} +0 -0
@@ -48,9 +48,7 @@ import {
48
48
  TextPartFlag,
49
49
  } from 'treb-base-types';
50
50
 
51
- import type {
52
- Parser,
53
- ExpressionUnit} from 'treb-parser';
51
+ import type { ExpressionUnit } from 'treb-parser';
54
52
  import {
55
53
  DecimalMarkType,
56
54
  ArgumentSeparatorType,
@@ -66,7 +64,6 @@ import { SelectionRenderer } from '../render/selection-renderer';
66
64
  import { TabBar } from './tab_bar';
67
65
  import type { StatsEntry } from './tab_bar';
68
66
 
69
- import { Sheet } from './sheet';
70
67
  import { MockLayout } from '../layout/mock-layout';
71
68
  import type { BaseLayout } from '../layout/base_layout';
72
69
  import { TileRange } from '../layout/base_layout';
@@ -79,21 +76,24 @@ import { TileRange } from '../layout/base_layout';
79
76
 
80
77
  import { GridLayout } from '../layout/grid_layout';
81
78
 
82
- import type { GridSelection } from './grid_selection';
83
79
  import { OverlayEditor } from '../editors/overlay_editor';
84
80
 
85
81
  import { TileRenderer } from '../render/tile_renderer';
86
82
  import type { GridEvent } from './grid_events';
87
83
  import { ErrorCode } from './grid_events';
88
- import type { LegacySerializedSheet } from './sheet_types';
89
- // import { FormulaBar } from '../editors/formula_bar';
90
- import { FormulaBar } from '../editors/formula_bar';
91
84
 
85
+ import type {
86
+ CompositeNamed,
87
+ DataModel,
88
+ GridSelection,
89
+ LegacySerializedSheet,
90
+ } from 'treb-data-model';
91
+ import { Annotation, type AnnotationData, Sheet } from 'treb-data-model';
92
+
93
+ import { FormulaBar } from '../editors/formula_bar';
92
94
  import type { GridOptions } from './grid_options';
93
95
  import { BorderConstants } from './border_constants';
94
- import type { SerializeOptions } from './serialize_options';
95
96
  import { UA } from '../util/ua';
96
- import { Annotation, type AnnotationData } from './annotation';
97
97
  import { Autocomplete } from '../editors/autocomplete';
98
98
 
99
99
  import { MouseDrag } from './drag_mask';
@@ -109,8 +109,6 @@ import type {
109
109
  import { CommandKey
110
110
  } from './grid_command';
111
111
 
112
- import type { DataModel, SerializedModel } from './data_model';
113
-
114
112
  import { DOMContext } from 'treb-base-types';
115
113
  import { GridBase } from './grid_base';
116
114
  import type { SetRangeOptions } from './set_range_options';
@@ -891,7 +889,8 @@ export class Grid extends GridBase {
891
889
  public FromImportData(
892
890
  import_data: {
893
891
  sheets: ImportedSheetData[],
894
- names?: Record<string, string|number>,
892
+ // names?: Record<string, string|number>,
893
+ named?: CompositeNamed[],
895
894
  active_tab?: number,
896
895
  },
897
896
  render = false,
@@ -969,14 +968,26 @@ export class Grid extends GridBase {
969
968
  }
970
969
 
971
970
  this.model.sheets.UpdateIndexes();
972
- this.model.named_ranges.Reset();
973
- this.model.named_expressions.clear();
974
971
 
972
+ this.model.named.Reset();
973
+ // this.model.named_ranges.Reset();
974
+ // this.model.named_expressions.clear();
975
+
976
+ console.info({IDX: import_data.named});
977
+
978
+ if (import_data.named) {
979
+ this.model.UnserializeComposite(import_data.named, this.active_sheet);
980
+ }
981
+
982
+ /*
975
983
  if (import_data.names) {
976
984
 
985
+ console.info("IDN", { names: import_data.names })
986
+
977
987
  for (const name of Object.keys(import_data.names)) {
978
988
 
979
- const validated = this.model.named_ranges.ValidateNamed(name);
989
+ const validated = this.model.named.ValidateNamed(name);
990
+
980
991
  if (!validated) {
981
992
  console.warn(`invalid name: ${name}`, import_data.names[name]);
982
993
  continue;
@@ -994,14 +1005,14 @@ export class Grid extends GridBase {
994
1005
  const sheet_id = name_map[parse_result.expression.start.sheet || ''];
995
1006
  if (sheet_id) {
996
1007
  parse_result.expression.start.sheet_id = sheet_id;
997
- this.model.named_ranges.SetName(validated, new Area(parse_result.expression.start, parse_result.expression.end), false);
1008
+ this.model.named.SetNamedRange(validated, new Area(parse_result.expression.start, parse_result.expression.end));
998
1009
  }
999
1010
  }
1000
1011
  else if (parse_result.expression.type === 'address') {
1001
1012
  const sheet_id = name_map[parse_result.expression.sheet || ''];
1002
1013
  if (sheet_id) {
1003
1014
  parse_result.expression.sheet_id = sheet_id;
1004
- this.model.named_ranges.SetName(validated, new Area(parse_result.expression), false);
1015
+ this.model.named.SetNamedRange(validated, new Area(parse_result.expression));
1005
1016
  }
1006
1017
  }
1007
1018
  else {
@@ -1022,13 +1033,16 @@ export class Grid extends GridBase {
1022
1033
  }
1023
1034
  return true;
1024
1035
  });
1025
- this.model.named_expressions.set(validated, expr);
1036
+
1037
+ this.model.named.SetNamedExpression(validated, expr);
1038
+
1026
1039
  }
1027
1040
  }
1028
1041
  }
1029
1042
  }
1030
- this.model.named_ranges.RebuildList();
1043
+ // this.model.named_ranges.RebuildList();
1031
1044
  }
1045
+ */
1032
1046
 
1033
1047
  // FIXME: do we need to rebuild autocomplete here (A: yes)
1034
1048
  // ...
@@ -1190,6 +1204,15 @@ export class Grid extends GridBase {
1190
1204
  this.Repaint(true);
1191
1205
  }
1192
1206
 
1207
+ /**
1208
+ * we need this method for split views
1209
+ */
1210
+ public UpdateTabBar(): void {
1211
+ if (this.tab_bar) {
1212
+ this.tab_bar.Update();
1213
+ }
1214
+ }
1215
+
1193
1216
  /**
1194
1217
  * @param initial first call, from the grid Initialize() method
1195
1218
  */
@@ -1563,52 +1586,50 @@ export class Grid extends GridBase {
1563
1586
  }
1564
1587
 
1565
1588
  /**
1566
- * set or clear name
1589
+ * set or clear name. optionally overwrite existing name. note that
1590
+ * you cannot overwrite function names, only existing named ranges/expressions.
1591
+ *
1592
+ * set name to refer to a range (named range) or expression/value (named
1593
+ * expression). range has priority if you set both (FIXME: make that impossible)
1594
+ *
1595
+ * note that expression here must be a valid expression in SL. if you want
1596
+ * to set a literal string, enclose it in double quotes (as you would when
1597
+ * using a string as an argument to a function).
1567
1598
  */
1568
- public SetName(name: string, range?: ICellAddress | Area, expression?: string): void {
1599
+ public SetName(name: string, range?: ICellAddress | Area, expression?: string, scope?: number, overwrite = false): void {
1569
1600
 
1570
- // console.info('setname', name, range, expression);
1601
+ // console.info('setname', name, range, expression, scope, overwrite);
1571
1602
 
1572
1603
  // validate/translate name first
1573
1604
 
1574
- const validated = this.model.named_ranges.ValidateNamed(name);
1605
+ const validated = this.model.named.ValidateNamed(name);
1575
1606
 
1576
1607
  if (!validated) {
1577
1608
  throw new Error('invalid name');
1578
1609
  }
1579
1610
 
1580
- // check against functions
1611
+ name = validated;
1581
1612
 
1582
- // console.info('checking...', name, this.autocomplete_matcher?.function_map);
1613
+ // check against functions. also an error if the name exists
1614
+ // but the overwrite flag is not set.
1583
1615
 
1584
- const compare = name.trim().toUpperCase();
1585
1616
  if (this.autocomplete_matcher) {
1586
- for (const name of Object.keys(this.autocomplete_matcher.function_map)) {
1587
- if (compare === name.toUpperCase()) {
1588
- // const descriptor = this.autocomplete_matcher.function_map[name];
1589
-
1590
- // hmmm... we're not actually setting this type
1591
- // (DescriptorType.Function). it seems like we only
1592
- // set the _other_ type. sloppy.
1593
1617
 
1618
+ const ac_entry = this.autocomplete_matcher.Get(name);
1619
+ if (ac_entry) {
1620
+ if (!ac_entry.named || !overwrite) {
1594
1621
  if (range || expression) {
1595
1622
  throw new Error('name already defined');
1596
1623
  }
1597
-
1598
- //if (descriptor.type !== DescriptorType.Token) {
1599
- // throw new Error('invalid name');
1600
- //}
1601
-
1602
- break; // since we can't have two with the same name
1603
1624
  }
1604
1625
  }
1605
- }
1606
-
1607
- name = validated;
1608
1626
 
1627
+ }
1628
+
1609
1629
  const command: SetNameCommand = {
1610
1630
  key: CommandKey.SetName,
1611
1631
  name,
1632
+ scope,
1612
1633
  };
1613
1634
 
1614
1635
  if (range) {
@@ -1629,7 +1650,19 @@ export class Grid extends GridBase {
1629
1650
 
1630
1651
  }
1631
1652
  else if (expression) {
1653
+
1632
1654
  const parse_result = this.parser.Parse(expression);
1655
+
1656
+ // there's a case we're missing here: if you pass a literal
1657
+ // string, not as a function, that should be interpreted as
1658
+ // a string. we still want to use the parser on functions
1659
+ // and literal types... how to distinguish?
1660
+
1661
+ // actually, check that: let's require strings to be quoted,
1662
+ // so they get interpreted as literals. if you want to do fancy
1663
+ // switching do that at a higher level.
1664
+
1665
+ // ...
1633
1666
 
1634
1667
  // resolve sheet. otherwise we wind up with dangling
1635
1668
  // references. NOTE: need to do this on import as well
@@ -1700,7 +1733,7 @@ export class Grid extends GridBase {
1700
1733
  // should this persist, or should we only subscribe when we're active? (...)
1701
1734
  // in theory, at least, it won't send any events unless something changes
1702
1735
 
1703
- editor.Subscribe(event => this.HighlightDependencies(editor.dependencies));
1736
+ editor.Subscribe(() => this.HighlightDependencies(editor.dependencies));
1704
1737
  }
1705
1738
 
1706
1739
  this.external_editor.AttachNodes(config.nodes, config.assume_formula ?? true);
@@ -2048,7 +2081,7 @@ export class Grid extends GridBase {
2048
2081
 
2049
2082
  if (!area) {
2050
2083
  if (this.primary_selection.empty) { return; }
2051
- area = this.primary_selection.area;
2084
+ area = this.active_sheet.RealArea(this.primary_selection.area);
2052
2085
  }
2053
2086
 
2054
2087
  this.ExecCommand({
@@ -2564,7 +2597,10 @@ export class Grid extends GridBase {
2564
2597
 
2565
2598
  case 'identifier':
2566
2599
  {
2567
- target_area = this.model.named_ranges.Get(parse_result.expression.name);
2600
+ const named = this.model.GetName(parse_result.expression.name, this.active_sheet.id); // assuming it's in the active sheet? what if it's qualified?
2601
+ if (named?.type === 'range') {
2602
+ target_area = named.area;
2603
+ }
2568
2604
  if (!target_area) {
2569
2605
  if (!this.primary_selection.empty) {
2570
2606
  this.SetName(parse_result.expression.name.toUpperCase(), this.primary_selection.area);
@@ -3886,7 +3922,7 @@ export class Grid extends GridBase {
3886
3922
  type: 'cell-event',
3887
3923
  data: {
3888
3924
  type: 'hyperlink',
3889
- data: link,
3925
+ reference: link,
3890
3926
  }
3891
3927
  });
3892
3928
  });
@@ -3939,17 +3975,6 @@ export class Grid extends GridBase {
3939
3975
 
3940
3976
  }
3941
3977
 
3942
- /*
3943
- if (result.event) {
3944
- Yield().then(() => {
3945
- this.grid_events.Publish({
3946
- type: 'cell-event',
3947
- data: result.event,
3948
- });
3949
- });
3950
- }
3951
- */
3952
-
3953
3978
  return;
3954
3979
  }
3955
3980
  }
@@ -3977,7 +4002,7 @@ export class Grid extends GridBase {
3977
4002
  y: move_event.offsetY - offset.y,
3978
4003
  };
3979
4004
  const testpoint = grid_rect.Clamp(point.x, point.y);
3980
- const address = this.layout.PointToAddress_Grid(testpoint, true);
4005
+ const address = this.layout.PointToAddress_Grid(testpoint);
3981
4006
 
3982
4007
  const scroll_node = this.layout.scroll_reference_node;
3983
4008
 
@@ -4349,7 +4374,7 @@ export class Grid extends GridBase {
4349
4374
  const data = this.active_sheet.CellData(selection.area.start);
4350
4375
  const target = new Area(data.merge_area ? data.merge_area.start : selection.target);
4351
4376
 
4352
- let label = this.model.named_ranges.MatchSelection(selection.area, target);
4377
+ let label = this.model.named.MatchSelection(selection.area, target);
4353
4378
 
4354
4379
  if (!label) {
4355
4380
 
@@ -4375,16 +4400,16 @@ export class Grid extends GridBase {
4375
4400
  // for now, we might update that in the future.
4376
4401
 
4377
4402
  if (this.overlay_editor?.editing && this.overlay_editor.selecting) {
4378
- this.overlay_editor.InsertReference(label, 0);
4403
+ this.overlay_editor.InsertReference(label);
4379
4404
  }
4380
4405
  else if (this.formula_bar && this.formula_bar.selecting) {
4381
- this.formula_bar.InsertReference(label, 0);
4406
+ this.formula_bar.InsertReference(label);
4382
4407
  }
4383
4408
  else if (this.external_editor_config) {
4384
4409
 
4385
4410
  if (this.external_editor?.active) {
4386
4411
  this.external_editor.FocusEditor();
4387
- this.external_editor.InsertReference(label, 0);
4412
+ this.external_editor.InsertReference(label);
4388
4413
  }
4389
4414
 
4390
4415
  if (this.external_editor_config.update) {
@@ -5338,8 +5363,11 @@ export class Grid extends GridBase {
5338
5363
  break;
5339
5364
 
5340
5365
  case 'identifier':
5341
- if (this.model.named_ranges.Get(unit.name)) {
5342
- unit.name = unit.name.toUpperCase();
5366
+ {
5367
+ const named_range = this.model.GetName(unit.name, this.active_sheet.id); // FIXME: is this the correct sheet ref?
5368
+ if (named_range?.type === 'range') {
5369
+ unit.name = unit.name.toUpperCase();
5370
+ }
5343
5371
  }
5344
5372
  break;
5345
5373
 
@@ -6133,6 +6161,7 @@ export class Grid extends GridBase {
6133
6161
  // be a rectangle) and one of those new cells might itself be merged.
6134
6162
  // so we need to iterate. there's a lot of duplication here, though.
6135
6163
 
6164
+ // eslint-disable-next-line no-constant-condition
6136
6165
  recheck_loop: while (true) {
6137
6166
  for (const cell of this.active_sheet.cells.Iterate(real_area, false)) {
6138
6167
  if (cell.merge_area && !real_area.ContainsArea(cell.merge_area)) {
@@ -6420,8 +6449,8 @@ export class Grid extends GridBase {
6420
6449
  const target = new Area(data.merge_area ? data.merge_area.start : selection.target);
6421
6450
 
6422
6451
  this.formula_bar.label =
6423
- this.model.named_ranges.MatchSelection(selection.area, target)
6424
- || Area.CellAddressToLabel(target.start);
6452
+ this.model.named.MatchSelection(selection.area, target)
6453
+ || Area.CellAddressToLabel(target.start);
6425
6454
 
6426
6455
  }
6427
6456
 
@@ -36,21 +36,24 @@
36
36
  */
37
37
 
38
38
  import { EventSource } from 'treb-utils';
39
- import type { DataModel, MacroFunction, SerializedModel, SerializedNamedExpression, ViewModel } from './data_model';
39
+ import type { DataModel, ConditionalFormat, // MacroFunction, SerializedModel, SerializedNamedExpression,
40
+ ViewModel } from 'treb-data-model';
41
+
40
42
  import type { Parser, UnitAddress} from 'treb-parser';
41
- import { type ExpressionUnit, IllegalSheetNameRegex, ParseCSV, ArgumentSeparatorType, DecimalMarkType } from 'treb-parser';
43
+ import { type ExpressionUnit, IllegalSheetNameRegex, ParseCSV, DecimalMarkType } from 'treb-parser';
42
44
  import { Area, IsCellAddress, ValidationType, ValueType, DefaultTableSortOptions } from 'treb-base-types';
43
- import type { ICellAddress, IArea, Cell, CellValue , Style, CellStyle, Table, TableSortOptions, TableTheme, Complex, PatchOptions as PatchAreaOptions } from 'treb-base-types';
44
- import { Sheet } from './sheet';
45
+ import type { ICellAddress, IArea, Cell, CellValue, CellStyle, Table, TableSortOptions, TableTheme, Complex, PatchOptions as PatchAreaOptions } from 'treb-base-types';
46
+
47
+ import { Sheet, type SerializeOptions, type Annotation } from 'treb-data-model';
48
+
45
49
  import type { FunctionDescriptor} from '../editors/autocomplete_matcher';
46
- import { AutocompleteMatcher, DescriptorType } from '../editors/autocomplete_matcher';
50
+ import { AutocompleteMatcher } from '../editors/autocomplete_matcher';
47
51
  import { NumberFormat, ValueParser } from 'treb-format';
48
52
 
49
53
  import type { GridEvent } from './grid_events';
50
54
  import { ErrorCode } from './grid_events';
51
55
  import type { CommandRecord, DataValidationCommand, DuplicateSheetCommand, FreezeCommand, InsertColumnsCommand, InsertRowsCommand, ResizeColumnsCommand, ResizeRowsCommand, SelectCommand, SetRangeCommand, ShowSheetCommand, SortTableCommand } from './grid_command';
52
56
  import { DefaultGridOptions, type GridOptions } from './grid_options';
53
- import type { SerializeOptions } from './serialize_options';
54
57
 
55
58
  import { BorderConstants } from './border_constants';
56
59
 
@@ -58,15 +61,18 @@ import { CommandKey } from './grid_command';
58
61
  import type { Command, ActivateSheetCommand,
59
62
  DeleteSheetCommand, UpdateBordersCommand, SheetSelection } from './grid_command';
60
63
  import type { UpdateFlags } from './update_flags';
61
- import type { FreezePane, LegacySerializedSheet } from './sheet_types';
62
- import type { Annotation } from './annotation';
64
+ import type { FreezePane, LegacySerializedSheet } from 'treb-data-model';
63
65
  import type { ClipboardCellData } from './clipboard_data';
64
- import type { ConditionalFormat } from './conditional_format';
65
66
 
66
67
  interface PatchOptions extends PatchAreaOptions {
67
68
  sheet: Sheet;
68
69
  }
69
70
 
71
+ // this is an assert, bascially, for completeness. we could probably
72
+ // resolve the eslint issue (there's no type option) but not sure it's
73
+ // useful to do so
74
+
75
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
70
76
  const AssertNever = (value: never) => {
71
77
  console.error('invalid case');
72
78
  };
@@ -666,6 +672,7 @@ export class GridBase {
666
672
  *
667
673
  * this is non-UI; specialization should handle the UI part
668
674
  */
675
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
669
676
  public UpdateSheets(data: LegacySerializedSheet[], render = false, activate_sheet?: number | string): void {
670
677
 
671
678
  Sheet.Reset(); // reset ID generation
@@ -719,24 +726,43 @@ export class GridBase {
719
726
  */
720
727
  public SetAutocompleteFunctions(functions: FunctionDescriptor[]): void {
721
728
 
722
- // why does iterable support forEach but not map?
723
-
724
729
  const expressions: FunctionDescriptor[] = [];
730
+
731
+ for (const entry of this.model.named.list) {
732
+ expressions.push({
733
+ name: entry.name,
734
+ named: true,
735
+ type: 'token',
736
+ });
737
+ }
738
+
739
+ /*
725
740
  for (const name of this.model.named_expressions.keys()) {
726
741
  expressions.push({
727
- name, type: DescriptorType.Function,
742
+ name,
743
+ named: true,
744
+ type: 'token',
728
745
  });
729
746
  }
747
+ */
730
748
 
749
+ const consolidated= functions.slice(0).concat(expressions);
750
+
751
+ /*
731
752
  const consolidated = functions.slice(0).concat(
732
753
  this.model.named_ranges.List().map((named_range) => {
733
- return { name: named_range.name, type: DescriptorType.Token };
754
+ return {
755
+ name: named_range.name,
756
+ named: true,
757
+ type: 'token'
758
+ };
734
759
  }),
735
760
  expressions,
736
761
  );
762
+ */
737
763
 
738
- //this.autocomplete_matcher.SetFunctions(functions);
739
764
  this.autocomplete_matcher.SetFunctions(consolidated);
765
+
740
766
  }
741
767
 
742
768
  public ResetMetadata(): void {
@@ -813,8 +839,9 @@ export class GridBase {
813
839
 
814
840
  Sheet.Reset();
815
841
  this.UpdateSheets([], true);
816
- this.model.named_ranges.Reset();
817
- this.model.named_expressions.clear();
842
+
843
+ this.model.named.Reset();
844
+
818
845
  this.model.macro_functions.clear(); // = {};
819
846
  this.model.tables.clear();
820
847
 
@@ -839,7 +866,7 @@ export class GridBase {
839
866
  return false;
840
867
  }
841
868
 
842
- let valid = true;
869
+ // let valid = true;
843
870
 
844
871
  for (const cell of sheet.cells.Iterate(area)) {
845
872
 
@@ -885,9 +912,9 @@ export class GridBase {
885
912
  });
886
913
  */
887
914
 
888
- if (!valid) {
889
- return false;
890
- }
915
+ // if (!valid) {
916
+ // return false;
917
+ // }
891
918
 
892
919
  }
893
920
  return true;
@@ -985,7 +1012,7 @@ export class GridBase {
985
1012
  if (i === command.index || sheet.id === command.id || sheet.name.toLowerCase() === named_sheet) {
986
1013
  is_active = (sheet === this.active_sheet);
987
1014
 
988
- this.model.named_ranges.RemoveRangesForSheet(sheet.id);
1015
+ this.model.named.RemoveRangesForSheet(sheet.id);
989
1016
  target_name = sheet.name;
990
1017
 
991
1018
  index = i;
@@ -1917,6 +1944,7 @@ export class GridBase {
1917
1944
  // have to have a proper area. there's no case where we would
1918
1945
  // want to add it. so we only handle the area case.
1919
1946
 
1947
+ // eslint-disable-next-line no-fallthrough
1920
1948
  case CommandKey.RemoveConditionalFormat:
1921
1949
 
1922
1950
  if (command.area) {
@@ -2515,7 +2543,7 @@ export class GridBase {
2515
2543
  return;
2516
2544
  }
2517
2545
 
2518
- let error = false;
2546
+ // let error = false;
2519
2547
  area = sheet.RealArea(area); // collapse
2520
2548
 
2521
2549
  for (const cell of sheet.cells.Iterate(area)) {
@@ -2554,13 +2582,17 @@ export class GridBase {
2554
2582
  }
2555
2583
  }
2556
2584
 
2585
+ /*
2557
2586
  if (error) {
2558
2587
  this.Error(ErrorCode.array); // `You can't change part of an array.`
2559
2588
  }
2560
2589
  else {
2561
2590
  sheet.ClearArea(area);
2562
2591
  }
2563
-
2592
+ */
2593
+
2594
+ sheet.ClearArea(area);
2595
+
2564
2596
  }
2565
2597
 
2566
2598
  /**
@@ -2678,6 +2710,7 @@ export class GridBase {
2678
2710
  *
2679
2711
  * @param command
2680
2712
  */
2713
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2681
2714
  protected SelectInternal(command: SelectCommand) {
2682
2715
  // does nothing
2683
2716
  }
@@ -2942,7 +2975,7 @@ export class GridBase {
2942
2975
  }
2943
2976
 
2944
2977
 
2945
- this.model.named_ranges.PatchNamedRanges(target_sheet.id, 0, 0, command.before_row, command.count);
2978
+ this.model.named.PatchNamedRanges(target_sheet.id, 0, 0, command.before_row, command.count);
2946
2979
 
2947
2980
  const target_sheet_name = target_sheet.name.toLowerCase();
2948
2981
 
@@ -3284,7 +3317,7 @@ export class GridBase {
3284
3317
  }
3285
3318
 
3286
3319
 
3287
- this.model.named_ranges.PatchNamedRanges(target_sheet.id, command.before_column, command.count, 0, 0);
3320
+ this.model.named.PatchNamedRanges(target_sheet.id, command.before_column, command.count, 0, 0);
3288
3321
 
3289
3322
  // FIXME: we need an event here?
3290
3323
 
@@ -3929,7 +3962,7 @@ export class GridBase {
3929
3962
  sheet.UpdateCellStyle(address, {
3930
3963
  indent: Math.max(0, (style.indent || 0) + command.delta),
3931
3964
  }, true);
3932
- };
3965
+ }
3933
3966
  }
3934
3967
 
3935
3968
  if (sheet === this.active_sheet) {
@@ -4011,42 +4044,25 @@ export class GridBase {
4011
4044
  // FOR THE TIME BEING we're going to add that restriction to
4012
4045
  // the calling function, which (atm) is the only way to get here.
4013
4046
 
4014
- if (command.area) {
4015
-
4016
- //if (this.model.named_expressions[command.name]) {
4017
- // delete this.model.named_expressions[command.name];
4018
- //}
4019
- this.model.named_expressions.delete(command.name);
4047
+ {
4048
+ const ac_token: FunctionDescriptor = { type: 'token', named: true, name: command.name, scope: command.scope };
4049
+ if (command.area || command.expression) {
4050
+ if (command.area) {
4051
+ this.model.named.SetNamedRange(command.name, new Area(command.area.start, command.area.end), command.scope);
4052
+ }
4053
+ else if (command.expression) {
4054
+ this.model.named.SetNamedExpression(command.name, command.expression, command.scope);
4055
+ }
4056
+ this.autocomplete_matcher.AddFunctions(ac_token);
4057
+ }
4058
+ else {
4059
+ this.model.named.ClearName(command.name, command.scope);
4060
+ this.autocomplete_matcher.RemoveFunctions(ac_token);
4061
+ }
4020
4062
 
4021
- this.model.named_ranges.SetName(command.name,
4022
- new Area(command.area.start, command.area.end));
4023
- this.autocomplete_matcher.AddFunctions({
4024
- type: DescriptorType.Token,
4025
- name: command.name,
4026
- });
4027
- }
4028
- else if (command.expression) {
4029
- this.model.named_ranges.ClearName(command.name);
4030
- this.model.named_expressions.set(command.name, command.expression);
4031
- this.autocomplete_matcher.AddFunctions({
4032
- type: DescriptorType.Token,
4033
- name: command.name,
4034
- });
4035
- }
4036
- else {
4037
- this.model.named_ranges.ClearName(command.name);
4038
- //if (this.model.named_expressions[command.name]) {
4039
- // delete this.model.named_expressions[command.name];
4040
- //}
4041
- this.model.named_expressions.delete(command.name);
4042
-
4043
- this.autocomplete_matcher.RemoveFunctions({
4044
- type: DescriptorType.Token,
4045
- name: command.name,
4046
- });
4063
+ flags.structure_event = true;
4064
+ flags.structure_rebuild_required = true;
4047
4065
  }
4048
- flags.structure_event = true;
4049
- flags.structure_rebuild_required = true;
4050
4066
  break;
4051
4067
 
4052
4068
  case CommandKey.UpdateBorders:
@@ -19,10 +19,10 @@
19
19
  *
20
20
  */
21
21
 
22
- import type { ICellAddress, IArea, Style, CellStyle, Color, CellValue, Table, TableSortType, TableTheme } from 'treb-base-types';
22
+ import type { ICellAddress, IArea, CellStyle, Color, CellValue, Table, TableSortType, TableTheme } from 'treb-base-types';
23
23
  import type { ExpressionUnit } from 'treb-parser';
24
24
  import type { BorderConstants } from './border_constants';
25
- import type { ConditionalFormat } from './conditional_format';
25
+ import type { ConditionalFormat } from 'treb-data-model';
26
26
 
27
27
  /**
28
28
  * switching to an exec-command based model, so we can serialize
@@ -220,6 +220,7 @@ export interface SetNameCommand {
220
220
  name: string;
221
221
  area?: IArea;
222
222
  expression?: ExpressionUnit;
223
+ scope?: number;
223
224
  }
224
225
 
225
226
  export interface DataValidationCommand {