npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

best-shell-tool

v1.1.1

Published

BST实现的是一个shell & command的操作库,分别提供了shell控制字符串操作、shell终端操作、command parse操作和基础shell功能组件四大能力。

Downloads

24

Readme

Best Shell tool

dev以来需要用--legacy-peer-deps来解决冲突

npm version npm version npm bundle size github activity languages gitHub watchers gitHub stars


1. 关于BST

BST期望做到简化命令行编程能力,更快、更简单地开发命令行工具和cli。在后续的介绍过程中,会带大家实现几个命令行小功能,来了解BST开发命令行工具的过程。


2. shell控制字符模块

该模块提供了生成控制字符的能力。所谓控制字符其实就是改变终端或文件显示的一些行为。一个控制符是由 CONTRL + key 组成的(同时按下)。控制字符同样可以通过转义以八进制或十六进制的方式显示。

2.1 getFontStyle

getFontStyle(fontColor:Color, backColor:Color, msg:string):string

关于Color的定义如下TS所示:

type Color = 'black' | 'red' | 'green' | 'yellow' | 'blue' | 'purple' | 'celeste' | 'white';

示例:

const bst = require('best-shell-tool')

console.log(bst.getFontStyle('blue', '', '我是蓝色字'))
console.log(bst.getFontStyle('red', '', '我是红色字'))
console.log(bst.getFontStyle('yellow', 'blue', '我是黄色字蓝色背景'))

输出:

图一

2.2 clearAllProps

获取清除所有属性的shell消息。通过这个可以清除前文所设置的所有属性样式。

clearAllProps(msg:string):string

示例:

const bst = require('best-shell-tool')

console.log(bst.getFontStyle('blue')+'我是蓝色')
console.log(bst.getFontStyle('blue')+bst.clearAllProps('我的蓝色属性没有被继承过来'))

输出:

图二

2.3 getHighlightString

获取高亮的shell消息,其实个人感觉就是稍微加粗了一下。

getHighlightString(msg:string):string

示例:

const bst = require('best-shell-tool')

console.log(bst.clearAllProps('我是普通字'))
console.log(bst.getHighlightString('我是高亮字'))
console.log(bst.getFontStyle('red') + bst.getHighlightString('我是红色高亮字'))

输出:

图三

2.4 getUnderLineString

获取下划线的shell消息

getUnderLineString(msg:string):string

示例:

const bst = require('best-shell-tool')

console.log(bst.clearAllProps('我是普通字'))
console.log(bst.getUnderLineString('我是下划线字'))
console.log(bst.getFontStyle('red') + bst.getUnderLineString('我是红色下划线字'))

输出:

图四

2.5 getBlinkString

获取闪烁字体的shell消息,故名思议,该功能实现了shell文字闪烁,一般在shell交互能力中,用于表示已经选中的选项。

getUnderLineString(msg:string):string

示例:

const bst = require('best-shell-tool')

console.log(bst.clearAllProps('我是普通字'))
console.log(bst.getBlinkString('我是闪烁字'))
console.log(bst.getFontStyle('red') + bst.getBlinkString('我是红色闪烁字'))

2.6 getRDisplayString

获取反显的shell消息,所谓反显,就是模拟文字被选中的状态,一般呈现为 背景=字体颜色, 字体颜色=背景。

getRDisplayString(msg:string):string

示例:

const bst = require('best-shell-tool')

console.log(bst.clearAllProps('我是普通字'))
console.log(bst.getRDisplayString('我是反显状态'))
console.log(bst.getFontStyle('red') + bst.getRDisplayString('我是红色字反显状态'))

输出:

图五

2.7 getCancelHideString

获取消隐的shell消息,消隐的消息在控制台是看不见的,但是占位符是真实存在的,并且文字也是可以真实复制的。

getCancelHideString(msg:string):string

示例:

const bst = require('best-shell-tool')

console.log(bst.clearAllProps('我是普通字'))
console.log(bst.getCancelHideString('我是消隐状态'))

2.8 controlArrowMove

