@gitbook/react-openapi 1.1.9 → 1.1.10

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 (60) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/InteractiveSection.jsx +7 -6
  3. package/dist/OpenAPICodeSample.d.ts +2 -2
  4. package/dist/OpenAPICodeSample.jsx +3 -8
  5. package/dist/OpenAPICodeSampleInteractive.jsx +31 -19
  6. package/dist/OpenAPICodeSampleSelector.d.ts +15 -0
  7. package/dist/OpenAPICodeSampleSelector.jsx +49 -0
  8. package/dist/OpenAPIExample.d.ts +34 -0
  9. package/dist/OpenAPIExample.jsx +103 -0
  10. package/dist/OpenAPIOperation.d.ts +2 -2
  11. package/dist/OpenAPIOperation.jsx +3 -7
  12. package/dist/OpenAPIPath.d.ts +10 -2
  13. package/dist/OpenAPIPath.jsx +9 -4
  14. package/dist/OpenAPIResponseExample.d.ts +2 -2
  15. package/dist/OpenAPIResponseExample.jsx +4 -95
  16. package/dist/OpenAPISchema.jsx +18 -5
  17. package/dist/OpenAPISchemaName.jsx +2 -7
  18. package/dist/OpenAPISecurities.jsx +6 -6
  19. package/dist/OpenAPISelect.d.ts +15 -0
  20. package/dist/OpenAPISelect.jsx +32 -0
  21. package/dist/OpenAPITabs.jsx +9 -9
  22. package/dist/context.d.ts +54 -0
  23. package/dist/context.js +11 -0
  24. package/dist/generateSchemaExample.js +4 -0
  25. package/dist/getOrCreateStoreByKey.d.ts +10 -0
  26. package/dist/getOrCreateStoreByKey.js +20 -0
  27. package/dist/index.d.ts +1 -1
  28. package/dist/resolveOpenAPIOperation.js +10 -5
  29. package/dist/schemas/OpenAPISchemas.d.ts +5 -6
  30. package/dist/schemas/OpenAPISchemas.jsx +45 -38
  31. package/dist/schemas/resolveOpenAPISchemas.d.ts +4 -3
  32. package/dist/schemas/resolveOpenAPISchemas.js +0 -1
  33. package/dist/tsconfig.build.tsbuildinfo +1 -1
  34. package/dist/types.d.ts +32 -26
  35. package/package.json +1 -1
  36. package/src/InteractiveSection.tsx +10 -8
  37. package/src/OpenAPICodeSample.tsx +8 -15
  38. package/src/OpenAPICodeSampleInteractive.tsx +43 -26
  39. package/src/OpenAPICodeSampleSelector.tsx +87 -0
  40. package/src/OpenAPIExample.tsx +129 -0
  41. package/src/OpenAPIOperation.tsx +6 -10
  42. package/src/OpenAPIPath.tsx +23 -6
  43. package/src/OpenAPIResponseExample.tsx +13 -118
  44. package/src/OpenAPISchema.tsx +26 -9
  45. package/src/OpenAPISchemaName.tsx +2 -8
  46. package/src/OpenAPISecurities.tsx +22 -9
  47. package/src/OpenAPISelect.tsx +70 -0
  48. package/src/OpenAPITabs.tsx +9 -9
  49. package/src/context.ts +64 -0
  50. package/src/generateSchemaExample.test.ts +1020 -0
  51. package/src/generateSchemaExample.ts +5 -0
  52. package/src/getOrCreateStoreByKey.ts +35 -0
  53. package/src/index.ts +1 -1
  54. package/src/resolveOpenAPIOperation.ts +14 -3
  55. package/src/schemas/OpenAPISchemas.tsx +75 -70
  56. package/src/schemas/resolveOpenAPISchemas.ts +4 -5
  57. package/src/types.ts +36 -29
  58. package/dist/useSyncedTabsGlobalState.d.ts +0 -10
  59. package/dist/useSyncedTabsGlobalState.js +0 -20
  60. package/src/useSyncedTabsGlobalState.ts +0 -35
