This repository was archived by the owner on Aug 6, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 171
/
Copy pathroutes
executable file
·129 lines (118 loc) · 3.02 KB
/
routes
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#! /usr/bin/env node
const acorn = require('acorn')
const acornWalk = require('acorn-walk')
const fs = require('fs')
const _ = require('lodash')
const glob = require('glob')
print = console.log
const Methods = new Set([
'get',
'head',
'post',
'put',
'delete',
'connect',
'options',
'trace',
'patch'
])
const isMethod = str => {
return Methods.has(str)
}
// Check if the expression is a call on a router, return data about it, or null
const routerCall = callExpression => {
const callee = callExpression.callee
const property = callee.property
const args = callExpression.arguments
if (!callee.object || !callee.object.name) {
return false
}
const routerName = callee.object.name
if ( // Match known names for the Express routers: app, webRouter, whateverRouter, etc...
isMethod(property.name) &&
(routerName === 'app' || routerName.match('^.*[rR]outer$'))
) {
return {
routerName: routerName,
method: property.name,
args: args
}
} else {
return null
}
}
const formatMethodCall = expression => {
if (!expression.object || !expression.property) {
return '????'
}
return `${expression.object.name}.${expression.property.name}`
}
const parseAndPrintRoutesSync = path => {
const content = fs.readFileSync(path)
// Walk the AST (Abstract Syntax Tree)
acornWalk.simple(acorn.parse(content), {
// We only care about call expression ( like `a.b()` )
CallExpression(node) {
const call = routerCall(node)
if (call) {
const firstArg = _.first(call.args)
const lastArg = _.last(call.args)
try {
print(
` ${formatRouterName(call.routerName)}\t .${call.method} \t: ${
firstArg.value
} => ${formatMethodCall(lastArg)}`
)
} catch (e) {
print('>> Error')
print(e)
print(JSON.stringify(call))
process.exit(1)
}
}
}
})
}
const routerNameMapping = {
'privateApiRouter': 'privateApi',
'publicApiRouter': 'publicApi'
}
const formatRouterName = (name) => {
return routerNameMapping[name] || name
}
const main = () => {
// Take an optional filter to apply to file names
const filter = process.argv[2] || null
if (filter && (filter === '--help' || filter == 'help')) {
print('')
print(' Usage: bin/routes [filter]')
print(' Examples:')
print(' bin/routes')
print(' bin/routes GitBridge')
print('')
process.exit(0)
}
// Find all routers
glob('*[rR]outer.js', { matchBase: true }, (err, files) => {
for (file of files) {
if (file.match('^node_modules.*$') || file.match('.*/public/.*')) {
continue
}
// Restrict to the filter (if filter is present)
if (filter && !file.match(`.*${filter}.*`)) {
continue
}
print(`[${file}]`)
try {
parseAndPrintRoutesSync(file)
} catch (_e) {
print('>> Error parsing file')
continue
}
}
process.exit(0)
})
}
if (require.main === module) {
main()
}