@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.
- package/README.md +34 -0
- package/dist/components/ui/Checkbox.d.ts +14 -0
- package/dist/components/ui/Checkbox.d.ts.map +1 -0
- package/dist/components/ui/Checkbox.js +43 -0
- package/dist/components/ui/Checkbox.js.map +1 -0
- package/dist/components/ui/CheckboxGroup.d.ts +15 -0
- package/dist/components/ui/CheckboxGroup.d.ts.map +1 -0
- package/dist/components/ui/CheckboxGroup.js +33 -0
- package/dist/components/ui/CheckboxGroup.js.map +1 -0
- package/dist/components/ui/Input.d.ts +14 -0
- package/dist/components/ui/Input.d.ts.map +1 -0
- package/dist/components/ui/Input.js +49 -0
- package/dist/components/ui/Input.js.map +1 -0
- package/dist/components/ui/Radio.d.ts +14 -0
- package/dist/components/ui/Radio.d.ts.map +1 -0
- package/dist/components/ui/Radio.js +43 -0
- package/dist/components/ui/Radio.js.map +1 -0
- package/dist/components/ui/Select.d.ts +18 -0
- package/dist/components/ui/Select.d.ts.map +1 -0
- package/dist/components/ui/Select.js +44 -0
- package/dist/components/ui/Select.js.map +1 -0
- package/dist/components/ui/Textarea.d.ts +13 -0
- package/dist/components/ui/Textarea.d.ts.map +1 -0
- package/dist/components/ui/Textarea.js +42 -0
- package/dist/components/ui/Textarea.js.map +1 -0
- package/dist/components/ui/index.d.ts +13 -0
- package/dist/components/ui/index.d.ts.map +1 -0
- package/dist/components/ui/index.js +7 -0
- package/dist/components/ui/index.js.map +1 -0
- package/dist/form/index.d.ts +10 -0
- package/dist/form/index.d.ts.map +1 -0
- package/dist/form/index.js +5 -0
- package/dist/form/index.js.map +1 -0
- package/dist/form/interfaces/field-container.d.ts +8 -0
- package/dist/form/interfaces/field-container.d.ts.map +1 -0
- package/dist/form/interfaces/field-container.js +2 -0
- package/dist/form/interfaces/field-container.js.map +1 -0
- package/dist/form/interfaces/interfaces.d.ts +8 -0
- package/dist/form/interfaces/interfaces.d.ts.map +1 -0
- package/dist/form/interfaces/interfaces.js +2 -0
- package/dist/form/interfaces/interfaces.js.map +1 -0
- package/dist/form/interfaces/settings.d.ts +10 -0
- package/dist/form/interfaces/settings.d.ts.map +1 -0
- package/dist/form/interfaces/settings.js +2 -0
- package/dist/form/interfaces/settings.js.map +1 -0
- package/dist/form/interfaces/template.d.ts +6 -0
- package/dist/form/interfaces/template.d.ts.map +1 -0
- package/dist/form/interfaces/template.js +2 -0
- package/dist/form/interfaces/template.js.map +1 -0
- package/dist/form/interfaces/wise-form-specs.d.ts +9 -0
- package/dist/form/interfaces/wise-form-specs.d.ts.map +1 -0
- package/dist/form/interfaces/wise-form-specs.js +2 -0
- package/dist/form/interfaces/wise-form-specs.js.map +1 -0
- package/dist/form/view/components/containers/index.d.ts +3 -0
- package/dist/form/view/components/containers/index.d.ts.map +1 -0
- package/dist/form/view/components/containers/index.js +12 -0
- package/dist/form/view/components/containers/index.js.map +1 -0
- package/dist/form/view/components/error.d.ts +5 -0
- package/dist/form/view/components/error.d.ts.map +1 -0
- package/dist/form/view/components/error.js +8 -0
- package/dist/form/view/components/error.js.map +1 -0
- package/dist/form/view/components/field/container.d.ts +5 -0
- package/dist/form/view/components/field/container.d.ts.map +1 -0
- package/dist/form/view/components/field/container.js +5 -0
- package/dist/form/view/components/field/container.js.map +1 -0
- package/dist/form/view/components/field/index.d.ts +18 -0
- package/dist/form/view/components/field/index.d.ts.map +1 -0
- package/dist/form/view/components/field/index.js +89 -0
- package/dist/form/view/components/field/index.js.map +1 -0
- package/dist/form/view/components/field/selection.d.ts +2 -0
- package/dist/form/view/components/field/selection.d.ts.map +1 -0
- package/dist/form/view/components/field/selection.js +35 -0
- package/dist/form/view/components/field/selection.js.map +1 -0
- package/dist/form/view/components/field/use-field.d.ts +4 -0
- package/dist/form/view/components/field/use-field.d.ts.map +1 -0
- package/dist/form/view/components/field/use-field.js +41 -0
- package/dist/form/view/components/field/use-field.js.map +1 -0
- package/dist/form/view/components/rows/row-container.d.ts +18 -0
- package/dist/form/view/components/rows/row-container.d.ts.map +1 -0
- package/dist/form/view/components/rows/row-container.js +89 -0
- package/dist/form/view/components/rows/row-container.js.map +1 -0
- package/dist/form/view/components/rows/wrapper.d.ts +12 -0
- package/dist/form/view/components/rows/wrapper.d.ts.map +1 -0
- package/dist/form/view/components/rows/wrapper.js +27 -0
- package/dist/form/view/components/rows/wrapper.js.map +1 -0
- package/dist/form/view/components/wrapped-form.d.ts +6 -0
- package/dist/form/view/components/wrapped-form.d.ts.map +1 -0
- package/dist/form/view/components/wrapped-form.js +26 -0
- package/dist/form/view/components/wrapped-form.js.map +1 -0
- package/dist/form/view/context.d.ts +23 -0
- package/dist/form/view/context.d.ts.map +1 -0
- package/dist/form/view/context.js +7 -0
- package/dist/form/view/context.js.map +1 -0
- package/dist/form/view/hooks/use-model.d.ts +10 -0
- package/dist/form/view/hooks/use-model.d.ts.map +1 -0
- package/dist/form/view/hooks/use-model.js +31 -0
- package/dist/form/view/hooks/use-model.js.map +1 -0
- package/dist/form/view/hooks/use-template.d.ts +14 -0
- package/dist/form/view/hooks/use-template.d.ts.map +1 -0
- package/dist/form/view/hooks/use-template.js +57 -0
- package/dist/form/view/hooks/use-template.js.map +1 -0
- package/dist/form/view/hooks/use-types.d.ts +2 -0
- package/dist/form/view/hooks/use-types.d.ts.map +1 -0
- package/dist/form/view/hooks/use-types.js +19 -0
- package/dist/form/view/hooks/use-types.js.map +1 -0
- package/dist/form/view/index.d.ts +3 -0
- package/dist/form/view/index.d.ts.map +1 -0
- package/dist/form/view/index.js +38 -0
- package/dist/form/view/index.js.map +1 -0
- package/dist/formulas/helpers/condition-types.d.ts +5 -0
- package/dist/formulas/helpers/condition-types.d.ts.map +1 -0
- package/dist/formulas/helpers/condition-types.js +5 -0
- package/dist/formulas/helpers/condition-types.js.map +1 -0
- package/dist/formulas/helpers/evaluations.d.ts +15 -0
- package/dist/formulas/helpers/evaluations.d.ts.map +1 -0
- package/dist/formulas/helpers/evaluations.js +44 -0
- package/dist/formulas/helpers/evaluations.js.map +1 -0
- package/dist/formulas/helpers/formula.d.ts +6 -0
- package/dist/formulas/helpers/formula.d.ts.map +1 -0
- package/dist/formulas/helpers/formula.js +26 -0
- package/dist/formulas/helpers/formula.js.map +1 -0
- package/dist/formulas/helpers/lexer.d.ts +10 -0
- package/dist/formulas/helpers/lexer.d.ts.map +1 -0
- package/dist/formulas/helpers/lexer.js +73 -0
- package/dist/formulas/helpers/lexer.js.map +1 -0
- package/dist/formulas/helpers/parser.d.ts +24 -0
- package/dist/formulas/helpers/parser.d.ts.map +1 -0
- package/dist/formulas/helpers/parser.js +48 -0
- package/dist/formulas/helpers/parser.js.map +1 -0
- package/dist/formulas/helpers/token.d.ts +14 -0
- package/dist/formulas/helpers/token.d.ts.map +1 -0
- package/dist/formulas/helpers/token.js +14 -0
- package/dist/formulas/helpers/token.js.map +1 -0
- package/dist/formulas/index.d.ts +59 -0
- package/dist/formulas/index.d.ts.map +1 -0
- package/dist/formulas/index.js +186 -0
- package/dist/formulas/index.js.map +1 -0
- package/dist/formulas/types/formulas.d.ts +68 -0
- package/dist/formulas/types/formulas.d.ts.map +1 -0
- package/dist/formulas/types/formulas.js +2 -0
- package/dist/formulas/types/formulas.js.map +1 -0
- package/dist/formulas/types/index.d.ts +5 -0
- package/dist/formulas/types/index.d.ts.map +1 -0
- package/dist/formulas/types/index.js +2 -0
- package/dist/formulas/types/index.js.map +1 -0
- package/dist/formulas/variants/array-formula.d.ts +24 -0
- package/dist/formulas/variants/array-formula.d.ts.map +1 -0
- package/dist/formulas/variants/array-formula.js +142 -0
- package/dist/formulas/variants/array-formula.js.map +1 -0
- package/dist/formulas/variants/base.d.ts +6 -0
- package/dist/formulas/variants/base.d.ts.map +1 -0
- package/dist/formulas/variants/base.js +3 -0
- package/dist/formulas/variants/base.js.map +1 -0
- package/dist/formulas/variants/basic.d.ts +18 -0
- package/dist/formulas/variants/basic.d.ts.map +1 -0
- package/dist/formulas/variants/basic.js +128 -0
- package/dist/formulas/variants/basic.js.map +1 -0
- package/dist/formulas/variants/comparison.d.ts +25 -0
- package/dist/formulas/variants/comparison.d.ts.map +1 -0
- package/dist/formulas/variants/comparison.js +153 -0
- package/dist/formulas/variants/comparison.js.map +1 -0
- package/dist/formulas/variants/conditional.d.ts +18 -0
- package/dist/formulas/variants/conditional.d.ts.map +1 -0
- package/dist/formulas/variants/conditional.js +183 -0
- package/dist/formulas/variants/conditional.js.map +1 -0
- package/dist/formulas/variants/iterative-array.d.ts +20 -0
- package/dist/formulas/variants/iterative-array.d.ts.map +1 -0
- package/dist/formulas/variants/iterative-array.js +155 -0
- package/dist/formulas/variants/iterative-array.js.map +1 -0
- package/dist/formulas/variants/per-value.d.ts +20 -0
- package/dist/formulas/variants/per-value.d.ts.map +1 -0
- package/dist/formulas/variants/per-value.js +154 -0
- package/dist/formulas/variants/per-value.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/models/base.d.ts +55 -0
- package/dist/models/base.d.ts.map +1 -0
- package/dist/models/base.js +146 -0
- package/dist/models/base.js.map +1 -0
- package/dist/models/callback-manager.d.ts +7 -0
- package/dist/models/callback-manager.d.ts.map +1 -0
- package/dist/models/callback-manager.js +89 -0
- package/dist/models/callback-manager.js.map +1 -0
- package/dist/models/field.d.ts +121 -0
- package/dist/models/field.d.ts.map +1 -0
- package/dist/models/field.js +374 -0
- package/dist/models/field.js.map +1 -0
- package/dist/models/index.d.ts +13 -0
- package/dist/models/index.d.ts.map +1 -0
- package/dist/models/index.js +7 -0
- package/dist/models/index.js.map +1 -0
- package/dist/models/model.d.ts +37 -0
- package/dist/models/model.d.ts.map +1 -0
- package/dist/models/model.js +245 -0
- package/dist/models/model.js.map +1 -0
- package/dist/models/plugins/base.d.ts +9 -0
- package/dist/models/plugins/base.d.ts.map +1 -0
- package/dist/models/plugins/base.js +3 -0
- package/dist/models/plugins/base.js.map +1 -0
- package/dist/models/plugins/formula.d.ts +18 -0
- package/dist/models/plugins/formula.d.ts.map +1 -0
- package/dist/models/plugins/formula.js +82 -0
- package/dist/models/plugins/formula.js.map +1 -0
- package/dist/models/plugins/index.d.ts +11 -0
- package/dist/models/plugins/index.d.ts.map +1 -0
- package/dist/models/plugins/index.js +52 -0
- package/dist/models/plugins/index.js.map +1 -0
- package/dist/models/plugins/plugins.d.ts +7 -0
- package/dist/models/plugins/plugins.d.ts.map +1 -0
- package/dist/models/plugins/plugins.js +7 -0
- package/dist/models/plugins/plugins.js.map +1 -0
- package/dist/models/types/base-wise-model.d.ts +7 -0
- package/dist/models/types/base-wise-model.d.ts.map +1 -0
- package/dist/models/types/base-wise-model.js +2 -0
- package/dist/models/types/base-wise-model.js.map +1 -0
- package/dist/models/types/callbacks.d.ts +19 -0
- package/dist/models/types/callbacks.d.ts.map +1 -0
- package/dist/models/types/callbacks.js +2 -0
- package/dist/models/types/callbacks.js.map +1 -0
- package/dist/models/types/disabled.d.ts +8 -0
- package/dist/models/types/disabled.d.ts.map +1 -0
- package/dist/models/types/disabled.js +2 -0
- package/dist/models/types/disabled.js.map +1 -0
- package/dist/models/types/form-field.d.ts +25 -0
- package/dist/models/types/form-field.d.ts.map +1 -0
- package/dist/models/types/form-field.js +2 -0
- package/dist/models/types/form-field.js.map +1 -0
- package/dist/models/types/model.d.ts +13 -0
- package/dist/models/types/model.d.ts.map +1 -0
- package/dist/models/types/model.js +2 -0
- package/dist/models/types/model.js.map +1 -0
- package/dist/models/types/plugins.d.ts +13 -0
- package/dist/models/types/plugins.d.ts.map +1 -0
- package/dist/models/types/plugins.js +2 -0
- package/dist/models/types/plugins.js.map +1 -0
- package/dist/models/types/wrapped-form-model-props.d.ts +11 -0
- package/dist/models/types/wrapped-form-model-props.d.ts.map +1 -0
- package/dist/models/types/wrapped-form-model-props.js +2 -0
- package/dist/models/types/wrapped-form-model-props.js.map +1 -0
- package/dist/models/wrapper.d.ts +30 -0
- package/dist/models/wrapper.d.ts.map +1 -0
- package/dist/models/wrapper.js +213 -0
- package/dist/models/wrapper.js.map +1 -0
- package/dist/settings/index.d.ts +7 -0
- package/dist/settings/index.d.ts.map +1 -0
- package/dist/settings/index.js +26 -0
- package/dist/settings/index.js.map +1 -0
- package/dist/utils/pending-promise.d.ts +6 -0
- package/dist/utils/pending-promise.d.ts.map +1 -0
- package/dist/utils/pending-promise.js +24 -0
- package/dist/utils/pending-promise.js.map +1 -0
- package/package.json +38 -0
- package/src/components/ui/Checkbox.tsx +68 -0
- package/src/components/ui/CheckboxGroup.tsx +60 -0
- package/src/components/ui/Input.tsx +72 -0
- package/src/components/ui/Radio.tsx +68 -0
- package/src/components/ui/Select.tsx +73 -0
- package/src/components/ui/Textarea.tsx +63 -0
- package/src/components/ui/index.ts +14 -0
- package/src/form/index.ts +11 -0
- package/src/form/interfaces/field-container.ts +9 -0
- package/src/form/interfaces/interfaces.ts +12 -0
- package/src/form/interfaces/settings.ts +11 -0
- package/src/form/interfaces/template.ts +7 -0
- package/src/form/interfaces/wise-form-specs.ts +10 -0
- package/src/form/styles.css +40 -0
- package/src/form/view/components/containers/index.tsx +18 -0
- package/src/form/view/components/error.tsx +9 -0
- package/src/form/view/components/field/container.tsx +6 -0
- package/src/form/view/components/field/index.tsx +107 -0
- package/src/form/view/components/field/selection.tsx +39 -0
- package/src/form/view/components/field/use-field.tsx +49 -0
- package/src/form/view/components/rows/row-container.tsx +96 -0
- package/src/form/view/components/rows/wrapper.tsx +28 -0
- package/src/form/view/components/wrapped-form.tsx +32 -0
- package/src/form/view/context.tsx +26 -0
- package/src/form/view/hooks/use-model.ts +37 -0
- package/src/form/view/hooks/use-template.tsx +64 -0
- package/src/form/view/hooks/use-types.ts +21 -0
- package/src/form/view/index.tsx +48 -0
- package/src/formulas/helpers/condition-types.ts +5 -0
- package/src/formulas/helpers/evaluations.ts +48 -0
- package/src/formulas/helpers/formula.ts +27 -0
- package/src/formulas/helpers/lexer.ts +82 -0
- package/src/formulas/helpers/parser.ts +55 -0
- package/src/formulas/helpers/token.ts +22 -0
- package/src/formulas/index.ts +198 -0
- package/src/formulas/types/formulas.ts +72 -0
- package/src/formulas/types/index.ts +5 -0
- package/src/formulas/variants/array-formula.ts +138 -0
- package/src/formulas/variants/base.ts +6 -0
- package/src/formulas/variants/basic.ts +141 -0
- package/src/formulas/variants/comparison.ts +156 -0
- package/src/formulas/variants/conditional.ts +208 -0
- package/src/formulas/variants/iterative-array.ts +152 -0
- package/src/formulas/variants/per-value.ts +152 -0
- package/src/index.ts +6 -0
- package/src/models/base.ts +164 -0
- package/src/models/callback-manager.ts +102 -0
- package/src/models/field.ts +426 -0
- package/src/models/index.ts +14 -0
- package/src/models/model.ts +260 -0
- package/src/models/plugins/base.ts +11 -0
- package/src/models/plugins/formula.ts +80 -0
- package/src/models/plugins/index.ts +48 -0
- package/src/models/plugins/plugins.ts +8 -0
- package/src/models/types/base-wise-model.ts +7 -0
- package/src/models/types/callbacks.ts +23 -0
- package/src/models/types/disabled.ts +8 -0
- package/src/models/types/form-field.ts +22 -0
- package/src/models/types/model.ts +14 -0
- package/src/models/types/plugins.ts +15 -0
- package/src/models/types/wrapped-form-model-props.ts +9 -0
- package/src/models/wrapper.ts +242 -0
- package/src/settings/index.ts +11 -0
- package/src/utils/pending-promise.ts +29 -0
- 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,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,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
|
+
|