-
Notifications
You must be signed in to change notification settings - Fork 4
Open
Description
Hono CLI calls commander.js directly. This is tightly coupled.
If we will change CLI library, we have to re-write production code. It may be difficult to guarantee same behavior.
So, How about introducing anti-corruption layer (ACL)? 👀
1. make src/acl/command.ts
Hono CLI uses only belows from commander.js.
- name
- description
- version
- parse
- command
- argument
- option
- action
We make original class named Command which has thees methods.
e.g,)
import { Command as CommanderCommand } from 'commander'
type ActionCallback = (...args: any[]) => void | Promise<void>
export class Command {
private instance: CommanderCommand
/**
* @internal
* This method is used to pass the internal commander instance to other commands.
* It should not be used directly.
*/
_getCommanderInstance(): CommanderCommand {
return this.instance
}
constructor(name?: string) {
this.instance = new CommanderCommand(name)
}
name(name: string): this {
this.instance.name(name)
return this
}
description(str: string): this {
this.instance.description(str)
return this
}
addCommand(cmd: Command): this {
this.instance.addCommand(cmd._getCommanderInstance())
return this
}
option(flags: string, description?: string, defaultValue?: string | boolean | string[]): this {
this.instance.option(flags, description, defaultValue)
return this
}
action(fn: ActionCallback): this {
this.instance.action(fn)
return this
}
parse(argv?: readonly string[]): this {
this.instance.parse(argv)
return this
}
version(str: string, flags?: string, description?: string): this {
this.instance.version(str, flags, description)
return this
}
}This inverts the dependency: instead of Hono CLI being tied to the Commander interface, you can decide what interface you need for Hono CLI and then use the functionality you need from Commander.js.
2. Change import resouce
All files excluding src/acl/command.ts replace commander to src/acl/command.ts
- import { Command } from 'commander'
+ import { Command } from './acl/command.ts'
import { readFileSync } from 'node:fs'
import { dirname, join } from 'node:path'
import { fileURLToPath } from 'node:url'
import { docsCommand } from './commands/docs/index.js'
import { optimizeCommand } from './commands/optimize/index.js'
import { requestCommand } from './commands/request/index.js'
import { searchCommand } from './commands/search/index.js'
import { serveCommand } from './commands/serve/index.js'
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
...3. Add Test Code for src/acl/command.ts
This makes it easy to verify operation even if you replace commander.js with another CLI library.
Metadata
Metadata
Assignees
Labels
No labels