Статьи

Создайте интерфейс командной строки JavaScript (CLI) с Node.js

Несмотря на то, что Node.js предназначен для «традиционных» веб-приложений, его потенциальное использование гораздо шире. Микросервисы, API-интерфейсы REST, инструменты, работа с Интернетом вещей и даже настольные приложения.

Другая область, где Node.js действительно полезен, — это создание приложений командной строки — и это то, что мы собираемся сделать в этой статье. Мы начнем с рассмотрения ряда сторонних пакетов, предназначенных для работы с командной строкой, а затем создадим реальный пример с нуля.

Мы собираемся создать инструмент для инициализации Git-репозитория. Конечно, он будет запускать git init под капотом, но он сделает не только это. Он также создаст удаленный репозиторий на GitHub прямо из командной строки, позволит пользователю интерактивно создать файл .gitignore и, наконец, выполнить начальную фиксацию и отправку.

Как всегда, код, сопровождающий это руководство, можно найти в нашем репозитории GitHub .

Создайте CLI узла

Зачем создавать инструмент командной строки с Node.js?

Прежде чем мы углубимся и начнем сборку, стоит посмотреть, почему мы можем выбрать Node.js для создания приложения командной строки.

Наиболее очевидным преимуществом является то, что, если вы читаете это, вы, вероятно, уже знакомы с ним — и, действительно, с JavaScript.

Еще одно ключевое преимущество, которое мы увидим в дальнейшем, заключается в том, что сильная экосистема Node.js означает, что среди сотен тысяч пакетов, доступных для любых целей, есть ряд, специально предназначенных для создания мощных инструменты командной строки.

Наконец, мы можем использовать npm для управления любыми зависимостями, вместо того чтобы беспокоиться о специфичных для ОС менеджерах пакетов, таких как Aptitude, Yum или Homebrew.

Совет: это не обязательно так, потому что ваш инструмент командной строки может иметь другие внешние зависимости.

Что мы собираемся построить: ginit

Ginit, наш Node CLI в действии

Для этого урока мы собираемся создать утилиту командной строки, которую я называю ginit . Это git init , но на стероидах.

Вам, наверное, интересно, что на земле это значит.

Как вы, без сомнения, уже знаете, git init инициализирует Git-репозиторий в текущей папке. Однако это обычно только один из нескольких повторяющихся шагов, связанных с подключением нового или существующего проекта к Git. Например, в рамках типичного рабочего процесса вы можете:

  1. инициализируйте локальный репозиторий, запустив git init
  2. создать удаленный репозиторий, например, на GitHub или Bitbucket — обычно, оставив командную строку и запустив веб-браузер
  3. добавить пульт
  4. создать файл .gitignore
  5. добавить файлы вашего проекта
  6. зафиксировать начальный набор файлов
  7. нажмите на удаленный репозиторий.

Часто требуется больше шагов, но мы будем придерживаться их для целей нашего приложения. Тем не менее, эти шаги довольно повторяющиеся. Разве не было бы лучше, если бы мы могли делать все это из командной строки, без копирования-вставки URL-адресов Git и тому подобного?

Поэтому ginit создаст Git-репозиторий в текущей папке, создаст удаленный репозиторий — для этого мы будем использовать GitHub — а затем добавим его как удаленный. Затем он предоставит простой интерактивный «мастер» для создания файла .gitignore , добавит содержимое папки и отправит его в удаленный репозиторий. Это может не сэкономить ваши часы, но устранит некоторые начальные трения при запуске нового проекта.

Имея это в виду, давайте начнем.

Зависимости приложений

Одно можно сказать наверняка: с точки зрения внешнего вида, консоль никогда не будет обладать изощренным графическим интерфейсом пользователя. Тем не менее, это не значит, что это должен быть простой, некрасивый, монохромный текст. Вы можете быть удивлены тем, сколько вы можете сделать визуально, в то же время сохраняя его работоспособным. Мы рассмотрим несколько библиотек для улучшения отображения: мел для раскрашивания вывода и подсказки для добавления некоторых дополнительных визуальных компонентов. Просто для удовольствия, мы будем использовать figlet для создания причудливого баннера на основе ASCII, а также будем использовать clear для очистки консоли.

С точки зрения ввода и вывода, низкоуровневый модуль Readline Node.js может использоваться для запроса пользователя и запроса ввода, и в простых случаях его более чем достаточно. Но мы собираемся воспользоваться сторонним пакетом, который добавляет большую степень сложности — Inquirer . Помимо предоставления механизма для вопросов, он также реализует простые элементы управления вводом: подумайте о переключателях и флажках, но в консоли.

