UNPKG

@jsonjoy.com/json-type

Version:

High-performance JSON Pointer implementation

301 lines 9.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.aliasToJsonSchema = void 0; exports.typeToJsonSchema = typeToJsonSchema; const TypeExportContext_1 = require("../type/classes/ModuleType/TypeExportContext"); const aliasToJsonSchema = (alias) => { const node = { $id: alias.id, $ref: '#/$defs/' + alias.id, $defs: {}, }; const ctx = new TypeExportContext_1.TypeExportContext(); ctx.visitRef(alias.id); node.$defs[alias.id] = typeToJsonSchema(alias.type, ctx); let ref; while ((ref = ctx.nextMentionedRef())) { ctx.visitRef(ref); node.$defs[ref] = typeToJsonSchema(alias.system.resolve(ref).type, ctx); } return node; }; exports.aliasToJsonSchema = aliasToJsonSchema; /** * 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.kind(); 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); 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) { // TODO: Handle head and tail tuples. // function tupleToJsonSchema(type: TupType<any>, ctx?: TypeExportContext): JsonSchemaArray { // const baseSchema = getBaseJsonSchema(type, ctx); // const types = (type as any).types; // const result: JsonSchemaArray = { // type: 'array', // items: false, // prefixItems: types.map((t: any) => typeToJsonSchema(t, ctx)), // }; // // Add base properties // Object.assign(result, baseSchema); // return result; // } 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._value, 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.keys; for (const field of fields) { result.properties[field.key] = typeToJsonSchema(field.val, ctx); if (!field.optional) { required.push(field.key); } } if (required.length) result.required = required; if (schema.decodeUnknownKeys === 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; } //# sourceMappingURL=converter.js.map