@genesislcap/foundation-ui 14.258.3 → 14.259.0

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.
@@ -0,0 +1,297 @@
1
+ import { __decorate } from "tslib";
2
+ import { ExpressionBuilder, template, styles, Config } from '@genesislcap/expression-builder';
3
+ import { customElement, observable } from '@microsoft/fast-element';
4
+ import { mapFieldTypeToRuleExpressionType, numberTypes, toBinaryExpression, toMethodExpression, transformRuleValue, rebuildRuleValue, } from './expressions-shared-helpers';
5
+ import { RuleExpression } from './types';
6
+ /**
7
+ * CONFIG
8
+ * TODO: this file doesn't have unit tests, as the unit tests are basically identical to the rule-expression-builder file. Once we properly
9
+ * split responsibilities then everything can receive tests
10
+ */
11
+ /**
12
+ * Operator names for the server expression
13
+ * Mapped to the RuleExpression names where possible
14
+ * @internal
15
+ **/
16
+ const valueOperatorNames = {
17
+ TRIM: 'TRIM',
18
+ ADD: 'ADD',
19
+ SUBTRACT: 'SUBTRACT',
20
+ MULTIPLY: 'MULTIPLY',
21
+ DIVIDE: 'DIVIDE',
22
+ CONVERT_TO_DATE: 'CONVERT_TO_DATE',
23
+ CONVERT_TO_DATE_TIME: 'CONVERT_TO_DATE_TIME',
24
+ };
25
+ /**
26
+ * Operators for the server expression
27
+ * @internal
28
+ **/
29
+ const valueOperators = [
30
+ {
31
+ type: valueOperatorNames.TRIM,
32
+ applyTo: ['string'],
33
+ nbInputs: 0,
34
+ tooltip: "Returns a string whose value is this string, with all leading and trailing space removed, where space is defined as any character whose codepoint is less than or equal to 'U+0020' (the space character)",
35
+ },
36
+ {
37
+ type: valueOperatorNames.ADD,
38
+ applyTo: [...numberTypes],
39
+ nbInputs: 1,
40
+ tooltip: 'Returns the result of the field value mathematically added to the specified rule value. FIELD + VALUE',
41
+ },
42
+ {
43
+ type: valueOperatorNames.SUBTRACT,
44
+ applyTo: [...numberTypes],
45
+ nbInputs: 1,
46
+ tooltip: 'Returns the result of the field value mathematically subtracted by the specified rule value. FIELD - VALUE',
47
+ },
48
+ {
49
+ type: valueOperatorNames.MULTIPLY,
50
+ applyTo: [...numberTypes],
51
+ nbInputs: 1,
52
+ tooltip: 'Returns the result of the field value mathematically multiplied by the specified rule value. FIELD * VALUE',
53
+ },
54
+ {
55
+ type: valueOperatorNames.DIVIDE,
56
+ applyTo: [...numberTypes],
57
+ nbInputs: 1,
58
+ tooltip: 'Returns the result of the field value mathematically divided by the specified rule value. FIELD / VALUE',
59
+ },
60
+ {
61
+ type: valueOperatorNames.CONVERT_TO_DATE,
62
+ applyTo: ['date'],
63
+ nbInputs: 0,
64
+ tooltip: 'Returns the date, which is stored as the epoch time, as a formatted date YYYY/dd/mm',
65
+ },
66
+ {
67
+ type: valueOperatorNames.CONVERT_TO_DATE_TIME,
68
+ applyTo: ['date-time'],
69
+ nbInputs: 0,
70
+ tooltip: 'Returns the date-time, which is stored as the epoch time, as a formatted date YYYY/dd/mm HH:mm:ss',
71
+ },
72
+ ];
73
+ /**
74
+ * Converts a client operator name to a server operator name
75
+ *
76
+ * The opposite to `transformServerNameToOperatorName`
77
+ *
78
+ * @privateRemarks
79
+ * Most names are the same, but this handles cases where date comparison operator names are different
80
+ * on the display to their server name
81
+ *
82
+ * TODO: We could clean this up if we support labels/aliases on the client component
83
+ *
84
+ * @internal
85
+ **/
86
+ function transformOperatorNameToServerName(op) {
87
+ switch (op) {
88
+ default:
89
+ return op;
90
+ }
91
+ }
92
+ /**
93
+ * Converts a client `Rule` into the correct server `MethodExpression`
94
+ *
95
+ * @internal
96
+ **/
97
+ function ruleToRuleMethodExpression(rule, operatorName) {
98
+ switch (operatorName) {
99
+ case valueOperatorNames.TRIM:
100
+ return toMethodExpression(rule, RuleExpression.methodCall.TRIM, []);
101
+ case valueOperatorNames.CONVERT_TO_DATE:
102
+ return toMethodExpression(rule, RuleExpression.methodCall.LONG_TO_DATE, []);
103
+ case valueOperatorNames.CONVERT_TO_DATE_TIME:
104
+ return toMethodExpression(rule, RuleExpression.methodCall.LONG_TO_DATE_TIME, []);
105
+ }
106
+ }
107
+ /**
108
+ * Converts a client `Rule` into the correct server `Expression`
109
+ *
110
+ * @privateRemarks
111
+ * The server doesn't have a concept for a partial expression so if the user doesn't fill out all values
112
+ * (e.g. chooses a field but not an operator) that would be lost via this process
113
+ *
114
+ * @internal
115
+ **/
116
+ function ruleToRuleExpression(ruleInput) {
117
+ var _a, _b;
118
+ // If the user hasn't fully filled out the rule then we just ignore it for the condition
119
+ if (!(((_a = ruleInput.operator) === null || _a === void 0 ? void 0 : _a.type) && ((_b = ruleInput.field) === null || _b === void 0 ? void 0 : _b.fieldId)))
120
+ return null;
121
+ const rule = transformRuleValue(ruleInput);
122
+ const rhsType = mapFieldTypeToRuleExpressionType(rule);
123
+ const operatorName = transformOperatorNameToServerName(rule.operator.type);
124
+ switch (operatorName) {
125
+ case valueOperatorNames.TRIM:
126
+ case valueOperatorNames.CONVERT_TO_DATE:
127
+ case valueOperatorNames.CONVERT_TO_DATE_TIME:
128
+ return ruleToRuleMethodExpression(rule, operatorName);
129
+ case valueOperatorNames.ADD:
130
+ case valueOperatorNames.SUBTRACT:
131
+ case valueOperatorNames.DIVIDE:
132
+ case valueOperatorNames.MULTIPLY:
133
+ return toBinaryExpression(rule, operatorName, rhsType);
134
+ default:
135
+ throw new Error(`Unmatched case for operator name: ${operatorName}`);
136
+ }
137
+ }
138
+ /**
139
+ * Convert from Genesis to Expression builder
140
+ */
141
+ /**
142
+ * Converts a server operator name to a client operator name
143
+ *
144
+ * The opposite to `transformOperatorNameToServerName`
145
+ *
146
+ * @privateRemarks
147
+ * Most names are the same, but this handles cases where date comparison operator names are different
148
+ * on the display to their server name
149
+ *
150
+ * TODO: We could clean this up if we support labels/aliases on the client component
151
+ *
152
+ * @internal
153
+ **/
154
+ function transformServerNameToOperatorName(op, rulePartialField) {
155
+ // TODO: this function usage doens't need to do anything because all binary expression operator names match on client and server
156
+ // for now
157
+ const useDateOperatorNames = rulePartialField.field.type === 'date' || rulePartialField.field.type === 'date-time';
158
+ if (!useDateOperatorNames)
159
+ return op;
160
+ switch (op) {
161
+ default:
162
+ return op;
163
+ }
164
+ }
165
+ /**
166
+ * Handles operator names which have a special client name, but serialised to a normal operator on the server
167
+ *
168
+ * @internal
169
+ **/
170
+ function rebuildOperator(rulePartialField, binExpr) {
171
+ const operator = (() => {
172
+ const clientOperatorName = transformServerNameToOperatorName(binExpr.OPERATION, rulePartialField);
173
+ return valueOperators.find((o) => o.type === clientOperatorName);
174
+ })();
175
+ return Object.assign(Object.assign({}, rulePartialField), { operator });
176
+ }
177
+ /**
178
+ * Converts a server BinaryExpression to a client BinaryOperator
179
+ *
180
+ * The opposite of `toBinaryExpression`
181
+ * @internal
182
+ **/
183
+ function fromBinaryExpression(fields, binExpr) {
184
+ if (binExpr.LEFT.TYPE !== 'FIELD')
185
+ throw new Error('BinaryExpression LHS must be TYPE === FIELD');
186
+ if (!['STRING', 'NUMBER', 'BOOLEAN', 'NULL'].includes(binExpr.RIGHT.TYPE))
187
+ throw new Error('BinaryExpression RHS must be TYPE === NUMBER | STRING | BOOLEAN | NULL');
188
+ return rebuildRuleValue(rebuildOperator({
189
+ field: fields.find((f) => f.fieldId === binExpr.LEFT.NAME),
190
+ }, binExpr), binExpr.RIGHT);
191
+ }
192
+ /**
193
+ * Converts a server MethodExpression to a client BinaryOperator
194
+ *
195
+ * The opposite of `toMethodExpression`
196
+ *
197
+ * @internal
198
+ **/
199
+ function fromMethodExpression(fields, methodExpr) {
200
+ const [clientOperatorName, value] = (() => {
201
+ switch (true) {
202
+ case methodExpr.METHOD === 'TRIM':
203
+ return [valueOperatorNames[valueOperatorNames.TRIM], undefined];
204
+ case methodExpr.METHOD === 'LONG_TO_DATE':
205
+ return [valueOperatorNames[valueOperatorNames.CONVERT_TO_DATE], undefined];
206
+ case methodExpr.METHOD === 'LONG_TO_DATE_TIME':
207
+ return [valueOperatorNames[valueOperatorNames.CONVERT_TO_DATE_TIME], undefined];
208
+ default:
209
+ throw new Error('Unhandled fromMethodExpression case');
210
+ }
211
+ })();
212
+ return {
213
+ field: fields.find((f) => f.fieldId === methodExpr.PARAMETERS[0].NAME),
214
+ operator: valueOperators.find((o) => o.type === clientOperatorName),
215
+ value,
216
+ };
217
+ }
218
+ /**
219
+ * Converts recursively from a PREDICATE_EXPRESSION to client Groups and Rules
220
+ *
221
+ * @internal
222
+ **/
223
+ function ruleExpressionToGroup(fields, expr) {
224
+ return {
225
+ combinator: Config.NULL_COMBINATOR,
226
+ children: expr.EXPRESSIONS.map((condition) => {
227
+ if (!('TYPE' in condition))
228
+ throw new Error('RuleExpression format not yet supported - no TYPE');
229
+ if (condition.TYPE === 'PREDICATE_EXPRESSION')
230
+ return ruleExpressionToGroup(fields, condition);
231
+ if (condition.TYPE === 'BINARY_EXPRESSION')
232
+ return fromBinaryExpression(fields, condition);
233
+ if (condition.TYPE === 'METHOD_EXPRESSION')
234
+ return fromMethodExpression(fields, condition);
235
+ throw new Error('RuleExpression format not yet supported - unsupported TYPE');
236
+ }),
237
+ };
238
+ }
239
+ /**
240
+ * We don't create the foundation version of the component in the same way as the other components,
241
+ * they're composed from a base FAST component.
242
+ * The reason for this is that we want to have ExpressionBuilder as an independent and open source
243
+ * component, and due to this we don't want to release it as base components that someone needs to use
244
+ * FAST to compose.
245
+ */
246
+ let FoundationValueExpressionBuilder = class FoundationValueExpressionBuilder extends ExpressionBuilder {
247
+ valueConfigChanged(_, newConfig) {
248
+ const topLevelPredicateExpr = {
249
+ TYPE: 'PREDICATE_EXPRESSION',
250
+ OPERATION: 'NULL',
251
+ EXPRESSIONS: newConfig.model ? [newConfig.model] : [],
252
+ };
253
+ const model = ruleExpressionToGroup(newConfig.fields, topLevelPredicateExpr);
254
+ this.config = {
255
+ combinators: [Config.NULL_COMBINATOR],
256
+ operators: valueOperators,
257
+ fields: newConfig.fields,
258
+ model,
259
+ maxNesting: newConfig.maxNesting,
260
+ partialRuleValidationWarning: newConfig.partialRuleValidationWarning,
261
+ };
262
+ }
263
+ configChanged(oldConfig, newConfig) {
264
+ if (!newConfig.operators || !newConfig.combinators) {
265
+ throw new Error('Unable to detect operators or combinators. Did you set the config on the rule builder via the config property? Use the valueConfig property instead');
266
+ }
267
+ super.configChanged(oldConfig, newConfig);
268
+ }
269
+ dispatchChangeEvent(group) {
270
+ if (!('children' in group))
271
+ throw new Error('Invalid top level group hierarchy');
272
+ if (group.children.length === 0)
273
+ return;
274
+ if (group.children.length > 1)
275
+ throw new Error('Value expressions should not have multiple rules');
276
+ if ('children' in group.children[0])
277
+ throw new Error('Trying to convert group to rule');
278
+ const valueExpr = ruleToRuleExpression(group.children[0]);
279
+ this.dispatchEvent(new CustomEvent('change', {
280
+ detail: valueExpr,
281
+ bubbles: true,
282
+ cancelable: true,
283
+ composed: true,
284
+ }));
285
+ }
286
+ };
287
+ __decorate([
288
+ observable
289
+ ], FoundationValueExpressionBuilder.prototype, "valueConfig", void 0);
290
+ FoundationValueExpressionBuilder = __decorate([
291
+ customElement({
292
+ name: 'foundation-value-expression-builder',
293
+ styles: styles,
294
+ template,
295
+ })
296
+ ], FoundationValueExpressionBuilder);
297
+ export { FoundationValueExpressionBuilder };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@genesislcap/foundation-ui",
3
3
  "description": "Genesis Foundation UI",
