Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ hono routes [file] [options]

- `--verbose` - include middleware
- `--plain` - human-readable output instead of JSON
- `--exclude <prefix>` - hide routes whose path starts with the prefix, e.g. `--exclude /__void` for internal routes a framework adds (can be used multiple times)
- `-e, --external <package>` - Mark package as external (can be used multiple times)

**Output:**
Expand Down
24 changes: 24 additions & 0 deletions src/commands/routes/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,30 @@ describe('routesCommand', () => {
])
})

it('should hide routes that start with an --exclude prefix', async () => {
const app = new Hono()
app.get('/', (c) => c.text('Hello'))
app.get('/__void/a', (c) => c.text('a'))
app.get('/__internal/b', (c) => c.text('b'))
setupBasicMocks(app)

await program.parseAsync([
'node',
'test',
'routes',
'--exclude',
'/__void',
'--exclude',
'/__internal',
'test-app.js',
])

const parsed = JSON.parse(consoleLogSpy.mock.calls[0][0])
expect(parsed.data.routes).toEqual([
{ method: 'GET', path: '/', name: '[handler]', isMiddleware: false },
])
})

it('should print routes as text with --plain', async () => {
const app = new Hono()
app.get('/', (c) => c.text('Hello'))
Expand Down
14 changes: 12 additions & 2 deletions src/commands/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,20 @@ import { isVoidProject, loadVoidApp, startVite } from '../../utils/vite.js'
const help: CommandHelp = {
output:
'{ "router": "SmartRouter + RegExpRouter", "routes": [{ "method": "GET", "path": "/", "name": "[handler]", "isMiddleware": false }] }',
examples: ['hono routes', 'hono routes --verbose src/app.ts'],
examples: ['hono routes', 'hono routes --verbose src/app.ts', 'hono routes --exclude /__void'],
notes: [
'Routes are resolved from the real app instance, so mounted sub-apps and basePath are all expanded.',
'Run it first to get the full picture of an app without reading the source.',
'In a Void project (no entry file), the routes come from the app that Void builds through Vite.',
'--exclude hides the routes whose path starts with the prefix, e.g. internal routes a framework adds.',
],
}

interface RoutesOptions {
verbose: boolean
plain: boolean
external?: string[]
exclude: string[]
}

export function routesCommand(program: Command) {
Expand All @@ -32,6 +34,12 @@ export function routesCommand(program: Command) {
.argument('[file]', 'Path to the Hono app file')
.option('--verbose', 'include middleware', false)
.option('--plain', 'human-readable output instead of JSON', false)
.option(
'--exclude <prefix>',
'hide routes whose path starts with the prefix (can be used multiple times)',
(value: string, previous: string[]) => [...previous, value],
[] as string[]
)
.option(
'-e, --external <package>',
'Mark package as external (can be used multiple times)',
Expand Down Expand Up @@ -60,7 +68,9 @@ export function routesCommand(program: Command) {
}

const routes = inspectRoutes(app).filter(
({ isMiddleware }) => options.verbose || !isMiddleware
({ isMiddleware, path }) =>
(options.verbose || !isMiddleware) &&
!options.exclude.some((prefix) => path.startsWith(prefix))
)
const router = getRouterName(app)

Expand Down
Loading