forked from Savory/Danet-Swagger
-
Notifications
You must be signed in to change notification settings - Fork 0
/
mod.ts
98 lines (92 loc) · 2.7 KB
/
mod.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import {
DanetApplication,
MetadataHelper,
ModuleConstructor,
moduleMetadataKey,
path,
trimSlash,
} from './deps.ts';
import { Swagger } from './swagger.ts';
import Schema = Swagger.Schema;
import Path = Swagger.Path;
import { MethodDefiner } from './method-definer.ts';
export type Constructor<T = unknown> = new (...args: any[]) => T;
export class SwaggerModule {
static async createDocument(app: DanetApplication, spec: Swagger.Spec) {
const definition = await this.generateModuleDefinition(app.entryModule);
spec.paths = definition.paths;
spec.components = {
...spec.components,
schemas: definition.schemas,
};
return spec;
}
private static async generateModuleDefinition(Module: ModuleConstructor) {
const { controllers, imports } = MetadataHelper.getMetadata<any>(
moduleMetadataKey,
Module,
);
const definition: {
paths: { [key: string]: Path };
schemas: { [key: string]: Schema };
} = { paths: {}, schemas: {} };
if (imports) {
for (const childModule of imports) {
const childDef = await this.generateModuleDefinition(childModule);
definition.paths = { ...definition.paths, ...childDef.paths };
definition.schemas = { ...definition.schemas, ...childDef.schemas };
}
}
if (controllers) {
for (const controller of controllers) {
const { paths, schemas } = this.generateControllerDefinition(
controller,
);
definition.paths = {
...definition.paths,
...paths,
};
definition.schemas = {
...definition.schemas,
...schemas,
};
}
}
return definition;
}
private static generateControllerDefinition(Controller: Constructor) {
let paths: { [key: string]: Swagger.Path } = {};
let schemas: { [key: string]: Schema } = {};
const propertyNames = Object.getOwnPropertyNames(Controller.prototype);
for (const methodName of propertyNames) {
if (methodName !== 'constructor') {
const methodDefiner = new MethodDefiner(Controller, methodName);
const newDefinition = methodDefiner.addMethodDefinitionToActual(
paths,
schemas,
);
paths = newDefinition.paths;
schemas = newDefinition.schemas;
}
}
return { paths, schemas };
}
static async setup(
apiPath: string,
app: DanetApplication,
document: Swagger.Spec,
) {
const url = new URL("./swagger.html", import.meta.url).href
const swaggerHtml = await (await fetch(url)).text();
apiPath = trimSlash(apiPath);
app.danetRouter.router.get(`/${apiPath}`, async (context, next) => {
context.response.body = swaggerHtml;
await next();
});
app.danetRouter.router.get(`/${apiPath}/json`, async (context, next) => {
context.response.body = document;
await next();
});
}
}
export { SpecBuilder } from './builder.ts';