@bgroup/wise-form 1.0.1

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 (319) hide show
  1. package/README.md +34 -0
  2. package/dist/components/ui/Checkbox.d.ts +14 -0
  3. package/dist/components/ui/Checkbox.d.ts.map +1 -0
  4. package/dist/components/ui/Checkbox.js +43 -0
  5. package/dist/components/ui/Checkbox.js.map +1 -0
  6. package/dist/components/ui/CheckboxGroup.d.ts +15 -0
  7. package/dist/components/ui/CheckboxGroup.d.ts.map +1 -0
  8. package/dist/components/ui/CheckboxGroup.js +33 -0
  9. package/dist/components/ui/CheckboxGroup.js.map +1 -0
  10. package/dist/components/ui/Input.d.ts +14 -0
  11. package/dist/components/ui/Input.d.ts.map +1 -0
  12. package/dist/components/ui/Input.js +49 -0
  13. package/dist/components/ui/Input.js.map +1 -0
  14. package/dist/components/ui/Radio.d.ts +14 -0
  15. package/dist/components/ui/Radio.d.ts.map +1 -0
  16. package/dist/components/ui/Radio.js +43 -0
  17. package/dist/components/ui/Radio.js.map +1 -0
  18. package/dist/components/ui/Select.d.ts +18 -0
  19. package/dist/components/ui/Select.d.ts.map +1 -0
  20. package/dist/components/ui/Select.js +44 -0
  21. package/dist/components/ui/Select.js.map +1 -0
  22. package/dist/components/ui/Textarea.d.ts +13 -0
  23. package/dist/components/ui/Textarea.d.ts.map +1 -0
  24. package/dist/components/ui/Textarea.js +42 -0
  25. package/dist/components/ui/Textarea.js.map +1 -0
  26. package/dist/components/ui/index.d.ts +13 -0
  27. package/dist/components/ui/index.d.ts.map +1 -0
  28. package/dist/components/ui/index.js +7 -0
  29. package/dist/components/ui/index.js.map +1 -0
  30. package/dist/form/index.d.ts +10 -0
  31. package/dist/form/index.d.ts.map +1 -0
  32. package/dist/form/index.js +5 -0
  33. package/dist/form/index.js.map +1 -0
  34. package/dist/form/interfaces/field-container.d.ts +8 -0
  35. package/dist/form/interfaces/field-container.d.ts.map +1 -0
  36. package/dist/form/interfaces/field-container.js +2 -0
  37. package/dist/form/interfaces/field-container.js.map +1 -0
  38. package/dist/form/interfaces/interfaces.d.ts +8 -0
  39. package/dist/form/interfaces/interfaces.d.ts.map +1 -0
  40. package/dist/form/interfaces/interfaces.js +2 -0
  41. package/dist/form/interfaces/interfaces.js.map +1 -0
  42. package/dist/form/interfaces/settings.d.ts +10 -0
  43. package/dist/form/interfaces/settings.d.ts.map +1 -0
  44. package/dist/form/interfaces/settings.js +2 -0
  45. package/dist/form/interfaces/settings.js.map +1 -0
  46. package/dist/form/interfaces/template.d.ts +6 -0
  47. package/dist/form/interfaces/template.d.ts.map +1 -0
  48. package/dist/form/interfaces/template.js +2 -0
  49. package/dist/form/interfaces/template.js.map +1 -0
  50. package/dist/form/interfaces/wise-form-specs.d.ts +9 -0
  51. package/dist/form/interfaces/wise-form-specs.d.ts.map +1 -0
  52. package/dist/form/interfaces/wise-form-specs.js +2 -0
  53. package/dist/form/interfaces/wise-form-specs.js.map +1 -0
  54. package/dist/form/view/components/containers/index.d.ts +3 -0
  55. package/dist/form/view/components/containers/index.d.ts.map +1 -0
  56. package/dist/form/view/components/containers/index.js +12 -0
  57. package/dist/form/view/components/containers/index.js.map +1 -0
  58. package/dist/form/view/components/error.d.ts +5 -0
  59. package/dist/form/view/components/error.d.ts.map +1 -0
  60. package/dist/form/view/components/error.js +8 -0
  61. package/dist/form/view/components/error.js.map +1 -0
  62. package/dist/form/view/components/field/container.d.ts +5 -0
  63. package/dist/form/view/components/field/container.d.ts.map +1 -0
  64. package/dist/form/view/components/field/container.js +5 -0
  65. package/dist/form/view/components/field/container.js.map +1 -0
  66. package/dist/form/view/components/field/index.d.ts +18 -0
  67. package/dist/form/view/components/field/index.d.ts.map +1 -0
  68. package/dist/form/view/components/field/index.js +89 -0
  69. package/dist/form/view/components/field/index.js.map +1 -0
  70. package/dist/form/view/components/field/selection.d.ts +2 -0
  71. package/dist/form/view/components/field/selection.d.ts.map +1 -0
  72. package/dist/form/view/components/field/selection.js +35 -0
  73. package/dist/form/view/components/field/selection.js.map +1 -0
  74. package/dist/form/view/components/field/use-field.d.ts +4 -0
  75. package/dist/form/view/components/field/use-field.d.ts.map +1 -0
  76. package/dist/form/view/components/field/use-field.js +41 -0
  77. package/dist/form/view/components/field/use-field.js.map +1 -0
  78. package/dist/form/view/components/rows/row-container.d.ts +18 -0
  79. package/dist/form/view/components/rows/row-container.d.ts.map +1 -0
  80. package/dist/form/view/components/rows/row-container.js +89 -0
  81. package/dist/form/view/components/rows/row-container.js.map +1 -0
  82. package/dist/form/view/components/rows/wrapper.d.ts +12 -0
  83. package/dist/form/view/components/rows/wrapper.d.ts.map +1 -0
  84. package/dist/form/view/components/rows/wrapper.js +27 -0
  85. package/dist/form/view/components/rows/wrapper.js.map +1 -0
  86. package/dist/form/view/components/wrapped-form.d.ts +6 -0
  87. package/dist/form/view/components/wrapped-form.d.ts.map +1 -0
  88. package/dist/form/view/components/wrapped-form.js +26 -0
  89. package/dist/form/view/components/wrapped-form.js.map +1 -0
  90. package/dist/form/view/context.d.ts +23 -0
  91. package/dist/form/view/context.d.ts.map +1 -0
  92. package/dist/form/view/context.js +7 -0
  93. package/dist/form/view/context.js.map +1 -0
  94. package/dist/form/view/hooks/use-model.d.ts +10 -0
  95. package/dist/form/view/hooks/use-model.d.ts.map +1 -0
  96. package/dist/form/view/hooks/use-model.js +31 -0
  97. package/dist/form/view/hooks/use-model.js.map +1 -0
  98. package/dist/form/view/hooks/use-template.d.ts +14 -0
  99. package/dist/form/view/hooks/use-template.d.ts.map +1 -0
  100. package/dist/form/view/hooks/use-template.js +57 -0
  101. package/dist/form/view/hooks/use-template.js.map +1 -0
  102. package/dist/form/view/hooks/use-types.d.ts +2 -0
  103. package/dist/form/view/hooks/use-types.d.ts.map +1 -0
  104. package/dist/form/view/hooks/use-types.js +19 -0
  105. package/dist/form/view/hooks/use-types.js.map +1 -0
  106. package/dist/form/view/index.d.ts +3 -0
  107. package/dist/form/view/index.d.ts.map +1 -0
  108. package/dist/form/view/index.js +38 -0
  109. package/dist/form/view/index.js.map +1 -0
  110. package/dist/formulas/helpers/condition-types.d.ts +5 -0
  111. package/dist/formulas/helpers/condition-types.d.ts.map +1 -0
  112. package/dist/formulas/helpers/condition-types.js +5 -0
  113. package/dist/formulas/helpers/condition-types.js.map +1 -0
  114. package/dist/formulas/helpers/evaluations.d.ts +15 -0
  115. package/dist/formulas/helpers/evaluations.d.ts.map +1 -0
  116. package/dist/formulas/helpers/evaluations.js +44 -0
  117. package/dist/formulas/helpers/evaluations.js.map +1 -0
  118. package/dist/formulas/helpers/formula.d.ts +6 -0
  119. package/dist/formulas/helpers/formula.d.ts.map +1 -0
  120. package/dist/formulas/helpers/formula.js +26 -0
  121. package/dist/formulas/helpers/formula.js.map +1 -0
  122. package/dist/formulas/helpers/lexer.d.ts +10 -0
  123. package/dist/formulas/helpers/lexer.d.ts.map +1 -0
  124. package/dist/formulas/helpers/lexer.js +73 -0
  125. package/dist/formulas/helpers/lexer.js.map +1 -0
  126. package/dist/formulas/helpers/parser.d.ts +24 -0
  127. package/dist/formulas/helpers/parser.d.ts.map +1 -0
  128. package/dist/formulas/helpers/parser.js +48 -0
  129. package/dist/formulas/helpers/parser.js.map +1 -0
  130. package/dist/formulas/helpers/token.d.ts +14 -0
  131. package/dist/formulas/helpers/token.d.ts.map +1 -0
  132. package/dist/formulas/helpers/token.js +14 -0
  133. package/dist/formulas/helpers/token.js.map +1 -0
  134. package/dist/formulas/index.d.ts +59 -0
  135. package/dist/formulas/index.d.ts.map +1 -0
  136. package/dist/formulas/index.js +186 -0
  137. package/dist/formulas/index.js.map +1 -0
  138. package/dist/formulas/types/formulas.d.ts +68 -0
  139. package/dist/formulas/types/formulas.d.ts.map +1 -0
  140. package/dist/formulas/types/formulas.js +2 -0
  141. package/dist/formulas/types/formulas.js.map +1 -0
  142. package/dist/formulas/types/index.d.ts +5 -0
  143. package/dist/formulas/types/index.d.ts.map +1 -0
  144. package/dist/formulas/types/index.js +2 -0
  145. package/dist/formulas/types/index.js.map +1 -0
  146. package/dist/formulas/variants/array-formula.d.ts +24 -0
  147. package/dist/formulas/variants/array-formula.d.ts.map +1 -0
  148. package/dist/formulas/variants/array-formula.js +142 -0
  149. package/dist/formulas/variants/array-formula.js.map +1 -0
  150. package/dist/formulas/variants/base.d.ts +6 -0
  151. package/dist/formulas/variants/base.d.ts.map +1 -0
  152. package/dist/formulas/variants/base.js +3 -0
  153. package/dist/formulas/variants/base.js.map +1 -0
  154. package/dist/formulas/variants/basic.d.ts +18 -0
  155. package/dist/formulas/variants/basic.d.ts.map +1 -0
  156. package/dist/formulas/variants/basic.js +128 -0
  157. package/dist/formulas/variants/basic.js.map +1 -0
  158. package/dist/formulas/variants/comparison.d.ts +25 -0
  159. package/dist/formulas/variants/comparison.d.ts.map +1 -0
  160. package/dist/formulas/variants/comparison.js +153 -0
  161. package/dist/formulas/variants/comparison.js.map +1 -0
  162. package/dist/formulas/variants/conditional.d.ts +18 -0
  163. package/dist/formulas/variants/conditional.d.ts.map +1 -0
  164. package/dist/formulas/variants/conditional.js +183 -0
  165. package/dist/formulas/variants/conditional.js.map +1 -0
  166. package/dist/formulas/variants/iterative-array.d.ts +20 -0
  167. package/dist/formulas/variants/iterative-array.d.ts.map +1 -0
  168. package/dist/formulas/variants/iterative-array.js +155 -0
  169. package/dist/formulas/variants/iterative-array.js.map +1 -0
  170. package/dist/formulas/variants/per-value.d.ts +20 -0
  171. package/dist/formulas/variants/per-value.d.ts.map +1 -0
  172. package/dist/formulas/variants/per-value.js +154 -0
  173. package/dist/formulas/variants/per-value.js.map +1 -0
  174. package/dist/index.d.ts +5 -0
  175. package/dist/index.d.ts.map +1 -0
  176. package/dist/index.js +6 -0
  177. package/dist/index.js.map +1 -0
  178. package/dist/models/base.d.ts +55 -0
  179. package/dist/models/base.d.ts.map +1 -0
  180. package/dist/models/base.js +146 -0
  181. package/dist/models/base.js.map +1 -0
  182. package/dist/models/callback-manager.d.ts +7 -0
  183. package/dist/models/callback-manager.d.ts.map +1 -0
  184. package/dist/models/callback-manager.js +89 -0
  185. package/dist/models/callback-manager.js.map +1 -0
  186. package/dist/models/field.d.ts +121 -0
  187. package/dist/models/field.d.ts.map +1 -0
  188. package/dist/models/field.js +374 -0
  189. package/dist/models/field.js.map +1 -0
  190. package/dist/models/index.d.ts +13 -0
  191. package/dist/models/index.d.ts.map +1 -0
  192. package/dist/models/index.js +7 -0
  193. package/dist/models/index.js.map +1 -0
  194. package/dist/models/model.d.ts +37 -0
  195. package/dist/models/model.d.ts.map +1 -0
  196. package/dist/models/model.js +245 -0
  197. package/dist/models/model.js.map +1 -0
  198. package/dist/models/plugins/base.d.ts +9 -0
  199. package/dist/models/plugins/base.d.ts.map +1 -0
  200. package/dist/models/plugins/base.js +3 -0
  201. package/dist/models/plugins/base.js.map +1 -0
  202. package/dist/models/plugins/formula.d.ts +18 -0
  203. package/dist/models/plugins/formula.d.ts.map +1 -0
  204. package/dist/models/plugins/formula.js +82 -0
  205. package/dist/models/plugins/formula.js.map +1 -0
  206. package/dist/models/plugins/index.d.ts +11 -0
  207. package/dist/models/plugins/index.d.ts.map +1 -0
  208. package/dist/models/plugins/index.js +52 -0
  209. package/dist/models/plugins/index.js.map +1 -0
  210. package/dist/models/plugins/plugins.d.ts +7 -0
  211. package/dist/models/plugins/plugins.d.ts.map +1 -0
  212. package/dist/models/plugins/plugins.js +7 -0
  213. package/dist/models/plugins/plugins.js.map +1 -0
  214. package/dist/models/types/base-wise-model.d.ts +7 -0
  215. package/dist/models/types/base-wise-model.d.ts.map +1 -0
  216. package/dist/models/types/base-wise-model.js +2 -0
  217. package/dist/models/types/base-wise-model.js.map +1 -0
  218. package/dist/models/types/callbacks.d.ts +19 -0
  219. package/dist/models/types/callbacks.d.ts.map +1 -0
  220. package/dist/models/types/callbacks.js +2 -0
  221. package/dist/models/types/callbacks.js.map +1 -0
  222. package/dist/models/types/disabled.d.ts +8 -0
  223. package/dist/models/types/disabled.d.ts.map +1 -0
  224. package/dist/models/types/disabled.js +2 -0
  225. package/dist/models/types/disabled.js.map +1 -0
  226. package/dist/models/types/form-field.d.ts +25 -0
  227. package/dist/models/types/form-field.d.ts.map +1 -0
  228. package/dist/models/types/form-field.js +2 -0
  229. package/dist/models/types/form-field.js.map +1 -0
  230. package/dist/models/types/model.d.ts +13 -0
  231. package/dist/models/types/model.d.ts.map +1 -0
  232. package/dist/models/types/model.js +2 -0
  233. package/dist/models/types/model.js.map +1 -0
  234. package/dist/models/types/plugins.d.ts +13 -0
  235. package/dist/models/types/plugins.d.ts.map +1 -0
  236. package/dist/models/types/plugins.js +2 -0
  237. package/dist/models/types/plugins.js.map +1 -0
  238. package/dist/models/types/wrapped-form-model-props.d.ts +11 -0
  239. package/dist/models/types/wrapped-form-model-props.d.ts.map +1 -0
  240. package/dist/models/types/wrapped-form-model-props.js +2 -0
  241. package/dist/models/types/wrapped-form-model-props.js.map +1 -0
  242. package/dist/models/wrapper.d.ts +30 -0
  243. package/dist/models/wrapper.d.ts.map +1 -0
  244. package/dist/models/wrapper.js +213 -0
  245. package/dist/models/wrapper.js.map +1 -0
  246. package/dist/settings/index.d.ts +7 -0
  247. package/dist/settings/index.d.ts.map +1 -0
  248. package/dist/settings/index.js +26 -0
  249. package/dist/settings/index.js.map +1 -0
  250. package/dist/utils/pending-promise.d.ts +6 -0
  251. package/dist/utils/pending-promise.d.ts.map +1 -0
  252. package/dist/utils/pending-promise.js +24 -0
  253. package/dist/utils/pending-promise.js.map +1 -0
  254. package/package.json +38 -0
  255. package/src/components/ui/Checkbox.tsx +68 -0
  256. package/src/components/ui/CheckboxGroup.tsx +60 -0
  257. package/src/components/ui/Input.tsx +72 -0
  258. package/src/components/ui/Radio.tsx +68 -0
  259. package/src/components/ui/Select.tsx +73 -0
  260. package/src/components/ui/Textarea.tsx +63 -0
  261. package/src/components/ui/index.ts +14 -0
  262. package/src/form/index.ts +11 -0
  263. package/src/form/interfaces/field-container.ts +9 -0
  264. package/src/form/interfaces/interfaces.ts +12 -0
  265. package/src/form/interfaces/settings.ts +11 -0
  266. package/src/form/interfaces/template.ts +7 -0
  267. package/src/form/interfaces/wise-form-specs.ts +10 -0
  268. package/src/form/styles.css +40 -0
  269. package/src/form/view/components/containers/index.tsx +18 -0
  270. package/src/form/view/components/error.tsx +9 -0
  271. package/src/form/view/components/field/container.tsx +6 -0
  272. package/src/form/view/components/field/index.tsx +107 -0
  273. package/src/form/view/components/field/selection.tsx +39 -0
  274. package/src/form/view/components/field/use-field.tsx +49 -0
  275. package/src/form/view/components/rows/row-container.tsx +96 -0
  276. package/src/form/view/components/rows/wrapper.tsx +28 -0
  277. package/src/form/view/components/wrapped-form.tsx +32 -0
  278. package/src/form/view/context.tsx +26 -0
  279. package/src/form/view/hooks/use-model.ts +37 -0
  280. package/src/form/view/hooks/use-template.tsx +64 -0
  281. package/src/form/view/hooks/use-types.ts +21 -0
  282. package/src/form/view/index.tsx +48 -0
  283. package/src/formulas/helpers/condition-types.ts +5 -0
  284. package/src/formulas/helpers/evaluations.ts +48 -0
  285. package/src/formulas/helpers/formula.ts +27 -0
  286. package/src/formulas/helpers/lexer.ts +82 -0
  287. package/src/formulas/helpers/parser.ts +55 -0
  288. package/src/formulas/helpers/token.ts +22 -0
  289. package/src/formulas/index.ts +198 -0
  290. package/src/formulas/types/formulas.ts +72 -0
  291. package/src/formulas/types/index.ts +5 -0
  292. package/src/formulas/variants/array-formula.ts +138 -0
  293. package/src/formulas/variants/base.ts +6 -0
  294. package/src/formulas/variants/basic.ts +141 -0
  295. package/src/formulas/variants/comparison.ts +156 -0
  296. package/src/formulas/variants/conditional.ts +208 -0
  297. package/src/formulas/variants/iterative-array.ts +152 -0
  298. package/src/formulas/variants/per-value.ts +152 -0
  299. package/src/index.ts +6 -0
  300. package/src/models/base.ts +164 -0
  301. package/src/models/callback-manager.ts +102 -0
  302. package/src/models/field.ts +426 -0
  303. package/src/models/index.ts +14 -0
  304. package/src/models/model.ts +260 -0
  305. package/src/models/plugins/base.ts +11 -0
  306. package/src/models/plugins/formula.ts +80 -0
  307. package/src/models/plugins/index.ts +48 -0
  308. package/src/models/plugins/plugins.ts +8 -0
  309. package/src/models/types/base-wise-model.ts +7 -0
  310. package/src/models/types/callbacks.ts +23 -0
  311. package/src/models/types/disabled.ts +8 -0
  312. package/src/models/types/form-field.ts +22 -0
  313. package/src/models/types/model.ts +14 -0
  314. package/src/models/types/plugins.ts +15 -0
  315. package/src/models/types/wrapped-form-model-props.ts +9 -0
  316. package/src/models/wrapper.ts +242 -0
  317. package/src/settings/index.ts +11 -0
  318. package/src/utils/pending-promise.ts +29 -0
  319. package/tsconfig.json +39 -0
