当前位置: 首页 > article >正文

构建优雅、高效的 Nodejs 命令行工具 - Archons

目录

    • 项目简介
    • 安装
    • 基本用法
    • 样例
      • 创建一个简单的命令行工具
      • 使用`archons`上下文创建进度条
    • 最后

项目地址: https://github.com/noctisynth/archons
Bug反馈或功能请求:https://github.com/noctisynth/archons/issues

项目简介

Archons意思是“执政官”,我使用Rust作为Nodejs的Native层并将方法通过napi-rs导出到Nodejs,这使得我们可以借助Rust来帮助Nodejs使用者创建高效、强大和优雅的终端命令行工具。

创建这个项目首先是由于citty项目的启发,但是citty很多更高级的功能并不完善,个人感觉社区活跃度也不高,因为我的PR至今没人处理。于是我便想着另起炉灶,但是既然都重写了,为什么不RIIR(Rewrite it in Rust)呢?Rust的命令行工具已经有了一套完整的生态,我们完全可以让Nodejs工具在Rust的肩膀上新生。

于是Archons应运而生。

从本质上来讲,我只是对Rust很多生态例如clapindicatif等库的套壳,但是这的确能够让我们的Nodejs命令行工具更加优雅和强大。我采用类似citty的函数式的声明方式,这能够更加清晰的进行开发。

安装

我们将archons作为开发依赖安装:

  1. 使用npm安装:

    npm install --save-dev archons
    
  2. 使用pnpm安装:

    pnpm add -D archons
    
  3. 使用yarn安装:

    yarn add -D archons
    
  4. 使用bun安装:

    bun add -d archons
    

基本用法

  1. defineCommand 方法

    构建一个基本的命令(或子命令)。

  2. run 方法

    将一个命令作为主命令并运行。

样例

所有样例:https://github.com/noctisynth/archons/tree/main/examples

命令行选项所有可用参数:https://github.com/noctisynth/archons/blob/main/index.d.ts#L66-L210

创建一个简单的命令行工具

Archons 中参数的行为将尽量与 clap 保持一致,部分参数由于Rust与Nodejs的差异,在代码文档中均有标注。

import { defineCommand, run, type Context } from 'archons';

// 子命令
const dev = defineCommand({
  meta: {
    name: 'dev',
    about: 'Run development server',
  },
  options: {
    port: {
      type: 'option',
      parser: 'number',
      default: '3000',
    },
  },
  callback: (ctx: Context) => {
    console.log(ctx); // 这里输出完整的上下文
    console.log(ctx.args.port) // 这里port的值,缺省值为3000
  }
})

const main = defineCommand({
  meta: {
    name: 'simple',
    version: '0.0.1',
    about: 'A simple command line tool',
    styled: true,  // 启用色彩
  },
  options: {
    name: {
      type: 'positional', // 位置参数
      required: true, // 必须传入
      help: 'Name of the person to greet',
    },
    verbose: {
      type: 'option',
      parser: 'boolean',
      action: 'store',
      help: 'Enable verbose output',
      global: true // 全局参数,会被子命令继承
    },
  },
  // 子命令
  subcommands: {
    dev,
  },
  callback: (ctx: Context) => {
    console.log(ctx);
  }
})

run(main) // 执行主命令

使用archons上下文创建进度条

Archons 中进度条的创建行为与 indicatif 一致。

import { type Context, defineCommand, run } from 'archons'

const spinner = defineCommand({
  meta: {
    name: 'spinner',
  },
  options: {
    'enable-steady-tick': {
      type: 'option',
      action: 'store',
    },
  },
  callback: async (ctx: Context) => {
    const spinner = ctx.createSpinner()
    spinner.setMessage('loading')
    spinner.tick()
    let i = 100
    const interval = ctx.args.interval as number
    if (ctx.args['enable-steady-tick']) {
      spinner.println('Enabled steady tick')
      spinner.enableSteadyTick(interval)
      while (i--) {
        if (i < 30) {
          spinner.setMessage('Disabled steady tick for now')
          spinner.disableSteadyTick()
        }
        await new Promise((resolve) => setTimeout(resolve, interval))
      }
    } else {
      spinner.println('Disabled steady tick')
      while (i--) {
        spinner.tick()
        await new Promise((resolve) => setTimeout(resolve, interval))
      }
    }
    spinner.finishWithMessage('✨ finished')
  },
})

const bar = defineCommand({
  meta: {
    name: 'bar',
  },
  options: {
    clear: {
      type: 'option',
      action: 'store',
      help: 'Clear the progress bar',
      parser: 'boolean',
    },
  },
  callback: async (ctx: Context) => {
    const bar = ctx.createProgressBar(ctx.args.total as number)
    bar.setTemplate('{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {pos:>5}/{len:5} {msg}')
    bar.setProgressChars('=>-')
    let i = 100
    const interval = ctx.args.interval as number
    while (i--) {
      bar.inc(1)
      await new Promise((resolve) => setTimeout(resolve, interval))
    }
    if (ctx.args.clear) {
      bar.finishAndClear()
    } else {
      bar.finish()
    }
    console.log('✨ finished')
  },
})

const main = defineCommand({
  meta: {
    name: 'progressbar',
    styled: true,
    subcommandRequired: true,
  },
  options: {
    interval: {
      type: 'option',
      numArgs: '1',
      default: '100',
      global: true,
      help: 'Interval of spinner',
      parser: 'number',
    },
    total: {
      type: 'option',
      numArgs: '1',
      default: '100',
      global: true,
      help: 'Total of progress bar',
      parser: 'number',
    },
  },
  subcommands: {
    spinner,
    bar,
  },
})

run(main)

最后

如果你认为这个项目有所帮助,欢迎在GitHub给我一个Star哦!


http://www.kler.cn/a/503887.html

相关文章:

  • golang运维开发-gopsutil(1)
  • 开源项目stable-diffusion-webui部署及生成照片
  • Genymotion配套VirtualBox所在地址
  • 跨境电商领域云手机之选:亚矩阵云手机的卓越优势
  • springboot
  • EFK采集k8s日志
  • day13-第一次摸底考试题及讲解
  • L2 正则化(权重衰减)
  • 优化 MySQL 的慢查询
  • WPF系列十二:图形控件CombinedGeometry
  • 42_Lua table表
  • 【拒绝算法PUA】3065. 超过阈值的最少操作数 I
  • Spring Boot 2 学习全攻略
  • w~大模型~合集27
  • 托宾效应和托宾q理论。简单解释
  • uniapp 发布后原生img正常,image无法显示,img与uniapp image使用区别
  • 【Block总结】Conv2Former的Block,结合卷积网络和Transformer的优点|即插即用
  • 视频超分(VSR)论文阅读记录/idea积累(一)
  • 【学术会议指南】方向包括遥感、测绘、图像处理、信息化教育、计算机技术、通信、大数据、人工智能、机械设计、仿真...可线上参与
  • Oracle重启后业务连接大量library cache lock
  • 【web靶场】之upload-labs专项训练(基于BUUCTF平台)
  • 工程师 - Eclipse安装和UML插件
  • 代码随想录刷题day07|(数组篇)58.区间和
  • LeetCode 热题 100_从前序与中序遍历序列构造二叉树(47_105_中等_C++)(二叉树;递归)
  • AI-ANNE:探索型神经网络——将深度学习模型转移到微控制器和嵌入式系统
  • 【网络云SRE运维开发】2025第2周-每日【2025/01/11】小测-【第11章NAT理论和实操考试】解析和参考