zudoku 0.0.0-zacd7778d → 0.0.0-zce59fc03
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config/loader.js +3 -1
- package/dist/config/loader.js.map +1 -1
- package/dist/config/validators/InputNavigationSchema.d.ts +119 -119
- package/dist/config/validators/ProtectedRoutesSchema.d.ts +1 -1
- package/dist/config/validators/validate.d.ts +28 -10
- package/dist/config/validators/validate.js +6 -3
- package/dist/config/validators/validate.js.map +1 -1
- package/dist/flat-config.d.ts +28 -27
- package/dist/lib/components/Heading.d.ts +1 -1
- package/dist/lib/components/index.d.ts +18 -74
- package/dist/lib/components/index.js +19 -36
- package/dist/lib/components/index.js.map +1 -1
- package/dist/lib/core/plugins.d.ts +11 -1
- package/dist/lib/core/plugins.js +1 -0
- package/dist/lib/core/plugins.js.map +1 -1
- package/dist/lib/core/transform-config.d.ts +2 -0
- package/dist/lib/core/transform-config.js +22 -0
- package/dist/lib/core/transform-config.js.map +1 -0
- package/dist/lib/hooks/index.d.ts +7 -30
- package/dist/lib/hooks/index.js +7 -15
- package/dist/lib/hooks/index.js.map +1 -1
- package/dist/lib/oas/graphql/circular.d.ts +1 -1
- package/dist/lib/oas/graphql/circular.js +18 -35
- package/dist/lib/oas/graphql/circular.js.map +1 -1
- package/dist/lib/oas/graphql/circular.test.js +33 -2
- package/dist/lib/oas/graphql/circular.test.js.map +1 -1
- package/dist/lib/oas/parser/index.js +14 -5
- package/dist/lib/oas/parser/index.js.map +1 -1
- package/dist/lib/plugins/openapi/OasProvider.js +6 -2
- package/dist/lib/plugins/openapi/OasProvider.js.map +1 -1
- package/dist/lib/plugins/openapi/OperationList.js +4 -8
- package/dist/lib/plugins/openapi/OperationList.js.map +1 -1
- package/dist/lib/plugins/openapi/interfaces.d.ts +3 -0
- package/dist/lib/plugins/openapi/util/getRoutes.d.ts +3 -0
- package/dist/lib/plugins/openapi/util/getRoutes.js +2 -1
- package/dist/lib/plugins/openapi/util/getRoutes.js.map +1 -1
- package/dist/lib/ui/Command.d.ts +3 -3
- package/dist/lib/util/flattenAllOf.d.ts +0 -2
- package/dist/lib/util/flattenAllOf.js +0 -46
- package/dist/lib/util/flattenAllOf.js.map +1 -1
- package/dist/lib/util/flattenAllOf.test.js +2 -1
- package/dist/lib/util/flattenAllOf.test.js.map +1 -1
- package/dist/lib/util/flattenAllOfProcessor.d.ts +2 -0
- package/dist/lib/util/flattenAllOfProcessor.js +48 -0
- package/dist/lib/util/flattenAllOfProcessor.js.map +1 -0
- package/dist/lib/util/readFrontmatter.js +2 -1
- package/dist/lib/util/readFrontmatter.js.map +1 -1
- package/dist/vite/api/SchemaManager.d.ts +11 -1
- package/dist/vite/api/SchemaManager.js +29 -18
- package/dist/vite/api/SchemaManager.js.map +1 -1
- package/dist/vite/api/SchemaManager.test.js +45 -1
- package/dist/vite/api/SchemaManager.test.js.map +1 -1
- package/dist/vite/build.js +91 -73
- package/dist/vite/build.js.map +1 -1
- package/dist/vite/error-handler.js +1 -5
- package/dist/vite/error-handler.js.map +1 -1
- package/dist/vite/mdx/remark-inject-filepath.js +5 -1
- package/dist/vite/mdx/remark-inject-filepath.js.map +1 -1
- package/dist/vite/mdx/remark-link-rewrite.js +3 -2
- package/dist/vite/mdx/remark-link-rewrite.js.map +1 -1
- package/dist/vite/plugin-api.js +5 -3
- package/dist/vite/plugin-api.js.map +1 -1
- package/dist/vite/plugin-docs.js +9 -7
- package/dist/vite/plugin-docs.js.map +1 -1
- package/dist/vite/plugin-markdown-export.js +4 -2
- package/dist/vite/plugin-markdown-export.js.map +1 -1
- package/lib/{ClaudeLogo-DHxJUhN_.js → ClaudeLogo-C6q-Xn_l.js} +26 -22
- package/lib/{ClaudeLogo-DHxJUhN_.js.map → ClaudeLogo-C6q-Xn_l.js.map} +1 -1
- package/lib/{MdxPage-CD36PJ17.js → MdxPage-B1G4W1TK.js} +8 -8
- package/lib/{MdxPage-CD36PJ17.js.map → MdxPage-B1G4W1TK.js.map} +1 -1
- package/lib/{Mermaid-Koc3z8mU.js → Mermaid-B1xNo-pf.js} +3 -2
- package/lib/{Mermaid-Koc3z8mU.js.map → Mermaid-B1xNo-pf.js.map} +1 -1
- package/lib/{OAuthErrorPage-4mN5DA86.js → OAuthErrorPage-01Ke086W.js} +20 -18
- package/lib/{OAuthErrorPage-4mN5DA86.js.map → OAuthErrorPage-01Ke086W.js.map} +1 -1
- package/lib/OasProvider-oHPiMJZg.js +48 -0
- package/lib/OasProvider-oHPiMJZg.js.map +1 -0
- package/lib/{OperationList-CaknPbvq.js → OperationList-CZ4OK8Pm.js} +1284 -1284
- package/lib/OperationList-CZ4OK8Pm.js.map +1 -0
- package/lib/{RouteGuard--A04ESy8.js → RouteGuard-B1lCR0C_.js} +5 -5
- package/lib/{RouteGuard--A04ESy8.js.map → RouteGuard-B1lCR0C_.js.map} +1 -1
- package/lib/{SchemaList-Dw3-CJPb.js → SchemaList-DoQFkJgM.js} +7 -7
- package/lib/{SchemaList-Dw3-CJPb.js.map → SchemaList-DoQFkJgM.js.map} +1 -1
- package/lib/{SchemaView-DyJkiQkD.js → SchemaView-D2k6ZJck.js} +3 -3
- package/lib/{SchemaView-DyJkiQkD.js.map → SchemaView-D2k6ZJck.js.map} +1 -1
- package/lib/{SignUp-DRvN-8cq.js → SignUp-8kDBaLbO.js} +31 -26
- package/lib/{SignUp-DRvN-8cq.js.map → SignUp-8kDBaLbO.js.map} +1 -1
- package/lib/{SyntaxHighlight-klTH8c6-.js → SyntaxHighlight-hZOFnYl0.js} +6 -5
- package/lib/SyntaxHighlight-hZOFnYl0.js.map +1 -0
- package/lib/{Toc-PbuF-u9x.js → Toc-qEIii_-W.js} +2 -2
- package/lib/{Toc-PbuF-u9x.js.map → Toc-qEIii_-W.js.map} +1 -1
- package/lib/{index-BDsEwofZ.js → Zudoku-DUsdmPME.js} +2250 -2268
- package/lib/Zudoku-DUsdmPME.js.map +1 -0
- package/lib/{ZudokuContext-BZB1TWdT.js → ZudokuContext-BBI06sOx.js} +5 -5
- package/lib/{ZudokuContext-BZB1TWdT.js.map → ZudokuContext-BBI06sOx.js.map} +1 -1
- package/lib/{circular-DFquXeY2.js → circular-D9tSKG2c.js} +1327 -1346
- package/lib/{circular-DFquXeY2.js.map → circular-D9tSKG2c.js.map} +1 -1
- package/lib/createServer-BprC4n85.js +13036 -0
- package/lib/createServer-BprC4n85.js.map +1 -0
- package/lib/{errors-rWHkzVTd.js → errors-7hgPDs1h.js} +3 -3
- package/lib/{errors-rWHkzVTd.js.map → errors-7hgPDs1h.js.map} +1 -1
- package/lib/{firebase-BmGU1FuD.js → firebase-Dwn-2ju-.js} +13 -13
- package/lib/firebase-Dwn-2ju-.js.map +1 -0
- package/lib/{hook-BGlHBdET.js → hook-ZEd1Es7D.js} +2 -2
- package/lib/{hook-BGlHBdET.js.map → hook-ZEd1Es7D.js.map} +1 -1
- package/lib/{index-BQB9hb6n.js → index-CyIW9rHv.js} +485 -480
- package/lib/{index-BQB9hb6n.js.map → index-CyIW9rHv.js.map} +1 -1
- package/lib/index-DAWHN3cH.js +86 -0
- package/lib/index-DAWHN3cH.js.map +1 -0
- package/lib/{index-DRBOFufT.js → index-Dxdhrp-I.js} +2 -2
- package/lib/{index-DRBOFufT.js.map → index-Dxdhrp-I.js.map} +1 -1
- package/lib/{index.esm-B_0dvNjB.js → index.esm-Ca5zvoff.js} +20 -20
- package/lib/{index.esm-B_0dvNjB.js.map → index.esm-Ca5zvoff.js.map} +1 -1
- package/lib/{index.esm-Cx8B1YJQ.js → index.esm-DG4KaDKR.js} +2 -2
- package/lib/index.esm-DG4KaDKR.js.map +1 -0
- package/lib/{invariant-BJAl77rw.js → invariant-B_t_F2s_.js} +3 -3
- package/lib/{invariant-BJAl77rw.js.map → invariant-B_t_F2s_.js.map} +1 -1
- package/lib/ui/SyntaxHighlight.js +3 -3
- package/lib/useExposedProps-CzTDfXfq.js +30 -0
- package/lib/useExposedProps-CzTDfXfq.js.map +1 -0
- package/lib/zudoku.__internal.js +1492 -1030
- package/lib/zudoku.__internal.js.map +1 -1
- package/lib/zudoku.auth-auth0.js +1 -1
- package/lib/zudoku.auth-azureb2c.js +4 -4
- package/lib/zudoku.auth-clerk.js +2 -2
- package/lib/zudoku.auth-firebase.js +5 -5
- package/lib/zudoku.auth-openid.js +5 -5
- package/lib/zudoku.auth-supabase.js +4 -4
- package/lib/zudoku.components.js +31 -29
- package/lib/zudoku.components.js.map +1 -1
- package/lib/zudoku.hooks.js +24 -11
- package/lib/zudoku.hooks.js.map +1 -1
- package/lib/zudoku.mermaid.js +4 -3
- package/lib/zudoku.mermaid.js.map +1 -1
- package/lib/zudoku.plugin-api-catalog.js +36 -32
- package/lib/zudoku.plugin-api-catalog.js.map +1 -1
- package/lib/zudoku.plugin-api-keys.js +131 -130
- package/lib/zudoku.plugin-api-keys.js.map +1 -1
- package/lib/zudoku.plugin-custom-pages.js +1 -1
- package/lib/zudoku.plugin-markdown.js +1 -1
- package/lib/zudoku.plugin-openapi.js +2 -2
- package/lib/zudoku.plugin-search-pagefind.js +2 -2
- package/lib/zudoku.plugins.js +9 -8
- package/lib/zudoku.plugins.js.map +1 -1
- package/package.json +11 -9
- package/src/lib/components/index.ts +19 -39
- package/src/lib/core/plugins.ts +21 -1
- package/src/lib/core/transform-config.ts +29 -0
- package/src/lib/hooks/index.ts +7 -16
- package/src/lib/oas/graphql/circular.test.ts +37 -2
- package/src/lib/oas/graphql/circular.ts +25 -51
- package/src/lib/oas/parser/index.ts +17 -6
- package/src/lib/plugins/openapi/OasProvider.tsx +10 -2
- package/src/lib/plugins/openapi/OperationList.tsx +4 -9
- package/src/lib/plugins/openapi/interfaces.ts +6 -1
- package/src/lib/plugins/openapi/util/getRoutes.tsx +4 -1
- package/src/lib/util/flattenAllOf.test.ts +2 -1
- package/src/lib/util/flattenAllOf.ts +0 -57
- package/src/lib/util/flattenAllOfProcessor.ts +58 -0
- package/src/lib/util/readFrontmatter.ts +2 -1
- package/src/shiki/langs/c3.js +1 -0
- package/src/shiki/langs/gn.js +1 -0
- package/src/shiki/langs/moonbit.js +1 -0
- package/src/zuplo/enrich-with-zuplo-mcp.ts +168 -0
- package/src/zuplo/enrich-with-zuplo.ts +254 -0
- package/src/zuplo/policy-types.ts +46 -0
- package/src/zuplo/with-zuplo-processors.ts +35 -0
- package/src/zuplo/with-zuplo.ts +14 -0
- package/lib/OasProvider-DSe-hk5Y.js +0 -40
- package/lib/OasProvider-DSe-hk5Y.js.map +0 -1
- package/lib/OperationList-CaknPbvq.js.map +0 -1
- package/lib/SyntaxHighlight-klTH8c6-.js.map +0 -1
- package/lib/___vite-browser-external_commonjs-proxy-BttVsNON.js +0 -9
- package/lib/___vite-browser-external_commonjs-proxy-BttVsNON.js.map +0 -1
- package/lib/createServer-BXZ0CAUn.js +0 -16693
- package/lib/createServer-BXZ0CAUn.js.map +0 -1
- package/lib/firebase-BmGU1FuD.js.map +0 -1
- package/lib/index-BDsEwofZ.js.map +0 -1
- package/lib/index-DBjOT2H1.js +0 -133
- package/lib/index-DBjOT2H1.js.map +0 -1
- package/lib/index.esm-Cx8B1YJQ.js.map +0 -1
|
@@ -1,46 +1,26 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
} from "./
|
|
14
|
-
import { useZudoku as useZudokuImport } from "./context/ZudokuContext.js";
|
|
15
|
-
import { Heading as HeadingImport } from "./Heading.js";
|
|
16
|
-
import { Markdown as MarkdownImport } from "./Markdown.js";
|
|
17
|
-
import { Slot as SlotImport } from "./Slot.js";
|
|
18
|
-
import { Spinner as SpinnerImport } from "./Spinner.js";
|
|
19
|
-
import { Typography as TypographyImport } from "./Typography.js";
|
|
20
|
-
import { Zudoku as ZudokuImport } from "./Zudoku.js";
|
|
1
|
+
export { Helmet as Head } from "@zudoku/react-helmet-async";
|
|
2
|
+
export { Link } from "react-router";
|
|
3
|
+
export { Button } from "../ui/Button.js";
|
|
4
|
+
export { Callout } from "../ui/Callout.js";
|
|
5
|
+
export { ZudokuError } from "../util/invariant.js";
|
|
6
|
+
export { ClientOnly } from "./ClientOnly.js";
|
|
7
|
+
export { Heading } from "./Heading.js";
|
|
8
|
+
export { Markdown } from "./Markdown.js";
|
|
9
|
+
export { Search } from "./Search.js";
|
|
10
|
+
export { Slot } from "./Slot.js";
|
|
11
|
+
export { Spinner } from "./Spinner.js";
|
|
12
|
+
export { Typography } from "./Typography.js";
|
|
13
|
+
export { Zudoku } from "./Zudoku.js";
|
|
21
14
|
|
|
22
|
-
|
|
23
|
-
export const Heading = /*@__PURE__*/ HeadingImport;
|
|
24
|
-
export const Callout = /*@__PURE__*/ CalloutImport;
|
|
25
|
-
export const Markdown = /*@__PURE__*/ MarkdownImport;
|
|
26
|
-
export const Spinner = /*@__PURE__*/ SpinnerImport;
|
|
27
|
-
export const ClientOnly = /*@__PURE__*/ ClientOnlyImport;
|
|
28
|
-
export const Button = /*@__PURE__*/ ButtonImport;
|
|
29
|
-
export const Link = /*@__PURE__*/ LinkImport;
|
|
30
|
-
export const Zudoku = /*@__PURE__*/ ZudokuImport;
|
|
31
|
-
export const Typography = /*@__PURE__*/ TypographyImport;
|
|
32
|
-
export const Slot = /*@__PURE__*/ SlotImport;
|
|
33
|
-
export const ZudokuError = /*@__PURE__*/ ZudokuErrorImport;
|
|
15
|
+
//
|
|
34
16
|
|
|
35
17
|
/** @deprecated Import from `zudoku/hooks` instead */
|
|
36
|
-
export
|
|
18
|
+
export { useMDXComponents } from "@mdx-js/react";
|
|
37
19
|
/** @deprecated Import from `zudoku/hooks` instead */
|
|
38
|
-
export
|
|
20
|
+
export { useTheme } from "next-themes";
|
|
39
21
|
/** @deprecated Import from `zudoku/hooks` instead */
|
|
40
|
-
export
|
|
22
|
+
export { useAuth } from "../authentication/hook.js";
|
|
41
23
|
/** @deprecated Import from `zudoku/hooks` instead */
|
|
42
|
-
export
|
|
24
|
+
export { CACHE_KEYS, useCache } from "./cache.js";
|
|
43
25
|
/** @deprecated Import from `zudoku/hooks` instead */
|
|
44
|
-
export
|
|
45
|
-
/** @deprecated Import from `zudoku/hooks` instead */
|
|
46
|
-
export const useTheme = /*@__PURE__*/ useThemeImport;
|
|
26
|
+
export { useZudoku } from "./context/ZudokuContext.js";
|
package/src/lib/core/plugins.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { ReactNode } from "react";
|
|
|
3
3
|
import type { Location, RouteObject } from "react-router";
|
|
4
4
|
import type { Navigation } from "../../config/validators/NavigationSchema.js";
|
|
5
5
|
import type { ProtectedRoutesInput } from "../../config/validators/ProtectedRoutesSchema.js";
|
|
6
|
+
import type { ZudokuConfig } from "../../config/validators/validate.js";
|
|
6
7
|
import type { AuthenticationPlugin } from "../authentication/authentication.js";
|
|
7
8
|
import type { MdxComponentsType } from "../util/MdxComponents.js";
|
|
8
9
|
import type {
|
|
@@ -18,7 +19,8 @@ export type ZudokuPlugin =
|
|
|
18
19
|
| ApiIdentityPlugin
|
|
19
20
|
| SearchProviderPlugin
|
|
20
21
|
| EventConsumerPlugin
|
|
21
|
-
| AuthenticationPlugin
|
|
22
|
+
| AuthenticationPlugin
|
|
23
|
+
| TransformConfigPlugin;
|
|
22
24
|
|
|
23
25
|
export type { AuthenticationPlugin, RouteObject };
|
|
24
26
|
|
|
@@ -60,6 +62,19 @@ export type ProfileNavigationItem = {
|
|
|
60
62
|
icon?: LucideIcon;
|
|
61
63
|
};
|
|
62
64
|
|
|
65
|
+
export interface ConfigHookContext {
|
|
66
|
+
mode: typeof process.env.ZUDOKU_ENV;
|
|
67
|
+
rootDir: string;
|
|
68
|
+
configPath: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface TransformConfigPlugin {
|
|
72
|
+
transformConfig?: (
|
|
73
|
+
config: ZudokuConfig,
|
|
74
|
+
ctx: ConfigHookContext,
|
|
75
|
+
) => Partial<ZudokuConfig> | void | Promise<Partial<ZudokuConfig> | void>;
|
|
76
|
+
}
|
|
77
|
+
|
|
63
78
|
export interface CommonPlugin {
|
|
64
79
|
initialize?: (
|
|
65
80
|
context: ZudokuContext,
|
|
@@ -110,3 +125,8 @@ export const isApiIdentityPlugin = (
|
|
|
110
125
|
obj: ZudokuPlugin,
|
|
111
126
|
): obj is ApiIdentityPlugin =>
|
|
112
127
|
"getIdentities" in obj && typeof obj.getIdentities === "function";
|
|
128
|
+
|
|
129
|
+
export const isTransformConfigPlugin = (
|
|
130
|
+
obj: ZudokuPlugin,
|
|
131
|
+
): obj is TransformConfigPlugin =>
|
|
132
|
+
"transformConfig" in obj && typeof obj.transformConfig === "function";
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import createDeepmerge from "@fastify/deepmerge";
|
|
2
|
+
import type { ConfigWithMeta } from "../../config/loader.js";
|
|
3
|
+
import { type ConfigHookContext, isTransformConfigPlugin } from "./plugins.js";
|
|
4
|
+
|
|
5
|
+
const mergeConfig = createDeepmerge({
|
|
6
|
+
mergeArray: (opt) => (_, source) => opt.clone(source),
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
export const runTransformConfigHooks = async (
|
|
10
|
+
config: ConfigWithMeta,
|
|
11
|
+
): Promise<ConfigWithMeta> => {
|
|
12
|
+
const ctx = {
|
|
13
|
+
mode: config.__meta.mode,
|
|
14
|
+
rootDir: config.__meta.rootDir,
|
|
15
|
+
configPath: config.__meta.configPath,
|
|
16
|
+
} satisfies ConfigHookContext;
|
|
17
|
+
const plugins = config.plugins ?? [];
|
|
18
|
+
|
|
19
|
+
let result = config;
|
|
20
|
+
|
|
21
|
+
for (const plugin of plugins.filter(isTransformConfigPlugin)) {
|
|
22
|
+
const partial = await plugin.transformConfig?.(result, ctx);
|
|
23
|
+
if (!partial) continue;
|
|
24
|
+
|
|
25
|
+
result = mergeConfig(result, partial) as ConfigWithMeta;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return result;
|
|
29
|
+
};
|
package/src/lib/hooks/index.ts
CHANGED
|
@@ -1,16 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
export const useEvent = /*@__PURE__*/ useEventImport;
|
|
10
|
-
export const useTheme = /*@__PURE__*/ useThemeImport;
|
|
11
|
-
export const useExposedProps = /*@__PURE__*/ useExposedPropsImport;
|
|
12
|
-
export const useMDXComponents = /*@__PURE__*/ useMDXComponentsImport;
|
|
13
|
-
export const useAuth = /*@__PURE__*/ useAuthImport;
|
|
14
|
-
export const useZudoku = /*@__PURE__*/ useZudokuImport;
|
|
15
|
-
export const useCache = /*@__PURE__*/ useCacheImport;
|
|
16
|
-
export { CACHE_KEYS };
|
|
1
|
+
export { useMDXComponents } from "@mdx-js/react";
|
|
2
|
+
export { useTheme } from "next-themes";
|
|
3
|
+
export { useAuth } from "../authentication/hook.js";
|
|
4
|
+
export { CACHE_KEYS, useCache } from "../components/cache.js";
|
|
5
|
+
export { useZudoku } from "../components/context/ZudokuContext.js";
|
|
6
|
+
export { useExposedProps } from "../util/useExposedProps.js";
|
|
7
|
+
export { useEvent } from "./useEvent.js";
|
|
@@ -156,16 +156,20 @@ describe("handleCircularRefs", () => {
|
|
|
156
156
|
});
|
|
157
157
|
});
|
|
158
158
|
|
|
159
|
-
it("should
|
|
159
|
+
it("should handle shared object instances with __$ref without marking circular", () => {
|
|
160
160
|
const shared = { __$ref: "#/components/schemas/Foo", type: "string" };
|
|
161
161
|
const obj = { a: shared, b: shared };
|
|
162
162
|
const result = handleCircularRefs(obj);
|
|
163
163
|
|
|
164
|
+
// Both should return the cached result, not mark as circular
|
|
164
165
|
expect(result.a).toEqual({
|
|
165
166
|
__$ref: "#/components/schemas/Foo",
|
|
166
167
|
type: "string",
|
|
167
168
|
});
|
|
168
|
-
expect(result.b).
|
|
169
|
+
expect(result.b).toEqual({
|
|
170
|
+
__$ref: "#/components/schemas/Foo",
|
|
171
|
+
type: "string",
|
|
172
|
+
});
|
|
169
173
|
});
|
|
170
174
|
|
|
171
175
|
it("should mark circular ref with property name from path", () => {
|
|
@@ -183,4 +187,35 @@ describe("handleCircularRefs", () => {
|
|
|
183
187
|
|
|
184
188
|
expect(result.properties.child.properties.back).toContain(CIRCULAR_REF);
|
|
185
189
|
});
|
|
190
|
+
|
|
191
|
+
// Exact reproduction of #1869 - shared object instances with __$ref
|
|
192
|
+
it("should NOT mark shared object instances with __$ref as circular (issue #1869)", () => {
|
|
193
|
+
// When dereferencing, the SAME object instance is returned for all refs to the same schema
|
|
194
|
+
const timestampSchema = {
|
|
195
|
+
__$ref: "#/components/schemas/timestamp",
|
|
196
|
+
type: "string",
|
|
197
|
+
format: "date-time",
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
// Both created_at and updated_at point to the SAME object instance
|
|
201
|
+
const obj = {
|
|
202
|
+
type: "object",
|
|
203
|
+
properties: {
|
|
204
|
+
created_at: timestampSchema,
|
|
205
|
+
updated_at: timestampSchema,
|
|
206
|
+
},
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
const result = handleCircularRefs(obj);
|
|
210
|
+
|
|
211
|
+
// The first one should be fully expanded
|
|
212
|
+
expect(result.properties.created_at).toEqual({
|
|
213
|
+
__$ref: "#/components/schemas/timestamp",
|
|
214
|
+
type: "string",
|
|
215
|
+
format: "date-time",
|
|
216
|
+
});
|
|
217
|
+
// The second one should ALSO be fully expanded (not marked as circular)
|
|
218
|
+
expect(typeof result.properties.updated_at).toBe("object");
|
|
219
|
+
expect(result.properties.updated_at).not.toContain(CIRCULAR_REF);
|
|
220
|
+
});
|
|
186
221
|
});
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { GraphQLScalarType } from "graphql/index.js";
|
|
2
2
|
import { GraphQLJSON } from "graphql-type-json";
|
|
3
|
-
import type { RecordAny } from "../../util/traverse.js";
|
|
4
3
|
|
|
5
4
|
export const CIRCULAR_REF = "$[Circular Reference]";
|
|
6
5
|
export const SCHEMA_REF_PREFIX = "$ref:";
|
|
@@ -17,73 +16,48 @@ const OPENAPI_PROPS = new Set([
|
|
|
17
16
|
export const handleCircularRefs = (
|
|
18
17
|
// biome-ignore lint/suspicious/noExplicitAny: Allow any type
|
|
19
18
|
obj: any,
|
|
20
|
-
|
|
19
|
+
currentPath = new WeakSet(),
|
|
21
20
|
refs = new WeakMap(),
|
|
22
21
|
path: string[] = [],
|
|
23
|
-
|
|
22
|
+
currentRefPaths = new Set<string>(),
|
|
24
23
|
// biome-ignore lint/suspicious/noExplicitAny: Allow any type
|
|
25
24
|
): any => {
|
|
26
25
|
if (obj === null || typeof obj !== "object") return obj;
|
|
27
26
|
|
|
28
27
|
const refPath = obj.__$ref;
|
|
28
|
+
const isCircular =
|
|
29
|
+
currentPath.has(obj) ||
|
|
30
|
+
(typeof refPath === "string" && currentRefPaths.has(refPath));
|
|
29
31
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
// instead of the full data to avoid JSON.stringify serializing duplicates
|
|
33
|
-
if (typeof refPath === "string" && seenRefPaths.has(refPath)) {
|
|
34
|
-
return SCHEMA_REF_PREFIX + refPath;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (visited.has(obj)) {
|
|
38
|
-
const cached = refs.get(obj);
|
|
39
|
-
if (cached) {
|
|
40
|
-
return typeof refPath === "string"
|
|
41
|
-
? // If already processed, return ref marker to avoid duplicate serialization
|
|
42
|
-
SCHEMA_REF_PREFIX + refPath
|
|
43
|
-
: cached;
|
|
44
|
-
}
|
|
32
|
+
if (isCircular) {
|
|
33
|
+
if (typeof refPath === "string") return SCHEMA_REF_PREFIX + refPath;
|
|
45
34
|
const circularProp = path.find((p) => !OPENAPI_PROPS.has(p)) || path[0];
|
|
46
|
-
|
|
47
35
|
return [CIRCULAR_REF, circularProp].filter(Boolean).join(":");
|
|
48
36
|
}
|
|
49
37
|
|
|
50
|
-
|
|
38
|
+
if (refs.has(obj)) return refs.get(obj);
|
|
51
39
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if (typeof refPath === "string") {
|
|
55
|
-
seenRefPaths.add(refPath);
|
|
56
|
-
}
|
|
40
|
+
currentPath.add(obj);
|
|
41
|
+
if (typeof refPath === "string") currentRefPaths.add(refPath);
|
|
57
42
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
[...path, index.toString()],
|
|
66
|
-
seenRefPaths,
|
|
67
|
-
),
|
|
43
|
+
const recurse = (value: unknown, key: string) =>
|
|
44
|
+
handleCircularRefs(
|
|
45
|
+
value,
|
|
46
|
+
currentPath,
|
|
47
|
+
refs,
|
|
48
|
+
[...path, key],
|
|
49
|
+
currentRefPaths,
|
|
68
50
|
);
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
visited,
|
|
75
|
-
refs,
|
|
76
|
-
[...path, key],
|
|
77
|
-
seenRefPaths,
|
|
51
|
+
|
|
52
|
+
const result = Array.isArray(obj)
|
|
53
|
+
? obj.map((item, i) => recurse(item, i.toString()))
|
|
54
|
+
: Object.fromEntries(
|
|
55
|
+
Object.entries(obj).map(([k, v]) => [k, recurse(v, k)]),
|
|
78
56
|
);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
refs.set(obj, result);
|
|
82
57
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
58
|
+
refs.set(obj, result);
|
|
59
|
+
currentPath.delete(obj);
|
|
60
|
+
if (typeof refPath === "string") currentRefPaths.delete(refPath);
|
|
87
61
|
|
|
88
62
|
return result;
|
|
89
63
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { GraphQLError } from "graphql/error/index.js";
|
|
2
2
|
import { OpenAPIV3, type OpenAPIV3_1 } from "openapi-types";
|
|
3
|
-
import {
|
|
3
|
+
import { flattenAllOf } from "../../util/flattenAllOf.js";
|
|
4
|
+
import { traverse } from "../../util/traverse.js";
|
|
4
5
|
import { dereference, type JSONSchema } from "./dereference/index.js";
|
|
5
6
|
import { upgradeSchema } from "./upgrade/index.js";
|
|
6
7
|
|
|
@@ -104,11 +105,21 @@ export const validate = async (schemaInput: unknown) => {
|
|
|
104
105
|
const dereferenced = await dereference(schema);
|
|
105
106
|
const upgraded = upgradeSchema(dereferenced);
|
|
106
107
|
|
|
107
|
-
const flattened =
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
108
|
+
const flattened = traverse(upgraded, (spec) => {
|
|
109
|
+
if (!spec || typeof spec !== "object" || Array.isArray(spec)) {
|
|
110
|
+
return spec;
|
|
111
|
+
}
|
|
112
|
+
const isSchemaObject =
|
|
113
|
+
"type" in spec ||
|
|
114
|
+
"properties" in spec ||
|
|
115
|
+
"allOf" in spec ||
|
|
116
|
+
"anyOf" in spec ||
|
|
117
|
+
"oneOf" in spec;
|
|
118
|
+
|
|
119
|
+
if (!isSchemaObject) return spec;
|
|
120
|
+
|
|
121
|
+
return flattenAllOf(spec) as typeof spec;
|
|
122
|
+
}) as OpenAPIDocument;
|
|
112
123
|
|
|
113
124
|
return flattened;
|
|
114
125
|
};
|
|
@@ -19,13 +19,21 @@ export const OasProvider = ({
|
|
|
19
19
|
client: GraphQLClient;
|
|
20
20
|
}) => {
|
|
21
21
|
const value = useMemo(() => {
|
|
22
|
-
const {
|
|
22
|
+
const {
|
|
23
|
+
versions: availableVersions,
|
|
24
|
+
labels,
|
|
25
|
+
downloadUrls,
|
|
26
|
+
} = getVersionMetadata(config);
|
|
23
27
|
const currentVersion = version ?? availableVersions.at(0);
|
|
24
28
|
|
|
25
29
|
const versionLinks = Object.fromEntries(
|
|
26
30
|
availableVersions.map((id) => [
|
|
27
31
|
id,
|
|
28
|
-
{
|
|
32
|
+
{
|
|
33
|
+
path: joinUrl(basePath, id),
|
|
34
|
+
label: labels[id] ?? id,
|
|
35
|
+
downloadUrl: downloadUrls[id],
|
|
36
|
+
},
|
|
29
37
|
]),
|
|
30
38
|
);
|
|
31
39
|
|
|
@@ -20,7 +20,6 @@ import { Heading } from "../../components/Heading.js";
|
|
|
20
20
|
import { Markdown } from "../../components/Markdown.js";
|
|
21
21
|
import { PagefindSearchMeta } from "../../components/PagefindSearchMeta.js";
|
|
22
22
|
import { Pagination } from "../../components/Pagination.js";
|
|
23
|
-
import { joinUrl } from "../../util/joinUrl.js";
|
|
24
23
|
import { useCreateQuery } from "./client/useCreateQuery.js";
|
|
25
24
|
import { useOasConfig } from "./context.js";
|
|
26
25
|
import { DownloadSchemaButton } from "./DownloadSchemaButton.js";
|
|
@@ -151,11 +150,6 @@ const OperationsForTagQuery = graphql(/* GraphQL */ `
|
|
|
151
150
|
|
|
152
151
|
const LAZY_OPERATION_LIST_THRESHOLD = 30;
|
|
153
152
|
|
|
154
|
-
const getFileExtension = (filename: string): string => {
|
|
155
|
-
const lastDotIndex = filename.lastIndexOf(".");
|
|
156
|
-
return lastDotIndex !== -1 ? filename.slice(lastDotIndex) : "";
|
|
157
|
-
};
|
|
158
|
-
|
|
159
153
|
export const OperationList = ({
|
|
160
154
|
tag,
|
|
161
155
|
untagged,
|
|
@@ -163,7 +157,7 @@ export const OperationList = ({
|
|
|
163
157
|
tag?: string;
|
|
164
158
|
untagged?: boolean;
|
|
165
159
|
}) => {
|
|
166
|
-
const {
|
|
160
|
+
const { input, type, versions, version, options } = useOasConfig();
|
|
167
161
|
const { tag: tagFromParams } = useParams<"tag">();
|
|
168
162
|
const query = useCreateQuery(OperationsForTagQuery, {
|
|
169
163
|
input,
|
|
@@ -252,11 +246,12 @@ export const OperationList = ({
|
|
|
252
246
|
const tagTitle = schema.tag.extensions?.["x-displayName"] ?? schema.tag.name;
|
|
253
247
|
const helmetTitle = [tagTitle, title].filter(Boolean).join(" - ");
|
|
254
248
|
|
|
249
|
+
const currentVersion = version != null ? versions[version] : undefined;
|
|
255
250
|
const downloadUrl =
|
|
256
251
|
typeof input === "string"
|
|
257
252
|
? type === "url"
|
|
258
253
|
? input
|
|
259
|
-
:
|
|
254
|
+
: currentVersion?.downloadUrl
|
|
260
255
|
: undefined;
|
|
261
256
|
|
|
262
257
|
return (
|
|
@@ -291,7 +286,7 @@ export const OperationList = ({
|
|
|
291
286
|
{showVersions && (
|
|
292
287
|
<span className="text-xl text-muted-foreground ms-1.5">
|
|
293
288
|
{" "}
|
|
294
|
-
({version})
|
|
289
|
+
({schema.version})
|
|
295
290
|
</span>
|
|
296
291
|
)}
|
|
297
292
|
</Heading>
|
|
@@ -7,6 +7,8 @@ type DynamicInput = () => Promise<unknown>;
|
|
|
7
7
|
|
|
8
8
|
export type VersionedInput<T> = Array<{
|
|
9
9
|
path: string;
|
|
10
|
+
version?: string;
|
|
11
|
+
downloadUrl?: string;
|
|
10
12
|
label?: string;
|
|
11
13
|
input: T;
|
|
12
14
|
}>;
|
|
@@ -85,5 +87,8 @@ export type OasPluginConfig = BaseOasConfig & OasSource;
|
|
|
85
87
|
export type OasPluginContext = BaseOasConfig &
|
|
86
88
|
ContextOasSource & {
|
|
87
89
|
version?: string;
|
|
88
|
-
versions: Record<
|
|
90
|
+
versions: Record<
|
|
91
|
+
string,
|
|
92
|
+
{ path: string; label: string; downloadUrl?: string }
|
|
93
|
+
>;
|
|
89
94
|
};
|
|
@@ -150,7 +150,7 @@ const createVersionRoutes = (
|
|
|
150
150
|
|
|
151
151
|
export const getVersionMetadata = (config: OasPluginConfig) => {
|
|
152
152
|
if (config.type === "raw" || !Array.isArray(config.input)) {
|
|
153
|
-
return { versions: [], labels: {} };
|
|
153
|
+
return { versions: [], labels: {}, downloadUrls: {} };
|
|
154
154
|
}
|
|
155
155
|
|
|
156
156
|
return {
|
|
@@ -158,6 +158,9 @@ export const getVersionMetadata = (config: OasPluginConfig) => {
|
|
|
158
158
|
labels: Object.fromEntries(
|
|
159
159
|
config.input.map((v) => [v.path, v.label ?? v.path]),
|
|
160
160
|
),
|
|
161
|
+
downloadUrls: Object.fromEntries(
|
|
162
|
+
config.input.map((v) => [v.path, v.downloadUrl]),
|
|
163
|
+
),
|
|
161
164
|
};
|
|
162
165
|
};
|
|
163
166
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { JSONSchema7 } from "json-schema";
|
|
2
2
|
import { describe, expect, it, vi } from "vitest";
|
|
3
3
|
import type { OpenAPIDocument } from "../oas/parser/index.js";
|
|
4
|
-
import { flattenAllOf
|
|
4
|
+
import { flattenAllOf } from "./flattenAllOf.js";
|
|
5
|
+
import { flattenAllOfProcessor } from "./flattenAllOfProcessor.js";
|
|
5
6
|
import invariant from "./invariant.js";
|
|
6
7
|
|
|
7
8
|
describe("flattenAllOf", () => {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { $RefParser } from "@apidevtools/json-schema-ref-parser";
|
|
2
1
|
import {
|
|
3
2
|
createComparator,
|
|
4
3
|
createMerger,
|
|
@@ -9,62 +8,6 @@ import {
|
|
|
9
8
|
createIntersector,
|
|
10
9
|
} from "@x0k/json-schema-merge/lib/array";
|
|
11
10
|
import type { JSONSchema7Definition } from "json-schema";
|
|
12
|
-
import type { Processor } from "../../config/validators/BuildSchema.js";
|
|
13
|
-
import type { OpenAPIDocument } from "../oas/parser/index.js";
|
|
14
|
-
import { type RecordAny, traverse } from "./traverse.js";
|
|
15
|
-
|
|
16
|
-
export const flattenAllOfProcessor: Processor = async ({ schema, file }) => {
|
|
17
|
-
try {
|
|
18
|
-
// Resolve refs once - creates a lookup table without modifying the schema
|
|
19
|
-
const parser = new $RefParser();
|
|
20
|
-
await parser.resolve(schema);
|
|
21
|
-
const $refs = parser.$refs;
|
|
22
|
-
|
|
23
|
-
const flattened = traverse(schema, (spec) => {
|
|
24
|
-
if (!spec || typeof spec !== "object" || Array.isArray(spec)) {
|
|
25
|
-
return spec;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const isSchemaObject =
|
|
29
|
-
"type" in spec ||
|
|
30
|
-
"properties" in spec ||
|
|
31
|
-
"allOf" in spec ||
|
|
32
|
-
"anyOf" in spec ||
|
|
33
|
-
"oneOf" in spec;
|
|
34
|
-
|
|
35
|
-
if (!isSchemaObject) return spec;
|
|
36
|
-
|
|
37
|
-
if ("allOf" in spec && Array.isArray(spec.allOf)) {
|
|
38
|
-
const resolvedAllOf = spec.allOf.map((item) => {
|
|
39
|
-
if (
|
|
40
|
-
item &&
|
|
41
|
-
typeof item === "object" &&
|
|
42
|
-
"$ref" in item &&
|
|
43
|
-
typeof item.$ref === "string"
|
|
44
|
-
) {
|
|
45
|
-
try {
|
|
46
|
-
return $refs.get(item.$ref) ?? item;
|
|
47
|
-
} catch {
|
|
48
|
-
return item;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
return item;
|
|
52
|
-
});
|
|
53
|
-
return flattenAllOf({ ...spec, allOf: resolvedAllOf }) as RecordAny;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return flattenAllOf(spec) as RecordAny;
|
|
57
|
-
}) as OpenAPIDocument;
|
|
58
|
-
|
|
59
|
-
return flattened;
|
|
60
|
-
} catch (error) {
|
|
61
|
-
// biome-ignore lint/suspicious/noConsole: Logging allowed here
|
|
62
|
-
console.warn(
|
|
63
|
-
`Failed to flatten \`allOf\` in ${file}: ${error instanceof Error ? error.message : error}`,
|
|
64
|
-
);
|
|
65
|
-
return schema;
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
11
|
|
|
69
12
|
const { compareSchemaDefinitions, compareSchemaValues } = createComparator();
|
|
70
13
|
const { mergeArrayOfSchemaDefinitions } = createMerger({
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { $RefParser } from "@apidevtools/json-schema-ref-parser";
|
|
2
|
+
import type { Processor } from "../../config/validators/BuildSchema.js";
|
|
3
|
+
import type { OpenAPIDocument } from "../oas/parser/index.js";
|
|
4
|
+
import { flattenAllOf } from "./flattenAllOf.js";
|
|
5
|
+
import { type RecordAny, traverse } from "./traverse.js";
|
|
6
|
+
|
|
7
|
+
export const flattenAllOfProcessor: Processor = async ({ schema, file }) => {
|
|
8
|
+
try {
|
|
9
|
+
// Resolve refs once - creates a lookup table without modifying the schema
|
|
10
|
+
const parser = new $RefParser();
|
|
11
|
+
await parser.resolve(schema);
|
|
12
|
+
const $refs = parser.$refs;
|
|
13
|
+
|
|
14
|
+
const flattened = traverse(schema, (spec) => {
|
|
15
|
+
if (!spec || typeof spec !== "object" || Array.isArray(spec)) {
|
|
16
|
+
return spec;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const isSchemaObject =
|
|
20
|
+
"type" in spec ||
|
|
21
|
+
"properties" in spec ||
|
|
22
|
+
"allOf" in spec ||
|
|
23
|
+
"anyOf" in spec ||
|
|
24
|
+
"oneOf" in spec;
|
|
25
|
+
|
|
26
|
+
if (!isSchemaObject) return spec;
|
|
27
|
+
|
|
28
|
+
if ("allOf" in spec && Array.isArray(spec.allOf)) {
|
|
29
|
+
const resolvedAllOf = spec.allOf.map((item) => {
|
|
30
|
+
if (
|
|
31
|
+
item &&
|
|
32
|
+
typeof item === "object" &&
|
|
33
|
+
"$ref" in item &&
|
|
34
|
+
typeof item.$ref === "string"
|
|
35
|
+
) {
|
|
36
|
+
try {
|
|
37
|
+
return $refs.get(item.$ref) ?? item;
|
|
38
|
+
} catch {
|
|
39
|
+
return item;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return item;
|
|
43
|
+
});
|
|
44
|
+
return flattenAllOf({ ...spec, allOf: resolvedAllOf }) as RecordAny;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return flattenAllOf(spec) as RecordAny;
|
|
48
|
+
}) as OpenAPIDocument;
|
|
49
|
+
|
|
50
|
+
return flattened;
|
|
51
|
+
} catch (error) {
|
|
52
|
+
// biome-ignore lint/suspicious/noConsole: Logging allowed here
|
|
53
|
+
console.warn(
|
|
54
|
+
`Failed to flatten \`allOf\` in ${file}: ${error instanceof Error ? error.message : error}`,
|
|
55
|
+
);
|
|
56
|
+
return schema;
|
|
57
|
+
}
|
|
58
|
+
};
|
|
@@ -9,5 +9,6 @@ export const yaml = {
|
|
|
9
9
|
|
|
10
10
|
export const readFrontmatter = async (filePath: string) => {
|
|
11
11
|
const content = await readFile(filePath, "utf-8");
|
|
12
|
-
|
|
12
|
+
const normalizedContent = content.replace(/\r\n/g, "\n");
|
|
13
|
+
return matter(normalizedContent, { engines: { yaml } });
|
|
13
14
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "@shikijs/langs/c3";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "@shikijs/langs/gn";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "@shikijs/langs/moonbit";
|