@odoo/o-spreadsheet 14.0.1 → 15.0.0

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 (203) hide show
  1. package/dist/o_spreadsheet.cjs.js +31302 -0
  2. package/dist/o_spreadsheet.d.ts +6604 -0
  3. package/dist/o_spreadsheet.esm.js +31257 -0
  4. package/dist/o_spreadsheet.iife.js +31304 -0
  5. package/dist/o_spreadsheet.iife.min.js +3071 -0
  6. package/package.json +57 -15
  7. package/.eslintrc.json +0 -20
  8. package/.husky/post-checkout +0 -9
  9. package/.husky/pre-commit +0 -39
  10. package/.prettierignore +0 -1
  11. package/astToFormula.patch +0 -0
  12. package/demo/data.js +0 -255
  13. package/demo/index.html +0 -9
  14. package/demo/libs/Chart.bundle.js +0 -20755
  15. package/demo/main.js +0 -101
  16. package/doc/readme.md +0 -46
  17. package/rollup.config.js +0 -23
  18. package/src/base_plugin.ts +0 -102
  19. package/src/components/autofill.ts +0 -146
  20. package/src/components/bottom_bar.ts +0 -199
  21. package/src/components/color_picker.ts +0 -150
  22. package/src/components/composer/autocomplete_dropdown.ts +0 -135
  23. package/src/components/composer/composer.ts +0 -487
  24. package/src/components/composer/content_editable_helper.ts +0 -146
  25. package/src/components/figures/chart.ts +0 -70
  26. package/src/components/figures/container.ts +0 -268
  27. package/src/components/figures/text_figure.ts +0 -36
  28. package/src/components/grid.ts +0 -635
  29. package/src/components/helpers/dom_helpers.ts +0 -7
  30. package/src/components/helpers/drag_and_drop.ts +0 -17
  31. package/src/components/icons.ts +0 -36
  32. package/src/components/index.ts +0 -1
  33. package/src/components/menu.ts +0 -288
  34. package/src/components/overlay.ts +0 -457
  35. package/src/components/scrollbar.ts +0 -22
  36. package/src/components/selection_input.ts +0 -168
  37. package/src/components/side_panel/cell_is_rule_editor.ts +0 -169
  38. package/src/components/side_panel/chart_panel.ts +0 -104
  39. package/src/components/side_panel/color_scale_rule_editor.ts +0 -145
  40. package/src/components/side_panel/conditional_formatting.ts +0 -396
  41. package/src/components/side_panel/side_panel.ts +0 -127
  42. package/src/components/side_panel/translations_terms.ts +0 -45
  43. package/src/components/spreadsheet.ts +0 -198
  44. package/src/components/top_bar.ts +0 -535
  45. package/src/constants.ts +0 -26
  46. package/src/data.ts +0 -149
  47. package/src/fonts.ts +0 -41
  48. package/src/formulas/compiler.ts +0 -258
  49. package/src/formulas/composer_tokenizer.ts +0 -70
  50. package/src/formulas/index.ts +0 -15
  51. package/src/formulas/normalize.ts +0 -52
  52. package/src/formulas/parser.ts +0 -280
  53. package/src/formulas/range_tokenizer.ts +0 -97
  54. package/src/formulas/tokenizer.ts +0 -242
  55. package/src/functions/arguments.ts +0 -114
  56. package/src/functions/dates.ts +0 -302
  57. package/src/functions/helpers.ts +0 -592
  58. package/src/functions/index.ts +0 -52
  59. package/src/functions/module_database.ts +0 -282
  60. package/src/functions/module_date.ts +0 -743
  61. package/src/functions/module_info.ts +0 -69
  62. package/src/functions/module_logical.ts +0 -208
  63. package/src/functions/module_lookup.ts +0 -185
  64. package/src/functions/module_math.ts +0 -1252
  65. package/src/functions/module_operators.ts +0 -291
  66. package/src/functions/module_statistical.ts +0 -882
  67. package/src/functions/module_text.ts +0 -370
  68. package/src/helpers/color.ts +0 -30
  69. package/src/helpers/coordinates.ts +0 -71
  70. package/src/helpers/grid_manipulation.ts +0 -68
  71. package/src/helpers/index.ts +0 -7
  72. package/src/helpers/misc.ts +0 -76
  73. package/src/helpers/numbers.ts +0 -117
  74. package/src/helpers/uuid.ts +0 -19
  75. package/src/helpers/zones.ts +0 -263
  76. package/src/history.ts +0 -186
  77. package/src/index.ts +0 -84
  78. package/src/model.ts +0 -261
  79. package/src/plugins/autofill.ts +0 -412
  80. package/src/plugins/chart.ts +0 -404
  81. package/src/plugins/clipboard.ts +0 -461
  82. package/src/plugins/conditional_format.ts +0 -445
  83. package/src/plugins/core.ts +0 -1502
  84. package/src/plugins/edition.ts +0 -157
  85. package/src/plugins/evaluation.ts +0 -428
  86. package/src/plugins/figures.ts +0 -123
  87. package/src/plugins/formatting.ts +0 -630
  88. package/src/plugins/highlight.ts +0 -187
  89. package/src/plugins/index.ts +0 -32
  90. package/src/plugins/merge.ts +0 -524
  91. package/src/plugins/renderer.ts +0 -571
  92. package/src/plugins/selection.ts +0 -562
  93. package/src/plugins/selection_inputs.ts +0 -326
  94. package/src/registries/autofill_modifiers.ts +0 -76
  95. package/src/registries/autofill_rules.ts +0 -98
  96. package/src/registries/figure_registry.ts +0 -30
  97. package/src/registries/index.ts +0 -7
  98. package/src/registries/menu_items_registry.ts +0 -110
  99. package/src/registries/menus/cell_menu_registry.ts +0 -79
  100. package/src/registries/menus/col_menu_registry.ts +0 -63
  101. package/src/registries/menus/index.ts +0 -6
  102. package/src/registries/menus/menu_items_actions.ts +0 -425
  103. package/src/registries/menus/row_menu_registry.ts +0 -63
  104. package/src/registries/menus/sheet_menu_registry.ts +0 -75
  105. package/src/registries/menus/topbar_menu_registry.ts +0 -204
  106. package/src/registries/side_panel_registry.ts +0 -26
  107. package/src/registries/topbar_component_registry.ts +0 -12
  108. package/src/registry.ts +0 -51
  109. package/src/translation.ts +0 -44
  110. package/src/types/autofill.ts +0 -48
  111. package/src/types/chart.ts +0 -26
  112. package/src/types/commands.ts +0 -716
  113. package/src/types/conditional_formatting.ts +0 -124
  114. package/src/types/env.ts +0 -13
  115. package/src/types/functions.ts +0 -35
  116. package/src/types/getters.ts +0 -103
  117. package/src/types/index.ts +0 -20
  118. package/src/types/misc.ts +0 -143
  119. package/src/types/rendering.ts +0 -41
  120. package/src/types/workbook_data.ts +0 -62
  121. package/tests/__mocks__/uuid.ts +0 -7
  122. package/tests/canvas.mock.ts +0 -34
  123. package/tests/components/__mocks__/content_editable_helper.ts +0 -79
  124. package/tests/components/__mocks__/scrollbar.ts +0 -18
  125. package/tests/components/__snapshots__/autocomplete_dropdown_test.ts.snap +0 -29
  126. package/tests/components/__snapshots__/bottom_bar_test.ts.snap +0 -75
  127. package/tests/components/__snapshots__/context_menu_test.ts.snap +0 -88
  128. package/tests/components/__snapshots__/grid_test.ts.snap +0 -60
  129. package/tests/components/__snapshots__/spreadsheet_test.ts.snap +0 -455
  130. package/tests/components/__snapshots__/top_bar_test.ts.snap +0 -705
  131. package/tests/components/autocomplete_dropdown_test.ts +0 -315
  132. package/tests/components/autofill_test.ts +0 -167
  133. package/tests/components/bottom_bar_test.ts +0 -262
  134. package/tests/components/chart_side_panel_test.ts +0 -123
  135. package/tests/components/composer_test.ts +0 -400
  136. package/tests/components/context_menu_test.ts +0 -825
  137. package/tests/components/grid_manipulation_test.ts +0 -163
  138. package/tests/components/grid_test.ts +0 -581
  139. package/tests/components/overlay_test.ts +0 -541
  140. package/tests/components/selection_input_test.ts +0 -259
  141. package/tests/components/side_panel_test.ts +0 -148
  142. package/tests/components/spreadsheet_test.ts +0 -194
  143. package/tests/components/top_bar_test.ts +0 -427
  144. package/tests/data_test.ts +0 -175
  145. package/tests/dom_helper.ts +0 -42
  146. package/tests/formulas/__snapshots__/compiler_test.ts.snap +0 -302
  147. package/tests/formulas/compiler_test.ts +0 -266
  148. package/tests/formulas/composer_tokenizer_test.ts +0 -137
  149. package/tests/formulas/expressions_test.ts +0 -57
  150. package/tests/formulas/formulas_test.ts +0 -80
  151. package/tests/formulas/normalize_test.ts +0 -82
  152. package/tests/formulas/parser_test.ts +0 -224
  153. package/tests/formulas/range_tokenizer_test.ts +0 -187
  154. package/tests/formulas/tokenizer_test.ts +0 -164
  155. package/tests/functions/arguments_test.ts +0 -141
  156. package/tests/functions/dates_test.ts +0 -1081
  157. package/tests/functions/functions_test.ts +0 -53
  158. package/tests/functions/helper_test.ts +0 -98
  159. package/tests/functions/module_database_test.ts +0 -311
  160. package/tests/functions/module_date_test.ts +0 -941
  161. package/tests/functions/module_info_test.ts +0 -139
  162. package/tests/functions/module_logical_test.ts +0 -369
  163. package/tests/functions/module_lookup_test.ts +0 -541
  164. package/tests/functions/module_math_test.ts +0 -2482
  165. package/tests/functions/module_operators_test.ts +0 -955
  166. package/tests/functions/module_statistical_test.ts +0 -2014
  167. package/tests/functions/module_text_test.ts +0 -667
  168. package/tests/helpers/coordinates_test.ts +0 -25
  169. package/tests/helpers/misc_test.ts +0 -95
  170. package/tests/helpers/numbers_test.ts +0 -196
  171. package/tests/helpers/zones_test.ts +0 -97
  172. package/tests/helpers.ts +0 -384
  173. package/tests/menu_items_registry_test.ts +0 -540
  174. package/tests/model/plugins/__snapshots__/chart_test.ts.snap +0 -90
  175. package/tests/model/plugins/chart_test.ts +0 -562
  176. package/tests/model_test.ts +0 -82
  177. package/tests/plugins/__snapshots__/conditional_formatting_test.ts.snap +0 -131
  178. package/tests/plugins/__snapshots__/renderer_test.ts.snap +0 -371
  179. package/tests/plugins/autofill_test.ts +0 -457
  180. package/tests/plugins/borders_test.ts +0 -295
  181. package/tests/plugins/clipboard_test.ts +0 -1180
  182. package/tests/plugins/conditional_formatting_test.ts +0 -1253
  183. package/tests/plugins/core_test.ts +0 -614
  184. package/tests/plugins/edition_test.ts +0 -100
  185. package/tests/plugins/evaluation_async_test.ts +0 -332
  186. package/tests/plugins/evaluation_dates_test.ts +0 -79
  187. package/tests/plugins/evaluation_test.ts +0 -901
  188. package/tests/plugins/figures_test.ts +0 -327
  189. package/tests/plugins/formatting_test.ts +0 -391
  190. package/tests/plugins/grid_manipulation_test.ts +0 -1366
  191. package/tests/plugins/highlight_test.ts +0 -413
  192. package/tests/plugins/history_test.ts +0 -142
  193. package/tests/plugins/import_export_test.ts +0 -276
  194. package/tests/plugins/merges_test.ts +0 -490
  195. package/tests/plugins/navigation_test.ts +0 -181
  196. package/tests/plugins/plugins/evaluation_test.ts +0 -111
  197. package/tests/plugins/renderer_test.ts +0 -598
  198. package/tests/plugins/resizing_test.ts +0 -152
  199. package/tests/plugins/selection_input_test.ts +0 -409
  200. package/tests/plugins/selection_test.ts +0 -442
  201. package/tests/plugins/sheets_test.ts +0 -643
  202. package/tests/plugins/style_test.ts +0 -90
  203. package/tsconfig.json +0 -22
