setup-node/node_modules/@octokit/rest/plugins/validate/validate.js

114 lines
3.6 KiB
JavaScript
Raw Permalink Normal View History

2019-08-05 15:18:52 -04:00
'use strict'
module.exports = validate
const { RequestError } = require('@octokit/request-error')
const get = require('lodash.get')
const set = require('lodash.set')
function validate (octokit, options) {
if (!options.request.validate) {
return
}
const { validate: params } = options.request
Object.keys(params).forEach(parameterName => {
const parameter = get(params, parameterName)
const expectedType = parameter.type
let parentParameterName
let parentValue
let parentParamIsPresent = true
let parentParameterIsArray = false
if (/\./.test(parameterName)) {
parentParameterName = parameterName.replace(/\.[^.]+$/, '')
parentParameterIsArray = parentParameterName.slice(-2) === '[]'
if (parentParameterIsArray) {
parentParameterName = parentParameterName.slice(0, -2)
}
parentValue = get(options, parentParameterName)
parentParamIsPresent = parentParameterName === 'headers' || (typeof parentValue === 'object' && parentValue !== null)
}
const values = parentParameterIsArray
? (get(options, parentParameterName) || []).map(value => value[parameterName.split(/\./).pop()])
: [get(options, parameterName)]
values.forEach((value, i) => {
const valueIsPresent = typeof value !== 'undefined'
const valueIsNull = value === null
const currentParameterName = parentParameterIsArray
? parameterName.replace(/\[\]/, `[${i}]`)
: parameterName
if (!parameter.required && !valueIsPresent) {
return
}
// if the parent parameter is of type object but allows null
// then the child parameters can be ignored
if (!parentParamIsPresent) {
return
}
if (parameter.allowNull && valueIsNull) {
return
}
if (!parameter.allowNull && valueIsNull) {
throw new RequestError(`'${currentParameterName}' cannot be null`, 400, {
request: options
})
}
if (parameter.required && !valueIsPresent) {
throw new RequestError(`Empty value for parameter '${currentParameterName}': ${JSON.stringify(value)}`, 400, {
request: options
})
}
// parse to integer before checking for enum
// so that string "1" will match enum with number 1
if (expectedType === 'integer') {
const unparsedValue = value
value = parseInt(value, 10)
if (isNaN(value)) {
throw new RequestError(`Invalid value for parameter '${currentParameterName}': ${JSON.stringify(unparsedValue)} is NaN`, 400, {
request: options
})
}
}
if (parameter.enum && parameter.enum.indexOf(value) === -1) {
throw new RequestError(`Invalid value for parameter '${currentParameterName}': ${JSON.stringify(value)}`, 400, {
request: options
})
}
if (parameter.validation) {
const regex = new RegExp(parameter.validation)
if (!regex.test(value)) {
throw new RequestError(`Invalid value for parameter '${currentParameterName}': ${JSON.stringify(value)}`, 400, {
request: options
})
}
}
if (expectedType === 'object' && typeof value === 'string') {
try {
value = JSON.parse(value)
} catch (exception) {
throw new RequestError(`JSON parse error of value for parameter '${currentParameterName}': ${JSON.stringify(value)}`, 400, {
request: options
})
}
}
set(options, parameter.mapTo || currentParameterName, value)
})
})
return options
}