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.
- package/README.md +244 -14
- package/dist/constants.d.ts +1 -0
- package/dist/generators/generateFastifyHandler.d.ts +4 -0
- package/dist/generators/generateFastifyHandler.js +78 -0
- package/dist/generators/generateFastifyHandler.js.map +1 -0
- package/dist/generators/generateOperationCore.d.ts +6 -0
- package/dist/generators/generateOperationCore.js +534 -0
- package/dist/generators/generateOperationCore.js.map +1 -0
- package/dist/generators/generateQueryBuilderHelper.js +85 -69
- package/dist/generators/generateQueryBuilderHelper.js.map +1 -1
- package/dist/generators/generateRouter.js +1 -25
- package/dist/generators/generateRouter.js.map +1 -1
- package/dist/generators/generateRouterFastify.d.ts +5 -0
- package/dist/generators/generateRouterFastify.js +512 -0
- package/dist/generators/generateRouterFastify.js.map +1 -0
- package/dist/generators/generateUnifiedDocs.d.ts +2 -1
- package/dist/generators/generateUnifiedDocs.js +147 -82
- package/dist/generators/generateUnifiedDocs.js.map +1 -1
- package/dist/generators/generateUnifiedHandler.d.ts +0 -1
- package/dist/generators/generateUnifiedHandler.js +47 -516
- package/dist/generators/generateUnifiedHandler.js.map +1 -1
- package/dist/generators/generateUnifiedScalarUI.d.ts +2 -0
- package/dist/generators/generateUnifiedScalarUI.js +127 -1324
- package/dist/generators/generateUnifiedScalarUI.js.map +1 -1
- package/dist/index.js +33 -8
- package/dist/index.js.map +1 -1
- package/dist/utils/copyFiles.d.ts +2 -1
- package/dist/utils/copyFiles.js +73 -39
- package/dist/utils/copyFiles.js.map +1 -1
- package/dist/utils/writeFileSafely.js +3 -0
- package/dist/utils/writeFileSafely.js.map +1 -1
- package/package.json +4 -1
- package/src/client/encodeQueryParams.ts +1 -1
- package/src/constants.ts +2 -0
- package/src/copy/createOutputValidatorMiddleware.ts +9 -12
- package/src/copy/docsRenderer.ts +1285 -0
- package/src/copy/parseQueryParams.ts +4 -8
- package/src/copy/routeConfig.ts +10 -4
- package/src/generators/generateFastifyHandler.ts +86 -0
- package/src/generators/generateOperationCore.ts +545 -0
- package/src/generators/generateQueryBuilderHelper.ts +86 -70
- package/src/generators/generateRouter.ts +1 -25
- package/src/generators/generateRouterFastify.ts +522 -0
- package/src/generators/generateUnifiedDocs.ts +164 -81
- package/src/generators/generateUnifiedHandler.ts +45 -533
- package/src/generators/generateUnifiedScalarUI.ts +134 -1323
- package/src/index.ts +45 -9
- package/src/utils/copyFiles.ts +88 -44
- 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
|
|
43
|
+
const target = getTarget(options)
|
|
30
44
|
|
|
31
|
-
console.log(
|
|
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:
|
|
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:
|
|
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('')
|
package/src/utils/copyFiles.ts
CHANGED
|
@@ -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
|
-
|
|
6
|
-
const
|
|
7
|
-
if (
|
|
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
|
-
|
|
22
|
+
const fromSrc = path.join(__dirname, '..', '..', 'src', subpath)
|
|
23
|
+
if (fs.existsSync(fromSrc)) return fromSrc
|
|
22
24
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
32
|
+
}
|
|
44
33
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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
|
-
|
|
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(
|
|
66
|
+
console.error(`[prisma-generator-express] ✗ Required source file not found: ${srcPath}`)
|
|
71
67
|
return false
|
|
72
68
|
}
|
|
73
|
-
console.warn(
|
|
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
|
|
110
|
-
|
|
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}`)
|