prisma-swagger-autogen 1.0.3 → 1.0.5
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/dist/cli.cjs +4 -42
- package/dist/index.cjs +17 -93
- package/dist/index.js +189 -3
- package/package.json +6 -6
- package/dist/chunk-6R6DHPOL.js +0 -233
- package/dist/cli.d.cts +0 -2
- package/dist/cli.d.ts +0 -2
- package/dist/cli.js +0 -9
package/dist/cli.cjs
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
#!/usr/bin/env node
|
|
1
3
|
"use strict";
|
|
2
4
|
var __create = Object.create;
|
|
3
5
|
var __defProp = Object.defineProperty;
|
|
@@ -61,12 +63,7 @@ function loadDmmfFromProject(schemaPath) {
|
|
|
61
63
|
}
|
|
62
64
|
const datamodel = import_node_fs.default.readFileSync(resolvedSchemaPath, "utf8");
|
|
63
65
|
const require2 = getRequire();
|
|
64
|
-
|
|
65
|
-
try {
|
|
66
|
-
internals = require2("@prisma/internals");
|
|
67
|
-
} catch {
|
|
68
|
-
throw new Error(`Unable to load @prisma/internals`);
|
|
69
|
-
}
|
|
66
|
+
const internals = require2("@prisma/internals");
|
|
70
67
|
if (typeof internals.getDMMF !== "function") {
|
|
71
68
|
throw new Error(`@prisma/internals.getDMMF not available`);
|
|
72
69
|
}
|
|
@@ -180,41 +177,6 @@ function buildSchemasFromPrismaDmmf(schemaPath) {
|
|
|
180
177
|
schemas[putName] = putSchema;
|
|
181
178
|
schemas[listName] = listResponseSchema(`#/components/schemas/${getName}`);
|
|
182
179
|
}
|
|
183
|
-
schemas["ExceptionResponse"] = {
|
|
184
|
-
type: "object",
|
|
185
|
-
properties: {
|
|
186
|
-
detail: { type: "string" },
|
|
187
|
-
errors: { type: "array", items: { type: "string" } },
|
|
188
|
-
status: { type: "number" },
|
|
189
|
-
title: { type: "string" },
|
|
190
|
-
type: { type: "string" }
|
|
191
|
-
},
|
|
192
|
-
required: ["status", "title", "type"]
|
|
193
|
-
};
|
|
194
|
-
schemas["BadRequestResponse"] = {
|
|
195
|
-
allOf: [{ $ref: "#/components/schemas/ExceptionResponse" }],
|
|
196
|
-
example: {
|
|
197
|
-
status: 400,
|
|
198
|
-
title: "The request was invalid",
|
|
199
|
-
type: "https://tools.ietf.org/html/rfc7231#section-6.5.1"
|
|
200
|
-
}
|
|
201
|
-
};
|
|
202
|
-
schemas["NotFoundResponse"] = {
|
|
203
|
-
allOf: [{ $ref: "#/components/schemas/ExceptionResponse" }],
|
|
204
|
-
example: {
|
|
205
|
-
status: 404,
|
|
206
|
-
title: "The specified resource was not found",
|
|
207
|
-
type: "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.4"
|
|
208
|
-
}
|
|
209
|
-
};
|
|
210
|
-
schemas["InternalErrorResponse"] = {
|
|
211
|
-
allOf: [{ $ref: "#/components/schemas/ExceptionResponse" }],
|
|
212
|
-
example: {
|
|
213
|
-
status: 500,
|
|
214
|
-
title: "An error occurred while processing your request",
|
|
215
|
-
type: "https://tools.ietf.org/html/rfc7231#section-6.6.1"
|
|
216
|
-
}
|
|
217
|
-
};
|
|
218
180
|
return schemas;
|
|
219
181
|
}
|
|
220
182
|
function generateSwaggerConfigJs(schemas) {
|
|
@@ -254,7 +216,7 @@ async function run(args = []) {
|
|
|
254
216
|
}
|
|
255
217
|
|
|
256
218
|
// src/cli.ts
|
|
257
|
-
run(process.argv.slice(2)).catch((e) => {
|
|
219
|
+
void run(process.argv.slice(2)).catch((e) => {
|
|
258
220
|
console.error(e);
|
|
259
221
|
process.exitCode = 1;
|
|
260
222
|
});
|
package/dist/index.cjs
CHANGED
|
@@ -1,43 +1,8 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var
|
|
3
|
-
var
|
|
4
|
-
var
|
|
5
|
-
var
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __export = (target, all) => {
|
|
9
|
-
for (var name in all)
|
|
10
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
-
};
|
|
12
|
-
var __copyProps = (to, from, except, desc) => {
|
|
13
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
-
for (let key of __getOwnPropNames(from))
|
|
15
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
-
}
|
|
18
|
-
return to;
|
|
19
|
-
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
-
|
|
30
|
-
// src/index.ts
|
|
31
|
-
var index_exports = {};
|
|
32
|
-
__export(index_exports, {
|
|
33
|
-
run: () => run
|
|
34
|
-
});
|
|
35
|
-
module.exports = __toCommonJS(index_exports);
|
|
36
|
-
var import_node_fs = __toESM(require("fs"), 1);
|
|
37
|
-
var import_node_path = __toESM(require("path"), 1);
|
|
38
|
-
var import_node_module = require("module");
|
|
39
|
-
var import_glob = require("glob");
|
|
40
|
-
var import_meta = {};
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }// src/index.ts
|
|
2
|
+
var _fs = require('fs'); var _fs2 = _interopRequireDefault(_fs);
|
|
3
|
+
var _path = require('path'); var _path2 = _interopRequireDefault(_path);
|
|
4
|
+
var _module = require('module');
|
|
5
|
+
var _glob = require('glob');
|
|
41
6
|
var CONFIG = {
|
|
42
7
|
projectRoot: process.cwd(),
|
|
43
8
|
controllersGlob: "./src/web/api/controllers/**/*.ts",
|
|
@@ -54,29 +19,24 @@ var CONFIG = {
|
|
|
54
19
|
omitFieldsInWriteDtos: /* @__PURE__ */ new Set(["id", "createdAt", "updatedAt", "v"])
|
|
55
20
|
};
|
|
56
21
|
function ensurePosix(p) {
|
|
57
|
-
return p.split(
|
|
22
|
+
return p.split(_path2.default.sep).join(_path2.default.posix.sep);
|
|
58
23
|
}
|
|
59
24
|
function pluralize(name) {
|
|
60
25
|
if (name.endsWith("s")) return `${name}es`;
|
|
61
26
|
return `${name}s`;
|
|
62
27
|
}
|
|
63
28
|
function getRequire() {
|
|
64
|
-
const base = typeof __filename !== "undefined" ? __filename :
|
|
65
|
-
return (0,
|
|
29
|
+
const base = typeof __filename !== "undefined" ? __filename : import.meta.url;
|
|
30
|
+
return _module.createRequire.call(void 0, base);
|
|
66
31
|
}
|
|
67
32
|
function loadDmmfFromProject(schemaPath) {
|
|
68
|
-
const resolvedSchemaPath = schemaPath ?
|
|
69
|
-
if (!
|
|
33
|
+
const resolvedSchemaPath = schemaPath ? _path2.default.resolve(process.cwd(), schemaPath) : _path2.default.resolve(process.cwd(), "prisma/schema.prisma");
|
|
34
|
+
if (!_fs2.default.existsSync(resolvedSchemaPath)) {
|
|
70
35
|
throw new Error(`Prisma schema not found at ${resolvedSchemaPath}`);
|
|
71
36
|
}
|
|
72
|
-
const datamodel =
|
|
37
|
+
const datamodel = _fs2.default.readFileSync(resolvedSchemaPath, "utf8");
|
|
73
38
|
const require2 = getRequire();
|
|
74
|
-
|
|
75
|
-
try {
|
|
76
|
-
internals = require2("@prisma/internals");
|
|
77
|
-
} catch {
|
|
78
|
-
throw new Error(`Unable to load @prisma/internals`);
|
|
79
|
-
}
|
|
39
|
+
const internals = require2("@prisma/internals");
|
|
80
40
|
if (typeof internals.getDMMF !== "function") {
|
|
81
41
|
throw new Error(`@prisma/internals.getDMMF not available`);
|
|
82
42
|
}
|
|
@@ -190,45 +150,10 @@ function buildSchemasFromPrismaDmmf(schemaPath) {
|
|
|
190
150
|
schemas[putName] = putSchema;
|
|
191
151
|
schemas[listName] = listResponseSchema(`#/components/schemas/${getName}`);
|
|
192
152
|
}
|
|
193
|
-
schemas["ExceptionResponse"] = {
|
|
194
|
-
type: "object",
|
|
195
|
-
properties: {
|
|
196
|
-
detail: { type: "string" },
|
|
197
|
-
errors: { type: "array", items: { type: "string" } },
|
|
198
|
-
status: { type: "number" },
|
|
199
|
-
title: { type: "string" },
|
|
200
|
-
type: { type: "string" }
|
|
201
|
-
},
|
|
202
|
-
required: ["status", "title", "type"]
|
|
203
|
-
};
|
|
204
|
-
schemas["BadRequestResponse"] = {
|
|
205
|
-
allOf: [{ $ref: "#/components/schemas/ExceptionResponse" }],
|
|
206
|
-
example: {
|
|
207
|
-
status: 400,
|
|
208
|
-
title: "The request was invalid",
|
|
209
|
-
type: "https://tools.ietf.org/html/rfc7231#section-6.5.1"
|
|
210
|
-
}
|
|
211
|
-
};
|
|
212
|
-
schemas["NotFoundResponse"] = {
|
|
213
|
-
allOf: [{ $ref: "#/components/schemas/ExceptionResponse" }],
|
|
214
|
-
example: {
|
|
215
|
-
status: 404,
|
|
216
|
-
title: "The specified resource was not found",
|
|
217
|
-
type: "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.4"
|
|
218
|
-
}
|
|
219
|
-
};
|
|
220
|
-
schemas["InternalErrorResponse"] = {
|
|
221
|
-
allOf: [{ $ref: "#/components/schemas/ExceptionResponse" }],
|
|
222
|
-
example: {
|
|
223
|
-
status: 500,
|
|
224
|
-
title: "An error occurred while processing your request",
|
|
225
|
-
type: "https://tools.ietf.org/html/rfc7231#section-6.6.1"
|
|
226
|
-
}
|
|
227
|
-
};
|
|
228
153
|
return schemas;
|
|
229
154
|
}
|
|
230
155
|
function generateSwaggerConfigJs(schemas) {
|
|
231
|
-
const routes = (0,
|
|
156
|
+
const routes = _glob.globSync.call(void 0, CONFIG.controllersGlob, { nodir: true }).map((p) => ensurePosix(p));
|
|
232
157
|
const docs = {
|
|
233
158
|
info: { title: CONFIG.serviceTitle },
|
|
234
159
|
servers: [{ url: CONFIG.serverUrl }],
|
|
@@ -254,7 +179,7 @@ function generateSwaggerConfigJs(schemas) {
|
|
|
254
179
|
const docs = ${JSON.stringify(docs, null, 2)};
|
|
255
180
|
const routes = ${JSON.stringify(routes, null, 2)};
|
|
256
181
|
swaggerAutogen('${ensurePosix(CONFIG.openapiOut)}', routes, docs);`;
|
|
257
|
-
|
|
182
|
+
_fs2.default.writeFileSync(_path2.default.resolve(CONFIG.projectRoot, CONFIG.outFile), fileContent, "utf8");
|
|
258
183
|
}
|
|
259
184
|
async function run(args = []) {
|
|
260
185
|
const schemaFlagIndex = args.findIndex((a) => a === "--schema");
|
|
@@ -262,7 +187,6 @@ async function run(args = []) {
|
|
|
262
187
|
const schemas = buildSchemasFromPrismaDmmf(schemaPath);
|
|
263
188
|
generateSwaggerConfigJs(schemas);
|
|
264
189
|
}
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
});
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
exports.run = run;
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,192 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { createRequire } from "module";
|
|
5
|
+
import { globSync } from "glob";
|
|
6
|
+
var CONFIG = {
|
|
7
|
+
projectRoot: process.cwd(),
|
|
8
|
+
controllersGlob: "./src/web/api/controllers/**/*.ts",
|
|
9
|
+
outFile: "./swagger.config.js",
|
|
10
|
+
openapiOut: "./src/web/api/openapi.json",
|
|
11
|
+
serviceTitle: "Prescription Service",
|
|
12
|
+
serverUrl: "http://localhost:3008",
|
|
13
|
+
securitySchemeName: "keycloakOAuth",
|
|
14
|
+
oauth: {
|
|
15
|
+
tokenUrl: "http://auth.localhost/realms/haemo/protocol/openid-connect/token",
|
|
16
|
+
refreshUrl: "http://auth.localhost/realms/haemo/protocol/openid-connect/refresh",
|
|
17
|
+
scopes: { openid: "openid scope" }
|
|
18
|
+
},
|
|
19
|
+
omitFieldsInWriteDtos: /* @__PURE__ */ new Set(["id", "createdAt", "updatedAt", "v"])
|
|
20
|
+
};
|
|
21
|
+
function ensurePosix(p) {
|
|
22
|
+
return p.split(path.sep).join(path.posix.sep);
|
|
23
|
+
}
|
|
24
|
+
function pluralize(name) {
|
|
25
|
+
if (name.endsWith("s")) return `${name}es`;
|
|
26
|
+
return `${name}s`;
|
|
27
|
+
}
|
|
28
|
+
function getRequire() {
|
|
29
|
+
const base = typeof __filename !== "undefined" ? __filename : import.meta.url;
|
|
30
|
+
return createRequire(base);
|
|
31
|
+
}
|
|
32
|
+
function loadDmmfFromProject(schemaPath) {
|
|
33
|
+
const resolvedSchemaPath = schemaPath ? path.resolve(process.cwd(), schemaPath) : path.resolve(process.cwd(), "prisma/schema.prisma");
|
|
34
|
+
if (!fs.existsSync(resolvedSchemaPath)) {
|
|
35
|
+
throw new Error(`Prisma schema not found at ${resolvedSchemaPath}`);
|
|
36
|
+
}
|
|
37
|
+
const datamodel = fs.readFileSync(resolvedSchemaPath, "utf8");
|
|
38
|
+
const require2 = getRequire();
|
|
39
|
+
const internals = require2("@prisma/internals");
|
|
40
|
+
if (typeof internals.getDMMF !== "function") {
|
|
41
|
+
throw new Error(`@prisma/internals.getDMMF not available`);
|
|
42
|
+
}
|
|
43
|
+
return internals.getDMMF({ datamodel });
|
|
44
|
+
}
|
|
45
|
+
function scalarToSchema(scalar) {
|
|
46
|
+
switch (scalar) {
|
|
47
|
+
case "String":
|
|
48
|
+
return { type: "string" };
|
|
49
|
+
case "Boolean":
|
|
50
|
+
return { type: "boolean" };
|
|
51
|
+
case "Int":
|
|
52
|
+
return { type: "integer" };
|
|
53
|
+
case "BigInt":
|
|
54
|
+
return { type: "integer", format: "int64" };
|
|
55
|
+
case "Float":
|
|
56
|
+
return { type: "number" };
|
|
57
|
+
case "Decimal":
|
|
58
|
+
return { type: "number" };
|
|
59
|
+
case "DateTime":
|
|
60
|
+
return { type: "string", format: "date-time" };
|
|
61
|
+
case "Json":
|
|
62
|
+
return { type: "object" };
|
|
63
|
+
case "Bytes":
|
|
64
|
+
return { type: "string", format: "byte" };
|
|
65
|
+
default:
|
|
66
|
+
return { type: "string" };
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function fieldSchema(field, getRefName) {
|
|
70
|
+
if (field.kind === "scalar") {
|
|
71
|
+
const base = scalarToSchema(field.type);
|
|
72
|
+
if (field.isList) return { type: "array", items: base };
|
|
73
|
+
return base;
|
|
74
|
+
}
|
|
75
|
+
if (field.kind === "enum") {
|
|
76
|
+
const base = { $ref: `#/components/schemas/${field.type}` };
|
|
77
|
+
if (field.isList) return { type: "array", items: base };
|
|
78
|
+
return base;
|
|
79
|
+
}
|
|
80
|
+
if (field.kind === "object") {
|
|
81
|
+
const ref = { $ref: `#/components/schemas/${getRefName(String(field.type))}` };
|
|
82
|
+
if (field.isList) return { type: "array", items: ref };
|
|
83
|
+
return ref;
|
|
84
|
+
}
|
|
85
|
+
return { type: "object" };
|
|
86
|
+
}
|
|
87
|
+
function modelToGetSchema(model, getRefName) {
|
|
88
|
+
const properties = {};
|
|
89
|
+
const required = [];
|
|
90
|
+
for (const f of model.fields) {
|
|
91
|
+
properties[f.name] = fieldSchema(f, getRefName);
|
|
92
|
+
if (f.isRequired) required.push(f.name);
|
|
93
|
+
}
|
|
94
|
+
const schema = { type: "object", properties };
|
|
95
|
+
if (required.length) schema.required = required;
|
|
96
|
+
return schema;
|
|
97
|
+
}
|
|
98
|
+
function stripWriteFields(model, getSchema, omit) {
|
|
99
|
+
const schema = JSON.parse(JSON.stringify(getSchema));
|
|
100
|
+
if (!schema.properties) return schema;
|
|
101
|
+
const relationFieldNames = new Set(model.fields.filter((f) => f.kind === "object").map((f) => f.name));
|
|
102
|
+
for (const key of Object.keys(schema.properties)) {
|
|
103
|
+
if (omit.has(key) || relationFieldNames.has(key)) {
|
|
104
|
+
delete schema.properties[key];
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (Array.isArray(schema.required)) {
|
|
108
|
+
schema.required = schema.required.filter((k) => !omit.has(k) && !relationFieldNames.has(k));
|
|
109
|
+
if (schema.required.length === 0) delete schema.required;
|
|
110
|
+
}
|
|
111
|
+
return schema;
|
|
112
|
+
}
|
|
113
|
+
function makeAllOptional(schema) {
|
|
114
|
+
const s = JSON.parse(JSON.stringify(schema));
|
|
115
|
+
delete s.required;
|
|
116
|
+
return s;
|
|
117
|
+
}
|
|
118
|
+
function listResponseSchema(itemRef) {
|
|
119
|
+
return {
|
|
120
|
+
type: "object",
|
|
121
|
+
properties: {
|
|
122
|
+
count: { type: "number" },
|
|
123
|
+
hasPreviousPage: { type: "boolean" },
|
|
124
|
+
hasNextPage: { type: "boolean" },
|
|
125
|
+
pageNumber: { type: "number" },
|
|
126
|
+
pageSize: { type: "number" },
|
|
127
|
+
totalPages: { type: "number" },
|
|
128
|
+
items: { type: "array", items: { $ref: itemRef } }
|
|
129
|
+
},
|
|
130
|
+
required: ["count", "hasPreviousPage", "hasNextPage", "pageNumber", "pageSize", "totalPages", "items"]
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
function buildSchemasFromPrismaDmmf(schemaPath) {
|
|
134
|
+
const dmmf = loadDmmfFromProject(schemaPath);
|
|
135
|
+
const schemas = {};
|
|
136
|
+
const getRefName = (modelName) => `Get${modelName}Response`;
|
|
137
|
+
for (const e of dmmf.datamodel.enums) {
|
|
138
|
+
schemas[e.name] = { type: "string", enum: e.values.map((v) => v.name) };
|
|
139
|
+
}
|
|
140
|
+
for (const model of dmmf.datamodel.models) {
|
|
141
|
+
const getName = `Get${model.name}Response`;
|
|
142
|
+
const postName = `Post${model.name}Request`;
|
|
143
|
+
const putName = `Put${model.name}Request`;
|
|
144
|
+
const listName = `List${pluralize(model.name)}Response`;
|
|
145
|
+
const getSchema = modelToGetSchema(model, getRefName);
|
|
146
|
+
const postSchema = stripWriteFields(model, getSchema, CONFIG.omitFieldsInWriteDtos);
|
|
147
|
+
const putSchema = makeAllOptional(postSchema);
|
|
148
|
+
schemas[getName] = getSchema;
|
|
149
|
+
schemas[postName] = postSchema;
|
|
150
|
+
schemas[putName] = putSchema;
|
|
151
|
+
schemas[listName] = listResponseSchema(`#/components/schemas/${getName}`);
|
|
152
|
+
}
|
|
153
|
+
return schemas;
|
|
154
|
+
}
|
|
155
|
+
function generateSwaggerConfigJs(schemas) {
|
|
156
|
+
const routes = globSync(CONFIG.controllersGlob, { nodir: true }).map((p) => ensurePosix(p));
|
|
157
|
+
const docs = {
|
|
158
|
+
info: { title: CONFIG.serviceTitle },
|
|
159
|
+
servers: [{ url: CONFIG.serverUrl }],
|
|
160
|
+
components: {
|
|
161
|
+
schemas,
|
|
162
|
+
securitySchemes: {
|
|
163
|
+
[CONFIG.securitySchemeName]: {
|
|
164
|
+
type: "oauth2",
|
|
165
|
+
description: "This API uses OAuth2 with the password flow.",
|
|
166
|
+
flows: {
|
|
167
|
+
password: {
|
|
168
|
+
tokenUrl: CONFIG.oauth.tokenUrl,
|
|
169
|
+
refreshUrl: CONFIG.oauth.refreshUrl,
|
|
170
|
+
scopes: CONFIG.oauth.scopes
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
security: [{ [CONFIG.securitySchemeName]: ["openid"] }]
|
|
177
|
+
};
|
|
178
|
+
const fileContent = `const swaggerAutogen = require('swagger-autogen')();
|
|
179
|
+
const docs = ${JSON.stringify(docs, null, 2)};
|
|
180
|
+
const routes = ${JSON.stringify(routes, null, 2)};
|
|
181
|
+
swaggerAutogen('${ensurePosix(CONFIG.openapiOut)}', routes, docs);`;
|
|
182
|
+
fs.writeFileSync(path.resolve(CONFIG.projectRoot, CONFIG.outFile), fileContent, "utf8");
|
|
183
|
+
}
|
|
184
|
+
async function run(args = []) {
|
|
185
|
+
const schemaFlagIndex = args.findIndex((a) => a === "--schema");
|
|
186
|
+
const schemaPath = schemaFlagIndex >= 0 ? args[schemaFlagIndex + 1] : void 0;
|
|
187
|
+
const schemas = buildSchemasFromPrismaDmmf(schemaPath);
|
|
188
|
+
generateSwaggerConfigJs(schemas);
|
|
189
|
+
}
|
|
4
190
|
export {
|
|
5
191
|
run
|
|
6
192
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prisma-swagger-autogen",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "Generate swagger-autogen config + Prisma DMMF schemas and fix swagger-autogen output.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Joyce Marvin Rafflenbeul",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
}
|
|
32
32
|
},
|
|
33
33
|
"bin": {
|
|
34
|
-
"prisma-swagger-autogen": "
|
|
34
|
+
"prisma-swagger-autogen": "dist/cli.cjs"
|
|
35
35
|
},
|
|
36
36
|
"files": [
|
|
37
37
|
"dist",
|
|
@@ -39,20 +39,20 @@
|
|
|
39
39
|
"LICENSE"
|
|
40
40
|
],
|
|
41
41
|
"scripts": {
|
|
42
|
-
"build": "tsup
|
|
42
|
+
"build": "tsup && chmod +x dist/cli.cjs",
|
|
43
43
|
"prepublishOnly": "npm run build"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@prisma/internals": "^6.0.0"
|
|
46
|
+
"@prisma/internals": "^6.0.0",
|
|
47
|
+
"glob": "^10.3.10"
|
|
47
48
|
},
|
|
48
49
|
"peerDependencies": {
|
|
49
50
|
"@prisma/client": ">=4",
|
|
50
|
-
"glob": ">=10",
|
|
51
51
|
"swagger-autogen": ">=2"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@types/node": "^25.1.0",
|
|
55
|
-
"tsup": "^8.
|
|
55
|
+
"tsup": "^8.5.1",
|
|
56
56
|
"typescript": "^5.0.0"
|
|
57
57
|
}
|
|
58
58
|
}
|
package/dist/chunk-6R6DHPOL.js
DELETED
|
@@ -1,233 +0,0 @@
|
|
|
1
|
-
// src/index.ts
|
|
2
|
-
import fs from "fs";
|
|
3
|
-
import path from "path";
|
|
4
|
-
import { createRequire } from "module";
|
|
5
|
-
import { globSync } from "glob";
|
|
6
|
-
var CONFIG = {
|
|
7
|
-
projectRoot: process.cwd(),
|
|
8
|
-
controllersGlob: "./src/web/api/controllers/**/*.ts",
|
|
9
|
-
outFile: "./swagger.config.js",
|
|
10
|
-
openapiOut: "./src/web/api/openapi.json",
|
|
11
|
-
serviceTitle: "Prescription Service",
|
|
12
|
-
serverUrl: "http://localhost:3008",
|
|
13
|
-
securitySchemeName: "keycloakOAuth",
|
|
14
|
-
oauth: {
|
|
15
|
-
tokenUrl: "http://auth.localhost/realms/haemo/protocol/openid-connect/token",
|
|
16
|
-
refreshUrl: "http://auth.localhost/realms/haemo/protocol/openid-connect/refresh",
|
|
17
|
-
scopes: { openid: "openid scope" }
|
|
18
|
-
},
|
|
19
|
-
omitFieldsInWriteDtos: /* @__PURE__ */ new Set(["id", "createdAt", "updatedAt", "v"])
|
|
20
|
-
};
|
|
21
|
-
function ensurePosix(p) {
|
|
22
|
-
return p.split(path.sep).join(path.posix.sep);
|
|
23
|
-
}
|
|
24
|
-
function pluralize(name) {
|
|
25
|
-
if (name.endsWith("s")) return `${name}es`;
|
|
26
|
-
return `${name}s`;
|
|
27
|
-
}
|
|
28
|
-
function getRequire() {
|
|
29
|
-
const base = typeof __filename !== "undefined" ? __filename : import.meta.url;
|
|
30
|
-
return createRequire(base);
|
|
31
|
-
}
|
|
32
|
-
function loadDmmfFromProject(schemaPath) {
|
|
33
|
-
const resolvedSchemaPath = schemaPath ? path.resolve(process.cwd(), schemaPath) : path.resolve(process.cwd(), "prisma/schema.prisma");
|
|
34
|
-
if (!fs.existsSync(resolvedSchemaPath)) {
|
|
35
|
-
throw new Error(`Prisma schema not found at ${resolvedSchemaPath}`);
|
|
36
|
-
}
|
|
37
|
-
const datamodel = fs.readFileSync(resolvedSchemaPath, "utf8");
|
|
38
|
-
const require2 = getRequire();
|
|
39
|
-
let internals;
|
|
40
|
-
try {
|
|
41
|
-
internals = require2("@prisma/internals");
|
|
42
|
-
} catch {
|
|
43
|
-
throw new Error(`Unable to load @prisma/internals`);
|
|
44
|
-
}
|
|
45
|
-
if (typeof internals.getDMMF !== "function") {
|
|
46
|
-
throw new Error(`@prisma/internals.getDMMF not available`);
|
|
47
|
-
}
|
|
48
|
-
return internals.getDMMF({ datamodel });
|
|
49
|
-
}
|
|
50
|
-
function scalarToSchema(scalar) {
|
|
51
|
-
switch (scalar) {
|
|
52
|
-
case "String":
|
|
53
|
-
return { type: "string" };
|
|
54
|
-
case "Boolean":
|
|
55
|
-
return { type: "boolean" };
|
|
56
|
-
case "Int":
|
|
57
|
-
return { type: "integer" };
|
|
58
|
-
case "BigInt":
|
|
59
|
-
return { type: "integer", format: "int64" };
|
|
60
|
-
case "Float":
|
|
61
|
-
return { type: "number" };
|
|
62
|
-
case "Decimal":
|
|
63
|
-
return { type: "number" };
|
|
64
|
-
case "DateTime":
|
|
65
|
-
return { type: "string", format: "date-time" };
|
|
66
|
-
case "Json":
|
|
67
|
-
return { type: "object" };
|
|
68
|
-
case "Bytes":
|
|
69
|
-
return { type: "string", format: "byte" };
|
|
70
|
-
default:
|
|
71
|
-
return { type: "string" };
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
function fieldSchema(field, getRefName) {
|
|
75
|
-
if (field.kind === "scalar") {
|
|
76
|
-
const base = scalarToSchema(field.type);
|
|
77
|
-
if (field.isList) return { type: "array", items: base };
|
|
78
|
-
return base;
|
|
79
|
-
}
|
|
80
|
-
if (field.kind === "enum") {
|
|
81
|
-
const base = { $ref: `#/components/schemas/${field.type}` };
|
|
82
|
-
if (field.isList) return { type: "array", items: base };
|
|
83
|
-
return base;
|
|
84
|
-
}
|
|
85
|
-
if (field.kind === "object") {
|
|
86
|
-
const ref = { $ref: `#/components/schemas/${getRefName(String(field.type))}` };
|
|
87
|
-
if (field.isList) return { type: "array", items: ref };
|
|
88
|
-
return ref;
|
|
89
|
-
}
|
|
90
|
-
return { type: "object" };
|
|
91
|
-
}
|
|
92
|
-
function modelToGetSchema(model, getRefName) {
|
|
93
|
-
const properties = {};
|
|
94
|
-
const required = [];
|
|
95
|
-
for (const f of model.fields) {
|
|
96
|
-
properties[f.name] = fieldSchema(f, getRefName);
|
|
97
|
-
if (f.isRequired) required.push(f.name);
|
|
98
|
-
}
|
|
99
|
-
const schema = { type: "object", properties };
|
|
100
|
-
if (required.length) schema.required = required;
|
|
101
|
-
return schema;
|
|
102
|
-
}
|
|
103
|
-
function stripWriteFields(model, getSchema, omit) {
|
|
104
|
-
const schema = JSON.parse(JSON.stringify(getSchema));
|
|
105
|
-
if (!schema.properties) return schema;
|
|
106
|
-
const relationFieldNames = new Set(model.fields.filter((f) => f.kind === "object").map((f) => f.name));
|
|
107
|
-
for (const key of Object.keys(schema.properties)) {
|
|
108
|
-
if (omit.has(key) || relationFieldNames.has(key)) {
|
|
109
|
-
delete schema.properties[key];
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
if (Array.isArray(schema.required)) {
|
|
113
|
-
schema.required = schema.required.filter((k) => !omit.has(k) && !relationFieldNames.has(k));
|
|
114
|
-
if (schema.required.length === 0) delete schema.required;
|
|
115
|
-
}
|
|
116
|
-
return schema;
|
|
117
|
-
}
|
|
118
|
-
function makeAllOptional(schema) {
|
|
119
|
-
const s = JSON.parse(JSON.stringify(schema));
|
|
120
|
-
delete s.required;
|
|
121
|
-
return s;
|
|
122
|
-
}
|
|
123
|
-
function listResponseSchema(itemRef) {
|
|
124
|
-
return {
|
|
125
|
-
type: "object",
|
|
126
|
-
properties: {
|
|
127
|
-
count: { type: "number" },
|
|
128
|
-
hasPreviousPage: { type: "boolean" },
|
|
129
|
-
hasNextPage: { type: "boolean" },
|
|
130
|
-
pageNumber: { type: "number" },
|
|
131
|
-
pageSize: { type: "number" },
|
|
132
|
-
totalPages: { type: "number" },
|
|
133
|
-
items: { type: "array", items: { $ref: itemRef } }
|
|
134
|
-
},
|
|
135
|
-
required: ["count", "hasPreviousPage", "hasNextPage", "pageNumber", "pageSize", "totalPages", "items"]
|
|
136
|
-
};
|
|
137
|
-
}
|
|
138
|
-
function buildSchemasFromPrismaDmmf(schemaPath) {
|
|
139
|
-
const dmmf = loadDmmfFromProject(schemaPath);
|
|
140
|
-
const schemas = {};
|
|
141
|
-
const getRefName = (modelName) => `Get${modelName}Response`;
|
|
142
|
-
for (const e of dmmf.datamodel.enums) {
|
|
143
|
-
schemas[e.name] = { type: "string", enum: e.values.map((v) => v.name) };
|
|
144
|
-
}
|
|
145
|
-
for (const model of dmmf.datamodel.models) {
|
|
146
|
-
const getName = `Get${model.name}Response`;
|
|
147
|
-
const postName = `Post${model.name}Request`;
|
|
148
|
-
const putName = `Put${model.name}Request`;
|
|
149
|
-
const listName = `List${pluralize(model.name)}Response`;
|
|
150
|
-
const getSchema = modelToGetSchema(model, getRefName);
|
|
151
|
-
const postSchema = stripWriteFields(model, getSchema, CONFIG.omitFieldsInWriteDtos);
|
|
152
|
-
const putSchema = makeAllOptional(postSchema);
|
|
153
|
-
schemas[getName] = getSchema;
|
|
154
|
-
schemas[postName] = postSchema;
|
|
155
|
-
schemas[putName] = putSchema;
|
|
156
|
-
schemas[listName] = listResponseSchema(`#/components/schemas/${getName}`);
|
|
157
|
-
}
|
|
158
|
-
schemas["ExceptionResponse"] = {
|
|
159
|
-
type: "object",
|
|
160
|
-
properties: {
|
|
161
|
-
detail: { type: "string" },
|
|
162
|
-
errors: { type: "array", items: { type: "string" } },
|
|
163
|
-
status: { type: "number" },
|
|
164
|
-
title: { type: "string" },
|
|
165
|
-
type: { type: "string" }
|
|
166
|
-
},
|
|
167
|
-
required: ["status", "title", "type"]
|
|
168
|
-
};
|
|
169
|
-
schemas["BadRequestResponse"] = {
|
|
170
|
-
allOf: [{ $ref: "#/components/schemas/ExceptionResponse" }],
|
|
171
|
-
example: {
|
|
172
|
-
status: 400,
|
|
173
|
-
title: "The request was invalid",
|
|
174
|
-
type: "https://tools.ietf.org/html/rfc7231#section-6.5.1"
|
|
175
|
-
}
|
|
176
|
-
};
|
|
177
|
-
schemas["NotFoundResponse"] = {
|
|
178
|
-
allOf: [{ $ref: "#/components/schemas/ExceptionResponse" }],
|
|
179
|
-
example: {
|
|
180
|
-
status: 404,
|
|
181
|
-
title: "The specified resource was not found",
|
|
182
|
-
type: "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.4"
|
|
183
|
-
}
|
|
184
|
-
};
|
|
185
|
-
schemas["InternalErrorResponse"] = {
|
|
186
|
-
allOf: [{ $ref: "#/components/schemas/ExceptionResponse" }],
|
|
187
|
-
example: {
|
|
188
|
-
status: 500,
|
|
189
|
-
title: "An error occurred while processing your request",
|
|
190
|
-
type: "https://tools.ietf.org/html/rfc7231#section-6.6.1"
|
|
191
|
-
}
|
|
192
|
-
};
|
|
193
|
-
return schemas;
|
|
194
|
-
}
|
|
195
|
-
function generateSwaggerConfigJs(schemas) {
|
|
196
|
-
const routes = globSync(CONFIG.controllersGlob, { nodir: true }).map((p) => ensurePosix(p));
|
|
197
|
-
const docs = {
|
|
198
|
-
info: { title: CONFIG.serviceTitle },
|
|
199
|
-
servers: [{ url: CONFIG.serverUrl }],
|
|
200
|
-
components: {
|
|
201
|
-
schemas,
|
|
202
|
-
securitySchemes: {
|
|
203
|
-
[CONFIG.securitySchemeName]: {
|
|
204
|
-
type: "oauth2",
|
|
205
|
-
description: "This API uses OAuth2 with the password flow.",
|
|
206
|
-
flows: {
|
|
207
|
-
password: {
|
|
208
|
-
tokenUrl: CONFIG.oauth.tokenUrl,
|
|
209
|
-
refreshUrl: CONFIG.oauth.refreshUrl,
|
|
210
|
-
scopes: CONFIG.oauth.scopes
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
},
|
|
216
|
-
security: [{ [CONFIG.securitySchemeName]: ["openid"] }]
|
|
217
|
-
};
|
|
218
|
-
const fileContent = `const swaggerAutogen = require('swagger-autogen')();
|
|
219
|
-
const docs = ${JSON.stringify(docs, null, 2)};
|
|
220
|
-
const routes = ${JSON.stringify(routes, null, 2)};
|
|
221
|
-
swaggerAutogen('${ensurePosix(CONFIG.openapiOut)}', routes, docs);`;
|
|
222
|
-
fs.writeFileSync(path.resolve(CONFIG.projectRoot, CONFIG.outFile), fileContent, "utf8");
|
|
223
|
-
}
|
|
224
|
-
async function run(args = []) {
|
|
225
|
-
const schemaFlagIndex = args.findIndex((a) => a === "--schema");
|
|
226
|
-
const schemaPath = schemaFlagIndex >= 0 ? args[schemaFlagIndex + 1] : void 0;
|
|
227
|
-
const schemas = buildSchemasFromPrismaDmmf(schemaPath);
|
|
228
|
-
generateSwaggerConfigJs(schemas);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
export {
|
|
232
|
-
run
|
|
233
|
-
};
|
package/dist/cli.d.cts
DELETED
package/dist/cli.d.ts
DELETED