zudoku 0.1.1-dev.2 → 0.1.1-dev.3

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.
Files changed (110) hide show
  1. package/dist/app/{app.js → App.js} +2 -21
  2. package/dist/app/App.js.map +1 -0
  3. package/dist/app/DevPortal.d.ts +0 -1
  4. package/dist/app/authentication/openid.js +2 -2
  5. package/dist/app/authentication/openid.js.map +1 -1
  6. package/dist/app/components/Dialog.d.ts +19 -0
  7. package/dist/app/components/Dialog.js +23 -0
  8. package/dist/app/components/Dialog.js.map +1 -0
  9. package/dist/app/components/Header.d.ts +0 -1
  10. package/dist/app/components/Input.d.ts +5 -0
  11. package/dist/app/components/Input.js +9 -0
  12. package/dist/app/components/Input.js.map +1 -0
  13. package/dist/app/components/SyntaxHighlight.js +2 -0
  14. package/dist/app/components/SyntaxHighlight.js.map +1 -1
  15. package/dist/app/components/context/DevPortalProvider.d.ts +0 -1
  16. package/dist/app/components/navigation/SideNavigationWrapper.d.ts +1 -2
  17. package/dist/app/components/navigation/useNavigationCollapsibleState.d.ts +0 -1
  18. package/dist/app/main.js +1 -1
  19. package/dist/app/plugins/markdown/index.d.ts +0 -1
  20. package/dist/app/plugins/openapi/ColorizedParam.d.ts +5 -1
  21. package/dist/app/plugins/openapi/ColorizedParam.js +10 -5
  22. package/dist/app/plugins/openapi/ColorizedParam.js.map +1 -1
  23. package/dist/app/plugins/openapi/MakeRequest.js +18 -6
  24. package/dist/app/plugins/openapi/MakeRequest.js.map +1 -1
  25. package/dist/app/plugins/openapi/OperationList.d.ts +2 -45
  26. package/dist/app/plugins/openapi/OperationList.js +18 -17
  27. package/dist/app/plugins/openapi/OperationList.js.map +1 -1
  28. package/dist/app/plugins/openapi/OperationListItem.d.ts +2 -2
  29. package/dist/app/plugins/openapi/OperationListItem.js +2 -2
  30. package/dist/app/plugins/openapi/OperationListItem.js.map +1 -1
  31. package/dist/app/plugins/openapi/RequestBodySidecarBox.js +8 -8
  32. package/dist/app/plugins/openapi/RequestBodySidecarBox.js.map +1 -1
  33. package/dist/app/plugins/openapi/ResponsesSidecarBox.js +1 -1
  34. package/dist/app/plugins/openapi/ResponsesSidecarBox.js.map +1 -1
  35. package/dist/app/plugins/openapi/Sidecar.js +73 -18
  36. package/dist/app/plugins/openapi/Sidecar.js.map +1 -1
  37. package/dist/app/plugins/openapi/SidecarBox.d.ts +3 -5
  38. package/dist/app/plugins/openapi/SidecarBox.js +3 -5
  39. package/dist/app/plugins/openapi/SidecarBox.js.map +1 -1
  40. package/dist/app/plugins/openapi/graphql/fragment-masking.d.ts +19 -0
  41. package/dist/app/plugins/openapi/graphql/fragment-masking.js +16 -0
  42. package/dist/app/plugins/openapi/graphql/fragment-masking.js.map +1 -0
  43. package/dist/app/plugins/openapi/graphql/gql.d.ts +58 -0
  44. package/dist/app/plugins/openapi/graphql/gql.js +22 -0
  45. package/dist/app/plugins/openapi/graphql/gql.js.map +1 -0
  46. package/dist/app/plugins/openapi/graphql/graphql.d.ts +291 -0
  47. package/dist/app/plugins/openapi/graphql/graphql.js +539 -0
  48. package/dist/app/plugins/openapi/graphql/graphql.js.map +1 -0
  49. package/dist/app/plugins/openapi/graphql/index.d.ts +2 -836
  50. package/dist/app/plugins/openapi/graphql/index.js +2 -3
  51. package/dist/app/plugins/openapi/graphql/index.js.map +1 -1
  52. package/dist/app/plugins/openapi/index.d.ts +0 -1
  53. package/dist/app/plugins/openapi/index.js +2 -1
  54. package/dist/app/plugins/openapi/index.js.map +1 -1
  55. package/dist/app/plugins/openapi/playground/Playground.d.ts +8 -0
  56. package/dist/app/plugins/openapi/playground/Playground.js +98 -0
  57. package/dist/app/plugins/openapi/playground/Playground.js.map +1 -0
  58. package/dist/app/plugins/openapi/util/urql.d.ts +0 -1
  59. package/dist/app/ui/Button.d.ts +11 -0
  60. package/dist/app/ui/Button.js +34 -0
  61. package/dist/app/ui/Button.js.map +1 -0
  62. package/dist/app/ui/Card.js +1 -1
  63. package/dist/app/ui/Card.js.map +1 -1
  64. package/dist/app/ui/Tabs.d.ts +7 -0
  65. package/dist/app/ui/Tabs.js +13 -0
  66. package/dist/app/ui/Tabs.js.map +1 -0
  67. package/dist/app/util/MdxComponents.d.ts +2 -2
  68. package/dist/app/util/createVariantComponent.d.ts +15 -0
  69. package/dist/app/util/createVariantComponent.js +12 -0
  70. package/dist/app/util/createVariantComponent.js.map +1 -0
  71. package/dist/app/util/createWaitForNotify.d.ts +1 -1
  72. package/dist/app/util/slugify.d.ts +0 -1
  73. package/dist/vite/config.d.ts +1 -0
  74. package/dist/vite/config.js +45 -10
  75. package/dist/vite/config.js.map +1 -1
  76. package/dist/vite/config.test.d.ts +1 -0
  77. package/dist/vite/config.test.js +9 -0
  78. package/dist/vite/config.test.js.map +1 -0
  79. package/package.json +15 -5
  80. package/src/app/{app.tsx → App.tsx} +1 -23
  81. package/src/app/components/Dialog.tsx +119 -0
  82. package/src/app/components/Input.tsx +24 -0
  83. package/src/app/components/SyntaxHighlight.tsx +2 -0
  84. package/src/app/main.tsx +1 -1
  85. package/src/app/plugins/openapi/ColorizedParam.tsx +18 -9
  86. package/src/app/plugins/openapi/MakeRequest.tsx +19 -0
  87. package/src/app/plugins/openapi/OperationList.tsx +22 -23
  88. package/src/app/plugins/openapi/OperationListItem.tsx +3 -3
  89. package/src/app/plugins/openapi/RequestBodySidecarBox.tsx +31 -28
  90. package/src/app/plugins/openapi/ResponsesSidecarBox.tsx +1 -1
  91. package/src/app/plugins/openapi/Sidecar.tsx +81 -20
  92. package/src/app/plugins/openapi/SidecarBox.tsx +30 -29
  93. package/src/app/plugins/openapi/graphql/fragment-masking.ts +111 -0
  94. package/src/app/plugins/openapi/graphql/gql.ts +70 -0
  95. package/src/app/plugins/openapi/graphql/graphql.ts +804 -0
  96. package/src/app/plugins/openapi/graphql/index.ts +2 -13
  97. package/src/app/plugins/openapi/index.tsx +2 -1
  98. package/src/app/plugins/openapi/playground/Playground.tsx +309 -0
  99. package/src/app/plugins/openapi/queries.graphql +6 -0
  100. package/src/app/ui/Button.tsx +56 -0
  101. package/src/app/ui/Card.tsx +1 -1
  102. package/src/app/ui/Tabs.tsx +52 -0
  103. package/src/app/util/createVariantComponent.tsx +30 -0
  104. package/dist/app/app.js.map +0 -1
  105. package/dist/app/plugins/openapi/util/getCode.d.ts +0 -2
  106. package/dist/app/plugins/openapi/util/getCode.js +0 -54
  107. package/dist/app/plugins/openapi/util/getCode.js.map +0 -1
  108. package/src/app/plugins/openapi/graphql/env.d.ts +0 -48
  109. package/src/app/plugins/openapi/util/getCode.tsx +0 -69
  110. /package/dist/app/{app.d.ts → App.d.ts} +0 -0
