Skip to content

Commit dbb6817

Browse files
committed
Fix after review
1 parent acc529f commit dbb6817

File tree

13 files changed

+220
-153
lines changed

13 files changed

+220
-153
lines changed

packages/gitbook/src/components/DocumentView/OpenAPI/OpenAPI.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { JSONDocument } from '@gitbook/api';
22
import { Icon } from '@gitbook/icons';
33
import { OpenAPIOperation } from '@gitbook/react-openapi';
44

5-
import { type AnyOpenAPIOperationBlock, resolveOpenAPIBlock } from '@/lib/openapi/fetch';
5+
import { resolveOpenAPIOperationBlock } from '@/lib/openapi/resolveOpenAPIOperationBlock';
66
import { tcls } from '@/lib/tailwind';
77

88
import type { BlockProps } from '../Block';
@@ -12,11 +12,12 @@ import { Heading } from '../Heading';
1212

1313
import './scalar.css';
1414
import './style.css';
15+
import type { AnyOpenAPIBlock } from '@/lib/openapi/types';
1516

1617
/**
1718
* Render an openapi block or an openapi-operation block.
1819
*/
19-
export async function OpenAPI(props: BlockProps<AnyOpenAPIOperationBlock>) {
20+
export async function OpenAPI(props: BlockProps<AnyOpenAPIBlock>) {
2021
const { style } = props;
2122
return (
2223
<div className={tcls('flex w-full', style, 'max-w-full')}>
@@ -25,14 +26,14 @@ export async function OpenAPI(props: BlockProps<AnyOpenAPIOperationBlock>) {
2526
);
2627
}
2728

28-
async function OpenAPIBody(props: BlockProps<AnyOpenAPIOperationBlock>) {
29+
async function OpenAPIBody(props: BlockProps<AnyOpenAPIBlock>) {
2930
const { block, context } = props;
3031

3132
if (!context.contentContext) {
3233
return null;
3334
}
3435

35-
const { data, specUrl, error } = await resolveOpenAPIBlock({
36+
const { data, specUrl, error } = await resolveOpenAPIOperationBlock({
3637
block,
3738
context: context.contentContext,
3839
});

packages/gitbook/src/lib/document-sections.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { JSONDocument } from '@gitbook/api';
22
import type { GitBookAnyContext } from '@v2/lib/context';
33

44
import { getNodeText } from './document';
5-
import { resolveOpenAPIBlock } from './openapi/fetch';
5+
import { resolveOpenAPIOperationBlock } from './openapi/resolveOpenAPIOperationBlock';
66

77
export interface DocumentSection {
88
id: string;
@@ -38,7 +38,7 @@ export async function getDocumentSections(
3838
}
3939

4040
if ((block.type === 'swagger' || block.type === 'openapi-operation') && block.meta?.id) {
41-
const { data: operation } = await resolveOpenAPIBlock({
41+
const { data: operation } = await resolveOpenAPIOperationBlock({
4242
block,
4343
context,
4444
});
Lines changed: 19 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -1,122 +1,40 @@
1-
import type { DocumentBlockOpenAPI, DocumentBlockOpenAPIOperation } from '@gitbook/api';
2-
import { OpenAPIParseError, parseOpenAPI } from '@gitbook/openapi-parser';
3-
import {
4-
type OpenAPIModelsData,
5-
type OpenAPIOperationData,
6-
resolveOpenAPIModels,
7-
resolveOpenAPIOperation,
8-
} from '@gitbook/react-openapi';
9-
import type { GitBookAnyContext } from '@v2/lib/context';
1+
import { parseOpenAPI } from '@gitbook/openapi-parser';
102

113
import { type CacheFunctionOptions, cache, noCacheFetchOptions } from '@/lib/cache';
12-
4+
import type { ResolveOpenAPIBlockArgs } from '@/lib/openapi/types';
135
import { assert } from 'ts-essentials';
146
import { resolveContentRef } from '../references';
157
import { isV2 } from '../v2';
168
import { enrichFilesystem } from './enrich';
17-
18-
//!!TODO: Add DocumentBlockOpenAPIModels when available in @gitbook/api
19-
export type AnyOpenAPIOperationBlock = DocumentBlockOpenAPI | DocumentBlockOpenAPIOperation;
20-
21-
export type OpenAPIBlockType = 'operation' | 'models';
22-
23-
export type OpenAPIOperationResult = {
24-
data: OpenAPIOperationData | null;
25-
error: undefined;
26-
specUrl: string | null;
27-
};
28-
29-
export type OpenAPIModelsResult = {
30-
data: OpenAPIModelsData | null;
31-
error: undefined;
32-
specUrl: string | null;
33-
};
34-
35-
export type OpenAPIErrorResult = {
36-
data?: undefined;
37-
specUrl?: undefined;
38-
error: OpenAPIParseError;
39-
};
40-
41-
export type OpenAPIBlockResult<T extends OpenAPIBlockType = 'operation'> =
42-
| (T extends 'operation' ? OpenAPIOperationResult : OpenAPIModelsResult)
43-
| OpenAPIErrorResult;
44-
45-
type ResolveOpenAPIBlockArgs<T = OpenAPIBlockType> = {
46-
block: AnyOpenAPIOperationBlock;
47-
context: GitBookAnyContext;
48-
/**
49-
* The type of the block.
50-
* Can be either 'operation' or 'models'.
51-
* @default 'operation'
52-
*/
53-
type?: T | OpenAPIBlockType;
54-
};
55-
56-
const weakmap = new WeakMap<AnyOpenAPIOperationBlock, Promise<OpenAPIBlockResult>>();
9+
import type { FetchOpenAPIFilesystemResult } from './types';
5710

5811
/**
59-
* Cache the result of resolving an OpenAPI block.
60-
* It is important because the resolve is called in sections and in the block itself.
12+
* Fetch OpenAPI block.
6113
*/
62-
export function resolveOpenAPIBlock<T extends OpenAPIBlockType = 'operation'>(
63-
args: ResolveOpenAPIBlockArgs<T>
64-
): Promise<OpenAPIBlockResult<T>> {
65-
if (weakmap.has(args.block)) {
66-
// We enforce the type here cause weakmap doesn't know the type of the value
67-
return weakmap.get(args.block) as Promise<OpenAPIBlockResult<T>>;
68-
}
69-
70-
const result = baseResolveOpenAPIBlock(args);
71-
weakmap.set(args.block, result as Promise<OpenAPIBlockResult>);
72-
return result;
73-
}
74-
75-
/**
76-
* Resolve OpenAPI block.
77-
*/
78-
async function baseResolveOpenAPIBlock<T extends OpenAPIBlockType = 'operation'>(
79-
args: ResolveOpenAPIBlockArgs<T>
80-
): Promise<OpenAPIBlockResult<T>> {
81-
const { context, block, type = 'operation' } = args;
82-
if (!block.data.path || !block.data.method) {
83-
return createResults<T>(null);
84-
}
14+
export async function fetchOpenAPIFilesystem(
15+
args: ResolveOpenAPIBlockArgs
16+
): Promise<FetchOpenAPIFilesystemResult> {
17+
const { context, block } = args;
8518

8619
const ref = block.data.ref;
8720
const resolved = ref ? await resolveContentRef(ref, context) : null;
8821

8922
if (!resolved) {
90-
return createResults<T>(null);
23+
return { filesystem: null, specUrl: null };
9124
}
9225

93-
try {
94-
const filesystem = await (() => {
95-
if (ref.kind === 'openapi') {
96-
assert(resolved.openAPIFilesystem);
97-
return resolved.openAPIFilesystem;
98-
}
99-
return fetchFilesystem(resolved.href);
100-
})();
101-
102-
let data: OpenAPIOperationData | OpenAPIModelsData | null = null;
103-
if (type === 'models') {
104-
data = await resolveOpenAPIModels(filesystem);
105-
} else {
106-
data = await resolveOpenAPIOperation(filesystem, {
107-
path: block.data.path,
108-
method: block.data.method,
109-
});
26+
const filesystem = await (() => {
27+
if (ref.kind === 'openapi') {
28+
assert(resolved.openAPIFilesystem);
29+
return resolved.openAPIFilesystem;
11030
}
31+
return fetchFilesystem(resolved.href);
32+
})();
11133

112-
return createResults<T>(data, resolved.href);
113-
} catch (error) {
114-
if (error instanceof OpenAPIParseError) {
115-
return { error };
116-
}
117-
118-
throw error;
119-
}
34+
return {
35+
filesystem,
36+
specUrl: resolved.href,
37+
};
12038
}
12139

12240
function fetchFilesystem(url: string) {
@@ -181,17 +99,3 @@ async function fetchFilesystemUncached(
18199

182100
return richFilesystem;
183101
}
184-
185-
/**
186-
* Create a result for OpenAPI based on the type.
187-
*/
188-
function createResults<T extends OpenAPIBlockType>(
189-
data: OpenAPIOperationData | OpenAPIModelsData | null,
190-
specUrl?: string
191-
): OpenAPIBlockResult<T> {
192-
return {
193-
error: undefined,
194-
data,
195-
specUrl,
196-
} as OpenAPIBlockResult<T>;
197-
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { fetchOpenAPIFilesystem } from '@/lib/openapi/fetch';
2+
import type { ResolveOpenAPIModelsBlockResult } from '@/lib/openapi/types';
3+
import { OpenAPIParseError } from '@gitbook/openapi-parser';
4+
import { resolveOpenAPIModels } from '@gitbook/react-openapi';
5+
import type { AnyOpenAPIBlock, ResolveOpenAPIBlockArgs } from './types';
6+
7+
const weakmap = new WeakMap<AnyOpenAPIBlock, Promise<ResolveOpenAPIModelsBlockResult>>();
8+
9+
/**
10+
* Cache the result of resolving an OpenAPI block.
11+
* It is important because the resolve is called in sections and in the block itself.
12+
*/
13+
export function resolveOpenAPIModelsBlock(
14+
args: ResolveOpenAPIBlockArgs
15+
): Promise<ResolveOpenAPIModelsBlockResult> {
16+
if (weakmap.has(args.block)) {
17+
return weakmap.get(args.block)!;
18+
}
19+
20+
const result = baseResolveOpenAPIModelsBlock(args);
21+
weakmap.set(args.block, result);
22+
return result;
23+
}
24+
25+
/**
26+
* Resolve OpenAPI models block.
27+
*/
28+
async function baseResolveOpenAPIModelsBlock(
29+
args: ResolveOpenAPIBlockArgs
30+
): Promise<ResolveOpenAPIModelsBlockResult> {
31+
const { context, block } = args;
32+
if (!block.data.path || !block.data.method) {
33+
return { data: null, specUrl: null };
34+
}
35+
36+
try {
37+
const { filesystem, specUrl } = await fetchOpenAPIFilesystem({ block, context });
38+
39+
if (!filesystem || !specUrl) {
40+
return { data: null, specUrl: null };
41+
}
42+
43+
const data = await resolveOpenAPIModels(filesystem);
44+
45+
return { data, specUrl };
46+
} catch (error) {
47+
if (error instanceof OpenAPIParseError) {
48+
return { error };
49+
}
50+
51+
throw error;
52+
}
53+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { fetchOpenAPIFilesystem } from '@/lib/openapi/fetch';
2+
import { OpenAPIParseError } from '@gitbook/openapi-parser';
3+
import { resolveOpenAPIOperation } from '@gitbook/react-openapi';
4+
import type {
5+
AnyOpenAPIBlock,
6+
ResolveOpenAPIBlockArgs,
7+
ResolveOpenAPIOperationBlockResult,
8+
} from './types';
9+
10+
const weakmap = new WeakMap<AnyOpenAPIBlock, Promise<ResolveOpenAPIOperationBlockResult>>();
11+
12+
/**
13+
* Cache the result of resolving an OpenAPI block.
14+
* It is important because the resolve is called in sections and in the block itself.
15+
*/
16+
export function resolveOpenAPIOperationBlock(
17+
args: ResolveOpenAPIBlockArgs
18+
): Promise<ResolveOpenAPIOperationBlockResult> {
19+
if (weakmap.has(args.block)) {
20+
return weakmap.get(args.block)!;
21+
}
22+
23+
const result = baseResolveOpenAPIOperationBlock(args);
24+
weakmap.set(args.block, result);
25+
return result;
26+
}
27+
28+
/**
29+
* Resolve OpenAPI operation block.
30+
*/
31+
async function baseResolveOpenAPIOperationBlock(
32+
args: ResolveOpenAPIBlockArgs
33+
): Promise<ResolveOpenAPIOperationBlockResult> {
34+
const { context, block } = args;
35+
if (!block.data.path || !block.data.method) {
36+
return { data: null, specUrl: null };
37+
}
38+
39+
try {
40+
const { filesystem, specUrl } = await fetchOpenAPIFilesystem({ block, context });
41+
42+
if (!filesystem) {
43+
return { data: null, specUrl: null };
44+
}
45+
46+
const data = await resolveOpenAPIOperation(filesystem, {
47+
path: block.data.path,
48+
method: block.data.method,
49+
});
50+
51+
return { data, specUrl };
52+
} catch (error) {
53+
if (error instanceof OpenAPIParseError) {
54+
return { error };
55+
}
56+
57+
throw error;
58+
}
59+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import type { DocumentBlockOpenAPI, DocumentBlockOpenAPIOperation } from '@gitbook/api';
2+
import type { Filesystem, OpenAPIParseError, OpenAPIV3xDocument } from '@gitbook/openapi-parser';
3+
import type { OpenAPIModelsData, OpenAPIOperationData } from '@gitbook/react-openapi';
4+
import type { GitBookAnyContext } from '@v2/lib/context';
5+
6+
//!!TODO: Add DocumentBlockOpenAPIModels when available in @gitbook/api
7+
export type AnyOpenAPIBlock = DocumentBlockOpenAPI | DocumentBlockOpenAPIOperation;
8+
9+
/**
10+
* Arguments for resolving OpenAPI block.
11+
*/
12+
export type ResolveOpenAPIBlockArgs = {
13+
block: AnyOpenAPIBlock;
14+
context: GitBookAnyContext;
15+
};
16+
17+
/**
18+
* Fetch OpenAPI filesystem result.
19+
*/
20+
export type FetchOpenAPIFilesystemResult =
21+
| {
22+
error?: undefined;
23+
filesystem: Filesystem<OpenAPIV3xDocument> | null;
24+
specUrl: string | null;
25+
}
26+
| FetchOpenAPIFilesystemError;
27+
28+
/**
29+
* Fetch OpenAPI filesystem error.
30+
*/
31+
type FetchOpenAPIFilesystemError = {
32+
error: OpenAPIParseError;
33+
filesystem?: undefined;
34+
specUrl?: undefined;
35+
};
36+
37+
/**
38+
* Resolved OpenAPI models block result.
39+
*/
40+
export type ResolveOpenAPIModelsBlockResult =
41+
| { error?: undefined; data: OpenAPIModelsData | null; specUrl: string | null }
42+
| ResolveOpenAPIBlockError;
43+
44+
/**
45+
* Resolved OpenAPI operation block result.
46+
*/
47+
export type ResolveOpenAPIOperationBlockResult =
48+
| { error?: undefined; data: OpenAPIOperationData | null; specUrl: string | null }
49+
| ResolveOpenAPIBlockError;
50+
51+
/**
52+
* Resolved OpenAPI block error.
53+
*/
54+
type ResolveOpenAPIBlockError = {
55+
error: OpenAPIParseError;
56+
data?: undefined;
57+
specUrl?: undefined;
58+
};

0 commit comments

Comments
 (0)