控制shell光标移动的shell消息,通过方向指令和移动数量来控制光标的移动,可以实现在不同位置做输出的功能。

controlArrowMove(direct:Direct, lines:number, msg:string):string

关于Direct的定义如下TS所示:

type Direct = 'up' | 'down' | 'right' | 'left' | '上' | '下' | '左' | '右';

示例:

const bst = require('best-shell-tool')

console.log('00 01 02 03')
console.log('10 11 12 13')
console.log('20 21 22 23')
console.log('30 31 32 33')
console.log(bst.controlArrowMove('上', 2, '我是移动后的'))

输出:

图六

2.9 setArrowPosition

设置shell光标位置的shell消息,和controlArrowMove相比,这个是直接通过指定坐标点来移动光标。

setArrowPosition(x:number | '', y:number | '', msg:string):string

2.10 clearScreen

清屏,顾名思义,清除之前屏幕所有的内容。

clearScreen(msg:string):string

2.11 saveArrowPosition

保存当前光标位置

saveArrowPosition(msg:string):string

2.12 readArrowPosition

取出之前保存的光标位置

saveArrowPosition(msg:string):string

2.13 hideArrow

隐藏光标,就是把shell的那个小黑点隐藏。

hideArrow(msg:string):string

2.14 showArrow

显示光标

showArrow(msg:string):string

2.15 clearPositionAfter

清除光标之后这一行的消息。在制作进度条的时候可以用它时时清除一行后的消息,保留之前输出的消息。

clearPositionAfter(msg:string):string

2.16 getFmtString

获取格式化字符串。和前面的不同,这个是链式获取一串格式化消息,通过end结束链式调用,拿到格式化消息。其中每次返回的StandOutOperate操作对象,里面的所有操作链都能和前面的函数一一对应。

function getFmtString(_msg:string):StandOutOperate

关于StandOutOperate的定义如下TS所示:

interface StandOutOperate {
  /**
   * @description: 附加消息
   * @param {string} msg 要附加的消息
   * @return {StandOutOperate}
   */
  msg?: (msg?:string) => StandOutOperate,

  /**
   * @description: 结束并获得格式化后的字符
   * @return {string}
   */
  end?: () => string,

  /**
   * @description: 设置字体样式
   * @param {Color | ''} fontColor 字体颜色
   * @param {Color | ''} background 背景色
   * @return {StandOutOperate}
   */
  setFont?: (fontColor?: Color | '', background?: Color | '', msg?:string) => StandOutOperate,

  /**
   * @description: 清除所有控制属性
   * @param {string} msg 附加消息
   * @return {StandOutOperate}
   */
  clearProps?: (msg?:string) => StandOutOperate,

  /**
   * @description: 高亮文本
   * @param {string} msg 消息
   * @return {StandOutOperate}
   */
  highlight?: (msg?:string) => StandOutOperate,

  /**
   * @description: 下划线
   * @param {string} msg 消息
   * @return {StandOutOperate}
   */
  underline?: (msg?:string) => StandOutOperate,

  /**
   * @description: 闪烁
   * @param {string} msg 消息
   * @return {StandOutOperate}
   */
  blink?: (msg?:string) => StandOutOperate,

  /**
   * @description: 反显
   * @param {string} msg 消息
   * @return {StandOutOperate}
   */
  rdisplay?: (msg?:string) => StandOutOperate,

  /**
   * @description: 消隐
   * @param {string} msg 消息
   * @return {StandOutOperate}
   */
  cancelHide?: (msg?:string) => StandOutOperate,

  /**
   * @description: 控制光标移动
   * @param {Direct} direct 移动方向
   * @param {number} lines 移动行数
   * @param {string} msg 附加消息
   * @return {StandOutOperate}
   */
  arrowMove?: (direct?:Direct, lines?:number, msg?:string) => StandOutOperate,

  /**
   * @description: 设置鼠标位置
   * @param {number | ''} x 横坐标移动距离
   * @param {number | ''} y 纵坐标移动距离
   * @param {string} msg 附加消息
   * @return {StandOutOperate}
   */
  setArrow?: (x?:number | '', y?:number | '', msg?:string) => StandOutOperate,

