| "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(String(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; |
| } |