UNPKG

openapi-typescript

Version:

Convert OpenAPI 3.0 & 3.1 schemas to TypeScript

1,358 lines (1,343 loc) 75 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __commonJS = (cb, mod) => function __require() { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // ../../node_modules/.pnpm/ansi-colors@4.1.3/node_modules/ansi-colors/symbols.js var require_symbols = __commonJS({ "../../node_modules/.pnpm/ansi-colors@4.1.3/node_modules/ansi-colors/symbols.js"(exports, module2) { "use strict"; var isHyper = typeof process !== "undefined" && process.env.TERM_PROGRAM === "Hyper"; var isWindows = typeof process !== "undefined" && process.platform === "win32"; var isLinux = typeof process !== "undefined" && process.platform === "linux"; var common = { ballotDisabled: "\u2612", ballotOff: "\u2610", ballotOn: "\u2611", bullet: "\u2022", bulletWhite: "\u25E6", fullBlock: "\u2588", heart: "\u2764", identicalTo: "\u2261", line: "\u2500", mark: "\u203B", middot: "\xB7", minus: "\uFF0D", multiplication: "\xD7", obelus: "\xF7", pencilDownRight: "\u270E", pencilRight: "\u270F", pencilUpRight: "\u2710", percent: "%", pilcrow2: "\u2761", pilcrow: "\xB6", plusMinus: "\xB1", question: "?", section: "\xA7", starsOff: "\u2606", starsOn: "\u2605", upDownArrow: "\u2195" }; var windows = Object.assign({}, common, { check: "\u221A", cross: "\xD7", ellipsisLarge: "...", ellipsis: "...", info: "i", questionSmall: "?", pointer: ">", pointerSmall: "\xBB", radioOff: "( )", radioOn: "(*)", warning: "\u203C" }); var other = Object.assign({}, common, { ballotCross: "\u2718", check: "\u2714", cross: "\u2716", ellipsisLarge: "\u22EF", ellipsis: "\u2026", info: "\u2139", questionFull: "\uFF1F", questionSmall: "\uFE56", pointer: isLinux ? "\u25B8" : "\u276F", pointerSmall: isLinux ? "\u2023" : "\u203A", radioOff: "\u25EF", radioOn: "\u25C9", warning: "\u26A0" }); module2.exports = isWindows && !isHyper ? windows : other; Reflect.defineProperty(module2.exports, "common", { enumerable: false, value: common }); Reflect.defineProperty(module2.exports, "windows", { enumerable: false, value: windows }); Reflect.defineProperty(module2.exports, "other", { enumerable: false, value: other }); } }); // ../../node_modules/.pnpm/ansi-colors@4.1.3/node_modules/ansi-colors/index.js var require_ansi_colors = __commonJS({ "../../node_modules/.pnpm/ansi-colors@4.1.3/node_modules/ansi-colors/index.js"(exports, module2) { "use strict"; var isObject = (val) => val !== null && typeof val === "object" && !Array.isArray(val); var ANSI_REGEX = /[\u001b\u009b][[\]#;?()]*(?:(?:(?:[^\W_]*;?[^\W_]*)\u0007)|(?:(?:[0-9]{1,4}(;[0-9]{0,4})*)?[~0-9=<>cf-nqrtyA-PRZ]))/g; var hasColor = () => { if (typeof process !== "undefined") { return process.env.FORCE_COLOR !== "0"; } return false; }; var create = () => { const colors = { enabled: hasColor(), visible: true, styles: {}, keys: {} }; const ansi = (style2) => { let open = style2.open = `\x1B[${style2.codes[0]}m`; let close = style2.close = `\x1B[${style2.codes[1]}m`; let regex = style2.regex = new RegExp(`\\u001b\\[${style2.codes[1]}m`, "g"); style2.wrap = (input, newline) => { if (input.includes(close)) input = input.replace(regex, close + open); let output = open + input + close; return newline ? output.replace(/\r*\n/g, `${close}$&${open}`) : output; }; return style2; }; const wrap = (style2, input, newline) => { return typeof style2 === "function" ? style2(input) : style2.wrap(input, newline); }; const style = (input, stack) => { if (input === "" || input == null) return ""; if (colors.enabled === false) return input; if (colors.visible === false) return ""; let str = "" + input; let nl = str.includes("\n"); let n = stack.length; if (n > 0 && stack.includes("unstyle")) { stack = [.../* @__PURE__ */ new Set(["unstyle", ...stack])].reverse(); } while (n-- > 0) str = wrap(colors.styles[stack[n]], str, nl); return str; }; const define = (name, codes, type) => { colors.styles[name] = ansi({ name, codes }); let keys = colors.keys[type] || (colors.keys[type] = []); keys.push(name); Reflect.defineProperty(colors, name, { configurable: true, enumerable: true, set(value) { colors.alias(name, value); }, get() { let color = (input) => style(input, color.stack); Reflect.setPrototypeOf(color, colors); color.stack = this.stack ? this.stack.concat(name) : [name]; return color; } }); }; define("reset", [0, 0], "modifier"); define("bold", [1, 22], "modifier"); define("dim", [2, 22], "modifier"); define("italic", [3, 23], "modifier"); define("underline", [4, 24], "modifier"); define("inverse", [7, 27], "modifier"); define("hidden", [8, 28], "modifier"); define("strikethrough", [9, 29], "modifier"); define("black", [30, 39], "color"); define("red", [31, 39], "color"); define("green", [32, 39], "color"); define("yellow", [33, 39], "color"); define("blue", [34, 39], "color"); define("magenta", [35, 39], "color"); define("cyan", [36, 39], "color"); define("white", [37, 39], "color"); define("gray", [90, 39], "color"); define("grey", [90, 39], "color"); define("bgBlack", [40, 49], "bg"); define("bgRed", [41, 49], "bg"); define("bgGreen", [42, 49], "bg"); define("bgYellow", [43, 49], "bg"); define("bgBlue", [44, 49], "bg"); define("bgMagenta", [45, 49], "bg"); define("bgCyan", [46, 49], "bg"); define("bgWhite", [47, 49], "bg"); define("blackBright", [90, 39], "bright"); define("redBright", [91, 39], "bright"); define("greenBright", [92, 39], "bright"); define("yellowBright", [93, 39], "bright"); define("blueBright", [94, 39], "bright"); define("magentaBright", [95, 39], "bright"); define("cyanBright", [96, 39], "bright"); define("whiteBright", [97, 39], "bright"); define("bgBlackBright", [100, 49], "bgBright"); define("bgRedBright", [101, 49], "bgBright"); define("bgGreenBright", [102, 49], "bgBright"); define("bgYellowBright", [103, 49], "bgBright"); define("bgBlueBright", [104, 49], "bgBright"); define("bgMagentaBright", [105, 49], "bgBright"); define("bgCyanBright", [106, 49], "bgBright"); define("bgWhiteBright", [107, 49], "bgBright"); colors.ansiRegex = ANSI_REGEX; colors.hasColor = colors.hasAnsi = (str) => { colors.ansiRegex.lastIndex = 0; return typeof str === "string" && str !== "" && colors.ansiRegex.test(str); }; colors.alias = (name, color) => { let fn = typeof color === "string" ? colors[color] : color; if (typeof fn !== "function") { throw new TypeError("Expected alias to be the name of an existing color (string) or a function"); } if (!fn.stack) { Reflect.defineProperty(fn, "name", { value: name }); colors.styles[name] = fn; fn.stack = [name]; } Reflect.defineProperty(colors, name, { configurable: true, enumerable: true, set(value) { colors.alias(name, value); }, get() { let color2 = (input) => style(input, color2.stack); Reflect.setPrototypeOf(color2, colors); color2.stack = this.stack ? this.stack.concat(fn.stack) : fn.stack; return color2; } }); }; colors.theme = (custom) => { if (!isObject(custom)) throw new TypeError("Expected theme to be an object"); for (let name of Object.keys(custom)) { colors.alias(name, custom[name]); } return colors; }; colors.alias("unstyle", (str) => { if (typeof str === "string" && str !== "") { colors.ansiRegex.lastIndex = 0; return str.replace(colors.ansiRegex, ""); } return ""; }); colors.alias("noop", (str) => str); colors.none = colors.clear = colors.noop; colors.stripColor = colors.unstyle; colors.symbols = require_symbols(); colors.define = define; return colors; }; module2.exports = create(); module2.exports.create = create; } }); // src/index.ts var src_exports = {}; __export(src_exports, { COMMENT_HEADER: () => COMMENT_HEADER, default: () => src_default }); module.exports = __toCommonJS(src_exports); var import_node_url2 = require("url"); // src/load.ts var import_node_fs = __toESM(require("fs"), 1); var import_node_path2 = __toESM(require("path"), 1); var import_node_stream = require("stream"); var import_node_url = require("url"); var import_js_yaml = __toESM(require("js-yaml"), 1); // src/utils.ts var import_ansi_colors = __toESM(require_ansi_colors(), 1); var import_node_path = require("path"); // ../../node_modules/.pnpm/supports-color@9.4.0/node_modules/supports-color/index.js var import_node_process = __toESM(require("process"), 1); var import_node_os = __toESM(require("os"), 1); var import_node_tty = __toESM(require("tty"), 1); function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : import_node_process.default.argv) { const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--"; const position = argv.indexOf(prefix + flag); const terminatorPosition = argv.indexOf("--"); return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition); } var { env } = import_node_process.default; var flagForceColor; if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) { flagForceColor = 0; } else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) { flagForceColor = 1; } function envForceColor() { if ("FORCE_COLOR" in env) { if (env.FORCE_COLOR === "true") { return 1; } if (env.FORCE_COLOR === "false") { return 0; } return env.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3); } } function translateLevel(level) { if (level === 0) { return false; } return { level, hasBasic: true, has256: level >= 2, has16m: level >= 3 }; } function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) { const noFlagForceColor = envForceColor(); if (noFlagForceColor !== void 0) { flagForceColor = noFlagForceColor; } const forceColor = sniffFlags ? flagForceColor : noFlagForceColor; if (forceColor === 0) { return 0; } if (sniffFlags) { if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) { return 3; } if (hasFlag("color=256")) { return 2; } } if ("TF_BUILD" in env && "AGENT_NAME" in env) { return 1; } if (haveStream && !streamIsTTY && forceColor === void 0) { return 0; } const min = forceColor || 0; if (env.TERM === "dumb") { return min; } if (import_node_process.default.platform === "win32") { const osRelease = import_node_os.default.release().split("."); if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) { return Number(osRelease[2]) >= 14931 ? 3 : 2; } return 1; } if ("CI" in env) { if ("GITHUB_ACTIONS" in env || "GITEA_ACTIONS" in env) { return 3; } if (["TRAVIS", "CIRCLECI", "APPVEYOR", "GITLAB_CI", "BUILDKITE", "DRONE"].some((sign) => sign in env) || env.CI_NAME === "codeship") { return 1; } return min; } if ("TEAMCITY_VERSION" in env) { return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0; } if (env.COLORTERM === "truecolor") { return 3; } if (env.TERM === "xterm-kitty") { return 3; } if ("TERM_PROGRAM" in env) { const version = Number.parseInt((env.TERM_PROGRAM_VERSION || "").split(".")[0], 10); switch (env.TERM_PROGRAM) { case "iTerm.app": { return version >= 3 ? 3 : 2; } case "Apple_Terminal": { return 2; } } } if (/-256(color)?$/i.test(env.TERM)) { return 2; } if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) { return 1; } if ("COLORTERM" in env) { return 1; } return min; } function createSupportsColor(stream, options = {}) { const level = _supportsColor(stream, { streamIsTTY: stream && stream.isTTY, ...options }); return translateLevel(level); } var supportsColor = { stdout: createSupportsColor({ isTTY: import_node_tty.default.isatty(1) }), stderr: createSupportsColor({ isTTY: import_node_tty.default.isatty(2) }) }; var supports_color_default = supportsColor; // src/utils.ts var import_undici = require("undici"); if (!supports_color_default.stdout || supports_color_default.stdout.hasBasic === false) import_ansi_colors.default.enabled = false; var COMMENT_RE = /\*\//g; var LB_RE = /\r?\n/g; var DOUBLE_QUOTE_RE = /(?<!\\)"/g; var ESC_0_RE = /~0/g; var ESC_1_RE = /~1/g; var TS_UNION_INTERSECTION_RE = /[&|]/; var TS_READONLY_RE = /^readonly\s+/; var JS_OBJ_KEY = /^(\d+|[A-Za-z_$][A-Za-z0-9_$]*)$/; function walk(obj, cb, path2 = []) { if (!obj || typeof obj !== "object") return; if (Array.isArray(obj)) { for (let i = 0; i < obj.length; i++) walk(obj[i], cb, path2.concat(i)); return; } cb(obj, path2); for (const k of Object.keys(obj)) walk(obj[k], cb, path2.concat(k)); } function getSchemaObjectComment(v, indentLv) { if (!v || typeof v !== "object") return; const output = []; if (v.title) output.push(v.title); if (v.summary) output.push(v.summary); if (v.format) output.push(`Format: ${v.format}`); if (v.deprecated) output.push("@deprecated"); const supportedJsDocTags = ["description", "default", "example"]; for (const field of supportedJsDocTags) { const allowEmptyString = field === "default" || field === "example"; if (v[field] === void 0) { continue; } if (v[field] === "" && !allowEmptyString) { continue; } const serialized = typeof v[field] === "object" ? JSON.stringify(v[field], null, 2) : v[field]; output.push(`@${field} ${serialized}`); } if ("const" in v) output.push("@constant"); if (v.enum) { let type = "unknown"; if (Array.isArray(v.type)) type = v.type.join("|"); else if (typeof v.type === "string") type = v.type; output.push(`@enum {${type}${v.nullable ? `|null` : ""}}`); } return output.length ? comment(output.join("\n"), indentLv) : void 0; } function comment(text, indentLv) { const commentText = text.trim().replace(COMMENT_RE, "*\\/"); if (!commentText.includes("\n")) return `/** ${commentText} */`; const star = indent(" *", indentLv != null ? indentLv : 0); const body = commentText.split(LB_RE).map((ln) => { ln = ln.trimEnd(); return ln.length > 0 ? `${star} ${ln}` : star; }); return ["/**", body.join("\n"), indent(" */", indentLv != null ? indentLv : 0)].join("\n"); } function parseRef(ref) { if (typeof ref !== "string") return { filename: ".", path: [] }; if (ref.includes("#/")) { const [filename, pathStr] = ref.split("#"); const parts = pathStr.split("/"); const path2 = []; for (const part of parts) { if (!part || part === "properties") continue; path2.push(decodeRef(part)); } return { filename: filename || ".", path: path2 }; } else if (ref.includes('["')) { const parts = ref.split('["'); const path2 = []; for (const part of parts) { const sanitized = part.replace('"]', "").trim(); if (!sanitized || sanitized === "properties") continue; path2.push(sanitized); } return { filename: ".", path: path2 }; } return { filename: ref, path: [] }; } function makeTSIndex(parts) { return `${parts[0]}[${parts.slice(1).map(escStr).join("][")}]`; } function decodeRef(ref) { return ref.replace(ESC_0_RE, "~").replace(ESC_1_RE, "/").replace(DOUBLE_QUOTE_RE, '\\"'); } function parenthesise(type) { return TS_UNION_INTERSECTION_RE.test(type) || TS_READONLY_RE.test(type) ? `(${type})` : type; } function tsArrayOf(type) { return `${parenthesise(type)}[]`; } function tsIntersectionOf(...types) { types = types.filter((t) => t !== "unknown"); if (types.length === 0) return "unknown"; if (types.length === 1) return String(types[0]); return types.map((t) => parenthesise(t)).join(" & "); } function tsOneOf(...types) { if (types.length === 1) { return types[0]; } else if (types.length > 5) { return tsUnionOf(...types); } return `OneOf<[${types.join(", ")}]>`; } function tsOmit(root, keys) { return `Omit<${root}, ${tsUnionOf(...keys.map(escStr))}>`; } function tsWithRequired(root, keys) { return `WithRequired<${root}, ${tsUnionOf(...keys.map(escStr))}>`; } function tsOptionalProperty(key) { return `${key}?`; } function tsReadonly(type) { return `readonly ${type}`; } function tsTupleOf(...types) { return `[${types.join(", ")}]`; } function tsUnionOf(...types) { if (types.length === 0) return "never"; const members = /* @__PURE__ */ new Set(); for (const t of types) { if (t === "unknown") return "unknown"; members.add(String(t)); } if (members.has("never") && members.size === 1) return "never"; members.delete("never"); const memberArr = Array.from(members); if (members.size === 1) return memberArr[0]; let out = ""; for (let i = 0; i < memberArr.length; i++) { const t = memberArr[i]; out += parenthesise(t); if (i !== memberArr.length - 1) out += " | "; } return out; } function escStr(input) { if (typeof input !== "string") return JSON.stringify(input); return `"${input.replace(LB_RE, "").replace(DOUBLE_QUOTE_RE, '\\"')}"`; } function escObjKey(input) { return JS_OBJ_KEY.test(input) ? input : escStr(input); } function indent(input, level) { if (level > 0) { return " ".repeat(level).concat(input); } else { return input; } } function getEntries(obj, alphabetize, excludeDeprecated) { let entries = Object.entries(obj); if (alphabetize) entries.sort(([a], [b]) => a.localeCompare(b, "en", { numeric: true })); if (excludeDeprecated) entries = entries.filter(([, v]) => !(v && typeof v === "object" && "deprecated" in v && v.deprecated)); return entries; } function error(msg) { console.error(import_ansi_colors.default.red(` \u2718 ${msg}`)); } function isRemoteURL(url) { return url.startsWith("https://") || url.startsWith("//") || url.startsWith("http://"); } function isFilepath(url) { return url.startsWith("file://") || (0, import_node_path.isAbsolute)(url); } function getDefaultFetch() { const globalFetch = globalThis.fetch; if (typeof globalFetch === "undefined") { return import_undici.fetch; } return globalFetch; } // src/load.ts var EXT_RE = /\.(yaml|yml|json)#?\/?/i; var VIRTUAL_JSON_URL = `file:///_json`; function parseSchema(source) { return source.trim().startsWith("{") ? JSON.parse(source) : import_js_yaml.default.load(source); } function resolveSchema(filename) { if (isRemoteURL(filename)) return new import_node_url.URL(filename.startsWith("//") ? `https:${filename}` : filename); const localPath = import_node_path2.default.isAbsolute(filename) ? new import_node_url.URL(`file://${filename}`) : new import_node_url.URL(filename, `file://${process.cwd()}/`); if (!import_node_fs.default.existsSync(localPath)) { error(`Could not locate ${filename}`); process.exit(1); } else if (import_node_fs.default.statSync(localPath).isDirectory()) { error(`${localPath} is a directory not a file`); process.exit(1); } return localPath; } function parseHttpHeaders(httpHeaders) { const finalHeaders = {}; for (const [k, v] of Object.entries(httpHeaders)) { if (typeof v === "string") { finalHeaders[k] = v; } else { try { const stringVal = JSON.stringify(v); finalHeaders[k] = stringVal; } catch (err) { error(`Can\u2019t parse key: ${k} into JSON format. Continuing with the next HTTP header that is specified`); } } } return finalHeaders; } async function load(schema, options) { var _a; let schemaID = "."; if (schema instanceof import_node_url.URL) { const hint = (_a = options.hint) != null ? _a : "OpenAPI3"; if (schema.href !== options.rootURL.href) { schemaID = relativePath(options.rootURL, schema); } if (options.urlCache.has(schemaID)) { return options.schemas; } options.urlCache.add(schemaID); if (schema.protocol.startsWith("http")) { const headers = { "User-Agent": "openapi-typescript" }; if (options.auth) headers.Authorization = options.auth; if (options.httpHeaders) { const parsedHeaders = parseHttpHeaders(options.httpHeaders); for (const [k, v] of Object.entries(parsedHeaders)) { headers[k] = v; } } const res = await options.fetch(schema, { method: options.httpMethod || "GET", headers }); const contents = await res.text(); options.schemas[schemaID] = { hint, schema: parseSchema(contents) }; } else { const contents = import_node_fs.default.readFileSync(schema, "utf8"); options.schemas[schemaID] = { hint, schema: parseSchema(contents) }; } } else if (schema instanceof import_node_stream.Readable) { const readable = schema; const contents = await new Promise((resolve) => { readable.resume(); readable.setEncoding("utf8"); let content = ""; readable.on("data", (chunk) => { content += chunk; }); readable.on("end", () => { resolve(content.trim()); }); }); options.schemas[schemaID] = { hint: "OpenAPI3", schema: parseSchema(contents) }; } else if (typeof schema === "object") { options.schemas[schemaID] = { hint: "OpenAPI3", schema: JSON.parse(JSON.stringify(schema)) // create deep clone of inline schema (don’t mutate) }; } else { error(`Invalid schema`); process.exit(1); } const currentSchema = options.schemas[schemaID].schema; if (options.schemas[schemaID].hint === "OpenAPI3") { if ("components" in currentSchema && currentSchema.components && "examples" in currentSchema.components) delete currentSchema.components.examples; } const refPromises = []; walk(currentSchema, (rawNode, nodePath) => { for (const k of ["allOf", "anyOf", "oneOf"]) { if (Array.isArray(rawNode[k])) { rawNode[k] = rawNode[k].filter((o) => { if (!o || typeof o !== "object" || Array.isArray(o)) throw new Error(`${nodePath}.${k}: Expected array of objects. Is your schema valid?`); if (!("$ref" in o) || typeof o.$ref !== "string") return true; const ref2 = parseRef(o.$ref); return !ref2.path.some((i) => i.startsWith("x-")); }); } } if (!rawNode || typeof rawNode !== "object" || Array.isArray(rawNode)) throw new Error(`${nodePath}: Expected object, got ${Array.isArray(rawNode) ? "array" : typeof rawNode}. Is your schema valid?`); if (!("$ref" in rawNode) || typeof rawNode.$ref !== "string") return; const node = rawNode; const ref = parseRef(node.$ref); if (ref.filename === ".") { return; } if (ref.path.some((i) => i.startsWith("x-"))) { delete node.$ref; return; } const isRemoteFullSchema = ref.path[0] === "paths" || ref.path[0] === "components"; const hintPath = [...nodePath]; if (ref.filename) hintPath.push(ref.filename); hintPath.push(...ref.path); const hint = isRemoteFullSchema ? "OpenAPI3" : getHint({ path: hintPath, external: !!ref.filename, startFrom: options.hint }); if (isRemoteURL(ref.filename) || isFilepath(ref.filename)) { const nextURL2 = new import_node_url.URL(ref.filename.startsWith("//") ? `https://${ref.filename}` : ref.filename); refPromises.push(load(nextURL2, { ...options, hint })); node.$ref = node.$ref.replace(ref.filename, nextURL2.href); return; } if (options.rootURL.href === VIRTUAL_JSON_URL) { error(`Can\u2019t resolve "${ref.filename}" from dynamic JSON. Either load this schema from a filepath/URL, or set the \`cwd\` option: \`openapiTS(schema, { cwd: '/path/to/cwd' })\`.`); process.exit(1); } const nextURL = new import_node_url.URL(ref.filename, schema instanceof import_node_url.URL ? schema : options.rootURL); const nextID = relativePath(schema instanceof import_node_url.URL ? schema : options.rootURL, nextURL); refPromises.push(load(nextURL, { ...options, hint })); node.$ref = node.$ref.replace(ref.filename, nextID); }); await Promise.all(refPromises); if (schemaID === ".") { for (const subschemaID of Object.keys(options.schemas)) { walk(options.schemas[subschemaID].schema, (rawNode) => { if (!("$ref" in rawNode) || typeof rawNode.$ref !== "string") return; const node = rawNode; const ref = parseRef(node.$ref); if (ref.filename === ".") { if (subschemaID === "." || ref.path[0] === "external") { node.$ref = makeTSIndex(ref.path); } else { node.$ref = makeTSIndex(["external", subschemaID, ...ref.path]); } } else { const refURL = new import_node_url.URL(ref.filename, new import_node_url.URL(subschemaID, options.rootURL)); node.$ref = makeTSIndex(["external", relativePath(options.rootURL, refURL), ...ref.path]); } }); } } for (const k of Object.keys(options.schemas)) { walk(options.schemas[k].schema, (rawNode, nodePath) => { if (typeof rawNode === "object" && "in" in rawNode) { const key = k === "." ? makeTSIndex(nodePath) : makeTSIndex(["external", k, ...nodePath]); options.parameters[key] = rawNode; } }); } for (const k of Object.keys(options.schemas)) { if (JSON.stringify(options.schemas[k].schema).includes('"discriminator"')) { walk(options.schemas[k].schema, (rawNode, nodePath) => { const node = rawNode; if (!node.discriminator) return; const discriminator = { ...node.discriminator }; const oneOf = []; if (Array.isArray(node.oneOf)) { for (const child of node.oneOf) { if (!child || typeof child !== "object" || !("$ref" in child)) continue; oneOf.push(child.$ref); } } if (oneOf.length) discriminator.oneOf = oneOf; options.discriminators[schemaID === "." ? makeTSIndex(nodePath) : makeTSIndex(["external", k, ...nodePath])] = discriminator; }); } } return options.schemas; } function relativePath(src, dest) { const isSameOrigin = dest.protocol.startsWith("http") && src.protocol.startsWith("http") && dest.origin === src.origin; const isSameDisk = dest.protocol === "file:" && src.protocol === "file:"; if (isSameOrigin || isSameDisk) { return import_node_path2.default.posix.relative(import_node_path2.default.posix.dirname(src.pathname), dest.pathname); } return dest.href; } function getHint({ path: path2, external, startFrom }) { if (startFrom && startFrom !== "OpenAPI3") { switch (startFrom) { case "OperationObject": return getHintFromOperationObject(path2, external); case "RequestBodyObject": return getHintFromRequestBodyObject(path2, external); case "ResponseObject": return getHintFromResponseObject(path2, external); case "SchemaMap": return "SchemaObject"; default: return startFrom; } } switch (path2[0]) { case "paths": { if (EXT_RE.test(path2[2])) { return "SchemaMap"; } return getHintFromPathItemObject(path2.slice(2), external); } case "components": return getHintFromComponentsObject(path2.slice(1), external); } return void 0; } function getHintFromComponentsObject(path2, external) { switch (path2[0]) { case "schemas": case "headers": return getHintFromSchemaObject(path2.slice(2), external); case "parameters": return getHintFromParameterObject(path2.slice(2), external); case "responses": return getHintFromResponseObject(path2.slice(2), external); case "requestBodies": return getHintFromRequestBodyObject(path2.slice(2), external); case "pathItems": return getHintFromPathItemObject(path2.slice(2), external); } return "SchemaObject"; } function getHintFromMediaTypeObject(path2, external) { switch (path2[0]) { case "schema": return getHintFromSchemaObject(path2.slice(1), external); } return "MediaTypeObject"; } function getHintFromOperationObject(path2, external) { switch (path2[0]) { case "parameters": return "ParameterObject[]"; case "requestBody": return getHintFromRequestBodyObject(path2.slice(1), external); case "responses": return getHintFromResponseObject(path2.slice(2), external); } return "OperationObject"; } function getHintFromParameterObject(path2, external) { switch (path2[0]) { case "content": return getHintFromMediaTypeObject(path2.slice(2), external); case "schema": return getHintFromSchemaObject(path2.slice(1), external); } return "ParameterObject"; } function getHintFromPathItemObject(path2, external) { switch (path2[0]) { case "parameters": { if (typeof path2[1] === "number") { return "ParameterObject[]"; } return getHintFromParameterObject(path2.slice(1), external); } default: return getHintFromOperationObject(path2.slice(1), external); } } function getHintFromRequestBodyObject(path2, external) { switch (path2[0]) { case "content": return getHintFromMediaTypeObject(path2.slice(2), external); } return "RequestBodyObject"; } function getHintFromResponseObject(path2, external) { switch (path2[0]) { case "headers": return getHintFromSchemaObject(path2.slice(2), external); case "content": return getHintFromMediaTypeObject(path2.slice(2), external); } return "ResponseObject"; } function getHintFromSchemaObject(path2, external) { switch (path2[0]) { case "allOf": case "anyOf": case "oneOf": return "SchemaMap"; } if (path2.length >= 2 && external) { return "SchemaMap"; } return "SchemaObject"; } // src/transform/parameter-object.ts function transformParameterObject(parameterObject, { path: path2, ctx }) { return parameterObject.schema ? transformSchemaObject(parameterObject.schema, { path: path2, ctx }) : "string"; } // src/transform/request-body-object.ts function transformRequestBodyObject(requestBodyObject, { path: path2, ctx }) { let { indentLv } = ctx; const output = ["{"]; indentLv++; output.push(indent(ctx.immutableTypes ? tsReadonly("content: {") : "content: {", indentLv)); indentLv++; if (!Object.keys(requestBodyObject.content).length) { output.push(indent(`${escStr("*/*")}: never;`, indentLv)); } for (const [contentType, mediaTypeObject] of getEntries(requestBodyObject.content, ctx.alphabetize, ctx.excludeDeprecated)) { const c2 = getSchemaObjectComment(mediaTypeObject, indentLv); if (c2) output.push(indent(c2, indentLv)); let key = escStr(contentType); if (ctx.immutableTypes) key = tsReadonly(key); if ("$ref" in mediaTypeObject) { output.push( indent( `${key}: ${transformSchemaObject(mediaTypeObject, { path: `${path2}/${contentType}`, ctx: { ...ctx, indentLv } })};`, indentLv ) ); } else { const mediaType = transformMediaTypeObject(mediaTypeObject, { path: `${path2}/${contentType}`, ctx: { ...ctx, indentLv } }); output.push(indent(`${key}: ${mediaType};`, indentLv)); } } indentLv--; output.push(indent("};", indentLv)); indentLv--; output.push(indent("}", indentLv)); return output.join("\n"); } // src/transform/response-object.ts function transformResponseObject(responseObject, { path: path2, ctx }) { const output = ["{"]; let { indentLv } = ctx; if (responseObject.headers) { indentLv++; output.push(indent(`headers: {`, indentLv)); indentLv++; for (const [name, headerObject] of getEntries(responseObject.headers, ctx.alphabetize, ctx.excludeDeprecated)) { const c2 = getSchemaObjectComment(headerObject, indentLv); if (c2) output.push(indent(c2, indentLv)); let key = escObjKey(name); if (ctx.immutableTypes) key = tsReadonly(key); if ("$ref" in headerObject) { output.push(indent(`${key}: ${headerObject.$ref};`, indentLv)); } else { if (!headerObject.required) key = tsOptionalProperty(key); output.push( indent( `${key}: ${transformHeaderObject(headerObject, { path: `${path2}/headers/${name}`, ctx: { ...ctx, indentLv } })};`, indentLv ) ); } } indentLv--; output.push(indent(`};`, indentLv)); indentLv--; } if (responseObject.content) { indentLv++; output.push(indent("content: {", indentLv)); indentLv++; for (const [contentType, mediaTypeObject] of getEntries(responseObject.content, ctx.alphabetize, ctx.excludeDeprecated)) { let key = escStr(contentType); if (ctx.immutableTypes) key = tsReadonly(key); output.push( indent( `${key}: ${transformMediaTypeObject(mediaTypeObject, { path: `${path2}/content/${contentType}`, ctx: { ...ctx, indentLv } })};`, indentLv ) ); } indentLv--; output.push(indent("};", indentLv)); indentLv--; } else { indentLv++; output.push(indent("content: never;", indentLv)); indentLv--; } output.push(indent("}", indentLv)); return output.join("\n"); } // src/transform/operation-object.ts function transformOperationObject(operationObject, { path: path2, ctx, wrapObject = true }) { var _a; let { indentLv } = ctx; const output = wrapObject ? ["{"] : []; indentLv++; { if (operationObject.parameters) { const parameterOutput = []; indentLv++; for (const paramIn of ["query", "header", "path", "cookie"]) { const paramInternalOutput = []; indentLv++; let allOptional = true; for (const param of (_a = operationObject.parameters) != null ? _a : []) { const node = "$ref" in param ? ctx.parameters[param.$ref] : param; if ((node == null ? void 0 : node.in) !== paramIn) continue; let key = escObjKey(node.name); if (paramIn !== "path" && !node.required) { key = tsOptionalProperty(key); } else { allOptional = false; } const c2 = getSchemaObjectComment(param, indentLv); if (c2) paramInternalOutput.push(indent(c2, indentLv)); const parameterType = "$ref" in param ? param.$ref : transformParameterObject(param, { path: `${path2}/parameters/${param.name}`, ctx: { ...ctx, indentLv } }); paramInternalOutput.push(indent(`${key}: ${parameterType};`, indentLv)); } indentLv--; if (paramInternalOutput.length) { const key = allOptional ? tsOptionalProperty(paramIn) : paramIn; parameterOutput.push(indent(`${key}: {`, indentLv)); parameterOutput.push(...paramInternalOutput); parameterOutput.push(indent(`};`, indentLv)); } } indentLv--; if (parameterOutput.length) { output.push(indent(`parameters: {`, indentLv)); output.push(parameterOutput.join("\n")); output.push(indent("};", indentLv)); } } } { if (operationObject.requestBody) { const c2 = getSchemaObjectComment(operationObject.requestBody, indentLv); if (c2) output.push(indent(c2, indentLv)); let key = "requestBody"; if (ctx.immutableTypes) key = tsReadonly(key); if ("$ref" in operationObject.requestBody) { output.push(indent(`${key}: ${transformSchemaObject(operationObject.requestBody, { path: path2, ctx })};`, indentLv)); } else { if (!operationObject.requestBody.required) key = tsOptionalProperty(key); const requestBody = transformRequestBodyObject(operationObject.requestBody, { path: `${path2}/requestBody`, ctx: { ...ctx, indentLv } }); output.push(indent(`${key}: ${requestBody};`, indentLv)); } } } { if (operationObject.responses) { output.push(indent(`responses: {`, indentLv)); indentLv++; for (const [responseCode, responseObject] of getEntries(operationObject.responses, ctx.alphabetize, ctx.excludeDeprecated)) { const key = escObjKey(responseCode); const c2 = getSchemaObjectComment(responseObject, indentLv); if (c2) output.push(indent(c2, indentLv)); if ("$ref" in responseObject) { output.push( indent( `${key}: ${transformSchemaObject(responseObject, { path: `${path2}/responses/${responseCode}`, ctx })};`, indentLv ) ); } else { const responseType = transformResponseObject(responseObject, { path: `${path2}/responses/${responseCode}`, ctx: { ...ctx, indentLv } }); output.push(indent(`${key}: ${responseType};`, indentLv)); } } indentLv--; output.push(indent(`};`, indentLv)); } } indentLv--; if (wrapObject) { output.push(indent("}", indentLv)); } return output.join("\n"); } // src/transform/path-item-object.ts function transformPathItemObject(pathItem, { path: path2, ctx }) { var _a, _b, _c; let { indentLv } = ctx; const output = []; output.push("{"); indentLv++; for (const method of ["get", "put", "post", "delete", "options", "head", "patch", "trace"]) { const operationObject = pathItem[method]; if (!operationObject) continue; const c2 = getSchemaObjectComment(operationObject, indentLv); if (c2) output.push(indent(c2, indentLv)); const keyedParameters = {}; if (!("$ref" in operationObject)) { for (const parameter of [...(_a = pathItem.parameters) != null ? _a : [], ...(_b = operationObject.parameters) != null ? _b : []]) { keyedParameters["$ref" in parameter ? parameter.$ref : parameter.name] = parameter; } } if ("$ref" in operationObject) { output.push(indent(`${method}: ${operationObject.$ref}`, indentLv)); } else if (operationObject.operationId) { const operationType = transformOperationObject({ ...operationObject, parameters: Object.values(keyedParameters) }, { path: path2, ctx: { ...ctx, indentLv: 1 } }); ctx.operations[operationObject.operationId] = { operationType, comment: getSchemaObjectComment(operationObject, 1) }; output.push(indent(`${method}: operations[${escStr(operationObject.operationId)}];`, indentLv)); } else { const operationType = transformOperationObject({ ...operationObject, parameters: Object.values(keyedParameters) }, { path: path2, ctx: { ...ctx, indentLv } }); output.push(indent(`${method}: ${operationType};`, indentLv)); } } if ((_c = pathItem.parameters) == null ? void 0 : _c.length) { output.push(indent(transformOperationObject({ parameters: pathItem.parameters }, { path: path2, ctx, wrapObject: false }).trim(), indentLv)); } indentLv--; output.push(indent("}", indentLv)); return output.join("\n"); } // src/transform/schema-object-map.ts function transformSchemaObjectMap(schemaObjMap, { path: path2, ctx }) { if ("type" in schemaObjMap && typeof schemaObjMap.type === "string" || "allOf" in schemaObjMap && Array.isArray(schemaObjMap.allOf) || "oneOf" in schemaObjMap && Array.isArray(schemaObjMap.oneOf) || "anyOf" in schemaObjMap && Array.isArray(schemaObjMap.anyOf)) { return transformSchemaObject(schemaObjMap, { path: path2, ctx }); } let { indentLv } = ctx; const output = ["{"]; indentLv++; outer: for (const [name, schemaObject] of getEntries(schemaObjMap, ctx.alphabetize, ctx.excludeDeprecated)) { if (!schemaObject || typeof schemaObject !== "object") continue; const c2 = getSchemaObjectComment(schemaObject, indentLv); if (c2) output.push(indent(c2, indentLv)); let key = escObjKey(name); if (ctx.immutableTypes || schemaObject.readOnly) key = tsReadonly(key); if (!("type" in schemaObject) && !("$ref" in schemaObject)) { for (const method of ["get", "put", "post", "delete", "options", "head", "patch", "trace"]) { if (method in schemaObject) { output.push(indent(`${key}: ${transformPathItemObject(schemaObject, { path: `${path2}${name}`, ctx: { ...ctx, indentLv } })};`, indentLv)); continue outer; } } } if ("in" in schemaObject) { output.push(indent(`${key}: ${transformParameterObject(schemaObject, { path: `${path2}${name}`, ctx: { ...ctx, indentLv } })};`, indentLv)); continue; } output.push(indent(`${key}: ${transformSchemaObject(schemaObject, { path: `${path2}${name}`, ctx: { ...ctx, indentLv } })};`, indentLv)); } indentLv--; output.push(indent("}", indentLv)); return output.join("\n"); } // src/transform/schema-object.ts function transformSchemaObject(schemaObject, options) { const result = defaultSchemaObjectTransform(schemaObject, options); if (typeof options.ctx.postTransform === "function") { const postResult = options.ctx.postTransform(result, options); if (postResult) return postResult; } return result; } function defaultSchemaObjectTransform(schemaObject, { path: path2, ctx }) { var _a, _b, _c; let { indentLv } = ctx; if (typeof schemaObject === "boolean") { return schemaObject ? "unknown" : "never"; } if (!schemaObject || typeof schemaObject !== "object") return schemaObject; if (Array.isArray(schemaObject)) { const finalType2 = tsTupleOf(...schemaObject); return ctx.immutableTypes ? tsReadonly(finalType2) : finalType2; } if ("$ref" in schemaObject) { return schemaObject.$ref; } if (typeof ctx.transform === "function") { const result = ctx.transform(schemaObject, { path: path2, ctx }); if (result) return result; } if (schemaObject.const !== null && schemaObject.const !== void 0) { return transformSchemaObject(escStr(schemaObject.const), { path: path2, ctx: { ...ctx, immutableTypes: false, indentLv: indentLv + 1 } // note: guarantee readonly happens once, here }); } if (typeof schemaObject === "object" && !!schemaObject.enum && schemaObject.type !== "object") { let items = schemaObject.enum; if ("type" in schemaObject) { if (schemaObject.type === "string" || Array.isArray(schemaObject.type) && schemaObject.type.includes("string")) { items = items.map((t) => escStr(t)); } } else { items = items.map((t) => escStr(t || "")); } return tsUnionOf(...items, ...schemaObject.nullable ? ["null"] : []); } const oneOf = typeof schemaObject === "object" && !schemaObject.discriminator && schemaObject.oneOf || schemaObject.enum || void 0; if (oneOf && !oneOf.some((t) => "$ref" in t && ctx.discriminators[t.$ref])) { const oneOfNormalized = oneOf.map((item) => transformSchemaObject(item, { path: path2, ctx })); if (schemaObject.nullable) oneOfNormalized.push("null"); if ("type" in schemaObject && Array.isArray(schemaObject.type)) { const coreTypes = schemaObject.type.map((t) => transformSchemaObject({ ...schemaObject, oneOf: void 0, type: t }, { path: path2, ctx })); return tsUnionOf(...oneOfNormalized, ...coreTypes); } const oneOfTypes = oneOfNormalized.some((t) => typeof t === "string" && t.includes("{")) ? tsOneOf(...oneOfNormalized) : tsUnionOf(...oneOfNormalized); if ("type" in schemaObject && schemaObject.type === "object" && (schemaObject.properties || schemaObject.additionalProperties)) { return tsIntersectionOf(transformSchemaObject({ ...schemaObject, oneOf: void 0, enum: void 0 }, { path: path2, ctx }), oneOfTypes); } return oneOfTypes; } if ("type" in schemaObject) { if (schemaObject.type === "null") return "null"; if (schemaObject.type === "string" || schemaObject.type === "boolean") { return schemaObject.nullable ? tsUnionOf(schemaObject.type, "null") : schemaObject.type; } if (schemaObject.type === "number" || schemaObject.type === "integer") { return schemaObject.nullable ? tsUnionOf("number", "null") : "number"; } if (schemaObject.type === "array") { indentLv++; let itemType = "unknown"; let isTupleType = false; if (schemaObject.prefixItems || Array.isArray(schemaObject.items)) { isTupleType = true; const result = []; for (const item of (_a = schemaObject.prefixItems) != null ? _a : schemaObject.items) { result.push(transformSchemaObject(item, { path: path2, ctx: { ...ctx, indentLv } })); } itemType = `[${result.join(", ")}]`; } else if (schemaObject.items) { itemType = transformSchemaObject(schemaObject.items, { path: path2, ctx: { ...ctx, indentLv } }); } const min = typeof schemaObject.minItems === "number" && schemaObject.minItems >= 0 ? schemaObject.minItems : 0; const max = typeof schemaObject.maxItems === "number" && schemaObject.maxItems >= 0 && min <= schemaObject.maxItems ? schemaObject.maxItems : void 0; const estimateCodeSize = typeof max !== "number" ? min : (max * (max + 1) - min * (min - 1)) / 2; if (ctx.supportArrayLength && (min !== 0 || max !== void 0) && estimateCodeSize < 30) { if (typeof schemaObject.maxItems !== "number") { itemType = tsTupleOf(...Array.from({ length: min }).map(() => itemType), `...${tsArrayOf(itemType)}`); return ctx.immutableTypes || schemaObject.readOnly ? tsReadonly(itemType) : itemType; } else { return tsUnionOf( ...Array.from({ length: (max != null ? max : 0) - min + 1 }).map((_, i) => i + min).map((n) => { const t = tsTupleOf(...Array.from({ length: n }).map(() => itemType)); return ctx.immutableTypes || schemaObject.readOnly ? tsReadonly(t) : t; }) ); } } if (!isTupleType) { itemType = tsArrayOf(itemType); } itemType = ctx.immutableTypes || schemaObject.readOnly ? tsReadonly(itemType) : itemType; return schemaObject.nullable ? tsUnionOf(itemType, "null") : itemType; } if (Array.isArray(schemaObject.type)) { return tsUnionOf(...schemaObject.type.map((t) => transformSchemaObject({ ...schemaObject, type: t }, { path: path2, ctx }))); } } const coreType = []; for (const k of ["oneOf", "allOf", "anyOf"]) { if (!schemaObject[k]) continue; const discriminatorRef = schemaObject[k].find( (t) => "$ref" in t && (ctx.discriminators[t.$ref] || // explicit allOf from this node Object.values(ctx.discriminators).find((d) => { var _a2; return (_a2 = d.oneOf) == null ? void 0 : _a2.includes(path2); })) // implicit oneOf from parent ); if (discriminatorRef && ctx.d