UNPKG

@openactive/data-model-validator

Version:

A library to allow a developer to validate a JSON document against the OpenActive Modelling Opportunity Specification

124 lines (118 loc) 4.34 kB
const Rule = require('../rule'); const PropertyHelper = require('../../helpers/property'); const ValidationErrorType = require('../../errors/validation-error-type'); const ValidationErrorCategory = require('../../errors/validation-error-category'); const ValidationErrorSeverity = require('../../errors/validation-error-severity'); module.exports = class ValueInOptionsRule extends Rule { constructor(options) { super(options); this.targetFields = '*'; this.meta = { name: 'ValueInOptionsRule', description: 'Validates that properties contain allowed values.', tests: { default: { message: 'Value `"{{value}}"` is not in the allowed values for this property. Must be one of:\n\n{{allowedValues}}.', sampleValues: { value: 'Male', allowedValues: '<ul><li>`"https://openactive.io/Female"`</li><li>`"https://openactive.io/Male"`</li><li>`"https://openactive.io/NoRestriction"`</li></ul>', }, category: ValidationErrorCategory.CONFORMANCE, severity: ValidationErrorSeverity.FAILURE, type: ValidationErrorType.FIELD_NOT_IN_DEFINED_VALUES, }, fieldArray: { message: 'This property cannot be an array. Must be one of:\n\n{{allowedValues}}.', sampleValues: { value: 'Male', allowedValues: '<ul><li>`"https://openactive.io/Female"`</li><li>`"https://openactive.io/Male"`</li><li>`"https://openactive.io/NoRestriction"`</li></ul>', }, category: ValidationErrorCategory.CONFORMANCE, severity: ValidationErrorSeverity.FAILURE, type: ValidationErrorType.FIELD_NOT_IN_DEFINED_VALUES, }, }, }; } validateField(node, field) { // Don't do this check for models that we don't actually have a spec for if (!node.model.hasSpecification) { return []; } const errors = []; const fieldObj = node.model.getField(field); const fieldValue = node.getValue(field); if ( typeof fieldValue !== 'undefined' && typeof fieldObj !== 'undefined' ) { let isInOptions = true; let isArrayButCannotBeArray = false; let allowedOptions; let testType; const possibleTypes = fieldObj.getAllPossibleTypes(); if (possibleTypes.length === 1) { testType = possibleTypes[0].replace(/^ArrayOf#/, ''); } else { testType = fieldObj.detectType(fieldValue).replace(/^ArrayOf#/, ''); } if ( typeof fieldObj.options !== 'undefined' ) { allowedOptions = fieldObj.options; } else if ( typeof testType !== 'undefined' && PropertyHelper.isEnum(testType, node.options.version) ) { allowedOptions = PropertyHelper.getEnumOptions(testType, node.options.version); } let singleFieldValue = fieldValue; if (typeof allowedOptions !== 'undefined') { if (fieldValue instanceof Array && fieldObj.canBeArray()) { for (const value of fieldValue) { if (allowedOptions.indexOf(value) < 0) { isInOptions = false; isArrayButCannotBeArray = false; singleFieldValue = value; break; } } } else if (fieldValue instanceof Array && !fieldObj.canBeArray()) { isArrayButCannotBeArray = true; } else if (allowedOptions.indexOf(fieldValue) < 0) { isInOptions = false; } } if (isArrayButCannotBeArray) { errors.push( this.createError( 'fieldArray', { value: singleFieldValue, path: node.getPath(field), }, { value: singleFieldValue, allowedValues: `<ul><li>\`"${allowedOptions.join('"`</li><li>`"')}"\`</li></ul>`, }, ), ); } else if (!isInOptions) { errors.push( this.createError( 'default', { value: singleFieldValue, path: node.getPath(field), }, { value: singleFieldValue, allowedValues: `<ul><li>\`"${allowedOptions.join('"`</li><li>`"')}"\`</li></ul>`, }, ), ); } } return errors; } };