Por qué las utilidades de consola necesitan su propia alternativa a OpenAPI y cómo funciona el proyecto Usage
Cada vez que escribo una pequeña utilidad de consola, la misma historia se repite. Primero esbozas los argumentos y flags en el código. Luego decides agregar autocompletado para bash y zsh, te sumerges en recordar la sintaxis de scripts de shell o buscar generadores. A continuación necesitas formatear documentación en Markdown, actualizar páginas man y recordar dar soporte a variables de entorno. Si el proyecto se reescribe en otro lenguaje o gana wrappers de Python o Bash, tienes que duplicar manualmente toda la estructura de argumentos.
El desarrollador jdx, conocido por el popular gestor de versiones mise, abordó esta rutina de forma sistemática y creó el proyecto Usage.
Un contrato en lugar de soluciones dispersas
La idea central detrás de Usage es simple: el software de consola necesita su propia alternativa a OpenAPI o Swagger. En lugar de vincular las descripciones de argumentos a una librería específica en un lenguaje específico, Usage ofrece una única especificación portable en formato KDL.
KDL no fue elegido al azar. Este lenguaje de documentos es más limpio y legible que JSON o YAML, lo que lo hace conveniente para describir comandos anidados, flags, alias cortos y tipos de datos.
Describir la interfaz de tu utilidad en este formato una vez resuelve varios problemas a la vez:
- Generar scripts de autocompletado para todos los shells de comandos populares.
- Ensamblaje automático de documentación en Markdown y páginas man.
- Parsing de argumentos desde scripts en otros lenguajes.
- Generación de código base para diferentes librerías CLI.
Cómo se ve en Rust
Si estás escribiendo en Rust, no tienes que escribir el manifiesto KDL a mano en absoluto. El proyecto incluye un crate usage-rs que genera la especificación directamente desde tu estructura de datos usando macros derive.
Aquí tienes un ejemplo 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 готовы к работе
}
El parser en tiempo de ejecución no arrastra dependencias pesadas. Al mismo tiempo, puedes exportar una especificación KDL lista para usar desde la misma estructura y usarla en infraestructura de build externa o pipelines de CI/CD.
Diferencias con el familiar clap
La mayoría de los desarrolladores de Rust están acostumbrados a usar clap. El autor de Usage reconoce abiertamente la influencia de esta librería y preservó un formato de salida similar para los mensajes de ayuda y los informes de errores para hacer la transición lo menos dolorosa posible.
La diferencia radica en la filosofía. clap está estrictamente orientado al ecosistema de Rust. usage mueve el esquema de la interfaz a un nivel superior, convirtiéndolo en un contrato universal. Puedes tomar la especificación y parsear argumentos en un script Bash a través de la utilidad CLI usage sin reescribir tu lógica de validación de flags.
Empresas como 37signals ya están entre los patrocinadores del proyecto. Esto demuestra el interés de la industria en estandarizar las interfaces de terminal.
Para quién es útil el proyecto ahora mismo
Es poco probable que Usage sea necesario para un script de veinte líneas que solo se usa una vez. Sin embargo, la herramienta encaja perfectamente en el desarrollo de utilidades internas complejas de empresas, clientes CLI de APIs y herramientas de plataforma usadas por diferentes equipos.
Si estás cansado de sincronizar manualmente la documentación con los flags y escribir scripts de autocompletado para cada shell, definitivamente vale la pena echarle un vistazo al proyecto. La documentación y las guías de migración están disponibles en el sitio web oficial usage.jdx.dev.
Proyectos relacionados