@defra/forms-model 3.0.429 → 3.0.431

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 (49) hide show
  1. package/README.md +163 -1
  2. package/dist/module/common/pagination/index.js +2 -2
  3. package/dist/module/common/pagination/index.js.map +1 -1
  4. package/dist/module/common/search/index.js +4 -4
  5. package/dist/module/common/search/index.js.map +1 -1
  6. package/dist/module/common/sorting/index.js +2 -2
  7. package/dist/module/common/sorting/index.js.map +1 -1
  8. package/dist/module/form/form-definition/index.js +156 -156
  9. package/dist/module/form/form-definition/index.js.map +1 -1
  10. package/dist/module/form/form-editor/index.js +47 -37
  11. package/dist/module/form/form-editor/index.js.map +1 -1
  12. package/dist/module/form/form-editor/types.js.map +1 -1
  13. package/dist/module/form/form-manager/index.js +3 -3
  14. package/dist/module/form/form-manager/index.js.map +1 -1
  15. package/dist/module/form/form-metadata/index.js +34 -34
  16. package/dist/module/form/form-metadata/index.js.map +1 -1
  17. package/dist/module/form/form-submission/index.js +13 -13
  18. package/dist/module/form/form-submission/index.js.map +1 -1
  19. package/dist/module/types/joi-to-json.d.js +2 -0
  20. package/dist/module/types/joi-to-json.d.js.map +1 -0
  21. package/dist/types/common/pagination/index.d.ts.map +1 -1
  22. package/dist/types/common/search/index.d.ts.map +1 -1
  23. package/dist/types/common/sorting/index.d.ts.map +1 -1
  24. package/dist/types/form/form-definition/index.d.ts.map +1 -1
  25. package/dist/types/form/form-editor/index.d.ts +17 -7
  26. package/dist/types/form/form-editor/index.d.ts.map +1 -1
  27. package/dist/types/form/form-editor/types.d.ts +45 -1
  28. package/dist/types/form/form-editor/types.d.ts.map +1 -1
  29. package/dist/types/form/form-manager/index.d.ts.map +1 -1
  30. package/dist/types/form/form-metadata/index.d.ts.map +1 -1
  31. package/dist/types/form/form-submission/index.d.ts.map +1 -1
  32. package/package.json +6 -4
  33. package/scripts/generate-schemas.js +238 -0
  34. package/scripts/schema-modules/constants.js +39 -0
  35. package/scripts/schema-modules/schema-processors.js +109 -0
  36. package/scripts/schema-modules/schema-simplifiers.js +351 -0
  37. package/scripts/schema-modules/title-processors.js +327 -0
  38. package/scripts/schema-modules/types.js +21 -0
  39. package/scripts/schema-modules/utils.js +41 -0
  40. package/src/common/pagination/index.ts +8 -1
  41. package/src/common/search/index.ts +17 -3
  42. package/src/common/sorting/index.ts +8 -2
  43. package/src/form/form-definition/index.ts +567 -238
  44. package/src/form/form-editor/index.ts +207 -24
  45. package/src/form/form-editor/types.ts +69 -0
  46. package/src/form/form-manager/index.ts +11 -2
  47. package/src/form/form-metadata/index.ts +118 -40
  48. package/src/form/form-submission/index.ts +33 -10
  49. package/src/types/joi-to-json.d.ts +15 -0
@@ -17,6 +17,8 @@ export enum QuestionTypeSubGroup {
17
17
  export const pageTypeSchema = Joi.string()
18
18
  .required()
19
19
  .valid('question', 'guidance')
20
+ .description('Type of page - either a question page or guidance page')
21
+
20
22
  export const questionTypeSchema = Joi.string()
21
23
  .required()
22
24
  .valid(
@@ -32,6 +34,7 @@ export const questionTypeSchema = Joi.string()
32
34
  ComponentType.RadiosField,
33
35
  ComponentType.AutocompleteField
34
36
  )
37
+ .description('The high-level type of question, including grouped types')
35
38
 
36
39
  export const questionTypeFullSchema = Joi.string()
37
40
  .required()
@@ -50,6 +53,7 @@ export const questionTypeFullSchema = Joi.string()
50
53
  ComponentType.RadiosField,
51
54
  ComponentType.AutocompleteField
52
55
  )
