@trebco/treb 23.6.5 → 25.0.0-rc1

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 (217) hide show
  1. package/.eslintignore +8 -0
  2. package/.eslintrc.js +164 -0
  3. package/README-shadow-DOM.md +88 -0
  4. package/README.md +37 -130
  5. package/api-config.json +29 -0
  6. package/api-generator/api-generator-types.ts +82 -0
  7. package/api-generator/api-generator.ts +1172 -0
  8. package/api-generator/package.json +3 -0
  9. package/build/treb-spreadsheet.mjs +14 -0
  10. package/{treb.d.ts → build/treb.d.ts} +285 -269
  11. package/esbuild-custom-element.mjs +336 -0
  12. package/esbuild.js +305 -0
  13. package/package.json +43 -14
  14. package/treb-base-types/package.json +5 -0
  15. package/treb-base-types/src/api_types.ts +36 -0
  16. package/treb-base-types/src/area.ts +583 -0
  17. package/treb-base-types/src/basic_types.ts +45 -0
  18. package/treb-base-types/src/cell.ts +612 -0
  19. package/treb-base-types/src/cells.ts +1066 -0
  20. package/treb-base-types/src/color.ts +124 -0
  21. package/treb-base-types/src/import.ts +71 -0
  22. package/treb-base-types/src/index-standalone.ts +29 -0
  23. package/treb-base-types/src/index.ts +42 -0
  24. package/treb-base-types/src/layout.ts +47 -0
  25. package/treb-base-types/src/localization.ts +187 -0
  26. package/treb-base-types/src/rectangle.ts +145 -0
  27. package/treb-base-types/src/render_text.ts +72 -0
  28. package/treb-base-types/src/style.ts +545 -0
  29. package/treb-base-types/src/table.ts +109 -0
  30. package/treb-base-types/src/text_part.ts +54 -0
  31. package/treb-base-types/src/theme.ts +608 -0
  32. package/treb-base-types/src/union.ts +152 -0
  33. package/treb-base-types/src/value-type.ts +164 -0
  34. package/treb-base-types/style/resizable.css +59 -0
  35. package/treb-calculator/modern.tsconfig.json +11 -0
  36. package/treb-calculator/package.json +5 -0
  37. package/treb-calculator/src/calculator.ts +2546 -0
  38. package/treb-calculator/src/complex-math.ts +558 -0
  39. package/treb-calculator/src/dag/array-vertex.ts +198 -0
  40. package/treb-calculator/src/dag/graph.ts +951 -0
  41. package/treb-calculator/src/dag/leaf_vertex.ts +118 -0
  42. package/treb-calculator/src/dag/spreadsheet_vertex.ts +327 -0
  43. package/treb-calculator/src/dag/spreadsheet_vertex_base.ts +44 -0
  44. package/treb-calculator/src/dag/vertex.ts +352 -0
  45. package/treb-calculator/src/descriptors.ts +162 -0
  46. package/treb-calculator/src/expression-calculator.ts +1069 -0
  47. package/treb-calculator/src/function-error.ts +103 -0
  48. package/treb-calculator/src/function-library.ts +103 -0
  49. package/treb-calculator/src/functions/base-functions.ts +1214 -0
  50. package/treb-calculator/src/functions/checkbox.ts +164 -0
  51. package/treb-calculator/src/functions/complex-functions.ts +253 -0
  52. package/treb-calculator/src/functions/finance-functions.ts +399 -0
  53. package/treb-calculator/src/functions/information-functions.ts +102 -0
  54. package/treb-calculator/src/functions/matrix-functions.ts +182 -0
  55. package/treb-calculator/src/functions/sparkline.ts +335 -0
  56. package/treb-calculator/src/functions/statistics-functions.ts +350 -0
  57. package/treb-calculator/src/functions/text-functions.ts +298 -0
  58. package/treb-calculator/src/index.ts +27 -0
  59. package/treb-calculator/src/notifier-types.ts +59 -0
  60. package/treb-calculator/src/primitives.ts +428 -0
  61. package/treb-calculator/src/utilities.ts +305 -0
  62. package/treb-charts/package.json +5 -0
  63. package/treb-charts/src/chart-functions.ts +156 -0
  64. package/treb-charts/src/chart-types.ts +230 -0
  65. package/treb-charts/src/chart.ts +1288 -0
  66. package/treb-charts/src/index.ts +24 -0
  67. package/treb-charts/src/main.ts +37 -0
  68. package/treb-charts/src/rectangle.ts +52 -0
  69. package/treb-charts/src/renderer.ts +1841 -0
  70. package/treb-charts/src/util.ts +122 -0
  71. package/treb-charts/style/charts.scss +221 -0
  72. package/treb-charts/style/old-charts.scss +250 -0
  73. package/treb-embed/markup/layout.html +137 -0
  74. package/treb-embed/markup/toolbar.html +175 -0
  75. package/treb-embed/modern.tsconfig.json +25 -0
  76. package/treb-embed/src/custom-element/content-types.d.ts +18 -0
  77. package/treb-embed/src/custom-element/global.d.ts +11 -0
  78. package/treb-embed/src/custom-element/spreadsheet-constructor.ts +1227 -0
  79. package/treb-embed/src/custom-element/treb-global.ts +44 -0
  80. package/treb-embed/src/custom-element/treb-spreadsheet-element.ts +52 -0
  81. package/treb-embed/src/embedded-spreadsheet.ts +5362 -0
  82. package/treb-embed/src/index.ts +16 -0
  83. package/treb-embed/src/language-model.ts +41 -0
  84. package/treb-embed/src/options.ts +320 -0
  85. package/treb-embed/src/progress-dialog.ts +228 -0
  86. package/treb-embed/src/selection-state.ts +16 -0
  87. package/treb-embed/src/spinner.ts +42 -0
  88. package/treb-embed/src/toolbar-message.ts +96 -0
  89. package/treb-embed/src/types.ts +167 -0
  90. package/treb-embed/style/autocomplete.scss +103 -0
  91. package/treb-embed/style/dark-theme.scss +114 -0
  92. package/treb-embed/style/defaults.scss +36 -0
  93. package/treb-embed/style/dialog.scss +181 -0
  94. package/treb-embed/style/dropdown-select.scss +101 -0
  95. package/treb-embed/style/formula-bar.scss +193 -0
  96. package/treb-embed/style/grid.scss +374 -0
  97. package/treb-embed/style/layout.scss +424 -0
  98. package/treb-embed/style/mouse-mask.scss +67 -0
  99. package/treb-embed/style/note.scss +92 -0
  100. package/treb-embed/style/overlay-editor.scss +102 -0
  101. package/treb-embed/style/spinner.scss +92 -0
  102. package/treb-embed/style/tab-bar.scss +228 -0
  103. package/treb-embed/style/table.scss +80 -0
  104. package/treb-embed/style/theme-defaults.scss +444 -0
  105. package/treb-embed/style/toolbar.scss +416 -0
  106. package/treb-embed/style/tooltip.scss +68 -0
  107. package/treb-embed/style/treb-icons.scss +130 -0
  108. package/treb-embed/style/treb-spreadsheet-element.scss +20 -0
  109. package/treb-embed/style/z-index.scss +43 -0
  110. package/treb-export/docs/charts.md +68 -0
  111. package/treb-export/modern.tsconfig.json +19 -0
  112. package/treb-export/package.json +4 -0
  113. package/treb-export/src/address-type.ts +77 -0
  114. package/treb-export/src/base-template.ts +22 -0
  115. package/treb-export/src/column-width.ts +85 -0
  116. package/treb-export/src/drawing2/chart-template-components2.ts +389 -0
  117. package/treb-export/src/drawing2/chart2.ts +282 -0
  118. package/treb-export/src/drawing2/column-chart-template2.ts +521 -0
  119. package/treb-export/src/drawing2/donut-chart-template2.ts +296 -0
  120. package/treb-export/src/drawing2/drawing2.ts +355 -0
  121. package/treb-export/src/drawing2/embedded-image.ts +71 -0
  122. package/treb-export/src/drawing2/scatter-chart-template2.ts +555 -0
  123. package/treb-export/src/export-worker/export-worker.ts +99 -0
  124. package/treb-export/src/export-worker/index-modern.ts +22 -0
  125. package/treb-export/src/export2.ts +2204 -0
  126. package/treb-export/src/import2.ts +882 -0
  127. package/treb-export/src/relationship.ts +36 -0
  128. package/treb-export/src/shared-strings2.ts +128 -0
  129. package/treb-export/src/template-2.ts +22 -0
  130. package/treb-export/src/unescape_xml.ts +47 -0
  131. package/treb-export/src/workbook-sheet2.ts +182 -0
  132. package/treb-export/src/workbook-style2.ts +1285 -0
  133. package/treb-export/src/workbook-theme2.ts +88 -0
  134. package/treb-export/src/workbook2.ts +491 -0
  135. package/treb-export/src/xml-utils.ts +201 -0
  136. package/treb-export/template/base/[Content_Types].xml +2 -0
  137. package/treb-export/template/base/_rels/.rels +2 -0
  138. package/treb-export/template/base/docProps/app.xml +2 -0
  139. package/treb-export/template/base/docProps/core.xml +12 -0
  140. package/treb-export/template/base/xl/_rels/workbook.xml.rels +2 -0
  141. package/treb-export/template/base/xl/sharedStrings.xml +2 -0
  142. package/treb-export/template/base/xl/styles.xml +2 -0
  143. package/treb-export/template/base/xl/theme/theme1.xml +2 -0
  144. package/treb-export/template/base/xl/workbook.xml +2 -0
  145. package/treb-export/template/base/xl/worksheets/sheet1.xml +2 -0
  146. package/treb-export/template/base.xlsx +0 -0
  147. package/treb-format/package.json +8 -0
  148. package/treb-format/src/format.test.ts +213 -0
  149. package/treb-format/src/format.ts +942 -0
  150. package/treb-format/src/format_cache.ts +199 -0
  151. package/treb-format/src/format_parser.ts +723 -0
  152. package/treb-format/src/index.ts +25 -0
  153. package/treb-format/src/number_format_section.ts +100 -0
  154. package/treb-format/src/value_parser.ts +337 -0
  155. package/treb-grid/package.json +5 -0
  156. package/treb-grid/src/editors/autocomplete.ts +394 -0
  157. package/treb-grid/src/editors/autocomplete_matcher.ts +260 -0
  158. package/treb-grid/src/editors/formula_bar.ts +473 -0
  159. package/treb-grid/src/editors/formula_editor_base.ts +910 -0
  160. package/treb-grid/src/editors/overlay_editor.ts +511 -0
  161. package/treb-grid/src/index.ts +37 -0
  162. package/treb-grid/src/layout/base_layout.ts +2618 -0
  163. package/treb-grid/src/layout/grid_layout.ts +299 -0
  164. package/treb-grid/src/layout/rectangle_cache.ts +86 -0
  165. package/treb-grid/src/render/selection-renderer.ts +414 -0
  166. package/treb-grid/src/render/svg_header_overlay.ts +93 -0
  167. package/treb-grid/src/render/svg_selection_block.ts +187 -0
  168. package/treb-grid/src/render/tile_renderer.ts +2122 -0
  169. package/treb-grid/src/types/annotation.ts +216 -0
  170. package/treb-grid/src/types/border_constants.ts +34 -0
  171. package/treb-grid/src/types/clipboard_data.ts +31 -0
  172. package/treb-grid/src/types/data_model.ts +334 -0
  173. package/treb-grid/src/types/drag_mask.ts +81 -0
  174. package/treb-grid/src/types/grid.ts +7743 -0
  175. package/treb-grid/src/types/grid_base.ts +3644 -0
  176. package/treb-grid/src/types/grid_command.ts +470 -0
  177. package/treb-grid/src/types/grid_events.ts +124 -0
  178. package/treb-grid/src/types/grid_options.ts +97 -0
  179. package/treb-grid/src/types/grid_selection.ts +60 -0
  180. package/treb-grid/src/types/named_range.ts +369 -0
  181. package/treb-grid/src/types/scale-control.ts +202 -0
  182. package/treb-grid/src/types/serialize_options.ts +72 -0
  183. package/treb-grid/src/types/set_range_options.ts +52 -0
  184. package/treb-grid/src/types/sheet.ts +3099 -0
  185. package/treb-grid/src/types/sheet_types.ts +95 -0
  186. package/treb-grid/src/types/tab_bar.ts +464 -0
  187. package/treb-grid/src/types/tile.ts +59 -0
  188. package/treb-grid/src/types/update_flags.ts +75 -0
  189. package/treb-grid/src/util/dom_utilities.ts +44 -0
  190. package/treb-grid/src/util/fontmetrics2.ts +179 -0
  191. package/treb-grid/src/util/ua.ts +104 -0
  192. package/treb-logo.svg +18 -0
  193. package/treb-parser/package.json +5 -0
  194. package/treb-parser/src/csv-parser.ts +122 -0
  195. package/treb-parser/src/index.ts +25 -0
  196. package/treb-parser/src/md-parser.ts +526 -0
  197. package/treb-parser/src/parser-types.ts +397 -0
  198. package/treb-parser/src/parser.test.ts +298 -0
  199. package/treb-parser/src/parser.ts +2673 -0
  200. package/treb-utils/package.json +5 -0
  201. package/treb-utils/src/dispatch.ts +57 -0
  202. package/treb-utils/src/event_source.ts +147 -0
  203. package/treb-utils/src/ievent_source.ts +33 -0
  204. package/treb-utils/src/index.ts +31 -0
  205. package/treb-utils/src/measurement.ts +174 -0
  206. package/treb-utils/src/resizable.ts +160 -0
  207. package/treb-utils/src/scale.ts +137 -0
  208. package/treb-utils/src/serialize_html.ts +124 -0
  209. package/treb-utils/src/template.ts +70 -0
  210. package/treb-utils/src/validate_uri.ts +61 -0
  211. package/tsconfig.json +10 -0
  212. package/tsproject.json +30 -0
  213. package/util/license-plugin-esbuild.js +86 -0
  214. package/util/list-css-vars.sh +46 -0
  215. package/README-esm.md +0 -37
  216. package/treb-bundle.css +0 -2
  217. package/treb-bundle.mjs +0 -15