Мы также будем использовать minimist для разбора аргументов командной строки.

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

  • мел — раскрашивает вывод
  • очиститьочистить экран терминала
  • clui — рисует таблицы командной строки, датчики и счетчики
  • figlet — создает текст ASCII из текста
  • inquirer — создает интерактивный пользовательский интерфейс командной строки
  • minimist — анализирует параметры аргумента
  • configstore — легко загружает и сохраняет конфигурацию, не думая о том, где и как.

Кроме того, мы также будем использовать следующее:

  • @ octokit / rest — клиент GitHub REST API для Node.js
  • lodash — библиотека утилит JavaScript
  • simple-git — инструмент для запуска команд Git в приложении Node.js
  • touch — инструмент для реализации сенсорной команды Unix.

Начиная

Хотя мы собираемся создать приложение с нуля, не забывайте, что вы также можете получить копию кода из репозитория, который прилагается к этой статье .

Создайте новый каталог для проекта. Вы не должны называть это ginit , конечно:

 mkdir ginit cd ginit 

Создайте новый файл package.json :

 npm init -y 

И отредактируйте его так, чтобы он выглядел так:

 { "name": "ginit", "version": "1.0.0", "description": "'git init' on steroids", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [ "Git", "CLI" ], "author": "<YOUR NAME>", "license": "ISC" } 

Теперь установите зависимости:

 npm install chalk clear clui figlet inquirer minimist configstore @octokit/rest lodash simple-git touch 

Теперь создайте файл index.js в той же папке и index.js следующих зависимостей:

 const chalk = require('chalk'); const clear = require('clear'); const figlet = require('figlet'); 

Добавление некоторых вспомогательных методов

Мы собираемся создать папку lib где мы разделим наш вспомогательный код на модули:

  • files.js — базовое управление файлами
  • inquirer.js — взаимодействие с пользователем из командной строки
  • github.js — управление токенами доступа
  • repo.js — управление Git-репозиторием.

Давайте начнем с lib/files.js . Здесь нам нужно:

  • получить текущий каталог (чтобы получить имя репо по умолчанию)
  • проверьте, существует ли каталог (чтобы определить, является ли текущая папка уже репозиторием Git, ищите папку с именем .git ).

Это звучит просто, но есть пара моментов, которые нужно учитывать.

Во-первых, у вас может возникнуть желание использовать метод realpathSync модуля fs для получения текущего каталога:

 path.basename(path.dirname(fs.realpathSync(__filename))); 

Это будет работать, когда мы вызываем приложение из того же каталога (например, с помощью node index.js ), но имейте в виду, что мы сделаем наше консольное приложение доступным глобально. Это означает, что нам нужно имя каталога, в котором мы работаем, а не каталог, в котором находится приложение. Для этого лучше использовать process.cwd :

 path.basename(process.cwd()); 

Во-вторых, предпочтительный метод проверки, существует ли файл или каталог, постоянно меняется . Текущий способ заключается в использовании existsSync . Это возвращает true если путь существует, false противном случае.

Наконец, стоит отметить, что когда вы пишете приложение для командной строки, использовать синхронную версию методов такого рода просто замечательно.

Собрав все это вместе, давайте создадим пакет утилит в lib/files.js :

 const fs = require('fs'); const path = require('path'); module.exports = { getCurrentDirectoryBase: () => { return path.basename(process.cwd()); }, directoryExists: (filePath) => { return fs.existsSync(filePath); } }; 

Вернитесь к index.js и убедитесь, что вам require новый файл:

 const files = require('./lib/files'); 

Имея это в виду, мы можем начать разработку приложения.

Инициализация узла CLI

Теперь давайте реализуем фазу запуска нашего консольного приложения.

Чтобы продемонстрировать некоторые из пакетов, которые мы установили для улучшения вывода консоли, давайте очистим экран и затем отобразим баннер:

 // index.js clear(); console.log( chalk.yellow( figlet.textSync('Ginit', { horizontalLayout: 'full' }) ) ); 

Вы можете запустить приложение, используя node index.js . Результат этого показан ниже.

Приветственный баннер на нашем Node CLI, созданный с использованием Chalk и Figlet