56
+ .description('The specific component type to use for this question')
53
57
 
54
58
  export const writtenAnswerSubSchema = Joi.string()
55
59
  .required()
@@ -58,6 +62,8 @@ export const writtenAnswerSubSchema = Joi.string()
58
62
  ComponentType.MultilineTextField,
59
63
  ComponentType.NumberField
60
64
  )
65
+ .description('Subtype for written answer questions')
66
+
61
67
  export const dateSubSchema = Joi.string()
62
68
  .required()
63
69
  .valid(ComponentType.DatePartsField, ComponentType.MonthYearField)
@@ -69,59 +75,226 @@ export const listSubSchema = Joi.string()
69
75
  ComponentType.RadiosField,
70
76
  ComponentType.AutocompleteField
71
77
  )
78
+ .description('Subtype for date-related questions')
79
+
80
+ export const nameSchema = Joi.string()
81
+ .trim()
82
+ .required()
83
+ .description('Unique identifier for the field')
84
+
85
+ export const questionSchema = Joi.string()
86
+ .trim()
87
+ .required()
88
+ .description('The question text displayed to the user')
89
+
90
+ export const hintTextSchema = Joi.string()
91
+ .trim()
92
+ .optional()
93
+ .allow('')
94
+ .description('Optional guidance text displayed below the question')
72
95
 
73
- export const nameSchema = Joi.string().trim().required()
74
- export const questionSchema = Joi.string().trim().required()
75
- export const hintTextSchema = Joi.string().trim().optional().allow('')
76
96
  export const questionOptionalSchema = Joi.string()
77
97
  .trim()
78
98
  .optional()
79
99
  .valid('', 'true')
80
- export const shortDescriptionSchema = Joi.string().trim().required()
81
- export const pageHeadingAndGuidanceSchema = Joi.string().trim().optional()
82
- export const pageHeadingSchema = Joi.string().trim().required()
83
- export const guidanceTextSchema = Joi.string().trim()
84
- export const needDeclarationSchema = Joi.string().trim().required()
85
- export const declarationTextSchema = Joi.string().trim().required()
86
- export const exactFilesSchema = Joi.number().empty('').integer().min(1).max(25)
87
- export const minFilesSchema = Joi.number().empty('').integer().min(0).max(25)
88
- export const maxFilesSchema = Joi.number().empty('').integer().min(1).max(25)
89
- export const minSchema = Joi.number().empty('').integer()
90
- export const maxSchema = Joi.number().empty('').integer()
91
- export const minLengthSchema = Joi.number().empty('').integer().min(1)
92
- export const maxLengthSchema = Joi.number().empty('').integer().min(1)
93
- export const maxFutureSchema = Joi.number().empty('').integer().min(0)
94
- export const maxPastSchema = Joi.number().empty('').integer().min(0)
95
- export const precisionSchema = Joi.number().empty('').integer().min(0).max(5)
96
- export const prefixSchema = Joi.string().trim().optional().allow('')
97
- export const regexSchema = Joi.string().optional().allow('')
98
- export const rowsSchema = Joi.number().empty('').integer().min(1)
99
- export const suffixSchema = Joi.string().trim().optional().allow('')
100
- export const classesSchema = Joi.string().trim().optional().allow('')
100
+ .description(
101
+ 'Indicates whether a question is optional. Empty string or "true" values are accepted.'
102
+ )
103
+
104
+ export const exactFilesSchema = Joi.number()
105
+ .empty('')
106
+ .integer()
107
+ .min(1)
108
+ .max(25)
109
+ .description(
110
+ 'Specifies the exact number of files required for upload. Must be between 1 and 25.'
111
+ )
112
+
113
+ export const minFilesSchema = Joi.number()
114
+ .empty('')
115
+ .integer()
116
+ .min(0)
117
+ .max(25)
118
+ .description(
119
+ 'Minimum number of files required for upload. Must be between 0 and 25.'
120
+ )
121
+
122
+ export const maxFilesSchema = Joi.number()
123
+ .empty('')
124
+ .integer()
125
+ .min(1)
126
+ .max(25)
127
+ .description(
128
+ 'Maximum number of files allowed for upload. Must be between 1 and 25.'
129
+ )
130
+
101
131
  export const fileTypesSchema = Joi.array()
