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.
Files changed (268) hide show
  1. package/.eslintrc.js +26 -0
  2. package/.prettierrc.js +7 -0
  3. package/README.md +383 -0
  4. package/cli/cli.ts +59 -0
  5. package/cli/entry.cjs +3 -0
  6. package/cli/prettyprint.ts +16 -0
  7. package/dist/cli/cli.d.ts +2 -0
  8. package/dist/cli/cli.d.ts.map +1 -0
  9. package/dist/cli/cli.js +79 -0
  10. package/dist/cli/prettyprint.d.ts +4 -0
  11. package/dist/cli/prettyprint.d.ts.map +1 -0
  12. package/dist/cli/prettyprint.js +18 -0
  13. package/dist/src/errors/BaseHttpError.d.ts +13 -0
  14. package/dist/src/errors/BaseHttpError.d.ts.map +1 -0
  15. package/dist/src/errors/BaseHttpError.js +13 -0
  16. package/dist/src/errors/HttpErrorHandler.d.ts +3 -0
  17. package/dist/src/errors/HttpErrorHandler.d.ts.map +1 -0
  18. package/dist/src/errors/HttpErrorHandler.js +23 -0
  19. package/dist/src/errors/UserFacingErrors.d.ts +11 -0
  20. package/dist/src/errors/UserFacingErrors.d.ts.map +1 -0
  21. package/dist/src/errors/UserFacingErrors.js +23 -0
  22. package/dist/src/hooks/authentication/useAuth.d.ts +3 -0
  23. package/dist/src/hooks/authentication/useAuth.d.ts.map +1 -0
  24. package/dist/src/hooks/authentication/useAuth.js +7 -0
  25. package/dist/src/hooks/authentication/useOptionalAuth.d.ts +3 -0
  26. package/dist/src/hooks/authentication/useOptionalAuth.d.ts.map +1 -0
  27. package/dist/src/hooks/authentication/useOptionalAuth.js +16 -0
  28. package/dist/src/hooks/useApiEndpoint.d.ts +8 -0
  29. package/dist/src/hooks/useApiEndpoint.d.ts.map +1 -0
  30. package/dist/src/hooks/useApiEndpoint.js +7 -0
  31. package/dist/src/hooks/useApiHeader/index.d.ts +2 -0
  32. package/dist/src/hooks/useApiHeader/index.d.ts.map +1 -0
  33. package/dist/src/hooks/useApiHeader/index.js +17 -0
  34. package/dist/src/hooks/useApiHeader/useApiHeader.d.ts +3 -0
  35. package/dist/src/hooks/useApiHeader/useApiHeader.d.ts.map +1 -0
  36. package/dist/src/hooks/useApiHeader/useApiHeader.js +6 -0
  37. package/dist/src/hooks/useApiHeader/useApiHeader.spec.data.d.ts +2 -0
  38. package/dist/src/hooks/useApiHeader/useApiHeader.spec.data.d.ts.map +1 -0
  39. package/dist/src/hooks/useApiHeader/useApiHeader.spec.data.js +22 -0
  40. package/dist/src/hooks/useCookieParams.d.ts +9 -0
  41. package/dist/src/hooks/useCookieParams.d.ts.map +1 -0
  42. package/dist/src/hooks/useCookieParams.js +50 -0
  43. package/dist/src/hooks/useExposeApiModel/index.d.ts +2 -0
  44. package/dist/src/hooks/useExposeApiModel/index.d.ts.map +1 -0
  45. package/dist/src/hooks/useExposeApiModel/index.js +17 -0
  46. package/dist/src/hooks/useExposeApiModel/useExposeApiModel.d.ts +3 -0
  47. package/dist/src/hooks/useExposeApiModel/useExposeApiModel.d.ts.map +1 -0
  48. package/dist/src/hooks/useExposeApiModel/useExposeApiModel.js +9 -0
  49. package/dist/src/hooks/useExposeApiModel/useExposeApiModel.spec.data.d.ts +2 -0
  50. package/dist/src/hooks/useExposeApiModel/useExposeApiModel.spec.data.d.ts.map +1 -0
  51. package/dist/src/hooks/useExposeApiModel/useExposeApiModel.spec.data.js +16 -0
  52. package/dist/src/hooks/useHeaderParams.d.ts +12 -0
  53. package/dist/src/hooks/useHeaderParams.d.ts.map +1 -0
  54. package/dist/src/hooks/useHeaderParams.js +52 -0
  55. package/dist/src/hooks/usePathParams.d.ts +22 -0
  56. package/dist/src/hooks/usePathParams.d.ts.map +1 -0
  57. package/dist/src/hooks/usePathParams.js +46 -0
  58. package/dist/src/hooks/useQueryParams.d.ts +9 -0
  59. package/dist/src/hooks/useQueryParams.d.ts.map +1 -0
  60. package/dist/src/hooks/useQueryParams.js +50 -0
  61. package/dist/src/hooks/useRequestBody.d.ts +9 -0
  62. package/dist/src/hooks/useRequestBody.d.ts.map +1 -0
  63. package/dist/src/hooks/useRequestBody.js +59 -0
  64. package/dist/src/hooks/useRequestRawBody.d.ts +7 -0
  65. package/dist/src/hooks/useRequestRawBody.d.ts.map +1 -0
  66. package/dist/src/hooks/useRequestRawBody.js +34 -0
  67. package/dist/src/index.d.ts +18 -0
  68. package/dist/src/index.d.ts.map +1 -0
  69. package/dist/src/index.js +33 -0
  70. package/dist/src/openapi/analyzerModule/analyzerModule.d.ts +18 -0
  71. package/dist/src/openapi/analyzerModule/analyzerModule.d.ts.map +1 -0
  72. package/dist/src/openapi/analyzerModule/analyzerModule.js +192 -0
  73. package/dist/src/openapi/analyzerModule/nodeParsers.d.ts +19 -0
  74. package/dist/src/openapi/analyzerModule/nodeParsers.d.ts.map +1 -0
  75. package/dist/src/openapi/analyzerModule/nodeParsers.js +521 -0
  76. package/dist/src/openapi/analyzerModule/parseEndpoint.d.ts +4 -0
  77. package/dist/src/openapi/analyzerModule/parseEndpoint.d.ts.map +1 -0
  78. package/dist/src/openapi/analyzerModule/parseEndpoint.js +246 -0
  79. package/dist/src/openapi/analyzerModule/parseExposedModels.d.ts +5 -0
  80. package/dist/src/openapi/analyzerModule/parseExposedModels.d.ts.map +1 -0
  81. package/dist/src/openapi/analyzerModule/parseExposedModels.js +32 -0
  82. package/dist/src/openapi/analyzerModule/test/openApiAnalyzer.spec.data.d.ts +2 -0
  83. package/dist/src/openapi/analyzerModule/test/openApiAnalyzer.spec.data.d.ts.map +1 -0
  84. package/dist/src/openapi/analyzerModule/test/openApiAnalyzer.spec.data.js +400 -0
  85. package/dist/src/openapi/analyzerModule/types.d.ts +53 -0
  86. package/dist/src/openapi/analyzerModule/types.d.ts.map +1 -0
  87. package/dist/src/openapi/analyzerModule/types.js +2 -0
  88. package/dist/src/openapi/discoveryModule/discoverImports/discoverImports.d.ts +8 -0
  89. package/dist/src/openapi/discoveryModule/discoverImports/discoverImports.d.ts.map +1 -0
  90. package/dist/src/openapi/discoveryModule/discoverImports/discoverImports.js +33 -0
  91. package/dist/src/openapi/discoveryModule/discoverRouterFiles/data/testRouterA.spec.data.d.ts +4 -0
  92. package/dist/src/openapi/discoveryModule/discoverRouterFiles/data/testRouterA.spec.data.d.ts.map +1 -0
  93. package/dist/src/openapi/discoveryModule/discoverRouterFiles/data/testRouterA.spec.data.js +8 -0
  94. package/dist/src/openapi/discoveryModule/discoverRouterFiles/data/testRouterB.spec.data.d.ts +4 -0
  95. package/dist/src/openapi/discoveryModule/discoverRouterFiles/data/testRouterB.spec.data.d.ts.map +1 -0
  96. package/dist/src/openapi/discoveryModule/discoverRouterFiles/data/testRouterB.spec.data.js +8 -0
  97. package/dist/src/openapi/discoveryModule/discoverRouterFiles/discoverRouterFiles.d.ts +17 -0
  98. package/dist/src/openapi/discoveryModule/discoverRouterFiles/discoverRouterFiles.d.ts.map +1 -0
  99. package/dist/src/openapi/discoveryModule/discoverRouterFiles/discoverRouterFiles.js +80 -0
  100. package/dist/src/openapi/discoveryModule/discoverRouters/discoverRouters.d.ts +6 -0
  101. package/dist/src/openapi/discoveryModule/discoverRouters/discoverRouters.d.ts.map +1 -0
  102. package/dist/src/openapi/discoveryModule/discoverRouters/discoverRouters.js +31 -0
  103. package/dist/src/openapi/discoveryModule/discoverRouters/discoverRouters.spec.data.d.ts +5 -0
  104. package/dist/src/openapi/discoveryModule/discoverRouters/discoverRouters.spec.data.d.ts.map +1 -0
  105. package/dist/src/openapi/discoveryModule/discoverRouters/discoverRouters.spec.data.js +38 -0
  106. package/dist/src/openapi/discoveryModule/index.d.ts +3 -0
  107. package/dist/src/openapi/discoveryModule/index.d.ts.map +1 -0
  108. package/dist/src/openapi/discoveryModule/index.js +18 -0
  109. package/dist/src/openapi/generatorModule/generateComponentSchemas.d.ts +4 -0
  110. package/dist/src/openapi/generatorModule/generateComponentSchemas.d.ts.map +1 -0
  111. package/dist/src/openapi/generatorModule/generateComponentSchemas.js +12 -0
  112. package/dist/src/openapi/generatorModule/generatePaths.d.ts +10 -0
  113. package/dist/src/openapi/generatorModule/generatePaths.d.ts.map +1 -0
  114. package/dist/src/openapi/generatorModule/generatePaths.js +116 -0
  115. package/dist/src/openapi/generatorModule/generatorModule.d.ts +16 -0
  116. package/dist/src/openapi/generatorModule/generatorModule.d.ts.map +1 -0
  117. package/dist/src/openapi/generatorModule/generatorModule.js +18 -0
  118. package/dist/src/openapi/generatorModule/getSchema.d.ts +36 -0
  119. package/dist/src/openapi/generatorModule/getSchema.d.ts.map +1 -0
  120. package/dist/src/openapi/generatorModule/getSchema.js +133 -0
  121. package/dist/src/openapi/generatorModule/index.d.ts +5 -0
  122. package/dist/src/openapi/generatorModule/index.d.ts.map +1 -0
  123. package/dist/src/openapi/generatorModule/index.js +20 -0
  124. package/dist/src/openapi/generatorModule/test/openApiGenerator.spec.data.d.ts +515 -0
  125. package/dist/src/openapi/generatorModule/test/openApiGenerator.spec.data.d.ts.map +1 -0
  126. package/dist/src/openapi/generatorModule/test/openApiGenerator.spec.data.js +1119 -0
  127. package/dist/src/openapi/initOpenApiEngine.d.ts +4 -0
  128. package/dist/src/openapi/initOpenApiEngine.d.ts.map +1 -0
  129. package/dist/src/openapi/initOpenApiEngine.js +14 -0
  130. package/dist/src/openapi/manager/OpenApiManager.d.ts +67 -0
  131. package/dist/src/openapi/manager/OpenApiManager.d.ts.map +1 -0
  132. package/dist/src/openapi/manager/OpenApiManager.js +86 -0
  133. package/dist/src/openapi/router/OpenApiRouter.d.ts +4 -0
  134. package/dist/src/openapi/router/OpenApiRouter.d.ts.map +1 -0
  135. package/dist/src/openapi/router/OpenApiRouter.js +11 -0
  136. package/dist/src/openapi/types.d.ts +81 -0
  137. package/dist/src/openapi/types.d.ts.map +1 -0
  138. package/dist/src/openapi/types.js +2 -0
  139. package/dist/src/router/Router.d.ts +23 -0
  140. package/dist/src/router/Router.d.ts.map +1 -0
  141. package/dist/src/router/Router.js +81 -0
  142. package/dist/src/router/responseValueToJson.d.ts +2 -0
  143. package/dist/src/router/responseValueToJson.d.ts.map +1 -0
  144. package/dist/src/router/responseValueToJson.js +10 -0
  145. package/dist/src/setupTests.d.ts +1 -0
  146. package/dist/src/setupTests.d.ts.map +1 -0
  147. package/dist/src/setupTests.js +3 -0
  148. package/dist/src/test/TestAppRouter.d.ts +8 -0
  149. package/dist/src/test/TestAppRouter.d.ts.map +1 -0
  150. package/dist/src/test/TestAppRouter.js +58 -0
  151. package/dist/src/test/app.d.ts +3 -0
  152. package/dist/src/test/app.d.ts.map +1 -0
  153. package/dist/src/test/app.js +41 -0
  154. package/dist/src/utils/TypeUtils.d.ts +22 -0
  155. package/dist/src/utils/TypeUtils.d.ts.map +1 -0
  156. package/dist/src/utils/TypeUtils.js +2 -0
  157. package/dist/src/utils/fromZodSchema.d.ts +2 -0
  158. package/dist/src/utils/fromZodSchema.d.ts.map +1 -0
  159. package/dist/src/utils/fromZodSchema.js +6 -0
  160. package/dist/src/utils/loadTestData.d.ts +2 -0
  161. package/dist/src/utils/loadTestData.d.ts.map +1 -0
  162. package/dist/src/utils/loadTestData.js +39 -0
  163. package/dist/src/utils/mockContext.d.ts +20 -0
  164. package/dist/src/utils/mockContext.d.ts.map +1 -0
  165. package/dist/src/utils/mockContext.js +85 -0
  166. package/dist/src/utils/nameOf.d.ts +5 -0
  167. package/dist/src/utils/nameOf.d.ts.map +1 -0
  168. package/dist/src/utils/nameOf.js +7 -0
  169. package/dist/src/utils/object.d.ts +7 -0
  170. package/dist/src/utils/object.d.ts.map +1 -0
  171. package/dist/src/utils/object.js +21 -0
  172. package/dist/src/utils/printers.d.ts +6 -0
  173. package/dist/src/utils/printers.d.ts.map +1 -0
  174. package/dist/src/utils/printers.js +76 -0
  175. package/dist/src/utils/validationMessages.d.ts +18 -0
  176. package/dist/src/utils/validationMessages.d.ts.map +1 -0
  177. package/dist/src/utils/validationMessages.js +43 -0
  178. package/dist/src/validators/BuiltInValidators.d.ts +61 -0
  179. package/dist/src/validators/BuiltInValidators.d.ts.map +1 -0
  180. package/dist/src/validators/BuiltInValidators.js +66 -0
  181. package/dist/src/validators/InternalParamWrappers.d.ts +5 -0
  182. package/dist/src/validators/InternalParamWrappers.d.ts.map +1 -0
  183. package/dist/src/validators/InternalParamWrappers.js +5 -0
  184. package/dist/src/validators/ParamWrappers.d.ts +11 -0
  185. package/dist/src/validators/ParamWrappers.d.ts.map +1 -0
  186. package/dist/src/validators/ParamWrappers.js +9 -0
  187. package/dist/src/validators/types.d.ts +18 -0
  188. package/dist/src/validators/types.d.ts.map +1 -0
  189. package/dist/src/validators/types.js +2 -0
  190. package/dist/tsconfig.build.tsbuildinfo +1 -0
  191. package/package.json +59 -0
  192. package/src/errors/BaseHttpError.ts +16 -0
  193. package/src/errors/HttpErrorHandler.ts +20 -0
  194. package/src/errors/UserFacingErrors.ts +39 -0
  195. package/src/hooks/authentication/useAuth.ts +8 -0
  196. package/src/hooks/authentication/useOptionalAuth.ts +17 -0
  197. package/src/hooks/useApiEndpoint.spec.ts +11 -0
  198. package/src/hooks/useApiEndpoint.ts +10 -0
  199. package/src/hooks/useApiHeader/index.ts +1 -0
  200. package/src/hooks/useApiHeader/useApiHeader.spec.data.ts +22 -0
  201. package/src/hooks/useApiHeader/useApiHeader.spec.ts +34 -0
  202. package/src/hooks/useApiHeader/useApiHeader.ts +6 -0
  203. package/src/hooks/useCookieParams.spec.ts +174 -0
  204. package/src/hooks/useCookieParams.ts +73 -0
  205. package/src/hooks/useExposeApiModel/index.ts +1 -0
  206. package/src/hooks/useExposeApiModel/useExposeApiModel.spec.data.ts +48 -0
  207. package/src/hooks/useExposeApiModel/useExposeApiModel.spec.ts +388 -0
  208. package/src/hooks/useExposeApiModel/useExposeApiModel.ts +9 -0
  209. package/src/hooks/useHeaderParams.spec.ts +186 -0
  210. package/src/hooks/useHeaderParams.ts +83 -0
  211. package/src/hooks/usePathParams.spec.ts +161 -0
  212. package/src/hooks/usePathParams.ts +89 -0
  213. package/src/hooks/useQueryParams.spec.ts +224 -0
  214. package/src/hooks/useQueryParams.ts +73 -0
  215. package/src/hooks/useRequestBody.spec.ts +215 -0
  216. package/src/hooks/useRequestBody.ts +94 -0
  217. package/src/hooks/useRequestRawBody.spec.ts +154 -0
  218. package/src/hooks/useRequestRawBody.ts +56 -0
  219. package/src/index.ts +17 -0
  220. package/src/openapi/analyzerModule/analyzerModule.ts +228 -0
  221. package/src/openapi/analyzerModule/nodeParsers.ts +648 -0
  222. package/src/openapi/analyzerModule/parseEndpoint.ts +305 -0
  223. package/src/openapi/analyzerModule/parseExposedModels.ts +34 -0
  224. package/src/openapi/analyzerModule/test/openApiAnalyzer.spec.data.ts +521 -0
  225. package/src/openapi/analyzerModule/test/openApiAnalyzer.spec.ts +1043 -0
  226. package/src/openapi/analyzerModule/types.ts +72 -0
  227. package/src/openapi/discoveryModule/discoverImports/discoverImports.ts +43 -0
  228. package/src/openapi/discoveryModule/discoverRouterFiles/data/testRouterA.spec.data.ts +7 -0
  229. package/src/openapi/discoveryModule/discoverRouterFiles/data/testRouterB.spec.data.ts +7 -0
  230. package/src/openapi/discoveryModule/discoverRouterFiles/discoverRouterFiles.spec.ts +36 -0
  231. package/src/openapi/discoveryModule/discoverRouterFiles/discoverRouterFiles.ts +80 -0
  232. package/src/openapi/discoveryModule/discoverRouters/discoverRouters.spec.data.ts +42 -0
  233. package/src/openapi/discoveryModule/discoverRouters/discoverRouters.spec.ts +18 -0
  234. package/src/openapi/discoveryModule/discoverRouters/discoverRouters.ts +39 -0
  235. package/src/openapi/discoveryModule/index.ts +2 -0
  236. package/src/openapi/generatorModule/generateComponentSchemas.ts +12 -0
  237. package/src/openapi/generatorModule/generatePaths.ts +138 -0
  238. package/src/openapi/generatorModule/generatorModule.ts +17 -0
  239. package/src/openapi/generatorModule/getSchema.ts +169 -0
  240. package/src/openapi/generatorModule/index.ts +4 -0
  241. package/src/openapi/generatorModule/test/openApiGenerator.spec.data.ts +1119 -0
  242. package/src/openapi/generatorModule/test/openApiGenerator.spec.ts +783 -0
  243. package/src/openapi/initOpenApiEngine.ts +20 -0
  244. package/src/openapi/manager/OpenApiManager.ts +153 -0
  245. package/src/openapi/router/OpenApiRouter.ts +11 -0
  246. package/src/openapi/types.ts +86 -0
  247. package/src/router/Router.ts +123 -0
  248. package/src/router/responseValueToJson.ts +6 -0
  249. package/src/setupTests.ts +3 -0
  250. package/src/test/TestAppRouter.ts +76 -0
  251. package/src/test/app.spec.ts +130 -0
  252. package/src/test/app.ts +43 -0
  253. package/src/utils/TypeUtils.ts +51 -0
  254. package/src/utils/loadTestData.ts +15 -0
  255. package/src/utils/mockContext.ts +86 -0
  256. package/src/utils/nameOf.ts +7 -0
  257. package/src/utils/object.spec.ts +27 -0
  258. package/src/utils/object.ts +17 -0
  259. package/src/utils/printers.spec.ts +103 -0
  260. package/src/utils/printers.ts +49 -0
  261. package/src/utils/validationMessages.ts +65 -0
  262. package/src/validators/BuiltInValidators.ts +64 -0
  263. package/src/validators/InternalParamWrappers.ts +14 -0
  264. package/src/validators/ParamWrappers.ts +22 -0
  265. package/src/validators/types.ts +35 -0
  266. package/tsconfig.build.json +15 -0
  267. package/tsconfig.json +29 -0
  268. 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,7 @@
1
+ export interface ClassConstructor {
2
+ new (): unknown
3
+ }
4
+
5
+ export const nameOf = <T extends ClassConstructor | (() => unknown)>(a: T) => {
6
+ return a.name
7
+ }
@@ -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
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "sourceMap": false,
5
+ "declaration": true,
6
+ },
7
+ "exclude": [
8
+ "node_modules",
9
+ "test",
10
+ "dist",
11
+ "**/*spec.ts",
12
+ ".eslintrc.js",
13
+ "vite.config.ts"
14
+ ]
15
+ }
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)