@odoo/o-spreadsheet 14.0.1 → 14.0.3

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 (204) hide show
  1. package/dist/o-spreadsheet.cjs.js +17880 -0
  2. package/dist/o-spreadsheet.d.ts +4119 -0
  3. package/dist/o-spreadsheet.esm.js +17845 -0
  4. package/dist/o-spreadsheet.iife.js +17882 -0
  5. package/dist/o-spreadsheet.iife.min.js +1446 -0
  6. package/package.json +32 -9
  7. package/readme.md +10 -0
  8. package/.eslintrc.json +0 -20
  9. package/.husky/post-checkout +0 -9
  10. package/.husky/pre-commit +0 -39
  11. package/.prettierignore +0 -1
  12. package/astToFormula.patch +0 -0
  13. package/demo/data.js +0 -255
  14. package/demo/index.html +0 -9
  15. package/demo/libs/Chart.bundle.js +0 -20755
  16. package/demo/main.js +0 -101
  17. package/doc/readme.md +0 -46
  18. package/rollup.config.js +0 -23
  19. package/src/base_plugin.ts +0 -102
  20. package/src/components/autofill.ts +0 -146
  21. package/src/components/bottom_bar.ts +0 -199
  22. package/src/components/color_picker.ts +0 -150
  23. package/src/components/composer/autocomplete_dropdown.ts +0 -135
  24. package/src/components/composer/composer.ts +0 -487
  25. package/src/components/composer/content_editable_helper.ts +0 -146
  26. package/src/components/figures/chart.ts +0 -70
  27. package/src/components/figures/container.ts +0 -268
  28. package/src/components/figures/text_figure.ts +0 -36
  29. package/src/components/grid.ts +0 -635
  30. package/src/components/helpers/dom_helpers.ts +0 -7
  31. package/src/components/helpers/drag_and_drop.ts +0 -17
  32. package/src/components/icons.ts +0 -36
  33. package/src/components/index.ts +0 -1
  34. package/src/components/menu.ts +0 -288
  35. package/src/components/overlay.ts +0 -457
  36. package/src/components/scrollbar.ts +0 -22
  37. package/src/components/selection_input.ts +0 -168
  38. package/src/components/side_panel/cell_is_rule_editor.ts +0 -169
  39. package/src/components/side_panel/chart_panel.ts +0 -104
  40. package/src/components/side_panel/color_scale_rule_editor.ts +0 -145
  41. package/src/components/side_panel/conditional_formatting.ts +0 -396
  42. package/src/components/side_panel/side_panel.ts +0 -127
  43. package/src/components/side_panel/translations_terms.ts +0 -45
  44. package/src/components/spreadsheet.ts +0 -198
  45. package/src/components/top_bar.ts +0 -535
  46. package/src/constants.ts +0 -26
  47. package/src/data.ts +0 -149
  48. package/src/fonts.ts +0 -41
  49. package/src/formulas/compiler.ts +0 -258
  50. package/src/formulas/composer_tokenizer.ts +0 -70
  51. package/src/formulas/index.ts +0 -15
  52. package/src/formulas/normalize.ts +0 -52
  53. package/src/formulas/parser.ts +0 -280
  54. package/src/formulas/range_tokenizer.ts +0 -97
  55. package/src/formulas/tokenizer.ts +0 -242
  56. package/src/functions/arguments.ts +0 -114
  57. package/src/functions/dates.ts +0 -302
  58. package/src/functions/helpers.ts +0 -592
  59. package/src/functions/index.ts +0 -52
  60. package/src/functions/module_database.ts +0 -282
  61. package/src/functions/module_date.ts +0 -743
  62. package/src/functions/module_info.ts +0 -69
  63. package/src/functions/module_logical.ts +0 -208
  64. package/src/functions/module_lookup.ts +0 -185
  65. package/src/functions/module_math.ts +0 -1252
  66. package/src/functions/module_operators.ts +0 -291
  67. package/src/functions/module_statistical.ts +0 -882
  68. package/src/functions/module_text.ts +0 -370
  69. package/src/helpers/color.ts +0 -30
  70. package/src/helpers/coordinates.ts +0 -71
  71. package/src/helpers/grid_manipulation.ts +0 -68
  72. package/src/helpers/index.ts +0 -7
  73. package/src/helpers/misc.ts +0 -76
  74. package/src/helpers/numbers.ts +0 -117
  75. package/src/helpers/uuid.ts +0 -19
  76. package/src/helpers/zones.ts +0 -263
  77. package/src/history.ts +0 -186
  78. package/src/index.ts +0 -84
  79. package/src/model.ts +0 -261
  80. package/src/plugins/autofill.ts +0 -412
  81. package/src/plugins/chart.ts +0 -404
  82. package/src/plugins/clipboard.ts +0 -461
  83. package/src/plugins/conditional_format.ts +0 -445
  84. package/src/plugins/core.ts +0 -1502
  85. package/src/plugins/edition.ts +0 -157
  86. package/src/plugins/evaluation.ts +0 -428
  87. package/src/plugins/figures.ts +0 -123
  88. package/src/plugins/formatting.ts +0 -630
  89. package/src/plugins/highlight.ts +0 -187
  90. package/src/plugins/index.ts +0 -32
  91. package/src/plugins/merge.ts +0 -524
  92. package/src/plugins/renderer.ts +0 -571
  93. package/src/plugins/selection.ts +0 -562
  94. package/src/plugins/selection_inputs.ts +0 -326
  95. package/src/registries/autofill_modifiers.ts +0 -76
  96. package/src/registries/autofill_rules.ts +0 -98
  97. package/src/registries/figure_registry.ts +0 -30
  98. package/src/registries/index.ts +0 -7
  99. package/src/registries/menu_items_registry.ts +0 -110
  100. package/src/registries/menus/cell_menu_registry.ts +0 -79
  101. package/src/registries/menus/col_menu_registry.ts +0 -63
  102. package/src/registries/menus/index.ts +0 -6
  103. package/src/registries/menus/menu_items_actions.ts +0 -425
  104. package/src/registries/menus/row_menu_registry.ts +0 -63
  105. package/src/registries/menus/sheet_menu_registry.ts +0 -75
  106. package/src/registries/menus/topbar_menu_registry.ts +0 -204
  107. package/src/registries/side_panel_registry.ts +0 -26
  108. package/src/registries/topbar_component_registry.ts +0 -12
  109. package/src/registry.ts +0 -51
  110. package/src/translation.ts +0 -44
  111. package/src/types/autofill.ts +0 -48
  112. package/src/types/chart.ts +0 -26
  113. package/src/types/commands.ts +0 -716
  114. package/src/types/conditional_formatting.ts +0 -124
  115. package/src/types/env.ts +0 -13
  116. package/src/types/functions.ts +0 -35
  117. package/src/types/getters.ts +0 -103
  118. package/src/types/index.ts +0 -20
  119. package/src/types/misc.ts +0 -143
  120. package/src/types/rendering.ts +0 -41
  121. package/src/types/workbook_data.ts +0 -62
  122. package/tests/__mocks__/uuid.ts +0 -7
  123. package/tests/canvas.mock.ts +0 -34
  124. package/tests/components/__mocks__/content_editable_helper.ts +0 -79
  125. package/tests/components/__mocks__/scrollbar.ts +0 -18
  126. package/tests/components/__snapshots__/autocomplete_dropdown_test.ts.snap +0 -29
  127. package/tests/components/__snapshots__/bottom_bar_test.ts.snap +0 -75
  128. package/tests/components/__snapshots__/context_menu_test.ts.snap +0 -88
  129. package/tests/components/__snapshots__/grid_test.ts.snap +0 -60
  130. package/tests/components/__snapshots__/spreadsheet_test.ts.snap +0 -455
  131. package/tests/components/__snapshots__/top_bar_test.ts.snap +0 -705
  132. package/tests/components/autocomplete_dropdown_test.ts +0 -315
  133. package/tests/components/autofill_test.ts +0 -167
  134. package/tests/components/bottom_bar_test.ts +0 -262
  135. package/tests/components/chart_side_panel_test.ts +0 -123
  136. package/tests/components/composer_test.ts +0 -400
  137. package/tests/components/context_menu_test.ts +0 -825
  138. package/tests/components/grid_manipulation_test.ts +0 -163
  139. package/tests/components/grid_test.ts +0 -581
  140. package/tests/components/overlay_test.ts +0 -541
  141. package/tests/components/selection_input_test.ts +0 -259
  142. package/tests/components/side_panel_test.ts +0 -148
  143. package/tests/components/spreadsheet_test.ts +0 -194
  144. package/tests/components/top_bar_test.ts +0 -427
  145. package/tests/data_test.ts +0 -175
  146. package/tests/dom_helper.ts +0 -42
  147. package/tests/formulas/__snapshots__/compiler_test.ts.snap +0 -302
  148. package/tests/formulas/compiler_test.ts +0 -266
  149. package/tests/formulas/composer_tokenizer_test.ts +0 -137
  150. package/tests/formulas/expressions_test.ts +0 -57
  151. package/tests/formulas/formulas_test.ts +0 -80
  152. package/tests/formulas/normalize_test.ts +0 -82
  153. package/tests/formulas/parser_test.ts +0 -224
  154. package/tests/formulas/range_tokenizer_test.ts +0 -187
  155. package/tests/formulas/tokenizer_test.ts +0 -164
  156. package/tests/functions/arguments_test.ts +0 -141
  157. package/tests/functions/dates_test.ts +0 -1081
  158. package/tests/functions/functions_test.ts +0 -53
  159. package/tests/functions/helper_test.ts +0 -98
  160. package/tests/functions/module_database_test.ts +0 -311
  161. package/tests/functions/module_date_test.ts +0 -941
  162. package/tests/functions/module_info_test.ts +0 -139
  163. package/tests/functions/module_logical_test.ts +0 -369
  164. package/tests/functions/module_lookup_test.ts +0 -541
  165. package/tests/functions/module_math_test.ts +0 -2482
  166. package/tests/functions/module_operators_test.ts +0 -955
  167. package/tests/functions/module_statistical_test.ts +0 -2014
  168. package/tests/functions/module_text_test.ts +0 -667
  169. package/tests/helpers/coordinates_test.ts +0 -25
  170. package/tests/helpers/misc_test.ts +0 -95
  171. package/tests/helpers/numbers_test.ts +0 -196
  172. package/tests/helpers/zones_test.ts +0 -97
  173. package/tests/helpers.ts +0 -384
  174. package/tests/menu_items_registry_test.ts +0 -540
  175. package/tests/model/plugins/__snapshots__/chart_test.ts.snap +0 -90
  176. package/tests/model/plugins/chart_test.ts +0 -562
  177. package/tests/model_test.ts +0 -82
  178. package/tests/plugins/__snapshots__/conditional_formatting_test.ts.snap +0 -131
  179. package/tests/plugins/__snapshots__/renderer_test.ts.snap +0 -371
  180. package/tests/plugins/autofill_test.ts +0 -457
  181. package/tests/plugins/borders_test.ts +0 -295
  182. package/tests/plugins/clipboard_test.ts +0 -1180
  183. package/tests/plugins/conditional_formatting_test.ts +0 -1253
  184. package/tests/plugins/core_test.ts +0 -614
  185. package/tests/plugins/edition_test.ts +0 -100
  186. package/tests/plugins/evaluation_async_test.ts +0 -332
  187. package/tests/plugins/evaluation_dates_test.ts +0 -79
  188. package/tests/plugins/evaluation_test.ts +0 -901
  189. package/tests/plugins/figures_test.ts +0 -327
  190. package/tests/plugins/formatting_test.ts +0 -391
  191. package/tests/plugins/grid_manipulation_test.ts +0 -1366
  192. package/tests/plugins/highlight_test.ts +0 -413
  193. package/tests/plugins/history_test.ts +0 -142
  194. package/tests/plugins/import_export_test.ts +0 -276
  195. package/tests/plugins/merges_test.ts +0 -490
  196. package/tests/plugins/navigation_test.ts +0 -181
  197. package/tests/plugins/plugins/evaluation_test.ts +0 -111
  198. package/tests/plugins/renderer_test.ts +0 -598
  199. package/tests/plugins/resizing_test.ts +0 -152
  200. package/tests/plugins/selection_input_test.ts +0 -409
  201. package/tests/plugins/selection_test.ts +0 -442
  202. package/tests/plugins/sheets_test.ts +0 -643
  203. package/tests/plugins/style_test.ts +0 -90
  204. package/tsconfig.json +0 -22