@@ -166,6 +166,11 @@ const getExampleFromSchema = (
166
166
  // But if `emptyString` is set, we do want to see some values.
167
167
  const makeUpRandomData = !!options?.emptyString;
168
168
 
169
+ // If the property is deprecated we don't show it in examples.
170
+ if (schema.deprecated) {
171
+ return undefined;
172
+ }
173
+
169
174
  // Check if the property is read-only/write-only
170
175
  if (
171
176
  (options?.mode === 'write' && schema.readOnly) ||
@@ -0,0 +1,35 @@
1
+ 'use client';
2
+
3
+ import { createStore } from 'zustand';
4
+
5
+ type Key = string | number;
6
+
7
+ type State = {
8
+ key: Key | null;
9
+ };
10
+
11
+ type Actions = { setKey: (key: Key | null) => void };
12
+
13
+ type Store = State & Actions;
14
+
15
+ const createStateStore = (initial?: Key) => {
16
+ return createStore<Store>()((set) => ({
17
+ key: initial ?? null,
18
+ setKey: (key) => {
19
+ set(() => ({ key }));
20
+ },
21
+ }));
22
+ };
23
+
24
+ const defaultStores = new Map<string, ReturnType<typeof createStateStore>>();
25
+
26
+ const createStateStoreFactory = (stores: typeof defaultStores) => {
27
+ return (storeKey: string, initialKey?: Key) => {
28
+ if (!stores.has(storeKey)) {
29
+ stores.set(storeKey, createStateStore(initialKey));
30
+ }
31
+ return stores.get(storeKey)!;
32
+ };
33
+ };
34
+
35
+ export const getOrCreateStoreByKey = createStateStoreFactory(defaultStores);
package/src/index.ts CHANGED
@@ -2,4 +2,4 @@ export * from './schemas';
2
2
  export * from './OpenAPIOperation';
3
3
  export * from './OpenAPIOperationContext';
4
4
  export * from './resolveOpenAPIOperation';
5
- export type { OpenAPISchemasData, OpenAPIOperationData } from './types';
5
+ export type { OpenAPIOperationData, OpenAPIContext } from './types';
@@ -40,16 +40,27 @@ export async function resolveOpenAPIOperation(
40
40
  }
41
41
 
42
42
  const servers = 'servers' in schema ? (schema.servers ?? []) : [];
43
- const security = flattenSecurities(operation.security ?? schema.security ?? []);
43
+ const security: OpenAPIV3_1.SecurityRequirementObject[] =
44
+ operation.security ?? schema.security ?? [];
45
+
46
+ // If security includes an empty object, it means that the security is optional
47
+ const isOptionalSecurity = security.some((entry) => Object.keys(entry).length === 0);
48
+ const flatSecurities = flattenSecurities(security);
44
49
 
45
50
  // Resolve securities
46
51
  const securities: OpenAPIOperationData['securities'] = [];
47
- for (const entry of security) {
52
+ for (const entry of flatSecurities) {
48
53
  const securityKey = Object.keys(entry)[0];
49
54
  if (securityKey) {
50
55
  const securityScheme = schema.components?.securitySchemes?.[securityKey];
51
56
  if (securityScheme && !checkIsReference(securityScheme)) {
52
- securities.push([securityKey, securityScheme]);
57
+ securities.push([
58
+ securityKey,
59
+ {
60
+ ...securityScheme,
61
+ required: !isOptionalSecurity,
62
+ },
63
+ ]);
53
64
  }
54
65
  }
55
66
  }
@@ -1,99 +1,104 @@
1
+ import type { OpenAPISchema } from '@gitbook/openapi-parser';
1
2
  import clsx from 'clsx';
2
3
  import { OpenAPIDisclosureGroup } from '../OpenAPIDisclosureGroup';
4
+ import { OpenAPIExample, getExampleFromSchema } from '../OpenAPIExample';
3
5
  import { OpenAPIRootSchema } from '../OpenAPISchemaServer';
4
- import { Section, SectionBody } from '../StaticSection';
5
- import type { OpenAPIClientContext, OpenAPIContextProps, OpenAPISchemasData } from '../types';
6
-
7
- type OpenAPISchemasContextProps = Omit<
8
- OpenAPIContextProps,
9
- 'renderCodeBlock' | 'renderHeading' | 'renderDocument'
10
- >;
6
+ import { Section, SectionBody, StaticSection } from '../StaticSection';
7
+ import { getOpenAPIClientContext } from '../context';
8
+ import type { OpenAPIContext } from '../types';
11
9
 
12
10
  /**
13
- * Display OpenAPI Schemas.
11
+ * OpenAPI Schemas component.
14
12
  */
15
13
  export function OpenAPISchemas(props: {
16
14
  className?: string;
17
- data: OpenAPISchemasData;
18
- context: OpenAPISchemasContextProps;
15
+ schemas: OpenAPISchema[];
16
+ context: OpenAPIContext;
19
17
  /**
20
18
  * Whether to show the schema directly if there is only one.
21
19
  */
22
20
  grouped?: boolean;
23
21
  }) {
24
- const { className, data, context, grouped } = props;
25
- const { schemas } = data;
22
+ const { schemas, context, grouped, className } = props;
26
23
 
27
- const clientContext: OpenAPIClientContext = {
28
- defaultInteractiveOpened: context.defaultInteractiveOpened,
29
- icons: context.icons,
30
- blockKey: context.blockKey,
31
- };
24
+ const firstSchema = schemas[0];
32
25
 
33
- if (!schemas.length) {
26
+ if (!firstSchema) {
34
27
  return null;
35
28
  }
36
29
 
37
- return (
38
- <div className={clsx('openapi-schemas', className)}>
39
- <OpenAPIRootSchemasSchema grouped={grouped} schemas={schemas} context={clientContext} />
40
- </div>
41
- );
42
- }
43
-
44
- /**
45
- * Root schema for OpenAPI schemas.
46
- * It displays a single model or a disclosure group for multiple schemas.
47
- */
48
- function OpenAPIRootSchemasSchema(props: {
49
- schemas: OpenAPISchemasData['schemas'];
50
- context: OpenAPIClientContext;
51
- grouped?: boolean;
52
- }) {
53
- const { schemas, context, grouped } = props;
30
+ const clientContext = getOpenAPIClientContext(context);
54
31
 
55
32
  // If there is only one model and we are not grouping, we show it directly.
56
33
  if (schemas.length === 1 && !grouped) {
57
- const schema = schemas?.[0]?.schema;
58
-
59
- if (!schema) {
60
- return null;
61
- }
62
-
34
+ const title = `The ${firstSchema.name} object`;
63
35
  return (
64
- <Section>
65
- <SectionBody>
66
- <OpenAPIRootSchema schema={schema} context={context} />
67
- </SectionBody>
68
- </Section>
36
+ <div className={clsx('openapi-schemas', className)}>
37
+ <div className="openapi-summary" id={context.id}>
38
+ {context.renderHeading({
39
+ title,
40
+ })}
41
+ </div>
42
+ <div className="openapi-columns">
43
+ <div className="openapi-column-spec">
44
+ <StaticSection className="openapi-parameters" header="Attributes">
45
+ <OpenAPIRootSchema
46
+ schema={firstSchema.schema}
47
+ context={clientContext}
48
+ />
49
+ </StaticSection>
50
+ </div>
51
+ <div className="openapi-column-preview">
52
+ <div className="openapi-column-preview-body">
53
+ <div className="openapi-panel">
54
+ <h4 className="openapi-panel-heading">{title}</h4>
55
+ <div className="openapi-panel-body">
56
+ <OpenAPIExample
57
+ example={getExampleFromSchema({
58
+ schema: firstSchema.schema,
59
+ })}
60
+ context={context}
61
+ syntax="json"
62
+ />
63
+ </div>
64
+ </div>
65
+ </div>
66
+ </div>
67
+ </div>
68
+ </div>
69
69
  );
70
70
  }
71
71
 
72
72
  // If there are multiple schemas, we use a disclosure group to show them all.
73
73
  return (
74
- <OpenAPIDisclosureGroup
75
- allowsMultipleExpanded
76
- icon={context.icons.chevronRight}
77
- groups={schemas.map(({ name, schema }) => ({
78
- id: name,
79
- label: (
80
- <div className="openapi-response-tab-content" key={`model-${name}`}>
81
- <span className="openapi-response-statuscode">{name}</span>
82
- </div>
83
- ),
84
- tabs: [
85
- {
86
- id: 'model',
87
- body: (
88
- <Section className="openapi-section-schemas">
89
- <SectionBody>
90
- <OpenAPIRootSchema schema={schema} context={context} />
91
- </SectionBody>
92
- </Section>
93
- ),
94
- },
95
- ],
96
- }))}
97
- />
74
+ <div className={clsx('openapi-schemas', className)}>
75
+ <OpenAPIDisclosureGroup
76
+ allowsMultipleExpanded
77
+ icon={context.icons.chevronRight}
78
+ groups={schemas.map(({ name, schema }) => ({
79
+ id: name,
80
+ label: (
81
+ <div className="openapi-response-tab-content" key={`model-${name}`}>
82
+ <span className="openapi-response-statuscode">{name}</span>
83
+ </div>
84
+ ),
85
+ tabs: [
86
+ {
87
+ id: 'model',
88
+ body: (
89
+ <Section className="openapi-section-schemas">
90
+ <SectionBody>
91
+ <OpenAPIRootSchema
92
+ schema={schema}
93
+ context={clientContext}
94
+ />
95
+ </SectionBody>
96
+ </Section>
97
+ ),
98
+ },
99
+ ],
100
+ }))}
101
+ />
102
+ </div>
98
103
  );
99
104
  }
@@ -1,9 +1,6 @@
1
- import type { Filesystem, OpenAPIV3xDocument } from '@gitbook/openapi-parser';
1
+ import type { Filesystem, OpenAPISchema, OpenAPIV3xDocument } from '@gitbook/openapi-parser';
2
2
  import { filterSelectedOpenAPISchemas } from '@gitbook/openapi-parser';
3
3
  import { dereferenceFilesystem } from '../dereference';
4
- import type { OpenAPISchemasData } from '../types';
5
-
6
- //!!TODO: We should return only the schemas that are used in the block. Still a WIP awaiting future work.
7
4
 
8
5
  /**
9
6
  * Resolve an OpenAPI schemas from a file and compile it to a more usable format.
@@ -14,7 +11,9 @@ export async function resolveOpenAPISchemas(
14
11
  options: {
15
12
  schemas: string[];
16
13
  }
17
- ): Promise<OpenAPISchemasData | null> {
14
+ ): Promise<{
15
+ schemas: OpenAPISchema[];
16
+ } | null> {
18
17
  const { schemas: selectedSchemas } = options;
19
18
 
20
19
  const schema = await dereferenceFilesystem(filesystem);
package/src/types.ts CHANGED
@@ -1,33 +1,13 @@
1
1
  import type {
2
2
  OpenAPICustomOperationProperties,
3
3
  OpenAPICustomSpecProperties,
4
- OpenAPISchema,
5
4
  OpenAPIV3,
6
5
  } from '@gitbook/openapi-parser';
7
6
 
8
- export interface OpenAPIContextProps extends OpenAPIClientContext {
9
- /**
10
- * Render a code block.
11
- */
12
- renderCodeBlock: (props: { code: string; syntax: string }) => React.ReactNode;
13
- /**
14
- * Render the heading of the operation.
15
- */
16
- renderHeading: (props: {
17
- deprecated: boolean;
18
- title: string;
19
- stability?: string;
20
- }) => React.ReactNode;
7
+ export interface OpenAPIClientContext {
21
8
  /**
22
- * Render the document of the operation.
9
+ * Icons used in the block.
23
10
  */
24
- renderDocument: (props: { document: object }) => React.ReactNode;
25
-
26
- /** Spec url for the Scalar Api Client */
27
- specUrl: string;
28
- }
29
-
30
- export interface OpenAPIClientContext {
31
11
  icons: {
32
12
  chevronDown: React.ReactNode;
33
13
  chevronRight: React.ReactNode;
@@ -39,14 +19,46 @@ export interface OpenAPIClientContext {
39
19
  * @default false
40
20
  */
41
21
  defaultInteractiveOpened?: boolean;
22
+
42
23
  /**
43
24
  * The key of the block
44
25
  */
45
26
  blockKey?: string;
46
- /** Optional id attached to the OpenAPI Operation heading and used as an anchor */
27
+
28
+ /**
29
+ * Optional id attached to the heading and used as an anchor.
30
+ */
47
31
  id?: string;
48
32
  }
49
33
 
34
+ export interface OpenAPIContext extends OpenAPIClientContext {
35
+ /**
36
+ * Render a code block.
37
+ */
38
+ renderCodeBlock: (props: { code: string; syntax: string }) => React.ReactNode;
39
+
40
+ /**
41
+ * Render the heading of the operation.
42
+ */
43
+ renderHeading: (props: {
44
+ deprecated?: boolean;
45
+ title: string;
46
+ stability?: string;
47
+ }) => React.ReactNode;
48
+
49
+ /**
50
+ * Render the document of the operation.
51
+ */
52
+ renderDocument: (props: { document: object }) => React.ReactNode;
53
+
54
+ /**
55
+ * Specification URL.
56
+ */
57
+ specUrl: string;
58
+ }
59
+
60
+ export type OpenAPISecurityWithRequired = OpenAPIV3.SecuritySchemeObject & { required?: boolean };
61
+
50
62
  export interface OpenAPIOperationData extends OpenAPICustomSpecProperties {
51
63
  path: string;
52
64
  method: string;
@@ -58,10 +70,5 @@ export interface OpenAPIOperationData extends OpenAPICustomSpecProperties {
58
70
  operation: OpenAPIV3.OperationObject<OpenAPICustomOperationProperties>;
59
71
 
60
72
  /** Securities that should be used for this operation */
61
- securities: [string, OpenAPIV3.SecuritySchemeObject][];
62
- }
63
-
64
- export interface OpenAPISchemasData {
65
- /** Components schemas to be used for schemas */
66
- schemas: OpenAPISchema[];
73
+ securities: [string, OpenAPISecurityWithRequired][];
67
74
  }
@@ -1,10 +0,0 @@
1
- type Key = string | number;
2
- type TabState = {
3
- tabKey: Key | null;
4
- };
5
- type TabActions = {
6
- setTabKey: (tab: Key | null) => void;
7
- };
8
- type TabStore = TabState & TabActions;
9
- export declare const getOrCreateTabStoreByKey: (storeKey: string, initialKey?: Key) => import("zustand").StoreApi<TabStore>;
10
- export {};
@@ -1,20 +0,0 @@
1
- 'use client';
2
- import { createStore } from 'zustand';
3
- var createTabStore = function (initialTab) {
4
- return createStore()(function (set) { return ({
5
- tabKey: initialTab !== null && initialTab !== void 0 ? initialTab : null,
6
- setTabKey: function (tabKey) {
7
- set(function () { return ({ tabKey: tabKey }); });
8
- },
9
- }); });
10
- };
11
- var defaultTabStores = new Map();
12
- var createTabStoreFactory = function (stores) {
13
- return function (storeKey, initialKey) {
14
- if (!stores.has(storeKey)) {
15
- stores.set(storeKey, createTabStore(initialKey));
16
- }
17
- return stores.get(storeKey);
18
- };
19
- };
20
- export var getOrCreateTabStoreByKey = createTabStoreFactory(defaultTabStores);
@@ -1,35 +0,0 @@
1
- 'use client';
2
-
3
- import { createStore } from 'zustand';
4
-
5
- type Key = string | number;
6
-
7
- type TabState = {
8
- tabKey: Key | null;
9
- };
10
-
11
- type TabActions = { setTabKey: (tab: Key | null) => void };
12
-
13
- type TabStore = TabState & TabActions;
14
-
15
- const createTabStore = (initialTab?: Key) => {
16
- return createStore<TabStore>()((set) => ({
17
- tabKey: initialTab ?? null,
18
- setTabKey: (tabKey) => {
19
- set(() => ({ tabKey }));
20
- },
21
- }));
22
- };
23
-
24
- const defaultTabStores = new Map<string, ReturnType<typeof createTabStore>>();
25
-
26
- const createTabStoreFactory = (stores: typeof defaultTabStores) => {
27
- return (storeKey: string, initialKey?: Key) => {
28
- if (!stores.has(storeKey)) {
29
- stores.set(storeKey, createTabStore(initialKey));
30
- }
31
- return stores.get(storeKey)!;
32
- };
33
- };
34
-
35
- export const getOrCreateTabStoreByKey = createTabStoreFactory(defaultTabStores);