@flagpolejs/json-validator
Version:
Simple JSON validator that is similar to JSON Schema format, but with some simplified format that is more readable
192 lines • 6.47 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ValidationError = void 0;
class ValidationError {
}
exports.ValidationError = ValidationError;
function getType(value) {
if (value === undefined) {
return "undefined";
}
if (value === null) {
return "null";
}
const myType = typeof value;
if (Array.isArray(value)) {
return "array";
}
if (myType === "object") {
return "object";
}
if (myType == "boolean") {
return "boolean";
}
if (myType == "number") {
return "number";
}
return "string";
}
class JsonValidator {
constructor(schema) {
this._errors = [];
this.compile(schema);
}
static validate(schema, document) {
const validator = new JsonValidator(schema);
validator.validate(document);
return validator;
}
get isValid() {
return this._errors.length === 0;
}
get errors() {
return this._errors;
}
compile(schema) {
this._schema = typeof schema === "string" ? JSON.parse(schema) : schema;
return this.validate;
}
validate(root) {
this._errors = [];
this._isValid(this._schema, root, "$");
return this;
}
_logError(error) {
this._errors.push(error);
}
_matchesType(schema, document, path) {
const [schemaType, docType] = this.compareTypes(schema, document);
if (schemaType != "undefined") {
if (schemaType == "string") {
if (docType != schema) {
this._logError({
keyword: "type",
instancePath: path,
message: `must be ${schemaType}, but it was ${docType}`,
});
return false;
}
}
else if (schemaType == "array") {
const allowedTypes = schema;
if (allowedTypes.indexOf(docType) < 0) {
const oneOfType = allowedTypes.join(" | ");
this._logError({
keyword: "type",
instancePath: path,
message: `must be ${oneOfType}, but it was ${docType}`,
});
return false;
}
}
}
return true;
}
_matchesEnum(schema, document, path) {
if (getType(schema) == "array") {
if (schema.indexOf(document) < 0) {
const enumVals = schema.join(", ");
this._logError({
keyword: "value",
instancePath: path,
message: `value must be in enum ${enumVals}, but it was ${document}`,
});
return false;
}
}
return true;
}
_matchesPattern(schema, document, path) {
const [schemaType] = this.compareTypes(schema, document);
if (schemaType != "undefined" &&
!new RegExp(schema).test(String(document))) {
this._logError({
keyword: "value",
instancePath: path,
message: `value ${document} did not match ${String(schema)}`,
});
return false;
}
return true;
}
_matchesItems(schema, document, path) {
const [schemaType, docType] = this.compareTypes(schema, document);
if (schemaType != "undefined") {
if (docType != "array") {
this._logError({
keyword: "schema",
instancePath: path,
message: `must be an array, but schema defines items.`,
});
return false;
}
return document.every((subItem, index) => {
if (schemaType == "string" || schemaType == "array") {
return this._matchesType(schema, subItem, `${path}[${index}]`);
}
else if (schemaType == "object") {
return this._isValid(schema, subItem, `${path}[${index}]`);
}
return true;
});
}
return true;
}
compareTypes(schema, document) {
return [getType(schema), getType(document)];
}
_matchesProperties(schema, document, path) {
const [schemaType, docType] = this.compareTypes(schema, document);
if (schemaType != "undefined") {
if (docType != "object") {
this._logError({
keyword: "schema",
instancePath: "path",
message: `must be an object, but schema defines properties.`,
});
return false;
}
if (schemaType == "string" || schemaType == "array") {
return Object.keys(document).every((key) => {
return this._matchesType(schema, document[key], `${path}.${key}`);
});
}
if (schemaType == "object") {
return Object.keys(schema).every((key) => {
return this._isValid(schema[key], document[key], `${path}.${key}`);
});
}
}
return true;
}
_isValid(schema, document, path) {
const [schemaType] = this.compareTypes(schema, document);
if (schemaType == "string" || schemaType == "array") {
if (!this._matchesType(schema, document, path)) {
return false;
}
}
else if (schemaType == "object") {
if (!this._matchesType(schema.type, document, path)) {
if (!schema.optional || typeof document != "undefined") {
return false;
}
}
if (!this._matchesEnum(schema.enum, document, path)) {
return false;
}
if (!this._matchesPattern(schema.matches, document, path)) {
return false;
}
if (!this._matchesItems(schema.items, document, path)) {
return false;
}
if (!this._matchesProperties(schema.properties, document, path)) {
return false;
}
}
return true;
}
}
exports.default = JsonValidator;
//# sourceMappingURL=index.js.map