102
132
  .items(Joi.string())
103
133
  .single()
104
134
  .empty(null)
105
135
  .default([])
136
+ .description(
137
+ 'Array of allowed file types. Can be provided as a single value or an array.'
138
+ )
139
+
106
140
  export const documentTypesSchema = Joi.array()
107
141
  .items(Joi.string())
108
142
  .single()
109
143
  .empty(null)
110
144
  .default([])
145
+ .description(
146
+ 'Array of allowed document types. Can be provided as a single value or an array.'
147
+ )
148
+
111
149
  export const imageTypesSchema = Joi.array()
112
150
  .items(Joi.string())
113
151
  .single()
114
152
  .empty(null)
115
153
  .default([])
154
+ .description(
155
+ 'Array of allowed image types. Can be provided as a single value or an array.'
156
+ )
157
+
116
158
  export const tabularDataTypesSchema = Joi.array()
117
159
  .items(Joi.string())
118
160
  .single()
119
161
  .empty(null)
120
162
  .default([])
163
+ export const enhancedActionSchema = Joi.string()
164
+ .trim()
165
+ .optional()
166
+ .allow('')
167
+ .description('Action field that can include enhanced functionality')
168
+
169
+ export const radioIdSchema = Joi.string()
170
+ .trim()
171
+ .optional()
172
+ .allow('')
173
+ .description('Unique identifier for radio options')
174
+
175
+ export const radioLabelSchema = Joi.string()
176
+ .trim()
177
+ .required()
178
+ .description('The visible text shown next to radio options')
179
+
180
+ export const radioHintSchema = Joi.string()
181
+ .trim()
182
+ .optional()
183
+ .allow('')
184
+ .description(
185
+ 'Optional hint text displayed with radio buttons to provide additional guidance'
186
+ )
187
+
188
+ export const radioValueSchema = Joi.string()
189
+ .trim()
190
+ .optional()
191
+ .allow('')
192
+ .description(
193
+ 'Array of allowed tabular data types. Can be provided as a single value or an array.'
194
+ )
195
+
196
+ export const shortDescriptionSchema = Joi.string()
197
+ .trim()
198
+ .required()
199
+ .description('Brief description of the question for internal use')
200
+
201
+ export const pageHeadingAndGuidanceSchema = Joi.string()
202
+ .trim()
203
+ .optional()
204
+ .description('Combined heading and guidance for the page')
205
+
206
+ export const pageHeadingSchema = Joi.string()
207
+ .trim()
208
+ .required()
209
+ .description('Main heading displayed at the top of the page')
210
+
211
+ export const guidanceTextSchema = Joi.string()
212
+ .trim()
213
+ .description('Guidance text to assist users in completing the page')
214
+
215
+ export const needDeclarationSchema = Joi.string()
216
+ .trim()
217
+ .required()
218
+ .description('Whether a declaration is needed')
219
+
220
+ export const declarationTextSchema = Joi.string()
221
+ .trim()
222
+ .required()
223
+ .description('Text of the declaration that users must agree to')
224
+
225
+ export const minSchema = Joi.number()
226
+ .empty('')
227
+ .integer()
228
+ .description('Minimum value for numeric inputs')
229
+
230
+ export const maxSchema = Joi.number()
231
+ .empty('')
232
+ .integer()
233
+ .description('Maximum value for numeric inputs')
234
+
235
+ export const minLengthSchema = Joi.number()
236
+ .empty('')
237
+ .integer()
238
+ .min(1)
239
+ .description('Minimum character length for text inputs')
240
+
241
+ export const maxLengthSchema = Joi.number()
242
+ .empty('')
243
+ .integer()
244
+ .min(1)
245
+ .description('Maximum character length for text inputs')
246
+
247
+ export const maxFutureSchema = Joi.number()
248
+ .empty('')
249
+ .integer()
250
+ .min(1)
251
+ .description('Maximum days in the future allowed for date inputs')
252
+
253
+ export const maxPastSchema = Joi.number()
254
+ .empty('')
255
+ .integer()
256
+ .min(1)
257
+ .description('Maximum days in the past allowed for date inputs')
258
+
259
+ export const precisionSchema = Joi.number()
260
+ .empty('')
261
+ .integer()
262
+ .min(1)
263
+ .description('Decimal precision for numeric inputs')
264
+
265
+ export const prefixSchema = Joi.string()
266
+ .trim()
267
+ .optional()
268
+ .allow('')
269
+ .description('Text to display before the input (e.g., £)')
270
+
271
+ export const regexSchema = Joi.string()
272
+ .optional()
273
+ .allow('')
274
+ .description('Regular expression pattern for validation')
275
+
276
+ export const rowsSchema = Joi.number()
277
+ .empty('')
278
+ .integer()
279
+ .min(1)
280
+ .description('Number of rows for multiline text fields')
281
+
282
+ export const suffixSchema = Joi.string()
283
+ .trim()
284
+ .optional()
285
+ .allow('')
286
+ .description('Text to display after the input (e.g., kg)')
287
+
288
+ export const classesSchema = Joi.string()
289
+ .trim()
290
+ .optional()
291
+ .allow('')
292
+ .description('Custom CSS classes to apply to the component')
121
293
 
