@ukhomeoffice/cop-react-form-renderer 6.15.6-alpha → 6.15.8-alpha

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 (16) hide show
  1. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/forms/form-hidden-component-show-when-in-component-and-page.json +62 -0
  2. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/forms/form-hidden-page-same-component-reused.json +61 -0
  3. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/input/cop-airpax-change-what-happened-before.json +300 -0
  4. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/input/data-hidden-component-show-when-in-component-and-page.json +6 -0
  5. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/input/data-hidden-page-same-component-reused.json +6 -0
  6. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/cop-airpax-change-what-happened-after.json +280 -0
  7. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/data-hidden-component-show-when-in-component-and-page-removed.json +5 -0
  8. package/dist/components/FormRenderer/clear-uncompleted-routes/test-data/output/data-hidden-page-same-component-reused-removed.json +5 -0
  9. package/dist/components/FormRenderer/helpers/clearOutUncompletedRoutes.js +84 -189
  10. package/dist/components/FormRenderer/helpers/clearOutUncompletedRoutes.test.js +64 -27
  11. package/dist/components/FormRenderer/helpers/clearOutUncompletedRoutesUtils.js +290 -0
  12. package/dist/components/FormRenderer/helpers/clearOutUncompletedRoutesUtils.test.js +502 -0
  13. package/dist/components/FormRenderer/onCYAAction.js +4 -0
  14. package/package.json +1 -1
  15. package/dist/components/FormRenderer/helpers/deleteNodeByPath.js +0 -29
  16. package/dist/components/FormRenderer/helpers/deleteNodeByPath.test.js +0 -56
@@ -4,6 +4,9 @@ var _index = _interopRequireDefault(require("./index"));
4
4
  var _formHiddenComponent = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/forms/form-hidden-component.json"));
5
5
  var _dataHiddenComponent = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/input/data-hidden-component.json"));
6
6
  var _dataHiddenComponentRemoved = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/output/data-hidden-component-removed.json"));
7
+ var _formHiddenComponentShowWhenInComponentAndPage = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/forms/form-hidden-component-show-when-in-component-and-page.json"));
8
+ var _dataHiddenComponentShowWhenInComponentAndPage = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/input/data-hidden-component-show-when-in-component-and-page.json"));
9
+ var _dataHiddenComponentShowWhenInComponentAndPageRemoved = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/output/data-hidden-component-show-when-in-component-and-page-removed.json"));
7
10
  var _formHiddenEmbeddedComponent = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/forms/form-hidden-embedded-component.json"));
8
11
  var _dataHiddenEmbeddedComponent = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/input/data-hidden-embedded-component.json"));
9
12
  var _dataHiddenEmbeddedComponentRemoved = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/output/data-hidden-embedded-component-removed.json"));
