@innovixx/prisma-typed-json-generator 0.0.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) Innovixx Digital Limited
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # prisma-typed-json-generator
2
+
3
+ A Prisma generator that automatically creates TypeScript types for your `Json` fields with `@type()` annotations, and patches the generated Prisma Client types to use your custom types.
4
+
5
+ ## Features
6
+ - Extracts custom types from commented blocks in your Prisma schema.
7
+ - Generates a `prisma-json.types.ts` file in your Prisma Client output directory.
8
+ - Patches the generated `index.d.ts` to use your custom types for annotated `Json` fields, using a namespace import to avoid type name clashes.
9
+ - Context-aware: only patches the correct field in the correct model, even if multiple models use the same field name.
10
+
11
+ ## Usage
12
+
13
+ 1. Add the generator to your `schema.prisma`:
14
+
15
+ ```
16
+ generator client {
17
+ provider = "prisma-client-js"
18
+ output = "./client"
19
+ }
20
+
21
+ generator prisma_types_json_generator {
22
+ provider = "prisma-typed-json-generator"
23
+ output = "../types"
24
+ }
25
+ ```
26
+
27
+ 2. Annotate your `Json` fields with `@type()` and define your types in comments:
28
+
29
+ ```
30
+ // type Address {
31
+ // street string
32
+ // city string
33
+ // country string
34
+ // }
35
+
36
+ model User {
37
+ id Int @id @default(autoincrement())
38
+ email String @unique
39
+ name String?
40
+ address Json // @type(Address)
41
+ }
42
+ ```
43
+
44
+ 3. Run `prisma generate`:
45
+
46
+ ```
47
+ npx prisma generate
48
+ ```
49
+
50
+ 4. The generator will:
51
+ - Create `prisma-json.types.ts` in your client output directory.
52
+ - Patch `index.d.ts` to use `PrismaJsonTypes.Address` for the `address` field in the `User` model.
53
+
54
+ ## Why?
55
+ Prisma's `Json` fields are typed as `Prisma.JsonValue` by default, which is not type-safe. This generator lets you use your own types for better safety and DX.
56
+
57
+ ## License
58
+ MIT
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import '../index.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/bin/index.ts"],"names":[],"mappings":";AACA,OAAO,aAAa,CAAA","sourcesContent":["#!/usr/bin/env node\nimport '../index.js'\n"]}
package/dist/index.js ADDED
@@ -0,0 +1,131 @@
1
+ function extractJsonTypeAnnotations(schemaContent) {
2
+ const result = {};
3
+ const modelRegex = /model\s+([A-Za-z0-9_]+)\s*\{([\s\S]*?)\}/g;
4
+ let modelMatch;
5
+ while ((modelMatch = modelRegex.exec(schemaContent)) !== null) {
6
+ const modelName = modelMatch[1];
7
+ const body = modelMatch[2];
8
+ for (const line of body.split('\n')) {
9
+ const fieldMatch = /^\s*([A-Za-z0-9_]+)\s+Json.*@type\(([^)]+)\)/.exec(line);
10
+ if (fieldMatch) {
11
+ const fieldName = fieldMatch[1];
12
+ const typeName = fieldMatch[2];
13
+ result[`${modelName}.${fieldName}`] = typeName;
14
+ }
15
+ }
16
+ }
17
+ return result;
18
+ }
19
+ import generatorHelper from '@prisma/generator-helper';
20
+ import internals from '@prisma/internals';
21
+ import path from 'path';
22
+ import pkg from '../package.json' with { type: "json" };
23
+ import fs from 'fs';
24
+ export function extractCommentedTypes(schemaContent) {
25
+ const commentedTypeBlocks = [];
26
+ const typeBlockRegex = /\/\/\s*type\s+([A-Za-z0-9_]+)\s*\{([\s\S]*?)\}/g;
27
+ let match;
28
+ while ((match = typeBlockRegex.exec(schemaContent)) !== null) {
29
+ commentedTypeBlocks.push(match[0]);
30
+ }
31
+ const typeObjects = {};
32
+ for (const block of commentedTypeBlocks) {
33
+ const headerMatch = /type\s+([A-Za-z0-9_]+)\s*\{([\s\S]*?)\}/.exec(block);
34
+ if (!headerMatch)
35
+ continue;
36
+ const typeName = headerMatch[1];
37
+ const body = headerMatch[2];
38
+ const fields = {};
39
+ for (const line of body.split('\n')) {
40
+ const cleaned = line.replace(/^\s*\/\//, '').trim();
41
+ if (!cleaned)
42
+ continue;
43
+ const fieldMatch = /^([A-Za-z0-9_]+)\s+([A-Za-z0-9_\[\]?]+)$/.exec(cleaned);
44
+ if (fieldMatch) {
45
+ fields[fieldMatch[1]] = fieldMatch[2];
46
+ }
47
+ }
48
+ typeObjects[typeName] = fields;
49
+ }
50
+ return typeObjects;
51
+ }
52
+ export async function writeTypesFile(typeObjects, clientDir) {
53
+ let typeFileContent = '// This file is auto-generated by prisma-typed-json-generator\n\n';
54
+ for (const [typeName, fields] of Object.entries(typeObjects)) {
55
+ typeFileContent += `export type ${typeName} = {\n`;
56
+ for (const [field, type] of Object.entries(fields)) {
57
+ let tsType = type
58
+ .replace(/^string$/i, 'string')
59
+ .replace(/^int$/i, 'number')
60
+ .replace(/^float$/i, 'number')
61
+ .replace(/^boolean$/i, 'boolean')
62
+ .replace(/^json$/i, 'any')
63
+ .replace(/\?$/, ' | null')
64
+ .replace(/\[\]$/, '[]');
65
+ typeFileContent += ` ${field}: ${tsType};\n`;
66
+ }
67
+ typeFileContent += '}\n\n';
68
+ }
69
+ const outputPath = path.join(clientDir, 'prisma-json.types.ts');
70
+ await fs.promises.mkdir(clientDir, { recursive: true });
71
+ await fs.promises.writeFile(outputPath, typeFileContent, 'utf-8');
72
+ return outputPath;
73
+ }
74
+ const { generatorHandler } = generatorHelper;
75
+ const { logger } = internals;
76
+ generatorHandler({
77
+ onManifest() {
78
+ return {
79
+ version: pkg.version,
80
+ defaultOutput: '../generated',
81
+ prettyName: "prisma-typed-json-generator",
82
+ };
83
+ },
84
+ onGenerate: async (options) => {
85
+ logger.info(`prisma-typed-json-generator:Generating...`);
86
+ const schemaFileLocation = options.generator.sourceFilePath;
87
+ const clientGenerator = options.otherGenerators.find((g) => g.name === 'client');
88
+ if (!clientGenerator)
89
+ throw new Error('Prisma Client generator not found. Please ensure that generator Client is specified in your schema.');
90
+ const clientOutput = clientGenerator.output?.value;
91
+ const schemaContent = await fs.promises.readFile(schemaFileLocation, 'utf-8');
92
+ const typeObjects = extractCommentedTypes(schemaContent);
93
+ if (clientOutput) {
94
+ await writeTypesFile(typeObjects, clientOutput);
95
+ }
96
+ if (clientOutput) {
97
+ const indexDtsPath = path.join(clientOutput, 'index.d.ts');
98
+ let indexDtsContent = await fs.promises.readFile(indexDtsPath, 'utf-8');
99
+ let updated = false;
100
+ const jsonTypeAnnotations = extractJsonTypeAnnotations(schemaContent);
101
+ for (const [modelField, typeName] of Object.entries(jsonTypeAnnotations)) {
102
+ const [model, field] = modelField.split('.');
103
+ const payloadBlockRegex = new RegExp(`export type \\$${model}Payload<[^=]+=[^>]+> = {([\\s\\S]*?)}\\n`, 'g');
104
+ indexDtsContent = indexDtsContent.replace(payloadBlockRegex, (block) => {
105
+ const lines = block.split('\n');
106
+ let inScalars = false;
107
+ for (let i = 0; i < lines.length; i++) {
108
+ if (lines[i].includes('scalars: $Extensions.GetPayloadResult<{'))
109
+ inScalars = true;
110
+ if (inScalars && lines[i].includes(`${field}: Prisma.JsonValue`)) {
111
+ lines[i] = lines[i].replace('Prisma.JsonValue', `PrismaJsonTypes.${typeName}`);
112
+ updated = true;
113
+ }
114
+ if (inScalars && lines[i].includes('}, ExtArgs["result"]'))
115
+ inScalars = false;
116
+ }
117
+ return lines.join('\n');
118
+ });
119
+ }
120
+ if (updated) {
121
+ const importLine = `import * as PrismaJsonTypes from './prisma-json.types';`;
122
+ if (!indexDtsContent.includes(importLine)) {
123
+ indexDtsContent = indexDtsContent.replace(/(import .*?;\n)/, `$1${importLine}\n`);
124
+ }
125
+ await fs.promises.writeFile(indexDtsPath, indexDtsContent, 'utf-8');
126
+ }
127
+ }
128
+ logger.info(`prisma-typed-json-generator:Generating...Done`);
129
+ },
130
+ });
131
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["function extractJsonTypeAnnotations(schemaContent: string): Record<string, string> {\n\tconst result: Record<string, string> = {};\n\tconst modelRegex = /model\\s+([A-Za-z0-9_]+)\\s*\\{([\\s\\S]*?)\\}/g;\n\tlet modelMatch;\n\twhile ((modelMatch = modelRegex.exec(schemaContent)) !== null) {\n\t\tconst modelName = modelMatch[1];\n\t\tconst body = modelMatch[2];\n\t\tfor (const line of body.split('\\n')) {\n\t\t\tconst fieldMatch = /^\\s*([A-Za-z0-9_]+)\\s+Json.*@type\\(([^)]+)\\)/.exec(line);\n\t\t\tif (fieldMatch) {\n\t\t\t\tconst fieldName = fieldMatch[1];\n\t\t\t\tconst typeName = fieldMatch[2];\n\t\t\t\tresult[`${modelName}.${fieldName}`] = typeName;\n\t\t\t}\n\t\t}\n\t}\n\treturn result;\n}\nimport generatorHelper, { GeneratorOptions } from '@prisma/generator-helper';\nimport internals from '@prisma/internals'\nimport path from 'path'\nimport pkg from '../package.json' with { type: \"json\" }\nimport fs from 'fs'\n\n\nexport function extractCommentedTypes(schemaContent: string): Record<string, Record<string, string>> {\n\tconst commentedTypeBlocks: string[] = [];\n\tconst typeBlockRegex = /\\/\\/\\s*type\\s+([A-Za-z0-9_]+)\\s*\\{([\\s\\S]*?)\\}/g;\n\tlet match;\n\twhile ((match = typeBlockRegex.exec(schemaContent)) !== null) {\n\t\tcommentedTypeBlocks.push(match[0]);\n\t}\n\tconst typeObjects: Record<string, Record<string, string>> = {};\n\tfor (const block of commentedTypeBlocks) {\n\t\tconst headerMatch = /type\\s+([A-Za-z0-9_]+)\\s*\\{([\\s\\S]*?)\\}/.exec(block);\n\t\tif (!headerMatch) continue;\n\t\tconst typeName = headerMatch[1];\n\t\tconst body = headerMatch[2];\n\t\tconst fields: Record<string, string> = {};\n\t\tfor (const line of body.split('\\n')) {\n\t\t\tconst cleaned = line.replace(/^\\s*\\/\\//, '').trim();\n\t\t\tif (!cleaned) continue;\n\t\t\tconst fieldMatch = /^([A-Za-z0-9_]+)\\s+([A-Za-z0-9_\\[\\]?]+)$/.exec(cleaned);\n\t\t\tif (fieldMatch) {\n\t\t\t\tfields[fieldMatch[1]] = fieldMatch[2];\n\t\t\t}\n\t\t}\n\t\ttypeObjects[typeName] = fields;\n\t}\n\treturn typeObjects;\n}\n\nexport async function writeTypesFile(\n\ttypeObjects: Record<string, Record<string, string>>,\n\tclientDir: string\n) {\n\tlet typeFileContent = '// This file is auto-generated by prisma-typed-json-generator\\n\\n';\n\tfor (const [typeName, fields] of Object.entries(typeObjects)) {\n\t\ttypeFileContent += `export type ${typeName} = {\\n`;\n\t\tfor (const [field, type] of Object.entries(fields)) {\n\t\t\tlet tsType = type\n\t\t\t\t.replace(/^string$/i, 'string')\n\t\t\t\t.replace(/^int$/i, 'number')\n\t\t\t\t.replace(/^float$/i, 'number')\n\t\t\t\t.replace(/^boolean$/i, 'boolean')\n\t\t\t\t.replace(/^json$/i, 'any')\n\t\t\t\t.replace(/\\?$/, ' | null')\n\t\t\t\t.replace(/\\[\\]$/, '[]');\n\t\t\ttypeFileContent += ` ${field}: ${tsType};\\n`;\n\t\t}\n\t\ttypeFileContent += '}\\n\\n';\n\t}\n\tconst outputPath = path.join(clientDir, 'prisma-json.types.ts');\n\tawait fs.promises.mkdir(clientDir, { recursive: true });\n\tawait fs.promises.writeFile(outputPath, typeFileContent, 'utf-8');\n\treturn outputPath;\n}\n\nconst { generatorHandler } = generatorHelper;\nconst { logger } = internals;\n\ngeneratorHandler({\n\tonManifest() {\n\t\treturn {\n\t\t\tversion: pkg.version,\n\t\t\tdefaultOutput: '../generated',\n\t\t\tprettyName: \"prisma-typed-json-generator\",\n\t\t}\n\t},\n\tonGenerate: async (options: GeneratorOptions) => {\n\t\tlogger.info(`prisma-typed-json-generator:Generating...`)\n\n\t\tconst schemaFileLocation = options.generator.sourceFilePath\n\n\t\tconst clientGenerator = options.otherGenerators.find((g) => g.name === 'client')\n\t\tif (!clientGenerator) throw new Error('Prisma Client generator not found. Please ensure that generator Client is specified in your schema.');\n\n\t\tconst clientOutput = clientGenerator.output?.value\n\n\t\tconst schemaContent = await fs.promises.readFile(schemaFileLocation, 'utf-8');\n\t\tconst typeObjects = extractCommentedTypes(schemaContent);\n\n\t\tif (clientOutput) {\n\t\t\tawait writeTypesFile(typeObjects, clientOutput);\n\t\t}\n\n\t\tif (clientOutput) {\n\t\t\tconst indexDtsPath = path.join(clientOutput, 'index.d.ts');\n\t\t\tlet indexDtsContent = await fs.promises.readFile(indexDtsPath, 'utf-8');\n\t\t\tlet updated = false;\n\n\t\t\tconst jsonTypeAnnotations = extractJsonTypeAnnotations(schemaContent);\n\t\t\tfor (const [modelField, typeName] of Object.entries(jsonTypeAnnotations)) {\n\t\t\t\tconst [model, field] = modelField.split('.');\n\t\t\t\tconst payloadBlockRegex = new RegExp(`export type \\\\$${model}Payload<[^=]+=[^>]+> = {([\\\\s\\\\S]*?)}\\\\n`, 'g');\n\t\t\t\tindexDtsContent = indexDtsContent.replace(payloadBlockRegex, (block) => {\n\t\t\t\t\tconst lines = block.split('\\n');\n\t\t\t\t\tlet inScalars = false;\n\t\t\t\t\tfor (let i = 0; i < lines.length; i++) {\n\t\t\t\t\t\tif (lines[i].includes('scalars: $Extensions.GetPayloadResult<{')) inScalars = true;\n\t\t\t\t\t\tif (inScalars && lines[i].includes(`${field}: Prisma.JsonValue`)) {\n\t\t\t\t\t\t\tlines[i] = lines[i].replace('Prisma.JsonValue', `PrismaJsonTypes.${typeName}`);\n\t\t\t\t\t\t\tupdated = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (inScalars && lines[i].includes('}, ExtArgs[\"result\"]')) inScalars = false;\n\t\t\t\t\t}\n\t\t\t\t\treturn lines.join('\\n');\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (updated) {\n\t\t\t\tconst importLine = `import * as PrismaJsonTypes from './prisma-json.types';`;\n\t\t\t\tif (!indexDtsContent.includes(importLine)) {\n\t\t\t\t\tindexDtsContent = indexDtsContent.replace(/(import .*?;\\n)/, `$1${importLine}\\n`);\n\t\t\t\t}\n\t\t\t\tawait fs.promises.writeFile(indexDtsPath, indexDtsContent, 'utf-8');\n\t\t\t}\n\t\t}\n\n\t\tlogger.info(`prisma-typed-json-generator:Generating...Done`)\n\t},\n})\n"]}
@@ -0,0 +1,5 @@
1
+ export const genEnum = ({ name, values }) => {
2
+ const enumValues = values.map(({ name }) => `${name}="${name}"`).join(',\n');
3
+ return `enum ${name} { \n${enumValues}\n }`;
4
+ };
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/getEnum/index.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,EAAE,IAAI,EAAE,MAAM,EAAsB,EAAE,EAAE;IAC/D,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,GAAG,IAAI,KAAK,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAE5E,OAAO,QAAQ,IAAI,QAAQ,UAAU,MAAM,CAAA;AAC5C,CAAC,CAAA","sourcesContent":["import { DMMF } from '@prisma/generator-helper'\n\nexport const genEnum = ({ name, values }: DMMF.DatamodelEnum) => {\n\tconst enumValues = values.map(({ name }) => `${name}=\"${name}\"`).join(',\\n')\n\n\treturn `enum ${name} { \\n${enumValues}\\n }`\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@innovixx/prisma-typed-json-generator",
3
+ "version": "0.0.1",
4
+ "main": "dist/index.js",
5
+ "type": "module",
6
+ "author": "Innovixx <info@innovixx.co.uk>",
7
+ "license": "UNLICENSED",
8
+ "bin": {
9
+ "@innovixx/prisma-typed-json-generator": "dist/bin/index.js"
10
+ },
11
+ "scripts": {
12
+ "dev": "tsx src/index.ts",
13
+ "build": "tsc",
14
+ "lint": "eslint ./src/**/*.{js,jsx,ts,tsx}"
15
+ },
16
+ "dependencies": {
17
+ "@prisma/client": "7.4.2",
18
+ "@prisma/generator-helper": "7.4.2",
19
+ "@prisma/internals": "^7.4.2"
20
+ },
21
+ "devDependencies": {
22
+ "@innovixx/eslint-config": "^3.0.11",
23
+ "prisma": "7.4.2",
24
+ "tsx": "^4.19.1",
25
+ "typescript": "^5.7.3"
26
+ }
27
+ }