@sandro-sikic/maker 1.0.7 → 1.0.9
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.md +244 -0
- package/docs/API.md +191 -0
- package/docs/USAGE.md +572 -0
- package/example.js +13 -0
- package/index.js +31 -76
- package/package.json +4 -9
- package/test/index.test.js +1161 -0
- package/__tests__/index.test.js +0 -119
- package/babel.config.js +0 -10
- package/jest.config.cjs +0 -8
package/README.md
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
# Maker
|
|
2
|
+
|
|
3
|
+
A lightweight library for building interactive command-line tools with ease.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@sandro-sikic/maker)
|
|
6
|
+
[](https://opensource.org/licenses/ISC)
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
✨ **Simple API** - Just 5 core functions to build powerful CLI tools
|
|
11
|
+
🎯 **Interactive Prompts** - Built-in support for user input via [@inquirer/prompts](https://github.com/SBoudrias/Inquirer.js)
|
|
12
|
+
⚡ **Command Execution** - Run shell commands with streaming output
|
|
13
|
+
🎨 **Beautiful Spinners** - Visual feedback with [ora](https://github.com/sindresorhus/ora)
|
|
14
|
+
🛡️ **Graceful Shutdown** - Automatic cleanup on exit signals
|
|
15
|
+
📘 **TypeScript Support** - Full type definitions included
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @sandro-sikic/maker
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
```javascript
|
|
26
|
+
import * as maker from '@sandro-sikic/maker';
|
|
27
|
+
|
|
28
|
+
// Initialize CLI environment
|
|
29
|
+
maker.init();
|
|
30
|
+
|
|
31
|
+
// Prompt user for input
|
|
32
|
+
const name = await maker.prompt.input({
|
|
33
|
+
message: 'What is your project name?',
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// Show progress with spinner
|
|
37
|
+
const loading = maker.spinner('Creating project...').start();
|
|
38
|
+
|
|
39
|
+
// Run shell commands
|
|
40
|
+
await maker.run(`mkdir ${name}`);
|
|
41
|
+
await maker.run(`cd ${name} && npm init -y`);
|
|
42
|
+
|
|
43
|
+
loading.succeed('Project created! 🎉');
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## API Overview
|
|
47
|
+
|
|
48
|
+
### Core Functions
|
|
49
|
+
|
|
50
|
+
| Function | Description |
|
|
51
|
+
| -------------------- | -------------------------------------------------- |
|
|
52
|
+
| `init()` | Validates interactive terminal environment |
|
|
53
|
+
| `run(command, opts)` | Executes shell commands with streaming output |
|
|
54
|
+
| `onExit(callback)` | Registers cleanup function for graceful shutdown |
|
|
55
|
+
| `prompt.*` | Interactive prompts (input, select, confirm, etc.) |
|
|
56
|
+
| `spinner(text)` | Creates terminal loading indicators |
|
|
57
|
+
|
|
58
|
+
### Example: Simple Build Tool
|
|
59
|
+
|
|
60
|
+
```javascript
|
|
61
|
+
import * as maker from '@sandro-sikic/maker';
|
|
62
|
+
|
|
63
|
+
async function build() {
|
|
64
|
+
maker.init();
|
|
65
|
+
|
|
66
|
+
// Register cleanup
|
|
67
|
+
maker.onExit(() => {
|
|
68
|
+
console.log('Cleanup complete');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// Confirm action
|
|
72
|
+
const shouldBuild = await maker.prompt.confirm({
|
|
73
|
+
message: 'Start build?',
|
|
74
|
+
default: true,
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
if (!shouldBuild) return;
|
|
78
|
+
|
|
79
|
+
// Execute with spinner
|
|
80
|
+
const building = maker.spinner('Building...').start();
|
|
81
|
+
const result = await maker.run('npm run build');
|
|
82
|
+
|
|
83
|
+
if (result.isError) {
|
|
84
|
+
building.fail('Build failed!');
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
building.succeed('Build complete!');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
build();
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Documentation
|
|
95
|
+
|
|
96
|
+
📖 **[Complete Usage Guide](./docs/USAGE.md)** - Detailed documentation with examples
|
|
97
|
+
⚡ **[API Quick Reference](./docs/API.md)** - Fast lookup for all functions
|
|
98
|
+
|
|
99
|
+
## API Details
|
|
100
|
+
|
|
101
|
+
### `init()`
|
|
102
|
+
|
|
103
|
+
Ensures your CLI is running in an interactive terminal. Always call this first.
|
|
104
|
+
|
|
105
|
+
```javascript
|
|
106
|
+
maker.init();
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### `run(command, opts)`
|
|
110
|
+
|
|
111
|
+
Execute shell commands with real-time output streaming.
|
|
112
|
+
|
|
113
|
+
```javascript
|
|
114
|
+
const result = await maker.run('npm test');
|
|
115
|
+
|
|
116
|
+
if (result.isError) {
|
|
117
|
+
console.error('Command failed:', result.stderr);
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**Returns:** `{ output, stdout, stderr, code, isError, error }`
|
|
122
|
+
|
|
123
|
+
### `onExit(callback)`
|
|
124
|
+
|
|
125
|
+
Register cleanup handlers for graceful shutdown (SIGINT, SIGTERM, SIGQUIT).
|
|
126
|
+
|
|
127
|
+
```javascript
|
|
128
|
+
maker.onExit(async () => {
|
|
129
|
+
await closeDatabase();
|
|
130
|
+
await stopServer();
|
|
131
|
+
});
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### `prompt.*`
|
|
135
|
+
|
|
136
|
+
Interactive prompts powered by [@inquirer/prompts](https://github.com/SBoudrias/Inquirer.js):
|
|
137
|
+
|
|
138
|
+
```javascript
|
|
139
|
+
await maker.prompt.input({ message: 'Name?' });
|
|
140
|
+
await maker.prompt.confirm({ message: 'Continue?' });
|
|
141
|
+
await maker.prompt.select({ message: 'Choose:', choices: [...] });
|
|
142
|
+
await maker.prompt.checkbox({ message: 'Select:', choices: [...] });
|
|
143
|
+
await maker.prompt.password({ message: 'API key:' });
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### `spinner(text)`
|
|
147
|
+
|
|
148
|
+
Create terminal spinners with [ora](https://github.com/sindresorhus/ora):
|
|
149
|
+
|
|
150
|
+
```javascript
|
|
151
|
+
const s = maker.spinner('Loading...').start();
|
|
152
|
+
s.succeed('Done!'); // ✔
|
|
153
|
+
s.fail('Failed!'); // ✖
|
|
154
|
+
s.warn('Warning!'); // ⚠
|
|
155
|
+
s.info('Info!'); // ℹ
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Real-World Example
|
|
159
|
+
|
|
160
|
+
```javascript
|
|
161
|
+
import * as maker from '@sandro-sikic/maker';
|
|
162
|
+
|
|
163
|
+
async function setupProject() {
|
|
164
|
+
maker.init();
|
|
165
|
+
|
|
166
|
+
// Get project configuration
|
|
167
|
+
const config = {
|
|
168
|
+
name: await maker.prompt.input({
|
|
169
|
+
message: 'Project name:',
|
|
170
|
+
}),
|
|
171
|
+
framework: await maker.prompt.select({
|
|
172
|
+
message: 'Framework:',
|
|
173
|
+
choices: [
|
|
174
|
+
{ name: 'React', value: 'react' },
|
|
175
|
+
{ name: 'Vue', value: 'vue' },
|
|
176
|
+
{ name: 'Angular', value: 'angular' },
|
|
177
|
+
],
|
|
178
|
+
}),
|
|
179
|
+
features: await maker.prompt.checkbox({
|
|
180
|
+
message: 'Features:',
|
|
181
|
+
choices: [
|
|
182
|
+
{ name: 'TypeScript', value: 'typescript' },
|
|
183
|
+
{ name: 'ESLint', value: 'eslint' },
|
|
184
|
+
{ name: 'Testing', value: 'testing' },
|
|
185
|
+
],
|
|
186
|
+
}),
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
// Confirm setup
|
|
190
|
+
const proceed = await maker.prompt.confirm({
|
|
191
|
+
message: 'Create project?',
|
|
192
|
+
default: true,
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
if (!proceed) {
|
|
196
|
+
console.log('Cancelled');
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Setup with progress indicators
|
|
201
|
+
const setup = maker.spinner('Creating project...').start();
|
|
202
|
+
|
|
203
|
+
await maker.run(`mkdir ${config.name}`);
|
|
204
|
+
setup.text = 'Installing dependencies...';
|
|
205
|
+
await maker.run(`cd ${config.name} && npm init -y`);
|
|
206
|
+
await maker.run(`cd ${config.name} && npm install ${config.framework}`);
|
|
207
|
+
|
|
208
|
+
for (const feature of config.features) {
|
|
209
|
+
setup.text = `Installing ${feature}...`;
|
|
210
|
+
await maker.run(`cd ${config.name} && npm install ${feature}`);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
setup.succeed('Project ready! 🚀');
|
|
214
|
+
console.log(`\nNext:\n cd ${config.name}\n npm start`);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
setupProject();
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## TypeScript
|
|
221
|
+
|
|
222
|
+
Full TypeScript support with included type definitions:
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
import { run, RunResult, Ora } from '@sandro-sikic/maker';
|
|
226
|
+
|
|
227
|
+
const result: RunResult = await run('echo "Hello"');
|
|
228
|
+
const spinner: Ora = maker.spinner('Loading...');
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## Repository
|
|
232
|
+
|
|
233
|
+
[github.com/sandro-sikic/maker](https://github.com/sandro-sikic/maker)
|
|
234
|
+
|
|
235
|
+
## License
|
|
236
|
+
|
|
237
|
+
ISC
|
|
238
|
+
|
|
239
|
+
## Credits
|
|
240
|
+
|
|
241
|
+
Built with:
|
|
242
|
+
|
|
243
|
+
- [@inquirer/prompts](https://github.com/SBoudrias/Inquirer.js) - Interactive prompts
|
|
244
|
+
- [ora](https://github.com/sindresorhus/ora) - Terminal spinners
|
package/docs/API.md
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# Maker - API Quick Reference
|
|
2
|
+
|
|
3
|
+
Quick reference guide for `@sandro-sikic/maker` functions.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## `init()`
|
|
8
|
+
|
|
9
|
+
Validates interactive terminal environment. **Call first** in your CLI app.
|
|
10
|
+
|
|
11
|
+
```javascript
|
|
12
|
+
maker.init();
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Exits with code 1 if not running in an interactive terminal (TTY).
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## `run(command, opts)`
|
|
20
|
+
|
|
21
|
+
Execute shell commands with streaming output.
|
|
22
|
+
|
|
23
|
+
```javascript
|
|
24
|
+
const result = await run('npm install', { maxLines: 10000 });
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**Parameters:**
|
|
28
|
+
|
|
29
|
+
- `command` - Shell command string (required)
|
|
30
|
+
- `opts.maxLines` - Max output lines to capture (default: 10000)
|
|
31
|
+
|
|
32
|
+
**Returns:**
|
|
33
|
+
|
|
34
|
+
```javascript
|
|
35
|
+
{
|
|
36
|
+
output: string, // Combined stdout + stderr
|
|
37
|
+
stdout: string, // Standard output
|
|
38
|
+
stderr: string, // Standard error
|
|
39
|
+
code: number|null, // Exit code
|
|
40
|
+
isError: boolean, // true if failed
|
|
41
|
+
error: Error|null // Spawn error if any
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Usage patterns:**
|
|
46
|
+
|
|
47
|
+
```javascript
|
|
48
|
+
// Foreground (waits for completion)
|
|
49
|
+
await run('npm test');
|
|
50
|
+
|
|
51
|
+
// Background (non-blocking)
|
|
52
|
+
run('npm run dev');
|
|
53
|
+
|
|
54
|
+
// Error handling
|
|
55
|
+
const result = await run('npm build');
|
|
56
|
+
if (result.isError) {
|
|
57
|
+
console.error('Failed:', result.stderr);
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## `onExit(callback)`
|
|
64
|
+
|
|
65
|
+
Register cleanup function for graceful shutdown.
|
|
66
|
+
|
|
67
|
+
```javascript
|
|
68
|
+
onExit(async () => {
|
|
69
|
+
await cleanup();
|
|
70
|
+
});
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Parameters:**
|
|
74
|
+
|
|
75
|
+
- `callback` - Sync or async cleanup function
|
|
76
|
+
|
|
77
|
+
**Returns:**
|
|
78
|
+
|
|
79
|
+
- Unregister function
|
|
80
|
+
|
|
81
|
+
**Triggers on:**
|
|
82
|
+
|
|
83
|
+
- SIGINT (Ctrl+C)
|
|
84
|
+
- SIGTERM
|
|
85
|
+
- SIGQUIT
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## `prompt.*`
|
|
90
|
+
|
|
91
|
+
Interactive prompts ([inquirer](https://github.com/SBoudrias/Inquirer.js/tree/master/packages/prompts)).
|
|
92
|
+
|
|
93
|
+
```javascript
|
|
94
|
+
// Text input
|
|
95
|
+
await prompt.input({ message: 'Name?' });
|
|
96
|
+
|
|
97
|
+
// Yes/no
|
|
98
|
+
await prompt.confirm({ message: 'Continue?' });
|
|
99
|
+
|
|
100
|
+
// Select one
|
|
101
|
+
await prompt.select({
|
|
102
|
+
message: 'Choose:',
|
|
103
|
+
choices: [
|
|
104
|
+
{ name: 'Option 1', value: '1' },
|
|
105
|
+
{ name: 'Option 2', value: '2' }
|
|
106
|
+
]
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// Select multiple
|
|
110
|
+
await prompt.checkbox({
|
|
111
|
+
message: 'Select:',
|
|
112
|
+
choices: [...]
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// Password
|
|
116
|
+
await prompt.password({ message: 'API key:' });
|
|
117
|
+
|
|
118
|
+
// Number
|
|
119
|
+
await prompt.number({ message: 'Port:', default: 3000 });
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## `spinner(text)`
|
|
125
|
+
|
|
126
|
+
Terminal spinner ([ora](https://github.com/sindresorhus/ora)).
|
|
127
|
+
|
|
128
|
+
```javascript
|
|
129
|
+
const s = spinner('Loading...').start();
|
|
130
|
+
|
|
131
|
+
// Update text
|
|
132
|
+
s.text = 'Still loading...';
|
|
133
|
+
|
|
134
|
+
// Complete
|
|
135
|
+
s.succeed('Done!'); // ✔
|
|
136
|
+
s.fail('Failed!'); // ✖
|
|
137
|
+
s.warn('Warning!'); // ⚠
|
|
138
|
+
s.info('Info!'); // ℹ
|
|
139
|
+
s.stop(); // Stop and clear
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Complete Example
|
|
145
|
+
|
|
146
|
+
```javascript
|
|
147
|
+
import * as maker from '@sandro-sikic/maker';
|
|
148
|
+
|
|
149
|
+
// 1. Initialize
|
|
150
|
+
maker.init();
|
|
151
|
+
|
|
152
|
+
// 2. Register cleanup
|
|
153
|
+
maker.onExit(async () => {
|
|
154
|
+
console.log('Cleaning up...');
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// 3. Prompt user
|
|
158
|
+
const name = await maker.prompt.input({
|
|
159
|
+
message: 'Project name:',
|
|
160
|
+
default: 'my-app',
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
const confirmed = await maker.prompt.confirm({
|
|
164
|
+
message: 'Install dependencies?',
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// 4. Run commands with spinner
|
|
168
|
+
if (confirmed) {
|
|
169
|
+
const s = maker.spinner('Installing...').start();
|
|
170
|
+
|
|
171
|
+
const result = await maker.run(`npm create ${name}`);
|
|
172
|
+
|
|
173
|
+
if (result.isError) {
|
|
174
|
+
s.fail('Installation failed');
|
|
175
|
+
process.exit(1);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
s.succeed('Installation complete!');
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## TypeScript Types
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
import type { RunResult, Ora } from '@sandro-sikic/maker';
|
|
188
|
+
|
|
189
|
+
// Also exports all @inquirer/prompts types
|
|
190
|
+
import type { ConfirmPrompt, InputPrompt } from '@sandro-sikic/maker';
|
|
191
|
+
```
|