Skip to content

Commit d10ef81

Browse files
authored
fix: lint (#28)
* fix: lint * fix: types
1 parent 32c2f66 commit d10ef81

File tree

7 files changed

+16
-138
lines changed

7 files changed

+16
-138
lines changed

bin/completion-handlers.ts

Lines changed: 0 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,5 @@
11
// TODO: i do not see any completion functionality in this file. nothing is being provided for the defined commands of these package managers. this is a blocker for release. every each of them should be handled.
22
import { Completion } from '../src/index.js';
3-
import { execSync } from 'child_process';
4-
5-
const DEBUG = false; // for debugging purposes
6-
7-
function debugLog(...args: any[]) {
8-
if (DEBUG) {
9-
console.error('[DEBUG]', ...args);
10-
}
11-
}
12-
13-
async function checkCliHasCompletions(
14-
cliName: string,
15-
packageManager: string
16-
): Promise<boolean> {
17-
try {
18-
debugLog(`Checking if ${cliName} has completions via ${packageManager}`);
19-
const command = `${packageManager} ${cliName} complete --`;
20-
const result = execSync(command, {
21-
encoding: 'utf8',
22-
stdio: ['pipe', 'pipe', 'ignore'],
23-
timeout: 1000, // AMIR: we still havin issues with this, it still hangs if a cli doesn't have completions. longer timeout needed for shell completion system (shell → node → package manager → cli)
24-
});
25-
const hasCompletions = !!result.trim();
26-
debugLog(`${cliName} supports completions: ${hasCompletions}`);
27-
return hasCompletions;
28-
} catch (error) {
29-
debugLog(`Error checking completions for ${cliName}:`, error);
30-
return false;
31-
}
32-
}
33-
34-
async function getCliCompletions(
35-
cliName: string,
36-
packageManager: string,
37-
args: string[]
38-
): Promise<string[]> {
39-
try {
40-
const completeArgs = args.map((arg) =>
41-
arg.includes(' ') ? `"${arg}"` : arg
42-
);
43-
const completeCommand = `${packageManager} ${cliName} complete -- ${completeArgs.join(' ')}`;
44-
debugLog(`Getting completions with command: ${completeCommand}`);
45-
46-
const result = execSync(completeCommand, {
47-
encoding: 'utf8',
48-
stdio: ['pipe', 'pipe', 'ignore'],
49-
timeout: 1000, // same: longer timeout needed for shell completion system (shell → node → package manager → cli)
50-
});
51-
52-
const completions = result.trim().split('\n').filter(Boolean);
53-
debugLog(`Got ${completions.length} completions from ${cliName}`);
54-
return completions;
55-
} catch (error) {
56-
debugLog(`Error getting completions from ${cliName}:`, error);
57-
return [];
58-
}
59-
}
603

614
export function setupCompletionForPackageManager(
625
packageManager: string,

examples/demo.cac.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import cac from 'cac';
22
import tab from '../src/cac';
3-
import type { Command, Option, OptionsMap } from '../src/t';
3+
import type { Option, OptionsMap } from '../src/t';
44

55
const cli = cac('vite');
66

examples/demo.t.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,7 @@ t.command('dev build', 'Build project');
9696
t.command('dev start', 'Start development server');
9797

9898
// Copy command with multiple arguments
99-
const copyCmd = t
100-
.command('copy', 'Copy files')
99+
t.command('copy', 'Copy files')
101100
.argument('source', function (complete) {
102101
complete('src/', 'Source directory');
103102
complete('dist/', 'Distribution directory');
@@ -110,7 +109,7 @@ const copyCmd = t
110109
});
111110

112111
// Lint command with variadic arguments
113-
const lintCmd = t.command('lint', 'Lint project').argument(
112+
t.command('lint', 'Lint project').argument(
114113
'files',
115114
function (complete) {
116115
complete('main.ts', 'Main file');

src/cac.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import * as powershell from './powershell';
55
import type { CAC } from 'cac';
66
import { assertDoubleDashes } from './shared';
77
import { CompletionConfig } from './shared';
8-
import t from './t';
8+
import t, { RootCommand } from './t';
99

1010
const execPath = process.execPath;
1111
const processArgs = process.argv.slice(1);
@@ -22,7 +22,7 @@ function quoteIfNeeded(path: string): string {
2222
export default async function tab(
2323
instance: CAC,
2424
completionConfig?: CompletionConfig
25-
): Promise<any> {
25+
): Promise<RootCommand> {
2626
// Add all commands and their options
2727
for (const cmd of [instance.globalCommand, ...instance.commands]) {
2828
if (cmd.name === 'complete') continue; // Skip completion command

src/citty.ts

Lines changed: 2 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ import type {
1111
} from 'citty';
1212
import { generateFigSpec } from './fig';
1313
import { CompletionConfig, assertDoubleDashes } from './shared';
14-
import { OptionHandler, Command, Option, OptionsMap } from './t';
15-
import t from './t';
14+
import t, { RootCommand } from './t';
1615

1716
function quoteIfNeeded(path: string) {
1817
return path.includes(' ') ? `'${path}'` : path;
@@ -32,59 +31,6 @@ function isConfigPositional<T extends ArgsDef>(config: CommandDef<T>) {
3231
);
3332
}
3433

35-
// Convert Handler from index.ts to OptionHandler from t.ts
36-
function convertOptionHandler(handler: any): OptionHandler {
37-
return function (
38-
this: Option,
39-
complete: (value: string, description: string) => void,
40-
options: OptionsMap,
41-
previousArgs?: string[],
42-
toComplete?: string,
43-
endsWithSpace?: boolean
44-
) {
45-
// For short flags with equals sign and a value, don't complete (citty behavior)
46-
// Check if this is a short flag option and if the toComplete looks like a value
47-
if (
48-
this.alias &&
49-
toComplete &&
50-
toComplete !== '' &&
51-
!toComplete.startsWith('-')
52-
) {
53-
// This might be a short flag with equals sign and a value
54-
// Check if the previous args contain a short flag with equals sign
55-
if (previousArgs && previousArgs.length > 0) {
56-
const lastArg = previousArgs[previousArgs.length - 1];
57-
if (lastArg.includes('=')) {
58-
const [flag, value] = lastArg.split('=');
59-
if (flag.startsWith('-') && !flag.startsWith('--') && value !== '') {
60-
return; // Don't complete short flags with equals sign and value
61-
}
62-
}
63-
}
64-
}
65-
66-
// Call the old handler with the proper context
67-
const result = handler(
68-
previousArgs || [],
69-
toComplete || '',
70-
endsWithSpace || false
71-
);
72-
73-
if (Array.isArray(result)) {
74-
result.forEach((item: any) =>
75-
complete(item.value, item.description || '')
76-
);
77-
} else if (result && typeof result.then === 'function') {
78-
// Handle async handlers
79-
result.then((items: any[]) => {
80-
items.forEach((item: any) =>
81-
complete(item.value, item.description || '')
82-
);
83-
});
84-
}
85-
};
86-
}
87-
8834
async function handleSubCommands(
8935
subCommands: SubCommandsDef,
9036
parentCmd?: string,
@@ -169,7 +115,7 @@ async function handleSubCommands(
169115
export default async function tab<TArgs extends ArgsDef>(
170116
instance: CommandDef<TArgs>,
171117
completionConfig?: CompletionConfig
172-
): Promise<any> {
118+
): Promise<RootCommand> {
173119
const meta = await resolve(instance.meta);
174120

175121
if (!meta) {

src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { Completion as CompletionItem } from './t';
77

88
const DEBUG = false;
99

10-
function debugLog(...args: any[]) {
10+
function debugLog(...args: unknown[]) {
1111
if (DEBUG) {
1212
console.error('[DEBUG]', ...args);
1313
}

src/t.ts

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -88,16 +88,7 @@ export class Command {
8888
this.description = description;
8989
}
9090

91-
// Function overloads for better UX
92-
option(value: string, description: string): Command;
93-
option(value: string, description: string, alias: string): Command;
94-
option(value: string, description: string, handler: OptionHandler): Command;
95-
option(
96-
value: string,
97-
description: string,
98-
handler: OptionHandler,
99-
alias: string
100-
): Command;
91+
// Function overloads for better UX - combined into single signature with optional parameters
10192
option(
10293
value: string,
10394
description: string,
@@ -211,22 +202,23 @@ export class RootCommand extends Command {
211202
args = this.stripOptions(args);
212203
const parts: string[] = [];
213204
let remaining: string[] = [];
214-
let matched: Command = this;
205+
let matchedCommand: Command | null = null;
215206

216207
for (let i = 0; i < args.length; i++) {
217208
const k = args[i];
218209
parts.push(k);
219210
const potential = this.commands.get(parts.join(' '));
220211

221212
if (potential) {
222-
matched = potential;
213+
matchedCommand = potential;
223214
} else {
224215
remaining = args.slice(i, args.length);
225216
break;
226217
}
227218
}
228219

229-
return [matched, remaining];
220+
// If no command was matched, use the root command (this)
221+
return [matchedCommand || this, remaining];
230222
}
231223

232224
// Determine if we should complete flags
@@ -282,12 +274,10 @@ export class RootCommand extends Command {
282274
) {
283275
// Handle flag value completion
284276
let optionName: string | undefined;
285-
let valueToComplete = toComplete;
286277

287278
if (toComplete.includes('=')) {
288-
const [flag, value] = toComplete.split('=');
279+
const [flag] = toComplete.split('=');
289280
optionName = flag;
290-
valueToComplete = value || '';
291281
} else if (lastPrevArg?.startsWith('-')) {
292282
optionName = lastPrevArg;
293283
}
@@ -350,7 +340,7 @@ export class RootCommand extends Command {
350340
if (option) return option;
351341

352342
// Try by short alias
353-
for (const [name, opt] of command.options) {
343+
for (const [_name, opt] of command.options) {
354344
if (opt.alias && `-${opt.alias}` === optionName) {
355345
return opt;
356346
}
@@ -399,7 +389,7 @@ export class RootCommand extends Command {
399389

400390
if (currentArgIndex < argumentEntries.length) {
401391
// We're within the defined arguments
402-
const [argName, argument] = argumentEntries[currentArgIndex];
392+
const [_argName, argument] = argumentEntries[currentArgIndex];
403393
targetArgument = argument;
404394
} else {
405395
// We're beyond the defined arguments, check if the last argument is variadic

0 commit comments

Comments
 (0)