UNPKG

@jsonjoy.com/json-type

Version:

High-performance JSON Pointer implementation

281 lines (280 loc) 10.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.validateSchema = exports.validateMinMax = exports.validateWithValidator = exports.validateTType = exports.validateTExample = exports.validateDisplay = void 0; const validateDisplay = ({ title, description, intro }) => { if (title !== undefined && typeof title !== 'string') throw new Error('INVALID_TITLE'); if (description !== undefined && typeof description !== 'string') throw new Error('INVALID_DESCRIPTION'); if (intro !== undefined && typeof intro !== 'string') throw new Error('INVALID_INTRO'); }; exports.validateDisplay = validateDisplay; const validateTExample = (example) => { (0, exports.validateDisplay)(example); }; exports.validateTExample = validateTExample; const validateTType = (tType, kind) => { (0, exports.validateDisplay)(tType); const { id } = tType; if (id !== undefined && typeof id !== 'string') throw new Error('INVALID_ID'); if (tType.kind !== kind) throw new Error('INVALID_TYPE'); const { examples } = tType; if (examples) { if (!Array.isArray(examples)) throw new Error('INVALID_EXAMPLES'); examples.forEach(exports.validateTExample); } }; exports.validateTType = validateTType; const validateWithValidator = ({ validator }) => { if (validator !== undefined) { if (Array.isArray(validator)) { for (const v of validator) if (typeof v !== 'string') throw new Error('INVALID_VALIDATOR'); } else if (typeof validator !== 'string') throw new Error('INVALID_VALIDATOR'); } }; exports.validateWithValidator = validateWithValidator; const validateMinMax = (min, max) => { if (min !== undefined) { if (typeof min !== 'number') throw new Error('MIN_TYPE'); if (min < 0) throw new Error('MIN_NEGATIVE'); if (min % 1 !== 0) throw new Error('MIN_DECIMAL'); } if (max !== undefined) { if (typeof max !== 'number') throw new Error('MAX_TYPE'); if (max < 0) throw new Error('MAX_NEGATIVE'); if (max % 1 !== 0) throw new Error('MAX_DECIMAL'); } if (min !== undefined && max !== undefined && min > max) throw new Error('MIN_MAX'); }; exports.validateMinMax = validateMinMax; // Individual schema validation functions for each type const validateAnySchema = (schema) => { (0, exports.validateTType)(schema, 'any'); }; const validateBooleanSchema = (schema) => { (0, exports.validateTType)(schema, 'bool'); }; const validateNumberSchema = (schema) => { (0, exports.validateTType)(schema, 'num'); (0, exports.validateWithValidator)(schema); const { format, gt, gte, lt, lte } = schema; if (gt !== undefined && typeof gt !== 'number') throw new Error('GT_TYPE'); if (gte !== undefined && typeof gte !== 'number') throw new Error('GTE_TYPE'); if (lt !== undefined && typeof lt !== 'number') throw new Error('LT_TYPE'); if (lte !== undefined && typeof lte !== 'number') throw new Error('LTE_TYPE'); if (gt !== undefined && gte !== undefined) throw new Error('GT_GTE'); if (lt !== undefined && lte !== undefined) throw new Error('LT_LTE'); if ((gt !== undefined || gte !== undefined) && (lt !== undefined || lte !== undefined)) if ((gt ?? gte) > (lt ?? lte)) throw new Error('GT_LT'); if (format !== undefined) { if (typeof format !== 'string') throw new Error('FORMAT_TYPE'); if (!format) throw new Error('FORMAT_EMPTY'); switch (format) { case 'i': case 'u': case 'f': case 'i8': case 'i16': case 'i32': case 'i64': case 'u8': case 'u16': case 'u32': case 'u64': case 'f32': case 'f64': break; default: throw new Error('FORMAT_INVALID'); } } }; const validateStringSchema = (schema) => { (0, exports.validateTType)(schema, 'str'); (0, exports.validateWithValidator)(schema); const { min, max, ascii, noJsonEscape, format } = schema; (0, exports.validateMinMax)(min, max); if (ascii !== undefined) { if (typeof ascii !== 'boolean') throw new Error('ASCII'); } if (noJsonEscape !== undefined) { if (typeof noJsonEscape !== 'boolean') throw new Error('NO_JSON_ESCAPE_TYPE'); } if (format !== undefined) { if (format !== 'ascii' && format !== 'utf8') { throw new Error('INVALID_STRING_FORMAT'); } // If both format and ascii are specified, they should be consistent if (ascii !== undefined && format === 'ascii' && !ascii) { throw new Error('FORMAT_ASCII_MISMATCH'); } } }; const binaryFormats = new Set(['bencode', 'bson', 'cbor', 'ion', 'json', 'msgpack', 'resp3', 'ubjson']); const validateBinarySchema = (schema, validateChildSchema) => { (0, exports.validateTType)(schema, 'bin'); const { min, max, format } = schema; (0, exports.validateMinMax)(min, max); if (format !== undefined) { if (!binaryFormats.has(format)) throw new Error('FORMAT'); } validateChildSchema(schema.type); }; const validateArraySchema = (schema, validateChildSchema) => { (0, exports.validateTType)(schema, 'arr'); const { min, max } = schema; (0, exports.validateMinMax)(min, max); validateChildSchema(schema.type); }; const validateConstSchema = (schema) => { (0, exports.validateTType)(schema, 'con'); }; const validateTupleSchema = (schema, validateChildSchema) => { (0, exports.validateTType)(schema, 'tup'); (0, exports.validateWithValidator)(schema); const { types } = schema; if (!Array.isArray(types)) throw new Error('TYPES_TYPE'); for (const type of types) validateChildSchema(type); }; const validateObjectSchema = (schema, validateChildSchema) => { (0, exports.validateTType)(schema, 'obj'); (0, exports.validateWithValidator)(schema); const { fields, unknownFields } = schema; if (!Array.isArray(fields)) throw new Error('FIELDS_TYPE'); if (unknownFields !== undefined && typeof unknownFields !== 'boolean') throw new Error('UNKNOWN_FIELDS_TYPE'); for (const field of fields) validateChildSchema(field); }; const validateFieldSchema = (schema, validateChildSchema) => { (0, exports.validateTType)(schema, 'field'); const { key, optional } = schema; if (typeof key !== 'string') throw new Error('KEY_TYPE'); if (optional !== undefined && typeof optional !== 'boolean') throw new Error('OPTIONAL_TYPE'); validateChildSchema(schema.value); }; const validateMapSchema = (schema, validateChildSchema) => { (0, exports.validateTType)(schema, 'map'); validateChildSchema(schema.value); if (schema.key) { validateChildSchema(schema.key); } }; const validateRefSchema = (schema) => { (0, exports.validateTType)(schema, 'ref'); const { ref } = schema; if (typeof ref !== 'string') throw new Error('REF_TYPE'); if (!ref) throw new Error('REF_EMPTY'); }; const validateOrSchema = (schema, validateChildSchema) => { (0, exports.validateTType)(schema, 'or'); const { types, discriminator } = schema; if (!discriminator || (discriminator[0] === 'num' && discriminator[1] === -1)) throw new Error('DISCRIMINATOR'); if (!Array.isArray(types)) throw new Error('TYPES_TYPE'); if (!types.length) throw new Error('TYPES_LENGTH'); for (const type of types) validateChildSchema(type); }; const validateFunctionSchema = (schema, validateChildSchema) => { (0, exports.validateTType)(schema, 'fn'); validateChildSchema(schema.req); validateChildSchema(schema.res); }; const validateFunctionStreamingSchema = (schema, validateChildSchema) => { (0, exports.validateTType)(schema, 'fn$'); validateChildSchema(schema.req); validateChildSchema(schema.res); }; /** * Main router function that validates a schema based on its kind. * This replaces the individual validateSchema() methods from type classes. */ const validateSchema = (schema) => { switch (schema.kind) { case 'any': validateAnySchema(schema); break; case 'bool': validateBooleanSchema(schema); break; case 'num': validateNumberSchema(schema); break; case 'str': validateStringSchema(schema); break; case 'bin': validateBinarySchema(schema, exports.validateSchema); break; case 'arr': validateArraySchema(schema, exports.validateSchema); break; case 'con': validateConstSchema(schema); break; case 'tup': validateTupleSchema(schema, exports.validateSchema); break; case 'obj': validateObjectSchema(schema, exports.validateSchema); break; case 'field': validateFieldSchema(schema, exports.validateSchema); break; case 'map': validateMapSchema(schema, exports.validateSchema); break; case 'ref': validateRefSchema(schema); break; case 'or': validateOrSchema(schema, exports.validateSchema); break; case 'fn': validateFunctionSchema(schema, exports.validateSchema); break; case 'fn$': validateFunctionStreamingSchema(schema, exports.validateSchema); break; default: throw new Error(`Unknown schema kind: ${schema.kind}`); } }; exports.validateSchema = validateSchema;