prisma-generator-express 1.27.0 → 1.29.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 +255 -16
  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 +64 -38
  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 +79 -45
  49. package/src/utils/writeFileSafely.ts +4 -0
package/src/index.ts CHANGED
@@ -4,17 +4,31 @@ import {
4
4
  DMMF,
5
5
  } from '@prisma/generator-helper'
6
6
  import { generateUnifiedHandler } from './generators/generateUnifiedHandler.js'
7
+ import { generateFastifyHandler } from './generators/generateFastifyHandler.js'
7
8
  import { generateRouterFunction } from './generators/generateRouter.js'
9
+ import { generateFastifyRouterFunction } from './generators/generateRouterFastify.js'
8
10
  import { generateScalarUIHandler } from './generators/generateUnifiedScalarUI.js'
9
11
  import { generateUnifiedDocs } from './generators/generateUnifiedDocs.js'
10
12
  import { generateQueryBuilderHelper } from './generators/generateQueryBuilderHelper.js'
13
+ import {
14
+ generateOperationRuntime,
15
+ generateModelCore,
16
+ } from './generators/generateOperationCore.js'
11
17
  import {
12
18
  generateImportPrismaStatement,
13
19
  getRelativeClientPath,
14
20
  } from './generators/generateImportPrismaStatement.js'
15
21
  import { writeFileSafely } from './utils/writeFileSafely.js'
16
22
  import { copyFiles } from './utils/copyFiles.js'
17
- import { GENERATOR_NAME } from './constants.js'
23
+ import { GENERATOR_NAME, Target } from './constants.js'
24
+
25
+ function getTarget(options: GeneratorOptions): Target {
26
+ const raw = String(
27
+ (options.generator.config as Record<string, unknown>).target ?? 'express',
28
+ ).toLowerCase()
29
+ if (raw === 'express' || raw === 'fastify') return raw
30
+ throw new Error(`Invalid target "${raw}". Expected "express" or "fastify".`)
31
+ }
18
32
 
