/
RoutesCommand.swift
108 lines (99 loc) 路 3.28 KB
/
RoutesCommand.swift
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
/// Displays all routes registered to the `Application`'s `Router` in an ASCII-formatted table.
///
/// $ swift run Run routes
/// +------+------------------+
/// | GET | /search |
/// +------+------------------+
/// | GET | /hash/:string |
/// +------+------------------+
///
/// A colon preceding a path component indicates a variable parameter. A colon with no text following
/// is a parameter whose result will be discarded.
///
/// The path will be displayed with the same syntax that is used to register a route.
public final class RoutesCommand: Command {
public struct Signature: CommandSignature {
public init() { }
}
public var help: String {
return "Displays all registered routes."
}
init() { }
public func run(using context: CommandContext, signature: Signature) throws {
let routes = context.application.routes
let includeDescription = !routes.all.filter { $0.userInfo["description"] != nil }.isEmpty
let pathSeparator = "/".consoleText()
context.console.outputASCIITable(routes.all.map { route -> [ConsoleText] in
var column = [route.method.string.consoleText()]
if route.path.isEmpty {
column.append(pathSeparator)
} else {
column.append(route.path
.map { pathSeparator + $0.consoleText() }
.reduce("".consoleText(), +)
)
}
if includeDescription {
let desc = route.userInfo["description"]
.flatMap { $0 as? String }
.flatMap { $0.consoleText() } ?? ""
column.append(desc)
}
return column
})
}
}
extension PathComponent {
func consoleText() -> ConsoleText {
switch self {
case .constant:
return description.consoleText()
default:
return description.consoleText(.info)
}
}
}
extension Console {
func outputASCIITable(_ rows: [[ConsoleText]]) {
var columnWidths: [Int] = []
// calculate longest columns
for row in rows {
for (i, column) in row.enumerated() {
if columnWidths.count <= i {
columnWidths.append(0)
}
if column.description.count > columnWidths[i] {
columnWidths[i] = column.description.count
}
}
}
func hr() {
var text: ConsoleText = ""
for columnWidth in columnWidths {
text += "+"
text += "-"
for _ in 0..<columnWidth {
text += "-"
}
text += "-"
}
text += "+"
self.output(text)
}
for row in rows {
hr()
var text: ConsoleText = ""
for (i, column) in row.enumerated() {
text += "| "
text += column
for _ in 0..<(columnWidths[i] - column.description.count) {
text += " "
}
text += " "
}
text += "|"
self.output(text)
}
hr()
}
}