UNPKG

dtsgenerator

Version:

TypeScript d.ts file generator for JSON Schema file

439 lines (438 loc) 16.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.selectSchemaType = exports.searchAllSubSchema = exports.setId = exports.getId = exports.getSubSchema = void 0; const tslib_1 = require("tslib"); const JsonPointer = tslib_1.__importStar(require("../jsonPointer")); const schemaId_1 = tslib_1.__importDefault(require("./schemaId")); const type_1 = require("./type"); const utils_1 = require("./utils"); function getSubSchema(rootSchema, pointer, id) { const content = JsonPointer.get(rootSchema.content, JsonPointer.parse(pointer)); if (id == null) { const subId = typeof content === 'boolean' ? undefined : getId(rootSchema.type, content); const getParentIds = (s, result) => { result.push(s.id.getAbsoluteId()); return s.rootSchema == null ? result : getParentIds(s.rootSchema, result); }; if (subId) { id = new schemaId_1.default(subId, getParentIds(rootSchema, [])); } else { id = new schemaId_1.default(pointer, getParentIds(rootSchema, [])); } } return { type: rootSchema.type, id, content, rootSchema, }; } exports.getSubSchema = getSubSchema; const Draft04Id = 'id'; const Draft07Id = '$id'; function getId(type, content) { var _a, _b; if ((0, type_1.isJsonSchemaDraft04)(content, type)) { return (_a = content[Draft04Id]) !== null && _a !== void 0 ? _a : ''; } else { return (_b = content[Draft07Id]) !== null && _b !== void 0 ? _b : ''; } } exports.getId = getId; function setId(type, content, id) { var _a, _b; if ((0, type_1.isJsonSchemaDraft04)(content, type)) { (_a = content[Draft04Id]) !== null && _a !== void 0 ? _a : (content[Draft04Id] = id); } else { (_b = content[Draft07Id]) !== null && _b !== void 0 ? _b : (content[Draft07Id] = id); } } exports.setId = setId; function searchAllSubSchema(schema, onFoundSchema, onFoundReference) { const walkArray = (array, paths, parentIds) => { if (array == null) { return; } array.forEach((item, index) => { walk(item, paths.concat(index.toString()), parentIds); }); }; const walkObject = (obj, paths, parentIds) => { if (obj == null) { return; } Object.keys(obj).forEach((key) => { const sub = obj[key]; if (sub != null) { walk(sub, paths.concat(key), parentIds); } }); }; const walkMaybeArray = (item, paths, parentIds) => { if (Array.isArray(item)) { walkArray(item, paths, parentIds); } else { walk(item, paths, parentIds); } }; const walk = (s, paths, parentIds) => { if (s == null || typeof s !== 'object') { return; } const id = getId(schema.type, s); if (id && typeof id === 'string') { const schemaId = new schemaId_1.default(id, parentIds); const subSchema = { type: schema.type, id: schemaId, content: s, rootSchema: schema, }; onFoundSchema(subSchema); parentIds = parentIds.concat([schemaId.getAbsoluteId()]); } if (typeof s.$ref === 'string') { const schemaId = new schemaId_1.default(s.$ref, parentIds); s.$ref = schemaId.getAbsoluteId(); onFoundReference(schemaId); } walkArray(s.allOf, paths.concat('allOf'), parentIds); walkArray(s.anyOf, paths.concat('anyOf'), parentIds); walkArray(s.oneOf, paths.concat('oneOf'), parentIds); walk(s.not, paths.concat('not'), parentIds); walkMaybeArray(s.items, paths.concat('items'), parentIds); walk(s.additionalItems, paths.concat('additionalItems'), parentIds); walk(s.additionalProperties, paths.concat('additionalProperties'), parentIds); walkObject(s.definitions, paths.concat('definitions'), parentIds); walkObject(s.properties, paths.concat('properties'), parentIds); walkObject(s.patternProperties, paths.concat('patternProperties'), parentIds); walkMaybeArray(s.dependencies, paths.concat('dependencies'), parentIds); if (schema.type === 'Draft07') { if ('propertyNames' in s) { walk(s.propertyNames, paths.concat('propertyNames'), parentIds); walk(s.contains, paths.concat('contains'), parentIds); walk(s.if, paths.concat('if'), parentIds); walk(s.then, paths.concat('then'), parentIds); walk(s.else, paths.concat('else'), parentIds); } } }; function searchOpenApiSubSchema(openApi) { function createId(paths) { return '#/' + paths.join('/'); } function convertKeyToTypeName(key) { key = key.replace(/\/(.)/g, (_match, p1) => { return p1.toUpperCase(); }); return key .replace(/}/g, '') .replace(/{/g, '$') .replace(/^\//, '') .replace(/[^0-9A-Za-z_$]+/g, '_'); } function setSubIdToAnyObject(f, obj, keys) { if (obj == null) { return; } Object.keys(obj).forEach((key) => { const item = obj[key]; if (item != null) { f(item, keys.concat(convertKeyToTypeName(key))); } }); } function setSubIdToParameterObject(obj, keys) { if (obj == null) { return; } addParameterSchema(Object.entries(obj), keys); } function setSubIdToParameters(array, keys) { if (array == null) { return; } addParameterSchema(array.map((item, index) => { const key = 'name' in item ? item.name : `${index}`; return [key, item]; }), keys); } function addParameterSchema(input, keys) { const map = new Map(); const pushItem = (key, po) => { let work = map.get(key); if (work == null) { work = []; map.set(key, work); } work.push(po); }; for (const [key, item] of input) { if ('schema' in item) { setSubId(item.schema, keys.concat(key)); pushItem(item.in, [key, item]); } if ('content' in item) { setSubIdToMediaTypes(item.content, keys.concat(key)); pushItem(item.in, [key, item]); } if ('$ref' in item) { setSubId(item, keys.concat(key)); } if ('type' in item && item.in !== undefined) { setSubId(item, keys.concat(key)); pushItem(item.in, [key, item]); } } for (const [key, params] of map) { const [paths, obj] = buildParameterSchema(key, params, keys); setSubId(obj, paths); } } function buildParameterSchema(inType, params, keys) { const paths = keys .slice(0, keys.length - 1) .concat(inType + 'Parameters'); const properties = {}; params.forEach(([key, _]) => { properties[key] = { $ref: createId(keys.concat(key)), }; }); return [ paths, { id: createId(paths), type: 'object', properties, required: params .filter(([_, item]) => item.required === true) .map(([_, item]) => item.name), }, ]; } const setSubIdToResponsesV2 = (responses, keys) => setSubIdToAnyObject(setSubIdToResponseV2, responses, keys); function setSubIdToResponseV2(response, keys) { if (response == null) { return; } if ('schema' in response) { const s = response.schema; if (s != null && s.type === 'file') { return; } setSubId(s, keys); } } function setSubIdToOperationV2(ops, keys) { if (ops == null) { return; } const operationId = ops.operationId; if (operationId) { keys = [keys[0], convertKeyToTypeName(operationId)]; } setSubIdToParameters(ops.parameters, keys.concat('parameters')); setSubIdToResponsesV2(ops.responses, keys.concat('responses')); } const setSubIdToPathsV2 = (paths, keys) => setSubIdToAnyObject(setSubIdToPathItemV2, paths, keys); function setSubIdToPathItemV2(pathItem, keys) { setSubIdToParameters(pathItem.parameters, keys.concat('parameters')); setSubIdToOperationV2(pathItem.get, keys.concat('get')); setSubIdToOperationV2(pathItem.put, keys.concat('put')); setSubIdToOperationV2(pathItem.post, keys.concat('post')); setSubIdToOperationV2(pathItem.delete, keys.concat('delete')); setSubIdToOperationV2(pathItem.options, keys.concat('options')); setSubIdToOperationV2(pathItem.head, keys.concat('head')); setSubIdToOperationV2(pathItem.patch, keys.concat('patch')); } function setSubIdToMediaTypes(types, keys) { if (types == null) { return; } for (const mime of Object.keys(types)) { if ((0, utils_1.checkValidMIMEType)(mime)) { const mt = types[mime]; if (mt != null) { setSubId(mt.schema, keys); } } } } const setSubIdToRequestBodies = (bodies, keys) => setSubIdToAnyObject(setSubIdToRequestBody, bodies, keys); function setSubIdToRequestBody(body, keys) { if (body == null) { return; } if ('content' in body) { setSubIdToMediaTypes(body.content, keys); } else if ('$ref' in body) { setSubId(body, keys); } else { setSubId({ type: 'object' }, keys); } } const setSubIdToResponsesV3 = (responses, keys) => setSubIdToAnyObject(setSubIdToResponseV3, responses, keys); function setSubIdToResponseV3(response, keys) { if (response == null) { return; } if ('content' in response) { setSubIdToMediaTypes(response.content, keys); } else if ('$ref' in response) { setSubId(response, keys); } else { setSubId({ type: 'object' }, keys); } } function setSubIdToOperationV3(ops, keys) { if (ops == null) { return; } const operationId = ops.operationId; if (operationId) { keys = [keys[0], convertKeyToTypeName(operationId)]; } setSubIdToParameters(ops.parameters, keys.concat('parameters')); setSubIdToRequestBody(ops.requestBody, keys.concat('requestBody')); setSubIdToResponsesV3(ops.responses, keys.concat('responses')); } const setSubIdToPathsV3 = (paths, keys) => setSubIdToAnyObject(setSubIdToPathItemV3, paths, keys); function setSubIdToPathItemV3(pathItem, keys) { setSubIdToParameters(pathItem.parameters, keys.concat('parameters')); setSubIdToOperationV3(pathItem.get, keys.concat('get')); setSubIdToOperationV3(pathItem.put, keys.concat('put')); setSubIdToOperationV3(pathItem.post, keys.concat('post')); setSubIdToOperationV3(pathItem.delete, keys.concat('delete')); setSubIdToOperationV3(pathItem.options, keys.concat('options')); setSubIdToOperationV3(pathItem.head, keys.concat('head')); setSubIdToOperationV3(pathItem.patch, keys.concat('patch')); setSubIdToOperationV3(pathItem.trace, keys.concat('trace')); } function setSubIdToObject(obj, paths) { if (obj == null) { return; } Object.keys(obj).forEach((key) => { const sub = obj[key]; setSubId(sub, paths.concat(key)); }); } function setSubId(s, paths) { switch (typeof s) { case 'object': { const id = createId(paths); setId(schema.type, s, id); walk(s, paths, []); break; } case 'boolean': { const id = createId(paths); const schemaId = new schemaId_1.default(id, []); const subSchema = { type: schema.type, id: schemaId, content: s, rootSchema: schema, }; onFoundSchema(subSchema); break; } } } if ('swagger' in openApi) { setSubIdToObject(openApi.definitions, ['definitions']); setSubIdToParameterObject(openApi.parameters, ['parameters']); setSubIdToResponsesV2(openApi.responses, ['responses']); setSubIdToPathsV2(openApi.paths, ['paths']); } else { if (openApi.components) { const components = openApi.components; setSubIdToObject(components.schemas, ['components', 'schemas']); setSubIdToResponsesV3(components.responses, [ 'components', 'responses', ]); setSubIdToParameterObject(components.parameters, [ 'components', 'parameters', ]); setSubIdToRequestBodies(components.requestBodies, [ 'components', 'requestBodies', ]); } setSubIdToPathsV3(openApi.paths, ['paths']); } } if (schema.openApiVersion != null) { const obj = schema.content; searchOpenApiSubSchema(obj); return; } walk(schema.content, ['#'], []); } exports.searchAllSubSchema = searchAllSubSchema; function selectSchemaType(content) { var _a; if (typeof content === 'boolean') { return { type: 'Draft07' }; } if (typeof content !== 'object') { throw new Error(`expect parameter of type object, received ${typeof content}`); } if ('$schema' in content) { const schema = (_a = content.$schema) !== null && _a !== void 0 ? _a : ''; if (/^https?:\/\/json-schema.org\/schema#?$/.test(schema)) { return { type: 'Latest' }; } const match = /^https?:\/\/json-schema\.org\/(?:draft\/(\d{4}-\d{2})|draft-(\d+))\/schema#?$/.exec(schema); if (match) { if (match[1] != null) { switch (match[1]) { case '2019-09': return { type: '2019-09' }; case '2020-12': return { type: '2020-12' }; } } const version = Number(match[2]); if (version <= 4) { return { type: 'Draft04' }; } else { return { type: 'Draft07' }; } } } if ('swagger' in content && content.swagger === '2.0') { return { type: 'Draft04', openApiVersion: 2, }; } if ('openapi' in content && content.openapi) { const { openapi } = content; if (/^3\.\d+\.\d+$/.test(openapi)) { return { type: 'Draft07', openApiVersion: 3, }; } } return { type: 'Draft04' }; } exports.selectSchemaType = selectSchemaType;