@syncfusion/ej2-form-renderer 34.2.2

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 (214) hide show
  1. package/README.md +60 -0
  2. package/common.d.ts +4 -0
  3. package/common.js +4 -0
  4. package/dist/ej2-form-renderer.umd.min.js +11 -0
  5. package/dist/ej2-form-renderer.umd.min.js.map +1 -0
  6. package/dist/es6/ej2-form-renderer.es2015.js +6787 -0
  7. package/dist/es6/ej2-form-renderer.es2015.js.map +1 -0
  8. package/dist/es6/ej2-form-renderer.es5.js +7055 -0
  9. package/dist/es6/ej2-form-renderer.es5.js.map +1 -0
  10. package/dist/global/ej2-form-renderer.min.js +11 -0
  11. package/dist/global/ej2-form-renderer.min.js.map +1 -0
  12. package/dist/global/index.d.ts +14 -0
  13. package/form-renderer.d.ts +4 -0
  14. package/form-renderer.js +4 -0
  15. package/index.d.ts +4 -0
  16. package/index.js +4 -0
  17. package/license +10 -0
  18. package/package.json +41 -0
  19. package/src/common/checkbox-group.d.ts +55 -0
  20. package/src/common/checkbox-group.js +241 -0
  21. package/src/common/conditional-rule-engine.d.ts +241 -0
  22. package/src/common/conditional-rule-engine.js +505 -0
  23. package/src/common/custom-validation-engine.d.ts +57 -0
  24. package/src/common/custom-validation-engine.js +152 -0
  25. package/src/common/datagrid-component.d.ts +156 -0
  26. package/src/common/datagrid-component.js +410 -0
  27. package/src/common/expressions/dependency-tracker.d.ts +29 -0
  28. package/src/common/expressions/dependency-tracker.js +137 -0
  29. package/src/common/expressions/expression-engine.d.ts +94 -0
  30. package/src/common/expressions/expression-engine.js +514 -0
  31. package/src/common/expressions/expression-parser.d.ts +40 -0
  32. package/src/common/expressions/expression-parser.js +270 -0
  33. package/src/common/expressions/grid-expressions.d.ts +24 -0
  34. package/src/common/expressions/grid-expressions.js +92 -0
  35. package/src/common/expressions/index.d.ts +4 -0
  36. package/src/common/expressions/index.js +4 -0
  37. package/src/common/index.d.ts +10 -0
  38. package/src/common/index.js +10 -0
  39. package/src/common/json-converter.d.ts +945 -0
  40. package/src/common/json-converter.js +1110 -0
  41. package/src/common/minmax-rule-engine.d.ts +105 -0
  42. package/src/common/minmax-rule-engine.js +380 -0
  43. package/src/common/option-fetcher.d.ts +30 -0
  44. package/src/common/option-fetcher.js +139 -0
  45. package/src/common/parser.d.ts +98 -0
  46. package/src/common/parser.js +788 -0
  47. package/src/common/static-html-renderer.d.ts +45 -0
  48. package/src/common/static-html-renderer.js +77 -0
  49. package/src/common/utils.d.ts +116 -0
  50. package/src/common/utils.js +484 -0
  51. package/src/form-renderer/form-renderer-model.d.ts +65 -0
  52. package/src/form-renderer/form-renderer.d.ts +425 -0
  53. package/src/form-renderer/form-renderer.js +2277 -0
  54. package/src/form-renderer/index.d.ts +6 -0
  55. package/src/form-renderer/index.js +5 -0
  56. package/src/form-renderer/render-form-field.d.ts +31 -0
  57. package/src/form-renderer/render-form-field.js +816 -0
  58. package/src/form-renderer/types/form-schema.d.ts +452 -0
  59. package/src/form-renderer/types/form-schema.js +32 -0
  60. package/src/global.js +1 -0
  61. package/src/index.d.ts +4 -0
  62. package/src/index.js +4 -0
  63. package/styles/bds-lite.css +599 -0
  64. package/styles/bds-lite.scss +2 -0
  65. package/styles/bds.css +599 -0
  66. package/styles/bds.scss +2 -0
  67. package/styles/bootstrap-dark-lite.css +608 -0
  68. package/styles/bootstrap-dark-lite.scss +2 -0
  69. package/styles/bootstrap-dark.css +608 -0
  70. package/styles/bootstrap-dark.scss +2 -0
  71. package/styles/bootstrap-lite.css +595 -0
  72. package/styles/bootstrap-lite.scss +2 -0
  73. package/styles/bootstrap.css +595 -0
  74. package/styles/bootstrap.scss +2 -0
  75. package/styles/bootstrap4-lite.css +595 -0
  76. package/styles/bootstrap4-lite.scss +2 -0
  77. package/styles/bootstrap4.css +595 -0
  78. package/styles/bootstrap4.scss +2 -0
  79. package/styles/bootstrap5-dark-lite.css +595 -0
  80. package/styles/bootstrap5-dark-lite.scss +2 -0
  81. package/styles/bootstrap5-dark.css +595 -0
  82. package/styles/bootstrap5-dark.scss +2 -0
  83. package/styles/bootstrap5-lite.css +595 -0
  84. package/styles/bootstrap5-lite.scss +2 -0
  85. package/styles/bootstrap5.3-lite.css +679 -0
  86. package/styles/bootstrap5.3-lite.scss +2 -0
  87. package/styles/bootstrap5.3.css +679 -0
  88. package/styles/bootstrap5.3.scss +2 -0
  89. package/styles/bootstrap5.css +595 -0
  90. package/styles/bootstrap5.scss +2 -0
  91. package/styles/fabric-dark-lite.css +608 -0
  92. package/styles/fabric-dark-lite.scss +2 -0
  93. package/styles/fabric-dark.css +608 -0
  94. package/styles/fabric-dark.scss +2 -0
  95. package/styles/fabric-lite.css +595 -0
  96. package/styles/fabric-lite.scss +2 -0
  97. package/styles/fabric.css +595 -0
  98. package/styles/fabric.scss +2 -0
  99. package/styles/fluent-dark-lite.css +595 -0
  100. package/styles/fluent-dark-lite.scss +2 -0
  101. package/styles/fluent-dark.css +595 -0
  102. package/styles/fluent-dark.scss +2 -0
  103. package/styles/fluent-lite.css +595 -0
  104. package/styles/fluent-lite.scss +2 -0
  105. package/styles/fluent.css +595 -0
  106. package/styles/fluent.scss +2 -0
  107. package/styles/fluent2-lite.css +681 -0
  108. package/styles/fluent2-lite.scss +2 -0
  109. package/styles/fluent2.css +681 -0
  110. package/styles/fluent2.scss +2 -0
  111. package/styles/form-renderer/_all.scss +2 -0
  112. package/styles/form-renderer/_bds-definition.scss +8 -0
  113. package/styles/form-renderer/_bootstrap-dark-definition.scss +8 -0
  114. package/styles/form-renderer/_bootstrap-definition.scss +8 -0
  115. package/styles/form-renderer/_bootstrap4-definition.scss +8 -0
  116. package/styles/form-renderer/_bootstrap5-dark-definition.scss +8 -0
  117. package/styles/form-renderer/_bootstrap5-definition.scss +8 -0
  118. package/styles/form-renderer/_bootstrap5.3-definition.scss +8 -0
  119. package/styles/form-renderer/_fabric-dark-definition.scss +8 -0
  120. package/styles/form-renderer/_fabric-definition.scss +8 -0
  121. package/styles/form-renderer/_fluent-dark-definition.scss +8 -0
  122. package/styles/form-renderer/_fluent-definition.scss +8 -0
  123. package/styles/form-renderer/_fluent2-definition.scss +8 -0
  124. package/styles/form-renderer/_highcontrast-definition.scss +8 -0
  125. package/styles/form-renderer/_highcontrast-light-definition.scss +8 -0
  126. package/styles/form-renderer/_layout.scss +480 -0
  127. package/styles/form-renderer/_material-dark-definition.scss +8 -0
  128. package/styles/form-renderer/_material-definition.scss +8 -0
  129. package/styles/form-renderer/_material3-dark-definition.scss +8 -0
  130. package/styles/form-renderer/_material3-definition.scss +8 -0
  131. package/styles/form-renderer/_mixin.scss +26 -0
  132. package/styles/form-renderer/_tailwind-dark-definition.scss +8 -0
  133. package/styles/form-renderer/_tailwind-definition.scss +8 -0
  134. package/styles/form-renderer/_tailwind3-definition.scss +8 -0
  135. package/styles/form-renderer/_theme.scss +69 -0
  136. package/styles/form-renderer/_variables.scss +2 -0
  137. package/styles/form-renderer/bds.css +599 -0
  138. package/styles/form-renderer/bds.scss +2 -0
  139. package/styles/form-renderer/bootstrap-dark.css +608 -0
  140. package/styles/form-renderer/bootstrap-dark.scss +2 -0
  141. package/styles/form-renderer/bootstrap.css +595 -0
  142. package/styles/form-renderer/bootstrap.scss +2 -0
  143. package/styles/form-renderer/bootstrap4.css +595 -0
  144. package/styles/form-renderer/bootstrap4.scss +2 -0
  145. package/styles/form-renderer/bootstrap5-dark.css +595 -0
  146. package/styles/form-renderer/bootstrap5-dark.scss +2 -0
  147. package/styles/form-renderer/bootstrap5.3.css +679 -0
  148. package/styles/form-renderer/bootstrap5.3.scss +2 -0
  149. package/styles/form-renderer/bootstrap5.css +595 -0
  150. package/styles/form-renderer/bootstrap5.scss +2 -0
  151. package/styles/form-renderer/fabric-dark.css +608 -0
  152. package/styles/form-renderer/fabric-dark.scss +2 -0
  153. package/styles/form-renderer/fabric.css +595 -0
  154. package/styles/form-renderer/fabric.scss +2 -0
  155. package/styles/form-renderer/fluent-dark.css +595 -0
  156. package/styles/form-renderer/fluent-dark.scss +2 -0
  157. package/styles/form-renderer/fluent.css +595 -0
  158. package/styles/form-renderer/fluent.scss +2 -0
  159. package/styles/form-renderer/fluent2.css +681 -0
  160. package/styles/form-renderer/fluent2.scss +2 -0
  161. package/styles/form-renderer/highcontrast-light.css +595 -0
  162. package/styles/form-renderer/highcontrast-light.scss +2 -0
  163. package/styles/form-renderer/highcontrast.css +608 -0
  164. package/styles/form-renderer/highcontrast.scss +2 -0
  165. package/styles/form-renderer/material-dark.css +608 -0
  166. package/styles/form-renderer/material-dark.scss +2 -0
  167. package/styles/form-renderer/material.css +595 -0
  168. package/styles/form-renderer/material.scss +2 -0
  169. package/styles/form-renderer/material3-dark.css +677 -0
  170. package/styles/form-renderer/material3-dark.scss +2 -0
  171. package/styles/form-renderer/material3.css +679 -0
  172. package/styles/form-renderer/material3.scss +2 -0
  173. package/styles/form-renderer/tailwind-dark.css +595 -0
  174. package/styles/form-renderer/tailwind-dark.scss +2 -0
  175. package/styles/form-renderer/tailwind.css +595 -0
  176. package/styles/form-renderer/tailwind.scss +2 -0
  177. package/styles/form-renderer/tailwind3.css +669 -0
  178. package/styles/form-renderer/tailwind3.scss +2 -0
  179. package/styles/highcontrast-light-lite.css +595 -0
  180. package/styles/highcontrast-light-lite.scss +2 -0
  181. package/styles/highcontrast-light.css +595 -0
  182. package/styles/highcontrast-light.scss +2 -0
  183. package/styles/highcontrast-lite.css +608 -0
  184. package/styles/highcontrast-lite.scss +2 -0
  185. package/styles/highcontrast.css +608 -0
  186. package/styles/highcontrast.scss +2 -0
  187. package/styles/material-dark-lite.css +608 -0
  188. package/styles/material-dark-lite.scss +2 -0
  189. package/styles/material-dark.css +608 -0
  190. package/styles/material-dark.scss +2 -0
  191. package/styles/material-lite.css +595 -0
  192. package/styles/material-lite.scss +2 -0
  193. package/styles/material.css +595 -0
  194. package/styles/material.scss +2 -0
  195. package/styles/material3-dark-lite.css +677 -0
  196. package/styles/material3-dark-lite.scss +2 -0
  197. package/styles/material3-dark.css +677 -0
  198. package/styles/material3-dark.scss +2 -0
  199. package/styles/material3-lite.css +679 -0
  200. package/styles/material3-lite.scss +2 -0
  201. package/styles/material3.css +679 -0
  202. package/styles/material3.scss +2 -0
  203. package/styles/tailwind-dark-lite.css +595 -0
  204. package/styles/tailwind-dark-lite.scss +2 -0
  205. package/styles/tailwind-dark.css +595 -0
  206. package/styles/tailwind-dark.scss +2 -0
  207. package/styles/tailwind-lite.css +595 -0
  208. package/styles/tailwind-lite.scss +2 -0
  209. package/styles/tailwind.css +595 -0
  210. package/styles/tailwind.scss +2 -0
  211. package/styles/tailwind3-lite.css +669 -0
  212. package/styles/tailwind3-lite.scss +2 -0
  213. package/styles/tailwind3.css +669 -0
  214. package/styles/tailwind3.scss +2 -0
