@jsonjoy.com/json-type
Version:
High-performance JSON Pointer implementation
301 lines • 9.4 kB
JavaScript
"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