json-schema-to-yup
Version:
Build a Yup schema from a JSON Schema. Also supports custom/alternative schema models such as GraphQL type defs
198 lines (180 loc) • 4.66 kB
JavaScript
// - `alpha-numeric`
// - `alpha`
// - `ascii`
// - `byte`
// - `credit-card`
// - `currency-amount`
// - `data-uri`
// - `date-time`
// - `date`
// - `domain-name`
// - `email`
// - `hash`
// - `hex-color`
// - `ipv4`
// - `ipv6`
// - `isbn`
// - `magnet-uri`
// - `mime-type`
// - `mobile-phone`
// - `mongo-id`
// - `postal-code`
// - `uri`
// - `uuid`
// const validator = require("validator");
import dashify from 'dashify';
//const camelCase = require("camelcase");
import camelCase from 'uppercamelcase';
import { addMethod, string } from 'yup';
const toConstraintsMap = (values, opts = {}) => {
return values.reduce((acc, value) => {
if (typeof value !== "string" && !(value instanceof Object)) {
if (opts.throws !== false) {
throw `toConstraintsMap: invalid entry ${value}`;
} else {
return acc;
}
}
if (typeof value === "string") {
acc[name] = {};
} else {
if (!value.name) {
if (opts.throws !== false) {
throw `toConstraintsMap: invalid entry ${value} missing name`;
} else {
return acc;
}
}
acc[value.name] = value;
}
return acc;
}, {});
};
// const defaultConstraints = [
// 'ascii',
// {
// name: alphanumeric,
// optsKey: "locale"
// },
// // ...
// ]
const defaultConstraints = {
alphanumeric: {
optsKey: "locale"
},
alpha: {
optsKey: "locale"
},
ascii: {},
byte: {},
creditCard: {},
currency: {
opts: "currencyOpts"
},
dataUri: {},
dateTime: {},
date: {},
domainName: {
opts: "domainOpts"
},
hash: {
opts: "hashAlgo"
},
hexColor: {},
ipv4: {},
ipv6: {},
isbn: {},
magnetUri: {},
mimeType: {},
mobilePhone: {},
mongoId: {},
postalCode: {},
uuid: {}
};
// Template:
// Yup.addMethod(Yup.string, "isHexColor", function(args) {
// const { message } = args;
// return this.test("hex-color", message, function(value) {
// const { path, createError } = this;
// // [value] - value of the property being tested
// // [path] - property name,
// // ...
// return validator.isHexColor(value) || createError({ path, message });
// });
// });
const defaults = {
createValidatorName: (validatorName, key) => {
const name = validatorName || key;
validatorName = camelCase(name);
validatorName = validatorName.replace(/Uri$/, "URI");
validatorName = validatorName.replace(/Id$/, "ID");
return `is${validatorName}`;
},
createTestName: (testName, key) => (testName = dashify(testName || key))
};
const fallBackFnMap = {
isMagnetURI: (value, isMagnetUri) => {
return /magnet:\?xt=urn:[a-z0-9]+:[a-z0-9]{32}/i.test(value);
}
};
function extendYupApi({
constraints,
override = false,
validator,
createValidatorName,
createTestName
} = {}) {
if (!validator) {
throw "extendYupApi: missing validator option";
}
if (Array.isArray(constraints)) {
constraints = toConstraintsMap(constraints);
}
if (!override) {
constraints = {
...defaultConstraints,
...(constraints || {})
};
} else {
constraints = constraints || defaultConstraints;
}
createValidatorName = createValidatorName || defaults.createValidatorName;
createTestName = createTestName || defaults.createTestName;
Object.keys(constraints).map(key => {
let { testName, optsKey, validatorName, logging } = constraints[key];
const fullValidatorName = createValidatorName(validatorName, key);
testName = createTestName(testName, key);
// See https://github.com/jquense/yup#yupaddmethodschematype-schema-name-string-method--schema-void
addMethod(string, key, (args = {}) => {
const { message } = args;
const opts = args[optsKey];
return string().test(testName, message, value => {
// return this.transform(value => {
const { path, createError } = this;
// [value] - value of the property being tested
// [path] - property name,
// ...
let validatorFn = validator[fullValidatorName];
validatorFn = validatorFn || fallBackFnMap[fullValidatorName];
if (typeof validatorFn !== "function") {
throw Error("No method named ${validatorName} on validator");
}
const valid = validatorFn(value, opts);
if (logging === true) {
console.log("Yup validator bridge", {
key,
fullValidatorName,
testName,
value,
valid
});
}
return valid || createError({ path, message });
});
});
});
}
export {
extendYupApi,
toConstraintsMap
};