@defra/forms-model 3.0.493 → 3.0.495

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,107 @@
1
+ import type Joi from 'joi'
2
+ import { type ValidationError } from 'joi'
3
+
4
+ import {
5
+ FormDefinitionError,
6
+ FormDefinitionErrorType,
7
+ formDefinitionErrors,
8
+ type FormDefinitionErrorCause
9
+ } from '~/src/form/form-manager/types.js'
10
+
11
+ /**
12
+ * Checks and applies an `errorType` and also an `errorCode` for known errors
13
+ */
14
+ export const checkErrors = (
15
+ formErrors: FormDefinitionError | FormDefinitionError[]
16
+ ) => {
17
+ const possibleErrors = Array.isArray(formErrors) ? formErrors : [formErrors]
18
+
19
+ return function (errors: Joi.ErrorReport[]) {
20
+ errors.forEach((err) => {
21
+ if (err.local.errorType) {
22
+ return
23
+ }
24
+
25
+ for (const formError of possibleErrors) {
26
+ const errorDetails = formDefinitionErrors[formError]
27
+
28
+ // Joi's `context.key` will be the index for arrays
29
+ // in which case use the path, otherwise use the key
30
+ const keyMatch =
31
+ typeof err.local.key === 'number' ? err.local.path : err.local.key
32
+
33
+ if (
34
+ errorDetails.type === FormDefinitionErrorType.Unique &&
35
+ err.code === 'array.unique' &&
36
+ keyMatch === errorDetails.key
37
+ ) {
38
+ err.local.errorCode = formError
39
+ err.local.errorType = FormDefinitionErrorType.Unique
40
+ return
41
+ }
42
+
43
+ if (
44
+ errorDetails.type === FormDefinitionErrorType.Ref &&
45
+ err.code === 'any.only' &&
46
+ keyMatch === errorDetails.key
47
+ ) {
48
+ err.local.errorCode = formError
49
+ err.local.errorType = FormDefinitionErrorType.Ref
50
+ return
51
+ }
52
+
53
+ err.local.errorType = FormDefinitionErrorType.Type
54
+ }
55
+ })
56
+ return errors
57
+ }
58
+ }
59
+
60
+ /**
61
+ * Get the custom errors from a form definition joi validation error
62
+ */
63
+ export function getErrors(
64
+ validationError: ValidationError | undefined
65
+ ): FormDefinitionErrorCause[] {
66
+ return (
67
+ validationError?.details.map((detail) => {
68
+ if (
69
+ detail.context?.errorType === FormDefinitionErrorType.Unique &&
70
+ detail.context.errorCode
71
+ ) {
72
+ return {
73
+ id: /** @type {FormDefinitionError} */ detail.context.errorCode,
74
+ type: FormDefinitionErrorType.Unique,
75
+ message: detail.message,
76
+ detail: {
77
+ path: detail.path,
78
+ pos: detail.context.pos,
79
+ dupePos: detail.context.dupePos
80
+ }
81
+ }
82
+ }
83
+
84
+ if (
85
+ detail.context?.errorType === FormDefinitionErrorType.Ref &&
86
+ detail.context.errorCode
87
+ ) {
88
+ return {
89
+ id: /** @type {FormDefinitionError} */ detail.context.errorCode,
90
+ type: FormDefinitionErrorType.Ref,
91
+ message: detail.message,
92
+ detail: {
93
+ path: detail.path
94
+ }
95
+ }
96
+ }
97
+
98
+ // Catch all others
99
+ return {
100
+ id: FormDefinitionError.Other,
101
+ type: FormDefinitionErrorType.Type,
102
+ message: detail.message,
103
+ detail: detail.context
104
+ }
105
+ }) ?? []
106
+ )
107
+ }
@@ -23,8 +23,8 @@ export enum FormDefinitionErrorType {
23
23
 
24
24
  // Enum for errors that can exist in a form definition
25
25
  export enum FormDefinitionError {
26
- UniquePagePath = 'unique_page_path',
27
26
  UniquePageId = 'unique_page_id',
27
+ UniquePagePath = 'unique_page_path',
28
28
  UniquePageComponentId = 'unique_page_component_id',
29
29
  UniquePageComponentName = 'unique_page_component_name',
30
30
  UniqueSectionName = 'unique_section_name',
@@ -46,11 +46,7 @@ export enum FormDefinitionError {
46
46
  Other = 'other'
47
47
  }
48
48
 
49
- export const N = Symbol('AnyNumber')
50
-
51
- export type ErrorMatchPath = (string | typeof N)[]
52
49
  export interface ErrorMatchValue {
53
- path: ErrorMatchPath
54
50
  key: string
55
51
  type: FormDefinitionErrorType
56
52
  }
@@ -60,107 +56,86 @@ export type FormDefinitionErrors = Record<FormDefinitionError, ErrorMatchValue>
60
56
  // The errors that can exist in the form definition
61
57
  export const formDefinitionErrors: FormDefinitionErrors = {
62
58
  [FormDefinitionError.UniquePagePath]: {
63
- path: ['pages', N],
64
59
  key: 'path',
65
60
  type: FormDefinitionErrorType.Unique
66
61
  },
67
62
  [FormDefinitionError.UniquePageId]: {
68
- path: ['pages', N],
69
63
  key: 'id',
70
64
  type: FormDefinitionErrorType.Unique
71
65
  },
72
66
  [FormDefinitionError.UniquePageComponentId]: {
73
- path: ['pages', N, 'components', N],
74
67
  key: 'id',
75
68
  type: FormDefinitionErrorType.Unique
76
69
  },
77
70
  [FormDefinitionError.UniquePageComponentName]: {
78
- path: ['pages', N, 'components', N],
79
71
  key: 'name',
80
72
  type: FormDefinitionErrorType.Unique
81
73
  },
82
74
  [FormDefinitionError.UniqueSectionName]: {
83
- path: ['sections', N],
84
75
  key: 'name',
85
76
  type: FormDefinitionErrorType.Unique
86
77
  },
87
78
  [FormDefinitionError.UniqueSectionTitle]: {
88
- path: ['sections', N],
89
79
  key: 'title',
90
80
  type: FormDefinitionErrorType.Unique
91
81
  },
92
82
  [FormDefinitionError.UniqueListId]: {
93
- path: ['lists', N],
94
83
  key: 'id',
95
84
  type: FormDefinitionErrorType.Unique
96
85
  },
97
86
  [FormDefinitionError.UniqueListTitle]: {
98
- path: ['lists', N],
99
87
  key: 'title',
100
88
  type: FormDefinitionErrorType.Unique
101
89
  },
102
90
  [FormDefinitionError.UniqueListName]: {
103
- path: ['lists', N],
104
91
  key: 'name',
105
92
  type: FormDefinitionErrorType.Unique
106
93
  },
107
94
  [FormDefinitionError.UniqueConditionDisplayName]: {
108
- path: ['conditions', N],
109
95
  key: 'displayName',
110
96
  type: FormDefinitionErrorType.Unique
111
97
  },
112
98
  [FormDefinitionError.UniqueConditionId]: {
113
- path: ['conditions', N],
114
99
  key: 'id',
115
100
  type: FormDefinitionErrorType.Unique
116
101
  },
117
102
  [FormDefinitionError.UniqueListItemId]: {
118
- path: ['lists', N, 'items', N],
119
103
  key: 'id',
120
104
  type: FormDefinitionErrorType.Unique
121
105
  },
122
106
  [FormDefinitionError.UniqueListItemText]: {
123
- path: ['lists', N, 'items', N],
124
107
  key: 'text',
125
108
  type: FormDefinitionErrorType.Unique
126
109
  },
127
110
  [FormDefinitionError.UniqueListItemValue]: {
128
- path: ['lists', N, 'items', N],
129
111
  key: 'value',
130
112
  type: FormDefinitionErrorType.Unique
131
113
  },
132
114
  [FormDefinitionError.RefPageCondition]: {
133
- path: ['pages', N, 'condition'],
134
115
  key: 'condition',
135
116
  type: FormDefinitionErrorType.Ref
136
117
  },
137
118
  [FormDefinitionError.RefConditionComponentId]: {
138
- path: ['conditions', N, 'items', N, 'componentId'],
139
119
  key: 'componentId',
140
120
  type: FormDefinitionErrorType.Ref
141
121
  },
142
122
  [FormDefinitionError.RefConditionListId]: {
143
- path: ['conditions', N, 'items', N, 'value', 'listId'],
144
123
  key: 'listId',
145
124
  type: FormDefinitionErrorType.Ref
146
125
  },
147
126
  [FormDefinitionError.RefConditionItemId]: {
148
- path: ['conditions', N, 'items', N, 'value', 'itemId'],
149
127
  key: 'itemId',
150
128
  type: FormDefinitionErrorType.Ref
151
129
  },
152
130
  [FormDefinitionError.RefConditionConditionId]: {
153
- path: ['conditions', N, 'items', N, 'conditionId'],
154
131
  key: 'conditionId',
155
132
  type: FormDefinitionErrorType.Ref
156
133
  },
157
134
  [FormDefinitionError.RefPageComponentList]: {
158
- path: ['pages', N, 'components', N, 'list'],
159
135
  key: 'list',
160
136
  type: FormDefinitionErrorType.Ref
161
137
  },
162
138
  [FormDefinitionError.Other]: {
163
- path: [],
164
139
  key: '',
165
140
  type: FormDefinitionErrorType.Type
166
141
  }
@@ -6,7 +6,7 @@ import {
6
6
  type PageQuestion,
7
7
  type PageRepeat
8
8
  } from '~/src/form/form-definition/types.js'
9
- import { ComponentType } from '~/src/index.js'
9
+ import { ComponentType, hasFormField } from '~/src/index.js'
10
10
  import {
11
11
  ControllerNames,
12
12
  ControllerTypes
@@ -153,3 +153,22 @@ export function omitFileUploadComponent(page: Page | undefined): boolean {
153
153
  }
154
154
  return false
155
155
  }
156
+
157
+ /**
158
+ * Gets page title, or title of first question (if no page title set)
159
+ * @param {Page} page
160
+ * @returns {string}
161
+ */
162
+ export function getPageTitle(page: Page) {
163
+ if (page.title !== '') {
164
+ return page.title
165
+ }
166
+
167
+ if (hasComponentsEvenIfNoNext(page)) {
168
+ const firstComp = page.components.find(hasFormField)
169
+ if (firstComp) {
170
+ return firstComp.title
171
+ }
172
+ }
173
+ return 'Page title unknown'
174
+ }
@@ -8,6 +8,7 @@ export { PageTypes } from '~/src/pages/page-types.js'
8
8
  export {
9
9
  controllerNameFromPath,
10
10
  getPageDefaults,
11
+ getPageTitle,
11
12
  hasComponents,
12
13
  hasComponentsEvenIfNoNext,
13
14
  hasFormComponents,