@@ -0,0 +1,198 @@
1
+ import { parse } from 'mathjs';
2
+ import { EvaluationsManager } from './helpers/evaluations';
3
+ import { ReactiveModel } from '@beyond-js/reactive/model';
4
+ import { Lexer } from './helpers/lexer';
5
+ import { Parser } from './helpers/parser';
6
+ import { Token } from './helpers/token';
7
+ import { IComplexCondition, IConditionalFormula, FormulaObserver, FormulaType, FormulaFields } from './types/formulas';
8
+ import { FormulaBasic } from './variants/basic';
9
+ import { FormulaConditional } from './variants/conditional';
10
+ import { FormulaPerValue } from './variants/per-value';
11
+ import { FormulaComparison } from './variants/comparison';
12
+ import { FormulaArray } from './variants/array-formula';
13
+ import { IterativeArrayFormula } from './variants/iterative-array';
14
+ type ParserData = {
15
+ parser: Parser;
16
+ tokens: Token[];
17
+ [key: string]: any;
18
+ };
19
+ export class FormulaManager extends ReactiveModel<FormulaManager> {
20
+ #lexer = new Lexer(true);
21
+
22
+ #tokens: Token[];
23
+ get tokens() {
24
+ return this.#tokens;
25
+ }
26
+ #parser: Parser;
27
+ get parser() {
28
+ return this.#parser;
29
+ }
30
+
31
+ #specs: FormulaObserver;
32
+ get formula() {
33
+ return this.#specs.formula;
34
+ }
35
+ get name() {
36
+ return this.#specs.name;
37
+ }
38
+
39
+ get conditional() {
40
+ return typeof this.#specs.formula === 'object';
41
+ }
42
+
43
+ get conditions() {
44
+ if (typeof this.#specs.formula === 'string') return;
45
+ const formula = this.#specs.formula as IComplexCondition;
46
+ return formula.conditions;
47
+ }
48
+
49
+ /**
50
+ * Represents the fields defined in the plugin settings
51
+ */
52
+ get fields() {
53
+ const formula = <IComplexCondition>this.formula;
54
+ return typeof formula?.fields === 'string' ? [formula?.fields] : formula?.fields;
55
+ }
56
+
57
+ #parsedBase;
58
+ get parsedBase() {
59
+ return this.#parsedBase;
60
+ }
61
+ #type: string;
62
+ get type() {
63
+ return this.#type;
64
+ }
65
+
66
+ get base() {
67
+ const formula = <IComplexCondition>this.#specs.formula;
68
+ return formula.base;
69
+ }
70
+
71
+ #variables: string[] = [];
72
+ get variables() {
73
+ return this.#variables;
74
+ }
75
+
76
+ get value() {
77
+ return this.#instance.value;
78
+ }
79
+
80
+ #parsers: Map<string, ParserData> = new Map();
81
+ #plugin: any;
82
+ #instance: any;
83
+
84
+ constructor(plugin, specs) {
85
+ super();
86
+ this.#plugin = plugin;
87
+ this.#specs = specs;
88
+ this.#initialize();
89
+ }
90
+
91
+ #initialize() {
92
+ this.#type = this.getType();
93
+
94
+ const objects = {
95
+ basic: FormulaBasic,
96
+ 'base-conditional': FormulaConditional,
97
+ 'value-conditions': FormulaPerValue,
98
+ comparison: FormulaComparison,
99
+ array: FormulaArray,
100
+ 'iterative-array': IterativeArrayFormula,
101
+ };
102
+
103
+ if (!objects[this.type]) {
104
+ throw new Error(`this type ${this.type} not found`);
105
+ }
106
+
107
+ this.#instance = new objects[this.type](this, this.#plugin, this.#specs);
108
+ }
109
+
110
+ initialize() {
111
+ this.#instance.initialize();
112
+ }
113
+ /**
114
+ * Returns the models that are part of the formula
115
+ * The models could be fields or formulas
116
+ * @param variables
117
+ * @returns
118
+ */
119
+ getModels(variables: FormulaFields) {
120
+ const varsArray = Array.isArray(variables) ? variables : [variables];
121
+ return varsArray.map(name => {
122
+ if (this.#plugin.formulas.has(name)) return this.#plugin.formulas.get(name);
123
+ return this.#plugin.form.getField(name);
124
+ });
125
+ }
126
+
127
+ private getType(): FormulaType {
128
+ const { type, formula } = this.#specs;
129
+ if (type) return type;
130
+ if (typeof formula === 'string') return 'basic';
131
+ if (formula.conditions) return formula.base ? 'base-conditional' : 'value-conditions';
132
+ }
133
+
134
+ processConditional() {
135
+ const formula = <IComplexCondition>this.formula;
136
+ if (this.base) {
137
+ this.#parsedBase = this.getParser({ formula: this.base });
138
+ }
139
+ }
140
+ calculate() {
141
+ if (!this.#instance || this.#instance.calculate) {
142
+ }
143
+ this.#instance.calculate();
144
+
145
+ this.trigger('change');
146
+ return;
147
+ }
148
+
149
+ /**
150
+ * Returns the parser for the formula, if the parser is already created it will return the memoized parser
151
+ *
152
+ *
153
+ * The formula is tokenized and parsed to create a parser instance
154
+ * the object returned contains the tokens, the parser and the formula
155
+ * @param data Receives the formula to be parsed
156
+ * @returns
157
+ */
158
+ getParser(data): ParserData {
159
+ if (!data.formula) throw new Error('To get a parser you must provide a formula');
160
+ if (this.#parsers.has(data.formula)) return this.#parsers.get(data.formula);
161
+ const tokens = this.#lexer.tokenize(data.formula);
162
+ const parser = new Parser(tokens);
163
+ const result = { tokens, parser, ...data };
164
+
165
+ this.#parsers.set(data.formula, result);
166
+ return result;
167
+ }
168
+
169
+ async getParams(variables: string[]) {
170
+ const params = {};
171
+ const { form, formulas } = this.#plugin;
172
+ const build = async value => {
173
+ /**
174
+ * the value could be a formula or a field
175
+ */
176
+ const element = formulas.has(value) ? formulas.get(value) : form.getField(value);
177
+ if (!element)
178
+ throw new Error(`Field ${value} used in formula ${this.name}, not found in form ${form.name}, `);
179
+ await element.isReady;
180
+ params[value] = [undefined, '', null, NaN].includes(element.value) ? 0 : element.value;
181
+ };
182
+ variables.forEach(build);
183
+
184
+ return params;
185
+ }
186
+
187
+ /**
188
+ * A form can have multiple formulas, this method will create an instance of the formula manager
189
+ * and memoize it to avoid creating multiple instances of the same formula.
190
+ * @param specs
191
+ * @returns
192
+ */
193
+ static async create(plugin, specs) {
194
+ const instance = new FormulaManager(plugin, specs);
195
+ // FormulaManager.instances.set(plugin.form.name, instance);
196
+ return instance;
197
+ }
198
+ }
@@ -0,0 +1,72 @@
1
+ import type { Parser } from "../helpers/parser";
2
+ import type { Token } from "../helpers/token";
3
+
4
+ export interface ISimpleFormula {
5
+ name: string;
6
+ formula: string;
7
+ type?: FormulaType;
8
+ emptyValue?: string | number;
9
+ fields?: FormulaFields;
10
+ propertyValue?: string;
11
+ propertyToSet?: string;
12
+ formulas?: any[];
13
+ arrayFieldProperty?: string;
14
+ arrayFieldName?: string
15
+ }
16
+
17
+ export interface IFormulaCondition {
18
+ condition: "hasValue" | "upper" | "lower" | "equal" | "different" | "between" | "lessOrEqual" | "greaterOrEqual";
19
+ value?: string | number | [number, number];
20
+ formula: string;
21
+ conditions?: IConditionalField[];
22
+ fields?: string[];
23
+ }
24
+
25
+ export type FormulaFields = string | string[];
26
+ export type EvaluatedFormula = { value?: string | number; formula: string; condition?: string };
27
+ export interface IConditionalFormula { }
28
+
29
+ export interface IConditionalField {
30
+ field?: string | string[];
31
+ condition?: string;
32
+ values?: [EvaluatedFormula];
33
+ conditions?: IFormulaCondition[];
34
+ fields?: string[];
35
+ formula?: string;
36
+ type?: string;
37
+ value: string | number;
38
+ }
39
+
40
+ export interface IComplexCondition {
41
+ fields: FormulaFields;
42
+ base?: string;
43
+ conditions: IConditionalField | IConditionalField[];
44
+ condition?: string;
45
+ arrayFieldName?: string,
46
+ arrayFieldProperty?: string;
47
+ }
48
+
49
+ export interface IConditionalFormula {
50
+ name: string;
51
+ type?: FormulaType;
52
+ fields?: FormulaFields;
53
+ formula: IComplexCondition | string;
54
+ conditions?: IConditionalField[];
55
+ emptyValue?: string | number;
56
+ propertyValue?: string;
57
+ propertyToSet?: string;
58
+ formulas?: any[];
59
+ arrayFieldName?: string,
60
+ arrayFieldProperty?: string;
61
+ }
62
+
63
+ export type ParserData = {
64
+ parser: Parser;
65
+ tokens: Token[];
66
+ [key: string]: any;
67
+ };
68
+
69
+ export type FormulaType = "basic" | "base-conditional" | "value-conditions" | "comparison" | "array" | "iterative-array" | undefined;
70
+
71
+ export type FormulaObserver = ISimpleFormula | IConditionalFormula;
72
+
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Defines the type of token based on the part of the expression it represents.
3
+ */
4
+ export type TokenType = 'variable' | 'number' | 'operator' | 'parenthesis';
5
+
@@ -0,0 +1,138 @@
1
+ import type { FormulaManager } from '..';
2
+ import { EvaluationsManager } from '../helpers/evaluations';
3
+ import { FormulaObserver, IComplexCondition } from '../types/formulas';
4
+ import { parse } from 'mathjs';
5
+
6
+ export class FormulaArray {
7
+ #plugin: any;
8
+ #specs: FormulaObserver;
9
+ get formula() {
10
+ return this.#specs.formula;
11
+ }
12
+ get base() {
13
+ const formula = <IComplexCondition>this.#specs.formula;
14
+ return formula.base;
15
+ }
16
+ #value: any[] = [];
17
+ get value() {
18
+ return this.#value;
19
+ }
20
+ get name() {
21
+ return this.#specs.name;
22
+ }
23
+ /**
24
+ * Represents the fields defined in the plugin settings
25
+ */
26
+ get fields() {
27
+ const formula = <IComplexCondition>this.formula;
28
+ return typeof formula?.fields === 'string' ? [formula?.fields] : formula?.fields;
29
+ }
30
+
31
+ get conditions() {
32
+ if (typeof this.#specs.formula === 'string') return;
33
+ const formula = this.#specs.formula as IComplexCondition;
34
+ return formula.conditions;
35
+ }
36
+
37
+ #emptyValue: string | number;
38
+ #variables: string[] = [];
39
+ get variables() {
40
+ return this.#variables;
41
+ }
42
+
43
+ #round: boolean;
44
+ #ceil: boolean
45
+
46
+ #parent: FormulaManager;
47
+
48
+ #formulaField
49
+ constructor(parent, plugin, specs) {
50
+ this.#parent = parent;
51
+ this.#plugin = plugin;
52
+ this.#specs = specs;
53
+ this.#round = specs.round;
54
+ this.#ceil = specs.ceil;
55
+ this.#specs.emptyValue = specs.emptyValue;
56
+
57
+ this.#formulaField = this.#plugin.form.getField(this.name);
58
+ }
59
+
60
+ initialize() {
61
+ this.#formulaField.on('change', this.calculate.bind(this));
62
+ };
63
+
64
+ evaluate = (data: { formulas: any[], values: any }) => {
65
+ const values = {};
66
+ for (const formula of data.formulas) {
67
+
68
+ let result;
69
+ let formulaEvaluate = formula.formula
70
+ try {
71
+ if (formula.conditions) {
72
+ for (const condition of formula.conditions) {
73
+ const comparisonValue = { ...data.values, ...values }[condition.property]
74
+ let conditionMet = EvaluationsManager.validate(condition.condition, comparisonValue, condition.value);
75
+ if (conditionMet) {
76
+ formulaEvaluate = condition.formula;
77
+ break
78
+ }
79
+ }
80
+ }
81
+ const attrs = this.sanitizeData({ ...data.values, ...values });
82
+
83
+ result = parse(formulaEvaluate as string).evaluate(attrs);
84
+
85
+ } catch (error) {
86
+ console.log("Error evaluating formula:", formula.formula, "Error:", error);
87
+ }
88
+ const isInvalidResult = [-Infinity, Infinity, undefined, null, NaN].includes(result);
89
+
90
+ if (formula.round && !isInvalidResult) result = Math.round(result);
91
+ if (formula.ceil && !isInvalidResult) result = Math.ceil(result);
92
+ result = isInvalidResult ? formula.emptyValue : Number(result.toFixed(2));
93
+ values[formula.propertyToSet] = result;
94
+ }
95
+ return values;
96
+ };
97
+
98
+ async calculate() {
99
+ const formulaField = this.#plugin.form.getField(this.name);
100
+ if (!formulaField) return;
101
+ const value = formulaField[this.#specs.propertyValue || 'entries']
102
+ if (!value || !Array.isArray(value) || !value.length) {
103
+ formulaField.set({ [this.#specs.propertyValue]: [] });
104
+ return
105
+ };
106
+ const newValue = value.map(item => {
107
+ let results = this.evaluate({ formulas: this.#specs.formulas, values: item })
108
+ return {
109
+ ...item,
110
+ ...results
111
+ }
112
+ });
113
+ this.#value = newValue
114
+ formulaField.set({ [this.#specs.propertyValue]: newValue })
115
+ };
116
+
117
+
118
+ private sanitizeData(data: any): any {
119
+ if (Array.isArray(data)) {
120
+ return data.map(item => this.sanitizeData(item));
121
+ } else if (typeof data === 'object' && data !== null) {
122
+ const sanitizedData: any = {};
123
+ for (const key in data) {
124
+ if (data.hasOwnProperty(key)) {
125
+ sanitizedData[key] = this.sanitizeData(data[key]);
126
+ }
127
+ }
128
+ return sanitizedData;
129
+ } else {
130
+ return this.sanitizeValue(data);
131
+ }
132
+ }
133
+
134
+ private sanitizeValue(value: any, defaultValue: number = 0): number {
135
+ return (value === null || value === undefined || isNaN(value)) ? defaultValue : Number(value);
136
+ }
137
+ }
138
+
@@ -0,0 +1,6 @@
1
+ export abstract class WiseFormFormulaPlugin {
2
+ abstract initialize(): void;
3
+ abstract validate(): void;
4
+ abstract calculate(): void;
5
+ }
6
+
@@ -0,0 +1,141 @@
1
+ import type { FormulaManager } from '..';
2
+ import { EvaluationsManager } from '../helpers/evaluations';
3
+ import { Token } from '../helpers/token';
4
+ import {
5
+ EvaluatedFormula,
6
+ FormulaObserver,
7
+ IComplexCondition,
8
+ IConditionalField,
9
+ } from '../types/formulas';
10
+ import { parse } from 'mathjs';
11
+
12
+ export class FormulaBasic {
13
+ #plugin: any;
14
+ #specs: FormulaObserver;
15
+ #tokens: Token[];
16
+ get formula() {
17
+ return this.#specs.formula;
18
+ }
19
+ get base() {
20
+ const formula = <IComplexCondition>this.#specs.formula;
21
+ return formula.base;
22
+ }
23
+ #value: string | number | undefined | 0;
24
+ get value() {
25
+ return this.#value;
26
+ }
27
+ get name() {
28
+ return this.#specs.name;
29
+ }
30
+ /**
31
+ * Represents the fields defined in the plugin settings
32
+ */
33
+ get fields() {
34
+ const formula = <IComplexCondition>this.formula;
35
+ return typeof formula?.fields === 'string'
36
+ ? [formula?.fields]
37
+ : formula?.fields;
38
+ }
39
+
40
+ get conditions() {
41
+ if (typeof this.#specs.formula === 'string') return;
42
+ const formula = this.#specs.formula as IComplexCondition;
43
+ return formula.conditions;
44
+ }
45
+
46
+ #emptyValue: string | number;
47
+ #variables: string[] = [];
48
+ get variables() {
49
+ return this.#variables;
50
+ }
51
+
52
+ #round: boolean;
53
+ #ceil: boolean;
54
+
55
+ #parent: FormulaManager;
56
+
57
+ #isNotListenToChanges = false;
58
+ constructor(parent, plugin, specs) {
59
+ this.#parent = parent;
60
+ this.#plugin = plugin;
61
+ this.#specs = specs;
62
+ this.#round = specs.round;
63
+ this.#ceil = specs.ceil;
64
+ this.#emptyValue = specs.emptyValue;
65
+
66
+ this.#isNotListenToChanges = specs.isNotListenToChanges;
67
+ }
68
+
69
+ initialize() {
70
+ const { tokens } = this.#parent.getParser(this.#specs);
71
+ this.#tokens = tokens;
72
+ const variables = this.#tokens
73
+ .filter((token) => token.type === 'variable')
74
+ .map((item) => item.value);
75
+ this.#variables = variables;
76
+ const models = this.#parent.getModels(variables);
77
+ if (!this.#isNotListenToChanges)
78
+ models.forEach((model) => {
79
+ if ([undefined].includes(model)) {
80
+ return;
81
+ }
82
+
83
+ model.on('change', this.calculate.bind(this));
84
+ });
85
+ if (!Array.isArray(this.#variables) || !this.#variables.length) {
86
+ this.#value = parse(this.formula as string).evaluate();
87
+ }
88
+ }
89
+
90
+ async calculate() {
91
+ const variables = this.#variables;
92
+
93
+ const formulaField = this.#plugin.form.getField(this.name);
94
+ let params = await this.#parent.getParams(variables);
95
+ const models = this.#parent.getModels(variables);
96
+
97
+ const empty = (models as any[]).every((model) =>
98
+ [null, undefined, ''].includes(model.value)
99
+ );
100
+
101
+ if (empty) {
102
+ // If all models are empty, set the input to empty if exists.
103
+ if (formulaField)
104
+ formulaField.set({ value: this.#emptyValue || '' });
105
+ this.#value = undefined;
106
+ return;
107
+ }
108
+
109
+ try {
110
+ let result =
111
+ models.length === 1 &&
112
+ !['+', '-', '*', '/'].some((item) =>
113
+ this.formula.toString().includes(item)
114
+ )
115
+ ? models[0].value
116
+ : parse(this.formula as string).evaluate(params);
117
+ const isInvalidResult = [
118
+ -Infinity,
119
+ Infinity,
120
+ undefined,
121
+ null,
122
+ NaN,
123
+ ].includes(result);
124
+ if (this.#round && !isInvalidResult) result = Math.round(result);
125
+ if (this.#ceil && !isInvalidResult) result = Math.ceil(result);
126
+ this.#value = isInvalidResult
127
+ ? this.#emptyValue
128
+ : Number(result.toFixed(2));
129
+ if (formulaField) formulaField.set({ value: this.#value });
130
+
131
+ this.#parent.trigger('change');
132
+ } catch (e) {
133
+ console.log('formula', this.name, this.formula, params);
134
+ console.trace(e);
135
+ throw new Error(
136
+ `Error calculating the formula: ${e.message} ${this.name}`
137
+ );
138
+ }
139
+ }
140
+ }
141
+