@defra/forms-model 3.0.431 → 3.0.432

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 (48) hide show
  1. package/package.json +1 -1
  2. package/schemas/component-schema-v2.json +162 -0
  3. package/schemas/component-schema.json +162 -0
  4. package/schemas/date-sub-schema.json +11 -0
  5. package/schemas/form-definition-schema.json +1876 -0
  6. package/schemas/form-definition-v2-payload-schema.json +1459 -0
  7. package/schemas/form-editor-input-check-answers-setting-schema.json +18 -0
  8. package/schemas/form-editor-input-page-schema.json +41 -0
  9. package/schemas/form-editor-input-page-settings-schema.json +28 -0
  10. package/schemas/form-editor-input-question-schema.json +38 -0
  11. package/schemas/form-metadata-author-schema.json +24 -0
  12. package/schemas/form-metadata-contact-schema.json +61 -0
  13. package/schemas/form-metadata-email-schema.json +25 -0
  14. package/schemas/form-metadata-input-schema.json +127 -0
  15. package/schemas/form-metadata-online-schema.json +25 -0
  16. package/schemas/form-metadata-schema.json +340 -0
  17. package/schemas/form-metadata-state-schema.json +72 -0
  18. package/schemas/form-submit-payload-schema.json +124 -0
  19. package/schemas/form-submit-record-schema.json +30 -0
  20. package/schemas/form-submit-recordset-schema.json +62 -0
  21. package/schemas/list-schema-v2.json +486 -0
  22. package/schemas/list-schema.json +486 -0
  23. package/schemas/max-future-schema.json +8 -0
  24. package/schemas/max-length-schema.json +8 -0
  25. package/schemas/max-past-schema.json +8 -0
  26. package/schemas/max-schema.json +7 -0
  27. package/schemas/min-length-schema.json +8 -0
  28. package/schemas/min-schema.json +7 -0
  29. package/schemas/page-schema-payload-v2.json +400 -0
  30. package/schemas/page-schema-v2.json +400 -0
  31. package/schemas/page-schema.json +400 -0
  32. package/schemas/page-type-schema.json +11 -0
  33. package/schemas/pagination-options-schema.json +27 -0
  34. package/schemas/patch-page-schema.json +26 -0
  35. package/schemas/query-options-schema.json +94 -0
  36. package/schemas/question-schema.json +7 -0
  37. package/schemas/question-type-full-schema.json +22 -0
  38. package/schemas/question-type-schema.json +20 -0
  39. package/schemas/search-options-schema.json +59 -0
  40. package/schemas/sorting-options-schema.json +28 -0
  41. package/schemas/written-answer-sub-schema.json +12 -0
  42. package/scripts/generate-schemas.js +0 -238
  43. package/scripts/schema-modules/constants.js +0 -39
  44. package/scripts/schema-modules/schema-processors.js +0 -109
  45. package/scripts/schema-modules/schema-simplifiers.js +0 -351
  46. package/scripts/schema-modules/title-processors.js +0 -327
  47. package/scripts/schema-modules/types.js +0 -21
  48. package/scripts/schema-modules/utils.js +0 -41
