'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 }