mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-16 15:45:13 +00:00
Replace $ref with $reference in json-decycle (#3049)
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'@gitbook/react-openapi': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Replace $ref with $reference in json-decycle
|
||||||
@@ -241,7 +241,6 @@
|
|||||||
"@scalar/oas-utils": "^0.2.120",
|
"@scalar/oas-utils": "^0.2.120",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"flatted": "^3.2.9",
|
"flatted": "^3.2.9",
|
||||||
"json-decycle": "^4.0.0",
|
|
||||||
"json-xml-parse": "^1.3.0",
|
"json-xml-parse": "^1.3.0",
|
||||||
"react-aria": "^3.37.0",
|
"react-aria": "^3.37.0",
|
||||||
"react-aria-components": "^1.6.0",
|
"react-aria-components": "^1.6.0",
|
||||||
@@ -2070,8 +2069,6 @@
|
|||||||
|
|
||||||
"json-buffer": ["json-buffer@3.0.0", "", {}, "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ=="],
|
"json-buffer": ["json-buffer@3.0.0", "", {}, "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ=="],
|
||||||
|
|
||||||
"json-decycle": ["json-decycle@4.0.0", "", {}, "sha512-3GFL/vWazCbMu1kw+NdIfAHh6Ugq5pxkKcSUnK1f/Fw1nDtt1i+BiBfRJs0iPEKscYAz4k4+osvgjY95hmuJXQ=="],
|
|
||||||
|
|
||||||
"json-parse-even-better-errors": ["json-parse-even-better-errors@2.3.1", "", {}, "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="],
|
"json-parse-even-better-errors": ["json-parse-even-better-errors@2.3.1", "", {}, "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="],
|
||||||
|
|
||||||
"json-schema": ["json-schema@0.4.0", "", {}, "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="],
|
"json-schema": ["json-schema@0.4.0", "", {}, "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="],
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
"@scalar/oas-utils": "^0.2.120",
|
"@scalar/oas-utils": "^0.2.120",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"flatted": "^3.2.9",
|
"flatted": "^3.2.9",
|
||||||
"json-decycle": "^4.0.0",
|
|
||||||
"json-xml-parse": "^1.3.0",
|
"json-xml-parse": "^1.3.0",
|
||||||
"react-aria-components": "^1.6.0",
|
"react-aria-components": "^1.6.0",
|
||||||
"react-aria": "^3.37.0",
|
"react-aria": "^3.37.0",
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
|||||||
import { useId } from 'react';
|
import { useId } from 'react';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { retrocycle } from 'json-decycle';
|
|
||||||
import { Markdown } from './Markdown';
|
import { Markdown } from './Markdown';
|
||||||
import { OpenAPIDisclosure } from './OpenAPIDisclosure';
|
import { OpenAPIDisclosure } from './OpenAPIDisclosure';
|
||||||
import { OpenAPISchemaName } from './OpenAPISchemaName';
|
import { OpenAPISchemaName } from './OpenAPISchemaName';
|
||||||
|
import { retrocycle } from './decycle';
|
||||||
import type { OpenAPIClientContext } from './types';
|
import type { OpenAPIClientContext } from './types';
|
||||||
import { checkIsReference, resolveDescription, resolveFirstExample } from './utils';
|
import { checkIsReference, resolveDescription, resolveFirstExample } from './utils';
|
||||||
|
|
||||||
@@ -122,7 +122,7 @@ export function OpenAPISchemaPropertiesFromServer(props: {
|
|||||||
return (
|
return (
|
||||||
<OpenAPISchemaProperties
|
<OpenAPISchemaProperties
|
||||||
id={props.id}
|
id={props.id}
|
||||||
properties={safeJSONParse(props.properties)}
|
properties={JSON.parse(props.properties, retrocycle())}
|
||||||
context={props.context}
|
context={props.context}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@@ -172,7 +172,12 @@ export function OpenAPIRootSchemaFromServer(props: {
|
|||||||
schema: string;
|
schema: string;
|
||||||
context: OpenAPIClientContext;
|
context: OpenAPIClientContext;
|
||||||
}) {
|
}) {
|
||||||
return <OpenAPIRootSchema schema={safeJSONParse(props.schema)} context={props.context} />;
|
return (
|
||||||
|
<OpenAPIRootSchema
|
||||||
|
schema={JSON.parse(props.schema, retrocycle())}
|
||||||
|
context={props.context}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -460,19 +465,3 @@ function getDisclosureLabel(schema: OpenAPIV3.SchemaObject): string {
|
|||||||
|
|
||||||
return schema.title || 'child attributes';
|
return schema.title || 'child attributes';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Safely parse a JSON string using retrocycle.
|
|
||||||
* If parsing fails, it falls back to standard JSON.parse.
|
|
||||||
*/
|
|
||||||
function safeJSONParse(jsonString: string) {
|
|
||||||
try {
|
|
||||||
return JSON.parse(jsonString, retrocycle());
|
|
||||||
} catch {
|
|
||||||
try {
|
|
||||||
return JSON.parse(jsonString);
|
|
||||||
} catch (fallbackError) {
|
|
||||||
throw new Error(`Failed to parse JSON string: ${fallbackError}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
||||||
import { decycle } from 'json-decycle';
|
|
||||||
import {
|
import {
|
||||||
OpenAPIRootSchemaFromServer,
|
OpenAPIRootSchemaFromServer,
|
||||||
OpenAPISchemaPropertiesFromServer,
|
OpenAPISchemaPropertiesFromServer,
|
||||||
type OpenAPISchemaPropertyEntry,
|
type OpenAPISchemaPropertyEntry,
|
||||||
} from './OpenAPISchema';
|
} from './OpenAPISchema';
|
||||||
|
import { decycle } from './decycle';
|
||||||
import type { OpenAPIClientContext } from './types';
|
import type { OpenAPIClientContext } from './types';
|
||||||
|
|
||||||
export function OpenAPISchemaProperties(props: {
|
export function OpenAPISchemaProperties(props: {
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
// Forked from: https://github.com/YChebotaev/json-decycle/blob/master/src/index.ts
|
||||||
|
// Replaced `$ref` with `$reference` to avoid conflicts with OpenAPI
|
||||||
|
|
||||||
|
const isObject = (value: any): value is object =>
|
||||||
|
typeof value === 'object' &&
|
||||||
|
value != null &&
|
||||||
|
!(value instanceof Boolean) &&
|
||||||
|
!(value instanceof Date) &&
|
||||||
|
!(value instanceof Number) &&
|
||||||
|
!(value instanceof RegExp) &&
|
||||||
|
!(value instanceof String);
|
||||||
|
|
||||||
|
const toPointer = (parts: string[]) =>
|
||||||
|
`#${parts.map((part) => String(part).replace(/~/g, '~0').replace(/\//g, '~1')).join('/')}`;
|
||||||
|
|
||||||
|
export const decycle = () => {
|
||||||
|
const paths = new WeakMap();
|
||||||
|
|
||||||
|
return function replacer(this: any, key: string | symbol, value: any) {
|
||||||
|
if (key !== '$reference' && isObject(value)) {
|
||||||
|
const seen = paths.has(value);
|
||||||
|
|
||||||
|
if (seen) {
|
||||||
|
return { $reference: toPointer(paths.get(value)) };
|
||||||
|
}
|
||||||
|
|
||||||
|
paths.set(value, [...(paths.get(this) ?? []), key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export function retrocycle() {
|
||||||
|
const parents = new WeakMap();
|
||||||
|
const keys = new WeakMap();
|
||||||
|
const refs = new Set();
|
||||||
|
|
||||||
|
function dereference(this: { [k: string]: any }, ref: { $reference: string }) {
|
||||||
|
const parts = ref.$reference.slice(1).split('/');
|
||||||
|
let key: any;
|
||||||
|
let value = this;
|
||||||
|
|
||||||
|
for (let i = 0; i < parts.length; i++) {
|
||||||
|
key = parts[i]?.replace(/~1/g, '/').replace(/~0/g, '~');
|
||||||
|
value = value[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
const parent = parents.get(ref);
|
||||||
|
parent[keys.get(ref)] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return function reviver(this: object, key: string | symbol, value: any) {
|
||||||
|
if (key === '$reference') {
|
||||||
|
refs.add(this);
|
||||||
|
} else if (isObject(value)) {
|
||||||
|
const isRoot = key === '' && Object.keys(this).length === 1;
|
||||||
|
if (isRoot) {
|
||||||
|
refs.forEach(dereference as any, this);
|
||||||
|
} else {
|
||||||
|
parents.set(value, this);
|
||||||
|
keys.set(value, key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user