@sapporta/rest-open-api 3.52.1 → 3.52.2
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/CHANGELOG.md +6 -0
- package/README.md +76 -9
- package/index.cjs.d.ts +1 -0
- package/index.cjs.default.js +1 -0
- package/index.cjs.js +673 -0
- package/index.cjs.mjs +2 -0
- package/index.esm.js +668 -0
- package/package.json +15 -5
- package/src/index.d.ts +2 -0
- package/src/lib/contract-traversal.d.ts +14 -0
- package/src/lib/parsers/body.d.ts +14 -0
- package/src/lib/parsers/headers.d.ts +14 -0
- package/src/lib/parsers/path-params.d.ts +20 -0
- package/src/lib/parsers/query-params.d.ts +15 -0
- package/src/lib/parsers/test-helpers.d.ts +4 -0
- package/src/lib/parsers/utils.d.ts +11 -0
- package/src/lib/ts-rest-open-api.d.ts +46 -0
- package/src/lib/types.d.ts +83 -0
- package/src/lib/utils.d.ts +5 -0
- package/.babelrc +0 -10
- package/.eslintrc.json +0 -21
- package/jest.config.ts +0 -16
- package/project.json +0 -51
- package/src/index.ts +0 -6
- package/src/lib/contract-traversal.ts +0 -217
- package/src/lib/parsers/body.ts +0 -71
- package/src/lib/parsers/headers.ts +0 -163
- package/src/lib/parsers/path-params.spec.ts +0 -235
- package/src/lib/parsers/path-params.ts +0 -140
- package/src/lib/parsers/query-params.spec.ts +0 -129
- package/src/lib/parsers/query-params.ts +0 -89
- package/src/lib/parsers/test-helpers.ts +0 -26
- package/src/lib/parsers/utils.spec.ts +0 -117
- package/src/lib/parsers/utils.ts +0 -82
- package/src/lib/ts-rest-open-api.ts +0 -245
- package/src/lib/types.ts +0 -109
- package/src/lib/utils.ts +0 -92
- package/tsconfig.json +0 -22
- package/tsconfig.lib.json +0 -10
- package/tsconfig.spec.json +0 -9
- package/typedoc.json +0 -5
- /package/src/lib/parsers/{index.ts → index.d.ts} +0 -0
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import { AppRoute, isStandardSchema } from '@sapporta/rest-core';
|
|
2
|
-
import {
|
|
3
|
-
AsyncAndSyncHelper,
|
|
4
|
-
GetAsyncFunction,
|
|
5
|
-
GetSyncFunction,
|
|
6
|
-
SchemaTransformerAsync,
|
|
7
|
-
SchemaTransformerSync,
|
|
8
|
-
} from '../types';
|
|
9
|
-
import { ParameterObject } from 'openapi3-ts';
|
|
10
|
-
import { schemaObjectToParameters } from './utils';
|
|
11
|
-
|
|
12
|
-
type GetQueryParameterHelper = AsyncAndSyncHelper<
|
|
13
|
-
{
|
|
14
|
-
appRoute: AppRoute;
|
|
15
|
-
id: string;
|
|
16
|
-
concatenatedPath: string;
|
|
17
|
-
jsonQuery?: boolean;
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
transformSchema: SchemaTransformerSync;
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
transformSchema: SchemaTransformerAsync;
|
|
24
|
-
},
|
|
25
|
-
Array<ParameterObject>
|
|
26
|
-
>;
|
|
27
|
-
|
|
28
|
-
const syncFunc: GetSyncFunction<GetQueryParameterHelper> = ({
|
|
29
|
-
transformSchema,
|
|
30
|
-
appRoute,
|
|
31
|
-
id,
|
|
32
|
-
concatenatedPath,
|
|
33
|
-
jsonQuery = false,
|
|
34
|
-
}) => {
|
|
35
|
-
const schema = appRoute.query;
|
|
36
|
-
const isSchema = isStandardSchema(schema);
|
|
37
|
-
|
|
38
|
-
if (!isSchema) {
|
|
39
|
-
return [];
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const transformedSchema = transformSchema({
|
|
43
|
-
schema,
|
|
44
|
-
appRoute,
|
|
45
|
-
id,
|
|
46
|
-
concatenatedPath,
|
|
47
|
-
type: 'query',
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
if (!transformedSchema) {
|
|
51
|
-
return [];
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return schemaObjectToParameters(transformedSchema, 'query', jsonQuery);
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
const asyncFunc: GetAsyncFunction<GetQueryParameterHelper> = async ({
|
|
58
|
-
transformSchema,
|
|
59
|
-
appRoute,
|
|
60
|
-
id,
|
|
61
|
-
concatenatedPath,
|
|
62
|
-
jsonQuery = false,
|
|
63
|
-
}) => {
|
|
64
|
-
const schema = appRoute.query;
|
|
65
|
-
const isSchema = isStandardSchema(schema);
|
|
66
|
-
|
|
67
|
-
if (!isSchema) {
|
|
68
|
-
return [];
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const transformedSchema = await transformSchema({
|
|
72
|
-
schema,
|
|
73
|
-
appRoute,
|
|
74
|
-
id,
|
|
75
|
-
concatenatedPath,
|
|
76
|
-
type: 'query',
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
if (!transformedSchema) {
|
|
80
|
-
return [];
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
return schemaObjectToParameters(transformedSchema, 'query', jsonQuery);
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
export const getQueryParameterSchema: GetQueryParameterHelper = {
|
|
87
|
-
sync: syncFunc,
|
|
88
|
-
async: asyncFunc,
|
|
89
|
-
};
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { SchemaObject } from 'openapi3-ts';
|
|
2
|
-
import { z } from 'zod';
|
|
3
|
-
import { SchemaTransformerAsync, SchemaTransformerSync } from '../types';
|
|
4
|
-
|
|
5
|
-
const stripJsonSchemaMetadata = (schema: unknown): SchemaObject => {
|
|
6
|
-
if (!schema || typeof schema !== 'object') {
|
|
7
|
-
return schema as SchemaObject;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
const { $schema, ...rest } = schema as Record<string, unknown>;
|
|
11
|
-
return rest as SchemaObject;
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
export const zodV4SchemaTransformer: SchemaTransformerSync = ({ schema }) => {
|
|
15
|
-
if (!schema || typeof schema !== 'object' || !('_zod' in schema)) {
|
|
16
|
-
return null;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
return stripJsonSchemaMetadata(z.toJSONSchema(schema as z.ZodTypeAny));
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export const ZOD_SYNC = zodV4SchemaTransformer;
|
|
23
|
-
|
|
24
|
-
export const ZOD_ASYNC: SchemaTransformerAsync = async (args) => {
|
|
25
|
-
return zodV4SchemaTransformer(args);
|
|
26
|
-
};
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import { SchemaObject } from 'openapi3-ts';
|
|
2
|
-
import { schemaObjectToParameters } from './utils';
|
|
3
|
-
import { z } from 'zod';
|
|
4
|
-
import { zodV4SchemaTransformer } from './test-helpers';
|
|
5
|
-
|
|
6
|
-
const generateSchema = (schema: z.ZodTypeAny): SchemaObject => {
|
|
7
|
-
return zodV4SchemaTransformer({
|
|
8
|
-
schema,
|
|
9
|
-
appRoute: {
|
|
10
|
-
method: 'GET',
|
|
11
|
-
path: '/',
|
|
12
|
-
responses: {},
|
|
13
|
-
},
|
|
14
|
-
id: 'test',
|
|
15
|
-
concatenatedPath: 'test',
|
|
16
|
-
type: 'query',
|
|
17
|
-
})!;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
describe('utils', () => {
|
|
21
|
-
describe('schemaObjectToParameters', () => {
|
|
22
|
-
const schema: SchemaObject = {
|
|
23
|
-
type: 'object',
|
|
24
|
-
properties: { name: { type: 'string' } },
|
|
25
|
-
required: ['name'],
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
const parameters = schemaObjectToParameters(schema, 'query');
|
|
29
|
-
|
|
30
|
-
it('should return an array of parameters', () => {
|
|
31
|
-
expect(parameters).toEqual([
|
|
32
|
-
{
|
|
33
|
-
name: 'name',
|
|
34
|
-
in: 'query',
|
|
35
|
-
required: true,
|
|
36
|
-
schema: { type: 'string' },
|
|
37
|
-
},
|
|
38
|
-
]);
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('should return an empty array if the schema is not an object', () => {
|
|
42
|
-
const schema: SchemaObject = { type: 'string' };
|
|
43
|
-
const parameters = schemaObjectToParameters(schema, 'query');
|
|
44
|
-
expect(parameters).toEqual([]);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('should return optional parameters if the schema is not required', async () => {
|
|
48
|
-
const schema = generateSchema(
|
|
49
|
-
z.object({
|
|
50
|
-
name: z.string().optional(),
|
|
51
|
-
}),
|
|
52
|
-
);
|
|
53
|
-
|
|
54
|
-
const parameters = schemaObjectToParameters(schema, 'query');
|
|
55
|
-
expect(parameters).toEqual([
|
|
56
|
-
{
|
|
57
|
-
name: 'name',
|
|
58
|
-
in: 'query',
|
|
59
|
-
schema: { type: 'string' },
|
|
60
|
-
},
|
|
61
|
-
]);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
it("should inlude `style: 'deepObject'` if the schema is a deep object", () => {
|
|
65
|
-
const schema = generateSchema(
|
|
66
|
-
z.object({
|
|
67
|
-
parent: z.object({
|
|
68
|
-
child: z.string(),
|
|
69
|
-
}),
|
|
70
|
-
}),
|
|
71
|
-
);
|
|
72
|
-
|
|
73
|
-
const parameters = schemaObjectToParameters(schema, 'query');
|
|
74
|
-
|
|
75
|
-
expect(parameters).toEqual([
|
|
76
|
-
{
|
|
77
|
-
name: 'parent',
|
|
78
|
-
in: 'query',
|
|
79
|
-
required: true,
|
|
80
|
-
schema: {
|
|
81
|
-
additionalProperties: false,
|
|
82
|
-
properties: {
|
|
83
|
-
child: { type: 'string' },
|
|
84
|
-
},
|
|
85
|
-
required: ['child'],
|
|
86
|
-
type: 'object',
|
|
87
|
-
},
|
|
88
|
-
style: 'deepObject',
|
|
89
|
-
},
|
|
90
|
-
]);
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
it('should work for jsonQuery', () => {
|
|
94
|
-
const schema = generateSchema(
|
|
95
|
-
z.object({
|
|
96
|
-
name: z.string(),
|
|
97
|
-
}),
|
|
98
|
-
);
|
|
99
|
-
|
|
100
|
-
const parameters = schemaObjectToParameters(schema, 'query', true);
|
|
101
|
-
expect(parameters).toEqual([
|
|
102
|
-
{
|
|
103
|
-
name: 'name',
|
|
104
|
-
in: 'query',
|
|
105
|
-
required: true,
|
|
106
|
-
content: {
|
|
107
|
-
'application/json': {
|
|
108
|
-
schema: {
|
|
109
|
-
type: 'string',
|
|
110
|
-
},
|
|
111
|
-
},
|
|
112
|
-
},
|
|
113
|
-
},
|
|
114
|
-
]);
|
|
115
|
-
});
|
|
116
|
-
});
|
|
117
|
-
});
|
package/src/lib/parsers/utils.ts
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { ExamplesObject, ParameterObject, SchemaObject } from 'openapi3-ts';
|
|
2
|
-
|
|
3
|
-
export const schemaToParameter = (
|
|
4
|
-
schema: SchemaObject,
|
|
5
|
-
where: 'query' | 'header' | 'path',
|
|
6
|
-
required: boolean,
|
|
7
|
-
key: string,
|
|
8
|
-
jsonQuery: boolean,
|
|
9
|
-
): ParameterObject => {
|
|
10
|
-
let description: string | undefined = undefined;
|
|
11
|
-
|
|
12
|
-
if ('description' in schema) {
|
|
13
|
-
description = schema['description'];
|
|
14
|
-
delete schema['description'];
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
let examples: ExamplesObject | undefined = undefined;
|
|
18
|
-
if ('mediaExamples' in schema) {
|
|
19
|
-
examples = schema['mediaExamples'];
|
|
20
|
-
delete schema['mediaExamples'];
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const isDeepObject = 'properties' in schema;
|
|
24
|
-
|
|
25
|
-
if (jsonQuery) {
|
|
26
|
-
return {
|
|
27
|
-
name: key,
|
|
28
|
-
in: where,
|
|
29
|
-
...(description && { description }),
|
|
30
|
-
...(required && { required }),
|
|
31
|
-
content: {
|
|
32
|
-
'application/json': {
|
|
33
|
-
schema,
|
|
34
|
-
...(examples && { examples }),
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
};
|
|
38
|
-
} else {
|
|
39
|
-
return {
|
|
40
|
-
name: key,
|
|
41
|
-
in: where,
|
|
42
|
-
...(examples && { examples }),
|
|
43
|
-
...(description && { description }),
|
|
44
|
-
...(required && { required }),
|
|
45
|
-
...(isDeepObject && !jsonQuery && { style: 'deepObject' }),
|
|
46
|
-
schema,
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Convert a @type {SchemaObject} to an array of @type {ParameterObject}
|
|
53
|
-
*
|
|
54
|
-
* @param schema - Zod 4 JSON schema output
|
|
55
|
-
* @param where - The location of the parameters
|
|
56
|
-
* @param jsonQuery - Whether the schema is a JSON query
|
|
57
|
-
* @returns The parameters for the schema
|
|
58
|
-
*/
|
|
59
|
-
export const schemaObjectToParameters = (
|
|
60
|
-
schema: SchemaObject,
|
|
61
|
-
where: 'query' | 'header' | 'path',
|
|
62
|
-
jsonQuery = false,
|
|
63
|
-
): ParameterObject[] => {
|
|
64
|
-
const parameters: ParameterObject[] = [];
|
|
65
|
-
|
|
66
|
-
if (schema.type === 'object') {
|
|
67
|
-
const requiredSet = new Set(schema.required ?? []);
|
|
68
|
-
const properties = schema.properties;
|
|
69
|
-
|
|
70
|
-
if (!properties) {
|
|
71
|
-
return [];
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
for (const [key, value] of Object.entries(properties)) {
|
|
75
|
-
parameters.push(
|
|
76
|
-
schemaToParameter(value, where, requiredSet.has(key), key, jsonQuery),
|
|
77
|
-
);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
return parameters;
|
|
82
|
-
};
|
|
@@ -1,245 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type AppRoute,
|
|
3
|
-
type AppRouter,
|
|
4
|
-
isAppRouteOtherResponse,
|
|
5
|
-
} from '@sapporta/rest-core';
|
|
6
|
-
import type {
|
|
7
|
-
ExamplesObject,
|
|
8
|
-
InfoObject,
|
|
9
|
-
OpenAPIObject,
|
|
10
|
-
OperationObject,
|
|
11
|
-
PathsObject,
|
|
12
|
-
SchemaObject,
|
|
13
|
-
} from 'openapi3-ts';
|
|
14
|
-
import {
|
|
15
|
-
PathSchemaResults,
|
|
16
|
-
RouterPath,
|
|
17
|
-
SchemaTransformerAsync,
|
|
18
|
-
SchemaTransformerSync,
|
|
19
|
-
} from './types';
|
|
20
|
-
import { performContractTraversal } from './contract-traversal';
|
|
21
|
-
import {
|
|
22
|
-
convertSchemaObjectToMediaTypeObject,
|
|
23
|
-
extractReferenceSchemas,
|
|
24
|
-
} from './utils';
|
|
25
|
-
|
|
26
|
-
declare module 'openapi3-ts' {
|
|
27
|
-
interface SchemaObject {
|
|
28
|
-
mediaExamples?: ExamplesObject;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Generate OpenAPI specification from ts-rest router
|
|
34
|
-
*
|
|
35
|
-
* @param router - The ts-rest router to generate OpenAPI from
|
|
36
|
-
* @param apiDoc - Base OpenAPI document configuration
|
|
37
|
-
* @param options - Generation options
|
|
38
|
-
* @param options.setOperationId - Whether to set operation IDs (true, false, or 'concatenated-path')
|
|
39
|
-
* @param options.jsonQuery - Enable JSON query parameters, [see](/docs/open-api#json-query-params)
|
|
40
|
-
* @param options.operationMapper - Function to customize OpenAPI operations. Receives the operation object, app route, and operation ID
|
|
41
|
-
* @returns OpenAPI specification object
|
|
42
|
-
*/
|
|
43
|
-
export function generateOpenApi(
|
|
44
|
-
router: AppRouter,
|
|
45
|
-
apiDoc: Omit<OpenAPIObject, 'paths' | 'openapi'> & { info: InfoObject },
|
|
46
|
-
options: {
|
|
47
|
-
setOperationId?: boolean | 'concatenated-path';
|
|
48
|
-
jsonQuery?: boolean;
|
|
49
|
-
operationMapper?: (
|
|
50
|
-
operation: OperationObject,
|
|
51
|
-
appRoute: AppRoute,
|
|
52
|
-
id: string,
|
|
53
|
-
) => OperationObject;
|
|
54
|
-
schemaTransformer: SchemaTransformerSync;
|
|
55
|
-
},
|
|
56
|
-
): OpenAPIObject {
|
|
57
|
-
const paths = performContractTraversal.sync({
|
|
58
|
-
contract: router,
|
|
59
|
-
transformSchema: options?.schemaTransformer,
|
|
60
|
-
jsonQuery: !!options?.jsonQuery,
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
return traversedPathsToOpenApi(paths, apiDoc, {
|
|
64
|
-
setOperationId: options?.setOperationId,
|
|
65
|
-
jsonQuery: options?.jsonQuery,
|
|
66
|
-
operationMapper: options?.operationMapper,
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Generate OpenAPI specification from ts-rest router with custom schema transformer
|
|
72
|
-
*
|
|
73
|
-
* @param router - The ts-rest router to generate OpenAPI from
|
|
74
|
-
* @param apiDoc - Base OpenAPI document configuration
|
|
75
|
-
* @param options - Generation options
|
|
76
|
-
* @param options.setOperationId - Whether to set operation IDs (true, false, or 'concatenated-path')
|
|
77
|
-
* @param options.jsonQuery - Enable JSON query parameters, [see](/docs/open-api#json-query-params)
|
|
78
|
-
* @param options.operationMapper - Function to customize OpenAPI operations. Receives the operation object, app route, and operation ID
|
|
79
|
-
* @param options.schemaTransformer - Custom schema transformer function.
|
|
80
|
-
*/
|
|
81
|
-
export async function generateOpenApiAsync(
|
|
82
|
-
router: AppRouter,
|
|
83
|
-
apiDoc: Omit<OpenAPIObject, 'paths' | 'openapi'> & { info: InfoObject },
|
|
84
|
-
options: {
|
|
85
|
-
setOperationId?: boolean | 'concatenated-path';
|
|
86
|
-
jsonQuery?: boolean;
|
|
87
|
-
operationMapper?: (
|
|
88
|
-
operation: OperationObject,
|
|
89
|
-
appRoute: AppRoute,
|
|
90
|
-
id: string,
|
|
91
|
-
) => OperationObject;
|
|
92
|
-
schemaTransformer: SchemaTransformerAsync;
|
|
93
|
-
},
|
|
94
|
-
): Promise<OpenAPIObject> {
|
|
95
|
-
const paths = await performContractTraversal.async({
|
|
96
|
-
contract: router,
|
|
97
|
-
transformSchema: options.schemaTransformer,
|
|
98
|
-
jsonQuery: !!options.jsonQuery,
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
return traversedPathsToOpenApi(paths, apiDoc, {
|
|
102
|
-
setOperationId: options.setOperationId,
|
|
103
|
-
jsonQuery: options.jsonQuery,
|
|
104
|
-
operationMapper: options.operationMapper,
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Inner function to be reused by both sync and async functions
|
|
110
|
-
*/
|
|
111
|
-
const traversedPathsToOpenApi = (
|
|
112
|
-
paths: Array<RouterPath & { schemaResults: PathSchemaResults }>,
|
|
113
|
-
apiDoc: Omit<OpenAPIObject, 'paths' | 'openapi'> & { info: InfoObject },
|
|
114
|
-
options: {
|
|
115
|
-
setOperationId?: boolean | 'concatenated-path';
|
|
116
|
-
jsonQuery?: boolean;
|
|
117
|
-
operationMapper?: (
|
|
118
|
-
operation: OperationObject,
|
|
119
|
-
appRoute: AppRoute,
|
|
120
|
-
id: string,
|
|
121
|
-
) => OperationObject;
|
|
122
|
-
},
|
|
123
|
-
) => {
|
|
124
|
-
const mapMethod = {
|
|
125
|
-
GET: 'get',
|
|
126
|
-
POST: 'post',
|
|
127
|
-
PUT: 'put',
|
|
128
|
-
DELETE: 'delete',
|
|
129
|
-
PATCH: 'patch',
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
const operationIds = new Map<string, string[]>();
|
|
133
|
-
|
|
134
|
-
const referenceSchemas: { [id: string]: SchemaObject } = {};
|
|
135
|
-
|
|
136
|
-
const pathObject: PathsObject = {};
|
|
137
|
-
|
|
138
|
-
for (const path of paths) {
|
|
139
|
-
if (options.setOperationId === true) {
|
|
140
|
-
const existingOp = operationIds.get(path.id);
|
|
141
|
-
if (existingOp) {
|
|
142
|
-
throw new Error(
|
|
143
|
-
`Route '${path.id}' already defined under ${existingOp.join('.')}`,
|
|
144
|
-
);
|
|
145
|
-
}
|
|
146
|
-
operationIds.set(path.id, path.paths);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
const _bodySchema = path.schemaResults.body;
|
|
150
|
-
const bodySchema =
|
|
151
|
-
_bodySchema && typeof _bodySchema === 'object' && 'title' in _bodySchema
|
|
152
|
-
? extractReferenceSchemas(
|
|
153
|
-
path.schemaResults.body as SchemaObject,
|
|
154
|
-
referenceSchemas,
|
|
155
|
-
)
|
|
156
|
-
: path.schemaResults.body;
|
|
157
|
-
|
|
158
|
-
const responses: Record<string, SchemaObject> = {};
|
|
159
|
-
|
|
160
|
-
for (const [statusCode, response] of Object.entries(path.route.responses)) {
|
|
161
|
-
const contentType = isAppRouteOtherResponse(response)
|
|
162
|
-
? response.contentType
|
|
163
|
-
: 'application/json';
|
|
164
|
-
|
|
165
|
-
const responseSchemaObject = path.schemaResults.responses[statusCode];
|
|
166
|
-
const responseSchemaObjectWithReferences = responseSchemaObject
|
|
167
|
-
? extractReferenceSchemas(responseSchemaObject, referenceSchemas)
|
|
168
|
-
: null;
|
|
169
|
-
|
|
170
|
-
responses[statusCode] = {
|
|
171
|
-
...(responseSchemaObjectWithReferences
|
|
172
|
-
? {
|
|
173
|
-
content: {
|
|
174
|
-
[contentType]: {
|
|
175
|
-
...convertSchemaObjectToMediaTypeObject(
|
|
176
|
-
responseSchemaObjectWithReferences,
|
|
177
|
-
),
|
|
178
|
-
},
|
|
179
|
-
},
|
|
180
|
-
}
|
|
181
|
-
: {}),
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
const contentType =
|
|
186
|
-
path.route?.method !== 'GET' && 'contentType' in path.route
|
|
187
|
-
? path.route?.contentType ?? 'application/json'
|
|
188
|
-
: 'application/json';
|
|
189
|
-
|
|
190
|
-
const pathOperation: OperationObject = {
|
|
191
|
-
description: path.route.description,
|
|
192
|
-
summary: path.route.summary,
|
|
193
|
-
deprecated: path.route.deprecated,
|
|
194
|
-
tags: path.paths,
|
|
195
|
-
parameters: [
|
|
196
|
-
...path.schemaResults.path,
|
|
197
|
-
...path.schemaResults.headers,
|
|
198
|
-
...path.schemaResults.query,
|
|
199
|
-
],
|
|
200
|
-
...(options.setOperationId
|
|
201
|
-
? {
|
|
202
|
-
operationId:
|
|
203
|
-
options.setOperationId === 'concatenated-path'
|
|
204
|
-
? [...path.paths, path.id].join('.')
|
|
205
|
-
: path.id,
|
|
206
|
-
}
|
|
207
|
-
: {}),
|
|
208
|
-
...(bodySchema
|
|
209
|
-
? {
|
|
210
|
-
requestBody: {
|
|
211
|
-
description: 'Body',
|
|
212
|
-
content: {
|
|
213
|
-
[contentType]: {
|
|
214
|
-
...convertSchemaObjectToMediaTypeObject(bodySchema),
|
|
215
|
-
},
|
|
216
|
-
},
|
|
217
|
-
},
|
|
218
|
-
}
|
|
219
|
-
: {}),
|
|
220
|
-
responses,
|
|
221
|
-
};
|
|
222
|
-
|
|
223
|
-
pathObject[path.path] = {
|
|
224
|
-
...pathObject[path.path],
|
|
225
|
-
[mapMethod[path.route.method]]: options.operationMapper
|
|
226
|
-
? options.operationMapper(pathOperation, path.route, path.id)
|
|
227
|
-
: pathOperation,
|
|
228
|
-
};
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
if (Object.keys(referenceSchemas).length) {
|
|
232
|
-
apiDoc['components'] = {
|
|
233
|
-
schemas: {
|
|
234
|
-
...referenceSchemas,
|
|
235
|
-
},
|
|
236
|
-
...apiDoc['components'],
|
|
237
|
-
};
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
return {
|
|
241
|
-
openapi: '3.0.2',
|
|
242
|
-
paths: pathObject,
|
|
243
|
-
...apiDoc,
|
|
244
|
-
};
|
|
245
|
-
};
|
package/src/lib/types.ts
DELETED
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import { AppRoute } from '@sapporta/rest-core';
|
|
2
|
-
import { ParameterObject, ResponseObject, SchemaObject } from 'openapi3-ts';
|
|
3
|
-
|
|
4
|
-
type SchemaTransformerArgs = {
|
|
5
|
-
/**
|
|
6
|
-
* The schema to transform.
|
|
7
|
-
*/
|
|
8
|
-
schema: unknown;
|
|
9
|
-
/**
|
|
10
|
-
* The app route.
|
|
11
|
-
*/
|
|
12
|
-
appRoute: AppRoute;
|
|
13
|
-
/**
|
|
14
|
-
* The key of the route in a contract e.g. `getPokemon` or `createPokemon`.
|
|
15
|
-
*/
|
|
16
|
-
id: string;
|
|
17
|
-
/**
|
|
18
|
-
* The concatenated path of the route. e.g. `pokemon.getPokemon` or `pokemon.createPokemon`.
|
|
19
|
-
*/
|
|
20
|
-
concatenatedPath: string;
|
|
21
|
-
/**
|
|
22
|
-
* Where the schema is used, can be used to conditionally transform the schema.
|
|
23
|
-
*/
|
|
24
|
-
type: 'body' | 'response' | 'query' | 'header' | 'path';
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Sync schema transformer.
|
|
29
|
-
*
|
|
30
|
-
* This will be invoked for all schemas, e.g. every query, pathParam, body, etc.
|
|
31
|
-
*
|
|
32
|
-
* You should guard against your schema type here, and return null if it's not the schema you want to transform.
|
|
33
|
-
*/
|
|
34
|
-
export type SchemaTransformerSync = (
|
|
35
|
-
args: SchemaTransformerArgs,
|
|
36
|
-
) => SchemaObject | null;
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Async schema transformer.
|
|
40
|
-
*
|
|
41
|
-
* This will be invoked for all schemas, e.g. every query, pathParam, body, etc.
|
|
42
|
-
*
|
|
43
|
-
* You should guard against your schema type here, and return null if it's not the schema you want to transform.
|
|
44
|
-
*/
|
|
45
|
-
export type SchemaTransformerAsync = (
|
|
46
|
-
args: SchemaTransformerArgs,
|
|
47
|
-
) => Promise<SchemaObject | null>;
|
|
48
|
-
|
|
49
|
-
export type SchemaTransformer = SchemaTransformerSync | SchemaTransformerAsync;
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* We need to have many functions that are the same, but some are sync and some are async.
|
|
53
|
-
*
|
|
54
|
-
* This helper lets us make this trivial and avoids having different types for each function.
|
|
55
|
-
*
|
|
56
|
-
* @hidden
|
|
57
|
-
*/
|
|
58
|
-
export type AsyncAndSyncHelper<T, TFuncSyncArgs, TFuncAsyncArgs, TReturn> = {
|
|
59
|
-
sync: (args: T & TFuncSyncArgs) => TReturn;
|
|
60
|
-
async: (args: T & TFuncAsyncArgs) => Promise<TReturn>;
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* @hidden
|
|
65
|
-
*/
|
|
66
|
-
export type GetSyncFunction<THelper> = THelper extends AsyncAndSyncHelper<
|
|
67
|
-
any,
|
|
68
|
-
any,
|
|
69
|
-
any,
|
|
70
|
-
any
|
|
71
|
-
>
|
|
72
|
-
? THelper['sync']
|
|
73
|
-
: never;
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* @hidden
|
|
77
|
-
*/
|
|
78
|
-
export type GetAsyncFunction<THelper> = THelper extends AsyncAndSyncHelper<
|
|
79
|
-
any,
|
|
80
|
-
any,
|
|
81
|
-
any,
|
|
82
|
-
any
|
|
83
|
-
>
|
|
84
|
-
? THelper['async']
|
|
85
|
-
: never;
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* @hidden
|
|
89
|
-
*/
|
|
90
|
-
export type RouterPath = {
|
|
91
|
-
id: string;
|
|
92
|
-
path: string;
|
|
93
|
-
route: AppRoute;
|
|
94
|
-
paths: string[];
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* @hidden
|
|
99
|
-
*/
|
|
100
|
-
export type PathSchemaResults = {
|
|
101
|
-
path: ParameterObject[];
|
|
102
|
-
headers: ParameterObject[];
|
|
103
|
-
query: ParameterObject[];
|
|
104
|
-
body: SchemaObject | null;
|
|
105
|
-
/**
|
|
106
|
-
* Status code to response.
|
|
107
|
-
*/
|
|
108
|
-
responses: Record<string, SchemaObject>;
|
|
109
|
-
};
|