@@ -0,0 +1,1110 @@
1
+ var __assign = (this && this.__assign) || function () {
2
+ __assign = Object.assign || function(t) {
3
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
4
+ s = arguments[i];
5
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
+ t[p] = s[p];
7
+ }
8
+ return t;
9
+ };
10
+ return __assign.apply(this, arguments);
11
+ };
12
+ import { sanitizeId } from './utils';
13
+ /**
14
+ * @private
15
+ */
16
+ export var generateId = function (type) {
17
+ var timestamp = Date.now();
18
+ var random = Math.floor(Math.random() * 1000);
19
+ return type + "_" + timestamp + "_" + random;
20
+ };
21
+ /**
22
+ * @private
23
+ */
24
+ export var generateName = function (type) {
25
+ var random = Math.floor(Math.random() * 1000);
26
+ return type + "_" + random;
27
+ };
28
+ /**
29
+ * @private
30
+ */
31
+ export function labelToFieldKey(label, fallbackId) {
32
+ if (!label || label.trim() === '') {
33
+ return fallbackId || 'field';
34
+ }
35
+ // Remove special characters, keep letters, numbers, and spaces
36
+ var cleaned = label
37
+ .replace(/[^\w\s]/g, '') // Remove special chars
38
+ .trim();
39
+ if (cleaned === '') {
40
+ return fallbackId || 'field';
41
+ }
42
+ // Split by spaces/underscores and convert to camelCase
43
+ var words = cleaned.split(/[\s_]+/);
44
+ if (words.length === 0) {
45
+ return fallbackId || 'field';
46
+ }
47
+ // First word lowercase, rest title case
48
+ var camelCase = words
49
+ .map(function (word, index) {
50
+ if (index === 0) {
51
+ return word.toLowerCase();
52
+ }
53
+ return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
54
+ })
55
+ .join('');
56
+ return camelCase || fallbackId || 'field';
57
+ }
58
+ /**
59
+ * @private
60
+ */
61
+ export function makeUniqueFieldKey(baseKey, existingKeys, originalId) {
62
+ if (!existingKeys.has(baseKey)) {
63
+ return baseKey;
64
+ }
65
+ // Try with original ID suffix first
66
+ if (originalId) {
67
+ var withId = baseKey + "_" + originalId.split('_').pop();
68
+ if (!existingKeys.has(withId)) {
69
+ return withId;
70
+ }
71
+ }
72
+ // Fall back to numeric suffix
73
+ var counter = 2;
74
+ while (existingKeys.has("" + baseKey + counter)) {
75
+ counter++;
76
+ }
77
+ return "" + baseKey + counter;
78
+ }
79
+ /**
80
+ * @private
81
+ */
82
+ export var UI_TYPE_TO_SEMANTIC_TYPE = {
83
+ // String types
84
+ 'textbox': { type: 'string' },
85
+ 'textarea': { type: 'string' },
86
+ 'email': { type: 'string', format: 'email' },
87
+ 'url': { type: 'string', format: 'url' },
88
+ 'phone': { type: 'string' },
89
+ 'password': { type: 'string' },
90
+ 'inputMask': { type: 'string' },
91
+ // Numeric types
92
+ 'number': { type: 'number' },
93
+ 'rangeSlider': { type: 'number' },
94
+ 'rating': { type: 'number' },
95
+ // Boolean types
96
+ 'checkbox': { type: 'boolean' },
97
+ 'switch': { type: 'boolean' },
98
+ // Date/Time types
99
+ 'date': { type: 'string', format: 'date' },
100
+ 'dateTime': { type: 'string', format: 'date-time' },
101
+ 'time': { type: 'string', format: 'time' },
102
+ 'dateRange': { type: 'string', format: 'date' },
103
+ // Array types
104
+ 'multiselect': { type: 'array' },
105
+ 'checkboxGroup': { type: 'array' },
106
+ // Single-value selection (stored as string)
107
+ 'dropdown': { type: 'string' },
108
+ 'radio': { type: 'string' },
109
+ 'splitButton': { type: 'string' },
110
+ // Special types (excluded from data schema)
111
+ 'button': { type: 'button' },
112
+ 'message': { type: 'message' },
113
+ 'signature': { type: 'sign' },
114
+ 'imageEditor': { type: 'image' },
115
+ 'fileUpload': { type: 'file' },
116
+ 'colorPicker': { type: 'color' },
117
+ 'dataGrid': { type: 'grid' },
118
+ // Layout types (excluded from data schema)
119
+ 'staticHtml': { type: 'string' },
120
+ 'table': null,
121
+ 'panel': null,
122
+ 'tabs': null,
123
+ 'card': null
124
+ };
125
+ /**
126
+ * @private
127
+ */
128
+ function stripConfiguredFlag(properties) {
129
+ var out = {};
130
+ var keys = Object.keys(properties || {});
131
+ for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
132
+ var key = keys_1[_i];
133
+ var val = properties[key];
134
+ var copy = __assign({}, val);
135
+ if (copy && copy._configured !== undefined) {
136
+ delete copy._configured;
137
+ }
138
+ out[key] = copy;
139
+ }
140
+ return out;
141
+ }
142
+ /**
143
+ * @private
144
+ */
145
+ function cleanConditionRules(condition, validFieldIds) {
146
+ if (!condition || !condition.rules || !Array.isArray(condition.rules)) {
147
+ return undefined;
148
+ }
149
+ var cleanedRules = condition.rules
150
+ .map(function (rule) {
151
+ // If rule has nested rules (group), recursively clean
152
+ if (rule.rules && Array.isArray(rule.rules)) {
153
+ return cleanConditionRules(rule, validFieldIds);
154
+ }
155
+ // If rule references non-existent field, exclude it
156
+ if (rule.field && !validFieldIds.has(rule.field)) {
157
+ return null;
158
+ }
159
+ return rule;
160
+ })
161
+ .filter(function (rule) { return rule !== null && rule !== undefined; });
162
+ // If no rules remain, return undefined
163
+ if (cleanedRules.length === 0) {
164
+ return undefined;
165
+ }
166
+ return __assign({}, condition, { rules: cleanedRules });
167
+ }
168
+ /**
169
+ * @private
170
+ */
171
+ function getAllComponentIds(components) {
172
+ var ids = new Set();
173
+ var stack = components.slice();
174
+ while (stack.length) {
175
+ var comp = stack.pop();
176
+ ids.add(comp.id);
177
+ if (comp.children)
178
+ stack.push.apply(stack, comp.children);
179
+ if (comp.tabItems) {
180
+ comp.tabItems.forEach(function (tab) {
181
+ if (tab.content)
182
+ stack.push.apply(stack, tab.content);
183
+ });
184
+ }
185
+ if (comp.tableCells) {
186
+ comp.tableCells.forEach(function (row) {
187
+ row.forEach(function (cell) { return stack.push.apply(stack, cell); });
188
+ });
189
+ }
190
+ }
191
+ return ids;
192
+ }
193
+ /**
194
+ * @private
195
+ */
196
+ export function splitSchema(heartSchema) {
197
+ var dataFields = {};
198
+ var uiFields = {};
199
+ var layout = [];
200
+ var usedFieldKeys = new Set(); // Track unique field keys
201
+ var seenComponentIds = new Set(); // Track component IDs to prevent duplicates
202
+ // ✅ Get all valid field IDs for condition validation
203
+ var validFieldIds = getAllComponentIds(heartSchema.components);
204
+ // Stack for iterative traversal (avoid recursion)
205
+ var stack = heartSchema.components.map(function (c) { return ({
206
+ component: c,
207
+ layoutParent: layout
208
+ }); });
209
+ var _loop_1 = function () {
210
+ // Use shift() instead of pop() to maintain order (FIFO instead of LIFO)
211
+ var _a = stack.shift(), component = _a.component, layoutParent = _a.layoutParent;
212
+ // ✅ Clean conditions before processing
213
+ if (component.conditions) {
214
+ var cleanedConditions = {};
215
+ var hasValidConditions = false;
216
+ if (component.conditions.visibleWhen) {
217
+ var cleaned = cleanConditionRules(component.conditions.visibleWhen, validFieldIds);
218
+ if (cleaned) {
219
+ cleanedConditions.visibleWhen = cleaned;
220
+ hasValidConditions = true;
221
+ }
222
+ }
223
+ if (component.conditions.hideWhen) {
224
+ var cleaned = cleanConditionRules(component.conditions.hideWhen, validFieldIds);
225
+ if (cleaned) {
226
+ cleanedConditions.hideWhen = cleaned;
227
+ hasValidConditions = true;
228
+ }
229
+ }
230
+ if (component.conditions.readOnlyWhen) {
231
+ var cleaned = cleanConditionRules(component.conditions.readOnlyWhen, validFieldIds);
232
+ if (cleaned) {
233
+ cleanedConditions.readOnlyWhen = cleaned;
234
+ hasValidConditions = true;
235
+ }
236
+ }
237
+ if (component.conditions.disabledWhen) {
238
+ var cleaned = cleanConditionRules(component.conditions.disabledWhen, validFieldIds);
239
+ if (cleaned) {
240
+ cleanedConditions.disabledWhen = cleaned;
241
+ hasValidConditions = true;
242
+ }
243
+ }
244
+ if (component.conditions.requiredWhen) {
245
+ var cleaned = cleanConditionRules(component.conditions.requiredWhen, validFieldIds);
246
+ if (cleaned) {
247
+ cleanedConditions.requiredWhen = cleaned;
248
+ hasValidConditions = true;
249
+ }
250
+ }
251
+ if (component.conditions.setValueWhen) {
252
+ var cleaned = cleanConditionRules(component.conditions.setValueWhen.condition, validFieldIds);
253
+ if (cleaned && component.conditions.setValueWhen.value !== undefined && component.conditions.setValueWhen.value !== '') {
254
+ cleanedConditions.setValueWhen = {
255
+ condition: cleaned,
256
+ value: component.conditions.setValueWhen.value
257
+ };
258
+ hasValidConditions = true;
259
+ }
260
+ }
261
+ if (component.conditions && component.conditions.choiceBasedField) {
262
+ var rule = component.conditions.choiceBasedField;
263
+ // Validate that primary field exists
264
+ if (rule.primaryFieldId && validFieldIds.has(rule.primaryFieldId)) {
265
+ cleanedConditions.choiceBasedField = rule;
266
+ hasValidConditions = true;
267
+ }
268
+ }
269
+ if (component.conditions.conditionalData && Array.isArray(component.conditions.conditionalData)) {
270
+ var cleanedDataRules = component.conditions.conditionalData
271
+ .map(function (rule) {
272
+ var cleaned = cleanConditionRules(rule.condition, validFieldIds);
273
+ if (cleaned && rule.dataSource) {
274
+ return {
275
+ condition: cleaned,
276
+ dataSource: rule.dataSource,
277
+ columns: rule.columns,
278
+ includeColumns: rule.includeColumns
279
+ };
280
+ }
281
+ return null;
282
+ })
283
+ .filter(function (rule) { return rule !== null && rule !== undefined; });
284
+ if (cleanedDataRules.length > 0) {
285
+ cleanedConditions.conditionalData = cleanedDataRules;
286
+ hasValidConditions = true;
287
+ }
288
+ }
289
+ // Update component conditions (or remove if empty)
290
+ component.conditions = hasValidConditions ? cleanedConditions : undefined;
291
+ }
292
+ // Get semantic type mapping (may be null for presentation-only widgets)
293
+ var semanticType = UI_TYPE_TO_SEMANTIC_TYPE[component.type];
294
+ // Handle layout containers
295
+ if (component.type === 'table') {
296
+ var safeId = sanitizeId(component.id, generateId(semanticType.type));
297
+ var tableNode_1 = __assign({ type: 'table', id: safeId, name: component.name, label: component.label, cssClass: component.cssClass, hideBorders: component.hideBorders, rows: (component.tableCells && component.tableCells.length) || 0, cols: (component.tableCells && component.tableCells[0] && component.tableCells[0].length) || 0, cells: [], columnWidths: component.columnWidths }, (component.conditions ? { conditions: component.conditions } : {}));
298
+ // Process table cells
299
+ if (component.tableCells) {
300
+ component.tableCells.forEach(function (row, rowIndex) {
301
+ var cellRow = [];
302
+ row.forEach(function (cellComponents, colIndex) {
303
+ var cellChildren = [];
304
+ // Reverse children and use unshift() to maintain order with depth-first processing
305
+ cellComponents.slice().reverse().forEach(function (comp) {
306
+ stack.unshift({ component: comp, layoutParent: cellChildren });
307
+ });
308
+ cellRow.push({ row: rowIndex, col: colIndex, children: cellChildren });
309
+ });
310
+ tableNode_1.cells.push(cellRow);
311
+ });
312
+ }
313
+ layoutParent.push(tableNode_1);
314
+ return "continue";
315
+ }
316
+ if (component.type === 'panel') {
317
+ var safeId = sanitizeId(component.id, generateId(semanticType.type));
318
+ var panelNode_1 = __assign({ type: 'panel', id: safeId, name: component.name, label: component.label, cssClass: component.cssClass, hideBorders: component.hideBorders, hideLabel: component.hideLabel, children: [] }, (component.conditions ? { conditions: component.conditions } : {}));
319
+ // Process panel children
320
+ // Reverse children and use unshift() to maintain order with depth-first processing
321
+ (component.children || []).slice().reverse().forEach(function (child) {
322
+ stack.unshift({ component: child, layoutParent: panelNode_1.children });
323
+ });
324
+ layoutParent.push(panelNode_1);
325
+ return "continue";
326
+ }
327
+ if (component.type === 'tabs') {
328
+ var safeId = sanitizeId(component.id, generateId(semanticType.type));
329
+ var tabsNode_1 = __assign({ type: 'tabs', name: component.name, id: safeId, label: component.label, cssClass: component.cssClass, tabOptions: component.tabOptions, tabs: [] }, (component.conditions ? { conditions: component.conditions } : {}));
330
+ // Process tabs
331
+ if (component.tabItems) {
332
+ component.tabItems.forEach(function (tab) {
333
+ var tabChildren = [];
334
+ // Reverse children and use unshift() to maintain order with depth-first processing
335
+ (tab.content || []).slice().reverse().forEach(function (comp) {
336
+ stack.unshift({ component: comp, layoutParent: tabChildren });
337
+ });
338
+ tabsNode_1.tabs.push({ header: tab.header, children: tabChildren });
339
+ });
340
+ }
341
+ layoutParent.push(tabsNode_1);
342
+ return "continue";
343
+ }
344
+ if (component.type === 'card') {
345
+ var safeId = sanitizeId(component.id, generateId(semanticType.type));
346
+ var cardNode_1 = __assign({ type: 'card', id: safeId, name: component.name, label: component.label, cssClass: component.cssClass, hideLabel: component.hideLabel, cardTitle: component.cardTitle, cardSubtitle: component.cardSubtitle, children: [] }, (component.conditions ? { conditions: component.conditions } : {}));
347
+ // Process card children
348
+ // Reverse children and use unshift() to maintain order with depth-first processing
349
+ (component.children || []).slice().reverse().forEach(function (child) {
350
+ stack.unshift({ component: child, layoutParent: cardNode_1.children });
351
+ });
352
+ layoutParent.push(cardNode_1);
353
+ return "continue";
354
+ }
355
+ // ✅ DEDUPLICATION: Skip if we've already processed this component ID
356
+ if (seenComponentIds.has(component.id)) {
357
+ return "continue";
358
+ }
359
+ seenComponentIds.add(component.id);
360
+ // Generate semantic field key from label
361
+ var baseFieldKey = labelToFieldKey(component.label || component.id, component.id);
362
+ var fieldKey = makeUniqueFieldKey(baseFieldKey, usedFieldKeys, component.id);
363
+ usedFieldKeys.add(fieldKey);
364
+ // Extract data field properties (all components, no skipping)
365
+ // If no semantic type mapping exists, use 'any' as the type
366
+ var dataField = extractDataField(component, semanticType || { type: 'any' });
367
+ dataFields[fieldKey] = dataField;
368
+ // Extract UI field properties (all components)
369
+ uiFields[fieldKey] = extractUIField(component);
370
+ // Add property reference to layout (use fieldKey instead of component ID)
371
+ layoutParent.push({ type: 'field', propertyId: fieldKey });
372
+ };
373
+ while (stack.length > 0) {
374
+ _loop_1();
375
+ }
376
+ // ✅ Merge data and UI fields into unified properties
377
+ var unifiedProperties = {};
378
+ Object.keys(dataFields).forEach(function (fieldKey) {
379
+ var dataField = dataFields[fieldKey];
380
+ var uiField = uiFields[fieldKey];
381
+ unifiedProperties[fieldKey] = __assign({}, dataField, uiField, {
382
+ // Ensure widget is always set
383
+ widget: (uiField && uiField.widget) || inferWidgetFromType(dataField.type, dataField.format, dataField.options !== undefined) });
384
+ });
385
+ var settings = heartSchema.settings ? __assign({}, heartSchema.settings) : {};
386
+ return __assign({ version: heartSchema.version, properties: stripConfiguredFlag(unifiedProperties), layout: layout }, (Object.keys(settings).length > 0 ? { settings: settings } : {}));
387
+ }
388
+ /**
389
+ * @private
390
+ */
391
+ function extractDataField(component, semanticType) {
392
+ var safeId = sanitizeId(component.id, generateId(semanticType.type));
393
+ var dataField = {
394
+ id: safeId,
395
+ name: component.name,
396
+ type: semanticType.type,
397
+ };
398
+ // Add format if present
399
+ if (semanticType.format) {
400
+ dataField.format = semanticType.format;
401
+ }
402
+ // Extract allowed properties only
403
+ if (component.label !== undefined)
404
+ dataField.label = component.label;
405
+ if (component.defaultValue !== undefined)
406
+ dataField.defaultValue = component.defaultValue;
407
+ if (component.expressionValue !== undefined)
408
+ dataField.expressionValue = component.expressionValue;
409
+ if (component.content !== undefined)
410
+ dataField.content = component.content;
411
+ if (component.buttonType !== undefined)
412
+ dataField.buttonType = component.buttonType;
413
+ if (component.textboxType !== undefined)
414
+ dataField.textboxType = component.textboxType;
415
+ if (component.required !== undefined)
416
+ dataField.required = component.required;
417
+ // Extract options for selection fields (dropdown, radio, multiselect)
418
+ if (component.options !== undefined)
419
+ dataField.options = component.options;
420
+ if (component.minLength !== undefined)
421
+ dataField.minLength = component.minLength;
422
+ if (component.maxLength !== undefined)
423
+ dataField.maxLength = component.maxLength;
424
+ // Handle numeric validation (use canonical names)
425
+ if (component.minValue !== undefined)
426
+ dataField.minValue = component.minValue;
427
+ if (component.maxValue !== undefined)
428
+ dataField.maxValue = component.maxValue;
429
+ // Date/time validation
430
+ if (component.minDate !== undefined)
431
+ dataField.minDate = component.minDate;
432
+ if (component.maxDate !== undefined)
433
+ dataField.maxDate = component.maxDate;
434
+ if (component.minTime !== undefined)
435
+ dataField.minTime = component.minTime;
436
+ if (component.maxTime !== undefined)
437
+ dataField.maxTime = component.maxTime;
438
+ // Pattern validation (rename from regex, convert RegExp to string)
439
+ if (component.regex !== undefined) {
440
+ var regex = component.regex;
441
+ dataField.pattern = regex instanceof RegExp ? regex.source : regex;
442
+ }
443
+ if (component.pattern !== undefined) {
444
+ var pattern = component.pattern;
445
+ dataField.pattern = pattern instanceof RegExp ? pattern.source : pattern;
446
+ }
447
+ return dataField;
448
+ }
449
+ /**
450
+ * @private
451
+ */
452
+ function extractUIField(component) {
453
+ var uiField = {
454
+ widget: component.type,
455
+ };
456
+ // Copy all properties EXCEPT those in data schema allowed list
457
+ var dataSchemaProps = new Set([
458
+ 'id', 'type', 'label', 'format', 'defaultValue', 'required', 'options', 'name', 'expressionValue',
459
+ 'minLength', 'maxLength', 'minimum', 'maximum', 'minValue', 'maxValue',
460
+ 'minDate', 'maxDate', 'minTime', 'maxTime', 'regex', 'pattern', 'content', 'buttonType', 'textboxType'
461
+ ]);
462
+ Object.keys(component).forEach(function (key) {
463
+ if (!dataSchemaProps.has(key) && key !== 'id' && key !== 'type') {
464
+ uiField[key] = component[key];
465
+ }
466
+ });
467
+ // Special handling: Filter dataGrid columns to keep only required properties
468
+ if (component.type === 'dataGrid' && uiField.columns && Array.isArray(uiField.columns)) {
469
+ var requiredColumnProps_1 = [
470
+ 'field',
471
+ 'headerText',
472
+ 'type',
473
+ 'width',
474
+ 'format',
475
+ 'editType',
476
+ 'validationRules',
477
+ 'allowEditing',
478
+ 'expression',
479
+ 'isPrimaryKey',
480
+ 'customValidation'
481
+ ];
482
+ uiField.columns = uiField.columns.map(function (col) {
483
+ var filteredCol = {};
484
+ requiredColumnProps_1.forEach(function (prop) {
485
+ if (col[prop] !== undefined) {
486
+ filteredCol[prop] = col[prop];
487
+ }
488
+ });
489
+ return filteredCol;
490
+ });
491
+ }
492
+ return uiField;
493
+ }
494
+ /**
495
+ * @private
496
+ */
497
+ export function mergeSchema(unified) {
498
+ // Create lookup map for O(1) access to unified properties
499
+ var propertyMap = new Map();
500
+ var unifiedPropKeys = Object.keys(unified.properties);
501
+ for (var _i = 0, unifiedPropKeys_1 = unifiedPropKeys; _i < unifiedPropKeys_1.length; _i++) {
502
+ var id = unifiedPropKeys_1[_i];
503
+ propertyMap.set(id, unified.properties[id]);
504
+ }
505
+ // Track processed field IDs to prevent duplicates
506
+ var processedFieldIds = new Set();
507
+ // Recursive function to process layout nodes
508
+ var processLayoutNodes = function (layoutNodes) {
509
+ var components = [];
510
+ var _loop_2 = function (node) {
511
+ if (node.type === 'field') {
512
+ var fieldNode = node;
513
+ // ✅ DEDUPLICATION: Skip if we've already processed this field
514
+ if (processedFieldIds.has(fieldNode.propertyId)) {
515
+ return "continue";
516
+ }
517
+ processedFieldIds.add(fieldNode.propertyId);
518
+ var unifiedField = propertyMap.get(fieldNode.propertyId);
519
+ if (!unifiedField) {
520
+ // console.warn(`Field ${fieldNode.propertyId} in layout not found in schema`);
521
+ // Generate fallback component
522
+ var fallbackComponent = {
523
+ id: fieldNode.propertyId || generateId('textbox'),
524
+ name: generateName(''),
525
+ type: 'textbox',
526
+ label: 'Unknown Field',
527
+ _configured: true
528
+ };
529
+ components.push(fallbackComponent);
530
+ }
531
+ else {
532
+ components.push(mergeUnifiedField(unifiedField));
533
+ }
534
+ }
535
+ else if (node.type === 'table') {
536
+ var tableNode = node;
537
+ var tableComponent_1 = __assign({ id: tableNode.id || generateId('table'), name: tableNode.name, type: 'table', label: tableNode.label || 'Table', cssClass: tableNode.cssClass, hideBorders: tableNode.hideBorders, rows: tableNode.rows, columns: tableNode.cols, columnWidths: tableNode.columnWidths, tableCells: [], _configured: true }, (tableNode.conditions ? { conditions: tableNode.conditions } : {}));
538
+ // Process table cells recursively
539
+ tableNode.cells.forEach(function (row) {
540
+ var cellRow = [];
541
+ row.forEach(function (cell) {
542
+ var cellComponents = processLayoutNodes(cell.children);
543
+ cellRow.push(cellComponents);
544
+ });
545
+ tableComponent_1.tableCells.push(cellRow);
546
+ });
547
+ components.push(tableComponent_1);
548
+ }
549
+ else if (node.type === 'panel') {
550
+ var panelNode = node;
551
+ var panelComponent = __assign({ id: panelNode.id || generateId('panel'), type: 'panel', name: panelNode.name, cssClass: panelNode.cssClass, hideBorders: panelNode.hideBorders, hideLabel: panelNode.hideLabel, label: panelNode.label || 'Panel', children: processLayoutNodes(panelNode.children), _configured: true }, (panelNode.conditions ? { conditions: panelNode.conditions } : {}));
552
+ components.push(panelComponent);
553
+ }
554
+ else if (node.type === 'tabs') {
555
+ var tabsNode = node;
556
+ var tabsComponent_1 = __assign({ id: tabsNode.id || generateId('tabs'), type: 'tabs', name: tabsNode.name, label: tabsNode.label || 'Tabs', cssClass: tabsNode.cssClass, tabOptions: tabsNode.tabOptions, tabItems: [], _configured: true }, (tabsNode.conditions ? { conditions: tabsNode.conditions } : {}));
557
+ // Process tabs recursively
558
+ tabsNode.tabs.forEach(function (tab) {
559
+ tabsComponent_1.tabItems.push({
560
+ header: tab.header,
561
+ content: processLayoutNodes(tab.children)
562
+ });
563
+ });
564
+ components.push(tabsComponent_1);
565
+ }
566
+ else if (node.type === 'card') {
567
+ var cardNode = node;
568
+ var cardComponent = __assign({ id: cardNode.id || generateId('card'), type: 'card', name: cardNode.name, label: cardNode.label || 'Card', cssClass: cardNode.cssClass, hideLabel: cardNode.hideLabel, children: processLayoutNodes(cardNode.children), _configured: true }, (cardNode.conditions ? { conditions: cardNode.conditions } : {}));
569
+ // Add card-specific properties
570
+ if (cardNode.cardTitle !== undefined)
571
+ cardComponent.cardTitle = cardNode.cardTitle;
572
+ if (cardNode.cardSubtitle !== undefined)
573
+ cardComponent.cardSubtitle = cardNode.cardSubtitle;
574
+ components.push(cardComponent);
575
+ }
576
+ };
577
+ for (var _i = 0, layoutNodes_1 = layoutNodes; _i < layoutNodes_1.length; _i++) {
578
+ var node = layoutNodes_1[_i];
579
+ _loop_2(node);
580
+ }
581
+ return components;
582
+ };
583
+ // Process root layout nodes
584
+ var components;
585
+ if (!unified.layout || unified.layout.length === 0) {
586
+ // If layout is undefined or empty, generate a flat layout from properties
587
+ var flatPropKeys = Object.keys(unified.properties);
588
+ components = flatPropKeys.map(function (key) {
589
+ return mergeUnifiedField(unified.properties[key]);
590
+ });
591
+ }
592
+ else {
593
+ components = processLayoutNodes(unified.layout);
594
+ }
595
+ return __assign({ version: unified.version, components: components }, (unified.settings ? { settings: unified.settings } : {}));
596
+ }
597
+ /**
598
+ * @private
599
+ */
600
+ function mergeUnifiedField(unifiedField) {
601
+ var hasOptions = unifiedField.options !== undefined && unifiedField.options.length > 0;
602
+ var component = {
603
+ id: unifiedField.id || generateId(unifiedField.widget || inferWidgetFromType(unifiedField.type, unifiedField.format, hasOptions)),
604
+ name: unifiedField.name,
605
+ type: (unifiedField.widget || inferWidgetFromType(unifiedField.type, unifiedField.format, hasOptions)),
606
+ label: unifiedField.label || unifiedField.id,
607
+ };
608
+ // Copy all data and UI properties from unified field
609
+ var dataSchemaProps = new Set([
610
+ 'id', 'type', 'name', 'label', 'format', 'widget', 'defaultValue', 'required', 'options', 'expressionValue',
611
+ 'minLength', 'maxLength', 'minimum', 'maximum', 'minValue', 'maxValue',
612
+ 'minDate', 'maxDate', 'minTime', 'maxTime', 'regex', 'pattern', 'content', 'buttonType', 'textboxType'
613
+ ]);
614
+ Object.keys(unifiedField).forEach(function (key) {
615
+ if (!dataSchemaProps.has(key) && key !== 'id' && key !== 'name' && key !== 'type' && key !== 'label') {
616
+ component[key] = unifiedField[key];
617
+ }
618
+ });
619
+ // Copy specific data properties
620
+ if (unifiedField.defaultValue !== undefined)
621
+ component.defaultValue = unifiedField.defaultValue;
622
+ if (unifiedField.expressionValue !== undefined)
623
+ component.expressionValue = unifiedField.expressionValue;
624
+ if (unifiedField.required !== undefined)
625
+ component.required = unifiedField.required;
626
+ if (unifiedField.content !== undefined)
627
+ component.content = unifiedField.content;
628
+ if (unifiedField.buttonType !== undefined)
629
+ component.buttonType = unifiedField.buttonType;
630
+ if (unifiedField.textboxType !== undefined)
631
+ component.textboxType = unifiedField.textboxType;
632
+ if (unifiedField.options !== undefined)
633
+ component.options = unifiedField.options;
634
+ if (unifiedField.minLength !== undefined)
635
+ component.minLength = unifiedField.minLength;
636
+ if (unifiedField.maxLength !== undefined)
637
+ component.maxLength = unifiedField.maxLength;
638
+ if (unifiedField.minValue !== undefined)
639
+ component.minValue = unifiedField.minValue;
640
+ if (unifiedField.maxValue !== undefined)
641
+ component.maxValue = unifiedField.maxValue;
642
+ if (unifiedField.minDate !== undefined)
643
+ component.minDate = unifiedField.minDate;
644
+ if (unifiedField.maxDate !== undefined)
645
+ component.maxDate = unifiedField.maxDate;
646
+ if (unifiedField.minTime !== undefined)
647
+ component.minTime = unifiedField.minTime;
648
+ if (unifiedField.maxTime !== undefined)
649
+ component.maxTime = unifiedField.maxTime;
650
+ if (unifiedField.pattern !== undefined)
651
+ component.regex = unifiedField.pattern;
652
+ return component;
653
+ }
654
+ /**
655
+ * @private
656
+ */
657
+ export function inferWidgetFromType(type, format, hasOptions) {
658
+ if (type === 'string') {
659
+ if (format === 'date')
660
+ return 'date';
661
+ if (format === 'date-time')
662
+ return 'dateTime';
663
+ if (format === 'time')
664
+ return 'time';
665
+ if (format === 'email')
666
+ return 'email';
667
+ if (format === 'url')
668
+ return 'url';
669
+ // If options are present, default to dropdown for string types
670
+ if (hasOptions)
671
+ return 'dropdown';
672
+ return 'textbox';
673
+ }
674
+ if (type === 'number')
675
+ return 'number';
676
+ if (type === 'boolean')
677
+ return 'checkbox';
678
+ if (type === 'array') {
679
+ // For array type with options, use multiselect
680
+ return 'multiselect';
681
+ }
682
+ if (type === 'button')
683
+ return 'button';
684
+ if (type === 'message')
685
+ return 'message';
686
+ if (type === 'sign')
687
+ return 'signature';
688
+ if (type === 'image')
689
+ return 'imageEditor';
690
+ if (type === 'file')
691
+ return 'fileUpload';
692
+ if (type === 'color')
693
+ return 'colorPicker';
694
+ if (type === 'grid')
695
+ return 'dataGrid';
696
+ if (type === 'any')
697
+ return 'textbox';
698
+ return 'textbox';
699
+ }
700
+ /**
701
+ * @private
702
+ */
703
+ function levenshteinDistance(str1, str2) {
704
+ var len1 = str1.length;
705
+ var len2 = str2.length;
706
+ var matrix = [];
707
+ // Initialize matrix
708
+ for (var i = 0; i <= len1; i++) {
709
+ matrix[i] = [i];
710
+ }
711
+ for (var j = 0; j <= len2; j++) {
712
+ matrix[0][j] = j;
713
+ }
714
+ // Fill matrix
715
+ for (var i = 1; i <= len1; i++) {
716
+ for (var j = 1; j <= len2; j++) {
717
+ var cost = str1[i - 1] === str2[j - 1] ? 0 : 1;
718
+ matrix[i][j] = Math.min(matrix[i - 1][j] + 1, // deletion
719
+ matrix[i][j - 1] + 1, // insertion
720
+ matrix[i - 1][j - 1] + cost // substitution
721
+ );
722
+ }
723
+ }
724
+ return matrix[len1][len2];
725
+ }
726
+ /**
727
+ * @private
728
+ */
729
+ function calculateSimilarity(str1, str2) {
730
+ var distance = levenshteinDistance(str1.toLowerCase(), str2.toLowerCase());
731
+ var maxLen = Math.max(str1.length, str2.length);
732
+ if (maxLen === 0)
733
+ return 100;
734
+ return Math.round(((maxLen - distance) / maxLen) * 100);
735
+ }
736
+ /**
737
+ * @private
738
+ */
739
+ export function matchFieldWithIDPreservation(newDataField, existingUISchema) {
740
+ // 1. Try exact ID match first
741
+ if (existingUISchema.properties[newDataField.id]) {
742
+ return {
743
+ existingId: newDataField.id,
744
+ newDataId: newDataField.id,
745
+ confidence: 'exact',
746
+ method: 'id',
747
+ similarity: 100
748
+ };
749
+ }
750
+ // 2. Try fuzzy match by ID (check if existing ID starts with new ID or vice versa)
751
+ var bestIdMatch = null;
752
+ var idMatchKeys = Object.keys(existingUISchema.properties);
753
+ for (var _i = 0, idMatchKeys_1 = idMatchKeys; _i < idMatchKeys_1.length; _i++) {
754
+ var existingId = idMatchKeys_1[_i];
755
+ var existingUIField = existingUISchema.properties[existingId];
756
+ // Skip if this is a layout container
757
+ if (existingUIField.widget === 'table' || existingUIField.widget === 'panel' || existingUIField.widget === 'tabs') {
758
+ continue;
759
+ }
760
+ // Check if one ID is a prefix of the other (common case: radio_123 vs radio_123_456)
761
+ var newId = newDataField.id || '';
762
+ var isPrefix = existingId.indexOf(newId + '_') === 0 || newId.indexOf(existingId + '_') === 0;
763
+ if (isPrefix) {
764
+ var similarity = Math.round((Math.min(newId.length, existingId.length) / Math.max(newId.length, existingId.length)) * 100);
765
+ if (!bestIdMatch || (bestIdMatch.similarity && similarity > bestIdMatch.similarity)) {
766
+ bestIdMatch = {
767
+ existingId: existingId,
768
+ newDataId: newDataField.id,
769
+ confidence: similarity >= 90 ? 'high' : similarity >= 70 ? 'medium' : 'low',
770
+ method: 'id',
771
+ similarity: similarity
772
+ };
773
+ }
774
+ }
775
+ else {
776
+ // Try Levenshtein distance for ID similarity
777
+ var idSimilarity = calculateSimilarity(existingId, newId);
778
+ // Only consider as potential match if very similar (≥85%)
779
+ if (idSimilarity >= 85) {
780
+ if (!bestIdMatch || (bestIdMatch.similarity && idSimilarity > bestIdMatch.similarity)) {
781
+ bestIdMatch = {
782
+ existingId: existingId,
783
+ newDataId: newDataField.id,
784
+ confidence: idSimilarity >= 90 ? 'high' : 'medium',
785
+ method: 'id',
786
+ similarity: idSimilarity
787
+ };
788
+ }
789
+ }
790
+ }
791
+ }
792
+ // If we found a good ID match, use it
793
+ if (bestIdMatch && bestIdMatch.similarity && bestIdMatch.similarity >= 70) {
794
+ //console.log(`ID fuzzy match: "${newDataField.id}" → "${bestIdMatch.existingId}" (${bestIdMatch.similarity}% similar)`);
795
+ return bestIdMatch;
796
+ }
797
+ // 3. Try fuzzy match by label
798
+ var bestLabelMatch = null;
799
+ var labelMatchKeys = Object.keys(existingUISchema.properties);
800
+ for (var _a = 0, labelMatchKeys_1 = labelMatchKeys; _a < labelMatchKeys_1.length; _a++) {
801
+ var existingId = labelMatchKeys_1[_a];
802
+ var existingUIField = existingUISchema.properties[existingId];
803
+ // Skip if this is a layout container
804
+ if (existingUIField.widget === 'table' || existingUIField.widget === 'panel' || existingUIField.widget === 'tabs') {
805
+ continue;
806
+ }
807
+ // Get label from UI field or try to extract from ID
808
+ var existingLabel = existingUIField.label || existingId;
809
+ var newLabel = newDataField.label || newDataField.id;
810
+ if (!existingLabel || !newLabel)
811
+ continue;
812
+ var similarity = calculateSimilarity(existingLabel, newLabel);
813
+ // Update best match if this is better
814
+ if (!bestLabelMatch || (bestLabelMatch.similarity && similarity > bestLabelMatch.similarity)) {
815
+ bestLabelMatch = {
816
+ existingId: existingId,
817
+ newDataId: newDataField.id,
818
+ confidence: similarity >= 90 ? 'high' : similarity >= 70 ? 'medium' : 'low',
819
+ method: similarity === 100 ? 'label-exact' : 'label-fuzzy',
820
+ similarity: similarity
821
+ };
822
+ }
823
+ }
824
+ // 4. Return best label match if similarity is good enough (≥70%)
825
+ if (bestLabelMatch && bestLabelMatch.similarity && bestLabelMatch.similarity >= 70) {
826
+ //console.log(`Label fuzzy match: "${newDataField.label}" → "${bestLabelMatch.existingId}" (${bestLabelMatch.similarity}% similar)`);
827
+ return bestLabelMatch;
828
+ }
829
+ // 5. No match found - use new ID
830
+ return {
831
+ existingId: newDataField.id,
832
+ newDataId: newDataField.id,
833
+ confidence: 'exact',
834
+ method: 'new',
835
+ similarity: 100
836
+ };
837
+ }
838
+ /**
839
+ * @private
840
+ */
841
+ export function mergeWithIDRemapping(newDataSchema, existingUISchema) {
842
+ var idMap = new Map(); // newId → canonicalId
843
+ var matchResults = [];
844
+ // Build ID mapping table
845
+ var newDataPropKeys = Object.keys(newDataSchema.properties);
846
+ for (var _i = 0, newDataPropKeys_1 = newDataPropKeys; _i < newDataPropKeys_1.length; _i++) {
847
+ var newId = newDataPropKeys_1[_i];
848
+ var dataField = newDataSchema.properties[newId];
849
+ var match = matchFieldWithIDPreservation(dataField, existingUISchema);
850
+ matchResults.push(match);
851
+ idMap.set(newId, match.existingId || generateId(labelToFieldKey(dataField.label || '')));
852
+ // Log remapping if IDs differ
853
+ if (match.newDataId !== match.existingId) {
854
+ //console.log(`ID remapped: ${match.newDataId} → ${match.existingId} (${match.method}, ${match.similarity}% similar)`);
855
+ }
856
+ }
857
+ // Remap all data field IDs to canonical IDs
858
+ var remappedDataFields = {};
859
+ var newDataPropKeys2 = Object.keys(newDataSchema.properties);
860
+ for (var _a = 0, newDataPropKeys2_1 = newDataPropKeys2; _a < newDataPropKeys2_1.length; _a++) {
861
+ var newId = newDataPropKeys2_1[_a];
862
+ var dataField = newDataSchema.properties[newId];
863
+ var canonicalId = idMap.get(newId) || newId;
864
+ remappedDataFields[canonicalId] = __assign({}, dataField, { id: canonicalId // Use canonical ID
865
+ });
866
+ }
867
+ // Get existing field IDs from the layout
868
+ var existingFieldIds = extractFieldIdsFromLayout(existingUISchema.layout);
869
+ var newFieldIds = Object.keys(remappedDataFields).filter(function (id) { return !existingFieldIds.has(id); });
870
+ //console.log(`📋 Existing fields in layout: ${existingFieldIds.size}, New fields: ${newFieldIds.length}`);
871
+ // ✅ CHECK IF SUBMIT BUTTON EXISTS: Prevent duplicate submit buttons
872
+ var existingUIValues = Object.keys(existingUISchema.properties).map(function (k) { return existingUISchema.properties[k]; });
873
+ var hasExistingSubmitButton = existingUIValues.some(function (uiField) { return uiField.widget === 'button'; });
874
+ // Filter out new submit buttons if one already exists
875
+ var filteredNewFieldIds = newFieldIds.filter(function (id) {
876
+ var dataField = remappedDataFields[id];
877
+ if ((dataField.type === 'button' && dataField.buttonType === 'submit') && hasExistingSubmitButton) {
878
+ //console.log(`⚠️ Skipping new button "${dataField.label}" - submit button already exists in layout`);
879
+ return false;
880
+ }
881
+ return true;
882
+ });
883
+ //console.log(`📋 New fields after filtering: ${filteredNewFieldIds.length}`);
884
+ // Update layout references to use canonical IDs
885
+ var remappedLayout = remapLayoutIds(existingUISchema.layout, idMap);
886
+ // Create UI properties for new fields that don't have them yet
887
+ // ✅ Ensure all existing UI properties have _configured flag (add if missing from imported JSON)
888
+ var enhancedUIProperties = {};
889
+ var existingUIKeys = Object.keys(existingUISchema.properties);
890
+ for (var _b = 0, existingUIKeys_1 = existingUIKeys; _b < existingUIKeys_1.length; _b++) {
891
+ var key = existingUIKeys_1[_b];
892
+ var uiField = existingUISchema.properties[key];
893
+ enhancedUIProperties[key] = __assign({}, uiField, { _configured: uiField._configured !== undefined ? uiField._configured : true });
894
+ }
895
+ if (filteredNewFieldIds.length > 0) {
896
+ //console.log(`➕ Adding ${filteredNewFieldIds.length} new fields to layout`);
897
+ // Check if submit button exists and is at the last position (not moved by user)
898
+ var lastNode = remappedLayout[remappedLayout.length - 1];
899
+ var isSubmitAtEnd = lastNode && lastNode.type === 'field' &&
900
+ enhancedUIProperties[lastNode.propertyId] && enhancedUIProperties[lastNode.propertyId].widget === 'button';
901
+ var newFieldNodes_1 = [];
902
+ // Generate default UI properties for new fields
903
+ filteredNewFieldIds.forEach(function (id) {
904
+ var dataField = remappedDataFields[id];
905
+ var hasOptions = dataField.options !== undefined && dataField.options.length > 0;
906
+ var widget = inferWidgetFromType(dataField.type, dataField.format, hasOptions);
907
+ // ✅ Add default button styling
908
+ var uiProperties = {
909
+ widget: widget,
910
+ label: dataField.label,
911
+ _configured: true
912
+ };
913
+ // Add primary styling for buttons
914
+ if (widget === 'button') {
915
+ uiProperties.isPrimary = true;
916
+ uiProperties.name = 'defaultFormSubmit';
917
+ uiProperties.cssClass = 'e-primary';
918
+ }
919
+ enhancedUIProperties[id] = uiProperties;
920
+ newFieldNodes_1.push({
921
+ type: 'field',
922
+ propertyId: id
923
+ });
924
+ });
925
+ // Apply same logic as App.tsx: insert before submit if it's at the end
926
+ if (isSubmitAtEnd) {
927
+ // Insert new fields BEFORE the submit button
928
+ remappedLayout = remappedLayout.slice(0, -1).concat(newFieldNodes_1, [remappedLayout[remappedLayout.length - 1]]);
929
+ //console.log(`📐 Layout rebuilt: new fields inserted before submit button at end`);
930
+ }
931
+ else {
932
+ // Submit moved or doesn't exist - add new fields at end
933
+ remappedLayout = remappedLayout.concat(newFieldNodes_1);
934
+ //console.log(`📐 Layout rebuilt: new fields added at end`);
935
+ }
936
+ }
937
+ // Merge to FormSchema using unified schema
938
+ var unifiedProperties = {};
939
+ Object.keys(remappedDataFields).forEach(function (fieldKey) {
940
+ var dataField = remappedDataFields[fieldKey];
941
+ var uiField = enhancedUIProperties[fieldKey];
942
+ unifiedProperties[fieldKey] = __assign({}, dataField, uiField, { widget: (uiField && uiField.widget) || inferWidgetFromType(dataField.type, dataField.format, dataField.options !== undefined) });
943
+ });
944
+ var mergedSchema = mergeSchema(__assign({ version: newDataSchema.version, properties: unifiedProperties, layout: remappedLayout }, (newDataSchema.settings ? { settings: newDataSchema.settings } : {})));
945
+ return mergedSchema;
946
+ }
947
+ /**
948
+ * @private
949
+ */
950
+ function remapLayoutIds(layout, idMap) {
951
+ return layout.map(function (node) {
952
+ if (node.type === 'field') {
953
+ var fieldNode = node;
954
+ var canonicalId = idMap.get(fieldNode.propertyId) || fieldNode.propertyId;
955
+ return __assign({}, fieldNode, { propertyId: canonicalId });
956
+ }
957
+ else if (node.type === 'table') {
958
+ var tableNode = node;
959
+ return __assign({}, tableNode, { cells: tableNode.cells.map(function (row) {
960
+ return row.map(function (cell) { return (__assign({}, cell, { children: remapLayoutIds(cell.children, idMap) })); });
961
+ }) });
962
+ }
963
+ else if (node.type === 'panel') {
964
+ var panelNode = node;
965
+ return __assign({}, panelNode, { children: remapLayoutIds(panelNode.children, idMap) });
966
+ }
967
+ else if (node.type === 'tabs') {
968
+ var tabsNode = node;
969
+ return __assign({}, tabsNode, { tabs: tabsNode.tabs.map(function (tab) { return (__assign({}, tab, { children: remapLayoutIds(tab.children, idMap) })); }) });
970
+ }
971
+ else if (node.type === 'card') {
972
+ var cardNode = node;
973
+ return __assign({}, cardNode, { children: remapLayoutIds(cardNode.children, idMap) });
974
+ }
975
+ return node;
976
+ });
977
+ }
978
+ /**
979
+ * @private
980
+ */
981
+ export function extractFieldIdsFromLayout(layout) {
982
+ var fieldIds = new Set();
983
+ var stack = layout.slice();
984
+ while (stack.length > 0) {
985
+ var node = stack.shift();
986
+ if (node.type === 'field') {
987
+ fieldIds.add(node.propertyId);
988
+ }
989
+ else if (node.type === 'table') {
990
+ node.cells.forEach(function (row) {
991
+ return row.forEach(function (cell) { return stack.push.apply(stack, cell.children); });
992
+ });
993
+ }
994
+ else if (node.type === 'panel') {
995
+ stack.push.apply(stack, node.children);
996
+ }
997
+ else if (node.type === 'tabs') {
998
+ node.tabs.forEach(function (tab) { return stack.push.apply(stack, tab.children); });
999
+ }
1000
+ else if (node.type === 'card') {
1001
+ stack.push.apply(stack, node.children);
1002
+ }
1003
+ }
1004
+ return fieldIds;
1005
+ }
1006
+ /**
1007
+ * @private
1008
+ */
1009
+ export function convertComponentsToDataSchema(components) {
1010
+ var properties = {};
1011
+ var seenComponentIds = new Set(); // Track component IDs to prevent duplicates
1012
+ // Flatten all components (including nested ones)
1013
+ var stack = components.slice();
1014
+ while (stack.length > 0) {
1015
+ var comp = stack.shift();
1016
+ // Infer semantic type from component
1017
+ var semanticType = UI_TYPE_TO_SEMANTIC_TYPE[comp.type];
1018
+ // Skip presentation-only widgets (button, message, etc.) - they have null semantic type
1019
+ if (semanticType === null) {
1020
+ // Still process nested children for layout containers
1021
+ if (comp.children && comp.children.length) {
1022
+ stack.unshift.apply(stack, comp.children);
1023
+ }
1024
+ if (comp.tabItems && comp.tabItems.length) {
1025
+ for (var _i = 0, _a = comp.tabItems; _i < _a.length; _i++) {
1026
+ var tab = _a[_i];
1027
+ if (tab.content && tab.content.length) {
1028
+ stack.unshift.apply(stack, tab.content);
1029
+ }
1030
+ }
1031
+ }
1032
+ if (comp.tableCells && comp.tableCells.length) {
1033
+ for (var _b = 0, _c = comp.tableCells; _b < _c.length; _b++) {
1034
+ var row = _c[_b];
1035
+ for (var _d = 0, row_1 = row; _d < row_1.length; _d++) {
1036
+ var cell = row_1[_d];
1037
+ if (cell.length) {
1038
+ stack.unshift.apply(stack, cell);
1039
+ }
1040
+ }
1041
+ }
1042
+ }
1043
+ continue; // Skip adding to data schema
1044
+ }
1045
+ // ✅ DEDUPLICATION: Skip if we've already processed this component ID
1046
+ if (seenComponentIds.has(comp.id)) {
1047
+ //console.log(`⚠️ Skipping duplicate component: ${comp.id} (${comp.label})`);
1048
+ // Still process nested children
1049
+ if (comp.children && comp.children.length) {
1050
+ stack.unshift.apply(stack, comp.children);
1051
+ }
1052
+ if (comp.tabItems && comp.tabItems.length) {
1053
+ for (var _e = 0, _f = comp.tabItems; _e < _f.length; _e++) {
1054
+ var tab = _f[_e];
1055
+ if (tab.content && tab.content.length) {
1056
+ stack.unshift.apply(stack, tab.content);
1057
+ }
1058
+ }
1059
+ }
1060
+ if (comp.tableCells && comp.tableCells.length) {
1061
+ for (var _g = 0, _h = comp.tableCells; _g < _h.length; _g++) {
1062
+ var row = _h[_g];
1063
+ for (var _j = 0, row_2 = row; _j < row_2.length; _j++) {
1064
+ var cell = row_2[_j];
1065
+ if (cell.length) {
1066
+ stack.unshift.apply(stack, cell);
1067
+ }
1068
+ }
1069
+ }
1070
+ }
1071
+ continue;
1072
+ }
1073
+ seenComponentIds.add(comp.id);
1074
+ // Generate fieldKey from label or ID
1075
+ var baseFieldKey = labelToFieldKey(comp.label || comp.id, comp.id);
1076
+ var fieldKey = makeUniqueFieldKey(baseFieldKey, new Set(Object.keys(properties)), comp.id);
1077
+ var dataField = extractDataField(comp, semanticType || { type: 'any' });
1078
+ properties[fieldKey] = dataField;
1079
+ // Process nested children
1080
+ if (comp.children && comp.children.length) {
1081
+ stack.unshift.apply(stack, comp.children);
1082
+ }
1083
+ // Process tab items
1084
+ if (comp.tabItems && comp.tabItems.length) {
1085
+ for (var _k = 0, _l = comp.tabItems; _k < _l.length; _k++) {
1086
+ var tab = _l[_k];
1087
+ if (tab.content && tab.content.length) {
1088
+ stack.unshift.apply(stack, tab.content);
1089
+ }
1090
+ }
1091
+ }
1092
+ // Process table cells
1093
+ if (comp.tableCells && comp.tableCells.length) {
1094
+ for (var _m = 0, _o = comp.tableCells; _m < _o.length; _m++) {
1095
+ var row = _o[_m];
1096
+ for (var _p = 0, row_3 = row; _p < row_3.length; _p++) {
1097
+ var cell = row_3[_p];
1098
+ // cell is FormNode[], not an object with .components
1099
+ if (cell.length) {
1100
+ stack.unshift.apply(stack, cell);
1101
+ }
1102
+ }
1103
+ }
1104
+ }
1105
+ }
1106
+ return {
1107
+ version: '1.0',
1108
+ properties: properties
1109
+ };
1110
+ }