@trebco/treb 30.2.4 → 30.2.10

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.
@@ -34,4 +34,5 @@ export type { AnnotationData, AnnotationType } from './annotation';
34
34
 
35
35
  export * from './data-validation';
36
36
  export * from './types';
37
+ export * from './language-model';
37
38
 
@@ -37,5 +37,8 @@ export interface LanguageModel {
37
37
  version?: string;
38
38
  locale?: string;
39
39
  functions?: TranslatedFunctionDescriptor[];
40
+
41
+ boolean_true?: string;
42
+ boolean_false?: string;
40
43
  }
41
44
 
@@ -807,19 +807,6 @@ export class Sheet {
807
807
  }
808
808
  }
809
809
 
810
- /* *
811
- * factory method creates a sheet from a 2D array.
812
- *
813
- * /
814
- public static FromArray(data: any[] = [], transpose = false): Sheet {
815
- const sheet = new Sheet();
816
- sheet.cells.FromArray(data, transpose);
817
-
818
- return sheet;
819
- }
820
- */
821
-
822
-
823
810
  // --- public methods -------------------------------------------------------
824
811
 
825
812
  public MergeCells(area: Area): void {
@@ -49,7 +49,10 @@ import type {
49
49
  CondifionalFormatExpressionOptions,
50
50
  ConditionalFormatCellMatchOptions,
51
51
  ConditionalFormatCellMatch,
52
-
52
+
53
+ LanguageModel,
54
+ TranslatedFunctionDescriptor,
55
+
53
56
  } from 'treb-data-model';
54
57
 
55
58
 
@@ -88,7 +91,6 @@ import { Spinner } from './spinner';
88
91
  import { type EmbeddedSpreadsheetOptions, DefaultOptions, type ExportOptions } from './options';
89
92
  import { type TREBDocument, SaveFileType, LoadSource, type EmbeddedSheetEvent, type InsertTableOptions } from './types';
90
93
 
91
- import type { LanguageModel, TranslatedFunctionDescriptor } from './language-model';
92
94
  import type { SelectionState } from './selection-state';
93
95
  import type { BorderToolbarMessage, ToolbarMessage } from './toolbar-message';
94
96
 
@@ -341,8 +343,9 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
341
343
  return Localization;
342
344
  }
343
345
 
344
- /** loaded language model, if any */
346
+ /* * loaded language model, if any (moved to data model) * /
345
347
  protected language_model?: LanguageModel;
348
+ */
346
349
 
347
350
  /** FIXME: fix type (needs to be extensible) */
348
351
  protected events = new EventSource<{ type: string }>();
@@ -1204,10 +1207,10 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
1204
1207
 
1205
1208
  let list: FunctionDescriptor[] = this.calculator.SupportedFunctions();
1206
1209
 
1207
- if (this.language_model?.functions) {
1210
+ if (this.model.language_model?.functions) {
1208
1211
 
1209
1212
  const map: Record<string, TranslatedFunctionDescriptor> = {};
1210
- for (const entry of this.language_model.functions || []) {
1213
+ for (const entry of this.model.language_model.functions || []) {
1211
1214
  map[entry.base.toUpperCase()] = entry;
1212
1215
  }
1213
1216
 
@@ -2002,8 +2005,6 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
2002
2005
  language = parts[0];
2003
2006
  }
2004
2007
 
2005
- this.SetLanguage(); // clear
2006
-
2007
2008
  language = language.toLowerCase();
2008
2009
 
2009
2010
  let mod: { LanguageMap: LanguageModel } | undefined;
@@ -2029,39 +2030,14 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
2029
2030
  }
2030
2031
 
2031
2032
  if (mod) {
2032
- this.SetLanguage(mod.LanguageMap);
2033
- }
2034
-
2035
- }
2036
-
2037
- /**
2038
- * this is not public _yet_
2039
- *
2040
- * @internal
2041
- */
2042
- public SetLanguage(model?: LanguageModel): void {
2043
-
2044
- this.language_model = model;
2045
-
2046
- if (!model) {
2047
- this.grid.SetLanguageMap(); // clear
2033
+ this.model.SetLanguage(mod.LanguageMap);
2048
2034
  }
2049
2035
  else {
2050
-
2051
- // create a name map for grid
2052
-
2053
- const map: Record< string, string > = {};
2054
-
2055
- if (model.functions) {
2056
- for (const entry of model.functions || []) {
2057
- map[entry.base] = entry.name;
2058
- }
2059
- }
2060
-
2061
- this.grid.SetLanguageMap(map);
2062
-
2036
+ this.model.SetLanguage();
2063
2037
  }
2064
2038
 
2039
+ this.grid.Reselect();
2040
+ this.grid.Update(true);
2065
2041
  this.UpdateAC();
2066
2042
 
2067
2043
  }
