oas
Version:
Comprehensive tooling for working with OpenAPI definitions
786 lines (758 loc) • 28.4 kB
JavaScript
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
var _chunk4EWSCVWCcjs = require('./chunk-4EWSCVWC.cjs');
var _chunkTDI4MZLIcjs = require('./chunk-TDI4MZLI.cjs');
var _chunkQ2TBKI3Ocjs = require('./chunk-Q2TBKI3O.cjs');
var _chunkXS7VDTTTcjs = require('./chunk-XS7VDTTT.cjs');
// src/index.ts
var _openapiparser = require('@readme/openapi-parser');
var _pathtoregexp = require('path-to-regexp');
// src/lib/get-auth.ts
function getKey(user, scheme) {
switch (scheme.type) {
case "oauth2":
case "apiKey":
return user[scheme._key] || user.apiKey || scheme["x-default"] || null;
case "http":
if (scheme.scheme === "basic") {
return user[scheme._key] || { user: user.user || null, pass: user.pass || null };
}
if (scheme.scheme === "bearer") {
return user[scheme._key] || user.apiKey || scheme["x-default"] || null;
}
return null;
default:
return null;
}
}
function getByScheme(user, scheme = {}, selectedApp) {
if (_optionalChain([user, 'optionalAccess', _ => _.keys]) && user.keys.length) {
if (selectedApp) {
return getKey(
user.keys.find((key) => key.name === selectedApp),
scheme
);
}
return getKey(user.keys[0], scheme);
}
return getKey(user, scheme);
}
function getAuth(api, user, selectedApp) {
return Object.keys(_optionalChain([api, 'optionalAccess', _2 => _2.components, 'optionalAccess', _3 => _3.securitySchemes]) || {}).map((scheme) => {
return {
[scheme]: getByScheme(
user,
{
// This sucks but since we dereference we'll never have a `$ref` pointer here with a
// `ReferenceObject` type.
...api.components.securitySchemes[scheme],
_key: scheme
},
selectedApp
)
};
}).reduce((prev, next) => Object.assign(prev, next), {});
}
// src/lib/get-user-variable.ts
function getUserVariable(user, property, selectedApp) {
let key = user;
if ("keys" in user && Array.isArray(user.keys) && user.keys.length) {
if (selectedApp) {
key = user.keys.find((k) => k.name === selectedApp);
} else {
key = user.keys[0];
}
}
return key[property] || user[property] || null;
}
// src/index.ts
var SERVER_VARIABLE_REGEX = /{([-_a-zA-Z0-9:.[\]]+)}/g;
function ensureProtocol(url) {
if (url.match(/^\/\//)) {
return `https:${url}`;
}
if (!url.match(/\/\//)) {
return `https://${url}`;
}
return url;
}
function stripTrailingSlash(url) {
if (url[url.length - 1] === "/") {
return url.slice(0, -1);
}
return url;
}
function normalizedUrl(api, selected) {
const exampleDotCom = "https://example.com";
let url;
try {
url = api.servers[selected].url;
if (!url) throw new Error("no url");
url = stripTrailingSlash(url);
if (url.startsWith("/") && !url.startsWith("//")) {
const urlWithOrigin = new URL(exampleDotCom);
urlWithOrigin.pathname = url;
url = urlWithOrigin.href;
}
} catch (e) {
url = exampleDotCom;
}
return ensureProtocol(url);
}
function transformUrlIntoRegex(url) {
return stripTrailingSlash(url.replace(SERVER_VARIABLE_REGEX, "([-_a-zA-Z0-9:.[\\]]+)"));
}
function normalizePath(path) {
return path.replace(/({?){(.*?)}(}?)/g, (str, ...args) => {
return `:${args[1].replace("-", "")}`;
}).replace(/::/, "\\::").split("?")[0];
}
function generatePathMatches(paths, pathName, origin) {
const prunedPathName = pathName.split("?")[0];
return Object.keys(paths).map((path) => {
const cleanedPath = normalizePath(path);
let matchResult;
try {
const matchStatement = _pathtoregexp.match.call(void 0, cleanedPath, { decode: decodeURIComponent });
matchResult = matchStatement(prunedPathName);
} catch (err) {
return;
}
const slugs = {};
if (matchResult && Object.keys(matchResult.params).length) {
Object.keys(matchResult.params).forEach((param) => {
slugs[`:${param}`] = matchResult.params[param];
});
}
return {
url: {
origin,
path: cleanedPath.replace(/\\::/, "::"),
nonNormalizedPath: path,
slugs
},
operation: paths[path],
match: matchResult
};
}).filter(Boolean).filter((p) => p.match);
}
function filterPathMethods(pathMatches, targetMethod) {
const regExp = _pathtoregexp.pathToRegexp.call(void 0, targetMethod);
return pathMatches.map((p) => {
const captures = Object.keys(p.operation).filter((r) => regExp.regexp.exec(r));
if (captures.length) {
const method = captures[0];
p.url.method = method.toUpperCase();
return {
url: p.url,
operation: p.operation[method]
};
}
return false;
}).filter(Boolean);
}
function findTargetPath(pathMatches) {
let minCount = Object.keys(pathMatches[0].url.slugs).length;
let operation;
for (let m = 0; m < pathMatches.length; m += 1) {
const selection = pathMatches[m];
const paramCount = Object.keys(selection.url.slugs).length;
if (paramCount <= minCount) {
minCount = paramCount;
operation = selection;
}
}
return operation;
}
var Oas = class _Oas {
/**
* An OpenAPI API Definition.
*/
/**
* The current user that we should use when pulling auth tokens from security schemes.
*/
/**
* Internal storage array that the library utilizes to keep track of the times the
* {@see Oas.dereference} has been called so that if you initiate multiple promises they'll all
* end up returning the same data set once the initial dereference call completed.
*/
/**
* Internal storage array that the library utilizes to keep track of its `dereferencing` state so
* it doesn't initiate multiple dereferencing processes.
*/
/**
* @param oas An OpenAPI definition.
* @param user The information about a user that we should use when pulling auth tokens from
* security schemes.
*/
constructor(oas, user) {
if (typeof oas === "string") {
oas = JSON.parse(oas);
}
this.api = oas || {};
this.user = user || {};
this.promises = [];
this.dereferencing = {
processing: false,
complete: false,
circularRefs: []
};
}
/**
* This will initialize a new instance of the `Oas` class. This method is useful if you're using
* Typescript and are attempting to supply an untyped JSON object into `Oas` as it will force-type
* that object to an `OASDocument` for you.
*
* @param oas An OpenAPI definition.
* @param user The information about a user that we should use when pulling auth tokens from
* security schemes.
*/
static init(oas, user) {
return new _Oas(oas, user);
}
/**
* Retrieve the OpenAPI version that this API definition is targeted for.
*/
getVersion() {
if (this.api.openapi) {
return this.api.openapi;
}
throw new Error("Unable to recognize what specification version this API definition conforms to.");
}
/**
* Retrieve the current OpenAPI API Definition.
*
*/
getDefinition() {
return this.api;
}
url(selected = 0, variables) {
const url = normalizedUrl(this.api, selected);
return this.replaceUrl(url, variables || this.defaultVariables(selected)).trim();
}
variables(selected = 0) {
let variables;
try {
variables = this.api.servers[selected].variables;
if (!variables) throw new Error("no variables");
} catch (e) {
variables = {};
}
return variables;
}
defaultVariables(selected = 0) {
const variables = this.variables(selected);
const defaults = {};
Object.keys(variables).forEach((key) => {
defaults[key] = getUserVariable(this.user, key) || variables[key].default || "";
});
return defaults;
}
splitUrl(selected = 0) {
const url = normalizedUrl(this.api, selected);
const variables = this.variables(selected);
return url.split(/({.+?})/).filter(Boolean).map((part, i) => {
const isVariable = part.match(/[{}]/);
const value = part.replace(/[{}]/g, "");
const key = `${value}-${i}`;
if (!isVariable) {
return {
type: "text",
value,
key
};
}
const variable = _optionalChain([variables, 'optionalAccess', _4 => _4[value]]);
return {
type: "variable",
value,
key,
description: _optionalChain([variable, 'optionalAccess', _5 => _5.description]),
enum: _optionalChain([variable, 'optionalAccess', _6 => _6.enum])
};
});
}
/**
* With a fully composed server URL, run through our list of known OAS servers and return back
* which server URL was selected along with any contained server variables split out.
*
* For example, if you have an OAS server URL of `https://{name}.example.com:{port}/{basePath}`,
* and pass in `https://buster.example.com:3000/pet` to this function, you'll get back the
* following:
*
* { selected: 0, variables: { name: 'buster', port: 3000, basePath: 'pet' } }
*
* Re-supplying this data to `oas.url()` should return the same URL you passed into this method.
*
* @param baseUrl A given URL to extract server variables out of.
*/
splitVariables(baseUrl) {
const matchedServer = (this.api.servers || []).map((server, i) => {
const rgx = transformUrlIntoRegex(server.url);
const found = new RegExp(rgx).exec(baseUrl);
if (!found) {
return false;
}
const variables = {};
Array.from(server.url.matchAll(SERVER_VARIABLE_REGEX)).forEach((variable, y) => {
variables[variable[1]] = found[y + 1];
});
return {
selected: i,
variables
};
}).filter(Boolean);
return matchedServer.length ? matchedServer[0] : false;
}
/**
* Replace templated variables with supplied data in a given URL.
*
* There are a couple ways that this will utilize variable data:
*
* - Supplying a `variables` object. If this is supplied, this data will always take priority.
* This incoming `variables` object can be two formats:
* `{ variableName: { default: 'value' } }` and `{ variableName: 'value' }`. If the former is
* present, that will take precedence over the latter.
* - If the supplied `variables` object is empty or does not match the current template name,
* we fallback to the data stored in `this.user` and attempt to match against that.
* See `getUserVariable` for some more information on how this data is pulled from `this.user`.
*
* If no variables supplied match up with the template name, the template name will instead be
* used as the variable data.
*
* @param url A URL to swap variables into.
* @param variables An object containing variables to swap into the URL.
*/
replaceUrl(url, variables = {}) {
return stripTrailingSlash(
url.replace(SERVER_VARIABLE_REGEX, (original, key) => {
if (key in variables) {
const data = variables[key];
if (typeof data === "object") {
if (!Array.isArray(data) && data !== null && "default" in data) {
return data.default;
}
} else {
return data;
}
}
const userVariable = getUserVariable(this.user, key);
if (userVariable) {
return userVariable;
}
return original;
})
);
}
/**
* Retrieve an Operation of Webhook class instance for a given path and method.
*
* @param path Path to lookup and retrieve.
* @param method HTTP Method to retrieve on the path.
*/
operation(path, method, opts = {}) {
let operation = {
parameters: []
};
if (opts.isWebhook) {
const api = this.api;
if (_optionalChain([api, 'optionalAccess', _7 => _7.webhooks, 'access', _8 => _8[path], 'optionalAccess', _9 => _9[method]])) {
operation = api.webhooks[path][method];
return new (0, _chunk4EWSCVWCcjs.Webhook)(api, path, method, operation);
}
}
if (_optionalChain([this, 'optionalAccess', _10 => _10.api, 'optionalAccess', _11 => _11.paths, 'optionalAccess', _12 => _12[path], 'optionalAccess', _13 => _13[method]])) {
operation = this.api.paths[path][method];
}
return new (0, _chunk4EWSCVWCcjs.Operation)(this.api, path, method, operation);
}
findOperationMatches(url) {
const { origin, hostname } = new URL(url);
const originRegExp = new RegExp(origin, "i");
const { servers, paths } = this.api;
let pathName;
let targetServer;
let matchedServer;
if (!servers || !servers.length) {
matchedServer = {
url: "https://example.com"
};
} else {
matchedServer = servers.find((s) => originRegExp.exec(this.replaceUrl(s.url, s.variables || {})));
if (!matchedServer) {
const hostnameRegExp = new RegExp(hostname);
matchedServer = servers.find((s) => hostnameRegExp.exec(this.replaceUrl(s.url, s.variables || {})));
}
}
if (!matchedServer) {
const matchedServerAndPath = servers.map((server) => {
const rgx = transformUrlIntoRegex(server.url);
const found = new RegExp(rgx).exec(url);
if (!found) {
return void 0;
}
return {
matchedServer: server,
pathName: url.split(new RegExp(rgx)).slice(-1).pop()
};
}).filter(Boolean);
if (!matchedServerAndPath.length) {
return void 0;
}
pathName = matchedServerAndPath[0].pathName;
targetServer = {
...matchedServerAndPath[0].matchedServer
};
} else {
targetServer = {
...matchedServer,
url: this.replaceUrl(matchedServer.url, matchedServer.variables || {})
};
[, pathName] = url.split(new RegExp(targetServer.url, "i"));
}
if (pathName === void 0) return void 0;
if (pathName === "") pathName = "/";
const annotatedPaths = generatePathMatches(paths, pathName, targetServer.url);
if (!annotatedPaths.length) return void 0;
return annotatedPaths;
}
/**
* Discover an operation in an OAS from a fully-formed URL and HTTP method. Will return an object
* containing a `url` object and another one for `operation`. This differs from `getOperation()`
* in that it does not return an instance of the `Operation` class.
*
* @param url A full URL to look up.
* @param method The cooresponding HTTP method to look up.
*/
findOperation(url, method) {
const annotatedPaths = this.findOperationMatches(url);
if (!annotatedPaths) {
return void 0;
}
const matches = filterPathMethods(annotatedPaths, method);
if (!matches.length) return void 0;
return findTargetPath(matches);
}
/**
* Discover an operation in an OAS from a fully-formed URL without an HTTP method. Will return an
* object containing a `url` object and another one for `operation`.
*
* @param url A full URL to look up.
*/
findOperationWithoutMethod(url) {
const annotatedPaths = this.findOperationMatches(url);
if (!annotatedPaths) {
return void 0;
}
return findTargetPath(annotatedPaths);
}
/**
* Retrieve an operation in an OAS from a fully-formed URL and HTTP method. Differs from
* `findOperation` in that while this method will return an `Operation` instance,
* `findOperation()` does not.
*
* @param url A full URL to look up.
* @param method The cooresponding HTTP method to look up.
*/
getOperation(url, method) {
const op = this.findOperation(url, method);
if (op === void 0) {
return void 0;
}
return this.operation(op.url.nonNormalizedPath, method);
}
/**
* Retrieve an operation in an OAS by an `operationId`.
*
* If an operation does not have an `operationId` one will be generated in place, using the
* default behavior of `Operation.getOperationId()`, and then asserted against your query.
*
* Note that because `operationId`s are unique that uniqueness does include casing so the ID
* you are looking for will be asserted as an exact match.
*
* @see {Operation.getOperationId()}
* @param id The `operationId` to look up.
*/
getOperationById(id) {
let found;
Object.values(this.getPaths()).forEach((operations) => {
if (found) return;
found = Object.values(operations).find((operation) => operation.getOperationId() === id);
});
if (found) {
return found;
}
Object.entries(this.getWebhooks()).forEach(([, webhooks]) => {
if (found) return;
found = Object.values(webhooks).find((webhook) => webhook.getOperationId() === id);
});
return found;
}
/**
* With an object of user information, retrieve the appropriate API auth keys from the current
* OAS definition.
*
* @see {@link https://docs.readme.com/docs/passing-data-to-jwt}
* @param user User
* @param selectedApp The user app to retrieve an auth key for.
*/
getAuth(user, selectedApp) {
if (!_optionalChain([this, 'access', _14 => _14.api, 'optionalAccess', _15 => _15.components, 'optionalAccess', _16 => _16.securitySchemes])) {
return {};
}
return getAuth(this.api, user, selectedApp);
}
/**
* Returns the `paths` object that exists in this API definition but with every `method` mapped
* to an instance of the `Operation` class.
*
* @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md#openapi-object}
* @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#openapi-object}
*/
getPaths() {
const paths = {};
Object.keys(this.api.paths ? this.api.paths : []).forEach((path) => {
if (path.startsWith("x-")) {
return;
}
paths[path] = {};
if ("$ref" in this.api.paths[path]) {
this.api.paths[path] = _chunkTDI4MZLIcjs.findSchemaDefinition.call(void 0, this.api.paths[path].$ref, this.api);
}
Object.keys(this.api.paths[path]).forEach((method) => {
if (!_chunkTDI4MZLIcjs.supportedMethods.includes(method)) return;
paths[path][method] = this.operation(path, method);
});
});
return paths;
}
/**
* Returns the `webhooks` object that exists in this API definition but with every `method`
* mapped to an instance of the `Webhook` class.
*
* @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md#openapi-object}
* @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#openapi-object}
*/
getWebhooks() {
const webhooks = {};
const api = this.api;
Object.keys(api.webhooks ? api.webhooks : []).forEach((id) => {
webhooks[id] = {};
Object.keys(api.webhooks[id]).forEach((method) => {
webhooks[id][method] = this.operation(id, method, { isWebhook: true });
});
});
return webhooks;
}
/**
* Return an array of all tag names that exist on this API definition.
*
* @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md#openapi-object}
* @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#openapi-object}
* @param setIfMissing If a tag is not present on an operation that operations path will be added
* into the list of tags returned.
*/
getTags(setIfMissing = false) {
const allTags = /* @__PURE__ */ new Set();
const oasTags = _optionalChain([this, 'access', _17 => _17.api, 'access', _18 => _18.tags, 'optionalAccess', _19 => _19.map, 'call', _20 => _20((tag) => {
return tag.name;
})]) || [];
const disableTagSorting = _chunkXS7VDTTTcjs.getExtension.call(void 0, "disable-tag-sorting", this.api);
Object.entries(this.getPaths()).forEach(([path, operations]) => {
Object.values(operations).forEach((operation) => {
const tags = operation.getTags();
if (setIfMissing && !tags.length) {
allTags.add(path);
return;
}
tags.forEach((tag) => {
allTags.add(tag.name);
});
});
});
Object.entries(this.getWebhooks()).forEach(([path, webhooks]) => {
Object.values(webhooks).forEach((webhook) => {
const tags = webhook.getTags();
if (setIfMissing && !tags.length) {
allTags.add(path);
return;
}
tags.forEach((tag) => {
allTags.add(tag.name);
});
});
});
const endpointTags = [];
const tagsArray = [];
if (disableTagSorting) {
return Array.from(allTags);
}
Array.from(allTags).forEach((tag) => {
if (oasTags.includes(tag)) {
tagsArray.push(tag);
} else {
endpointTags.push(tag);
}
});
let sortedTags = tagsArray.sort((a, b) => {
return oasTags.indexOf(a) - oasTags.indexOf(b);
});
sortedTags = sortedTags.concat(endpointTags);
return sortedTags;
}
/**
* Determine if a given a custom specification extension exists within the API definition.
*
* @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specification-extensions}
* @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#specification-extensions}
* @param extension Specification extension to lookup.
*/
hasExtension(extension) {
return _chunkXS7VDTTTcjs.hasRootExtension.call(void 0, extension, this.api);
}
/**
* Retrieve a custom specification extension off of the API definition.
*
* @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specification-extensions}
* @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#specification-extensions}
* @param extension Specification extension to lookup.
*/
getExtension(extension, operation) {
return _chunkXS7VDTTTcjs.getExtension.call(void 0, extension, this.api, operation);
}
/**
* Determine if a given OpenAPI custom extension is valid or not.
*
* @see {@link https://docs.readme.com/docs/openapi-extensions}
* @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specification-extensions}
* @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#specification-extensions}
* @param extension Specification extension to validate.
* @throws
*/
validateExtension(extension) {
if (this.hasExtension("x-readme")) {
const data = this.getExtension("x-readme");
if (typeof data !== "object" || Array.isArray(data) || data === null) {
throw new TypeError('"x-readme" must be of type "Object"');
}
if (extension in data) {
if ([_chunkXS7VDTTTcjs.CODE_SAMPLES, _chunkXS7VDTTTcjs.HEADERS, _chunkXS7VDTTTcjs.PARAMETER_ORDERING, _chunkXS7VDTTTcjs.SAMPLES_LANGUAGES].includes(extension)) {
if (!Array.isArray(data[extension])) {
throw new TypeError(`"x-readme.${extension}" must be of type "Array"`);
}
if (extension === _chunkXS7VDTTTcjs.PARAMETER_ORDERING) {
_chunkXS7VDTTTcjs.validateParameterOrdering.call(void 0, data[extension], `x-readme.${extension}`);
}
} else if (extension === _chunkXS7VDTTTcjs.OAUTH_OPTIONS) {
if (typeof data[extension] !== "object") {
throw new TypeError(`"x-readme.${extension}" must be of type "Object"`);
}
} else if (typeof data[extension] !== "boolean") {
throw new TypeError(`"x-readme.${extension}" must be of type "Boolean"`);
}
}
}
if (this.hasExtension(`x-${extension}`)) {
const data = this.getExtension(`x-${extension}`);
if ([_chunkXS7VDTTTcjs.CODE_SAMPLES, _chunkXS7VDTTTcjs.HEADERS, _chunkXS7VDTTTcjs.PARAMETER_ORDERING, _chunkXS7VDTTTcjs.SAMPLES_LANGUAGES].includes(extension)) {
if (!Array.isArray(data)) {
throw new TypeError(`"x-${extension}" must be of type "Array"`);
}
if (extension === _chunkXS7VDTTTcjs.PARAMETER_ORDERING) {
_chunkXS7VDTTTcjs.validateParameterOrdering.call(void 0, data, `x-${extension}`);
}
} else if (extension === _chunkXS7VDTTTcjs.OAUTH_OPTIONS) {
if (typeof data !== "object") {
throw new TypeError(`"x-${extension}" must be of type "Object"`);
}
} else if (typeof data !== "boolean") {
throw new TypeError(`"x-${extension}" must be of type "Boolean"`);
}
}
}
/**
* Validate all of our custom or known OpenAPI extensions, throwing exceptions when necessary.
*
* @see {@link https://docs.readme.com/docs/openapi-extensions}
* @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specification-extensions}
* @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#specification-extensions}
*/
validateExtensions() {
Object.keys(_chunkXS7VDTTTcjs.extensionDefaults).forEach((extension) => {
this.validateExtension(extension);
});
}
/**
* Retrieve any circular `$ref` pointers that maybe present within the API definition.
*
* This method requires that you first dereference the definition.
*
* @see Oas.dereference
*/
getCircularReferences() {
if (!this.dereferencing.complete) {
throw new Error("#dereference() must be called first in order for this method to obtain circular references.");
}
return this.dereferencing.circularRefs;
}
/**
* Dereference the current OAS definition so it can be parsed free of worries of `$ref` schemas
* and circular structures.
*
*/
async dereference(opts = { preserveRefAsJSONSchemaTitle: false }) {
if (this.dereferencing.complete) {
return new Promise((resolve) => {
resolve(true);
});
}
if (this.dereferencing.processing) {
return new Promise((resolve, reject) => {
this.promises.push({ resolve, reject });
});
}
this.dereferencing.processing = true;
const { api, promises } = this;
if (api.components && api.components.schemas && typeof api.components.schemas === "object") {
Object.keys(api.components.schemas).forEach((schemaName) => {
if (_chunkQ2TBKI3Ocjs.isPrimitive.call(void 0, api.components.schemas[schemaName]) || Array.isArray(api.components.schemas[schemaName]) || api.components.schemas[schemaName] === null) {
return;
}
if (opts.preserveRefAsJSONSchemaTitle) {
api.components.schemas[schemaName].title = schemaName;
}
api.components.schemas[schemaName]["x-readme-ref-name"] = schemaName;
});
}
const circularRefs = /* @__PURE__ */ new Set();
return _openapiparser.dereference.call(void 0, api, {
resolve: {
// We shouldn't be resolving external pointers at this point so just ignore them.
external: false
},
dereference: {
// If circular `$refs` are ignored they'll remain in the OAS as `$ref: String`, otherwise
// `$ref‘ just won't exist. This allows us to do easy circular reference detection.
circular: "ignore",
onCircular: (path) => {
circularRefs.add(`#${path.split("#")[1]}`);
}
}
}).then((dereferenced) => {
this.api = dereferenced;
this.promises = promises;
this.dereferencing = {
processing: false,
complete: true,
// We need to convert our `Set` to an array in order to match the typings.
circularRefs: [...circularRefs]
};
if (opts.cb) {
opts.cb();
}
}).then(() => {
return this.promises.map((deferred) => deferred.resolve());
});
}
};
exports.Oas = Oas;
//# sourceMappingURL=chunk-7XLR2GY5.cjs.map