@visulima/crud 3.0.0-alpha.7 → 3.0.0-alpha.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/LICENSE.md +21 -0
  3. package/dist/adapter/prisma/index.d.cts +39 -0
  4. package/dist/adapter/prisma/index.d.mts +39 -0
  5. package/dist/adapter/prisma/index.d.ts +39 -0
  6. package/dist/adapter/prisma/types.d.cts +31 -0
  7. package/dist/adapter/prisma/types.d.mts +31 -0
  8. package/dist/adapter/prisma/types.d.ts +31 -0
  9. package/dist/adapter/prisma/utils/models-to-route-names.d.cts +5 -0
  10. package/dist/adapter/prisma/utils/models-to-route-names.d.mts +5 -0
  11. package/dist/adapter/prisma/utils/models-to-route-names.d.ts +5 -0
  12. package/dist/adapter/prisma/utils/parse-cursor.d.cts +3 -0
  13. package/dist/adapter/prisma/utils/parse-cursor.d.mts +3 -0
  14. package/dist/adapter/prisma/utils/parse-cursor.d.ts +3 -0
  15. package/dist/adapter/prisma/utils/parse-order-by.d.cts +4 -0
  16. package/dist/adapter/prisma/utils/parse-order-by.d.mts +4 -0
  17. package/dist/adapter/prisma/utils/parse-order-by.d.ts +4 -0
  18. package/dist/adapter/prisma/utils/parse-recursive.d.cts +4 -0
  19. package/dist/adapter/prisma/utils/parse-recursive.d.mts +4 -0
  20. package/dist/adapter/prisma/utils/parse-recursive.d.ts +4 -0
  21. package/dist/adapter/prisma/utils/parse-where.d.cts +4 -0
  22. package/dist/adapter/prisma/utils/parse-where.d.mts +4 -0
  23. package/dist/adapter/prisma/utils/parse-where.d.ts +4 -0
  24. package/dist/base-crud-handler.d.cts +9 -0
  25. package/dist/base-crud-handler.d.mts +9 -0
  26. package/dist/base-crud-handler.d.ts +9 -0
  27. package/dist/handler/create.d.cts +11 -0
  28. package/dist/handler/create.d.mts +11 -0
  29. package/dist/handler/create.d.ts +11 -0
  30. package/dist/handler/delete.d.cts +7 -0
  31. package/dist/handler/delete.d.mts +7 -0
  32. package/dist/handler/delete.d.ts +7 -0
  33. package/dist/handler/list.d.cts +9 -0
  34. package/dist/handler/list.d.mts +9 -0
  35. package/dist/handler/list.d.ts +9 -0
  36. package/dist/handler/read.d.cts +7 -0
  37. package/dist/handler/read.d.mts +7 -0
  38. package/dist/handler/read.d.ts +7 -0
  39. package/dist/handler/update.d.cts +11 -0
  40. package/dist/handler/update.d.mts +11 -0
  41. package/dist/handler/update.d.ts +11 -0
  42. package/dist/index.cjs +13 -0
  43. package/dist/index.d.cts +6 -0
  44. package/dist/index.d.mts +6 -127
  45. package/dist/index.d.ts +6 -127
  46. package/dist/index.mjs +3 -1085
  47. package/dist/next/api/edge/index.d.cts +3 -0
  48. package/dist/next/api/edge/index.d.mts +3 -0
  49. package/dist/next/api/edge/index.d.ts +3 -0
  50. package/dist/next/api/node/index.d.cts +4 -0
  51. package/dist/next/api/node/index.d.mts +4 -0
  52. package/dist/next/api/node/index.d.ts +4 -0
  53. package/dist/next/index.cjs +11 -0
  54. package/dist/next/index.d.cts +2 -0
  55. package/dist/next/index.d.mts +2 -8
  56. package/dist/next/index.d.ts +2 -8
  57. package/dist/next/index.mjs +2 -4863
  58. package/dist/packem_shared/PrismaAdapter-BTCwgMow.cjs +324 -0
  59. package/dist/packem_shared/PrismaAdapter-dVBZvBOv.mjs +318 -0
  60. package/dist/packem_shared/RouteType-Bk3uAK0x.cjs +14 -0
  61. package/dist/packem_shared/RouteType-CB2xrWdf.mjs +10 -0
  62. package/dist/packem_shared/base-crud-handler-BRbm1Ki9.cjs +572 -0
  63. package/dist/packem_shared/base-crud-handler-HgHqhIuP.mjs +587 -0
  64. package/dist/packem_shared/edgeHandler-3vMMElLT.mjs +16 -0
  65. package/dist/packem_shared/edgeHandler-CqtcF9J3.cjs +18 -0
  66. package/dist/packem_shared/get-accessible-routes-C6NF9Iry.cjs +16 -0
  67. package/dist/packem_shared/get-accessible-routes-sV5SDdFn.mjs +14 -0
  68. package/dist/packem_shared/models-to-route-names-CdwsK0V1.mjs +9 -0
  69. package/dist/packem_shared/models-to-route-names-Dv94PzhE.cjs +11 -0
  70. package/dist/packem_shared/modelsToOpenApi-Bq98YsFg.mjs +706 -0
  71. package/dist/{index.js → packem_shared/modelsToOpenApi-WQ8Ol6q7.cjs} +65 -452
  72. package/dist/packem_shared/nodeHandler-2kUmzwin.cjs +16 -0
  73. package/dist/packem_shared/nodeHandler-BnlkVX2A.mjs +14 -0
  74. package/dist/query-parser.d.cts +3 -0
  75. package/dist/query-parser.d.mts +3 -0
  76. package/dist/query-parser.d.ts +3 -0
  77. package/dist/swagger/adapter/prisma/index.d.cts +22 -0
  78. package/dist/swagger/adapter/prisma/index.d.mts +22 -0
  79. package/dist/swagger/adapter/prisma/index.d.ts +22 -0
  80. package/dist/swagger/json-schema-parser.d.cts +18 -0
  81. package/dist/swagger/json-schema-parser.d.mts +18 -0
  82. package/dist/swagger/json-schema-parser.d.ts +18 -0
  83. package/dist/swagger/parameters.d.cts +5 -0
  84. package/dist/swagger/parameters.d.mts +5 -0
  85. package/dist/swagger/parameters.d.ts +5 -0
  86. package/dist/swagger/types.d.cts +39 -0
  87. package/dist/swagger/types.d.mts +39 -0
  88. package/dist/swagger/types.d.ts +39 -0
  89. package/dist/swagger/utils/format-example-ref.d.cts +2 -0
  90. package/dist/swagger/utils/format-example-ref.d.mts +2 -0
  91. package/dist/swagger/utils/format-example-ref.d.ts +2 -0
  92. package/dist/swagger/utils/format-schema-ref.d.cts +2 -0
  93. package/dist/swagger/utils/format-schema-ref.d.mts +2 -0
  94. package/dist/swagger/utils/format-schema-ref.d.ts +2 -0
  95. package/dist/swagger/utils/get-models-accessible-routes.d.cts +4 -0
  96. package/dist/swagger/utils/get-models-accessible-routes.d.mts +4 -0
  97. package/dist/swagger/utils/get-models-accessible-routes.d.ts +4 -0
  98. package/dist/swagger/utils/get-swagger-paths.d.cts +12 -0
  99. package/dist/swagger/utils/get-swagger-paths.d.mts +12 -0
  100. package/dist/swagger/utils/get-swagger-paths.d.ts +12 -0
  101. package/dist/swagger/utils/get-swagger-tags.d.cts +4 -0
  102. package/dist/swagger/utils/get-swagger-tags.d.mts +4 -0
  103. package/dist/swagger/utils/get-swagger-tags.d.ts +4 -0
  104. package/dist/types.d.cts +106 -0
  105. package/dist/types.d.mts +106 -0
  106. package/dist/types.d.ts +106 -0
  107. package/dist/utils/format-resource-id.d.cts +2 -0
  108. package/dist/utils/format-resource-id.d.mts +2 -0
  109. package/dist/utils/format-resource-id.d.ts +2 -0
  110. package/dist/utils/get-accessible-routes.d.cts +3 -0
  111. package/dist/utils/get-accessible-routes.d.mts +3 -0
  112. package/dist/utils/get-accessible-routes.d.ts +3 -0
  113. package/dist/utils/get-resource-name-from-url.d.cts +5 -0
  114. package/dist/utils/get-resource-name-from-url.d.mts +5 -0
  115. package/dist/utils/get-resource-name-from-url.d.ts +5 -0
  116. package/dist/utils/get-route-type.d.cts +7 -0
  117. package/dist/utils/get-route-type.d.mts +7 -0
  118. package/dist/utils/get-route-type.d.ts +7 -0
  119. package/dist/utils/is-primitive.d.cts +2 -0
  120. package/dist/utils/is-primitive.d.mts +2 -0
  121. package/dist/utils/is-primitive.d.ts +2 -0
  122. package/dist/utils/validate-adapter-methods.d.cts +3 -0
  123. package/dist/utils/validate-adapter-methods.d.mts +3 -0
  124. package/dist/utils/validate-adapter-methods.d.ts +3 -0
  125. package/package.json +34 -17
  126. package/dist/chunk-GTXTWDUH.js +0 -77
  127. package/dist/chunk-GTXTWDUH.js.map +0 -1
  128. package/dist/chunk-VFQBXTKL.mjs +0 -73
  129. package/dist/chunk-VFQBXTKL.mjs.map +0 -1
  130. package/dist/index.js.map +0 -1
  131. package/dist/index.mjs.map +0 -1
  132. package/dist/next/index.js +0 -4870
  133. package/dist/next/index.js.map +0 -1
  134. package/dist/next/index.mjs.map +0 -1
  135. package/dist/types-C5c2M01-.d.mts +0 -138
  136. package/dist/types-C5c2M01-.d.ts +0 -138
