moonflower 0.9.0
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/.eslintrc.js +26 -0
- package/.prettierrc.js +7 -0
- package/README.md +383 -0
- package/cli/cli.ts +59 -0
- package/cli/entry.cjs +3 -0
- package/cli/prettyprint.ts +16 -0
- package/dist/cli/cli.d.ts +2 -0
- package/dist/cli/cli.d.ts.map +1 -0
- package/dist/cli/cli.js +79 -0
- package/dist/cli/prettyprint.d.ts +4 -0
- package/dist/cli/prettyprint.d.ts.map +1 -0
- package/dist/cli/prettyprint.js +18 -0
- package/dist/src/errors/BaseHttpError.d.ts +13 -0
- package/dist/src/errors/BaseHttpError.d.ts.map +1 -0
- package/dist/src/errors/BaseHttpError.js +13 -0
- package/dist/src/errors/HttpErrorHandler.d.ts +3 -0
- package/dist/src/errors/HttpErrorHandler.d.ts.map +1 -0
- package/dist/src/errors/HttpErrorHandler.js +23 -0
- package/dist/src/errors/UserFacingErrors.d.ts +11 -0
- package/dist/src/errors/UserFacingErrors.d.ts.map +1 -0
- package/dist/src/errors/UserFacingErrors.js +23 -0
- package/dist/src/hooks/authentication/useAuth.d.ts +3 -0
- package/dist/src/hooks/authentication/useAuth.d.ts.map +1 -0
- package/dist/src/hooks/authentication/useAuth.js +7 -0
- package/dist/src/hooks/authentication/useOptionalAuth.d.ts +3 -0
- package/dist/src/hooks/authentication/useOptionalAuth.d.ts.map +1 -0
- package/dist/src/hooks/authentication/useOptionalAuth.js +16 -0
- package/dist/src/hooks/useApiEndpoint.d.ts +8 -0
- package/dist/src/hooks/useApiEndpoint.d.ts.map +1 -0
- package/dist/src/hooks/useApiEndpoint.js +7 -0
- package/dist/src/hooks/useApiHeader/index.d.ts +2 -0
- package/dist/src/hooks/useApiHeader/index.d.ts.map +1 -0
- package/dist/src/hooks/useApiHeader/index.js +17 -0
- package/dist/src/hooks/useApiHeader/useApiHeader.d.ts +3 -0
- package/dist/src/hooks/useApiHeader/useApiHeader.d.ts.map +1 -0
- package/dist/src/hooks/useApiHeader/useApiHeader.js +6 -0
- package/dist/src/hooks/useApiHeader/useApiHeader.spec.data.d.ts +2 -0
- package/dist/src/hooks/useApiHeader/useApiHeader.spec.data.d.ts.map +1 -0
- package/dist/src/hooks/useApiHeader/useApiHeader.spec.data.js +22 -0
- package/dist/src/hooks/useCookieParams.d.ts +9 -0
- package/dist/src/hooks/useCookieParams.d.ts.map +1 -0
- package/dist/src/hooks/useCookieParams.js +50 -0
- package/dist/src/hooks/useExposeApiModel/index.d.ts +2 -0
- package/dist/src/hooks/useExposeApiModel/index.d.ts.map +1 -0
- package/dist/src/hooks/useExposeApiModel/index.js +17 -0
- package/dist/src/hooks/useExposeApiModel/useExposeApiModel.d.ts +3 -0
- package/dist/src/hooks/useExposeApiModel/useExposeApiModel.d.ts.map +1 -0
- package/dist/src/hooks/useExposeApiModel/useExposeApiModel.js +9 -0
- package/dist/src/hooks/useExposeApiModel/useExposeApiModel.spec.data.d.ts +2 -0
- package/dist/src/hooks/useExposeApiModel/useExposeApiModel.spec.data.d.ts.map +1 -0
- package/dist/src/hooks/useExposeApiModel/useExposeApiModel.spec.data.js +16 -0
- package/dist/src/hooks/useHeaderParams.d.ts +12 -0
- package/dist/src/hooks/useHeaderParams.d.ts.map +1 -0
- package/dist/src/hooks/useHeaderParams.js +52 -0
- package/dist/src/hooks/usePathParams.d.ts +22 -0
- package/dist/src/hooks/usePathParams.d.ts.map +1 -0
- package/dist/src/hooks/usePathParams.js +46 -0
- package/dist/src/hooks/useQueryParams.d.ts +9 -0
- package/dist/src/hooks/useQueryParams.d.ts.map +1 -0
- package/dist/src/hooks/useQueryParams.js +50 -0
- package/dist/src/hooks/useRequestBody.d.ts +9 -0
- package/dist/src/hooks/useRequestBody.d.ts.map +1 -0
- package/dist/src/hooks/useRequestBody.js +59 -0
- package/dist/src/hooks/useRequestRawBody.d.ts +7 -0
- package/dist/src/hooks/useRequestRawBody.d.ts.map +1 -0
- package/dist/src/hooks/useRequestRawBody.js +34 -0
- package/dist/src/index.d.ts +18 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +33 -0
- package/dist/src/openapi/analyzerModule/analyzerModule.d.ts +18 -0
- package/dist/src/openapi/analyzerModule/analyzerModule.d.ts.map +1 -0
- package/dist/src/openapi/analyzerModule/analyzerModule.js +192 -0
- package/dist/src/openapi/analyzerModule/nodeParsers.d.ts +19 -0
- package/dist/src/openapi/analyzerModule/nodeParsers.d.ts.map +1 -0
- package/dist/src/openapi/analyzerModule/nodeParsers.js +521 -0
- package/dist/src/openapi/analyzerModule/parseEndpoint.d.ts +4 -0
- package/dist/src/openapi/analyzerModule/parseEndpoint.d.ts.map +1 -0
- package/dist/src/openapi/analyzerModule/parseEndpoint.js +246 -0
- package/dist/src/openapi/analyzerModule/parseExposedModels.d.ts +5 -0
- package/dist/src/openapi/analyzerModule/parseExposedModels.d.ts.map +1 -0
- package/dist/src/openapi/analyzerModule/parseExposedModels.js +32 -0
- package/dist/src/openapi/analyzerModule/test/openApiAnalyzer.spec.data.d.ts +2 -0
- package/dist/src/openapi/analyzerModule/test/openApiAnalyzer.spec.data.d.ts.map +1 -0
- package/dist/src/openapi/analyzerModule/test/openApiAnalyzer.spec.data.js +400 -0
- package/dist/src/openapi/analyzerModule/types.d.ts +53 -0
- package/dist/src/openapi/analyzerModule/types.d.ts.map +1 -0
- package/dist/src/openapi/analyzerModule/types.js +2 -0
- package/dist/src/openapi/discoveryModule/discoverImports/discoverImports.d.ts +8 -0
- package/dist/src/openapi/discoveryModule/discoverImports/discoverImports.d.ts.map +1 -0
- package/dist/src/openapi/discoveryModule/discoverImports/discoverImports.js +33 -0
- package/dist/src/openapi/discoveryModule/discoverRouterFiles/data/testRouterA.spec.data.d.ts +4 -0
- package/dist/src/openapi/discoveryModule/discoverRouterFiles/data/testRouterA.spec.data.d.ts.map +1 -0
- package/dist/src/openapi/discoveryModule/discoverRouterFiles/data/testRouterA.spec.data.js +8 -0
- package/dist/src/openapi/discoveryModule/discoverRouterFiles/data/testRouterB.spec.data.d.ts +4 -0
- package/dist/src/openapi/discoveryModule/discoverRouterFiles/data/testRouterB.spec.data.d.ts.map +1 -0
- package/dist/src/openapi/discoveryModule/discoverRouterFiles/data/testRouterB.spec.data.js +8 -0
- package/dist/src/openapi/discoveryModule/discoverRouterFiles/discoverRouterFiles.d.ts +17 -0
- package/dist/src/openapi/discoveryModule/discoverRouterFiles/discoverRouterFiles.d.ts.map +1 -0
- package/dist/src/openapi/discoveryModule/discoverRouterFiles/discoverRouterFiles.js +80 -0
- package/dist/src/openapi/discoveryModule/discoverRouters/discoverRouters.d.ts +6 -0
- package/dist/src/openapi/discoveryModule/discoverRouters/discoverRouters.d.ts.map +1 -0
- package/dist/src/openapi/discoveryModule/discoverRouters/discoverRouters.js +31 -0
- package/dist/src/openapi/discoveryModule/discoverRouters/discoverRouters.spec.data.d.ts +5 -0
- package/dist/src/openapi/discoveryModule/discoverRouters/discoverRouters.spec.data.d.ts.map +1 -0
- package/dist/src/openapi/discoveryModule/discoverRouters/discoverRouters.spec.data.js +38 -0
- package/dist/src/openapi/discoveryModule/index.d.ts +3 -0
- package/dist/src/openapi/discoveryModule/index.d.ts.map +1 -0
- package/dist/src/openapi/discoveryModule/index.js +18 -0
- package/dist/src/openapi/generatorModule/generateComponentSchemas.d.ts +4 -0
- package/dist/src/openapi/generatorModule/generateComponentSchemas.d.ts.map +1 -0
- package/dist/src/openapi/generatorModule/generateComponentSchemas.js +12 -0
- package/dist/src/openapi/generatorModule/generatePaths.d.ts +10 -0
- package/dist/src/openapi/generatorModule/generatePaths.d.ts.map +1 -0
- package/dist/src/openapi/generatorModule/generatePaths.js +116 -0
- package/dist/src/openapi/generatorModule/generatorModule.d.ts +16 -0
- package/dist/src/openapi/generatorModule/generatorModule.d.ts.map +1 -0
- package/dist/src/openapi/generatorModule/generatorModule.js +18 -0
- package/dist/src/openapi/generatorModule/getSchema.d.ts +36 -0
- package/dist/src/openapi/generatorModule/getSchema.d.ts.map +1 -0
- package/dist/src/openapi/generatorModule/getSchema.js +133 -0
- package/dist/src/openapi/generatorModule/index.d.ts +5 -0
- package/dist/src/openapi/generatorModule/index.d.ts.map +1 -0
- package/dist/src/openapi/generatorModule/index.js +20 -0
- package/dist/src/openapi/generatorModule/test/openApiGenerator.spec.data.d.ts +515 -0
- package/dist/src/openapi/generatorModule/test/openApiGenerator.spec.data.d.ts.map +1 -0
- package/dist/src/openapi/generatorModule/test/openApiGenerator.spec.data.js +1119 -0
- package/dist/src/openapi/initOpenApiEngine.d.ts +4 -0
- package/dist/src/openapi/initOpenApiEngine.d.ts.map +1 -0
- package/dist/src/openapi/initOpenApiEngine.js +14 -0
- package/dist/src/openapi/manager/OpenApiManager.d.ts +67 -0
- package/dist/src/openapi/manager/OpenApiManager.d.ts.map +1 -0
- package/dist/src/openapi/manager/OpenApiManager.js +86 -0
- package/dist/src/openapi/router/OpenApiRouter.d.ts +4 -0
- package/dist/src/openapi/router/OpenApiRouter.d.ts.map +1 -0
- package/dist/src/openapi/router/OpenApiRouter.js +11 -0
- package/dist/src/openapi/types.d.ts +81 -0
- package/dist/src/openapi/types.d.ts.map +1 -0
- package/dist/src/openapi/types.js +2 -0
- package/dist/src/router/Router.d.ts +23 -0
- package/dist/src/router/Router.d.ts.map +1 -0
- package/dist/src/router/Router.js +81 -0
- package/dist/src/router/responseValueToJson.d.ts +2 -0
- package/dist/src/router/responseValueToJson.d.ts.map +1 -0
- package/dist/src/router/responseValueToJson.js +10 -0
- package/dist/src/setupTests.d.ts +1 -0
- package/dist/src/setupTests.d.ts.map +1 -0
- package/dist/src/setupTests.js +3 -0
- package/dist/src/test/TestAppRouter.d.ts +8 -0
- package/dist/src/test/TestAppRouter.d.ts.map +1 -0
- package/dist/src/test/TestAppRouter.js +58 -0
- package/dist/src/test/app.d.ts +3 -0
- package/dist/src/test/app.d.ts.map +1 -0
- package/dist/src/test/app.js +41 -0
- package/dist/src/utils/TypeUtils.d.ts +22 -0
- package/dist/src/utils/TypeUtils.d.ts.map +1 -0
- package/dist/src/utils/TypeUtils.js +2 -0
- package/dist/src/utils/fromZodSchema.d.ts +2 -0
- package/dist/src/utils/fromZodSchema.d.ts.map +1 -0
- package/dist/src/utils/fromZodSchema.js +6 -0
- package/dist/src/utils/loadTestData.d.ts +2 -0
- package/dist/src/utils/loadTestData.d.ts.map +1 -0
- package/dist/src/utils/loadTestData.js +39 -0
- package/dist/src/utils/mockContext.d.ts +20 -0
- package/dist/src/utils/mockContext.d.ts.map +1 -0
- package/dist/src/utils/mockContext.js +85 -0
- package/dist/src/utils/nameOf.d.ts +5 -0
- package/dist/src/utils/nameOf.d.ts.map +1 -0
- package/dist/src/utils/nameOf.js +7 -0
- package/dist/src/utils/object.d.ts +7 -0
- package/dist/src/utils/object.d.ts.map +1 -0
- package/dist/src/utils/object.js +21 -0
- package/dist/src/utils/printers.d.ts +6 -0
- package/dist/src/utils/printers.d.ts.map +1 -0
- package/dist/src/utils/printers.js +76 -0
- package/dist/src/utils/validationMessages.d.ts +18 -0
- package/dist/src/utils/validationMessages.d.ts.map +1 -0
- package/dist/src/utils/validationMessages.js +43 -0
- package/dist/src/validators/BuiltInValidators.d.ts +61 -0
- package/dist/src/validators/BuiltInValidators.d.ts.map +1 -0
- package/dist/src/validators/BuiltInValidators.js +66 -0
- package/dist/src/validators/InternalParamWrappers.d.ts +5 -0
- package/dist/src/validators/InternalParamWrappers.d.ts.map +1 -0
- package/dist/src/validators/InternalParamWrappers.js +5 -0
- package/dist/src/validators/ParamWrappers.d.ts +11 -0
- package/dist/src/validators/ParamWrappers.d.ts.map +1 -0
- package/dist/src/validators/ParamWrappers.js +9 -0
- package/dist/src/validators/types.d.ts +18 -0
- package/dist/src/validators/types.d.ts.map +1 -0
- package/dist/src/validators/types.js +2 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/package.json +59 -0
- package/src/errors/BaseHttpError.ts +16 -0
- package/src/errors/HttpErrorHandler.ts +20 -0
- package/src/errors/UserFacingErrors.ts +39 -0
- package/src/hooks/authentication/useAuth.ts +8 -0
- package/src/hooks/authentication/useOptionalAuth.ts +17 -0
- package/src/hooks/useApiEndpoint.spec.ts +11 -0
- package/src/hooks/useApiEndpoint.ts +10 -0
- package/src/hooks/useApiHeader/index.ts +1 -0
- package/src/hooks/useApiHeader/useApiHeader.spec.data.ts +22 -0
- package/src/hooks/useApiHeader/useApiHeader.spec.ts +34 -0
- package/src/hooks/useApiHeader/useApiHeader.ts +6 -0
- package/src/hooks/useCookieParams.spec.ts +174 -0
- package/src/hooks/useCookieParams.ts +73 -0
- package/src/hooks/useExposeApiModel/index.ts +1 -0
- package/src/hooks/useExposeApiModel/useExposeApiModel.spec.data.ts +48 -0
- package/src/hooks/useExposeApiModel/useExposeApiModel.spec.ts +388 -0
- package/src/hooks/useExposeApiModel/useExposeApiModel.ts +9 -0
- package/src/hooks/useHeaderParams.spec.ts +186 -0
- package/src/hooks/useHeaderParams.ts +83 -0
- package/src/hooks/usePathParams.spec.ts +161 -0
- package/src/hooks/usePathParams.ts +89 -0
- package/src/hooks/useQueryParams.spec.ts +224 -0
- package/src/hooks/useQueryParams.ts +73 -0
- package/src/hooks/useRequestBody.spec.ts +215 -0
- package/src/hooks/useRequestBody.ts +94 -0
- package/src/hooks/useRequestRawBody.spec.ts +154 -0
- package/src/hooks/useRequestRawBody.ts +56 -0
- package/src/index.ts +17 -0
- package/src/openapi/analyzerModule/analyzerModule.ts +228 -0
- package/src/openapi/analyzerModule/nodeParsers.ts +648 -0
- package/src/openapi/analyzerModule/parseEndpoint.ts +305 -0
- package/src/openapi/analyzerModule/parseExposedModels.ts +34 -0
- package/src/openapi/analyzerModule/test/openApiAnalyzer.spec.data.ts +521 -0
- package/src/openapi/analyzerModule/test/openApiAnalyzer.spec.ts +1043 -0
- package/src/openapi/analyzerModule/types.ts +72 -0
- package/src/openapi/discoveryModule/discoverImports/discoverImports.ts +43 -0
- package/src/openapi/discoveryModule/discoverRouterFiles/data/testRouterA.spec.data.ts +7 -0
- package/src/openapi/discoveryModule/discoverRouterFiles/data/testRouterB.spec.data.ts +7 -0
- package/src/openapi/discoveryModule/discoverRouterFiles/discoverRouterFiles.spec.ts +36 -0
- package/src/openapi/discoveryModule/discoverRouterFiles/discoverRouterFiles.ts +80 -0
- package/src/openapi/discoveryModule/discoverRouters/discoverRouters.spec.data.ts +42 -0
- package/src/openapi/discoveryModule/discoverRouters/discoverRouters.spec.ts +18 -0
- package/src/openapi/discoveryModule/discoverRouters/discoverRouters.ts +39 -0
- package/src/openapi/discoveryModule/index.ts +2 -0
- package/src/openapi/generatorModule/generateComponentSchemas.ts +12 -0
- package/src/openapi/generatorModule/generatePaths.ts +138 -0
- package/src/openapi/generatorModule/generatorModule.ts +17 -0
- package/src/openapi/generatorModule/getSchema.ts +169 -0
- package/src/openapi/generatorModule/index.ts +4 -0
- package/src/openapi/generatorModule/test/openApiGenerator.spec.data.ts +1119 -0
- package/src/openapi/generatorModule/test/openApiGenerator.spec.ts +783 -0
- package/src/openapi/initOpenApiEngine.ts +20 -0
- package/src/openapi/manager/OpenApiManager.ts +153 -0
- package/src/openapi/router/OpenApiRouter.ts +11 -0
- package/src/openapi/types.ts +86 -0
- package/src/router/Router.ts +123 -0
- package/src/router/responseValueToJson.ts +6 -0
- package/src/setupTests.ts +3 -0
- package/src/test/TestAppRouter.ts +76 -0
- package/src/test/app.spec.ts +130 -0
- package/src/test/app.ts +43 -0
- package/src/utils/TypeUtils.ts +51 -0
- package/src/utils/loadTestData.ts +15 -0
- package/src/utils/mockContext.ts +86 -0
- package/src/utils/nameOf.ts +7 -0
- package/src/utils/object.spec.ts +27 -0
- package/src/utils/object.ts +17 -0
- package/src/utils/printers.spec.ts +103 -0
- package/src/utils/printers.ts +49 -0
- package/src/utils/validationMessages.ts +65 -0
- package/src/validators/BuiltInValidators.ts +64 -0
- package/src/validators/InternalParamWrappers.ts +14 -0
- package/src/validators/ParamWrappers.ts +22 -0
- package/src/validators/types.ts +35 -0
- package/tsconfig.build.json +15 -0
- package/tsconfig.json +29 -0
- package/vite.config.ts +16 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import Koa from 'koa'
|
|
2
|
+
|
|
3
|
+
import { prepareOpenApiSpec } from './analyzerModule/analyzerModule'
|
|
4
|
+
import { OpenApiRouter } from './router/OpenApiRouter'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Middleware to initialize the openApi engine.
|
|
8
|
+
* Can be at any position in the middleware execution order.
|
|
9
|
+
* All files with routers or exposed models must be included in `props.sourceFilePaths`.
|
|
10
|
+
* @param props Paths to files to analyze, relative to project root.
|
|
11
|
+
*/
|
|
12
|
+
export const initOpenApiEngine = (props: Parameters<typeof prepareOpenApiSpec>[0]) => {
|
|
13
|
+
prepareOpenApiSpec(props)
|
|
14
|
+
|
|
15
|
+
const builtInRoutes = OpenApiRouter.routes()
|
|
16
|
+
const builtInAllowedMethods = OpenApiRouter.allowedMethods()
|
|
17
|
+
return (ctx: Koa.ParameterizedContext<any, any>, next: Koa.Next) => {
|
|
18
|
+
return builtInRoutes(ctx, () => builtInAllowedMethods(ctx, next))
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { Router } from '../../router/Router'
|
|
2
|
+
import { EndpointData, ExposedModelData } from '../types'
|
|
3
|
+
|
|
4
|
+
type UrlType = `${'http' | 'https'}://${string}.${string}`
|
|
5
|
+
|
|
6
|
+
export type ApiDocsHeader = {
|
|
7
|
+
title: string
|
|
8
|
+
version: string
|
|
9
|
+
description?: string
|
|
10
|
+
termsOfService?: UrlType
|
|
11
|
+
contact?: {
|
|
12
|
+
name?: string
|
|
13
|
+
url?: UrlType
|
|
14
|
+
email?: string
|
|
15
|
+
}
|
|
16
|
+
license?: {
|
|
17
|
+
name?: string
|
|
18
|
+
url?: UrlType
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type ApiDocsPreferences = {
|
|
23
|
+
allowOptionalPathParams: boolean
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export type ApiAnalysisStats = {
|
|
27
|
+
explicitRouterFiles: {
|
|
28
|
+
path: string
|
|
29
|
+
routers: {
|
|
30
|
+
name: string
|
|
31
|
+
endpoints: string[]
|
|
32
|
+
}[]
|
|
33
|
+
}[]
|
|
34
|
+
discoveredRouterFiles: {
|
|
35
|
+
path: string
|
|
36
|
+
routers: {
|
|
37
|
+
name: string
|
|
38
|
+
endpoints: string[]
|
|
39
|
+
}[]
|
|
40
|
+
}[]
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export class OpenApiManager {
|
|
44
|
+
private static instance: OpenApiManager | null = null
|
|
45
|
+
|
|
46
|
+
private isInitialized = false
|
|
47
|
+
private registeredRouters: Router[] = []
|
|
48
|
+
|
|
49
|
+
constructor(
|
|
50
|
+
private apiDocsHeader: ApiDocsHeader,
|
|
51
|
+
private exposedModels: ExposedModelData[],
|
|
52
|
+
private endpoints: EndpointData[],
|
|
53
|
+
private preferences: ApiDocsPreferences,
|
|
54
|
+
private stats: ApiAnalysisStats
|
|
55
|
+
) {}
|
|
56
|
+
|
|
57
|
+
public isReady(): boolean {
|
|
58
|
+
return this.isInitialized
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
public hasExposedModel(name: string) {
|
|
62
|
+
return this.exposedModels.some((model) => model.name === name)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
public getExposedModels() {
|
|
66
|
+
return this.exposedModels
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
public setExposedModels(models: ExposedModelData[]) {
|
|
70
|
+
this.exposedModels = models
|
|
71
|
+
return this
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
public setEndpoints(endpoints: EndpointData[]) {
|
|
75
|
+
this.endpoints = endpoints
|
|
76
|
+
return this
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
public markAsReady() {
|
|
80
|
+
this.isInitialized = true
|
|
81
|
+
return this
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public getHeader(): ApiDocsHeader {
|
|
85
|
+
return this.apiDocsHeader
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
public setHeader(docs: ApiDocsHeader) {
|
|
89
|
+
this.apiDocsHeader = docs
|
|
90
|
+
return this
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
public getEndpoints() {
|
|
94
|
+
return this.endpoints
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
public getPreferences() {
|
|
98
|
+
return this.preferences
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
public setPreferences(preferences: ApiDocsPreferences) {
|
|
102
|
+
this.preferences = {
|
|
103
|
+
...preferences,
|
|
104
|
+
}
|
|
105
|
+
return this
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
public getStats() {
|
|
109
|
+
return this.stats
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
public setStats(stats: ApiAnalysisStats) {
|
|
113
|
+
this.stats = {
|
|
114
|
+
...stats,
|
|
115
|
+
}
|
|
116
|
+
return this
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
public getRouters(): readonly Router[] {
|
|
120
|
+
return this.registeredRouters
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
public registerRouters(routers: Router<any, any>[]) {
|
|
124
|
+
routers.forEach((r) => this.registeredRouters.push(r))
|
|
125
|
+
return this
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
public reset() {
|
|
129
|
+
this.exposedModels = []
|
|
130
|
+
this.endpoints = []
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
public static getInstance() {
|
|
134
|
+
if (!OpenApiManager.instance) {
|
|
135
|
+
OpenApiManager.instance = new OpenApiManager(
|
|
136
|
+
{
|
|
137
|
+
title: 'Default title',
|
|
138
|
+
version: '1.0.0',
|
|
139
|
+
},
|
|
140
|
+
[],
|
|
141
|
+
[],
|
|
142
|
+
{
|
|
143
|
+
allowOptionalPathParams: false,
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
discoveredRouterFiles: [],
|
|
147
|
+
explicitRouterFiles: [],
|
|
148
|
+
}
|
|
149
|
+
)
|
|
150
|
+
}
|
|
151
|
+
return OpenApiManager.instance
|
|
152
|
+
}
|
|
153
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Router } from '../../router/Router'
|
|
2
|
+
import { generateOpenApiSpec } from '../generatorModule/generatorModule'
|
|
3
|
+
import { OpenApiManager } from '../manager/OpenApiManager'
|
|
4
|
+
|
|
5
|
+
const router = new Router({ skipOpenApiAnalysis: true })
|
|
6
|
+
|
|
7
|
+
router.get('/api-json', () => {
|
|
8
|
+
return generateOpenApiSpec(OpenApiManager.getInstance())
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
export const OpenApiRouter = router
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { ShapeOfType } from './analyzerModule/types'
|
|
2
|
+
import { SchemaType } from './generatorModule/getSchema'
|
|
3
|
+
|
|
4
|
+
type PathParam = {
|
|
5
|
+
name: string
|
|
6
|
+
in: 'query' | 'path' | 'header'
|
|
7
|
+
description: string
|
|
8
|
+
required: true | false | undefined
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export type PathDefinition = {
|
|
12
|
+
summary?: string
|
|
13
|
+
description: string
|
|
14
|
+
operationId?: string
|
|
15
|
+
parameters: PathParam[]
|
|
16
|
+
requestBody: any
|
|
17
|
+
tags?: string[]
|
|
18
|
+
responses: Record<
|
|
19
|
+
string,
|
|
20
|
+
{
|
|
21
|
+
description: string
|
|
22
|
+
content?: {
|
|
23
|
+
'application/json': {
|
|
24
|
+
schema: {
|
|
25
|
+
oneOf: SchemaType[]
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
>
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type ExposedModelData = {
|
|
34
|
+
name: string
|
|
35
|
+
shape: string | ShapeOfType[]
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export type EndpointData = {
|
|
39
|
+
method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'
|
|
40
|
+
path: string
|
|
41
|
+
sourceFilePath: string
|
|
42
|
+
name?: string
|
|
43
|
+
summary?: string
|
|
44
|
+
description?: string
|
|
45
|
+
tags?: string[]
|
|
46
|
+
requestPathParams: {
|
|
47
|
+
identifier: string
|
|
48
|
+
signature: string | ShapeOfType[]
|
|
49
|
+
optional: boolean
|
|
50
|
+
description?: string
|
|
51
|
+
errorMessage?: string
|
|
52
|
+
}[]
|
|
53
|
+
requestQuery: {
|
|
54
|
+
identifier: string
|
|
55
|
+
signature: string | ShapeOfType[]
|
|
56
|
+
optional: boolean
|
|
57
|
+
description?: string
|
|
58
|
+
errorMessage?: string
|
|
59
|
+
}[]
|
|
60
|
+
requestHeaders: {
|
|
61
|
+
identifier: string
|
|
62
|
+
signature: string | ShapeOfType[]
|
|
63
|
+
optional: boolean
|
|
64
|
+
description?: string
|
|
65
|
+
errorMessage?: string
|
|
66
|
+
}[]
|
|
67
|
+
rawBody?: {
|
|
68
|
+
signature: string | ShapeOfType[]
|
|
69
|
+
optional: boolean
|
|
70
|
+
description?: string
|
|
71
|
+
errorMessage?: string
|
|
72
|
+
}
|
|
73
|
+
objectBody: {
|
|
74
|
+
identifier: string
|
|
75
|
+
signature: string | ShapeOfType[]
|
|
76
|
+
optional: boolean
|
|
77
|
+
description?: string
|
|
78
|
+
errorMessage?: string
|
|
79
|
+
}[]
|
|
80
|
+
responses: {
|
|
81
|
+
status: number
|
|
82
|
+
signature: string | ShapeOfType[]
|
|
83
|
+
description?: string
|
|
84
|
+
errorMessage?: string
|
|
85
|
+
}[]
|
|
86
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
|
2
|
+
import KoaRouter from '@koa/router'
|
|
3
|
+
import Koa from 'koa'
|
|
4
|
+
|
|
5
|
+
import { OpenApiManager } from '../openapi/manager/OpenApiManager'
|
|
6
|
+
import { ExtractedRequestParams } from '../utils/TypeUtils'
|
|
7
|
+
import { responseValueToJson } from './responseValueToJson'
|
|
8
|
+
|
|
9
|
+
type Props = {
|
|
10
|
+
skipOpenApiAnalysis: boolean
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export class Router<StateT = Koa.DefaultState, ContextT = Koa.DefaultContext> {
|
|
14
|
+
public koaRouter: KoaRouter = new KoaRouter()
|
|
15
|
+
|
|
16
|
+
public constructor(props: Props = { skipOpenApiAnalysis: false }) {
|
|
17
|
+
if (!props.skipOpenApiAnalysis) {
|
|
18
|
+
const openApiManager = OpenApiManager.getInstance()
|
|
19
|
+
openApiManager.registerRouters([this])
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public use(...middleware: Array<KoaRouter.Middleware<StateT, ContextT>>) {
|
|
24
|
+
// @ts-ignore
|
|
25
|
+
this.koaRouter.use(...middleware)
|
|
26
|
+
return this
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public with<ResponseTypeT extends Record<string, any>>(
|
|
30
|
+
middleware: (ctx: Koa.ParameterizedContext<ContextT>) => ResponseTypeT
|
|
31
|
+
) {
|
|
32
|
+
type AugmentedData = ResponseTypeT extends Promise<any> ? Awaited<ResponseTypeT> : ResponseTypeT
|
|
33
|
+
this.koaRouter.use(async (ctx, next) => {
|
|
34
|
+
// @ts-ignore
|
|
35
|
+
const userData = await Promise.resolve(middleware(ctx))
|
|
36
|
+
Object.keys(userData).forEach((key) => {
|
|
37
|
+
ctx[key] = userData[key]
|
|
38
|
+
})
|
|
39
|
+
await next()
|
|
40
|
+
})
|
|
41
|
+
return this as Router<StateT, ContextT & AugmentedData>
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
public get<P extends string>(
|
|
45
|
+
path: P,
|
|
46
|
+
callback: KoaRouter.Middleware<StateT, ContextT & ExtractedRequestParams<P>>
|
|
47
|
+
) {
|
|
48
|
+
this.koaRouter.get(path, async (ctx) => {
|
|
49
|
+
// @ts-ignore
|
|
50
|
+
const responseValue = await callback(ctx, undefined)
|
|
51
|
+
ctx.body = responseValueToJson(responseValue)
|
|
52
|
+
})
|
|
53
|
+
return this
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
public post<P extends string>(
|
|
57
|
+
path: P,
|
|
58
|
+
callback: KoaRouter.Middleware<StateT, ContextT & ExtractedRequestParams<P>>
|
|
59
|
+
) {
|
|
60
|
+
this.koaRouter.post(path, async (ctx) => {
|
|
61
|
+
// @ts-ignore
|
|
62
|
+
const responseValue = await callback(ctx, undefined)
|
|
63
|
+
ctx.body = responseValueToJson(responseValue)
|
|
64
|
+
})
|
|
65
|
+
return this
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public put<P extends string>(
|
|
69
|
+
path: P,
|
|
70
|
+
callback: KoaRouter.Middleware<StateT, ContextT & ExtractedRequestParams<P>>
|
|
71
|
+
) {
|
|
72
|
+
this.koaRouter.put(path, async (ctx) => {
|
|
73
|
+
// @ts-ignore
|
|
74
|
+
const responseValue = await callback(ctx, undefined)
|
|
75
|
+
ctx.body = responseValueToJson(responseValue)
|
|
76
|
+
})
|
|
77
|
+
return this
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
public delete<P extends string>(
|
|
81
|
+
path: P,
|
|
82
|
+
callback: KoaRouter.Middleware<StateT, ContextT & ExtractedRequestParams<P>>
|
|
83
|
+
) {
|
|
84
|
+
this.koaRouter.delete(path, async (ctx) => {
|
|
85
|
+
// @ts-ignore
|
|
86
|
+
const responseValue = await callback(ctx, undefined)
|
|
87
|
+
ctx.body = responseValueToJson(responseValue)
|
|
88
|
+
})
|
|
89
|
+
return this
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
public del<P extends string>(
|
|
93
|
+
path: P,
|
|
94
|
+
callback: KoaRouter.Middleware<StateT, ContextT & ExtractedRequestParams<P>>
|
|
95
|
+
) {
|
|
96
|
+
this.koaRouter.del(path, async (ctx) => {
|
|
97
|
+
// @ts-ignore
|
|
98
|
+
const responseValue = await callback(ctx, undefined)
|
|
99
|
+
ctx.body = responseValueToJson(responseValue)
|
|
100
|
+
})
|
|
101
|
+
return this
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
public patch<P extends string>(
|
|
105
|
+
path: P,
|
|
106
|
+
callback: KoaRouter.Middleware<StateT, ContextT & ExtractedRequestParams<P>>
|
|
107
|
+
) {
|
|
108
|
+
this.koaRouter.patch(path, async (ctx) => {
|
|
109
|
+
// @ts-ignore
|
|
110
|
+
const responseValue = await callback(ctx, undefined)
|
|
111
|
+
ctx.body = responseValueToJson(responseValue)
|
|
112
|
+
})
|
|
113
|
+
return this
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
public routes() {
|
|
117
|
+
return this.koaRouter.routes()
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
public allowedMethods() {
|
|
121
|
+
return this.koaRouter.allowedMethods()
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BadRequestError,
|
|
3
|
+
EmailValidator,
|
|
4
|
+
NonEmptyStringValidator,
|
|
5
|
+
UnauthorizedError,
|
|
6
|
+
useQueryParams,
|
|
7
|
+
} from '..'
|
|
8
|
+
import { Router as RenamedRouter } from '../router/Router'
|
|
9
|
+
|
|
10
|
+
const myRouter = new RenamedRouter()
|
|
11
|
+
.use((_, next) => next())
|
|
12
|
+
.with(() => {
|
|
13
|
+
const user = { id: '123' }
|
|
14
|
+
return {
|
|
15
|
+
user,
|
|
16
|
+
}
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
myRouter.get('/test/hello', () => {
|
|
20
|
+
return {
|
|
21
|
+
greeting: 'hello world',
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
myRouter.get('/test/query', (ctx) => {
|
|
26
|
+
const { email, string } = useQueryParams(ctx, {
|
|
27
|
+
email: EmailValidator,
|
|
28
|
+
string: NonEmptyStringValidator,
|
|
29
|
+
})
|
|
30
|
+
return {
|
|
31
|
+
email,
|
|
32
|
+
string,
|
|
33
|
+
}
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
myRouter.post('/test/post', () => {
|
|
37
|
+
return 'post response'
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
myRouter.del('/test/del', () => {
|
|
41
|
+
// Empty
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
myRouter.delete('/test/delete', () => {
|
|
45
|
+
// Empty
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
myRouter.patch('/test/patch', () => {
|
|
49
|
+
return 'patch response'
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
myRouter.get('/test/error/generic', () => {
|
|
53
|
+
throw new Error('Generic error')
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
myRouter.get('/test/error/unauthorized', () => {
|
|
57
|
+
throw new UnauthorizedError('Test error')
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
myRouter.get('/test/error/badrequest', () => {
|
|
61
|
+
throw new BadRequestError('Test error')
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
myRouter.get('/test/get/bigint', () => {
|
|
65
|
+
return {
|
|
66
|
+
foo: BigInt(100),
|
|
67
|
+
}
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
myRouter.get('/test/get/middleware-data', (ctx) => {
|
|
71
|
+
return {
|
|
72
|
+
user: ctx.user,
|
|
73
|
+
}
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
export const TestAppRouter = myRouter
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import request from 'supertest'
|
|
2
|
+
import { vi } from 'vitest'
|
|
3
|
+
|
|
4
|
+
import { generateOpenApiSpec } from '../openapi/generatorModule/generatorModule'
|
|
5
|
+
import { app } from './app'
|
|
6
|
+
|
|
7
|
+
describe('TestAppRouter', () => {
|
|
8
|
+
it('handles get request correctly', async () => {
|
|
9
|
+
const response = await request(app.callback()).get('/test/hello')
|
|
10
|
+
expect(response.status).toBe(200)
|
|
11
|
+
expect(response.text).toBe(JSON.stringify({ greeting: 'hello world' }))
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('handles query params', async () => {
|
|
15
|
+
const response = await request(app.callback()).get('/test/query?email=test@test.com&string=someval')
|
|
16
|
+
expect(response.status).toBe(200)
|
|
17
|
+
expect(response.text).toBe(JSON.stringify({ email: 'test@test.com', string: 'someval' }))
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
it('handles incorrect method', async () => {
|
|
21
|
+
const response = await request(app.callback()).post('/test/hello')
|
|
22
|
+
expect(response.status).toBe(405)
|
|
23
|
+
expect(response.text).toBe('Method Not Allowed')
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
it('handles post request correctly', async () => {
|
|
27
|
+
const response = await request(app.callback()).post('/test/post')
|
|
28
|
+
expect(response.status).toBe(200)
|
|
29
|
+
expect(response.text).toBe('post response')
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('handles del request correctly', async () => {
|
|
33
|
+
const response = await request(app.callback()).del('/test/del')
|
|
34
|
+
expect(response.status).toBe(204)
|
|
35
|
+
expect(response.text).toBe('')
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('handles delete request correctly', async () => {
|
|
39
|
+
const response = await request(app.callback()).delete('/test/delete')
|
|
40
|
+
expect(response.status).toBe(204)
|
|
41
|
+
expect(response.text).toBe('')
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('handles patch request correctly', async () => {
|
|
45
|
+
const response = await request(app.callback()).patch('/test/patch')
|
|
46
|
+
expect(response.status).toBe(200)
|
|
47
|
+
expect(response.text).toBe('patch response')
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
it('rethrows a generic error', async () => {
|
|
51
|
+
const consoleError = console.error
|
|
52
|
+
console.error = vi.fn()
|
|
53
|
+
const response = await request(app.callback()).get('/test/error/generic')
|
|
54
|
+
expect(response.status).toBe(500)
|
|
55
|
+
expect(response.text).toBe('Internal Server Error')
|
|
56
|
+
console.error = consoleError
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
it('handles an unauthorized error correctly', async () => {
|
|
60
|
+
const response = await request(app.callback()).get('/test/error/unauthorized')
|
|
61
|
+
expect(response.status).toBe(401)
|
|
62
|
+
expect(response.text).toBe(JSON.stringify({ status: 401, reason: 'Unauthorized', message: 'Test error' }))
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it('handles a bad request error correctly', async () => {
|
|
66
|
+
const response = await request(app.callback()).get('/test/error/badrequest')
|
|
67
|
+
expect(response.status).toBe(400)
|
|
68
|
+
expect(response.text).toBe(JSON.stringify({ status: 400, reason: 'Bad Request', message: 'Test error' }))
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
it('handles bigint return value correctly', async () => {
|
|
72
|
+
const response = await request(app.callback()).get('/test/get/bigint')
|
|
73
|
+
expect(response.status).toBe(200)
|
|
74
|
+
expect(response.text).toBe(JSON.stringify({ foo: '100' }))
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it('includes middleware data from context', async () => {
|
|
78
|
+
const response = await request(app.callback()).get('/test/get/middleware-data')
|
|
79
|
+
expect(response.status).toBe(200)
|
|
80
|
+
expect(response.text).toBe(JSON.stringify({ user: { id: '123' } }))
|
|
81
|
+
})
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
describe('OpenApiRouter', () => {
|
|
85
|
+
it('sends the openapi spec', async () => {
|
|
86
|
+
const response = await request(app.callback()).get('/api-json')
|
|
87
|
+
expect(response.status).toBe(200)
|
|
88
|
+
const responseJson = JSON.parse(response.text) as ReturnType<typeof generateOpenApiSpec>
|
|
89
|
+
expect(responseJson.openapi).toBe('3.1.0')
|
|
90
|
+
expect(responseJson.info).toEqual({
|
|
91
|
+
title: 'Test title',
|
|
92
|
+
version: '1.0.0',
|
|
93
|
+
description: 'Test description',
|
|
94
|
+
termsOfService: 'http://example.com',
|
|
95
|
+
contact: {
|
|
96
|
+
name: 'QA Engineer',
|
|
97
|
+
url: 'http://best-qa.com',
|
|
98
|
+
email: 'admin@best-qa.com',
|
|
99
|
+
},
|
|
100
|
+
license: {
|
|
101
|
+
name: 'MIT',
|
|
102
|
+
url: 'http://best-qa.com/license',
|
|
103
|
+
},
|
|
104
|
+
})
|
|
105
|
+
expect(responseJson.paths['/test/hello']).toEqual({
|
|
106
|
+
get: {
|
|
107
|
+
description: '',
|
|
108
|
+
parameters: [],
|
|
109
|
+
responses: {
|
|
110
|
+
'200': {
|
|
111
|
+
description: '',
|
|
112
|
+
content: {
|
|
113
|
+
'application/json': {
|
|
114
|
+
schema: {
|
|
115
|
+
oneOf: [
|
|
116
|
+
{
|
|
117
|
+
type: 'object',
|
|
118
|
+
properties: { greeting: { type: 'string' } },
|
|
119
|
+
required: ['greeting'],
|
|
120
|
+
},
|
|
121
|
+
],
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
})
|
|
129
|
+
})
|
|
130
|
+
})
|
package/src/test/app.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import Koa from 'koa'
|
|
2
|
+
import bodyParser from 'koa-bodyparser'
|
|
3
|
+
import { resolve } from 'path'
|
|
4
|
+
|
|
5
|
+
import { HttpErrorHandler, initOpenApiEngine, useApiHeader as useRenamedApiHeader } from '..'
|
|
6
|
+
import { TestAppRouter } from './TestAppRouter'
|
|
7
|
+
|
|
8
|
+
export const app = new Koa()
|
|
9
|
+
|
|
10
|
+
useRenamedApiHeader({
|
|
11
|
+
title: 'Test title',
|
|
12
|
+
version: '1.0.0',
|
|
13
|
+
description: 'Test description',
|
|
14
|
+
termsOfService: 'http://example.com',
|
|
15
|
+
contact: {
|
|
16
|
+
name: 'QA Engineer',
|
|
17
|
+
url: 'http://best-qa.com',
|
|
18
|
+
email: 'admin@best-qa.com',
|
|
19
|
+
},
|
|
20
|
+
license: {
|
|
21
|
+
name: 'MIT',
|
|
22
|
+
url: 'http://best-qa.com/license',
|
|
23
|
+
},
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
app
|
|
27
|
+
.use(HttpErrorHandler)
|
|
28
|
+
.use(
|
|
29
|
+
bodyParser({
|
|
30
|
+
enableTypes: ['text', 'json', 'form'],
|
|
31
|
+
})
|
|
32
|
+
)
|
|
33
|
+
.use(TestAppRouter.routes())
|
|
34
|
+
.use(TestAppRouter.allowedMethods())
|
|
35
|
+
.use(
|
|
36
|
+
initOpenApiEngine({
|
|
37
|
+
tsconfigPath: './tsconfig.json',
|
|
38
|
+
sourceFileDiscovery: {
|
|
39
|
+
rootPath: resolve(__dirname, '.'),
|
|
40
|
+
},
|
|
41
|
+
sourceFilePaths: ['./src/test/TestAppRouter.ts'],
|
|
42
|
+
})
|
|
43
|
+
)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
|
2
|
+
export type RemoveFirstFromTuple<T extends any[]> = T['length'] extends 0
|
|
3
|
+
? undefined
|
|
4
|
+
: ((...b: T) => void) extends (a: infer Q, ...b: infer I) => void
|
|
5
|
+
? I
|
|
6
|
+
: []
|
|
7
|
+
|
|
8
|
+
export type SplitStringBy<S extends string, D extends string> = string extends S
|
|
9
|
+
? string[]
|
|
10
|
+
: S extends ''
|
|
11
|
+
? []
|
|
12
|
+
: S extends `${infer T}${D}${infer U}`
|
|
13
|
+
? [T, ...SplitStringBy<U, D>]
|
|
14
|
+
: [S]
|
|
15
|
+
|
|
16
|
+
type PickParams<S extends string[], P extends string> = S['length'] extends 0
|
|
17
|
+
? []
|
|
18
|
+
: S[0] extends `${P}${string}`
|
|
19
|
+
? // @ts-ignore
|
|
20
|
+
[S[0], ...PickParams<RemoveFirstFromTuple<S>, P>]
|
|
21
|
+
: // @ts-ignore
|
|
22
|
+
PickParams<RemoveFirstFromTuple<S>, P>
|
|
23
|
+
|
|
24
|
+
export type Substring<S extends string[]> = S['length'] extends 0
|
|
25
|
+
? []
|
|
26
|
+
: // @ts-ignore
|
|
27
|
+
[SplitStringBy<S[0], ':'>[1], ...Substring<RemoveFirstFromTuple<S>>]
|
|
28
|
+
|
|
29
|
+
export type ExtractedRequestParams<S extends string> = {
|
|
30
|
+
parsedPathParams: PickParams<SplitStringBy<S, '/'>, ':'>
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type CamelCase<S extends string> = S extends `${infer P1}_${infer P2}${infer P3}`
|
|
34
|
+
? `${Lowercase<P1>}${Uppercase<P2>}${CamelCase<P3>}`
|
|
35
|
+
: S extends `${infer P1}-${infer P2}${infer P3}`
|
|
36
|
+
? `${Lowercase<P1>}${Uppercase<P2>}${CamelCase<P3>}`
|
|
37
|
+
: S
|
|
38
|
+
|
|
39
|
+
export type KeysToCamelCase<T> = {
|
|
40
|
+
[K in keyof T as CamelCase<string & K>]: T[K] extends Record<any, any> ? KeysToCamelCase<T[K]> : T[K]
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
type RemoveLeadingColon<S extends string> = S['length'] extends 0 ? never : SplitStringBy<S, ':'>[1]
|
|
44
|
+
type RemoveTrailingQuestion<S extends string> = S['length'] extends 0 ? never : SplitStringBy<S, '?'>[0]
|
|
45
|
+
export type CleanUpPathParam<S> = S extends string
|
|
46
|
+
? //@ts-ignore
|
|
47
|
+
RemoveLeadingColon<RemoveTrailingQuestion<S>> extends string
|
|
48
|
+
? //@ts-ignore
|
|
49
|
+
RemoveLeadingColon<RemoveTrailingQuestion<S>>
|
|
50
|
+
: ''
|
|
51
|
+
: never
|