first commit
This commit is contained in:
134
services/web/bin/routes
Executable file
134
services/web/bin/routes
Executable file
@@ -0,0 +1,134 @@
|
||||
#! /usr/bin/env node
|
||||
|
||||
const acorn = require('acorn')
|
||||
const acornWalk = require('acorn-walk')
|
||||
const fs = require('fs')
|
||||
const _ = require('lodash')
|
||||
const glob = require('glob')
|
||||
const escodegen = require('escodegen')
|
||||
const 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,
|
||||
method: property.name,
|
||||
args,
|
||||
}
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
const formatMethodCall = expression => {
|
||||
return escodegen.generate(expression, { format: { compact: true } })
|
||||
}
|
||||
|
||||
const parseAndPrintRoutesSync = path => {
|
||||
const content = fs.readFileSync(path)
|
||||
// Walk the AST (Abstract Syntax Tree)
|
||||
acornWalk.simple(
|
||||
acorn.parse(content, { sourceType: 'module', ecmaVersion: 2020 }),
|
||||
{
|
||||
// We only care about call expression ( like `a.b()` )
|
||||
CallExpression(node) {
|
||||
const call = routerCall(node)
|
||||
if (call) {
|
||||
const firstArg = _.first(call.args)
|
||||
try {
|
||||
print(
|
||||
` ${formatRouterName(call.routerName)}\t .${call.method} \t: ${
|
||||
firstArg.value
|
||||
} => ${call.args.slice(1).map(formatMethodCall).join(' => ')}`
|
||||
)
|
||||
} 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) => {
|
||||
if (err) {
|
||||
console.error(err)
|
||||
process.exit(1)
|
||||
}
|
||||
for (const 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()
|
||||
}
|
Reference in New Issue
Block a user