@visulima/cerebro 3.0.2 → 3.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/CHANGELOG.md +9 -0
- package/MIGRATION-GUIDE.md +732 -0
- package/dist/commands/completion-command.d.ts +3 -3
- package/dist/commands/completion-command.js +1 -1
- package/dist/commands/help-command.d.ts +1 -1
- package/dist/commands/help-command.js +1 -1
- package/dist/commands/readme-command.d.ts +3 -3
- package/dist/commands/readme-command.js +17 -17
- package/dist/commands/version-command.d.ts +1 -1
- package/dist/index.d.ts +403 -433
- package/dist/index.js +1 -1
- package/dist/logger/create-pail-logger.d.ts +533 -555
- package/dist/packem_chunks/has-new-version.js +1 -1
- package/dist/packem_shared/Cerebro-CHB2i5uf.js +4 -0
- package/dist/packem_shared/{VisulimaError-C90oeIMu.js → VisulimaError-BheWBD7j.js} +2 -2
- package/dist/packem_shared/{cerebro-error-BjBcYVRO.js → cerebro-error-DnA3fjrR.js} +1 -1
- package/dist/packem_shared/command.d-B_G9vIYJ.d.ts +633 -0
- package/dist/packem_shared/{index-DvVGK4kr.js → index-BAKCiGjO.js} +10 -10
- package/dist/packem_shared/index.d-CnnVYgSZ.d.ts +117 -0
- package/dist/packem_shared/renderError-DjesnVYT-pHitCa3e.js +25 -0
- package/dist/packem_shared/split-by-case-DpyL5bdy.js +1 -0
- package/dist/plugins/error-handler-plugin.d.ts +18 -7
- package/dist/plugins/error-handler-plugin.js +1 -1
- package/dist/plugins/runtime-version-check-plugin.d.ts +5 -5
- package/dist/plugins/update-notifier/update-notifier-plugin.d.ts +11 -10
- package/dist/util/general/compile-cache.d.ts +37 -37
- package/dist/util/general/heap-tuning.d.ts +11 -11
- package/dist/util/general/heap-tuning.js +1 -1
- package/package.json +4 -3
- package/dist/packem_shared/Cerebro-Czc4t-75.js +0 -4
- package/dist/packem_shared/command.d-DbhtfXF4.d.ts +0 -639
- package/dist/packem_shared/index.d-BL4NtVR3.d.ts +0 -127
- package/dist/packem_shared/renderError-B3ePOoBG-BmZlyMcr.js +0 -25
- package/dist/packem_shared/split-by-case-Dbpgd7rf.js +0 -1
|
@@ -0,0 +1,732 @@
|
|
|
1
|
+
# Migration Guide
|
|
2
|
+
|
|
3
|
+
This guide documents breaking changes and migration steps for the `@visulima/cerebro` package.
|
|
4
|
+
|
|
5
|
+
## Version 2.0.0 (Upcoming)
|
|
6
|
+
|
|
7
|
+
### Breaking Changes Summary
|
|
8
|
+
|
|
9
|
+
- **Supported runtimes**: Node.js 20.19+, Deno 1.0+, Bun 1.0+
|
|
10
|
+
- **Module format**: ESM-only (CommonJS removed)
|
|
11
|
+
- **Import structure**: Granular plugin and command exports
|
|
12
|
+
- **Error handling**: Enhanced error types and validation
|
|
13
|
+
|
|
14
|
+
### CommonJS (CJS) Export Removed
|
|
15
|
+
|
|
16
|
+
The CommonJS (CJS) export has been removed in favor of ECMAScript Modules (ESM) only. Cerebro now supports Node.js, Deno, and Bun runtimes. For CJS compatibility in Node.js 20.19+, use dynamic imports.
|
|
17
|
+
|
|
18
|
+
#### Before (v1.x)
|
|
19
|
+
|
|
20
|
+
```javascript
|
|
21
|
+
// This no longer works
|
|
22
|
+
const { Cerebro, createCerebro } = require("@visulima/cerebro");
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
#### After (v2.x) - Node.js 20.19+, Deno 1.0+, Bun 1.0+
|
|
26
|
+
|
|
27
|
+
```javascript
|
|
28
|
+
// Use dynamic import for ESM modules from CJS (Node.js only)
|
|
29
|
+
const { Cerebro, createCerebro } = await import("@visulima/cerebro");
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Note**: Deno and Bun natively support ESM, so you can use standard `import` statements directly.
|
|
33
|
+
|
|
34
|
+
#### Alternative: Convert to ESM
|
|
35
|
+
|
|
36
|
+
For better compatibility and performance, convert your project to use ESM:
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
// package.json
|
|
40
|
+
{
|
|
41
|
+
"name": "your-project",
|
|
42
|
+
"version": "1.0.0",
|
|
43
|
+
"type": "module"
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
// Your files can now use ESM imports
|
|
49
|
+
import { createCerebro } from "@visulima/cerebro";
|
|
50
|
+
|
|
51
|
+
const cli = createCerebro("my-app", {
|
|
52
|
+
packageName: "my-app",
|
|
53
|
+
packageVersion: "1.0.0",
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
cli.addCommand({
|
|
57
|
+
execute: ({ logger }) => {
|
|
58
|
+
logger.info("Hello ESM world!");
|
|
59
|
+
},
|
|
60
|
+
name: "hello",
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
await cli.run();
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Granular Plugin and Command Exports
|
|
67
|
+
|
|
68
|
+
Plugins and commands are now exported from specific paths for better tree-shaking and smaller bundle sizes.
|
|
69
|
+
|
|
70
|
+
#### Old Export Structure
|
|
71
|
+
|
|
72
|
+
```javascript
|
|
73
|
+
// This may work but is not recommended
|
|
74
|
+
import { errorHandlerPlugin } from "@visulima/cerebro";
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
#### New Granular Export Structure
|
|
78
|
+
|
|
79
|
+
```javascript
|
|
80
|
+
// Import plugins from specific paths
|
|
81
|
+
import { completionCommand } from "@visulima/cerebro/command/completion";
|
|
82
|
+
// Import commands from specific paths
|
|
83
|
+
import { helpCommand } from "@visulima/cerebro/command/help";
|
|
84
|
+
import { versionCommand } from "@visulima/cerebro/command/version";
|
|
85
|
+
// Import logger utilities
|
|
86
|
+
import { createPailLogger } from "@visulima/cerebro/logger/pail";
|
|
87
|
+
import { errorHandlerPlugin } from "@visulima/cerebro/plugins/error-handler";
|
|
88
|
+
import { runtimeVersionCheckPlugin } from "@visulima/cerebro/plugins/runtime-version-check";
|
|
89
|
+
import { updateNotifierPlugin } from "@visulima/cerebro/plugins/update-notifier";
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
#### Benefits
|
|
93
|
+
|
|
94
|
+
- **Smaller bundle sizes**: Only import what you need
|
|
95
|
+
- **Better tree-shaking**: Unused code is excluded from bundles
|
|
96
|
+
- **Clearer dependencies**: Explicit imports make dependencies obvious
|
|
97
|
+
- **Improved performance**: Reduced bundle size and faster loading
|
|
98
|
+
|
|
99
|
+
### Nested Command Support
|
|
100
|
+
|
|
101
|
+
Cerebro now supports nested commands (subcommands) using the `commandPath` property. This allows you to create hierarchical command structures like `cli deploy staging` or `cli db migrate up`.
|
|
102
|
+
|
|
103
|
+
#### Defining Nested Commands
|
|
104
|
+
|
|
105
|
+
Create nested commands by specifying a `commandPath` array in your command definition:
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
// Parent command path: ["deploy"]
|
|
109
|
+
cli.addCommand({
|
|
110
|
+
name: "staging",
|
|
111
|
+
commandPath: ["deploy"],
|
|
112
|
+
description: "Deploy to staging environment",
|
|
113
|
+
execute: ({ logger }) => {
|
|
114
|
+
logger.info("Deploying to staging...");
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
cli.addCommand({
|
|
119
|
+
name: "production",
|
|
120
|
+
commandPath: ["deploy"],
|
|
121
|
+
description: "Deploy to production environment",
|
|
122
|
+
execute: ({ logger }) => {
|
|
123
|
+
logger.info("Deploying to production...");
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Usage:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
cli deploy staging
|
|
132
|
+
cli deploy production
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
#### Multi-Level Nested Commands
|
|
136
|
+
|
|
137
|
+
You can nest commands multiple levels deep:
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
cli.addCommand({
|
|
141
|
+
name: "up",
|
|
142
|
+
commandPath: ["db", "migrate"],
|
|
143
|
+
description: "Run database migrations",
|
|
144
|
+
execute: ({ logger }) => {
|
|
145
|
+
logger.info("Running migrations...");
|
|
146
|
+
},
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
cli.addCommand({
|
|
150
|
+
name: "down",
|
|
151
|
+
commandPath: ["db", "migrate"],
|
|
152
|
+
description: "Rollback database migrations",
|
|
153
|
+
execute: ({ logger }) => {
|
|
154
|
+
logger.info("Rolling back migrations...");
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Usage:
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
cli db migrate up
|
|
163
|
+
cli db migrate down
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
#### Accessing Command Path
|
|
167
|
+
|
|
168
|
+
The `commandPath` is available through the `command` property in the execute function:
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
cli.addCommand({
|
|
172
|
+
name: "staging",
|
|
173
|
+
commandPath: ["deploy"],
|
|
174
|
+
execute: ({ command, logger }) => {
|
|
175
|
+
// command.commandPath will be ["deploy"]
|
|
176
|
+
// command.name will be "staging"
|
|
177
|
+
const fullPath = command.commandPath ? [...command.commandPath, command.name].join(" ") : command.name;
|
|
178
|
+
logger.info(`Executing command: ${fullPath}`);
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
#### Options in Nested Commands
|
|
184
|
+
|
|
185
|
+
Nested commands support options just like regular commands:
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
cli.addCommand({
|
|
189
|
+
name: "up",
|
|
190
|
+
commandPath: ["db", "migrate"],
|
|
191
|
+
options: [
|
|
192
|
+
{
|
|
193
|
+
name: "force",
|
|
194
|
+
type: Boolean,
|
|
195
|
+
description: "Force migration even if already applied",
|
|
196
|
+
},
|
|
197
|
+
],
|
|
198
|
+
execute: ({ options, logger }) => {
|
|
199
|
+
if (options.force) {
|
|
200
|
+
logger.info("Forcing migration...");
|
|
201
|
+
}
|
|
202
|
+
logger.info("Running migrations...");
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Usage:
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
cli db migrate up --force
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
#### Calling Nested Commands Programmatically
|
|
214
|
+
|
|
215
|
+
Use `runtime.runCommand()` with the full command path (space-separated):
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
cli.addCommand({
|
|
219
|
+
name: "deploy-all",
|
|
220
|
+
execute: async ({ runtime, logger }) => {
|
|
221
|
+
logger.info("Deploying to all environments...");
|
|
222
|
+
|
|
223
|
+
// Call nested commands programmatically
|
|
224
|
+
await runtime.runCommand("deploy staging");
|
|
225
|
+
await runtime.runCommand("deploy production");
|
|
226
|
+
},
|
|
227
|
+
});
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Enhanced Error Handling
|
|
231
|
+
|
|
232
|
+
Error handling has been improved with better error types and validation.
|
|
233
|
+
|
|
234
|
+
#### Command Not Found Errors
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
import { CommandNotFoundError } from "@visulima/cerebro";
|
|
238
|
+
|
|
239
|
+
// Before - Generic error
|
|
240
|
+
try {
|
|
241
|
+
await cli.run();
|
|
242
|
+
} catch (error) {
|
|
243
|
+
console.error("Error:", error.message);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// After - Specific error types
|
|
247
|
+
try {
|
|
248
|
+
await cli.run();
|
|
249
|
+
} catch (error) {
|
|
250
|
+
if (error instanceof CommandNotFoundError) {
|
|
251
|
+
console.error(`Command not found: ${error.command}`);
|
|
252
|
+
console.error(`Did you mean: ${error.alternatives.join(", ")}?`);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Migration Steps
|
|
258
|
+
|
|
259
|
+
#### 1. Update Package Configuration
|
|
260
|
+
|
|
261
|
+
Ensure your `package.json` uses ESM:
|
|
262
|
+
|
|
263
|
+
```json
|
|
264
|
+
{
|
|
265
|
+
"name": "your-project",
|
|
266
|
+
"version": "1.0.0",
|
|
267
|
+
"type": "module",
|
|
268
|
+
"engines": {
|
|
269
|
+
"node": ">=20.19"
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
> **Note**: Deno and Bun don't use the `package.json` engines field. Deno uses `deno.json`, and Bun supports both `package.json` and `bunfig.toml`.
|
|
275
|
+
|
|
276
|
+
#### 2. Update Imports
|
|
277
|
+
|
|
278
|
+
Replace CJS `require()` calls with ESM `import` statements:
|
|
279
|
+
|
|
280
|
+
```javascript
|
|
281
|
+
// Before
|
|
282
|
+
import { createCerebro } from "@visulima/cerebro";
|
|
283
|
+
|
|
284
|
+
// After
|
|
285
|
+
const { createCerebro } = require("@visulima/cerebro");
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
#### 3. Update Plugin Imports
|
|
289
|
+
|
|
290
|
+
Use granular plugin imports:
|
|
291
|
+
|
|
292
|
+
```javascript
|
|
293
|
+
// Before
|
|
294
|
+
import { errorHandlerPlugin } from "@visulima/cerebro";
|
|
295
|
+
|
|
296
|
+
// After
|
|
297
|
+
import { errorHandlerPlugin } from "@visulima/cerebro/plugins/error-handler";
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
#### 4. Handle Async Context
|
|
301
|
+
|
|
302
|
+
Ensure functions using Cerebro are async when needed:
|
|
303
|
+
|
|
304
|
+
```typescript
|
|
305
|
+
// Before
|
|
306
|
+
function setupCLI() {
|
|
307
|
+
const { createCerebro } = require("@visulima/cerebro");
|
|
308
|
+
|
|
309
|
+
return createCerebro("my-app");
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// After
|
|
313
|
+
async function setupCLI() {
|
|
314
|
+
const { createCerebro } = await import("@visulima/cerebro");
|
|
315
|
+
|
|
316
|
+
return createCerebro("my-app");
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
Or better, use static imports:
|
|
321
|
+
|
|
322
|
+
```typescript
|
|
323
|
+
import { createCerebro } from "@visulima/cerebro";
|
|
324
|
+
|
|
325
|
+
function setupCLI() {
|
|
326
|
+
return createCerebro("my-app");
|
|
327
|
+
}
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### Migration Issues & Solutions
|
|
331
|
+
|
|
332
|
+
#### 1. require() Calls No Longer Work
|
|
333
|
+
|
|
334
|
+
**Problem**: `require('@visulima/cerebro')` throws "module not found" error.
|
|
335
|
+
|
|
336
|
+
**Solution**: Use dynamic imports or convert to ESM:
|
|
337
|
+
|
|
338
|
+
```javascript
|
|
339
|
+
// Dynamic import for ESM modules from CJS
|
|
340
|
+
const { createCerebro } = await import("@visulima/cerebro");
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
#### 2. Plugin Imports Fail
|
|
344
|
+
|
|
345
|
+
**Problem**: Plugin imports from main package no longer work.
|
|
346
|
+
|
|
347
|
+
**Solution**: Use granular plugin imports:
|
|
348
|
+
|
|
349
|
+
```javascript
|
|
350
|
+
// Before
|
|
351
|
+
import { errorHandlerPlugin } from "@visulima/cerebro";
|
|
352
|
+
|
|
353
|
+
// After
|
|
354
|
+
import { errorHandlerPlugin } from "@visulima/cerebro/plugins/error-handler";
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
#### 3. Async Context Required
|
|
358
|
+
|
|
359
|
+
**Problem**: Functions using Cerebro must be async when using dynamic imports.
|
|
360
|
+
|
|
361
|
+
**Solution**: Mark functions as async and await the import, or use static ESM imports:
|
|
362
|
+
|
|
363
|
+
```typescript
|
|
364
|
+
// Static imports (recommended)
|
|
365
|
+
import { createCerebro } from "@visulima/cerebro";
|
|
366
|
+
|
|
367
|
+
// Or dynamic imports
|
|
368
|
+
async function setupCLI() {
|
|
369
|
+
const { createCerebro } = await import("@visulima/cerebro");
|
|
370
|
+
|
|
371
|
+
return createCerebro("my-app");
|
|
372
|
+
}
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
### Verification Steps
|
|
376
|
+
|
|
377
|
+
1. **Test ESM imports**:
|
|
378
|
+
|
|
379
|
+
```javascript
|
|
380
|
+
// test.mjs
|
|
381
|
+
import { createCerebro } from "@visulima/cerebro";
|
|
382
|
+
|
|
383
|
+
const cli = createCerebro("test-app");
|
|
384
|
+
|
|
385
|
+
cli.addCommand({
|
|
386
|
+
execute: ({ logger }) => {
|
|
387
|
+
logger.info("ESM import successful");
|
|
388
|
+
},
|
|
389
|
+
name: "test",
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
await cli.run({ argv: ["test"] });
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
2. **Test plugin imports**:
|
|
396
|
+
|
|
397
|
+
```javascript
|
|
398
|
+
// test-plugins.mjs
|
|
399
|
+
import { createCerebro } from "@visulima/cerebro";
|
|
400
|
+
import { errorHandlerPlugin } from "@visulima/cerebro/plugins/error-handler";
|
|
401
|
+
import { runtimeVersionCheckPlugin } from "@visulima/cerebro/plugins/runtime-version-check";
|
|
402
|
+
|
|
403
|
+
const cli = createCerebro("test-app");
|
|
404
|
+
|
|
405
|
+
cli.addPlugin(errorHandlerPlugin());
|
|
406
|
+
cli.addPlugin(runtimeVersionCheckPlugin());
|
|
407
|
+
|
|
408
|
+
console.log("Plugin imports successful");
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
3. **Test dynamic imports from CJS**:
|
|
412
|
+
|
|
413
|
+
```javascript
|
|
414
|
+
// test.cjs
|
|
415
|
+
async function test() {
|
|
416
|
+
const { createCerebro } = await import("@visulima/cerebro");
|
|
417
|
+
const cli = createCerebro("test-app");
|
|
418
|
+
|
|
419
|
+
cli.addCommand({
|
|
420
|
+
execute: ({ logger }) => {
|
|
421
|
+
logger.info("Dynamic import successful");
|
|
422
|
+
},
|
|
423
|
+
name: "test",
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
await cli.run({ argv: ["test"] });
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
test().catch(console.error);
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
## Migrating from Other CLI Libraries
|
|
433
|
+
|
|
434
|
+
### From Commander.js
|
|
435
|
+
|
|
436
|
+
Commander.js uses a different API structure. Here's how to migrate:
|
|
437
|
+
|
|
438
|
+
#### Commander.js Example
|
|
439
|
+
|
|
440
|
+
```javascript
|
|
441
|
+
const { Command } = require("commander");
|
|
442
|
+
|
|
443
|
+
const program = new Command();
|
|
444
|
+
|
|
445
|
+
program.name("my-app").description("My CLI application").version("1.0.0");
|
|
446
|
+
|
|
447
|
+
program
|
|
448
|
+
.command("build")
|
|
449
|
+
.description("Build the project")
|
|
450
|
+
.option("-p, --production", "Build for production")
|
|
451
|
+
.action((options) => {
|
|
452
|
+
console.log("Building...", options.production);
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
program.parse();
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
#### Cerebro Equivalent
|
|
459
|
+
|
|
460
|
+
```typescript
|
|
461
|
+
import { createCerebro } from "@visulima/cerebro";
|
|
462
|
+
|
|
463
|
+
const cli = createCerebro("my-app", {
|
|
464
|
+
packageName: "my-app",
|
|
465
|
+
packageVersion: "1.0.0",
|
|
466
|
+
});
|
|
467
|
+
|
|
468
|
+
cli.addCommand({
|
|
469
|
+
description: "Build the project",
|
|
470
|
+
execute: ({ logger, options }) => {
|
|
471
|
+
logger.info("Building...", options.production);
|
|
472
|
+
},
|
|
473
|
+
name: "build",
|
|
474
|
+
options: [
|
|
475
|
+
{
|
|
476
|
+
alias: "p",
|
|
477
|
+
description: "Build for production",
|
|
478
|
+
name: "production",
|
|
479
|
+
type: Boolean,
|
|
480
|
+
},
|
|
481
|
+
],
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
await cli.run();
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
### From Yargs
|
|
488
|
+
|
|
489
|
+
Yargs uses a builder pattern. Here's how to migrate:
|
|
490
|
+
|
|
491
|
+
#### Yargs Example
|
|
492
|
+
|
|
493
|
+
```javascript
|
|
494
|
+
const yargs = require("yargs");
|
|
495
|
+
|
|
496
|
+
yargs
|
|
497
|
+
.command(
|
|
498
|
+
"deploy",
|
|
499
|
+
"Deploy the application",
|
|
500
|
+
(yargs) =>
|
|
501
|
+
yargs
|
|
502
|
+
.option("env", {
|
|
503
|
+
alias: "e",
|
|
504
|
+
demandOption: true,
|
|
505
|
+
description: "Environment",
|
|
506
|
+
type: "string",
|
|
507
|
+
})
|
|
508
|
+
.option("force", {
|
|
509
|
+
alias: "f",
|
|
510
|
+
description: "Force deployment",
|
|
511
|
+
type: "boolean",
|
|
512
|
+
}),
|
|
513
|
+
(argv) => {
|
|
514
|
+
console.log("Deploying to", argv.env);
|
|
515
|
+
},
|
|
516
|
+
)
|
|
517
|
+
.help().argv;
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
#### Cerebro Equivalent
|
|
521
|
+
|
|
522
|
+
```typescript
|
|
523
|
+
import { createCerebro } from "@visulima/cerebro";
|
|
524
|
+
|
|
525
|
+
const cli = createCerebro("my-app");
|
|
526
|
+
|
|
527
|
+
cli.addCommand({
|
|
528
|
+
description: "Deploy the application",
|
|
529
|
+
execute: ({ logger, options }) => {
|
|
530
|
+
logger.info(`Deploying to ${options.env}`);
|
|
531
|
+
},
|
|
532
|
+
name: "deploy",
|
|
533
|
+
options: [
|
|
534
|
+
{
|
|
535
|
+
alias: "e",
|
|
536
|
+
description: "Environment",
|
|
537
|
+
name: "env",
|
|
538
|
+
required: true,
|
|
539
|
+
type: String,
|
|
540
|
+
},
|
|
541
|
+
{
|
|
542
|
+
alias: "f",
|
|
543
|
+
description: "Force deployment",
|
|
544
|
+
name: "force",
|
|
545
|
+
type: Boolean,
|
|
546
|
+
},
|
|
547
|
+
],
|
|
548
|
+
});
|
|
549
|
+
|
|
550
|
+
await cli.run();
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
### From Meow
|
|
554
|
+
|
|
555
|
+
Meow uses a simpler API. Here's how to migrate:
|
|
556
|
+
|
|
557
|
+
#### Meow Example
|
|
558
|
+
|
|
559
|
+
```javascript
|
|
560
|
+
const meow = require("meow");
|
|
561
|
+
|
|
562
|
+
const cli = meow(
|
|
563
|
+
`
|
|
564
|
+
Usage
|
|
565
|
+
$ my-app <input>
|
|
566
|
+
|
|
567
|
+
Options
|
|
568
|
+
--production, -p Build for production
|
|
569
|
+
|
|
570
|
+
Examples
|
|
571
|
+
$ my-app build --production
|
|
572
|
+
`,
|
|
573
|
+
{
|
|
574
|
+
flags: {
|
|
575
|
+
production: {
|
|
576
|
+
alias: "p",
|
|
577
|
+
type: "boolean",
|
|
578
|
+
},
|
|
579
|
+
},
|
|
580
|
+
},
|
|
581
|
+
);
|
|
582
|
+
|
|
583
|
+
console.log(cli.input, cli.flags);
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
#### Cerebro Equivalent
|
|
587
|
+
|
|
588
|
+
```typescript
|
|
589
|
+
import { createCerebro } from "@visulima/cerebro";
|
|
590
|
+
|
|
591
|
+
const cli = createCerebro("my-app");
|
|
592
|
+
|
|
593
|
+
cli.setCommandSection({
|
|
594
|
+
footer: "Examples:\n $ my-app build --production",
|
|
595
|
+
header: "My CLI Application",
|
|
596
|
+
});
|
|
597
|
+
|
|
598
|
+
cli.addCommand({
|
|
599
|
+
argument: {
|
|
600
|
+
name: "input",
|
|
601
|
+
type: String,
|
|
602
|
+
},
|
|
603
|
+
execute: ({ argument, logger, options }) => {
|
|
604
|
+
logger.info("Input:", argument[0]);
|
|
605
|
+
logger.info("Production:", options.production);
|
|
606
|
+
},
|
|
607
|
+
name: "build",
|
|
608
|
+
options: [
|
|
609
|
+
{
|
|
610
|
+
alias: "p",
|
|
611
|
+
description: "Build for production",
|
|
612
|
+
name: "production",
|
|
613
|
+
type: Boolean,
|
|
614
|
+
},
|
|
615
|
+
],
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
await cli.run();
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
## New Features in Recent Versions
|
|
622
|
+
|
|
623
|
+
### Global Options (v2.0.0+)
|
|
624
|
+
|
|
625
|
+
Register options that are available to every command using `addGlobalOption()`. Global options are parsed alongside command-specific options and displayed in the help output:
|
|
626
|
+
|
|
627
|
+
```typescript
|
|
628
|
+
const cli = createCerebro("my-app");
|
|
629
|
+
|
|
630
|
+
// Add a global --cwd option available to all commands
|
|
631
|
+
cli.addGlobalOption({
|
|
632
|
+
name: "cwd",
|
|
633
|
+
type: String,
|
|
634
|
+
description: "Override working directory",
|
|
635
|
+
});
|
|
636
|
+
|
|
637
|
+
// Global options are accessible in commands via toolbox.options
|
|
638
|
+
cli.addCommand({
|
|
639
|
+
name: "build",
|
|
640
|
+
execute: ({ options }) => {
|
|
641
|
+
const cwd = options.cwd as string | undefined;
|
|
642
|
+
// ...
|
|
643
|
+
},
|
|
644
|
+
});
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
**Notes:**
|
|
648
|
+
|
|
649
|
+
- Global options appear under "Global Options" in help output alongside built-in options
|
|
650
|
+
- Cannot override built-in options (`verbose`, `debug`, `help`, `quiet`, `version`, `no-color`, `color`)
|
|
651
|
+
- Use `getGlobalOptions()` to retrieve all global options (built-in + custom)
|
|
652
|
+
|
|
653
|
+
### Programmatic Command Execution (v1.1.0+)
|
|
654
|
+
|
|
655
|
+
The `runCommand` method allows commands to call other commands programmatically:
|
|
656
|
+
|
|
657
|
+
```typescript
|
|
658
|
+
cli.addCommand({
|
|
659
|
+
execute: async ({ logger, runtime }) => {
|
|
660
|
+
logger.info("Building...");
|
|
661
|
+
await runtime.runCommand("build", {
|
|
662
|
+
argv: ["--production"],
|
|
663
|
+
});
|
|
664
|
+
|
|
665
|
+
logger.info("Testing...");
|
|
666
|
+
await runtime.runCommand("test", {
|
|
667
|
+
argv: ["--coverage"],
|
|
668
|
+
});
|
|
669
|
+
|
|
670
|
+
logger.info("Deploying...");
|
|
671
|
+
},
|
|
672
|
+
name: "deploy",
|
|
673
|
+
});
|
|
674
|
+
```
|
|
675
|
+
|
|
676
|
+
### Enhanced Error Handling
|
|
677
|
+
|
|
678
|
+
Error handling plugins provide structured error reporting:
|
|
679
|
+
|
|
680
|
+
```typescript
|
|
681
|
+
import { errorHandlerPlugin } from "@visulima/cerebro/plugins/error-handler";
|
|
682
|
+
|
|
683
|
+
cli.addPlugin(
|
|
684
|
+
errorHandlerPlugin({
|
|
685
|
+
detailed: true,
|
|
686
|
+
useCriticalLevel: false,
|
|
687
|
+
}),
|
|
688
|
+
);
|
|
689
|
+
```
|
|
690
|
+
|
|
691
|
+
### Runtime Version Checking
|
|
692
|
+
|
|
693
|
+
Automatic runtime version checking:
|
|
694
|
+
|
|
695
|
+
```typescript
|
|
696
|
+
import { runtimeVersionCheckPlugin } from "@visulima/cerebro/plugins/runtime-version-check";
|
|
697
|
+
|
|
698
|
+
cli.addPlugin(
|
|
699
|
+
runtimeVersionCheckPlugin({
|
|
700
|
+
runtimes: {
|
|
701
|
+
bun: { minVersion: 1 },
|
|
702
|
+
node: { minVersion: 20 },
|
|
703
|
+
},
|
|
704
|
+
}),
|
|
705
|
+
);
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
## Migration Benefits
|
|
709
|
+
|
|
710
|
+
### ESM Migration Benefits
|
|
711
|
+
|
|
712
|
+
- **Better Performance**: ESM's improved module caching in Node.js 20.19+, native ESM support in Deno and Bun
|
|
713
|
+
- **Cross-Runtime Support**: Works seamlessly across Node.js, Deno, and Bun
|
|
714
|
+
- **Modern JavaScript**: Consistent module syntax across environments
|
|
715
|
+
- **Bundle Optimization**: Better tree-shaking and dead code elimination
|
|
716
|
+
- **Developer Experience**: Improved IDE support and error messages
|
|
717
|
+
- **Future-Proof**: Aligned with JavaScript ecosystem direction
|
|
718
|
+
|
|
719
|
+
### Granular Import Benefits
|
|
720
|
+
|
|
721
|
+
- **Smaller bundle sizes**: Only import what you need
|
|
722
|
+
- **Better tree-shaking**: Unused code is excluded from bundles
|
|
723
|
+
- **Clearer dependencies**: Explicit imports make dependencies obvious
|
|
724
|
+
- **Improved performance**: Reduced bundle size and faster loading
|
|
725
|
+
|
|
726
|
+
### Enhanced API Benefits
|
|
727
|
+
|
|
728
|
+
- **Type Safety**: Full TypeScript support with proper types
|
|
729
|
+
- **Extensibility**: Plugin system for adding functionality
|
|
730
|
+
- **Composability**: Commands can call other commands
|
|
731
|
+
- **Error Handling**: Structured error handling with helpful messages
|
|
732
|
+
- **Validation**: Built-in validation for options and arguments
|