122
294
  export const questionDetailsFullSchema = {
123
295
  classesSchema,
124
296
  documentTypesSchema,
297
+ enhancedActionSchema,
125
298
  exactFilesSchema,
126
299
  fileTypesSchema,
127
300
  hintTextSchema,
@@ -140,6 +313,10 @@ export const questionDetailsFullSchema = {
140
313
  questionOptionalSchema,
141
314
  questionSchema,
142
315
  questionTypeFullSchema,
316
+ radioHintSchema,
317
+ radioIdSchema,
318
+ radioLabelSchema,
319
+ radioValueSchema,
143
320
  regexSchema,
144
321
  rowsSchema,
145
322
  shortDescriptionSchema,
@@ -159,6 +336,7 @@ export const formEditorInputPageKeys = {
159
336
  export const formEditorInputPageSchema = Joi.object<FormEditorInputPage>()
160
337
  .keys(formEditorInputPageKeys)
161
338
  .required()
339
+ .description('Input schema for creating a new page in the form editor')
162
340
 
163
341
  export const formEditorInputheckAnswersSettingsKeys = {
164
342
  declarationText: shortDescriptionSchema
@@ -172,6 +350,7 @@ export const formEditorInputCheckAnswersSettingSchema =
172
350
  Joi.object<FormEditorInputCheckAnswersSettings>()
173
351
  .keys(formEditorInputheckAnswersSettingsKeys)
174
352
  .required()
353
+ .description('Configuration for the check-answers page')
175
354
 
176
355
  export const formEditorInputQuestionKeys = {
177
356
  question: questionSchema,
@@ -188,6 +367,9 @@ export const formEditorInputQuestionSchema =
188
367
  Joi.object<FormEditorInputQuestion>()
189
368
  .keys(formEditorInputQuestionKeys)
190
369
  .required()
370
+ .description(
371
+ 'Input schema for creating or updating a question in the form editor'
372
+ )
191
373
 
192
374
  export const formEditorInputPageSettingsKeys = {
193
375
  pageHeadingAndGuidance: pageHeadingAndGuidanceSchema,
@@ -203,3 +385,4 @@ export const formEditorInputPageSettingsSchema =
203
385
  Joi.object<FormEditorInputPageSettings>()
204
386
  .keys(formEditorInputPageSettingsKeys)
205
387
  .required()
388
+ .description('Settings for page content and display in the form editor')
@@ -1,3 +1,5 @@
1
+ import { type ComponentDef } from '~/src/components/types.js'
2
+
1
3
  /**
2
4
  * Interface for `FormEditor` Joi schema
3
5
  */
@@ -171,6 +173,36 @@ export interface FormEditor {
171
173
  * The types of tabular data files for upload
172
174
  */
173
175
  tabularDataTypes: string[]
176
+
177
+ /**
178
+ * The action required from within a sub-section
179
+ */
180
+ enhancedAction: string
181
+
182
+ /**
183
+ * Placeholder for inserted section to handle adding/editing radios or checkboxes
184
+ */
185
+ radiosOrCheckboxes: string
186
+
187
+ /**
188
+ * The unique id of the radio item
189
+ */
190
+ radioId: string
191
+
192
+ /**
193
+ * The display text of the radio item
194
+ */
195
+ radioLabel: string
196
+
197
+ /**
198
+ * The hint of the radio item
199
+ */
200
+ radioHint: string
201
+
202
+ /**
203
+ * The value of the radio item
204
+ */
205
+ radioValue: string
174
206
  }
175
207
 
176
208
  export type FormEditorInputPage = Pick<
@@ -210,6 +242,11 @@ export type FormEditorInputQuestion = Pick<
210
242
  | 'documentTypes'
211
243
  | 'imageTypes'
212
244
  | 'tabularDataTypes'
245
+ | 'enhancedAction'
246
+ | 'radioId'
247
+ | 'radioLabel'
248
+ | 'radioHint'
249
+ | 'radioValue'
213
250
  >
214
251
 
215
252
  export type FormEditorInputPageSettings = Pick<
@@ -222,6 +259,36 @@ export type FormEditorInputGuidancePage = Pick<
222
259
  'pageHeading' | 'guidanceText'
223
260
  >
224
261
 
262
+ export type FormEditorInputQuestionDetails = Pick<
263
+ FormEditorInputQuestion,
264
+ | 'question'
265
+ | 'hintText'
266
+ | 'shortDescription'
267
+ | 'questionOptional'
268
+ | 'questionType'
269
+ | 'fileTypes'
270
+ | 'documentTypes'
271
+ | 'imageTypes'
272
+ | 'tabularDataTypes'
273
+ | 'enhancedAction'
274
+ | 'radioId'
275
+ | 'radioLabel'
276
+ | 'radioHint'
277
+ | 'radioValue'
278
+ >
279
+
280
+ export interface EnhancedActionState {
281
+ questionDetails: Partial<ComponentDef>
282
+ state: {
283
+ radioId?: string
284
+ radioLabel?: string
285
+ radioHint?: string
286
+ radioValue?: string
287
+ expanded?: boolean
288
+ }
289
+ listItems: { label?: string; hint?: string; value?: string; id?: string }[]
290
+ }
291
+
225
292
  export interface GovukField {
226
293
  id?: string
227
294
  name?: string
@@ -236,6 +303,7 @@ export interface GovukField {
236
303
  items?: { text?: string; value?: string; checked?: boolean }[]
237
304
  rows?: number
238
305
  type?: string
306
+ customTemplate?: string
239
307
  }
240
308
 
241
309
  export interface FormEditorGovukField {
@@ -247,6 +315,7 @@ export interface FormEditorGovukField {
247
315
  documentTypes?: GovukField
248
316
  imageTypes?: GovukField
249
317
  tabularDataTypes?: GovukField
318
+ radiosOrCheckboxes?: GovukField
250
319
  errorMessage?: { text: string }
251
320
  }
252
321
 
@@ -5,8 +5,17 @@ import { pageSchema } from '~/src/index.js'
5
5
 
6
6
  export const patchPageSchema = Joi.object<PatchPageFields>()
7
7
  .keys({
8
- title: pageSchema.extract('title').optional(),
9
- path: pageSchema.extract('path').optional()
8
+ title: pageSchema
9
+ .extract('title')
10
+ .optional()
11
+ .description('New title to set for the page'),
12
+ path: pageSchema
13
+ .extract('path')
14
+ .optional()
15
+ .description('New URL path to set for the page')
10
16
  })
11
17
  .required()
12
18
  .min(1)
19
+ .description(
20
+ 'Schema for partially updating a page, requiring at least one field to be provided'
21
+ )
@@ -22,30 +22,63 @@ export const organisations = [
22
22
  'Veterinary Medicines Directorate – VMD'
23
23
  ]
24
24
 
25
- export const idSchema = Joi.string().hex().length(24).required()
26
- export const titleSchema = Joi.string().max(250).trim().required()
25
+ export const idSchema = Joi.string()
26
+ .hex()
27
+ .length(24)
28
+ .required()
29
+ .description(
30
+ 'Unique identifier for the form, 24-character hexadecimal string'
31
+ )
32
+
33
+ export const titleSchema = Joi.string()
34
+ .max(250)
35
+ .trim()
36
+ .required()
37
+ .description('Title of the form, displayed to users')
38
+
27
39
  export const slugSchema = Joi.string()
28
40
  .pattern(/^[a-z0-9-]+$/, { name: 'letters, numbers and hyphens only' })
29
41
  .required()
42
+ .description('URL-friendly identifier used in form paths')
30
43
 
31
44
  export const organisationSchema = Joi.string()
32
45
  .valid(...organisations)
33
46
  .required()
47
+ .description('Defra organisation responsible for the form')
48
+
49
+ export const teamNameSchema = Joi.string()
50
+ .max(100)
51
+ .trim()
52
+ .required()
53
+ .description('Name of the team responsible for the form')
34
54
 
35
- export const teamNameSchema = Joi.string().max(100).trim().required()
36
55
  export const teamEmailSchema = Joi.string()
37
56
  .email({ tlds: { allow: ['uk'] } })
38
57
  .trim()
39
58
  .required()
59
+ .description('Contact email for the team responsible for the form')
60
+
61
+ export const phoneSchema = Joi.string()
62
+ .trim()
63
+ .description('Phone number for form-related inquiries')
64
+
65
+ export const emailAddressSchema = Joi.string()
66
+ .email()
67
+ .trim()
68
+ .required()
69
+ .description('Email address for form-related inquiries')
40
70
 
41
- export const phoneSchema = Joi.string().trim()
71
+ export const emailResponseTimeSchema = Joi.string()
72
+ .trim()
73
+ .required()
74
+ .description('Expected response time for email inquiries')
42
75
 
43
- export const emailAddressSchema = Joi.string().email().trim().required()
44
- export const emailResponseTimeSchema = Joi.string().trim().required()
45
- export const emailSchema = Joi.object<FormMetadataContactEmail>().keys({
46
- address: emailAddressSchema,
47
- responseTime: emailResponseTimeSchema
48
- })
76
+ export const emailSchema = Joi.object<FormMetadataContactEmail>()
77
+ .keys({
78
+ address: emailAddressSchema,
79
+ responseTime: emailResponseTimeSchema
80
+ })
81
+ .description('Email contact details including response expectations')
49
82
 
50
83
  export const onlineUrlSchema = Joi.string()
51
84
  .uri({
@@ -53,34 +86,61 @@ export const onlineUrlSchema = Joi.string()
53
86
  })
54
87
  .trim()
55
88
  .required()
56
- export const onlineTextSchema = Joi.string().trim().required()
57
- export const onlineSchema = Joi.object<FormMetadataContactOnline>().keys({
58
- url: onlineUrlSchema,
59
- text: onlineTextSchema
60
- })
89
+ .description('URL for online contact method')
90
+
91
+ export const onlineTextSchema = Joi.string()
92
+ .trim()
93
+ .required()
94
+ .description('Descriptive text for the online contact link')
61
95
 
62
- export const contactSchema = Joi.object<FormMetadataContact>().keys({
63
- phone: phoneSchema,
64
- email: emailSchema,
65
- online: onlineSchema
66
- })
96
+ export const onlineSchema = Joi.object<FormMetadataContactOnline>()
97
+ .keys({
98
+ url: onlineUrlSchema,
99
+ text: onlineTextSchema
100
+ })
101
+ .description('Online contact details with URL and descriptive text')
67
102
 
68
- export const submissionGuidanceSchema = Joi.string().trim()
103
+ export const contactSchema = Joi.object<FormMetadataContact>()
104
+ .keys({
105
+ phone: phoneSchema,
106
+ email: emailSchema,
107
+ online: onlineSchema
108
+ })
109
+ .description('Complete contact information for form-related inquiries')
110
+
111
+ export const submissionGuidanceSchema = Joi.string()
112
+ .trim()
113
+ .description('Guidance text shown to users when submitting the form')
69
114
 
70
115
  export const privacyNoticeUrlSchema = Joi.string()
71
116
  .uri({
72
117
  scheme: ['http', 'https']
73
118
  })
74
119
  .trim()
120
+ .description('URL to the privacy notice for this form')
75
121
 
76
122
  export const notificationEmailAddressSchema = Joi.string()
77
123
  .email({ tlds: { allow: ['uk'] } })
78
124
  .trim()
79
125
  .pattern(/\.gov\.uk$|\.org\.uk$/)
126
+ .description(
127
+ 'Email address to receive form submission notifications, must be a .gov.uk or .org.uk address'
128
+ )
129
+
130
+ export const authoredAtSchema = Joi.date()
131
+ .iso()
132
+ .required()
133
+ .description('ISO format timestamp of when an action occurred')
80
134
 
81
- export const authoredAtSchema = Joi.date().iso().required()
82
- export const authorIdSchema = Joi.string().trim().required()
83
- export const authorDisplayNameSchema = Joi.string().trim().required()
135
+ export const authorIdSchema = Joi.string()
136
+ .trim()
137
+ .required()
138
+ .description('Unique identifier for the author')
139
+
140
+ export const authorDisplayNameSchema = Joi.string()
141
+ .trim()
142
+ .required()
143
+ .description('Human-readable name of the author')
84
144
 
85
145
  export const formMetadataInputKeys = {
86
146
  title: titleSchema,
@@ -100,6 +160,7 @@ export const formMetadataInputKeys = {
100
160
  export const formMetadataInputSchema = Joi.object<FormMetadataInput>()
101
161
  .keys(formMetadataInputKeys)
102
162
  .required()
163
+ .description('Input data for creating or updating form metadata')
103
164
 
104
165
  /**
105
166
  * Joi schema for `FormMetadataAuthor` interface
@@ -111,29 +172,46 @@ export const formMetadataAuthorSchema = Joi.object<FormMetadataAuthor>()
111
172
  displayName: authorDisplayNameSchema
112
173
  })
113
174
  .required()
175
+ .description('Information about the author of a form or form change')
114
176
 
115
177
  /**
116
178
  * Joi schema for `FormMetadataState` interface
117
179
  * @see {@link FormMetadataState}
118
180
  */
119
- export const formMetadataStateSchema = Joi.object<FormMetadataState>().keys({
120
- createdAt: authoredAtSchema,
121
- createdBy: formMetadataAuthorSchema,
122
- updatedAt: authoredAtSchema,
123
- updatedBy: formMetadataAuthorSchema
124
- })
181
+ export const formMetadataStateSchema = Joi.object<FormMetadataState>()
182
+ .keys({
183
+ createdAt: authoredAtSchema.description(
184
+ 'When this version was first created'
185
+ ),
186
+ createdBy: formMetadataAuthorSchema.description('Who created this version'),
187
+ updatedAt: authoredAtSchema.description(
188
+ 'When this version was last updated'
189
+ ),
190
+ updatedBy: formMetadataAuthorSchema.description(
191
+ 'Who last updated this version'
192
+ )
193
+ })
194
+ .description('Metadata about a specific version state (draft or live)')
125
195
 
126
196
  /**
127
197
  * Joi schema for `FormMetadata` interface
128
198
  * @see {@link FormMetadata}
129
199
  */
130
- export const formMetadataSchema = formMetadataInputSchema.append<FormMetadata>({
131
- id: idSchema,
132
- slug: slugSchema,
133
- draft: formMetadataStateSchema,
134
- live: formMetadataStateSchema,
135
- createdAt: authoredAtSchema,
136
- createdBy: formMetadataAuthorSchema,
137
- updatedAt: authoredAtSchema,
138
- updatedBy: formMetadataAuthorSchema
139
- })
200
+ export const formMetadataSchema = formMetadataInputSchema
201
+ .append<FormMetadata>({
202
+ id: idSchema,
203
+ slug: slugSchema,
204
+ draft: formMetadataStateSchema.description(
205
+ 'Metadata for the draft version'
206
+ ),
207
+ live: formMetadataStateSchema.description(
208
+ 'Metadata for the published version'
209
+ ),
210
+ createdAt: authoredAtSchema.description('When the form was first created'),
211
+ createdBy: formMetadataAuthorSchema.description('Who created the form'),
212
+ updatedAt: authoredAtSchema.description('When the form was last updated'),
213
+ updatedBy: formMetadataAuthorSchema.description('Who last updated the form')
214
+ })
215
+ .description(
216
+ 'Complete metadata for a form, including version information and authoring details'
217
+ )