Skip to content

Commit f1cb21e

Browse files
committed
refactor(validation.js): add validationIssue method
1 parent 7717c28 commit f1cb21e

File tree

1 file changed

+43
-44
lines changed

1 file changed

+43
-44
lines changed

lib/editor/util/validation.js

Lines changed: 43 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ export type EditorValidationIssue = {
1515
reason: string
1616
}
1717

18+
const EMPTY_FIELD_REASON = 'Required field must not be empty'
19+
1820
export function doesNotExist (value: any): boolean {
1921
return value === '' || value === null || typeof value === 'undefined'
2022
}
@@ -39,7 +41,6 @@ export function validate (
3941
const isOptionalAndEmpty = !required && valueDoesNotExist
4042
const agencies = getTableById(tableData, 'agency')
4143
let locationType: ?number = null
42-
let reason = 'Required field must not be empty'
4344

4445
// entity.locationtype is a string. Convert to number for conditinals later on.
4546
if (entity && entity.location_type !== null) {
@@ -52,13 +53,21 @@ export function validate (
5253
result: false | EditorValidationIssue
5354
}
5455

56+
/**
57+
* Construct an EditorValidationIssue for the field name and reason (defaults to
58+
* empty field message).
59+
*/
60+
function validationIssue (reason = EMPTY_FIELD_REASON, field = name) {
61+
return {field, invalid: true, reason}
62+
}
63+
5564
/**
5665
* Checks whether value is a positive number
5766
*/
5867
function checkPositiveNumber (): CheckPositiveOutput {
5968
if (isRequiredButEmpty) {
6069
return {
61-
result: {field: name, invalid: isRequiredButEmpty, reason}
70+
result: validationIssue()
6271
}
6372
} else if (isOptionalAndEmpty) {
6473
return {
@@ -70,14 +79,14 @@ export function validate (
7079
// make sure value is parseable to a number
7180
if (isNaN(num)) {
7281
return {
73-
result: {field: name, invalid: true, reason: 'Field must be a valid number'}
82+
result: validationIssue('Field must be a valid number')
7483
}
7584
}
7685

7786
// make sure value is positive
7887
if (num < 0) {
7988
return {
80-
result: {field: name, invalid: true, reason: 'Field must be a positive number'}
89+
result: validationIssue('Field must be a positive number')
8190
}
8291
}
8392

@@ -112,21 +121,20 @@ export function validate (
112121
idList.length > 1 &&
113122
valueDoesNotExist
114123
) {
115-
reason = 'Identifier is required if more than one agency exists'
116-
return {field: name, invalid: isRequiredButEmpty, reason}
124+
return validationIssue('Identifier is required if more than one agency exists')
117125
}
118126
if (isRequiredButEmpty || isNotUnique) {
127+
let reason
119128
if (isNotUnique) {
120129
reason = 'Identifier must be unique'
121130
}
122-
return {field: name, invalid: isRequiredButEmpty || isNotUnique, reason}
131+
return validationIssue(reason)
123132
} else {
124133
return false
125134
}
126135
case 'TEXT':
127136
if (name === 'stop_name' && locationType !== null && (typeof locationType === 'number' && locationType <= 2)) {
128-
reason = 'Stop name is required for your current location type'
129-
return {field: name, invalid: isOptionalAndEmpty, reason}
137+
return validationIssue('Stop name is required for your current location type')
130138
}
131139
if (name === 'route_short_name' && !value && entity && entity.route_long_name) {
132140
return false
@@ -139,7 +147,7 @@ export function validate (
139147
return false
140148
} else {
141149
if (isRequiredButEmpty) {
142-
return {field: name, invalid: isRequiredButEmpty, reason}
150+
return validationIssue()
143151
} else {
144152
return false
145153
}
@@ -150,82 +158,77 @@ export function validate (
150158
case 'GTFS_FARE':
151159
case 'GTFS_SERVICE':
152160
if (isRequiredButEmpty) {
153-
return {field: name, invalid: isRequiredButEmpty, reason}
161+
return validationIssue()
154162
} else {
155163
return false
156164
}
157165
case 'URL':
158166
const isNotUrl = value && !validator.isURL(value)
159167
if (isRequiredButEmpty || isNotUrl) {
168+
let reason
160169
if (isNotUrl) {
161170
reason = 'Field must contain valid URL.'
162171
}
163-
return {field: name, invalid: isRequiredButEmpty || isNotUrl, reason}
172+
return validationIssue(reason)
164173
} else {
165174
return false
166175
}
167176
case 'EMAIL':
168177
const isNotEmail = value && !validator.isEmail(value)
169178
if (isRequiredButEmpty || isNotEmail) {
179+
let reason
170180
if (isNotEmail) {
171181
reason = 'Field must contain valid email address.'
172182
}
173-
return {field: name, invalid: isRequiredButEmpty || isNotEmail, reason}
183+
return validationIssue(reason)
174184
} else {
175185
return false
176186
}
177187
case 'GTFS_ZONE':
178188
if (isRequiredButEmpty) {
179-
return {field: name, invalid: isRequiredButEmpty, reason}
189+
return validationIssue()
180190
} else {
181191
return false
182192
}
183193
case 'TIMEZONE':
184194
if (isRequiredButEmpty) {
185-
return {field: name, invalid: isRequiredButEmpty, reason}
195+
return validationIssue()
186196
} else {
187197
return false
188198
}
189199
case 'LANGUAGE':
190200
if (isRequiredButEmpty) {
191-
return {field: name, invalid: isRequiredButEmpty, reason}
201+
return validationIssue()
192202
} else {
193203
return false
194204
}
195205
case 'LATITUDE':
196206
const isNotLat = value > 90 || value < -90
197207
if (isNotLat) {
198-
reason = 'Field must be valid latitude.'
199-
return {field: name, invalid: isNotLat, reason}
208+
return validationIssue(name, 'Field must be valid latitude.')
200209
}
201210
if (isOptionalAndEmpty && locationType !== null && (typeof locationType === 'number' && locationType <= 2)) {
202-
reason = 'Latitude and Longitude are required for your current location type'
203-
return {field: name, invalid: isOptionalAndEmpty, reason}
211+
return validationIssue('Latitude and Longitude are required for your current location type')
204212
}
205213
return false
206214
case 'LONGITUDE':
207215
const isNotLng = value > 180 || value < -180
208216
if (isNotLng) {
209-
reason = 'Field must be valid longitude.'
210-
return {field: name, invalid: isOptionalAndEmpty || isNotLng, reason}
217+
return validationIssue('Field must be valid longitude.')
211218
}
212-
if (isOptionalAndEmpty && locationType !== null && (typeof locationType === 'number' && locationType <= 2)) {
213-
reason = 'Latitude and Longitude are required for your current location type'
214-
return {field: name, invalid: isOptionalAndEmpty || isNotLng, reason}
219+
if (isOptionalAndEmpty && typeof locationType === 'number' && locationType <= 2) {
220+
return validationIssue('Latitude and Longitude are required for your current location type')
215221
}
216222
return false
217223
case 'TIME':
218224
case 'NUMBER':
219225
const isNotANumber = isNaN(value)
220226
if (isRequiredButEmpty || isNotANumber) {
227+
let reason
221228
if (isNotANumber) {
222229
reason = 'Field must be valid number'
223230
}
224-
return {
225-
field: name,
226-
invalid: isRequiredButEmpty || isNotANumber,
227-
reason
228-
}
231+
return validationIssue(reason)
229232
} else {
230233
return false
231234
}
@@ -247,8 +250,7 @@ export function validate (
247250
}
248251
if (!hasService && name === 'monday') {
249252
// only add validation issue for one day of week (monday)
250-
reason = 'Calendar must have service for at least one day'
251-
return {field: name, invalid: isRequiredButEmpty, reason}
253+
return validationIssue('Calendar must have service for at least one day')
252254
}
253255
return false
254256
case 'DROPDOWN':
@@ -257,7 +259,7 @@ export function validate (
257259
field.options &&
258260
field.options.findIndex(o => o.value === '') === -1
259261
) {
260-
return {field: name, invalid: isRequiredButEmpty, reason}
262+
return validationIssue()
261263
} else {
262264
return false
263265
}
@@ -267,11 +269,7 @@ export function validate (
267269
agencies.length > 1
268270
) {
269271
if (valueDoesNotExist) {
270-
return {
271-
field: name,
272-
invalid: true,
273-
reason: 'Field must be populated for feeds with more than one agency.'
274-
}
272+
return validationIssue('Field must be populated for feeds with more than one agency.')
275273
}
276274
}
277275
return false
@@ -300,18 +298,19 @@ export function validate (
300298
}
301299
}
302300
if (!value || value.length === 0) {
303-
return {field: `dates`, invalid: true, reason}
301+
return validationIssue(EMPTY_FIELD_REASON, 'dates')
304302
}
305303
// check if date already exists in this or other exceptions
306304
for (let i = 0; i < value.length; i++) {
305+
const dateItemName = `dates-${i}`
307306
if (dateMap[value[i]] && dateMap[value[i]].length > 1) {
308307
// eslint-disable-next-line standard/computed-property-even-spacing
309-
reason = `Date (${value[
308+
const reason = `Date (${value[
310309
i
311310
]}) cannot appear more than once for all exceptions`
312-
return {field: `dates-${i}`, invalid: true, reason}
311+
return validationIssue(reason, dateItemName)
313312
} else if (!moment(value[i], 'YYYYMMDD', true).isValid()) {
314-
return {field: `dates-${i}`, invalid: true, reason}
313+
return validationIssue(EMPTY_FIELD_REASON, dateItemName)
315314
}
316315
}
317316
return false
@@ -331,7 +330,7 @@ export function validate (
331330
)
332331
)
333332
) {
334-
return {field: name, invalid: true, reason: 'Field must be a positive integer'}
333+
return validationIssue(name, 'Field must be a positive integer')
335334
}
336335
return false
337336
case 'POSITIVE_NUM':
@@ -342,7 +341,7 @@ export function validate (
342341
case 'COLOR':
343342
default:
344343
if (isRequiredButEmpty) {
345-
return {field: name, invalid: isRequiredButEmpty, reason}
344+
return validationIssue()
346345
}
347346
return false
348347
}

0 commit comments

Comments
 (0)