prisma-generator-express 1.28.0 → 1.30.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 (49) hide show
  1. package/README.md +244 -14
  2. package/dist/constants.d.ts +1 -0
  3. package/dist/generators/generateFastifyHandler.d.ts +4 -0
  4. package/dist/generators/generateFastifyHandler.js +78 -0
  5. package/dist/generators/generateFastifyHandler.js.map +1 -0
  6. package/dist/generators/generateOperationCore.d.ts +6 -0
  7. package/dist/generators/generateOperationCore.js +534 -0
  8. package/dist/generators/generateOperationCore.js.map +1 -0
  9. package/dist/generators/generateQueryBuilderHelper.js +85 -69
  10. package/dist/generators/generateQueryBuilderHelper.js.map +1 -1
  11. package/dist/generators/generateRouter.js +1 -25
  12. package/dist/generators/generateRouter.js.map +1 -1
  13. package/dist/generators/generateRouterFastify.d.ts +5 -0
  14. package/dist/generators/generateRouterFastify.js +512 -0
  15. package/dist/generators/generateRouterFastify.js.map +1 -0
  16. package/dist/generators/generateUnifiedDocs.d.ts +2 -1
  17. package/dist/generators/generateUnifiedDocs.js +147 -82
  18. package/dist/generators/generateUnifiedDocs.js.map +1 -1
  19. package/dist/generators/generateUnifiedHandler.d.ts +0 -1
  20. package/dist/generators/generateUnifiedHandler.js +47 -516
  21. package/dist/generators/generateUnifiedHandler.js.map +1 -1
  22. package/dist/generators/generateUnifiedScalarUI.d.ts +2 -0
  23. package/dist/generators/generateUnifiedScalarUI.js +127 -1324
  24. package/dist/generators/generateUnifiedScalarUI.js.map +1 -1
  25. package/dist/index.js +33 -8
  26. package/dist/index.js.map +1 -1
  27. package/dist/utils/copyFiles.d.ts +2 -1
  28. package/dist/utils/copyFiles.js +73 -39
  29. package/dist/utils/copyFiles.js.map +1 -1
  30. package/dist/utils/writeFileSafely.js +3 -0
  31. package/dist/utils/writeFileSafely.js.map +1 -1
  32. package/package.json +4 -1
  33. package/src/client/encodeQueryParams.ts +1 -1
  34. package/src/constants.ts +2 -0
  35. package/src/copy/createOutputValidatorMiddleware.ts +9 -12
  36. package/src/copy/docsRenderer.ts +1285 -0
  37. package/src/copy/parseQueryParams.ts +4 -8
  38. package/src/copy/routeConfig.ts +10 -4
  39. package/src/generators/generateFastifyHandler.ts +86 -0
  40. package/src/generators/generateOperationCore.ts +545 -0
  41. package/src/generators/generateQueryBuilderHelper.ts +86 -70
  42. package/src/generators/generateRouter.ts +1 -25
  43. package/src/generators/generateRouterFastify.ts +522 -0
  44. package/src/generators/generateUnifiedDocs.ts +164 -81
  45. package/src/generators/generateUnifiedHandler.ts +45 -533
  46. package/src/generators/generateUnifiedScalarUI.ts +134 -1323
  47. package/src/index.ts +45 -9
  48. package/src/utils/copyFiles.ts +88 -44
  49. package/src/utils/writeFileSafely.ts +4 -0