@@ -0,0 +1,28 @@
1
+ {
2
+ "type": "object",
3
+ "properties": {
4
+ "sortBy": {
5
+ "type": "string",
6
+ "description": "Field to sort results by",
7
+ "enum": [
8
+ "updatedAt",
9
+ "title"
10
+ ],
11
+ "title": "Sort By"
12
+ },
13
+ "order": {
14
+ "type": "string",
15
+ "description": "Sort order (ascending or descending)",
16
+ "enum": [
17
+ "asc",
18
+ "desc"
19
+ ],
20
+ "title": "Order"
21
+ }
22
+ },
23
+ "additionalProperties": false,
24
+ "$schema": "http://json-schema.org/draft-07/schema#",
25
+ "title": "Sorting Options Schema",
26
+ "description": "JSON Schema for validating Sorting Options Schema in Defra forms",
27
+ "$id": "@defra/forms-model/schemas/sorting-options-schema.json"
28
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "type": "string",
3
+ "description": "Subtype for written answer questions",
4
+ "enum": [
5
+ "TextField",
6
+ "MultilineTextField",
7
+ "NumberField"
8
+ ],
9
+ "$schema": "http://json-schema.org/draft-07/schema#",
10
+ "title": "Written Answer Sub Schema",
11
+ "$id": "@defra/forms-model/schemas/written-answer-sub-schema.json"
12
+ }
@@ -1,238 +0,0 @@
1
- import fs from 'fs'
2
- import path from 'path'
3
- import parse from 'joi-to-json'
4
-
5
- import { schemasDir } from './schema-modules/constants.js'
6
- import { ensureDirectoryExists, toTitleCase } from './schema-modules/utils.js'
7
- import { addTitles } from './schema-modules/title-processors.js'
8
- import { simplifyForDocs } from './schema-modules/schema-simplifiers.js'
9
-
10
- /**
11
- * Cleans the schemas directory by removing all existing JSON files
12
- * @returns {number} Number of files cleaned
13
- */
14
- export function cleanSchemaDirectory() {
15
- console.log('Cleaning existing schema files...')
16
- const existingFiles = fs
17
- .readdirSync(schemasDir)
18
- .filter((file) => file.endsWith('.json'))
19
-
20
- for (const file of existingFiles) {
21
- fs.unlinkSync(path.join(schemasDir, file))
22
- }
23
-
24
- console.log(`Cleaned ${existingFiles.length} existing schema files`)
25
- return existingFiles.length
26
- }
27
-
28
- /**
29
- * Gets the schema map that defines which files should be generated
30
- * @returns {Record<string, string>} Schema map with filename-to-schema-export mapping
31
- */
32
- export function getSchemaMap() {
33
- return {
34
- // Form definition schemas
35
- 'form-definition-schema': 'formDefinitionSchema',
36
- 'form-definition-v2-payload-schema': 'formDefinitionV2PayloadSchema',
37
-
38
- // Component schemas
39
- 'component-schema': 'componentSchema',
40
- 'component-schema-v2': 'componentSchemaV2',
41
-
42
- // Page schemas
43
- 'page-schema': 'pageSchema',
44
- 'page-schema-v2': 'pageSchemaV2',
45
- 'page-schema-payload-v2': 'pageSchemaPayloadV2',
46
-
47
- // List schemas
48
- 'list-schema': 'listSchema',
49
- 'list-schema-v2': 'listSchemaV2',
50
-
51
- // Form metadata schemas
52
- 'form-metadata-schema': 'formMetadataSchema',
53
- 'form-metadata-author-schema': 'formMetadataAuthorSchema',
54
- 'form-metadata-input-schema': 'formMetadataInputSchema',
55
- 'form-metadata-state-schema': 'formMetadataStateSchema',
56
-
57
- // Form metadata field schemas
58
- 'form-metadata-contact-schema': 'contactSchema',
59
- 'form-metadata-email-schema': 'emailSchema',
60
- 'form-metadata-online-schema': 'onlineSchema',
61
-
62
- // Form editor schemas
63
- 'form-editor-input-page-schema': 'formEditorInputPageSchema',
64
- 'form-editor-input-check-answers-setting-schema':
65
- 'formEditorInputCheckAnswersSettingSchema',
66
- 'form-editor-input-question-schema': 'formEditorInputQuestionSchema',
67
- 'form-editor-input-page-settings-schema':
68
- 'formEditorInputPageSettingsSchema',
69
-
70
- // Form editor field schemas
71
- 'page-type-schema': 'pageTypeSchema',
72
- 'question-type-schema': 'questionTypeSchema',
73
- 'question-type-full-schema': 'questionTypeFullSchema',
74
- 'written-answer-sub-schema': 'writtenAnswerSubSchema',
75
- 'date-sub-schema': 'dateSubSchema',
76
-
77
- // Form submission schemas
78
- 'form-submit-payload-schema': 'formSubmitPayloadSchema',
79
- 'form-submit-record-schema': 'formSubmitRecordSchema',
80
- 'form-submit-recordset-schema': 'formSubmitRecordsetSchema',
81
-
82
- // Form manager schemas
83
- 'patch-page-schema': 'patchPageSchema',
84
-
85
- // Section schemas
86
- 'question-schema': 'questionSchema',
87
-
88
- // Validation schemas
89
- 'min-schema': 'minSchema',
90
- 'max-schema': 'maxSchema',
91
- 'min-length-schema': 'minLengthSchema',
92
- 'max-length-schema': 'maxLengthSchema',
93
- 'max-future-schema': 'maxFutureSchema',
94
- 'max-past-schema': 'maxPastSchema',
95
-
96
- // Common schemas
97
- 'search-options-schema': 'searchOptionsSchema',
98
- 'query-options-schema': 'queryOptionsSchema',
99
- 'pagination-options-schema': 'paginationOptionsSchema',
100
- 'sorting-options-schema': 'sortingOptionsSchema'
101
- }
102
- }
103
-
104
- /**
105
- * Process a single schema and create its JSON Schema file
106
- * @param {string} fileName - Output file name
107
- * @param {string} schemaName - Schema export name in the model
108
- * @param {Record<string, unknown>} model - The loaded model containing schemas
109
- * @returns {boolean} Whether processing was successful
110
- */
111
- export function processSchema(fileName, schemaName, model) {
112
- try {
113
- /** @type {unknown} */
114
- const joiSchema = model[schemaName]
115
-
116
- if (!joiSchema) {
117
- return false
118
- }
119
-
120
- /** @type {import('./schema-modules/types.js').SchemaObject} */
121
- let jsonSchema = parse(
122
- /** @type {Schema} */ (joiSchema),
123
- 'json',
124
- {},
125
- {
126
- includeSchemaDialect: true,
127
- includeDescriptions: true
128
- }
129
- )
130
-
131
- const title = toTitleCase(fileName)
132
- if (!jsonSchema.title) {
133
- jsonSchema.title = title
134
- }
135
- if (!jsonSchema.description) {
136
- jsonSchema.description = `JSON Schema for validating ${title} in Defra forms`
137
- }
138
-
139
- if (!jsonSchema.$id) {
140
- jsonSchema.$id = `@defra/forms-model/schemas/${fileName}.json`
141
- }
142
-
143
- addTitles(jsonSchema, '')
144
-
145
- jsonSchema = simplifyForDocs(jsonSchema, '')
146
-
147
- const outputPath = path.join(schemasDir, `${fileName}.json`)
148
- fs.writeFileSync(outputPath, JSON.stringify(jsonSchema, null, 2))
149
- return true
150
- } catch (/** @type {unknown} */ err) {
151
- const error = err instanceof Error ? err : new Error(String(err))
152
- console.error(`✗ Failed to process ${fileName}: ${error.message}`)
153
- return false
154
- }
155
- }
156
-
157
- /**
158
- * Loads the model with all schemas
159
- * @returns {Promise<Record<string, unknown>>} Loaded model
160
- */
161
- async function loadModelSchemas() {
162
- console.log('Loading model schemas...')
163
- return import('../dist/module/index.js')
164
- }
165
-
166
- /**
167
- * Processes all schemas and generates JSON Schema files
168
- * @param {Record<string, unknown>} model - The loaded model containing schemas
169
- * @returns {{ successCount: number, errorCount: number }} Object containing success and error counts
170
- */
171
- export function processAllSchemas(model) {
172
- const schemaMap = getSchemaMap()
173
- let successCount = 0
174
- let errorCount = 0
175
-
176
- for (const [fileName, schemaName] of Object.entries(schemaMap)) {
177
- const success = processSchema(fileName, schemaName, model)
178
-
179
- if (success) {
180
- successCount++
181
- } else {
182
- errorCount++
183
- }
184
- }
185
-
186
- return { successCount, errorCount }
187
- }
188
-
189
- /**
190
- * Generates schema files from Joi schemas
191
- */
192
- export async function generateSchemas() {
193
- try {
194
- const model = await loadModelSchemas()
195
-
196
- ensureDirectoryExists(schemasDir)
197
-
198
- cleanSchemaDirectory()
199
-
200
- const { successCount, errorCount } = processAllSchemas(model)
201
-
202
- console.log('\nSchema generation complete!')
203
- console.log(`✓ Successfully generated ${successCount} schemas`)
204
- if (errorCount > 0) {
205
- console.log(`✗ Failed to generate ${errorCount} schemas`)
206
- }
207
-
208
- return { successCount, errorCount }
209
- } catch (err) {
210
- const error = err instanceof Error ? err : new Error(String(err))
211
- console.error(`\n✗ Schema generation failed: ${error.message}`)
212
- throw error
213
- }
214
- }
215
-
216
- // Only run when executed directly, not when imported as a module
217
- if (import.meta.url === `file://${process.argv[1]}`) {
218
- ;(async () => {
219
- try {
220
- await generateSchemas()
221
- } catch (err) {
222
- console.error('Schema generation failed:', err)
223
- throw err
224
- }
225
- })().catch((err) => {
226
- console.error('Unhandled error:', err)
227
- // eslint-disable-next-line no-process-exit
228
- process.exit(1)
229
- })
230
- }
231
-
232
- /**
233
- * @import { Schema } from 'joi'
234
- */
235
-
236
- /**
237
- * @import { SchemaObject } from './schema-modules/types.js'
238
- */
@@ -1,39 +0,0 @@
1
- import path from 'path'
2
- import { fileURLToPath } from 'url'
3
-
4
- export const currentDirname = path.dirname(fileURLToPath(import.meta.url))
5
- export const schemasDir = path.resolve(currentDirname, '../../schemas')
6
-
7
- /**
8
- * Condition type constants
9
- */
10
- export const CONDITION_TYPES = {
11
- DEFINITION: 'Condition Definition',
12
- REFERENCE: 'Condition Reference',
13
- NESTED_GROUP: 'Nested Condition Group'
14
- }
15
-
16
- /**
17
- * Value type constants
18
- */
19
- export const VALUE_TYPES = {
20
- STATIC: 'Static Value',
21
- RELATIVE_DATE: 'Relative Date Value'
22
- }
23
-
24
- /**
25
- * Common description constants
26
- */
27
- export const DESCRIPTIONS = {
28
- NESTED_CONDITION_GROUP:
29
- 'A nested group of conditions that allows building complex logical expressions with multiple levels.'
30
- }
31
-
32
- /**
33
- * Path segment constants
34
- */
35
- export const PATH_SEGMENTS = {
36
- CONDITIONS: 'conditions',
37
- ITEMS: 'items',
38
- PROPERTIES: 'properties'
39
- }
@@ -1,109 +0,0 @@
1
- import { CONDITION_TYPES, DESCRIPTIONS, VALUE_TYPES } from './constants.js'
2
-
3
- /**
4
- * Fixes titles for condition items in anyOfTitles
5
- * @param {SchemaObject} obj - Schema to process
6
- * @returns {boolean} True if changes were made
7
- */
8
- export function fixConditionItems(obj) {
9
- if (!obj.anyOfTitles?.includes('Conditions Item Variant 3')) {
10
- return false
11
- }
12
-
13
- const EXPECTED_CONDITION_TYPES_COUNT = 3
14
-
15
- obj.anyOfTitles = [
16
- CONDITION_TYPES.DEFINITION,
17
- CONDITION_TYPES.REFERENCE,
18
- CONDITION_TYPES.NESTED_GROUP
19
- ]
20
-
21
- if (obj.anyOf?.length === EXPECTED_CONDITION_TYPES_COUNT) {
22
- if (obj.anyOf[0].properties?.field) {
23
- obj.anyOf[0].title = CONDITION_TYPES.DEFINITION
24
- }
25
- if (obj.anyOf[1].properties?.conditionName) {
26
- obj.anyOf[1].title = CONDITION_TYPES.REFERENCE
27
- }
28
- if (obj.anyOf[2].$ref?.includes('conditionGroupSchema')) {
29
- obj.anyOf[2].title = CONDITION_TYPES.NESTED_GROUP
30
- obj.anyOf[2].description = DESCRIPTIONS.NESTED_CONDITION_GROUP
31
- }
32
- }
33
- return true
34
- }
35
-
36
- /**
37
- * Fixes titles for value objects in anyOfTitles
38
- * @param {SchemaObject} obj - Schema to process
39
- * @returns {boolean} True if changes were made
40
- */
41
- export function fixValueObjects(obj) {
42
- if (
43
- obj.anyOfTitles?.length !== 2 ||
44
- obj.anyOfTitles[0] !== 'Value (object)' ||
45
- obj.anyOfTitles[1] !== 'Value (object)'
46
- ) {
47
- return false
48
- }
49
-
50
- obj.anyOfTitles = [VALUE_TYPES.STATIC, VALUE_TYPES.RELATIVE_DATE]
51
-
52
- if (obj.anyOf?.length === 2) {
53
- if (obj.anyOf[0].properties?.value) {
54
- obj.anyOf[0].title = VALUE_TYPES.STATIC
55
- }
56
- if (obj.anyOf[1].properties?.period) {
57
- obj.anyOf[1].title = VALUE_TYPES.RELATIVE_DATE
58
- }
59
- }
60
-
61
- return true
62
- }
63
-
64
- /**
65
- * Processes the anyOfTitles array in an object
66
- * @param {SchemaObject} obj - Schema to process
67
- */
68
- export function processAnyOfTitles(obj) {
69
- if (!obj || typeof obj !== 'object') {
70
- return
71
- }
72
-
73
- if (!Array.isArray(obj.anyOfTitles)) {
74
- return
75
- }
76
-
77
- if (!fixConditionItems(obj)) {
78
- fixValueObjects(obj)
79
- }
80
- }
81
-
82
- /**
83
- * Recursively fixes all condition titles and anyOfTitles throughout the schema
84
- * regardless of their nesting level
85
- * @param {SchemaObject} obj - The schema or subschema to fix
86
- */
87
- export function fixConditionTitles(obj) {
88
- if (!obj || typeof obj !== 'object') {
89
- return
90
- }
91
-
92
- processAnyOfTitles(obj)
93
-
94
- if (obj.title === 'Conditions Item Variant 3') {
95
- obj.title = CONDITION_TYPES.NESTED_GROUP
96
- obj.description = DESCRIPTIONS.NESTED_CONDITION_GROUP
97
- }
98
-
99
- Object.keys(obj).forEach((key) => {
100
- const value = obj[key]
101
- if (value && typeof value === 'object') {
102
- fixConditionTitles(value)
103
- }
104
- })
105
- }
106
-
107
- /**
108
- * @import { SchemaObject } from './types.js'
109
- */