Skip to content

Commit 72df3a8

Browse files
committed
clean npm handler
1 parent ee4a0eb commit 72df3a8

File tree

4 files changed

+117
-155
lines changed

4 files changed

+117
-155
lines changed

bin/handlers/bun-handler.ts

Lines changed: 16 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -9,57 +9,52 @@ import {
99
safeExec,
1010
safeExecSync,
1111
// createLogLevelHandler,
12-
} from '../utils/package-manager-base.js';
12+
} from '../utils/shared.js';
1313

14-
// regex patterns to avoid recompilation in loops
1514
const COMMANDS_SECTION_RE = /^Commands:\s*$/i;
1615
const FLAGS_SECTION_RE = /^Flags:\s*$/i;
1716
const SECTION_END_RE = /^(Examples|Full documentation|Learn more)/i;
1817
const COMMAND_VALIDATION_RE = /^[a-z][a-z0-9-]*$/;
1918
const BUN_OPTION_RE =
2019
/^\s*(?:-([a-zA-Z]),?\s*)?--([a-z][a-z0-9-]*)(?:=<[^>]+>)?\s+(.+)$/;
21-
// const NON_INDENTED_LINE_RE = /^\s/;
20+
const MAIN_COMMAND_RE = /^ ([a-z][a-z0-9-]*)\s+(.+)$/;
21+
const CONTINUATION_COMMAND_RE = /^\s{12,}([a-z][a-z0-9-]*)\s+(.+)$/;
22+
const EMPTY_LINE_FOLLOWED_BY_NON_COMMAND_RE = /^\s+[a-z]/;
23+
const DESCRIPTION_SPLIT_RE = /\s{2,}/;
24+
const CAPITAL_LETTER_START_RE = /^[A-Z]/;
2225