@@ -1,20 +1,33 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.generateUnifiedDocs = generateUnifiedDocs;
4
- function generateUnifiedDocs(models) {
4
+ function generateUnifiedDocs(models, target = 'express') {
5
5
  const imports = models
6
- .map((model) => `import { ${model}Docs } from './${model}/${model}Docs'`)
6
+ .map((model) => `import { ${model}Docs } from './${model}/${model}Docs.js'`)
7
7
  .join('\n');
8
8
  const handlersEntries = models
9
9
  .map((model) => ` ${model}: ${model}Docs`)
10
10
  .join(',\n');
11
+ const frameworkImport = target === 'fastify'
12
+ ? `import type { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify'`
13
+ : `import { Request, Response } from 'express'`;
14
+ const routeConfigImport = `import type { RouteConfig } from './routeConfig.js'`;
15
+ const handlerType = target === 'fastify'
16
+ ? `(config: any) => (request: FastifyRequest, reply: FastifyReply) => Promise<void>`
17
+ : `(config: any) => (req: Request, res: Response) => any`;
18
+ const combinedDocsReturn = target === 'fastify'
19
+ ? generateFastifyCombinedDocs()
20
+ : generateExpressCombinedDocs();
21
+ const registerDocs = target === 'fastify'
22
+ ? generateFastifyRegisterDocs()
23
+ : generateExpressRegisterDocs();
11
24
  return `${imports}
12
- import { Request, Response } from 'express'
13
- import type { RouteConfig } from './routeConfig'
25
+ ${frameworkImport}
26
+ ${routeConfigImport}
14
27
 
15
28
  const _env = typeof process !== 'undefined' && process.env ? process.env : {} as Record<string, string | undefined>
16
29
 
17
- const docsHandlers: Record<string, (config: any) => (req: Request, res: Response) => any> = {
30
+ const docsHandlers: Record<string, ${handlerType}> = {
18
31
  ${handlersEntries}
19
32
  }
20
33
 
@@ -64,96 +77,125 @@ function isPlaygroundAvailable(config?: ModelDocsConfig) {
64
77
  return true
65
78
  }
66
79
 
67
- export function generateCombinedDocs(config: CombinedDocsConfig) {
80
+ function buildCombinedHtml(
81
+ config: CombinedDocsConfig,
82
+ registeredModels: string[],
83
+ ) {
68
84
  const title = config.title || 'API Documentation'
69
85
  const description = config.description || ''
70
86
  const version = config.version || ''
87
+ const basePath = removeTrailingSlash(config.basePath || '/docs')
88
+ const generatedAt = new Date().toISOString()
89
+
90
+ const modelRows = registeredModels.map((m) => {
91
+ const lower = m.toLowerCase()
92
+ const docsUrl = basePath + '/' + lower
93
+ const scalarUrl = docsUrl + '?ui=scalar'
94
+ const jsonUrl = docsUrl + '?ui=json'
95
+ const yamlUrl = docsUrl + '?ui=yaml'
96
+ const playgroundUrl = docsUrl + '?ui=playground'
97
+ const modelCfg = config.modelConfigs[m]
98
+ const modelPlayground = isPlaygroundAvailable(modelCfg)
99
+ const playgroundLink = modelPlayground
100
+ ? ', <a href="' + playgroundUrl + '" class="text-inherit underline">playground</a>'
101
+ : ''
102
+ return '<tr>' +
103
+ '<td class="text-left py-2 px-2 border-b border-gray-300 align-top">' + escapeHtml(m) + '</td>' +
104
+ '<td class="text-left py-2 px-2 border-b border-gray-300 align-top"><a href="' + docsUrl + '" class="text-inherit underline">' + escapeHtml(docsUrl) + '</a></td>' +
105
+ '<td class="text-left py-2 px-2 border-b border-gray-300 align-top">' +
106
+ '<a href="' + scalarUrl + '" class="text-inherit underline">scalar</a>, ' +
107
+ '<a href="' + jsonUrl + '" class="text-inherit underline">json</a>, ' +
108
+ '<a href="' + yamlUrl + '" class="text-inherit underline">yaml</a>' +
109
+ playgroundLink +
110
+ '</td>' +
111
+ '</tr>'
112
+ }).join('')
113
+
114
+ const descriptionHtml = description
115
+ ? '<div class="mt-1.5 text-gray-500 text-sm">' + escapeHtml(description) + '</div>'
116
+ : ''
117
+ const versionHtml = version
118
+ ? '<div>Version: ' + escapeHtml(version) + '</div>'
119
+ : ''
120
+
121
+ return '<!DOCTYPE html>' +
122
+ '<html lang="en">' +
123
+ '<head>' +
124
+ '<meta charset="utf-8" />' +
125
+ '<meta name="viewport" content="width=device-width, initial-scale=1" />' +
126
+ '<title>' + escapeHtml(title) + '</title>' +
127
+ '<script src="https://cdn.tailwindcss.com"></' + 'script>' +
128
+ '</head>' +
129
+ '<body class="m-0 bg-white text-gray-900 font-serif leading-normal">' +
130
+ '<div class="max-w-[980px] mx-auto px-7 pt-10 pb-16">' +
131
+ '<div class="border-b-2 border-gray-900 pb-3.5 mb-[18px]">' +
132
+ '<div class="text-[28px] font-bold tracking-wide">' + escapeHtml(title) + '</div>' +
133
+ descriptionHtml +
134
+ '<div class="mt-3 flex gap-x-5 text-[13px] text-gray-500">' +
135
+ versionHtml +
136
+ '<div>Generated: ' + escapeHtml(generatedAt) + '</div>' +
137
+ '</div>' +
138
+ '</div>' +
139
+ '<div class="mt-[22px]">' +
140
+ '<h2 class="m-0 mb-2.5 text-lg border-t border-gray-300 pt-3.5">Models</h2>' +
141
+ '<table class="w-full border-collapse text-[13px]">' +
142
+ '<thead>' +
143
+ '<tr>' +
144
+ '<th class="text-left py-2 px-2 border-b border-gray-300 align-top font-bold">Model</th>' +
145
+ '<th class="text-left py-2 px-2 border-b border-gray-300 align-top font-bold">Documentation</th>' +
146
+ '<th class="text-left py-2 px-2 border-b border-gray-300 align-top font-bold">Views</th>' +
147
+ '</tr>' +
148
+ '</thead>' +
149
+ '<tbody>' + modelRows + '</tbody>' +
150
+ '</table>' +
151
+ '</div>' +
152
+ '</div>' +
153
+ '</body>' +
154
+ '</html>'
155
+ }
71
156
 
157
+ function getRegisteredModels(config: CombinedDocsConfig) {
158
+ return Object.keys(config.modelConfigs).filter((m) => {
159
+ const cfg = config.modelConfigs[m]
160
+ return m in docsHandlers && !isOpenApiDisabled(cfg?.disableOpenApi ?? config.disableOpenApi)
161
+ })
162
+ }
163
+
164
+ ${combinedDocsReturn}
165
+
166
+ ${registerDocs}
167
+ `;
168
+ }
169
+ function generateExpressCombinedDocs() {
170
+ return `export function generateCombinedDocs(config: CombinedDocsConfig) {
72
171
  return (req: Request, res: Response) => {
73
- const registeredModels = Object.keys(config.modelConfigs).filter((m) => {
74
- const cfg = config.modelConfigs[m]
75
- return m in docsHandlers && !isOpenApiDisabled(cfg?.disableOpenApi ?? config.disableOpenApi)
76
- })
172
+ const registeredModels = getRegisteredModels(config)
77
173
 
78
174
  if (registeredModels.length === 0) {
79
175
  return res.status(404).send('OpenAPI documentation is disabled')
80
176
  }
81
177
 
82
- const basePath = removeTrailingSlash(config.basePath || '/docs')
83
- const generatedAt = new Date().toISOString()
84
-
85
- const modelRows = registeredModels.map((m) => {
86
- const lower = m.toLowerCase()
87
- const docsUrl = basePath + '/' + lower
88
- const scalarUrl = docsUrl + '?ui=scalar'
89
- const jsonUrl = docsUrl + '?ui=json'
90
- const yamlUrl = docsUrl + '?ui=yaml'
91
- const playgroundUrl = docsUrl + '?ui=playground'
92
- const modelCfg = config.modelConfigs[m]
93
- const modelPlayground = isPlaygroundAvailable(modelCfg)
94
- const playgroundLink = modelPlayground
95
- ? ', <a href="' + playgroundUrl + '" class="text-inherit underline">playground</a>'
96
- : ''
97
- return '<tr>' +
98
- '<td class="text-left py-2 px-2 border-b border-gray-300 align-top">' + escapeHtml(m) + '</td>' +
99
- '<td class="text-left py-2 px-2 border-b border-gray-300 align-top"><a href="' + docsUrl + '" class="text-inherit underline">' + escapeHtml(docsUrl) + '</a></td>' +
100
- '<td class="text-left py-2 px-2 border-b border-gray-300 align-top">' +
101
- '<a href="' + scalarUrl + '" class="text-inherit underline">scalar</a>, ' +
102
- '<a href="' + jsonUrl + '" class="text-inherit underline">json</a>, ' +
103
- '<a href="' + yamlUrl + '" class="text-inherit underline">yaml</a>' +
104
- playgroundLink +
105
- '</td>' +
106
- '</tr>'
107
- }).join('')
108
-
109
- const descriptionHtml = description
110
- ? '<div class="mt-1.5 text-gray-500 text-sm">' + escapeHtml(description) + '</div>'
111
- : ''
112
- const versionHtml = version
113
- ? '<div>Version: ' + escapeHtml(version) + '</div>'
114
- : ''
115
-
116
- const html =
117
- '<!DOCTYPE html>' +
118
- '<html lang="en">' +
119
- '<head>' +
120
- '<meta charset="utf-8" />' +
121
- '<meta name="viewport" content="width=device-width, initial-scale=1" />' +
122
- '<title>' + escapeHtml(title) + '</title>' +
123
- '<script src="https://cdn.tailwindcss.com"></' + 'script>' +
124
- '</head>' +
125
- '<body class="m-0 bg-white text-gray-900 font-serif leading-normal">' +
126
- '<div class="max-w-[980px] mx-auto px-7 pt-10 pb-16">' +
127
- '<div class="border-b-2 border-gray-900 pb-3.5 mb-[18px]">' +
128
- '<div class="text-[28px] font-bold tracking-wide">' + escapeHtml(title) + '</div>' +
129
- descriptionHtml +
130
- '<div class="mt-3 flex gap-x-5 text-[13px] text-gray-500">' +
131
- versionHtml +
132
- '<div>Generated: ' + escapeHtml(generatedAt) + '</div>' +
133
- '</div>' +
134
- '</div>' +
135
- '<div class="mt-[22px]">' +
136
- '<h2 class="m-0 mb-2.5 text-lg border-t border-gray-300 pt-3.5">Models</h2>' +
137
- '<table class="w-full border-collapse text-[13px]">' +
138
- '<thead>' +
139
- '<tr>' +
140
- '<th class="text-left py-2 px-2 border-b border-gray-300 align-top font-bold">Model</th>' +
141
- '<th class="text-left py-2 px-2 border-b border-gray-300 align-top font-bold">Documentation</th>' +
142
- '<th class="text-left py-2 px-2 border-b border-gray-300 align-top font-bold">Views</th>' +
143
- '</tr>' +
144
- '</thead>' +
145
- '<tbody>' + modelRows + '</tbody>' +
146
- '</table>' +
147
- '</div>' +
148
- '</div>' +
149
- '</body>' +
150
- '</html>'
151
-
178
+ const html = buildCombinedHtml(config, registeredModels)
152
179
  res.type('html').send(html)
153
180
  }
181
+ }`;
154
182
  }
183
+ function generateFastifyCombinedDocs() {
184
+ return `export function generateCombinedDocs(config: CombinedDocsConfig) {
185
+ return async (request: FastifyRequest, reply: FastifyReply) => {
186
+ const registeredModels = getRegisteredModels(config)
187
+
188
+ if (registeredModels.length === 0) {
189
+ return reply.code(404).send('OpenAPI documentation is disabled')
190
+ }
155
191
 
156
- export function registerModelDocs(
192
+ const html = buildCombinedHtml(config, registeredModels)
193
+ return reply.type('text/html').send(html)
194
+ }
195
+ }`;
196
+ }
197
+ function generateExpressRegisterDocs() {
198
+ return `export function registerModelDocs(
157
199
  app: any,
158
200
  basePath: string = '/docs',
159
201
  configs: CombinedDocsConfig['modelConfigs'] = {},
@@ -174,7 +216,30 @@ export function registerModelDocs(
174
216
  console.log(' Registered docs: ' + docPath)
175
217
  app.get(docPath, handler(cfg))
176
218
  })
219
+ }`;
177
220
  }
178
- `;
221
+ function generateFastifyRegisterDocs() {
222
+ return `export function registerModelDocs(
223
+ app: FastifyInstance,
224
+ basePath: string = '/docs',
225
+ configs: CombinedDocsConfig['modelConfigs'] = {},
226
+ options?: { disableOpenApi?: boolean }
227
+ ) {
228
+ const normalizedBase = removeTrailingSlash(basePath)
229
+ const registeredModels = Object.keys(configs).filter((m) => {
230
+ const cfg = configs[m]
231
+ return m in docsHandlers && !isOpenApiDisabled(cfg?.disableOpenApi ?? options?.disableOpenApi)
232
+ })
233
+
234
+ if (registeredModels.length === 0) return
235
+
236
+ registeredModels.forEach((model) => {
237
+ const handler = docsHandlers[model]
238
+ const cfg = configs[model] || {}
239
+ const docPath = normalizedBase + '/' + model.toLowerCase()
240
+ console.log(' Registered docs: ' + docPath)
241
+ app.get(docPath, handler(cfg))
242
+ })
243
+ }`;
179
244
  }
180
245
  //# sourceMappingURL=generateUnifiedDocs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"generateUnifiedDocs.js","sourceRoot":"","sources":["../../src/generators/generateUnifiedDocs.ts"],"names":[],"mappings":";;AAAA,kDAiLC;AAjLD,SAAgB,mBAAmB,CAAC,MAAgB;IAClD,MAAM,OAAO,GAAG,MAAM;SACnB,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,KAAK,kBAAkB,KAAK,IAAI,KAAK,OAAO,CAAC;SACxE,IAAI,CAAC,IAAI,CAAC,CAAA;IAEb,MAAM,eAAe,GAAG,MAAM;SAC3B,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,KAAK,KAAK,MAAM,CAAC;SAC1C,IAAI,CAAC,KAAK,CAAC,CAAA;IAEd,OAAO,GAAG,OAAO;;;;;;;EAOjB,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgKhB,CAAA;AACD,CAAC"}
1
+ {"version":3,"file":"generateUnifiedDocs.js","sourceRoot":"","sources":["../../src/generators/generateUnifiedDocs.ts"],"names":[],"mappings":";;AAEA,kDAkLC;AAlLD,SAAgB,mBAAmB,CACjC,MAAgB,EAChB,SAAiB,SAAS;IAE1B,MAAM,OAAO,GAAG,MAAM;SACnB,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,KAAK,kBAAkB,KAAK,IAAI,KAAK,UAAU,CAAC;SAC3E,IAAI,CAAC,IAAI,CAAC,CAAA;IAEb,MAAM,eAAe,GAAG,MAAM;SAC3B,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,KAAK,KAAK,MAAM,CAAC;SAC1C,IAAI,CAAC,KAAK,CAAC,CAAA;IAEd,MAAM,eAAe,GACnB,MAAM,KAAK,SAAS;QAClB,CAAC,CAAC,8EAA8E;QAChF,CAAC,CAAC,6CAA6C,CAAA;IAEnD,MAAM,iBAAiB,GAAG,qDAAqD,CAAA;IAE/E,MAAM,WAAW,GACf,MAAM,KAAK,SAAS;QAClB,CAAC,CAAC,kFAAkF;QACpF,CAAC,CAAC,uDAAuD,CAAA;IAE7D,MAAM,kBAAkB,GACtB,MAAM,KAAK,SAAS;QAClB,CAAC,CAAC,2BAA2B,EAAE;QAC/B,CAAC,CAAC,2BAA2B,EAAE,CAAA;IAEnC,MAAM,YAAY,GAChB,MAAM,KAAK,SAAS;QAClB,CAAC,CAAC,2BAA2B,EAAE;QAC/B,CAAC,CAAC,2BAA2B,EAAE,CAAA;IAEnC,OAAO,GAAG,OAAO;EACjB,eAAe;EACf,iBAAiB;;;;qCAIkB,WAAW;EAC9C,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqIf,kBAAkB;;EAElB,YAAY;CACb,CAAA;AACD,CAAC;AAED,SAAS,2BAA2B;IAClC,OAAO;;;;;;;;;;;EAWP,CAAA;AACF,CAAC;AAED,SAAS,2BAA2B;IAClC,OAAO;;;;;;;;;;;EAWP,CAAA;AACF,CAAC;AAED,SAAS,2BAA2B;IAClC,OAAO;;;;;;;;;;;;;;;;;;;;;EAqBP,CAAA;AACF,CAAC;AAED,SAAS,2BAA2B;IAClC,OAAO;;;;;;;;;;;;;;;;;;;;;EAqBP,CAAA;AACF,CAAC"}
@@ -1,6 +1,5 @@
1
1
  import { DMMF } from '@prisma/generator-helper';
2
2
  export interface UnifiedHandlerOptions {
3
3
  model: DMMF.Model;
4
- prismaImportStatement: string;
5
4
  }
6
5
  export declare function generateUnifiedHandler(options: UnifiedHandlerOptions): string;