@@ -727,6 +727,20 @@ export class TileRenderer {
727
727
  let pad_entry: RenderTextPart | undefined;
728
728
  let composite_width = 0;
729
729
 
730
+ // -------------------------------------------------------------------------
731
+
732
+ // moved translated boolean formatting here. I don't like this. it
733
+ // should be in sheet (at least that's where the rest of formatting
734
+ // is), but sheet doesn't have a reference to data model (and because
735
+ // sheets are owned by data model, I don't want to add a circular ref).
736
+
737
+ if (cell.rendered_type === ValueType.boolean) {
738
+ const value = cell.calculated_type ? cell.calculated : cell.value;
739
+ cell.formatted = value ? (this.model.language_model?.boolean_true || 'TRUE') : (this.model.language_model?.boolean_false || 'FALSE');
740
+ }
741
+
742
+ // -------------------------------------------------------------------------
743
+
730
744
  let override_formatting: string | undefined;
731
745
  let formatted = cell.editing ? '' : cell.formatted; // <-- empty on editing, to remove overflows
732
746
 
@@ -175,18 +175,6 @@ export class Grid extends GridBase {
175
175
 
176
176
  // --- private members -------------------------------------------------------
177
177
 
178
- /**
179
- * maps common language (english) -> local language. this should
180
- * be passed in (actually set via a function).
181
- */
182
- private language_map?: Record<string, string>;
183
-
184
- /**
185
- * maps local language -> common (english). this should be constructed
186
- * when the forward function is passed in, so there's a 1-1 correspondence.
187
- */
188
- private reverse_language_map?: Record<string, string>;
189
-
190
178
  // testing
191
179
  private hover_data: {
192
180
  note?: boolean;
@@ -648,33 +636,10 @@ export class Grid extends GridBase {
648
636
  // --- public methods --------------------------------------------------------
649
637
 
650
638
  /**
651
- * set the language translation map. this is a set of function names
652
- * (in english) -> the local equivalent. both should be in canonical form,
653
- * as that will be used when we translate one way or the other.
639
+ * re-select the current selection, for side effects. used when switching
640
+ * languages to update the function view (if any)
654
641
  */
655
- public SetLanguageMap(language_map?: Record<string, string>) {
656
-
657
- if (!language_map) {
658
- this.language_map = this.reverse_language_map = undefined;
659
- }
660
- else {
661
-
662
- const keys = Object.keys(language_map);
663
-
664
- // normalize forward
665
- this.language_map = {};
666
- for (const key of keys) {
667
- this.language_map[key.toUpperCase()] = language_map[key];
668
- }
669
-
670
- // normalize backward
671
- this.reverse_language_map = {};
672
- for (const key of keys) {
673
- const value = language_map[key];
674
- this.reverse_language_map[value.toUpperCase()] = key;
675
- }
676
-
677
- }
642
+ public Reselect() {
678
643
 
679
644
  // we might need to update the current displayed selection. depends
680
645
  // on when we expect languages to be set.
@@ -2171,7 +2136,7 @@ export class Grid extends GridBase {
2171
2136
 
2172
2137
 
2173
2138
  // this is public so we need to (un)translate.
2174
- data = this.UntranslateData(data);
2139
+ data = this.model.UntranslateData(data);
2175
2140
 
2176
2141
  // single value, easiest
2177
2142
  if (!Array.isArray(data)) {
@@ -2481,105 +2446,12 @@ export class Grid extends GridBase {
2481
2446
 
2482
2447
  // --- private methods -------------------------------------------------------
2483
2448
 
2484
- /**
2485
- * translation back and forth is the same operation, with a different
2486
- * (inverted) map. although it still might be worth inlining depending
2487
- * on cost.
2488
- *
2489
- * FIXME: it's about time we started using proper maps, we dropped
2490
- * support for IE11 some time ago.
2491
- */
2492
- private TranslateInternal(value: string, map: Record<string, string>): string {
2493
-
2494
- const parse_result = this.parser.Parse(value);
2495
-
2496
- if (parse_result.expression) {
2497
-
2498
- let modified = false;
2499
- this.parser.Walk(parse_result.expression, unit => {
2500
- if (unit.type === 'call') {
2501
- const replacement = map[unit.name.toUpperCase()];
2502
- if (replacement) {
2503
- modified = true;
2504
- unit.name = replacement;
2505
- }
2506
- }
2507
- return true;
2508
- });
2509
-
2510
- if (modified) {
2511
- return '=' + this.parser.Render(parse_result.expression, { missing: '' });
2512
- }
2513
- }
2514
-
2515
- return value;
2516
-
2517
- }
2518
-
2519
2449
  protected RenameSheetInternal(target: Sheet, name: string) {
2520
2450
  super.RenameSheetInternal(target, name);
2521
2451
  this.tab_bar?.Update();
2522
2452
 
2523
2453
  }
2524
2454
 
2525
- /**
2526
- * translate function from common (english) -> local language. this could
2527
- * be inlined (assuming it's only called in one place), but we are breaking
2528
- * it out so we can develop/test/manage it.
2529
- */
2530
- protected TranslateFunction(value: string): string {
2531
- if (this.language_map) {
2532
- return this.TranslateInternal(value, this.language_map);
2533
- }
2534
- return value;
2535
- }
2536
-
2537
- /**
2538
- * translate from local language -> common (english).
2539
- * @see TranslateFunction
2540
- */
2541
- protected UntranslateFunction(value: string): string {
2542
- if (this.reverse_language_map) {
2543
- return this.TranslateInternal(value, this.reverse_language_map);
2544
- }
2545
- return value;
2546
- }
2547
-
2548
- protected UntranslateData(value: CellValue|CellValue[]|CellValue[][]): CellValue|CellValue[]|CellValue[][] {
2549
-
2550
- if (Array.isArray(value)) {
2551
-
2552
- // could be 1d or 2d. typescript is complaining, not sure why...
2553
-
2554
- if (Is2DArray(value)) {
2555
- return value.map(row => row.map(entry => {
2556
- if (entry && typeof entry === 'string' && entry[0] === '=') {
2557
- return this.UntranslateFunction(entry);
2558
- }
2559
- return entry;
2560
- }));
2561
- }
2562
- else {
2563
- return value.map(entry => {
2564
- if (entry && typeof entry === 'string' && entry[0] === '=') {
2565
- return this.UntranslateFunction(entry);
2566
- }
2567
- return entry;
2568
- });
2569
- }
2570
-
2571
- }
2572
- else if (value && typeof value === 'string' && value[0] === '=') {
2573
-
2574
- // single value
2575
- value = this.UntranslateFunction(value);
2576
-
2577
- }
2578
-
2579
- return value;
2580
-
2581
- }
2582
-
2583
2455
  private StyleDefaultFromTheme() {
2584
2456
  this.model.theme_style_properties.font_face = this.theme.grid_cell?.font_face || '';
2585
2457
  this.model.theme_style_properties.font_size =
@@ -5520,15 +5392,26 @@ export class Grid extends GridBase {
5520
5392
 
5521
5393
  }
5522
5394
 
5523
- const parse_result: ParseResult2 = (expression && expression.type === 'complex') ?
5524
- {
5395
+ let parse_result: ParseResult2|undefined;
5396
+
5397
+ if (expression?.type === 'complex') {
5398
+ parse_result = {
5525
5399
  type: ValueType.complex,
5526
5400
  value: {
5527
5401
  real: expression.real,
5528
5402
  imaginary: expression.imaginary
5529
5403
  },
5530
- } :
5531
- ValueParser.TryParse(value);
5404
+ };
5405
+ }
5406
+ else if (expression?.type === 'literal' && typeof expression.value === 'boolean') {
5407
+ parse_result = {
5408
+ type: ValueType.boolean,
5409
+ value: expression.value,
5410
+ };
5411
+ }
5412
+ else {
5413
+ parse_result = ValueParser.TryParse(value);
5414
+ }
5532
5415
 
5533
5416
  if (!is_function && parse_result.type === ValueType.number) {
5534
5417
 
@@ -5593,7 +5476,7 @@ export class Grid extends GridBase {
5593
5476
  key: CommandKey.SetRange,
5594
5477
  area: array ? selection.area : target,
5595
5478
  array,
5596
- value: is_function ? this.UntranslateFunction(value || '') : parse_result.value,
5479
+ value: is_function ? this.model.UntranslateFunction(value || '') : parse_result.value,
5597
5480
  });
5598
5481
 
5599
5482
  if (exec) {
@@ -5778,7 +5661,10 @@ export class Grid extends GridBase {
5778
5661
  }
5779
5662
  }
5780
5663
  else if (cell.ValueIsBoolean()) {
5781
- return cell.value.toString().toUpperCase(); // ? 'True' : 'False';
5664
+
5665
+ // TRANSLATION: FIXME/CENTRALIZE
5666
+ return cell.value ? (this.model.language_model?.boolean_true || 'TRUE') : (this.model.language_model?.boolean_false || 'FALSE');
5667
+
5782
5668
  }
5783
5669
  else if (cell.ValueIsNumber()) { // no style: I think this is no longer possible
5784
5670
  if (cell_value && Localization.decimal_separator === ',') {
@@ -5821,7 +5707,7 @@ export class Grid extends GridBase {
5821
5707
  // this is where we _render_ translation. so names in function
5822
5708
  // calls shoule be translated before returning.
5823
5709
 
5824
- cell_value = this.TranslateFunction(cell.value);
5710
+ cell_value = this.model.TranslateFunction(cell.value);
5825
5711
 
5826
5712
  }
5827
5713
 
@@ -398,6 +398,12 @@ export interface OptionalParserFlags {
398
398
  */
399
399
  // complex_numbers: true,
400
400
 
401
+ /** string representing boolean true, for parsing/rendering */
402
+ boolean_true?: string;
403
+
404
+ /** string representing boolean false, for parsing/rendering */
405
+ boolean_false?: string;
406
+
401
407
  }
402
408
 
403
409
  export type ParserFlags = Partial<OptionalParserFlags> & RequiredParserFlags;
@@ -423,6 +429,10 @@ export interface RenderOptions {
423
429
  convert_imaginary_number: 'i'|'j';
424
430
  long_structured_references: boolean;
425
431
  table_name: string;
432
+
433
+ boolean_true?: string;
434
+ boolean_false?: string;
435
+
426
436
  }
427
437
 
428
438
  /*
@@ -439,5 +449,7 @@ export const DefaultParserConfig: ParserFlags = {
439
449
  fractions: true,
440
450
  decimal_mark: DecimalMarkType.Period,
441
451
  argument_separator: ArgumentSeparatorType.Comma,
452
+ boolean_true: 'TRUE',
453
+ boolean_false: 'FALSE',
442
454
  };
443
455
 
@@ -108,8 +108,12 @@ const LC_Z = 0x7a;
108
108
  const LC_I = 0x69;
109
109
  // const LC_J = 0x6a;
110
110
 
111
+ // there are a couple of characters we don't want in this
112
+ // range; we should split into separate ranges. also we
113
+ // probably have characters we don't need (atm)
114
+
111
115
  const ACCENTED_RANGE_START = 192;
112
- const ACCENTED_RANGE_END = 312;
116
+ const ACCENTED_RANGE_END = 382; // bumping up for polish // 312;
113
117
 
114
118
  /**
115
119
  * precedence map
@@ -533,7 +537,7 @@ export class Parser {
533
537
  convert_argument_separator,
534
538
  // convert_imaginary_number,
535
539
  long_structured_references,
536
- table_name
540
+ table_name,
537
541
  } = options;
538
542
 
539
543
  // use default separator, unless we're explicitly converting.
@@ -673,6 +677,18 @@ export class Parser {
673
677
  // escape any quotation marks in string
674
678
  return '"' + unit.value.replace(/"/g, '""') + '"';
675
679
  }
680
+ else if (typeof unit.value === 'boolean') {
681
+
682
+ // use render option (replacement) value; then flags value; then a default
683
+
684
+ if (unit.value) {
685
+ return options.boolean_true || this.flags.boolean_true || 'true' ; // default
686
+ }
687
+ else {
688
+ return options.boolean_false || this.flags.boolean_false || 'false' ; // default
689
+ }
690
+
691
+ }
676
692
  else if (convert_decimal && typeof unit.value === 'number') {
677
693
  if (unit.text) {
678
694
  // here we want to translate the literal typed-in value.
@@ -2290,6 +2306,8 @@ export class Parser {
2290
2306
 
2291
2307
  }
2292
2308
 
2309
+ /* remove special handling
2310
+
2293
2311
  // special handling
2294
2312
 
2295
2313
  if (str.toLowerCase() === 'true') {
@@ -2309,6 +2327,8 @@ export class Parser {
2309
2327
  };
2310
2328
  }
2311
2329
 
2330
+ */
2331
+
2312
2332
  // function takes precendence over address? I guess so
2313
2333
 
2314
2334
  this.ConsumeWhiteSpace();
@@ -2345,8 +2365,29 @@ export class Parser {
2345
2365
 
2346
2366
  }
2347
2367
 
2368
+ // move true/false handling here
2369
+ // should we accept english even if it's not the active language? (...)
2370
+
2371
+ const lc = str.toLowerCase();
2348
2372
 
2373
+ if (lc === 'true' || (this.flags.boolean_true && lc === this.flags.boolean_true.toLowerCase())) {
2374
+ return {
2375
+ type: 'literal',
2376
+ id: this.id_counter++,
2377
+ value: true,
2378
+ position,
2379
+ };
2380
+ }
2349
2381
 
2382
+ if (lc === 'false' || (this.flags.boolean_false && lc === this.flags.boolean_false.toLowerCase())) {
2383
+ return {
2384
+ type: 'literal',
2385
+ id: this.id_counter++,
2386
+ value: false,
2387
+ position,
2388
+ };
2389
+ }
2390
+
2350
2391
  const identifier: UnitIdentifier = {
2351
2392
  type: 'identifier',
2352
2393
  id: this.id_counter++,
package/tsproject.json CHANGED
@@ -18,7 +18,7 @@
18
18
  "noEmitHelpers": true,
19
19
  "verbatimModuleSyntax": true,
20
20
  "lib": [
21
- "dom", "ESNext"
21
+ "dom", "esnext"
22
22
  ],
23
23
  "allowSyntheticDefaultImports": true,
24
24
  "esModuleInterop": true