@syncfusion/ej2-react-form-renderer 0.1.2-beta → 34.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. package/README.md +88 -105
  2. package/diConfig.json +85 -0
  3. package/dist/ej2-react-form-renderer.min.js +10 -0
  4. package/dist/ej2-react-form-renderer.umd.min.js +11 -0
  5. package/dist/ej2-react-form-renderer.umd.min.js.map +1 -0
  6. package/dist/es6/ej2-react-form-renderer.es2015.js +37 -0
  7. package/dist/es6/ej2-react-form-renderer.es2015.js.map +1 -0
  8. package/form-renderer.d.ts +4 -0
  9. package/form-renderer.js +4 -0
  10. package/index.d.ts +2 -4
  11. package/index.js +2 -4
  12. package/license +6 -13
  13. package/package.json +19 -38
  14. package/src/form-renderer/formrenderer.component.d.ts +34 -0
  15. package/src/form-renderer/formrenderer.component.js +49 -0
  16. package/src/form-renderer/index.d.ts +1 -0
  17. package/src/form-renderer/index.js +1 -0
  18. package/src/global.js +1 -0
  19. package/src/index.d.ts +2 -6
  20. package/src/index.js +2 -6
  21. package/styles/bds-lite.css +1 -0
  22. package/styles/bds-lite.scss +1 -0
  23. package/styles/bds.css +1 -0
  24. package/styles/bds.scss +1 -0
  25. package/styles/bootstrap-dark-lite.css +1 -0
  26. package/styles/bootstrap-dark-lite.scss +1 -0
  27. package/styles/bootstrap-dark.css +1 -26
  28. package/styles/bootstrap-dark.scss +1 -0
  29. package/styles/bootstrap-lite.css +1 -0
  30. package/styles/bootstrap-lite.scss +1 -0
  31. package/styles/bootstrap.css +1 -26
  32. package/styles/bootstrap.scss +1 -0
  33. package/styles/bootstrap4-lite.css +1 -0
  34. package/styles/bootstrap4-lite.scss +1 -0
  35. package/styles/bootstrap4.css +1 -26
  36. package/styles/bootstrap4.scss +1 -0
  37. package/styles/bootstrap5-dark-lite.css +1 -0
  38. package/styles/bootstrap5-dark-lite.scss +1 -0
  39. package/styles/bootstrap5-dark.css +1 -26
  40. package/styles/bootstrap5-dark.scss +1 -0
  41. package/styles/bootstrap5-lite.css +1 -0
  42. package/styles/bootstrap5-lite.scss +1 -0
  43. package/styles/bootstrap5.3-lite.css +1 -0
  44. package/styles/bootstrap5.3-lite.scss +1 -0
  45. package/styles/bootstrap5.3.css +1 -26
  46. package/styles/bootstrap5.3.scss +1 -0
  47. package/styles/bootstrap5.css +1 -26
  48. package/styles/bootstrap5.scss +1 -0
  49. package/styles/fabric-dark-lite.css +1 -0
  50. package/styles/fabric-dark-lite.scss +1 -0
  51. package/styles/fabric-dark.css +1 -0
  52. package/styles/fabric-dark.scss +1 -0
  53. package/styles/fabric-lite.css +1 -0
  54. package/styles/fabric-lite.scss +1 -0
  55. package/styles/fabric.css +1 -0
  56. package/styles/fabric.scss +1 -0
  57. package/styles/fluent-dark-lite.css +1 -0
  58. package/styles/fluent-dark-lite.scss +1 -0
  59. package/styles/fluent-dark.css +1 -26
  60. package/styles/fluent-dark.scss +1 -0
  61. package/styles/fluent-lite.css +1 -0
  62. package/styles/fluent-lite.scss +1 -0
  63. package/styles/fluent.css +1 -26
  64. package/styles/fluent.scss +1 -0
  65. package/styles/fluent2-lite.css +1 -0
  66. package/styles/fluent2-lite.scss +1 -0
  67. package/styles/fluent2.css +1 -26
  68. package/styles/fluent2.scss +1 -0
  69. package/styles/form-renderer/bds.css +1 -0
  70. package/styles/form-renderer/bds.scss +1 -0
  71. package/styles/form-renderer/bootstrap-dark.css +1 -0
  72. package/styles/form-renderer/bootstrap-dark.scss +1 -0
  73. package/styles/form-renderer/bootstrap.css +1 -0
  74. package/styles/form-renderer/bootstrap.scss +1 -0
  75. package/styles/form-renderer/bootstrap4.css +1 -0
  76. package/styles/form-renderer/bootstrap4.scss +1 -0
  77. package/styles/form-renderer/bootstrap5-dark.css +1 -0
  78. package/styles/form-renderer/bootstrap5-dark.scss +1 -0
  79. package/styles/form-renderer/bootstrap5.3.css +1 -0
  80. package/styles/form-renderer/bootstrap5.3.scss +1 -0
  81. package/styles/form-renderer/bootstrap5.css +1 -0
  82. package/styles/form-renderer/bootstrap5.scss +1 -0
  83. package/styles/form-renderer/fabric-dark.css +1 -0
  84. package/styles/form-renderer/fabric-dark.scss +1 -0
  85. package/styles/form-renderer/fabric.css +1 -0
  86. package/styles/form-renderer/fabric.scss +1 -0
  87. package/styles/form-renderer/fluent-dark.css +1 -0
  88. package/styles/form-renderer/fluent-dark.scss +1 -0
  89. package/styles/form-renderer/fluent.css +1 -0
  90. package/styles/form-renderer/fluent.scss +1 -0
  91. package/styles/form-renderer/fluent2.css +1 -0
  92. package/styles/form-renderer/fluent2.scss +1 -0
  93. package/styles/form-renderer/highcontrast-light.css +1 -0
  94. package/styles/form-renderer/highcontrast-light.scss +1 -0
  95. package/styles/form-renderer/highcontrast.css +1 -0
  96. package/styles/form-renderer/highcontrast.scss +1 -0
  97. package/styles/form-renderer/material-dark.css +1 -0
  98. package/styles/form-renderer/material-dark.scss +1 -0
  99. package/styles/form-renderer/material.css +1 -0
  100. package/styles/form-renderer/material.scss +1 -0
  101. package/styles/form-renderer/material3-dark.css +1 -0
  102. package/styles/form-renderer/material3-dark.scss +1 -0
  103. package/styles/form-renderer/material3.css +1 -0
  104. package/styles/form-renderer/material3.scss +1 -0
  105. package/styles/form-renderer/tailwind-dark.css +1 -0
  106. package/styles/form-renderer/tailwind-dark.scss +1 -0
  107. package/styles/form-renderer/tailwind.css +1 -0
  108. package/styles/form-renderer/tailwind.scss +1 -0
  109. package/styles/form-renderer/tailwind3.css +1 -0
  110. package/styles/form-renderer/tailwind3.scss +1 -0
  111. package/styles/highcontrast-light-lite.css +1 -0
  112. package/styles/highcontrast-light-lite.scss +1 -0
  113. package/styles/highcontrast-light.css +1 -0
  114. package/styles/highcontrast-light.scss +1 -0
  115. package/styles/highcontrast-lite.css +1 -0
  116. package/styles/highcontrast-lite.scss +1 -0
  117. package/styles/highcontrast.css +1 -0
  118. package/styles/highcontrast.scss +1 -0
  119. package/styles/material-dark-lite.css +1 -0
  120. package/styles/material-dark-lite.scss +1 -0
  121. package/styles/material-dark.css +1 -26
  122. package/styles/material-dark.scss +1 -0
  123. package/styles/material-lite.css +1 -0
  124. package/styles/material-lite.scss +1 -0
  125. package/styles/material.css +1 -26
  126. package/styles/material.scss +1 -0
  127. package/styles/material3-dark-lite.css +1 -0
  128. package/styles/material3-dark-lite.scss +1 -0
  129. package/styles/material3-dark.css +1 -26
  130. package/styles/material3-dark.scss +1 -0
  131. package/styles/material3-lite.css +1 -0
  132. package/styles/material3-lite.scss +1 -0
  133. package/styles/material3.css +1 -26
  134. package/styles/material3.scss +1 -0
  135. package/styles/tailwind-dark-lite.css +1 -0
  136. package/styles/tailwind-dark-lite.scss +1 -0
  137. package/styles/tailwind-dark.css +1 -26
  138. package/styles/tailwind-dark.scss +1 -0
  139. package/styles/tailwind-lite.css +1 -0
  140. package/styles/tailwind-lite.scss +1 -0
  141. package/styles/tailwind.css +1 -26
  142. package/styles/tailwind.scss +1 -0
  143. package/styles/tailwind3-lite.css +1 -0
  144. package/styles/tailwind3-lite.scss +1 -0
  145. package/styles/tailwind3.css +1 -26
  146. package/styles/tailwind3.scss +1 -0
  147. package/src/CheckboxGroup.d.ts +0 -12
  148. package/src/CheckboxGroup.js +0 -49
  149. package/src/ConditionalRuleEngine.d.ts +0 -295
  150. package/src/ConditionalRuleEngine.js +0 -566
  151. package/src/CustomTabComponent.d.ts +0 -13
  152. package/src/CustomTabComponent.js +0 -35
  153. package/src/DataGridComponent.d.ts +0 -28
  154. package/src/DataGridComponent.js +0 -147
  155. package/src/FormRenderer.d.ts +0 -84
  156. package/src/FormRenderer.js +0 -707
  157. package/src/FormValidator.d.ts +0 -479
  158. package/src/FormValidator.js +0 -579
  159. package/src/MinMaxRuleEngine.d.ts +0 -95
  160. package/src/MinMaxRuleEngine.js +0 -361
  161. package/src/StaticHtmlRenderer.d.ts +0 -8
  162. package/src/StaticHtmlRenderer.js +0 -21
  163. package/src/expressions/DependencyTracker.d.ts +0 -30
  164. package/src/expressions/DependencyTracker.js +0 -128
  165. package/src/expressions/ExpressionEngine.d.ts +0 -81
  166. package/src/expressions/ExpressionEngine.js +0 -503
  167. package/src/expressions/ExpressionParser.d.ts +0 -39
  168. package/src/expressions/ExpressionParser.js +0 -270
  169. package/src/json-converter.d.ts +0 -171
  170. package/src/json-converter.js +0 -1209
  171. package/src/parser.d.ts +0 -99
  172. package/src/parser.js +0 -753
  173. package/src/renderFormField.d.ts +0 -21
  174. package/src/renderFormField.js +0 -226
  175. package/src/types/FormSchema.d.ts +0 -211
  176. package/src/types/FormSchema.js +0 -1
  177. package/src/utils.js +0 -408
  178. package/styles/bootstrap5.3-dark.css +0 -26
  179. package/styles/fluent2-dark.css +0 -26
  180. package/styles/form-renderer.base.css +0 -499
  181. package/styles/tailwind3-dark.css +0 -10
