prisma-generator-express 1.18.0 → 1.19.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 (71) hide show
  1. package/README.md +399 -194
  2. package/dist/bin.d.ts +2 -0
  3. package/dist/bin.js +1 -1
  4. package/dist/bin.js.map +1 -1
  5. package/dist/client/encodeQueryParams.d.ts +1 -0
  6. package/dist/client/encodeQueryParams.js +33 -0
  7. package/dist/client/encodeQueryParams.js.map +1 -0
  8. package/dist/constants.d.ts +1 -0
  9. package/dist/copy/misc.d.ts +5 -0
  10. package/dist/copy/misc.js +52 -0
  11. package/dist/copy/misc.js.map +1 -0
  12. package/dist/generators/generateImportPrismaStatement.d.ts +3 -0
  13. package/dist/generators/generateImportPrismaStatement.js +55 -0
  14. package/dist/generators/generateImportPrismaStatement.js.map +1 -0
  15. package/dist/generators/generateQueryBuilderHelper.d.ts +2 -0
  16. package/dist/generators/generateQueryBuilderHelper.js +139 -0
  17. package/dist/generators/generateQueryBuilderHelper.js.map +1 -0
  18. package/dist/generators/generateRouter.d.ts +6 -0
  19. package/dist/generators/generateRouter.js +340 -0
  20. package/dist/generators/generateRouter.js.map +1 -0
  21. package/dist/generators/generateUnifiedDocs.d.ts +1 -0
  22. package/dist/generators/generateUnifiedDocs.js +171 -0
  23. package/dist/generators/generateUnifiedDocs.js.map +1 -0
  24. package/dist/generators/generateUnifiedHandler.d.ts +6 -0
  25. package/dist/generators/generateUnifiedHandler.js +444 -0
  26. package/dist/generators/generateUnifiedHandler.js.map +1 -0
  27. package/dist/generators/generateUnifiedScalarUI.d.ts +5 -0
  28. package/dist/generators/generateUnifiedScalarUI.js +1390 -0
  29. package/dist/generators/generateUnifiedScalarUI.js.map +1 -0
  30. package/dist/index.d.ts +1 -0
  31. package/dist/index.js +80 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/utils/copyFiles.d.ts +6 -0
  34. package/dist/utils/copyFiles.js +123 -21
  35. package/dist/utils/copyFiles.js.map +1 -1
  36. package/dist/utils/strings.d.ts +2 -0
  37. package/dist/utils/writeFileSafely.d.ts +10 -0
  38. package/dist/utils/writeFileSafely.js +86 -14
  39. package/dist/utils/writeFileSafely.js.map +1 -1
  40. package/package.json +64 -31
  41. package/src/client/encodeQueryParams.ts +56 -0
  42. package/src/copy/buildModelOpenApi.ts +1569 -0
  43. package/src/copy/misc.ts +21 -0
  44. package/src/copy/operationDefinitions.ts +96 -0
  45. package/src/copy/parseQueryParams.ts +36 -21
  46. package/src/copy/routeConfig.ts +68 -28
  47. package/dist/generator.js +0 -47
  48. package/dist/generator.js.map +0 -1
  49. package/dist/helpers/generateImportPrismaStatement.js +0 -25
  50. package/dist/helpers/generateImportPrismaStatement.js.map +0 -1
  51. package/dist/helpers/generateOperation.js +0 -471
  52. package/dist/helpers/generateOperation.js.map +0 -1
  53. package/dist/helpers/generateRouteFile.js +0 -210
  54. package/dist/helpers/generateRouteFile.js.map +0 -1
  55. package/dist/utils/formatFile.js +0 -26
  56. package/dist/utils/formatFile.js.map +0 -1
  57. package/src/bin.ts +0 -2
  58. package/src/constants.ts +0 -1
  59. package/src/copy/encodeQueryParams.spec.ts +0 -303
  60. package/src/copy/encodeQueryParams.ts +0 -44
  61. package/src/copy/misc.spec.ts +0 -62
  62. package/src/copy/parseQueryParams.spec.ts +0 -187
  63. package/src/copy/transformZod.spec.ts +0 -763
  64. package/src/generator.ts +0 -54
  65. package/src/helpers/generateImportPrismaStatement.ts +0 -38
  66. package/src/helpers/generateOperation.ts +0 -515
  67. package/src/helpers/generateRouteFile.ts +0 -213
  68. package/src/utils/copyFiles.ts +0 -27
  69. package/src/utils/formatFile.ts +0 -22
  70. package/src/utils/strings.ts +0 -7
  71. package/src/utils/writeFileSafely.ts +0 -29