19
33
  generatorHandler({
20
34
  onManifest() {
@@ -26,14 +40,29 @@ generatorHandler({
26
40
  },
27
41
 
28
42
  async onGenerate(options: GeneratorOptions) {
29
- const prismaImportStatement = generateImportPrismaStatement(options)
43
+ const target = getTarget(options)
30
44
 
31
- console.log('\n═══ Prisma Generator Express ═══')
45
+ console.log(`\n═══ Prisma Generator (${target.toUpperCase()}) ═══`)
46
+ console.log(` Target: ${target}`)
32
47
 
33
- await copyFiles(options)
48
+ await copyFiles(options, target)
49
+
50
+ await writeFileSafely({
51
+ content: generateOperationRuntime(),
52
+ options,
53
+ operation: 'operationRuntime',
54
+ })
34
55
 
35
56
  const modelNames: string[] = []
36
57
 
58
+ const generateHandler =
59
+ target === 'fastify' ? generateFastifyHandler : generateUnifiedHandler
60
+
61
+ const generateRouter =
62
+ target === 'fastify'
63
+ ? generateFastifyRouterFunction
64
+ : generateRouterFunction
65
+
37
66
  for (const model of options.dmmf.datamodel.models) {
38
67
  if (
39
68
  model.documentation &&
@@ -48,9 +77,15 @@ generatorHandler({
48
77
  const relativeClientPath = getRelativeClientPath(options, model.name)
49
78
 
50
79
  await writeFileSafely({
51
- content: generateUnifiedHandler({
80
+ content: generateModelCore({ model: model as DMMF.Model }),
81
+ options,
82
+ model: model as DMMF.Model,
83
+ operation: 'Core',
84
+ })
85
+
86
+ await writeFileSafely({
87
+ content: generateHandler({
52
88
  model: model as DMMF.Model,
53
- prismaImportStatement,
54
89
  }),
55
90
  options,
56
91
  model: model as DMMF.Model,
@@ -58,7 +93,7 @@ generatorHandler({
58
93
  })
59
94
 
60
95
  await writeFileSafely({
61
- content: generateRouterFunction({
96
+ content: generateRouter({
62
97
  model: model as DMMF.Model,
63
98
  enums: options.dmmf.datamodel.enums as DMMF.DatamodelEnum[],
64
99
  relativeClientPath,
@@ -72,6 +107,7 @@ generatorHandler({
72
107
  content: generateScalarUIHandler({
73
108
  model: model as DMMF.Model,
74
109
  enums: options.dmmf.datamodel.enums as DMMF.DatamodelEnum[],
110
+ target,
75
111
  }),
76
112
  options,
77
113
  model: model as DMMF.Model,
@@ -80,7 +116,7 @@ generatorHandler({
80
116
  }
81
117
 
82
118
  await writeFileSafely({
83
- content: generateUnifiedDocs(modelNames),
119
+ content: generateUnifiedDocs(modelNames, target),
84
120
  options,
85
121
  operation: 'combinedDocs',
86
122
  })
@@ -92,7 +128,7 @@ generatorHandler({
92
128
  })
93
129
 
94
130
  console.log('\n═══ Generation Complete ═══')
95
- console.log(`✓ ${modelNames.length} models`)
131
+ console.log(`✓ ${modelNames.length} models (${target})`)
96
132
  console.log(`✓ OpenAPI documentation generated`)
97
133
  console.log(`✓ Query builder helper generated`)
98
134
  console.log('')
@@ -1,54 +1,36 @@
1
1
  import { GeneratorOptions } from '@prisma/generator-helper'
2
2
  import * as fs from 'fs'
3
3
  import * as path from 'path'
4
+ import { Target } from '../constants.js'
5
+
6
+ const SHARED_FILES = [
7
+ 'parseQueryParams.ts',
8
+ 'buildModelOpenApi.ts',
9
+ 'operationDefinitions.ts',
10
+ 'misc.ts',
11
+ 'docsRenderer.ts',
12
+ ]
13
+
14
+ const TARGET_FILES: Record<Target, string[]> = {
15
+ express: ['routeConfig.ts'],
16
+ fastify: ['routeConfig.ts'],
17
+ }
4
18
 
5
- export async function copyFiles(options: GeneratorOptions): Promise<void> {
6
- const outputPath = options.generator.output?.value
7
- if (!outputPath) return
8
-
9
- const srcDir = path.join(__dirname, '..', '..', 'src', 'copy')
10
-
11
- const baseFiles = [
12
- 'routeConfig.ts',
13
- 'parseQueryParams.ts',
14
- 'buildModelOpenApi.ts',
15
- 'operationDefinitions.ts',
16
- 'misc.ts',
17
- ]
18
-
19
- let allCopied = true
20
-
21
- console.log(`Copying utility files to: ${outputPath}`)
19
+ function resolveTemplateDir(subpath: string): string {
20
+ const fromSibling = path.join(__dirname, '..', subpath)
21
+ if (fs.existsSync(fromSibling)) return fromSibling
22
22
 
23
- for (const file of baseFiles) {
24
- const ok = await copyFile(srcDir, outputPath, file, { required: true })
25
- if (!ok) allCopied = false
26
- }
23
+ const fromSrc = path.join(__dirname, '..', '..', 'src', subpath)
24
+ if (fs.existsSync(fromSrc)) return fromSrc
27
25
 
28
- const clientDir = path.join(outputPath, 'client')
29
- if (!fs.existsSync(clientDir)) {
30
- fs.mkdirSync(clientDir, { recursive: true })
31
- }
32
-
33
- const clientSrcDir = path.join(__dirname, '..', '..', 'src', 'client')
34
- const clientOk = await copyFile(
35
- clientSrcDir,
36
- clientDir,
37
- 'encodeQueryParams.ts',
38
- {
39
- required: true,
40
- importRewrites: [{ from: '../copy/misc.js', to: '../misc.js' }],
41
- },
26
+ throw new Error(
27
+ `Template directory "${subpath}" not found. Searched:\n ${fromSibling}\n ${fromSrc}\nEnsure template files are included in the published package.`,
42
28
  )
43
- if (!clientOk) allCopied = false
29
+ }
44
30
 
45
- if (allCopied) {
46
- console.log(`✓ Utility files copied successfully`)
47
- } else {
48
- throw new Error(
49
- 'One or more required utility files could not be copied. Generation aborted.',
50
- )
51
- }
31
+ function getTargetSourceDir(copyBase: string, target: Target): string {
32
+ if (target === 'express') return copyBase
33
+ return path.join(copyBase, target)
52
34
  }
53
35
 
54
36
  interface CopyFileOptions {
@@ -56,6 +38,10 @@ interface CopyFileOptions {
56
38
  importRewrites?: Array<{ from: string; to: string }>
57
39
  }
58
40
 
41
+ function escapeRegex(str: string): string {
42
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
43
+ }
44
+
59
45
  async function copyFile(
60
46
  srcDir: string,
61
47
  destDir: string,
@@ -106,6 +92,54 @@ async function copyFile(
106
92
  return true
107
93
  }
108
94
 
109
- function escapeRegex(str: string): string {
110
- return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
95
+ export async function copyFiles(
96
+ options: GeneratorOptions,
97
+ target: Target,
98
+ ): Promise<void> {
99
+ const outputPath = options.generator.output?.value
100
+ if (!outputPath) return
101
+
102
+ const copyBase = resolveTemplateDir('copy')
103
+
104
+ let allCopied = true
105
+
106
+ console.log(` Copying utility files to: ${outputPath} (target: ${target})`)
107
+
108
+ for (const file of SHARED_FILES) {
109
+ const ok = await copyFile(copyBase, outputPath, file, { required: true })
110
+ if (!ok) allCopied = false
111
+ }
112
+
113
+ const targetSrcDir = getTargetSourceDir(copyBase, target)
114
+ for (const file of TARGET_FILES[target]) {
115
+ const ok = await copyFile(targetSrcDir, outputPath, file, {
116
+ required: true,
117
+ })
118
+ if (!ok) allCopied = false
119
+ }
120
+
121
+ const clientDir = path.join(outputPath, 'client')
122
+ if (!fs.existsSync(clientDir)) {
123
+ fs.mkdirSync(clientDir, { recursive: true })
124
+ }
125
+
126
+ const clientSrcDir = resolveTemplateDir('client')
127
+ const clientOk = await copyFile(
128
+ clientSrcDir,
129
+ clientDir,
130
+ 'encodeQueryParams.ts',
131
+ {
132
+ required: true,
133
+ importRewrites: [{ from: '../copy/misc.js', to: '../misc.js' }],
134
+ },
135
+ )
136
+ if (!clientOk) allCopied = false
137
+
138
+ if (allCopied) {
139
+ console.log(` ✓ Utility files copied successfully`)
140
+ } else {
141
+ throw new Error(
142
+ 'One or more required utility files could not be copied. Generation aborted.',
143
+ )
144
+ }
111
145
  }
@@ -41,6 +41,10 @@ export async function writeFileSafely({
41
41
  filePath = path.join(outputPath, 'queryBuilder.ts')
42
42
  break
43
43
 
44
+ case 'operationRuntime':
45
+ filePath = path.join(outputPath, 'operationRuntime.ts')
46
+ break
47
+
44
48
  default:
45
49
  if (!model) {
46
50
  throw new Error(`Model required for operation: ${operation}`)