  /**
   * @description: 清屏
   * @param {string} msg 附加消息
   * @return {StandOutOperate}
   */
  clear?: (msg?:string) => StandOutOperate,

  /**
   * @description: 保存光标位置
   * @param {string} msg 附加消息
   * @return {StandOutOperate}
   */
  saveArrow?: (msg?:string) => StandOutOperate,

  /**
   * @description: 读取恢复光标位置
   * @param {string} msg 附加消息
   * @return {StandOutOperate}
   */
  readArrow?: (msg?:string) => StandOutOperate,

  /**
   * @description: 隐藏光标
   * @param {string} msg 附加消息
   * @return {StandOutOperate}
   */
  hideArrow?: (msg?:string) => StandOutOperate,

  /**
   * @description: 显示光标
   * @param {string} msg 附加消息
   * @return {StandOutOperate}
   */
  showArrow?: (msg?:string) => StandOutOperate,

  /**
   * @description: 清除光标所在位置之后这一行的所有内容
   * @param {string} msg 附加消息
   * @return {StandOutOperate}
   */
  clearAfter?: (msg?:string) => StandOutOperate,
}

示例:

const bst = require('best-shell-tool')

console.log(
  bst.getFmtString('我是普通字体')
  .setFont('red', '', '我是红色字体')
  .clearProps()
  .underline('没想到我带下划线了')
  .setFont('blue', '', '我蓝了')
  .end()
)

输出:

图七

2.17 基于控制字符实现一个 进度条 功能

这里是一个简单的实战教学,基于前文提供的api制作一个简单的进度条功能。当然,因为这个进度条工具很常用,BST自带的组件库里面已经封装了进度条。这里的实现只是为了大家更好的掌握和熟悉BST-控制字符模块的功能。

示例:

function process (current, total, len = 10) {
  const back = bst.getFontStyle('', 'white', ' ')
  const active = bst.getFontStyle('', 'green', ' ')
  const activeNum = parseInt((current / total) * len, 10)
  let processStr = ''
  for(let i = 0; i < len; i++) {
    if(i < activeNum) processStr += active
    else processStr += back
  }
  console.log(
    bst.getFmtString()
    .hideArrow()
    .arrowMove('上', 1)
    .clearAfter(processStr)
    .clearProps()
    .msg(current)
    .msg('/')
    .msg(total)
    .end()
  )
}

let count = 0
let total = 21
console.log('准备加载进度\n')
setTimeout(()=>{
  const timer = setInterval(()=>{
    if(count === total) clearInterval(timer)
    process(count, total, 25)
    count++
  }, 1000)
}, 1000)

3. CommandX语法和语法解析器

CommandX是作者定义的一种简单命令交互语法,它是一种简化、弱化后的shell命令模式,设计之初的目的是为了解决node开发命令行工具时,希望对用户开放命令交互的愿景,CommandX语法通过cmParse可以将对应的命令解析成命令对象的形式。形式定义如下:

interface ParseStruct {
  command?: string,
  defaultArgs?: string,
  args?: {
    [argsName:string]:any
  }
}

3.1 CommandX语法

