prisma-swagger-autogen 1.0.2 → 1.0.3
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/{chunk-B6OADLRN.js → chunk-6R6DHPOL.js} +40 -146
- package/dist/cli.cjs +40 -147
- package/dist/cli.d.cts +2 -1
- package/dist/cli.d.ts +2 -1
- package/dist/cli.js +1 -2
- package/dist/index.cjs +40 -146
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +4 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
import fs from "fs";
|
|
3
3
|
import path from "path";
|
|
4
|
-
import { globSync } from "glob";
|
|
5
4
|
import { createRequire } from "module";
|
|
5
|
+
import { globSync } from "glob";
|
|
6
6
|
var CONFIG = {
|
|
7
7
|
projectRoot: process.cwd(),
|
|
8
8
|
controllersGlob: "./src/web/api/controllers/**/*.ts",
|
|
@@ -25,6 +25,28 @@ function pluralize(name) {
|
|
|
25
25
|
if (name.endsWith("s")) return `${name}es`;
|
|
26
26
|
return `${name}s`;
|
|
27
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
|
+
}
|
|
28
50
|
function scalarToSchema(scalar) {
|
|
29
51
|
switch (scalar) {
|
|
30
52
|
case "String":
|
|
@@ -83,7 +105,9 @@ function stripWriteFields(model, getSchema, omit) {
|
|
|
83
105
|
if (!schema.properties) return schema;
|
|
84
106
|
const relationFieldNames = new Set(model.fields.filter((f) => f.kind === "object").map((f) => f.name));
|
|
85
107
|
for (const key of Object.keys(schema.properties)) {
|
|
86
|
-
if (omit.has(key) || relationFieldNames.has(key))
|
|
108
|
+
if (omit.has(key) || relationFieldNames.has(key)) {
|
|
109
|
+
delete schema.properties[key];
|
|
110
|
+
}
|
|
87
111
|
}
|
|
88
112
|
if (Array.isArray(schema.required)) {
|
|
89
113
|
schema.required = schema.required.filter((k) => !omit.has(k) && !relationFieldNames.has(k));
|
|
@@ -100,100 +124,19 @@ function listResponseSchema(itemRef) {
|
|
|
100
124
|
return {
|
|
101
125
|
type: "object",
|
|
102
126
|
properties: {
|
|
103
|
-
count: { type: "number"
|
|
104
|
-
hasPreviousPage: { type: "boolean"
|
|
105
|
-
hasNextPage: { type: "boolean"
|
|
106
|
-
pageNumber: { type: "number"
|
|
107
|
-
pageSize: { type: "number"
|
|
108
|
-
totalPages: { type: "number"
|
|
127
|
+
count: { type: "number" },
|
|
128
|
+
hasPreviousPage: { type: "boolean" },
|
|
129
|
+
hasNextPage: { type: "boolean" },
|
|
130
|
+
pageNumber: { type: "number" },
|
|
131
|
+
pageSize: { type: "number" },
|
|
132
|
+
totalPages: { type: "number" },
|
|
109
133
|
items: { type: "array", items: { $ref: itemRef } }
|
|
110
134
|
},
|
|
111
135
|
required: ["count", "hasPreviousPage", "hasNextPage", "pageNumber", "pageSize", "totalPages", "items"]
|
|
112
136
|
};
|
|
113
137
|
}
|
|
114
|
-
function
|
|
115
|
-
|
|
116
|
-
switch (type) {
|
|
117
|
-
case "string":
|
|
118
|
-
return "string";
|
|
119
|
-
case "integer":
|
|
120
|
-
return 0;
|
|
121
|
-
case "number":
|
|
122
|
-
return 0;
|
|
123
|
-
case "boolean":
|
|
124
|
-
return true;
|
|
125
|
-
case "object":
|
|
126
|
-
return {};
|
|
127
|
-
default:
|
|
128
|
-
return null;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
function buildExampleFromSchema(schema, components, depth = 0) {
|
|
132
|
-
if (depth > 2) return void 0;
|
|
133
|
-
if (schema.$ref) {
|
|
134
|
-
const name = String(schema.$ref).split("/").pop() || "";
|
|
135
|
-
const target = components[name];
|
|
136
|
-
if (!target) return void 0;
|
|
137
|
-
return buildExampleFromSchema(target, components, depth + 1);
|
|
138
|
-
}
|
|
139
|
-
if (Array.isArray(schema.allOf) && schema.allOf.length) {
|
|
140
|
-
const merged = {};
|
|
141
|
-
for (const part of schema.allOf) {
|
|
142
|
-
const ex = buildExampleFromSchema(part, components, depth + 1);
|
|
143
|
-
if (ex && typeof ex === "object" && !Array.isArray(ex)) Object.assign(merged, ex);
|
|
144
|
-
}
|
|
145
|
-
return Object.keys(merged).length ? merged : void 0;
|
|
146
|
-
}
|
|
147
|
-
if (schema.type === "array" && schema.items) {
|
|
148
|
-
const item = buildExampleFromSchema(schema.items, components, depth + 1);
|
|
149
|
-
return item === void 0 ? [] : [item];
|
|
150
|
-
}
|
|
151
|
-
if (schema.type === "object" && schema.properties) {
|
|
152
|
-
const obj = {};
|
|
153
|
-
for (const [k, v] of Object.entries(schema.properties)) {
|
|
154
|
-
const ex = buildExampleFromSchema(v, components, depth + 1);
|
|
155
|
-
if (ex !== void 0) obj[k] = ex;
|
|
156
|
-
}
|
|
157
|
-
return obj;
|
|
158
|
-
}
|
|
159
|
-
if (Array.isArray(schema.enum) && schema.enum.length) return schema.enum[0];
|
|
160
|
-
if (typeof schema.type === "string") return exampleForScalarType(schema.type, schema.format);
|
|
161
|
-
return void 0;
|
|
162
|
-
}
|
|
163
|
-
function attachExample(schema, components) {
|
|
164
|
-
const s = JSON.parse(JSON.stringify(schema));
|
|
165
|
-
if (s.example === void 0) {
|
|
166
|
-
const ex = buildExampleFromSchema(s, components);
|
|
167
|
-
if (ex !== void 0) s.example = ex;
|
|
168
|
-
}
|
|
169
|
-
return s;
|
|
170
|
-
}
|
|
171
|
-
function loadDmmfFromProject() {
|
|
172
|
-
const schemaPath = path.resolve(process.cwd(), "prisma/schema.prisma");
|
|
173
|
-
if (!fs.existsSync(schemaPath)) {
|
|
174
|
-
throw new Error(`Prisma schema not found at: ${schemaPath}`);
|
|
175
|
-
}
|
|
176
|
-
const datamodel = fs.readFileSync(schemaPath, "utf8");
|
|
177
|
-
const require2 = createRequire(import.meta.url);
|
|
178
|
-
const tryLoad = (id) => {
|
|
179
|
-
try {
|
|
180
|
-
return require2(id);
|
|
181
|
-
} catch {
|
|
182
|
-
return null;
|
|
183
|
-
}
|
|
184
|
-
};
|
|
185
|
-
const runtime = tryLoad("@prisma/client/runtime/library") ?? tryLoad("@prisma/client/runtime");
|
|
186
|
-
if (!runtime || typeof runtime.getDMMF !== "function") {
|
|
187
|
-
throw new Error(
|
|
188
|
-
`Unable to load Prisma runtime getDMMF(). Ensure @prisma/client is installed in the target project.
|
|
189
|
-
Tried: @prisma/client/runtime/library and @prisma/client/runtime`
|
|
190
|
-
);
|
|
191
|
-
}
|
|
192
|
-
const dmmf = runtime.getDMMF({ datamodel });
|
|
193
|
-
if (!dmmf?.datamodel?.models) throw new Error("Failed to load Prisma DMMF (unexpected structure).");
|
|
194
|
-
return dmmf;
|
|
195
|
-
}
|
|
196
|
-
function buildSchemasFromDmmf(dmmf) {
|
|
138
|
+
function buildSchemasFromPrismaDmmf(schemaPath) {
|
|
139
|
+
const dmmf = loadDmmfFromProject(schemaPath);
|
|
197
140
|
const schemas = {};
|
|
198
141
|
const getRefName = (modelName) => `Get${modelName}Response`;
|
|
199
142
|
for (const e of dmmf.datamodel.enums) {
|
|
@@ -247,10 +190,6 @@ function buildSchemasFromDmmf(dmmf) {
|
|
|
247
190
|
type: "https://tools.ietf.org/html/rfc7231#section-6.6.1"
|
|
248
191
|
}
|
|
249
192
|
};
|
|
250
|
-
for (const name of Object.keys(schemas)) {
|
|
251
|
-
if (name.startsWith("Post") && name.endsWith("Request")) schemas[name] = attachExample(schemas[name], schemas);
|
|
252
|
-
if (name.startsWith("Put") && name.endsWith("Request")) schemas[name] = attachExample(schemas[name], schemas);
|
|
253
|
-
}
|
|
254
193
|
return schemas;
|
|
255
194
|
}
|
|
256
195
|
function generateSwaggerConfigJs(schemas) {
|
|
@@ -277,60 +216,15 @@ function generateSwaggerConfigJs(schemas) {
|
|
|
277
216
|
security: [{ [CONFIG.securitySchemeName]: ["openid"] }]
|
|
278
217
|
};
|
|
279
218
|
const fileContent = `const swaggerAutogen = require('swagger-autogen')();
|
|
280
|
-
const fs = require('fs');
|
|
281
|
-
const path = require('node:path');
|
|
282
|
-
|
|
283
|
-
function isPlainObject(v){return v!==null && typeof v==='object' && !Array.isArray(v);}
|
|
284
|
-
|
|
285
|
-
function normalizeSchema(schema){
|
|
286
|
-
if(!isPlainObject(schema)) return schema;
|
|
287
|
-
if(schema.$ref) return schema;
|
|
288
|
-
|
|
289
|
-
if(isPlainObject(schema.type) && typeof schema.type.example === 'string') schema.type = schema.type.example;
|
|
290
|
-
if(isPlainObject(schema.format) && typeof schema.format.example === 'string') schema.format = schema.format.example;
|
|
291
|
-
if(isPlainObject(schema.required) && Array.isArray(schema.required.example)) schema.required = schema.required.example;
|
|
292
|
-
if(isPlainObject(schema.enum) && Array.isArray(schema.enum.example)) schema.enum = schema.enum.example;
|
|
293
|
-
|
|
294
|
-
if(Array.isArray(schema.allOf)) schema.allOf = schema.allOf.map(normalizeSchema);
|
|
295
|
-
if(isPlainObject(schema.items)) schema.items = normalizeSchema(schema.items);
|
|
296
|
-
if(isPlainObject(schema.additionalProperties)) schema.additionalProperties = normalizeSchema(schema.additionalProperties);
|
|
297
|
-
|
|
298
|
-
if(isPlainObject(schema.properties)){
|
|
299
|
-
for(const k of Object.keys(schema.properties)){
|
|
300
|
-
schema.properties[k] = normalizeSchema(schema.properties[k]);
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
return schema;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
function fixOpenApiFile(openapiPath){
|
|
308
|
-
const abs = path.resolve(process.cwd(), openapiPath);
|
|
309
|
-
if(!fs.existsSync(abs)) return;
|
|
310
|
-
const doc = JSON.parse(fs.readFileSync(abs,'utf8'));
|
|
311
|
-
|
|
312
|
-
if(doc && doc.components && isPlainObject(doc.components.schemas)){
|
|
313
|
-
for(const name of Object.keys(doc.components.schemas)){
|
|
314
|
-
doc.components.schemas[name] = normalizeSchema(doc.components.schemas[name]);
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
fs.writeFileSync(abs, JSON.stringify(doc,null,2),'utf8');
|
|
319
|
-
}
|
|
320
|
-
|
|
321
219
|
const docs = ${JSON.stringify(docs, null, 2)};
|
|
322
220
|
const routes = ${JSON.stringify(routes, null, 2)};
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
.then(() => fixOpenApiFile('${ensurePosix(CONFIG.openapiOut)}'))
|
|
326
|
-
.catch((e) => { console.error(e); process.exitCode = 1; });
|
|
327
|
-
`;
|
|
328
|
-
const outPath = path.resolve(CONFIG.projectRoot, CONFIG.outFile);
|
|
329
|
-
fs.writeFileSync(outPath, fileContent, "utf8");
|
|
221
|
+
swaggerAutogen('${ensurePosix(CONFIG.openapiOut)}', routes, docs);`;
|
|
222
|
+
fs.writeFileSync(path.resolve(CONFIG.projectRoot, CONFIG.outFile), fileContent, "utf8");
|
|
330
223
|
}
|
|
331
|
-
async function run(
|
|
332
|
-
const
|
|
333
|
-
const
|
|
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);
|
|
334
228
|
generateSwaggerConfigJs(schemas);
|
|
335
229
|
}
|
|
336
230
|
|
package/dist/cli.cjs
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
1
|
"use strict";
|
|
3
2
|
var __create = Object.create;
|
|
4
3
|
var __defProp = Object.defineProperty;
|
|
@@ -26,8 +25,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
26
25
|
// src/index.ts
|
|
27
26
|
var import_node_fs = __toESM(require("fs"), 1);
|
|
28
27
|
var import_node_path = __toESM(require("path"), 1);
|
|
29
|
-
var import_glob = require("glob");
|
|
30
28
|
var import_node_module = require("module");
|
|
29
|
+
var import_glob = require("glob");
|
|
31
30
|
var import_meta = {};
|
|
32
31
|
var CONFIG = {
|
|
33
32
|
projectRoot: process.cwd(),
|
|
@@ -51,6 +50,28 @@ function pluralize(name) {
|
|
|
51
50
|
if (name.endsWith("s")) return `${name}es`;
|
|
52
51
|
return `${name}s`;
|
|
53
52
|
}
|
|
53
|
+
function getRequire() {
|
|
54
|
+
const base = typeof __filename !== "undefined" ? __filename : import_meta.url;
|
|
55
|
+
return (0, import_node_module.createRequire)(base);
|
|
56
|
+
}
|
|
57
|
+
function loadDmmfFromProject(schemaPath) {
|
|
58
|
+
const resolvedSchemaPath = schemaPath ? import_node_path.default.resolve(process.cwd(), schemaPath) : import_node_path.default.resolve(process.cwd(), "prisma/schema.prisma");
|
|
59
|
+
if (!import_node_fs.default.existsSync(resolvedSchemaPath)) {
|
|
60
|
+
throw new Error(`Prisma schema not found at ${resolvedSchemaPath}`);
|
|
61
|
+
}
|
|
62
|
+
const datamodel = import_node_fs.default.readFileSync(resolvedSchemaPath, "utf8");
|
|
63
|
+
const require2 = getRequire();
|
|
64
|
+
let internals;
|
|
65
|
+
try {
|
|
66
|
+
internals = require2("@prisma/internals");
|
|
67
|
+
} catch {
|
|
68
|
+
throw new Error(`Unable to load @prisma/internals`);
|
|
69
|
+
}
|
|
70
|
+
if (typeof internals.getDMMF !== "function") {
|
|
71
|
+
throw new Error(`@prisma/internals.getDMMF not available`);
|
|
72
|
+
}
|
|
73
|
+
return internals.getDMMF({ datamodel });
|
|
74
|
+
}
|
|
54
75
|
function scalarToSchema(scalar) {
|
|
55
76
|
switch (scalar) {
|
|
56
77
|
case "String":
|
|
@@ -109,7 +130,9 @@ function stripWriteFields(model, getSchema, omit) {
|
|
|
109
130
|
if (!schema.properties) return schema;
|
|
110
131
|
const relationFieldNames = new Set(model.fields.filter((f) => f.kind === "object").map((f) => f.name));
|
|
111
132
|
for (const key of Object.keys(schema.properties)) {
|
|
112
|
-
if (omit.has(key) || relationFieldNames.has(key))
|
|
133
|
+
if (omit.has(key) || relationFieldNames.has(key)) {
|
|
134
|
+
delete schema.properties[key];
|
|
135
|
+
}
|
|
113
136
|
}
|
|
114
137
|
if (Array.isArray(schema.required)) {
|
|
115
138
|
schema.required = schema.required.filter((k) => !omit.has(k) && !relationFieldNames.has(k));
|
|
@@ -126,100 +149,19 @@ function listResponseSchema(itemRef) {
|
|
|
126
149
|
return {
|
|
127
150
|
type: "object",
|
|
128
151
|
properties: {
|
|
129
|
-
count: { type: "number"
|
|
130
|
-
hasPreviousPage: { type: "boolean"
|
|
131
|
-
hasNextPage: { type: "boolean"
|
|
132
|
-
pageNumber: { type: "number"
|
|
133
|
-
pageSize: { type: "number"
|
|
134
|
-
totalPages: { type: "number"
|
|
152
|
+
count: { type: "number" },
|
|
153
|
+
hasPreviousPage: { type: "boolean" },
|
|
154
|
+
hasNextPage: { type: "boolean" },
|
|
155
|
+
pageNumber: { type: "number" },
|
|
156
|
+
pageSize: { type: "number" },
|
|
157
|
+
totalPages: { type: "number" },
|
|
135
158
|
items: { type: "array", items: { $ref: itemRef } }
|
|
136
159
|
},
|
|
137
160
|
required: ["count", "hasPreviousPage", "hasNextPage", "pageNumber", "pageSize", "totalPages", "items"]
|
|
138
161
|
};
|
|
139
162
|
}
|
|
140
|
-
function
|
|
141
|
-
|
|
142
|
-
switch (type) {
|
|
143
|
-
case "string":
|
|
144
|
-
return "string";
|
|
145
|
-
case "integer":
|
|
146
|
-
return 0;
|
|
147
|
-
case "number":
|
|
148
|
-
return 0;
|
|
149
|
-
case "boolean":
|
|
150
|
-
return true;
|
|
151
|
-
case "object":
|
|
152
|
-
return {};
|
|
153
|
-
default:
|
|
154
|
-
return null;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
function buildExampleFromSchema(schema, components, depth = 0) {
|
|
158
|
-
if (depth > 2) return void 0;
|
|
159
|
-
if (schema.$ref) {
|
|
160
|
-
const name = String(schema.$ref).split("/").pop() || "";
|
|
161
|
-
const target = components[name];
|
|
162
|
-
if (!target) return void 0;
|
|
163
|
-
return buildExampleFromSchema(target, components, depth + 1);
|
|
164
|
-
}
|
|
165
|
-
if (Array.isArray(schema.allOf) && schema.allOf.length) {
|
|
166
|
-
const merged = {};
|
|
167
|
-
for (const part of schema.allOf) {
|
|
168
|
-
const ex = buildExampleFromSchema(part, components, depth + 1);
|
|
169
|
-
if (ex && typeof ex === "object" && !Array.isArray(ex)) Object.assign(merged, ex);
|
|
170
|
-
}
|
|
171
|
-
return Object.keys(merged).length ? merged : void 0;
|
|
172
|
-
}
|
|
173
|
-
if (schema.type === "array" && schema.items) {
|
|
174
|
-
const item = buildExampleFromSchema(schema.items, components, depth + 1);
|
|
175
|
-
return item === void 0 ? [] : [item];
|
|
176
|
-
}
|
|
177
|
-
if (schema.type === "object" && schema.properties) {
|
|
178
|
-
const obj = {};
|
|
179
|
-
for (const [k, v] of Object.entries(schema.properties)) {
|
|
180
|
-
const ex = buildExampleFromSchema(v, components, depth + 1);
|
|
181
|
-
if (ex !== void 0) obj[k] = ex;
|
|
182
|
-
}
|
|
183
|
-
return obj;
|
|
184
|
-
}
|
|
185
|
-
if (Array.isArray(schema.enum) && schema.enum.length) return schema.enum[0];
|
|
186
|
-
if (typeof schema.type === "string") return exampleForScalarType(schema.type, schema.format);
|
|
187
|
-
return void 0;
|
|
188
|
-
}
|
|
189
|
-
function attachExample(schema, components) {
|
|
190
|
-
const s = JSON.parse(JSON.stringify(schema));
|
|
191
|
-
if (s.example === void 0) {
|
|
192
|
-
const ex = buildExampleFromSchema(s, components);
|
|
193
|
-
if (ex !== void 0) s.example = ex;
|
|
194
|
-
}
|
|
195
|
-
return s;
|
|
196
|
-
}
|
|
197
|
-
function loadDmmfFromProject() {
|
|
198
|
-
const schemaPath = import_node_path.default.resolve(process.cwd(), "prisma/schema.prisma");
|
|
199
|
-
if (!import_node_fs.default.existsSync(schemaPath)) {
|
|
200
|
-
throw new Error(`Prisma schema not found at: ${schemaPath}`);
|
|
201
|
-
}
|
|
202
|
-
const datamodel = import_node_fs.default.readFileSync(schemaPath, "utf8");
|
|
203
|
-
const require2 = (0, import_node_module.createRequire)(import_meta.url);
|
|
204
|
-
const tryLoad = (id) => {
|
|
205
|
-
try {
|
|
206
|
-
return require2(id);
|
|
207
|
-
} catch {
|
|
208
|
-
return null;
|
|
209
|
-
}
|
|
210
|
-
};
|
|
211
|
-
const runtime = tryLoad("@prisma/client/runtime/library") ?? tryLoad("@prisma/client/runtime");
|
|
212
|
-
if (!runtime || typeof runtime.getDMMF !== "function") {
|
|
213
|
-
throw new Error(
|
|
214
|
-
`Unable to load Prisma runtime getDMMF(). Ensure @prisma/client is installed in the target project.
|
|
215
|
-
Tried: @prisma/client/runtime/library and @prisma/client/runtime`
|
|
216
|
-
);
|
|
217
|
-
}
|
|
218
|
-
const dmmf = runtime.getDMMF({ datamodel });
|
|
219
|
-
if (!dmmf?.datamodel?.models) throw new Error("Failed to load Prisma DMMF (unexpected structure).");
|
|
220
|
-
return dmmf;
|
|
221
|
-
}
|
|
222
|
-
function buildSchemasFromDmmf(dmmf) {
|
|
163
|
+
function buildSchemasFromPrismaDmmf(schemaPath) {
|
|
164
|
+
const dmmf = loadDmmfFromProject(schemaPath);
|
|
223
165
|
const schemas = {};
|
|
224
166
|
const getRefName = (modelName) => `Get${modelName}Response`;
|
|
225
167
|
for (const e of dmmf.datamodel.enums) {
|
|
@@ -273,10 +215,6 @@ function buildSchemasFromDmmf(dmmf) {
|
|
|
273
215
|
type: "https://tools.ietf.org/html/rfc7231#section-6.6.1"
|
|
274
216
|
}
|
|
275
217
|
};
|
|
276
|
-
for (const name of Object.keys(schemas)) {
|
|
277
|
-
if (name.startsWith("Post") && name.endsWith("Request")) schemas[name] = attachExample(schemas[name], schemas);
|
|
278
|
-
if (name.startsWith("Put") && name.endsWith("Request")) schemas[name] = attachExample(schemas[name], schemas);
|
|
279
|
-
}
|
|
280
218
|
return schemas;
|
|
281
219
|
}
|
|
282
220
|
function generateSwaggerConfigJs(schemas) {
|
|
@@ -303,60 +241,15 @@ function generateSwaggerConfigJs(schemas) {
|
|
|
303
241
|
security: [{ [CONFIG.securitySchemeName]: ["openid"] }]
|
|
304
242
|
};
|
|
305
243
|
const fileContent = `const swaggerAutogen = require('swagger-autogen')();
|
|
306
|
-
const fs = require('fs');
|
|
307
|
-
const path = require('node:path');
|
|
308
|
-
|
|
309
|
-
function isPlainObject(v){return v!==null && typeof v==='object' && !Array.isArray(v);}
|
|
310
|
-
|
|
311
|
-
function normalizeSchema(schema){
|
|
312
|
-
if(!isPlainObject(schema)) return schema;
|
|
313
|
-
if(schema.$ref) return schema;
|
|
314
|
-
|
|
315
|
-
if(isPlainObject(schema.type) && typeof schema.type.example === 'string') schema.type = schema.type.example;
|
|
316
|
-
if(isPlainObject(schema.format) && typeof schema.format.example === 'string') schema.format = schema.format.example;
|
|
317
|
-
if(isPlainObject(schema.required) && Array.isArray(schema.required.example)) schema.required = schema.required.example;
|
|
318
|
-
if(isPlainObject(schema.enum) && Array.isArray(schema.enum.example)) schema.enum = schema.enum.example;
|
|
319
|
-
|
|
320
|
-
if(Array.isArray(schema.allOf)) schema.allOf = schema.allOf.map(normalizeSchema);
|
|
321
|
-
if(isPlainObject(schema.items)) schema.items = normalizeSchema(schema.items);
|
|
322
|
-
if(isPlainObject(schema.additionalProperties)) schema.additionalProperties = normalizeSchema(schema.additionalProperties);
|
|
323
|
-
|
|
324
|
-
if(isPlainObject(schema.properties)){
|
|
325
|
-
for(const k of Object.keys(schema.properties)){
|
|
326
|
-
schema.properties[k] = normalizeSchema(schema.properties[k]);
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
return schema;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
function fixOpenApiFile(openapiPath){
|
|
334
|
-
const abs = path.resolve(process.cwd(), openapiPath);
|
|
335
|
-
if(!fs.existsSync(abs)) return;
|
|
336
|
-
const doc = JSON.parse(fs.readFileSync(abs,'utf8'));
|
|
337
|
-
|
|
338
|
-
if(doc && doc.components && isPlainObject(doc.components.schemas)){
|
|
339
|
-
for(const name of Object.keys(doc.components.schemas)){
|
|
340
|
-
doc.components.schemas[name] = normalizeSchema(doc.components.schemas[name]);
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
fs.writeFileSync(abs, JSON.stringify(doc,null,2),'utf8');
|
|
345
|
-
}
|
|
346
|
-
|
|
347
244
|
const docs = ${JSON.stringify(docs, null, 2)};
|
|
348
245
|
const routes = ${JSON.stringify(routes, null, 2)};
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
.then(() => fixOpenApiFile('${ensurePosix(CONFIG.openapiOut)}'))
|
|
352
|
-
.catch((e) => { console.error(e); process.exitCode = 1; });
|
|
353
|
-
`;
|
|
354
|
-
const outPath = import_node_path.default.resolve(CONFIG.projectRoot, CONFIG.outFile);
|
|
355
|
-
import_node_fs.default.writeFileSync(outPath, fileContent, "utf8");
|
|
246
|
+
swaggerAutogen('${ensurePosix(CONFIG.openapiOut)}', routes, docs);`;
|
|
247
|
+
import_node_fs.default.writeFileSync(import_node_path.default.resolve(CONFIG.projectRoot, CONFIG.outFile), fileContent, "utf8");
|
|
356
248
|
}
|
|
357
|
-
async function run(
|
|
358
|
-
const
|
|
359
|
-
const
|
|
249
|
+
async function run(args = []) {
|
|
250
|
+
const schemaFlagIndex = args.findIndex((a) => a === "--schema");
|
|
251
|
+
const schemaPath = schemaFlagIndex >= 0 ? args[schemaFlagIndex + 1] : void 0;
|
|
252
|
+
const schemas = buildSchemasFromPrismaDmmf(schemaPath);
|
|
360
253
|
generateSwaggerConfigJs(schemas);
|
|
361
254
|
}
|
|
362
255
|
|
package/dist/cli.d.cts
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
|
|
2
|
+
export { }
|
package/dist/cli.d.ts
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
|
|
2
|
+
export { }
|
package/dist/cli.js
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -35,8 +35,8 @@ __export(index_exports, {
|
|
|
35
35
|
module.exports = __toCommonJS(index_exports);
|
|
36
36
|
var import_node_fs = __toESM(require("fs"), 1);
|
|
37
37
|
var import_node_path = __toESM(require("path"), 1);
|
|
38
|
-
var import_glob = require("glob");
|
|
39
38
|
var import_node_module = require("module");
|
|
39
|
+
var import_glob = require("glob");
|
|
40
40
|
var import_meta = {};
|
|
41
41
|
var CONFIG = {
|
|
42
42
|
projectRoot: process.cwd(),
|
|
@@ -60,6 +60,28 @@ function pluralize(name) {
|
|
|
60
60
|
if (name.endsWith("s")) return `${name}es`;
|
|
61
61
|
return `${name}s`;
|
|
62
62
|
}
|
|
63
|
+
function getRequire() {
|
|
64
|
+
const base = typeof __filename !== "undefined" ? __filename : import_meta.url;
|
|
65
|
+
return (0, import_node_module.createRequire)(base);
|
|
66
|
+
}
|
|
67
|
+
function loadDmmfFromProject(schemaPath) {
|
|
68
|
+
const resolvedSchemaPath = schemaPath ? import_node_path.default.resolve(process.cwd(), schemaPath) : import_node_path.default.resolve(process.cwd(), "prisma/schema.prisma");
|
|
69
|
+
if (!import_node_fs.default.existsSync(resolvedSchemaPath)) {
|
|
70
|
+
throw new Error(`Prisma schema not found at ${resolvedSchemaPath}`);
|
|
71
|
+
}
|
|
72
|
+
const datamodel = import_node_fs.default.readFileSync(resolvedSchemaPath, "utf8");
|
|
73
|
+
const require2 = getRequire();
|
|
74
|
+
let internals;
|
|
75
|
+
try {
|
|
76
|
+
internals = require2("@prisma/internals");
|
|
77
|
+
} catch {
|
|
78
|
+
throw new Error(`Unable to load @prisma/internals`);
|
|
79
|
+
}
|
|
80
|
+
if (typeof internals.getDMMF !== "function") {
|
|
81
|
+
throw new Error(`@prisma/internals.getDMMF not available`);
|
|
82
|
+
}
|
|
83
|
+
return internals.getDMMF({ datamodel });
|
|
84
|
+
}
|
|
63
85
|
function scalarToSchema(scalar) {
|
|
64
86
|
switch (scalar) {
|
|
65
87
|
case "String":
|
|
@@ -118,7 +140,9 @@ function stripWriteFields(model, getSchema, omit) {
|
|
|
118
140
|
if (!schema.properties) return schema;
|
|
119
141
|
const relationFieldNames = new Set(model.fields.filter((f) => f.kind === "object").map((f) => f.name));
|
|
120
142
|
for (const key of Object.keys(schema.properties)) {
|
|
121
|
-
if (omit.has(key) || relationFieldNames.has(key))
|
|
143
|
+
if (omit.has(key) || relationFieldNames.has(key)) {
|
|
144
|
+
delete schema.properties[key];
|
|
145
|
+
}
|
|
122
146
|
}
|
|
123
147
|
if (Array.isArray(schema.required)) {
|
|
124
148
|
schema.required = schema.required.filter((k) => !omit.has(k) && !relationFieldNames.has(k));
|
|
@@ -135,100 +159,19 @@ function listResponseSchema(itemRef) {
|
|
|
135
159
|
return {
|
|
136
160
|
type: "object",
|
|
137
161
|
properties: {
|
|
138
|
-
count: { type: "number"
|
|
139
|
-
hasPreviousPage: { type: "boolean"
|
|
140
|
-
hasNextPage: { type: "boolean"
|
|
141
|
-
pageNumber: { type: "number"
|
|
142
|
-
pageSize: { type: "number"
|
|
143
|
-
totalPages: { type: "number"
|
|
162
|
+
count: { type: "number" },
|
|
163
|
+
hasPreviousPage: { type: "boolean" },
|
|
164
|
+
hasNextPage: { type: "boolean" },
|
|
165
|
+
pageNumber: { type: "number" },
|
|
166
|
+
pageSize: { type: "number" },
|
|
167
|
+
totalPages: { type: "number" },
|
|
144
168
|
items: { type: "array", items: { $ref: itemRef } }
|
|
145
169
|
},
|
|
146
170
|
required: ["count", "hasPreviousPage", "hasNextPage", "pageNumber", "pageSize", "totalPages", "items"]
|
|
147
171
|
};
|
|
148
172
|
}
|
|
149
|
-
function
|
|
150
|
-
|
|
151
|
-
switch (type) {
|
|
152
|
-
case "string":
|
|
153
|
-
return "string";
|
|
154
|
-
case "integer":
|
|
155
|
-
return 0;
|
|
156
|
-
case "number":
|
|
157
|
-
return 0;
|
|
158
|
-
case "boolean":
|
|
159
|
-
return true;
|
|
160
|
-
case "object":
|
|
161
|
-
return {};
|
|
162
|
-
default:
|
|
163
|
-
return null;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
function buildExampleFromSchema(schema, components, depth = 0) {
|
|
167
|
-
if (depth > 2) return void 0;
|
|
168
|
-
if (schema.$ref) {
|
|
169
|
-
const name = String(schema.$ref).split("/").pop() || "";
|
|
170
|
-
const target = components[name];
|
|
171
|
-
if (!target) return void 0;
|
|
172
|
-
return buildExampleFromSchema(target, components, depth + 1);
|
|
173
|
-
}
|
|
174
|
-
if (Array.isArray(schema.allOf) && schema.allOf.length) {
|
|
175
|
-
const merged = {};
|
|
176
|
-
for (const part of schema.allOf) {
|
|
177
|
-
const ex = buildExampleFromSchema(part, components, depth + 1);
|
|
178
|
-
if (ex && typeof ex === "object" && !Array.isArray(ex)) Object.assign(merged, ex);
|
|
179
|
-
}
|
|
180
|
-
return Object.keys(merged).length ? merged : void 0;
|
|
181
|
-
}
|
|
182
|
-
if (schema.type === "array" && schema.items) {
|
|
183
|
-
const item = buildExampleFromSchema(schema.items, components, depth + 1);
|
|
184
|
-
return item === void 0 ? [] : [item];
|
|
185
|
-
}
|
|
186
|
-
if (schema.type === "object" && schema.properties) {
|
|
187
|
-
const obj = {};
|
|
188
|
-
for (const [k, v] of Object.entries(schema.properties)) {
|
|
189
|
-
const ex = buildExampleFromSchema(v, components, depth + 1);
|
|
190
|
-
if (ex !== void 0) obj[k] = ex;
|
|
191
|
-
}
|
|
192
|
-
return obj;
|
|
193
|
-
}
|
|
194
|
-
if (Array.isArray(schema.enum) && schema.enum.length) return schema.enum[0];
|
|
195
|
-
if (typeof schema.type === "string") return exampleForScalarType(schema.type, schema.format);
|
|
196
|
-
return void 0;
|
|
197
|
-
}
|
|
198
|
-
function attachExample(schema, components) {
|
|
199
|
-
const s = JSON.parse(JSON.stringify(schema));
|
|
200
|
-
if (s.example === void 0) {
|
|
201
|
-
const ex = buildExampleFromSchema(s, components);
|
|
202
|
-
if (ex !== void 0) s.example = ex;
|
|
203
|
-
}
|
|
204
|
-
return s;
|
|
205
|
-
}
|
|
206
|
-
function loadDmmfFromProject() {
|
|
207
|
-
const schemaPath = import_node_path.default.resolve(process.cwd(), "prisma/schema.prisma");
|
|
208
|
-
if (!import_node_fs.default.existsSync(schemaPath)) {
|
|
209
|
-
throw new Error(`Prisma schema not found at: ${schemaPath}`);
|
|
210
|
-
}
|
|
211
|
-
const datamodel = import_node_fs.default.readFileSync(schemaPath, "utf8");
|
|
212
|
-
const require2 = (0, import_node_module.createRequire)(import_meta.url);
|
|
213
|
-
const tryLoad = (id) => {
|
|
214
|
-
try {
|
|
215
|
-
return require2(id);
|
|
216
|
-
} catch {
|
|
217
|
-
return null;
|
|
218
|
-
}
|
|
219
|
-
};
|
|
220
|
-
const runtime = tryLoad("@prisma/client/runtime/library") ?? tryLoad("@prisma/client/runtime");
|
|
221
|
-
if (!runtime || typeof runtime.getDMMF !== "function") {
|
|
222
|
-
throw new Error(
|
|
223
|
-
`Unable to load Prisma runtime getDMMF(). Ensure @prisma/client is installed in the target project.
|
|
224
|
-
Tried: @prisma/client/runtime/library and @prisma/client/runtime`
|
|
225
|
-
);
|
|
226
|
-
}
|
|
227
|
-
const dmmf = runtime.getDMMF({ datamodel });
|
|
228
|
-
if (!dmmf?.datamodel?.models) throw new Error("Failed to load Prisma DMMF (unexpected structure).");
|
|
229
|
-
return dmmf;
|
|
230
|
-
}
|
|
231
|
-
function buildSchemasFromDmmf(dmmf) {
|
|
173
|
+
function buildSchemasFromPrismaDmmf(schemaPath) {
|
|
174
|
+
const dmmf = loadDmmfFromProject(schemaPath);
|
|
232
175
|
const schemas = {};
|
|
233
176
|
const getRefName = (modelName) => `Get${modelName}Response`;
|
|
234
177
|
for (const e of dmmf.datamodel.enums) {
|
|
@@ -282,10 +225,6 @@ function buildSchemasFromDmmf(dmmf) {
|
|
|
282
225
|
type: "https://tools.ietf.org/html/rfc7231#section-6.6.1"
|
|
283
226
|
}
|
|
284
227
|
};
|
|
285
|
-
for (const name of Object.keys(schemas)) {
|
|
286
|
-
if (name.startsWith("Post") && name.endsWith("Request")) schemas[name] = attachExample(schemas[name], schemas);
|
|
287
|
-
if (name.startsWith("Put") && name.endsWith("Request")) schemas[name] = attachExample(schemas[name], schemas);
|
|
288
|
-
}
|
|
289
228
|
return schemas;
|
|
290
229
|
}
|
|
291
230
|
function generateSwaggerConfigJs(schemas) {
|
|
@@ -312,60 +251,15 @@ function generateSwaggerConfigJs(schemas) {
|
|
|
312
251
|
security: [{ [CONFIG.securitySchemeName]: ["openid"] }]
|
|
313
252
|
};
|
|
314
253
|
const fileContent = `const swaggerAutogen = require('swagger-autogen')();
|
|
315
|
-
const fs = require('fs');
|
|
316
|
-
const path = require('node:path');
|
|
317
|
-
|
|
318
|
-
function isPlainObject(v){return v!==null && typeof v==='object' && !Array.isArray(v);}
|
|
319
|
-
|
|
320
|
-
function normalizeSchema(schema){
|
|
321
|
-
if(!isPlainObject(schema)) return schema;
|
|
322
|
-
if(schema.$ref) return schema;
|
|
323
|
-
|
|
324
|
-
if(isPlainObject(schema.type) && typeof schema.type.example === 'string') schema.type = schema.type.example;
|
|
325
|
-
if(isPlainObject(schema.format) && typeof schema.format.example === 'string') schema.format = schema.format.example;
|
|
326
|
-
if(isPlainObject(schema.required) && Array.isArray(schema.required.example)) schema.required = schema.required.example;
|
|
327
|
-
if(isPlainObject(schema.enum) && Array.isArray(schema.enum.example)) schema.enum = schema.enum.example;
|
|
328
|
-
|
|
329
|
-
if(Array.isArray(schema.allOf)) schema.allOf = schema.allOf.map(normalizeSchema);
|
|
330
|
-
if(isPlainObject(schema.items)) schema.items = normalizeSchema(schema.items);
|
|
331
|
-
if(isPlainObject(schema.additionalProperties)) schema.additionalProperties = normalizeSchema(schema.additionalProperties);
|
|
332
|
-
|
|
333
|
-
if(isPlainObject(schema.properties)){
|
|
334
|
-
for(const k of Object.keys(schema.properties)){
|
|
335
|
-
schema.properties[k] = normalizeSchema(schema.properties[k]);
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
return schema;
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
function fixOpenApiFile(openapiPath){
|
|
343
|
-
const abs = path.resolve(process.cwd(), openapiPath);
|
|
344
|
-
if(!fs.existsSync(abs)) return;
|
|
345
|
-
const doc = JSON.parse(fs.readFileSync(abs,'utf8'));
|
|
346
|
-
|
|
347
|
-
if(doc && doc.components && isPlainObject(doc.components.schemas)){
|
|
348
|
-
for(const name of Object.keys(doc.components.schemas)){
|
|
349
|
-
doc.components.schemas[name] = normalizeSchema(doc.components.schemas[name]);
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
fs.writeFileSync(abs, JSON.stringify(doc,null,2),'utf8');
|
|
354
|
-
}
|
|
355
|
-
|
|
356
254
|
const docs = ${JSON.stringify(docs, null, 2)};
|
|
357
255
|
const routes = ${JSON.stringify(routes, null, 2)};
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
.then(() => fixOpenApiFile('${ensurePosix(CONFIG.openapiOut)}'))
|
|
361
|
-
.catch((e) => { console.error(e); process.exitCode = 1; });
|
|
362
|
-
`;
|
|
363
|
-
const outPath = import_node_path.default.resolve(CONFIG.projectRoot, CONFIG.outFile);
|
|
364
|
-
import_node_fs.default.writeFileSync(outPath, fileContent, "utf8");
|
|
256
|
+
swaggerAutogen('${ensurePosix(CONFIG.openapiOut)}', routes, docs);`;
|
|
257
|
+
import_node_fs.default.writeFileSync(import_node_path.default.resolve(CONFIG.projectRoot, CONFIG.outFile), fileContent, "utf8");
|
|
365
258
|
}
|
|
366
|
-
async function run(
|
|
367
|
-
const
|
|
368
|
-
const
|
|
259
|
+
async function run(args = []) {
|
|
260
|
+
const schemaFlagIndex = args.findIndex((a) => a === "--schema");
|
|
261
|
+
const schemaPath = schemaFlagIndex >= 0 ? args[schemaFlagIndex + 1] : void 0;
|
|
262
|
+
const schemas = buildSchemasFromPrismaDmmf(schemaPath);
|
|
369
263
|
generateSwaggerConfigJs(schemas);
|
|
370
264
|
}
|
|
371
265
|
// Annotate the CommonJS export names for ESM import in node:
|
package/dist/index.d.cts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prisma-swagger-autogen",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
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",
|
|
@@ -42,6 +42,9 @@
|
|
|
42
42
|
"build": "tsup src/index.ts src/cli.ts --format esm,cjs --dts --out-dir dist --tsconfig tsconfig.json",
|
|
43
43
|
"prepublishOnly": "npm run build"
|
|
44
44
|
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"@prisma/internals": "^6.0.0"
|
|
47
|
+
},
|
|
45
48
|
"peerDependencies": {
|
|
46
49
|
"@prisma/client": ">=4",
|
|
47
50
|
"glob": ">=10",
|