|
| 1 | +# Commander Fork Notice |
| 2 | + |
| 3 | +## What We Did |
| 4 | + |
| 5 | +We forked commander v3.0.2 and stripped it down from **1332 lines** to **744 lines** (~44% reduction). |
| 6 | + |
| 7 | +### Removed Features (~588 lines) |
| 8 | + |
| 9 | +1. **Subcommands** - `.command()` with action handlers |
| 10 | +2. **Git-style executable subcommands** - `executeSubCommand()`, child_process.spawn |
| 11 | +3. **Action handlers** - `.action()` method |
| 12 | +4. **Argument parsing** - `.arguments()`, `.parseExpectedArgs()` |
| 13 | +5. **Complex command hierarchy** - parent/child commands, aliases |
| 14 | +6. **Inspector port incrementing** - `incrementNodeInspectorPort()` |
| 15 | +7. **File existence checks** - `exists()` helper (only used for executables) |
| 16 | +8. **Command help** - `.commandHelp()`, `.prepareCommands()` |
| 17 | +9. **Variadic arguments** - `.variadicArgNotLast()` |
| 18 | +10. **Missing argument errors** - `.missingArgument()` (we don't use positional args) |
| 19 | + |
| 20 | +### Removed Dependencies |
| 21 | + |
| 22 | +- ❌ `child_process` (spawn) - only needed for executable subcommands |
| 23 | +- ❌ `fs` - only needed for checking executable file existence |
| 24 | +- ❌ `path.dirname` - only needed for finding executable paths |
| 25 | + |
| 26 | +### Kept Dependencies (Built-ins) |
| 27 | + |
| 28 | +- ✅ `events.EventEmitter` - needed for option parsing event system |
| 29 | +- ✅ `util.inherits` - needed to extend EventEmitter |
| 30 | +- ✅ `path.basename` - needed for guessing command name from argv[1] |
| 31 | + |
| 32 | +## What We Kept |
| 33 | + |
| 34 | +### Core Methods |
| 35 | + |
| 36 | +- `.version(str, flags?, description?)` - Auto-register version flag |
| 37 | +- `.description(str)` - Set command description |
| 38 | +- `.option(flags, description, fn?, defaultValue?)` - **THE MOST IMPORTANT METHOD** |
| 39 | +- `.parse(argv)` - Parse command-line arguments |
| 40 | +- `.opts()` - Get parsed options as object |
| 41 | +- `.usage(str?)` - Get/set usage string |
| 42 | +- `.name(str?)` - Get/set command name |
| 43 | +- `.allowUnknownOption(arg?)` - Allow unknown flags |
| 44 | +- `.help(cb?)` - Output help and exit |
| 45 | +- `.outputHelp(cb?)` - Output help without exiting |
| 46 | +- `.helpOption(flags, description)` - Customize help flags |
| 47 | + |
| 48 | +### Critical Behavior Preserved |
| 49 | + |
| 50 | +**The `--no-` prefix handling** - This is why we forked! |
| 51 | + |
| 52 | +```javascript |
| 53 | +.option('--no-dotfiles', 'Exclude dotfiles') |
| 54 | + |
| 55 | +// Without flag: program.dotfiles === true (implicit default!) |
| 56 | +// With --no-dotfiles: program.dotfiles === false |
| 57 | +``` |
| 58 | + |
| 59 | +In commander v9+, this requires explicit defaults. We're freezing v3 behavior. |
| 60 | + |
| 61 | +### Option Parsing Features |
| 62 | + |
| 63 | +- ✅ Short flags (`-d`) |
| 64 | +- ✅ Long flags (`--dir`) |
| 65 | +- ✅ Required arguments (`--dir <path>`) |
| 66 | +- ✅ Optional arguments (`--file [path]`) |
| 67 | +- ✅ Boolean flags (`--verbose`) |
| 68 | +- ✅ Negatable flags (`--no-dotfiles`) |
| 69 | +- ✅ Default values |
| 70 | +- ✅ Custom coercion functions |
| 71 | +- ✅ Argument normalization (`-abc` → `-a -b -c`) |
| 72 | +- ✅ Equal sign support (`--foo=bar` → `--foo bar`) |
| 73 | +- ✅ Concatenated short options (`-d80` → `-d 80`) |
| 74 | +- ✅ Argument terminator (`--`) |
| 75 | +- ✅ Property access (`program.dir` after parse) |
| 76 | + |
| 77 | +### Help System |
| 78 | + |
| 79 | +- ✅ Auto-generated `--help` output |
| 80 | +- ✅ Option listing with descriptions |
| 81 | +- ✅ Default value display |
| 82 | +- ✅ Custom help callback support |
| 83 | + |
| 84 | +## File Size Comparison |
| 85 | + |
| 86 | +| Version | Lines | Size | Change | |
| 87 | +|---------|-------|------|--------| |
| 88 | +| Original v3.0.2 | 1332 | 32KB | - | |
| 89 | +| Commander-fork | 744 | 17KB | **-47% lines, -47% size** | |
| 90 | + |
| 91 | +## Why We Forked |
| 92 | + |
| 93 | +Commander v4-v14 introduced many breaking changes: |
| 94 | + |
| 95 | +1. **v9.0.0** - Boolean option default values behavior changed |
| 96 | +2. **v9.0.0** - Option property names now match flag casing exactly |
| 97 | +3. **v9.0.0** - Excess arguments now error by default |
| 98 | +4. **v12.0.0** - Default export removed (must use named import) |
| 99 | + |
| 100 | +Each of these would break existing user scripts. Rather than force users to adapt, we froze v3.0.2 behavior permanently. |
| 101 | + |
| 102 | +## Maintenance Plan |
| 103 | + |
| 104 | +This fork is **FROZEN**. We will only update for: |
| 105 | + |
| 106 | +1. **Critical security vulnerabilities** |
| 107 | +2. **Bugs that affect angular-cli-ghpages** |
| 108 | +3. **Node.js compatibility issues** |
| 109 | + |
| 110 | +For any fixes: |
| 111 | +- Update `commander-fork/index.js` |
| 112 | +- Add test in `commander-fork/__tests__/` |
| 113 | +- Bump version: `3.0.2-fork.1` → `3.0.2-fork.2` |
| 114 | +- Document the fix here |
| 115 | + |
| 116 | +## Testing |
| 117 | + |
| 118 | +We maintain test coverage for our usage patterns: |
| 119 | + |
| 120 | +- ✅ All option types (boolean, required, optional, negatable) |
| 121 | +- ✅ Short and long flags |
| 122 | +- ✅ Default value handling |
| 123 | +- ✅ `--no-` prefix behavior (critical!) |
| 124 | +- ✅ Version flag |
| 125 | +- ✅ Help output |
| 126 | +- ✅ Property access after parsing |
| 127 | +- ✅ Unknown option errors |
| 128 | + |
| 129 | +## License |
| 130 | + |
| 131 | +MIT License - same as original commander.js |
| 132 | + |
| 133 | +Original work Copyright (c) 2011 TJ Holowaychuk |
| 134 | +Modified work Copyright (c) 2025 angular-cli-ghpages contributors |
| 135 | + |
| 136 | +See LICENSE file for full text. |
| 137 | + |
| 138 | +## Credits |
| 139 | + |
| 140 | +Huge thanks to TJ Holowaychuk and all commander.js contributors for creating this excellent library. This fork exists only to preserve specific v3 behavior for our narrow use case. |
| 141 | + |
| 142 | +Original project: https://github.com/tj/commander.js |
0 commit comments