package/src/copy/misc.ts CHANGED
@@ -23,3 +23,24 @@ export function safeJSONparse<T>(
23
23
  export const isObject = (value: unknown): value is Record<string, unknown> => {
24
24
  return typeof value === 'object' && value !== null && !Array.isArray(value)
25
25
  }
26
+
27
+ const UNSAFE_KEYS = new Set(['__proto__', 'constructor', 'prototype'])
28
+
29
+ export function isSafeKey(key: string): boolean {
30
+ return !UNSAFE_KEYS.has(key)
31
+ }
32
+
33
+ export function sanitizeKeys<T>(value: T): T {
34
+ if (Array.isArray(value)) {
35
+ return value.map(sanitizeKeys) as T
36
+ }
37
+ if (isObject(value)) {
38
+ const result: Record<string, unknown> = {}
39
+ for (const key of Object.keys(value)) {
40
+ if (!isSafeKey(key)) continue
41
+ result[key] = sanitizeKeys((value as Record<string, unknown>)[key])
42
+ }
43
+ return result as T
44
+ }
45
+ return value
46
+ }
@@ -0,0 +1,96 @@
1
+ export type HttpMethod = 'get' | 'post' | 'put' | 'patch' | 'delete'
2
+
3
+ export interface OperationDef {
4
+ name: string
5
+ method: HttpMethod
6
+ pathSuffix: string
7
+ configKey: string
8
+ }
9
+
10
+ export const OPERATION_DEFS: OperationDef[] = [
11
+ { name: 'findMany', method: 'get', pathSuffix: '', configKey: 'findMany' },
12
+ {
13
+ name: 'findUnique',
14
+ method: 'get',
15
+ pathSuffix: '/unique',
16
+ configKey: 'findUnique',
17
+ },
18
+ {
19
+ name: 'findUniqueOrThrow',
20
+ method: 'get',
21
+ pathSuffix: '/unique/strict',
22
+ configKey: 'findUniqueOrThrow',
23
+ },
24
+ {
25
+ name: 'findFirst',
26
+ method: 'get',
27
+ pathSuffix: '/first',
28
+ configKey: 'findFirst',
29
+ },
30
+ {
31
+ name: 'findFirstOrThrow',
32
+ method: 'get',
33
+ pathSuffix: '/first/strict',
34
+ configKey: 'findFirstOrThrow',
35
+ },
36
+ {
37
+ name: 'findManyPaginated',
38
+ method: 'get',
39
+ pathSuffix: '/paginated',
40
+ configKey: 'findManyPaginated',
41
+ },
42
+ { name: 'create', method: 'post', pathSuffix: '', configKey: 'create' },
43
+ {
44
+ name: 'createMany',
45
+ method: 'post',
46
+ pathSuffix: '/many',
47
+ configKey: 'createMany',
48
+ },
49
+ {
50
+ name: 'createManyAndReturn',
51
+ method: 'post',
52
+ pathSuffix: '/many/return',
53
+ configKey: 'createManyAndReturn',
54
+ },
55
+ { name: 'update', method: 'put', pathSuffix: '', configKey: 'update' },
56
+ {
57
+ name: 'updateMany',
58
+ method: 'put',
59
+ pathSuffix: '/many',
60
+ configKey: 'updateMany',
61
+ },
62
+ {
63
+ name: 'updateManyAndReturn',
64
+ method: 'put',
65
+ pathSuffix: '/many/return',
66
+ configKey: 'updateManyAndReturn',
67
+ },
68
+ { name: 'upsert', method: 'patch', pathSuffix: '', configKey: 'upsert' },
69
+ { name: 'delete', method: 'delete', pathSuffix: '', configKey: 'delete' },
70
+ {
71
+ name: 'deleteMany',
72
+ method: 'delete',
73
+ pathSuffix: '/many',
74
+ configKey: 'deleteMany',
75
+ },
76
+ { name: 'count', method: 'get', pathSuffix: '/count', configKey: 'count' },
77
+ {
78
+ name: 'aggregate',
79
+ method: 'get',
80
+ pathSuffix: '/aggregate',
81
+ configKey: 'aggregate',
82
+ },
83
+ {
84
+ name: 'groupBy',
85
+ method: 'get',
86
+ pathSuffix: '/groupby',
87
+ configKey: 'groupBy',
88
+ },
89
+ ]
90
+
91
+ export function isOperationEnabled(
92
+ config: Record<string, any>,
93
+ def: OperationDef,
94
+ ): boolean {
95
+ return !!(config.enableAll || config[def.configKey])
96
+ }
@@ -1,29 +1,38 @@
1
- import { isObject } from './misc'
2
- import { ParsedQs } from 'qs'
1
+ import { isObject, isSafeKey, sanitizeKeys } from './misc'
3
2
 
4
- /**
5
- * Type definition for possible query parameter types.
6
- */
7
- type QueryParams = string | ParsedQs | string[] | ParsedQs[] | Array<string | ParsedQs> | undefined
3
+ type QueryParams =
4
+ | string
5
+ | Record<string, unknown>
6
+ | string[]
7
+ | Record<string, unknown>[]
8
+ | undefined
8
9
 
9
- /**
10
- * Parses a query value to convert strings to their respective types.
11
- * @param {string} value - The query value to parse.
12
- * @returns {unknown} The parsed value.
13
- */
14
- const parseQueryValue = (value: string): unknown => {
10
+ const NUMERIC_KEYS = new Set(['take', 'skip'])
11
+
12
+ const parseQueryValue = (value: string, key?: string): unknown => {
13
+ if (value.startsWith('{') || value.startsWith('[') || value.startsWith('"')) {
14
+ try {
15
+ const parsed = JSON.parse(value)
16
+ return sanitizeKeys(parsed)
17
+ } catch {
18
+ // fall through
19
+ }
20
+ }
15
21
  if (value === 'true') return true
16
22
  if (value === 'false') return false
17
23
  if (value === 'null') return null
18
- if (!isNaN(Number(value))) return Number(value)
24
+ if (
25
+ key &&
26
+ NUMERIC_KEYS.has(key) &&
27
+ value !== '' &&
28
+ !isNaN(Number(value)) &&
29
+ isFinite(Number(value))
30
+ ) {
31
+ return Number(value)
32
+ }
19
33
  return value
20
34
  }
21
35
 
22
- /**
23
- * Recursively parses query parameters to convert strings to their respective types.
24
- * @param {QueryParams} params - The query parameters to parse.
25
- * @returns {unknown} The parsed query parameters.
26
- */
27
36
  export const parseQueryParams = (params: QueryParams): unknown => {
28
37
  if (typeof params === 'string') {
29
38
  return parseQueryValue(params)
@@ -33,10 +42,16 @@ export const parseQueryParams = (params: QueryParams): unknown => {
33
42
  }
34
43
  if (isObject(params)) {
35
44
  const parsedParams: Record<string, unknown> = {}
36
- for (const key in params) {
37
- parsedParams[key] = parseQueryParams(params[key])
45
+ for (const key of Object.keys(params)) {
46
+ if (!isSafeKey(key)) continue
47
+ const raw = params[key]
48
+ if (typeof raw === 'string') {
49
+ parsedParams[key] = parseQueryValue(raw, key)
50
+ } else {
51
+ parsedParams[key] = raw
52
+ }
38
53
  }
39
54
  return parsedParams
40
55
  }
41
56
  return params
42
- }
57
+ }
@@ -1,36 +1,76 @@
1
- import { RequestHandler } from 'express'
2
- import { ZodType } from 'zod'
1
+ import { RequestHandler, Request } from 'express'
3
2
 
4
- export interface ValidatorConfig {
5
- allow?: string[]
6
- forbid?: string[]
7
- schema: ZodType
3
+ export interface OperationConfig {
4
+ before?: RequestHandler[]
5
+ after?: RequestHandler[]
6
+ shape?: Record<string, any>
8
7
  }
9
8
 
10
- interface MiddlewareConfig<M> {
11
- before?: M[]
12
- after?: RequestHandler[]
13
- inputValidator?: ValidatorConfig
14
- outputValidator?: ValidatorConfig
9
+ export interface QueryBuilderConfig {
10
+ enabled?: boolean
11
+ port?: number
12
+ host?: string
13
+ schemaPath?: string
14
+ databaseUrl?: string
15
15
  }
16
16
 
17
- export interface RouteConfig<M> {
18
- findFirst?: MiddlewareConfig<M>
19
- findMany?: MiddlewareConfig<M>
20
- findUnique?: MiddlewareConfig<M>
21
- create?: MiddlewareConfig<M>
22
- createMany?: MiddlewareConfig<M>
23
- createManyAndReturn?: MiddlewareConfig<M>
24
- update?: MiddlewareConfig<M>
25
- updateMany?: MiddlewareConfig<M>
26
- updateManyAndReturn?: MiddlewareConfig<M>
27
- upsert?: MiddlewareConfig<M>
28
- delete?: MiddlewareConfig<M>
29
- deleteMany?: MiddlewareConfig<M>
30
- aggregate?: MiddlewareConfig<M>
31
- count?: MiddlewareConfig<M>
32
- groupBy?: MiddlewareConfig<M>
33
- addModelPrefix?: boolean
17
+ export interface OpenApiServerConfig {
18
+ url: string
19
+ description?: string
20
+ }
21
+
22
+ export interface OpenApiSecuritySchemeConfig {
23
+ type: string
24
+ scheme?: string
25
+ bearerFormat?: string
26
+ name?: string
27
+ in?: string
28
+ description?: string
29
+ }
30
+
31
+ export interface RouteConfig {
34
32
  enableAll?: boolean
33
+ addModelPrefix?: boolean
35
34
  customUrlPrefix?: string
35
+ specBasePath?: string
36
+ disableOpenApi?: boolean
37
+ scalarCdnUrl?: string
38
+
39
+ openApiTitle?: string
40
+ openApiDescription?: string
41
+ openApiVersion?: string
42
+ openApiServers?: OpenApiServerConfig[]
43
+ openApiSecuritySchemes?: Record<string, OpenApiSecuritySchemeConfig>
44
+ openApiSecurity?: Record<string, string[]>[]
45
+
46
+ guard?: {
47
+ resolveVariant?: (req: Request) => string | undefined
48
+ variantHeader?: string
49
+ }
50
+
51
+ queryBuilder?: QueryBuilderConfig | false
52
+
53
+ pagination?: {
54
+ defaultLimit?: number
55
+ maxLimit?: number
56
+ }
57
+
58
+ findUnique?: OperationConfig
59
+ findUniqueOrThrow?: OperationConfig
60
+ findFirst?: OperationConfig
61
+ findFirstOrThrow?: OperationConfig
62
+ findMany?: OperationConfig
63
+ findManyPaginated?: OperationConfig
64
+ create?: OperationConfig
65
+ createMany?: OperationConfig
66
+ createManyAndReturn?: OperationConfig
67
+ update?: OperationConfig
68
+ updateMany?: OperationConfig
69
+ updateManyAndReturn?: OperationConfig
70
+ upsert?: OperationConfig
71
+ delete?: OperationConfig
72
+ deleteMany?: OperationConfig
73
+ aggregate?: OperationConfig
74
+ count?: OperationConfig
75
+ groupBy?: OperationConfig
36
76
  }
package/dist/generator.js DELETED
@@ -1,47 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const generator_helper_1 = require("@prisma/generator-helper");
4
- const sdk_1 = require("@prisma/sdk");
5
- const constants_1 = require("./constants");
6
- const writeFileSafely_1 = require("./utils/writeFileSafely");
7
- const generateImportPrismaStatement_1 = require("./helpers/generateImportPrismaStatement");
8
- const generateRouteFile_1 = require("./helpers/generateRouteFile");
9
- const generateOperation_1 = require("./helpers/generateOperation");
10
- const copyFiles_1 = require("./utils/copyFiles");
11
- const { version } = require('../package.json');
12
- (0, generator_helper_1.generatorHandler)({
13
- onManifest() {
14
- sdk_1.logger.info(`${constants_1.GENERATOR_NAME}:Registered`);
15
- return {
16
- version,
17
- defaultOutput: '../generated',
18
- prettyName: constants_1.GENERATOR_NAME,
19
- };
20
- },
21
- onGenerate: async (options) => {
22
- const prismaImportStatement = (0, generateImportPrismaStatement_1.generateImportPrismaStatement)(options);
23
- for await (const model of options.dmmf.datamodel.models) {
24
- if (model.documentation &&
25
- model.documentation.includes('generator off')) {
26
- sdk_1.logger.info(`Skipping generation for model ${model.name} as it is marked with 'generator off'.`);
27
- continue;
28
- }
29
- for (const cfg of generateOperation_1.OPERATION_CONFIGS) {
30
- await (0, writeFileSafely_1.writeFileSafely)({
31
- content: (0, generateOperation_1.generateOperationFunction)(cfg, model, prismaImportStatement),
32
- options,
33
- model,
34
- operation: cfg.operation,
35
- });
36
- }
37
- await (0, writeFileSafely_1.writeFileSafely)({
38
- content: (0, generateRouteFile_1.generateRouterFunction)({ model }),
39
- options,
40
- model,
41
- operation: 'index',
42
- });
43
- }
44
- await (0, copyFiles_1.copyFiles)(options);
45
- },
46
- });
47
- //# sourceMappingURL=generator.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"generator.js","sourceRoot":"","sources":["../src/generator.ts"],"names":[],"mappings":";;AAAA,+DAA6E;AAC7E,qCAAoC;AACpC,2CAA4C;AAC5C,6DAAyD;AACzD,2FAAuF;AACvF,mEAAoE;AACpE,mEAA0F;AAC1F,iDAA6C;AAE7C,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAA;AAE9C,IAAA,mCAAgB,EAAC;IACf,UAAU;QACR,YAAM,CAAC,IAAI,CAAC,GAAG,0BAAc,aAAa,CAAC,CAAA;QAC3C,OAAO;YACL,OAAO;YACP,aAAa,EAAE,cAAc;YAC7B,UAAU,EAAE,0BAAc;SAC3B,CAAA;IACH,CAAC;IACD,UAAU,EAAE,KAAK,EAAE,OAAyB,EAAE,EAAE;QAC9C,MAAM,qBAAqB,GAAG,IAAA,6DAA6B,EAAC,OAAO,CAAC,CAAA;QAEpE,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC;YACxD,IACE,KAAK,CAAC,aAAa;gBACnB,KAAK,CAAC,aAAa,CAAC,QAAQ,CAAC,eAAe,CAAC,EAC7C,CAAC;gBACD,YAAM,CAAC,IAAI,CACT,iCAAiC,KAAK,CAAC,IAAI,wCAAwC,CACpF,CAAA;gBACD,SAAQ;YACV,CAAC;YAED,KAAK,MAAM,GAAG,IAAI,qCAAiB,EAAE,CAAC;gBACpC,MAAM,IAAA,iCAAe,EAAC;oBACpB,OAAO,EAAE,IAAA,6CAAyB,EAAC,GAAG,EAAE,KAAK,EAAE,qBAAqB,CAAC;oBACrE,OAAO;oBACP,KAAK;oBACL,SAAS,EAAE,GAAG,CAAC,SAAS;iBACzB,CAAC,CAAA;YACJ,CAAC;YAED,MAAM,IAAA,iCAAe,EAAC;gBACpB,OAAO,EAAE,IAAA,0CAAsB,EAAC,EAAE,KAAK,EAAE,CAAC;gBAC1C,OAAO;gBACP,KAAK;gBACL,SAAS,EAAE,OAAO;aACnB,CAAC,CAAA;QACJ,CAAC;QAED,MAAM,IAAA,qBAAS,EAAC,OAAO,CAAC,CAAA;IAC1B,CAAC;CACF,CAAC,CAAA"}
@@ -1,25 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.generateImportPrismaStatement = generateImportPrismaStatement;
7
- const path_1 = __importDefault(require("path"));
8
- function getImportGeneratorOptions(options) {
9
- var _a, _b;
10
- const clientGenerator = options.otherGenerators.find((gen) => gen.name === 'client');
11
- if (!clientGenerator || !((_a = clientGenerator.output) === null || _a === void 0 ? void 0 : _a.value)) {
12
- throw new Error('Prisma client generator not found.');
13
- }
14
- const modelDirPath = path_1.default.join((_b = options.generator.output) === null || _b === void 0 ? void 0 : _b.value, 'modelFolder');
15
- const clientOutputPath = clientGenerator.output.value;
16
- const relativeImportPath = path_1.default.relative(modelDirPath, clientOutputPath);
17
- return {
18
- outputPath: relativeImportPath.split(path_1.default.sep).join(path_1.default.posix.sep),
19
- };
20
- }
21
- function generateImportPrismaStatement(generatorOptions) {
22
- const options = getImportGeneratorOptions(generatorOptions);
23
- return `import type { Prisma } from '${options.outputPath}';\nimport type { PrismaClient } from '${options.outputPath}';\n`;
24
- }
25
- //# sourceMappingURL=generateImportPrismaStatement.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"generateImportPrismaStatement.js","sourceRoot":"","sources":["../../src/helpers/generateImportPrismaStatement.ts"],"names":[],"mappings":";;;;;AA+BA,sEAMC;AApCD,gDAAuB;AAMvB,SAAS,yBAAyB,CAChC,OAAyB;;IAEzB,MAAM,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,IAAI,CAClD,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,QAAQ,CAC/B,CAAA;IAED,IAAI,CAAC,eAAe,IAAI,CAAC,CAAA,MAAA,eAAe,CAAC,MAAM,0CAAE,KAAK,CAAA,EAAE,CAAC;QACvD,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAA;IACvD,CAAC;IAED,MAAM,YAAY,GAAG,cAAI,CAAC,IAAI,CAC5B,MAAA,OAAO,CAAC,SAAS,CAAC,MAAM,0CAAE,KAAM,EAChC,aAAa,CACd,CAAA;IACD,MAAM,gBAAgB,GAAG,eAAe,CAAC,MAAM,CAAC,KAAK,CAAA;IAErD,MAAM,kBAAkB,GAAG,cAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAA;IAExE,OAAO;QACL,UAAU,EAAE,kBAAkB,CAAC,KAAK,CAAC,cAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,cAAI,CAAC,KAAK,CAAC,GAAG,CAAC;KACpE,CAAA;AACH,CAAC;AAED,SAAgB,6BAA6B,CAC3C,gBAAkC;IAElC,MAAM,OAAO,GAAG,yBAAyB,CAAC,gBAAgB,CAAC,CAAA;IAE3D,OAAO,gCAAgC,OAAO,CAAC,UAAU,0CAA0C,OAAO,CAAC,UAAU,MAAM,CAAA;AAC7H,CAAC"}