diff --git a/.changeset/honest-ants-appear.md b/.changeset/honest-ants-appear.md new file mode 100644 index 000000000..71eadafb1 --- /dev/null +++ b/.changeset/honest-ants-appear.md @@ -0,0 +1,7 @@ +--- +'@gitbook/openapi-parser': patch +'@gitbook/react-openapi': patch +'gitbook': patch +--- + +Improve the OpenAPI package API diff --git a/packages/gitbook/src/components/DocumentView/OpenAPI/OpenAPI.tsx b/packages/gitbook/src/components/DocumentView/OpenAPI/OpenAPI.tsx index 82534316d..e92d680c8 100644 --- a/packages/gitbook/src/components/DocumentView/OpenAPI/OpenAPI.tsx +++ b/packages/gitbook/src/components/DocumentView/OpenAPI/OpenAPI.tsx @@ -33,7 +33,7 @@ async function OpenAPIBody(props: BlockProps) { return (

- Error with {error.url}: {error.message} + Error with {error.rootURL}: {error.message}

); diff --git a/packages/gitbook/src/lib/openapi.ts b/packages/gitbook/src/lib/openapi.ts index 4ae19e9bc..591e5d77f 100644 --- a/packages/gitbook/src/lib/openapi.ts +++ b/packages/gitbook/src/lib/openapi.ts @@ -1,10 +1,6 @@ import { ContentRef, DocumentBlockOpenAPI } from '@gitbook/api'; import { parseOpenAPI, OpenAPIParseError, traverse } from '@gitbook/openapi-parser'; -import { - OpenAPIOperationData, - fetchOpenAPIOperation, - OpenAPIFetcher, -} from '@gitbook/react-openapi'; +import { type OpenAPIOperationData, resolveOpenAPIOperation } from '@gitbook/react-openapi'; import { cache, noCacheFetchOptions, CacheFunctionOptions } from '@/lib/cache'; @@ -27,14 +23,11 @@ export async function fetchOpenAPIBlock( } try { - const data = await fetchOpenAPIOperation( - { - url: resolved.href, - path: block.data.path, - method: block.data.method, - }, - fetcher, - ); + const filesystem = await fetchFilesystem(resolved.href); + const data = await resolveOpenAPIOperation(filesystem, { + path: block.data.path, + method: block.data.method, + }); return { data, specUrl: resolved.href }; } catch (error) { @@ -46,50 +39,44 @@ export async function fetchOpenAPIBlock( } } -const fetcher: OpenAPIFetcher = { - fetch: cache({ - name: 'openapi.fetch.v5', - get: async (url: string, options: CacheFunctionOptions) => { - // Wrap the raw string to prevent invalid URLs from being passed to fetch. - // This can happen if the URL has whitespace, which is currently handled differently by Cloudflare's implementation of fetch: - // https://github.com/cloudflare/workerd/issues/1957 - const response = await fetch(new URL(url), { - ...noCacheFetchOptions, - signal: options.signal, - }); +const fetchFilesystem = cache({ + name: 'openapi.fetch.v5', + get: async (url: string, options: CacheFunctionOptions) => { + // Wrap the raw string to prevent invalid URLs from being passed to fetch. + // This can happen if the URL has whitespace, which is currently handled differently by Cloudflare's implementation of fetch: + // https://github.com/cloudflare/workerd/issues/1957 + const response = await fetch(new URL(url), { + ...noCacheFetchOptions, + signal: options.signal, + }); - if (!response.ok) { - throw new Error( - `Failed to fetch OpenAPI file: ${response.status} ${response.statusText}`, - ); - } + if (!response.ok) { + throw new Error( + `Failed to fetch OpenAPI file: ${response.status} ${response.statusText}`, + ); + } - const text = await response.text(); - const filesystem = await parseOpenAPI({ url, value: text }); - const cache: Map> = new Map(); - const transformedFs = await traverse(filesystem, async (node) => { - if ( - 'description' in node && - typeof node.description === 'string' && - node.description - ) { - if (cache.has(node.description)) { - node['x-description-html'] = await cache.get(node.description); - } else { - const promise = parseMarkdown(node.description); - cache.set(node.description, promise); - node['x-description-html'] = await promise; - } + const text = await response.text(); + const filesystem = await parseOpenAPI({ value: text, rootURL: url }); + const cache: Map> = new Map(); + const transformedFs = await traverse(filesystem, async (node) => { + if ('description' in node && typeof node.description === 'string' && node.description) { + if (cache.has(node.description)) { + node['x-description-html'] = await cache.get(node.description); + } else { + const promise = parseMarkdown(node.description); + cache.set(node.description, promise); + node['x-description-html'] = await promise; } - return node; - }); - return { - // Cache for 4 hours - ttl: 24 * 60 * 60, - // Revalidate every 2 hours - revalidateBefore: 22 * 60 * 60, - data: transformedFs, - }; - }, - }), -}; + } + return node; + }); + return { + // Cache for 4 hours + ttl: 24 * 60 * 60, + // Revalidate every 2 hours + revalidateBefore: 22 * 60 * 60, + data: transformedFs, + }; + }, +}); diff --git a/packages/openapi-parser/src/error.ts b/packages/openapi-parser/src/error.ts index 3bcb109d4..d26db1492 100644 --- a/packages/openapi-parser/src/error.ts +++ b/packages/openapi-parser/src/error.ts @@ -1,14 +1,28 @@ +type OpenAPIParseErrorCode = + | 'invalid' + | 'parse-v2-in-v3' + | 'v2-conversion' + | 'dereference' + | 'yaml-parse'; + /** * Error thrown when the OpenAPI document is invalid. */ export class OpenAPIParseError extends Error { public override name = 'OpenAPIParseError'; + public code: OpenAPIParseErrorCode; + public rootURL: string | null; constructor( message: string, - public readonly url: string, - public readonly code?: 'invalid-spec' | 'v2-spec' | 'failed-dereference', + options: { + code: OpenAPIParseErrorCode; + rootURL?: string | null; + cause?: Error; + }, ) { - super(message); + super(message, { cause: options.cause }); + this.code = options.code; + this.rootURL = options.rootURL ?? null; } } diff --git a/packages/openapi-parser/src/filesystem.test.ts b/packages/openapi-parser/src/filesystem.test.ts index 32560f7f8..c9b80370e 100644 --- a/packages/openapi-parser/src/filesystem.test.ts +++ b/packages/openapi-parser/src/filesystem.test.ts @@ -34,7 +34,7 @@ describe('#createFileSystem', () => { const url = new URL('/root/spec.yaml', server.url).href; const filesystem = await createFileSystem({ value: url, - baseUrl: url, + rootURL: url, }); expect(filesystem).toHaveLength(4); expect(filesystem[0]!.isEntrypoint).toBe(true); diff --git a/packages/openapi-parser/src/filesystem.ts b/packages/openapi-parser/src/filesystem.ts index a651f33df..6ba1e5339 100644 --- a/packages/openapi-parser/src/filesystem.ts +++ b/packages/openapi-parser/src/filesystem.ts @@ -1,5 +1,5 @@ import { type AnyApiDefinitionFormat, load } from '@scalar/openapi-parser'; -import { fetchUrls } from './scalar-plugins/fetchURLs'; +import { fetchURLs } from './scalar-plugins/fetchURLs'; import type { Filesystem } from './types'; /** @@ -7,11 +7,18 @@ import type { Filesystem } from './types'; * Fetches all the URLs specified in references and builds a filesystem. */ export async function createFileSystem(input: { + /** + * The OpenAPI document to create the filesystem from. + */ value: AnyApiDefinitionFormat; - baseUrl: string; + /** + * The root URL of the specified OpenAPI document. + * Used to resolve relative URLs. + */ + rootURL: string | null; }): Promise { const { filesystem } = await load(input.value, { - plugins: [fetchUrls({ baseUrl: input.baseUrl })], + plugins: [fetchURLs({ rootURL: input.rootURL })], }); return filesystem; } diff --git a/packages/openapi-parser/src/parse.test.ts b/packages/openapi-parser/src/parse.test.ts index 32dc98302..aad0b4b40 100644 --- a/packages/openapi-parser/src/parse.test.ts +++ b/packages/openapi-parser/src/parse.test.ts @@ -7,7 +7,7 @@ describe('#parseOpenAPI', () => { it('parses an OpenAPI document', async () => { const schema = await parseOpenAPI({ value: spec, - url: 'https://example.com', + rootURL: null, }); // Ensure the structure returned is not recursive (not dereferenced). JSON.stringify(schema); diff --git a/packages/openapi-parser/src/parse.ts b/packages/openapi-parser/src/parse.ts index bd73a19b3..9c102d457 100644 --- a/packages/openapi-parser/src/parse.ts +++ b/packages/openapi-parser/src/parse.ts @@ -1,3 +1,4 @@ +import { AnyApiDefinitionFormat } from '@scalar/openapi-parser'; import { OpenAPIParseError } from './error'; import { convertOpenAPIV2ToOpenAPIV3 } from './v2'; import { parseOpenAPIV3 } from './v3'; @@ -7,11 +8,20 @@ import { parseOpenAPIV3 } from './v3'; * It will also convert Swagger 2.0 to OpenAPI 3.0. * It can throw an `OpenAPIParseError` if the document is invalid. */ -export async function parseOpenAPI(input: { value: string; url: string }) { +export async function parseOpenAPI(input: { + /** + * The API definition to parse. + */ + value: AnyApiDefinitionFormat; + /** + * The root URL of the specified OpenAPI document. + */ + rootURL: string | null; +}) { try { return await parseOpenAPIV3(input); } catch (error) { - if (error instanceof OpenAPIParseError && error.code === 'v2-spec') { + if (error instanceof OpenAPIParseError && error.code === 'parse-v2-in-v3') { return convertOpenAPIV2ToOpenAPIV3(input); } throw error; diff --git a/packages/openapi-parser/src/scalar-plugins/fetchURLs.ts b/packages/openapi-parser/src/scalar-plugins/fetchURLs.ts index 92edf725e..df820196e 100644 --- a/packages/openapi-parser/src/scalar-plugins/fetchURLs.ts +++ b/packages/openapi-parser/src/scalar-plugins/fetchURLs.ts @@ -4,11 +4,11 @@ export const fetchUrlsDefaultConfiguration = { limit: 40, }; -export const fetchUrls: (customConfiguration: { +export const fetchURLs: (customConfiguration: { /** - * Base URL to use for relative paths. + * Root URL to resolve relative URLs. */ - baseUrl: string; + rootURL: string | null; /** * Limit the number of requests. Set to `false` to disable the limit. @@ -53,7 +53,7 @@ export const fetchUrls: (customConfiguration: { try { numberOfRequests++; - const url = getReferenceUrl(value, configuration.baseUrl); + const url = getReferenceUrl({ value, rootURL: configuration.rootURL }); const response = await fetch(url); return await response.text(); } catch (error: any) { @@ -66,6 +66,7 @@ export const fetchUrls: (customConfiguration: { /** * Check if a path is relative. + * Meaning it does not start with http://, https://, www., data:, or #/. */ function isRelativePath(path: string): boolean { // Exclude external URLs @@ -76,9 +77,13 @@ function isRelativePath(path: string): boolean { /** * Get the reference URL. */ -function getReferenceUrl(value: string, baseUrl: string) { +function getReferenceUrl(input: { value: string; rootURL: string | null }) { + const { value, rootURL } = input; if (isRelativePath(value)) { - return new URL(value, baseUrl).href; + if (!rootURL) { + throw new Error(`[fetchUrls] Cannot resolve relative path without rootURL (${value})`); + } + return new URL(value, rootURL).href; } return value; diff --git a/packages/openapi-parser/src/traverse.test.ts b/packages/openapi-parser/src/traverse.test.ts index 77e2a843d..733db014f 100644 --- a/packages/openapi-parser/src/traverse.test.ts +++ b/packages/openapi-parser/src/traverse.test.ts @@ -35,7 +35,7 @@ describe('#traverse', () => { it('traverses a complete filesystem', async () => { const filesystem = await createFileSystem({ value: JSON.parse(recursiveSpec), - baseUrl: 'https://example.com', + rootURL: 'https://example.com', }); const transformedFilesystem = await traverse(filesystem, async (node) => { diff --git a/packages/openapi-parser/src/v2.test.ts b/packages/openapi-parser/src/v2.test.ts index 5588f1e52..519d8134c 100644 --- a/packages/openapi-parser/src/v2.test.ts +++ b/packages/openapi-parser/src/v2.test.ts @@ -7,7 +7,7 @@ describe('#convertOpenAPIV2ToOpenAPIV3', () => { it('converts an OpenAPIV2 in V3', async () => { const schema = await convertOpenAPIV2ToOpenAPIV3({ value: specV2, - url: 'https://example.com', + rootURL: null, }); // Ensure the structure returned is not recursive (not dereferenced). JSON.stringify(schema); diff --git a/packages/openapi-parser/src/v2.ts b/packages/openapi-parser/src/v2.ts index 8bfe69483..aa0227624 100644 --- a/packages/openapi-parser/src/v2.ts +++ b/packages/openapi-parser/src/v2.ts @@ -10,12 +10,18 @@ import type { Filesystem, OpenAPIV3xDocument } from './types'; * Convert a Swagger 2.0 schema to an OpenAPI 3.0 schema. */ export async function convertOpenAPIV2ToOpenAPIV3(input: { + /** + * The API definition to parse. + */ value: AnyApiDefinitionFormat; - url: string; + /** + * The root URL of the specified OpenAPI document. + */ + rootURL: string | null; }): Promise> { - const { value, url } = input; + const { value, rootURL } = input; // In this case we want the raw value to be able to convert it. - const schema = typeof value === 'string' ? rawParseOpenAPI({ value, url }) : value; + const schema = typeof value === 'string' ? rawParseOpenAPI({ value, rootURL }) : value; try { // @ts-expect-error Types are incompatible between the two libraries const convertResult = (await swagger2openapi.convertObj(schema, { @@ -29,13 +35,14 @@ export async function convertOpenAPIV2ToOpenAPIV3(input: { patch: true, })) as ConvertOutputOptions; - return parseOpenAPIV3({ url, value: convertResult.openapi }); + return parseOpenAPIV3({ rootURL, value: convertResult.openapi }); } catch (error) { if (error instanceof Error && error.name === 'S2OError') { - throw new OpenAPIParseError( - 'Failed to convert Swagger 2.0 to OpenAPI 3.0: ' + (error as Error).message, - url, - ); + throw new OpenAPIParseError('Failed to convert Swagger 2.0 to OpenAPI 3.0', { + code: 'v2-conversion', + rootURL, + cause: error, + }); } else { throw error; } @@ -46,8 +53,8 @@ export async function convertOpenAPIV2ToOpenAPIV3(input: { * Parse the config file from a raw string. * Useful to get the raw object from a file. */ -function rawParseOpenAPI(input: { value: string; url: string }): unknown { - const { value, url } = input; +function rawParseOpenAPI(input: { value: string; rootURL: string | null }): unknown { + const { value, rootURL } = input; // Try with JSON try { @@ -58,7 +65,10 @@ function rawParseOpenAPI(input: { value: string; url: string }): unknown { return YAML.parse(value); } catch (yamlError) { if (yamlError instanceof Error && yamlError.name.startsWith('YAML')) { - throw new OpenAPIParseError('Failed to parse YAML: ' + yamlError.message, url); + throw new OpenAPIParseError('Failed to parse YAML: ' + yamlError.message, { + code: 'yaml-parse', + rootURL, + }); } throw yamlError; } diff --git a/packages/openapi-parser/src/v3.ts b/packages/openapi-parser/src/v3.ts index 08be7f40a..557c2350c 100644 --- a/packages/openapi-parser/src/v3.ts +++ b/packages/openapi-parser/src/v3.ts @@ -9,22 +9,34 @@ import type { Filesystem, OpenAPIV3xDocument } from './types'; * It can throw an `OpenAPIFetchError` if the document is invalid. */ export async function parseOpenAPIV3(input: { + /** + * The API definition to parse. + */ value: AnyApiDefinitionFormat; - url: string; + /** + * The root URL of the specified OpenAPI document. + */ + rootURL: string | null; }): Promise> { - const { value, url } = input; + const { value, rootURL } = input; const result = await validate(value); // Spec is invalid, we stop here. if (!result.specification) { - throw new OpenAPIParseError('Invalid OpenAPI document', url, 'invalid-spec'); + throw new OpenAPIParseError('Invalid OpenAPI document', { + code: 'invalid', + rootURL, + }); } if (result.version === '2.0') { - throw new OpenAPIParseError('Only OpenAPI v3 is supported', url, 'v2-spec'); + throw new OpenAPIParseError('Only OpenAPI v3 is supported', { + code: 'parse-v2-in-v3', + rootURL, + }); } - const filesystem = await createFileSystem({ value: result.specification, baseUrl: url }); + const filesystem = await createFileSystem({ value: result.specification, rootURL }); return filesystem; } diff --git a/packages/openapi-parser/tsconfig.tsbuildinfo b/packages/openapi-parser/tsconfig.tsbuildinfo new file mode 100644 index 000000000..0eadf27d6 --- /dev/null +++ b/packages/openapi-parser/tsconfig.tsbuildinfo @@ -0,0 +1 @@ +{"fileNames":["../../node_modules/typescript/lib/lib.es5.d.ts","../../node_modules/typescript/lib/lib.es2015.d.ts","../../node_modules/typescript/lib/lib.es2016.d.ts","../../node_modules/typescript/lib/lib.es2017.d.ts","../../node_modules/typescript/lib/lib.es2018.d.ts","../../node_modules/typescript/lib/lib.es2019.d.ts","../../node_modules/typescript/lib/lib.es2020.d.ts","../../node_modules/typescript/lib/lib.es2021.d.ts","../../node_modules/typescript/lib/lib.es2022.d.ts","../../node_modules/typescript/lib/lib.es2023.d.ts","../../node_modules/typescript/lib/lib.esnext.d.ts","../../node_modules/typescript/lib/lib.dom.d.ts","../../node_modules/typescript/lib/lib.es2015.core.d.ts","../../node_modules/typescript/lib/lib.es2015.collection.d.ts","../../node_modules/typescript/lib/lib.es2015.generator.d.ts","../../node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../node_modules/typescript/lib/lib.es2015.promise.d.ts","../../node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../node_modules/typescript/lib/lib.es2016.intl.d.ts","../../node_modules/typescript/lib/lib.es2017.date.d.ts","../../node_modules/typescript/lib/lib.es2017.object.d.ts","../../node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.es2017.string.d.ts","../../node_modules/typescript/lib/lib.es2017.intl.d.ts","../../node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../node_modules/typescript/lib/lib.es2018.intl.d.ts","../../node_modules/typescript/lib/lib.es2018.promise.d.ts","../../node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../node_modules/typescript/lib/lib.es2019.array.d.ts","../../node_modules/typescript/lib/lib.es2019.object.d.ts","../../node_modules/typescript/lib/lib.es2019.string.d.ts","../../node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../node_modules/typescript/lib/lib.es2019.intl.d.ts","../../node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../node_modules/typescript/lib/lib.es2020.date.d.ts","../../node_modules/typescript/lib/lib.es2020.promise.d.ts","../../node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.es2020.string.d.ts","../../node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../node_modules/typescript/lib/lib.es2020.intl.d.ts","../../node_modules/typescript/lib/lib.es2020.number.d.ts","../../node_modules/typescript/lib/lib.es2021.promise.d.ts","../../node_modules/typescript/lib/lib.es2021.string.d.ts","../../node_modules/typescript/lib/lib.es2021.weakref.d.ts","../../node_modules/typescript/lib/lib.es2021.intl.d.ts","../../node_modules/typescript/lib/lib.es2022.array.d.ts","../../node_modules/typescript/lib/lib.es2022.error.d.ts","../../node_modules/typescript/lib/lib.es2022.intl.d.ts","../../node_modules/typescript/lib/lib.es2022.object.d.ts","../../node_modules/typescript/lib/lib.es2022.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.es2022.string.d.ts","../../node_modules/typescript/lib/lib.es2022.regexp.d.ts","../../node_modules/typescript/lib/lib.es2023.array.d.ts","../../node_modules/typescript/lib/lib.es2023.collection.d.ts","../../node_modules/typescript/lib/lib.es2023.intl.d.ts","../../node_modules/typescript/lib/lib.esnext.array.d.ts","../../node_modules/typescript/lib/lib.esnext.collection.d.ts","../../node_modules/typescript/lib/lib.esnext.intl.d.ts","../../node_modules/typescript/lib/lib.esnext.disposable.d.ts","../../node_modules/typescript/lib/lib.esnext.string.d.ts","../../node_modules/typescript/lib/lib.esnext.promise.d.ts","../../node_modules/typescript/lib/lib.esnext.decorators.d.ts","../../node_modules/typescript/lib/lib.esnext.object.d.ts","../../node_modules/typescript/lib/lib.esnext.regexp.d.ts","../../node_modules/typescript/lib/lib.esnext.iterator.d.ts","../../node_modules/typescript/lib/lib.decorators.d.ts","../../node_modules/typescript/lib/lib.decorators.legacy.d.ts","./src/error.ts","../../node_modules/@scalar/openapi-parser/dist/configuration/index.d.ts","../../node_modules/fast-uri/types/index.d.ts","../../node_modules/ajv/dist/compile/codegen/code.d.ts","../../node_modules/ajv/dist/compile/codegen/scope.d.ts","../../node_modules/ajv/dist/compile/codegen/index.d.ts","../../node_modules/ajv/dist/compile/rules.d.ts","../../node_modules/ajv/dist/compile/util.d.ts","../../node_modules/ajv/dist/compile/validate/subschema.d.ts","../../node_modules/ajv/dist/compile/errors.d.ts","../../node_modules/ajv/dist/compile/validate/index.d.ts","../../node_modules/ajv/dist/compile/validate/datatype.d.ts","../../node_modules/ajv/dist/vocabularies/applicator/additionalitems.d.ts","../../node_modules/ajv/dist/vocabularies/applicator/items2020.d.ts","../../node_modules/ajv/dist/vocabularies/applicator/contains.d.ts","../../node_modules/ajv/dist/vocabularies/applicator/dependencies.d.ts","../../node_modules/ajv/dist/vocabularies/applicator/propertynames.d.ts","../../node_modules/ajv/dist/vocabularies/applicator/additionalproperties.d.ts","../../node_modules/ajv/dist/vocabularies/applicator/not.d.ts","../../node_modules/ajv/dist/vocabularies/applicator/anyof.d.ts","../../node_modules/ajv/dist/vocabularies/applicator/oneof.d.ts","../../node_modules/ajv/dist/vocabularies/applicator/if.d.ts","../../node_modules/ajv/dist/vocabularies/applicator/index.d.ts","../../node_modules/ajv/dist/vocabularies/validation/limitnumber.d.ts","../../node_modules/ajv/dist/vocabularies/validation/multipleof.d.ts","../../node_modules/ajv/dist/vocabularies/validation/pattern.d.ts","../../node_modules/ajv/dist/vocabularies/validation/required.d.ts","../../node_modules/ajv/dist/vocabularies/validation/uniqueitems.d.ts","../../node_modules/ajv/dist/vocabularies/validation/const.d.ts","../../node_modules/ajv/dist/vocabularies/validation/enum.d.ts","../../node_modules/ajv/dist/vocabularies/validation/index.d.ts","../../node_modules/ajv/dist/vocabularies/format/format.d.ts","../../node_modules/ajv/dist/vocabularies/unevaluated/unevaluatedproperties.d.ts","../../node_modules/ajv/dist/vocabularies/unevaluated/unevaluateditems.d.ts","../../node_modules/ajv/dist/vocabularies/validation/dependentrequired.d.ts","../../node_modules/ajv/dist/vocabularies/discriminator/types.d.ts","../../node_modules/ajv/dist/vocabularies/discriminator/index.d.ts","../../node_modules/ajv/dist/vocabularies/errors.d.ts","../../node_modules/ajv/dist/types/json-schema.d.ts","../../node_modules/ajv/dist/runtime/validation_error.d.ts","../../node_modules/ajv/dist/compile/ref_error.d.ts","../../node_modules/ajv/dist/ajv.d.ts","../../node_modules/ajv/dist/compile/resolve.d.ts","../../node_modules/ajv/dist/compile/index.d.ts","../../node_modules/ajv/dist/types/index.d.ts","../../node_modules/ajv/dist/types/jtd-schema.d.ts","../../node_modules/ajv/dist/core.d.ts","../../node_modules/ajv-draft-04/dist/index.d.ts","../../node_modules/ajv/dist/2020.d.ts","../../node_modules/@scalar/openapi-types/dist/openapi-types.d.ts","../../node_modules/@scalar/openapi-types/dist/index.d.ts","../../node_modules/@scalar/openapi-parser/dist/types/index.d.ts","../../node_modules/@scalar/openapi-parser/dist/lib/validator/validator.d.ts","../../node_modules/@scalar/openapi-parser/dist/utils/resolvereferences.d.ts","../../node_modules/@scalar/openapi-parser/dist/lib/validator/index.d.ts","../../node_modules/@scalar/openapi-parser/dist/lib/index.d.ts","../../node_modules/@scalar/openapi-parser/dist/utils/dereference.d.ts","../../node_modules/@scalar/types/dist/utils/utility-types.d.ts","../../node_modules/@scalar/types/dist/utils/index.d.ts","../../node_modules/@scalar/openapi-parser/dist/utils/details.d.ts","../../node_modules/@scalar/openapi-parser/dist/utils/escapejsonpointer.d.ts","../../node_modules/@scalar/openapi-parser/dist/utils/filter.d.ts","../../node_modules/@scalar/openapi-parser/dist/utils/getentrypoint.d.ts","../../node_modules/@scalar/openapi-parser/dist/utils/getlistofreferences.d.ts","../../node_modules/@scalar/openapi-parser/dist/utils/getsegmentsfrompath.d.ts","../../node_modules/@scalar/openapi-parser/dist/utils/isfilesystem.d.ts","../../node_modules/@scalar/openapi-parser/dist/utils/isjson.d.ts","../../node_modules/@scalar/openapi-parser/dist/utils/isobject.d.ts","../../node_modules/@scalar/openapi-parser/dist/utils/isyaml.d.ts","../../node_modules/@scalar/openapi-parser/dist/utils/load/load.d.ts","../../node_modules/@scalar/openapi-parser/dist/utils/load/index.d.ts","../../node_modules/@scalar/openapi-parser/dist/utils/normalize.d.ts","../../node_modules/@scalar/openapi-parser/dist/utils/openapi/openapi.d.ts","../../node_modules/@scalar/openapi-parser/dist/utils/openapi/index.d.ts","../../node_modules/@scalar/openapi-parser/dist/utils/tojson.d.ts","../../node_modules/@scalar/openapi-parser/dist/utils/toyaml.d.ts","../../node_modules/@scalar/openapi-parser/dist/utils/transformerrors.d.ts","../../node_modules/@scalar/openapi-parser/dist/utils/traverse.d.ts","../../node_modules/@scalar/openapi-parser/dist/utils/unescapejsonpointer.d.ts","../../node_modules/@scalar/openapi-parser/dist/utils/upgrade.d.ts","../../node_modules/@scalar/openapi-parser/dist/utils/upgradefromthreetothreeone.d.ts","../../node_modules/@scalar/openapi-parser/dist/utils/upgradefromtwotothree.d.ts","../../node_modules/@scalar/openapi-parser/dist/utils/validate.d.ts","../../node_modules/@scalar/openapi-parser/dist/utils/transform/utils/addlatestopenapiversion.d.ts","../../node_modules/@scalar/openapi-parser/dist/utils/transform/utils/addinfoobject.d.ts","../../node_modules/@scalar/openapi-parser/dist/utils/transform/sanitize.d.ts","../../node_modules/@scalar/openapi-parser/dist/utils/transform/index.d.ts","../../node_modules/@scalar/openapi-parser/dist/utils/index.d.ts","../../node_modules/@scalar/openapi-parser/dist/index.d.ts","./src/scalar-plugins/fetchurls.ts","./src/types.ts","./src/filesystem.ts","./src/filesystem.test.ts","../../node_modules/yaml/types.d.ts","../../node_modules/yaml/util.d.ts","../../node_modules/yaml/parse-cst.d.ts","../../node_modules/yaml/index.d.ts","../../node_modules/@types/node/ts5.6/globals.typedarray.d.ts","../../node_modules/@types/node/ts5.6/buffer.buffer.d.ts","../../node_modules/@types/node/assert.d.ts","../../node_modules/@types/node/assert/strict.d.ts","../../node_modules/undici-types/header.d.ts","../../node_modules/undici-types/readable.d.ts","../../node_modules/undici-types/file.d.ts","../../node_modules/undici-types/fetch.d.ts","../../node_modules/undici-types/formdata.d.ts","../../node_modules/undici-types/connector.d.ts","../../node_modules/undici-types/client.d.ts","../../node_modules/undici-types/errors.d.ts","../../node_modules/undici-types/dispatcher.d.ts","../../node_modules/undici-types/global-dispatcher.d.ts","../../node_modules/undici-types/global-origin.d.ts","../../node_modules/undici-types/pool-stats.d.ts","../../node_modules/undici-types/pool.d.ts","../../node_modules/undici-types/handlers.d.ts","../../node_modules/undici-types/balanced-pool.d.ts","../../node_modules/undici-types/agent.d.ts","../../node_modules/undici-types/mock-interceptor.d.ts","../../node_modules/undici-types/mock-agent.d.ts","../../node_modules/undici-types/mock-client.d.ts","../../node_modules/undici-types/mock-pool.d.ts","../../node_modules/undici-types/mock-errors.d.ts","../../node_modules/undici-types/proxy-agent.d.ts","../../node_modules/undici-types/env-http-proxy-agent.d.ts","../../node_modules/undici-types/retry-handler.d.ts","../../node_modules/undici-types/retry-agent.d.ts","../../node_modules/undici-types/api.d.ts","../../node_modules/undici-types/interceptors.d.ts","../../node_modules/undici-types/util.d.ts","../../node_modules/undici-types/cookies.d.ts","../../node_modules/undici-types/patch.d.ts","../../node_modules/undici-types/websocket.d.ts","../../node_modules/undici-types/eventsource.d.ts","../../node_modules/undici-types/filereader.d.ts","../../node_modules/undici-types/diagnostics-channel.d.ts","../../node_modules/undici-types/content-type.d.ts","../../node_modules/undici-types/cache.d.ts","../../node_modules/undici-types/index.d.ts","../../node_modules/@types/node/globals.d.ts","../../node_modules/@types/node/async_hooks.d.ts","../../node_modules/@types/node/buffer.d.ts","../../node_modules/@types/node/child_process.d.ts","../../node_modules/@types/node/cluster.d.ts","../../node_modules/@types/node/console.d.ts","../../node_modules/@types/node/constants.d.ts","../../node_modules/@types/node/crypto.d.ts","../../node_modules/@types/node/dgram.d.ts","../../node_modules/@types/node/diagnostics_channel.d.ts","../../node_modules/@types/node/dns.d.ts","../../node_modules/@types/node/dns/promises.d.ts","../../node_modules/@types/node/domain.d.ts","../../node_modules/@types/node/dom-events.d.ts","../../node_modules/@types/node/events.d.ts","../../node_modules/@types/node/fs.d.ts","../../node_modules/@types/node/fs/promises.d.ts","../../node_modules/@types/node/http.d.ts","../../node_modules/@types/node/http2.d.ts","../../node_modules/@types/node/https.d.ts","../../node_modules/@types/node/inspector.d.ts","../../node_modules/@types/node/module.d.ts","../../node_modules/@types/node/net.d.ts","../../node_modules/@types/node/os.d.ts","../../node_modules/@types/node/path.d.ts","../../node_modules/@types/node/perf_hooks.d.ts","../../node_modules/@types/node/process.d.ts","../../node_modules/@types/node/punycode.d.ts","../../node_modules/@types/node/querystring.d.ts","../../node_modules/@types/node/readline.d.ts","../../node_modules/@types/node/readline/promises.d.ts","../../node_modules/@types/node/repl.d.ts","../../node_modules/@types/node/sea.d.ts","../../node_modules/@types/node/stream.d.ts","../../node_modules/@types/node/stream/promises.d.ts","../../node_modules/@types/node/stream/consumers.d.ts","../../node_modules/@types/node/stream/web.d.ts","../../node_modules/@types/node/string_decoder.d.ts","../../node_modules/@types/node/test.d.ts","../../node_modules/@types/node/timers.d.ts","../../node_modules/@types/node/timers/promises.d.ts","../../node_modules/@types/node/tls.d.ts","../../node_modules/@types/node/trace_events.d.ts","../../node_modules/@types/node/tty.d.ts","../../node_modules/@types/node/url.d.ts","../../node_modules/@types/node/util.d.ts","../../node_modules/@types/node/v8.d.ts","../../node_modules/@types/node/vm.d.ts","../../node_modules/@types/node/wasi.d.ts","../../node_modules/@types/node/worker_threads.d.ts","../../node_modules/@types/node/zlib.d.ts","../../node_modules/@types/node/globals.global.d.ts","../../node_modules/@types/node/ts5.6/index.d.ts","../../node_modules/openapi-types/dist/index.d.ts","../../node_modules/@types/swagger2openapi/index.d.ts","./src/v3.ts","./src/v2.ts","./src/parse.ts","./src/traverse.ts","./src/index.ts","./src/parse.test.ts","./src/traverse.test.ts","./src/v2.test.ts","../../node_modules/@types/ws/index.d.ts","../../node_modules/@types/ws/index.d.mts","../../node_modules/bun-types/fetch.d.ts","../../node_modules/bun-types/globals.d.ts","../../node_modules/bun-types/bun.d.ts","../../node_modules/bun-types/overrides.d.ts","../../node_modules/bun-types/ffi.d.ts","../../node_modules/bun-types/test.d.ts","../../node_modules/bun-types/html-rewriter.d.ts","../../node_modules/bun-types/jsc.d.ts","../../node_modules/bun-types/sqlite.d.ts","../../node_modules/bun-types/wasm.d.ts","../../node_modules/bun-types/deprecated.d.ts","../../node_modules/bun-types/index.d.ts"],"fileIdsList":[[172,214,279,287],[75,125,129,161,172,214,279,287],[128,172,214,279,287],[126,127,172,214,279,287],[75,121,122,125,172,214,279,287],[75,124,172,214,279,287],[125,127,172,214,279,287],[125,132,172,214,279,287],[125,172,214,279,287],[127,130,133,134,135,136,137,138,139,140,141,142,143,144,145,147,148,149,150,151,152,153,154,155,156,160,172,214,279,287],[143,172,214,279,287],[146,172,214,279,287],[125,144,161,162,172,214,279,287],[124,125,172,214,279,287],[159,172,214,279,287],[124,125,157,158,172,214,279,287],[124,132,172,214,279,287],[123,172,214,279,287],[131,172,214,279,287],[172,173,214,279,287],[172,213,214,279,287],[172,214,219,248,279,287],[172,214,215,220,226,227,234,245,256,279,287],[172,214,215,216,226,234,279,287],[172,214,217,257,279,287],[172,214,218,219,227,235,279,287],[172,214,219,245,253,279,287],[172,214,220,222,226,234,279,287],[172,213,214,221,279,287],[172,214,222,223,279,287],[172,214,226,279,287],[172,214,224,226,279,287],[172,213,214,226,279,287],[172,214,226,227,228,245,256,279,287],[172,214,226,227,228,241,245,248,279,280,287],[172,211,214,261,279,287],[172,214,222,226,229,234,245,256,279,287],[172,214,226,227,229,230,234,245,253,256,279,287],[172,214,229,231,245,253,256,279,287],[172,214,226,232,279,287],[172,214,233,256,261,279,287],[172,214,222,226,234,245,279,287],[172,214,235,279,287],[172,214,236,279,287],[172,213,214,237,279,287],[172,173,174,213,214,215,216,217,218,219,220,221,222,223,224,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,279,280,287],[172,214,239,279,287],[172,214,240,279,287],[172,214,226,241,242,279,287],[172,214,241,243,257,259,279,287],[172,214,226,245,246,247,248,279,287],[172,214,245,247,279,287],[172,214,245,246,279,287],[172,214,248,279,287],[172,214,249,279,287],[172,173,214,245,279,287],[172,214,226,251,252,279,287],[172,214,251,252,279,287],[172,214,219,234,245,253,279,280,287],[172,214,254,279,287],[214,279,287],[171,172,173,174,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,279,287],[172,214,234,255,279,287],[172,214,229,240,256,279,287],[172,214,219,257,279,287],[172,214,245,258,279,287],[172,214,233,259,279,287],[172,214,260,279,287],[172,214,219,226,228,237,245,256,259,261,279,287],[172,214,245,262,279,287],[172,214,245,264,265,279,287],[172,214,275,279,287],[172,214,226,229,231,245,253,256,262,264,279,280,287],[118,120,172,214,279,287],[79,80,84,111,112,113,114,117,118,120,172,214,279,287],[77,78,172,214,279,287],[77,172,214,279,287],[79,118,172,214,279,287],[79,80,116,118,120,172,214,279,287],[118,172,214,279,287],[76,115,118,172,214,279,287],[79,80,117,118,172,214,279,287],[79,80,82,83,117,118,172,214,279,287],[79,80,81,117,118,172,214,279,287],[79,80,84,111,112,113,114,117,118,119,172,214,279,287],[76,79,80,84,117,120,172,214,279,287],[84,118,172,214,279,287],[86,87,88,89,90,91,92,93,94,95,118,172,214,279,287],[109,118,172,214,279,287],[85,96,104,105,106,107,108,110,172,214,279,287],[89,118,172,214,279,287],[97,98,99,100,101,102,103,118,172,214,279,287],[172,214,219,253,257,280,287],[172,214,279],[172,211,214,279,287],[172,211,214,219,237,245,248,257,261,276,277,279,287],[172,214,264,275,277,278,279,280,281,282,283,284,285,286,287],[172,214,228,253,279,287],[172,214,279,282,287],[172,183,187,214,256,279,287],[172,183,214,245,256,279,287],[172,178,214,279,287],[172,180,183,214,253,256,279,280,287],[172,214,234,253,279,280,287],[172,214,264,279,287],[172,178,214,264,279,287],[172,180,183,214,234,256,279,287],[172,175,176,179,182,214,226,245,256,279,287],[172,183,190,214,279,287],[172,175,181,214,279,287],[172,183,204,205,214,279,287],[172,179,183,214,248,256,264,279,287],[172,204,214,264,279,287],[172,177,178,214,264,279,287],[172,183,214,279,287],[172,177,178,179,180,181,182,183,184,185,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,205,206,207,208,209,210,214,279,287],[172,183,198,214,279,287],[172,183,190,191,214,279,287],[172,181,183,191,192,214,279,287],[172,182,214,279,287],[172,175,178,183,214,279,287],[172,183,187,191,192,214,279,287],[172,187,214,279,287],[172,181,183,186,214,256,279,287],[172,175,180,183,190,214,279,287],[172,214,245,279,287],[172,178,183,204,214,261,264,279,287],[167,168,169,172,214,279,287],[168,172,214,279,287],[168,169,170,172,214,279,287],[167,169,170,172,214,279,287],[165,172,214,279,282,287],[162,163,164,172,214,279,287],[74,124,162,164,172,214,269,270,279,287],[172,214,269,279,282,287],[74,162,172,214,267,268,279,287],[162,172,214,279,287],[162,165,172,214,270,279,282,287],[124,162,172,214,279,287],[172,214,268,279,282,287],[74,162,164,170,172,214,266,267,279,287],[74,162,164,165,172,214,279,287]],"fileInfos":[{"version":"44e584d4f6444f58791784f1d530875970993129442a847597db702a073ca68c","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"9a68c0c07ae2fa71b44384a839b7b8d81662a236d4b9ac30916718f7510b1b2d","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","impliedFormat":1},{"version":"feecb1be483ed332fad555aff858affd90a48ab19ba7272ee084704eb7167569","impliedFormat":1},{"version":"5514e54f17d6d74ecefedc73c504eadffdeda79c7ea205cf9febead32d45c4bc","impliedFormat":1},{"version":"27bdc30a0e32783366a5abeda841bc22757c1797de8681bbe81fbc735eeb1c10","impliedFormat":1},{"version":"abee51ebffafd50c07d76be5848a34abfe4d791b5745ef1e5648718722fab924","impliedFormat":1},{"version":"9e8ca8ed051c2697578c023d9c29d6df689a083561feba5c14aedee895853999","affectsGlobalScope":true,"impliedFormat":1},{"version":"6920e1448680767498a0b77c6a00a8e77d14d62c3da8967b171f1ddffa3c18e4","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"45d8ccb3dfd57355eb29749919142d4321a0aa4df6acdfc54e30433d7176600a","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"93495ff27b8746f55d19fcbcdbaccc99fd95f19d057aed1bd2c0cafe1335fbf0","affectsGlobalScope":true,"impliedFormat":1},{"version":"6fc23bb8c3965964be8c597310a2878b53a0306edb71d4b5a4dfe760186bcc01","affectsGlobalScope":true,"impliedFormat":1},{"version":"ea011c76963fb15ef1cdd7ce6a6808b46322c527de2077b6cfdf23ae6f5f9ec7","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"4738f2420687fd85629c9efb470793bb753709c2379e5f85bc1815d875ceadcd","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"9fc46429fbe091ac5ad2608c657201eb68b6f1b8341bd6d670047d32ed0a88fa","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"1a94697425a99354df73d9c8291e2ecd4dddd370aed4023c2d6dee6cccb32666","affectsGlobalScope":true,"impliedFormat":1},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true,"impliedFormat":1},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true,"impliedFormat":1},{"version":"bf14a426dbbf1022d11bd08d6b8e709a2e9d246f0c6c1032f3b2edb9a902adbe","affectsGlobalScope":true,"impliedFormat":1},{"version":"e3f9fc0ec0b96a9e642f11eda09c0be83a61c7b336977f8b9fdb1e9788e925fe","affectsGlobalScope":true,"impliedFormat":1},{"version":"59fb2c069260b4ba00b5643b907ef5d5341b167e7d1dbf58dfd895658bda2867","affectsGlobalScope":true,"impliedFormat":1},{"version":"479553e3779be7d4f68e9f40cdb82d038e5ef7592010100410723ceced22a0f7","affectsGlobalScope":true,"impliedFormat":1},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true,"impliedFormat":1},{"version":"af3dd424cf267428f30ccfc376f47a2c0114546b55c44d8c0f1d57d841e28d74","affectsGlobalScope":true,"impliedFormat":1},{"version":"995c005ab91a498455ea8dfb63aa9f83fa2ea793c3d8aa344be4a1678d06d399","affectsGlobalScope":true,"impliedFormat":1},{"version":"d3d7b04b45033f57351c8434f60b6be1ea71a2dfec2d0a0c3c83badbb0e3e693","affectsGlobalScope":true,"impliedFormat":1},{"version":"956d27abdea9652e8368ce029bb1e0b9174e9678a273529f426df4b3d90abd60","affectsGlobalScope":true,"impliedFormat":1},{"version":"4fa6ed14e98aa80b91f61b9805c653ee82af3502dc21c9da5268d3857772ca05","affectsGlobalScope":true,"impliedFormat":1},{"version":"e6633e05da3ff36e6da2ec170d0d03ccf33de50ca4dc6f5aeecb572cedd162fb","affectsGlobalScope":true,"impliedFormat":1},{"version":"15c1c3d7b2e46e0025417ed6d5f03f419e57e6751f87925ca19dc88297053fe6","affectsGlobalScope":true,"impliedFormat":1},{"version":"8444af78980e3b20b49324f4a16ba35024fef3ee069a0eb67616ea6ca821c47a","affectsGlobalScope":true,"impliedFormat":1},{"version":"caccc56c72713969e1cfe5c3d44e5bab151544d9d2b373d7dbe5a1e4166652be","affectsGlobalScope":true,"impliedFormat":1},{"version":"3287d9d085fbd618c3971944b65b4be57859f5415f495b33a6adc994edd2f004","affectsGlobalScope":true,"impliedFormat":1},{"version":"b4b67b1a91182421f5df999988c690f14d813b9850b40acd06ed44691f6727ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"9d540251809289a05349b70ab5f4b7b99f922af66ab3c39ba56a475dcf95d5ff","affectsGlobalScope":true,"impliedFormat":1},{"version":"436aaf437562f276ec2ddbee2f2cdedac7664c1e4c1d2c36839ddd582eeb3d0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e3c06ea092138bf9fa5e874a1fdbc9d54805d074bee1de31b99a11e2fec239d","affectsGlobalScope":true,"impliedFormat":1},{"version":"0b11f3ca66aa33124202c80b70cd203219c3d4460cfc165e0707aa9ec710fc53","affectsGlobalScope":true,"impliedFormat":1},{"version":"6a3f5a0129cc80cf439ab71164334d649b47059a4f5afca90282362407d0c87f","affectsGlobalScope":true,"impliedFormat":1},{"version":"811c71eee4aa0ac5f7adf713323a5c41b0cf6c4e17367a34fbce379e12bbf0a4","affectsGlobalScope":true,"impliedFormat":1},{"version":"51ad4c928303041605b4d7ae32e0c1ee387d43a24cd6f1ebf4a2699e1076d4fa","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a6282c8827e4b9a95f4bf4f5c205673ada31b982f50572d27103df8ceb8013c","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac77cb3e8c6d3565793eb90a8373ee8033146315a3dbead3bde8db5eaf5e5ec6","affectsGlobalScope":true,"impliedFormat":1},{"version":"d4b1d2c51d058fc21ec2629fff7a76249dec2e36e12960ea056e3ef89174080f","affectsGlobalScope":true,"impliedFormat":1},{"version":"2fef54945a13095fdb9b84f705f2b5994597640c46afeb2ce78352fab4cb3279","affectsGlobalScope":true,"impliedFormat":1},{"version":"56e4ed5aab5f5920980066a9409bfaf53e6d21d3f8d020c17e4de584d29600ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"61d6a2092f48af66dbfb220e31eea8b10bc02b6932d6e529005fd2d7b3281290","affectsGlobalScope":true,"impliedFormat":1},{"version":"33358442698bb565130f52ba79bfd3d4d484ac85fe33f3cb1759c54d18201393","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},"4bf6bc2bbef3898f6279d67cff5fd8c9ab567ff5486ac01f6aed2a015a0f8f9d",{"version":"a02b7bf8bd796decb97c3ceb336de2a80d1b332a0edfb30663d3cab629526925","impliedFormat":99},{"version":"ee660a1f2acd3d7fc7b28df06c4e2125229666c4d72e5455ae3841bfd222f684","impliedFormat":1},{"version":"2d225e7bda2871c066a7079c88174340950fb604f624f2586d3ea27bb9e5f4ff","impliedFormat":1},{"version":"6a785f84e63234035e511817dd48ada756d984dd8f9344e56eb8b2bdcd8fd001","impliedFormat":1},{"version":"c1422d016f7df2ccd3594c06f2923199acd09898f2c42f50ea8159f1f856f618","impliedFormat":1},{"version":"2973b1b7857ca144251375b97f98474e9847a890331e27132d5a8b3aea9350a8","impliedFormat":1},{"version":"0eb6152d37c84d6119295493dfcc20c331c6fda1304a513d159cdaa599dcb78b","impliedFormat":1},{"version":"237df26f8c326ca00cd9d2deb40214a079749062156386b6d75bdcecc6988a6b","impliedFormat":1},{"version":"cd44995ee13d5d23df17a10213fed7b483fabfd5ea08f267ab52c07ce0b6b4da","impliedFormat":1},{"version":"58ce1486f851942bd2d3056b399079bc9cb978ec933fe9833ea417e33eab676e","impliedFormat":1},{"version":"7557d4d7f19f94341f4413575a3453ba7f6039c9591015bcf4282a8e75414043","impliedFormat":1},{"version":"a3b2cc16f3ce2d882eca44e1066f57a24751545f2a5e4a153d4de31b4cac9bb5","impliedFormat":1},{"version":"ac2b3b377d3068bfb6e1cb8889c99098f2c875955e2325315991882a74d92cc8","impliedFormat":1},{"version":"8deb39d89095469957f73bd194d11f01d9894b8c1f1e27fbf3f6e8122576b336","impliedFormat":1},{"version":"a38a9c41f433b608a0d37e645a31eecf7233ef3d3fffeb626988d3219f80e32f","impliedFormat":1},{"version":"8e1428dcba6a984489863935049893631170a37f9584c0479f06e1a5b1f04332","impliedFormat":1},{"version":"1fce9ecb87a2d3898941c60df617e52e50fb0c03c9b7b2ba8381972448327285","impliedFormat":1},{"version":"5ef0597b8238443908b2c4bf69149ed3894ac0ddd0515ac583d38c7595b151f1","impliedFormat":1},{"version":"ac52b775a80badff5f4ac329c5725a26bd5aaadd57afa7ad9e98b4844767312a","impliedFormat":1},{"version":"6ae5b4a63010c82bf2522b4ecfc29ffe6a8b0c5eea6b2b35120077e9ac54d7a1","impliedFormat":1},{"version":"dd7109c49f416f218915921d44f0f28975df78e04e437c62e1e1eb3be5e18a35","impliedFormat":1},{"version":"eee181112e420b345fc78422a6cc32385ede3d27e2eaf8b8c4ad8b2c29e3e52e","impliedFormat":1},{"version":"25fbe57c8ee3079e2201fe580578fab4f3a78881c98865b7c96233af00bf9624","impliedFormat":1},{"version":"62cc8477858487b4c4de7d7ae5e745a8ce0015c1592f398b63ee05d6e64ca295","impliedFormat":1},{"version":"cc2a9ec3cb10e4c0b8738b02c31798fad312d21ef20b6a2f5be1d077e9f5409d","impliedFormat":1},{"version":"4b4fadcda7d34034737598c07e2dca5d7e1e633cb3ba8dd4d2e6a7782b30b296","impliedFormat":1},{"version":"360fdc8829a51c5428636f1f83e7db36fef6c5a15ed4411b582d00a1c2bd6e97","impliedFormat":1},{"version":"1cf0d15e6ab1ecabbf329b906ae8543e6b8955133b7f6655f04d433e3a0597ab","impliedFormat":1},{"version":"7c9f98fe812643141502b30fb2b5ec56d16aaf94f98580276ae37b7924dd44a4","impliedFormat":1},{"version":"b3547893f24f59d0a644c52f55901b15a3fa1a115bc5ea9a582911469b9348b7","impliedFormat":1},{"version":"596e5b88b6ca8399076afcc22af6e6e0c4700c7cd1f420a78d637c3fb44a885e","impliedFormat":1},{"version":"adddf736e08132c7059ee572b128fdacb1c2650ace80d0f582e93d097ed4fbaf","impliedFormat":1},{"version":"d4cad9dc13e9c5348637170ddd5d95f7ed5fdfc856ddca40234fa55518bc99a6","impliedFormat":1},{"version":"d70675ba7ba7d02e52b7070a369957a70827e4b2bca2c1680c38a832e87b61fd","impliedFormat":1},{"version":"3be71f4ce8988a01e2f5368bdd58e1d60236baf511e4510ee9291c7b3729a27e","impliedFormat":1},{"version":"423d2ccc38e369a7527988d682fafc40267bcd6688a7473e59c5eea20a29b64f","impliedFormat":1},{"version":"2f9fde0868ed030277c678b435f63fcf03d27c04301299580a4017963cc04ce6","impliedFormat":1},{"version":"feeb73d48cc41c6dd23d17473521b0af877751504c30c18dc84267c8eeea429a","impliedFormat":1},{"version":"cde493e09daad4bb29922fe633f760be9f0e8e2f39cdca999cce3b8690b5e13a","impliedFormat":1},{"version":"3d7f9eb12aface876f7b535cc89dcd416daf77f0b3573333f16ec0a70bcf902a","impliedFormat":1},{"version":"41b8775befd7ded7245a627e9f4de6110236688ce4c124d2d40c37bc1a3bfe05","impliedFormat":1},{"version":"e0205f04611bea8b5b82168065b8ef1476a8e96236201494eb8c785331c43118","impliedFormat":1},{"version":"62d26d8ba4fa15ab425c1b57a050ed76c5b0ecbffaa53f182110aa3a02405a07","impliedFormat":1},{"version":"9941cbf7ca695e95d588f5f1692ab040b078d44a95d231fa9a8f828186b7b77d","impliedFormat":1},{"version":"25f1159094dc0bf3a71313a74e0885426af21c5d6564a254004f2cadf9c5b052","impliedFormat":1},{"version":"b83139ae818dd20f365118f9999335ca4cd84ae518348619adc5728e7e0372d5","impliedFormat":1},{"version":"706fddf475c77bd45be0aa3537b913951c527be3f9f483f4dcdb13e7315f8955","impliedFormat":1},{"version":"66a5ace456d19768103c1da9df2abafa9cb2e78ff61c938746527ec2524e5d11","impliedFormat":1},{"version":"d953569ea82df74ed44a74075eec4af36eb1c9c0da81fa9fd02980b7f5278c94","impliedFormat":99},{"version":"775024159878d7c12458e7bb6be8237e480af873e6fcc70b09efe513e4691656","impliedFormat":99},{"version":"4513917dc834000605eb803c20dd2194ae11423d5348f764c67371b487c121c7","affectsGlobalScope":true,"impliedFormat":99},{"version":"15020d1a60272a3e78d5642405264acb8fe44a5db775ea23bb96837b9d81b6e2","impliedFormat":99},{"version":"31932f570554e871e9ece18ef4ac65bb49252bc17a7e3ac701fa5b1e1bec766d","impliedFormat":99},{"version":"c3a70b2eefb56edb51966e05aefdc44a23e1acd0d361443eb6361df2a0da70be","impliedFormat":99},{"version":"3a4835c3496bf5bba45bc4cfe28627719289bdf154945886c922923eec789a89","impliedFormat":99},{"version":"0ef1c6a6f70688ac6a0c804d93e33d2913021573447f859dda41ab5e4b21cccb","impliedFormat":99},{"version":"5809248d74849a8ba790cc6706bba3f37feb633f82b305367f79678cd57c537d","impliedFormat":99},{"version":"95eb415bfd87e75f1a7b2ad3a1a173bb72d2150eeaec31f99e67d301561b0870","impliedFormat":99},{"version":"af15168980d9dc77620a50a74dd53a1a2f9a63ddbe7b596ee452ed1b874fb782","impliedFormat":99},{"version":"4c259bd2c34c5cd88c74484297a395d3deda93d31d833b839bb2a4024d76ffcb","impliedFormat":99},{"version":"f61c5576fda9fc9ad35f916b0f0d7d3d95c8630d011abd66abf623ac166b7bb3","impliedFormat":99},{"version":"f8c19dbe4f36d185c28b4f6ba4e3bdb2935a43c548e3fab23c86daacf509ad45","impliedFormat":99},{"version":"f796e58920ca2266c1148551e4ec91776e468866569a4fc0d15002d66ffa0c9c","impliedFormat":99},{"version":"f4cfe6ee5a8920f86432b79cd87a03f5f6188a5cd6bdabc96e64d650a90cef0b","impliedFormat":99},{"version":"e1626fcfe55dd458933391911b9af9a33fae01d308a1f075036f94d3f884d5ae","impliedFormat":99},{"version":"7ee6c5e82e333cb97acb44a6679e886e5a72b5249d7c4ed9697d9721a92469d4","impliedFormat":99},{"version":"84c2960f37d57cd119405d21d4984abfc2cdbffc36fff2a2015fb761ca103311","impliedFormat":99},{"version":"8008df553e1ac6d74912108aefb7d411493b5f8887d30cf7aecc49770e2104d8","impliedFormat":99},{"version":"2ece4f48aa86dfaa637c78e1b8efcfa0eb34b046490f36e371c18610c5b97f5e","impliedFormat":99},{"version":"2bf883ccdc41b83798ef412dfaffa6f108e3d3d6892189608665b715b6048c7e","impliedFormat":99},{"version":"bfb4ff5c77ef15cf53b79f62c60adb4caa753d746a248e6f111b9b63e7a26693","impliedFormat":99},{"version":"e66b031d9ca94495651720dcd9176618924cd08d4d5bb662fbf78acdabd227a2","impliedFormat":99},{"version":"222f4417612b71463bd1f2a1d75a01030ef10eed52d0e2716b121315012f985c","impliedFormat":99},{"version":"b3742d792537f016da2f8fd7a76696ddcd1a3cb4ef8e081d44fa1daae52b1aac","impliedFormat":99},{"version":"05a58ec10c4e3a3590873ab03039978f476b78f287a25bc921ec568151e71f0a","impliedFormat":99},{"version":"f6619d55bf3130e3834c3b3c7491fd8921417dcbd3d96bbdd2f5f96d7b6fd97f","impliedFormat":99},{"version":"b8de26fc63ab774d900959fe78c9dac56da58b96f11ceca9960bcb90120e8e6b","impliedFormat":99},{"version":"e0759ab5886e2613dfb547ade1f98c3d1ffd4bef981d9113255f2903373e1b7a","impliedFormat":99},{"version":"286f4285c3a87f20734279fc5f60b514505ed349999dc498afca0eea77ecf82e","impliedFormat":99},{"version":"e8c8e8929eee724be5d4a21512aa4dfbe4cf652214a9b9fff5c1dfa670398a6d","impliedFormat":99},{"version":"7e88648aa018e35a5efa92171d3251fa5cb690696f87d831723d047b24a4c1fa","impliedFormat":99},{"version":"a9a39f15ecdc5f09974901332674ae807da376558112d28755c7caff72a51c8b","impliedFormat":99},{"version":"76f809aca03b25f81adab0012908b8e800f75ba4bc19dff8edd90dbe4dc05960","impliedFormat":99},{"version":"e07405f56bbe97799f28fd03234746872e9cc1034d960ddab464ca2addafe97a","impliedFormat":99},{"version":"fcf1731e58d749cd5602ef695de1ccef29488d0e1692a1b7ef575e1c7b05a256","impliedFormat":99},{"version":"fb30274713f66bbd3d2b7f13207a5797baf49dc3f8a4800d3b313317eaeaf5a7","impliedFormat":99},{"version":"98fe6880dd0279fe6cb2aabf8a4222754b736bc9a18137fe8580b4f197d5ace3","impliedFormat":99},{"version":"6583c05fd8315e2fc2154b3a5d6d0f0a41190543f8172857aacbd6763f4a83a8","impliedFormat":99},"2191d369fe1167bea0d4dfb8f54b1e9364c25b8b5c85db569db478b005683894","184a1d9f4b6e25ab506c177c7b5f6d1e3e8575f1f3972bc835d033cc382541dc","2f6281c107e5f76dc4987ede0736a7ba7091a0b92084830dc3dc26ebffe933f3","2f462aa75b0b0fc0dfa395de381f9cfbf4afa66690399f5e929f0fe62316087d",{"version":"c3a8e97bce8330542633139409885c529c46ff9bcf8fda0dc28a7c8fdda41e24","impliedFormat":1},{"version":"4d99772cffbb09646a934867ca42d77337dc3cfd591b648b78fc0b6e09e2d88d","impliedFormat":1},{"version":"b10413a27f0fa373997ebf631da8af501d6b36bdfe627475b3ec5ef98e9bc80d","impliedFormat":1},{"version":"b3280c01b5c948bb27e60a94076b4ed23e34db4044d687ef628a5831c09c9811","impliedFormat":1},{"version":"613b21ccdf3be6329d56e6caa13b258c842edf8377be7bc9f014ed14cdcfc308","affectsGlobalScope":true,"impliedFormat":1},{"version":"2d1319e6b5d0efd8c5eae07eb864a00102151e8b9afddd2d45db52e9aae002c4","affectsGlobalScope":true,"impliedFormat":1},{"version":"2db0dd3aaa2ed285950273ce96ae8a450b45423aa9da2d10e194570f1233fa6b","impliedFormat":1},{"version":"7394959e5a741b185456e1ef5d64599c36c60a323207450991e7a42e08911419","impliedFormat":1},{"version":"5929864ce17fba74232584d90cb721a89b7ad277220627cc97054ba15a98ea8f","impliedFormat":1},{"version":"24bd580b5743dc56402c440dc7f9a4f5d592ad7a419f25414d37a7bfe11e342b","impliedFormat":1},{"version":"25c8056edf4314820382a5fdb4bb7816999acdcb929c8f75e3f39473b87e85bc","impliedFormat":1},{"version":"c464d66b20788266e5353b48dc4aa6bc0dc4a707276df1e7152ab0c9ae21fad8","impliedFormat":1},{"version":"78d0d27c130d35c60b5e5566c9f1e5be77caf39804636bc1a40133919a949f21","impliedFormat":1},{"version":"c6fd2c5a395f2432786c9cb8deb870b9b0e8ff7e22c029954fabdd692bff6195","impliedFormat":1},{"version":"1d6e127068ea8e104a912e42fc0a110e2aa5a66a356a917a163e8cf9a65e4a75","impliedFormat":1},{"version":"5ded6427296cdf3b9542de4471d2aa8d3983671d4cac0f4bf9c637208d1ced43","impliedFormat":1},{"version":"6bdc71028db658243775263e93a7db2fd2abfce3ca569c3cca5aee6ed5eb186d","impliedFormat":1},{"version":"cadc8aced301244057c4e7e73fbcae534b0f5b12a37b150d80e5a45aa4bebcbd","impliedFormat":1},{"version":"385aab901643aa54e1c36f5ef3107913b10d1b5bb8cbcd933d4263b80a0d7f20","impliedFormat":1},{"version":"9670d44354bab9d9982eca21945686b5c24a3f893db73c0dae0fd74217a4c219","impliedFormat":1},{"version":"0b8a9268adaf4da35e7fa830c8981cfa22adbbe5b3f6f5ab91f6658899e657a7","impliedFormat":1},{"version":"11396ed8a44c02ab9798b7dca436009f866e8dae3c9c25e8c1fbc396880bf1bb","impliedFormat":1},{"version":"ba7bc87d01492633cb5a0e5da8a4a42a1c86270e7b3d2dea5d156828a84e4882","impliedFormat":1},{"version":"4893a895ea92c85345017a04ed427cbd6a1710453338df26881a6019432febdd","impliedFormat":1},{"version":"c21dc52e277bcfc75fac0436ccb75c204f9e1b3fa5e12729670910639f27343e","impliedFormat":1},{"version":"13f6f39e12b1518c6650bbb220c8985999020fe0f21d818e28f512b7771d00f9","impliedFormat":1},{"version":"9b5369969f6e7175740bf51223112ff209f94ba43ecd3bb09eefff9fd675624a","impliedFormat":1},{"version":"4fe9e626e7164748e8769bbf74b538e09607f07ed17c2f20af8d680ee49fc1da","impliedFormat":1},{"version":"24515859bc0b836719105bb6cc3d68255042a9f02a6022b3187948b204946bd2","impliedFormat":1},{"version":"ea0148f897b45a76544ae179784c95af1bd6721b8610af9ffa467a518a086a43","impliedFormat":1},{"version":"24c6a117721e606c9984335f71711877293a9651e44f59f3d21c1ea0856f9cc9","impliedFormat":1},{"version":"dd3273ead9fbde62a72949c97dbec2247ea08e0c6952e701a483d74ef92d6a17","impliedFormat":1},{"version":"405822be75ad3e4d162e07439bac80c6bcc6dbae1929e179cf467ec0b9ee4e2e","impliedFormat":1},{"version":"0db18c6e78ea846316c012478888f33c11ffadab9efd1cc8bcc12daded7a60b6","impliedFormat":1},{"version":"4d2b0eb911816f66abe4970898f97a2cfc902bcd743cbfa5017fad79f7ef90d8","impliedFormat":1},{"version":"bd0532fd6556073727d28da0edfd1736417a3f9f394877b6d5ef6ad88fba1d1a","impliedFormat":1},{"version":"89167d696a849fce5ca508032aabfe901c0868f833a8625d5a9c6e861ef935d2","impliedFormat":1},{"version":"e53a3c2a9f624d90f24bf4588aacd223e7bec1b9d0d479b68d2f4a9e6011147f","impliedFormat":1},{"version":"24b8685c62562f5d98615c5a0c1d05f297cf5065f15246edfe99e81ec4c0e011","impliedFormat":1},{"version":"93507c745e8f29090efb99399c3f77bec07db17acd75634249dc92f961573387","impliedFormat":1},{"version":"339dc5265ee5ed92e536a93a04c4ebbc2128f45eeec6ed29f379e0085283542c","impliedFormat":1},{"version":"4732aec92b20fb28c5fe9ad99521fb59974289ed1e45aecb282616202184064f","impliedFormat":1},{"version":"2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","impliedFormat":1},{"version":"c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","impliedFormat":1},{"version":"bf67d53d168abc1298888693338cb82854bdb2e69ef83f8a0092093c2d562107","impliedFormat":1},{"version":"4eedea23b8a843ec0fd51a384fb6b9fe1bc89198f713d0465c2c8392a9d51271","affectsGlobalScope":true,"impliedFormat":1},{"version":"3d77c73be94570813f8cadd1f05ebc3dc5e2e4fdefe4d340ca20cd018724ee36","impliedFormat":1},{"version":"d674383111e06b6741c4ad2db962131b5b0fa4d0294b998566c635e86195a453","affectsGlobalScope":true,"impliedFormat":1},{"version":"f3e58c4c18a031cbb17abec7a4ad0bd5ae9fc70c1f4ba1e7fb921ad87c504aca","impliedFormat":1},{"version":"a3e8bafb2af8e850c644f4be7f5156cf7d23b7bfdc3b786bd4d10ed40329649c","impliedFormat":1},{"version":"35ec8b6760fd7138bbf5809b84551e31028fb2ba7b6dc91d95d098bf212ca8b4","affectsGlobalScope":true,"impliedFormat":1},{"version":"a40826e8476694e90da94aa008283a7de50d1dafd37beada623863f1901cb7fb","impliedFormat":1},{"version":"c521f961c1606c94dc831992e659f426b6def6e2e6e327ee25d3c642eb393f95","affectsGlobalScope":true,"impliedFormat":1},{"version":"b0c0d1d13be149f790a75b381b413490f98558649428bb916fd2d71a3f47a134","impliedFormat":1},{"version":"3c884d9d9ec454bdf0d5a0b8465bf8297d2caa4d853851d92cc417ac6f30b969","impliedFormat":1},{"version":"5a369483ac4cfbdf0331c248deeb36140e6907db5e1daed241546b4a2055f82c","impliedFormat":1},{"version":"e8f5b5cc36615c17d330eaf8eebbc0d6bdd942c25991f96ef122f246f4ff722f","impliedFormat":1},{"version":"f0bd7e6d931657b59605c44112eaf8b980ba7f957a5051ed21cb93d978cf2f45","impliedFormat":1},{"version":"ee1ee365d88c4c6c0c0a5a5701d66ebc27ccd0bcfcfaa482c6e2e7fe7b98edf7","affectsGlobalScope":true,"impliedFormat":1},{"version":"f0de0233242682db9ac13efa0ddbb456a41abe6f291211b40ba3aa766b03e9b3","affectsGlobalScope":true,"impliedFormat":1},{"version":"596572d40c1f13d8b57920d6d1a77c5ec6fe4952dc157f416f04a801cd3e2678","impliedFormat":1},{"version":"ad23fd126ff06e72728dd7bfc84326a8ca8cec2b9d2dac0193d42a777df0e7d8","impliedFormat":1},{"version":"a55fd4d49da86d2cc19de575beb1515184e55f5f3165e1482ff02fd99f900b5c","impliedFormat":1},{"version":"93bd413918fa921c8729cef45302b24d8b6c7855d72d5bf82d3972595ae8dcbf","impliedFormat":1},{"version":"4ff41188773cbf465807dd2f7059c7494cbee5115608efc297383832a1150c43","impliedFormat":1},{"version":"dccdf1677e531e33f8ac961a68bc537418c9a414797c1ea7e91307501cdc3f5e","impliedFormat":1},{"version":"7edec695cdb707c7146ac34c44ca364469c7ea504344b3206c686e79f61b61a2","affectsGlobalScope":true,"impliedFormat":1},{"version":"d206b4baf4ddcc15d9d69a9a2f4999a72a2c6adeaa8af20fa7a9960816287555","impliedFormat":1},{"version":"93f437e1398a4f06a984f441f7fa7a9f0535c04399619b5c22e0b87bdee182cb","impliedFormat":1},{"version":"d1b1295af3667779be43eb6d4fbaa342e656aa2c4b77a4ad3cf42ec55baeea00","impliedFormat":1},{"version":"70731d10d5311bd4cf710ef7f6539b62660f4b0bfdbb3f9fbe1d25fe6366a7fa","affectsGlobalScope":true,"impliedFormat":1},{"version":"a20f1e119615bf7632729fd89b6c0b5ffdc2df3b512d6304146294528e3ebe19","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e043a1bc8fbf2a255bccf9bf27e0f1caf916c3b0518ea34aa72357c0afd42ec","impliedFormat":1},{"version":"137c2894e8f3e9672d401cc0a305dc7b1db7c69511cf6d3970fb53302f9eae09","impliedFormat":1},{"version":"dd9492e12a57068f08d70cb5eb5ceb39fa5bcf23be01af574270aeee95b982af","impliedFormat":1},{"version":"e432b0e3761ca9ba734bdd41e19a75fec1454ca8e9769bfdf8b31011854cf06a","impliedFormat":1},{"version":"f9d9d753d430ed050dc1bf2667a1bab711ccbb1c1507183d794cc195a5b085cc","impliedFormat":1},{"version":"9eece5e586312581ccd106d4853e861aaaa1a39f8e3ea672b8c3847eedd12f6e","impliedFormat":1},{"version":"78955c9259da94920609be3e589fc9253268b3fffa822e1e31d28ee2ce0b8a74","impliedFormat":1},{"version":"269929a24b2816343a178008ac9ae9248304d92a8ba8e233055e0ed6dbe6ef71","impliedFormat":1},{"version":"93452d394fdd1dc551ec62f5042366f011a00d342d36d50793b3529bfc9bd633","impliedFormat":1},{"version":"73aa178e8fb1449ef3666093d8dca25f96302a80ee45f8ff027df8e4792bf9fd","affectsGlobalScope":true,"impliedFormat":1},{"version":"1851a3b4db78664f83901bb9cac9e45e03a37bb5933cc5bf37e10bb7e91ab4eb","impliedFormat":1},{"version":"fdedf82878e4c744bc2a1c1e802ae407d63474da51f14a54babe039018e53d8f","affectsGlobalScope":true,"impliedFormat":1},{"version":"08353b04a3501d84fc8d7b49de99f6c1cc26026e6d9d697a18315f3bfe92ed03","affectsGlobalScope":true,"impliedFormat":1},{"version":"578d8bb6dcb2a1c03c4c3f8eb71abc9677e1a5c788b7f24848e3138ce17f3400","impliedFormat":1},{"version":"4f029899f9bae07e225c43aef893590541b2b43267383bf5e32e3a884d219ed5","impliedFormat":1},{"version":"ae56f65caf3be91108707bd8dfbccc2a57a91feb5daabf7165a06a945545ed26","impliedFormat":1},{"version":"a136d5de521da20f31631a0a96bf712370779d1c05b7015d7019a9b2a0446ca9","impliedFormat":1},{"version":"710ad93f8de29dc15e5892aa735e72348b62f40a6d1220f2849837d332f92885","affectsGlobalScope":true,"impliedFormat":1},{"version":"1f1da5d682cdb628890e4a8578fb9e8ab332e6a1a4b3a13fce08b7b4d45d192a","affectsGlobalScope":true,"impliedFormat":1},{"version":"efeedd8bbc5c0d53e760d8b120a010470722982e6ae14de8d1bcff66ebc2ae71","impliedFormat":1},{"version":"b718a94332858862943630649a310d6f8e9a09f86ae7215d8554e75bbbfd7817","impliedFormat":1},{"version":"d91a7d8b5655c42986f1bdfe2105c4408f472831c8f20cf11a8c3345b6b56c8c","impliedFormat":1},{"version":"616075a6ac578cf5a013ee12964188b4412823796ce0b202c6f1d2e4ca8480d7","affectsGlobalScope":true,"impliedFormat":1},{"version":"e8a979b8af001c9fc2e774e7809d233c8ca955a28756f52ee5dee88ccb0611d2","impliedFormat":1},{"version":"ab9b9a36e5284fd8d3bf2f7d5fcbc60052f25f27e4d20954782099282c60d23e","affectsGlobalScope":true,"impliedFormat":1},{"version":"483bb10b755f3572526fd76d9481221e8dc30568edcc1a9cc73479d8874bd16d","impliedFormat":1},{"version":"2df62cd6db7d86f765cfc05606bbd27b38ed7bae502b5c4d927996bcf3638d64","impliedFormat":1},{"version":"805323dc5c4c6f2598b709bcc2be2c11002c0817e00791afc0c639cd2399961e","impliedFormat":1},"bf53c6109ab7882edc67f6631afeff1a8a9799887ea335b10f566cf18e2806d9","ad19bcacd961cf2edc99111a4e385b5b5ac2655884aee90ae3cf7d0fad2d2de1","555ef3ad7acf4181dd5224c552040fdcc8810b5bd0f34cbd7b67baeada0f9ca4","bcb025caff4404b22387702772b9c42a36faa040b6312a5d1380b11e18cc7abd","518aa9ad01b2e0c0ed7ec8e416293c7db8571a3ef672eb8560e132a656f8df69","1d14342afed73704689cb678c8bf62c7cdb9dbf8dcbad55a2789b5dcf4d0fc4c","bff8f33bffcf0a6ba5c609c9fc3cbfffb010a4435b4db0a5659fe6afdef7191e","afb131d5bf1c2154575a1332fb275cf90206b4189b964c13ae7bcd8cf971eb27",{"version":"9a2eaab4e54953c6b2ba21f7ac4c2593859da03917011c10a2acd8864e38e7b2","impliedFormat":1},{"version":"a3b563e1c55f84097b8cb1f1f479f7a4a2a0330a0db15b9faebc8333d0022445","impliedFormat":99},{"version":"720f5d028d71bc22ed4a5311a6ea884329db475d994f805ea86470111eccc1a1","impliedFormat":1},{"version":"b73ccd89cc59bd39ff723ad779cd353b4b5c8d1a24d2afa15b00c0c2e38dec85","affectsGlobalScope":true,"impliedFormat":1},{"version":"f8afc704019b043619b871c58cf664e16ffa2bc252ee036e63a397d1d376fa85","affectsGlobalScope":true,"impliedFormat":1},{"version":"3de9f829f53966384023e023185c0515d18b747f0001924a1919751e6ac5308d","affectsGlobalScope":true,"impliedFormat":1},{"version":"75e5eba775a6a65a949380d689933849e190fef8a12867eb6fe884141af09d30","impliedFormat":1},{"version":"43a495a494b76a0a752f6926e571976c6e7bb1d5c29c84c2a57d4e75ea934bbd","affectsGlobalScope":true,"impliedFormat":1},{"version":"2b8af6e8cf44313406800b820bffc49e83a8ec4598772db25954d03a86c96818","affectsGlobalScope":true,"impliedFormat":1},{"version":"95d4d18508a76d6a7036029d974d27e5ffddd742650f967dca22cf035518ca28","impliedFormat":1},{"version":"c0745e81d1d3574a559ae6ef39808a6783f01081536c1a45fbb9954158154df7","impliedFormat":1},{"version":"d2e66d9477edaa0e4dea79d699f0855a5a7419915da740e28fbfdb322c6a60a6","affectsGlobalScope":true,"impliedFormat":1},{"version":"ca69bbf884a17e7a485bb4fcd129386874050916b275e414af14b2170b4ea728","affectsGlobalScope":true,"impliedFormat":1},{"version":"b52c121cd491cfdbea04c3a77d23e193c23cb411e7598a04ba13a4592842fe2f","impliedFormat":1}],"root":[74,[163,166],[267,274]],"options":{"allowUnreachableCode":false,"allowUnusedLabels":false,"checkJs":true,"esModuleInterop":true,"exactOptionalPropertyTypes":true,"module":99,"noFallthroughCasesInSwitch":true,"noImplicitOverride":true,"noImplicitReturns":true,"noPropertyAccessFromIndexSignature":true,"noUncheckedIndexedAccess":true,"noUnusedLocals":true,"noUnusedParameters":true,"skipLibCheck":true,"strict":true,"target":9},"referencedMap":[[75,1],[162,2],[129,3],[128,4],[126,5],[125,6],[130,7],[133,8],[134,1],[135,9],[136,9],[137,9],[138,1],[161,10],[139,1],[140,1],[141,1],[142,1],[144,11],[143,9],[145,8],[147,12],[146,13],[127,14],[148,9],[149,9],[160,15],[159,16],[158,9],[157,9],[150,9],[151,9],[152,1],[153,14],[154,17],[155,17],[156,9],[124,18],[123,1],[132,19],[131,1],[173,20],[174,20],[213,21],[214,22],[215,23],[216,24],[217,25],[218,26],[219,27],[220,28],[221,29],[222,30],[223,30],[225,31],[224,32],[226,33],[227,34],[228,35],[212,36],[263,1],[229,37],[230,38],[231,39],[232,40],[233,41],[234,42],[235,43],[236,44],[237,45],[238,46],[239,47],[240,48],[241,49],[242,49],[243,50],[244,1],[245,51],[247,52],[246,53],[248,54],[249,55],[250,56],[251,57],[252,58],[253,59],[254,60],[172,61],[171,1],[264,62],[255,63],[256,64],[257,65],[258,66],[259,67],[260,68],[261,69],[262,70],[266,71],[276,72],[275,73],[121,74],[122,75],[115,75],[77,1],[79,76],[78,77],[83,78],[117,79],[114,80],[116,81],[80,80],[81,82],[85,82],[84,83],[82,84],[120,85],[113,80],[118,86],[112,1],[119,1],[86,87],[91,80],[93,80],[88,80],[89,87],[95,80],[96,88],[87,80],[92,80],[94,80],[90,80],[110,89],[109,80],[111,90],[105,80],[107,80],[106,80],[102,80],[108,91],[103,80],[104,92],[97,80],[98,80],[99,80],[100,80],[101,80],[279,93],[287,94],[277,95],[281,1],[278,96],[283,1],[288,97],[284,1],[280,98],[285,1],[282,99],[286,1],[76,1],[265,1],[72,1],[73,1],[12,1],[14,1],[13,1],[2,1],[15,1],[16,1],[17,1],[18,1],[19,1],[20,1],[21,1],[22,1],[3,1],[23,1],[4,1],[24,1],[28,1],[25,1],[26,1],[27,1],[29,1],[30,1],[31,1],[5,1],[32,1],[33,1],[34,1],[35,1],[6,1],[39,1],[36,1],[37,1],[38,1],[40,1],[7,1],[41,1],[46,1],[47,1],[42,1],[43,1],[44,1],[45,1],[8,1],[51,1],[48,1],[49,1],[50,1],[52,1],[9,1],[53,1],[54,1],[55,1],[58,1],[56,1],[57,1],[59,1],[60,1],[10,1],[61,1],[1,1],[62,1],[63,1],[11,1],[68,1],[65,1],[64,1],[71,1],[69,1],[67,1],[70,1],[66,1],[190,100],[200,101],[189,100],[210,102],[181,103],[180,104],[209,105],[203,106],[208,107],[183,108],[197,109],[182,110],[206,111],[178,112],[177,105],[207,113],[179,114],[184,115],[185,1],[188,115],[175,1],[211,116],[201,117],[192,118],[193,119],[195,120],[191,121],[194,122],[204,105],[186,123],[187,124],[196,125],[176,126],[199,117],[198,115],[202,1],[205,127],[170,128],[169,129],[167,130],[168,131],[74,1],[166,132],[165,133],[271,134],[272,135],[269,136],[163,137],[273,138],[270,137],[164,139],[274,140],[268,141],[267,142]],"affectedFilesPendingEmit":[74,166,165,271,272,269,163,273,270,164,274,268,267],"version":"5.6.3"} \ No newline at end of file diff --git a/packages/react-openapi/src/OpenAPICodeSample.tsx b/packages/react-openapi/src/OpenAPICodeSample.tsx index e9b96a1bb..5d60d4c70 100644 --- a/packages/react-openapi/src/OpenAPICodeSample.tsx +++ b/packages/react-openapi/src/OpenAPICodeSample.tsx @@ -1,9 +1,8 @@ import { CodeSampleInput, codeSampleGenerators } from './code-samples'; -import { OpenAPIOperationData } from './fetchOpenAPIOperation'; import { generateMediaTypeExample, generateSchemaExample } from './generateSchemaExample'; import { InteractiveSection } from './InteractiveSection'; import { getServersURL } from './OpenAPIServerURL'; -import { OpenAPIContextProps } from './types'; +import type { OpenAPIContextProps, OpenAPIOperationData } from './types'; import { noReference } from './utils'; import { stringifyOpenAPI } from './stringifyOpenAPI'; import { OpenAPITabs, OpenAPITabsList, OpenAPITabsPanels } from './OpenAPITabs'; diff --git a/packages/react-openapi/src/OpenAPIOperation.tsx b/packages/react-openapi/src/OpenAPIOperation.tsx index 40a2bf0cd..778e3a924 100644 --- a/packages/react-openapi/src/OpenAPIOperation.tsx +++ b/packages/react-openapi/src/OpenAPIOperation.tsx @@ -1,11 +1,10 @@ import clsx from 'clsx'; -import type { OpenAPIOperationData } from './fetchOpenAPIOperation'; import { Markdown } from './Markdown'; import { OpenAPICodeSample } from './OpenAPICodeSample'; import { OpenAPIResponseExample } from './OpenAPIResponseExample'; import { OpenAPISpec } from './OpenAPISpec'; -import { OpenAPIClientContext, type OpenAPIContextProps } from './types'; +import type { OpenAPIClientContext, OpenAPIContextProps, OpenAPIOperationData } from './types'; import { OpenAPIPath } from './OpenAPIPath'; import { resolveDescription } from './utils'; diff --git a/packages/react-openapi/src/OpenAPIPath.tsx b/packages/react-openapi/src/OpenAPIPath.tsx index ef200782c..59b0b7aea 100644 --- a/packages/react-openapi/src/OpenAPIPath.tsx +++ b/packages/react-openapi/src/OpenAPIPath.tsx @@ -1,6 +1,5 @@ -import type { OpenAPIOperationData } from './fetchOpenAPIOperation'; import { ScalarApiButton } from './ScalarApiButton'; -import type { OpenAPIContextProps } from './types'; +import type { OpenAPIOperationData, OpenAPIContextProps } from './types'; /** * Display the path of an operation. diff --git a/packages/react-openapi/src/OpenAPIResponseExample.tsx b/packages/react-openapi/src/OpenAPIResponseExample.tsx index c95f803e4..eab4bd0ed 100644 --- a/packages/react-openapi/src/OpenAPIResponseExample.tsx +++ b/packages/react-openapi/src/OpenAPIResponseExample.tsx @@ -1,7 +1,6 @@ import type { OpenAPIV3 } from '@gitbook/openapi-parser'; -import type { OpenAPIOperationData } from './fetchOpenAPIOperation'; import { generateSchemaExample } from './generateSchemaExample'; -import type { OpenAPIContextProps } from './types'; +import type { OpenAPIContextProps, OpenAPIOperationData } from './types'; import { checkIsReference, noReference, resolveDescription } from './utils'; import { stringifyOpenAPI } from './stringifyOpenAPI'; import { OpenAPITabs, OpenAPITabsList, OpenAPITabsPanels } from './OpenAPITabs'; diff --git a/packages/react-openapi/src/OpenAPISecurities.tsx b/packages/react-openapi/src/OpenAPISecurities.tsx index b766560a7..302e4b086 100644 --- a/packages/react-openapi/src/OpenAPISecurities.tsx +++ b/packages/react-openapi/src/OpenAPISecurities.tsx @@ -1,8 +1,7 @@ import type { OpenAPIV3_1 } from '@gitbook/openapi-parser'; -import type { OpenAPIClientContext } from './types'; +import type { OpenAPIClientContext, OpenAPIOperationData } from './types'; import { InteractiveSection } from './InteractiveSection'; import { Markdown } from './Markdown'; -import { OpenAPIOperationData } from './fetchOpenAPIOperation'; import { OpenAPISchemaName } from './OpenAPISchemaName'; import { resolveDescription } from './utils'; diff --git a/packages/react-openapi/src/OpenAPISpec.tsx b/packages/react-openapi/src/OpenAPISpec.tsx index 2a93c19af..f0bb46056 100644 --- a/packages/react-openapi/src/OpenAPISpec.tsx +++ b/packages/react-openapi/src/OpenAPISpec.tsx @@ -2,13 +2,12 @@ import type { OpenAPI } from '@gitbook/openapi-parser'; -import { OpenAPIOperationData } from './fetchOpenAPIOperation'; import { InteractiveSection } from './InteractiveSection'; import { OpenAPIRequestBody } from './OpenAPIRequestBody'; import { OpenAPIResponses } from './OpenAPIResponses'; import { OpenAPISchemaProperties } from './OpenAPISchema'; import { OpenAPISecurities } from './OpenAPISecurities'; -import { OpenAPIClientContext } from './types'; +import type { OpenAPIClientContext, OpenAPIOperationData } from './types'; import { noReference, resolveDescription } from './utils'; /** diff --git a/packages/react-openapi/src/fetchOpenAPIOperation.test.ts b/packages/react-openapi/src/fetchOpenAPIOperation.test.ts deleted file mode 100644 index 6d7d6987c..000000000 --- a/packages/react-openapi/src/fetchOpenAPIOperation.test.ts +++ /dev/null @@ -1,193 +0,0 @@ -import { it, expect } from 'bun:test'; - -import { fetchOpenAPIOperation, type OpenAPIFetcher } from './fetchOpenAPIOperation'; -import { parseOpenAPI, traverse } from '@gitbook/openapi-parser'; - -const fetcher: OpenAPIFetcher = { - fetch: async (url) => { - const response = await fetch(url); - const text = await response.text(); - const filesystem = await parseOpenAPI({ value: text, url }); - const transformedFs = await traverse(filesystem, async (node) => { - if ('description' in node && typeof node.description === 'string' && node.description) { - node['x-description-html'] = node.description; - } - return node; - }); - return transformedFs; - }, -}; - -it('should resolve refs', async () => { - const resolved = await fetchOpenAPIOperation( - { - url: 'https://petstore3.swagger.io/api/v3/openapi.json', - method: 'put', - path: '/pet', - }, - fetcher, - ); - - expect(resolved).toMatchObject({ - servers: [ - { - url: '/api/v3', - }, - ], - operation: { - tags: ['pet'], - summary: 'Update an existing pet', - description: 'Update an existing pet by Id', - requestBody: { - content: { - 'application/json': { - schema: { - type: 'object', - required: ['name', 'photoUrls'], - }, - }, - }, - }, - }, - }); -}); - -it('should support yaml', async () => { - const resolved = await fetchOpenAPIOperation( - { - url: 'https://petstore3.swagger.io/api/v3/openapi.yaml', - method: 'put', - path: '/pet', - }, - fetcher, - ); - - expect(resolved).toMatchObject({ - servers: [ - { - url: '/api/v3', - }, - ], - operation: { - tags: ['pet'], - summary: 'Update an existing pet', - description: 'Update an existing pet by Id', - requestBody: { - content: { - 'application/json': { - schema: { - type: 'object', - required: ['name', 'photoUrls'], - }, - }, - }, - }, - }, - }); -}); - -it('should resolve circular refs', async () => { - const resolved = await fetchOpenAPIOperation( - { - url: 'https://api.gitbook.com/openapi.json', - method: 'post', - path: '/search/ask', - }, - fetcher, - ); - - expect(resolved).toMatchObject({ - servers: [ - { - url: '{host}/v1', - }, - ], - operation: { - operationId: 'askQuery', - }, - }); -}); - -it('should resolve to null if the method is not supported', async () => { - const resolved = await fetchOpenAPIOperation( - { - url: 'https://petstore3.swagger.io/api/v3/openapi.json', - method: 'dontexist', - path: '/pet', - }, - fetcher, - ); - - expect(resolved).toBe(null); -}); - -it('should parse Swagger 2.0', async () => { - const resolved = await fetchOpenAPIOperation( - { - url: 'https://petstore.swagger.io/v2/swagger.json', - method: 'put', - path: '/pet', - }, - fetcher, - ); - - expect(resolved).toMatchObject({ - servers: [ - { - url: 'https://petstore.swagger.io/v2', - }, - { - url: 'http://petstore.swagger.io/v2', - }, - ], - operation: { - tags: ['pet'], - summary: 'Update an existing pet', - description: '', - requestBody: { - content: { - 'application/json': { - schema: { - type: 'object', - required: ['name', 'photoUrls'], - }, - }, - }, - }, - }, - }); -}); - -it('should resolve a ref with whitespace', async () => { - const resolved = await fetchOpenAPIOperation( - { - url: ' https://petstore3.swagger.io/api/v3/openapi.json', - method: 'put', - path: '/pet', - }, - fetcher, - ); - - expect(resolved).toMatchObject({ - servers: [ - { - url: '/api/v3', - }, - ], - operation: { - tags: ['pet'], - summary: 'Update an existing pet', - description: 'Update an existing pet by Id', - requestBody: { - content: { - 'application/json': { - schema: { - type: 'object', - required: ['name', 'photoUrls'], - }, - }, - }, - }, - }, - }); -}); diff --git a/packages/react-openapi/src/index.ts b/packages/react-openapi/src/index.ts index b78fa3aed..9d8d0b47a 100644 --- a/packages/react-openapi/src/index.ts +++ b/packages/react-openapi/src/index.ts @@ -1,3 +1,4 @@ -export * from './fetchOpenAPIOperation'; +export * from './resolveOpenAPIOperation'; export * from './OpenAPIOperation'; export * from './OpenAPIOperationContext'; +export type { OpenAPIOperationData } from './types'; diff --git a/packages/react-openapi/src/resolveOpenAPIOperation.test.ts b/packages/react-openapi/src/resolveOpenAPIOperation.test.ts new file mode 100644 index 000000000..9ae6a3712 --- /dev/null +++ b/packages/react-openapi/src/resolveOpenAPIOperation.test.ts @@ -0,0 +1,177 @@ +import { it, expect, describe } from 'bun:test'; + +import { resolveOpenAPIOperation } from './resolveOpenAPIOperation'; +import { parseOpenAPI, traverse } from '@gitbook/openapi-parser'; + +async function fetchFilesystem(url: string) { + const response = await fetch(url); + const text = await response.text(); + const filesystem = await parseOpenAPI({ value: text, rootURL: url }); + const transformedFs = await traverse(filesystem, async (node) => { + if ('description' in node && typeof node.description === 'string' && node.description) { + node['x-description-html'] = node.description; + } + return node; + }); + return transformedFs; +} + +describe('#resolveOpenAPIOperation', () => { + it('should resolve refs', async () => { + const filesystem = await fetchFilesystem( + 'https://petstore3.swagger.io/api/v3/openapi.json', + ); + const resolved = await resolveOpenAPIOperation(filesystem, { method: 'put', path: '/pet' }); + + expect(resolved).toMatchObject({ + servers: [ + { + url: '/api/v3', + }, + ], + operation: { + tags: ['pet'], + summary: 'Update an existing pet', + description: 'Update an existing pet by Id', + requestBody: { + content: { + 'application/json': { + schema: { + type: 'object', + required: ['name', 'photoUrls'], + }, + }, + }, + }, + }, + }); + }); + + it('should support yaml', async () => { + const filesystem = await fetchFilesystem( + 'https://petstore3.swagger.io/api/v3/openapi.yaml', + ); + const resolved = await resolveOpenAPIOperation(filesystem, { method: 'put', path: '/pet' }); + + expect(resolved).toMatchObject({ + servers: [ + { + url: '/api/v3', + }, + ], + operation: { + tags: ['pet'], + summary: 'Update an existing pet', + description: 'Update an existing pet by Id', + requestBody: { + content: { + 'application/json': { + schema: { + type: 'object', + required: ['name', 'photoUrls'], + }, + }, + }, + }, + }, + }); + }); + + it('should resolve circular refs', async () => { + const filesystem = await fetchFilesystem('https://api.gitbook.com/openapi.json'); + const resolved = await resolveOpenAPIOperation(filesystem, { + method: 'post', + path: '/search/ask', + }); + + expect(resolved).toMatchObject({ + servers: [ + { + url: '{host}/v1', + }, + ], + operation: { + operationId: 'askQuery', + }, + }); + }); + + it('should resolve to null if the method is not supported', async () => { + const filesystem = await fetchFilesystem( + 'https://petstore3.swagger.io/api/v3/openapi.json', + ); + const resolved = await resolveOpenAPIOperation(filesystem, { + method: 'dontexist', + path: '/pet', + }); + + expect(resolved).toBe(null); + }); + + it('should parse Swagger 2.0', async () => { + const filesystem = await fetchFilesystem('https://petstore.swagger.io/v2/swagger.json'); + const resolved = await resolveOpenAPIOperation(filesystem, { + method: 'put', + path: '/pet', + }); + + expect(resolved).toMatchObject({ + servers: [ + { + url: 'https://petstore.swagger.io/v2', + }, + { + url: 'http://petstore.swagger.io/v2', + }, + ], + operation: { + tags: ['pet'], + summary: 'Update an existing pet', + description: '', + requestBody: { + content: { + 'application/json': { + schema: { + type: 'object', + required: ['name', 'photoUrls'], + }, + }, + }, + }, + }, + }); + }); + + it('should resolve a ref with whitespace', async () => { + const filesystem = await fetchFilesystem( + ' https://petstore3.swagger.io/api/v3/openapi.json', + ); + const resolved = await resolveOpenAPIOperation(filesystem, { + method: 'put', + path: '/pet', + }); + + expect(resolved).toMatchObject({ + servers: [ + { + url: '/api/v3', + }, + ], + operation: { + tags: ['pet'], + summary: 'Update an existing pet', + description: 'Update an existing pet by Id', + requestBody: { + content: { + 'application/json': { + schema: { + type: 'object', + required: ['name', 'photoUrls'], + }, + }, + }, + }, + }, + }); + }); +}); diff --git a/packages/react-openapi/src/fetchOpenAPIOperation.ts b/packages/react-openapi/src/resolveOpenAPIOperation.ts similarity index 70% rename from packages/react-openapi/src/fetchOpenAPIOperation.ts rename to packages/react-openapi/src/resolveOpenAPIOperation.ts index e5a30ee33..53435d240 100644 --- a/packages/react-openapi/src/fetchOpenAPIOperation.ts +++ b/packages/react-openapi/src/resolveOpenAPIOperation.ts @@ -1,61 +1,37 @@ import { toJSON, fromJSON } from 'flatted'; import { - type OpenAPICustomOperationProperties, - type OpenAPICustomSpecProperties, type OpenAPIV3xDocument, type Filesystem, type OpenAPIV3, type OpenAPIV3_1, - OpenAPIParseError, dereference, } from '@gitbook/openapi-parser'; import { noReference } from './utils'; - -export interface OpenAPIFetcher { - /** - * Fetch an OpenAPI file by its URL. It should return a fully parsed OpenAPI v3 document. - */ - fetch: (url: string) => Promise>; -} - -export interface OpenAPIOperationData extends OpenAPICustomSpecProperties { - path: string; - method: string; - - /** Servers to be used for this operation */ - servers: OpenAPIV3.ServerObject[]; - - /** Spec of the operation */ - operation: OpenAPIV3.OperationObject; - - /** Securities that should be used for this operation */ - securities: [string, OpenAPIV3.SecuritySchemeObject][]; -} +import { OpenAPIOperationData } from './types'; export { toJSON, fromJSON }; /** * Resolve an OpenAPI operation in a file and compile it to a more usable format. */ -export async function fetchOpenAPIOperation( - input: { - url: string; +export async function resolveOpenAPIOperation( + filesystem: Filesystem, + operationDescriptor: { path: string; method: string; }, - fetcher: OpenAPIFetcher, ): Promise { - const filesystem = await fetcher.fetch(input.url); - const schema = await memoDereferenceFilesystem(filesystem, input.url); - let operation = getOperationByPathAndMethod(schema, input.path, input.method); + const { path, method } = operationDescriptor; + const schema = await memoDereferenceFilesystem(filesystem); + let operation = getOperationByPathAndMethod(schema, path, method); if (!operation) { return null; } // Resolve common parameters - const commonParameters = getPathObjectParameter(schema, input.path); + const commonParameters = getPathObjectParameter(schema, path); if (commonParameters) { operation = { ...operation, @@ -81,8 +57,8 @@ export async function fetchOpenAPIOperation( return { servers, operation, - method: input.method, - path: input.path, + method, + path, securities, 'x-codeSamples': typeof schema['x-codeSamples'] === 'boolean' ? schema['x-codeSamples'] : undefined, @@ -98,15 +74,12 @@ const dereferenceCache = new WeakMap>(); /** * Memoized version of `dereferenceSchema`. */ -function memoDereferenceFilesystem( - filesystem: Filesystem, - url: string, -): Promise { +function memoDereferenceFilesystem(filesystem: Filesystem): Promise { if (dereferenceCache.has(filesystem)) { return dereferenceCache.get(filesystem) as Promise; } - const promise = dereferenceFilesystem(filesystem, url); + const promise = dereferenceFilesystem(filesystem); dereferenceCache.set(filesystem, promise); return promise; } @@ -114,18 +87,11 @@ function memoDereferenceFilesystem( /** * Dereference an OpenAPI schema. */ -async function dereferenceFilesystem( - filesystem: Filesystem, - url: string, -): Promise { +async function dereferenceFilesystem(filesystem: Filesystem): Promise { const result = await dereference(filesystem); if (!result.schema) { - throw new OpenAPIParseError( - 'Failed to dereference OpenAPI document', - url, - 'failed-dereference', - ); + throw new Error('Failed to dereference OpenAPI document'); } return result.schema as OpenAPIV3xDocument; diff --git a/packages/react-openapi/src/types.ts b/packages/react-openapi/src/types.ts index 5eacfbe33..b3a9ed0e3 100644 --- a/packages/react-openapi/src/types.ts +++ b/packages/react-openapi/src/types.ts @@ -1,3 +1,9 @@ +import type { + OpenAPICustomOperationProperties, + OpenAPICustomSpecProperties, + OpenAPIV3, +} from '@gitbook/openapi-parser'; + export interface OpenAPIContextProps extends OpenAPIClientContext { CodeBlock: React.ComponentType<{ code: string; syntax: string }>; @@ -24,3 +30,17 @@ export interface OpenAPIClientContext { /** Optional id attached to the OpenAPI Operation heading and used as an anchor */ id?: string; } + +export interface OpenAPIOperationData extends OpenAPICustomSpecProperties { + path: string; + method: string; + + /** Servers to be used for this operation */ + servers: OpenAPIV3.ServerObject[]; + + /** Spec of the operation */ + operation: OpenAPIV3.OperationObject; + + /** Securities that should be used for this operation */ + securities: [string, OpenAPIV3.SecuritySchemeObject][]; +}