@@ -0,0 +1,119 @@
1
+ import * as React from "react"
2
+ import * as DialogPrimitive from "@radix-ui/react-dialog"
3
+ import { XIcon } from "lucide-react"
4
+ import { cn } from "../util/cn.js";
5
+
6
+ const Dialog = DialogPrimitive.Root
7
+
8
+ const DialogTrigger = DialogPrimitive.Trigger
9
+
10
+ const DialogPortal = DialogPrimitive.Portal
11
+
12
+ const DialogClose = DialogPrimitive.Close
13
+
14
+ const DialogOverlay = React.forwardRef<
15
+ React.ElementRef<typeof DialogPrimitive.Overlay>,
16
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
17
+ >(({ className, ...props }, ref) => (
18
+ <DialogPrimitive.Overlay
19
+ ref={ref}
20
+ className={cn(
21
+ "fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
22
+ className
23
+ )}
24
+ {...props}
25
+ />
26
+ ))
27
+ DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
28
+
29
+ const DialogContent = React.forwardRef<
30
+ React.ElementRef<typeof DialogPrimitive.Content>,
31
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
32
+ >(({ className, children, ...props }, ref) => (
33
+ <DialogPortal>
34
+ <DialogOverlay />
35
+ <DialogPrimitive.Content
36
+ ref={ref}
37
+ className={cn(
38
+ "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
39
+ className
40
+ )}
41
+ {...props}
42
+ >
43
+ {children}
44
+ <DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
45
+ <XIcon className="h-4 w-4" />
46
+ <span className="sr-only">Close</span>
47
+ </DialogPrimitive.Close>
48
+ </DialogPrimitive.Content>
49
+ </DialogPortal>
50
+ ))
51
+ DialogContent.displayName = DialogPrimitive.Content.displayName
52
+
53
+ const DialogHeader = ({
54
+ className,
55
+ ...props
56
+ }: React.HTMLAttributes<HTMLDivElement>) => (
57
+ <div
58
+ className={cn(
59
+ "flex flex-col space-y-1.5 text-center sm:text-left",
60
+ className
61
+ )}
62
+ {...props}
63
+ />
64
+ )
65
+ DialogHeader.displayName = "DialogHeader"
66
+
67
+ const DialogFooter = ({
68
+ className,
69
+ ...props
70
+ }: React.HTMLAttributes<HTMLDivElement>) => (
71
+ <div
72
+ className={cn(
73
+ "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
74
+ className
75
+ )}
76
+ {...props}
77
+ />
78
+ )
79
+ DialogFooter.displayName = "DialogFooter"
80
+
81
+ const DialogTitle = React.forwardRef<
82
+ React.ElementRef<typeof DialogPrimitive.Title>,
83
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
84
+ >(({ className, ...props }, ref) => (
85
+ <DialogPrimitive.Title
86
+ ref={ref}
87
+ className={cn(
88
+ "text-lg font-semibold leading-none tracking-tight",
89
+ className
90
+ )}
91
+ {...props}
92
+ />
93
+ ))
94
+ DialogTitle.displayName = DialogPrimitive.Title.displayName
95
+
96
+ const DialogDescription = React.forwardRef<
97
+ React.ElementRef<typeof DialogPrimitive.Description>,
98
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
99
+ >(({ className, ...props }, ref) => (
100
+ <DialogPrimitive.Description
101
+ ref={ref}
102
+ className={cn("text-sm text-muted-foreground", className)}
103
+ {...props}
104
+ />
105
+ ))
106
+ DialogDescription.displayName = DialogPrimitive.Description.displayName
107
+
108
+ export {
109
+ Dialog,
110
+ DialogPortal,
111
+ DialogOverlay,
112
+ DialogTrigger,
113
+ DialogClose,
114
+ DialogContent,
115
+ DialogHeader,
116
+ DialogFooter,
117
+ DialogTitle,
118
+ DialogDescription,
119
+ }
@@ -0,0 +1,24 @@
1
+ import * as React from "react";
2
+ import { cn } from "../util/cn.js";
3
+
4
+ export interface InputProps
5
+ extends React.InputHTMLAttributes<HTMLInputElement> {}
6
+
7
+ const Input = React.forwardRef<HTMLInputElement, InputProps>(
8
+ ({ className, type, ...props }, ref) => {
9
+ return (
10
+ <input
11
+ type={type}
12
+ className={cn(
13
+ "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
14
+ className,
15
+ )}
16
+ ref={ref}
17
+ {...props}
18
+ />
19
+ );
20
+ },
21
+ );
22
+ Input.displayName = "Input";
23
+
24
+ export { Input };
@@ -19,6 +19,8 @@ if (!import.meta.env.SSR) {
19
19
  import("prismjs/components/prism-php.min.js");
20
20
  // @ts-expect-error This is untyped
21
21
  import("prismjs/components/prism-json.min.js");
22
+ // @ts-expect-error This is untyped
23
+ import("prismjs/components/prism-java.min.js");
22
24
  }