23-
// bun-specific completion handlers
2426
const bunOptionHandlers: OptionHandlers = {
25-
// Use common handlers
2627
...commonOptionHandlers,
2728

28-
// bun doesn't have traditional log levels, but has verbose/silent
2929
silent: function (complete) {
3030
complete('true', 'Enable silent mode');
3131
complete('false', 'Disable silent mode');
3232
},
3333

3434
backend: function (complete) {
35-
// From bun help: "clonefile" (default), "hardlink", "symlink", "copyfile"
3635
complete('clonefile', 'Clone files (default, fastest)');
3736
complete('hardlink', 'Use hard links');
3837
complete('symlink', 'Use symbolic links');
3938
complete('copyfile', 'Copy files');
4039
},
4140

4241
linker: function (complete) {
43-
// From bun help: "isolated" or "hoisted"
4442
complete('isolated', 'Isolated linker strategy');
4543
complete('hoisted', 'Hoisted linker strategy');
4644
},
4745

4846
omit: function (complete) {
49-
// From bun help: 'dev', 'optional', or 'peer'
5047
complete('dev', 'Omit devDependencies');
5148
complete('optional', 'Omit optionalDependencies');
5249
complete('peer', 'Omit peerDependencies');
5350
},
5451

5552
shell: function (complete) {
56-
// From bun help: 'bun' or 'system'
5753
complete('bun', 'Use Bun shell');
5854
complete('system', 'Use system shell');
5955
},
6056

6157
'unhandled-rejections': function (complete) {
62-
// From bun help: "strict", "throw", "warn", "none", or "warn-with-error-code"
6358
complete('strict', 'Strict unhandled rejection handling');
6459
complete('throw', 'Throw on unhandled rejections');
6560
complete('warn', 'Warn on unhandled rejections');
@@ -68,11 +63,9 @@ const bunOptionHandlers: OptionHandlers = {
6863
},
6964
};
7065

71-
// Parse bun help text to extract commands and their descriptions
7266
export function parseBunHelp(helpText: string): Record<string, string> {
7367
const helpLines = stripAnsiEscapes(helpText).split(/\r?\n/);
7468

75-
// Find "Commands:" section
7669
let startIndex = -1;
7770
for (let i = 0; i < helpLines.length; i++) {
7871
if (COMMANDS_SECTION_RE.test(helpLines[i].trim())) {
@@ -85,44 +78,35 @@ export function parseBunHelp(helpText: string): Record<string, string> {
8578

8679
const commands: Record<string, string> = {};
8780

88-
// Parse bun's unique command format
81+
// parse bun's unique command format
8982
for (let i = startIndex; i < helpLines.length; i++) {
9083
const line = helpLines[i];
9184

92-
// Stop when we hit Flags section or empty line followed by non-command content
85+
// stop when we hit Flags section or empty line followed by non-command content
9386
if (
9487
FLAGS_SECTION_RE.test(line.trim()) ||
9588
(line.trim() === '' &&
9689
i + 1 < helpLines.length &&
97-
!helpLines[i + 1].match(/^\s+[a-z]/))
90+
!helpLines[i + 1].match(EMPTY_LINE_FOLLOWED_BY_NON_COMMAND_RE))
9891
)
9992
break;
10093

10194
// Skip empty lines
10295
if (line.trim() === '') continue;
10396

104-
// Handle different bun command formats:
105-
// Format 1: " run ./my-script.ts Execute a file with Bun"
106-
// Format 2: " lint Run a package.json script" (continuation)
107-
// Format 3: " install Install dependencies for a package.json (bun i)"
108-
109-
// Try to match command at start of line (2 spaces)
110-
const mainCommandMatch = line.match(/^ ([a-z][a-z0-9-]*)\s+(.+)$/);
97+
const mainCommandMatch = line.match(MAIN_COMMAND_RE);
11198
if (mainCommandMatch) {
11299
const [, command, rest] = mainCommandMatch;
113100
if (COMMAND_VALIDATION_RE.test(command)) {
114-
// Extract description - find the last part that looks like a description
115-
// Split by multiple spaces and take the last part that contains letters
116-
const parts = rest.split(/\s{2,}/);
101+
const parts = rest.split(DESCRIPTION_SPLIT_RE);
117102
let description = parts[parts.length - 1];
118103

119-
// If the last part starts with a capital letter, it's likely the description
120-
if (description && /^[A-Z]/.test(description)) {
104+
// If the last part starts with capital letter, it's likely the description
105+
if (description && CAPITAL_LETTER_START_RE.test(description)) {
121106
commands[command] = description.trim();
122107
} else if (parts.length > 1) {
123-
// Otherwise, look for the first part that starts with a capital
124108
for (const part of parts) {
125-
if (/^[A-Z]/.test(part)) {
109+
if (CAPITAL_LETTER_START_RE.test(part)) {
126110
commands[command] = part.trim();
127111
break;
128112
}
@@ -131,8 +115,7 @@ export function parseBunHelp(helpText: string): Record<string, string> {
131115
}
132116
}
133117

134-
// Handle continuation lines (12+ spaces)
135-
const continuationMatch = line.match(/^\s{12,}([a-z][a-z0-9-]*)\s+(.+)$/);
118+
const continuationMatch = line.match(CONTINUATION_COMMAND_RE);
136119
if (continuationMatch) {
137120
const [, command, description] = continuationMatch;
138121
if (COMMAND_VALIDATION_RE.test(command)) {
@@ -144,7 +127,6 @@ export function parseBunHelp(helpText: string): Record<string, string> {
144127
return commands;
145128
}
146129

147-
// Get bun commands from the main help output
148130
export async function getBunCommandsFromMainHelp(): Promise<
149131
Record<string, string>
150132
> {
@@ -200,7 +182,7 @@ export function parseBunOptions(
200182
return optionsOut;
201183
}
202184

203-
// Load dynamic options synchronously when requested
185+
// load dynamic options synchronously when requested
204186
function loadBunOptionsSync(cmd: LazyCommand, command: string): void {
205187
const output = safeExecSync(`bun ${command} --help`);
206188
if (!output) return;

0 commit comments

Comments
 (0)