@@ -34,6 +37,9 @@ var _dataNestedAnswersHiddenByOptionRemoved = _interopRequireDefault(require("..
34
37
  var _formHiddenPage = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/forms/form-hidden-page.json"));
35
38
  var _dataHiddenPage = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/input/data-hidden-page.json"));
36
39
  var _dataHiddenPageRemoved = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/output/data-hidden-page-removed.json"));
40
+ var _formHiddenPageSameComponentReused = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/forms/form-hidden-page-same-component-reused.json"));
41
+ var _dataHiddenPageSameComponentReused = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/input/data-hidden-page-same-component-reused.json"));
42
+ var _dataHiddenPageSameComponentReusedRemoved = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/output/data-hidden-page-same-component-reused-removed.json"));
37
43
  var _formHiddenPageComponentUsedElsewhere = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/forms/form-hidden-page-component-used-elsewhere.json"));
38
44
  var _dataHiddenPageComponentUsedElsewhere = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/input/data-hidden-page-component-used-elsewhere.json"));
39
45
  var _dataHiddenPageComponentUsedElsewhereRemoved = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/output/data-hidden-page-component-used-elsewhere-removed.json"));
@@ -79,9 +85,13 @@ var _copMandecRemoveUnspentConvictionsAfter = _interopRequireDefault(require("..
79
85
  var _formCopAirpax = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/forms/form-cop-airpax.json"));
80
86
  var _copAirpaxRemovePhotosBefore = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/input/cop-airpax-remove-photos-before.json"));
81
87
  var _copAirpaxRemovePhotosAfter = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/output/cop-airpax-remove-photos-after.json"));
88
+ var _copAirpaxChangeWhatHappenedBefore = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/input/cop-airpax-change-what-happened-before.json"));
89
+ var _copAirpaxChangeWhatHappenedAfter = _interopRequireDefault(require("../clear-uncompleted-routes/test-data/output/cop-airpax-change-what-happened-after.json"));
82
90
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
83
91
  // Hidden component
84
92
 
93
+ // Hidden component with show_when in page and component
94
+
85
95
  // Hidden embedded component
86
96
 
87
97
  // Hidden collection component
@@ -102,6 +112,8 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
102
112
 
103
113
  // Hidden page
104
114
 
115
+ // Hidden page containing same component reused
116
+
105
117
  // Hidden page with component used elsewhere
106
118
 
107
119
  // Hidden component with show_when rule referring to a collection
@@ -137,85 +149,104 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
137
149
  describe('FormRenderer', () => {
138
150
  describe('helpers', () => {
139
151
  describe('clearOutUncompletedRoutes', () => {
140
- it('should remove hidden component', () => {
152
+ it('should remove hidden component.', () => {
141
153
  const submissionData = JSON.parse(JSON.stringify(_dataHiddenComponent.default));
142
154
  const form = JSON.parse(JSON.stringify(_formHiddenComponent.default));
143
155
  const result = _index.default.clearOutUncompletedRoutes(form, submissionData);
144
156
  expect(result).toEqual(_dataHiddenComponentRemoved.default);
145
157
  });
146
- it('should remove hidden component embedded in page', () => {
158
+ it('should remove hidden component with show_when in page and component.', () => {
159
+ const submissionData = JSON.parse(JSON.stringify(_dataHiddenComponentShowWhenInComponentAndPage.default));
160
+ const form = JSON.parse(JSON.stringify(_formHiddenComponentShowWhenInComponentAndPage.default));
161
+ const result = _index.default.clearOutUncompletedRoutes(form, submissionData);
162
+ expect(result).toEqual(_dataHiddenComponentShowWhenInComponentAndPageRemoved.default);
163
+ });
164
+ it('should remove hidden component embedded in page.', () => {
147
165
  const submissionData = JSON.parse(JSON.stringify(_dataHiddenEmbeddedComponent.default));
148
166
  const form = JSON.parse(JSON.stringify(_formHiddenEmbeddedComponent.default));
149
167
  const result = _index.default.clearOutUncompletedRoutes(form, submissionData);
150
168
  expect(result).toEqual(_dataHiddenEmbeddedComponentRemoved.default);
151
169
  });
152
- it('should remove hidden collection component', () => {
170
+ it('should remove hidden collection component.', () => {
153
171
  const submissionData = JSON.parse(JSON.stringify(_dataHiddenCollectionComponent.default));
154
172
  const form = JSON.parse(JSON.stringify(_formHiddenCollectionComponent.default));
155
173
  const result = _index.default.clearOutUncompletedRoutes(form, submissionData);
156
174
  expect(result).toEqual(_dataHiddenCollectionComponentRemoved.default);
157
175
  });
158
- it('should remove hidden embedded collection component', () => {
176
+ it('should remove hidden embedded collection component.', () => {
159
177
  const submissionData = JSON.parse(JSON.stringify(_dataHiddenEmbeddedCollectionComponent.default));
160
178
  const form = JSON.parse(JSON.stringify(_formHiddenEmbeddedCollectionComponent.default));
161
179
  const result = _index.default.clearOutUncompletedRoutes(form, submissionData);
162
180
  expect(result).toEqual(_dataHiddenEmbeddedCollectionComponentRemoved.default);
163
181
  });
164
- it('should remove hidden containerised component', () => {
182
+ it('should remove hidden containerised component.', () => {
165
183
  const submissionData = JSON.parse(JSON.stringify(_dataHiddenContainerisedComponent.default));
166
184
  const form = JSON.parse(JSON.stringify(_formHiddenContainerisedComponent.default));
167
185
  const result = _index.default.clearOutUncompletedRoutes(form, submissionData);
168
186
  expect(result).toEqual(_dataHiddenContainerisedComponentRemoved.default);
169
187
  });
170
- it('should remove hidden multi-level containerised components', () => {
188
+ it('should remove hidden multi-level containerised components.', () => {
171
189
  const submissionData = JSON.parse(JSON.stringify(_dataHiddenMultilevelContainerisedComponent.default));
172
190
  const form = JSON.parse(JSON.stringify(_formHiddenMultilevelContainerisedComponent.default));
173
191
  const result = _index.default.clearOutUncompletedRoutes(form, submissionData);
174
192
  expect(result).toEqual(_dataHiddenMultilevelContainerisedComponentRemoved.default);
175
193
  });
176
- it('should remove hidden leaf-level in a multi-level containerised component', () => {
194
+ it('should remove hidden leaf-level in a multi-level containerised component.', () => {
177
195
  const submissionData = JSON.parse(JSON.stringify(_dataHiddenMultilevelContainerisedComponentLeafHidden.default));
178
196
  const form = JSON.parse(JSON.stringify(_formHiddenMultilevelContainerisedComponentLeafHidden.default));
179
197
  const result = _index.default.clearOutUncompletedRoutes(form, submissionData);
180
198
  expect(result).toEqual(_dataHiddenMultilevelContainerisedComponentLeafHiddenRemoved.default);
181
199
  });
182
- it('should remove hidden component with options', () => {
200
+ it('should remove hidden component with options.', () => {
183
201
  const submissionData = JSON.parse(JSON.stringify(_dataHiddenOptions.default));
184
202
  const form = JSON.parse(JSON.stringify(_formHiddenOptions.default));
185
203
  const result = _index.default.clearOutUncompletedRoutes(form, submissionData);
186
204
  expect(result).toEqual(_dataHiddenOptionsRemoved.default);
187
205
  });
188
- it('should remove hidden component with nested questions in options', () => {
206
+ it('should remove hidden component with nested questions in options.', () => {
189
207
  const submissionData = JSON.parse(JSON.stringify(_dataHiddenComponentWithNestedQuestions.default));
190
208
  const form = JSON.parse(JSON.stringify(_formHiddenComponentWithNestedQuestions.default));
191
209
  const result = _index.default.clearOutUncompletedRoutes(form, submissionData);
192
210
  expect(result).toEqual(_dataHiddenComponentWithNestedQuestionsRemoved.default);
193
211
  });
194
- it('should remove answers associated with unselected options in a containerised component', () => {
212
+ it('should remove answers associated with unselected options in a containerised component.', () => {
195
213
  const submissionData = JSON.parse(JSON.stringify(_dataNestedAnswersHiddenByOption.default));
196
214
  const form = JSON.parse(JSON.stringify(_formNestedAnswersHiddenByOption.default));
197
215
  const result = _index.default.clearOutUncompletedRoutes(form, submissionData);
198
216
  expect(result).toEqual(_dataNestedAnswersHiddenByOptionRemoved.default);
199
217
  });
200
- it('should remove hidden page', () => {
218
+ it('should remove hidden page.', () => {
201
219
  const submissionData = JSON.parse(JSON.stringify(_dataHiddenPage.default));
202
220
  const form = JSON.parse(JSON.stringify(_formHiddenPage.default));
203
221
  const result = _index.default.clearOutUncompletedRoutes(form, submissionData);
204
222
  expect(result).toEqual(_dataHiddenPageRemoved.default);
205
223
  });
206
- it('should remove a hidden collection on a page', () => {
224
+ it('should remove hidden page with same component reused.', () => {
225
+ const submissionData = JSON.parse(JSON.stringify(_dataHiddenPageSameComponentReused.default));
226
+ const form = JSON.parse(JSON.stringify(_formHiddenPageSameComponentReused.default));
227
+ const result = _index.default.clearOutUncompletedRoutes(form, submissionData);
228
+ expect(result).toEqual(_dataHiddenPageSameComponentReusedRemoved.default);
229
+ });
230
+
231
+ // TEST FOR 3 components with the same name, a page show_when, 1 of which is shown.
232
+
233
+ // Check the visited thing is working.
234
+
235
+ // Refactor and comment the toArray method.
236
+
237
+ it('should remove a hidden collection on a page.', () => {
207
238
  const submissionData = JSON.parse(JSON.stringify(_dataHiddenPageCollection.default));
208
239
  const form = JSON.parse(JSON.stringify(_formHiddenPageCollection.default));
209
240
  const result = _index.default.clearOutUncompletedRoutes(form, submissionData);
210
241
  expect(result).toEqual(_dataHiddenPageCollectionRemoved.default);
211
242
  });
212
- it('hidden component with show_when rule referring to a collection', () => {
243
+ it('hidden component with show_when rule referring to a collection.', () => {
213
244
  const submissionData = JSON.parse(JSON.stringify(_dataHiddenComponentReferringToCollection.default));
214
245
  const form = JSON.parse(JSON.stringify(_formHiddenComponentReferringToCollection.default));
215
246
  const result = _index.default.clearOutUncompletedRoutes(form, submissionData);
216
247
  expect(result).toEqual(_dataHiddenComponentReferringToCollectionRemoved.default);
217
248
  });
218
- it('hidden component with show_when rule referring to a hidden collection', () => {
249
+ it('hidden component with show_when rule referring to a hidden collection.', () => {
219
250
  const submissionData = JSON.parse(JSON.stringify(_dataHiddenComponentReferringToHiddenCollection.default));
220
251
  const form = JSON.parse(JSON.stringify(_formHiddenComponentReferringToHiddenCollection.default));
221
252
  try {
@@ -225,84 +256,90 @@ describe('FormRenderer', () => {
225
256
  expect(error.message).toContain('It is not possible to reliably clean hidden data when a component is dependent');
226
257
  }
227
258
  });
228
- it('should remove hidden collection components whether they are dependent on data inside or outside the collection', () => {
259
+ it('should remove hidden collection components whether they are dependent on data inside or outside the collection.', () => {
229
260
  const submissionData = JSON.parse(JSON.stringify(_dataHiddenCollectionComponentDependentOnExternalData.default));
230
261
  const form = JSON.parse(JSON.stringify(_formHiddenCollectionComponentDependentOnExternalData.default));
231
262
  const result = _index.default.clearOutUncompletedRoutes(form, submissionData);
232
263
  expect(result).toEqual(_dataHiddenCollectionComponentDependentOnExternalDataRemoved.default);
233
264
  });
234
- it('should not remove component on hidden page if component used elsewhere', () => {
265
+ it('should not remove component on hidden page if component used elsewhere.', () => {
235
266
  const submissionData = JSON.parse(JSON.stringify(_dataHiddenPageComponentUsedElsewhere.default));
236
267
  const form = JSON.parse(JSON.stringify(_formHiddenPageComponentUsedElsewhere.default));
237
268
  const result = _index.default.clearOutUncompletedRoutes(form, submissionData);
238
269
  expect(result).toEqual(_dataHiddenPageComponentUsedElsewhereRemoved.default);
239
270
  });
240
- it('chained show_whens should be resolved from the end of the chain backup to the start', () => {
271
+ it('chained show_whens should be resolved from the end of the chain backup to the start.', () => {
241
272
  const submissionData = JSON.parse(JSON.stringify(_dataChainedComponentShowWhens.default));
242
273
  const form = JSON.parse(JSON.stringify(_formChainedComponentShowWhens.default));
243
274
  const result = _index.default.clearOutUncompletedRoutes(form, submissionData);
244
275
  expect(result).toEqual(_dataChainedComponentShowWhensRemoved.default);
245
276
  });
246
- it('chained show_whens when top level dependency is field within refdata object', () => {
277
+ it('chained show_whens when top level dependency is field within refdata object.', () => {
247
278
  const submissionData = JSON.parse(JSON.stringify(_dataChainedComponentShowWhensRefdata.default));
248
279
  const form = JSON.parse(JSON.stringify(_formChainedComponentShowWhensRefdata.default));
249
280
  const result = _index.default.clearOutUncompletedRoutes(form, submissionData);
250
281
  expect(result).toEqual(_dataChainedComponentShowWhensRefdataRemoved.default);
251
282
  });
252
- it('chained show_whens should be resolved from the end of the chain backup to the start, even if the target and dependent components are in containers thus having segmented paths', () => {
283
+ it('chained show_whens should be resolved from the end of the chain backup to the start, even if the target and dependent components are in containers thus having segmented paths.', () => {
253
284
  const submissionData = JSON.parse(JSON.stringify(_dataChainedComponentShowWhensContainerised.default));
254
285
  const form = JSON.parse(JSON.stringify(_formChainedComponentShowWhensContainerised.default));
255
286
  const result = _index.default.clearOutUncompletedRoutes(form, submissionData);
256
287
  expect(result).toEqual(_dataChainedComponentShowWhensContainerisedRemoved.default);
257
288
  });
258
- it('chained show_whens when the component at the end of the chain is hidden indirectly via page show_when', () => {
289
+ it('chained show_whens when the component at the end of the chain is hidden indirectly via page show_when.', () => {
259
290
  const submissionData = JSON.parse(JSON.stringify(_dataChainedShowWhensPageHidden.default));
260
291
  const form = JSON.parse(JSON.stringify(_formChainedShowWhensPageHidden.default));
261
292
  const result = _index.default.clearOutUncompletedRoutes(form, submissionData);
262
293
  expect(result).toEqual(_dataChainedShowWhensPageHiddenRemoved.default);
263
294
  });
264
- it('chained show_whens when the dependent component is nested single question', () => {
295
+ it('chained show_whens when the dependent component is nested single question.', () => {
265
296
  const submissionData = JSON.parse(JSON.stringify(_dataChainedComponentShowWhensDependentComponentNested.default));
266
297
  const form = JSON.parse(JSON.stringify(_formChainedComponentShowWhensDependentComponentNested.default));
267
298
  const result = _index.default.clearOutUncompletedRoutes(form, submissionData);
268
299
  expect(result).toEqual(_dataChainedComponentShowWhensDependentComponentNestedRemoved.default);
269
300
  });
270
- it('chained show_whens when the target component is nested', () => {
301
+ it('chained show_whens when the target component is nested.', () => {
271
302
  const submissionData = JSON.parse(JSON.stringify(_dataChainedComponentShowWhensTargetComponentNested.default));
272
303
  const form = JSON.parse(JSON.stringify(_formChainedComponentShowWhensTargetComponentNested.default));
273
304
  const result = _index.default.clearOutUncompletedRoutes(form, submissionData);
274
305
  expect(result).toEqual(_dataChainedComponentShowWhensTargetComponentNestedRemoved.default);
275
306
  });
276
- it('chained show_whens when the dependent component is nested entire block', () => {
307
+ it('chained show_whens when the dependent component is nested entire block.', () => {
277
308
  const submissionData = JSON.parse(JSON.stringify(_dataChainedComponentShowWhensDependentComponentNestedBlock.default));
278
309
  const form = JSON.parse(JSON.stringify(_formChainedComponentShowWhensDependentComponentNestedBlock.default));
279
310
  const result = _index.default.clearOutUncompletedRoutes(form, submissionData);
280
311
  expect(result).toEqual(_dataChainedComponentShowWhensDependentComponentNestedBlockRemoved.default);
281
312
  });
282
- it('business interests removed from mandec', () => {
313
+ it('business interests removed from mandec.', () => {
283
314
  const submissionData = JSON.parse(JSON.stringify(_copMandecRemoveBusinessInterestsBefore.default));
284
315
  const form = JSON.parse(JSON.stringify(_formCopMandec.default));
285
316
  const result = _index.default.clearOutUncompletedRoutes(form, submissionData);
286
317
  expect(result).toEqual(_copMandecRemoveBusinessInterestsAfter.default);
287
318
  });
288
- it('criminality removed from mandec', () => {
319
+ it('criminality removed from mandec.', () => {
289
320
  const submissionData = JSON.parse(JSON.stringify(_copMandecRemoveCriminalityBefore.default));
290
321
  const form = JSON.parse(JSON.stringify(_formCopMandec.default));
291
322
  const result = _index.default.clearOutUncompletedRoutes(form, submissionData);
292
323
  expect(result).toEqual(_copMandecRemoveCriminalityAfter.default);
293
324
  });
294
- it('Unspent convictions removed from mandec', () => {
325
+ it('Unspent convictions removed from mandec.', () => {
295
326
  const submissionData = JSON.parse(JSON.stringify(_copMandecRemoveUnspentConvictionsBefore.default));
296
327
  const form = JSON.parse(JSON.stringify(_formCopMandec.default));
297
328
  const result = _index.default.clearOutUncompletedRoutes(form, submissionData);
298
329
  expect(result).toEqual(_copMandecRemoveUnspentConvictionsAfter.default);
299
330
  });
300
- it('photos removed from airpax', () => {
331
+ it('photos removed from airpax.', () => {
301
332
  const submissionData = JSON.parse(JSON.stringify(_copAirpaxRemovePhotosBefore.default));
302
333
  const form = JSON.parse(JSON.stringify(_formCopAirpax.default));
303
334
  const result = _index.default.clearOutUncompletedRoutes(form, submissionData);
304
335
  expect(result).toEqual(_copAirpaxRemovePhotosAfter.default);
305
336
  });
337
+ it('airpax change whatHappened to hide whoDecidedSelection.', () => {
338
+ const submissionData = JSON.parse(JSON.stringify(_copAirpaxChangeWhatHappenedBefore.default));
339
+ const form = JSON.parse(JSON.stringify(_formCopAirpax.default));
340
+ const result = _index.default.clearOutUncompletedRoutes(form, submissionData);
341
+ expect(result).toEqual(_copAirpaxChangeWhatHappenedAfter.default);
342
+ });
306
343
  });
307
344
  });
308
345
  });
@@ -0,0 +1,290 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.removeObjectWithSingleIdFieldInPlace = exports.removeEmptyArraysAndUnusedCollectionIDs = exports.isShowEntity = exports.getNestedQuestionPath = exports.getImmediateParent = exports.getDependencyObjectFromPath = exports.getDependencies = exports.findComponentDefinitionInForm = exports.deleteNodeByPath = exports.deleteCorrespondingMetaInfo = void 0;
7
+ var _Condition = _interopRequireDefault(require("../../../utils/Condition"));
8
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
9
+ /**
10
+ * Given a path, remove a node from this path within an object.
11
+ *
12
+ *
13
+ * @param {Object} obj Javascript object from which the node will be deleted. Updated by the method.
14
+ * @param {String} path A string containing a decimal point delimited path specifying the node to delete.
15
+ * @return Nothing, obj above updated.
16
+ */
17
+
18
+ /* eslint-disable consistent-return, no-param-reassign */
19
+ const deleteNodeByPath = (obj, path) => {
20
+ if (Array.isArray(obj)) {
21
+ // If obj is an array, recursively call deleteNodeByPath on each element
22
+ for (let i = 0; i < obj.length; i += 1) {
23
+ deleteNodeByPath(obj[i], path);
24
+ }
25
+ }
26
+ const keys = path.split('.');
27
+ let current = obj;
28
+ for (let i = 0; i < keys.length - 1; i += 1) {
29
+ current = current[keys[i]];
30
+ if (current === undefined) {
31
+ return;
32
+ }
33
+ }
34
+ if (current[keys[keys.length - 1]]) {
35
+ console.log("Deleting element : ".concat(keys[keys.length - 1]));
36
+ delete current[keys[keys.length - 1]];
37
+ }
38
+ return obj;
39
+ };
40
+
41
+ /**
42
+ * Pruning a collection payload may have resulted in objects that are only left with their 'id' field, which isn't data
43
+ * but added by the renderer to find the activeId. If so, remove these objects entirely as they have been pruned.
44
+ *
45
+ * @param {Array} array Array of objects. Each object which has only 1 remaining field called 'id' should be removed.
46
+ * @return Nothing, array above updated.
47
+ */
48
+ exports.deleteNodeByPath = deleteNodeByPath;
49
+ const removeObjectWithSingleIdFieldInPlace = array => {
50
+ for (let i = array.length - 1; i >= 0; i -= 1) {
51
+ const obj = array[i];
52
+ if (Object.keys(obj).length === 1 && Object.keys(obj)[0] === 'id') {
53
+ array.splice(i, 1);
54
+ }
55
+ }
56
+ };
57
+
58
+ /**
59
+ * Return the immediate parent of a path string passed in.
60
+ * Useful for processing 'options' in a form, as nested fieldIds are placed in the payload at
61
+ * the same level in the heirarchy as the option question they relate to.
62
+ *
63
+ * @param {String} path Decimal point delimited path.
64
+ * @returns {String} Immediate parent of the path passed in.
65
+ */
66
+ exports.removeObjectWithSingleIdFieldInPlace = removeObjectWithSingleIdFieldInPlace;
67
+ const getImmediateParent = path => {
68
+ if (typeof path !== 'string' || !path.includes('.')) {
69
+ return null;
70
+ }
71
+ const parts = path.split('.');
72
+ parts.pop();
73
+ return parts.join('.');
74
+ };
75
+
76
+ /**
77
+ * Questions can be nested within options, eg if you answer 'yes' to a radio question, this can
78
+ * reveal additional nested questions.
79
+ * The path of the fields from these nested questions are at the same level as the original option
80
+ * answer, so this utility derives the nested question path from the option path.
81
+ *
82
+ * @param {String} optionPath Decimal point delimited path
83
+ * @param {String} nestedFieldId fieldId (dataname) of the nested question within the above option
84
+ * @returns {String} Fully qualified path of the nested question
85
+ */
86
+ exports.getImmediateParent = getImmediateParent;
87
+ const getNestedQuestionPath = (optionPath, nestedFieldId) => {
88
+ const parentPath = getImmediateParent(optionPath);
89
+ return parentPath ? "".concat(parentPath, ".").concat(nestedFieldId) : nestedFieldId;
90
+ };
91
+
92
+ /**
93
+ * Helper method to establish all the payload paths (dependencies) that an entity (page or component) is
94
+ * dependent on through its show_when rule.
95
+ *
96
+ * This will be used to build a graph of chained dependencies to establish in which order
97
+ * to resolve dependencies. The exact rule is not required at this point, just the dependencies.
98
+ *
99
+ * The form specification allows complex show_when blocks including 1...n levels of nesting, so
100
+ * recursively search through the show_when block looking for all 'field' data items.
101
+ *
102
+ * @param {Object} entity Entity whose show_when rule is to be searched for 'field' data items within.
103
+ * @returns {Set} Set of payload paths that the entity (page or component) is dependent on.
104
+ */
105
+ exports.getNestedQuestionPath = getNestedQuestionPath;
106
+ const getDependencies = entity => {
107
+ const findShowWhenFields = (showWhenObject, showWhenFields) => {
108
+ if (typeof showWhenObject === 'object' && showWhenObject !== null) {
109
+ if (Array.isArray(showWhenObject)) {
110
+ showWhenObject.forEach(value => {
111
+ findShowWhenFields(value, showWhenFields);
112
+ });
113
+ } else {
114
+ Object.keys(showWhenObject).forEach(key => {
115
+ if (key === 'field') {
116
+ showWhenFields.push(showWhenObject[key]);
117
+ }
118
+ findShowWhenFields(showWhenObject[key], showWhenFields);
119
+ });
120
+ }
121
+ }
122
+ return showWhenFields;
123
+ };
124
+ return entity.show_when ? new Set(findShowWhenFields(entity.show_when, []) || []) : null;
125
+ };
126
+
127
+ /**
128
+ * Some show_when field values point to data items that are within objects provided by
129
+ * external calls to refdata, eg modeOfTransport.id. These won't map directly to the path
130
+ * keyed components in the allComponents map, so go back up levels in the path until we find
131
+ * the component that creates this field.
132
+ *
133
+ * This component might not be found at all, as the dependency might be on a field that is either
134
+ * provided by cop-ui (eg jobHolderStaffDetails.linemanagerEmail), or by the "addToFormData" function
135
+ * (eg epmsSubmitted). These will be leaf level in the dependency chain so component is not required.
136
+ *
137
+ * @param {String} optionPath Decimal point delimited path
138
+ * @param {String} nestedFieldId fieldId (dataname) of the nested question within the above option
139
+ * @returns {String} Fully qualified path of the nested question
140
+ *
141
+ */
142
+ exports.getDependencies = getDependencies;
143
+ const getDependencyObjectFromPath = (dependencyPath, allComponents) => {
144
+ const segments = dependencyPath.split(".");
145
+ for (let i = segments.length; i > 0; i -= 1) {
146
+ const currentPath = segments.slice(0, i).join(".");
147
+ const dependencyObject = allComponents.get(currentPath);
148
+ if (dependencyObject) return dependencyObject;
149
+ }
150
+ return null;
151
+ };
152
+
153
+ /**
154
+ *
155
+ * Evaluate the show_when rule to establish if the component should be shown (and the
156
+ * payload data should not be pruned). If there is no show_when rule, then return true.
157
+ *
158
+ * @param {*} entity A page or component that may have a show_when rule associated with it
159
+ * @param {*} data The payload data used to evaluate the show_when rule
160
+ * @returns {boolean} true if the show_when rule evaluate to true, or there is no show_when rule
161
+ */
162
+ exports.getDependencyObjectFromPath = getDependencyObjectFromPath;
163
+ const isShowEntity = (entity, data) => {
164
+ var _entity$show_when;
165
+ // If there is no rule set, then the entity can be shown
166
+ if (!entity.show_when) {
167
+ return true;
168
+ }
169
+ if (((_entity$show_when = entity.show_when) === null || _entity$show_when === void 0 ? void 0 : _entity$show_when.type) === "or") {
170
+ return _Condition.default.meetsOne(entity, data);
171
+ }
172
+ return _Condition.default.meetsAll(entity, data);
173
+ };
174
+
175
+ /**
176
+ *
177
+ * Components can be assigned to pages in 2 ways in the form specification:
178
+ *
179
+ * 1 - They can be included in the page's components array with the 'use' field, e.g.
180
+ * {
181
+ * "use": "port"
182
+ * }
183
+ * This "use" value will normally match a component's id, but can match its fieldId
184
+ * NB. In this case, a show_when rule can be applied here, which will supercede any show_when in the component. e.g.
185
+ *
186
+ * {
187
+ * "use": "port",
188
+ * "show_when": ....
189
+ * }
190
+ *
191
+ * 2 - The entire component can be embedded as an entry in the page's component array.
192
+ *
193
+ *
194
+ * @param {*} componentId The id of the component to find in the form.
195
+ * @param {*} componentByIdMap A map of all the form's components keyed on Id, for better performance than searching the form.
196
+ * @param {*} componentByFieldIdMap A map of all the form's components keyed on fieldId, for better performance than searching the form.
197
+ * @returns {Object} A cloned component object, containing the full definition of that component.
198
+ */
199
+ exports.isShowEntity = isShowEntity;
200
+ const findComponentDefinitionInForm = (pageComponentDef, componentByIdMap, componentByFieldIdMap) => {
201
+ var _ref, _componentByIdMap$get;
202
+ const componentInForm = (_ref = (_componentByIdMap$get = componentByIdMap.get(pageComponentDef.use)) !== null && _componentByIdMap$get !== void 0 ? _componentByIdMap$get : componentByFieldIdMap.get(pageComponentDef.use)) !== null && _ref !== void 0 ? _ref : pageComponentDef;
203
+ if (pageComponentDef.use && pageComponentDef.show_when) {
204
+ componentInForm.show_when = pageComponentDef.show_when;
205
+ }
206
+ // Retun clone of component, so subsequent processing can make changes to it without changing the form
207
+ return JSON.parse(JSON.stringify(componentInForm));
208
+ };
209
+
210
+ /**
211
+ *
212
+ * When documents are added to the payload of type multifile, they are also added to a section of the payload
213
+ * 'meta', specifically an array 'documents'. When we remove the multifile elements, we need to remove
214
+ * the corresponding meta.document entries.
215
+ *
216
+ * @param {*} component The component definition being deleted that needs corresponding meta data also deleted
217
+ * @param {*} collectionDataObject The payload containing the file data being deleted (for which the corresponding meta needs deleting)
218
+ * @param {*} formData The entire payload, which will include the meta section
219
+ * @returns Nothing, as the formData will be updated in situ
220
+ */
221
+ exports.findComponentDefinitionInForm = findComponentDefinitionInForm;
222
+ const deleteCorrespondingMetaInfo = (component, collectionDataObject, formData) => {
223
+ const {
224
+ meta: {
225
+ documents
226
+ }
227
+ } = formData;
228
+ const fileDataBeingDeleted = collectionDataObject[component.fieldId];
229
+ if (!documents || !fileDataBeingDeleted) return;
230
+ const fileDataAsArray = Array.isArray(fileDataBeingDeleted) ? fileDataBeingDeleted : [fileDataBeingDeleted];
231
+ // Iterate backwards to avoid index shifting when removing elements
232
+ for (let i = fileDataAsArray.length - 1; i >= 0; i -= 1) {
233
+ const matchIndex = documents.findIndex(metaDocument => metaDocument.url === fileDataAsArray[i].url);
234
+ if (matchIndex !== -1) {
235
+ documents.splice(matchIndex, 1);
236
+ }
237
+ }
238
+ };
239
+ /**
240
+ * After the payload has been cleansed of individual data items, empty arrays and objects may remain.
241
+ * Removing an array (when the payload for a collection) may leave a redundant activeId field. The active Id
242
+ * fields are not part of the payload data, but added by the react renderer to track which collection object
243
+ * is currently being worked on, so can be removed.
244
+ *
245
+ * To tidy this all up, recursively empty arrays and their associated "ActiveId" fields from a nested payload.
246
+ *
247
+ * This function traverses a given payload, which can be an array or an object, and performs the following operations:
248
+ * 1. If an empty array is found inside an array, it is removed using `splice`.
249
+ * 2. If an empty array is found inside an object:
250
+ * - It is removed from the object.
251
+ * - If there is a corresponding `<key>ActiveId` field, that field is also removed.
252
+ * 3. The function operates recursively to handle deeply nested structures.
253
+ *
254
+ * @param {any} payload - The input data structure, which can be an array or an object.
255
+ */
256
+ exports.deleteCorrespondingMetaInfo = deleteCorrespondingMetaInfo;
257
+ const removeEmptyArraysAndUnusedCollectionIDs = payload => {
258
+ if (Array.isArray(payload)) {
259
+ for (let i = payload.length - 1; i >= 0; i -= 1) {
260
+ if (Array.isArray(payload[i]) && payload[i].length === 0) {
261
+ payload.splice(i, 1);
262
+ } else {
263
+ removeEmptyArraysAndUnusedCollectionIDs(payload[i]); // Recurse for nested structures
264
+ }
265
+ // When unwinding out of the recursion, we may have emptied an object which is the remaining element of an
266
+ // array, in which case remove the element
267
+ if (typeof payload[i] === 'object' && Object.keys(payload[i]).length === 0) {
268
+ payload.splice(i, 1);
269
+ }
270
+ }
271
+ } else if (payload !== null && typeof payload === 'object') {
272
+ Object.keys(payload).forEach(key => {
273
+ if (Array.isArray(payload[key]) && payload[key].length === 0) {
274
+ // If the array being removed has an activeId associated with it, remove it
275
+ if (payload["".concat(key, "ActiveId")]) {
276
+ delete payload["".concat(key, "ActiveId")];
277
+ console.log("Deleted element : ".concat(key, "ActiveId}"));
278
+ }
279
+ delete payload["".concat(key, "ActiveId")];
280
+ if (payload[key]) {
281
+ delete payload[key];
282
+ console.log("Deleted element : ".concat(key));
283
+ }
284
+ } else {
285
+ removeEmptyArraysAndUnusedCollectionIDs(payload[key]); // Recurse for nested structures
286
+ }
287
+ });
288
+ }
289
+ };
290
+ exports.removeEmptyArraysAndUnusedCollectionIDs = removeEmptyArraysAndUnusedCollectionIDs;