Por que Utilitários de Console Precisam de Sua Própria Alternativa ao OpenAPI e Como o Projeto Usage Funciona
Toda vez que escrevo um pequeno utilitário de console, a mesma história se repete. Primeiro você esboça argumentos e flags no código. Então você decide adicionar autocompletar para bash e zsh, se aprofunda em lembrar a sintaxe de scripts de shell ou procurar geradores. Em seguida, você precisa formatar documentação em Markdown, atualizar páginas man e lembrar de suportar variáveis de ambiente. Se o projeto for reescrito em outra linguagem ou ganhar wrappers Python ou Bash, você tem que duplicar manualmente toda a estrutura de argumentos.
O desenvolvedor jdx, conhecido pelo popular gerenciador de versões mise, abordou essa rotina sistematicamente e criou o projeto Usage.
Um Contrato em Vez de Soluções Alternativas Dispersas
A ideia central por trás do Usage é simples: software de console precisa de sua própria alternativa ao OpenAPI ou Swagger. Em vez de vincular descrições de argumentos a uma biblioteca específica em uma linguagem específica, o Usage oferece uma única especificação portátil em formato KDL.
O KDL não foi escolhido aleatoriamente. Essa linguagem de documento é mais limpa e legível que JSON ou YAML, tornando-a conveniente para descrever comandos aninhados, flags, aliases curtos e tipos de dados.
Descrever a interface do seu utilitário nesse formato uma vez resolve vários problemas de uma só vez:
- Gerar scripts de autocompletar para todos os shells de comando populares.
- Montagem automática de documentação em Markdown e páginas man.
- Parsear argumentos de scripts em outras linguagens.
- Scaffolding de código para diferentes bibliotecas CLI.
Como Isso Funciona em Rust
Se você está escrevendo em Rust, não precisa escrever o manifesto KDL manualmente. O projeto inclui um crate usage-rs que gera a especificação diretamente da sua estrutura de dados usando derive macros.
Aqui está um exemplo básico:
[dependencies]
usage = { package = "usage-rs", version = "6" }
use usage::Cli;
#[derive(Cli)]
#[usage(bin = "example", version)]
struct App {
/// Print more detail.
#[usage(short = 'v', long, count)]
verbose: u8,
/// Files to process.
files: Vec<String>,
}
fn main() {
let app = App::parse();
// app.verbose и app.files готовы к работе
}
O parser runtime não arrasta dependências pesadas. Ao mesmo tempo, você pode exportar uma especificação KDL pronta da mesma estrutura e usá-la em infraestrutura de build externa ou pipelines CI/CD.
Diferenças do Familiar clap
A maioria dos desenvolvedores Rust está acostumada a usar clap. O autor do Usage reconhece abertamente a influência dessa biblioteca e preservou um formato de saída similar para mensagens de ajuda e relatórios de erro para tornar a transição menos dolorosa possível.
A diferença está na filosofia. clap é estritamente orientado para o ecossistema Rust. usage move o schema de interface para um nível superior, transformando-o em um contrato universal. Você pode pegar a especificação e parsear argumentos em um script Bash via utilitário CLI usage sem reescrever sua lógica de validação de flags.
Empresas como a 37signals já estão entre os patrocinadores do projeto. Isso demonstra o interesse da indústria em padronizar interfaces de terminal.
Para Quem o Projeto É Útil Agora
O Usage provavelmente não será necessário para um script descartável de vinte linhas. No entanto, a ferramenta se encaixa perfeitamente no desenvolvimento de utilitários internos complexos de empresas, clientes CLI de APIs e ferramentas de plataforma usadas por diferentes equipes.
Se você está cansado de sincronizar manualmente documentação com flags e escrever scripts de autocompletar para cada shell, o projeto definitivamente vale a pena explorar. Documentação e guias de migração estão disponíveis no site oficial usage.jdx.dev.
Projetos relacionados