使用oclif框架制造命令行工具

2,521 阅读5分钟

概述

oclif是用于在Node.js中构建CLI的框架,可以通用化以构建任何自定义CLI。它既设计用于带有几个标志选项的单命令CLI,也设计用于具有多命令的非常复杂的CLI。接下来让我来给大家介绍下oclif框架吧!!!

特性

首先,先介绍一下oclif的特性。

  • 标志/参数解析: 通过简单的写法定义标志选项和参数,灵活处理用户输入,以使用户能够以他们期望的方式使用CLI。
  • 超高速: 运行oclif CLI命令的开销几乎没有。此外,只有仅需要执行的命令被node加载。 因此,包含许多命令的大型CLI将与使用单个命令的小型CLI一样快地加载。
  • CLI生成器: 快速初始化一个项目模版,快速进行开发。
  • 自动文档: 默认情况下,您可以传递--help给CLI以获取帮助,例如标志选项和参数信息。每当发布CLI的npm软件包时,此信息也将自动放置在README.md中。
  • 插件: 使用插件,CLI的用户可以使用新功能对其进行扩展,CLI可以拆分为模块化组件,并且可以在多个CLI之间共享功能。
  • 钩子: 使用生命周期挂钩可在CLI启动时或在自定义触发器上运行功能。每当需要在CLI的各个组件之间共享自定义功能时,请使用此功能。
  • TypeScript: 支持TS,在初始化项目的时候可以选择JS或者TS,oclif的框架内部代码也是使用TS。
  • 方便调试: 不用编译,就可以在直接使用。

安装

建议全局安装,这样子在任何地方都可以使用oclif命令了。

# 建议全局安装
npm i oclif -g

单命令

首先,执行 oclif single myls初始化一个项目。根据询问选择自己适合的选项,如果不确定,直接回车就可以了。通过这个项目,我们来简单模拟一下ls的指令。

image.png 项目目录结构

image.png 编写index.ts,代码如下

import { Command, flags } from '@oclif/command'
import * as fs from 'fs'
class Myls extends Command {
  static description = 'a cli to simulate the cli ls'
  
  static examples = [
    'myls',
    'myls -f',
    'myls -d',
  ]
  
  static usage = 'myls [-f, -d]'
  
  static flags = {
    version: flags.version({ char: 'v' }),
    help: flags.help({ char: 'h' }),
    file: flags.boolean({ char: 'f', description: 'show all files under the dir', default: false }),
    dir: flags.boolean({ char: 'd', description: 'show all directories under the dir', default: false }),
  }
  
  static args = []

  async run() {
    const { flags } = this.parse(Myls)
    const { file, dir } = flags
    const currentPath = process.cwd()
    const dirs = fs.readdirSync(currentPath)
    if(dirs.length === 0) this.warn('there is nothing under the path')
    if(file && !dir) {
      let noFile = true
      for(let d of dirs) {
        if(fs.statSync(`${currentPath}/${d}`).isFile()) {
          noFile = false
          this.log(d)
        }
        noFile && this.warn('no file.')
      }
      this.exit()
    }
    if(dir && !file) {
      let noDir = true
      for(let d of dirs) {
        if(fs.statSync(`${currentPath}/${d}`).isDirectory()) {
          noDir = false
          this.log(d)
        }
      }
      noDir && this.warn('no directory.')
      this.exit()
    }
    for(const d of dirs) {
      this.log(d)
    }
  }
}

export = Myls

基类Command

用oclif命令行创建项目之后,默认会下载很多依赖,具体可以查看package.json文件。首先需要从 @oclif/command引入Command,这是所有命令的基类,所有的命令都应该直接或者间接地继承自它。这个类封装了很多好用的静态属性和方法。

静态属性

  1. description:这个属性是对于这个命令的简明描述。那你为什么用到它呢?运行命令myls --help
  2. hidden:当你设置为true的时候,在你执行myls --help,你将看不到它的存在。
  3. examples:它是一个数组,你可以把怎么使用这个命令的例子写在这里。
  4. usage:它是一个字符串,这条命令的基本使用,可以填写一条常用的命令在这里。

image.png

run方法

它是Command的实例函数,当你使用命令myls的时候,实际上就是去调用这个函数。如果你再这个函数里面只打印了一行内容,其他的什么也你不做,在你的终端上试一试,它就会按你写的打印。

async run() {
  console.log('running myls command')
}

//在终端执行命令 myls 打印如下
running myls command

命令参数

参数是传递给命令的位置参数mycli one two像这样传入参数。所有的参数在一个静态属性args中定义,每个参数名字和每个参数值是一一对应的关系。

参数名字参数值描述
argsfirstArgone它是一个对象,有this.parse()解析而出,注意不要和静态属性的args混为一谈。它的格式由静态属性的args定义。
secondArgtwo
参数下标参数值描述
argv0one它是一个数组,命令参数会依次的传入到这个数组。它也是有this.parse()解析而出。
1two
import {Command, flags} from '@oclif/command'
class MyCLI extends Command {
  static flags = {
    version: flags.version({ char: 'v' }),
    help: flags.help({ char: 'h' }),
  }
  static args = [
    {name: 'firstArg'},
    {name: 'secondArg'},
  ]
  async run() {
    const {args} = this.parse(MyCLI)
    console.log(`${args.firstArg}, ${args.secondArg}`)
    const {argv} = this.parse(MyCLI)
    console.log(`${argv[0]}, ${argv[1]}`)
  }
}
export = MyCLI

命令参数的选项配置

image.png

命令标志

标志选项是传递给命令的非位置参数。标志可以是带有参数的选项标志,也可以是不带参数的布尔标志。一个选项标志必须有一个参数。所有的标志在一个静态属性flags中定义,每个标志名字都可配置其相应的缩写。首先从oclif的API中引入flags,这个flags提供了很多函数可以定义不同类型的标志参数。有些可以直接从调用的函数名看出标志参数的类型。

// 简略版
import { Command, flags } from '@oclif/command'
class MyCLI extends Command {
  static flags = {
    version: flags.version({ char: 'v' }),
    help: flags.help({ char: 'h' }),
    force: flags.boolean({ char: 'f', default: true }),
    id: flags.integer({ char: 'i', options: ['1', '2', '3', '4'] }),
    name: flags.string({char: 'n', multiple: true}),
    age: age()
  }
}

命令标志的选项配置 image.png

常用命令

  1. oclif single <NAME>:在当前目录中创建一个单命令项目
  2. oclif multi <NAME>:在当前目录中创建一个多命令项目
  3. oclif command <NAME>:添加一条命令
  4. oclif hook <NAME> --event=<hook>:新建一个钩子
  5. oclif plugin <pluginName>:新建一个插件

参考资料

  1. oclif官网文档
  2. www.npmjs.com/package/inq…
  3. www.npmjs.com/package/ocl…