package/src/data.ts DELETED
@@ -1,149 +0,0 @@
1
- import { uuidv4 } from "./helpers/index";
2
- import { SheetData, Workbook, WorkbookData } from "./types/index";
3
-
4
- /**
5
- * This is the current state version number. It should be incremented each time
6
- * a breaking change is made in the way the state is handled, and an upgrade
7
- * function should be defined
8
- */
9
- export const CURRENT_VERSION = 5;
10
-
11
- /**
12
- * This function tries to load anything that could look like a valid
13
- * workbookData object. It applies any migrations, if needed, and return a
14
- * current, complete workbookData object.
15
- *
16
- * It also ensures that there is at least one sheet.
17
- */
18
- export function load(data?: any): WorkbookData {
19
- if (!data) {
20
- return createEmptyWorkbookData();
21
- }
22
- data = Object.assign({}, data);
23
-
24
- // apply migrations, if needed
25
- if ("version" in data) {
26
- if (data.version < CURRENT_VERSION) {
27
- data = migrate(data);
28
- }
29
- }
30
-
31
- // sanity check: try to fix missing fields/corrupted state by providing
32
- // sensible default values
33
- data = Object.assign(createEmptyWorkbookData(), data, { version: CURRENT_VERSION });
34
- data.sheets = data.sheets.map((s, i) => Object.assign(createEmptySheet(`Sheet${i + 1}`), s));
35
- if (!data.sheets.map((s) => s.id).includes(data.activeSheet)) {
36
- data.activeSheet = data.sheets[0].id;
37
- }
38
-
39
- if (data.sheets.length === 0) {
40
- data.sheets.push(createEmptySheet());
41
- }
42
- return data;
43
- }
44
-
45
- // -----------------------------------------------------------------------------
46
- // Migrations
47
- // -----------------------------------------------------------------------------
48
-
49
- interface Migration {
50
- from: number;
51
- to: number;
52
- applyMigration(data: any): any;
53
- description: string;
54
- }
55
-
56
- function migrate(data: any): WorkbookData {
57
- const index = MIGRATIONS.findIndex((m) => m.from === data.version);
58
- for (let i = index; i < MIGRATIONS.length; i++) {
59
- data = MIGRATIONS[i].applyMigration(data);
60
- }
61
- return data;
62
- }
63
-
64
- const MIGRATIONS: Migration[] = [
65
- {
66
- description: "add the `activeSheet` field on data",
67
- from: 1,
68
- to: 2,
69
- applyMigration(data: any): any {
70
- if (data.sheets && data.sheets[0]) {
71
- data.activeSheet = data.sheets[0].name;
72
- }
73
- return data;
74
- },
75
- },
76
- {
77
- description: "add an id field in each sheet",
78
- from: 2,
79
- to: 3,
80
- applyMigration(data: any): any {
81
- if (data.sheets && data.sheets.length) {
82
- for (let sheet of data.sheets) {
83
- sheet.id = sheet.id || sheet.name;
84
- }
85
- }
86
- return data;
87
- },
88
- },
89
- {
90
- description: "activeSheet is now an id, not the name of a sheet",
91
- from: 3,
92
- to: 4,
93
- applyMigration(data: any): any {
94
- const activeSheet = data.sheets.find((s) => s.name === data.activeSheet);
95
- data.activeSheet = activeSheet.id;
96
- return data;
97
- },
98
- },
99
- {
100
- description: "add figures object in each sheets",
101
- from: 4,
102
- to: 5,
103
- applyMigration(data: any): any {
104
- for (let sheet of data.sheets) {
105
- sheet.figures = sheet.figures || [];
106
- }
107
- return data;
108
- },
109
- },
110
- ];
111
-
112
- // -----------------------------------------------------------------------------
113
- // Helpers
114
- // -----------------------------------------------------------------------------
115
- function createEmptySheet(name: string = "Sheet1"): SheetData {
116
- return {
117
- id: uuidv4(),
118
- name,
119
- colNumber: 26,
120
- rowNumber: 100,
121
- cells: {},
122
- cols: {},
123
- rows: {},
124
- merges: [],
125
- conditionalFormats: [],
126
- figures: [],
127
- };
128
- }
129
-
130
- export function createEmptyWorkbookData(): WorkbookData {
131
- const data = {
132
- version: CURRENT_VERSION,
133
- sheets: [createEmptySheet("Sheet1")],
134
- activeSheet: "",
135
- entities: {},
136
- styles: {},
137
- borders: {},
138
- };
139
- data.activeSheet = data.sheets[0].id;
140
- return data;
141
- }
142
-
143
- export function createEmptyWorkbook(): Workbook {
144
- return {
145
- visibleSheets: [],
146
- sheets: {},
147
- activeSheet: null as any,
148
- };
149
- }
package/src/fonts.ts DELETED
@@ -1,41 +0,0 @@
1
- export interface Font {
2
- key: string;
3
- description: string;
4
- }
5
-
6
- export interface FontSize {
7
- pt: number;
8
- px: number;
9
- }
10
-
11
- export const fonts: Font[] = [
12
- { key: "Arial", description: "Arial" },
13
- { key: "Helvetica", description: "Helvetica" },
14
- { key: "Courier New", description: "Courier New" },
15
- { key: "Verdana", description: "Verdana" },
16
- { key: "Lato", description: "Lato" },
17
- ];
18
-
19
- export const fontSizes: FontSize[] = [
20
- { pt: 7.5, px: 10 },
21
- { pt: 8, px: 11 },
22
- { pt: 9, px: 12 },
23
- { pt: 10, px: 13 },
24
- { pt: 10.5, px: 14 },
25
- { pt: 11, px: 15 },
26
- { pt: 12, px: 16 },
27
- { pt: 14, px: 18.7 },
28
- { pt: 15, px: 20 },
29
- { pt: 16, px: 21.3 },
30
- { pt: 18, px: 24 },
31
- { pt: 22, px: 29.3 },
32
- { pt: 24, px: 32 },
33
- { pt: 26, px: 34.7 },
34
- { pt: 36, px: 48 },
35
- ];
36
-
37
- export const fontSizeMap: { [pt: number]: number } = {};
38
-
39
- for (let font of fontSizes) {
40
- fontSizeMap[font.pt] = font.px;
41
- }
@@ -1,258 +0,0 @@
1
- import { functionRegistry } from "../functions/index";
2
- import { _lt } from "../translation";
3
- import { Arg, CompiledFormula, NormalizedFormula } from "../types/index";
4
- import { AST, ASTAsyncFuncall, ASTFuncall, parse } from "./parser";
5
-
6
- const functions = functionRegistry.content;
7
-
8
- const OPERATOR_MAP = {
9
- "=": "EQ",
10
- "+": "ADD",
11
- "-": "MINUS",
12
- "*": "MULTIPLY",
13
- "/": "DIVIDE",
14
- ">=": "GTE",
15
- "<>": "NE",
16
- ">": "GT",
17
- "<=": "LTE",
18
- "<": "LT",
19
- "^": "POWER",
20
- "&": "CONCATENATE",
21
- };
22
-
23
- const UNARY_OPERATOR_MAP = {
24
- "-": "UMINUS",
25
- "+": "UPLUS",
26
- };
27
-
28
- // this cache contains all compiled function code, grouped by "structure". For
29
- // example, "=2*sum(A1:A4)" and "=2*sum(B1:B4)" are compiled into the same
30
- // structural function.
31
- //
32
- // It is only exported for testing purposes
33
- export const functionCache: { [key: string]: CompiledFormula } = {};
34
-
35
- // -----------------------------------------------------------------------------
36
- // COMPILER
37
- // -----------------------------------------------------------------------------
38
- const AsyncFunction = Object.getPrototypeOf(async function () {}).constructor;
39
-
40
- export function compile(str: NormalizedFormula): CompiledFormula {
41
- // TODO: rename that 'str' variable. Doesn't make sense
42
- let isAsync = false;
43
-
44
- if (!functionCache[str.text]) {
45
- const ast = parse(str.text);
46
- let nextId = 1;
47
- const code = [`// ${str.text}`];
48
-
49
- if (ast.type === "BIN_OPERATION" && ast.value === ":") {
50
- throw new Error(_lt("Invalid formula"));
51
- }
52
- if (ast.type === "UNKNOWN") {
53
- throw new Error(_lt("Invalid formula"));
54
- }
55
-
56
- /**
57
- * This function compile the function arguments. It is mostly straightforward,
58
- * except that there is a non trivial transformation in one situation:
59
- *
60
- * If a function argument is asking for a range, and get a cell, we transform
61
- * the cell value into a range. This allow the grid model to differentiate
62
- * between a cell value and a non cell value.
63
- */
64
- function compileFunctionArgs(ast: ASTAsyncFuncall | ASTFuncall): string[] {
65
- const functionDefinition = functions[ast.value.toUpperCase()];
66
- let argDefinition: Arg;
67
-
68
- const result: string[] = [];
69
- const currentFunctionArguments = ast.args;
70
-
71
- const isRepeating = functionDefinition.args.length
72
- ? functionDefinition.args[functionDefinition.args.length - 1].repeating
73
- : false;
74
- let minArg = 0;
75
- let maxArg = isRepeating ? Infinity : functionDefinition.args.length;
76
- for (let arg of functionDefinition.args) {
77
- if (!arg.optional) {
78
- minArg++;
79
- }
80
- }
81
- if (currentFunctionArguments.length < minArg || currentFunctionArguments.length > maxArg) {
82
- throw new Error(
83
- _lt(
84
- "Invalid number of arguments for the %s function. Expected %s, but got %s instead.",
85
- ast.value.toUpperCase(),
86
- functionDefinition.args.length.toString(),
87
- currentFunctionArguments.length.toString()
88
- )
89
- );
90
- }
91
- for (let i = 0; i < currentFunctionArguments.length; i++) {
92
- const arg = currentFunctionArguments[i];
93
- argDefinition = functionDefinition.args[i] || argDefinition!;
94
- const isLazy = argDefinition && argDefinition.lazy;
95
- const types = (argDefinition && argDefinition.type) || [];
96
- const hasRange = types.some(
97
- (t) =>
98
- t === "RANGE" ||
99
- t === "RANGE<BOOLEAN>" ||
100
- t === "RANGE<DATE>" ||
101
- t === "RANGE<NUMBER>" ||
102
- t === "RANGE<STRING>"
103
- );
104
- const isRangeOnly = types.every(
105
- (t) =>
106
- t === "RANGE" ||
107
- t === "RANGE<BOOLEAN>" ||
108
- t === "RANGE<DATE>" ||
109
- t === "RANGE<NUMBER>" ||
110
- t === "RANGE<STRING>"
111
- );
112
- if (isRangeOnly && arg.type !== "REFERENCE") {
113
- throw new Error(
114
- _lt(
115
- "Function %s expects the parameter %s to be reference to a cell or range, not a %s.",
116
- ast.value.toUpperCase(),
117
- (i + 1).toString(),
118
- arg.type.toLowerCase().replace("normalized_", "")
119
- )
120
- );
121
- }
122
- if (
123
- // a range of more than 1 cell
124
- arg.type === "BIN_OPERATION" &&
125
- arg.value === ":" &&
126
- arg.left.value !== arg.right.value &&
127
- !hasRange
128
- ) {
129
- throw new Error(
130
- _lt(
131
- "Function %s expects the parameter %s to be a single value or a single cell reference, not a range.",
132
- ast.value.toUpperCase(),
133
- (i + 1).toString()
134
- )
135
- );
136
- }
137
- let argValue = compileAST(arg, isLazy, hasRange, {
138
- functionName: ast.value.toUpperCase(),
139
- paramIndex: i + 1,
140
- });
141
- result.push(argValue);
142
- }
143
- return result;
144
- }
145
-
146
- /**
147
- * This function compiles all the information extracted by the parser into an
148
- * executable code for the evaluation of the cells content. It uses a cache to
149
- * not reevaluate identical code structures.
150
- *
151
- * The function is sensitive to parameter “isLazy”. It may vary when compiling
152
- * function arguments:
153
- *
154
- * - isLazy: In some cases the function arguments does not need to be
155
- * evaluated before entering the functions. For example the IF function might
156
- * take invalid arguments that do not need to be evaluate and thus should not
157
- * create an error. For this we have lazy arguments.
158
- *
159
- */
160
-
161
- function compileAST(
162
- ast: AST,
163
- isLazy = false,
164
- hasRange = false,
165
- referenceVerification: {
166
- functionName?: string;
167
- paramIndex?: number;
168
- } = {}
169
- ): string {
170
- let id, left, right, args, fnName, statement;
171
- if (ast.debug) {
172
- code.push("debugger;");
173
- }
174
- switch (ast.type) {
175
- case "BOOLEAN":
176
- case "NUMBER": // probably dead case
177
- case "STRING": // probably dead case
178
- id = nextId++;
179
- statement = ast.value;
180
- break;
181
- case "NORMALIZED_NUMBER":
182
- case "NORMALIZED_STRING":
183
- id = nextId++;
184
- statement = `deps[${ast.value}]`;
185
- break;
186
- case "REFERENCE":
187
- const referenceText = str.dependencies[ast.value];
188
- if (!referenceText) {
189
- id = nextId++;
190
- statement = `null`;
191
- break;
192
- }
193
- id = nextId++;
194
- if (hasRange) {
195
- statement = `range(${ast.value}, deps, sheetId)`;
196
- } else {
197
- statement = `ref(${ast.value}, deps, sheetId,
198
- "${referenceVerification.functionName}", ${referenceVerification.paramIndex})`;
199
- }
200
- break;
201
- case "FUNCALL":
202
- id = nextId++;
203
- args = compileFunctionArgs(ast);
204
- fnName = ast.value.toUpperCase();
205
- code.push(`ctx.__lastFnCalled = '${fnName}'`);
206
- statement = `ctx['${fnName}'](${args})`;
207
- break;
208
- case "ASYNC_FUNCALL":
209
- id = nextId++;
210
- isAsync = true;
211
- args = compileFunctionArgs(ast);
212
- fnName = ast.value.toUpperCase();
213
- code.push(`ctx.__lastFnCalled = '${fnName}'`);
214
- statement = `await ctx['${fnName}'](${args})`;
215
- break;
216
- case "UNARY_OPERATION":
217
- id = nextId++;
218
- right = compileAST(ast.right);
219
- fnName = UNARY_OPERATOR_MAP[ast.value];
220
- code.push(`ctx.__lastFnCalled = '${fnName}'`);
221
- statement = `ctx['${fnName}']( ${right})`;
222
- break;
223
- case "BIN_OPERATION":
224
- id = nextId++;
225
- left = compileAST(ast.left);
226
- right = compileAST(ast.right);
227
- fnName = OPERATOR_MAP[ast.value];
228
- code.push(`ctx.__lastFnCalled = '${fnName}'`);
229
- statement = `ctx['${fnName}'](${left}, ${right})`;
230
- break;
231
- case "UNKNOWN":
232
- if (!isLazy) {
233
- return "null";
234
- }
235
- id = nextId++;
236
- statement = `null`;
237
- break;
238
- }
239
- code.push(`let _${id} = ` + (isLazy ? `()=> ` : ``) + statement);
240
- return `_${id}`;
241
- }
242
- code.push(`return ${compileAST(ast)};`);
243
-
244
- const Constructor = isAsync ? AsyncFunction : Function;
245
- let baseFunction = new Constructor(
246
- "deps", // the dependencies in the current formula
247
- "sheetId", // the sheet the formula is currently evaluating
248
- "ref", // a function to access a certain dependency at a given index
249
- "range", // same as above, but guarantee that the result is in the form of a range
250
- "ctx",
251
- code.join("\n")
252
- );
253
- functionCache[str.text] = baseFunction;
254
- functionCache[str.text].async = isAsync;
255
- }
256
-
257
- return functionCache[str.text];
258
- }
@@ -1,70 +0,0 @@
1
- import { Token } from ".";
2
- import { mergeSymbolsIntoRanges } from "./range_tokenizer";
3
- import { tokenize } from "./tokenizer";
4
-
5
- /**
6
- * Enriched Token is used by the composer to add information on the tokens that
7
- * are only needed during the edition of a formula.
8
- *
9
- * The information added are:
10
- * - parenthesis matching
11
- * - range detection (replaces the tokens that composes the range with 1 token)
12
- * - length, start and end of each token
13
- */
14
-
15
- export interface EnrichedToken extends Token {
16
- start: number;
17
- end: number;
18
- length: number;
19
- parenIndex?: number;
20
- }
21
-
22
- /**
23
- * Add the following information on tokens:
24
- * - length
25
- * - start
26
- * - end
27
- */
28
- function enrichTokens(tokens: Token[]): EnrichedToken[] {
29
- let current = 0;
30
- return tokens.map((x) => {
31
- const len = x.value.toString().length;
32
- const token: EnrichedToken = Object.assign({}, x, {
33
- start: current,
34
- end: current + len,
35
- length: len,
36
- });
37
- current = token.end;
38
- return token;
39
- });
40
- }
41
-
42
- /**
43
- * add on each token the length, start and end
44
- * also matches the opening to its closing parenthesis (using the same number)
45
- */
46
- function mapParenthesis(tokens: EnrichedToken[]): EnrichedToken[] {
47
- let maxParen = 1;
48
- const stack: number[] = [];
49
- return tokens.map((token) => {
50
- if (token.type === "LEFT_PAREN") {
51
- stack.push(maxParen);
52
- token.parenIndex = maxParen;
53
- maxParen++;
54
- } else if (token.type === "RIGHT_PAREN") {
55
- token.parenIndex = stack.pop();
56
- }
57
- return token;
58
- });
59
- }
60
-
61
- /**
62
- * Take the result of the tokenizer and transform it to be usable in the composer.
63
- *
64
- * @param formula
65
- */
66
- export function composerTokenize(formula: string): EnrichedToken[] {
67
- const tokens = tokenize(formula);
68
-
69
- return mapParenthesis(enrichTokens(mergeSymbolsIntoRanges(tokens)));
70
- }
@@ -1,15 +0,0 @@
1
- /**
2
- * The formulas module provides all functionality related to manipulating
3
- * formulas:
4
- *
5
- * - tokenization (transforming a string into a list of tokens)
6
- * - parsing (same, but into an AST (Abstract Syntax Tree))
7
- * - compiler (getting an executable function representing a formula)
8
- */
9
-
10
- export { compile } from "./compiler";
11
- export { composerTokenize, EnrichedToken } from "./composer_tokenizer";
12
- export { normalize } from "./normalize";
13
- export { cellReference, parse, rangeReference } from "./parser";
14
- export { rangeTokenize } from "./range_tokenizer";
15
- export { Token, tokenize } from "./tokenizer";
@@ -1,52 +0,0 @@
1
- import { parseNumber } from "../helpers/numbers";
2
- import { Dependencies, NormalizedFormula } from "../types";
3
- import { cellReference } from "./parser";
4
- import { rangeTokenize } from "./range_tokenizer";
5
- import { FORMULA_REF_IDENTIFIER } from "./tokenizer";
6
-
7
- /**
8
- * parses a formula (as a string) into the same formula,
9
- * but with the references to other cells as well as strings and numbers extracted
10
- *
11
- * =sum(a3:b1) + c3 --> =sum(|0|) + |1|
12
- *
13
- * = sum(a3, 5) --> =sum(|0|, |N1|)
14
- *
15
- * =CONCAT(CONCAT(1, "beta"), A1) --> =CONCAT(CONCAT(|N0|, |S1|), |2|)
16
- *
17
- * Strings and Numbers are marked with a prefix of their type (S and N) to be detected
18
- * as their normalized form by the parser as they won't be processed like the references by the compiler.
19
- *
20
- * @param formula
21
- */
22
- export function normalize(formula: string): NormalizedFormula {
23
- const tokens = rangeTokenize(formula);
24
-
25
- let references: Dependencies = [];
26
-
27
- let noRefFormula = "".concat(
28
- ...tokens.map<string>((token) => {
29
- if (token.type === "SYMBOL" && cellReference.test(token.value)) {
30
- const value = token.value.trim();
31
- if (!references.includes(value)) {
32
- references.push(value);
33
- }
34
- return `${FORMULA_REF_IDENTIFIER}${references.indexOf(value)}${FORMULA_REF_IDENTIFIER}`;
35
- } else if (["STRING", "NUMBER"].includes(token.type)) {
36
- const value =
37
- token.type === "STRING"
38
- ? token.value.slice(1).slice(0, token.value.length - 2)
39
- : parseNumber(token.value);
40
- if (!references.includes(value)) {
41
- references.push(value);
42
- }
43
- return `${FORMULA_REF_IDENTIFIER}${token.type[0]}${references.indexOf(
44
- value
45
- )}${FORMULA_REF_IDENTIFIER}`;
46
- } else {
47
- return token.value;
48
- }
49
- })
50
- );
51
- return { text: noRefFormula, dependencies: references };
52
- }