Далее, давайте запустим простую проверку, чтобы убедиться, что текущая папка не является Git-репозиторием. Это просто: мы просто проверяем наличие папки .git используя только что созданный нами служебный метод:

 //index.js if (files.directoryExists('.git')) { console.log(chalk.red('Already a Git repository!')); process.exit(); } 

Совет: обратите внимание, что мы используем модуль мела, чтобы показать сообщение красного цвета.

Приглашение пользователя для ввода

Следующее, что нам нужно сделать, — это создать функцию, которая будет запрашивать у пользователя учетные данные GitHub.

Мы можем использовать Inquirer для этого. Модуль включает в себя ряд методов для различных типов приглашений, которые примерно аналогичны элементам управления HTML-формы. Чтобы собрать имя пользователя и пароль GitHub, мы будем использовать типы input и password соответственно.

Сначала создайте lib/inquirer.js и вставьте этот код:

 const inquirer = require('inquirer'); const files = require('./files'); module.exports = { askGithubCredentials: () => { const questions = [ { name: 'username', type: 'input', message: 'Enter your GitHub username or e-mail address:', validate: function( value ) { if (value.length) { return true; } else { return 'Please enter your username or e-mail address.'; } } }, { name: 'password', type: 'password', message: 'Enter your password:', validate: function(value) { if (value.length) { return true; } else { return 'Please enter your password.'; } } } ]; return inquirer.prompt(questions); }, }; 

Как видите, inquirer.prompt() задает пользователю ряд вопросов, представленных в виде массива в качестве первого аргумента. Каждый вопрос состоит из объекта, который определяет name поля, type (здесь мы просто используем соответственно input и password , но позже мы рассмотрим более сложный пример) и подсказку ( message ) для отобразить.

Вводимые пользователем данные будут переданы вызывающей функции в качестве Promise . В случае успеха мы получим простой объект с двумя свойствами; username и password .

Вы можете проверить все это, добавив в index.js следующее:

 const inquirer = require('./lib/inquirer'); const run = async () => { const credentials = await inquirer.askGithubCredentials(); console.log(credentials); }; run(); 

Затем запустите скрипт, используя node index.js .

Получение пользовательского ввода с Inquirer

Совет: Когда вы закончите тестирование, не забудьте удалить строку const inquirer = require('./lib/inquirer'); из index.js , поскольку в этом файле он нам на самом деле не понадобится.

Работа с аутентификацией GitHub

Следующим шагом является создание функции для получения токена OAuth для API GitHub. По сути, мы собираемся «обменять» имя пользователя и пароль на токен.

Конечно, мы не хотим, чтобы пользователи вводили свои учетные данные каждый раз, когда они используют инструмент. Вместо этого мы будем хранить токен OAuth для последующих запросов. Вот где приходит пакет configstore .

Хранение конфигурации

Сохранение конфигурации внешне довольно просто: вы можете просто читать и записывать в / из файла JSON без необходимости использования стороннего пакета. Однако пакет configstore предоставляет несколько ключевых преимуществ:

  1. Он определяет наиболее подходящее место для файла для вас с учетом вашей операционной системы и текущего пользователя.
  2. Нет необходимости явно читать или записывать в файл. Вы просто модифицируете объект configstore, и он позаботится о вас в фоновом режиме.

Чтобы использовать его, просто создайте экземпляр, передав ему идентификатор приложения. Например:

 const Configstore = require('configstore'); const conf = new Configstore('ginit'); 

Если файл configstore не существует, он вернет пустой объект и создаст файл в фоновом режиме. Если файл configstore уже существует, его содержимое будет декодировано в JSON и доступно для вашего приложения. Теперь вы можете использовать conf как простой объект, получая или устанавливая свойства по мере необходимости. Как уже упоминалось выше, вам не нужно беспокоиться о сохранении его потом. Это позаботится о вас.

Совет: в macOS вы найдете файл в /Users/[YOUR-USERNME]/.config/configstore/ginit.json , в Linux он находится в /home/[YOUR-USERNME]/.config/configstore/ginit.json

Связь с API GitHub

Давайте создадим библиотеку для обработки токена GitHub. Создайте файл lib/github.js и поместите в него следующий код:

 const CLI = require('clui'); const Configstore = require('configstore'); const Octokit = require('@octokit/rest'); const Spinner = CLI.Spinner; const inquirer = require('./inquirer'); const pkg = require('../package.json'); const conf = new Configstore(pkg.name); 

