diff --git a/README.md b/README.md index d95fafa..2989440 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,7 @@ hono routes [file] [options] - `--verbose` - include middleware - `--plain` - human-readable output instead of JSON +- `--exclude ` - 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 ` - Mark package as external (can be used multiple times) **Output:** diff --git a/src/commands/routes/index.test.ts b/src/commands/routes/index.test.ts index 1339bf7..3349ad4 100644 --- a/src/commands/routes/index.test.ts +++ b/src/commands/routes/index.test.ts @@ -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')) diff --git a/src/commands/routes/index.ts b/src/commands/routes/index.ts index 54eee08..f0e6a4c 100644 --- a/src/commands/routes/index.ts +++ b/src/commands/routes/index.ts @@ -10,11 +10,12 @@ 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.', ], } @@ -22,6 +23,7 @@ interface RoutesOptions { verbose: boolean plain: boolean external?: string[] + exclude: string[] } export function routesCommand(program: Command) { @@ -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 ', + 'hide routes whose path starts with the prefix (can be used multiple times)', + (value: string, previous: string[]) => [...previous, value], + [] as string[] + ) .option( '-e, --external ', 'Mark package as external (can be used multiple times)', @@ -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)