151 lines
4 KiB
JavaScript
151 lines
4 KiB
JavaScript
"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;
|
|
}
|