这一节将简单介绍一些CommandX语法编写,和对应转换成命令对象形式的样例。

  • 无参数直接命令 commandX语法 command 转换成js对象后

    { args: {}, command: 'command' }
  • 带参数命令 commandX语法 command -arg1 你好世界 -arg2 我是参数2 转换成js对象后

    { args: { arg1: '你好世界', arg2: '我是参数2' }, command: 'command' }
  • 布尔值参数使用 commandX语法 command -arg1 -arg2 arg1是布尔值 转换成js对象后

    { args: { arg1: true, arg2: 'arg1是布尔值' }, command: 'command' }
  • 默认参数值语法 commandX语法 command 我是默认值 -other 我不是默认值 转换成js对象后

    { args: { other: '我不是默认值' }, command: 'command', defaultArgs: '我是默认值' }

    commandX语法 command -other 我不是默认值 我是默认值 转换成js对象后

    { args: { other: '我不是默认值' }, command: 'command', defaultArgs: '我是默认值' }
  • 双引号限定字符串 commandX中,带上双引号的字符串叫作双引号限定字符串,该类型字符串中,反斜杠(\)和双引号(")属于特殊字符,需要用转义字符才能使他正确转换。 commandX语法 command "她说:\"我爱你\"" 转换成js对象后

    { args: {}, command: 'command', defaultArgs: '她说:"我爱你"' }
  • 自由非限定字符 commandX中,不被双引号(")包裹的字符串被称作自由非限定字符,对于这类字符是不能使用双引号(")和减号(-)开头。所以在自由非限定字符模式下,提供了unicode直接编码转换。用\U;的模式可以指定任意一个Unicode对应的字符。比如\65;就会被转换为字符A。对于一些特殊字符,可以直接使用\S标识转换的模式,如常用的空格可以用\space;转换。标识的对应关系如下:

    • \space; ===
    • \backslash; === \
    • \slash; === /
    • \semicolon; === ;

    commandX语法 command \65;\66;\67; 转换成js对象后

    { args: {}, command: 'command', defaultArgs: 'ABC' }

3.2 parser函数

parser函数是BST CommandParse模块提供的CommandX语法解析函数,用它可以将CommandX语法编译成js对象。参数str是要解析commandX语法,参数mode是指定报错模式,如果为normal,使用console.log进行错误提示。如果为strict,错误直接抛出。参数isDebugger是用来调试编译的语法分析,如果为true,则在每一次意外的语法分析,输出当前语法分析状态机的状态 function parser(str:string, mode:Mode = 'normal', isDebugger:boolean = false):ParseStruct

关于ParseStruct的定义如下TS所示:

interface ParseStruct {
  command?: string,
  defaultArgs?: string,
  args?: {
    [argsName:string]:any
  }
}

示例:

const bst = require('best-shell-tool')

const res = bst.cmParser.parser('command -arg hello,world')
console.log(res)

输出:

{ args: { arg: 'hello,world' }, command: 'command' }

3.3 data2Commandx函数

data2Commandx函数是parser的一个逆向过程,它能将命令对象转换成CommandX语法。 function data2Commandx(data:ParseStruct):string

关于ParseStruct的定义如下TS所示:

interface ParseStruct {
  command?: string,
  defaultArgs?: string,
  args?: {
    [argsName:string]:any
  }
}

示例:

const bst = require('best-shell-tool')

const data = {
  args: { isOpen: true, x: '10', y: '20' },
  command: 'command',
  defaultArgs: 'hello,world'
}
const res = bst.cmParser.data2Commandx(data)
console.log(res)

输出: command "hello,world" -isOpen -x "10" -y "20"

3.4 formatFree函数

formatFree函数是一个用来将自由非限定字符串转化为js字符串,CommandX的parser对于自由非限定字符串就是使用该函数实现。 function formatFree(str:string):string


4. IOStand标准输入输出库

BST提供了一个标准输入输出管理,用它可以轻松管理shell控制台的输入输出。

4.1 write

IOStand的write函数是输出一条消息到控制台。 write(data:string = ''):boolean

示例:

const bst = require('best-shell-tool')

const iostand = new bst.IOStand()
iostand.write('hello world\n')

此时你会发现控制台输出了hello world,和console.log效果类似,不同的是他不会自动在语句后换行。

4.2 writeChain

IOStand的writeChain函数是链式输出一条消息到控制台。里面会返回一条操作链。 writeChain(_msg:string = ''):StandOutOperate 其中StandOutOperate定义如下:

interface StandOutOperate {
  /**
   * @description: 附加消息
   * @param {string} msg 要附加的消息
   * @return {StandOutOperate}
   */
  msg?: (msg?:string) => StandOutOperate,

  /**
   * @description: 设置字体样式
   * @param {Color | ''} fontColor 字体颜色
   * @param {Color | ''} background 背景色
   * @return {StandOutOperate}
   */
  setFont?: (fontColor?: Color | '', background?: Color | '', msg?:string) => StandOutOperate,

  /**
   * @description: 清除所有控制属性
   * @param {string} msg 附加消息
   * @return {StandOutOperate}
   */
  clearProps?: (msg?:string) => StandOutOperate,

  /**
   * @description: 高亮文本
   * @param {string} msg 消息
   * @return {StandOutOperate}
   */
  highlight?: (msg?:string) => StandOutOperate,

  /**
   * @description: 下划线
   * @param {string} msg 消息
   * @return {StandOutOperate}
   */
  underline?: (msg?:string) => StandOutOperate,

  /**
   * @description: 闪烁
   * @param {string} msg 消息
   * @return {StandOutOperate}
   */
  blink?: (msg?:string) => StandOutOperate,

  /**
   * @description: 反显
   * @param {string} msg 消息
   * @return {StandOutOperate}
   */
  rdisplay?: (msg?:string) => StandOutOperate,

  /**
   * @description: 消隐
   * @param {string} msg 消息
   * @return {StandOutOperate}
   */
  cancelHide?: (msg?:string) => StandOutOperate,

  /**
   * @description: 控制光标移动
   * @param {Direct} direct 移动方向
   * @param {number} lines 移动行数
   * @param {string} msg 附加消息
   * @return {StandOutOperate}
   */
  arrowMove?: (direct?:Direct, lines?:number, msg?:string) => StandOutOperate,

  /**
   * @description: 设置鼠标位置
   * @param {number | ''} x 横坐标移动距离
   * @param {number | ''} y 纵坐标移动距离
   * @param {string} msg 附加消息
   * @return {StandOutOperate}
   */
  setArrow?: (x?:number | '', y?:number | '', msg?:string) => StandOutOperate,

  /**
   * @description: 清屏
   * @param {string} msg 附加消息
   * @return {StandOutOperate}
   */
  clear?: (msg?:string) => StandOutOperate,

  /**
   * @description: 保存光标位置
   * @param {string} msg 附加消息
   * @return {StandOutOperate}
   */
  saveArrow?: (msg?:string) => StandOutOperate,

  /**
   * @description: 读取恢复光标位置
   * @param {string} msg 附加消息
   * @return {StandOutOperate}
   */
  readArrow?: (msg?:string) => StandOutOperate,

  /**
   * @description: 隐藏光标
   * @param {string} msg 附加消息
   * @return {StandOutOperate}
   */
  hideArrow?: (msg?:string) => StandOutOperate,

  /**
   * @description: 显示光标
   * @param {string} msg 附加消息
   * @return {StandOutOperate}
   */
  showArrow?: (msg?:string) => StandOutOperate,

  /**
   * @description: 清除光标所在位置之后这一行的所有内容
   * @param {string} msg 附加消息
   * @return {StandOutOperate}
   */
  clearAfter?: (msg?:string) => StandOutOperate,
}

示例:

const bst = require('best-shell-tool')

const iostand = new bst.IOStand()
iostand.writeChain('我是普通字体')
  .setFont('red', '', '我是红色字体')
  .setFont('yellow', '', '我是黄色字体\n')

输出: 图八

4.3 start

start函数是开启命令交互模式,你可以使用oninput事件来监听输入,注意,当你注册了oninput事件,那么start就不会启用CommandX命令交互模式。

如下示例,我们注册了oninput事件来监听输入。

示例:

const bst = require('best-shell-tool')

const iostand = new bst.IOStand()
iostand.oninput = (data) => {
  console.log('你输入了:', data)
}
iostand.start()

如果我们直接使用start,相当于是一个CommandX交互模式,你需要通过addCommand函数来注册命令。如下示例所示。

示例:

const iostand = new bst.IOStand()

iostand.addCommand('hello')
  .action(()=>{
    console.log('hello world')
  })
iostand.start()

输出: 图九 图十 图十一

4.4 addCommand

addCommand是添加一条CommandX命令,这样在开启start交互后,就会根据CommandX寻找已经注册过的action去执行。 addCommand(cmd:string, notes:string = ''):AddCommandOperate

其中AddCommandOperate如下:

interface AddCommandOperate {
  /**
   * @description: 声明一个参数
   * @param {string} argName 参数名称
   * @param {string} notes 参数注释
   * @return {AddCommandOperate} 返回操作链
   */
  arg: (argName:string, notes:string) => AddCommandOperate;

  /**
   * @description: 声明一个默认参数
   * @param {string} notes 参数注释
   * @return {AddCommandOperate} 返回操作链
   */
  defaultArg: (notes:string) => AddCommandOperate;

  /**
   * @description: 注册操作函数
   * @param {(command:ParseStruct)=>Promise<number>} fn 操作函数
   * @return {AddCommandOperate} 返回操作链
   */
  action: (fn:(command:ParseStruct)=>Promise<number>)=>AddCommandOperate;
}

示例:

const bst = require('best-shell-tool')

const iostand = new bst.IOStand()
iostand.addCommand('say', '输出一句话到控制台')
  .defaultArg('要说的话')
  .arg('prefix', '前缀')
  .arg('suffyx', '后缀')
  .action((cmd)=>{
    const prefix = cmd.args.prefix || '';
    const suffix = cmd.args.suffix || '';
    const content = cmd.defaultArgs || '';
    console.log(prefix,content,suffix)
  })
iostand.start()

输出: 图十二

值得注意的是,IOStand里面其实默认注册了一个help命令,通过它可以在控制台查询已经注册过的命令使用方式。 其次,action注册的函数如果返回的是Promise,相当于你是一个异步函数,它会等你执行完成再监听输入。 如果已经存在某个命令,则不能再注册该命令。

4.5 listAllCommand

listAllCommand函数是列出已经注册过的CommandX命令。 listAllCommand():void

示例:

const bst = require('best-shell-tool')

const iostand = new bst.IOStand()
iostand.addCommand('say', '输出一句话到控制台')
  .defaultArg('要说的话')
  .arg('prefix', '前缀')
  .arg('suffyx', '后缀')
  .action((cmd)=>{
    const prefix = cmd.args.prefix || '';
    const suffix = cmd.args.suffix || '';
    const content = cmd.defaultArgs || '';
    console.log(prefix,content,suffix)
  })
iostand.listAllCommand()

输出:

help    
    -[默认参数] 要查看帮助的命令(可以不填写)

say    输出一句话到控制台
    -[默认参数] 要说的话
    -prefix 前缀
    -suffyx 后缀

4.6 awaitInput

awaitInput是等待一次输入,等待的这次输入不会受到CommandX交互的影响。 awaitInput():Promise<any>

示例:

const bst = require('best-shell-tool')

const iostand = new bst.IOStand();
(async () => {
  const inp = await iostand.awaitInput()
  console.log('你输入了:', inp)
})();

4.7 pause

pause同process.stdin.pause,暂停控制台。 pause():NodeJS.ReadStream & {fd:0;}

4.8 resume

resume同process.stdin.resume,恢复控制台输入。 resume():NodeJS.ReadStream & {fd: 0;}

4.9 exit

exit同process.exit,退出控制台。 exit():never

4.10 release

release是释放IOStand对象,当不再用到IOStand时候,请一定要使用该函数释放 release():void


5. Tool工具

Tool提供了一些集成好的小工具,但是目前只提供了一个进度条功能,后续会根据大家的需求进行增加迭代。

5.1 process进度条

process提供的是显示一个进度条能力。 function process(current:number, total:number = 100, len:number = 24):string

示例:

const bst = require('best-shell-tool')

const process = bst.tool.process;
const iostand = new bst.IOStand();

iostand.addCommand('wait', '等待')
  .defaultArg('要等待的时间')
  .action((cmd)=>{
    console.log('')
    return new Promise((res) => {
      const waitTime = parseInt(cmd.defaultArgs, 10) || 0
      let current = 0
      const timer = setInterval(()=>{
        console.log(process(current, waitTime))
        if(current === waitTime) {
          clearInterval(timer)
          console.log('已经结束等待')
          res()
        }
        current += 1
      }, 1000)
    })
  })

iostand.start()