ts-typed-api 0.1.14 → 0.1.15
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/openapi.js +1 -1
- package/package.json +1 -1
- package/src/openapi.ts +1 -1
- package/tests/openapi-spec.test.ts +86 -0
package/dist/openapi.js
CHANGED
|
@@ -98,7 +98,7 @@ function generateOpenApiSpec(definitions, options = {}) {
|
|
|
98
98
|
};
|
|
99
99
|
// Register the route with the registry
|
|
100
100
|
// The path needs to be transformed from Express-style (:param) to OpenAPI-style ({param})
|
|
101
|
-
const openApiPath = route.path.replace(/:(\w+)/g, '{$1}');
|
|
101
|
+
const openApiPath = `/${definition.prefix ?? ''}${route.path}`.replace(/\/+/g, '/').replace(/:(\w+)/g, '{$1}');
|
|
102
102
|
registry.registerPath({
|
|
103
103
|
method: route.method.toLowerCase(), // Ensure method is lowercase
|
|
104
104
|
path: openApiPath,
|
package/package.json
CHANGED
package/src/openapi.ts
CHANGED
|
@@ -116,7 +116,7 @@ export function generateOpenApiSpec(
|
|
|
116
116
|
|
|
117
117
|
// Register the route with the registry
|
|
118
118
|
// The path needs to be transformed from Express-style (:param) to OpenAPI-style ({param})
|
|
119
|
-
const openApiPath = route.path.replace(/:(\w+)/g, '{$1}');
|
|
119
|
+
const openApiPath = `/${definition.prefix ?? ''}${route.path}`.replace(/\/+/g, '/').replace(/:(\w+)/g, '{$1}');
|
|
120
120
|
|
|
121
121
|
registry.registerPath({
|
|
122
122
|
method: route.method.toLowerCase() as any, // Ensure method is lowercase
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { describe, test, expect } from '@jest/globals';
|
|
2
|
+
import { generateOpenApiSpec } from '../src/openapi';
|
|
3
|
+
import { PublicApiDefinition } from '../examples/simple/definitions';
|
|
4
|
+
import { PrivateApiDefinition } from '../examples/simple/definitions';
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { CreateApiDefinition } from '../src/definition';
|
|
7
|
+
|
|
8
|
+
describe('OpenAPI Specification Generation', () => {
|
|
9
|
+
test('should generate OpenAPI spec for a single definition', () => {
|
|
10
|
+
const spec = generateOpenApiSpec(PublicApiDefinition);
|
|
11
|
+
|
|
12
|
+
expect(spec).toBeDefined();
|
|
13
|
+
expect(spec.openapi).toBe('3.0.0');
|
|
14
|
+
expect(spec.info).toBeDefined();
|
|
15
|
+
expect(spec.paths).toBeDefined();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test('should generate OpenAPI spec for multiple definitions', () => {
|
|
19
|
+
const spec = generateOpenApiSpec([PublicApiDefinition, PrivateApiDefinition]);
|
|
20
|
+
|
|
21
|
+
expect(spec).toBeDefined();
|
|
22
|
+
expect(spec.openapi).toBe('3.0.0');
|
|
23
|
+
expect(spec.info).toBeDefined();
|
|
24
|
+
expect(spec.paths).toBeDefined();
|
|
25
|
+
|
|
26
|
+
// Verify paths from both definitions are included
|
|
27
|
+
const publicPaths = Object.keys(spec.paths ?? {}).filter(path =>
|
|
28
|
+
path.includes('/public/')
|
|
29
|
+
);
|
|
30
|
+
const privatePaths = Object.keys(spec.paths ?? {}).filter(path =>
|
|
31
|
+
path.includes('/private/')
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
expect(publicPaths.length).toBeGreaterThan(0);
|
|
35
|
+
expect(privatePaths.length).toBeGreaterThan(0);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test('should handle custom OpenAPI spec options', () => {
|
|
39
|
+
const spec = generateOpenApiSpec(PublicApiDefinition, {
|
|
40
|
+
info: {
|
|
41
|
+
title: 'Test API',
|
|
42
|
+
version: '2.0.0',
|
|
43
|
+
description: 'A test API description'
|
|
44
|
+
},
|
|
45
|
+
servers: [{ url: 'https://api.example.com', description: 'Production server' }]
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
expect(spec.info.title).toBe('Test API');
|
|
49
|
+
expect(spec.info.version).toBe('2.0.0');
|
|
50
|
+
expect(spec.info.description).toBe('A test API description');
|
|
51
|
+
expect(spec.servers?.[0]?.url).toBe('https://api.example.com');
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test('should handle complex Zod schemas', () => {
|
|
55
|
+
// Create a complex Zod schema to test schema registration
|
|
56
|
+
const ComplexSchema = z.object({
|
|
57
|
+
id: z.string().uuid(),
|
|
58
|
+
name: z.string().min(3).max(50),
|
|
59
|
+
age: z.number().int().positive(),
|
|
60
|
+
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
61
|
+
tags: z.array(z.string()).optional()
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const TestDefinition = CreateApiDefinition({
|
|
65
|
+
endpoints: {
|
|
66
|
+
test: {
|
|
67
|
+
complexEndpoint: {
|
|
68
|
+
method: 'POST' as const,
|
|
69
|
+
path: '/test/complex',
|
|
70
|
+
body: ComplexSchema,
|
|
71
|
+
responses: {
|
|
72
|
+
200: ComplexSchema,
|
|
73
|
+
422: z.object({ error: z.string() })
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
const spec = generateOpenApiSpec(TestDefinition);
|
|
81
|
+
|
|
82
|
+
expect(spec).toBeDefined();
|
|
83
|
+
expect(spec.components).toBeDefined();
|
|
84
|
+
expect(spec.components?.schemas).toBeDefined();
|
|
85
|
+
});
|
|
86
|
+
});
|