@@ -0,0 +1,428 @@
1
+ /*
2
+ * This file is part of TREB.
3
+ *
4
+ * TREB is free software: you can redistribute it and/or modify it under the
5
+ * terms of the GNU General Public License as published by the Free Software
6
+ * Foundation, either version 3 of the License, or (at your option) any
7
+ * later version.
8
+ *
9
+ * TREB is distributed in the hope that it will be useful, but WITHOUT ANY
10
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12
+ * details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License along
15
+ * with TREB. If not, see <https://www.gnu.org/licenses/>.
16
+ *
17
+ * Copyright 2022-2023 trebco, llc.
18
+ * info@treb.app
19
+ *
20
+ */
21
+
22
+ import { Complex, IsComplex, UnionValue, ValueType } from 'treb-base-types';
23
+ import { DivideByZeroError, ValueError } from './function-error';
24
+
25
+ import * as ComplexLib from './complex-math';
26
+
27
+ // import { PolarToRectangular, RectangularToPolar,
28
+ // MultiplyComplex, DivideComplex, PowerComplex } from './complex-math';
29
+
30
+ export type PrimitiveBinaryExpression = (a: UnionValue, b: UnionValue) => UnionValue;
31
+
32
+ type NumericTuple = [number, number, UnionValue?, UnionValue?, UnionValue?];
33
+
34
+ /**
35
+ * a is either a complex union value or undefined. if it's defined,
36
+ * return it. if it's undefined, return a complex number with the given
37
+ * real value.
38
+ */
39
+ const EnsureComplex = (a?: UnionValue, real = 0): { type: ValueType.complex, value: {real: number, imaginary: number}} => {
40
+
41
+ if (a && a.type === ValueType.complex) {
42
+ return a as {type: ValueType.complex, value: {real: number, imaginary: number}};
43
+ }
44
+
45
+ return {
46
+ type: ValueType.complex,
47
+ value: {
48
+ real,
49
+ imaginary: 0,
50
+ },
51
+ };
52
+
53
+ }
54
+
55
+ /**
56
+ * return a complex number or, if there's no imaginary component, reduce it to a real
57
+ */
58
+ const BoxComplex = (value: Complex): UnionValue => {
59
+ return value.imaginary ?
60
+ { type: ValueType.complex, value } :
61
+ { type: ValueType.number, value: value.real };
62
+ }
63
+
64
+ const NumericTypes = (a: UnionValue, b: UnionValue): NumericTuple => {
65
+
66
+ if (a.type === ValueType.error) { return [0, 0, a]; }
67
+ if (b.type === ValueType.error) { return [0, 0, b]; }
68
+
69
+ const result: NumericTuple = [0, 0];
70
+
71
+ // FIXME: what about empty string? should === 0?
72
+
73
+ switch (a.type) {
74
+ case ValueType.number:
75
+ result[0] = a.value as number;
76
+ break;
77
+
78
+ case ValueType.boolean:
79
+ result[0] = a.value ? 1 : 0;
80
+ break;
81
+
82
+ case ValueType.undefined:
83
+ break;
84
+
85
+ case ValueType.complex:
86
+ result[3] = a;
87
+ break;
88
+
89
+ default:
90
+ return [0, 0, ValueError()]; // FIXME
91
+ }
92
+
93
+ switch (b.type) {
94
+ case ValueType.number:
95
+ result[1] = b.value as number;
96
+ break;
97
+
98
+ case ValueType.boolean:
99
+ result[1] = b.value ? 1 : 0;
100
+ break;
101
+
102
+ case ValueType.undefined:
103
+ break;
104
+
105
+ case ValueType.complex:
106
+ result[4] = b;
107
+ break;
108
+
109
+ default:
110
+ return [0, 0, ValueError()]; // FIXME
111
+ }
112
+
113
+ // if we have one complex value, ensure we have two, so
114
+ // we don't have to test again.
115
+
116
+ if (result[3] || result[4]) {
117
+ result[3] = EnsureComplex(result[3], result[0]);
118
+ result[4] = EnsureComplex(result[4], result[1]);
119
+ }
120
+
121
+ return result;
122
+ }
123
+
124
+ export const Add = (a: UnionValue, b: UnionValue): UnionValue => {
125
+ const [x, y, z, c1, c2] = NumericTypes(a, b);
126
+
127
+ if (z) { return z; }
128
+
129
+ if (c1 && c2) {
130
+ return BoxComplex({
131
+ real: c1.value.real + c2.value.real,
132
+ imaginary: c1.value.imaginary + c2.value.imaginary,
133
+ });
134
+ }
135
+
136
+ return { value: x + y, type: ValueType.number };
137
+ };
138
+
139
+ export const Subtract = (a: UnionValue, b: UnionValue): UnionValue => {
140
+
141
+ const [x, y, z, c1, c2] = NumericTypes(a, b);
142
+
143
+ if (z) { return z; }
144
+
145
+ if (c1 && c2) {
146
+ return BoxComplex({
147
+ real: c1.value.real - c2.value.real,
148
+ imaginary: c1.value.imaginary - c2.value.imaginary,
149
+ });
150
+ }
151
+
152
+ return { value: x - y, type: ValueType.number };
153
+ };
154
+
155
+ /**
156
+ * power function that only uses complex numbers if one of
157
+ * the arguments is complex. this is intended to prevent complex
158
+ * numbers from leaking in to spreadsheets.
159
+ */
160
+ const PowerGated = (a: UnionValue, b: UnionValue): UnionValue => {
161
+ const [x, y, z, c1, c2] = NumericTypes(a, b);
162
+ if (z) { return z; }
163
+
164
+ if (c1 && c2) {
165
+ return BoxComplex(ComplexLib.Power(c1.value, c2.value));
166
+ }
167
+
168
+ const value = Math.pow(x, y);
169
+ if (isNaN(value)) { return ValueError(); }
170
+
171
+ return { type: ValueType.number, value };
172
+
173
+ };
174
+
175
+ /**
176
+ * power function that uses complex exponentiation if one of the arguments
177
+ * is complex, or if the exponent is < 1.
178
+ */
179
+ const PowerComplex = (a: UnionValue, b: UnionValue): UnionValue => {
180
+
181
+ const [x, y, z, c1, c2] = NumericTypes(a, b);
182
+ if (z) { return z; }
183
+
184
+ // if one argument is complex, we will always get both as complex.
185
+ // so we don't need to re-test. for the same reason if exponent
186
+ // is < 1 we will have to convert both.
187
+
188
+ if (c1 && c2) {
189
+ return BoxComplex(ComplexLib.Power(c1.value, c2.value));
190
+ }
191
+
192
+ if (x < 0 && y !== 0 && Math.abs(y) < 1) {
193
+ return BoxComplex(ComplexLib.Power(
194
+ { real: x, imaginary: 0}, { real: y, imaginary: 0 }));
195
+ }
196
+
197
+ const value = Math.pow(x, y);
198
+ if (isNaN(value)) { return ValueError(); }
199
+
200
+ return { type: ValueType.number, value };
201
+
202
+ };
203
+
204
+ /*
205
+ export const Power = (a: UnionValue, b: UnionValue): UnionValue => {
206
+ const [x, y, z, c1, c2] = NumericTypes(a, b);
207
+ if (z) { return z; }
208
+
209
+ if (c1 && c2) {
210
+ return BoxComplex(ComplexLib.Power(c1.value, c2.value));
211
+ }
212
+
213
+ const value = Math.pow(x, y);
214
+ if (isNaN(value)) { return ValueError(); }
215
+
216
+ return { type: ValueType.number, value };
217
+
218
+ };
219
+ */
220
+
221
+ let Power = PowerGated;
222
+
223
+ export const Multiply = (a: UnionValue, b: UnionValue): UnionValue => {
224
+
225
+ const [x, y, z, c1, c2] = NumericTypes(a, b);
226
+
227
+ if (z) { return z; }
228
+
229
+ if (c1 && c2) {
230
+ return BoxComplex(ComplexLib.Multiply(c1.value, c2.value));
231
+ }
232
+
233
+ return { value: x * y, type: ValueType.number };
234
+ };
235
+
236
+ export const Divide = (a: UnionValue, b: UnionValue): UnionValue => {
237
+ const [x, y, z, c1, c2] = NumericTypes(a, b);
238
+ if (z) { return z; }
239
+
240
+ if (c1 && c2) {
241
+ if (c2.value.real === 0 && c2.value.imaginary === 0) {
242
+ return DivideByZeroError();
243
+ }
244
+ return BoxComplex(ComplexLib.Divide(c1.value, c2.value));
245
+ }
246
+
247
+ if (y === 0) {
248
+ return DivideByZeroError();
249
+ }
250
+ return { value: x / y, type: ValueType.number };
251
+ };
252
+
253
+ export const Modulo = (a: UnionValue, b: UnionValue): UnionValue => {
254
+ const [x, y, z] = NumericTypes(a, b);
255
+ if (z) { return z; }
256
+ if (y === 0) {
257
+ return DivideByZeroError();
258
+ }
259
+ return { value: x % y, type: ValueType.number };
260
+ };
261
+
262
+ export const Concatenate = (a: UnionValue, b: UnionValue): UnionValue => {
263
+ if (a.type === ValueType.error) { return a; }
264
+ if (b.type === ValueType.error) { return b; }
265
+
266
+ return {
267
+ type: ValueType.string,
268
+ value: `${a.type === ValueType.undefined ? '' : a.value}${b.type === ValueType.undefined ? '' : b.value}`,
269
+ };
270
+
271
+ };
272
+
273
+ export const Equals = (a: UnionValue, b: UnionValue): UnionValue => {
274
+ if (a.type === ValueType.error) { return a; }
275
+ if (b.type === ValueType.error) { return b; }
276
+
277
+ // empty cells equal 0 (real or complex) and ""
278
+
279
+ if ((a.type === ValueType.undefined && (b.value === '' || b.value === 0 || (b.type === ValueType.complex && b.value.real === 0 && b.value.imaginary === 0)))
280
+ || (b.type === ValueType.undefined && (a.value === '' || a.value === 0 || (a.type === ValueType.complex && a.value.real === 0 && a.value.imaginary === 0)))) {
281
+ return { type: ValueType.boolean, value: true, };
282
+ }
283
+
284
+ if (a.type === ValueType.complex || b.type === ValueType.complex) {
285
+
286
+ // complex can equal real or complex
287
+
288
+ let equals = false;
289
+
290
+ if (a.type === b.type) {
291
+ equals =
292
+ a.value.real == b.value.real && // == ?
293
+ a.value.imaginary == b.value.imaginary // == ?
294
+ ;
295
+ }
296
+ else if (a.type === ValueType.number) {
297
+ equals =
298
+ b.value.real == a.value &&
299
+ !b.value.imaginary;
300
+ }
301
+ else if (b.type === ValueType.number) {
302
+ equals =
303
+ a.value.real == b.value &&
304
+ !a.value.imaginary;
305
+ }
306
+
307
+ return { type: ValueType.boolean, value: equals };
308
+
309
+ }
310
+
311
+ return { type: ValueType.boolean, value: a.value == b.value }; // note ==
312
+ };
313
+
314
+ export const NotEquals = (a: UnionValue, b: UnionValue): UnionValue => {
315
+ const result = Equals(a, b);
316
+ if (result.type === ValueType.error) {
317
+ return result;
318
+ }
319
+ return {
320
+ type: ValueType.boolean,
321
+ value: !result.value,
322
+ };
323
+ };
324
+
325
+ /* *
326
+ * this is duplicative, but it seems better than another function call.
327
+ * not sure if that is over-optimization (it is).
328
+ * /
329
+ export const NotEquals = (a: UnionValue, b: UnionValue): UnionValue => {
330
+ if (a.type === ValueType.error) { return a; }
331
+ if (b.type === ValueType.error) { return b; }
332
+
333
+ // empty cells equal 0 and ""
334
+ // FIXME: should also equal a complex with 0+0i
335
+
336
+ if ((a.type === ValueType.undefined && (b.value === '' || b.value === 0))
337
+ || (b.type === ValueType.undefined && (a.value === '' || a.value === 0))) {
338
+
339
+ return { type: ValueType.boolean, value: false, };
340
+ }
341
+
342
+ if (a.type === ValueType.complex || b.type === ValueType.complex) {
343
+ return {
344
+ type: ValueType.boolean,
345
+ value: !((a.type === b.type) &&
346
+ a.value.real == b.value.real && // ==
347
+ a.value.imaginary == b.value.imaginary) // ==
348
+ };
349
+
350
+ }
351
+
352
+ return { type: ValueType.boolean, value: a.value != b.value }; // note ==
353
+ };
354
+ */
355
+
356
+ // NOTE: our comparisons don't match Excel with different types -- we could
357
+ // probably figure out what Excel is doing, but I'm not sure it's useful or
358
+ // worthwhile
359
+
360
+ export const GreaterThan = (a: UnionValue, b: UnionValue): UnionValue => {
361
+ if (a.type === ValueType.error) { return a; }
362
+ if (b.type === ValueType.error) { return b; }
363
+
364
+ if (a.type === ValueType.complex || b.type === ValueType.complex) {
365
+ return ValueError();
366
+ }
367
+
368
+ return { type: ValueType.boolean, value: (a.value||0) > (b.value||0) };
369
+ };
370
+
371
+ export const GreaterThanEqual = (a: UnionValue, b: UnionValue): UnionValue => {
372
+ if (a.type === ValueType.error) { return a; }
373
+ if (b.type === ValueType.error) { return b; }
374
+
375
+ if (a.type === ValueType.complex || b.type === ValueType.complex) {
376
+ return ValueError();
377
+ }
378
+
379
+ return { type: ValueType.boolean, value: a.value >= b.value };
380
+ };
381
+
382
+ export const LessThan = (a: UnionValue, b: UnionValue): UnionValue => {
383
+ if (a.type === ValueType.error) { return a; }
384
+ if (b.type === ValueType.error) { return b; }
385
+
386
+ if (a.type === ValueType.complex || b.type === ValueType.complex) {
387
+ return ValueError();
388
+ }
389
+
390
+ return { type: ValueType.boolean, value: a.value < b.value };
391
+ };
392
+
393
+ export const LessThanEqual = (a: UnionValue, b: UnionValue): UnionValue => {
394
+ if (a.type === ValueType.error) { return a; }
395
+ if (b.type === ValueType.error) { return b; }
396
+
397
+ if (a.type === ValueType.complex || b.type === ValueType.complex) {
398
+ return ValueError();
399
+ }
400
+
401
+ return { type: ValueType.boolean, value: a.value <= b.value };
402
+ };
403
+
404
+ export const UseComplex = () => {
405
+ Power = PowerComplex;
406
+ }
407
+
408
+ export const MapOperator = (operator: string) => {
409
+ switch(operator) {
410
+ case '&': return Concatenate;
411
+ case '+': return Add;
412
+ case '-': return Subtract;
413
+ case '*': return Multiply;
414
+ case '/': return Divide;
415
+ case '^': return Power;
416
+ case '**': return Power;
417
+ case '%': return Modulo; // NOTE: not an excel operator
418
+ case '=': return Equals;
419
+ case '==': return Equals;
420
+ case '!=': return NotEquals;
421
+ case '<>': return NotEquals;
422
+ case '>': return GreaterThan;
423
+ case '>=': return GreaterThanEqual;
424
+ case '<': return LessThan;
425
+ case '<=': return LessThanEqual;
426
+ }
427
+ return undefined;
428
+ };