UNPKG

@flexbase/openapi-generator

Version:
1,355 lines 52.5 kB
#!/usr/bin/env node import { ConsoleLogger } from "@flexbase/logger"; import chalk from "chalk"; import { program } from "commander"; import * as glob from "glob"; import Path from "path"; import fs from "fs-extra"; import Handlebars from "handlebars"; import { array, code, collection, comparison, date, html, i18n, inflection, object, markdown, math, misc, number, path, regex, string, url } from "useful-handlebars-helpers"; import prettier from "prettier"; import $RefParser from "@stoplight/json-schema-ref-parser"; import { OpenAPIV3 } from "openapi-types"; class ChalkLogger extends ConsoleLogger { error(e, ...t) { super.error(typeof e == "object" ? e : chalk.redBright(e), ...t); } warn(e, ...t) { super.warn(typeof e == "object" ? e : chalk.yellow(e), ...t); } info(e, ...t) { super.info(typeof e == "object" ? e : chalk.blueBright(e), ...t); } debug(e, ...t) { super.debug(typeof e == "object" ? e : chalk.greenBright(e), ...t); } trace(e, ...t) { super.trace(typeof e == "object" ? e : chalk.magenta(e), ...t); } } const name = "@flexbase/openapi-generator", version = "3.3.0", description = "Open API code generator", pkg = { name, version, description }, references = /* @__PURE__ */ new Map(), createHandlebars = (jsonSchema) => { const handlebars = Handlebars.create(); handlebars.Utils.createFrame = function(n) { const e = handlebars.Utils.extend({}, n); return e._parent = n, e.data = /* @__PURE__ */ new Map(), e; }, [array, code, collection, comparison, date, html, i18n, inflection, object, markdown, math, misc, number, object, path, regex, string, url].forEach( (n) => { handlebars.registerHelper(n); } ); function isOptions(n) { return typeof n == "object" && typeof n?.hash == "object"; } function isBlock(n) { return isOptions(n) && typeof n.fn == "function" && typeof n.inverse == "function"; } function renderValue(n, e, t) { return isOptions(n) ? renderValue(null, n, t) : isOptions(e) ? renderValue(n, {}, e) : isBlock(t) ? n ? t.fn(e) : t.inverse(e) : n; } return handlebars.registerHelper("set", function(n, e, t, r) { console.log({ context: n, name: e, value: t, options: r }); }), handlebars.registerHelper("registerReference", function(n, e, t, r) { references.has(e) || references.set(e, /* @__PURE__ */ new Map()); const i = references.get(e); i.has(t) && handlebars.log(2, `Multiple references ${t} registered in ${e}, last one wins!`); const s = typeof n == "object" && r ? r.fn(n) : n; i.set(t, s); }), handlebars.registerHelper("resolveReference", function(n, e, t) { const r = references.get(e); r || handlebars.log(1, `${e} references not found`); const i = typeof n == "object" && t ? t.fn(n) : n, s = r.get(i); return s || handlebars.log(1, `Reference ${i} not registered with ${e}`), s; }), handlebars.registerHelper("clearReferences", function(n, e) { const t = typeof n == "object" && e ? e.fn(n) : n; if (typeof t == "string") { const r = references.get(t); r && r.clear(); } else references.clear(); }), handlebars.registerHelper("jsonRef", function(n, e) { if (typeof n == "function" && (n = n.call(handlebars)), !Handlebars.Utils.isEmpty(n)) { const t = jsonSchema.get(n), r = e.data ? Handlebars.createFrame(e.data) : void 0; return e.fn(t, { data: r, blockParams: [n] }); } }), handlebars.registerHelper("hasLength", function(n, e) { const t = n; let r = 0; return typeof t == "string" || Array.isArray(t) ? r = t.length : typeof t == "object" && (r = Object.keys(t).length), r === e; }), handlebars.registerHelper("wrap", function(n, e, t, r) { const i = r.fn(n); if (!i) return i; const s = i.trim(); return e && (e = e.replaceAll("\\n", ` `)), t && (t = t.replaceAll("\\n", ` `)), s.length > 0 ? `${e}${s}${t}` : s; }), handlebars.registerHelper("newline", function() { return ` `; }), handlebars.registerHelper("toRegex", function(n, e) { return new RegExp(n, e); }), handlebars.registerHelper("replace", function(n, e, t, r) { const i = (a) => typeof a == "string" && a !== "", s = (a) => Object.prototype.toString.call(a) === "[object RegExp]", o = typeof n == "object" && r ? r.fn(n) : n; return i(o) ? !i(e) && !s(e) ? o : (!i(t) && !s(t) && typeof t != "function" && (t = ""), o.replace(e, t)) : ""; }), handlebars.registerHelper("function", function(str, options) { const _isString = (n) => typeof n == "string" && n !== "", rendered = typeof str == "object" && options ? options.fn(str) : str; return _isString(rendered) ? eval(rendered) : ""; }), handlebars.registerHelper("extendProperty", function(n, e, t) { let r = t; isBlock(t) && (r = t.fn(n)), n[e] = r; }), handlebars.registerHelper("isDefined", function(n, e) { return renderValue(n, n, e) !== void 0; }), handlebars.registerHelper("strJoin", function(n, ...e) { return e.map((r) => typeof r == "string" ? r : void 0).filter((r) => r).join(n); }), handlebars.logger.actualLogger = new ChalkLogger(), handlebars.log = (n, ...e) => { const t = ["debug", "info", "warn", "error"], r = typeof n == "string" ? t.includes(n) ? n : "info" : t.at(n) ?? "info"; handlebars.logger.actualLogger[r](...e); }, handlebars; }, runPrettier = async (n, e) => await prettier.format(n, { semi: !0, singleQuote: !0, arrowParens: "avoid", tabWidth: 2, useTabs: !1, printWidth: 150, parser: e }), isReference$1 = (n) => n.type === "reference", isMediaContent = (n) => n.type === "mediaContent", isMediaType = (n) => n.type === "mediaTypeObject", isPrimative = (n) => ["string", "number", "boolean", "integer", "null"].includes(n.type), isObjectNode$1 = (n) => n.type === "object", isProperty = (n) => n.type === "property", isComposite$1 = (n) => n.type === "composite", isUnion$1 = (n) => n.type === "union", isXor$1 = (n) => n.type === "xor", isExclusion = (n) => n.type === "exclusion", isArrayNode = (n) => n.type === "array", isLink = (n) => n.type === "linkObject", isNamedLink = (n) => n.type === "link", isRequestBody = (n) => n.type === "requestBody", isResponseBody = (n) => n.type === "responseObject", isResponse = (n) => n.type === "response", isHeader = (n) => n.type === "headerObject", isNamedHeader = (n) => n.type === "header", isParameter$1 = (n) => n.type === "parameter", isCallback = (n) => n.type === "callback", isOperation = (n) => n.type === "operation", isPathItem = (n) => n.type === "pathItemObject", isReference = (n) => n.type === "reference", isObjectNode = (n) => n.type === "object", isParameter = (n) => n.type === "parameter", isParameterObject = (n) => n.type === "parameterObject", isHeaderObject = (n) => n.type === "headerObject", isUnion = (n) => n.type === "union", isComposite = (n) => n.type === "composite", isXor = (n) => n.type === "xor", murmurHash = (n, e) => { typeof n == "string" && (n = new TextEncoder().encode(n)); let t, r, i, s; const o = n.length & 3, a = n.length - o; t = e; const c = 3432918353, f = 461845907; for (s = 0; s < a; ) i = n[s] & 255 | (n[++s] & 255) << 8 | (n[++s] & 255) << 16 | (n[++s] & 255) << 24, ++s, i = (i & 65535) * c + (((i >>> 16) * c & 65535) << 16) & 4294967295, i = i << 15 | i >>> 17, i = (i & 65535) * f + (((i >>> 16) * f & 65535) << 16) & 4294967295, t ^= i, t = t << 13 | t >>> 19, r = (t & 65535) * 5 + (((t >>> 16) * 5 & 65535) << 16) & 4294967295, t = (r & 65535) + 27492 + (((r >>> 16) + 58964 & 65535) << 16); switch (i = 0, o) { case 3: i ^= (n[s + 2] & 255) << 16; case 2: i ^= (n[s + 1] & 255) << 8; case 1: i ^= n[s] & 255, i = (i & 65535) * c + (((i >>> 16) * c & 65535) << 16) & 4294967295, i = i << 15 | i >>> 17, i = (i & 65535) * f + (((i >>> 16) * f & 65535) << 16) & 4294967295, t ^= i; break; } return t ^= n.length, t ^= t >>> 16, t = (t & 65535) * 2246822507 + (((t >>> 16) * 2246822507 & 65535) << 16) & 4294967295, t ^= t >>> 13, t = (t & 65535) * 3266489909 + (((t >>> 16) * 3266489909 & 65535) << 16) & 4294967295, t ^= t >>> 16, t >>> 0; }; class Converter { constructor(e) { this._logger = e; } recursionDepth = 0; findInSection(e, t, r) { const i = e[r]; if (i) try { const s = i.filter((o) => o.referenceName === t.reference); return s === void 0 || s.length === 0 ? void 0 : (s.length > 1 && this._logger.warn(`mulitiple references of ${r} ${t.reference} found, using first instance`), s[0]); } catch (s) { this._logger.error(s, { node: t, section: r }); return; } } find(e, t) { for (const r of Object.keys(e)) { const i = this.findInSection(e, t, r); if (i) return { component: i, section: r }; } this._logger.warn(`missing reference: ${t.reference}`); } addComponent(e, t, r, i) { r[i] ??= {}, r[i][e] = t, r[i][e].name ??= e; } convertParsedNode(e, t, r) { try { if (this.recursionDepth += 1, this.recursionDepth > 20) return { type: e.type }; if (isReference$1(e)) { const i = this.find(t, e); return i && this.addComponent( i.component.name, this.convertParsedNode(i.component.definition, t, r), r, i.section ), this.convertReference(e); } else { if (isPrimative(e)) return this.convertPrimative(e); if (isParameter$1(e)) return this.convertParameter(e, t, r); if (isResponse(e)) return this.convertResponse(e, t, r); if (isResponseBody(e)) return this.convertResponseObject(e, t, r, 0); if (isHeader(e)) return this.convertHeader(e, t, r); if (isMediaType(e)) return this.convertMediaType(e, t, r); if (isObjectNode$1(e)) return this.convertObject(e, t, r); if (isArrayNode(e)) return this.convertArray(e, t, r); if (isUnion$1(e)) return this.convertUnion(e, t, r); if (isXor$1(e)) return this.convertXor(e, t, r); if (isComposite$1(e)) return this.convertComposite(e, t, r); if (isExclusion(e)) return this.convertExclusion(e, t, r); if (isRequestBody(e)) return this.convertRequestBody(e, t, r); } } catch { this._logger.error("error", { parsedNode: e }); } finally { this.recursionDepth -= 1; } return { type: e.type }; } convertReference(e) { return { type: "reference", $ref: e.reference.replace("#/components/schemas/", "#/components/models/"), summary: e.summary, description: e.description }; } convertPrimative(e) { return { ...e }; } convertObject(e, t, r) { return { ...e, properties: e.properties.map((i) => ({ ...i, definition: this.convertParsedNode(i.definition, t, r) })), additionalProperty: e.additionalProperty ? this.convertParsedNode(e.additionalProperty, t, r) : void 0 }; } compress(e, t, r) { if (e.definitions.length === 1) return this.convertParsedNode(e.definitions[0], t, r); let i, s; if ("discriminatorPropertyName" in e && e.discriminatorPropertyName && (i = e.discriminatorPropertyName, e.discriminatorMapping)) { s = {}; for (const [o, a] of Object.entries(e.discriminatorMapping)) s[o] = this.convertParsedNode(a, t, r); } return { ...e, definitions: e.definitions.map((o) => this.convertParsedNode(o, t, r)), discriminatorPropertyName: i, discriminatorMapping: s }; } convertUnion(e, t, r) { return this.compress(e, t, r); } convertXor(e, t, r) { return this.compress(e, t, r); } convertComposite(e, t, r) { return this.compress(e, t, r); } convertExclusion(e, t, r) { return { ...e, definition: this.convertParsedNode(e.definition, t, r) }; } convertArray(e, t, r) { return { ...e, definition: this.convertParsedNode(e.definition, t, r) }; } convertParameter(e, t, r) { let i = { type: "error" }; return e.definition ? i = this.convertParsedNode(e.definition, t, r) : e.content && (i = this.convertParsedNode(e.content[0], t, r)), { type: "parameterObject", name: e.name, properties: [ { type: "parameter", name: e.name, description: e.description, required: e.required, deprecated: e.deprecated, allowEmptyValue: e.allowEmptyValue, style: e.style, explode: e.explode, allowReserved: e.allowReserved, extensions: e.extensions, definition: i } ] }; } convertResponse(e, t, r) { const i = Number.isNaN(Number(e.status)) ? 200 : Number(e.status); let s, o; if (isReference$1(e.definition)) { const a = this.findInSection(t, e.definition, "responses"); s = a?.name, o = a?.definition; } else s = e.definition.name ?? e.name, o = e.definition; if (o) { const a = this.convertResponseObject(o, t, r, i), c = `${a.name ?? s ?? "_" + String(murmurHash(JSON.stringify(a), 42))}${i}`, f = `#/components/responseObjects/${c}`; return this.addComponent(c, a, r, "responseObjects"), { type: "reference", $ref: f }; } else return { type: "responseObject", status: i, name: s, description: e.description ?? "" }; } convertResponseObject(e, t, r, i) { let s, o; if (e.headers) { const a = []; e.headers?.forEach((c) => { const f = this.convertParsedNode(c.definition, t, r); a.push({ ...f, name: c.name }); }), o = { type: "headerObject", properties: a }; } return e.links && this._logger.warn("Response links not supported yet"), e.content?.forEach((a) => { s ??= {}, s[a.name] = this.convertParsedNode(a.definition, t, r); }), { type: "responseObject", status: i, name: e.name, description: e.description, headers: o, "content-type": s }; } convertRequestBody(e, t, r) { const i = {}, s = e.content?.length === 1 ? e.name : void 0; return e.content?.forEach((o) => { let a = this.convertParsedNode(o.definition, t, r); if (!isReference(a)) { const c = `${a.name ?? s ?? "_" + String(murmurHash(JSON.stringify(a), 42))}`; a.name = c; const f = `#/components/requestObjects/${c}`; this.addComponent(c, a, r, "requestObjects"), a = { type: "reference", $ref: f }; } i[o.name] = a; }), { ...e, name: e.name ?? "", type: "request", "content-type": i }; } convertHeader(e, t, r) { let i = { type: "error" }; return e.definition ? i = this.convertParsedNode(e.definition, t, r) : e.content && (i = this.convertParsedNode(e.content[0], t, r)), { name: e.name ?? "", type: "header", description: e.description, required: e.required, deprecated: e.deprecated, allowEmptyValue: e.allowEmptyValue, style: e.style, explode: e.explode, allowReserved: e.allowReserved, extensions: e.extensions, definition: i }; } convertMediaType(e, t, r) { return e.definition ? this.convertParsedNode(e.definition, t, r) : { type: "null" }; } } class OpenApiOptimizer { constructor(e) { this._logger = e, this._converter = new Converter(e); } _converter; optimize(e) { const t = this.optimizePaths(e); return this.optimizeComponents(t.components), this.buildPathRegex(t), t; } lookupReference(e, t, r) { const i = t[r]?.find((s) => s.referenceName === e.reference); if (!i) { this._logger.warn(`Unable to find ${r}: ${e.reference}`); return; } return i; } lookupComponent(e, t, r) { const i = e.$ref.substring(e.$ref.lastIndexOf("/") + 1), s = Object.entries(t[r] ?? {}).find((o) => o[0] === i); if (s) return s[1]; } createParameterObject(e, t, r) { const i = []; return e.forEach((s) => { if (isReference$1(s)) { const o = this.lookupReference(s, t, "parameters"); o && (i.push({ type: "reference", $ref: o.referenceName }), this._converter.addComponent( o.name, this._converter.convertParsedNode(o.definition, t, r), r, "parameters" )); } else s.definition && i.push(this._converter.convertParsedNode(s, t, r)); }), { type: "composite", definitions: i }; } optimizeParameters(e, t, r, i, s) { let o; if (r.length === 1) { const a = this._converter.convertParsedNode(r[0], e.components, t); isReference(a) ? o = a : (a.name = i, this._converter.addComponent(i, a, t, s), o = { type: "reference", $ref: `#/components/${s}/${i}` }); } else this._converter.addComponent(i, this.createParameterObject(r, e.components, t), t, s), o = { type: "reference", $ref: `#/components/${s}/${i}` }; return o; } optimizeOperationParameters(e, t, r) { let i, s, o, a; if (r.parameters) for (const u of r.parameters) switch ((isReference$1(u) ? this.lookupReference(u, e.components, "parameters")?.definition : u)?.in) { case "path": i ??= [], i.push(u); break; case "header": s ??= [], s.push(u); break; case "query": o ??= [], o.push(u); break; case "cookie": a ??= [], a.push(u); break; } let c, f, p, l, h; const d = `${r.operationId}`; return i && (c = this.optimizeParameters(e, t, i, d, "pathParameters")), s && (f = this.optimizeParameters(e, t, s, d, "headerParameters")), o && (p = this.optimizeParameters(e, t, o, d, "queryParameters")), a && (l = this.optimizeParameters(e, t, a, d, "cookieParameters")), { pathParameter: c, headerParameter: f, queryParameter: p, cookieParameter: l, pathRegex: h }; } optimizeOperationResponses(e, t, r) { let i; if (r.responses) { const s = `${r.operationId}`, o = `#/components/responses/${s}`, a = { type: "response", name: s, responses: [] }; this._converter.addComponent(s, a, t, "responses"), r.responses.forEach((c) => { const f = isReference$1(c) ? this.lookupReference(c, e.components, "responses")?.definition : c; if (f) { f.name ??= s; const p = this._converter.convertParsedNode(f, e.components, t); a.responses.push(p); } }), i = { type: "reference", $ref: o }; } return i; } optimizeOperationRequest(e, t, r) { let i; if (r.requestBody) { const s = isReference$1(r.requestBody) ? this.lookupReference(r.requestBody, e.components, "requests")?.definition : r.requestBody; if (s) { const o = s.name ?? `${r.operationId}`, a = `#/components/requests/${o}`, c = { ...this._converter.convertParsedNode(s, e.components, t), name: o, content: void 0 }; this._converter.addComponent(o, c, t, "requests"), i = { type: "reference", $ref: a }; } } return i; } optimizeOperation(e, t, r) { const i = this.optimizeOperationResponses(e, t, r), s = this.optimizeOperationRequest(e, t, r), { pathParameter: o, headerParameter: a, queryParameter: c, cookieParameter: f, pathRegex: p } = this.optimizeOperationParameters( e, t, r ); return { type: "operation", method: r.method, tags: r.tags, description: r.description, summary: r.summary, operationId: r.operationId, deprecated: r.deprecated, //callbacks: operation.callbacks, security: r.security, extensions: r.extensions, response: i, request: s, pathParameter: o, headerParameter: a, queryParameter: c, cookieParameter: f, pathRegex: p }; } optimizePathItem(e, t, r) { return r.operations.map((i) => this.optimizeOperation(e, t, i)); } optimizePaths(e) { const t = {}, r = []; return e.paths.forEach((i) => { if (i.definition) if (isReference$1(i.definition)) this._logger.warn("Path references not supported"); else { const s = this.optimizePathItem(e, t, i.definition); r.push({ type: "path", name: i.name, operations: s }); } }), { ...e, paths: r, components: t }; } compactComposite(e) { const t = [], r = []; for (const s of e.definitions) isObjectNode(s) || isParameterObject(s) || isHeaderObject(s) ? t.push(s) : r.push(s); const i = []; return t.forEach((s) => i.push(...s.properties)), i.length > 0 && r.push({ type: "object", properties: i }), r.length > 1 ? { ...e, definitions: r } : { ...e, definitions: void 0, ...r[0] }; } optimizeComponentRecord(e) { const t = Object.entries(e); for (const r of t) { const i = r[1]; if (isComposite(i)) { const s = this.compactComposite(i); e[r[0]] = s; } } return e; } optimizeComponents(e) { e.models && (e.models = this.optimizeComponentRecord(e.models)), e.requests && (e.requests = this.optimizeComponentRecord(e.requests)), e.requestObjects && (e.requestObjects = this.optimizeComponentRecord(e.requestObjects)), e.responses && (e.responses = this.optimizeComponentRecord(e.responses)), e.responseObjects && (e.responseObjects = this.optimizeComponentRecord(e.responseObjects)), e.parameters && (e.parameters = this.optimizeComponentRecord(e.parameters)), e.headers && (e.headers = this.optimizeComponentRecord(e.headers)), e.callbacks && (e.callbacks = this.optimizeComponentRecord(e.callbacks)), e.pathItems && (e.pathItems = this.optimizeComponentRecord(e.pathItems)), e.pathParameters && (e.pathParameters = this.optimizeComponentRecord(e.pathParameters)), e.headerParameters && (e.headerParameters = this.optimizeComponentRecord(e.headerParameters)), e.queryParameters && (e.queryParameters = this.optimizeComponentRecord(e.queryParameters)), e.cookieParameters && (e.cookieParameters = this.optimizeComponentRecord(e.cookieParameters)); } getPathParamRegex(e, t) { let r; const i = this.lookupComponent(e, t, "pathParameters") ?? this.lookupComponent(e, t, "parameters"); return i ? isObjectNode(i) || isParameterObject(i) ? i.properties.forEach((s) => { if (isParameter(s)) { const o = s.name, a = s.definition; r = { ...r, [o]: a.format ?? a.type }; } }) : (isComposite(i) || isUnion(i) || isXor(i)) && i.definitions?.forEach((s) => { isReference(s) && (r = { ...r, ...this.getPathParamRegex(s, t) }); }) : this._logger.warn(`Unable to find path parameter: (${e.$ref})`), r; } buildPathRegex(e) { e.paths.forEach((t) => { t.operations.forEach((r) => { r.pathParameter && (r.pathRegex = this.getPathParamRegex(r.pathParameter, e.components)); }); }); } } class Organizer { constructor(e) { this._logger = e; } organizeByTags(e) { return e.tags.map((r) => { const i = { title: r.name, apiName: e.apiName, description: r.description, version: e.version, tags: [r], paths: this.organizePathsByTags(e, r.name), components: {} }; return i.components = this.organizeComponentsByTags(e, i.paths), i; }); } organizePathsByTags(e, t) { const r = e.paths.map((s) => { const o = s.definition; if (o === void 0) return; if (isReference$1(o)) return s; const a = o.operations; if (a !== void 0 && a.some((c) => c.tags?.includes(t))) return s; }), i = (s) => s !== void 0; return r.filter(i); } organizeComponentsByTags(e, t) { const r = { models: [], requests: [], responses: [], parameters: [], headers: [], securitySchemes: [], callbacks: [], pathItems: [] }; return t.forEach((i) => { const s = i.definition; s !== void 0 && this.traverseReferences(e, r, s); }), r.models = r.models.sort((i, s) => i.name.localeCompare(s.name)), r.requests = r.requests.sort((i, s) => i.name.localeCompare(s.name)), r.responses = r.responses.sort((i, s) => i.name.localeCompare(s.name)), r.parameters = r.parameters.sort((i, s) => i.name.localeCompare(s.name)), r.headers = r.headers.sort((i, s) => i.name.localeCompare(s.name)), r.securitySchemes = r.securitySchemes.sort((i, s) => i.name.localeCompare(s.name)), r.callbacks = r.callbacks.sort((i, s) => i.name.localeCompare(s.name)), r.pathItems = r.pathItems.sort((i, s) => i.name.localeCompare(s.name)), r; } traverseReferences(e, t, r) { if (isReference$1(r)) { const { component: i, section: s } = this.find(e.components, r); if (!i) { this._logger.warn(`${r.reference} not found`); return; } const o = this.addIfMissing(i, t, s); o && this.traverseReferences(e, t, o.definition); } else isPathItem(r) ? r.operations.forEach((i) => this.traverseReferences(e, t, i)) : isOperation(r) ? (r.parameters && r.parameters.forEach((i) => this.traverseReferences(e, t, i)), r.requestBody && this.traverseReferences(e, t, r.requestBody), r.responses && r.responses.forEach((i) => this.traverseReferences(e, t, i)), r.callbacks && r.callbacks.forEach((i) => this.traverseReferences(e, t, i))) : isRequestBody(r) && r.content ? r.content.forEach((i) => { this.traverseReferences(e, t, i.definition); }) : isMediaContent(r) ? this.traverseReferences(e, t, r.definition) : isMediaType(r) && r.definition ? this.traverseReferences(e, t, r.definition) : isObjectNode$1(r) ? (r.properties.forEach((i) => this.traverseReferences(e, t, i)), r.additionalProperty && this.traverseReferences(e, t, r.additionalProperty)) : isProperty(r) ? this.traverseReferences(e, t, r.definition) : isResponse(r) ? this.traverseReferences(e, t, r.definition) : isResponseBody(r) ? (r.content && r.content.forEach((i) => { this.traverseReferences(e, t, i.definition); }), r.headers && r.headers.forEach((i) => { this.traverseReferences(e, t, i.definition); }), r.links && r.links.forEach((i) => { this.traverseReferences(e, t, i.definition); })) : isNamedHeader(r) ? this.traverseReferences(e, t, r.definition) : isHeader(r) ? (r.definition && this.traverseReferences(e, t, r.definition), r.content && r.content.forEach((i) => { this.traverseReferences(e, t, i.definition); })) : isCallback(r) ? this.traverseReferences(e, t, r.definition) : isArrayNode(r) ? this.traverseReferences(e, t, r.definition) : isComposite$1(r) ? r.definitions.forEach((i) => { this.traverseReferences(e, t, i); }) : isExclusion(r) ? this.traverseReferences(e, t, r.definition) : isNamedLink(r) ? this.traverseReferences(e, t, r.definition) : isLink(r) || (isParameter$1(r) ? (r.definition && this.traverseReferences(e, t, r.definition), r.content && r.content.forEach((i) => { this.traverseReferences(e, t, i.definition); })) : isUnion$1(r) ? r.definitions.forEach((i) => { this.traverseReferences(e, t, i); }) : isXor$1(r) && r.definitions.forEach((i) => { this.traverseReferences(e, t, i); })); } findInSection(e, t, r) { const i = e[r]; if (!i) return; const s = i.filter((o) => o.referenceName === t.reference); if (!(s === void 0 || s.length === 0)) return s.length > 1 && this._logger.warn(`mulitiple references of ${r} ${t.reference} found, using first instance`), s[0]; } find(e, t) { for (const r of Object.keys(e)) { const i = this.findInSection(e, t, r); if (i) return { component: i, section: r }; } return {}; } addIfMissing(e, t, r) { const i = t[r]; if (!i.find((o) => o.referenceName === e.referenceName)) return i.push(e), e; } } const childProcess = {}, registerPartials = (n, e) => { const t = glob.sync(e); for (const r of t) { const i = Path.basename(r), s = Path.extname(i); n.registerPartial(i.replace(s, ""), fs.readFileSync(r, "utf8")); } }, substituteParams = (n, e) => { const t = /({.*?})/g, r = n.match(t); if (!r) return n; let i = n; return r.forEach((s) => { const o = e.get(s); o && (i = i.replaceAll(s, o)); }), i; }, writeFile = async (n, e, t, r) => { const i = Path.join(n, e); let s = JSON.stringify(t); try { s = await runPrettier(s, "json"); } catch (o) { r.info(`Prettier error on ${i}`, o); } await fs.ensureDir(n), await fs.writeFile(i, s); }, isEmpty = (n) => n.components.models === void 0 && n.components.responses === void 0 && n.components.requests === void 0 && n.components.pathParameters === void 0 && n.components.headerParameters === void 0 && n.components.queryParameters === void 0 && n.components.cookieParameters === void 0 && n.paths.length === 0, build = async (n, e, t) => { if (n.generate === void 0) { t.info("No generate config settings found"); return; } const r = new Organizer(t), i = new OpenApiOptimizer(t), s = /* @__PURE__ */ new Map(), o = e.title.trim(), a = /([^a-zA-Z0-9])+/g, c = o.replace(a, "-").toLocaleLowerCase(); if (s.set("{api}", c), n.debug) { const f = substituteParams(n.debugPath, s); await writeFile(f, `${e.title}.parsed.json`, e, t), await writeFile(f, `${e.title}.optimized.json`, i.optimize(e), t); } for (const f of Object.entries(n.generate)) { const p = f[1], l = p.tags ?? n.tags, h = p.skipEmpty ?? n.skipEmpty, d = l ? r.organizeByTags(e) : [e]; for (const u of d) { const b = u.title.trim().replace(a, "-").toLocaleLowerCase(); s.set("{name}", b); const g = i.optimize(u); if (!(h && isEmpty(g))) { if (n.debug) { const m = substituteParams(n.debugPath, s); await writeFile(m, `${u.title}.parsed.json`, u, t), await writeFile(m, `${u.title}.optimized.json`, g, t); } await generate(n, p, s, g, t); } } } }, runScript = (n, e) => { let t = !1; const r = childProcess.fork(n); return r.on("error", function(i) { t || (t = !0, e(i)); }), r.on("exit", function(i) { if (t) return; t = !0; const s = i === 0 ? void 0 : new Error("exit code " + i); e(s); }), r; }, generate = async (n, e, t, r, i) => { const s = [...n.sharedTemplates ?? [], ...e.additionalTemplates ?? []], o = await $RefParser.resolve(r); if (e.script) { const l = runScript(e.script, (h) => { if (h) throw h; }); l.on("message", (h) => { h === "ready" && l.send(r); }); return; } const a = createHandlebars(o); registerPartials(a, s); const c = await fs.readFile(e.template, "utf8"), f = a.compile(c), p = substituteParams(e.target, t); await render(n, p, r, f, i); }, render = async (n, e, t, r, i) => { const s = { document: t }, o = Path.extname(e); await fs.ensureDir(Path.dirname(e)); try { let a = r(s, { data: /* @__PURE__ */ new Map(), allowProtoMethodsByDefault: !0 }); if (n.prettier) try { a = await runPrettier(a, o === ".ts" ? "typescript" : "babel"); } catch (c) { i.info(`Prettier error on ${e}`, c); } await fs.writeFile(e, a, "utf8"); } catch (a) { i.error(`Error generating ${e}`, a); } }; function IsDocument(n) { return "components" in n; } const nonArraySchemaObjectType = ["string", "number", "boolean", "integer", "null"]; class OpenApiParser { constructor(e) { this._logger = e; } parse(e) { const t = e.info.title, r = e.info.title, i = e.info.description, s = e.info.version, o = e.tags ? e.tags.map((f) => this.parseTag(f)) : [], a = e.components ? this.parseComponents(e.components) : {}, c = e.paths ? this.parsePaths(e.paths, a) : []; return { title: t, apiName: r, description: i, version: s, components: a, paths: c, tags: o }; } parseComponents(e) { const t = {}; if (e.schemas) { const r = Object.entries(e.schemas); for (const i of r) { const s = i[0], o = i[1], a = `#/components/schemas/${s}`, c = this.parseSchema(o); t.models ??= [], t.models.push({ name: s, referenceName: a, definition: c }); } } if (e.securitySchemes) { const r = Object.entries(e.securitySchemes); for (const i of r) { const s = i[0], o = i[1], a = `#/components/securitySchemes/${s}`, c = this.parseSecurityScheme(o); t.securitySchemes ??= [], t.securitySchemes.push({ name: s, referenceName: a, definition: c }); } } if (e.parameters) { const r = Object.entries(e.parameters); for (const i of r) { const s = i[0], o = i[1], a = `#/components/parameters/${s}`, c = this.parseParameter(o, t); t.parameters ??= [], t.parameters.push({ name: s, referenceName: a, definition: c }); } } if (e.headers) { const r = Object.entries(e.headers); for (const i of r) { const s = i[0], o = i[1], a = `#/components/headers/${s}`, c = this.parseHeaderObject(o, t); t.headers ??= [], t.headers.push({ name: s, referenceName: a, definition: c }); } } if (e.requestBodies) { const r = Object.entries(e.requestBodies); for (const i of r) { const s = i[0], o = i[1], a = `#/components/requestBodies/${s}`, c = this.parseRequestBody(o, t); isRequestBody(c) && (c.name = s), t.requests ??= [], t.requests.push({ name: s, referenceName: a, definition: c }); } } if (e.responses) { const r = Object.entries(e.responses); for (const i of r) { const s = i[0], o = i[1], a = `#/components/responses/${s}`, c = this.parseResponse(o, t); t.responses ??= [], t.responses.push({ name: s, referenceName: a, definition: c }); } } if (e.callbacks) { const r = Object.entries(e.callbacks); for (const i of r) { const s = i[0], o = i[1], a = `#/components/callbacks/${s}`, c = this.parseCallback(o, s, t); t.callbacks ??= [], t.callbacks.push({ name: s, referenceName: a, definition: c }); } } return t; } parsePaths(e, t) { const r = [], i = Object.entries(e); for (const s of i) { const o = s[0], a = s[1], c = a ? this.parsePathItemObject(a, t) : void 0; r.push({ type: "pathItem", name: o, definition: c }); } return r.sort((s, o) => { const a = (s.name.match(/{[^}]+}/g) || []).length, c = (o.name.match(/{[^}]+}/g) || []).length; if (a === 0 && c > 0) return -1; if (a > 0 && c === 0) return 1; if (a !== c) return a - c; const f = s.name.split("/").filter(Boolean).length, p = o.name.split("/").filter(Boolean).length; return f !== p ? p - f : s.name.localeCompare(o.name); }); } isReferenceObject(e) { return "$ref" in e; } isArraySchemaObject(e) { return e.type === "array"; } isNonArraySchemaObject(e) { return !("items" in e); } isMixedSchemaObject(e) { return Array.isArray(e.type); } isAllOf(e) { return e.allOf !== void 0; } isAnyOf(e) { return e.anyOf !== void 0; } isOneOf(e) { return e.oneOf !== void 0; } lookupReference(e, t, r) { const i = t[r]?.find((s) => s.referenceName === e.reference); if (!i) { this._logger.warn(`Unable to find ${r}: ${e.reference}`); return; } return i; } getExtensions(e) { const t = {}, r = Object.keys(e).filter((i) => i.startsWith("x-")); if (r.length !== 0) return r.forEach((i) => t[i] = e[i]), t; } getModifiers(e) { return { name: e.title, description: e.description, format: e.format, default: e.default, multipleOf: e.multipleOf, maximum: e.maximum, exclusiveMaximum: e.exclusiveMaximum, minimum: e.minimum, exclusiveMinimum: e.exclusiveMinimum, maxLength: e.maxLength, minLength: e.minLength, pattern: e.pattern, additionalProperties: e.additionalProperties, maxItems: e.maxItems, minItems: e.minItems, uniqueItems: e.uniqueItems, maxProperties: e.maxProperties, minProperties: e.minProperties, required: e.required, enum: e.enum, nullable: e.nullable, discriminator: e.discriminator, readOnly: e.readOnly, writeOnly: e.writeOnly, deprecated: e.deprecated, extensions: this.getExtensions(e), example: e.example }; } parseSchema(e, t) { if (this.isReferenceObject(e)) return this.createReference(e); e.type ??= t ?? e.enum ? "string" : "object"; const r = this.getModifiers(e); if (this.isArraySchemaObject(e)) return this.parseArray(e, r); if (this.isMixedSchemaObject(e)) return this.parseMixedSchemaObject(e, r); if (this.isNonArraySchemaObject(e)) { if (this.isAllOf(e)) return this.parseAllOf(e, r); if (this.isAnyOf(e)) return this.parseAnyOf(e, r); if (this.isOneOf(e)) return this.parseOneOf(e, r); if (e.not) return this.parseNotObject(e.not, r); if (e.type === "object") return this.parseObject(e, r); if (e.type && nonArraySchemaObjectType.includes(e.type)) return this.createLiteral(e, r); } throw this._logger.error(e), new Error("Unknown schema"); } parseMediaContent(e, t, r) { if (!e) return; const i = [], s = Object.entries(e); for (const o of s) { const a = o[0], c = o[1], f = this.parseMediaTypeObject(c, t, r); i.push({ type: "mediaContent", name: a, definition: f }); } return i; } parseMediaEncoding(e, t) { if (!e) return; const r = []; if (e) { const i = Object.entries(e); for (const s of i) { const o = s[0], a = s[1], c = this.parseEncodingObject(a, t); r.push({ name: o, ...c }); } } return r; } parseHeaders(e, t) { if (!e) return; const r = [], i = Object.entries(e); for (const s of i) { const o = s[0], a = s[1], c = this.parseHeaderObject(a, t); r.push({ type: "header", name: o, definition: c }); } return r; } parseLinks(e) { if (!e) return; const t = [], r = Object.entries(e); for (const i of r) { const s = i[0], o = i[1], a = this.parseLinkObject(o); t.push({ type: "link", name: s, definition: a }); } return t; } parseRequestBody(e, t, r) { if (this.isReferenceObject(e)) return this.createReference(e); const i = e.description, s = e.required, o = this.getExtensions(e), a = this.parseMediaContent(e.content, "readOnly", t); return { type: "requestBody", name: r, description: i, required: s, extensions: o, content: a }; } omitProperties(e, t, r) { const i = []; if (isObjectNode$1(e)) { for (const s of e.properties) if (s.definition[t] !== !0) if (isReference$1(s.definition)) { const o = this.lookupReference(s.definition, r, "models"); if (o && o.definition[t] !== !0) { const a = this.createOmitDefinition(o.definition, t, r); a ? (!isObjectNode$1(a) || a.properties.length > 0) && i.push({ ...s, definition: a }) : i.push(s); } } else i.push(s); } return i; } createOmitDefinition(e, t, r) { if (isReference$1(e)) { const i = this.lookupReference(e, r, "models"); if (i) return this.createOmitDefinition(i.definition, t, r); } else if (isObjectNode$1(e)) { const i = this.omitProperties(e, t, r); if (i.length !== e.properties.length) return { ...e, properties: i }; } else if (isComposite$1(e)) { const i = [...e.definitions]; let s = !1; for (let o = 0; o < i.length; ++o) { const a = this.createOmitDefinition(i[o], t, r); a && (s = !0, i[o] = a); } if (s) return { ...e, definitions: i }; } } parseMediaTypeObject(e, t, r) { const i = e.schema ? this.parseSchema(e.schema) : void 0, s = this.parseMediaEncoding(e.encoding, r); let o; if (i) if (isReference$1(i)) { const a = this.lookupReference(i, r, "models"); a && (o = this.createOmitDefinition(a.definition, t, r)); } else o = this.createOmitDefinition(i, t, r); return { type: "mediaTypeObject", definition: o ?? i, encodings: s }; } parseEncodingObject(e, t) { const r = e.contentType, i = e.style, s = e.explode, o = e.allowReserved, a = this.parseHeaders(e.headers, t); return { type: "encoding", contentType: r, style: i, explode: s, allowReserved: o, headers: a }; } parseHeaderObject(e, t) { return this.isReferenceObject(e) ? this.createReference(e) : { type: "headerObject", ...this.parseParameterBaseObject(e, t) }; } parseLinkObject(e) { if (this.isReferenceObject(e)) return this.createReference(e); const t = e.server, r = e.operationRef, i = e.operationId, s = e.requestBody, o = e.description, a = e.parameters; return { type: "linkObject", server: t, operationRef: r, operationId: i, requestBody: s, description: o, parameters: a }; } parseParameterSchema(e, t) { const r = this.parseSchema(e); return t && r.type !== "array" ? { type: "array", definition: r } : r; } parseParameterBaseObject(e, t) { const r = e.description, i = e.required, s = e.deprecated, o = e.allowEmptyValue, a = e.style, c = e.explode, f = e.allowReserved, p = e.schema ? this.parseParameterSchema(e.schema, a) : void 0, l = this.parseMediaContent(e.content, "readOnly", t); return { description: r, required: i, deprecated: s, allowEmptyValue: o, style: a, explode: c, allowReserved: f, definition: p, content: l }; } parseResponse(e, t) { if (this.isReferenceObject(e)) return this.createReference(e); const r = e.description, i = this.parseHeaders(e.headers, t), s = this.parseMediaContent(e.content, "writeOnly", t), o = this.parseLinks(e.links); return { type: "responseObject", description: r, headers: i, content: s, links: o }; } parseParameter(e, t) { return this.isReferenceObject(e) ? this.createReference(e) : { type: "parameter", name: e.name, in: e.in, ...this.parseParameterBaseObject(e, t) }; } parseSecurityScheme(e) { if (this.isReferenceObject(e)) return this.createReference(e); const t = "securityScheme", r = e.description; switch (e.type) { case "http": return { type: t, description: r, bearerFormat: e.bearerFormat, scheme: e.scheme }; case "apiKey": return { type: t, description: r, name: e.name, in: e.in }; case "openIdConnect": return { type: t, description: r, openIdConnectUrl: e.openIdConnectUrl }; case "oauth2": return { type: t, description: r, flows: e.flows }; default: throw new Error(`Unknown security scheme ${e}`); } } parseCallback(e, t, r) { const i = this.parsePathItemObject(e, r); return { type: "callback", name: t, definition: i }; } parsePathItemObject(e, t) { if (this.isReferenceObject(e)) return this.createReference(e); const r = []; for (const i in OpenAPIV3.HttpMethods) { const s = e[i.toLowerCase()]; if (!s) continue; const o = this.parseOperationObject(s, i.toLowerCase(), e.parameters, t); r.push(o); } return { type: "pathItemObject", operations: r //parameters, }; } parseOperationObject(e, t, r, i) { let s, o, a; const c = e.tags, f = e.description, p = e.summary, l = e.operationId, h = e.deprecated, d = this.getExtensions(e); (c === void 0 || c.length === 0) && this._logger.warn(`Operation ${l} does not have any tags`); const u = [...r ?? [], ...e.parameters ?? []]; for (const m of u) { const y = this.parseParameter(m, i); s ??= [], s.push(y); } const b = e.requestBody ? this.parseRequestBody(e.requestBody, i, l) : void 0; if (e.responses) { o = []; const m = Object.entries(e.responses); for (const y of m) { const P = y[0], v = y[1]; Number.isNaN(Number(P)) && this._logger.warn(`Operation ${l} has invalid response status: ${P}. Will use 200 instead`); const O = this.parseResponse(v, i); o.push({ type: "response", status: P, definition: O }); } } if (e.callbacks) { a = []; const m = Object.entries(e.callbacks); for (const y of m) { const P = y[0], v = y[1]; a.push(this.parseCallback(v, P, i)); } } const g = e.security; return { type: "operation", method: t, tags: c, description: f, summary: p, operationId: l, deprecated: h, parameters: s, requestBody: b, responses: o, callbacks: a, security: g, extensions: d }; } parseTag(e) { return { type: "tag", name: e.name, description: e.description }; } createReference(e) { return { type: "reference", reference: e.$ref, summary: e.summary, description: e.description }; } createLiteral(e, t) { return { type: e.type, ...t }; } createProperty(e, t, r) { const i = this.parseSchema(t), s = i.description; return i.description = void 0, { name: e, type: "property", definition: i, required: r, description: s }; } parseObject(e, t) { const r = []; if (e.properties) { const s = Object.entries(e.properties); for (const o of s) { if (o[0].length === 0) { this._logger.warn("property is missing name"); continue; } const a = e.required?.find((f) => f === o[0]) !== void 0, c = this.createProperty(o[0], o[1], a); r.push(c); } } let i; return e.additionalProperties && (typeof e.additionalProperties == "boolean" ? e.additionalProperties && (i = { type: "object", properties: [] }) : i = this.parseSchema(e.additionalProperties)), { ...t, type: "object", properties: r, additionalProperty: i, additionalProperties: void 0, required: void 0 }; } parseAllOf(e, t) { const i = e.allOf.map((s) => this.parseSchema(s, e.type)); return { type: "composite", ...t, definitions: i }; } parseAnyOf(e, t) { const i = e.anyOf.map((s) => this.parseSchema(s, e.type)); return { type: "union", ...t, definitions: i }; } parseOneOf(e, t) { const i = e.oneOf.map((a) => this.parseSchema(a, e.type)); let s, o; if (e.discriminator && (s = e.discriminator.propertyName, e.discriminator.mapping)) { o = {}; for (const [a, c] of Object.entries(e.discriminator.mapping)) { const f = this.parseDiscriminatorReference(c); o[a] = f; } } return { type: "xor", ...t, definitions: i, discriminatorPropertyName: s, discriminatorMapping: o }; } parseDiscriminatorReference(e) { const t = { $ref: e }; return this.createReference(t); } parseNotObject(e, t) { return { type: "exclusion", ...t, definition: this.parseSchema(e) }; } parseArray(e, t) { const r = e.items !== void 0, i = e.enum !== void 0; return { type: "array", ...t, enum: void 0, definition: r ? this.parseSchema(e.items) : i ? { type: "string", enum: e.enum } : { type: "object", properties: [] } }; } parseMixedSchemaObject(e, t) { if (!e.type) return this._logger.warn("Mixed schema missing type array"), { type: "error" }; const r = e.type.map((i) => i === "object" ? this.parseObject({ ...e, type: i }, t) : i === "array" ? this.parseArray({ ...e, type: i }, t) : nonArraySchemaObjectType.includes(i) ? this.createLiteral({ ...e, type: i }, t) : { type: "error" }); return { type: "union", ...t, enum: void 0, definitions: r }; } } class OpenApiParser3 extends OpenApiParser { constructor(e) { super(e); } } class OpenApiParser3_1 extends OpenApiParser { constructor(e) { super(e); } parseComponents(e) { const { models: t, requests: r, responses: i, parameters: s, headers: o, securitySchemes: a, callbacks: c } = super.parseComponents(e), f = []; if (e.pathItems) { const p = Object.entries(e.pathItems); for (const l of p) { const h = l[0], d = l[1], u = `#/components/pathItems/${h}`, b = this.parsePathItemObject(d, { models: t, requests: r, responses: i, parameters: s, headers: o, securitySchemes: a, callbacks: c }); f.push({ name: h, referenceName: u, definition: b }); } } return { models: t, requests: r, responses: i, parameters: s, headers: o, securitySchemes: a, callbacks: c, pathItems: f }; } } class OpenApiParserFactor { static isOpenAPIV2(e) { return "swagger" in e && e.swagger === "2.0"; } static isOpenAPIV3(e) { return "openapi" in e && e.openapi !== "3.1.0"; } static isOpenAPIV3_1(e) { return "openapi" in e && e.openapi === "3.1.0"; } static parse(e, t) { if (this.isOpenAPIV2(e)) throw new Error("v2 not supported"); if (thi