@@ -0,0 +1,706 @@
1
+ import { m as modelsToRouteNames } from './models-to-route-names-CdwsK0V1.mjs';
2
+ import { createPaginationMetaSchemaObject } from '@visulima/pagination';
3
+ import { getJSONSchemaProperty, transformDMMF } from '@visulima/prisma-dmmf-transformer';
4
+ import { g as getAccessibleRoutes } from './get-accessible-routes-sV5SDdFn.mjs';
5
+ import { RouteType } from './RouteType-CB2xrWdf.mjs';
6
+
7
+ const formatSchemaReference = (schemaName) => `#/components/schemas/${schemaName}`;
8
+
9
+ const getJSONSchemaScalar = (fieldType) => {
10
+ switch (fieldType) {
11
+ case "BigInt":
12
+ case "Int": {
13
+ return "integer";
14
+ }
15
+ case "Boolean": {
16
+ return "boolean";
17
+ }
18
+ case "Bytes":
19
+ case "DateTime":
20
+ case "String": {
21
+ return "string";
22
+ }
23
+ case "Decimal":
24
+ case "Float": {
25
+ return "number";
26
+ }
27
+ case "Json": {
28
+ return "object";
29
+ }
30
+ case "Null": {
31
+ return "null";
32
+ }
33
+ default: {
34
+ return "";
35
+ }
36
+ }
37
+ };
38
+ const PAGINATION_SCHEMA_NAME = "PaginationData";
39
+ const methodsNames = [
40
+ { methodStart: "createOne", schemaNameStart: "Create" },
41
+ { methodStart: "updateOne", schemaNameStart: "Update" }
42
+ ];
43
+ class PrismaJsonSchemaParser {
44
+ // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
45
+ constructor(dmmf) {
46
+ this.dmmf = dmmf;
47
+ }
48
+ dmmf;
49
+ schemaInputTypes = /* @__PURE__ */ new Map();
50
+ // eslint-disable-next-line class-methods-use-this,@typescript-eslint/explicit-module-boundary-types
51
+ formatInputTypeData(inputType) {
52
+ if (inputType.kind === "object") {
53
+ const reference = formatSchemaReference(inputType.type.name);
54
+ if (inputType.isList) {
55
+ return {
56
+ items: {
57
+ $ref: reference
58
+ },
59
+ type: "array",
60
+ xml: {
61
+ name: inputType.type.name,
62
+ wrapped: true
63
+ }
64
+ };
65
+ }
66
+ return { $ref: reference };
67
+ }
68
+ const type = getJSONSchemaScalar(inputType.type);
69
+ if (inputType.isList) {
70
+ return {
71
+ items: {
72
+ type
73
+ },
74
+ type: "array",
75
+ xml: {
76
+ name: inputType.type.name,
77
+ wrapped: true
78
+ }
79
+ };
80
+ }
81
+ return { type };
82
+ }
83
+ getExampleModelsSchemas(modelNames, schemas) {
84
+ const referenceToSchema = (reference) => {
85
+ const name = reference.replace("#/components/schemas/", "");
86
+ const model = schemas[name];
87
+ const values = {};
88
+ Object.entries(model.properties ?? {}).forEach(([key, v]) => {
89
+ const type = v.type;
90
+ values[key] = type === "array" ? [arrayItemsToSchema(v.items)] : type;
91
+ });
92
+ return values;
93
+ };
94
+ const objectPropertiesToSchema = (objectProperties) => {
95
+ const values = {};
96
+ Object.entries(objectProperties).forEach(([key, value]) => {
97
+ values[key] = value.$ref === void 0 ? value.type : referenceToSchema(value.$ref);
98
+ });
99
+ return values;
100
+ };
101
+ const arrayItemsToSchema = (items) => {
102
+ const values = {};
103
+ Object.entries(items).forEach(([key, value]) => {
104
+ if (value.items.$ref !== void 0) {
105
+ values[key] = [referenceToSchema(value.items.$ref)];
106
+ } else if (value.type === "array") {
107
+ values[key] = [arrayItemsToSchema(value.items)];
108
+ } else if (value.type === "object") {
109
+ values[key] = objectPropertiesToSchema(value.properties);
110
+ } else {
111
+ values[key] = value.type;
112
+ }
113
+ });
114
+ return values;
115
+ };
116
+ return modelNames.reduce((accumulator, modelName) => {
117
+ const value = {};
118
+ const model = schemas[modelName];
119
+ Object.entries(model.properties).forEach(([key, v]) => {
120
+ const type = v.type;
121
+ if (type === "array") {
122
+ value[key] = [referenceToSchema(v.items.$ref)];
123
+ } else if (type === "object") {
124
+ value[key] = objectPropertiesToSchema(v.properties);
125
+ } else {
126
+ value[key] = type;
127
+ }
128
+ });
129
+ const pagination = this.getPaginationDataSchema()[PAGINATION_SCHEMA_NAME];
130
+ const meta = {};
131
+ Object.entries(pagination.properties).forEach(([key, v]) => {
132
+ meta[key] = v.type;
133
+ });
134
+ return {
135
+ ...accumulator,
136
+ [`${modelName}Page`]: {
137
+ value: {
138
+ data: [value],
139
+ meta
140
+ }
141
+ },
142
+ [`${modelName}s`]: {
143
+ value: [value]
144
+ },
145
+ [modelName]: {
146
+ value
147
+ }
148
+ };
149
+ }, {});
150
+ }
151
+ // eslint-disable-next-line class-methods-use-this
152
+ getPaginatedModelsSchemas(modelNames) {
153
+ return modelNames.reduce((accumulator, modelName) => {
154
+ return {
155
+ ...accumulator,
156
+ [`${modelName}Page`]: {
157
+ properties: {
158
+ data: {
159
+ items: {
160
+ $ref: formatSchemaReference(modelName)
161
+ },
162
+ type: "array",
163
+ xml: {
164
+ name: "data",
165
+ wrapped: true
166
+ }
167
+ },
168
+ meta: {
169
+ $ref: formatSchemaReference(PAGINATION_SCHEMA_NAME)
170
+ }
171
+ },
172
+ type: "object",
173
+ xml: {
174
+ name: `${modelName}Page`
175
+ }
176
+ }
177
+ };
178
+ }, {});
179
+ }
180
+ // eslint-disable-next-line class-methods-use-this
181
+ getPaginationDataSchema() {
182
+ return createPaginationMetaSchemaObject(PAGINATION_SCHEMA_NAME);
183
+ }
184
+ parseInputTypes(models) {
185
+ const definitions = models.reduce((accumulator, modelName) => {
186
+ const methods = methodsNames.map((method) => {
187
+ return {
188
+ name: `${method.methodStart}${modelName}`,
189
+ schemaName: `${method.schemaNameStart}${modelName}`
190
+ };
191
+ });
192
+ methods.forEach(({ name: method, schemaName }) => {
193
+ const dataFields = this.dmmf.mutationType.fieldMap[method].args[0].inputTypes[0].type.fields;
194
+ const requiredProperties = [];
195
+ const properties = dataFields.reduce((propertiesAccumulator, field) => {
196
+ if (field.inputTypes[0].kind === "scalar") {
197
+ const schema = getJSONSchemaProperty(
198
+ this.dmmf.datamodel,
199
+ {}
200
+ )({
201
+ name: field.name,
202
+ ...field.inputTypes[0]
203
+ });
204
+ const { type: schemaType } = schema[1];
205
+ if (schemaType && Array.isArray(schemaType)) {
206
+ if (schemaType.includes("null")) {
207
+ propertiesAccumulator[field.name] = {
208
+ ...schemaType,
209
+ nullable: true,
210
+ type: schemaType.filter((type) => type !== "null")
211
+ };
212
+ if (propertiesAccumulator[field.name].type.length === 1) {
213
+ propertiesAccumulator[field.name] = {
214
+ ...propertiesAccumulator[field.name],
215
+ type: propertiesAccumulator[field.name].type[0]
216
+ };
217
+ }
218
+ }
219
+ } else {
220
+ propertiesAccumulator[field.name] = schema[1];
221
+ }
222
+ } else {
223
+ const typeName = this.parseObjectInputType(field.inputTypes[0]);
224
+ propertiesAccumulator[field.name] = {
225
+ ...typeName,
226
+ nullable: field.isNullable
227
+ };
228
+ }
229
+ if (field.isRequired) {
230
+ requiredProperties.push(field.name);
231
+ }
232
+ return propertiesAccumulator;
233
+ }, {});
234
+ accumulator[schemaName] = {
235
+ properties,
236
+ type: "object",
237
+ xml: {
238
+ name: schemaName
239
+ }
240
+ };
241
+ if (requiredProperties.length > 0) {
242
+ accumulator[schemaName].required = requiredProperties;
243
+ }
244
+ });
245
+ return accumulator;
246
+ }, {});
247
+ this.schemaInputTypes.forEach((value, key) => {
248
+ definitions[key] = {
249
+ properties: value,
250
+ type: "object",
251
+ xml: {
252
+ name: key
253
+ }
254
+ };
255
+ });
256
+ return definitions;
257
+ }
258
+ parseModels() {
259
+ const modelsDefinitions = transformDMMF(this.dmmf).definitions;
260
+ Object.keys(modelsDefinitions).forEach((definition) => {
261
+ const { properties } = modelsDefinitions[definition];
262
+ Object.keys(properties).forEach((property) => {
263
+ if (Array.isArray(properties[property].type) && properties[property].type.includes("null")) {
264
+ properties[property].type = properties[property].type.filter((type) => type !== "null");
265
+ if (properties[property].type.length === 1) {
266
+ properties[property].type = properties[property].type[0];
267
+ }
268
+ properties[property].nullable = true;
269
+ }
270
+ });
271
+ });
272
+ return modelsDefinitions;
273
+ }
274
+ // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
275
+ parseObjectInputType(fieldType) {
276
+ if (fieldType.kind === "object") {
277
+ if (!this.schemaInputTypes.has(fieldType.type.name)) {
278
+ this.schemaInputTypes.set(fieldType.type.name, {});
279
+ fieldType.type.fields.forEach((field) => {
280
+ let fieldData = {};
281
+ if (field.inputTypes.length > 1) {
282
+ let nullable = false;
283
+ const anyOf = field.inputTypes.map((inputType) => {
284
+ const inputTypeData = this.formatInputTypeData(inputType);
285
+ if (inputTypeData.type === "null") {
286
+ nullable = true;
287
+ return;
288
+ }
289
+ return inputTypeData;
290
+ }).filter(Boolean);
291
+ if (anyOf.length === 1) {
292
+ fieldData = anyOf[0];
293
+ } else {
294
+ fieldData.anyOf = anyOf;
295
+ }
296
+ if (nullable) {
297
+ fieldData.nullable = true;
298
+ }
299
+ } else {
300
+ const inputType = field.inputTypes[0];
301
+ fieldData = this.formatInputTypeData(inputType);
302
+ }
303
+ this.schemaInputTypes.set(fieldType.type.name, {
304
+ ...this.schemaInputTypes.get(fieldType.type.name),
305
+ [field.name]: fieldData
306
+ });
307
+ field.inputTypes.forEach((inputType) => {
308
+ if (inputType.kind === "object") {
309
+ this.parseObjectInputType(inputType);
310
+ }
311
+ });
312
+ });
313
+ }
314
+ return { $ref: formatSchemaReference(fieldType.type.name) };
315
+ }
316
+ return { type: getJSONSchemaScalar(fieldType.type) };
317
+ }
318
+ }
319
+
320
+ const getModelsAccessibleRoutes = (modelNames, models, defaultExposeStrategy = "all") => (
321
+ // eslint-disable-next-line unicorn/no-array-reduce
322
+ modelNames.reduce((accumulator, modelName) => {
323
+ if (models?.[modelName]) {
324
+ return {
325
+ ...accumulator,
326
+ [modelName]: getAccessibleRoutes(models[modelName].only, models[modelName].exclude, defaultExposeStrategy)
327
+ };
328
+ }
329
+ return {
330
+ ...accumulator,
331
+ [modelName]: getAccessibleRoutes(void 0, void 0, defaultExposeStrategy)
332
+ };
333
+ }, {})
334
+ );
335
+
336
+ const queryParameters = {
337
+ distinct: {
338
+ description: "Fields to distinctively retrieve",
339
+ name: "distinct",
340
+ schema: {
341
+ type: "string"
342
+ }
343
+ },
344
+ include: {
345
+ description: "Include relations, same as select",
346
+ name: "include",
347
+ schema: {
348
+ type: "string"
349
+ }
350
+ },
351
+ limit: {
352
+ description: "Maximum number of elements to retrieve",
353
+ name: "limit",
354
+ schema: {
355
+ minimum: 0,
356
+ type: "integer"
357
+ }
358
+ },
359
+ orderBy: {
360
+ description: 'Field on which to order by a direction. See <a href="https://next-crud.js.org/query-params#orderBy">the docs</a>',
361
+ name: "orderBy",
362
+ schema: {
363
+ type: "string"
364
+ }
365
+ },
366
+ page: {
367
+ description: "Page number. Use only for pagination.",
368
+ name: "page",
369
+ schema: {
370
+ minimum: 1,
371
+ type: "integer"
372
+ }
373
+ },
374
+ select: {
375
+ description: "Fields to select. For nested fields, chain them separated with a dot, eg: user.posts",
376
+ name: "select",
377
+ schema: {
378
+ type: "string"
379
+ }
380
+ },
381
+ skip: {
382
+ description: "Number of rows to skip",
383
+ name: "skip",
384
+ schema: {
385
+ minimum: 0,
386
+ type: "integer"
387
+ }
388
+ },
389
+ where: {
390
+ description: 'Fields to filter. See <a href="https://next-crud.js.org/query-params#where">the docs</a>',
391
+ name: "where",
392
+ schema: {
393
+ type: "string"
394
+ }
395
+ }
396
+ };
397
+ const commonQueryParameters = [queryParameters.select, queryParameters.include];
398
+ const listQueryParameters = [
399
+ ...commonQueryParameters,
400
+ queryParameters.limit,
401
+ queryParameters.skip,
402
+ queryParameters.where,
403
+ queryParameters.orderBy,
404
+ queryParameters.page,
405
+ queryParameters.distinct
406
+ ];
407
+ const getQueryParameters = (routeType, additionalQueryParameters = []) => {
408
+ if (routeType === RouteType.READ_ALL) {
409
+ return [...listQueryParameters, ...additionalQueryParameters].filter(Boolean);
410
+ }
411
+ return [...commonQueryParameters, ...additionalQueryParameters].filter(Boolean);
412
+ };
413
+
414
+ const formatExampleReference = (schemaName) => `#/components/examples/${schemaName}`;
415
+
416
+ const generateContentForSchema = (schemaName, isArray) => {
417
+ if (isArray) {
418
+ return {
419
+ items: {
420
+ $ref: formatSchemaReference(schemaName)
421
+ },
422
+ type: "array"
423
+ };
424
+ }
425
+ return {
426
+ $ref: formatSchemaReference(schemaName)
427
+ };
428
+ };
429
+ const generateSwaggerResponse = (routeType, modelName) => {
430
+ if (routeType === RouteType.CREATE) {
431
+ return {
432
+ content: {
433
+ content: {
434
+ "application/json": {
435
+ example: formatExampleReference(modelName),
436
+ schema: generateContentForSchema(modelName)
437
+ }
438
+ },
439
+ description: `${modelName} created`
440
+ },
441
+ statusCode: 201
442
+ };
443
+ }
444
+ if (routeType === RouteType.DELETE) {
445
+ return {
446
+ content: {
447
+ content: {
448
+ "application/json": {
449
+ example: formatExampleReference(modelName),
450
+ schema: generateContentForSchema(modelName)
451
+ }
452
+ },
453
+ description: `${modelName} item deleted`
454
+ },
455
+ statusCode: 200
456
+ };
457
+ }
458
+ if (routeType === RouteType.READ_ALL) {
459
+ return {
460
+ content: {
461
+ content: {
462
+ "application/json": {
463
+ examples: {
464
+ Default: {
465
+ $ref: formatExampleReference(`${modelName}s`)
466
+ },
467
+ Pagination: {
468
+ $ref: formatExampleReference(`${modelName}Page`)
469
+ }
470
+ },
471
+ schema: {
472
+ oneOf: [generateContentForSchema(modelName, true), generateContentForSchema(`${modelName}Page`, false)]
473
+ }
474
+ }
475
+ },
476
+ description: `${modelName} list retrieved`
477
+ },
478
+ statusCode: 200
479
+ };
480
+ }
481
+ if (routeType === RouteType.READ_ONE) {
482
+ return {
483
+ content: {
484
+ content: {
485
+ "application/json": {
486
+ example: formatExampleReference(modelName),
487
+ schema: generateContentForSchema(modelName)
488
+ }
489
+ },
490
+ description: `${modelName} item retrieved`
491
+ },
492
+ statusCode: 200
493
+ };
494
+ }
495
+ if (routeType === RouteType.UPDATE) {
496
+ return {
497
+ content: {
498
+ content: {
499
+ "application/json": {
500
+ example: formatExampleReference(modelName),
501
+ schema: generateContentForSchema(modelName)
502
+ }
503
+ },
504
+ description: `${modelName} item updated`
505
+ },
506
+ statusCode: 200
507
+ };
508
+ }
509
+ return void 0;
510
+ };
511
+ const generateRequestBody = (schemaStartName, modelName) => {
512
+ return {
513
+ content: {
514
+ "application/json": {
515
+ schema: {
516
+ $ref: formatSchemaReference(`${schemaStartName}${modelName}`)
517
+ }
518
+ }
519
+ }
520
+ };
521
+ };
522
+ const getRouteTypeMethod = (routeType) => {
523
+ switch (routeType) {
524
+ case RouteType.CREATE: {
525
+ return "post";
526
+ }
527
+ case RouteType.DELETE: {
528
+ return "delete";
529
+ }
530
+ case RouteType.READ_ALL:
531
+ case RouteType.READ_ONE: {
532
+ return "get";
533
+ }
534
+ case RouteType.UPDATE: {
535
+ return "put";
536
+ }
537
+ default: {
538
+ throw new TypeError(`Method for route type ${routeType} was not found.`);
539
+ }
540
+ }
541
+ };
542
+ const generateSwaggerPathObject = ({
543
+ hasId,
544
+ modelName,
545
+ modelsConfig,
546
+ routeTypes,
547
+ tag
548
+ }) => {
549
+ const methods = {};
550
+ routeTypes.forEach((routeType) => {
551
+ if (routeTypes.includes(routeType)) {
552
+ const returnType = modelsConfig?.[modelName]?.routeTypes?.[routeType]?.response.name ?? modelsConfig?.[modelName]?.type?.name ?? modelName;
553
+ const method = getRouteTypeMethod(routeType);
554
+ const response = generateSwaggerResponse(routeType, returnType);
555
+ if (response === void 0) {
556
+ throw new TypeError(`Route type ${routeType}; response config was not found.`);
557
+ }
558
+ methods[method] = {
559
+ parameters: getQueryParameters(routeType).map((queryParameter) => {
560
+ return { ...queryParameter, in: "query" };
561
+ }),
562
+ responses: {
563
+ [response.statusCode]: response.content,
564
+ ...modelsConfig?.[modelName]?.routeTypes?.[routeType]?.responses
565
+ },
566
+ summary: modelsConfig?.[modelName]?.routeTypes?.[routeType]?.summary,
567
+ tags: [tag]
568
+ };
569
+ if (hasId) {
570
+ methods[method].parameters.push({
571
+ description: `ID of the ${modelName}`,
572
+ in: "path",
573
+ name: "id",
574
+ required: true,
575
+ schema: {
576
+ type: "string"
577
+ }
578
+ });
579
+ }
580
+ if (routeType === RouteType.UPDATE) {
581
+ methods[method].requestBody = generateRequestBody("Update", returnType);
582
+ } else if (routeType === RouteType.CREATE) {
583
+ methods[method].requestBody = generateRequestBody("Create", returnType);
584
+ }
585
+ }
586
+ });
587
+ return methods;
588
+ };
589
+ const getSwaggerPaths = ({ models, modelsConfig, routes, routesMap }) => (
590
+ // eslint-disable-next-line unicorn/no-array-reduce
591
+ Object.keys(routes).reduce((accumulator, value) => {
592
+ const routeTypes = routes[value];
593
+ const resourceName = models?.[value]?.name ? models[value].name : routesMap?.[value] ?? value;
594
+ const tag = modelsConfig?.[value]?.tag.name ?? value;
595
+ if (routeTypes.includes(RouteType.CREATE) || routeTypes.includes(RouteType.READ_ALL)) {
596
+ const path = `/${resourceName}`;
597
+ const routeTypesToUse = [RouteType.READ_ALL, RouteType.CREATE].filter((routeType) => routeTypes.includes(routeType));
598
+ accumulator[path] = generateSwaggerPathObject({
599
+ modelName: value,
600
+ modelsConfig,
601
+ routeTypes: routeTypesToUse,
602
+ tag
603
+ });
604
+ }
605
+ if (routeTypes.includes(RouteType.READ_ONE) || routeTypes.includes(RouteType.UPDATE) || routeTypes.includes(RouteType.DELETE)) {
606
+ const path = `/${resourceName}/{id}`;
607
+ const routeTypesToUse = [RouteType.READ_ONE, RouteType.UPDATE, RouteType.DELETE].filter((routeType) => routeTypes.includes(routeType));
608
+ accumulator[path] = generateSwaggerPathObject({
609
+ hasId: true,
610
+ modelName: value,
611
+ modelsConfig,
612
+ routeTypes: routeTypesToUse,
613
+ tag
614
+ });
615
+ }
616
+ return accumulator;
617
+ }, {})
618
+ );
619
+
620
+ const getSwaggerTags = (modelNames, modelsConfig) => modelNames.map((modelName) => {
621
+ if (modelsConfig?.[modelName]?.tag) {
622
+ return modelsConfig[modelName].tag;
623
+ }
624
+ return {
625
+ name: modelName
626
+ };
627
+ });
628
+
629
+ const overwritePathsExampleWithModel = (swaggerPaths, examples) => {
630
+ Object.values(swaggerPaths).forEach((pathSpec) => {
631
+ Object.values(pathSpec).forEach((methodSpec) => {
632
+ if (typeof methodSpec.responses === "object") {
633
+ Object.values(methodSpec.responses).forEach((responseSpec) => {
634
+ if (typeof responseSpec.content === "object") {
635
+ Object.values(responseSpec.content).forEach(
636
+ (contentSpec) => {
637
+ if (typeof contentSpec.example === "string") {
638
+ const example = contentSpec.example.replace("#/components/examples/", "");
639
+ if (examples[example]?.value !== void 0) {
640
+ contentSpec.example = examples[example].value;
641
+ }
642
+ }
643
+ }
644
+ );
645
+ }
646
+ });
647
+ }
648
+ });
649
+ });
650
+ return swaggerPaths;
651
+ };
652
+ const modelsToOpenApi = async ({
653
+ crud = { models: {} },
654
+ defaultExposeStrategy = "all",
655
+ models: ctorModels,
656
+ prismaClient,
657
+ swagger = { allowedMediaTypes: { "application/json": true }, models: {} }
658
+ }) => {
659
+ let dmmf;
660
+ let prismaDmmfModels;
661
+ if (prismaClient._dmmf !== void 0) {
662
+ dmmf = prismaClient._dmmf;
663
+ prismaDmmfModels = dmmf?.mappingsMap;
664
+ } else if (prismaClient._getDmmf !== void 0) {
665
+ dmmf = await prismaClient._getDmmf();
666
+ prismaDmmfModels = dmmf.mappingsMap;
667
+ }
668
+ if (dmmf === void 0) {
669
+ throw new TypeError("Couldn't get prisma client models");
670
+ }
671
+ const parser = new PrismaJsonSchemaParser(dmmf);
672
+ const definitions = parser.parseModels();
673
+ const dModels = Object.keys(definitions);
674
+ const schema = JSON.stringify({
675
+ ...definitions,
676
+ ...parser.parseInputTypes(dModels),
677
+ ...parser.getPaginationDataSchema(),
678
+ ...parser.getPaginatedModelsSchemas(dModels)
679
+ });
680
+ if (ctorModels !== void 0) {
681
+ ctorModels.forEach((model) => {
682
+ if (!Object.keys(prismaDmmfModels).includes(model)) {
683
+ throw new Error(`Model name ${model} is invalid.`);
684
+ }
685
+ });
686
+ }
687
+ const models = ctorModels ?? Object.keys(prismaDmmfModels);
688
+ const swaggerRoutes = getModelsAccessibleRoutes(models, crud.models, defaultExposeStrategy);
689
+ const swaggerTags = getSwaggerTags(models, swagger.models);
690
+ const swaggerPaths = getSwaggerPaths({
691
+ models: crud.models,
692
+ modelsConfig: swagger.models,
693
+ routes: swaggerRoutes,
694
+ routesMap: modelsToRouteNames(prismaDmmfModels, models)
695
+ });
696
+ const schemas = JSON.parse(schema.replaceAll("#/definitions", "#/components/schemas"));
697
+ const examples = parser.getExampleModelsSchemas(dModels, schemas);
698
+ return {
699
+ examples,
700
+ paths: overwritePathsExampleWithModel(swaggerPaths, examples),
701
+ schemas,
702
+ tags: swaggerTags
703
+ };
704
+ };
705
+
706
+ export { modelsToOpenApi as default };