UNPKG

openapi-ts-json-schema

Version:

OpenAPI to JSON schema generator with TypeScript in mind

147 lines (146 loc) 6.36 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.openapiToTsJsonSchema = void 0; const fs_1 = require("fs"); const node_path_1 = __importDefault(require("node:path")); const json_schema_ref_parser_1 = __importDefault(require("@apidevtools/json-schema-ref-parser")); const lodash_get_1 = __importDefault(require("lodash.get")); const utils_1 = require("./utils"); async function openapiToTsJsonSchema(options) { const { plugins = [] } = options; // Execute plugins onInit method for (const { onInit } of plugins) { if (onInit) { await onInit({ options, }); } } const { openApiSchema: openApiSchemaRelative, definitionPathsToGenerateFrom, schemaPatcher, outputPath: providedOutputPath, silent, refHandling = 'import', $idMapper = ({ id }) => id, } = options; if (definitionPathsToGenerateFrom.length === 0 && !silent) { console.log(`[openapi-ts-json-schema] ⚠️ No schemas will be generated since definitionPathsToGenerateFrom option is empty`); } definitionPathsToGenerateFrom.forEach((defPath) => { if (node_path_1.default.isAbsolute(defPath)) { throw new Error(`[openapi-ts-json-schema] "definitionPathsToGenerateFrom" must be an array of relative paths. "${defPath}" found.`); } }); const openApiSchemaPath = node_path_1.default.resolve(openApiSchemaRelative); if (!(0, fs_1.existsSync)(openApiSchemaPath)) { throw new Error(`[openapi-ts-json-schema] Provided OpenAPI definition path doesn't exist: ${openApiSchemaPath}`); } const outputPath = providedOutputPath ?? node_path_1.default.resolve(node_path_1.default.dirname(openApiSchemaPath), 'schemas-autogenerated'); await (0, utils_1.clearFolder)(outputPath); const openApiParser = new json_schema_ref_parser_1.default(); const jsonSchemaParser = new json_schema_ref_parser_1.default(); // Resolve and inline external $ref definitions const bundledOpenApiSchema = await openApiParser.bundle(openApiSchemaPath); // Convert oas definitions to JSON schema const initialJsonSchema = (0, utils_1.convertOpenApiToJsonSchema)(bundledOpenApiSchema); const inlinedRefs = new Map(); // Inline and collect internal $ref definitions const dereferencedJsonSchema = await jsonSchemaParser.dereference(initialJsonSchema, { dereference: { // @ts-expect-error onDereference seems not to be properly typed onDereference: (ref, inlinedSchema) => { const id = (0, utils_1.refToId)(ref); // Keep track of inlined refs if (!inlinedRefs.has(id)) { // Shallow copy the ref schema to avoid the mutations below inlinedRefs.set(id, { // @ts-expect-error Spread types may only be created from object types ...jsonSchemaParser.$refs.get(ref), }); } /** * mark inlined ref objects with a "SCHEMA_ID_SYMBOL" * to retrieve their id once inlined */ inlinedSchema[utils_1.SCHEMA_ID_SYMBOL] = id; /** * "inline" refHandling support: * add a $ref comment to each inlined schema with the original ref value. * See: https://github.com/kaelzhang/node-comment-json */ if (refHandling === 'inline') { inlinedSchema[Symbol.for('before')] = [ { type: 'LineComment', value: ` $ref: "${ref}"`, }, ]; } }, }, }); const jsonSchema = (0, utils_1.convertOpenApiPathsParameters)(dereferencedJsonSchema); const schemaMetaDataMap = new Map(); /** * Create meta data for $ref schemas which have been previously dereferenced. * It happens only with "import" and "keep" refHandling since they expect * $ref schemas to be generated no matter of */ if (refHandling === 'import' || refHandling === 'keep') { for (const [id, schema] of inlinedRefs) { (0, utils_1.addSchemaToMetaData)({ id, $id: $idMapper({ id }), schemaMetaDataMap, schema, outputPath, isRef: true, }); } } /** * Create meta data for each output schema */ for (const definitionPath of definitionPathsToGenerateFrom) { const definitionSchemas = (0, lodash_get_1.default)(jsonSchema, definitionPath); for (const schemaName in definitionSchemas) { // Create expected OpenAPI ref const id = (0, utils_1.makeId)({ schemaRelativeDirName: definitionPath, schemaName, }); (0, utils_1.addSchemaToMetaData)({ id, $id: $idMapper({ id }), schemaMetaDataMap, schema: definitionSchemas[schemaName], outputPath, isRef: inlinedRefs.has(id), }); } } const returnPayload = { outputPath, metaData: { schemas: schemaMetaDataMap }, }; // Execute plugins onBeforeGeneration method for (const { onBeforeGeneration } of plugins) { if (onBeforeGeneration) { await onBeforeGeneration({ ...returnPayload, options, utils: { makeRelativeModulePath: utils_1.makeRelativeModulePath, formatTypeScript: utils_1.formatTypeScript, saveFile: utils_1.saveFile }, }); } } // Generate schemas await (0, utils_1.makeTsJsonSchemaFiles)({ refHandling, schemaMetaDataMap, schemaPatcher, $idMapper, }); if (!silent) { console.log(`[openapi-ts-json-schema] ✅ JSON schema models generated at ${outputPath}`); } return returnPayload; } exports.openapiToTsJsonSchema = openapiToTsJsonSchema;