swaps out ajv for joi

This commit is contained in:
James
2020-11-26 15:22:34 -05:00
parent 0e2fbe0e8f
commit 5ffa0ed6ee
10 changed files with 126 additions and 225 deletions

View File

@@ -1,154 +0,0 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "collection.schema.json",
"title": "Payload Collection Configuration",
"type": "object",
"required": [
"slug",
"fields"
],
"properties": {
"slug": {
"type": "string"
},
"labels": {
"type": "object",
"properties": {
"singular": {
"type": "string",
"description": "Name used when referring to an instance of the collection"
},
"plural": {
"type": "string",
"description": "Name used when referring to set of instances for the collection"
}
}
},
"access": {
"type": "object",
"description": "Callable functions to determine permission access"
},
"auth": {
"type": ["object", "boolean"],
"description": "Authentication properties",
"properties": {
"verify": {
"description": "Require users to verify their email before being able to login for this collection",
"anyOf": [
{
"type": "boolean",
"description": "Enable email verification of user accounts, set to true to enable the feature using Payload default settings"
},
{
"type": "object",
"anyOf": [
{
"required": [
"generateEmailSubject"
],
"properties": {
"generateEmailSubject": {
"type": "string",
"description": "Subject field used when sending verify email for new user accounts"
}
}
},
{
"required": [
"generateEmailHTML"
],
"generateEmailHTML": {
"type": "string",
"description": "Function that returns HTML for the body of the email sent to verify user accounts"
}
}
]
}
]
}
}
},
"fields": {
"type": "array",
"description": "The attributes of the collection",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "The attribute key of the field used on model instances"
},
"type": {
"type": "string",
"description": ""
},
"label": {
"type": "string",
"description": "Field label for the admin panel"
},
"required": {
"type": "boolean",
"description": "Enforce attribute has a value when saving"
},
"defaultValue": {
"description": "When not present, will be saved with when not given"
},
"unique": {
"description": "Enforce instances in the collection to not repeat the value",
"type": "boolean"
},
"access": {
"description": "Field level permissions",
"type": "object",
"properties": {
"create": {},
"update": {},
"read": {}
}
},
"relationTo": {
"description": "The name of the collection being referenced",
"anyOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "string"
}
}
]
},
"options": {
"description": "Choices",
"type": "array",
"items": {
"anyOf": [
{"type": "string"},
{
"type": "object",
"properties": {
"value": {
"description": "The data stored and returned for the selection",
"type": "string"
},
"label": {
"description": "The name that identifies the value to be selected",
"type": "string"
}
}
}
]
}
}
}
}
},
"timestamps": {
"type": "boolean",
"description": "Adds createdAt and updatedAt fields for the collection",
"default": true
}
}
}

View File

@@ -0,0 +1,7 @@
import Joi from 'joi';
const schema = Joi.object().keys({
slug: Joi.string().required(),
}).unknown();
export default schema;

View File

@@ -11,8 +11,6 @@ const sanitizeConfig = (config: Config): Config => {
// TODO: remove default values from sanitize in favor of assigning in the schema within validateSchema and use https://www.npmjs.com/package/ajv#coercing-data-types where needed
if (sanitizedConfig.publicENV === undefined) sanitizedConfig.publicENV = {};
if (sanitizedConfig.defaultDepth === undefined) sanitizedConfig.defaultDepth = 2;
sanitizedConfig.collections = sanitizedConfig.collections.map((collection) => sanitizeCollection(sanitizedConfig.collections, collection));
checkDuplicateCollections(sanitizedConfig.collections);

View File

@@ -1,53 +0,0 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "payload.schema.json",
"title": "Payload Configuration",
"type": "object",
"required": [
"collections"
],
"properties": {
"admin": {
"type": "object",
"description": "Admin panel configuration",
"properties": {
"user": {
"type": "string",
"description": "Collection name users designated to access the panel"
},
"meta": {
"type": "object",
"description": "Admin web interface configuration",
"required": [
"titleSuffix"
],
"properties": {
"titleSuffix": {
"type": "string",
"description": "Text to add at the end of the page title of the admin html head"
},
"ogImage": {
"type": "string",
"description": "src url for the admin image"
},
"favicon": {
"type": "string",
"description": "Admin panel favicon file to use"
}
}
}
}
},
"maxDepth": {
"type": "number",
"description": "The maximum population depth allowed for relationship fields",
"default": 10
},
"collections": {
"type": "array",
"items": {
"$ref": "./collection.schema.json"
}
}
}
}

53
src/config/schema.ts Normal file
View File

@@ -0,0 +1,53 @@
import Joi from 'joi';
import collectionSchema from '../collections/config/schema';
import globalSchema from '../globals/config/schema';
const schema = Joi.object().keys({
serverURL: Joi.string().required(),
routes: Joi.object()
.keys({
admin: Joi.string()
.default('/admin'),
api: Joi.string()
.default('/api'),
graphQL: Joi.string()
.default('/graphql'),
graphQLPlayground: Joi.string()
.default('/graphql-playground'),
}).default(),
collections: Joi.array()
.items(collectionSchema)
.default([]),
globals: Joi.array()
.items(globalSchema)
.default([]),
admin: Joi.object()
.keys({
user: Joi.string()
.default('users'),
meta: Joi.object()
.keys({
titleSuffix: Joi.string()
.default('- Payload'),
ogImage: Joi.string()
.default('/static/img/find-image-here.jpg'),
favicon: Joi.string()
.default('/static/img/whatever.png'),
})
.default(),
disable: Joi.bool()
.default(false),
components: Joi.object()
.keys({}),
}).default(),
defaultDepth: Joi.number()
.min(0)
.max(30)
.default(3),
maxDepth: Joi.number()
.min(0)
.max(100)
.default(11),
}).unknown();
export default schema;

View File

@@ -1,20 +1,22 @@
import Ajv from 'ajv';
import * as configSchema from './schema.json';
import * as collectionSchema from '../collections/config/schema.json';
import InvalidSchema from '../errors/InvalidSchema';
import schema from './schema';
import { PayloadConfig, Config } from './types';
const validateSchema = (config: PayloadConfig): Config => {
const ajv = new Ajv({ useDefaults: true });
const validate = ajv.addSchema(collectionSchema, '../collections/config/schema.json').compile(configSchema);
const valid = validate(config);
const result = schema.validate(config, {
abortEarly: false,
});
if (!valid) {
throw new InvalidSchema(`Invalid payload config provided. Found ${validate.errors.length} errors`, validate.errors);
if (result.error) {
console.error(`There were ${result.error.details.length} errors validating your Payload config`);
result.error.details.forEach(({ message }, i) => {
console.error(`${i + 1}: ${message}`);
});
process.exit(1);
}
return config as Config;
return result.value as Config;
};
export default validateSchema;

View File

@@ -0,0 +1,7 @@
import Joi from 'joi';
const schema = Joi.object().keys({
slug: Joi.string().required(),
}).unknown();
export default schema;