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,15 @@
|
|
|
1
|
+
import * as path from 'path'
|
|
2
|
+
import { Project } from 'ts-morph'
|
|
3
|
+
|
|
4
|
+
export const loadTestData = (filePath: string) => {
|
|
5
|
+
const project = new Project({
|
|
6
|
+
tsConfigFilePath: path.resolve('./tsconfig.json'),
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
const sourceFile = project.getSourceFile(filePath)
|
|
10
|
+
if (!sourceFile) {
|
|
11
|
+
throw new Error('Test data file not found')
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return sourceFile
|
|
15
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import Koa from 'koa'
|
|
2
|
+
import * as httpMocks from 'node-mocks-http'
|
|
3
|
+
|
|
4
|
+
import { keysOf } from './object'
|
|
5
|
+
import { ExtractedRequestParams } from './TypeUtils'
|
|
6
|
+
|
|
7
|
+
export interface MockContext<RequestBody = undefined> extends Koa.Context {
|
|
8
|
+
request: Koa.Context['request'] & {
|
|
9
|
+
body?: RequestBody
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const mockContext = <State = Koa.DefaultState, Context = MockContext>() => {
|
|
14
|
+
const app = new Koa<State, Context>()
|
|
15
|
+
const req = httpMocks.createRequest()
|
|
16
|
+
const res = httpMocks.createResponse()
|
|
17
|
+
const context = app.createContext(req, res) as Koa.ParameterizedContext<State, Context>
|
|
18
|
+
res.statusCode = 404
|
|
19
|
+
return context
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const mockContextPath = <Context extends Koa.ParameterizedContext, Path extends string>(
|
|
23
|
+
ctx: Context,
|
|
24
|
+
path: Path,
|
|
25
|
+
params: Record<string, string>
|
|
26
|
+
) => {
|
|
27
|
+
const typedContext = ctx as Context & { params: any } & ExtractedRequestParams<Path>
|
|
28
|
+
ctx.request.path = path
|
|
29
|
+
typedContext.params = params
|
|
30
|
+
return typedContext
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const mockContextQuery = <Context extends Koa.ParameterizedContext>(
|
|
34
|
+
ctx: Context,
|
|
35
|
+
params: Record<string, string>
|
|
36
|
+
) => {
|
|
37
|
+
ctx.query = params
|
|
38
|
+
return ctx
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export const mockContextCookies = <Context extends Koa.ParameterizedContext>(
|
|
42
|
+
ctx: Context,
|
|
43
|
+
params: Record<string, string | { value: string; expires?: Date }>
|
|
44
|
+
) => {
|
|
45
|
+
const cookies = keysOf(params).map((name) => {
|
|
46
|
+
const cookieData = params[name]
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
name,
|
|
50
|
+
value: typeof cookieData === 'string' ? cookieData : cookieData.value,
|
|
51
|
+
expires: typeof cookieData === 'string' ? undefined : cookieData.expires,
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
ctx.cookies = {
|
|
55
|
+
...ctx.cookies,
|
|
56
|
+
get: (name: string) => {
|
|
57
|
+
return cookies.find((cookie) => cookie.name === name)?.value || undefined
|
|
58
|
+
},
|
|
59
|
+
}
|
|
60
|
+
return ctx
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export const mockContextHeaders = <Context extends Koa.ParameterizedContext>(
|
|
64
|
+
ctx: Context,
|
|
65
|
+
params: Record<string, string>
|
|
66
|
+
) => {
|
|
67
|
+
ctx.request.headers = params
|
|
68
|
+
return ctx
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export const mockContextBody = <Context extends Koa.ParameterizedContext>(
|
|
72
|
+
ctx: Context,
|
|
73
|
+
params: Record<string, string | number | boolean | object | null>
|
|
74
|
+
) => {
|
|
75
|
+
ctx.request.body = params
|
|
76
|
+
ctx.request.rawBody = JSON.stringify(params)
|
|
77
|
+
return ctx
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export const mockContextRawBody = <Context extends Koa.ParameterizedContext>(
|
|
81
|
+
ctx: Context,
|
|
82
|
+
params: string
|
|
83
|
+
) => {
|
|
84
|
+
ctx.request.rawBody = params
|
|
85
|
+
return ctx
|
|
86
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { camelToKebabCase, camelToSnakeCase, snakeToCamelCase, uncapitalize } from './object'
|
|
2
|
+
|
|
3
|
+
describe('object utilities', () => {
|
|
4
|
+
describe('uncapitalize', () => {
|
|
5
|
+
it('uncapitalizes string correctly', () => {
|
|
6
|
+
expect(uncapitalize('CapitalizedString')).toEqual('capitalizedString')
|
|
7
|
+
})
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
describe('snakeToCamelCase', () => {
|
|
11
|
+
it('transforms snake_case string correctly', () => {
|
|
12
|
+
expect(snakeToCamelCase('snake_case_string')).toEqual('snakeCaseString')
|
|
13
|
+
})
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
describe('camelToSnakeCase', () => {
|
|
17
|
+
it('transforms camelCase string correctly', () => {
|
|
18
|
+
expect(camelToSnakeCase('camelCaseString')).toEqual('camel_case_string')
|
|
19
|
+
})
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
describe('camelToKebabCase', () => {
|
|
23
|
+
it('transforms camelCase string correctly', () => {
|
|
24
|
+
expect(camelToKebabCase('camelCaseString')).toEqual('camel-case-string')
|
|
25
|
+
})
|
|
26
|
+
})
|
|
27
|
+
})
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export const keysOf = <T extends string | number | symbol>(object: Record<T, unknown>) => {
|
|
2
|
+
return Object.keys(object) as (keyof typeof object)[]
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export const uncapitalize = (value: string) => `${value.substring(0, 1).toLowerCase()}${value.substring(1)}`
|
|
6
|
+
|
|
7
|
+
export const snakeToCamelCase = (value: string) => {
|
|
8
|
+
return value.replace(/(?!^)_(.)/g, (_, char) => char.toUpperCase())
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const kebabToCamelCase = (value: string) => {
|
|
12
|
+
return value.replace(/(?!^)-(.)/g, (_, char) => char.toUpperCase())
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const camelToSnakeCase = (value: string) => value.replace(/[A-Z]/g, (char) => `_${char.toLowerCase()}`)
|
|
16
|
+
|
|
17
|
+
export const camelToKebabCase = (value: string) => value.replace(/[A-Z]/g, (char) => `-${char.toLowerCase()}`)
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { Project } from 'ts-morph'
|
|
2
|
+
import * as util from 'util'
|
|
3
|
+
import { vi } from 'vitest'
|
|
4
|
+
|
|
5
|
+
import { debugNode, debugNodeChildren, debugNodes, debugObject } from './printers'
|
|
6
|
+
|
|
7
|
+
describe('printer utilities', () => {
|
|
8
|
+
const consoleMock = vi.fn()
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
consoleMock.mockClear()
|
|
12
|
+
console.debug = consoleMock
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
describe('debugNode', () => {
|
|
16
|
+
it('handles undefined node', () => {
|
|
17
|
+
debugNode(undefined)
|
|
18
|
+
expect(consoleMock).toHaveBeenCalledWith('Node is undefined')
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
it('handles simple node', () => {
|
|
22
|
+
const project = new Project({
|
|
23
|
+
useInMemoryFileSystem: true,
|
|
24
|
+
})
|
|
25
|
+
const sourceFile = project.createSourceFile(
|
|
26
|
+
'/test-file',
|
|
27
|
+
`
|
|
28
|
+
type Foo = string
|
|
29
|
+
`
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
debugNode(sourceFile.getFirstChild())
|
|
33
|
+
expect(consoleMock).toHaveBeenCalledWith([{ kind: 'TypeAliasDeclaration', text: 'type Foo = string' }])
|
|
34
|
+
})
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
describe('debugNodes', () => {
|
|
38
|
+
it('handles undefined node', () => {
|
|
39
|
+
debugNodes(undefined)
|
|
40
|
+
expect(consoleMock).toHaveBeenCalledWith('Nodes are undefined')
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
it('handles simple node', () => {
|
|
44
|
+
const project = new Project({
|
|
45
|
+
useInMemoryFileSystem: true,
|
|
46
|
+
})
|
|
47
|
+
const sourceFile = project.createSourceFile(
|
|
48
|
+
'/test-file',
|
|
49
|
+
`
|
|
50
|
+
type Foo = string
|
|
51
|
+
`
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
debugNodes(sourceFile.getChildren())
|
|
55
|
+
expect(consoleMock).toHaveBeenCalledWith([{ kind: 'TypeAliasDeclaration', text: 'type Foo = string' }])
|
|
56
|
+
})
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
describe('debugNodeChildren', () => {
|
|
60
|
+
it('handles undefined node', () => {
|
|
61
|
+
debugNodeChildren(undefined)
|
|
62
|
+
expect(consoleMock).toHaveBeenCalledWith('Node is undefined')
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it('handles simple node', () => {
|
|
66
|
+
const project = new Project({
|
|
67
|
+
useInMemoryFileSystem: true,
|
|
68
|
+
})
|
|
69
|
+
const sourceFile = project.createSourceFile(
|
|
70
|
+
'/test-file',
|
|
71
|
+
`
|
|
72
|
+
type Foo = string
|
|
73
|
+
`
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
debugNodeChildren(sourceFile.getFirstChild())
|
|
77
|
+
expect(consoleMock).toHaveBeenCalledWith([{ kind: 'TypeAliasDeclaration', text: 'type Foo = string' }])
|
|
78
|
+
})
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
describe('debugObject', () => {
|
|
82
|
+
it('prints non-object correctly', () => {
|
|
83
|
+
debugObject('test')
|
|
84
|
+
expect(consoleMock).toHaveBeenCalledWith('test')
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
it('prints object correctly', () => {
|
|
88
|
+
debugObject({
|
|
89
|
+
q1: 'qqq',
|
|
90
|
+
q2: 'www',
|
|
91
|
+
})
|
|
92
|
+
expect(consoleMock).toHaveBeenCalledWith(
|
|
93
|
+
util.inspect(
|
|
94
|
+
{
|
|
95
|
+
q1: 'qqq',
|
|
96
|
+
q2: 'www',
|
|
97
|
+
},
|
|
98
|
+
{ showHidden: false, depth: null, colors: true }
|
|
99
|
+
)
|
|
100
|
+
)
|
|
101
|
+
})
|
|
102
|
+
})
|
|
103
|
+
})
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Node } from 'ts-morph'
|
|
2
|
+
import * as util from 'util'
|
|
3
|
+
|
|
4
|
+
export const debugNode = (node: Node | undefined) => {
|
|
5
|
+
console.debug('Node:')
|
|
6
|
+
if (!node) {
|
|
7
|
+
console.debug('Node is undefined')
|
|
8
|
+
return
|
|
9
|
+
}
|
|
10
|
+
console.debug({
|
|
11
|
+
kind: node.getKindName(),
|
|
12
|
+
text: node.getText(),
|
|
13
|
+
})
|
|
14
|
+
debugNodeChildren(node)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const debugNodes = (nodes: Node | Node[] | undefined) => {
|
|
18
|
+
console.debug('Nodes:')
|
|
19
|
+
if (!nodes) {
|
|
20
|
+
console.debug('Nodes are undefined')
|
|
21
|
+
return
|
|
22
|
+
}
|
|
23
|
+
if (Array.isArray(nodes)) {
|
|
24
|
+
nodes.forEach((node) => debugNode(node))
|
|
25
|
+
} else {
|
|
26
|
+
debugNode(nodes)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export const debugNodeChildren = (node: Node | undefined) => {
|
|
31
|
+
console.debug('Children:')
|
|
32
|
+
if (!node) {
|
|
33
|
+
console.debug('Node is undefined')
|
|
34
|
+
return
|
|
35
|
+
}
|
|
36
|
+
const values = node.getChildren().map((child) => ({
|
|
37
|
+
kind: child.getKindName(),
|
|
38
|
+
text: child.getText(),
|
|
39
|
+
}))
|
|
40
|
+
console.debug(values)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export const debugObject = (object: Record<any, any> | any) => {
|
|
44
|
+
if (typeof object === 'object') {
|
|
45
|
+
console.debug(util.inspect(object, { showHidden: false, depth: null, colors: true }))
|
|
46
|
+
} else {
|
|
47
|
+
console.debug(object)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Validator } from '../validators/types'
|
|
2
|
+
|
|
3
|
+
export const getMissingParamMessage = (
|
|
4
|
+
result:
|
|
5
|
+
| {
|
|
6
|
+
name: string
|
|
7
|
+
validator: Pick<Validator<unknown>, 'description' | 'errorMessage'>
|
|
8
|
+
}
|
|
9
|
+
| {
|
|
10
|
+
originalName: string
|
|
11
|
+
validator: Pick<Validator<unknown>, 'description' | 'errorMessage'>
|
|
12
|
+
}
|
|
13
|
+
) => {
|
|
14
|
+
const name = 'name' in result ? result.name : result.originalName
|
|
15
|
+
const { description } = result.validator
|
|
16
|
+
|
|
17
|
+
if (description) {
|
|
18
|
+
return `'${name}' (${description})`
|
|
19
|
+
}
|
|
20
|
+
return `'${name}'`
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const getValidationResultMessage = (
|
|
24
|
+
result:
|
|
25
|
+
| {
|
|
26
|
+
name: string
|
|
27
|
+
validator: Pick<Validator<unknown>, 'description' | 'errorMessage'>
|
|
28
|
+
}
|
|
29
|
+
| {
|
|
30
|
+
originalName: string
|
|
31
|
+
validator: Pick<Validator<unknown>, 'description' | 'errorMessage'>
|
|
32
|
+
}
|
|
33
|
+
) => {
|
|
34
|
+
const name = 'name' in result ? result.name : result.originalName
|
|
35
|
+
const { description, errorMessage } = result.validator
|
|
36
|
+
|
|
37
|
+
if (errorMessage) {
|
|
38
|
+
return `'${name}' (${errorMessage})`
|
|
39
|
+
}
|
|
40
|
+
if (description) {
|
|
41
|
+
return `'${name}' (${description})`
|
|
42
|
+
}
|
|
43
|
+
return `'${name}'`
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const getMissingRawBodyMessage = (validator: Validator<unknown>) => {
|
|
47
|
+
const { description } = validator
|
|
48
|
+
|
|
49
|
+
if (description) {
|
|
50
|
+
return `Missing request body (${description}).`
|
|
51
|
+
}
|
|
52
|
+
return 'Missing request body.'
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export const getFailedRawBodyValidationMessage = (validator: Validator<unknown>) => {
|
|
56
|
+
const { description, errorMessage } = validator
|
|
57
|
+
|
|
58
|
+
if (errorMessage) {
|
|
59
|
+
return `Failed request body validation (${errorMessage}).`
|
|
60
|
+
}
|
|
61
|
+
if (description) {
|
|
62
|
+
return `Failed request body validation (${description}).`
|
|
63
|
+
}
|
|
64
|
+
return 'Failed request body validation.'
|
|
65
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { ValidationError } from '../errors/UserFacingErrors'
|
|
2
|
+
import { BuiltInValidatorParam } from './InternalParamWrappers'
|
|
3
|
+
|
|
4
|
+
export const EmailValidator = BuiltInValidatorParam({
|
|
5
|
+
parse: (v) => String(v),
|
|
6
|
+
validate: (v) => v.includes('@'),
|
|
7
|
+
description: "A string containing an '@' sign",
|
|
8
|
+
errorMessage: "Must include an '@' sign",
|
|
9
|
+
})
|
|
10
|
+
export const BooleanValidator = BuiltInValidatorParam({
|
|
11
|
+
prevalidate: (v) => v === '0' || v === '1' || v === 'false' || v === 'true',
|
|
12
|
+
parse: (v) => v === '1' || v === 'true',
|
|
13
|
+
description: 'Any boolean value',
|
|
14
|
+
errorMessage: "Must be '0', '1', 'false' or 'true'",
|
|
15
|
+
})
|
|
16
|
+
export const NullableBooleanValidator = BuiltInValidatorParam({
|
|
17
|
+
prevalidate: (v) => v === '0' || v === '1' || v === 'false' || v === 'true' || v === null,
|
|
18
|
+
parse: (v) => v === '1' || v === 'true' || v === null,
|
|
19
|
+
description: 'Any boolean value',
|
|
20
|
+
errorMessage: "Must be '0', '1', 'false' or 'true'",
|
|
21
|
+
})
|
|
22
|
+
export const StringValidator = BuiltInValidatorParam({
|
|
23
|
+
parse: (v) => String(v),
|
|
24
|
+
description: 'Any string value',
|
|
25
|
+
errorMessage: 'Must be a valid string',
|
|
26
|
+
})
|
|
27
|
+
export const NullableStringValidator = BuiltInValidatorParam({
|
|
28
|
+
parse: (v) => v,
|
|
29
|
+
description: 'Any string or null value',
|
|
30
|
+
errorMessage: 'Must be a valid string or null',
|
|
31
|
+
})
|
|
32
|
+
export const NonEmptyStringValidator = BuiltInValidatorParam({
|
|
33
|
+
parse: (v) => String(v),
|
|
34
|
+
validate: (v) => v.length > 0,
|
|
35
|
+
description: 'Any string value with at least one character',
|
|
36
|
+
errorMessage: 'Must be a string with at least one character',
|
|
37
|
+
})
|
|
38
|
+
export const NumberValidator = BuiltInValidatorParam({
|
|
39
|
+
parse: (v) => Number(v),
|
|
40
|
+
validate: (v) => Number.isFinite(v) && !Number.isNaN(v),
|
|
41
|
+
description: 'Any numeric value',
|
|
42
|
+
errorMessage: 'Must be a valid number',
|
|
43
|
+
})
|
|
44
|
+
export const NullableNumberValidator = BuiltInValidatorParam({
|
|
45
|
+
parse: (v) => (v === null ? null : Number(v)),
|
|
46
|
+
validate: (v) => v === null || (Number.isFinite(v) && !Number.isNaN(v)),
|
|
47
|
+
description: 'Any numeric value',
|
|
48
|
+
errorMessage: 'Must be a valid number',
|
|
49
|
+
})
|
|
50
|
+
export const BigIntValidator = BuiltInValidatorParam({
|
|
51
|
+
parse: (v) => {
|
|
52
|
+
if (v === null) {
|
|
53
|
+
throw new ValidationError('Encountered an unexpected null value')
|
|
54
|
+
}
|
|
55
|
+
return BigInt(v)
|
|
56
|
+
},
|
|
57
|
+
description: 'Any numeric value',
|
|
58
|
+
errorMessage: 'Must be a valid number',
|
|
59
|
+
})
|
|
60
|
+
export const NullableBigIntValidator = BuiltInValidatorParam({
|
|
61
|
+
parse: (v) => (v === null ? null : BigInt(v)),
|
|
62
|
+
description: 'Any numeric value',
|
|
63
|
+
errorMessage: 'Must be a valid number',
|
|
64
|
+
})
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { BuiltInValidator } from './types'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* More complex type to preserve description and errorMessage in .d.ts file.
|
|
5
|
+
* Functionally identical to RequiredParam.
|
|
6
|
+
* For internal use only.
|
|
7
|
+
*/
|
|
8
|
+
export const BuiltInValidatorParam = <T, DescriptionT extends string, ErrorMessageT extends string>(
|
|
9
|
+
validator: Omit<BuiltInValidator<T, DescriptionT, ErrorMessageT>, 'optional'> &
|
|
10
|
+
Pick<BuiltInValidator<T, DescriptionT, ErrorMessageT>, 'description' | 'errorMessage'>
|
|
11
|
+
): BuiltInValidator<T, DescriptionT, ErrorMessageT> & { optional: false } => ({
|
|
12
|
+
...validator,
|
|
13
|
+
optional: false,
|
|
14
|
+
})
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Validator } from './types'
|
|
2
|
+
|
|
3
|
+
export const PathParam = <T>(
|
|
4
|
+
validator: Omit<Validator<T>, 'optional'>
|
|
5
|
+
): Validator<T> & { optional: false } => ({
|
|
6
|
+
...validator,
|
|
7
|
+
optional: false,
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
export const RequiredParam = <T>(
|
|
11
|
+
validator: Omit<Validator<T>, 'optional'>
|
|
12
|
+
): Validator<T> & { optional: false } => ({
|
|
13
|
+
...validator,
|
|
14
|
+
optional: false,
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
export const OptionalParam = <T>(
|
|
18
|
+
validator: Omit<Validator<T>, 'optional'>
|
|
19
|
+
): Validator<T> & { optional: true } => ({
|
|
20
|
+
...validator,
|
|
21
|
+
optional: true,
|
|
22
|
+
})
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
type DeepPartial<T> = {
|
|
2
|
+
[P in keyof T]?: T[P] extends Array<infer U>
|
|
3
|
+
? Array<DeepPartial<U>>
|
|
4
|
+
: T[P] extends ReadonlyArray<infer U>
|
|
5
|
+
? ReadonlyArray<DeepPartial<U>>
|
|
6
|
+
: DeepPartial<T[P]>
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type ValidateArg<T> = T extends object ? DeepPartial<T> : T
|
|
10
|
+
|
|
11
|
+
export type Validator<T> = {
|
|
12
|
+
prevalidate?: (v: string | null) => boolean
|
|
13
|
+
parse: (v: string | null) => T
|
|
14
|
+
validate?: (v: ValidateArg<T>) => boolean
|
|
15
|
+
/**
|
|
16
|
+
* The field is optional and validation will be skipped if it is not provided.
|
|
17
|
+
* Optional parameters will always be nullable.
|
|
18
|
+
* For `usePathParams` this field is ignored.
|
|
19
|
+
*/
|
|
20
|
+
optional: boolean
|
|
21
|
+
/**
|
|
22
|
+
* OpenAPI description field.
|
|
23
|
+
* If 'errorMessage' is not provided, will be used to inform user in the event of failed validation.
|
|
24
|
+
*/
|
|
25
|
+
description?: string
|
|
26
|
+
/**
|
|
27
|
+
* Error message sent to user when validation fails.
|
|
28
|
+
*/
|
|
29
|
+
errorMessage?: string
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export type BuiltInValidator<T, DescriptionT extends string, ErrorMessageT extends string> = Validator<T> & {
|
|
33
|
+
description: DescriptionT
|
|
34
|
+
errorMessage: ErrorMessageT
|
|
35
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"module": "commonjs",
|
|
4
|
+
"declaration": true,
|
|
5
|
+
"declarationMap": true,
|
|
6
|
+
"removeComments": true,
|
|
7
|
+
"strict": true,
|
|
8
|
+
"emitDecoratorMetadata": true,
|
|
9
|
+
"experimentalDecorators": true,
|
|
10
|
+
"allowSyntheticDefaultImports": true,
|
|
11
|
+
"target": "es2017",
|
|
12
|
+
"esModuleInterop": true,
|
|
13
|
+
"sourceMap": true,
|
|
14
|
+
"outDir": "./dist",
|
|
15
|
+
"incremental": true,
|
|
16
|
+
"skipLibCheck": true,
|
|
17
|
+
"strictNullChecks": true,
|
|
18
|
+
"noImplicitAny": true,
|
|
19
|
+
"strictBindCallApply": true,
|
|
20
|
+
"forceConsistentCasingInFileNames": true,
|
|
21
|
+
"noFallthroughCasesInSwitch": true
|
|
22
|
+
},
|
|
23
|
+
"include": [
|
|
24
|
+
"cli/**/*",
|
|
25
|
+
"src/**/*",
|
|
26
|
+
".eslintrc.js",
|
|
27
|
+
"vite.config.ts",
|
|
28
|
+
]
|
|
29
|
+
}
|
package/vite.config.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { resolve } from 'path'
|
|
2
|
+
import { defineConfig, UserConfig } from 'vitest/config'
|
|
3
|
+
|
|
4
|
+
export const baseViteConfig: UserConfig = {
|
|
5
|
+
test: {
|
|
6
|
+
globals: true,
|
|
7
|
+
setupFiles: 'src/setupTests.ts',
|
|
8
|
+
},
|
|
9
|
+
resolve: {
|
|
10
|
+
alias: {
|
|
11
|
+
'@src': resolve(__dirname, './src'),
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export default defineConfig(baseViteConfig)
|