@@ -1,361 +0,0 @@
1
- export class MinMaxRuleEngine {
2
- /**
3
- * Extract min/max constraints from minMaxRange array
4
- * Handles three cases:
5
- * 1. Direct values (enabled: false)
6
- * 2. Single field reference (enabled: true, 1 range)
7
- * 3. Multiple ranges (enabled: true, 2+ ranges) - takes UTMOST
8
- *
9
- * @param minMaxRange - Array of range configurations
10
- * @param formValues - Current form state values (id → value)
11
- * @param componentType - 'number' | 'date' | 'dateRange'
12
- * @returns Constraints object with appropriate keys
13
- */
14
- static getConstraints(minMaxRange, formValues, componentType = 'number') {
15
- // No ranges provided
16
- if (!minMaxRange || minMaxRange.length === 0) {
17
- return this.getEmptyConstraints(componentType);
18
- }
19
- // First, check for CASE 1: Direct values (enabled: false)
20
- const directValueRange = minMaxRange.find(range => range.enabled === false);
21
- if (directValueRange) {
22
- // Use direct values without field lookup
23
- const minValue = this.resolveValue(directValueRange.minValue, {});
24
- const maxValue = this.resolveValue(directValueRange.maxValue, {});
25
- if (componentType === 'date' || componentType === 'dateRange') {
26
- return {
27
- minValue: undefined,
28
- maxValue: undefined,
29
- minDate: minValue,
30
- maxDate: maxValue,
31
- minTime: undefined,
32
- maxTime: undefined
33
- };
34
- }
35
- if (componentType === 'time') {
36
- return {
37
- minValue: undefined,
38
- maxValue: undefined,
39
- minDate: undefined,
40
- maxDate: undefined,
41
- minTime: minValue,
42
- maxTime: maxValue
43
- };
44
- }
45
- return {
46
- minValue,
47
- maxValue,
48
- minDate: undefined,
49
- maxDate: undefined,
50
- minTime: undefined,
51
- maxTime: undefined
52
- };
53
- }
54
- // CASE 2 & 3: Field references (enabled: true)
55
- const enabledRanges = minMaxRange.filter(range => range.enabled === true);
56
- // No enabled ranges - return empty
57
- if (enabledRanges.length === 0) {
58
- return this.getEmptyConstraints(componentType);
59
- }
60
- // Extract resolved values from each enabled range
61
- const resolvedRanges = enabledRanges
62
- .map(range => ({
63
- min: this.resolveValue(range.minValue, formValues),
64
- max: this.resolveValue(range.maxValue, formValues)
65
- }))
66
- .filter(range => range.min !== undefined || range.max !== undefined);
67
- // No valid ranges
68
- if (resolvedRanges.length === 0) {
69
- return this.getEmptyConstraints(componentType);
70
- }
71
- // Combine multiple ranges using UTMOST (most permissive)
72
- const finalMin = this.getPermissiveMin(resolvedRanges, componentType);
73
- const finalMax = this.getPermissiveMax(resolvedRanges, componentType);
74
- // Return appropriate keys based on component type
75
- if (componentType === 'date' || componentType === 'dateRange') {
76
- return {
77
- minValue: undefined,
78
- maxValue: undefined,
79
- minDate: finalMin,
80
- maxDate: finalMax,
81
- minTime: undefined,
82
- maxTime: undefined
83
- };
84
- }
85
- if (componentType === 'time') {
86
- return {
87
- minValue: undefined,
88
- maxValue: undefined,
89
- minDate: undefined,
90
- maxDate: undefined,
91
- minTime: finalMin,
92
- maxTime: finalMax
93
- };
94
- }
95
- return {
96
- minValue: finalMin,
97
- maxValue: finalMax,
98
- minDate: undefined,
99
- maxDate: undefined,
100
- minTime: undefined,
101
- maxTime: undefined
102
- };
103
- }
104
- /**
105
- * Resolve a single value - either direct or field reference
106
- *
107
- * @param value - Direct value or field reference object
108
- * @param formValues - Form state values for field lookup
109
- * @returns Resolved value or undefined
110
- */
111
- static resolveValue(value, formValues) {
112
- // Direct value (number or string)
113
- if (typeof value === 'number') {
114
- return value;
115
- }
116
- if (typeof value === 'string') {
117
- return value;
118
- }
119
- // Field reference object
120
- if (value && typeof value === 'object' && value.field) {
121
- const fieldId = value.field;
122
- const fieldValue = formValues[fieldId];
123
- return fieldValue !== undefined ? fieldValue : undefined;
124
- }
125
- return undefined;
126
- }
127
- /**
128
- * Get the most permissive (widest) minimum value
129
- * For numbers: MIN of all mins
130
- * For dates: earliest date (MIN string comparison on ISO format)
131
- * For times: earliest time (MIN string comparison on 24-hour format)
132
- *
133
- * @param ranges - Array of {min, max} values
134
- * @param componentType - Type of component
135
- * @returns Most permissive minimum value
136
- */
137
- static getPermissiveMin(ranges, componentType) {
138
- if (ranges.length === 0)
139
- return undefined;
140
- if (componentType === 'date' || componentType === 'dateRange') {
141
- // For dates, find earliest (minimum) date
142
- return ranges.reduce((earliest, current) => {
143
- if (!current.min)
144
- return earliest;
145
- if (!earliest)
146
- return current.min;
147
- const earliestIso = this.convertToISO(earliest);
148
- const currentIso = this.convertToISO(current.min);
149
- return currentIso < earliestIso ? current.min : earliest;
150
- }, undefined);
151
- }
152
- if (componentType === 'time') {
153
- // For times, find earliest (minimum) time
154
- return ranges.reduce((earliest, current) => {
155
- if (!current.min)
156
- return earliest;
157
- if (!earliest)
158
- return current.min;
159
- const earliest24 = this.convertTimeTo24Hour(earliest);
160
- const current24 = this.convertTimeTo24Hour(current.min);
161
- return current24 < earliest24 ? current.min : earliest;
162
- }, undefined);
163
- }
164
- // For numbers, find minimum (skip undefined values)
165
- const minValues = ranges.map(r => r.min).filter(v => v !== undefined);
166
- return minValues.length > 0 ? Math.min(...minValues) : undefined;
167
- }
168
- /**
169
- * Get the most permissive (widest) maximum value
170
- * For numbers: MAX of all maxs
171
- * For dates: latest date (MAX string comparison on ISO format)
172
- * For times: latest time (MAX string comparison on 24-hour format)
173
- *
174
- * @param ranges - Array of {min, max} values
175
- * @param componentType - Type of component
176
- * @returns Most permissive maximum value
177
- */
178
- static getPermissiveMax(ranges, componentType) {
179
- if (ranges.length === 0)
180
- return undefined;
181
- if (componentType === 'date' || componentType === 'dateRange') {
182
- // For dates, find latest (maximum) date
183
- return ranges.reduce((latest, current) => {
184
- if (!current.max)
185
- return latest;
186
- if (!latest)
187
- return current.max;
188
- const latestIso = this.convertToISO(latest);
189
- const currentIso = this.convertToISO(current.max);
190
- return currentIso > latestIso ? current.max : latest;
191
- }, undefined);
192
- }
193
- if (componentType === 'time') {
194
- // For times, find latest (maximum) time
195
- return ranges.reduce((latest, current) => {
196
- if (!current.max)
197
- return latest;
198
- if (!latest)
199
- return current.max;
200
- const latest24 = this.convertTimeTo24Hour(latest);
201
- const current24 = this.convertTimeTo24Hour(current.max);
202
- return current24 > latest24 ? current.max : latest;
203
- }, undefined);
204
- }
205
- // For numbers, find maximum (skip undefined values)
206
- const maxValues = ranges.map(r => r.max).filter(v => v !== undefined);
207
- return maxValues.length > 0 ? Math.max(...maxValues) : undefined;
208
- }
209
- /**
210
- * Convert MM/DD/YYYY date format to ISO (YYYY-MM-DD) for comparison
211
- * Handles both formats gracefully
212
- *
213
- * @param dateString - Date in MM/DD/YYYY or ISO format
214
- * @returns ISO date string (YYYY-MM-DD)
215
- */
216
- static convertToISO(dateString) {
217
- if (!dateString)
218
- return '';
219
- // Already ISO format (YYYY-MM-DD)
220
- if (dateString.includes('-') && dateString.length === 10) {
221
- return dateString;
222
- }
223
- // MM/DD/YYYY format
224
- if (dateString.includes('/')) {
225
- const [month, day, year] = dateString.split('/');
226
- if (!month || !day || !year)
227
- return dateString;
228
- return `${year}-${month.padStart(2, '0')}-${day.padStart(2, '0')}`;
229
- }
230
- return dateString;
231
- }
232
- /**
233
- * Convert 12-hour time format to 24-hour format for comparison
234
- * Handles both 12-hour (hh:mm a) and 24-hour (HH:mm) formats
235
- *
236
- * @param timeString - Time in 12-hour (hh:mm a/p) or 24-hour (HH:mm) format
237
- * @returns 24-hour format time string (HH:mm)
238
- */
239
- static convertTimeTo24Hour(timeString) {
240
- if (!timeString)
241
- return '';
242
- // Check if it contains AM/PM (12-hour format)
243
- const isPM = /PM/i.test(timeString);
244
- const isAM = /AM/i.test(timeString);
245
- if (isAM || isPM) {
246
- // Extract time part (before AM/PM)
247
- const timePart = timeString.replace(/\s*(AM|PM)/i, '').trim();
248
- const [hours, minutes] = timePart.split(':');
249
- if (!hours || !minutes)
250
- return timeString;
251
- let hour = parseInt(hours, 10);
252
- if (isPM && hour !== 12) {
253
- hour += 12; // Convert PM hours (except 12) to 24-hour
254
- }
255
- else if (isAM && hour === 12) {
256
- hour = 0; // Convert 12 AM to 00:00
257
- }
258
- return `${String(hour).padStart(2, '0')}:${minutes}`;
259
- }
260
- // Already in 24-hour format or unknown format
261
- return timeString;
262
- }
263
- /**
264
- * Get empty constraints object based on component type
265
- */
266
- static getEmptyConstraints(componentType) {
267
- if (componentType === 'date' || componentType === 'dateRange') {
268
- return {
269
- minValue: undefined,
270
- maxValue: undefined,
271
- minDate: undefined,
272
- maxDate: undefined,
273
- minTime: undefined,
274
- maxTime: undefined
275
- };
276
- }
277
- if (componentType === 'time') {
278
- return {
279
- minValue: undefined,
280
- maxValue: undefined,
281
- minDate: undefined,
282
- maxDate: undefined,
283
- minTime: undefined,
284
- maxTime: undefined
285
- };
286
- }
287
- return {
288
- minValue: undefined,
289
- maxValue: undefined,
290
- minDate: undefined,
291
- maxDate: undefined,
292
- minTime: undefined,
293
- maxTime: undefined
294
- };
295
- }
296
- /**
297
- * Validate if a value passes all min/max constraints (optional)
298
- * Can be used for client-side validation before submission
299
- *
300
- * @param value - Value to validate
301
- * @param constraints - Constraints to check against
302
- * @param componentType - Type of component
303
- * @returns Validation result with error message if invalid
304
- */
305
- static validateValue(value, constraints, componentType) {
306
- if (value === undefined || value === null || value === '') {
307
- return { isValid: true }; // Empty values pass (required handled separately)
308
- }
309
- if (componentType === 'date' || componentType === 'dateRange') {
310
- if (constraints.minDate) {
311
- const minIso = this.convertToISO(constraints.minDate);
312
- const valueIso = this.convertToISO(value);
313
- if (valueIso < minIso) {
314
- return { isValid: false, error: `Date must be on or after ${constraints.minDate}` };
315
- }
316
- }
317
- if (constraints.maxDate) {
318
- const maxIso = this.convertToISO(constraints.maxDate);
319
- const valueIso = this.convertToISO(value);
320
- if (valueIso > maxIso) {
321
- return { isValid: false, error: `Date must be on or before ${constraints.maxDate}` };
322
- }
323
- }
324
- }
325
- else if (componentType === 'time') {
326
- if (constraints.minTime) {
327
- if (value < constraints.minTime) {
328
- return { isValid: false, error: `Time must be on or after ${constraints.minTime}` };
329
- }
330
- }
331
- if (constraints.maxTime) {
332
- if (value > constraints.maxTime) {
333
- return { isValid: false, error: `Time must be on or before ${constraints.maxTime}` };
334
- }
335
- }
336
- }
337
- else {
338
- // Number type
339
- const numValue = Number(value);
340
- if (constraints.minValue !== undefined) {
341
- const minNum = Number(constraints.minValue);
342
- if (numValue < minNum) {
343
- return {
344
- isValid: false,
345
- error: `Value must be at least ${constraints.minValue}`
346
- };
347
- }
348
- }
349
- if (constraints.maxValue !== undefined) {
350
- const maxNum = Number(constraints.maxValue);
351
- if (numValue > maxNum) {
352
- return {
353
- isValid: false,
354
- error: `Value must be at most ${constraints.maxValue}`
355
- };
356
- }
357
- }
358
- }
359
- return { isValid: true };
360
- }
361
- }
@@ -1,8 +0,0 @@
1
- import React from 'react';
2
- export interface StaticHtmlRendererProps {
3
- content: string;
4
- id?: string;
5
- enableHtmlSanitizer?: boolean;
6
- }
7
- export declare const StaticHtmlRenderer: React.FC<StaticHtmlRendererProps>;
8
- export default StaticHtmlRenderer;
@@ -1,21 +0,0 @@
1
- import React from 'react';
2
- import { SanitizeHtmlHelper } from '@syncfusion/ej2-base';
3
- export const StaticHtmlRenderer = ({ content, id, enableHtmlSanitizer }) => {
4
- const sanitizedHtml = React.useMemo(() => {
5
- try {
6
- if (enableHtmlSanitizer) {
7
- return SanitizeHtmlHelper.sanitize(content);
8
- }
9
- return content;
10
- }
11
- catch (error) {
12
- console.error('HTML sanitization error:', error);
13
- return '';
14
- }
15
- }, [content]);
16
- return React.createElement('div', {
17
- id,
18
- dangerouslySetInnerHTML: { __html: sanitizedHtml }
19
- });
20
- };
21
- export default StaticHtmlRenderer;
@@ -1,30 +0,0 @@
1
- /**
2
- * DependencyTracker - Extract and track field dependencies
3
- *
4
- * Analyzes expressions to find field references and build dependency graphs
5
- * Detects circular dependencies and calculates evaluation order
6
- *
7
- * @spec Expression_Engine.md
8
- */
9
- export declare class DependencyTracker {
10
- private escapedBracePattern;
11
- /**
12
- * Extract field names referenced in expression
13
- */
14
- extractFieldReferences(expression: string): string[];
15
- /**
16
- * Build dependency graph from multiple expressions
17
- */
18
- buildGraph(expressions: Record<string, string>): Record<string, string[]>;
19
- /**
20
- * Detect circular dependencies using DFS
21
- */
22
- detectCircularDependencies(graph: Record<string, string[]>): string[][];
23
- /**
24
- * Get topological sort order for evaluation
25
- */
26
- getTopologicalOrder(graph: Record<string, string[]>): string[];
27
- private isFunctionCall;
28
- private isOperator;
29
- private isKeyword;
30
- }
@@ -1,128 +0,0 @@
1
- /**
2
- * DependencyTracker - Extract and track field dependencies
3
- *
4
- * Analyzes expressions to find field references and build dependency graphs
5
- * Detects circular dependencies and calculates evaluation order
6
- *
7
- * @spec Expression_Engine.md
8
- */
9
- export class DependencyTracker {
10
- escapedBracePattern = /\\{.*?\\}/g;
11
- /**
12
- * Extract field names referenced in expression
13
- */
14
- extractFieldReferences(expression) {
15
- if (!expression)
16
- return [];
17
- const refs = new Set();
18
- let match;
19
- // Remove escaped braces first
20
- const cleanExpression = expression.replace(this.escapedBracePattern, '');
21
- // Extract field references from {field} syntax
22
- const fieldRefPattern = /\{([^{}]+)\}/g;
23
- while ((match = fieldRefPattern.exec(cleanExpression)) !== null) {
24
- const ref = match[1].trim();
25
- // Skip if it's a function call or operator
26
- if (!this.isFunctionCall(ref) && !this.isOperator(ref)) {
27
- // Extract field name from nested paths
28
- const fieldName = ref.split(/[.\[\]]/)[0].trim();
29
- if (fieldName && !this.isKeyword(fieldName)) {
30
- refs.add(fieldName);
31
- }
32
- }
33
- }
34
- // Extract identifiers from ${...} math expressions
35
- const mathExprPattern = /\$\{([^}]+)\}/g;
36
- while ((match = mathExprPattern.exec(cleanExpression)) !== null) {
37
- const mathExpr = match[1];
38
- // Extract all identifiers from the math expression
39
- // Match word boundaries followed by identifier characters
40
- // But skip if followed by ( or . (those are function calls or property access)
41
- const identPattern = /\b([a-zA-Z_][a-zA-Z0-9_]*)\b(?!\s*[(\.])/g;
42
- let idMatch;
43
- while ((idMatch = identPattern.exec(mathExpr)) !== null) {
44
- const identifier = idMatch[1];
45
- // Skip keywords and constants
46
- if (!this.isKeyword(identifier) && identifier !== 'Math') {
47
- refs.add(identifier);
48
- }
49
- }
50
- }
51
- return Array.from(refs);
52
- }
53
- /**
54
- * Build dependency graph from multiple expressions
55
- */
56
- buildGraph(expressions) {
57
- const graph = {};
58
- for (const [fieldName, expression] of Object.entries(expressions)) {
59
- const deps = this.extractFieldReferences(expression);
60
- graph[fieldName] = deps;
61
- }
62
- return graph;
63
- }
64
- /**
65
- * Detect circular dependencies using DFS
66
- */
67
- detectCircularDependencies(graph) {
68
- const visited = new Set();
69
- const recursionStack = new Set();
70
- const cycles = [];
71
- const visit = (node, path) => {
72
- visited.add(node);
73
- recursionStack.add(node);
74
- path.push(node);
75
- const deps = graph[node] || [];
76
- for (const dep of deps) {
77
- if (!visited.has(dep)) {
78
- visit(dep, [...path]);
79
- }
80
- else if (recursionStack.has(dep)) {
81
- const cycleStart = path.indexOf(dep);
82
- cycles.push([...path.slice(cycleStart), dep]);
83
- }
84
- }
85
- recursionStack.delete(node);
86
- };
87
- for (const node of Object.keys(graph)) {
88
- if (!visited.has(node)) {
89
- visit(node, []);
90
- }
91
- }
92
- return cycles;
93
- }
94
- /**
95
- * Get topological sort order for evaluation
96
- */
97
- getTopologicalOrder(graph) {
98
- const visited = new Set();
99
- const order = [];
100
- const visit = (node) => {
101
- if (visited.has(node))
102
- return;
103
- visited.add(node);
104
- const deps = graph[node] || [];
105
- for (const dep of deps) {
106
- if (graph[dep]) {
107
- visit(dep);
108
- }
109
- }
110
- order.push(node);
111
- };
112
- for (const node of Object.keys(graph)) {
113
- visit(node);
114
- }
115
- return order;
116
- }
117
- // Private helpers
118
- isFunctionCall(ref) {
119
- return /^\w+\s*\(/.test(ref);
120
- }
121
- isOperator(ref) {
122
- return /^[+\-*/()=!<>&|]/.test(ref);
123
- }
124
- isKeyword(name) {
125
- const keywords = ['PI', 'TRUE', 'FALSE', 'NULL', 'UNDEFINED', 'and', 'or', 'in'];
126
- return keywords.includes(name.toUpperCase());
127
- }
128
- }
@@ -1,81 +0,0 @@
1
- export type FormValueType = string | number | boolean | Date | null | undefined | any[];
2
- export interface EvaluationOptions {
3
- timeout?: number;
4
- maxDepth?: number;
5
- locale?: string;
6
- currencyCode?: string;
7
- throwOnError?: boolean;
8
- }
9
- export type DependencyGraph = Record<string, string[]>;
10
- /**
11
- * ExpressionEngine - Core evaluation engine
12
- *
13
- * Safely evaluates user-defined expressions against form state
14
- * Supports field references, math operations, functions, and conditionals
15
- *
16
- * @spec Expression_Engine.md
17
- */
18
- export declare class ExpressionEngine {
19
- private parser;
20
- private dependencyTracker;
21
- private evaluationCache;
22
- private compiledFunctions;
23
- constructor();
24
- /**
25
- * Evaluate expression against form values
26
- */
27
- evaluate(expression: string, formValues: Record<string, FormValueType>, options?: EvaluationOptions): any;
28
- /**
29
- * Extract field names referenced in expression
30
- */
31
- extractDependencies(expression: string): string[];
32
- /**
33
- * Build dependency graph for all expressions
34
- */
35
- buildDependencyGraph(components: any[]): DependencyGraph;
36
- /**
37
- * Detect circular dependencies
38
- */
39
- detectCircularDependencies(graph: DependencyGraph): string[][];
40
- /**
41
- * Get topological order for evaluation
42
- */
43
- getTopologicalOrder(graph: DependencyGraph): string[];
44
- /**
45
- * Clear internal caches
46
- */
47
- clearCache(): void;
48
- private getCacheKey;
49
- private buildContext;
50
- }
51
- /**
52
- * ExpressionValidator - Validates expressions before runtime
53
- *
54
- * Checks syntax, validates field references, and detects circular dependencies
55
- *
56
- * @spec Expression_Engine.md
57
- */
58
- export declare class ExpressionValidator {
59
- private supportedFunctions;
60
- private keywords;
61
- /**
62
- * Validate expression against available fields
63
- */
64
- validate(expression: string, availableFields: string[] | any[]): ValidationError[];
65
- /**
66
- * Validate field operations - check for invalid operators on string/date types
67
- */
68
- private validateFieldOperations;
69
- private validateSyntax;
70
- private validateFieldReferences;
71
- private validateFunctionCalls;
72
- private isFunctionCall;
73
- private isMathExpression;
74
- }
75
- export interface ValidationError {
76
- type: 'SyntaxError' | 'UndefinedField' | 'InvalidFunction' | 'CircularDependency' | 'InvalidOperation';
77
- message: string;
78
- field?: string;
79
- line?: number;
80
- column?: number;
81
- }