Upgrade @scalar/openapi-parser (#3442)

This commit is contained in:
Greg Bergé
2025-07-07 14:33:40 +02:00
committed by GitHub
parent afba8fcb34
commit 4f5cbfe732
8 changed files with 77 additions and 29 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"@gitbook/openapi-parser": patch
---
Upgrade Scalar parser
+2 -6
View File
@@ -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=="],
+1 -1
View File
@@ -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": {
@@ -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');
});
});
+21 -4
View File
@@ -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<Filesystem> {
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,
},
];
}
+5 -3
View File
@@ -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<typeof bundle>[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[];
};
}
@@ -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 };
}
},
});
@@ -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 };
}
},
};