23
25
 
24
26
  import { useState } from "react";
package/src/app/main.tsx CHANGED
@@ -1,6 +1,6 @@
1
1
  import React from "react";
2
2
  import ReactDOM from "react-dom/client";
3
- import App from "./app.js";
3
+ import App from "./App.js";
4
4
 
5
5
  // if (import.meta.env.DEV) {
6
6
  // const { default: wdyr } = await import(
@@ -3,34 +3,42 @@ import { useTheme } from "../../components/context/ThemeContext.js";
3
3
  import { cn } from "../../util/cn.js";
4
4
  import { pastellize } from "../../util/pastellize.js";
5
5
 
6
- const DATA_ATTR = "data-linked-param";
6
+ export const DATA_ATTR = "data-linked-param";
7
+
8
+ export const usePastellizedColor = (name: string) => {
9
+ const [isDark] = useTheme();
10
+ return pastellize(
11
+ name,
12
+ !isDark ? { saturation: 100, lightness: 70 } : undefined,
13
+ );
14
+ };
7
15
 
8
16
  export const ColorizedParam = ({
9
17
  name,
18
+ value,
10
19
  className,
11
20
  backgroundOpacity = "100%",
12
21
  slug,
13
22
  children,
23
+ onClick,
14
24
  }: {
15
25
  name: string;
26
+ value?: string;
16
27
  className?: string;
17
28
  backgroundOpacity?: string;
18
29
  slug?: string;
19
30
  children?: ReactNode;
31
+ onClick?: () => void;
20
32
  }) => {
21
33
  const ref = useRef<HTMLSpanElement>(null);
22
- const [isDark] = useTheme();
23
34
  const normalized = name.replace("{", "").replace("}", "");
24
-
25
- const color = pastellize(
26
- normalized,
27
- !isDark ? { saturation: 100, lightness: 70 } : undefined,
28
- );
35
+ const color = usePastellizedColor(normalized);
29
36
 
30
37
  const borderColor = `hsl(${color})`;
31
38
  const backgroundColor = `hsl(${color} / ${backgroundOpacity})`;
32
39
 
33
40
  useEffect(() => {
41
+ if (!slug) return;
34
42
  if (!ref.current) return;
35
43
 
36
44
  const onMouseEnter = () => {
@@ -62,12 +70,13 @@ export const ColorizedParam = ({
62
70
  className={cn("inline-flex relative rounded group", className)}
63
71
  {...{ [DATA_ATTR]: slug }}
64
72
  ref={ref}
73
+ onClick={onClick}
65
74
  >
66
75
  <span
67
- className="absolute inset-0 border-b-2 rounded transition-opacity duration-200 opacity-30 group-data-[active=true]:opacity-100"
76
+ className="absolute inset-0 border-b-2 transition-opacity duration-200 opacity-30 group-data-[active=true]:opacity-100"
68
77
  style={{ borderColor, backgroundColor }}
69
78
  />
70
- <span className="relative">{children ?? name}</span>
79
+ <span className="relative">{children || name}</span>
71
80
  </span>
72
81
  );
73
82
  };
@@ -1,5 +1,16 @@
1
1
  import { useApiIdentities } from "../../components/context/DevPortalProvider.js";
2
2
  import type { OperationListItemResult } from "./OperationList.js";
3
+ import { Playground } from "./playground/Playground.js";
4
+ import { useOasConfig } from "./index.js";
5
+ import { gql, useQuery } from "urql";
6
+
7
+ const getServerQuery = gql`
8
+ query getServerQuery($input: JSON!, $type: SchemaType!) {
9
+ schema(input: $input, type: $type) {
10
+ url
11
+ }
12
+ }
13
+ `;
3
14
 
4
15
  export const MakeRequest = ({
5
16
  operation,
@@ -7,9 +18,17 @@ export const MakeRequest = ({
7
18
  operation: OperationListItemResult;
8
19
  }) => {
9
20
  const identities = useApiIdentities();
21
+ const variables = useOasConfig();
22
+ const [server] = useQuery({ query: getServerQuery, variables });
10
23
 
11
24
  return (
12
25
  <div>
26
+ <Playground
27
+ host={server.data?.schema.url}
28
+ method={operation.method}
29
+ url={operation.path}
30
+ defaultHeaders={[]}
31
+ />
13
32
  {identities.data.map((identity) => (
14
33
  <button
15
34
  key={identity.id}
@@ -1,14 +1,15 @@
1
- import { type ResultOf } from "gql.tada";
2
1
  import { Heading } from "../../Heading.js";
3
2
  import { CategoryHeading } from "../../components/CategoryHeading.js";
4
3
  import { Markdown, ProseClasses } from "../../components/Markdown.js";
5
4
  import { cn } from "../../util/cn.js";
6
5
  import { OperationListItem } from "./OperationListItem.js";
7
- import { graphql } from "./graphql/index.js";
8
6
  import { useOasConfig } from "./index.js";
7
+ import { graphql } from "./graphql/index.js";
8
+ import { SchemaType } from "./graphql/graphql.js";
9
9
  import { useQuery } from "./util/urql.js";
10
+ import { ResultOf } from "@graphql-typed-document-node/core";
10
11
 
11
- export const OperationsFragment = graphql(`
12
+ export const OperationsFragment = graphql(/* GraphQL */ `
12
13
  fragment OperationsFragment on OperationItem {
13
14
  slug
14
15
  summary
@@ -51,35 +52,33 @@ export const OperationsFragment = graphql(`
51
52
  }
52
53
  `);
53
54
 
54
- const AllOperationsQuery = graphql(
55
- `
56
- query AllOperations($input: JSON!, $type: SchemaType!) {
57
- schema(input: $input, type: $type) {
55
+ export type OperationListItemResult = ResultOf<typeof OperationsFragment>;
56
+
57
+ const AllOperationsQuery = graphql(/* GraphQL */ `
58
+ query AllOperations($input: JSON!, $type: SchemaType!) {
59
+ schema(input: $input, type: $type) {
60
+ description
61
+ title
62
+ url
63
+ version
64
+ tags {
65
+ name
58
66
  description
59
- title
60
- url
61
- version
62
- tags {
63
- name
64
- description
65
- operations {
66
- slug
67
- ...OperationsFragment
68
- }
67
+ operations {
68
+ slug
69
+ ...OperationsFragment
69
70
  }
70
71
  }
71
72
  }
72
- `,
73
- [OperationsFragment],
74
- );
75
-
76
- export type OperationListItemResult = ResultOf<typeof OperationsFragment>;
73
+ }
74
+ `);
77
75
 
78
76
  export const OperationList = () => {
79
77
  const { type, input } = useOasConfig();
78
+
80
79
  const [result] = useQuery({
81
80
  query: AllOperationsQuery,
82
- variables: { type, input },
81
+ variables: { type: SchemaType.Url, input },
83
82
  });
84
83
 
85
84
  if (!result.data) return null;
@@ -1,10 +1,10 @@
1
- import { readFragment, type FragmentOf } from "gql.tada";
2
1
  import { Heading } from "../../Heading.js";
3
2
  import { Markdown, ProseClasses } from "../../components/Markdown.js";
4
3
  import { groupBy } from "../../util/groupBy.js";
5
4
  import { OperationsFragment } from "./OperationList.js";
6
5
  import { ParameterList } from "./ParameterList.js";
7
6
  import { Sidecar } from "./Sidecar.js";
7
+ import { FragmentType, useFragment } from "./graphql/index.js";
8
8
 
9
9
  export const PARAM_GROUPS = ["path", "query", "header", "cookie"] as const;
10
10
  export type ParameterGroup = (typeof PARAM_GROUPS)[number];
@@ -12,9 +12,9 @@ export type ParameterGroup = (typeof PARAM_GROUPS)[number];
12
12
  export const OperationListItem = ({
13
13
  operationFragment,
14
14
  }: {
15
- operationFragment: FragmentOf<typeof OperationsFragment>;
15
+ operationFragment: FragmentType<typeof OperationsFragment>;
16
16
  }) => {
17
- const operation = readFragment(OperationsFragment, operationFragment);
17
+ const operation = useFragment(OperationsFragment, operationFragment);
18
18
  const groupedParameters = groupBy(operation?.parameters ?? [], "in");
19
19
 
20
20
  return (
@@ -3,7 +3,7 @@ import { SyntaxHighlight } from "../../components/SyntaxHighlight.js";
3
3
  import { type SchemaObject } from "../../oas/graphql/index.js";
4
4
  import type { OperationListItemResult } from "./OperationList.js";
5
5
  import { Select } from "./Select.js";
6
- import { SidecarBox } from "./SidecarBox.js";
6
+ import * as SidecarBox from "./SidecarBox.js";
7
7
  import { generateSchemaExample } from "./util/generateSchemaExample.js";
8
8
 
9
9
  type Content = NonNullable<
@@ -17,32 +17,35 @@ export const RequestBodySidecarBox = ({ content }: { content: Content }) => {
17
17
  if (!content.length) return null;
18
18
 
19
19
  return (
20
- <SidecarBox.Root>
21
- <SidecarBox.Head className="text-xs flex justify-between items-center">
22
- <span className="font-mono">Request Body</span>
23
- <Select
24
- onChange={(e) => setSelected(e.target.value)}
25
- options={[
26
- { value: "example", label: "Example" },
27
- { value: "schema", label: "Schema" },
28
- ]}
29
- />
30
- </SidecarBox.Head>
31
- <SidecarBox.Body>
32
- <SyntaxHighlight
33
- language="json"
34
- noBackground
35
- copyable={false}
36
- className="text-xs"
37
- code={JSON.stringify(
38
- selected === "example"
39
- ? generateSchemaExample(content[0].schema as SchemaObject)
40
- : content[0].schema,
41
- null,
42
- 2,
43
- )}
44
- />
45
- </SidecarBox.Body>
46
- </SidecarBox.Root>
20
+ <>
21
+ <div>lol</div>
22
+ <SidecarBox.Root>
23
+ <SidecarBox.Head className="text-xs flex justify-between items-center">
24
+ <span className="font-mono">Request Body</span>
25
+ <Select
26
+ onChange={(e) => setSelected(e.target.value)}
27
+ options={[
28
+ { value: "example", label: "Example" },
29
+ { value: "schema", label: "Schema" },
30
+ ]}
31
+ />
32
+ </SidecarBox.Head>
33
+ <SidecarBox.Body>
34
+ <SyntaxHighlight
35
+ language="json"
36
+ noBackground
37
+ copyable={false}
38
+ className="text-xs"
39
+ code={JSON.stringify(
40
+ selected === "example"
41
+ ? generateSchemaExample(content[0].schema as SchemaObject)
42
+ : content[0].schema,
43
+ null,
44
+ 2,
45
+ )}
46
+ />
47
+ </SidecarBox.Body>
48
+ </SidecarBox.Root>
49
+ </>
47
50
  );
48
51
  };
@@ -3,7 +3,7 @@ import { SyntaxHighlight } from "../../components/SyntaxHighlight.js";
3
3
  import { type SchemaObject } from "../../oas/graphql/index.js";
4
4
  import { cn } from "../../util/cn.js";
5
5
  import type { OperationListItemResult } from "./OperationList.js";
6
- import { SidecarBox } from "./SidecarBox.js";
6
+ import * as SidecarBox from "./SidecarBox.js";
7
7
  import { generateSchemaExample } from "./util/generateSchemaExample.js";
8
8
 
9
9
  type Responses = OperationListItemResult["responses"];
@@ -1,4 +1,4 @@
1
- import { Fragment, useState } from "react";
1
+ import { Fragment, useMemo, useState } from "react";
2
2
  import { SyntaxHighlight } from "../../components/SyntaxHighlight.js";
3
3
  import { cn } from "../../util/cn.js";
4
4
  import { ColorizedParam } from "./ColorizedParam.js";
@@ -8,8 +8,54 @@ import type { OperationListItemResult } from "./OperationList.js";
8
8
  import { RequestBodySidecarBox } from "./RequestBodySidecarBox.js";
9
9
  import { ResponsesSidecarBox } from "./ResponsesSidecarBox.js";
10
10
  import { Select } from "./Select.js";
11
- import { SidecarBox } from "./SidecarBox.js";
12
- import { getCode } from "./util/getCode.js";
11
+ import * as SidecarBox from "./SidecarBox.js";
12
+ import { HTTPSnippet } from "@zudoku/httpsnippet";
13
+ import { generateSchemaExample } from "./util/generateSchemaExample.js";
14
+ import type { SchemaObject } from "../../oas/parser/index.js";
15
+
16
+ const getConverted = (snippet: HTTPSnippet, option: string) => {
17
+ let converted;
18
+ switch (option) {
19
+ case "shell":
20
+ converted = snippet.convert("shell", "curl");
21
+ break;
22
+ case "js":
23
+ converted = snippet.convert("javascript", "fetch");
24
+ break;
25
+ case "python":
26
+ converted = snippet.convert("python", "requests");
27
+ break;
28
+ case "java":
29
+ converted = snippet.convert("java", "okhttp");
30
+ break;
31
+ case "go":
32
+ converted = snippet.convert("go", "native");
33
+ break;
34
+ case "csharp":
35
+ converted = snippet.convert("csharp", "httpclient");
36
+ break;
37
+ case "kotlin":
38
+ converted = snippet.convert("kotlin", "okhttp");
39
+ break;
40
+ case "objc":
41
+ converted = snippet.convert("objc", "nsurlsession");
42
+ break;
43
+ case "php":
44
+ converted = snippet.convert("php", "http2");
45
+ break;
46
+ case "ruby":
47
+ converted = snippet.convert("ruby");
48
+ break;
49
+ case "swift":
50
+ converted = snippet.convert("swift");
51
+ break;
52
+ default:
53
+ converted = snippet.convert("shell");
54
+ break;
55
+ }
56
+
57
+ return converted ? converted[0] : "";
58
+ };
13
59
 
14
60
  export const Sidecar = ({
15
61
  operation,
@@ -40,16 +86,27 @@ export const Sidecar = ({
40
86
  </Fragment>
41
87
  ));
42
88
 
43
- const language =
44
- {
45
- js: "javascript",
46
- go: "go",
47
- rust: "rust",
48
- curl: "bash",
49
- wget: "bash",
50
- ruby: "ruby",
51
- php: "php",
52
- }[option] ?? "bash";
89
+ const code = useMemo(() => {
90
+ const example = requestBodyContent?.[0]?.schema
91
+ ? generateSchemaExample(requestBodyContent[0].schema as SchemaObject)
92
+ : undefined;
93
+
94
+ const snippet = new HTTPSnippet(
95
+ {
96
+ method: operation.method.toLocaleUpperCase(),
97
+ url: operation.path.replaceAll("{", ":").replaceAll("}", ""),
98
+ headers: [{ name: "Authorization", value: "Bearer <token>" }],
99
+ postData: example
100
+ ? {
101
+ text: JSON.stringify(example, null, 2),
102
+ mimeType: "application/json",
103
+ }
104
+ : {},
105
+ } as never, // 👈 never touch this
106
+ );
107
+
108
+ return getConverted(snippet, option) ?? "";
109
+ }, [option, operation.method, operation.path, requestBodyContent]);
53
110
 
54
111
  return (
55
112
  <aside className="flex flex-col overflow-hidden sticky top-[--scroll-padding] gap-4">
@@ -67,23 +124,27 @@ export const Sidecar = ({
67
124
  className="self-start"
68
125
  onChange={(e) => setOption(e.target.value)}
69
126
  options={[
70
- { value: "curl", label: "cURL" },
71
- { value: "wget", label: "wget" },
127
+ { value: "shell", label: "cURL" },
72
128
  { value: "js", label: "Javascript" },
73
- { value: "ruby", label: "Ruby" },
74
- { value: "php", label: "PHP" },
129
+ { value: "python", label: "Python" },
130
+ { value: "java", label: "Java" },
75
131
  { value: "go", label: "Go" },
76
- { value: "rust", label: "Rust" },
132
+ { value: "csharp", label: "C#" },
133
+ { value: "kotlin", label: "Kotlin" },
134
+ { value: "objc", label: "Objective C" },
135
+ { value: "php", label: "PHP" },
136
+ { value: "ruby", label: "Ruby" },
137
+ { value: "swift", label: "Swift" },
77
138
  ]}
78
139
  />
79
140
  </SidecarBox.Head>
80
141
  <SidecarBox.Body>
81
142
  <SyntaxHighlight
82
- language={language}
143
+ language={option}
83
144
  copyable={false}
84
145
  noBackground
85
146
  className="text-xs"
86
- code={getCode(operation, option.toLowerCase())}
147
+ code={code}
87
148
  />
88
149
  </SidecarBox.Body>
89
150
  </SidecarBox.Root>
@@ -4,32 +4,33 @@ import { cn } from "../../util/cn.js";
4
4
  type BaseComponentProps<T = unknown> = PropsWithChildren<
5
5
  T & { className?: string }
6
6
  >;
7
- export const SidecarBox = {
8
- Root: ({ children, className }: BaseComponentProps) => (
9
- <div
10
- className={cn(
11
- "rounded-lg overflow-hidden border border-border dark:border-transparent",
12
- className,
13
- )}
14
- >
15
- {children}
16
- </div>
17
- ),
18
- Head: ({ children, className }: BaseComponentProps) => (
19
- <div
20
- className={cn(
21
- "border-b border-b-border dark:border-b-zinc-600 bg-zinc-100 dark:bg-zinc-700 p-2",
22
- className,
23
- )}
24
- >
25
- {children}
26
- </div>
27
- ),
28
- Body: ({ children, className }: BaseComponentProps) => (
29
- <div
30
- className={cn("bg-zinc-50 dark:bg-zinc-800 overflow-auto p-2", className)}
31
- >
32
- {children}
33
- </div>
34
- ),
35
- };
7
+
8
+ export const Root = ({ children, className }: BaseComponentProps) => (
9
+ <div
10
+ className={cn(
11
+ "rounded-lg overflow-hidden border border-border dark:border-transparent",
12
+ className,
13
+ )}
14
+ >
15
+ {children}
16
+ </div>
17
+ );
18
+
19
+ export const Head = ({ children, className }: BaseComponentProps) => (
20
+ <div
21
+ className={cn(
22
+ "border-b border-b-border dark:border-b-zinc-600 bg-zinc-100 dark:bg-zinc-700 p-2",
23
+ className,
24
+ )}
25
+ >
26
+ {children}
27
+ </div>
28
+ );
29
+
30
+ export const Body = ({ children, className }: BaseComponentProps) => (
31
+ <div
32
+ className={cn("bg-zinc-50 dark:bg-zinc-800 overflow-auto p-2", className)}
33
+ >
34
+ {children}
35
+ </div>
36
+ );