@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 +6 -0
- package/LICENSE.md +21 -0
- package/README.md +276 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +218 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +218 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +127 -0
- package/src/index.ts +6 -0
- package/src/model.ts +37 -0
- package/src/properties.ts +194 -0
- package/src/transform-dmmf.ts +44 -0
- package/src/types.d.ts +24 -0
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"
|
package/dist/index.d.ts
ADDED
|
@@ -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":";AAEA,OAAO,YAAY;AAMnB,SAAS,UAAa,OAAyC;AAC3D,SAAO,UAAU,UAAa,UAAU;AAC5C;AAEA,IAAM,sBAAsB,CAAC,cAAiF;AAC1G,UAAQ,WAAW;AAAA,IACf,KAAK;AAAA,IACL,KAAK,UAAU;AACX,aAAO;AAAA,IACX;AAAA,IACA,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK,UAAU;AACX,aAAO;AAAA,IACX;AAAA,IACA,KAAK;AAAA,IACL,KAAK,WAAW;AACZ,aAAO;AAAA,IACX;AAAA,IACA,KAAK,QAAQ;AACT,aAAO,CAAC,UAAU,UAAU,WAAW,UAAU,SAAS,MAAM;AAAA,IACpE;AAAA,IACA,KAAK,WAAW;AACZ,aAAO;AAAA,IACX;AAAA,IACA,SAAS;AACL,YAAM,IAAI,MAAM,yCAAyC,KAAK,UAAU,SAAS,GAAG;AAAA,IACxF;AAAA,EACJ;AACJ;AAEA,IAAM,oBAAoB,CAAC,UAA2C;AAClE,QAAM;AAAA,IACF;AAAA,IAAQ;AAAA,IAAY;AAAA,IAAM;AAAA,EAC9B,IAAI;AAEJ,MAAI,kBAAuC;AAE3C,MAAI,SAAS,YAAY,CAAC,QAAQ;AAC9B,sBAAkB,oBAAoB,IAAuB;AAAA,EACjE,WAAW,QAAQ;AACf,sBAAkB;AAAA,EACtB,WAAW,SAAS,QAAQ;AACxB,sBAAkB;AAAA,EACtB;AAEA,MAAI,cAAc,QAAQ;AACtB,WAAO;AAAA,EACX;AAEA,QAAM,eAAe,MAAM,QAAQ,eAAe;AAElD,MAAI,cAAc;AACd,WAAO,CAAC,GAAG,oBAAI,IAAI,CAAC,GAAG,iBAAiB,MAAM,CAAC,CAAC;AAAA,EACpD;AAEA,SAAO,CAAC,iBAAwC,MAAM;AAC1D;AAEA,IAAM,kBAAkB,CAAC,UAA8C;AACnE,QAAM,eAAe,MAAM;AAE3B,MAAI,CAAC,MAAM,iBAAiB;AACxB,WAAO;AAAA,EACX;AAEA,MAAI,MAAM,SAAS,QAAQ;AACvB,WAAO,OAAO,iBAAiB,WAAW,eAAe;AAAA,EAC7D;AAEA,MAAI,MAAM,SAAS,UAAU;AACzB,WAAO;AAAA,EACX;AAEA,UAAQ,MAAM,MAAM;AAAA,IAChB,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK,YAAY;AACb,aAAO,OAAO,iBAAiB,WAAW,eAAe;AAAA,IAC7D;AAAA,IACA,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK,WAAW;AACZ,aAAO,OAAO,iBAAiB,WAAW,eAAe;AAAA,IAC7D;AAAA,IACA,KAAK,WAAW;AACZ,aAAO,OAAO,iBAAiB,YAAY,eAAe;AAAA,IAC9D;AAAA,IACA,KAAK;AAAA,IACL,KAAK,SAAS;AACV,aAAO;AAAA,IACX;AAAA,IACA,SAAS;AACL,YAAM,IAAI,MAAM,yCAAyC,KAAK,UAAU,MAAM,IAAI,GAAG;AAAA,IACzF;AAAA,EACJ;AACJ;AAEA,IAAM,sBAAsB,CAAC,cAAsD;AAC/E,MAAI,cAAc,YAAY;AAC1B,WAAO;AAAA,EACX;AAEA,SAAO;AACX;AAEA,IAAM,oCAAoC,CAAC,OAAmB,EAAE,UAAU,oBAAoB,MAAqC;AAC/H,QAAM,cAAc,MAAM,cAAc,MAAM;AAE9C,SAAO,MAAM,OAAO,MAAM,MAAM,QAAQ;AAExC,QAAM,gBAAgB,iBAAiB,MAAM;AAC7C,QAAM,YAAY,EAAE,MAAM,WAAW,GAAG,WAAW,kBAAkB,cAAc;AAEnF,SAAO,cACD,YACA;AAAA,IACE,OAAO,CAAC,WAAW,EAAE,MAAM,OAAO,CAAC;AAAA,IACnC,GAAI,uBAAuB;AAAA,MACvB,cAAc,MAAM;AAAA,IACxB;AAAA,EACJ;AACR;AAEA,IAAM,qBAAqB,CAAC,OAAmB,qBAA6D;AACxG,MAAK,MAAM,SAAS,YAAY,CAAC,MAAM,UAAW,MAAM,SAAS,QAAQ;AACrE,WAAO;AAAA,EACX;AAEA,MAAI,MAAM,SAAS,YAAY,MAAM,QAAQ;AACzC,WAAO,EAAE,MAAM,oBAAoB,MAAM,IAAuB,EAAE;AAAA,EACtE;AAEA,SAAO,kCAAkC,OAAO,gBAAgB;AACpE;AAEA,IAAM,oBAAoB,CAAC,UAAsB,MAAM,SAAS,YAAY,CAAC,MAAM,UAAU,MAAM,SAAS;AAE5G,IAAM,wBAAwB,CAAC,kBAAiC,CAAC,UAA4C;AACzG,QAAM,WAAW,cAAc,MAAM,KAAK,CAAC,EAAE,KAAK,MAAM,SAAS,MAAM,IAAI;AAE3E,MAAI,CAAC,UAAU;AACX,WAAO;AAAA,EACX;AAEA,SAAO,SAAS,OAAO,IAAI,CAAC,SAAS,KAAK,IAAI;AAClD;AAEA,IAAM,iBAAiB,CAAC,UAAsB,MAAM;AAEpD,IAAM,wBAAwB,CAAC,eAA8B,kBAAoC,UAAsB;AACnH,QAAM,OAAO,kBAAkB,KAAK;AACpC,QAAM,SAAS,oBAAoB,MAAM,IAAI;AAC7C,QAAM,QAAQ,mBAAmB,OAAO,gBAAgB;AACxD,QAAM,WAAW,sBAAsB,aAAa,EAAE,KAAK;AAC3D,QAAM,eAAe,gBAAgB,KAAK;AAC1C,QAAM,cAAc,eAAe,KAAK;AAExC,SAAO;AAAA,IACH;AAAA,IACA,GAAI,iBAAiB,uBAAuB;AAAA,MACxC,cAAc,MAAM;AAAA,IACxB;AAAA,IACA,GAAI,UAAU,YAAY,KAAK,EAAE,SAAS,aAAa;AAAA,IACvD,GAAI,UAAU,MAAM,KAAK,EAAE,OAAO;AAAA,IAClC,GAAI,UAAU,KAAK,KAAK,EAAE,MAAM;AAAA,IAChC,GAAI,UAAU,QAAQ,KAAK,EAAE,MAAM,SAAS;AAAA,IAC5C,GAAI,UAAU,WAAW,KAAK,EAAE,YAAY;AAAA,EAChD;AACJ;AAEA,IAAM,wBAAwB,CAAC,eAA8B,qBAAuC,CAAC,UAAmC;AACpI,QAAM,mBAAqC;AAAA,IACvC,UAAU,MAAM;AAAA,IAChB,iBAAiB,MAAM;AAAA,IACvB,UAAU,MAAM,SAAS,YAAY,MAAM,SAAS;AAAA,EACxD;AAEA,QAAM,WAAW,kBAAkB,KAAK,IAClC,kCAAkC,OAAO,gBAAgB,IACzD,sBAAsB,eAAe,kBAAkB,KAAK;AAElE,SAAO,CAAC,MAAM,MAAM,UAAU,gBAAgB;AAClD;AAEA,IAAO,qBAAQ;;;AC3Lf,SAAS,wBAAwB,OAA6B;AAC1D,SAAO,MAAM,OAAO,QAAQ,CAAC,UAAU,MAAM,sBAAsB,CAAC,CAAC;AACzE;AAEA,IAAM,qBAAqB,CAAC,eAA8B,qBAAuC,CAAC,UAAqC;AACnI,QAAM,0BAA0B,MAAM,OAAO,IAAI,mBAAsB,eAAe,gBAAgB,CAAC;AAEvG,QAAM,gBAAgB,wBAAwB,IAAI,CAAC,CAAC,MAAMA,WAAU,MAAM,CAAC,MAAMA,WAAU,CAAkB;AAC7G,QAAM,uBAAuB,wBAAwB,KAAK;AAC1D,QAAM,mCAAmC,cAAc,OAAO,CAAC,aAAa,CAAC,qBAAqB,SAAS,SAAS,EAAE,CAAC;AAEvH,QAAM,aAAa,OAAO,aAAY,qDAAkB,8BAA6B,SAAS,gBAAgB,gCAAgC;AAE9I,QAAM,aAAoC;AAAA,IACtC,MAAM;AAAA,IACN;AAAA,EACJ;AAEA,MAAI,iBAAiB,uBAAuB;AACxC,eAAW,WAAW,wBAAwB,OAAO,CAAC,UAAoB,CAAC,MAAM,EAAE,aAAa,MAAM;AAClG,UAAI,cAAc,YAAY,cAAc,YAAY,CAAC,cAAc,iBAAiB;AACpF,iBAAS,KAAK,IAAI;AAAA,MACtB;AACA,aAAO;AAAA,IACX,GAAG,CAAC,CAAC;AAAA,EACT;AAEA,SAAO,CAAC,MAAM,MAAM,UAAU;AAClC;AAEA,IAAO,gBAAQ;;;AC9Bf,IAAM,cAAc,CAAC,SAAyB,KAAK,MAAM,GAAG,CAAC,EAAE,YAAY,IAAI,KAAK,MAAM,CAAC;AAE3F,IAAMC,yBAAwB,CAAC,EAAE,SAAS,MAAwB,CAAC,UAAwE;AACvI,QAAM,YAAY,iBAAiB,MAAM;AAEzC,SAAO;AAAA,IACH,YAAY,MAAM,IAAI;AAAA,IACtB;AAAA,MACI,MAAM,WAAW,GAAG,WAAW,cAAc;AAAA,IACjD;AAAA,EACJ;AACJ;AAEA,IAAM,gBAAgB,CAAC,MAAqB,mBAAqC,CAAC,MAAmB;AAEjG,QAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,GAAG,QAAQ,CAAC,EAAE,IAAI,KAAK;AACrD,QAAM,cAAc;AAAA,IAChB,SAAS;AAAA,IACT,aAAa,CAAC;AAAA,IACd,MAAM;AAAA,EACV;AACA,QAAM,EAAE,SAAS,IAAI;AAErB,QAAM,sBAAsB,OAAO,IAAI,cAAmB,EAAE,MAAM,GAAG,gBAAgB,CAAC;AACtF,QAAM,qBAAqB,MAAM,IAAI,cAAmB,EAAE,MAAM,GAAG,gBAAgB,CAAC;AACpF,QAAM,8BAA8B,OAAO,IAAIA,uBAAsB,gBAAgB,CAAC;AACtF,QAAM,cAAc,OAAO,YAAY,CAAC,GAAG,qBAAqB,GAAG,kBAAkB,CAAC;AACtF,QAAM,aAAa,OAAO,YAAY,2BAA2B;AAEjE,SAAO;AAAA,IACH,GAAI,WAAW,EAAE,KAAK,SAAS,IAAI;AAAA,IACnC,GAAG;AAAA,IACH;AAAA,IACA;AAAA,EACJ;AACJ;AAEA,IAAO,yBAAQ;","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
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
|
+
}
|