Теперь давайте добавим функцию, которая проверяет, есть ли у нас уже токен доступа. Мы также добавим функцию, которая позволяет другим octokit получать доступ к функциям octokit (GitHub):

 module.exports = { getInstance: () => { return octokit; }, getStoredGithubToken: () => { return conf.get('github.token'); }, }; 

Если объект conf существует и у него есть свойство github.token , это означает, что в хранилище уже есть токен. В этом случае мы возвращаем значение токена обратно вызывающей функции. Мы вернемся к этому позже.

Если токен не обнаружен, нам нужно получить его. Конечно, получение OAuth-токена включает сетевой запрос, что означает короткое ожидание пользователя. Это дает нам возможность взглянуть на пакет clui , который предоставляет некоторые улучшения для консольных приложений, в том числе анимированный спиннер.

Создать блесну легко:

 const status = new Spinner('Authenticating you, please wait...'); status.start(); 

Как только вы закончите, просто остановите его, и он исчезнет с экрана:

 status.stop(); 

Совет: вы также можете установить заголовок динамически, используя метод update . Это может быть полезно, если у вас есть какие-то индикаторы прогресса, например, отображение процента выполнения.

Вот код для аутентификации с помощью GitHub:

 ... let octokit; module.exports = { ... setGithubCredentials: async () => { const credentials = await inquirer.askGithubCredentials(); octokit = new Octokit({ auth: { username: credentials.username, password: credentials.password, } }); }, registerNewToken: async () => { const status = new Spinner('Authenticating you, please wait...'); status.start(); try { const response = await octokit.oauthAuthorizations.createAuthorization({ scopes: ['user', 'public_repo', 'repo', 'repo:status'], note: 'ginit, the command-line tool for initalizing Git repos' }); const token = response.data.token; if(token) { conf.set('github.token', token); return token; } else { throw new Error("Missing Token","GitHub token was not found in the response"); } } catch (err) { throw err; } finally { status.stop(); } }, }; 

Давайте пройдем через это:

  1. мы объявляем переменную octokit в верхней области видимости модуля
  2. мы запрашиваем у пользователя учетные данные, используя метод askGithubCredentials который мы определили ранее
  3. мы передаем опцию auth конструктору Octokit для включения аутентифицированных запросов
  4. результат присваивается переменной octokit чтобы он был доступен по всему модулю
  5. мы пытаемся зарегистрировать новый токен доступа для нашего приложения
  6. если нам удастся получить токен доступа, мы установим его в configstore на следующий раз.
  7. затем мы возвращаем токен.

Любые токены доступа, которые вы создадите, будь то вручную или через API, как мы делаем здесь, вы сможете увидеть их здесь . В ходе разработки вы можете обнаружить, что вам необходимо удалить токен доступа ginit, который можно определить по указанному выше параметру note чтобы вы могли его заново сгенерировать.

Совет: если в вашей учетной записи GitHub включена двухфакторная аутентификация, процесс будет несколько более сложным. Вам нужно будет запросить код подтверждения — например, один, отправленный с помощью SMS — и затем предоставить его с помощью заголовка X-GitHub-OTP . См. Документацию для получения дополнительной информации.

Если вы index.js и хотели бы попробовать то, что у нас есть, вы можете обновить index.js следующим образом:

 const github = require('./lib/github'); ... const run = async () => { let token = github.getStoredGithubToken(); if(!token) { await github.setGithubCredentials(); token = await github.registerNewToken(); } console.log(token); }: 

Обратите внимание, что вы можете получить ошибку Promise если что-то пойдет не так, например, введя неправильный пароль. Я покажу вам правильный способ обработки таких ошибок позже.

Создание хранилища

Получив токен OAuth, мы можем использовать его для создания удаленного репозитория с GitHub.

Опять же, мы можем использовать Inquirer, чтобы задать ряд вопросов. Нам нужно имя для репо, мы попросим дополнительное описание, и мы также должны знать, должно ли оно быть публичным или частным.

Мы будем использовать minimist, чтобы получить значения по умолчанию для имени и описания из необязательных аргументов командной строки. Например:

 ginit my-repo "just a test repository" 

Это установит имя по умолчанию my-repo а описание — just a test repository .

Следующая строка поместит аргументы в массив, индексированный подчеркиванием:

 const argv = require('minimist')(process.argv.slice(2)); // { _: [ 'my-repo', 'just a test repository' ] } 

