@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 ADDED
@@ -0,0 +1,244 @@
1
+ # Maker
2
+
3
+ A lightweight library for building interactive command-line tools with ease.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@sandro-sikic/maker)](https://www.npmjs.com/package/@sandro-sikic/maker)
6
+ [![License: ISC](https://img.shields.io/badge/License-ISC-blue.svg)](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
+ ```