@trebco/treb 30.1.8 → 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.
Files changed (35) hide show
  1. package/dist/languages/treb-i18n-da.mjs +1 -0
  2. package/dist/languages/treb-i18n-de.mjs +1 -0
  3. package/dist/languages/treb-i18n-es.mjs +1 -0
  4. package/dist/languages/treb-i18n-fr.mjs +1 -0
  5. package/dist/languages/treb-i18n-it.mjs +1 -0
  6. package/dist/languages/treb-i18n-nl.mjs +1 -0
  7. package/dist/languages/treb-i18n-no.mjs +1 -0
  8. package/dist/languages/treb-i18n-pl.mjs +1 -0
  9. package/dist/languages/treb-i18n-pt.mjs +1 -0
  10. package/dist/languages/treb-i18n-sv.mjs +1 -0
  11. package/dist/treb-spreadsheet-light.mjs +11 -11
  12. package/dist/treb-spreadsheet.mjs +11 -11
  13. package/dist/treb.d.ts +15 -1
  14. package/esbuild-custom-element.mjs +23 -1
  15. package/esbuild-utils.mjs +1 -0
  16. package/package.json +1 -1
  17. package/treb-calculator/src/calculator.ts +41 -0
  18. package/treb-calculator/src/expression-calculator.ts +40 -32
  19. package/treb-calculator/src/functions/base-functions.ts +164 -1
  20. package/treb-calculator/src/functions/statistics-functions.ts +134 -0
  21. package/treb-calculator/src/functions/text-functions.ts +45 -0
  22. package/treb-calculator/src/utilities.ts +5 -1
  23. package/treb-data-model/src/data_model.ts +227 -2
  24. package/treb-data-model/src/index.ts +1 -0
  25. package/{treb-embed → treb-data-model}/src/language-model.ts +3 -0
  26. package/treb-data-model/src/sheet.ts +0 -13
  27. package/treb-embed/src/embedded-spreadsheet.ts +84 -25
  28. package/treb-embed/src/options.ts +18 -0
  29. package/treb-embed/src/plugin.ts +31 -0
  30. package/treb-grid/src/editors/autocomplete_matcher.ts +8 -1
  31. package/treb-grid/src/render/tile_renderer.ts +14 -0
  32. package/treb-grid/src/types/grid.ts +25 -139
  33. package/treb-parser/src/parser-types.ts +12 -0
  34. package/treb-parser/src/parser.ts +43 -2
  35. package/tsproject.json +1 -1
@@ -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