@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.
- package/package.json +1 -1
- package/schemas/component-schema-v2.json +162 -0
- package/schemas/component-schema.json +162 -0
- package/schemas/date-sub-schema.json +11 -0
- package/schemas/form-definition-schema.json +1876 -0
- package/schemas/form-definition-v2-payload-schema.json +1459 -0
- package/schemas/form-editor-input-check-answers-setting-schema.json +18 -0
- package/schemas/form-editor-input-page-schema.json +41 -0
- package/schemas/form-editor-input-page-settings-schema.json +28 -0
- package/schemas/form-editor-input-question-schema.json +38 -0
- package/schemas/form-metadata-author-schema.json +24 -0
- package/schemas/form-metadata-contact-schema.json +61 -0
- package/schemas/form-metadata-email-schema.json +25 -0
- package/schemas/form-metadata-input-schema.json +127 -0
- package/schemas/form-metadata-online-schema.json +25 -0
- package/schemas/form-metadata-schema.json +340 -0
- package/schemas/form-metadata-state-schema.json +72 -0
- package/schemas/form-submit-payload-schema.json +124 -0
- package/schemas/form-submit-record-schema.json +30 -0
- package/schemas/form-submit-recordset-schema.json +62 -0
- package/schemas/list-schema-v2.json +486 -0
- package/schemas/list-schema.json +486 -0
- package/schemas/max-future-schema.json +8 -0
- package/schemas/max-length-schema.json +8 -0
- package/schemas/max-past-schema.json +8 -0
- package/schemas/max-schema.json +7 -0
- package/schemas/min-length-schema.json +8 -0
- package/schemas/min-schema.json +7 -0
- package/schemas/page-schema-payload-v2.json +400 -0
- package/schemas/page-schema-v2.json +400 -0
- package/schemas/page-schema.json +400 -0
- package/schemas/page-type-schema.json +11 -0
- package/schemas/pagination-options-schema.json +27 -0
- package/schemas/patch-page-schema.json +26 -0
- package/schemas/query-options-schema.json +94 -0
- package/schemas/question-schema.json +7 -0
- package/schemas/question-type-full-schema.json +22 -0
- package/schemas/question-type-schema.json +20 -0
- package/schemas/search-options-schema.json +59 -0
- package/schemas/sorting-options-schema.json +28 -0
- package/schemas/written-answer-sub-schema.json +12 -0
- package/scripts/generate-schemas.js +0 -238
- package/scripts/schema-modules/constants.js +0 -39
- package/scripts/schema-modules/schema-processors.js +0 -109
- package/scripts/schema-modules/schema-simplifiers.js +0 -351
- package/scripts/schema-modules/title-processors.js +0 -327
- package/scripts/schema-modules/types.js +0 -21
- 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
|
-
*/
|