Compare commits

...

4 Commits

Author SHA1 Message Date
Samy Pessé c0b339e406 Version Packages (#3075)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-04-02 13:36:04 +02:00
Nolann B. da485f5144 Fix read-only in generateSchemaExample (#3069) 2025-04-02 13:03:51 +02:00
Nolann B. 139a8050a5 Fix OpenAPI enum display (#3077) 2025-04-02 10:15:19 +02:00
Nolann B. da7b369ffd Fix missing headers in OpenAPIResponses (#3074) 2025-04-01 21:57:36 +02:00
10 changed files with 187 additions and 80 deletions
+11
View File
@@ -1,5 +1,16 @@
# gitbook
## 0.9.2
### Patch Changes
- da7b369: Fix missing headers in OpenAPIResponses
- 139a805: Fix OpenAPI enum display
- Updated dependencies [da7b369]
- Updated dependencies [da485f5]
- Updated dependencies [139a805]
- @gitbook/react-openapi@1.1.9
## 0.9.1
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "gitbook",
"version": "0.9.1",
"version": "0.9.2",
"private": true,
"scripts": {
"dev": "env-cmd --silent -f ../../.env.local next dev",
@@ -265,15 +265,11 @@
/* Schema Enum */
.openapi-schema-enum {
@apply flex flex-row text-sm leading-relaxed gap-2 flex-wrap text-tint;
}
.openapi-schema-enum-list {
@apply flex flex-row gap-1.5 items-center;
@apply text-sm leading-relaxed max-w-full text-tint;
}
.openapi-schema-enum-value {
@apply text-sm;
@apply text-sm mr-1.5;
}
.openapi-schema-enum-value:first-child {
+8
View File
@@ -1,5 +1,13 @@
# @gitbook/react-openapi
## 1.1.9
### Patch Changes
- da7b369: Fix missing headers in OpenAPIResponses
- da485f5: Fix read-only in generateSchemaExample
- 139a805: Fix OpenAPI enum display
## 1.1.8
### Patch Changes
+1 -1
View File
@@ -8,7 +8,7 @@
"default": "./dist/index.js"
}
},
"version": "1.1.8",
"version": "1.1.9",
"sideEffects": false,
"dependencies": {
"@gitbook/openapi-parser": "workspace:*",
@@ -36,13 +36,15 @@ export function OpenAPIResponse(props: {
/>
</OpenAPIDisclosure>
) : null}
<div className="openapi-responsebody">
<OpenAPISchemaProperties
id={`response-${context.blockKey}`}
properties={mediaType.schema ? [{ schema: mediaType.schema }] : []}
context={context}
/>
</div>
{mediaType.schema && (
<div className="openapi-responsebody">
<OpenAPISchemaProperties
id={`response-${context.blockKey}`}
properties={[{ schema: mediaType.schema }]}
context={context}
/>
</div>
)}
</div>
);
}
@@ -268,6 +268,7 @@ function getExamplesFromMediaTypeObject(args: {
value: {
[root]: generateSchemaExample(mediaTypeObject.schema, {
xml: mediaType === 'application/xml',
mode: 'read',
}),
},
},
@@ -277,7 +278,11 @@ function getExamplesFromMediaTypeObject(args: {
return [
{
key: 'default',
example: { value: generateSchemaExample(mediaTypeObject.schema) },
example: {
value: generateSchemaExample(mediaTypeObject.schema, {
mode: 'read',
}),
},
},
];
}
+37 -12
View File
@@ -21,7 +21,42 @@ export function OpenAPIResponses(props: {
icon={context.icons.chevronRight}
groups={Object.entries(responses).map(
([statusCode, response]: [string, OpenAPIV3.ResponseObject]) => {
const content = Object.entries(response.content ?? {});
const tabs = (() => {
// If there is no content, but there are headers, we need to show the headers
if (
(!response.content || !Object.keys(response.content).length) &&
response.headers &&
Object.keys(response.headers).length
) {
return [
{
id: 'default',
body: (
<OpenAPIResponse
response={response}
mediaType={{}}
context={context}
/>
),
},
];
}
return Object.entries(response.content ?? {}).map(
([contentType, mediaType]) => ({
id: contentType,
label: contentType,
body: (
<OpenAPIResponse
response={response}
mediaType={mediaType}
context={context}
/>
),
})
);
})();
const description = response.description;
return {
@@ -39,17 +74,7 @@ export function OpenAPIResponses(props: {
) : null}
</div>
),
tabs: content.map(([contentType, mediaType]) => ({
id: contentType,
label: contentType,
body: (
<OpenAPIResponse
response={response}
mediaType={mediaType}
context={context}
/>
),
})),
tabs,
};
}
)}
+14 -16
View File
@@ -275,22 +275,20 @@ function OpenAPISchemaEnum(props: {
}
return (
<div className="openapi-schema-enum">
<span>Available options:</span>
<div className="openapi-schema-enum-list">
{enumValues.map((item, index) => (
<span key={index} className="openapi-schema-enum-value">
<OpenAPICopyButton
value={item.value}
label={item.description}
withTooltip={!!item.description}
>
<code>{`${item.value}`}</code>
</OpenAPICopyButton>
</span>
))}
</div>
</div>
<span className="openapi-schema-enum">
Available options:{' '}
{enumValues.map((item, index) => (
<span key={index} className="openapi-schema-enum-value">
<OpenAPICopyButton
value={item.value}
label={item.description}
withTooltip={!!item.description}
>
<code>{`${item.value}`}</code>
</OpenAPICopyButton>
</span>
))}
</span>
);
}
@@ -16,14 +16,10 @@ export function generateSchemaExample(
schema: OpenAPIV3.SchemaObject,
options?: GenerateSchemaExampleOptions
): JSONValue | undefined {
return getExampleFromSchema(
schema,
{
emptyString: 'text',
...options,
},
3 // Max depth for circular references
);
return getExampleFromSchema(schema, {
emptyString: 'text',
...options,
});
}
/**
@@ -103,21 +99,6 @@ function guessFromFormat(schema: Record<string, any>, fallback = '') {
return genericExampleValues[schema.format] ?? fallback;
}
/** Map of all the results */
const resultCache = new WeakMap<Record<string, any>, any>();
/** Store result in the cache, and return the result */
function cache(schema: Record<string, any>, result: unknown) {
// Avoid unnecessary WeakMap operations for primitive values
if (typeof result !== 'object' || result === null) {
return result;
}
resultCache.set(schema, result);
return result;
}
/**
* This function takes an OpenAPI schema and generates an example from it
* Forked from : https://github.com/scalar/scalar/blob/main/packages/oas-utils/src/spec-getters/getExampleFromSchema.ts
@@ -152,8 +133,20 @@ const getExampleFromSchema = (
},
level = 0,
parentSchema?: Record<string, any>,
name?: string
name?: string,
resultCache = new WeakMap<Record<string, any>, any>()
): any => {
// Store result in the cache, and return the result
function cache(schema: Record<string, any>, result: unknown) {
// Avoid unnecessary WeakMap operations for primitive values
if (typeof result !== 'object' || result === null) {
return result;
}
resultCache.set(schema, result);
return result;
}
// Check if the result is already cached
if (resultCache.has(schema)) {
return resultCache.get(schema);
@@ -245,7 +238,8 @@ const getExampleFromSchema = (
options,
level + 1,
schema,
propertyName
propertyName,
resultCache
);
if (typeof response[propertyXmlTagName ?? propertyName] === 'undefined') {
@@ -269,7 +263,8 @@ const getExampleFromSchema = (
options,
level + 1,
schema,
exampleKey
exampleKey,
resultCache
);
}
}
@@ -290,21 +285,51 @@ const getExampleFromSchema = (
response.ANY_ADDITIONAL_PROPERTY = getExampleFromSchema(
schema.additionalProperties,
options,
level + 1
level + 1,
undefined,
undefined,
resultCache
);
}
}
if (schema.anyOf !== undefined) {
Object.assign(response, getExampleFromSchema(schema.anyOf[0], options, level + 1));
Object.assign(
response,
getExampleFromSchema(
schema.anyOf[0],
options,
level + 1,
undefined,
undefined,
resultCache
)
);
} else if (schema.oneOf !== undefined) {
Object.assign(response, getExampleFromSchema(schema.oneOf[0], options, level + 1));
Object.assign(
response,
getExampleFromSchema(
schema.oneOf[0],
options,
level + 1,
undefined,
undefined,
resultCache
)
);
} else if (schema.allOf !== undefined) {
Object.assign(
response,
...schema.allOf
.map((item: Record<string, any>) =>
getExampleFromSchema(item, options, level + 1, schema)
getExampleFromSchema(
item,
options,
level + 1,
schema,
undefined,
resultCache
)
)
.filter((item: any) => item !== undefined)
);
@@ -335,7 +360,9 @@ const getExampleFromSchema = (
{ type: 'object', allOf: schema.items.allOf },
options,
level + 1,
schema
schema,
undefined,
resultCache
);
return cache(
@@ -346,7 +373,14 @@ const getExampleFromSchema = (
// For non-objects (like strings), collect all examples
const examples = schema.items.allOf
.map((item: Record<string, any>) =>
getExampleFromSchema(item, options, level + 1, schema)
getExampleFromSchema(
item,
options,
level + 1,
schema,
undefined,
resultCache
)
)
.filter((item: any) => item !== undefined);
@@ -368,7 +402,14 @@ const getExampleFromSchema = (
const schemas = schema.items[rule].slice(0, 1);
const exampleFromRule = schemas
.map((item: Record<string, any>) =>
getExampleFromSchema(item, options, level + 1, schema)
getExampleFromSchema(
item,
options,
level + 1,
schema,
undefined,
resultCache
)
)
.filter((item: any) => item !== undefined);
@@ -380,7 +421,14 @@ const getExampleFromSchema = (
}
if (schema.items?.type) {
const exampleFromSchema = getExampleFromSchema(schema.items, options, level + 1);
const exampleFromSchema = getExampleFromSchema(
schema.items,
options,
level + 1,
undefined,
undefined,
resultCache
);
return wrapItems ? [{ [itemsXmlTagName]: exampleFromSchema }] : [exampleFromSchema];
}
@@ -407,7 +455,14 @@ const getExampleFromSchema = (
const firstOneOfItem = discriminateSchema[0];
// Return an example for the first item
return getExampleFromSchema(firstOneOfItem, options, level + 1);
return getExampleFromSchema(
firstOneOfItem,
options,
level + 1,
undefined,
undefined,
resultCache
);
}
// Check if schema has the `allOf` key
@@ -417,7 +472,14 @@ const getExampleFromSchema = (
// Loop through all `allOf` schemas
schema.allOf.forEach((allOfItem: Record<string, any>) => {
// Return an example from the schema
const newExample = getExampleFromSchema(allOfItem, options, level + 1);
const newExample = getExampleFromSchema(
allOfItem,
options,
level + 1,
undefined,
undefined,
resultCache
);
// Merge or overwrite the example
example =