yaml-to-json-schema
Version:
Generate json schema from yaml (swagger, openapi, asyncapi)
117 lines (116 loc) • 3.16 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.parse = void 0;
const path_1 = require("path");
const fs_1 = require("fs");
const js_yaml_1 = __importDefault(require("js-yaml"));
let basedir;
const keys = {};
const setKey = (key, ref, src) => {
if (!ref) {
return;
}
const file = path_1.normalize(ref);
keys[file] = key;
};
const getKey = (ref, src) => {
if (ref.startsWith('#')) {
return path_1.basename(ref);
}
const file = path_1.resolve(path_1.dirname(src), ref);
const path = path_1.relative(basedir, file);
const key = keys[path];
if (!key)
console.error('WARNING:', key, path);
return key;
};
const fixOf = (refs, src) => {
refs.forEach((item) => {
fixProperty(item, src);
});
};
const fixAddons = (doc, src) => {
if (doc.allOf) {
fixOf(doc.allOf, src);
}
else if (doc.oneOf) {
fixOf(doc.oneOf, src);
}
else if (doc.anyOf) {
fixOf(doc.anyOf, src);
}
else if (doc.not) {
fixProperty(doc.not, src);
}
};
const fixProperty = (prop, src) => {
if (prop.$ref) {
prop.$ref = '#definitions/' + getKey(prop.$ref, src);
}
else if (prop.type === 'object') {
fixRef(prop, src);
}
else if (prop.type === 'array') {
fixProperty(prop.items, src);
}
fixAddons(prop, src);
return prop;
};
const fixRef = (doc, src) => {
fixAddons(doc, src);
for (const key in doc.properties) {
fixProperty(doc.properties[key], src);
}
return doc;
};
const loadYamlFile = async (file) => {
const content = await fs_1.promises.readFile(file, 'utf8');
return js_yaml_1.default.load(content);
};
const loadPath = async (ref, src) => {
const dir = path_1.dirname(src);
const file = path_1.resolve(dir, ref);
const doc = await loadYamlFile(file);
if (!doc) {
throw new Error('Empty doc');
}
if (typeof doc === 'string' || typeof doc === 'number') {
throw new Error('Unsupported doc');
}
// @ts-ignore
return fixRef(doc, file);
};
const loadSchema = async (doc, src) => {
if (doc.$ref) {
return loadPath(doc.$ref, src);
}
return fixRef(doc, src);
};
const prepare = async (doc, src) => {
const definitions = {};
const properties = {};
const { schemas } = doc.components ?? {};
basedir = path_1.dirname(src);
for (const key in schemas) {
setKey(key, schemas[key].$ref, src);
}
for (const key in schemas) {
definitions[key] = await loadSchema(schemas[key], src);
// @ts-ignore // @TODO fix this issue. Error TS2740: Type '{ $ref: string; }'
properties[key] = { $ref: '#definitions/' + key };
}
return {
type: 'object',
definitions,
properties
};
};
async function parse(options) {
const { input } = options;
const doc = await loadYamlFile(input);
return prepare(doc, input);
}
exports.parse = parse;