@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
@@ -1,592 +0,0 @@
1
- // HELPERS
2
-
3
- import { isNumber, parseNumber } from "../helpers/index";
4
- import { _lt } from "../translation";
5
- import { parseDateTime } from "./dates";
6
-
7
- const INITIAL_1900_DAY = new Date(1899, 11, 30) as any;
8
- const MS_PER_DAY = 24 * 60 * 60 * 1000;
9
- const INITIAL_JS_DAY = new Date(0) as any;
10
- const DATE_JS_1900_OFFSET = INITIAL_JS_DAY - INITIAL_1900_DAY;
11
-
12
- const expectNumberValueError = (value: string) =>
13
- _lt(
14
- "The function [[FUNCTION_NAME]] expects a number value, but '%s' is a string, and cannot be coerced to a number.",
15
- value
16
- );
17
-
18
- export function toNumber(value: any): number {
19
- switch (typeof value) {
20
- case "number":
21
- return value;
22
- case "boolean":
23
- return value ? 1 : 0;
24
- case "string":
25
- if (isNumber(value) || value === "") {
26
- return parseNumber(value);
27
- }
28
- const internalDate = parseDateTime(value);
29
- if (internalDate) {
30
- return internalDate.value;
31
- }
32
- throw new Error(expectNumberValueError(value));
33
- case "object":
34
- if (value !== null && value.jsDate) {
35
- return value.value;
36
- }
37
- return value || 0;
38
- default:
39
- return value || 0;
40
- }
41
- }
42
-
43
- export function strictToNumber(value: any): number {
44
- if (value === "") {
45
- throw new Error(expectNumberValueError(value));
46
- }
47
- return toNumber(value);
48
- }
49
-
50
- export function visitNumbers(args: IArguments | any[], cb: (arg: number) => void): void {
51
- for (let n of args) {
52
- if (Array.isArray(n)) {
53
- for (let i of n) {
54
- for (let j of i) {
55
- if (typeof j === "number") {
56
- cb(j);
57
- } else if (typeof j === "object" && j !== null && j.jsDate) {
58
- cb(j.value);
59
- }
60
- }
61
- }
62
- } else {
63
- cb(strictToNumber(n));
64
- }
65
- }
66
- }
67
-
68
- function visitNumbersTextAs0(args: IArguments | any[], cb: (arg: number) => void): void {
69
- for (let n of args) {
70
- if (Array.isArray(n)) {
71
- for (let i of n) {
72
- for (let j of i) {
73
- if (j !== undefined && j !== null) {
74
- if (typeof j === "number") {
75
- cb(j);
76
- } else if (typeof j === "boolean") {
77
- cb(toNumber(j));
78
- } else if (typeof j === "object" && j !== null && j.jsDate) {
79
- cb(j.value);
80
- } else {
81
- cb(0);
82
- }
83
- }
84
- }
85
- }
86
- } else {
87
- cb(toNumber(n));
88
- }
89
- }
90
- }
91
-
92
- export function visitAny(arg: any, cb: (a: any) => void): void {
93
- if (Array.isArray(arg)) {
94
- for (let col of arg) {
95
- for (let cell of col) {
96
- cb(cell);
97
- }
98
- }
99
- } else {
100
- cb(arg);
101
- }
102
- }
103
-
104
- export function visitAnys(
105
- args: IArguments | any[],
106
- rangeCb: (a: any) => boolean,
107
- argCb: (a: any) => boolean
108
- ): void {
109
- for (let arg of args) {
110
- if (Array.isArray(arg)) {
111
- for (let col of arg) {
112
- for (let cell of col) {
113
- if (!rangeCb(cell)) return;
114
- }
115
- }
116
- } else {
117
- if (!argCb(arg)) return;
118
- }
119
- }
120
- }
121
-
122
- export function reduceArgs<T>(
123
- args: IArguments | any[],
124
- cb: (acc: T, a: any) => T,
125
- initialValue: T
126
- ): T {
127
- let val = initialValue;
128
- for (let arg of args) {
129
- visitAny(arg, (a) => {
130
- val = cb(val, a);
131
- });
132
- }
133
- return val;
134
- }
135
-
136
- export function reduceNumbers<T>(
137
- args: IArguments | any[],
138
- cb: (acc: T, a: any) => T,
139
- initialValue: T
140
- ): T {
141
- let val = initialValue;
142
- visitNumbers(args, (a) => {
143
- val = cb(val, a);
144
- });
145
- return val;
146
- }
147
-
148
- export function reduceNumbersTextAs0<T>(
149
- args: IArguments | any[],
150
- cb: (acc: T, a: any) => T,
151
- initialValue: T
152
- ): T {
153
- let val = initialValue;
154
- visitNumbersTextAs0(args, (a) => {
155
- val = cb(val, a);
156
- });
157
- return val;
158
- }
159
-
160
- export function toString(value: any): string {
161
- switch (typeof value) {
162
- case "string":
163
- return value;
164
- case "number":
165
- return value.toString();
166
- case "boolean":
167
- return value ? "TRUE" : "FALSE";
168
- default:
169
- return "";
170
- }
171
- }
172
-
173
- const expectBooleanValueError = (value: string) =>
174
- _lt(
175
- "The function [[FUNCTION_NAME]] expects a boolean value, but '%s' is a text, and cannot be coerced to a number.",
176
- value
177
- );
178
-
179
- export function toBoolean(value: any): boolean {
180
- switch (typeof value) {
181
- case "boolean":
182
- return value;
183
- case "string":
184
- if (value) {
185
- let uppercaseVal = value.toUpperCase();
186
- if (uppercaseVal === "TRUE") {
187
- return true;
188
- }
189
- if (uppercaseVal === "FALSE") {
190
- return false;
191
- }
192
- throw new Error(expectBooleanValueError(value));
193
- } else {
194
- return false;
195
- }
196
- case "number":
197
- return value ? true : false;
198
- default:
199
- return false;
200
- }
201
- }
202
-
203
- export function strictToBoolean(value: any): boolean {
204
- if (value === "") {
205
- throw new Error(expectBooleanValueError(value));
206
- }
207
- return toBoolean(value);
208
- }
209
-
210
- export function visitBooleans(args: IArguments, cb: (a: boolean) => boolean): void {
211
- visitAnys(
212
- args,
213
- (cell) => {
214
- if (typeof cell === "boolean") {
215
- return cb(cell);
216
- }
217
- if (typeof cell === "number") {
218
- return cb(cell ? true : false);
219
- }
220
- return true;
221
- },
222
- (arg) => (arg !== null ? cb(strictToBoolean(arg)) : true)
223
- );
224
- }
225
-
226
- // -----------------------------------------------------------------------------
227
- // CRITERION FUNCTIONS
228
- // -----------------------------------------------------------------------------
229
-
230
- type Operator = ">" | ">=" | "<" | "<=" | "<>" | "=";
231
- interface Predicate {
232
- operator: Operator;
233
- operand: any;
234
- regexp?: RegExp;
235
- }
236
-
237
- function getPredicate(descr: string, isQuery: boolean): Predicate {
238
- let operator: Operator;
239
- let operand: any;
240
-
241
- let subString = descr.substring(0, 2);
242
-
243
- if (subString === "<=" || subString === ">=" || subString === "<>") {
244
- operator = subString;
245
- operand = descr.substring(2);
246
- } else {
247
- subString = descr.substring(0, 1);
248
- if (subString === "<" || subString === ">" || subString === "=") {
249
- operator = subString;
250
- operand = descr.substring(1);
251
- } else {
252
- operator = "=";
253
- operand = descr;
254
- }
255
- }
256
-
257
- if (isNumber(operand)) {
258
- operand = toNumber(operand);
259
- } else if (operand === "TRUE" || operand === "FALSE") {
260
- operand = toBoolean(operand);
261
- }
262
-
263
- const result: Predicate = { operator, operand };
264
-
265
- if (typeof operand === "string") {
266
- if (isQuery) {
267
- operand += "*";
268
- }
269
- result.regexp = operandToRegExp(operand);
270
- }
271
-
272
- return result;
273
- }
274
-
275
- function operandToRegExp(operand: string): RegExp {
276
- let exp = "";
277
- let predecessor = "";
278
- for (let char of operand) {
279
- if (char === "?" && predecessor !== "~") {
280
- exp += ".";
281
- } else if (char === "*" && predecessor !== "~") {
282
- exp += ".*";
283
- } else {
284
- if (char === "*" || char === "?") {
285
- //remove "~"
286
- exp = exp.slice(0, -1);
287
- }
288
- if (["^", ".", "[", "]", "$", "(", ")", "*", "+", "?", "|", "{", "}", "\\"].includes(char)) {
289
- exp += "\\";
290
- }
291
- exp += char;
292
- }
293
- predecessor = char;
294
- }
295
- return new RegExp("^" + exp + "$", "i");
296
- }
297
-
298
- function evaluatePredicate(value: any, criterion: Predicate): boolean {
299
- const { operator, operand } = criterion;
300
-
301
- if (typeof operand === "number" && operator === "=") {
302
- return toString(value) === toString(operand);
303
- }
304
-
305
- if (operator === "<>" || operator === "=") {
306
- let result: boolean;
307
- if (typeof value === typeof operand) {
308
- if (criterion.regexp) {
309
- result = criterion.regexp.test(value);
310
- } else {
311
- result = value === operand;
312
- }
313
- } else {
314
- result = false;
315
- }
316
- return operator === "=" ? result : !result;
317
- }
318
-
319
- if (typeof value === typeof operand) {
320
- switch (operator) {
321
- case "<":
322
- return value < operand;
323
- case ">":
324
- return value > operand;
325
- case "<=":
326
- return value <= operand;
327
- case ">=":
328
- return value >= operand;
329
- }
330
- }
331
- return false;
332
- }
333
-
334
- /**
335
- * Functions used especially for predicate evaluation on ranges.
336
- *
337
- * Take ranges with same dimensions and take predicates, one for each range.
338
- * For (i, j) coordinates, if all elements with coordinates (i, j) of each
339
- * range correspond to the associated predicate, then the function uses a callback
340
- * function with the parameters "i" and "j".
341
- *
342
- * Syntax:
343
- * visitMatchingRanges([range1, predicate1, range2, predicate2, ...], cb(i,j), likeSelection)
344
- *
345
- * - range1 (range): The range to check against predicate1.
346
- * - predicate1 (string): The pattern or test to apply to range1.
347
- * - range2: (range, optional, repeatable) ranges to check.
348
- * - predicate2 (string, optional, repeatable): Additional pattern or test to apply to range2.
349
- *
350
- * - cb(i: number, j: number) => void: the callback function.
351
- *
352
- * - isQuery (boolean) indicates if the comparison with a string should be done as a SQL-like query.
353
- * (Ex1 isQuery = true, predicate = "abc", element = "abcde": predicate match the element),
354
- * (Ex2 isQuery = false, predicate = "abc", element = "abcde": predicate not match the element).
355
- * (Ex3 isQuery = true, predicate = "abc", element = "abc": predicate match the element),
356
- * (Ex4 isQuery = false, predicate = "abc", element = "abc": predicate match the element).
357
- */
358
- export function visitMatchingRanges(
359
- args: IArguments | any[],
360
- cb: (i: number, j: number) => void,
361
- isQuery: boolean = false
362
- ): void {
363
- const countArg = args.length;
364
-
365
- if (countArg % 2 === 1) {
366
- throw new Error(
367
- _lt(`Function [[FUNCTION_NAME]] expects criteria_range and criterion to be in pairs.`)
368
- );
369
- }
370
-
371
- const dimRow = args[0].length;
372
- const dimCol = args[0][0].length;
373
-
374
- let predicates: Predicate[] = [];
375
-
376
- for (let i = 0; i < countArg - 1; i += 2) {
377
- const criteriaRange = args[i];
378
-
379
- if (criteriaRange.length !== dimRow || criteriaRange[0].length !== dimCol) {
380
- throw new Error(
381
- _lt(`Function [[FUNCTION_NAME]] expects criteria_range to have the same dimension`)
382
- );
383
- }
384
-
385
- const description = toString(args[i + 1]);
386
- predicates.push(getPredicate(description, isQuery));
387
- }
388
-
389
- for (let i = 0; i < dimRow; i++) {
390
- for (let j = 0; j < dimCol; j++) {
391
- let validatedPredicates = true;
392
- for (let k = 0; k < countArg - 1; k += 2) {
393
- const criteriaValue = args[k][i][j];
394
- const criterion = predicates[k / 2];
395
- validatedPredicates = evaluatePredicate(criteriaValue, criterion);
396
- if (!validatedPredicates) {
397
- break;
398
- }
399
- }
400
- if (validatedPredicates) {
401
- cb(i, j);
402
- }
403
- }
404
- }
405
- }
406
-
407
- // -----------------------------------------------------------------------------
408
- // COMMON FUNCTIONS
409
- // -----------------------------------------------------------------------------
410
-
411
- /**
412
- * Perform a dichotomic search and return the index of the nearest match less than
413
- * or equal to the target. If all values in the range are greater than the target,
414
- * -1 is returned.
415
- * If the range is not in sorted order, an incorrect value might be returned.
416
- *
417
- * Example:
418
- * - [3, 6, 10], 3 => 0
419
- * - [3, 6, 10], 6 => 1
420
- * - [3, 6, 10], 9 => 1
421
- * - [3, 6, 10], 42 => 2
422
- * - [3, 6, 10], 2 => -1
423
- * - [3, undefined, 6, undefined, 10], 9 => 2
424
- * - [3, 6, undefined, undefined, undefined, 10], 2 => -1
425
- */
426
- export function dichotomicPredecessorSearch(range: any[], target: any): number {
427
- const targetType = typeof target;
428
-
429
- let valMin: any;
430
- let valMinIndex: number | undefined = undefined;
431
-
432
- let indexLeft = 0;
433
- let indexRight = range.length - 1;
434
-
435
- if (typeof range[indexLeft] === targetType && target < range[indexLeft]) {
436
- return -1;
437
- }
438
-
439
- if (typeof range[indexRight] === targetType && range[indexRight] <= target) {
440
- return indexRight;
441
- }
442
-
443
- let indexMedian: number;
444
- let currentIndex: number;
445
- let currentVal: any;
446
- let currentType: any;
447
-
448
- while (indexRight - indexLeft >= 0) {
449
- indexMedian = Math.ceil((indexLeft + indexRight) / 2);
450
-
451
- currentIndex = indexMedian;
452
- currentVal = range[currentIndex];
453
- currentType = typeof currentVal;
454
-
455
- // 1 - linear search to find value with the same type
456
- while (indexLeft <= currentIndex && targetType !== currentType) {
457
- currentIndex--;
458
- currentVal = range[currentIndex];
459
- currentType = typeof currentVal;
460
- }
461
-
462
- // 2 - check if value match
463
- if (currentType === targetType && currentVal <= target) {
464
- if (
465
- valMin === undefined ||
466
- valMin < currentVal ||
467
- (valMin === currentVal && valMinIndex! < currentIndex)
468
- ) {
469
- valMin = currentVal;
470
- valMinIndex = currentIndex;
471
- }
472
- }
473
-
474
- // 3 - give new indexs for the Binary search
475
- if (currentType === targetType && currentVal > target) {
476
- indexRight = currentIndex - 1;
477
- } else {
478
- indexLeft = indexMedian + 1;
479
- }
480
- }
481
-
482
- // note that valMinIndex could be 0
483
- return valMinIndex !== undefined ? valMinIndex : -1;
484
- }
485
-
486
- /**
487
- * Perform a dichotomic search and return the index of the nearest match more than
488
- * or equal to the target. If all values in the range are smaller than the target,
489
- * -1 is returned.
490
- * If the range is not in sorted order, an incorrect value might be returned.
491
- *
492
- * Example:
493
- * - [10, 6, 3], 3 => 2
494
- * - [10, 6, 3], 6 => 1
495
- * - [10, 6, 3], 9 => 0
496
- * - [10, 6, 3], 42 => -1
497
- * - [10, 6, 3], 2 => 2
498
- * - [10, undefined, 6, undefined, 3], 9 => 0
499
- * - [10, 6, undefined, undefined, undefined, 3], 2 => 5
500
- */
501
- export function dichotomicSuccessorSearch(range: any[], target: any): number {
502
- const targetType = typeof target;
503
-
504
- let valMax: any;
505
- let valMaxIndex: number | undefined = undefined;
506
-
507
- let indexLeft = 0;
508
- let indexRight = range.length - 1;
509
-
510
- if (typeof range[indexLeft] === targetType && target > range[indexLeft]) {
511
- return -1;
512
- }
513
-
514
- if (typeof range[indexRight] === targetType && range[indexRight] > target) {
515
- return indexRight;
516
- }
517
-
518
- let indexMedian: number;
519
- let currentIndex: number;
520
- let currentVal: any;
521
- let currentType: any;
522
-
523
- while (indexRight - indexLeft >= 0) {
524
- indexMedian = Math.ceil((indexLeft + indexRight) / 2);
525
- currentIndex = indexMedian;
526
- currentVal = range[currentIndex];
527
- currentType = typeof currentVal;
528
-
529
- // 1 - linear search to find value with the same type
530
- while (indexLeft <= currentIndex && targetType !== currentType) {
531
- currentIndex--;
532
- currentVal = range[currentIndex];
533
- currentType = typeof currentVal;
534
- }
535
-
536
- // 2 - check if value match
537
- if (currentType === targetType && currentVal >= target) {
538
- if (
539
- valMax === undefined ||
540
- valMax > currentVal ||
541
- (valMax === currentVal && valMaxIndex! > currentIndex)
542
- ) {
543
- valMax = currentVal;
544
- valMaxIndex = currentIndex;
545
- }
546
- }
547
-
548
- // 3 - give new indexs for the Binary search
549
- if (currentType === targetType && currentVal <= target) {
550
- indexRight = currentIndex - 1;
551
- } else {
552
- indexLeft = indexMedian + 1;
553
- }
554
- }
555
-
556
- // note that valMaxIndex could be 0
557
- return valMaxIndex !== undefined ? valMaxIndex : -1;
558
- }
559
-
560
- export function extractDateValue(arg: any) {
561
- if (typeof arg === "object" && arg.jsDate) {
562
- return arg.value;
563
- }
564
- return arg;
565
- }
566
-
567
- // -----------------------------------------------------------------------------
568
- // Conversion
569
- // -----------------------------------------------------------------------------
570
-
571
- export function numberToJsDate(value: number): Date {
572
- const truncValue = Math.trunc(value);
573
- let date = new Date(truncValue * MS_PER_DAY - DATE_JS_1900_OFFSET);
574
-
575
- let time = value - truncValue;
576
- time = time < 0 ? 1 + time : time;
577
-
578
- const hours = Math.round(time * 24);
579
- const minutes = Math.round((time - hours / 24) * 24 * 60);
580
- const seconds = Math.round((time - hours / 24 - minutes / 24 / 60) * 24 * 60 * 60);
581
-
582
- date.setHours(hours);
583
- date.setMinutes(minutes);
584
- date.setSeconds(seconds);
585
-
586
- return date;
587
- }
588
-
589
- export function jsDateToRoundNumber(date: Date): number {
590
- const delta = date.getTime() - INITIAL_1900_DAY.getTime();
591
- return Math.round(delta / MS_PER_DAY);
592
- }
@@ -1,52 +0,0 @@
1
- import { Registry } from "../registry";
2
- import { FunctionDescription } from "../types";
3
- import { validateArguments } from "./arguments";
4
- import * as database from "./module_database";
5
- import * as date from "./module_date";
6
- import * as info from "./module_info";
7
- import * as logical from "./module_logical";
8
- import * as lookup from "./module_lookup";
9
- import * as math from "./module_math";
10
- import * as operators from "./module_operators";
11
- import * as statistical from "./module_statistical";
12
- import * as text from "./module_text";
13
-
14
- export { args } from "./arguments";
15
-
16
- const functions: { [category: string]: { [name: string]: FunctionDescription } } = {
17
- database,
18
- date,
19
- info,
20
- lookup,
21
- logical,
22
- math,
23
- operators,
24
- statistical,
25
- text,
26
- };
27
-
28
- //------------------------------------------------------------------------------
29
- // Function registry
30
- //------------------------------------------------------------------------------
31
- class FunctionRegistry extends Registry<FunctionDescription> {
32
- mapping: { [key: string]: Function } = {};
33
-
34
- add(name: string, descr: FunctionDescription) {
35
- name = name.toUpperCase().replace("_", ".");
36
- validateArguments(descr.args);
37
- this.mapping[name] = descr.compute;
38
- super.add(name, descr);
39
- return this;
40
- }
41
- }
42
-
43
- export const functionRegistry = new FunctionRegistry();
44
-
45
- for (let category in functions) {
46
- const fns = functions[category];
47
- for (let name in fns) {
48
- const descr = fns[name];
49
- descr.category = category;
50
- functionRegistry.add(name, descr);
51
- }
52
- }