@visulima/prisma-dmmf-transformer 1.0.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/CHANGELOG.md ADDED
@@ -0,0 +1,6 @@
1
+ ## @visulima/prisma-dmmf-transformer 1.0.0 (2022-11-15)
2
+
3
+
4
+ ### Features
5
+
6
+ * added new packages for faster api creation ([#14](https://github.com/visulima/visulima/issues/14)) ([eb64fcf](https://github.com/visulima/visulima/commit/eb64fcf33f2a75ea48262ad6e71f80e159a93972))
package/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 visulima
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,276 @@
1
+ <div align="center">
2
+ <h3>Visulima prisma-dmmf-transformer</h3>
3
+ <p>
4
+ Visulima prisma-dmmf-transformer is a generator for <a href="https://www.prisma.io/" title="Prisma">Prisma</a> to generate a valid <a href="https://json-schema.org/specification.html" title="JSON Schema">JSON Schema v7</a>.
5
+
6
+ </p>
7
+ </div>
8
+
9
+ <br />
10
+
11
+ <div align="center">
12
+
13
+ [![typescript-image]][typescript-url] [![npm-image]][npm-url] [![license-image]][license-url]
14
+
15
+ </div>
16
+
17
+ ---
18
+
19
+ <div align="center">
20
+ <p>
21
+ <sup>
22
+ Daniel Bannert's open source work is supported by the community on <a href="https://github.com/sponsors/prisis">GitHub Sponsors</a>
23
+ </sup>
24
+ </p>
25
+ </div>
26
+
27
+ ---
28
+
29
+ ## Features
30
+
31
+ ## Installation
32
+
33
+ ```sh
34
+ npm install @visulima/prisma-dmmf-transformer
35
+ ```
36
+
37
+ ```sh
38
+ yarn add @visulima/prisma-dmmf-transformer
39
+ ```
40
+
41
+ ```sh
42
+ pnpm add @visulima/prisma-dmmf-transformer
43
+ ```
44
+
45
+ ## Usage
46
+
47
+ ```ts
48
+ import { transformDMMF, getJSONSchemaProperty } from "@visulima/prisma-dmmf-transformer";
49
+
50
+ const generator = async (prismaClient) => {
51
+ const dmmf = await prismaClient._getDmmf();
52
+ const schema = transformDMMF(dmmf);
53
+
54
+ console.log(schema);
55
+ };
56
+ ```
57
+
58
+ The generator currently supports a few options as a second argument:
59
+
60
+ | Key | Default Value | Description |
61
+ | ------------------------ | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
62
+ | keepRelationScalarFields | "false" | By default, the JSON Schema that’s generated will output only objects for related model records. If set to "true", this will cause the generator to also output foreign key fields for related records |
63
+ | schemaId | undefined | Add an id to the generated schema. All references will include the schema id |
64
+ | includeRequiredFields | "false" | If this flag is `"true"` all required scalar prisma fields that do not have a default value, will be added to the `required` properties field for that schema definition. |
65
+ | persistOriginalType | "false" | If this flag is `"true"` the original type will be outputed under the property key "originalType" |
66
+
67
+ ## Examples
68
+
69
+ ### PostgreSQL
70
+
71
+ This generator converts a prisma schema like this:
72
+
73
+ ```prisma
74
+ datasource db {
75
+ provider = "postgresql"
76
+ url = env("DATABASE_URL")
77
+ }
78
+
79
+ model User {
80
+ id Int @id @default(autoincrement())
81
+ // Double Slash Comment: It will NOT show up in JSON schema
82
+ createdAt DateTime @default(now())
83
+ /// Triple Slash Comment: It will show up in JSON schema [EMAIL]
84
+ email String @unique
85
+ weight Float?
86
+ is18 Boolean?
87
+ name String?
88
+ number BigInt @default(34534535435353)
89
+ favouriteDecimal Decimal
90
+ bytes Bytes /// Triple Slash Inline Comment: It will show up in JSON schema [BYTES]
91
+ successorId Int? @unique
92
+ successor User? @relation("BlogOwnerHistory", fields: [successorId], references: [id])
93
+ predecessor User? @relation("BlogOwnerHistory")
94
+ role Role @default(USER)
95
+ posts Post[]
96
+ keywords String[]
97
+ biography Json
98
+ }
99
+
100
+ model Post {
101
+ id Int @id @default(autoincrement())
102
+ user User? @relation(fields: [userId], references: [id])
103
+ userId Int?
104
+ }
105
+
106
+ enum Role {
107
+ USER
108
+ ADMIN
109
+ }
110
+ ```
111
+
112
+ Into:
113
+
114
+ ```json5
115
+ {
116
+ $schema: 'http://json-schema.org/draft-07/schema#',
117
+ definitions: {
118
+ Post: {
119
+ properties: {
120
+ id: { type: 'integer' },
121
+ user: {
122
+ anyOf: [
123
+ { $ref: '#/definitions/User' },
124
+ { type: 'null' },
125
+ ],
126
+ },
127
+ },
128
+ type: 'object',
129
+ },
130
+ User: {
131
+ properties: {
132
+ biography: {
133
+ type: [
134
+ 'number',
135
+ 'string',
136
+ 'boolean',
137
+ 'object',
138
+ 'array',
139
+ 'null'
140
+ ],
141
+ },
142
+ createdAt: { format: 'date-time', type: 'string' },
143
+ email: {
144
+ description: 'Triple Slash Comment: Will show up in JSON schema [EMAIL]',
145
+ type: 'string'
146
+ },
147
+ id: { type: 'integer' },
148
+ is18: { type: ['boolean', 'null'] },
149
+ keywords: { items: { type: 'string' }, type: 'array' },
150
+ name: { type: ['string', 'null'] },
151
+ number: { type: 'integer', default: '34534535435353' },
152
+ bytes: {
153
+ description: 'Triple Slash Inline Comment: Will show up in JSON schema [BYTES]',
154
+ type: 'string'
155
+ },
156
+ favouriteDecimal: { type: 'number' },
157
+ posts: {
158
+ items: { $ref: '#/definitions/Post' },
159
+ type: 'array',
160
+ },
161
+ predecessor: {
162
+ anyOf: [
163
+ { $ref: '#/definitions/User' },
164
+ { type: 'null' },
165
+ ],
166
+ },
167
+ role: { enum: ['USER', 'ADMIN'], type: 'string', default: 'USER' },
168
+ successor: {
169
+ anyOf: [
170
+ { $ref: '#/definitions/User' },
171
+ { type: 'null' },
172
+ ],
173
+ },
174
+ weight: { type: ['integer', 'null'] },
175
+ },
176
+ type: 'object',
177
+ },
178
+ },
179
+ properties: {
180
+ post: { $ref: '#/definitions/Post' },
181
+ user: { $ref: '#/definitions/User' },
182
+ },
183
+ type: 'object',
184
+ }
185
+ ```
186
+
187
+ ### MongoDB
188
+
189
+ The generator also takes care of composite types in MongoDB:
190
+
191
+ ```prisma
192
+ datasource db {
193
+ provider = "mongodb"
194
+ url = env("DATABASE_URL")
195
+ }
196
+
197
+ model User {
198
+ id String @id @default(auto()) @map("_id") @db.ObjectId
199
+ photos Photo[]
200
+ }
201
+
202
+ type Photo {
203
+ height Int @default(200)
204
+ width Int @default(100)
205
+ url String
206
+ }
207
+ ```
208
+
209
+ Output:
210
+
211
+ ```json5
212
+ {
213
+ $schema: 'http://json-schema.org/draft-07/schema#',
214
+ definitions: {
215
+ User: {
216
+ properties: {
217
+ id: { type: 'string' },
218
+ photos: {
219
+ items: { $ref: '#/definitions/Photo' },
220
+ type: 'array',
221
+ },
222
+ },
223
+ type: 'object',
224
+ },
225
+ Photo: {
226
+ properties: {
227
+ height: {
228
+ type: 'integer',
229
+ default: 200,
230
+ },
231
+ width: {
232
+ type: 'integer',
233
+ default: 100,
234
+ },
235
+ url: {
236
+ type: 'string',
237
+ },
238
+ },
239
+ type: 'object',
240
+ },
241
+ },
242
+ properties: {
243
+ user: { $ref: '#/definitions/User' },
244
+ },
245
+ type: 'object',
246
+ }
247
+ ```
248
+
249
+ ## Supported Node.js Versions
250
+
251
+ Libraries in this ecosystem make the best effort to track
252
+ [Node.js’ release schedule](https://github.com/nodejs/release#release-schedule). Here’s [a
253
+ post on why we think this is important](https://medium.com/the-node-js-collection/maintainers-should-consider-following-node-js-release-schedule-ab08ed4de71a).
254
+
255
+ ## Contributing
256
+
257
+ If you would like to help take a look at the [list of issues](https://github.com/visulima/visulima/issues) and check our [Contributing](.github/CONTRIBUTING.md) guild.
258
+
259
+ > **Note:** please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.
260
+
261
+ ## Credits
262
+
263
+ - [Valentin Palkovic](https://github.com/valentinpalkovic) and [prisma-json-schema-generator](https://github.com/valentinpalkovic/prisma-json-schema-generator)
264
+ - [Daniel Bannert](https://github.com/prisis)
265
+ - [All Contributors](https://github.com/visulima/visulima/graphs/contributors)
266
+
267
+ ## License
268
+
269
+ The visulima prisma-dmmf-transformer is open-sourced software licensed under the [MIT][license-url]
270
+
271
+ [typescript-image]: https://img.shields.io/badge/Typescript-294E80.svg?style=for-the-badge&logo=typescript
272
+ [typescript-url]: "typescript"
273
+ [license-image]: https://img.shields.io/npm/l/@visulima/prisma-dmmf-transformer?color=blueviolet&style=for-the-badge
274
+ [license-url]: LICENSE.md "license"
275
+ [npm-image]: https://img.shields.io/npm/v/@visulima/prisma-dmmf-transformer/alpha.svg?style=for-the-badge&logo=npm
276
+ [npm-url]: https://www.npmjs.com/package/@visulima/prisma-dmmf-transformer/v/alpha "npm"
@@ -0,0 +1,29 @@
1
+ import { DMMF } from '@prisma/generator-helper';
2
+ import * as json_schema from 'json-schema';
3
+ import { JSONSchema7Definition, JSONSchema7 } from 'json-schema';
4
+
5
+ interface PropertyMetaData {
6
+ required: boolean;
7
+ hasDefaultValue: boolean;
8
+ isScalar: boolean;
9
+ }
10
+
11
+ interface ModelMetaData {
12
+ enums: DMMF.DatamodelEnum[];
13
+ }
14
+
15
+ type DefinitionMap = [name: string, definition: JSONSchema7Definition];
16
+ type PropertyMap = [...DefinitionMap, PropertyMetaData];
17
+
18
+ interface TransformOptions {
19
+ keepRelationScalarFields?: "true" | "false";
20
+ schemaId?: string;
21
+ includeRequiredFields?: "true" | "false";
22
+ persistOriginalType?: "true" | "false";
23
+ }
24
+
25
+ declare const transformDmmf: (dmmf: DMMF.Document, transformOptions?: TransformOptions) => JSONSchema7;
26
+
27
+ declare const getJSONSchemaProperty: (modelMetaData: ModelMetaData, transformOptions: TransformOptions) => (field: DMMF.Field) => [string, json_schema.JSONSchema7Definition, PropertyMetaData];
28
+
29
+ export { DefinitionMap, ModelMetaData, PropertyMap, PropertyMetaData, TransformOptions, getJSONSchemaProperty, transformDmmf as transformDMMF };
package/dist/index.js ADDED
@@ -0,0 +1,218 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }// src/properties.ts
2
+ var _assert = require('assert'); var _assert2 = _interopRequireDefault(_assert);
3
+ function isDefined(value) {
4
+ return value !== void 0 && value !== null;
5
+ }
6
+ var getJSONSchemaScalar = (fieldType) => {
7
+ switch (fieldType) {
8
+ case "Int":
9
+ case "BigInt": {
10
+ return "integer";
11
+ }
12
+ case "DateTime":
13
+ case "Bytes":
14
+ case "String": {
15
+ return "string";
16
+ }
17
+ case "Float":
18
+ case "Decimal": {
19
+ return "number";
20
+ }
21
+ case "Json": {
22
+ return ["number", "string", "boolean", "object", "array", "null"];
23
+ }
24
+ case "Boolean": {
25
+ return "boolean";
26
+ }
27
+ default: {
28
+ throw new Error(`Unhandled discriminated union member: ${JSON.stringify(fieldType)}`);
29
+ }
30
+ }
31
+ };
32
+ var getJSONSchemaType = (field) => {
33
+ const {
34
+ isList,
35
+ isRequired,
36
+ kind,
37
+ type
38
+ } = field;
39
+ let scalarFieldType = "object";
40
+ if (kind === "scalar" && !isList) {
41
+ scalarFieldType = getJSONSchemaScalar(type);
42
+ } else if (isList) {
43
+ scalarFieldType = "array";
44
+ } else if (kind === "enum") {
45
+ scalarFieldType = "string";
46
+ }
47
+ if (isRequired || isList) {
48
+ return scalarFieldType;
49
+ }
50
+ const isFieldUnion = Array.isArray(scalarFieldType);
51
+ if (isFieldUnion) {
52
+ return [.../* @__PURE__ */ new Set([...scalarFieldType, "null"])];
53
+ }
54
+ return [scalarFieldType, "null"];
55
+ };
56
+ var getDefaultValue = (field) => {
57
+ const fieldDefault = field.default;
58
+ if (!field.hasDefaultValue) {
59
+ return null;
60
+ }
61
+ if (field.kind === "enum") {
62
+ return typeof fieldDefault === "string" ? fieldDefault : null;
63
+ }
64
+ if (field.kind !== "scalar") {
65
+ return null;
66
+ }
67
+ switch (field.type) {
68
+ case "String":
69
+ case "BigInt":
70
+ case "DateTime": {
71
+ return typeof fieldDefault === "string" ? fieldDefault : null;
72
+ }
73
+ case "Int":
74
+ case "Float":
75
+ case "Decimal": {
76
+ return typeof fieldDefault === "number" ? fieldDefault : null;
77
+ }
78
+ case "Boolean": {
79
+ return typeof fieldDefault === "boolean" ? fieldDefault : null;
80
+ }
81
+ case "Json":
82
+ case "Bytes": {
83
+ return null;
84
+ }
85
+ default: {
86
+ throw new Error(`Unhandled discriminated union member: ${JSON.stringify(field.type)}`);
87
+ }
88
+ }
89
+ };
90
+ var getFormatByDMMFType = (fieldType) => {
91
+ if (fieldType === "DateTime") {
92
+ return "date-time";
93
+ }
94
+ return void 0;
95
+ };
96
+ var getJSONSchemaForPropertyReference = (field, { schemaId, persistOriginalType }) => {
97
+ const notNullable = field.isRequired || field.isList;
98
+ _assert2.default.equal(typeof field.type, "string");
99
+ const typeReference = `#/definitions/${field.type}`;
100
+ const reference = { $ref: schemaId ? `${schemaId}${typeReference}` : typeReference };
101
+ return notNullable ? reference : {
102
+ anyOf: [reference, { type: "null" }],
103
+ ...persistOriginalType && {
104
+ originalType: field.type
105
+ }
106
+ };
107
+ };
108
+ var getItemsByDMMFType = (field, transformOptions) => {
109
+ if (field.kind === "scalar" && !field.isList || field.kind === "enum") {
110
+ return void 0;
111
+ }
112
+ if (field.kind === "scalar" && field.isList) {
113
+ return { type: getJSONSchemaScalar(field.type) };
114
+ }
115
+ return getJSONSchemaForPropertyReference(field, transformOptions);
116
+ };
117
+ var isSingleReference = (field) => field.kind !== "scalar" && !field.isList && field.kind !== "enum";
118
+ var getEnumListByDMMFType = (modelMetaData) => (field) => {
119
+ const enumItem = modelMetaData.enums.find(({ name }) => name === field.type);
120
+ if (!enumItem) {
121
+ return void 0;
122
+ }
123
+ return enumItem.values.map((item) => item.name);
124
+ };
125
+ var getDescription = (field) => field.documentation;
126
+ var getPropertyDefinition = (modelMetaData, transformOptions, field) => {
127
+ const type = getJSONSchemaType(field);
128
+ const format = getFormatByDMMFType(field.type);
129
+ const items = getItemsByDMMFType(field, transformOptions);
130
+ const enumList = getEnumListByDMMFType(modelMetaData)(field);
131
+ const defaultValue = getDefaultValue(field);
132
+ const description = getDescription(field);
133
+ return {
134
+ type,
135
+ ...transformOptions.persistOriginalType && {
136
+ originalType: field.type
137
+ },
138
+ ...isDefined(defaultValue) && { default: defaultValue },
139
+ ...isDefined(format) && { format },
140
+ ...isDefined(items) && { items },
141
+ ...isDefined(enumList) && { enum: enumList },
142
+ ...isDefined(description) && { description }
143
+ };
144
+ };
145
+ var getJSONSchemaProperty = (modelMetaData, transformOptions) => (field) => {
146
+ const propertyMetaData = {
147
+ required: field.isRequired,
148
+ hasDefaultValue: field.hasDefaultValue,
149
+ isScalar: field.kind === "scalar" || field.kind === "enum"
150
+ };
151
+ const property = isSingleReference(field) ? getJSONSchemaForPropertyReference(field, transformOptions) : getPropertyDefinition(modelMetaData, transformOptions, field);
152
+ return [field.name, property, propertyMetaData];
153
+ };
154
+ var properties_default = getJSONSchemaProperty;
155
+
156
+ // src/model.ts
157
+ function getRelationScalarFields(model) {
158
+ return model.fields.flatMap((field) => field.relationFromFields || []);
159
+ }
160
+ var getJSONSchemaModel = (modelMetaData, transformOptions) => (model) => {
161
+ const definitionPropertiesMap = model.fields.map(properties_default(modelMetaData, transformOptions));
162
+ const propertiesMap = definitionPropertiesMap.map(([name, definition2]) => [name, definition2]);
163
+ const relationScalarFields = getRelationScalarFields(model);
164
+ const propertiesWithoutRelationScalars = propertiesMap.filter((property) => !relationScalarFields.includes(property[0]));
165
+ const properties = Object.fromEntries((transformOptions == null ? void 0 : transformOptions.keepRelationScalarFields) === "true" ? propertiesMap : propertiesWithoutRelationScalars);
166
+ const definition = {
167
+ type: "object",
168
+ properties
169
+ };
170
+ if (transformOptions.includeRequiredFields) {
171
+ definition.required = definitionPropertiesMap.reduce((filtered, [name, , fieldMetaData]) => {
172
+ if (fieldMetaData.required && fieldMetaData.isScalar && !fieldMetaData.hasDefaultValue) {
173
+ filtered.push(name);
174
+ }
175
+ return filtered;
176
+ }, []);
177
+ }
178
+ return [model.name, definition];
179
+ };
180
+ var model_default = getJSONSchemaModel;
181
+
182
+ // src/transform-dmmf.ts
183
+ var toCamelCase = (name) => name.slice(0, 1).toLowerCase() + name.slice(1);
184
+ var getPropertyDefinition2 = ({ schemaId }) => (model) => {
185
+ const reference = `#/definitions/${model.name}`;
186
+ return [
187
+ toCamelCase(model.name),
188
+ {
189
+ $ref: schemaId ? `${schemaId}${reference}` : reference
190
+ }
191
+ ];
192
+ };
193
+ var transformDmmf = (dmmf, transformOptions = {}) => {
194
+ const { models = [], enums = [], types = [] } = dmmf.datamodel;
195
+ const initialJSON = {
196
+ $schema: "http://json-schema.org/draft-07/schema#",
197
+ definitions: {},
198
+ type: "object"
199
+ };
200
+ const { schemaId } = transformOptions;
201
+ const modelDefinitionsMap = models.map(model_default({ enums }, transformOptions));
202
+ const typeDefinitionsMap = types.map(model_default({ enums }, transformOptions));
203
+ const modelPropertyDefinitionsMap = models.map(getPropertyDefinition2(transformOptions));
204
+ const definitions = Object.fromEntries([...modelDefinitionsMap, ...typeDefinitionsMap]);
205
+ const properties = Object.fromEntries(modelPropertyDefinitionsMap);
206
+ return {
207
+ ...schemaId ? { $id: schemaId } : null,
208
+ ...initialJSON,
209
+ definitions,
210
+ properties
211
+ };
212
+ };
213
+ var transform_dmmf_default = transformDmmf;
214
+
215
+
216
+
217
+ exports.getJSONSchemaProperty = properties_default; exports.transformDMMF = transform_dmmf_default;
218
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/properties.ts","../src/model.ts","../src/transform-dmmf.ts"],"names":["definition","getPropertyDefinition"],"mappings":"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","sourcesContent":["import type { DMMF } from \"@prisma/generator-helper\";\nimport type { JSONSchema7, JSONSchema7TypeName } from \"json-schema\";\nimport assert from \"node:assert\";\n\nimport type {\n ModelMetaData, PrismaPrimitive, PropertyMap, PropertyMetaData, TransformOptions,\n} from \"./types.d\";\n\nfunction isDefined<T>(value: T | undefined | null): value is T {\n return value !== undefined && value !== null;\n}\n\nconst getJSONSchemaScalar = (fieldType: PrismaPrimitive): JSONSchema7TypeName | Array<JSONSchema7TypeName> => {\n switch (fieldType) {\n case \"Int\":\n case \"BigInt\": {\n return \"integer\";\n }\n case \"DateTime\":\n case \"Bytes\":\n case \"String\": {\n return \"string\";\n }\n case \"Float\":\n case \"Decimal\": {\n return \"number\";\n }\n case \"Json\": {\n return [\"number\", \"string\", \"boolean\", \"object\", \"array\", \"null\"];\n }\n case \"Boolean\": {\n return \"boolean\";\n }\n default: {\n throw new Error(`Unhandled discriminated union member: ${JSON.stringify(fieldType)}`);\n }\n }\n};\n\nconst getJSONSchemaType = (field: DMMF.Field): JSONSchema7[\"type\"] => {\n const {\n isList, isRequired, kind, type,\n } = field;\n\n let scalarFieldType: JSONSchema7[\"type\"] = \"object\";\n\n if (kind === \"scalar\" && !isList) {\n scalarFieldType = getJSONSchemaScalar(type as PrismaPrimitive);\n } else if (isList) {\n scalarFieldType = \"array\";\n } else if (kind === \"enum\") {\n scalarFieldType = \"string\";\n }\n\n if (isRequired || isList) {\n return scalarFieldType;\n }\n\n const isFieldUnion = Array.isArray(scalarFieldType);\n\n if (isFieldUnion) {\n return [...new Set([...scalarFieldType, \"null\"])] as JSONSchema7[\"type\"];\n }\n\n return [scalarFieldType as JSONSchema7TypeName, \"null\"];\n};\n\nconst getDefaultValue = (field: DMMF.Field): JSONSchema7[\"default\"] => {\n const fieldDefault = field.default;\n\n if (!field.hasDefaultValue) {\n return null;\n }\n\n if (field.kind === \"enum\") {\n return typeof fieldDefault === \"string\" ? fieldDefault : null;\n }\n\n if (field.kind !== \"scalar\") {\n return null;\n }\n\n switch (field.type) {\n case \"String\":\n case \"BigInt\":\n case \"DateTime\": {\n return typeof fieldDefault === \"string\" ? fieldDefault : null;\n }\n case \"Int\":\n case \"Float\":\n case \"Decimal\": {\n return typeof fieldDefault === \"number\" ? fieldDefault : null;\n }\n case \"Boolean\": {\n return typeof fieldDefault === \"boolean\" ? fieldDefault : null;\n }\n case \"Json\":\n case \"Bytes\": {\n return null;\n }\n default: {\n throw new Error(`Unhandled discriminated union member: ${JSON.stringify(field.type)}`);\n }\n }\n};\n\nconst getFormatByDMMFType = (fieldType: DMMF.Field[\"type\"]): string | undefined => {\n if (fieldType === \"DateTime\") {\n return \"date-time\";\n }\n\n return undefined;\n};\n\nconst getJSONSchemaForPropertyReference = (field: DMMF.Field, { schemaId, persistOriginalType }: TransformOptions): JSONSchema7 => {\n const notNullable = field.isRequired || field.isList;\n\n assert.equal(typeof field.type, \"string\");\n\n const typeReference = `#/definitions/${field.type}`;\n const reference = { $ref: schemaId ? `${schemaId}${typeReference}` : typeReference };\n\n return notNullable\n ? reference\n : {\n anyOf: [reference, { type: \"null\" }],\n ...(persistOriginalType && {\n originalType: field.type,\n }),\n };\n};\n\nconst getItemsByDMMFType = (field: DMMF.Field, transformOptions: TransformOptions): JSONSchema7[\"items\"] => {\n if ((field.kind === \"scalar\" && !field.isList) || field.kind === \"enum\") {\n return undefined;\n }\n\n if (field.kind === \"scalar\" && field.isList) {\n return { type: getJSONSchemaScalar(field.type as PrismaPrimitive) };\n }\n\n return getJSONSchemaForPropertyReference(field, transformOptions);\n};\n\nconst isSingleReference = (field: DMMF.Field) => field.kind !== \"scalar\" && !field.isList && field.kind !== \"enum\";\n\nconst getEnumListByDMMFType = (modelMetaData: ModelMetaData) => (field: DMMF.Field): string[] | undefined => {\n const enumItem = modelMetaData.enums.find(({ name }) => name === field.type);\n\n if (!enumItem) {\n return undefined;\n }\n\n return enumItem.values.map((item) => item.name);\n};\n\nconst getDescription = (field: DMMF.Field) => field.documentation;\n\nconst getPropertyDefinition = (modelMetaData: ModelMetaData, transformOptions: TransformOptions, field: DMMF.Field) => {\n const type = getJSONSchemaType(field);\n const format = getFormatByDMMFType(field.type);\n const items = getItemsByDMMFType(field, transformOptions);\n const enumList = getEnumListByDMMFType(modelMetaData)(field);\n const defaultValue = getDefaultValue(field);\n const description = getDescription(field);\n\n return {\n type,\n ...(transformOptions.persistOriginalType && {\n originalType: field.type,\n }),\n ...(isDefined(defaultValue) && { default: defaultValue }),\n ...(isDefined(format) && { format }),\n ...(isDefined(items) && { items }),\n ...(isDefined(enumList) && { enum: enumList }),\n ...(isDefined(description) && { description }),\n };\n};\n\nconst getJSONSchemaProperty = (modelMetaData: ModelMetaData, transformOptions: TransformOptions) => (field: DMMF.Field): PropertyMap => {\n const propertyMetaData: PropertyMetaData = {\n required: field.isRequired,\n hasDefaultValue: field.hasDefaultValue,\n isScalar: field.kind === \"scalar\" || field.kind === \"enum\",\n };\n\n const property = isSingleReference(field)\n ? getJSONSchemaForPropertyReference(field, transformOptions)\n : getPropertyDefinition(modelMetaData, transformOptions, field);\n\n return [field.name, property, propertyMetaData];\n};\n\nexport default getJSONSchemaProperty;\n","import type { DMMF } from \"@prisma/generator-helper\";\nimport type { JSONSchema7Definition } from \"json-schema\";\n\nimport getJSONSchemaProperty from \"./properties\";\nimport type { DefinitionMap, ModelMetaData, TransformOptions } from \"./types.d\";\n\nfunction getRelationScalarFields(model: DMMF.Model): string[] {\n return model.fields.flatMap((field) => field.relationFromFields || []);\n}\n\nconst getJSONSchemaModel = (modelMetaData: ModelMetaData, transformOptions: TransformOptions) => (model: DMMF.Model): DefinitionMap => {\n const definitionPropertiesMap = model.fields.map(getJSONSchemaProperty(modelMetaData, transformOptions));\n\n const propertiesMap = definitionPropertiesMap.map(([name, definition]) => [name, definition] as DefinitionMap);\n const relationScalarFields = getRelationScalarFields(model);\n const propertiesWithoutRelationScalars = propertiesMap.filter((property) => !relationScalarFields.includes(property[0]));\n\n const properties = Object.fromEntries(transformOptions?.keepRelationScalarFields === \"true\" ? propertiesMap : propertiesWithoutRelationScalars);\n\n const definition: JSONSchema7Definition = {\n type: \"object\",\n properties,\n };\n\n if (transformOptions.includeRequiredFields) {\n definition.required = definitionPropertiesMap.reduce((filtered: string[], [name, , fieldMetaData]) => {\n if (fieldMetaData.required && fieldMetaData.isScalar && !fieldMetaData.hasDefaultValue) {\n filtered.push(name);\n }\n return filtered;\n }, []);\n }\n\n return [model.name, definition];\n};\n\nexport default getJSONSchemaModel;\n","import type { DMMF } from \"@prisma/generator-helper\";\nimport type { JSONSchema7, JSONSchema7Definition } from \"json-schema\";\n\nimport getJSONSchemaModel from \"./model\";\nimport type { TransformOptions } from \"./types.d\";\n\nconst toCamelCase = (name: string): string => name.slice(0, 1).toLowerCase() + name.slice(1);\n\nconst getPropertyDefinition = ({ schemaId }: TransformOptions) => (model: DMMF.Model): [name: string, reference: JSONSchema7Definition] => {\n const reference = `#/definitions/${model.name}`;\n\n return [\n toCamelCase(model.name),\n {\n $ref: schemaId ? `${schemaId}${reference}` : reference,\n },\n ];\n};\n\nconst transformDmmf = (dmmf: DMMF.Document, transformOptions: TransformOptions = {}): JSONSchema7 => {\n // TODO: Remove default values as soon as prisma version < 3.10.0 doesn't have to be supported anymore\n const { models = [], enums = [], types = [] } = dmmf.datamodel;\n const initialJSON = {\n $schema: \"http://json-schema.org/draft-07/schema#\",\n definitions: {},\n type: \"object\",\n } as JSONSchema7;\n const { schemaId } = transformOptions;\n\n const modelDefinitionsMap = models.map(getJSONSchemaModel({ enums }, transformOptions));\n const typeDefinitionsMap = types.map(getJSONSchemaModel({ enums }, transformOptions));\n const modelPropertyDefinitionsMap = models.map(getPropertyDefinition(transformOptions));\n const definitions = Object.fromEntries([...modelDefinitionsMap, ...typeDefinitionsMap]);\n const properties = Object.fromEntries(modelPropertyDefinitionsMap);\n\n return {\n ...(schemaId ? { $id: schemaId } : null),\n ...initialJSON,\n definitions,\n properties,\n };\n};\n\nexport default transformDmmf;\n"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,218 @@
1
+ // src/properties.ts
2
+ import assert from "assert";
3
+ function isDefined(value) {
4
+ return value !== void 0 && value !== null;
5
+ }
6
+ var getJSONSchemaScalar = (fieldType) => {
7
+ switch (fieldType) {
8
+ case "Int":
9
+ case "BigInt": {
10
+ return "integer";
11
+ }
12
+ case "DateTime":
13
+ case "Bytes":
14
+ case "String": {
15
+ return "string";
16
+ }
17
+ case "Float":
18
+ case "Decimal": {
19
+ return "number";
20
+ }
21
+ case "Json": {
22
+ return ["number", "string", "boolean", "object", "array", "null"];
23
+ }
24
+ case "Boolean": {
25
+ return "boolean";
26
+ }
27
+ default: {
28
+ throw new Error(`Unhandled discriminated union member: ${JSON.stringify(fieldType)}`);
29
+ }
30
+ }
31
+ };
32
+ var getJSONSchemaType = (field) => {
33
+ const {
34
+ isList,
35
+ isRequired,
36
+ kind,
37
+ type
38
+ } = field;
39
+ let scalarFieldType = "object";
40
+ if (kind === "scalar" && !isList) {
41
+ scalarFieldType = getJSONSchemaScalar(type);
42
+ } else if (isList) {
43
+ scalarFieldType = "array";
44
+ } else if (kind === "enum") {
45
+ scalarFieldType = "string";
46
+ }
47
+ if (isRequired || isList) {
48
+ return scalarFieldType;
49
+ }
50
+ const isFieldUnion = Array.isArray(scalarFieldType);
51
+ if (isFieldUnion) {
52
+ return [.../* @__PURE__ */ new Set([...scalarFieldType, "null"])];
53
+ }
54
+ return [scalarFieldType, "null"];
55
+ };
56
+ var getDefaultValue = (field) => {
57
+ const fieldDefault = field.default;
58
+ if (!field.hasDefaultValue) {
59
+ return null;
60
+ }
61
+ if (field.kind === "enum") {
62
+ return typeof fieldDefault === "string" ? fieldDefault : null;
63
+ }
64
+ if (field.kind !== "scalar") {
65
+ return null;
66
+ }
67
+ switch (field.type) {
68
+ case "String":
69
+ case "BigInt":
70
+ case "DateTime": {
71
+ return typeof fieldDefault === "string" ? fieldDefault : null;
72
+ }
73
+ case "Int":
74
+ case "Float":
75
+ case "Decimal": {
76
+ return typeof fieldDefault === "number" ? fieldDefault : null;
77
+ }
78
+ case "Boolean": {
79
+ return typeof fieldDefault === "boolean" ? fieldDefault : null;
80
+ }
81
+ case "Json":
82
+ case "Bytes": {
83
+ return null;
84
+ }
85
+ default: {
86
+ throw new Error(`Unhandled discriminated union member: ${JSON.stringify(field.type)}`);
87
+ }
88
+ }
89
+ };
90
+ var getFormatByDMMFType = (fieldType) => {
91
+ if (fieldType === "DateTime") {
92
+ return "date-time";
93
+ }
94
+ return void 0;
95
+ };
96
+ var getJSONSchemaForPropertyReference = (field, { schemaId, persistOriginalType }) => {
97
+ const notNullable = field.isRequired || field.isList;
98
+ assert.equal(typeof field.type, "string");
99
+ const typeReference = `#/definitions/${field.type}`;
100
+ const reference = { $ref: schemaId ? `${schemaId}${typeReference}` : typeReference };
101
+ return notNullable ? reference : {
102
+ anyOf: [reference, { type: "null" }],
103
+ ...persistOriginalType && {
104
+ originalType: field.type
105
+ }
106
+ };
107
+ };
108
+ var getItemsByDMMFType = (field, transformOptions) => {
109
+ if (field.kind === "scalar" && !field.isList || field.kind === "enum") {
110
+ return void 0;
111
+ }
112
+ if (field.kind === "scalar" && field.isList) {
113
+ return { type: getJSONSchemaScalar(field.type) };
114
+ }
115
+ return getJSONSchemaForPropertyReference(field, transformOptions);
116
+ };
117
+ var isSingleReference = (field) => field.kind !== "scalar" && !field.isList && field.kind !== "enum";
118
+ var getEnumListByDMMFType = (modelMetaData) => (field) => {
119
+ const enumItem = modelMetaData.enums.find(({ name }) => name === field.type);
120
+ if (!enumItem) {
121
+ return void 0;
122
+ }
123
+ return enumItem.values.map((item) => item.name);
124
+ };
125
+ var getDescription = (field) => field.documentation;
126
+ var getPropertyDefinition = (modelMetaData, transformOptions, field) => {
127
+ const type = getJSONSchemaType(field);
128
+ const format = getFormatByDMMFType(field.type);
129
+ const items = getItemsByDMMFType(field, transformOptions);
130
+ const enumList = getEnumListByDMMFType(modelMetaData)(field);
131
+ const defaultValue = getDefaultValue(field);
132
+ const description = getDescription(field);
133
+ return {
134
+ type,
135
+ ...transformOptions.persistOriginalType && {
136
+ originalType: field.type
137
+ },
138
+ ...isDefined(defaultValue) && { default: defaultValue },
139
+ ...isDefined(format) && { format },
140
+ ...isDefined(items) && { items },
141
+ ...isDefined(enumList) && { enum: enumList },
142
+ ...isDefined(description) && { description }
143
+ };
144
+ };
145
+ var getJSONSchemaProperty = (modelMetaData, transformOptions) => (field) => {
146
+ const propertyMetaData = {
147
+ required: field.isRequired,
148
+ hasDefaultValue: field.hasDefaultValue,
149
+ isScalar: field.kind === "scalar" || field.kind === "enum"
150
+ };
151
+ const property = isSingleReference(field) ? getJSONSchemaForPropertyReference(field, transformOptions) : getPropertyDefinition(modelMetaData, transformOptions, field);
152
+ return [field.name, property, propertyMetaData];
153
+ };
154
+ var properties_default = getJSONSchemaProperty;
155
+
156
+ // src/model.ts
157
+ function getRelationScalarFields(model) {
158
+ return model.fields.flatMap((field) => field.relationFromFields || []);
159
+ }
160
+ var getJSONSchemaModel = (modelMetaData, transformOptions) => (model) => {
161
+ const definitionPropertiesMap = model.fields.map(properties_default(modelMetaData, transformOptions));
162
+ const propertiesMap = definitionPropertiesMap.map(([name, definition2]) => [name, definition2]);
163
+ const relationScalarFields = getRelationScalarFields(model);
164
+ const propertiesWithoutRelationScalars = propertiesMap.filter((property) => !relationScalarFields.includes(property[0]));
165
+ const properties = Object.fromEntries((transformOptions == null ? void 0 : transformOptions.keepRelationScalarFields) === "true" ? propertiesMap : propertiesWithoutRelationScalars);
166
+ const definition = {
167
+ type: "object",
168
+ properties
169
+ };
170
+ if (transformOptions.includeRequiredFields) {
171
+ definition.required = definitionPropertiesMap.reduce((filtered, [name, , fieldMetaData]) => {
172
+ if (fieldMetaData.required && fieldMetaData.isScalar && !fieldMetaData.hasDefaultValue) {
173
+ filtered.push(name);
174
+ }
175
+ return filtered;
176
+ }, []);
177
+ }
178
+ return [model.name, definition];
179
+ };
180
+ var model_default = getJSONSchemaModel;
181
+
182
+ // src/transform-dmmf.ts
183
+ var toCamelCase = (name) => name.slice(0, 1).toLowerCase() + name.slice(1);
184
+ var getPropertyDefinition2 = ({ schemaId }) => (model) => {
185
+ const reference = `#/definitions/${model.name}`;
186
+ return [
187
+ toCamelCase(model.name),
188
+ {
189
+ $ref: schemaId ? `${schemaId}${reference}` : reference
190
+ }
191
+ ];
192
+ };
193
+ var transformDmmf = (dmmf, transformOptions = {}) => {
194
+ const { models = [], enums = [], types = [] } = dmmf.datamodel;
195
+ const initialJSON = {
196
+ $schema: "http://json-schema.org/draft-07/schema#",
197
+ definitions: {},
198
+ type: "object"
199
+ };
200
+ const { schemaId } = transformOptions;
201
+ const modelDefinitionsMap = models.map(model_default({ enums }, transformOptions));
202
+ const typeDefinitionsMap = types.map(model_default({ enums }, transformOptions));
203
+ const modelPropertyDefinitionsMap = models.map(getPropertyDefinition2(transformOptions));
204
+ const definitions = Object.fromEntries([...modelDefinitionsMap, ...typeDefinitionsMap]);
205
+ const properties = Object.fromEntries(modelPropertyDefinitionsMap);
206
+ return {
207
+ ...schemaId ? { $id: schemaId } : null,
208
+ ...initialJSON,
209
+ definitions,
210
+ properties
211
+ };
212
+ };
213
+ var transform_dmmf_default = transformDmmf;
214
+ export {
215
+ properties_default as getJSONSchemaProperty,
216
+ transform_dmmf_default as transformDMMF
217
+ };
218
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/properties.ts","../src/model.ts","../src/transform-dmmf.ts"],"sourcesContent":["import type { DMMF } from \"@prisma/generator-helper\";\nimport type { JSONSchema7, JSONSchema7TypeName } from \"json-schema\";\nimport assert from \"node:assert\";\n\nimport type {\n ModelMetaData, PrismaPrimitive, PropertyMap, PropertyMetaData, TransformOptions,\n} from \"./types.d\";\n\nfunction isDefined<T>(value: T | undefined | null): value is T {\n return value !== undefined && value !== null;\n}\n\nconst getJSONSchemaScalar = (fieldType: PrismaPrimitive): JSONSchema7TypeName | Array<JSONSchema7TypeName> => {\n switch (fieldType) {\n case \"Int\":\n case \"BigInt\": {\n return \"integer\";\n }\n case \"DateTime\":\n case \"Bytes\":\n case \"String\": {\n return \"string\";\n }\n case \"Float\":\n case \"Decimal\": {\n return \"number\";\n }\n case \"Json\": {\n return [\"number\", \"string\", \"boolean\", \"object\", \"array\", \"null\"];\n }\n case \"Boolean\": {\n return \"boolean\";\n }\n default: {\n throw new Error(`Unhandled discriminated union member: ${JSON.stringify(fieldType)}`);\n }\n }\n};\n\nconst getJSONSchemaType = (field: DMMF.Field): JSONSchema7[\"type\"] => {\n const {\n isList, isRequired, kind, type,\n } = field;\n\n let scalarFieldType: JSONSchema7[\"type\"] = \"object\";\n\n if (kind === \"scalar\" && !isList) {\n scalarFieldType = getJSONSchemaScalar(type as PrismaPrimitive);\n } else if (isList) {\n scalarFieldType = \"array\";\n } else if (kind === \"enum\") {\n scalarFieldType = \"string\";\n }\n\n if (isRequired || isList) {\n return scalarFieldType;\n }\n\n const isFieldUnion = Array.isArray(scalarFieldType);\n\n if (isFieldUnion) {\n return [...new Set([...scalarFieldType, \"null\"])] as JSONSchema7[\"type\"];\n }\n\n return [scalarFieldType as JSONSchema7TypeName, \"null\"];\n};\n\nconst getDefaultValue = (field: DMMF.Field): JSONSchema7[\"default\"] => {\n const fieldDefault = field.default;\n\n if (!field.hasDefaultValue) {\n return null;\n }\n\n if (field.kind === \"enum\") {\n return typeof fieldDefault === \"string\" ? fieldDefault : null;\n }\n\n if (field.kind !== \"scalar\") {\n return null;\n }\n\n switch (field.type) {\n case \"String\":\n case \"BigInt\":\n case \"DateTime\": {\n return typeof fieldDefault === \"string\" ? fieldDefault : null;\n }\n case \"Int\":\n case \"Float\":\n case \"Decimal\": {\n return typeof fieldDefault === \"number\" ? fieldDefault : null;\n }\n case \"Boolean\": {\n return typeof fieldDefault === \"boolean\" ? fieldDefault : null;\n }\n case \"Json\":\n case \"Bytes\": {\n return null;\n }\n default: {\n throw new Error(`Unhandled discriminated union member: ${JSON.stringify(field.type)}`);\n }\n }\n};\n\nconst getFormatByDMMFType = (fieldType: DMMF.Field[\"type\"]): string | undefined => {\n if (fieldType === \"DateTime\") {\n return \"date-time\";\n }\n\n return undefined;\n};\n\nconst getJSONSchemaForPropertyReference = (field: DMMF.Field, { schemaId, persistOriginalType }: TransformOptions): JSONSchema7 => {\n const notNullable = field.isRequired || field.isList;\n\n assert.equal(typeof field.type, \"string\");\n\n const typeReference = `#/definitions/${field.type}`;\n const reference = { $ref: schemaId ? `${schemaId}${typeReference}` : typeReference };\n\n return notNullable\n ? reference\n : {\n anyOf: [reference, { type: \"null\" }],\n ...(persistOriginalType && {\n originalType: field.type,\n }),\n };\n};\n\nconst getItemsByDMMFType = (field: DMMF.Field, transformOptions: TransformOptions): JSONSchema7[\"items\"] => {\n if ((field.kind === \"scalar\" && !field.isList) || field.kind === \"enum\") {\n return undefined;\n }\n\n if (field.kind === \"scalar\" && field.isList) {\n return { type: getJSONSchemaScalar(field.type as PrismaPrimitive) };\n }\n\n return getJSONSchemaForPropertyReference(field, transformOptions);\n};\n\nconst isSingleReference = (field: DMMF.Field) => field.kind !== \"scalar\" && !field.isList && field.kind !== \"enum\";\n\nconst getEnumListByDMMFType = (modelMetaData: ModelMetaData) => (field: DMMF.Field): string[] | undefined => {\n const enumItem = modelMetaData.enums.find(({ name }) => name === field.type);\n\n if (!enumItem) {\n return undefined;\n }\n\n return enumItem.values.map((item) => item.name);\n};\n\nconst getDescription = (field: DMMF.Field) => field.documentation;\n\nconst getPropertyDefinition = (modelMetaData: ModelMetaData, transformOptions: TransformOptions, field: DMMF.Field) => {\n const type = getJSONSchemaType(field);\n const format = getFormatByDMMFType(field.type);\n const items = getItemsByDMMFType(field, transformOptions);\n const enumList = getEnumListByDMMFType(modelMetaData)(field);\n const defaultValue = getDefaultValue(field);\n const description = getDescription(field);\n\n return {\n type,\n ...(transformOptions.persistOriginalType && {\n originalType: field.type,\n }),\n ...(isDefined(defaultValue) && { default: defaultValue }),\n ...(isDefined(format) && { format }),\n ...(isDefined(items) && { items }),\n ...(isDefined(enumList) && { enum: enumList }),\n ...(isDefined(description) && { description }),\n };\n};\n\nconst getJSONSchemaProperty = (modelMetaData: ModelMetaData, transformOptions: TransformOptions) => (field: DMMF.Field): PropertyMap => {\n const propertyMetaData: PropertyMetaData = {\n required: field.isRequired,\n hasDefaultValue: field.hasDefaultValue,\n isScalar: field.kind === \"scalar\" || field.kind === \"enum\",\n };\n\n const property = isSingleReference(field)\n ? getJSONSchemaForPropertyReference(field, transformOptions)\n : getPropertyDefinition(modelMetaData, transformOptions, field);\n\n return [field.name, property, propertyMetaData];\n};\n\nexport default getJSONSchemaProperty;\n","import type { DMMF } from \"@prisma/generator-helper\";\nimport type { JSONSchema7Definition } from \"json-schema\";\n\nimport getJSONSchemaProperty from \"./properties\";\nimport type { DefinitionMap, ModelMetaData, TransformOptions } from \"./types.d\";\n\nfunction getRelationScalarFields(model: DMMF.Model): string[] {\n return model.fields.flatMap((field) => field.relationFromFields || []);\n}\n\nconst getJSONSchemaModel = (modelMetaData: ModelMetaData, transformOptions: TransformOptions) => (model: DMMF.Model): DefinitionMap => {\n const definitionPropertiesMap = model.fields.map(getJSONSchemaProperty(modelMetaData, transformOptions));\n\n const propertiesMap = definitionPropertiesMap.map(([name, definition]) => [name, definition] as DefinitionMap);\n const relationScalarFields = getRelationScalarFields(model);\n const propertiesWithoutRelationScalars = propertiesMap.filter((property) => !relationScalarFields.includes(property[0]));\n\n const properties = Object.fromEntries(transformOptions?.keepRelationScalarFields === \"true\" ? propertiesMap : propertiesWithoutRelationScalars);\n\n const definition: JSONSchema7Definition = {\n type: \"object\",\n properties,\n };\n\n if (transformOptions.includeRequiredFields) {\n definition.required = definitionPropertiesMap.reduce((filtered: string[], [name, , fieldMetaData]) => {\n if (fieldMetaData.required && fieldMetaData.isScalar && !fieldMetaData.hasDefaultValue) {\n filtered.push(name);\n }\n return filtered;\n }, []);\n }\n\n return [model.name, definition];\n};\n\nexport default getJSONSchemaModel;\n","import type { DMMF } from \"@prisma/generator-helper\";\nimport type { JSONSchema7, JSONSchema7Definition } from \"json-schema\";\n\nimport getJSONSchemaModel from \"./model\";\nimport type { TransformOptions } from \"./types.d\";\n\nconst toCamelCase = (name: string): string => name.slice(0, 1).toLowerCase() + name.slice(1);\n\nconst getPropertyDefinition = ({ schemaId }: TransformOptions) => (model: DMMF.Model): [name: string, reference: JSONSchema7Definition] => {\n const reference = `#/definitions/${model.name}`;\n\n return [\n toCamelCase(model.name),\n {\n $ref: schemaId ? `${schemaId}${reference}` : reference,\n },\n ];\n};\n\nconst transformDmmf = (dmmf: DMMF.Document, transformOptions: TransformOptions = {}): JSONSchema7 => {\n // TODO: Remove default values as soon as prisma version < 3.10.0 doesn't have to be supported anymore\n const { models = [], enums = [], types = [] } = dmmf.datamodel;\n const initialJSON = {\n $schema: \"http://json-schema.org/draft-07/schema#\",\n definitions: {},\n type: \"object\",\n } as JSONSchema7;\n const { schemaId } = transformOptions;\n\n const modelDefinitionsMap = models.map(getJSONSchemaModel({ enums }, transformOptions));\n const typeDefinitionsMap = types.map(getJSONSchemaModel({ enums }, transformOptions));\n const modelPropertyDefinitionsMap = models.map(getPropertyDefinition(transformOptions));\n const definitions = Object.fromEntries([...modelDefinitionsMap, ...typeDefinitionsMap]);\n const properties = Object.fromEntries(modelPropertyDefinitionsMap);\n\n return {\n ...(schemaId ? { $id: schemaId } : null),\n ...initialJSON,\n definitions,\n properties,\n };\n};\n\nexport default transformDmmf;\n"],"mappings":"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","names":["definition","getPropertyDefinition"]}
package/package.json ADDED
@@ -0,0 +1,127 @@
1
+ {
2
+ "name": "@visulima/prisma-dmmf-transformer",
3
+ "version": "1.0.0",
4
+ "description": "A generator for Prisma to generate a valid JSON Schema v7.",
5
+ "keywords": [
6
+ "anolilab",
7
+ "visulima",
8
+ "prisma",
9
+ "prisma2",
10
+ "prisma3",
11
+ "prisma4",
12
+ "prisma-schema",
13
+ "dmmf",
14
+ "transformer",
15
+ "json-schema"
16
+ ],
17
+ "homepage": "https://visulima.com/packages/prisma-dmmf-transformer",
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "https://github.com/visulima/visulima.git",
21
+ "directory": "packages/prisma-dmmf-transformer"
22
+ },
23
+ "funding": [
24
+ {
25
+ "type": "github",
26
+ "url": "https://github.com/sponsors/prisis"
27
+ },
28
+ {
29
+ "type": "consulting",
30
+ "url": "https://anolilab.com/support"
31
+ }
32
+ ],
33
+ "license": "MIT",
34
+ "author": {
35
+ "name": "Daniel Bannert",
36
+ "email": "d.bannert@anolilab.de"
37
+ },
38
+ "sideEffects": false,
39
+ "exports": {
40
+ ".": {
41
+ "types": "./dist/index.d.ts",
42
+ "require": "./dist/index.js",
43
+ "import": "./dist/index.mjs"
44
+ },
45
+ "./package.json": "./package.json"
46
+ },
47
+ "main": "dist/index.js",
48
+ "module": "dist/index.module.mjs",
49
+ "source": "src/index.ts",
50
+ "types": "dist/index.d.ts",
51
+ "files": [
52
+ "src",
53
+ "dist",
54
+ "README.md",
55
+ "CHANGELOG.md",
56
+ "LICENSE.md"
57
+ ],
58
+ "scripts": {
59
+ "build": "cross-env NODE_ENV=development tsup",
60
+ "build:prod": "cross-env NODE_ENV=production tsup",
61
+ "clean": "rimraf node_modules dist",
62
+ "coverage": "vitest run --coverage",
63
+ "dev": "pnpm predev && pnpm run build --watch",
64
+ "lint:eslint": "cross-env NO_LOGS=true eslint --ext js,jsx,ts,tsx --max-warnings=0 --config .eslintrc.cjs",
65
+ "lint:eslint:fix": "pnpm run lint:eslint --fix",
66
+ "test": "vitest"
67
+ },
68
+ "dependencies": {
69
+ "@prisma/generator-helper": "4.6.1",
70
+ "@prisma/internals": "4.6.1"
71
+ },
72
+ "devDependencies": {
73
+ "@anolilab/eslint-config": "^4.0.9",
74
+ "@anolilab/semantic-release-preset": "^2.0.7",
75
+ "@prisma/client": "4.6.1",
76
+ "@rushstack/eslint-plugin-security": "^0.5.0",
77
+ "@types/json-schema": "7.0.11",
78
+ "@types/micromatch": "^4.0.2",
79
+ "@types/node": "^18.8.4",
80
+ "@typescript-eslint/eslint-plugin": "^5.40.0",
81
+ "@typescript-eslint/parser": "^5.40.0",
82
+ "ajv": "8.11.0",
83
+ "ajv-formats": "2.1.1",
84
+ "cross-env": "^7.0.3",
85
+ "eslint": "^8.25.0",
86
+ "eslint-plugin-compat": "^4.0.2",
87
+ "eslint-plugin-eslint-comments": "^3.2.0",
88
+ "eslint-plugin-import": "^2.26.0",
89
+ "eslint-plugin-json": "^3.1.0",
90
+ "eslint-plugin-jsonc": "^2.5.0",
91
+ "eslint-plugin-jsx-a11y": "^6.6.1",
92
+ "eslint-plugin-markdown": "^3.0.0",
93
+ "eslint-plugin-material-ui": "^1.0.1",
94
+ "eslint-plugin-no-loops": "^0.3.0",
95
+ "eslint-plugin-no-secrets": "^0.8.9",
96
+ "eslint-plugin-node": "^11.1.0",
97
+ "eslint-plugin-optimize-regex": "^1.2.1",
98
+ "eslint-plugin-promise": "^6.0.1",
99
+ "eslint-plugin-radar": "^0.2.1",
100
+ "eslint-plugin-react": "7.31.10",
101
+ "eslint-plugin-react-hooks": "4.6.0",
102
+ "eslint-plugin-simple-import-sort": "^8.0.0",
103
+ "eslint-plugin-sort-keys-fix": "^1.1.2",
104
+ "eslint-plugin-testing-library": "^5.7.2",
105
+ "eslint-plugin-unicorn": "^44.0.2",
106
+ "eslint-plugin-you-dont-need-lodash-underscore": "^6.12.0",
107
+ "eslint-plugin-you-dont-need-momentjs": "^1.6.0",
108
+ "prettier": "^2.7.1",
109
+ "prisma": "4.6.1",
110
+ "read-pkg": "^7.1.0",
111
+ "rimraf": "^3.0.2",
112
+ "semantic-release": "^19.0.5",
113
+ "tsup": "^6.2.3",
114
+ "typescript": "^4.8.4",
115
+ "vitest": "^0.24.1"
116
+ },
117
+ "peerDependencies": {
118
+ "@prisma/client": "3.* || 4.*",
119
+ "prisma": "3.* || 4.*"
120
+ },
121
+ "engines": {
122
+ "node": ">=16"
123
+ },
124
+ "publishConfig": {
125
+ "access": "public"
126
+ }
127
+ }
package/src/index.ts ADDED
@@ -0,0 +1,6 @@
1
+ export { default as transformDMMF } from "./transform-dmmf";
2
+ export { default as getJSONSchemaProperty } from "./properties";
3
+
4
+ export type {
5
+ DefinitionMap, PropertyMap, PropertyMetaData, TransformOptions, ModelMetaData,
6
+ } from "./types.d";
package/src/model.ts ADDED
@@ -0,0 +1,37 @@
1
+ import type { DMMF } from "@prisma/generator-helper";
2
+ import type { JSONSchema7Definition } from "json-schema";
3
+
4
+ import getJSONSchemaProperty from "./properties";
5
+ import type { DefinitionMap, ModelMetaData, TransformOptions } from "./types.d";
6
+
7
+ function getRelationScalarFields(model: DMMF.Model): string[] {
8
+ return model.fields.flatMap((field) => field.relationFromFields || []);
9
+ }
10
+
11
+ const getJSONSchemaModel = (modelMetaData: ModelMetaData, transformOptions: TransformOptions) => (model: DMMF.Model): DefinitionMap => {
12
+ const definitionPropertiesMap = model.fields.map(getJSONSchemaProperty(modelMetaData, transformOptions));
13
+
14
+ const propertiesMap = definitionPropertiesMap.map(([name, definition]) => [name, definition] as DefinitionMap);
15
+ const relationScalarFields = getRelationScalarFields(model);
16
+ const propertiesWithoutRelationScalars = propertiesMap.filter((property) => !relationScalarFields.includes(property[0]));
17
+
18
+ const properties = Object.fromEntries(transformOptions?.keepRelationScalarFields === "true" ? propertiesMap : propertiesWithoutRelationScalars);
19
+
20
+ const definition: JSONSchema7Definition = {
21
+ type: "object",
22
+ properties,
23
+ };
24
+
25
+ if (transformOptions.includeRequiredFields) {
26
+ definition.required = definitionPropertiesMap.reduce((filtered: string[], [name, , fieldMetaData]) => {
27
+ if (fieldMetaData.required && fieldMetaData.isScalar && !fieldMetaData.hasDefaultValue) {
28
+ filtered.push(name);
29
+ }
30
+ return filtered;
31
+ }, []);
32
+ }
33
+
34
+ return [model.name, definition];
35
+ };
36
+
37
+ export default getJSONSchemaModel;
@@ -0,0 +1,194 @@
1
+ import type { DMMF } from "@prisma/generator-helper";
2
+ import type { JSONSchema7, JSONSchema7TypeName } from "json-schema";
3
+ import assert from "node:assert";
4
+
5
+ import type {
6
+ ModelMetaData, PrismaPrimitive, PropertyMap, PropertyMetaData, TransformOptions,
7
+ } from "./types.d";
8
+
9
+ function isDefined<T>(value: T | undefined | null): value is T {
10
+ return value !== undefined && value !== null;
11
+ }
12
+
13
+ const getJSONSchemaScalar = (fieldType: PrismaPrimitive): JSONSchema7TypeName | Array<JSONSchema7TypeName> => {
14
+ switch (fieldType) {
15
+ case "Int":
16
+ case "BigInt": {
17
+ return "integer";
18
+ }
19
+ case "DateTime":
20
+ case "Bytes":
21
+ case "String": {
22
+ return "string";
23
+ }
24
+ case "Float":
25
+ case "Decimal": {
26
+ return "number";
27
+ }
28
+ case "Json": {
29
+ return ["number", "string", "boolean", "object", "array", "null"];
30
+ }
31
+ case "Boolean": {
32
+ return "boolean";
33
+ }
34
+ default: {
35
+ throw new Error(`Unhandled discriminated union member: ${JSON.stringify(fieldType)}`);
36
+ }
37
+ }
38
+ };
39
+
40
+ const getJSONSchemaType = (field: DMMF.Field): JSONSchema7["type"] => {
41
+ const {
42
+ isList, isRequired, kind, type,
43
+ } = field;
44
+
45
+ let scalarFieldType: JSONSchema7["type"] = "object";
46
+
47
+ if (kind === "scalar" && !isList) {
48
+ scalarFieldType = getJSONSchemaScalar(type as PrismaPrimitive);
49
+ } else if (isList) {
50
+ scalarFieldType = "array";
51
+ } else if (kind === "enum") {
52
+ scalarFieldType = "string";
53
+ }
54
+
55
+ if (isRequired || isList) {
56
+ return scalarFieldType;
57
+ }
58
+
59
+ const isFieldUnion = Array.isArray(scalarFieldType);
60
+
61
+ if (isFieldUnion) {
62
+ return [...new Set([...scalarFieldType, "null"])] as JSONSchema7["type"];
63
+ }
64
+
65
+ return [scalarFieldType as JSONSchema7TypeName, "null"];
66
+ };
67
+
68
+ const getDefaultValue = (field: DMMF.Field): JSONSchema7["default"] => {
69
+ const fieldDefault = field.default;
70
+
71
+ if (!field.hasDefaultValue) {
72
+ return null;
73
+ }
74
+
75
+ if (field.kind === "enum") {
76
+ return typeof fieldDefault === "string" ? fieldDefault : null;
77
+ }
78
+
79
+ if (field.kind !== "scalar") {
80
+ return null;
81
+ }
82
+
83
+ switch (field.type) {
84
+ case "String":
85
+ case "BigInt":
86
+ case "DateTime": {
87
+ return typeof fieldDefault === "string" ? fieldDefault : null;
88
+ }
89
+ case "Int":
90
+ case "Float":
91
+ case "Decimal": {
92
+ return typeof fieldDefault === "number" ? fieldDefault : null;
93
+ }
94
+ case "Boolean": {
95
+ return typeof fieldDefault === "boolean" ? fieldDefault : null;
96
+ }
97
+ case "Json":
98
+ case "Bytes": {
99
+ return null;
100
+ }
101
+ default: {
102
+ throw new Error(`Unhandled discriminated union member: ${JSON.stringify(field.type)}`);
103
+ }
104
+ }
105
+ };
106
+
107
+ const getFormatByDMMFType = (fieldType: DMMF.Field["type"]): string | undefined => {
108
+ if (fieldType === "DateTime") {
109
+ return "date-time";
110
+ }
111
+
112
+ return undefined;
113
+ };
114
+
115
+ const getJSONSchemaForPropertyReference = (field: DMMF.Field, { schemaId, persistOriginalType }: TransformOptions): JSONSchema7 => {
116
+ const notNullable = field.isRequired || field.isList;
117
+
118
+ assert.equal(typeof field.type, "string");
119
+
120
+ const typeReference = `#/definitions/${field.type}`;
121
+ const reference = { $ref: schemaId ? `${schemaId}${typeReference}` : typeReference };
122
+
123
+ return notNullable
124
+ ? reference
125
+ : {
126
+ anyOf: [reference, { type: "null" }],
127
+ ...(persistOriginalType && {
128
+ originalType: field.type,
129
+ }),
130
+ };
131
+ };
132
+
133
+ const getItemsByDMMFType = (field: DMMF.Field, transformOptions: TransformOptions): JSONSchema7["items"] => {
134
+ if ((field.kind === "scalar" && !field.isList) || field.kind === "enum") {
135
+ return undefined;
136
+ }
137
+
138
+ if (field.kind === "scalar" && field.isList) {
139
+ return { type: getJSONSchemaScalar(field.type as PrismaPrimitive) };
140
+ }
141
+
142
+ return getJSONSchemaForPropertyReference(field, transformOptions);
143
+ };
144
+
145
+ const isSingleReference = (field: DMMF.Field) => field.kind !== "scalar" && !field.isList && field.kind !== "enum";
146
+
147
+ const getEnumListByDMMFType = (modelMetaData: ModelMetaData) => (field: DMMF.Field): string[] | undefined => {
148
+ const enumItem = modelMetaData.enums.find(({ name }) => name === field.type);
149
+
150
+ if (!enumItem) {
151
+ return undefined;
152
+ }
153
+
154
+ return enumItem.values.map((item) => item.name);
155
+ };
156
+
157
+ const getDescription = (field: DMMF.Field) => field.documentation;
158
+
159
+ const getPropertyDefinition = (modelMetaData: ModelMetaData, transformOptions: TransformOptions, field: DMMF.Field) => {
160
+ const type = getJSONSchemaType(field);
161
+ const format = getFormatByDMMFType(field.type);
162
+ const items = getItemsByDMMFType(field, transformOptions);
163
+ const enumList = getEnumListByDMMFType(modelMetaData)(field);
164
+ const defaultValue = getDefaultValue(field);
165
+ const description = getDescription(field);
166
+
167
+ return {
168
+ type,
169
+ ...(transformOptions.persistOriginalType && {
170
+ originalType: field.type,
171
+ }),
172
+ ...(isDefined(defaultValue) && { default: defaultValue }),
173
+ ...(isDefined(format) && { format }),
174
+ ...(isDefined(items) && { items }),
175
+ ...(isDefined(enumList) && { enum: enumList }),
176
+ ...(isDefined(description) && { description }),
177
+ };
178
+ };
179
+
180
+ const getJSONSchemaProperty = (modelMetaData: ModelMetaData, transformOptions: TransformOptions) => (field: DMMF.Field): PropertyMap => {
181
+ const propertyMetaData: PropertyMetaData = {
182
+ required: field.isRequired,
183
+ hasDefaultValue: field.hasDefaultValue,
184
+ isScalar: field.kind === "scalar" || field.kind === "enum",
185
+ };
186
+
187
+ const property = isSingleReference(field)
188
+ ? getJSONSchemaForPropertyReference(field, transformOptions)
189
+ : getPropertyDefinition(modelMetaData, transformOptions, field);
190
+
191
+ return [field.name, property, propertyMetaData];
192
+ };
193
+
194
+ export default getJSONSchemaProperty;
@@ -0,0 +1,44 @@
1
+ import type { DMMF } from "@prisma/generator-helper";
2
+ import type { JSONSchema7, JSONSchema7Definition } from "json-schema";
3
+
4
+ import getJSONSchemaModel from "./model";
5
+ import type { TransformOptions } from "./types.d";
6
+
7
+ const toCamelCase = (name: string): string => name.slice(0, 1).toLowerCase() + name.slice(1);
8
+
9
+ const getPropertyDefinition = ({ schemaId }: TransformOptions) => (model: DMMF.Model): [name: string, reference: JSONSchema7Definition] => {
10
+ const reference = `#/definitions/${model.name}`;
11
+
12
+ return [
13
+ toCamelCase(model.name),
14
+ {
15
+ $ref: schemaId ? `${schemaId}${reference}` : reference,
16
+ },
17
+ ];
18
+ };
19
+
20
+ const transformDmmf = (dmmf: DMMF.Document, transformOptions: TransformOptions = {}): JSONSchema7 => {
21
+ // TODO: Remove default values as soon as prisma version < 3.10.0 doesn't have to be supported anymore
22
+ const { models = [], enums = [], types = [] } = dmmf.datamodel;
23
+ const initialJSON = {
24
+ $schema: "http://json-schema.org/draft-07/schema#",
25
+ definitions: {},
26
+ type: "object",
27
+ } as JSONSchema7;
28
+ const { schemaId } = transformOptions;
29
+
30
+ const modelDefinitionsMap = models.map(getJSONSchemaModel({ enums }, transformOptions));
31
+ const typeDefinitionsMap = types.map(getJSONSchemaModel({ enums }, transformOptions));
32
+ const modelPropertyDefinitionsMap = models.map(getPropertyDefinition(transformOptions));
33
+ const definitions = Object.fromEntries([...modelDefinitionsMap, ...typeDefinitionsMap]);
34
+ const properties = Object.fromEntries(modelPropertyDefinitionsMap);
35
+
36
+ return {
37
+ ...(schemaId ? { $id: schemaId } : null),
38
+ ...initialJSON,
39
+ definitions,
40
+ properties,
41
+ };
42
+ };
43
+
44
+ export default transformDmmf;
package/src/types.d.ts ADDED
@@ -0,0 +1,24 @@
1
+ import type { DMMF } from "@prisma/generator-helper";
2
+ import type { JSONSchema7Definition } from "json-schema";
3
+
4
+ export type PrismaPrimitive = "String" | "BigInt" | "Bytes" | "Decimal" | "Boolean" | "Int" | "Float" | "Json" | "DateTime";
5
+
6
+ export interface PropertyMetaData {
7
+ required: boolean;
8
+ hasDefaultValue: boolean;
9
+ isScalar: boolean;
10
+ }
11
+
12
+ export interface ModelMetaData {
13
+ enums: DMMF.DatamodelEnum[];
14
+ }
15
+
16
+ export type DefinitionMap = [name: string, definition: JSONSchema7Definition];
17
+ export type PropertyMap = [...DefinitionMap, PropertyMetaData];
18
+
19
+ export interface TransformOptions {
20
+ keepRelationScalarFields?: "true" | "false";
21
+ schemaId?: string;
22
+ includeRequiredFields?: "true" | "false";
23
+ persistOriginalType?: "true" | "false";
24
+ }