UNPKG

@jsonjoy.com/json-type

Version:

High-performance JSON Pointer implementation

283 lines (282 loc) 8.63 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.typeToJsonSchema = typeToJsonSchema; /** * Extracts the base JSON Schema properties that are common to all types. * This replaces the logic from AbsType.toJsonSchema(). */ function getBaseJsonSchema(type, ctx) { const typeSchema = type.getSchema(); const jsonSchema = {}; if (typeSchema.title) jsonSchema.title = typeSchema.title; if (typeSchema.description) jsonSchema.description = typeSchema.description; if (typeSchema.examples) { jsonSchema.examples = typeSchema.examples.map((example) => example.value); } return jsonSchema; } /** * Main router function that converts a type to JSON Schema using a switch statement. * This replaces the individual toJsonSchema() methods on each type class. */ function typeToJsonSchema(type, ctx) { const typeName = type.getTypeName(); switch (typeName) { case 'any': return anyToJsonSchema(type, ctx); case 'arr': return arrayToJsonSchema(type, ctx); case 'bin': return binaryToJsonSchema(type, ctx); case 'bool': return booleanToJsonSchema(type, ctx); case 'con': return constToJsonSchema(type, ctx); case 'map': return mapToJsonSchema(type, ctx); case 'num': return numberToJsonSchema(type, ctx); case 'obj': return objectToJsonSchema(type, ctx); case 'or': return orToJsonSchema(type, ctx); case 'ref': return refToJsonSchema(type, ctx); case 'str': return stringToJsonSchema(type, ctx); case 'tup': return tupleToJsonSchema(type, ctx); default: // Fallback to base implementation for unknown types return getBaseJsonSchema(type, ctx); } } // Individual converter functions for each type function anyToJsonSchema(type, ctx) { const baseSchema = getBaseJsonSchema(type, ctx); const result = { type: ['string', 'number', 'boolean', 'null', 'array', 'object'], }; // Add base properties Object.assign(result, baseSchema); return result; } function arrayToJsonSchema(type, ctx) { const schema = type.getSchema(); const baseSchema = getBaseJsonSchema(type, ctx); const result = { type: 'array', items: typeToJsonSchema(type.type, ctx), }; // Add base properties Object.assign(result, baseSchema); if (schema.min !== undefined) result.minItems = schema.min; if (schema.max !== undefined) result.maxItems = schema.max; return result; } function binaryToJsonSchema(type, ctx) { const baseSchema = getBaseJsonSchema(type, ctx); const result = { type: 'binary', }; // Add base properties Object.assign(result, baseSchema); return result; } function booleanToJsonSchema(type, ctx) { const baseSchema = getBaseJsonSchema(type, ctx); const result = { type: 'boolean', }; // Add base properties Object.assign(result, baseSchema); return result; } function constToJsonSchema(type, ctx) { const schema = type.getSchema(); const baseSchema = getBaseJsonSchema(type, ctx); const value = schema.value; if (typeof value === 'string') { const result = { type: 'string', const: value, }; Object.assign(result, baseSchema); return result; } else if (typeof value === 'number') { const result = { type: 'number', const: value, }; Object.assign(result, baseSchema); return result; } else if (typeof value === 'boolean') { const result = { type: 'boolean', const: value, }; Object.assign(result, baseSchema); return result; } else if (value === null) { const result = { type: 'null', const: null, }; Object.assign(result, baseSchema); return result; } else if (typeof value === 'undefined') { // For undefined values, we return a special schema const result = { type: 'undefined', const: undefined, }; Object.assign(result, baseSchema); return result; } else if (Array.isArray(value)) { const result = { type: 'array', const: value, items: false, }; Object.assign(result, baseSchema); return result; } else if (typeof value === 'object') { const result = { type: 'object', const: value, }; Object.assign(result, baseSchema); return result; } return baseSchema; } function mapToJsonSchema(type, ctx) { const baseSchema = getBaseJsonSchema(type, ctx); const result = { type: 'object', patternProperties: { '.*': typeToJsonSchema(type.valueType, ctx), }, }; // Add base properties Object.assign(result, baseSchema); return result; } function numberToJsonSchema(type, ctx) { const schema = type.getSchema(); const baseSchema = getBaseJsonSchema(type, ctx); const result = { type: 'number', }; // Check if it's an integer format const ints = new Set(['i8', 'i16', 'i32', 'u8', 'u16', 'u32']); if (schema.format && ints.has(schema.format)) { result.type = 'integer'; } // Add base properties Object.assign(result, baseSchema); if (schema.gt !== undefined) result.exclusiveMinimum = schema.gt; if (schema.gte !== undefined) result.minimum = schema.gte; if (schema.lt !== undefined) result.exclusiveMaximum = schema.lt; if (schema.lte !== undefined) result.maximum = schema.lte; return result; } function objectToJsonSchema(type, ctx) { const schema = type.getSchema(); const baseSchema = getBaseJsonSchema(type, ctx); const result = { type: 'object', properties: {}, }; const required = []; const fields = type.fields; for (const field of fields) { result.properties[field.key] = typeToJsonSchema(field.value, ctx); if (!field.constructor.name.includes('Optional')) { required.push(field.key); } } if (required.length) result.required = required; if (schema.unknownFields === false) result.additionalProperties = false; // Add base properties Object.assign(result, baseSchema); return result; } function orToJsonSchema(type, ctx) { const baseSchema = getBaseJsonSchema(type, ctx); const types = type.types; const result = { anyOf: types.map((t) => typeToJsonSchema(t, ctx)), }; // Add base properties Object.assign(result, baseSchema); return result; } function refToJsonSchema(type, ctx) { const schema = type.getSchema(); const baseSchema = getBaseJsonSchema(type, ctx); const ref = schema.ref; if (ctx) ctx.mentionRef(ref); const result = { $ref: `#/$defs/${ref}`, }; // Add base properties Object.assign(result, baseSchema); return result; } function stringToJsonSchema(type, ctx) { const schema = type.getSchema(); const baseSchema = getBaseJsonSchema(type, ctx); const result = { type: 'string', }; if (schema.min !== undefined) result.minLength = schema.min; if (schema.max !== undefined) result.maxLength = schema.max; // Add format to JSON Schema if specified if (schema.format) { if (schema.format === 'ascii') { // JSON Schema doesn't have an "ascii" format, but we can use a pattern // ASCII characters are from 0x00 to 0x7F (0-127) result.pattern = '^[\\x00-\\x7F]*$'; } // UTF-8 is the default for JSON Schema strings, so we don't need to add anything special } else if (schema.ascii) { // Backward compatibility: if ascii=true, add pattern result.pattern = '^[\\x00-\\x7F]*$'; } // Add base properties Object.assign(result, baseSchema); return result; } function tupleToJsonSchema(type, ctx) { const baseSchema = getBaseJsonSchema(type, ctx); const types = type.types; const result = { type: 'array', items: false, prefixItems: types.map((t) => typeToJsonSchema(t, ctx)), }; // Add base properties Object.assign(result, baseSchema); return result; }