4
- "version": "14.258.3",
4
+ "version": "14.259.0",
5
5
  "sideEffects": false,
6
6
  "license": "SEE LICENSE IN license.txt",
7
7
  "main": "dist/esm/index.js",
@@ -83,13 +83,13 @@
83
83
  }
84
84
  },
85
85
  "devDependencies": {
86
- "@genesislcap/foundation-testing": "14.258.3",
87
- "@genesislcap/genx": "14.258.3",
88
- "@genesislcap/rollup-builder": "14.258.3",
89
- "@genesislcap/ts-builder": "14.258.3",
90
- "@genesislcap/uvu-playwright-builder": "14.258.3",
91
- "@genesislcap/vite-builder": "14.258.3",
92
- "@genesislcap/webpack-builder": "14.258.3",
86
+ "@genesislcap/foundation-testing": "14.259.0",
87
+ "@genesislcap/genx": "14.259.0",
88
+ "@genesislcap/rollup-builder": "14.259.0",
89
+ "@genesislcap/ts-builder": "14.259.0",
90
+ "@genesislcap/uvu-playwright-builder": "14.259.0",
91
+ "@genesislcap/vite-builder": "14.259.0",
92
+ "@genesislcap/webpack-builder": "14.259.0",
93
93
  "copyfiles": "^2.4.1",
94
94
  "rimraf": "^5.0.0",
95
95
  "rxjs": "^7.5.4"
@@ -100,15 +100,15 @@
100
100
  "@fortawesome/free-regular-svg-icons": "^6.2.1",
101
101
  "@fortawesome/free-solid-svg-icons": "^6.2.1",
102
102
  "@genesiscommunitysuccess/analyzer-import-alias-plugin": "^5.0.3",
103
- "@genesislcap/expression-builder": "14.258.3",
104
- "@genesislcap/foundation-comms": "14.258.3",
105
- "@genesislcap/foundation-criteria": "14.258.3",
106
- "@genesislcap/foundation-errors": "14.258.3",
107
- "@genesislcap/foundation-events": "14.258.3",
108
- "@genesislcap/foundation-logger": "14.258.3",
109
- "@genesislcap/foundation-notifications": "14.258.3",
110
- "@genesislcap/foundation-user": "14.258.3",
111
- "@genesislcap/foundation-utils": "14.258.3",
103
+ "@genesislcap/expression-builder": "14.259.0",
104
+ "@genesislcap/foundation-comms": "14.259.0",
105
+ "@genesislcap/foundation-criteria": "14.259.0",
106
+ "@genesislcap/foundation-errors": "14.259.0",
107
+ "@genesislcap/foundation-events": "14.259.0",
108
+ "@genesislcap/foundation-logger": "14.259.0",
109
+ "@genesislcap/foundation-notifications": "14.259.0",
110
+ "@genesislcap/foundation-user": "14.259.0",
111
+ "@genesislcap/foundation-utils": "14.259.0",
112
112
  "@microsoft/fast-colors": "5.3.1",
113
113
  "@microsoft/fast-components": "2.30.6",
114
114
  "@microsoft/fast-element": "1.14.0",
@@ -130,5 +130,5 @@
130
130
  "access": "public"
131
131
  },
132
132
  "customElements": "dist/custom-elements.json",
133
- "gitHead": "0acd5f3f2eb9903b9b0d70b5d35210fd0b26d0c5"
133
+ "gitHead": "6656bbcddf94db7587bab3339ca021718ce54709"
134
134
  }