@flowerforce/flower-core 3.1.1 → 3.1.2-beta.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/dist/index.cjs.js +788 -812
- package/dist/index.esm.js +788 -813
- package/dist/src/CoreUtils.d.ts +3 -0
- package/dist/src/FlowerCoreStateFunctions.d.ts +3 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/interfaces/CoreInterface.d.ts +87 -0
- package/dist/src/interfaces/ReducerInterface.d.ts +208 -0
- package/dist/src/interfaces/SelectorsInterface.d.ts +70 -0
- package/dist/src/interfaces/UtilsInterface.d.ts +37 -0
- package/dist/src/rules-matcher/interface.d.ts +259 -0
- package/dist/src/rules-matcher/utils.d.ts +3 -0
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -21,859 +21,834 @@ import { unflatten } from 'flat';
|
|
|
21
21
|
const Emitter = new TinyEmitter();
|
|
22
22
|
|
|
23
23
|
const EMPTY_STRING_REGEXP = /^\s*$/;
|
|
24
|
+
/**
|
|
25
|
+
* Defines a utility object named rulesMatcherUtils, which contains various helper functions used for processing rules and data in a rule-matching context.
|
|
26
|
+
*/
|
|
24
27
|
const rulesMatcherUtils = {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
return false;
|
|
140
|
-
}
|
|
141
|
-
if (rulesMatcherUtils.isString(value)) {
|
|
142
|
-
return EMPTY_STRING_REGEXP.test(value);
|
|
143
|
-
}
|
|
144
|
-
if (Array.isArray(value)) {
|
|
145
|
-
return value.length === 0;
|
|
146
|
-
}
|
|
147
|
-
if (rulesMatcherUtils.isDate(value)) {
|
|
148
|
-
return false;
|
|
149
|
-
}
|
|
150
|
-
let attr;
|
|
151
|
-
if (rulesMatcherUtils.isObject(value)) {
|
|
152
|
-
for (attr in value) {
|
|
28
|
+
isNumber: (el) => {
|
|
29
|
+
const num = String(el);
|
|
30
|
+
return !!num.match(/(^-?|^\d+\.)\d+$/);
|
|
31
|
+
},
|
|
32
|
+
rule: (val, data, options) => {
|
|
33
|
+
const { prefix } = options || {};
|
|
34
|
+
const path = Object.keys(val)[0];
|
|
35
|
+
const valueBlock = val;
|
|
36
|
+
const pathWithPrefix = rulesMatcherUtils.getPath(path, prefix);
|
|
37
|
+
const valueForKey = _get(data, pathWithPrefix, undefined);
|
|
38
|
+
const { name } = _get(valueBlock, [path], {}) || {};
|
|
39
|
+
const { op, value, opt } = rulesMatcherUtils.getDefaultRule(valueBlock[path]);
|
|
40
|
+
const valueRef = value && String(value).indexOf('$ref:') === 0
|
|
41
|
+
? _get(data, rulesMatcherUtils.getPath(value.replace('$ref:', ''), prefix), undefined)
|
|
42
|
+
: value;
|
|
43
|
+
if (!operators[op]) {
|
|
44
|
+
throw new Error(`Error missing operator:${op}`);
|
|
45
|
+
}
|
|
46
|
+
const valid = operators[op] && operators[op](valueForKey, valueRef, opt, data);
|
|
47
|
+
return { valid, name: `${pathWithPrefix}___${name || op}` };
|
|
48
|
+
},
|
|
49
|
+
getKey: (block, keys, options) => {
|
|
50
|
+
if (Object.prototype.hasOwnProperty.call(block, '$and')) {
|
|
51
|
+
return block.$and.map((item) => rulesMatcherUtils.getKey(item, keys, options));
|
|
52
|
+
}
|
|
53
|
+
if (Object.prototype.hasOwnProperty.call(block, '$or')) {
|
|
54
|
+
return block.$or.map((item) => rulesMatcherUtils.getKey(item, keys, options));
|
|
55
|
+
}
|
|
56
|
+
const { prefix } = options || {};
|
|
57
|
+
const path = Object.keys(block)[0];
|
|
58
|
+
const valueBlock = block;
|
|
59
|
+
const res = rulesMatcherUtils.getPath(path, prefix);
|
|
60
|
+
const { value } = rulesMatcherUtils.getDefaultRule(valueBlock[path]);
|
|
61
|
+
if (value && String(value).indexOf('$ref:') === 0) {
|
|
62
|
+
keys[rulesMatcherUtils.getPath(value.replace('$ref:', ''), prefix)] = true;
|
|
63
|
+
}
|
|
64
|
+
return (keys[res] = true);
|
|
65
|
+
},
|
|
66
|
+
isDate: (v) => v instanceof Date,
|
|
67
|
+
isDefined: (v) => v !== null && v !== undefined,
|
|
68
|
+
isObject: (v) => v === Object(v),
|
|
69
|
+
isFunction: (v) => typeof v === 'function',
|
|
70
|
+
isString: (v) => typeof v === 'string',
|
|
71
|
+
getDefaultStringValue: (value) => {
|
|
72
|
+
switch (value) {
|
|
73
|
+
case '$required':
|
|
74
|
+
return { op: '$exists', value: true };
|
|
75
|
+
case '$exists':
|
|
76
|
+
return { op: '$exists', value: true };
|
|
77
|
+
default:
|
|
78
|
+
return { op: '$eq', value };
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
getTypeOf: (value) => Array.isArray(value)
|
|
82
|
+
? 'array'
|
|
83
|
+
: rulesMatcherUtils.isNumber(value)
|
|
84
|
+
? 'number'
|
|
85
|
+
: value === null
|
|
86
|
+
? null
|
|
87
|
+
: typeof value,
|
|
88
|
+
getDefaultRule: (value) => {
|
|
89
|
+
const valueType = rulesMatcherUtils.getTypeOf(value);
|
|
90
|
+
switch (valueType) {
|
|
91
|
+
case 'number':
|
|
92
|
+
return { op: '$eq', value };
|
|
93
|
+
case 'string':
|
|
94
|
+
return rulesMatcherUtils.getDefaultStringValue(value);
|
|
95
|
+
case 'boolean':
|
|
96
|
+
return { op: '$exists', value };
|
|
97
|
+
case 'array':
|
|
98
|
+
return { op: '$in', value };
|
|
99
|
+
case 'object':
|
|
100
|
+
return {
|
|
101
|
+
...value,
|
|
102
|
+
op: value.op || Object.keys(value)[0],
|
|
103
|
+
value: value.value || value[Object.keys(value)[0]]
|
|
104
|
+
};
|
|
105
|
+
default:
|
|
106
|
+
return { op: '$eq', value };
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
isEmpty: (value) => {
|
|
110
|
+
// Null and undefined are empty
|
|
111
|
+
if (!rulesMatcherUtils.isDefined(value)) {
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
// functions are non empty
|
|
115
|
+
if (rulesMatcherUtils.isFunction(value)) {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
/* if (isBool(value)) {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
*/
|
|
122
|
+
// Whitespace only strings are empty
|
|
123
|
+
if (rulesMatcherUtils.isString(value)) {
|
|
124
|
+
return EMPTY_STRING_REGEXP.test(value);
|
|
125
|
+
}
|
|
126
|
+
// For arrays we use the length property
|
|
127
|
+
if (Array.isArray(value)) {
|
|
128
|
+
return value.length === 0;
|
|
129
|
+
}
|
|
130
|
+
// Dates have no attributes but aren't empty
|
|
131
|
+
if (rulesMatcherUtils.isDate(value)) {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
// If we find at least one property we consider it non empty
|
|
135
|
+
let attr;
|
|
136
|
+
if (rulesMatcherUtils.isObject(value)) {
|
|
137
|
+
for (attr in value) {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
153
142
|
return false;
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
143
|
+
},
|
|
144
|
+
forceArray: (a) => (Array.isArray(a) ? a : [a]),
|
|
145
|
+
getPath: (path, prefix) => {
|
|
146
|
+
if (path.indexOf('^') === 0) {
|
|
147
|
+
return _trimStart(path, '^');
|
|
148
|
+
}
|
|
149
|
+
// da verificare se è ancora utilizzato
|
|
150
|
+
if (path.indexOf('$') === 0) {
|
|
151
|
+
return path;
|
|
152
|
+
}
|
|
153
|
+
return prefix ? `${prefix}.${path}` : path;
|
|
154
|
+
},
|
|
155
|
+
// TODO BUG NUMERI CON LETTERE 1asdas o solo
|
|
156
|
+
forceNumber: (el) => {
|
|
157
|
+
if (Array.isArray(el)) {
|
|
158
|
+
return el.length;
|
|
159
|
+
}
|
|
160
|
+
if (rulesMatcherUtils.isNumber(String(el))) {
|
|
161
|
+
return parseFloat(String(el));
|
|
162
|
+
}
|
|
163
|
+
// fix perchè un valore false < 1 è true, quindi sbagliato, mentre un valore undefined < 1 è false
|
|
164
|
+
return 0;
|
|
165
|
+
},
|
|
166
|
+
checkRule: (block, data, options) => {
|
|
167
|
+
if (!Array.isArray(block) &&
|
|
168
|
+
block &&
|
|
169
|
+
Object.prototype.hasOwnProperty.call(block, '$and')) {
|
|
170
|
+
if (block && block['$and'] && !block['$and'].length)
|
|
171
|
+
return true;
|
|
172
|
+
return block['$and'].every((item) => rulesMatcherUtils.checkRule(item, data, options));
|
|
173
|
+
}
|
|
174
|
+
if (!Array.isArray(block) &&
|
|
175
|
+
block &&
|
|
176
|
+
Object.prototype.hasOwnProperty.call(block, '$or')) {
|
|
177
|
+
if (block && block['$or'] && !block['$or'].length)
|
|
178
|
+
return true;
|
|
179
|
+
return block['$or'].some((item) => rulesMatcherUtils.checkRule(item, data, options));
|
|
180
|
+
}
|
|
181
|
+
const res = rulesMatcherUtils.rule(block, data, options);
|
|
182
|
+
return res.valid;
|
|
183
|
+
},
|
|
184
|
+
getKeys: (rules, options) => {
|
|
185
|
+
if (!rules)
|
|
186
|
+
return null;
|
|
187
|
+
if (typeof rules == 'function')
|
|
188
|
+
return [];
|
|
189
|
+
if (!rulesMatcherUtils
|
|
190
|
+
.forceArray(rules)
|
|
191
|
+
.every((r) => rulesMatcherUtils.isObject(r)))
|
|
192
|
+
return null;
|
|
193
|
+
const keys = {};
|
|
194
|
+
const conditions = Array.isArray(rules) ? { $and: rules } : rules;
|
|
195
|
+
rulesMatcherUtils.getKey(conditions, keys, options ?? {});
|
|
196
|
+
return Object.keys(keys);
|
|
186
197
|
}
|
|
187
|
-
const res = rulesMatcherUtils.rule(block, data, options);
|
|
188
|
-
return res.valid;
|
|
189
|
-
},
|
|
190
|
-
getKeys: (rules, options) => {
|
|
191
|
-
if (!rules) return null;
|
|
192
|
-
if (typeof rules == 'function') return [];
|
|
193
|
-
if (!rulesMatcherUtils.forceArray(rules).every(r => rulesMatcherUtils.isObject(r))) return null;
|
|
194
|
-
const keys = {};
|
|
195
|
-
const conditions = Array.isArray(rules) ? {
|
|
196
|
-
$and: rules
|
|
197
|
-
} : rules;
|
|
198
|
-
rulesMatcherUtils.getKey(conditions, keys, options ?? {});
|
|
199
|
-
return Object.keys(keys);
|
|
200
|
-
}
|
|
201
198
|
};
|
|
199
|
+
/**
|
|
200
|
+
* Defines a set of comparison operators used for matching rules against user input.
|
|
201
|
+
*/
|
|
202
202
|
const operators = {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
203
|
+
$exists: (a, b) => !rulesMatcherUtils.isEmpty(a) === b,
|
|
204
|
+
$eq: (a, b) => a === b,
|
|
205
|
+
$ne: (a, b) => a !== b,
|
|
206
|
+
$gt: (a, b) => rulesMatcherUtils.forceNumber(a) > parseFloat(b),
|
|
207
|
+
$gte: (a, b) => rulesMatcherUtils.forceNumber(a) >= parseFloat(b),
|
|
208
|
+
$lt: (a, b) => rulesMatcherUtils.forceNumber(a) < parseFloat(b),
|
|
209
|
+
$lte: (a, b) => rulesMatcherUtils.forceNumber(a) <= parseFloat(b),
|
|
210
|
+
$strGt: (a, b) => String(a || '').length > parseFloat(b),
|
|
211
|
+
$strGte: (a, b) => String(a || '').length >= parseFloat(b),
|
|
212
|
+
$strLt: (a, b) => String(a || '').length < parseFloat(b),
|
|
213
|
+
$strLte: (a, b) => String(a || '').length <= parseFloat(b),
|
|
214
|
+
$in: (a, b) => rulesMatcherUtils
|
|
215
|
+
.forceArray(b)
|
|
216
|
+
.some((c) => _intersection(rulesMatcherUtils.forceArray(a), rulesMatcherUtils.forceArray(c)).length),
|
|
217
|
+
$nin: (a, b) => !rulesMatcherUtils
|
|
218
|
+
.forceArray(b)
|
|
219
|
+
.some((c) => _intersection(rulesMatcherUtils.forceArray(a), rulesMatcherUtils.forceArray(c)).length),
|
|
220
|
+
$all: (a, b) => rulesMatcherUtils
|
|
221
|
+
.forceArray(b)
|
|
222
|
+
.every((c) => _intersection(rulesMatcherUtils.forceArray(a), rulesMatcherUtils.forceArray(c)).length),
|
|
223
|
+
$regex: (a, b, opt) => rulesMatcherUtils
|
|
224
|
+
.forceArray(b)
|
|
225
|
+
.some((c) => c instanceof RegExp ? c.test(a) : new RegExp(c, opt).test(a))
|
|
218
226
|
};
|
|
219
227
|
|
|
220
228
|
const rulesMatcher = (rules, formValue = {}, apply = true, options) => {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
229
|
+
if (!rules)
|
|
230
|
+
return [apply];
|
|
231
|
+
// if (typeof rules !== 'object' && !Array.isArray(rules)) {
|
|
232
|
+
// throw new Error('Rules accept only array or object');
|
|
233
|
+
// }
|
|
234
|
+
if (typeof rules === 'function') {
|
|
235
|
+
return [rules(formValue) === apply];
|
|
236
|
+
}
|
|
237
|
+
const conditions = Array.isArray(rules)
|
|
238
|
+
? { $and: rules }
|
|
239
|
+
: rules;
|
|
240
|
+
const valid = rulesMatcherUtils.checkRule(conditions, formValue, options ?? {});
|
|
241
|
+
return [valid === apply];
|
|
230
242
|
};
|
|
231
243
|
const MatchRules = {
|
|
232
|
-
|
|
233
|
-
|
|
244
|
+
rulesMatcher,
|
|
245
|
+
utils: rulesMatcherUtils
|
|
234
246
|
};
|
|
235
247
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
248
|
+
/* eslint-disable no-useless-escape */
|
|
249
|
+
// TODO align this set of functions to selectors and reducers functions
|
|
250
|
+
const flattenRules = (ob) => {
|
|
251
|
+
const result = {};
|
|
252
|
+
for (const i in ob) {
|
|
253
|
+
if (ob[i] === null) {
|
|
254
|
+
result[i] = null;
|
|
255
|
+
}
|
|
256
|
+
if ((typeof ob[i] === 'object' && !Array.isArray(ob[i])) ||
|
|
257
|
+
(Array.isArray(ob[i]) && typeof ob[i][0] === 'object')) {
|
|
258
|
+
const temp = flattenRules(ob[i]);
|
|
259
|
+
for (const j in temp) {
|
|
260
|
+
result[i + '*' + j] = temp[j];
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
result[i] = ob[i];
|
|
265
|
+
}
|
|
249
266
|
}
|
|
250
|
-
|
|
251
|
-
return result;
|
|
267
|
+
return result;
|
|
252
268
|
};
|
|
253
|
-
const
|
|
254
|
-
|
|
269
|
+
// export const searchEmptyKeyRecursively = <T extends object>(
|
|
270
|
+
// _key: "$and" | "$or",
|
|
271
|
+
// obj: T
|
|
272
|
+
// ) => {
|
|
273
|
+
// if (
|
|
274
|
+
// isEmpty(obj) ||
|
|
275
|
+
// typeof obj !== "object" ||
|
|
276
|
+
// Object.keys(obj).length === 0
|
|
277
|
+
// ) {
|
|
278
|
+
// return true;
|
|
279
|
+
// }
|
|
280
|
+
// if (Object.keys(obj).includes(_key)) {
|
|
281
|
+
// if (obj[_key] && obj[_key].length === 0) return true;
|
|
282
|
+
// return Object.keys(obj).map((key) =>
|
|
283
|
+
// searchEmptyKeyRecursively(_key, obj[key])
|
|
284
|
+
// );
|
|
285
|
+
// }
|
|
286
|
+
// return Object.keys(obj)
|
|
287
|
+
// .map((key) => searchEmptyKeyRecursively(_key, obj[key]))
|
|
288
|
+
// .every((v) => v === true);
|
|
289
|
+
// };
|
|
290
|
+
const getRulesExists = (rules) => {
|
|
291
|
+
return Object.keys(rules).length ? CoreUtils.mapEdge(rules) : undefined;
|
|
255
292
|
};
|
|
293
|
+
/**
|
|
294
|
+
* Defines a collection of utility functions for processing rules, nodes and graph-like structures
|
|
295
|
+
*/
|
|
256
296
|
const CoreUtils = {
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
297
|
+
generateRulesName: (nextRules) => {
|
|
298
|
+
const a = nextRules.reduce((acc, inc) => {
|
|
299
|
+
const n = typeof inc.rules === 'string'
|
|
300
|
+
? inc.rules || '__ERROR_NAME__'
|
|
301
|
+
: inc.rules?.name || '__ERROR_NAME__';
|
|
302
|
+
return {
|
|
303
|
+
...acc,
|
|
304
|
+
[n]: inc.nodeId
|
|
305
|
+
};
|
|
306
|
+
}, {});
|
|
307
|
+
return a;
|
|
308
|
+
},
|
|
309
|
+
mapKeysDeepLodash: (obj, cb, isRecursive) => {
|
|
310
|
+
/* istanbul ignore next */
|
|
311
|
+
if (!obj && !isRecursive) {
|
|
312
|
+
return {};
|
|
313
|
+
}
|
|
314
|
+
if (!isRecursive) {
|
|
315
|
+
/* istanbul ignore next */
|
|
316
|
+
if (typeof obj === 'string' ||
|
|
317
|
+
typeof obj === 'number' ||
|
|
318
|
+
typeof obj === 'boolean') {
|
|
319
|
+
return {};
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
if (Array.isArray(obj)) {
|
|
323
|
+
return obj.map((item) => CoreUtils.mapKeysDeepLodash(item, cb, true));
|
|
324
|
+
}
|
|
325
|
+
if (!isPlainObject(obj)) {
|
|
326
|
+
return obj;
|
|
327
|
+
}
|
|
328
|
+
const result = mapKeys(obj, cb);
|
|
329
|
+
return mapValues(result, (value) => CoreUtils.mapKeysDeepLodash(value, cb, true));
|
|
330
|
+
},
|
|
331
|
+
generateNodes: (nodes) => keyBy(nodes.map((s) => omit(s, 'nextRules')), 'nodeId'),
|
|
332
|
+
makeObjectRules: (nodes) => nodes.reduce((acc, inc) => ({ ...acc, [inc.nodeId]: inc.nextRules }), {}),
|
|
333
|
+
hasNode: (state, name, node) => has(state, [name, 'nodes', node]),
|
|
334
|
+
isEmptyRules: (rules) => {
|
|
335
|
+
if (isEmpty(rules))
|
|
336
|
+
return true;
|
|
337
|
+
if (isEmpty(_get(rules, 'rules')))
|
|
338
|
+
return true;
|
|
339
|
+
if (Object.keys(flattenRules(rules)).every((key) => key.endsWith('$and') || key.endsWith('$or'))) {
|
|
340
|
+
return true;
|
|
341
|
+
}
|
|
342
|
+
return false;
|
|
343
|
+
},
|
|
344
|
+
mapEdge: (nextNode) => {
|
|
345
|
+
const res = nextNode.sort((a, b) => {
|
|
346
|
+
const x = CoreUtils.isEmptyRules(a.rules);
|
|
347
|
+
const y = CoreUtils.isEmptyRules(b.rules);
|
|
348
|
+
return Number(x) - Number(y);
|
|
349
|
+
});
|
|
350
|
+
return res;
|
|
351
|
+
},
|
|
352
|
+
makeRules: (rules) => Object.entries(rules).reduce((acc2, [k, v]) => [...acc2, { nodeId: k, rules: v }], []),
|
|
353
|
+
generateNodesForFlowerJson: (nodes) => nodes
|
|
354
|
+
.filter((e) => !!_get(e, 'props.id'))
|
|
355
|
+
.map((e) => {
|
|
356
|
+
const rules = CoreUtils.makeRules(e.props.to ?? {});
|
|
357
|
+
const nextRules = getRulesExists(rules);
|
|
358
|
+
const children = e.props.data?.children;
|
|
359
|
+
return {
|
|
360
|
+
nodeId: e.props.id,
|
|
361
|
+
nodeType: e.type.displayName || e.props.as || 'FlowerNode',
|
|
362
|
+
nodeTitle: _get(e.props, 'data.title'),
|
|
363
|
+
children,
|
|
364
|
+
nextRules,
|
|
365
|
+
retain: e.props.retain,
|
|
366
|
+
disabled: e.props.disabled
|
|
367
|
+
};
|
|
368
|
+
}),
|
|
369
|
+
cleanPath: (name, char = '^') => _trimStart(name, char),
|
|
370
|
+
getPath: (idValue) => {
|
|
371
|
+
if (!idValue) {
|
|
372
|
+
return {
|
|
373
|
+
path: []
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
if (idValue === '*') {
|
|
377
|
+
return {
|
|
378
|
+
path: '*'
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
if (idValue.indexOf('^') === 0) {
|
|
382
|
+
const [flowNameFromPath, ...rest] = CoreUtils.cleanPath(idValue).split('.');
|
|
383
|
+
return {
|
|
384
|
+
flowNameFromPath,
|
|
385
|
+
path: rest
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
return {
|
|
389
|
+
path: idValue.split('.')
|
|
390
|
+
};
|
|
391
|
+
},
|
|
392
|
+
allEqual: (arr, arr2) => arr.length === arr2.length && arr.every((v) => arr2.includes(v)),
|
|
393
|
+
findValidRule: (nextRules, value, prefix) => find(nextRules, (rule) => {
|
|
394
|
+
// fix per evitare di entrare in un nodo senza regole, ma con un name,
|
|
395
|
+
// invocando un next() senza paramentri
|
|
396
|
+
if (typeof rule.rules === 'string') {
|
|
397
|
+
return false;
|
|
398
|
+
}
|
|
399
|
+
if (typeof rule.rules === 'function') {
|
|
400
|
+
return rule.rules(value);
|
|
401
|
+
}
|
|
402
|
+
if (rule.rules === null) {
|
|
403
|
+
return true;
|
|
404
|
+
}
|
|
405
|
+
if (typeof rule.rules?.rules === 'undefined') {
|
|
406
|
+
return false;
|
|
407
|
+
}
|
|
408
|
+
if (typeof rule.rules.rules === 'string') {
|
|
409
|
+
return false;
|
|
410
|
+
}
|
|
411
|
+
const [valid] = MatchRules.rulesMatcher(rule.rules.rules, value, true, {
|
|
412
|
+
prefix
|
|
413
|
+
});
|
|
414
|
+
return valid;
|
|
415
|
+
})
|
|
370
416
|
};
|
|
371
417
|
|
|
372
418
|
const FlowerStateUtils = {
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
[
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
419
|
+
getAllData: (state) => state &&
|
|
420
|
+
Object.entries(state ?? {}).reduce((acc, [k, v]) => ({ ...acc, [k]: v.data }), {}),
|
|
421
|
+
selectFlowerFormNode: (name, id) => (state) => _get(state, [name, 'form', id]),
|
|
422
|
+
makeSelectCurrentNextRules: (name) => (state) => {
|
|
423
|
+
const nextRules = _get(state, [name, 'nextRules']);
|
|
424
|
+
const currentNodeId = FlowerStateUtils.makeSelectCurrentNodeId(name)(state);
|
|
425
|
+
return _get(nextRules, [currentNodeId]);
|
|
426
|
+
},
|
|
427
|
+
makeSelectCurrentNodeId: (name) => (state) => {
|
|
428
|
+
const subState = _get(state, [name]);
|
|
429
|
+
const startId = _get(state, ['startId']);
|
|
430
|
+
return _get(subState, ['current']) || startId;
|
|
431
|
+
},
|
|
432
|
+
makeSelectNodeErrors: (name, currentNodeId) => (state) => {
|
|
433
|
+
const form = FlowerStateUtils.selectFlowerFormNode(name, currentNodeId)(state);
|
|
434
|
+
return {
|
|
435
|
+
touched: form?.touched || false,
|
|
436
|
+
errors: form?.errors,
|
|
437
|
+
isValidating: form?.isValidating,
|
|
438
|
+
isValid: form && form.errors
|
|
439
|
+
? Object.values(form.errors).flat().length === 0
|
|
440
|
+
: true
|
|
441
|
+
};
|
|
442
|
+
}
|
|
397
443
|
};
|
|
398
444
|
|
|
399
|
-
const {
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
generateRulesName,
|
|
404
|
-
findValidRule
|
|
405
|
-
} = CoreUtils;
|
|
445
|
+
const { generateNodes, hasNode, makeObjectRules, generateRulesName, findValidRule } = CoreUtils;
|
|
446
|
+
/**
|
|
447
|
+
* These functions are Redux reducers used in a Flux architecture for managing state transitions and updates in a Flower application.
|
|
448
|
+
*/
|
|
406
449
|
const FlowerCoreReducers = {
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
}
|
|
462
|
-
history.pop();
|
|
463
|
-
const total = originHistory.length - 2;
|
|
464
|
-
for (let index = total; index > 0; index--) {
|
|
465
|
-
const curr = originHistory[index];
|
|
466
|
-
const nodeType = _get(container, ['nodes', curr, 'nodeType']);
|
|
467
|
-
const nodeDisabled = _get(container, ['nodes', curr, 'disabled']);
|
|
468
|
-
if (nodeDisabled || nodeType === 'FlowerAction' || nodeType === 'FlowerServer' || !nodeType) {
|
|
450
|
+
historyAdd: (state, { payload }) => {
|
|
451
|
+
if (hasNode(state, payload.name, payload.node)) {
|
|
452
|
+
state[payload.name].history.push(payload.node);
|
|
453
|
+
_set(state, [payload.name, 'current'], payload.node);
|
|
454
|
+
}
|
|
455
|
+
return state;
|
|
456
|
+
},
|
|
457
|
+
historyPrevToNode: (state, { payload }) => {
|
|
458
|
+
const history = _get(state[typeof payload === 'string' ? payload : payload.name], ['history'], []);
|
|
459
|
+
const lastIndex = lastIndexOf(history, typeof payload === 'string' ? payload : payload.node);
|
|
460
|
+
// se passo un nodo che non esiste
|
|
461
|
+
if (lastIndex >= 0) {
|
|
462
|
+
const newHistory = _slice(history, 0, lastIndex + 1);
|
|
463
|
+
_set(state, [typeof payload === 'string' ? payload : payload.name, 'history'], newHistory);
|
|
464
|
+
_set(state, [typeof payload === 'string' ? payload : payload.name, 'current'], typeof payload === 'string' ? payload : payload.node);
|
|
465
|
+
}
|
|
466
|
+
return state;
|
|
467
|
+
},
|
|
468
|
+
setFormTouched: (state, { payload }) => {
|
|
469
|
+
if (!_get(state, [
|
|
470
|
+
typeof payload === 'string' ? payload : payload.flowName,
|
|
471
|
+
'nodes',
|
|
472
|
+
typeof payload === 'string' ? payload : payload.currentNode
|
|
473
|
+
])) {
|
|
474
|
+
return state;
|
|
475
|
+
}
|
|
476
|
+
_set(state, [
|
|
477
|
+
typeof payload === 'string' ? payload : payload.flowName,
|
|
478
|
+
'form',
|
|
479
|
+
typeof payload === 'string' ? payload : payload.currentNode,
|
|
480
|
+
'touched'
|
|
481
|
+
], true);
|
|
482
|
+
return state;
|
|
483
|
+
},
|
|
484
|
+
// TODO check internal logic and use case
|
|
485
|
+
/* istanbul ignore next */
|
|
486
|
+
forceAddHistory: (state, { payload }) => {
|
|
487
|
+
const { name, flowName, history } = payload;
|
|
488
|
+
const key = name || flowName || '' || '';
|
|
489
|
+
const resultHistory = history.slice(1, -1);
|
|
490
|
+
state[key].history.push(...resultHistory);
|
|
491
|
+
return state;
|
|
492
|
+
},
|
|
493
|
+
historyPop: (state, { payload }) => {
|
|
494
|
+
const container = _get(state, [payload.name]);
|
|
495
|
+
const startId = _get(container, ['startId']);
|
|
496
|
+
const history = _get(container, ['history']);
|
|
497
|
+
const originHistory = [..._get(container, ['history'], [])];
|
|
498
|
+
if (originHistory.length < 2) {
|
|
499
|
+
_set(state, [payload.name, 'current'], startId);
|
|
500
|
+
_set(state, [payload.name, 'history'], [startId]);
|
|
501
|
+
return state;
|
|
502
|
+
}
|
|
503
|
+
// elimino lo node corrente
|
|
469
504
|
history.pop();
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
node
|
|
493
|
-
} = payload;
|
|
494
|
-
if (hasNode(state, name || flowName || '', node)) {
|
|
495
|
-
_set(state, [name || flowName || '', 'current'], node);
|
|
496
|
-
_set(state, [name || flowName || '', 'history'], [node]);
|
|
497
|
-
}
|
|
498
|
-
return state;
|
|
499
|
-
},
|
|
500
|
-
initializeFromNode: (state, {
|
|
501
|
-
payload
|
|
502
|
-
}) => {
|
|
503
|
-
const {
|
|
504
|
-
name,
|
|
505
|
-
flowName,
|
|
506
|
-
node
|
|
507
|
-
} = payload;
|
|
508
|
-
if (hasNode(state, name || flowName || '', node)) {
|
|
509
|
-
_set(state, [name || flowName || '', 'startId'], node);
|
|
510
|
-
_set(state, [name || flowName || '', 'current'], node);
|
|
511
|
-
_set(state, [name || flowName || '', 'history'], [node]);
|
|
512
|
-
}
|
|
513
|
-
return state;
|
|
514
|
-
},
|
|
515
|
-
forceResetHistory: (state, {
|
|
516
|
-
payload
|
|
517
|
-
}) => {
|
|
518
|
-
const {
|
|
519
|
-
name,
|
|
520
|
-
flowName
|
|
521
|
-
} = payload;
|
|
522
|
-
if (!name && !flowName) return state;
|
|
523
|
-
_set(state, [name || flowName || '', 'history'], []);
|
|
524
|
-
return state;
|
|
525
|
-
},
|
|
526
|
-
destroy: (state, {
|
|
527
|
-
payload
|
|
528
|
-
}) => {
|
|
529
|
-
_set(state, [payload.name], {});
|
|
530
|
-
},
|
|
531
|
-
initNodes: (state, {
|
|
532
|
-
payload
|
|
533
|
-
}) => {
|
|
534
|
-
if (payload.persist && _get(state, [payload.name, 'persist'])) return;
|
|
535
|
-
const startId = payload.startId || _get(payload, 'nodes.0.nodeId');
|
|
536
|
-
if (!startId) {
|
|
537
|
-
console.warn('Flower is empty');
|
|
538
|
-
return;
|
|
539
|
-
}
|
|
540
|
-
_set(state, payload.name, {
|
|
541
|
-
persist: payload.persist,
|
|
542
|
-
startId,
|
|
543
|
-
current: startId,
|
|
544
|
-
history: [startId],
|
|
545
|
-
nodes: generateNodes(payload.nodes),
|
|
546
|
-
nextRules: makeObjectRules(payload.nodes),
|
|
547
|
-
data: payload.initialData
|
|
548
|
-
});
|
|
549
|
-
},
|
|
550
|
-
setCurrentNode: (state, {
|
|
551
|
-
payload
|
|
552
|
-
}) => {
|
|
553
|
-
if (hasNode(state, payload.name, payload.node)) {
|
|
554
|
-
const startId = _get(state, [payload.name, 'startId']);
|
|
555
|
-
if (payload.node === startId) {
|
|
505
|
+
const total = originHistory.length - 2;
|
|
506
|
+
// eslint-disable-next-line no-plusplus
|
|
507
|
+
for (let index = total; index > 0; index--) {
|
|
508
|
+
const curr = originHistory[index];
|
|
509
|
+
const nodeType = _get(container, ['nodes', curr, 'nodeType']);
|
|
510
|
+
const nodeDisabled = _get(container, ['nodes', curr, 'disabled']);
|
|
511
|
+
if (nodeDisabled ||
|
|
512
|
+
nodeType === 'FlowerAction' ||
|
|
513
|
+
nodeType === 'FlowerServer' ||
|
|
514
|
+
!nodeType) {
|
|
515
|
+
history.pop();
|
|
516
|
+
}
|
|
517
|
+
else {
|
|
518
|
+
break;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
const lastId = _last(history);
|
|
522
|
+
_set(state, [payload.name, 'current'], lastId);
|
|
523
|
+
return state;
|
|
524
|
+
},
|
|
525
|
+
restoreHistory: (state, { payload }) => {
|
|
526
|
+
const startId = _get(state, [payload.name, 'startId']);
|
|
556
527
|
_set(state, [payload.name, 'current'], startId);
|
|
557
528
|
_set(state, [payload.name, 'history'], [startId]);
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
payload
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
}
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
529
|
+
return state;
|
|
530
|
+
},
|
|
531
|
+
replaceNode: (state, { payload }) => {
|
|
532
|
+
const { name, flowName, node } = payload;
|
|
533
|
+
// non ancora implementanto nell'hook useFlower
|
|
534
|
+
/* istanbul ignore next */
|
|
535
|
+
if (hasNode(state, name || flowName || '', node)) {
|
|
536
|
+
_set(state, [name || flowName || '', 'current'], node);
|
|
537
|
+
_set(state, [name || flowName || '', 'history'], [node]);
|
|
538
|
+
}
|
|
539
|
+
/* istanbul ignore next */
|
|
540
|
+
return state;
|
|
541
|
+
},
|
|
542
|
+
/* istanbul ignore next */
|
|
543
|
+
initializeFromNode: (state, { payload }) => {
|
|
544
|
+
const { name, flowName, node } = payload;
|
|
545
|
+
if (hasNode(state, name || flowName || '', node)) {
|
|
546
|
+
_set(state, [name || flowName || '', 'startId'], node);
|
|
547
|
+
_set(state, [name || flowName || '', 'current'], node);
|
|
548
|
+
_set(state, [name || flowName || '', 'history'], [node]);
|
|
549
|
+
}
|
|
550
|
+
return state;
|
|
551
|
+
},
|
|
552
|
+
/* istanbul ignore next */
|
|
553
|
+
forceResetHistory: (state, { payload }) => {
|
|
554
|
+
const { name, flowName } = payload;
|
|
555
|
+
if (!name && !flowName)
|
|
556
|
+
return state;
|
|
557
|
+
_set(state, [name || flowName || '', 'history'], []);
|
|
558
|
+
return state;
|
|
559
|
+
},
|
|
560
|
+
destroy: (state, { payload }) => {
|
|
561
|
+
_set(state, [payload.name], {});
|
|
562
|
+
},
|
|
563
|
+
initNodes: (state, { payload }) => {
|
|
564
|
+
if (payload.persist && _get(state, [payload.name, 'persist']))
|
|
565
|
+
return;
|
|
566
|
+
const startId = payload.startId ||
|
|
567
|
+
_get(payload, 'initialState.startId') ||
|
|
568
|
+
_get(payload, 'nodes.0.nodeId');
|
|
569
|
+
// TODO non verificato, controllo precendente che non lo permette
|
|
570
|
+
/* istanbul ignore next */
|
|
571
|
+
if (!startId) {
|
|
572
|
+
// eslint-disable-next-line no-console
|
|
573
|
+
console.warn('Flower is empty');
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
576
|
+
const current = _get(payload, 'initialState.current') || startId;
|
|
577
|
+
const history = _get(payload, 'initialState.history') || [startId];
|
|
578
|
+
_set(state, payload.name, {
|
|
579
|
+
persist: payload.persist,
|
|
580
|
+
startId,
|
|
581
|
+
current,
|
|
582
|
+
history,
|
|
583
|
+
nodes: generateNodes(payload.nodes),
|
|
584
|
+
nextRules: makeObjectRules(payload.nodes),
|
|
585
|
+
data: payload.initialData
|
|
586
|
+
});
|
|
587
|
+
},
|
|
588
|
+
// TODO usato solo da flower su vscode
|
|
589
|
+
setCurrentNode: /* istanbul ignore next */ (state, { payload }) => {
|
|
590
|
+
/* istanbul ignore next */
|
|
591
|
+
if (hasNode(state, payload.name, payload.node)) {
|
|
592
|
+
const startId = _get(state, [payload.name, 'startId']);
|
|
593
|
+
if (payload.node === startId) {
|
|
594
|
+
_set(state, [payload.name, 'current'], startId);
|
|
595
|
+
_set(state, [payload.name, 'history'], [startId]);
|
|
596
|
+
}
|
|
597
|
+
else {
|
|
598
|
+
_set(state, [payload.name, 'current'], payload.node);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
},
|
|
602
|
+
formAddErrors: (state, { payload }) => {
|
|
603
|
+
_set(state, [payload.name, 'form', payload.currentNode, 'errors', payload.id], payload.errors);
|
|
604
|
+
},
|
|
605
|
+
formRemoveErrors: (state, { payload }) => {
|
|
606
|
+
_unset(state, [
|
|
607
|
+
payload.name,
|
|
608
|
+
'form',
|
|
609
|
+
payload.currentNode,
|
|
610
|
+
'errors',
|
|
611
|
+
payload.id
|
|
612
|
+
]);
|
|
613
|
+
_unset(state, [payload.name, 'form', payload.currentNode, 'isValidating']);
|
|
614
|
+
},
|
|
615
|
+
addData: (state, { payload }) => {
|
|
616
|
+
const prevData = _get(state, [payload.flowName, 'data']);
|
|
617
|
+
_set(state, [payload.flowName, 'data'], { ...prevData, ...payload.value });
|
|
618
|
+
},
|
|
619
|
+
addDataByPath: (state, { payload }) => {
|
|
620
|
+
if (payload.id && payload.id.length) {
|
|
621
|
+
_set(state, [payload.flowName, 'data', ...payload.id], payload.value);
|
|
622
|
+
}
|
|
623
|
+
},
|
|
624
|
+
// TODO usato al momento solo il devtool
|
|
625
|
+
replaceData: /* istanbul ignore next */ (state, { payload }) => {
|
|
626
|
+
/* istanbul ignore next */
|
|
627
|
+
_set(state, [payload.flowName, 'data'], payload.value);
|
|
628
|
+
},
|
|
629
|
+
unsetData: (state, { payload }) => {
|
|
630
|
+
_unset(state, [payload.flowName, 'data', ...payload.id]);
|
|
631
|
+
},
|
|
632
|
+
setFormIsValidating: (state, { payload }) => {
|
|
633
|
+
_set(state, [payload.name, 'form', payload.currentNode, 'isValidating'], payload.isValidating);
|
|
634
|
+
},
|
|
635
|
+
node: (state, { payload }) => {
|
|
636
|
+
const { name, history } = payload;
|
|
637
|
+
const node = payload.nodeId || payload.node || '';
|
|
638
|
+
const flowName = name || payload.flowName || '';
|
|
639
|
+
const startNode = _get(state, [payload.name, 'startId']);
|
|
640
|
+
const currentNodeId = _get(state, [payload.name, 'current'], startNode);
|
|
641
|
+
FlowerCoreReducers.setFormTouched(state, {
|
|
642
|
+
type: 'setFormTouched',
|
|
643
|
+
payload: { flowName, currentNode: currentNodeId }
|
|
644
|
+
});
|
|
645
|
+
/* istanbul ignore next */
|
|
646
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
647
|
+
if (devtoolState && _get(devtoolState, '__FLOWER_DEVTOOLS__') && history) {
|
|
648
|
+
FlowerCoreReducers.forceAddHistory(state, {
|
|
649
|
+
type: 'forceAddHistory',
|
|
650
|
+
payload: {
|
|
651
|
+
name,
|
|
652
|
+
flowName,
|
|
653
|
+
history
|
|
654
|
+
}
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
FlowerCoreReducers.historyAdd(state, {
|
|
658
|
+
type: 'historyAdd',
|
|
659
|
+
payload: { name: name || flowName || '', node }
|
|
660
|
+
});
|
|
661
|
+
},
|
|
662
|
+
prevToNode: (state, { payload }) => {
|
|
663
|
+
const { node, name, flowName } = payload;
|
|
664
|
+
FlowerCoreReducers.historyPrevToNode(state, {
|
|
665
|
+
type: 'historyPrevToNode',
|
|
666
|
+
payload: { name: name || flowName || '', node }
|
|
667
|
+
});
|
|
668
|
+
},
|
|
669
|
+
next: (state, { payload }) => {
|
|
670
|
+
const { name, data = {}, route } = payload;
|
|
671
|
+
const flowName = name || payload.flowName || '';
|
|
672
|
+
const currentNodeId = FlowerStateUtils.makeSelectCurrentNodeId(flowName)(state);
|
|
673
|
+
const currentNextRules = FlowerStateUtils.makeSelectCurrentNextRules(flowName)(state);
|
|
674
|
+
const form = FlowerStateUtils.makeSelectNodeErrors(flowName, currentNodeId)(state);
|
|
675
|
+
const clonedData = _cloneDeep(FlowerStateUtils.getAllData(state));
|
|
676
|
+
const stateWithNodeData = {
|
|
677
|
+
$in: data,
|
|
678
|
+
$form: form,
|
|
679
|
+
...clonedData
|
|
680
|
+
};
|
|
681
|
+
FlowerCoreReducers.setFormTouched(state, {
|
|
682
|
+
type: 'setFormTouched',
|
|
683
|
+
payload: { flowName, currentNode: currentNodeId }
|
|
684
|
+
});
|
|
685
|
+
if (!currentNextRules) {
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
688
|
+
if (route) {
|
|
689
|
+
const rulesByName = generateRulesName(currentNextRules);
|
|
690
|
+
if (!rulesByName[route]) {
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
693
|
+
FlowerCoreReducers.historyAdd(state, {
|
|
694
|
+
type: 'historyAdd',
|
|
695
|
+
payload: { name: flowName, node: rulesByName[route] }
|
|
696
|
+
});
|
|
697
|
+
return;
|
|
698
|
+
}
|
|
699
|
+
const validRule = findValidRule(currentNextRules, stateWithNodeData, flowName);
|
|
700
|
+
const nextNumberNode = _get(validRule, 'nodeId');
|
|
701
|
+
if (!nextNumberNode) {
|
|
702
|
+
return;
|
|
703
|
+
}
|
|
704
|
+
FlowerCoreReducers.historyAdd(state, {
|
|
705
|
+
type: 'historyAdd',
|
|
706
|
+
payload: { name: flowName, node: nextNumberNode }
|
|
707
|
+
});
|
|
708
|
+
},
|
|
709
|
+
prev: (state, { payload }) => {
|
|
710
|
+
const { name, flowName } = payload;
|
|
711
|
+
FlowerCoreReducers.historyPop(state, {
|
|
712
|
+
type: 'historyPop',
|
|
713
|
+
payload: { name: name || flowName || '' }
|
|
714
|
+
});
|
|
715
|
+
},
|
|
716
|
+
restart: (state, { payload }) => {
|
|
717
|
+
const { name, flowName } = payload;
|
|
718
|
+
FlowerCoreReducers.restoreHistory(state, {
|
|
719
|
+
type: 'restoreHistory',
|
|
720
|
+
payload: { name: name || flowName || '' }
|
|
721
|
+
});
|
|
722
|
+
},
|
|
723
|
+
reset: (state, { payload }) => {
|
|
724
|
+
const { name, flowName, initialData } = payload;
|
|
725
|
+
FlowerCoreReducers.restoreHistory(state, {
|
|
726
|
+
type: 'restoreHistory',
|
|
727
|
+
payload: { name: name || flowName || '' }
|
|
728
|
+
});
|
|
729
|
+
_set(state, [name || flowName || '', 'form'], {});
|
|
730
|
+
_set(state, [name || flowName || '', 'data'], initialData);
|
|
703
731
|
}
|
|
704
|
-
FlowerCoreReducers.historyAdd(state, {
|
|
705
|
-
type: 'historyAdd',
|
|
706
|
-
payload: {
|
|
707
|
-
name: flowName,
|
|
708
|
-
node: nextNumberNode
|
|
709
|
-
}
|
|
710
|
-
});
|
|
711
|
-
},
|
|
712
|
-
prev: (state, {
|
|
713
|
-
payload
|
|
714
|
-
}) => {
|
|
715
|
-
const {
|
|
716
|
-
name,
|
|
717
|
-
flowName
|
|
718
|
-
} = payload;
|
|
719
|
-
FlowerCoreReducers.historyPop(state, {
|
|
720
|
-
type: 'historyPop',
|
|
721
|
-
payload: {
|
|
722
|
-
name: name || flowName || ''
|
|
723
|
-
}
|
|
724
|
-
});
|
|
725
|
-
},
|
|
726
|
-
restart: (state, {
|
|
727
|
-
payload
|
|
728
|
-
}) => {
|
|
729
|
-
const {
|
|
730
|
-
name,
|
|
731
|
-
flowName
|
|
732
|
-
} = payload;
|
|
733
|
-
FlowerCoreReducers.restoreHistory(state, {
|
|
734
|
-
type: 'restoreHistory',
|
|
735
|
-
payload: {
|
|
736
|
-
name: name || flowName || ''
|
|
737
|
-
}
|
|
738
|
-
});
|
|
739
|
-
},
|
|
740
|
-
reset: (state, {
|
|
741
|
-
payload
|
|
742
|
-
}) => {
|
|
743
|
-
const {
|
|
744
|
-
name,
|
|
745
|
-
flowName,
|
|
746
|
-
initialData
|
|
747
|
-
} = payload;
|
|
748
|
-
FlowerCoreReducers.restoreHistory(state, {
|
|
749
|
-
type: 'restoreHistory',
|
|
750
|
-
payload: {
|
|
751
|
-
name: name || flowName || ''
|
|
752
|
-
}
|
|
753
|
-
});
|
|
754
|
-
_set(state, [name || flowName || '', 'form'], {});
|
|
755
|
-
_set(state, [name || flowName || '', 'data'], initialData);
|
|
756
|
-
}
|
|
757
732
|
};
|
|
758
733
|
|
|
759
734
|
const FlowerCoreStateSelectors = {
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
735
|
+
selectGlobal: (state) => state && state.flower,
|
|
736
|
+
selectFlower: (name) => (state) => _get(state, [name]),
|
|
737
|
+
selectFlowerFormNode: (id) => (state) => _get(state, ['form', id]),
|
|
738
|
+
selectFlowerHistory: (flower) => _get(flower, ['history'], []),
|
|
739
|
+
makeSelectNodesIds: (flower) => _get(flower, ['nodes']),
|
|
740
|
+
makeSelectStartNodeId: (flower) => _get(flower, ['startId']),
|
|
741
|
+
getDataByFlow: (flower) => _get(flower, ['data']) ?? {},
|
|
742
|
+
getDataFromState: (id) => (data) => (id === '*' ? data : _get(data, id)),
|
|
743
|
+
makeSelectNodeFormTouched: (form) => form && form.touched,
|
|
744
|
+
makeSelectCurrentNodeId: (flower, startNodeId) => _get(flower, ['current']) || startNodeId,
|
|
745
|
+
makeSelectCurrentNodeDisabled: (nodes, current) => !!_get(nodes, [current, 'disabled']),
|
|
746
|
+
makeSelectPrevNodeRetain: (nodes, history, current) => {
|
|
747
|
+
if (!nodes)
|
|
748
|
+
return;
|
|
749
|
+
const prevFlowerNode = [...history].reverse().find((el) => {
|
|
750
|
+
const { nodeType, retain } = nodes[el];
|
|
751
|
+
return nodeType === 'FlowerNode' || retain;
|
|
752
|
+
});
|
|
753
|
+
// eslint-disable-next-line consistent-return
|
|
754
|
+
if (nodes[current].nodeType === 'FlowerNode' || nodes[current].retain)
|
|
755
|
+
return;
|
|
756
|
+
if (!prevFlowerNode)
|
|
757
|
+
return;
|
|
758
|
+
if (nodes[prevFlowerNode] && nodes[prevFlowerNode].disabled)
|
|
759
|
+
return;
|
|
760
|
+
// eslint-disable-next-line consistent-return
|
|
761
|
+
return (nodes[prevFlowerNode] && nodes[prevFlowerNode].retain && prevFlowerNode);
|
|
762
|
+
},
|
|
763
|
+
makeSelectNodeErrors: (form) => {
|
|
764
|
+
return {
|
|
765
|
+
touched: form?.touched || false,
|
|
766
|
+
errors: form?.errors,
|
|
767
|
+
isValidating: form?.isValidating,
|
|
768
|
+
isValid: form && form.errors
|
|
769
|
+
? Object.values(form.errors).flat().length === 0
|
|
770
|
+
: true
|
|
771
|
+
};
|
|
772
|
+
},
|
|
773
|
+
makeSelectFieldError: (name, id, validate) => (data) => {
|
|
774
|
+
if (!validate || !data)
|
|
775
|
+
return [];
|
|
776
|
+
const errors = validate.filter((rule) => {
|
|
777
|
+
if (!rule)
|
|
778
|
+
return true;
|
|
779
|
+
if (!rule.rules)
|
|
780
|
+
return true;
|
|
781
|
+
const transformSelf = CoreUtils.mapKeysDeepLodash(rule.rules, (v, key) => key === '$self' ? id : key);
|
|
782
|
+
const [hasError] = MatchRules.rulesMatcher(transformSelf, data, false, {
|
|
783
|
+
prefix: name
|
|
784
|
+
});
|
|
785
|
+
return hasError;
|
|
786
|
+
});
|
|
787
|
+
const result = errors.map((r) => (r && r.message) || 'error');
|
|
788
|
+
return result.length === 0 ? [] : result;
|
|
789
|
+
},
|
|
790
|
+
selectorRulesDisabled: (id, rules, keys, flowName, value) => (data, form) => {
|
|
791
|
+
const newState = { ...data, ...value, $form: form };
|
|
792
|
+
const state = Object.assign(newState, id ? { $self: _get(newState, [flowName, ...id.split('.')]) } : {});
|
|
793
|
+
if (!rules)
|
|
794
|
+
return false;
|
|
795
|
+
if (typeof rules === 'function') {
|
|
796
|
+
return !rules(state);
|
|
797
|
+
}
|
|
798
|
+
if (!keys)
|
|
799
|
+
return false;
|
|
800
|
+
const res = keys.reduce((acc, inc) => {
|
|
801
|
+
const k = inc;
|
|
802
|
+
return Object.assign(acc, { [k]: _get(state, k) });
|
|
803
|
+
}, {});
|
|
804
|
+
const [disabled] = MatchRules.rulesMatcher(rules, { ...unflatten(res) }, false, { prefix: flowName });
|
|
805
|
+
return disabled;
|
|
819
806
|
}
|
|
820
|
-
if (!keys) return false;
|
|
821
|
-
const res = keys.reduce((acc, inc) => {
|
|
822
|
-
const k = inc;
|
|
823
|
-
return Object.assign(acc, {
|
|
824
|
-
[k]: _get(state, k)
|
|
825
|
-
});
|
|
826
|
-
}, {});
|
|
827
|
-
const [disabled] = MatchRules.rulesMatcher(rules, {
|
|
828
|
-
...unflatten(res)
|
|
829
|
-
}, false, {
|
|
830
|
-
prefix: flowName
|
|
831
|
-
});
|
|
832
|
-
return disabled;
|
|
833
|
-
}
|
|
834
807
|
};
|
|
835
808
|
|
|
836
809
|
var RulesModes;
|
|
837
810
|
(function (RulesModes) {
|
|
838
|
-
|
|
839
|
-
|
|
811
|
+
RulesModes["$and"] = "$and";
|
|
812
|
+
RulesModes["$or"] = "$or";
|
|
840
813
|
})(RulesModes || (RulesModes = {}));
|
|
841
814
|
var RulesOperators$1;
|
|
842
815
|
(function (RulesOperators) {
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
816
|
+
RulesOperators["$exist"] = "$exist";
|
|
817
|
+
RulesOperators["$eq"] = "$eq";
|
|
818
|
+
RulesOperators["$ne"] = "$ne";
|
|
819
|
+
RulesOperators["$gt"] = "$gt";
|
|
820
|
+
RulesOperators["$gte"] = "$gte";
|
|
821
|
+
RulesOperators["$lt"] = "$lt";
|
|
822
|
+
RulesOperators["$lte"] = "$lte";
|
|
823
|
+
RulesOperators["$strGt"] = "$strGt";
|
|
824
|
+
RulesOperators["$strGte"] = "$strGte";
|
|
825
|
+
RulesOperators["$strLt"] = "$strLt";
|
|
826
|
+
RulesOperators["$strLte"] = "$strLte";
|
|
827
|
+
RulesOperators["$in"] = "$in";
|
|
828
|
+
RulesOperators["$nin"] = "$nin";
|
|
829
|
+
RulesOperators["$all"] = "$all";
|
|
830
|
+
RulesOperators["$regex"] = "$regex";
|
|
858
831
|
})(RulesOperators$1 || (RulesOperators$1 = {}));
|
|
859
832
|
|
|
860
833
|
var RulesOperators;
|
|
861
834
|
(function (RulesOperators) {
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
835
|
+
RulesOperators["$exist"] = "$exist";
|
|
836
|
+
RulesOperators["$eq"] = "$eq";
|
|
837
|
+
RulesOperators["$ne"] = "$ne";
|
|
838
|
+
RulesOperators["$gt"] = "$gt";
|
|
839
|
+
RulesOperators["$gte"] = "$gte";
|
|
840
|
+
RulesOperators["$lt"] = "$lt";
|
|
841
|
+
RulesOperators["$lte"] = "$lte";
|
|
842
|
+
RulesOperators["$strGt"] = "$strGt";
|
|
843
|
+
RulesOperators["$strGte"] = "$strGte";
|
|
844
|
+
RulesOperators["$strLt"] = "$strLt";
|
|
845
|
+
RulesOperators["$strLte"] = "$strLte";
|
|
846
|
+
RulesOperators["$in"] = "$in";
|
|
847
|
+
RulesOperators["$nin"] = "$nin";
|
|
848
|
+
RulesOperators["$all"] = "$all";
|
|
849
|
+
RulesOperators["$regex"] = "$regex";
|
|
877
850
|
})(RulesOperators || (RulesOperators = {}));
|
|
878
851
|
|
|
879
|
-
|
|
852
|
+
const devtoolState = {};
|
|
853
|
+
|
|
854
|
+
export { CoreUtils, Emitter, FlowerCoreReducers, FlowerStateUtils, MatchRules, RulesModes, RulesOperators, FlowerCoreStateSelectors as Selectors, devtoolState };
|