Совет: это только действительно царапает поверхность минималистской упаковки. Вы также можете использовать его для интерпретации флагов, переключателей и пар имя / значение. Проверьте документацию для получения дополнительной информации.

Мы напишем код для разбора аргументов командной строки и зададим ряд вопросов. Сначала обновите lib/inquirer.js , вставив следующий код сразу после функции askGithubCredentials :

 askRepoDetails: () => { const argv = require('minimist')(process.argv.slice(2)); const questions = [ { type: 'input', name: 'name', message: 'Enter a name for the repository:', default: argv._[0] || files.getCurrentDirectoryBase(), validate: function( value ) { if (value.length) { return true; } else { return 'Please enter a name for the repository.'; } } }, { type: 'input', name: 'description', default: argv._[1] || null, message: 'Optionally enter a description of the repository:' }, { type: 'list', name: 'visibility', message: 'Public or private:', choices: [ 'public', 'private' ], default: 'public' } ]; return inquirer.prompt(questions); }, 

Затем создайте файл lib/repo.js и добавьте этот код:

 const CLI = require('clui'); const fs = require('fs'); const git = require('simple-git/promise')(); const Spinner = CLI.Spinner; const _ = require('lodash'); const inquirer = require('./inquirer'); const gh = require('./github'); module.exports = { createRemoteRepo: async () => { const github = gh.getInstance(); const answers = await inquirer.askRepoDetails(); const data = { name: answers.name, description: answers.description, private: (answers.visibility === 'private') }; const status = new Spinner('Creating remote repository...'); status.start(); try { const response = await github.repos.createForAuthenticatedUser(data); return response.data.ssh_url; } catch(err) { throw err; } finally { status.stop(); } }, }; 

Получив эту информацию, мы можем просто использовать пакет GitHub для создания репозитория, который даст нам URL-адрес для вновь созданного репозитория. Затем мы можем установить это как удаленный в нашем локальном репозитории Git. Однако сначала давайте интерактивно создадим файл .gitignore .

Создание файла .gitignore

На следующем шаге мы создадим простой «мастер» командной строки для создания файла .gitignore . Если пользователь запускает наше приложение в существующем каталоге проекта, давайте покажем им список файлов и каталогов, уже находящихся в текущем рабочем каталоге, и разрешим им выбирать, какие из них игнорировать.

Пакет Inquirer предоставляет checkbox типа ввода для этого.

Чекбоксы Inquirer в действии

Первое, что нам нужно сделать, это просканировать текущий каталог, игнорируя папку .git и любой существующий файл .gitignore (мы делаем это, используя метод lodash без метода):

 const filelist = _.without(fs.readdirSync('.'), '.git', '.gitignore'); 

Если добавить нечего, продолжать нет смысла, поэтому давайте просто touch текущего файла .gitignore и выйдем из функции:

 if (filelist.length) { ... } else { touch('.gitignore'); } 

Наконец, давайте используем флажок «виджет» Inquirer, чтобы вывести список файлов. Вставьте следующий код в lib/inquirer.js :

 askIgnoreFiles: (filelist) => { const questions = [ { type: 'checkbox', name: 'ignore', message: 'Select the files and/or folders you wish to ignore:', choices: filelist, default: ['node_modules', 'bower_components'] } ]; return inquirer.prompt(questions); }, 

Обратите внимание, что мы также можем предоставить список значений по умолчанию. В этом случае мы предварительно node_modules и bower_components , если они существуют.

Имея код Inquirer, мы можем теперь createGitignore() функцию createGitignore() . Вставьте этот код в lib/repo.js :

 createGitignore: async () => { const filelist = _.without(fs.readdirSync('.'), '.git', '.gitignore'); if (filelist.length) { const answers = await inquirer.askIgnoreFiles(filelist); if (answers.ignore.length) { fs.writeFileSync( '.gitignore', answers.ignore.join( '\n' ) ); } else { touch( '.gitignore' ); } } else { touch('.gitignore'); } }, 

После « .gitignore » мы генерируем .gitignore , объединяя выбранный список файлов, разделенных новой строкой. Теперь наша функция в значительной степени гарантирует, что у нас есть файл .gitignore , поэтому мы можем приступить к инициализации Git-репозитория.

Взаимодействие с Git из приложения

Существует несколько способов взаимодействия с Git, но, возможно, самый простой — использовать пакет simple-git . Это обеспечивает набор цепных методов, которые за кулисами запускают исполняемый файл Git.

