Skip to content

Commit f806955

Browse files
committed
init
1 parent 07acf01 commit f806955

File tree

4 files changed

+152
-4
lines changed

4 files changed

+152
-4
lines changed

bin/cli.ts

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
#!/usr/bin/env node
2+
3+
import cac from 'cac';
4+
import { script, Completion } from '../src/index.js';
5+
import tab from '../src/cac.js';
6+
7+
import {
8+
setupCompletionForPackageManager
9+
} from './completion-handlers';
10+
11+
const packageManagers = ['npm', 'pnpm', 'yarn', 'bun'];
12+
const shells = ['zsh', 'bash', 'fish', 'powershell'];
13+
14+
const cli = cac('tab');
15+
16+
cli.command('<packageManager> complete', 'Process completion requests from shell')
17+
.allowUnknownOptions()
18+
.action(async (packageManager) => {
19+
if (!packageManagers.includes(packageManager)) {
20+
console.error(`Error: Unsupported package manager "${packageManager}"`);
21+
console.error(`Supported package managers: ${packageManagers.join(', ')}`);
22+
process.exit(1);
23+
}
24+
25+
const dashIndex = process.argv.indexOf('--');
26+
if (dashIndex !== -1) {
27+
const completion = new Completion();
28+
setupCompletionForPackageManager(packageManager, completion);
29+
const toComplete = process.argv.slice(dashIndex + 1);
30+
await completion.parse(toComplete);
31+
process.exit(0);
32+
} else {
33+
console.error(`Error: Expected '--' followed by command to complete`);
34+
console.error(`Example: npx @bombsh/tab ${packageManager} complete -- command-to-complete`);
35+
process.exit(1);
36+
}
37+
});
38+
39+
cli.command('<packageManager> <shell>', 'Generate shell completion script for a package manager')
40+
.action(async (packageManager, shell) => {
41+
if (shell === 'complete') {
42+
const dashIndex = process.argv.indexOf('--');
43+
if (dashIndex !== -1) {
44+
const completion = new Completion();
45+
setupCompletionForPackageManager(packageManager, completion);
46+
const toComplete = process.argv.slice(dashIndex + 1);
47+
await completion.parse(toComplete);
48+
process.exit(0);
49+
} else {
50+
console.error(`Error: Expected '--' followed by command to complete`);
51+
console.error(`Example: npx @bombsh/tab ${packageManager} complete -- command-to-complete`);
52+
process.exit(1);
53+
}
54+
return;
55+
}
56+
57+
if (!packageManagers.includes(packageManager)) {
58+
console.error(`Error: Unsupported package manager "${packageManager}"`);
59+
console.error(`Supported package managers: ${packageManagers.join(', ')}`);
60+
process.exit(1);
61+
}
62+
63+
if (!shells.includes(shell)) {
64+
console.error(`Error: Unsupported shell "${shell}"`);
65+
console.error(`Supported shells: ${shells.join(', ')}`);
66+
process.exit(1);
67+
}
68+
69+
generateCompletionScript(packageManager, shell);
70+
});
71+
72+
const completion = tab(cli);
73+
74+
cli.parse();
75+
76+
function generateCompletionScript(packageManager: string, shell: string) {
77+
const name = packageManager;
78+
const executable = process.env.npm_execpath ?
79+
`${packageManager} exec @bombsh/tab ${packageManager}` :
80+
`node ${process.argv[1]} ${packageManager}`;
81+
script(shell as any, name, executable);
82+
}

