custom-menu-cli 1.0.1 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README-pt.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # Custom Menu CLI
2
2
 
3
+ ![Exemplo de Menu 1](./docs/example1.png)
4
+ ![Exemplo de Menu 2](./docs/example2.png)
5
+
3
6
  Esta é uma ferramenta de interface de linha de comando (CLI) que cria um menu interativo com base em um arquivo JSON. Ele foi projetado para simplificar a execução de comandos frequentes em um terminal.
4
7
 
5
8
  ## Funcionalidades
@@ -9,6 +12,12 @@ Esta é uma ferramenta de interface de linha de comando (CLI) que cria um menu i
9
12
  - Fácil de configurar e usar.
10
13
  - Suporte para execução de comandos com confirmação.
11
14
 
15
+
16
+ ## Lançamentos
17
+
18
+ Você pode encontrar todas as versões lançadas e os executáveis standalone pré-compilados na página de [Releases do GitHub](https://github.com/mateusmed/custom-menu-cli/releases).
19
+
20
+
12
21
  ## Instalação
13
22
 
14
23
  Para instalar esta ferramenta globalmente, execute o seguinte comando:
@@ -19,12 +28,66 @@ npm install -g custom-menu-cli
19
28
 
20
29
  ## Uso
21
30
 
22
- Para usar o CLI, você pode executar o comando `custom-menu-cli`, passando opcionalmente o caminho para um arquivo JSON. Se nenhum caminho for fornecido, ele procurará um arquivo `menu.json` no diretório atual.
31
+ Existem três maneiras principais de utilizar esta ferramenta:
32
+
33
+ ### 1. Como Executável (Build de Release)
34
+
35
+ Você pode gerar executáveis para Linux, macOS e Windows. Após o build, os arquivos estarão na pasta `dist/`.
36
+
37
+ Primeiro, gere os arquivos com o comando:
38
+
39
+ ```bash
40
+ npm run build
41
+ ```
42
+
43
+ Depois, execute o arquivo correspondente ao seu sistema operacional, passando opcionalmente o caminho para um arquivo de menu. Se nenhum caminho for fornecido, ele procurará por um `menu.json` no diretório atual.
44
+
45
+ ```bash
46
+ # No Linux/macOS
47
+ ./dist/custom-menu-linux [caminho/para/seu/menu.json]
48
+
49
+ # No Windows
50
+ .\dist\custom-menu-win.exe [caminho\para\seu\menu.json]
51
+ ```
52
+
53
+ ### 2. Globalmente via NPM
54
+
55
+ Instale o pacote globalmente para usar o comando `custom-menu-cli` em qualquer lugar do seu sistema.
56
+
57
+ ```bash
58
+ npm install -g custom-menu-cli
59
+ ```
60
+
61
+ Depois de instalado, execute o comando:
23
62
 
24
63
  ```bash
25
64
  custom-menu-cli [caminho/para/seu/menu.json]
26
65
  ```
27
66
 
67
+ ### 3. Programaticamente via `require`
68
+
69
+ Você pode importar a função `runCli` em seus próprios projetos Node.js para integrar a funcionalidade do menu.
70
+
71
+ Primeiro, adicione o pacote como uma dependência do seu projeto:
72
+ ```bash
73
+ npm install custom-menu-cli
74
+ ```
75
+
76
+ Depois, use-o em seu código:
77
+
78
+ ```javascript
79
+ const { runCli } = require('custom-menu-cli');
80
+
81
+ async function iniciarMeuMenuCustomizado() {
82
+ console.log("Iniciando menu customizado...");
83
+ // Opcionalmente, passe o caminho para o seu arquivo menu.json
84
+ await runCli('./caminho/para/seu/menu.json');
85
+ console.log("Menu customizado finalizado.");
86
+ }
87
+
88
+ iniciarMeuMenuCustomizado();
89
+ ```
90
+
28
91
  ## Estrutura do JSON
29
92
 
30
93
  O arquivo JSON que define o menu tem a seguinte estrutura:
package/README.md CHANGED
@@ -2,6 +2,9 @@
2
2
 
3
3
  [Português (Brasil)](./README-pt.md)
4
4
 
5
+ ![Menu Example 1](./docs/example1.png)
6
+ ![Menu Example 2](./docs/example2.png)
7
+
5
8
  This is a command-line interface (CLI) tool that creates an interactive menu based on a JSON file. It's designed to simplify the execution of frequent commands in a terminal.
6
9
 
7
10
  ## Features
@@ -11,6 +14,11 @@ This is a command-line interface (CLI) tool that creates an interactive menu bas
11
14
  - Easy to configure and use.
12
15
  - Support for command execution with confirmation.
13
16
 
17
+ ## Releases
18
+
19
+ You can find all released versions and pre-compiled standalone executables on the [GitHub Releases page](https://github.com/mateusmed/custom-menu-cli/releases).
20
+
21
+
14
22
  ## Installation
15
23
 
16
24
  To install this tool globally, run the following command:
@@ -21,12 +29,66 @@ npm install -g custom-menu-cli
21
29
 
22
30
  ## Usage
23
31
 
24
- To use the CLI, you can run the `custom-menu-cli` command, optionally passing the path to a JSON file. If no path is provided, it will look for a `menu.json` file in the current directory.
32
+ There are three main ways to use this tool:
33
+
34
+ ### 1. As an Executable (Release Build)
35
+
36
+ You can generate executables for Linux, macOS, and Windows. After the build, the files will be in the `dist/` folder.
37
+
38
+ First, generate the files with the command:
39
+
40
+ ```bash
41
+ npm run build
42
+ ```
43
+
44
+ Then, run the file corresponding to your operating system, optionally passing the path to a menu file. If no path is provided, it will look for a `menu.json` in the current directory.
45
+
46
+ ```bash
47
+ # On Linux/macOS
48
+ ./dist/custom-menu-linux [path/to/your/menu.json]
49
+
50
+ # On Windows
51
+ .\dist\custom-menu-win.exe [path\to\your\menu.json]
52
+ ```
53
+
54
+ ### 2. Globally via NPM
55
+
56
+ Install the package globally to use the `custom-menu-cli` command anywhere on your system.
57
+
58
+ ```bash
59
+ npm install -g custom-menu-cli
60
+ ```
61
+
62
+ Once installed, run the command:
25
63
 
26
64
  ```bash
27
65
  custom-menu-cli [path/to/your/menu.json]
28
66
  ```
29
67
 
68
+ ### 3. Programmatically via `require`
69
+
70
+ You can import the `runCli` function into your own Node.js projects to integrate the menu functionality.
71
+
72
+ First, add the package as a dependency to your project:
73
+ ```bash
74
+ npm install custom-menu-cli
75
+ ```
76
+
77
+ Then, use it in your code:
78
+
79
+ ```javascript
80
+ const { runCli } = require('custom-menu-cli');
81
+
82
+ async function startMyCustomMenu() {
83
+ console.log("Starting custom menu...");
84
+ // Optionally, pass the path to your menu.json file
85
+ await runCli('./path/to/your/menu.json');
86
+ console.log("Custom menu finished.");
87
+ }
88
+
89
+ startMyCustomMenu();
90
+ ```
91
+
30
92
  ## JSON Structure
31
93
 
32
94
  The JSON file that defines the menu has the following structure:
package/dist/.gitkeep ADDED
File without changes
Binary file
Binary file
package/index.js CHANGED
@@ -1,38 +1,24 @@
1
1
  #!/usr/bin/env node
2
- import chalk from 'chalk';
3
- import { loadMenuConfig } from './src/configLoader.js';
4
- import { showMenu, buildIdMap } from './src/menu.js';
5
2
 
6
- (async () => {
7
- const data = loadMenuConfig();
3
+ const { loadMenuConfig } = require('./src/configLoader.js');
4
+ const { showMenu, buildIdMap } = require('./src/menu.js');
5
+ const { displayHeader } = require('./src/header.js');
6
+
7
+ async function runCli(menuPath = null) {
8
+ const data = loadMenuConfig(menuPath);
8
9
  if (data.options) {
9
10
  buildIdMap(data.options);
10
11
  }
11
12
 
12
13
  console.clear();
13
14
 
14
- // Dynamic Header
15
- const name = data.name || 'Custom Menu';
16
- const description = data.description || 'A CLI Menu';
17
- const lines = [name, description];
18
- const maxLength = Math.max(...lines.map(line => line.length));
19
- const boxWidth = maxLength + 4;
15
+ displayHeader(data);
20
16
 
21
- const topBorder = '╔' + '═'.repeat(boxWidth) + '╗';
22
- const bottomBorder = '╚' + '═'.repeat(boxWidth) + '╝';
17
+ await showMenu(data);
18
+ }
23
19
 
24
- console.log(chalk.bold.blueBright(topBorder));
25
- lines.forEach(line => {
26
- const paddingTotal = boxWidth - line.length;
27
- const paddingLeft = Math.floor(paddingTotal / 2);
28
- const paddingRight = Math.ceil(paddingTotal / 2);
29
- const paddedLine = `║${' '.repeat(paddingLeft)}${line}${' '.repeat(paddingRight)}║`;
30
- console.log(chalk.bold.blueBright(paddedLine));
31
- });
32
- console.log(chalk.bold.blueBright(bottomBorder));
33
- console.log(''); // For spacing
34
- console.log(chalk.gray(`Developed by Mateus Medeiros - GitHub: @mateusmed`));
35
- console.log(''); // For spacing
20
+ if (require.main === module) {
21
+ runCli();
22
+ }
36
23
 
37
- await showMenu(data);
38
- })();
24
+ module.exports = { runCli };
package/package.json CHANGED
@@ -1,21 +1,22 @@
1
1
  {
2
2
  "name": "custom-menu-cli",
3
- "version": "1.0.1",
3
+ "version": "1.0.4",
4
4
  "description": "Menu interativo baseado em JSON para execução de comandos no terminal",
5
- "type": "module",
6
5
  "main": "index.js",
7
- "bin": {
8
- "custom-menu-cli": "index.js"
9
- },
6
+ "bin": "index.js",
10
7
  "scripts": {
11
- "start": "node index.js"
8
+ "start": "node index.js",
9
+ "build": "pkg . --targets node16-linux-x64,node16-win-x64,node16-macos-x64 --output dist/custom-menu-v$npm_package_version"
12
10
  },
13
- "keywords": ["cli", "menu", "json", "terminal", "deploy"],
11
+ "keywords": ["cli", "menu", "json", "terminal", "deploy", "custom"],
14
12
  "author": "Mateus Medeiros <https://github.com/mateusmed>",
15
13
  "license": "MIT",
16
14
  "dependencies": {
17
- "chalk": "^5.3.0",
15
+ "chalk": "^4.1.2",
18
16
  "dotenv": "^16.3.1",
19
- "inquirer": "^9.2.16"
17
+ "inquirer": "^8.2.4"
18
+ },
19
+ "devDependencies": {
20
+ "pkg": "^5.8.1"
20
21
  }
21
22
  }
package/src/actions.js CHANGED
@@ -1,20 +1,20 @@
1
- import inquirer from 'inquirer';
2
- import chalk from 'chalk';
3
- import {terminal} from './terminal.js';
1
+ const inquirer = require('inquirer');
2
+ const chalk = require('chalk');
3
+ const {terminal} = require('./terminal.js');
4
4
 
5
5
  async function confirmExecution(message) {
6
6
  const {ok} = await inquirer.prompt({type: 'confirm', name: 'ok', message, default: false});
7
7
  return ok;
8
8
  }
9
9
 
10
- export async function handleAction(selected) {
10
+ async function handleAction(selected) {
11
11
  const proceed = selected.confirm ? await confirmExecution(chalk.yellow(`Executing command: [id: ${selected.id} name: ${selected.name} ]`)) : true;
12
12
  if (proceed) {
13
13
  await terminal.execCommandSync(selected.command);
14
14
  }
15
15
  }
16
16
 
17
- export async function handleCustomAction(selected, flatMap) {
17
+ async function handleCustomAction(selected, flatMap) {
18
18
  const proceed = selected.confirm ? await confirmExecution(chalk.yellow(`Execute command list ${selected.idList.join(', ')}?`)) : true;
19
19
  if (proceed) {
20
20
  for (const id of selected.idList) {
@@ -27,6 +27,8 @@ export async function handleCustomAction(selected, flatMap) {
27
27
  }
28
28
  }
29
29
 
30
- export async function handleNavigation(selected) {
30
+ async function handleNavigation(selected) {
31
31
  return selected;
32
- }
32
+ }
33
+
34
+ module.exports = { handleAction, handleCustomAction, handleNavigation };
@@ -1,5 +1,5 @@
1
- import fs from 'fs';
2
- import chalk from 'chalk';
1
+ const fs = require('fs');
2
+ const chalk = require('chalk');
3
3
 
4
4
  const defaultMenu = {
5
5
  "name": "Example Menu",
@@ -15,21 +15,26 @@ const defaultMenu = {
15
15
  ]
16
16
  };
17
17
 
18
- export function loadMenuConfig() {
19
- const args = process.argv.slice(2);
20
- const path = args[0];
18
+ function loadMenuConfig(menuPath = null) {
21
19
  let data;
20
+ let finalPath = menuPath;
22
21
 
23
- if (path && fs.existsSync(path)) {
22
+ // If menuPath is not provided, check command line arguments
23
+ if (!finalPath) {
24
+ const args = process.argv.slice(2);
25
+ finalPath = args[0];
26
+ }
27
+
28
+ if (finalPath && fs.existsSync(finalPath)) {
24
29
  try {
25
- data = JSON.parse(fs.readFileSync(path, 'utf-8'));
30
+ data = JSON.parse(fs.readFileSync(finalPath, 'utf-8'));
26
31
  } catch (error) {
27
- console.log(chalk.red(`Error parsing JSON file: ${path}`));
32
+ console.log(chalk.red(`Error parsing JSON file: ${finalPath}`));
28
33
  console.error(error);
29
34
  process.exit(1);
30
35
  }
31
- } else if (path) {
32
- console.log(chalk.red(`File not found: ${path}`));
36
+ } else if (finalPath) {
37
+ console.log(chalk.red(`File not found: ${finalPath}`));
33
38
  process.exit(1);
34
39
  } else if (fs.existsSync('./menu.json')) {
35
40
  try {
@@ -46,3 +51,5 @@ export function loadMenuConfig() {
46
51
 
47
52
  return data;
48
53
  }
54
+
55
+ module.exports = { loadMenuConfig };
package/src/header.js ADDED
@@ -0,0 +1,27 @@
1
+ const chalk = require('chalk');
2
+
3
+ function displayHeader(data) {
4
+ const name = data.name || 'Custom Menu';
5
+ const description = data.description || 'A CLI Menu';
6
+ const lines = [name, description];
7
+ const maxLength = Math.max(...lines.map(line => line.length));
8
+ const boxWidth = maxLength + 4;
9
+
10
+ const topBorder = '╔' + '═'.repeat(boxWidth) + '╗';
11
+ const bottomBorder = '╚' + '═'.repeat(boxWidth) + '╝';
12
+
13
+ console.log(chalk.bold.blueBright(topBorder));
14
+ lines.forEach(line => {
15
+ const paddingTotal = boxWidth - line.length;
16
+ const paddingLeft = Math.floor(paddingTotal / 2);
17
+ const paddingRight = Math.ceil(paddingTotal / 2);
18
+ const paddedLine = `║${' '.repeat(paddingLeft)}${line}${' '.repeat(paddingRight)}║`;
19
+ console.log(chalk.bold.blueBright(paddedLine));
20
+ });
21
+ console.log(chalk.bold.blueBright(bottomBorder));
22
+ console.log('');
23
+ console.log(chalk.gray(`Developed by Mateus Medeiros - GitHub: @mateusmed`));
24
+ console.log('');
25
+ }
26
+
27
+ module.exports = { displayHeader };
package/src/menu.js CHANGED
@@ -1,17 +1,17 @@
1
- import inquirer from 'inquirer';
2
- import chalk from 'chalk';
3
- import { handleAction, handleCustomAction, handleNavigation } from './actions.js';
1
+ const inquirer = require('inquirer');
2
+ const chalk = require('chalk');
3
+ const { handleAction, handleCustomAction, handleNavigation } = require('./actions.js');
4
4
 
5
- export const flatMap = {};
5
+ const flatMap = {};
6
6
 
7
- export function buildIdMap(options) {
7
+ function buildIdMap(options) {
8
8
  for (const opt of options) {
9
9
  flatMap[opt.id] = opt;
10
10
  if (opt.options) buildIdMap(opt.options);
11
11
  }
12
12
  }
13
13
 
14
- export async function showMenu(menu) {
14
+ async function showMenu(menu) {
15
15
  while (true) {
16
16
  const choices = menu.options.map(o => `[${o.id}] ${o.name}`).concat([' Back']);
17
17
  const { choice } = await inquirer.prompt({
@@ -41,3 +41,5 @@ export async function showMenu(menu) {
41
41
  }
42
42
  }
43
43
  }
44
+
45
+ module.exports = { flatMap, buildIdMap, showMenu };
package/src/terminal.js CHANGED
@@ -1,16 +1,12 @@
1
- import { fileURLToPath } from 'url';
2
- import { dirname, join } from 'path';
3
- import { config } from 'dotenv';
4
- import { access } from 'fs/promises';
5
- import { execSync } from 'child_process';
6
- import chalk from 'chalk';
7
-
8
- const __filename = fileURLToPath(import.meta.url);
9
- const __dirname = dirname(__filename);
1
+ const { join } = require('path');
2
+ const { config } = require('dotenv');
3
+ const { access } = require('fs/promises');
4
+ const { execSync } = require('child_process');
5
+ const chalk = require('chalk');
10
6
 
11
7
  config({ path: join(__dirname, '../.env') });
12
8
 
13
- export const terminal = {
9
+ const terminal = {
14
10
 
15
11
  async directoryExists(path) {
16
12
  try {
@@ -53,3 +49,5 @@ export const terminal = {
53
49
  }
54
50
 
55
51
  }
52
+
53
+ module.exports = { terminal };