diff --git a/.changeset/tall-buckets-clean.md b/.changeset/tall-buckets-clean.md new file mode 100644 index 000000000..e2bb36206 --- /dev/null +++ b/.changeset/tall-buckets-clean.md @@ -0,0 +1,5 @@ +--- +"@gitbook/openapi-parser": patch +--- + +Upgrade Scalar parser diff --git a/bun.lock b/bun.lock index 99754f1f4..4f9dfe91e 100644 --- a/bun.lock +++ b/bun.lock @@ -169,7 +169,7 @@ "name": "@gitbook/openapi-parser", "version": "2.1.4", "dependencies": { - "@scalar/openapi-parser": "^0.10.10", + "@scalar/openapi-parser": "^0.18.0", "@scalar/openapi-types": "^0.1.9", }, "devDependencies": { @@ -1100,7 +1100,7 @@ "@scalar/object-utils": ["@scalar/object-utils@1.1.13", "", { "dependencies": { "flatted": "^3.3.1", "just-clone": "^6.2.0", "ts-deepmerge": "^7.0.1" } }, "sha512-311eTykIXgOtjCs4VTELj9UMT97jHTWc5qkGNoIzZ5nxjCcvOVe7kDQobIkE8dGT+ybOgHz5qly02Eu7nVHeZQ=="], - "@scalar/openapi-parser": ["@scalar/openapi-parser@0.10.14", "", { "dependencies": { "ajv": "^8.17.1", "ajv-draft-04": "^1.0.0", "ajv-formats": "^3.0.1", "jsonpointer": "^5.0.1", "leven": "^4.0.0", "yaml": "^2.4.5" } }, "sha512-VXr979NMx6wZ+kpFKor2eyCJZOjyMwcBRc6c4Gc92ZMOC7ZNYqjwbw+Ubh2ELJyP5cWAjOFSrNwtylema0pw5w=="], + "@scalar/openapi-parser": ["@scalar/openapi-parser@0.18.0", "", { "dependencies": { "ajv": "^8.17.1", "ajv-draft-04": "^1.0.0", "ajv-formats": "^3.0.1", "jsonpointer": "^5.0.1", "leven": "^4.0.0", "yaml": "^2.4.5" } }, "sha512-qAWEfJR5f/LwSFULFeSkD56LHgU9ovyj+e1uqy9XaW9Hb9P0ewIGKi+Gd4wTyxfFkdPLXTFYXApjviP6jV+new=="], "@scalar/openapi-types": ["@scalar/openapi-types@0.1.9", "", {}, "sha512-HQQudOSQBU7ewzfnBW9LhDmBE2XOJgSfwrh5PlUB7zJup/kaRkBGNgV2wMjNz9Af/uztiU/xNrO179FysmUT+g=="], @@ -3768,8 +3768,6 @@ "@scalar/api-client/@scalar/object-utils": ["@scalar/object-utils@1.2.1", "", { "dependencies": { "flatted": "^3.3.1", "just-clone": "^6.2.0", "ts-deepmerge": "^7.0.1", "type-fest": "^4.20.0" } }, "sha512-2P/0In6XSrV1Ye8yU3LyOWJKWkzXpxf0thHmTfJriqGBZz41s06td2KKqoqHSEEi+FAsl3O1ngmOOzLM3QUkkw=="], - "@scalar/api-client/@scalar/openapi-parser": ["@scalar/openapi-parser@0.18.0", "", { "dependencies": { "ajv": "^8.17.1", "ajv-draft-04": "^1.0.0", "ajv-formats": "^3.0.1", "jsonpointer": "^5.0.1", "leven": "^4.0.0", "yaml": "^2.4.5" } }, "sha512-qAWEfJR5f/LwSFULFeSkD56LHgU9ovyj+e1uqy9XaW9Hb9P0ewIGKi+Gd4wTyxfFkdPLXTFYXApjviP6jV+new=="], - "@scalar/api-client/@scalar/openapi-types": ["@scalar/openapi-types@0.3.3", "", { "dependencies": { "zod": "3.24.1" } }, "sha512-mr3OvbCyvuzSDgv9gR9D3pJAsl82BRNBp1P8ldgRgKF4Wiswfa7nQeKibpX0kHSGXLgiyvxWJULUFwgdWMXNNA=="], "@scalar/api-client/@scalar/themes": ["@scalar/themes@0.13.4", "", { "dependencies": { "@scalar/types": "0.2.3", "nanoid": "^5.1.5" } }, "sha512-PMiSqX+MZF29u32ogEjTVA5c/LBd5cE/QPF7lK0EJeemXRy2r/nWbvrXtqD9Y7Sw54g1caVNjK8yJcCYJdB6hw=="], @@ -3782,8 +3780,6 @@ "@scalar/components/@scalar/themes": ["@scalar/themes@0.13.4", "", { "dependencies": { "@scalar/types": "0.2.3", "nanoid": "^5.1.5" } }, "sha512-PMiSqX+MZF29u32ogEjTVA5c/LBd5cE/QPF7lK0EJeemXRy2r/nWbvrXtqD9Y7Sw54g1caVNjK8yJcCYJdB6hw=="], - "@scalar/import/@scalar/openapi-parser": ["@scalar/openapi-parser@0.18.0", "", { "dependencies": { "ajv": "^8.17.1", "ajv-draft-04": "^1.0.0", "ajv-formats": "^3.0.1", "jsonpointer": "^5.0.1", "leven": "^4.0.0", "yaml": "^2.4.5" } }, "sha512-qAWEfJR5f/LwSFULFeSkD56LHgU9ovyj+e1uqy9XaW9Hb9P0ewIGKi+Gd4wTyxfFkdPLXTFYXApjviP6jV+new=="], - "@scalar/oas-utils/@scalar/openapi-types": ["@scalar/openapi-types@0.2.0", "", { "dependencies": { "zod": "^3.23.8" } }, "sha512-waiKk12cRCqyUCWTOX0K1WEVX46+hVUK+zRPzAahDJ7G0TApvbNkuy5wx7aoUyEk++HHde0XuQnshXnt8jsddA=="], "@scalar/oas-utils/@scalar/types": ["@scalar/types@0.1.7", "", { "dependencies": { "@scalar/openapi-types": "0.2.0", "@unhead/schema": "^1.11.11", "nanoid": "^5.1.5", "type-fest": "^4.20.0", "zod": "^3.23.8" } }, "sha512-irIDYzTQG2KLvFbuTI8k2Pz/R4JR+zUUSykVTbEMatkzMmVFnn1VzNSMlODbadycwZunbnL2tA27AXed9URVjw=="], diff --git a/packages/openapi-parser/package.json b/packages/openapi-parser/package.json index e65ebb4dd..2f8352c22 100644 --- a/packages/openapi-parser/package.json +++ b/packages/openapi-parser/package.json @@ -12,7 +12,7 @@ "version": "2.1.4", "sideEffects": false, "dependencies": { - "@scalar/openapi-parser": "^0.10.10", + "@scalar/openapi-parser": "^0.18.0", "@scalar/openapi-types": "^0.1.9" }, "devDependencies": { diff --git a/packages/openapi-parser/src/filesystem.test.ts b/packages/openapi-parser/src/filesystem.test.ts index 46d4131e5..daf29e51b 100644 --- a/packages/openapi-parser/src/filesystem.test.ts +++ b/packages/openapi-parser/src/filesystem.test.ts @@ -39,11 +39,8 @@ describe('#createFileSystem', () => { value: url, rootURL: url, }); - expect(filesystem).toHaveLength(4); + expect(filesystem).toHaveLength(1); expect(filesystem[0]?.isEntrypoint).toBe(true); - expect(filesystem[1]?.isEntrypoint).toBe(false); - expect(filesystem[1]?.filename).toBe('user.yaml'); - expect(filesystem[2]?.filename).toBe('../tag.yaml'); - expect(filesystem[3]?.filename).toBe('http://localhost:3020/root/pet.yaml'); + expect(filesystem[0]?.filename).toBe('openapi.json'); }); }); diff --git a/packages/openapi-parser/src/filesystem.ts b/packages/openapi-parser/src/filesystem.ts index bde8be855..b0e82a134 100644 --- a/packages/openapi-parser/src/filesystem.ts +++ b/packages/openapi-parser/src/filesystem.ts @@ -1,5 +1,7 @@ -import { load } from '@scalar/openapi-parser'; +import { bundle } from '@scalar/openapi-parser'; +import { parseJson, parseYaml } from '@scalar/openapi-parser/plugins-browser'; import type { ParseOpenAPIInput } from './parse'; +import { fetchURL } from './scalar-plugins/fetchURL'; import { fetchURLs } from './scalar-plugins/fetchURLs'; import type { Filesystem } from './types'; @@ -12,9 +14,24 @@ export async function createFileSystem( ): Promise { const { value, rootURL, options } = input; - const { filesystem } = await load(value, { - plugins: [fetchURLs({ rootURL }), ...(options?.plugins || [])], + const result = await bundle(value, { + treeShake: false, + plugins: [ + fetchURL(), + parseYaml(), + parseJson(), + fetchURLs({ rootURL }), + ...(options?.plugins || []), + ], }); - return filesystem; + return [ + { + dir: '.', + isEntrypoint: true, + references: [], + filename: 'openapi.json', + specification: result, + }, + ]; } diff --git a/packages/openapi-parser/src/parse.ts b/packages/openapi-parser/src/parse.ts index dd3819f76..88b6c686b 100644 --- a/packages/openapi-parser/src/parse.ts +++ b/packages/openapi-parser/src/parse.ts @@ -1,13 +1,15 @@ -import type { AnyApiDefinitionFormat, LoadPlugin } from '@scalar/openapi-parser'; +import type { AnyObject, bundle } from '@scalar/openapi-parser'; import { OpenAPIParseError } from './error'; import { convertOpenAPIV2ToOpenAPIV3 } from './v2'; import { parseOpenAPIV3 } from './v3'; +export type ParsePlugin = Parameters[1]['plugins'][number]; + export interface ParseOpenAPIInput { /** * The API definition to parse. */ - value: AnyApiDefinitionFormat; + value: string | AnyObject; /** * The root URL of the specified OpenAPI document. */ @@ -20,7 +22,7 @@ export interface ParseOpenAPIInput { * Options for the parser. */ options?: { - plugins?: LoadPlugin[]; + plugins?: ParsePlugin[]; }; } diff --git a/packages/openapi-parser/src/scalar-plugins/fetchURL.ts b/packages/openapi-parser/src/scalar-plugins/fetchURL.ts new file mode 100644 index 000000000..0e6125d09 --- /dev/null +++ b/packages/openapi-parser/src/scalar-plugins/fetchURL.ts @@ -0,0 +1,27 @@ +import { normalize } from '@scalar/openapi-parser'; +import type { ParsePlugin } from '../parse'; + +export const fetchUrlsDefaultConfiguration = { + limit: 40, +}; + +export const fetchURL = (): ParsePlugin => ({ + validate(value) { + return URL.canParse(value); + }, + async exec(value) { + try { + const response = await fetch(value); + if (!response.ok) { + return { ok: false }; + } + const text = await response.text(); + return { + ok: true, + data: normalize(text), + }; + } catch { + return { ok: false }; + } + }, +}); diff --git a/packages/openapi-parser/src/scalar-plugins/fetchURLs.ts b/packages/openapi-parser/src/scalar-plugins/fetchURLs.ts index e9db5c600..bfc49f7e8 100644 --- a/packages/openapi-parser/src/scalar-plugins/fetchURLs.ts +++ b/packages/openapi-parser/src/scalar-plugins/fetchURLs.ts @@ -1,10 +1,11 @@ -import { type LoadPlugin, normalize } from '@scalar/openapi-parser'; +import { normalize } from '@scalar/openapi-parser'; +import type { ParsePlugin } from '../parse'; export const fetchUrlsDefaultConfiguration = { limit: 40, }; -export const fetchURLs: (customConfiguration: { +export const fetchURLs = (customConfiguration: { /** * Root URL to resolve relative URLs. */ @@ -14,7 +15,7 @@ export const fetchURLs: (customConfiguration: { * Limit the number of requests. Set to `false` to disable the limit. */ limit?: number | false; -}) => LoadPlugin = (customConfiguration) => { +}): ParsePlugin => { // State let numberOfRequests = 0; @@ -25,7 +26,7 @@ export const fetchURLs: (customConfiguration: { }; return { - check(value?: any) { + validate(value) { // Not a string if (typeof value !== 'string') { return false; @@ -42,10 +43,10 @@ export const fetchURLs: (customConfiguration: { return true; }, - async get(value?: any) { + async exec(value) { // Limit the number of requests if (configuration?.limit !== false && numberOfRequests >= configuration?.limit) { - return undefined; + return { ok: false }; } try { @@ -53,14 +54,17 @@ export const fetchURLs: (customConfiguration: { const url = getReferenceUrl({ value, rootURL: configuration.rootURL }); const response = await fetch(url); if (!response.ok) { - return undefined; + return { ok: false }; } const text = await response.text(); // Try to normalize the text to be sure it's a valid JSON or YAML. await normalize(text); - return text; - } catch (_error: any) { - return undefined; + return { + ok: true, + data: text, + }; + } catch { + return { ok: false }; } }, };