runtypes-to-jsonschema
Version:
convert runtypes schemas to jsonschema
102 lines (101 loc) • 3.92 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.tojsonschema = void 0;
const nev = (x) => {
throw new Error(`unhandled case: ${x}`);
};
const tojsonschema = (rtschema, subjsonschema = {}, options) => {
const { loose: isLooseMode } = options || {};
const js = subjsonschema;
const { description, defaultValue } = rtschema.meta || {};
if (description) {
js.description = description;
}
if (defaultValue != undefined) {
// https://json-schema.org/understanding-json-schema/reference/generic.html?highlight=default
js.default = defaultValue;
}
const reflect = rtschema.reflect;
switch (reflect.tag) {
case "array":
// https://json-schema.org/understanding-json-schema/reference/array.html#id6
js.type = "array";
js.items = (0, exports.tojsonschema)(reflect.element, {}, options);
return js;
case "void":
case "never":
case "unknown":
case "function":
case "instanceof":
case "symbol":
case "template":
if (isLooseMode) {
return js;
}
throw new Error(`unsupported ${reflect.tag}. consider using { loose: true }`);
case "bigint":
js.type = "integer";
return js;
case "number":
js.type = "number";
return js;
case "boolean":
js.type = "boolean";
return js;
case "brand":
return (0, exports.tojsonschema)(reflect.entity, js, options);
case "constraint":
// https://github.com/pelotom/runtypes/issues/319
return (0, exports.tojsonschema)(rtschema.underlying, js, options);
case "dictionary":
// https://json-schema.org/understanding-json-schema/reference/object.html#id5
js.type = "object";
js.properties = { builtin: (0, exports.tojsonschema)(reflect.value, {}, options) };
return js;
case "intersect":
// @todo - this could be tricky. go easy mode for 1st pass
// https://github.com/pelotom/runtypes#template-literals
js.type = "string";
return js;
case "literal":
js.const = reflect.value;
return js;
case "optional":
return (0, exports.tojsonschema)(reflect.underlying, {}, options);
case "record":
js.type = "object";
js.properties = Object.entries(reflect.fields).reduce((props, [k, v]) => {
let isRequired = reflect.isPartial ? false : true;
let underlying = v;
do {
if (underlying?.tag === "optional") {
isRequired = false;
break;
}
underlying =
"underlying" in underlying ? underlying.underlying : null;
} while (underlying);
if (isRequired) {
js.required = [...(js.required || []), k];
}
props[k] = (0, exports.tojsonschema)(v, {}, options);
return props;
}, {});
return js;
case "string":
js.type = "string";
return js;
case "tuple":
// https://json-schema.org/understanding-json-schema/reference/combining.html#id5
// @todo allOf drops order. is there a better way?
js.allOf = reflect.components.map((v) => (0, exports.tojsonschema)(v, {}, options));
return js;
case "union":
js.anyOf = reflect.alternatives.map((v) => (0, exports.tojsonschema)(v, {}, options));
return js;
default:
nev(reflect);
return js;
}
};
exports.tojsonschema = tojsonschema;