Это повторяющиеся задачи, которые мы будем использовать для автоматизации:

  1. запустить git init
  2. добавить файл .gitignore
  3. добавить оставшееся содержимое рабочего каталога
  4. выполнить первоначальный коммит
  5. добавить только что созданный удаленный репозиторий
  6. нажмите рабочий каталог до удаленного.

Вставьте следующий код в lib/repo.js :

 setupRepo: async (url) => { const status = new Spinner('Initializing local repository and pushing to remote...'); status.start(); return git.init() .then(git.add('.gitignore')) .then(git.add('./*')) .then(git.commit('Initial commit')) .then(git.addRemote('origin', url)) .then(git.push('origin', 'master')) .finally(status.stop()); }, 

Собираем все вместе

Сначала давайте установим вспомогательную функцию в lib/github.js для настройки oauth аутентификации:

 githubAuth: (token) => { octokit = new Octokit({ auth: token }); }, 

Далее мы создаем функцию в index.js для обработки логики получения токена. Поместите этот код перед функцией run() ‘:

 const getGithubToken = async () => { // Fetch token from config store let token = github.getStoredGithubToken(); if(token) { return token; } // No token found, use credentials to access GitHub account await github.setGithubCredentials(); // register new token token = await github.registerNewToken(); return token; }; 

Наконец, мы обновляем функцию run() , написав код, который будет обрабатывать основную логику приложения:

 const repo = require('./lib/repo'); ... const run = async () => { try { // Retrieve & Set Authentication Token const token = await getGithubToken(); github.githubAuth(token); // Create remote repository const url = await repo.createRemoteRepo(); // Create .gitignore file await repo.createGitignore(); // Set up local repository and push to remote await repo.setupRepo(url); console.log(chalk.green('All done!')); } catch(err) { if (err) { switch (err.status) { case 401: console.log(chalk.red('Couldn\'t log you in. Please provide correct credentials/token.')); break; case 422: console.log(chalk.red('There already exists a remote repository with the same name')); break; default: console.log(err); } } } }; 

Как видите, мы гарантируем, что пользователь проходит аутентификацию перед последовательным вызовом всех других наших функций ( createRemoteRepo() , createGitignore() , setupRepo() ). Код также обрабатывает любые ошибки и предлагает пользователю соответствующую обратную связь.

Вы можете проверить заполненный файл index.js в нашем репозитории GitHub.

На данный момент у вас должно быть рабочее приложение. Попробуйте и убедитесь, что все работает как положено.

Обеспечение доступности команды ginit по всему миру

Осталось сделать нашу команду доступной глобально. Для этого нам нужно добавить строку shebang в начало index.js :

 #!/usr/bin/env node 

Далее нам нужно добавить свойство bin в наш файл package.json . Это сопоставляет имя команды ( ginit ) с именем исполняемого файла (относительно package.json ).

 "bin": { "ginit": "./index.js" } 

После этого установите модуль глобально, и вы получите рабочую команду оболочки:

 npm install -g 

Совет: это также будет работать в Windows, так как npm будет полезно устанавливать оболочку cmd вместе с вашим скриптом .

Если вы хотите подтвердить, что установка прошла успешно, вы можете перечислить свои глобально установленные модули Node, используя:

 npm ls --depth=0 

Продолжая

У нас есть довольно изящное, хотя и простое приложение командной строки для инициализации репозиториев Git. Но есть еще много вещей, которые вы можете сделать, чтобы улучшить его.

Если вы являетесь пользователем Bitbucket, вы можете адаптировать программу для использования API Bitbucket для создания хранилища. Доступна оболочка API Node.js, которая поможет вам начать работу. Вы можете добавить дополнительную опцию командной строки или запрос, чтобы спросить пользователя, хотят ли они использовать GitHub или Bitbucket (для этого идеально подойдет Inquirer), или просто заменить специфичный для GitHub код альтернативой Bitbucket.

Вы также можете предоставить возможность указать собственный набор значений по умолчанию для файла .gitgnore вместо жестко закодированного списка. Здесь может подойти пакет настроек или вы могли бы предоставить набор «шаблонов» — возможно, запрашивающий у пользователя тип проекта. Возможно, вы захотите посмотреть на его интеграцию с инструментом командной строки .gitignore.io / API.

Помимо всего этого, вы также можете добавить дополнительную проверку, предоставить возможность пропустить определенные разделы и многое другое. Если у вас есть другие идеи, сообщите нам об этом в комментариях.