@@ -1,1252 +0,0 @@
1
- import { _lt } from "../translation";
2
- import { FunctionDescription } from "../types";
3
- import { args } from "./arguments";
4
- import {
5
- reduceArgs,
6
- reduceNumbers,
7
- strictToNumber,
8
- toNumber,
9
- toString,
10
- visitMatchingRanges,
11
- } from "./helpers";
12
-
13
- // -----------------------------------------------------------------------------
14
- // ACOS
15
- // -----------------------------------------------------------------------------
16
- export const ACOS: FunctionDescription = {
17
- description: _lt("Inverse cosine of a value, in radians."),
18
- args: args(`
19
- value (number) ${_lt(
20
- "The value for which to calculate the inverse cosine. Must be between -1 and 1, inclusive."
21
- )}
22
- `),
23
- returns: ["NUMBER"],
24
- compute: function (value: any): number {
25
- const _value = toNumber(value);
26
- if (Math.abs(_value) > 1) {
27
- throw new Error(
28
- _lt(
29
- "Function [[FUNCTION_NAME]] parameter 1 value is %s. Valid values are between -1 and 1 inclusive.",
30
- _value.toString()
31
- )
32
- );
33
- }
34
- return Math.acos(_value);
35
- },
36
- };
37
-
38
- // -----------------------------------------------------------------------------
39
- // ACOSH
40
- // -----------------------------------------------------------------------------
41
- export const ACOSH: FunctionDescription = {
42
- description: _lt("Inverse hyperbolic cosine of a number."),
43
- args: args(`
44
- value (number) ${_lt(
45
- "The value for which to calculate the inverse hyperbolic cosine. Must be greater than or equal to 1."
46
- )}
47
- `),
48
- returns: ["NUMBER"],
49
- compute: function (value: any): number {
50
- const _value = toNumber(value);
51
- if (_value < 1) {
52
- throw new Error(
53
- _lt(
54
- "Function [[FUNCTION_NAME]] parameter 1 value is %s. It should be greater than or equal to 1.",
55
- _value.toString()
56
- )
57
- );
58
- }
59
- return Math.acosh(_value);
60
- },
61
- };
62
-
63
- // -----------------------------------------------------------------------------
64
- // ACOT
65
- // -----------------------------------------------------------------------------
66
- export const ACOT: FunctionDescription = {
67
- description: _lt("Inverse cotangent of a value."),
68
- args: args(`
69
- value (number) ${_lt("The value for which to calculate the inverse cotangent.")}
70
- `),
71
- returns: ["NUMBER"],
72
- compute: function (value: any): number {
73
- const _value = toNumber(value);
74
- const sign = Math.sign(_value) || 1;
75
- // ACOT has two possible configurations:
76
- // @compatibility Excel: return Math.PI / 2 - Math.atan(toNumber(_value));
77
- // @compatibility Google: return sign * Math.PI / 2 - Math.atan(toNumber(_value));
78
- return (sign * Math.PI) / 2 - Math.atan(_value);
79
- },
80
- };
81
-
82
- // -----------------------------------------------------------------------------
83
- // ACOTH
84
- // -----------------------------------------------------------------------------
85
- export const ACOTH: FunctionDescription = {
86
- description: _lt("Inverse hyperbolic cotangent of a value."),
87
- args: args(`
88
- value (number) ${_lt(
89
- "The value for which to calculate the inverse hyperbolic cotangent. Must not be between -1 and 1, inclusive."
90
- )}
91
- `),
92
- returns: ["NUMBER"],
93
- compute: function (value: any): number {
94
- const _value = toNumber(value);
95
- if (Math.abs(_value) <= 1) {
96
- throw new Error(
97
- _lt(
98
- "Function [[FUNCTION_NAME]] parameter 1 value is %s. Valid values cannot be between -1 and 1 inclusive.",
99
- _value.toString()
100
- )
101
- );
102
- }
103
- return Math.log((_value + 1) / (_value - 1)) / 2;
104
- },
105
- };
106
-
107
- // -----------------------------------------------------------------------------
108
- // ASIN
109
- // -----------------------------------------------------------------------------
110
- export const ASIN: FunctionDescription = {
111
- description: _lt("Inverse sine of a value, in radians."),
112
- args: args(`
113
- value (number) ${_lt(
114
- "The value for which to calculate the inverse sine. Must be between -1 and 1, inclusive."
115
- )}
116
- `),
117
- returns: ["NUMBER"],
118
- compute: function (value: any): number {
119
- const _value = toNumber(value);
120
- if (Math.abs(_value) > 1) {
121
- throw new Error(
122
- _lt(
123
- "Function [[FUNCTION_NAME]] parameter 1 value is %S. Valid values are between -1 and 1 inclusive.",
124
- _value.toString()
125
- )
126
- );
127
- }
128
- return Math.asin(_value);
129
- },
130
- };
131
-
132
- // -----------------------------------------------------------------------------
133
- // ASINH
134
- // -----------------------------------------------------------------------------
135
- export const ASINH: FunctionDescription = {
136
- description: _lt("Inverse hyperbolic sine of a number."),
137
- args: args(`
138
- value (number) ${_lt("The value for which to calculate the inverse hyperbolic sine.")}
139
- `),
140
- returns: ["NUMBER"],
141
- compute: function (value: any): number {
142
- return Math.asinh(toNumber(value));
143
- },
144
- };
145
-
146
- // -----------------------------------------------------------------------------
147
- // ATAN
148
- // -----------------------------------------------------------------------------
149
- export const ATAN: FunctionDescription = {
150
- description: _lt("Inverse tangent of a value, in radians."),
151
- args: args(`
152
- value (number) ${_lt("The value for which to calculate the inverse tangent.")}
153
- `),
154
- returns: ["NUMBER"],
155
- compute: function (value: any): number {
156
- return Math.atan(toNumber(value));
157
- },
158
- };
159
-
160
- // -----------------------------------------------------------------------------
161
- // ATAN2
162
- // -----------------------------------------------------------------------------
163
- export const ATAN2: FunctionDescription = {
164
- description: _lt("Angle from the X axis to a point (x,y), in radians."),
165
- args: args(`
166
- x (number) ${_lt(
167
- "The x coordinate of the endpoint of the line segment for which to calculate the angle from the x-axis."
168
- )}
169
- y (number) ${_lt(
170
- "The y coordinate of the endpoint of the line segment for which to calculate the angle from the x-axis."
171
- )}
172
- `),
173
- returns: ["NUMBER"],
174
- compute: function (x: any, y: any): number {
175
- const _x = toNumber(x);
176
- const _y = toNumber(y);
177
- if (_x === 0 && _y === 0) {
178
- throw new Error(_lt(`Function [[FUNCTION_NAME]] caused a divide by zero error.`));
179
- }
180
- return Math.atan2(_y, _x);
181
- },
182
- };
183
-
184
- // -----------------------------------------------------------------------------
185
- // ATANH
186
- // -----------------------------------------------------------------------------
187
- export const ATANH: FunctionDescription = {
188
- description: _lt("Inverse hyperbolic tangent of a number."),
189
- args: args(`
190
- value (number) ${_lt(
191
- "The value for which to calculate the inverse hyperbolic tangent. Must be between -1 and 1, exclusive."
192
- )}
193
- `),
194
- returns: ["NUMBER"],
195
- compute: function (value: any): number {
196
- const _value = toNumber(value);
197
- if (Math.abs(_value) >= 1) {
198
- throw new Error(
199
- _lt(
200
- "Function [[FUNCTION_NAME]] parameter 1 value is %s. Valid values are between -1 and 1 exclusive.",
201
- _value.toString()
202
- )
203
- );
204
- }
205
- return Math.atanh(_value);
206
- },
207
- };
208
-
209
- // -----------------------------------------------------------------------------
210
- // CEILING
211
- // -----------------------------------------------------------------------------
212
- export const CEILING: FunctionDescription = {
213
- description: _lt(`Rounds number up to nearest multiple of factor.`),
214
- args: args(`
215
- value (number) ${_lt("The value to round up to the nearest integer multiple of factor.")}
216
- factor (number, optional, default=1) ${_lt(
217
- "The number to whose multiples value will be rounded."
218
- )}
219
- `),
220
- returns: ["NUMBER"],
221
- compute: function (value: any, factor: any = 1): number {
222
- const _value = toNumber(value);
223
- const _factor = toNumber(factor);
224
-
225
- if (_value > 0 && _factor < 0) {
226
- throw new Error(
227
- _lt(
228
- "Function CEILING expects the parameter '%s' to be positive when parameter '%s' is positive. Change '%s' from [%s] to a positive value.",
229
- CEILING.args[1].name,
230
- CEILING.args[0].name,
231
- CEILING.args[1].name,
232
- _factor.toString()
233
- )
234
- );
235
- }
236
- return _factor ? Math.ceil(_value / _factor) * _factor : 0;
237
- },
238
- };
239
-
240
- // -----------------------------------------------------------------------------
241
- // CEILING.MATH
242
- // -----------------------------------------------------------------------------
243
- export const CEILING_MATH: FunctionDescription = {
244
- description: _lt(`Rounds number up to nearest multiple of factor.`),
245
- args: args(`
246
- number (number) ${_lt("The value to round up to the nearest integer multiple of significance.")}
247
- significance (number, optional, default=1) ${_lt(
248
- "The number to whose multiples number will be rounded. The sign of significance will be ignored."
249
- )}
250
- mode (number, optional, default=0) ${_lt(
251
- "If number is negative, specifies the rounding direction. If 0 or blank, it is rounded towards zero. Otherwise, it is rounded away from zero."
252
- )}
253
- `),
254
- returns: ["NUMBER"],
255
- compute: function (number: any, significance: any = 1, mode: any = 0): number {
256
- let _significance = toNumber(significance);
257
- if (_significance === 0) {
258
- return 0;
259
- }
260
-
261
- const _number = toNumber(number);
262
- _significance = Math.abs(_significance);
263
- if (_number >= 0) {
264
- return Math.ceil(_number / _significance) * _significance;
265
- }
266
-
267
- const _mode = toNumber(mode);
268
- if (_mode === 0) {
269
- return -Math.floor(Math.abs(_number) / _significance) * _significance;
270
- }
271
-
272
- return -Math.ceil(Math.abs(_number) / _significance) * _significance;
273
- },
274
- };
275
-
276
- // -----------------------------------------------------------------------------
277
- // CEILING.PRECISE
278
- // -----------------------------------------------------------------------------
279
- export const CEILING_PRECISE: FunctionDescription = {
280
- description: _lt(`Rounds number up to nearest multiple of factor.`),
281
- args: args(`
282
- number (number) ${_lt("The value to round up to the nearest integer multiple of significance.")}
283
- significance (number, optional, default=1) ${_lt(
284
- "The number to whose multiples number will be rounded."
285
- )}
286
- `),
287
- returns: ["NUMBER"],
288
- compute: function (number: any, significance: any): number {
289
- return CEILING_MATH.compute(number, significance, 0);
290
- },
291
- };
292
-
293
- // -----------------------------------------------------------------------------
294
- // COS
295
- // -----------------------------------------------------------------------------
296
- export const COS: FunctionDescription = {
297
- description: _lt("Cosine of an angle provided in radians."),
298
- args: args(`
299
- angle (number) ${_lt("The angle to find the cosine of, in radians.")}
300
- `),
301
- returns: ["NUMBER"],
302
- compute: function (angle: any): number {
303
- return Math.cos(toNumber(angle));
304
- },
305
- };
306
-
307
- // -----------------------------------------------------------------------------
308
- // COSH
309
- // -----------------------------------------------------------------------------
310
- export const COSH: FunctionDescription = {
311
- description: _lt("Hyperbolic cosine of any real number."),
312
- args: args(`
313
- value (number) ${_lt("Any real value to calculate the hyperbolic cosine of.")}
314
- `),
315
- returns: ["NUMBER"],
316
- compute: function (value: any): number {
317
- return Math.cosh(toNumber(value));
318
- },
319
- };
320
-
321
- // -----------------------------------------------------------------------------
322
- // COT
323
- // -----------------------------------------------------------------------------
324
- export const COT: FunctionDescription = {
325
- description: _lt("Cotangent of an angle provided in radians."),
326
- args: args(`
327
- angle (number) ${_lt("The angle to find the cotangent of, in radians.")}
328
- `),
329
- returns: ["NUMBER"],
330
- compute: function (angle: any): number {
331
- const _angle = toNumber(angle);
332
- if (_angle === 0) {
333
- throw new Error(
334
- _lt(`Evaluation of function [[FUNCTION_NAME]] caused a divide by zero error.`)
335
- );
336
- }
337
- return 1 / Math.tan(_angle);
338
- },
339
- };
340
-
341
- // -----------------------------------------------------------------------------
342
- // COTH
343
- // -----------------------------------------------------------------------------
344
- export const COTH: FunctionDescription = {
345
- description: _lt("Hyperbolic cotangent of any real number."),
346
- args: args(`
347
- value (number) ${_lt("Any real value to calculate the hyperbolic cotangent of.")}
348
- `),
349
- returns: ["NUMBER"],
350
- compute: function (value: any): number {
351
- const _value = toNumber(value);
352
- if (_value === 0) {
353
- throw new Error(
354
- _lt(`Evaluation of function [[FUNCTION_NAME]] caused a divide by zero error.`)
355
- );
356
- }
357
- return 1 / Math.tanh(_value);
358
- },
359
- };
360
-
361
- // -----------------------------------------------------------------------------
362
- // COUNTBLANK
363
- // -----------------------------------------------------------------------------
364
- export const COUNTBLANK: FunctionDescription = {
365
- description: _lt("Number of empty values."),
366
- args: args(`
367
- value1 (any, range) ${_lt("The first value or range in which to count the number of blanks.")}
368
- value2 (any, range, optional, repeating) ${_lt(
369
- "Additional values or ranges in which to count the number of blanks."
370
- )}
371
- `),
372
- returns: ["NUMBER"],
373
- compute: function (): number {
374
- return reduceArgs(
375
- arguments,
376
- (acc, a) => (a === null || a === undefined || a === "" ? acc + 1 : acc),
377
- 0
378
- );
379
- },
380
- };
381
-
382
- // -----------------------------------------------------------------------------
383
- // COUNTIF
384
- // -----------------------------------------------------------------------------
385
- export const COUNTIF: FunctionDescription = {
386
- description: _lt("A conditional count across a range."),
387
- args: args(`
388
- range (range) ${_lt("The range that is tested against criterion.")}
389
- criterion (string) ${_lt("The pattern or test to apply to range.")}
390
- `),
391
- returns: ["NUMBER"],
392
- compute: function (): number {
393
- let count = 0;
394
- visitMatchingRanges(arguments, (i, j) => {
395
- count += 1;
396
- });
397
- return count;
398
- },
399
- };
400
-
401
- // -----------------------------------------------------------------------------
402
- // COUNTIFS
403
- // -----------------------------------------------------------------------------
404
- export const COUNTIFS: FunctionDescription = {
405
- description: _lt("Count values depending on multiple criteria."),
406
- args: args(`
407
- criteria_range (range) ${_lt("The range to check against criterion1.")}
408
- criterion (string) ${_lt("The pattern or test to apply to criteria_range1.")}
409
- additional_values (any, range, optional, repeating) ${_lt(
410
- "Additional criteria_range and criterion to check."
411
- )}
412
- `),
413
- // @compatibility: on google sheets, args definitions are next:
414
- // criteria_range1 (any, range) The range to check against criterion1.
415
- // criterion1 (string) The pattern or test to apply to criteria_range1.
416
- // criteria_range2 (any, range, optional repeating) Additional ranges over which to evaluate the additional criteria. The filtered set will be the intersection of the sets produced by each criterion-range pair.
417
- // criterion2 (string, optional repeating) Additional criteria to check.
418
- returns: ["NUMBER"],
419
- compute: function (): number {
420
- let count = 0;
421
- visitMatchingRanges(arguments, (i, j) => {
422
- count += 1;
423
- });
424
- return count;
425
- },
426
- };
427
-
428
- // -----------------------------------------------------------------------------
429
- // COUNTUNIQUE
430
- // -----------------------------------------------------------------------------
431
-
432
- function isDefined(value: any): boolean {
433
- switch (value) {
434
- case undefined:
435
- return false;
436
- case "":
437
- return false;
438
- case null:
439
- return false;
440
- default:
441
- return true;
442
- }
443
- }
444
-
445
- export const COUNTUNIQUE: FunctionDescription = {
446
- description: _lt("Counts number of unique values in a range."),
447
- args: args(`
448
- value1 (any, range) ${_lt("The first value or range to consider for uniqueness.")}
449
- value2 (any, range, optional, repeating) ${_lt(
450
- "Additional values or ranges to consider for uniqueness."
451
- )}
452
- `),
453
- returns: ["NUMBER"],
454
- compute: function (): number {
455
- return reduceArgs(arguments, (acc, a) => (isDefined(a) ? acc.add(a) : acc), new Set()).size;
456
- },
457
- };
458
-
459
- // -----------------------------------------------------------------------------
460
- // COUNTUNIQUEIFS
461
- // -----------------------------------------------------------------------------
462
-
463
- export const COUNTUNIQUEIFS: FunctionDescription = {
464
- description: _lt("Counts number of unique values in a range, filtered by a set of criteria."),
465
- args: args(`
466
- range (range) ${_lt(
467
- "The range of cells from which the number of unique values will be counted."
468
- )}
469
- criteria_range1 (range) ${_lt("The range of cells over which to evaluate criterion1.")}
470
- criterion1 (string) ${_lt(
471
- "The pattern or test to apply to criteria_range1, such that each cell that evaluates to TRUE will be included in the filtered set."
472
- )}
473
- additional_values (any, range, optional, repeating) ${_lt(
474
- "Additional criteria_range and criterion to check."
475
- )}
476
- `),
477
- // @compatibility: on google sheets, args definitions are next:
478
- // range (any, range) The range of cells from which the number of unique values will be counted.
479
- // criteria_range1 (any, range) The range of cells over which to evaluate criterion1.
480
- // criterion1 (string) The pattern or test to apply to criteria_range1, such that each cell that evaluates to TRUE will be included in the filtered set.
481
- // criteria_range2 (any, range, optional, repeating) Additional ranges over which to evaluate the additional criteria. The filtered set will be the intersection of the sets produced by each criterion-range pair.
482
- // criterion2 (string, optional, repeating) The pattern or test to apply to criteria_range2.
483
- returns: ["NUMBER"],
484
- compute: function (range, ...args): number {
485
- let uniqueValues = new Set();
486
- visitMatchingRanges(args, (i, j) => {
487
- const value = range[i][j];
488
- if (isDefined(value)) {
489
- uniqueValues.add(value);
490
- }
491
- });
492
- return uniqueValues.size;
493
- },
494
- };
495
-
496
- // -----------------------------------------------------------------------------
497
- // CSC
498
- // -----------------------------------------------------------------------------
499
- export const CSC: FunctionDescription = {
500
- description: _lt("Cosecant of an angle provided in radians."),
501
- args: args(`
502
- angle (number) ${_lt("The angle to find the cosecant of, in radians.")}
503
- `),
504
- returns: ["NUMBER"],
505
- compute: function (angle: any): number {
506
- const _angle = toNumber(angle);
507
- if (_angle === 0) {
508
- throw new Error(_lt(`Function [[FUNCTION_NAME]] caused a divide by zero error.`));
509
- }
510
- return 1 / Math.sin(_angle);
511
- },
512
- };
513
-
514
- // -----------------------------------------------------------------------------
515
- // CSCH
516
- // -----------------------------------------------------------------------------
517
- export const CSCH: FunctionDescription = {
518
- description: _lt("Hyperbolic cosecant of any real number."),
519
- args: args(`
520
- value (number) ${_lt("Any real value to calculate the hyperbolic cosecant of.")}
521
- `),
522
- returns: ["NUMBER"],
523
- compute: function (value: any): number {
524
- const _value = toNumber(value);
525
- if (_value === 0) {
526
- throw new Error(_lt(`Function [[FUNCTION_NAME]] caused a divide by zero error.`));
527
- }
528
- return 1 / Math.sinh(_value);
529
- },
530
- };
531
-
532
- // -----------------------------------------------------------------------------
533
- // DECIMAL
534
- // -----------------------------------------------------------------------------
535
- const decimalErrorParameter2 = (parameterName, base, value) =>
536
- _lt(
537
- "Function DECIMAL expects the parameter '%s' to be a valid base %s representation. Change '%s' from [%s] to a valid base %s representation.",
538
- parameterName,
539
- base,
540
- parameterName,
541
- value,
542
- base
543
- );
544
-
545
- export const DECIMAL: FunctionDescription = {
546
- description: _lt("Converts from another base to decimal."),
547
- args: args(`
548
- value (string) ${_lt("The number to convert.")},
549
- base (number) ${_lt("The base to convert the value from.")},
550
- `),
551
- returns: ["NUMBER"],
552
- compute: function (value: any, base: any): number {
553
- let _base = toNumber(base);
554
- _base = Math.floor(_base);
555
- if (_base < 2 || _base > 36) {
556
- throw new Error(
557
- _lt(
558
- "Function DECIMAL expects the parameter '%s' to be between 2 and 36 inclusive. Change '%s' from [%s] to a value between 2 and 36.",
559
- DECIMAL.args[1].name,
560
- DECIMAL.args[1].name,
561
- _base.toString()
562
- )
563
- );
564
- }
565
-
566
- const _value = toString(value);
567
- if (_value === "") {
568
- return 0;
569
- }
570
-
571
- /**
572
- * @compatibility: on Google sheets, expects the parameter 'value' to be positive.
573
- * Return error if 'value' is positive.
574
- * Remove '-?' in the next regex to catch this error.
575
- */
576
- if (!_value.match(/^-?[a-z0-9]+$/i)) {
577
- throw new Error(decimalErrorParameter2(DECIMAL.args[0].name, _base, _value));
578
- }
579
-
580
- const deci = parseInt(_value, _base);
581
- if (isNaN(deci)) {
582
- throw new Error(decimalErrorParameter2(DECIMAL.args[0].name, _base, _value));
583
- }
584
- return deci;
585
- },
586
- };
587
-
588
- // -----------------------------------------------------------------------------
589
- // DEGREES
590
- // -----------------------------------------------------------------------------
591
- export const DEGREES: FunctionDescription = {
592
- description: _lt(`Converts an angle value in radians to degrees.`),
593
- args: args(`
594
- angle (number) ${_lt("The angle to convert from radians to degrees.")}
595
- `),
596
- returns: ["NUMBER"],
597
- compute: function (angle: any): number {
598
- return (toNumber(angle) * 180) / Math.PI;
599
- },
600
- };
601
-
602
- // -----------------------------------------------------------------------------
603
- // EXP
604
- // -----------------------------------------------------------------------------
605
- export const EXP: FunctionDescription = {
606
- description: _lt(`Euler's number, e (~2.718) raised to a power.`),
607
- args: args(`
608
- value (number) ${_lt("The exponent to raise e.")}
609
- `),
610
- returns: ["NUMBER"],
611
- compute: function (value: any): number {
612
- return Math.exp(toNumber(value));
613
- },
614
- };
615
-
616
- // -----------------------------------------------------------------------------
617
- // FLOOR
618
- // -----------------------------------------------------------------------------
619
- export const FLOOR: FunctionDescription = {
620
- description: _lt(`Rounds number down to nearest multiple of factor.`),
621
- args: args(`
622
- value (number) ${_lt("The value to round down to the nearest integer multiple of factor.")}
623
- factor (number, optional, default=1) ${_lt(
624
- "The number to whose multiples value will be rounded."
625
- )}
626
- `),
627
- returns: ["NUMBER"],
628
- compute: function (value: any, factor: any = 1): number {
629
- const _value = toNumber(value);
630
- const _factor = toNumber(factor);
631
-
632
- if (_value > 0 && _factor < 0) {
633
- throw new Error(
634
- _lt(
635
- "Function FLOOR expects the parameter '%s' to be positive when parameter '%s' is positive. Change '%s' from [%s] to a positive value.",
636
- FLOOR.args[1].name,
637
- FLOOR.args[0].name,
638
- FLOOR.args[1].name,
639
- _factor.toString()
640
- )
641
- );
642
- }
643
- return _factor ? Math.floor(_value / _factor) * _factor : 0;
644
- },
645
- };
646
-
647
- // -----------------------------------------------------------------------------
648
- // FLOOR.MATH
649
- // -----------------------------------------------------------------------------
650
- export const FLOOR_MATH: FunctionDescription = {
651
- description: _lt(`Rounds number down to nearest multiple of factor.`),
652
- args: args(`
653
- number (number) ${_lt(
654
- "The value to round down to the nearest integer multiple of significance."
655
- )}
656
- significance (number, optional, default=1) ${_lt(
657
- "The number to whose multiples number will be rounded. The sign of significance will be ignored."
658
- )}
659
- mode (number, optional, default=0) ${_lt(
660
- "If number is negative, specifies the rounding direction. If 0 or blank, it is rounded away from zero. Otherwise, it is rounded towards zero."
661
- )}
662
- `),
663
- returns: ["NUMBER"],
664
- compute: function (number: any, significance: any = 1, mode: any = 0): number {
665
- let _significance = toNumber(significance);
666
- if (_significance === 0) {
667
- return 0;
668
- }
669
-
670
- const _number = toNumber(number);
671
- _significance = Math.abs(_significance);
672
- if (_number >= 0) {
673
- return Math.floor(_number / _significance) * _significance;
674
- }
675
-
676
- const _mode = toNumber(mode);
677
- if (_mode === 0) {
678
- return -Math.ceil(Math.abs(_number) / _significance) * _significance;
679
- }
680
- return -Math.floor(Math.abs(_number) / _significance) * _significance;
681
- },
682
- };
683
-
684
- // -----------------------------------------------------------------------------
685
- // FLOOR.PRECISE
686
- // -----------------------------------------------------------------------------
687
- export const FLOOR_PRECISE: FunctionDescription = {
688
- description: _lt(`Rounds number down to nearest multiple of factor.`),
689
- args: args(`
690
- number (number) ${_lt(
691
- "The value to round down to the nearest integer multiple of significance."
692
- )}
693
- significance (number, optional, default=1) ${_lt(
694
- "The number to whose multiples number will be rounded."
695
- )}
696
- `),
697
- returns: ["NUMBER"],
698
- compute: function (number: number, significance: number = 1): number {
699
- return FLOOR_MATH.compute(number, significance, 0);
700
- },
701
- };
702
-
703
- // -----------------------------------------------------------------------------
704
- // ISEVEN
705
- // -----------------------------------------------------------------------------
706
- export const ISEVEN: FunctionDescription = {
707
- description: _lt(`Whether the provided value is even.`),
708
- args: args(`
709
- value (number) ${_lt("The value to be verified as even.")}
710
- `),
711
- returns: ["BOOLEAN"],
712
- compute: function (value: any): boolean {
713
- const _value = strictToNumber(value);
714
-
715
- return Math.floor(Math.abs(_value)) & 1 ? false : true;
716
- },
717
- };
718
-
719
- // -----------------------------------------------------------------------------
720
- // ISO.CEILING
721
- // -----------------------------------------------------------------------------
722
- export const ISO_CEILING: FunctionDescription = {
723
- description: _lt(`Rounds number up to nearest multiple of factor.`),
724
- args: args(`
725
- number (number) ${_lt(
726
- "The value to round up to the nearest integer multiple of significance."
727
- )}
728
- significance (number, optional, default=1) ${_lt(
729
- "The number to whose multiples number will be rounded."
730
- )}
731
- `),
732
- returns: ["NUMBER"],
733
- compute: function (number: any, significance: any): number {
734
- return CEILING_MATH.compute(number, significance, 0);
735
- },
736
- };
737
-
738
- // -----------------------------------------------------------------------------
739
- // ISODD
740
- // -----------------------------------------------------------------------------
741
- export const ISODD: FunctionDescription = {
742
- description: _lt(`Whether the provided value is even.`),
743
- args: args(`
744
- value (number) ${_lt("The value to be verified as even.")}
745
- `),
746
- returns: ["BOOLEAN"],
747
- compute: function (value: any): boolean {
748
- const _value = strictToNumber(value);
749
-
750
- return Math.floor(Math.abs(_value)) & 1 ? true : false;
751
- },
752
- };
753
-
754
- // -----------------------------------------------------------------------------
755
- // LN
756
- // -----------------------------------------------------------------------------
757
- export const LN: FunctionDescription = {
758
- description: _lt(`The logarithm of a number, base e (euler's number).`),
759
- args: args(`
760
- value (number) ${_lt("The value for which to calculate the logarithm, base e.")}
761
- `),
762
- returns: ["NUMBER"],
763
- compute: function (value: any): number {
764
- const _value = toNumber(value);
765
- if (_value <= 0) {
766
- throw new Error(
767
- _lt(
768
- "Function [[FUNCTION_NAME]] parameter 1 value is %s. It should be greater than 0.",
769
- _value.toString()
770
- )
771
- );
772
- }
773
- return Math.log(_value);
774
- },
775
- };
776
-
777
- // -----------------------------------------------------------------------------
778
- // MOD
779
- // -----------------------------------------------------------------------------
780
- export const MOD: FunctionDescription = {
781
- description: _lt(`Modulo (remainder) operator.`),
782
- args: args(`
783
- dividend (number) ${_lt("The number to be divided to find the remainder.")}
784
- divisor (number) ${_lt("The number to divide by.")}
785
- `),
786
- returns: ["NUMBER"],
787
- compute: function (dividend: any, divisor: any): number {
788
- const _divisor = toNumber(divisor);
789
-
790
- if (_divisor === 0) {
791
- throw new Error(
792
- _lt(
793
- "Function MOD expects the parameter '%s' to be different from 0. Change '%s' to a value other than 0.",
794
- MOD.args[1].name,
795
- MOD.args[1].name
796
- )
797
- );
798
- }
799
- const _dividend = toNumber(dividend);
800
- const modulus = _dividend % _divisor;
801
- // -42 % 10 = -2 but we want 8, so need the code below
802
- if ((modulus > 0 && _divisor < 0) || (modulus < 0 && _divisor > 0)) {
803
- return modulus + _divisor;
804
- }
805
- return modulus;
806
- },
807
- };
808
-
809
- // -----------------------------------------------------------------------------
810
- // ODD
811
- // -----------------------------------------------------------------------------
812
- export const ODD: FunctionDescription = {
813
- description: _lt(`Rounds a number up to the nearest odd integer.`),
814
- args: args(`
815
- value (number) ${_lt("The value to round to the next greatest odd number.")}
816
- `),
817
- returns: ["NUMBER"],
818
- compute: function (value: any): number {
819
- const _value = toNumber(value);
820
-
821
- let temp = Math.ceil(Math.abs(_value));
822
- temp = temp & 1 ? temp : temp + 1;
823
- return _value < 0 ? -temp : temp;
824
- },
825
- };
826
-
827
- // -----------------------------------------------------------------------------
828
- // PI
829
- // -----------------------------------------------------------------------------
830
- export const PI: FunctionDescription = {
831
- description: _lt(`The number pi.`),
832
- args: [],
833
- returns: ["NUMBER"],
834
- compute: function (): number {
835
- return Math.PI;
836
- },
837
- };
838
-
839
- // -----------------------------------------------------------------------------
840
- // POWER
841
- // -----------------------------------------------------------------------------
842
- export const POWER: FunctionDescription = {
843
- description: _lt(`A number raised to a power.`),
844
- args: args(`
845
- base (number) ${_lt("The number to raise to the exponent power.")}
846
- exponent (number) ${_lt("The exponent to raise base to.")}
847
- `),
848
- returns: ["NUMBER"],
849
- compute: function (base: any, exponent: any): number {
850
- const _base = toNumber(base);
851
- const _exponent = toNumber(exponent);
852
-
853
- if (_base >= 0) {
854
- return Math.pow(_base, _exponent);
855
- }
856
- if (!Number.isInteger(_exponent)) {
857
- throw new Error(
858
- _lt(
859
- "Function POWER expects the parameter '%s' to be an integer when parameter '%s' is negative. Change '%s' from [%s] to an integer value.",
860
- POWER.args[1].name,
861
- POWER.args[0].name,
862
- POWER.args[1].name,
863
- _exponent.toString()
864
- )
865
- );
866
- }
867
- return Math.pow(_base, _exponent);
868
- },
869
- };
870
-
871
- // -----------------------------------------------------------------------------
872
- // PRODUCT
873
- // -----------------------------------------------------------------------------
874
- export const PRODUCT: FunctionDescription = {
875
- description: _lt("Result of multiplying a series of numbers together."),
876
- args: args(`
877
- factor1 (number, range<number>) ${_lt(
878
- "The first number or range to calculate for the product."
879
- )}
880
- factor2 (number, range<number>, optional, repeating) ${_lt(
881
- "More numbers or ranges to calculate for the product."
882
- )}
883
- `),
884
- returns: ["NUMBER"],
885
- compute: function (): number {
886
- let count = 0;
887
- let acc = 1;
888
- for (let n of arguments) {
889
- if (Array.isArray(n)) {
890
- for (let i of n) {
891
- for (let j of i) {
892
- if (typeof j === "number") {
893
- acc *= j;
894
- count += 1;
895
- }
896
- }
897
- }
898
- } else if (n !== null) {
899
- acc *= strictToNumber(n);
900
- count += 1;
901
- }
902
- }
903
- if (count === 0) {
904
- return 0;
905
- }
906
- return acc;
907
- },
908
- };
909
-
910
- // -----------------------------------------------------------------------------
911
- // RAND
912
- // -----------------------------------------------------------------------------
913
- export const RAND: FunctionDescription = {
914
- description: _lt("A random number between 0 inclusive and 1 exclusive."),
915
- args: [],
916
- returns: ["NUMBER"],
917
- compute: function (): number {
918
- return Math.random();
919
- },
920
- };
921
-
922
- // -----------------------------------------------------------------------------
923
- // RANDBETWEEN
924
- // -----------------------------------------------------------------------------
925
- export const RANDBETWEEN: FunctionDescription = {
926
- description: _lt("Random integer between two values, inclusive."),
927
- args: args(`
928
- low (number) ${_lt("The low end of the random range.")}
929
- high (number) ${_lt("The high end of the random range.")}
930
- `),
931
- returns: ["NUMBER"],
932
- compute: function (low: any, high: any): number {
933
- let _low = toNumber(low);
934
- if (!Number.isInteger(_low)) {
935
- _low = Math.ceil(_low);
936
- }
937
-
938
- let _high = toNumber(high);
939
- if (!Number.isInteger(_high)) {
940
- _high = Math.floor(_high);
941
- }
942
-
943
- if (_high < _low) {
944
- throw new Error(
945
- _lt(
946
- "Function RANDBETWEEN parameter '%s' value is %s. It should be greater than or equal to [%s].",
947
- RANDBETWEEN.args[1].name,
948
- _high.toString(),
949
- _low.toString()
950
- )
951
- );
952
- }
953
- return _low + Math.ceil((_high - _low + 1) * Math.random()) - 1;
954
- },
955
- };
956
-
957
- // -----------------------------------------------------------------------------
958
- // ROUND
959
- // -----------------------------------------------------------------------------
960
- export const ROUND: FunctionDescription = {
961
- description: _lt("Rounds a number according to standard rules."),
962
- args: args(`
963
- value (number) ${_lt("The value to round to places number of places.")}
964
- places (number, optional, default=0) ${_lt("The number of decimal places to which to round.")}
965
- `),
966
- returns: ["NUMBER"],
967
- compute: function (value: any, places: any = 0): number {
968
- const _value = toNumber(value);
969
- let _places = toNumber(places);
970
-
971
- const absValue = Math.abs(_value);
972
- let tempResult;
973
- if (_places === 0) {
974
- tempResult = Math.round(absValue);
975
- } else {
976
- if (!Number.isInteger(_places)) {
977
- _places = Math.trunc(_places);
978
- }
979
- tempResult = Math.round(absValue * Math.pow(10, _places)) / Math.pow(10, _places);
980
- }
981
- return _value >= 0 ? tempResult : -tempResult;
982
- },
983
- };
984
-
985
- // -----------------------------------------------------------------------------
986
- // ROUNDDOWN
987
- // -----------------------------------------------------------------------------
988
- export const ROUNDDOWN: FunctionDescription = {
989
- description: _lt(`Rounds down a number.`),
990
- args: args(`
991
- value (number) ${_lt("The value to round to places number of places, always rounding down.")}
992
- places (number, optional, default=0) ${_lt("The number of decimal places to which to round.")}
993
- `),
994
- returns: ["NUMBER"],
995
- compute: function (value: any, places: any = 0): number {
996
- const _value = toNumber(value);
997
- let _places = toNumber(places);
998
-
999
- const absValue = Math.abs(_value);
1000
- let tempResult;
1001
- if (_places === 0) {
1002
- tempResult = Math.floor(absValue);
1003
- } else {
1004
- if (!Number.isInteger(_places)) {
1005
- _places = Math.trunc(_places);
1006
- }
1007
- tempResult = Math.floor(absValue * Math.pow(10, _places)) / Math.pow(10, _places);
1008
- }
1009
- return _value >= 0 ? tempResult : -tempResult;
1010
- },
1011
- };
1012
-
1013
- // -----------------------------------------------------------------------------
1014
- // ROUNDUP
1015
- // -----------------------------------------------------------------------------
1016
- export const ROUNDUP: FunctionDescription = {
1017
- description: _lt(`Rounds up a number.`),
1018
- args: args(`
1019
- value (number) ${_lt("The value to round to places number of places, always rounding up.")}
1020
- places (number, optional, default=0) ${_lt("The number of decimal places to which to round.")}
1021
- `),
1022
- returns: ["NUMBER"],
1023
- compute: function (value: any, places: any): number {
1024
- const _value = toNumber(value);
1025
- let _places = toNumber(places);
1026
-
1027
- const absValue = Math.abs(_value);
1028
- let tempResult;
1029
- if (_places === 0) {
1030
- tempResult = Math.ceil(absValue);
1031
- } else {
1032
- if (!Number.isInteger(_places)) {
1033
- _places = Math.trunc(_places);
1034
- }
1035
- tempResult = Math.ceil(absValue * Math.pow(10, _places)) / Math.pow(10, _places);
1036
- }
1037
- return _value >= 0 ? tempResult : -tempResult;
1038
- },
1039
- };
1040
-
1041
- // -----------------------------------------------------------------------------
1042
- // SEC
1043
- // -----------------------------------------------------------------------------
1044
- export const SEC: FunctionDescription = {
1045
- description: _lt("Secant of an angle provided in radians."),
1046
- args: args(`
1047
- angle (number) ${_lt("The angle to find the secant of, in radians.")}
1048
- `),
1049
- returns: ["NUMBER"],
1050
- compute: function (angle: any): number {
1051
- return 1 / Math.cos(toNumber(angle));
1052
- },
1053
- };
1054
-
1055
- // -----------------------------------------------------------------------------
1056
- // SECH
1057
- // -----------------------------------------------------------------------------
1058
- export const SECH: FunctionDescription = {
1059
- description: _lt("Hyperbolic secant of any real number."),
1060
- args: args(`
1061
- value (number) ${_lt("Any real value to calculate the hyperbolic secant of.")}
1062
- `),
1063
- returns: ["NUMBER"],
1064
- compute: function (value: any): number {
1065
- return 1 / Math.cosh(toNumber(value));
1066
- },
1067
- };
1068
-
1069
- // -----------------------------------------------------------------------------
1070
- // SIN
1071
- // -----------------------------------------------------------------------------
1072
- export const SIN: FunctionDescription = {
1073
- description: _lt("Sine of an angle provided in radians."),
1074
- args: args(`
1075
- angle (number) ${_lt("The angle to find the sine of, in radians.")}
1076
- `),
1077
- returns: ["NUMBER"],
1078
- compute: function (angle: number): number {
1079
- return Math.sin(toNumber(angle));
1080
- },
1081
- };
1082
-
1083
- // -----------------------------------------------------------------------------
1084
- // SINH
1085
- // -----------------------------------------------------------------------------
1086
- export const SINH: FunctionDescription = {
1087
- description: _lt("Hyperbolic sine of any real number."),
1088
- args: args(`
1089
- value (number) ${_lt("Any real value to calculate the hyperbolic sine of.")}
1090
- `),
1091
- returns: ["NUMBER"],
1092
- compute: function (value: any): number {
1093
- return Math.sinh(toNumber(value));
1094
- },
1095
- };
1096
-
1097
- // -----------------------------------------------------------------------------
1098
- // SQRT
1099
- // -----------------------------------------------------------------------------
1100
- export const SQRT: FunctionDescription = {
1101
- description: _lt("Positive square root of a positive number."),
1102
- args: args(`
1103
- value (number) ${_lt("The number for which to calculate the positive square root.")}
1104
- `),
1105
- returns: ["NUMBER"],
1106
- compute: function (value: any): number {
1107
- const _value = toNumber(value);
1108
-
1109
- if (_value < 0) {
1110
- throw new Error(
1111
- _lt(
1112
- "Function SQRT parameter '%s' value is negative. It should be positive or zero. Change '%s' from [%s] to a positive value.",
1113
- SQRT.args[0].name,
1114
- SQRT.args[0].name,
1115
- _value.toString()
1116
- )
1117
- );
1118
- }
1119
- return Math.sqrt(_value);
1120
- },
1121
- };
1122
-
1123
- // -----------------------------------------------------------------------------
1124
- // SUM
1125
- // -----------------------------------------------------------------------------
1126
- export const SUM: FunctionDescription = {
1127
- description: _lt("Sum of a series of numbers and/or cells."),
1128
- args: args(`
1129
- value1 (number, range<number>) ${_lt("The first number or range to add together.")}
1130
- value2 (number, range<number>, optional, repeating) ${_lt(
1131
- "Additional numbers or ranges to add to value1."
1132
- )}
1133
- `),
1134
- returns: ["NUMBER"],
1135
- compute: function (): number {
1136
- return reduceNumbers(arguments, (acc, a) => acc + a, 0);
1137
- },
1138
- };
1139
-
1140
- // -----------------------------------------------------------------------------
1141
- // SUMIF
1142
- // -----------------------------------------------------------------------------
1143
- export const SUMIF: FunctionDescription = {
1144
- description: _lt("A conditional sum across a range."),
1145
- args: args(`
1146
- criteria_range (range) ${_lt("The range which is tested against criterion.")}
1147
- criterion (string) ${_lt("The pattern or test to apply to range.")}
1148
- sum_range (range, optional, default=criteria_range) ${_lt(
1149
- "The range to be summed, if different from range."
1150
- )}
1151
- `),
1152
- returns: ["NUMBER"],
1153
- compute: function (criteria_range: any, criterion: any, sum_range: any = undefined): number {
1154
- if (sum_range === undefined) {
1155
- sum_range = criteria_range;
1156
- }
1157
- let sum = 0;
1158
- visitMatchingRanges([criteria_range, criterion], (i, j) => {
1159
- const value = sum_range[i][j];
1160
- if (typeof value === "number") {
1161
- sum += value;
1162
- }
1163
- });
1164
- return sum;
1165
- },
1166
- };
1167
-
1168
- // -----------------------------------------------------------------------------
1169
- // SUMIFS
1170
- // -----------------------------------------------------------------------------
1171
- export const SUMIFS: FunctionDescription = {
1172
- description: _lt("Sums a range depending on multiple criteria."),
1173
- args: args(`
1174
- sum_range (range) ${_lt("The range to sum.")}
1175
- criteria_range1 (range) ${_lt("The range to check against criterion1.")}
1176
- criterion1 (string) ${_lt("The pattern or test to apply to criteria_range1.")}
1177
- additional_values (any, range, optional, repeating) ${_lt(
1178
- "Additional criteria_range and criterion to check."
1179
- )}
1180
- `),
1181
- // @compatibility: on google sheets, args definitions are next:
1182
- // sum_range (any, range) The range to sum.
1183
- // criteria_range1 (any, range) The range to check against criterion1.
1184
- // criterion1 (string) The pattern or test to apply to criteria_range1.
1185
- // criteria_range2 (any, range, optional, repeating) Additional ranges to check.
1186
- // criterion2 (string, optional, repeating) Additional criteria to check.
1187
- returns: ["NUMBER"],
1188
- compute: function (sum_range, ...args): number {
1189
- let sum = 0;
1190
- visitMatchingRanges(args, (i, j) => {
1191
- const value = sum_range[i][j];
1192
- if (typeof value === "number") {
1193
- sum += value;
1194
- }
1195
- });
1196
- return sum;
1197
- },
1198
- };
1199
-
1200
- // -----------------------------------------------------------------------------
1201
- // TAN
1202
- // -----------------------------------------------------------------------------
1203
- export const TAN: FunctionDescription = {
1204
- description: _lt("Tangent of an angle provided in radians."),
1205
- args: args(`
1206
- angle (number) ${_lt("The angle to find the tangent of, in radians.")}
1207
- `),
1208
- returns: ["NUMBER"],
1209
- compute: function (angle: any): number {
1210
- return Math.tan(toNumber(angle));
1211
- },
1212
- };
1213
-
1214
- // -----------------------------------------------------------------------------
1215
- // TANH
1216
- // -----------------------------------------------------------------------------
1217
- export const TANH: FunctionDescription = {
1218
- description: _lt("Hyperbolic tangent of any real number."),
1219
- args: args(`
1220
- value (number) ${_lt("Any real value to calculate the hyperbolic tangent of.")}
1221
- `),
1222
- returns: ["NUMBER"],
1223
- compute: function (value: any): number {
1224
- return Math.tanh(toNumber(value));
1225
- },
1226
- };
1227
-
1228
- // -----------------------------------------------------------------------------
1229
- // TRUNC
1230
- // -----------------------------------------------------------------------------
1231
- export const TRUNC: FunctionDescription = {
1232
- description: _lt("Truncates a number."),
1233
- args: args(`
1234
- value (number) ${_lt("The value to be truncated.")}
1235
- places (number, optional, default=0) ${_lt(
1236
- "The number of significant digits to the right of the decimal point to retain."
1237
- )}
1238
- `),
1239
- returns: ["NUMBER"],
1240
- compute: function (value: any, places: any = 0): number {
1241
- const _value = toNumber(value);
1242
- let _places = toNumber(places);
1243
-
1244
- if (_places === 0) {
1245
- return Math.trunc(_value);
1246
- }
1247
- if (!Number.isInteger(_places)) {
1248
- _places = Math.trunc(_places);
1249
- }
1250
- return Math.trunc(_value * Math.pow(10, _places)) / Math.pow(10, _places);
1251
- },
1252
- };