-
-
Notifications
You must be signed in to change notification settings - Fork 15
/
index.ts
114 lines (99 loc) · 4.09 KB
/
index.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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import {
ActionResult,
DefaultFacility,
HttpMethod,
Invocation,
Middleware,
PlumierApplication,
response,
RouteInfo,
} from "@plumier/core"
import { ServeStaticMiddleware } from "@plumier/serve-static"
import { OpenApiBuilder, OperationObject, PathItemObject, PathObject, ResponseObject } from "openapi3-ts"
import dist from "swagger-ui-dist"
import { join } from 'path'
// --------------------------------------------------------------------- //
// ------------------------------ HELPERS ------------------------------ //
// --------------------------------------------------------------------- //
interface RouteGroup { [url: string]: RouteInfo[] }
function groupRoutes(routes: RouteInfo[]): RouteGroup {
return routes.reduce((prev, cur) => {
prev[cur.url] = (prev[cur.url] || []).concat(cur)
return prev
}, {} as RouteGroup)
}
function transformUrl(url: string) {
return url.replace(/(:(\w*\d*)(\/|-{0,1}))/g, (a, b, par, slash) => `{${par}}${slash}`)
}
// --------------------------------------------------------------------- //
// ----------------------------- TRANSFORM ----------------------------- //
// --------------------------------------------------------------------- //
function transformPaths(group: RouteGroup) {
return Object.keys(group)
.map(x => transformPath(x, group[x]))
.reduce((result, [path, item]) => {
result[path] = item
return result
}, {} as PathObject)
}
function transformPath(path: string, route: RouteInfo[]): [string, PathItemObject] {
const item = route.map(x => transformOperation(x))
.reduce((result, [method, opr]) => {
result[method] = opr
return result
}, {} as PathItemObject)
return [transformUrl(path), item]
}
function transformOperation(route: RouteInfo): [HttpMethod, OperationObject] {
const operation: OperationObject = {
responses: transformResponses(route)
}
return [route.method, operation]
}
function transformResponses(route: RouteInfo): { [status: string]: ResponseObject } {
return {
"200": { description: "", content: {} }
}
}
function transform(routes: RouteInfo[]) {
const group = groupRoutes(routes)
const paths = transformPaths(group)
return OpenApiBuilder.create({
openapi: "3.0.0",
info: { title: "title", version: "1.0.0" },
paths
}).getSpec()
}
// --------------------------------------------------------------------- //
// ----------------------------- MIDDLEWARE ---------------------------- //
// --------------------------------------------------------------------- //
export interface OpenApiFacilityConfiguration { endpoint: string }
class OpenApiMiddleware implements Middleware {
constructor(private spec: any, private opt: OpenApiFacilityConfiguration) { }
async execute(invocation: Readonly<Invocation>): Promise<ActionResult> {
const uiPath = this.opt.endpoint.toLowerCase() + "/index"
if (invocation.context.path.toLowerCase() === "/swagger.json")
return response.json(this.spec)
if (invocation.context.path.toLowerCase() === this.opt.endpoint.toLowerCase())
return response.redirect(uiPath)
if (invocation.context.path.toLowerCase() === uiPath)
return response.file(join(dist.getAbsoluteFSPath(), "index.html"))
else
return invocation.proceed()
}
}
export class OpenApiFacility extends DefaultFacility {
opt: OpenApiFacilityConfiguration
constructor(opt?: OpenApiFacilityConfiguration) {
super()
this.opt = { endpoint: "/swagger", ...opt }
if(this.opt.endpoint.toLocaleLowerCase().endsWith("/index"))
this.opt.endpoint = this.opt.endpoint.substring(0, this.opt.endpoint.length - 6)
}
async initialize(app: Readonly<PlumierApplication>, routes: RouteInfo[]): Promise<void> {
const path = dist.getAbsoluteFSPath()
const spec = transform(routes)
app.use(new OpenApiMiddleware(spec, this.opt))
app.use(new ServeStaticMiddleware({ root: path, rootPath: this.opt.endpoint }))
}
}