@defra/forms-engine-plugin 5.0.0-alpha.27 → 5.0.0-alpha.29
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/.public/37c964ca545c240f010a.mjs +2 -0
- package/.public/37c964ca545c240f010a.mjs.LICENSE.txt +4 -0
- package/.public/assets-manifest.json +3 -0
- package/.public/javascripts/shared.min.js +1 -1
- package/.public/javascripts/shared.min.js.LICENSE.txt +2 -0
- package/.public/javascripts/shared.min.js.map +1 -1
- package/.public/javascripts/vendor/@defra.min.js +1 -1
- package/.public/javascripts/vendor/@defra.min.js.map +1 -1
- package/.public/javascripts/vendor/maplibre-gl.min.js +1 -1
- package/.public/javascripts/vendor/maplibre-gl.min.js.LICENSE.txt +3 -3
- package/.public/javascripts/vendor/maplibre-gl.min.js.map +1 -1
- package/.public/stylesheets/application.min.css +1 -1
- package/.public/stylesheets/application.min.css.map +1 -1
- package/.server/client/javascripts/geospatial-map.js +3 -3
- package/.server/client/javascripts/geospatial-map.js.map +1 -1
- package/.server/client/javascripts/location-map.js +2 -2
- package/.server/client/javascripts/location-map.js.map +1 -1
- package/.server/client/javascripts/map.d.ts +5 -2
- package/.server/client/javascripts/map.js +17 -5
- package/.server/client/javascripts/map.js.map +1 -1
- package/.server/server/plugins/engine/components/AutocompleteField.d.ts +1 -2
- package/.server/server/plugins/engine/components/AutocompleteField.js +9 -4
- package/.server/server/plugins/engine/components/AutocompleteField.js.map +1 -1
- package/.server/server/plugins/engine/components/CheckboxesField.d.ts +2 -2
- package/.server/server/plugins/engine/components/CheckboxesField.js.map +1 -1
- package/.server/server/plugins/engine/components/ComponentBase.d.ts +1 -1
- package/.server/server/plugins/engine/components/ComponentBase.js.map +1 -1
- package/.server/server/plugins/engine/components/DeclarationField.d.ts +2 -2
- package/.server/server/plugins/engine/components/DeclarationField.js.map +1 -1
- package/.server/server/plugins/engine/components/FileUploadField.d.ts +2 -2
- package/.server/server/plugins/engine/components/FileUploadField.js.map +1 -1
- package/.server/server/plugins/engine/components/ListFormComponent.d.ts +2 -2
- package/.server/server/plugins/engine/components/ListFormComponent.js.map +1 -1
- package/.server/server/plugins/engine/components/LocationFieldBase.js +11 -6
- package/.server/server/plugins/engine/components/LocationFieldBase.js.map +1 -1
- package/.server/server/plugins/engine/components/NumberField.js +14 -8
- package/.server/server/plugins/engine/components/NumberField.js.map +1 -1
- package/.server/server/plugins/engine/components/YesNoField.d.ts +1 -3
- package/.server/server/plugins/engine/components/YesNoField.js +9 -4
- package/.server/server/plugins/engine/components/YesNoField.js.map +1 -1
- package/.server/server/plugins/engine/components/helpers/index.d.ts +14 -1
- package/.server/server/plugins/engine/components/helpers/index.js +32 -0
- package/.server/server/plugins/engine/components/helpers/index.js.map +1 -1
- package/package.json +6 -6
- package/src/client/javascripts/geospatial-map.js +3 -3
- package/src/client/javascripts/location-map.js +2 -2
- package/src/client/javascripts/map.js +19 -8
- package/src/server/plugins/engine/components/AutocompleteField.ts +12 -5
- package/src/server/plugins/engine/components/CheckboxesField.ts +3 -3
- package/src/server/plugins/engine/components/ComponentBase.ts +4 -4
- package/src/server/plugins/engine/components/DeclarationField.ts +3 -4
- package/src/server/plugins/engine/components/FileUploadField.ts +2 -2
- package/src/server/plugins/engine/components/ListFormComponent.ts +4 -4
- package/src/server/plugins/engine/components/LocationFieldBase.ts +18 -8
- package/src/server/plugins/engine/components/NumberField.ts +17 -13
- package/src/server/plugins/engine/components/YesNoField.ts +14 -4
- package/src/server/plugins/engine/components/helpers/index.ts +45 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @ts-expect-error - no types
|
|
2
2
|
import createDatasetsPlugin from '@defra/interactive-map/plugins/datasets'
|
|
3
3
|
// @ts-expect-error - no types
|
|
4
|
-
import createDrawPlugin from '@defra/interactive-map/plugins/draw
|
|
4
|
+
import createDrawPlugin from '@defra/interactive-map/plugins/draw'
|
|
5
5
|
import { bbox } from '@turf/bbox'
|
|
6
6
|
|
|
7
7
|
import {
|
|
@@ -12,9 +12,9 @@ import {
|
|
|
12
12
|
import {
|
|
13
13
|
EVENTS,
|
|
14
14
|
createMap,
|
|
15
|
-
defaultConfig,
|
|
16
15
|
getCentroidGridRef,
|
|
17
16
|
getCoordinateGridRef,
|
|
17
|
+
getDefaultConfig,
|
|
18
18
|
getMapCountryLayers,
|
|
19
19
|
getMapLayers
|
|
20
20
|
} from './map.js'
|
|
@@ -223,7 +223,7 @@ export function processGeospatial(config, geospatial, index) {
|
|
|
223
223
|
}
|
|
224
224
|
|
|
225
225
|
const initConfig = {
|
|
226
|
-
...
|
|
226
|
+
...getDefaultConfig(),
|
|
227
227
|
bounds,
|
|
228
228
|
plugins
|
|
229
229
|
}
|
|
@@ -10,8 +10,8 @@ import {
|
|
|
10
10
|
EVENTS,
|
|
11
11
|
centerMap,
|
|
12
12
|
createMap,
|
|
13
|
-
defaultConfig,
|
|
14
13
|
eastingNorthingToLatLong,
|
|
14
|
+
getDefaultConfig,
|
|
15
15
|
getMapCountryLayers,
|
|
16
16
|
getMapLayers,
|
|
17
17
|
latLongToEastingNorthing,
|
|
@@ -446,7 +446,7 @@ export function processLocation(config, location, index) {
|
|
|
446
446
|
mapContainer.setAttribute('id', mapId)
|
|
447
447
|
mapContainer.setAttribute('class', 'map-container')
|
|
448
448
|
|
|
449
|
-
const initConfig = getInitMapConfig(location) ??
|
|
449
|
+
const initConfig = getInitMapConfig(location) ?? getDefaultConfig()
|
|
450
450
|
|
|
451
451
|
locationInputs.after(mapContainer)
|
|
452
452
|
|
|
@@ -122,10 +122,15 @@ export function getCentroidGridRef(feature) {
|
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
-
/**
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
125
|
+
/**
|
|
126
|
+
* Get the default config for a map
|
|
127
|
+
* @returns {InteractiveMapInitConfig}
|
|
128
|
+
*/
|
|
129
|
+
export const getDefaultConfig = () => {
|
|
130
|
+
return {
|
|
131
|
+
zoom: '6',
|
|
132
|
+
center: [DEFAULT_LONG, DEFAULT_LAT]
|
|
133
|
+
}
|
|
129
134
|
}
|
|
130
135
|
|
|
131
136
|
export const EVENTS = {
|
|
@@ -166,6 +171,7 @@ export function initMaps(config = {}) {
|
|
|
166
171
|
const {
|
|
167
172
|
assetPath = '/assets',
|
|
168
173
|
apiPath = '/form/api',
|
|
174
|
+
workerPath = '/assets/interactive-map/maplibre-gl-worker.mjs',
|
|
169
175
|
data = defaultData
|
|
170
176
|
} = config
|
|
171
177
|
const locations = document.querySelectorAll('.app-location-field')
|
|
@@ -197,11 +203,15 @@ export function initMaps(config = {}) {
|
|
|
197
203
|
}
|
|
198
204
|
|
|
199
205
|
locations.forEach((location, index) => {
|
|
200
|
-
processLocation({ assetPath, apiPath, data }, location, index)
|
|
206
|
+
processLocation({ assetPath, apiPath, workerPath, data }, location, index)
|
|
201
207
|
})
|
|
202
208
|
|
|
203
209
|
geospatials.forEach((geospatial, index) => {
|
|
204
|
-
processGeospatial(
|
|
210
|
+
processGeospatial(
|
|
211
|
+
{ assetPath, apiPath, workerPath, data },
|
|
212
|
+
geospatial,
|
|
213
|
+
index
|
|
214
|
+
)
|
|
205
215
|
})
|
|
206
216
|
}
|
|
207
217
|
|
|
@@ -258,7 +268,7 @@ export function makeTileRequestTransformer(apiPath) {
|
|
|
258
268
|
* @param {MapsEnvironmentConfig} mapsConfig - the map environment params
|
|
259
269
|
*/
|
|
260
270
|
export function createMap(mapId, initConfig, mapsConfig) {
|
|
261
|
-
const { assetPath, apiPath, data = defaultData } = mapsConfig
|
|
271
|
+
const { assetPath, apiPath, workerPath, data = defaultData } = mapsConfig
|
|
262
272
|
const logoAltText = 'Ordnance survey logo'
|
|
263
273
|
const interactPlugin = createInteractPlugin({
|
|
264
274
|
markerColor: { outdoor: '#ff0000', dark: '#00ff00' },
|
|
@@ -270,7 +280,7 @@ export function createMap(mapId, initConfig, mapsConfig) {
|
|
|
270
280
|
const map = new InteractiveMap(mapId, {
|
|
271
281
|
enableFullscreen: true,
|
|
272
282
|
autoColorScheme: false,
|
|
273
|
-
mapProvider: maplibreProvider(),
|
|
283
|
+
mapProvider: maplibreProvider({ workerUrl: workerPath }),
|
|
274
284
|
behaviour: 'inline',
|
|
275
285
|
minZoom: 6,
|
|
276
286
|
maxZoom: 18,
|
|
@@ -448,6 +458,7 @@ export function getMapCountryLayers(apiPath, country) {
|
|
|
448
458
|
* @typedef {object} MapsEnvironmentConfig
|
|
449
459
|
* @property {string} assetPath - the root asset path
|
|
450
460
|
* @property {string} apiPath - the root API path
|
|
461
|
+
* @property {string} workerPath - the maplibre worker path
|
|
451
462
|
* @property {TileData} data - the tile data config
|
|
452
463
|
*/
|
|
453
464
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type AutocompleteFieldComponent } from '@defra/forms-model'
|
|
2
|
-
import { type LanguageMessages } from 'joi'
|
|
3
2
|
|
|
4
3
|
import { SelectField } from './SelectField.js'
|
|
4
|
+
import { withCustomValidationOverrides } from './helpers/index.js'
|
|
5
5
|
import { type RenderContext } from './types.js'
|
|
6
6
|
import { buildValidationMessages } from '../i18n/buildValidationMessages.js'
|
|
7
7
|
import { messageTemplate } from '../pageControllers/validationOptions.js'
|
|
@@ -50,12 +50,19 @@ export class AutocompleteField extends SelectField {
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
getValidationMessagesOverride(translator: Translator) {
|
|
53
|
+
const { customValidationMessages } = this.options
|
|
53
54
|
const { t } = translator
|
|
55
|
+
const defaults = {
|
|
56
|
+
'any.required': buildValidationMessages(t).objectRequired,
|
|
57
|
+
'any.only': buildValidationMessages(t).objectRequired
|
|
58
|
+
}
|
|
59
|
+
|
|
54
60
|
return {
|
|
55
|
-
[this.name]:
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
61
|
+
[this.name]: withCustomValidationOverrides(
|
|
62
|
+
defaults,
|
|
63
|
+
undefined,
|
|
64
|
+
customValidationMessages
|
|
65
|
+
)
|
|
59
66
|
}
|
|
60
67
|
}
|
|
61
68
|
}
|
|
@@ -19,8 +19,8 @@ import {
|
|
|
19
19
|
export class CheckboxesField extends SelectionControlField {
|
|
20
20
|
declare options: CheckboxesFieldComponent['options']
|
|
21
21
|
declare schema: CheckboxesFieldComponent['schema']
|
|
22
|
-
declare formSchema: ArraySchema<string> | ArraySchema<number>
|
|
23
|
-
declare stateSchema: ArraySchema<string> | ArraySchema<number>
|
|
22
|
+
declare formSchema: ArraySchema<string[]> | ArraySchema<number[]>
|
|
23
|
+
declare stateSchema: ArraySchema<string[]> | ArraySchema<number[]>
|
|
24
24
|
declare limits: { min?: number; max?: number; length?: number }
|
|
25
25
|
|
|
26
26
|
constructor(
|
|
@@ -33,7 +33,7 @@ export class CheckboxesField extends SelectionControlField {
|
|
|
33
33
|
const { options, schema } = def
|
|
34
34
|
|
|
35
35
|
let formSchema =
|
|
36
|
-
type === 'string' ? joi.array<string>() : joi.array<number>()
|
|
36
|
+
type === 'string' ? joi.array<string[]>() : joi.array<number[]>()
|
|
37
37
|
|
|
38
38
|
const itemsSchema = joi[type]()
|
|
39
39
|
.valid(...this.values)
|
|
@@ -89,10 +89,10 @@ export class ComponentBase {
|
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
export type ComponentSchema =
|
|
92
|
-
| ArraySchema<string>
|
|
93
|
-
| ArraySchema<number>
|
|
94
|
-
| ArraySchema<boolean>
|
|
95
|
-
| ArraySchema<object>
|
|
92
|
+
| ArraySchema<string[]>
|
|
93
|
+
| ArraySchema<number[]>
|
|
94
|
+
| ArraySchema<boolean[]>
|
|
95
|
+
| ArraySchema<object[]>
|
|
96
96
|
| BooleanSchema<string>
|
|
97
97
|
| BooleanSchema
|
|
98
98
|
| DateSchema
|
|
@@ -8,8 +8,7 @@ import {
|
|
|
8
8
|
import joi, {
|
|
9
9
|
type ArraySchema,
|
|
10
10
|
type BooleanSchema,
|
|
11
|
-
type LanguageMessages
|
|
12
|
-
type StringSchema
|
|
11
|
+
type LanguageMessages
|
|
13
12
|
} from 'joi'
|
|
14
13
|
|
|
15
14
|
import {
|
|
@@ -34,7 +33,7 @@ export class DeclarationField extends FormComponent {
|
|
|
34
33
|
|
|
35
34
|
declare declarationConfirmationLabel: string | undefined
|
|
36
35
|
|
|
37
|
-
declare formSchema: ArraySchema<
|
|
36
|
+
declare formSchema: ArraySchema<string[]>
|
|
38
37
|
declare stateSchema: BooleanSchema
|
|
39
38
|
declare content: string
|
|
40
39
|
headerStartLevel: number
|
|
@@ -63,7 +62,7 @@ export class DeclarationField extends FormComponent {
|
|
|
63
62
|
'any.unknown': messageTemplate.declarationRequired as string,
|
|
64
63
|
'array.includesRequiredUnknowns':
|
|
65
64
|
messageTemplate.declarationRequired as string
|
|
66
|
-
})
|
|
65
|
+
})
|
|
67
66
|
|
|
68
67
|
this.formSchema = formSchema
|
|
69
68
|
this.stateSchema = joi.boolean().cast('string').label(this.label).required()
|
|
@@ -111,8 +111,8 @@ export const formItemSchema = itemSchema.append({
|
|
|
111
111
|
export class FileUploadField extends FormComponent {
|
|
112
112
|
declare options: FileUploadFieldComponent['options']
|
|
113
113
|
declare schema: FileUploadFieldComponent['schema']
|
|
114
|
-
declare formSchema: ArraySchema<FileState>
|
|
115
|
-
declare stateSchema: ArraySchema<FileState>
|
|
114
|
+
declare formSchema: ArraySchema<FileState[]>
|
|
115
|
+
declare stateSchema: ArraySchema<FileState[]>
|
|
116
116
|
declare limits: { min?: number; max?: number; length?: number }
|
|
117
117
|
|
|
118
118
|
constructor(
|
|
@@ -31,16 +31,16 @@ export class ListFormComponent extends FormComponent {
|
|
|
31
31
|
>['options']
|
|
32
32
|
|
|
33
33
|
declare formSchema:
|
|
34
|
-
| ArraySchema<string>
|
|
35
|
-
| ArraySchema<number>
|
|
34
|
+
| ArraySchema<string[]>
|
|
35
|
+
| ArraySchema<number[]>
|
|
36
36
|
| BooleanSchema<string>
|
|
37
37
|
| NumberSchema<string>
|
|
38
38
|
| NumberSchema
|
|
39
39
|
| StringSchema
|
|
40
40
|
|
|
41
41
|
declare stateSchema:
|
|
42
|
-
| ArraySchema<string>
|
|
43
|
-
| ArraySchema<number>
|
|
42
|
+
| ArraySchema<string[]>
|
|
43
|
+
| ArraySchema<number[]>
|
|
44
44
|
| BooleanSchema<string>
|
|
45
45
|
| NumberSchema<string>
|
|
46
46
|
| NumberSchema
|
|
@@ -9,7 +9,10 @@ import {
|
|
|
9
9
|
FormComponent,
|
|
10
10
|
isFormValue
|
|
11
11
|
} from './FormComponent.js'
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
addClassOptionIfNone,
|
|
14
|
+
withCustomValidationOverrides
|
|
15
|
+
} from './helpers/index.js'
|
|
13
16
|
import { type RenderContext } from './types.js'
|
|
14
17
|
import { buildValidationMessages } from '../i18n/buildValidationMessages.js'
|
|
15
18
|
import { messageTemplate } from '../pageControllers/validationOptions.js'
|
|
@@ -141,16 +144,23 @@ export abstract class LocationFieldBase extends FormComponent {
|
|
|
141
144
|
}
|
|
142
145
|
|
|
143
146
|
getValidationMessagesOverride(translator: Translator) {
|
|
147
|
+
const { customValidationMessage, customValidationMessages } = this.options
|
|
144
148
|
const { t } = translator
|
|
145
149
|
const config = this.getValidationConfig(translator)
|
|
150
|
+
const defaults = {
|
|
151
|
+
'any.required':
|
|
152
|
+
config.requiredMessage ?? buildValidationMessages(t).objectRequired,
|
|
153
|
+
'string.empty':
|
|
154
|
+
config.requiredMessage ?? buildValidationMessages(t).objectRequired,
|
|
155
|
+
'string.pattern.base': config.patternErrorMessage
|
|
156
|
+
}
|
|
157
|
+
|
|
146
158
|
return {
|
|
147
|
-
[this.name]:
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
'string.pattern.base': config.patternErrorMessage
|
|
153
|
-
} as LanguageMessages
|
|
159
|
+
[this.name]: withCustomValidationOverrides(
|
|
160
|
+
defaults,
|
|
161
|
+
customValidationMessage,
|
|
162
|
+
customValidationMessages
|
|
163
|
+
)
|
|
154
164
|
}
|
|
155
165
|
}
|
|
156
166
|
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import { type NumberFieldComponent } from '@defra/forms-model'
|
|
2
|
-
import joi, {
|
|
3
|
-
type CustomValidator,
|
|
4
|
-
type LanguageMessages,
|
|
5
|
-
type NumberSchema
|
|
6
|
-
} from 'joi'
|
|
2
|
+
import joi, { type CustomValidator, type NumberSchema } from 'joi'
|
|
7
3
|
|
|
8
4
|
import {
|
|
9
5
|
FormComponent,
|
|
10
6
|
isFormValue
|
|
11
7
|
} from './FormComponent.js'
|
|
8
|
+
import { withCustomValidationOverrides } from './helpers/index.js'
|
|
12
9
|
import { type RenderContext } from './types.js'
|
|
13
10
|
import { buildValidationMessages } from '../i18n/buildValidationMessages.js'
|
|
14
11
|
import { messageTemplate } from '../pageControllers/validationOptions.js'
|
|
@@ -137,16 +134,23 @@ export class NumberField extends FormComponent {
|
|
|
137
134
|
}
|
|
138
135
|
|
|
139
136
|
getValidationMessagesOverride(translator: Translator) {
|
|
137
|
+
const { customValidationMessage, customValidationMessages } = this.options
|
|
140
138
|
const { t } = translator
|
|
139
|
+
const defaults = {
|
|
140
|
+
'any.required': buildValidationMessages(t).objectRequired,
|
|
141
|
+
'number.base': buildValidationMessages(t).objectMissing,
|
|
142
|
+
'number.precision': buildValidationMessages(t).numberPrecision,
|
|
143
|
+
'number.integer': buildValidationMessages(t).numberInteger,
|
|
144
|
+
'number.min': buildValidationMessages(t).numberMin,
|
|
145
|
+
'number.max': buildValidationMessages(t).numberMax
|
|
146
|
+
}
|
|
147
|
+
|
|
141
148
|
return {
|
|
142
|
-
[this.name]:
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
'number.min': buildValidationMessages(t).numberMin,
|
|
148
|
-
'number.max': buildValidationMessages(t).numberMax
|
|
149
|
-
} as LanguageMessages
|
|
149
|
+
[this.name]: withCustomValidationOverrides(
|
|
150
|
+
defaults,
|
|
151
|
+
customValidationMessage,
|
|
152
|
+
customValidationMessages
|
|
153
|
+
)
|
|
150
154
|
}
|
|
151
155
|
}
|
|
152
156
|
|
|
@@ -6,7 +6,10 @@ import {
|
|
|
6
6
|
} from '@defra/forms-model'
|
|
7
7
|
|
|
8
8
|
import { SelectionControlField } from './SelectionControlField.js'
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
addClassOptionIfNone,
|
|
11
|
+
withCustomValidationOverrides
|
|
12
|
+
} from './helpers/index.js'
|
|
10
13
|
import { buildValidationMessages } from '../i18n/buildValidationMessages.js'
|
|
11
14
|
import { type Translator } from '../i18n/types.js'
|
|
12
15
|
import { messageTemplate } from '../pageControllers/validationOptions.js'
|
|
@@ -62,11 +65,18 @@ export class YesNoField extends SelectionControlField {
|
|
|
62
65
|
}
|
|
63
66
|
|
|
64
67
|
getValidationMessagesOverride(translator: Translator) {
|
|
68
|
+
const { customValidationMessage, customValidationMessages } = this.options
|
|
65
69
|
const { selectYesNoRequired } = buildValidationMessages(translator.t)
|
|
70
|
+
const defaults = {
|
|
71
|
+
'any.required': selectYesNoRequired
|
|
72
|
+
}
|
|
73
|
+
|
|
66
74
|
return {
|
|
67
|
-
[this.name]:
|
|
68
|
-
|
|
69
|
-
|
|
75
|
+
[this.name]: withCustomValidationOverrides(
|
|
76
|
+
defaults,
|
|
77
|
+
customValidationMessage,
|
|
78
|
+
customValidationMessages
|
|
79
|
+
)
|
|
70
80
|
}
|
|
71
81
|
}
|
|
72
82
|
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { type ComponentDef } from '@defra/forms-model'
|
|
2
|
-
import joi, {
|
|
2
|
+
import joi, {
|
|
3
|
+
type JoiExpression,
|
|
4
|
+
type LanguageMessages,
|
|
5
|
+
type ReferenceOptions
|
|
6
|
+
} from 'joi'
|
|
3
7
|
import lowerFirst from 'lodash/lowerFirst.js'
|
|
4
8
|
|
|
5
9
|
import { type Translator } from '../../i18n/types.js'
|
|
@@ -69,6 +73,46 @@ export const lowerFirstExpressionOptions = {
|
|
|
69
73
|
export const createLowerFirstExpression = (template: string): JoiExpression =>
|
|
70
74
|
joi.expression(template, lowerFirstExpressionOptions) as JoiExpression
|
|
71
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Joi's own LanguageMessages type only allows string values, but
|
|
78
|
+
* buildValidationMessages() returns JoiExpression for templated messages,
|
|
79
|
+
* which Joi accepts at runtime. This type covers both.
|
|
80
|
+
*/
|
|
81
|
+
type TranslatedValidationMessages = Record<string, string | JoiExpression>
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Keep the form author's custom validation message for any key they set,
|
|
85
|
+
* so translated defaults only fill in the keys the author left blank.
|
|
86
|
+
* A single customValidationMessage covers every key in the schema.
|
|
87
|
+
*/
|
|
88
|
+
export function withCustomValidationOverrides(
|
|
89
|
+
defaults: TranslatedValidationMessages,
|
|
90
|
+
customValidationMessage?: string,
|
|
91
|
+
customValidationMessages?: LanguageMessages
|
|
92
|
+
): LanguageMessages {
|
|
93
|
+
const messages: TranslatedValidationMessages = {}
|
|
94
|
+
|
|
95
|
+
// A global override for all messages is the value for all scenarios
|
|
96
|
+
if (customValidationMessage) {
|
|
97
|
+
for (const key of Object.keys(defaults)) {
|
|
98
|
+
messages[key] = customValidationMessage
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return messages as LanguageMessages
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// A default only fills a key that the user has not configured
|
|
105
|
+
const authorKeys = Object.keys(customValidationMessages ?? {})
|
|
106
|
+
|
|
107
|
+
for (const [key, message] of Object.entries(defaults)) {
|
|
108
|
+
if (!authorKeys.includes(key)) {
|
|
109
|
+
messages[key] = message
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return messages as LanguageMessages
|
|
114
|
+
}
|
|
115
|
+
|
|
72
116
|
/**
|
|
73
117
|
* Translate a component label, in precedence order of errorDescription, then shortDesciption, then title
|
|
74
118
|
* @param {ComponentDef} component
|