DevGang
Авторизоваться

Как создать инструмент CLI в NodeJS 

Как разработчики, мы как бы живем с инструментами CLI. Начиная от git и до cloud shells - мы используем эти инструменты везде. Итак, пришло время сделать свой собственный. В этом процессе мы будем использовать великолепную среду oclif от Heroku.

Что такое Oclif?

Это открытая среда для быстрого создания инструментов CLI, предоставляемая хорошо известным Heroku .

Что будет в результате?

Мы сделаем команду todo list, которая может иметь четыре действия:

  • Добавить новое задание
  • Посмотреть все задачи
  • Обновить задачу
  • Удалить задачу

Инициализировать наш проект

Oclif может генерировать два типа проектов -

  1. Проекты, которые имеют одну команду.
  2. Проекты, которые могут иметь несколько команд, включая вложенные.

В этой статье нам понадобится проект с несколькими командами, поэтому давайте сгенерируем его:

npx oclif multi todocli

Выполнение этой команды и следование инструкциям инициализирует новый проект с именем todocli в текущем каталоге.

Теперь давайте перейдем в каталог и запустим help:

cd todocli
# А затем
./bin/run --help

Получим следующий результат:

> USAGE   
    $ todocli [COMMAND]  
  COMMANDS
    hello   
    help   display help for todocli

Это показывает доступные команды и их документацию.

Структура проекта

Внутри src каталога мы можем найти каталог с именем commands. Этот каталог содержит все команды с их относительными именами файлов. Например, если у нас есть команда, hello в каталоге будет файл с именем hello.js, и команда будет работать без какой-либо дополнительной настройки. Давайте удалим, hello.js поскольку нам это не понадобится.

Настройка базы данных

Для хранения наших задач нам нужна система хранения. Для простоты мы будем использовать lowdb - довольно простую систему хранения файлов в виде json.

Давайте установим ее:

npm install lowdb --save

После установки lowdb создадим файл db.js со следующим содержимым:

// db.js
const low = require('lowdb');
const FileSync = require('lowdb/adapters/FileSync');
const adapter = new FileSync('db.json');
const db = low(adapter);

// Установим занчения по умолчанию и запишим их в нашу базу
db.defaults({todos: []}).write();
const Todo = db.get('todos');

module.exports = {
  db, 
  Todo
}

Здесь мы просто загружаем необходимую библиотеку и файл db.json (пустой файл), а затем определяем пустой массив todos в качестве нашей базовой коллекции (это похоже на таблицу, если вы знакомы с SQL базами данных).

Добавление задач

oclif предоставляет нам простую функциональность для генерации команд. Давайте запустим следующее:

oclif command add

Она создаст файл с именем add.js внутри src/commands каталога. Давайте заменим содержимое этого файла на код ниже:

// add.js
const { Command, flags } = require('@oclif/command');
const { Todo } = require('../db');

class AddCommand extends Command {
  async run() {
    const {
      flags: { task }
    } = this.parse(AddCommand);
    const res = await = Todo.push({
      task,
      id: Todo.value().length,
      done: false,
    }).write(); this.log(res);
  }
}

AddCommand.description = `Add a new Todo
...
Adds a new todo to the existing list
`

AddCommand.flags = {
  task: flags.string({
    char: 'n',
    description: 'task'
  }),
};

module.exports = AddCommand;

Файл имеет несколько ключевых компонентов:

  • функция run, которая выполняет основные функции этой команды,
  • descriptions, это документация для команды,
  • flags, которые описывают флаги, передаваемые команде.

Здесь у нас есть флаг с именем, task который имеет тип string. Мы можем запустить команду следующим образом:

./bin/run add --task="welcome task"

Эта команда добавит задачу в нашу базу данных и напечатает ответ этой операции.

Показать список задач

// show.js
const { Command } = require('@oclif/command');
const chalk = require('chalk');
const { Todo } = require('../db');

class ShowCommand extends Command {
  async run() {
    const res = await Todo.sortBy('id').value();
    res.forEach(({id, task, done}) => {
      this.log(
        `${chalk.magenta(id)} ${
          done ? chalk.green('DONE') : chalk.yellowBright('NOT DONE')
        } : ${task}`
       );
    });
  }
}

ShowCommand.description = `Shows existing task
...
Show all the task sorted by their ids
`

module.exports = ShowCommand;

Здесь внутри show.js мы показываем все задачи в порядке возрастания. Мы добавили немного цвета, с помощью chalkjs чтобы результаты нашей команды выглядели лучше.

Обновление задач

// update.js
const { Command, flags } = require('@oclif/command');
const { Todo } = require('../db');

class UpdateCommand extends Command {
  async run() {
    const {
      flags: { id },
    } = this.parse(UpdateCommand);
    
    const res = await Todo.find({
      id: parseInt(id, 10)
    }).assign({
      done: true 
    }).write(); this.log(res)
  }
}

UpdateCommand.description = `Marks a task as done
...
Marks a task as done
`

UpdateCommand.flags = {
  id: flags.string({
    char: 'n',
    description: 'task id'
  }),
};

module.exports = UpdateCommand;

Для простоты мы сейчас просто маркируем задачи, как done при обновлении. Мы просто передали id  задачи как flag.

./bin/run update --id=1

Эта команда установит done = true для задачи с id = 1.

Удаление задач

// remove.js
const { Command, flags } = require('@oclif/command');
const { Todo } = require('../db');

class RemoveCommand extends Command {
  async run() {
    const {
      flags: { id },
    } = this.parse(RemoveCommand);

    const res = await Todo.remove({
      id: parseInt(id, 10)
    }).write(); this.log(res)
  }
}

RemoveCommand.description = `Removes a task by id
...
Removes a task permanently from database by id
`
RemoveCommand.flags = {
  id: flags.string({
    char: 'n',
    description: 'task id'
  }),
};

module.exports = RemoveCommand;

Удаление довольно просто: мы передаем id как флаг, а затем удаляем соответствующую задачу из нашей базы данных.

В заключение

Для того чтобы нашим todo лист могли пользоваться не только вы но и ваши друзья, его можно опубликовать в npm, как это сделать, мы рассматривали в предыдущей статье: Как публиковать пакеты в npm

#NodeJS #NPM
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

В этом месте могла бы быть ваша реклама

Разместить рекламу