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
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,46 @@
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
+ ]
12
+
13
+ const TARGET_FILES: Record<Target, string[]> = {
14
+ express: ['routeConfig.ts'],
15
+ fastify: ['routeConfig.ts'],
16
+ }
4
17
 
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
18
+ function resolveTemplateDir(subpath: string): string {
19
+ const fromSibling = path.join(__dirname, '..', subpath)
20
+ if (fs.existsSync(fromSibling)) return fromSibling
20
21
 
21
- console.log(`Copying utility files to: ${outputPath}`)
22
+ const fromSrc = path.join(__dirname, '..', '..', 'src', subpath)
23
+ if (fs.existsSync(fromSrc)) return fromSrc
22
24
 
23
- for (const file of baseFiles) {
24
- const ok = await copyFile(srcDir, outputPath, file, { required: true })
25
- if (!ok) allCopied = false
26
- }
27
-
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
- },
25
+ throw new Error(
26
+ `[prisma-generator-express] Template directory "${subpath}" not found.\n` +
27
+ ` Searched:\n` +
28
+ ` ${fromSibling}\n` +
29
+ ` ${fromSrc}\n` +
30
+ ` Ensure template files are included in the published package.`,
42
31
  )
43
- if (!clientOk) allCopied = false
32
+ }
44
33
 
45
- if (allCopied) {
46
- console.log(`✓ Utility files copied successfully`)
47
- } else {
34
+ function getTargetSourceDir(copyBase: string, target: Target): string {
35
+ if (target === 'express') return copyBase
36
+ const targetDir = path.join(copyBase, target)
37
+ if (!fs.existsSync(targetDir)) {
48
38
  throw new Error(
49
- 'One or more required utility files could not be copied. Generation aborted.',
39
+ `[prisma-generator-express] Target template directory not found: ${targetDir}\n` +
40
+ ` Expected directory for target "${target}" at: ${targetDir}`,
50
41
  )
51
42
  }
43
+ return targetDir
52
44
  }
53
45
 
54
46
  interface CopyFileOptions {
@@ -56,6 +48,10 @@ interface CopyFileOptions {
56
48
  importRewrites?: Array<{ from: string; to: string }>
57
49
  }
58
50
 
51
+ function escapeRegex(str: string): string {
52
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
53
+ }
54
+
59
55
  async function copyFile(
60
56
  srcDir: string,
61
57
  destDir: string,
@@ -67,10 +63,10 @@ async function copyFile(
67
63
 
68
64
  if (!fs.existsSync(srcPath)) {
69
65
  if (options?.required) {
70
- console.error(`✗ Required source file not found: ${srcPath}`)
66
+ console.error(`[prisma-generator-express] Required source file not found: ${srcPath}`)
71
67
  return false
72
68
  }
73
- console.warn(`⚠️ Source file not found: ${srcPath}`)
69
+ console.warn(`[prisma-generator-express] ⚠️ Source file not found: ${srcPath}`)
74
70
  return true
75
71
  }
76
72
 
@@ -106,6 +102,54 @@ async function copyFile(
106
102
  return true
107
103
  }
108
104
 
109
- function escapeRegex(str: string): string {
110
- return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
105
+ export async function copyFiles(
106
+ options: GeneratorOptions,
107
+ target: Target,
108
+ ): Promise<void> {
109
+ const outputPath = options.generator.output?.value
110
+ if (!outputPath) return
111
+
112
+ const copyBase = resolveTemplateDir('copy')
113
+
114
+ let allCopied = true
115
+
116
+ console.log(` Copying utility files to: ${outputPath} (target: ${target})`)
117
+
118
+ for (const file of SHARED_FILES) {
119
+ const ok = await copyFile(copyBase, outputPath, file, { required: true })
120
+ if (!ok) allCopied = false
121
+ }
122
+
123
+ const targetSrcDir = getTargetSourceDir(copyBase, target)
124
+ for (const file of TARGET_FILES[target]) {
125
+ const ok = await copyFile(targetSrcDir, outputPath, file, {
126
+ required: true,
127
+ })
128
+ if (!ok) allCopied = false
129
+ }
130
+
131
+ const clientDir = path.join(outputPath, 'client')
132
+ if (!fs.existsSync(clientDir)) {
133
+ fs.mkdirSync(clientDir, { recursive: true })
134
+ }
135
+
136
+ const clientSrcDir = resolveTemplateDir('client')
137
+ const clientOk = await copyFile(
138
+ clientSrcDir,
139
+ clientDir,
140
+ 'encodeQueryParams.ts',
141
+ {
142
+ required: true,
143
+ importRewrites: [{ from: '../copy/misc.js', to: '../misc.js' }],
144
+ },
145
+ )
146
+ if (!clientOk) allCopied = false
147
+
148
+ if (allCopied) {
149
+ console.log(` ✓ Utility files copied successfully`)
150
+ } else {
151
+ throw new Error(
152
+ '[prisma-generator-express] One or more required utility files could not be copied. Generation aborted.',
153
+ )
154
+ }
111
155
  }
@@ -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}`)