bin/completion-handlers.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { Completion } from '../src/index.js';
2+
3+
export function setupCompletionForPackageManager(packageManager: string, completion: Completion) {
4+
if (packageManager === 'pnpm') {
5+
setupPnpmCompletions(completion);
6+
} else if (packageManager === 'npm') {
7+
setupNpmCompletions(completion);
8+
} else if (packageManager === 'yarn') {
9+
setupYarnCompletions(completion);
10+
} else if (packageManager === 'bun') {
11+
setupBunCompletions(completion);
12+
}
13+
}
14+
15+
export function setupPnpmCompletions(completion: Completion) {
16+
completion.addCommand('add', 'Install a package', [], async () => []);
17+
completion.addCommand('remove', 'Remove a package', [], async () => []);
18+
completion.addCommand('install', 'Install all dependencies', [], async () => []);
19+
completion.addCommand('update', 'Update packages', [], async () => []);
20+
completion.addCommand('exec', 'Execute a command', [], async () => []);
21+
completion.addCommand('run', 'Run a script', [], async () => []);
22+
completion.addCommand('publish', 'Publish package', [], async () => []);
23+
completion.addCommand('test', 'Run tests', [], async () => []);
24+
completion.addCommand('build', 'Build project', [], async () => []);
25+
}
26+
27+
export function setupNpmCompletions(completion: Completion) {
28+
completion.addCommand('install', 'Install a package', [], async () => []);
29+
completion.addCommand('uninstall', 'Uninstall a package', [], async () => []);
30+
completion.addCommand('run', 'Run a script', [], async () => []);
31+
completion.addCommand('test', 'Run tests', [], async () => []);
32+
completion.addCommand('publish', 'Publish package', [], async () => []);
33+
completion.addCommand('update', 'Update packages', [], async () => []);
34+
completion.addCommand('start', 'Start the application', [], async () => []);
35+
completion.addCommand('build', 'Build project', [], async () => []);
36+
}
37+
38+
export function setupYarnCompletions(completion: Completion) {
39+
completion.addCommand('add', 'Add a package', [], async () => []);
40+
completion.addCommand('remove', 'Remove a package', [], async () => []);
41+
completion.addCommand('run', 'Run a script', [], async () => []);
42+
completion.addCommand('test', 'Run tests', [], async () => []);
43+
completion.addCommand('publish', 'Publish package', [], async () => []);
44+
completion.addCommand('install', 'Install dependencies', [], async () => []);
45+
completion.addCommand('build', 'Build project', [], async () => []);
46+
}
47+
48+
export function setupBunCompletions(completion: Completion) {
49+
completion.addCommand('add', 'Add a package', [], async () => []);
50+
completion.addCommand('remove', 'Remove a package', [], async () => []);
51+
completion.addCommand('run', 'Run a script', [], async () => []);
52+
completion.addCommand('test', 'Run tests', [], async () => []);
53+
completion.addCommand('install', 'Install dependencies', [], async () => []);
54+
completion.addCommand('update', 'Update packages', [], async () => []);
55+
completion.addCommand('build', 'Build project', [], async () => []);
56+
}

package.json

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
11
{
2-
"name": "tab",
2+
"name": "@bombsh/tab",
33
"version": "0.0.0",
4-
"description": "",
54
"main": "./dist/index.js",
65
"types": "./dist/index.d.ts",
76
"type": "module",
7+
"bin": {
8+
"tab": "./dist/bin/cli.js"
9+
},
810
"scripts": {
911
"test": "vitest",
1012
"type-check": "tsc --noEmit",
1113
"format": "prettier --write .",
1214
"format:check": "prettier --check .",
1315
"build": "tsdown",
1416
"prepare": "pnpm build",
15-
"lint": "eslint src \"./*.ts\""
17+
"lint": "eslint src \"./*.ts\"",
18+
"test-cli": "tsx bin/cli.ts"
1619
},
1720
"files": [
1821
"dist"

tsdown.config.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
import { defineConfig } from 'tsdown';
22

33
export default defineConfig({
4-
entry: ['src/index.ts', 'src/citty.ts', 'src/cac.ts', 'src/commander.ts'],
4+
entry: [
5+
'src/index.ts',
6+
'src/citty.ts',
7+
'src/cac.ts',
8+
'src/commander.ts',
9+
'bin/cli.ts',
10+
'bin/completion-handlers.ts'
11+
],
512
format: ['esm'],
613
dts: true,
714
clean: true,

0 commit comments

Comments
 (0)