Skip to content

Commit 727bb53

Browse files
committed
apply suggestions from @43081j review
1 parent 4c078f5 commit 727bb53

File tree

3 files changed

+123
-109
lines changed

3 files changed

+123
-109
lines changed

examples/demo.citty.ts

Lines changed: 95 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { defineCommand, createMain } from 'citty';
1+
import { defineCommand, createMain, CommandDef, ArgsDef } from 'citty';
22
import tab from '../src/citty';
33

44
const main = defineCommand({
@@ -24,108 +24,109 @@ const main = defineCommand({
2424
alias: 'l',
2525
},
2626
},
27-
subCommands: {
28-
dev: defineCommand({
29-
meta: {
30-
name: 'dev',
31-
description: 'Start dev server',
32-
},
33-
args: {
34-
host: {
35-
type: 'string',
36-
description: 'Specify hostname',
37-
alias: 'H',
38-
},
39-
port: {
40-
type: 'string',
41-
description: 'Specify port',
42-
alias: 'p',
43-
},
44-
},
45-
run: () => {},
46-
}),
47-
build: defineCommand({
48-
meta: {
49-
name: 'build',
50-
description: 'Build project',
51-
},
52-
run: () => {},
53-
}),
54-
lint: defineCommand({
55-
meta: {
56-
name: 'lint',
57-
description: 'Lint project',
58-
},
59-
args: {
60-
files: {
61-
type: 'positional',
62-
description: 'Files to lint',
63-
required: false,
64-
},
65-
},
66-
run: () => {},
67-
}),
27+
run: () => {},
28+
});
29+
30+
const devCommand = defineCommand({
31+
meta: {
32+
name: 'dev',
33+
description: 'Start dev server',
34+
},
35+
args: {
36+
host: {
37+
type: 'string',
38+
description: 'Specify hostname',
39+
alias: 'H',
40+
},
41+
port: {
42+
type: 'string',
43+
description: 'Specify port',
44+
alias: 'p',
45+
},
6846
},
6947
run: () => {},
7048
});
7149

72-
const completion = await tab(main);
50+
const buildCommand = defineCommand({
51+
meta: {
52+
name: 'build',
53+
description: 'Build project',
54+
},
55+
run: () => {},
56+
});
7357

74-
for (const command of completion.commands.values()) {
75-
if (command.name === 'lint') {
76-
command.handler = () => {
77-
return [
78-
{ value: 'main.ts', description: 'Main file' },
79-
{ value: 'index.ts', description: 'Index file' },
80-
];
81-
};
82-
}
58+
const lintCommand = defineCommand({
59+
meta: {
60+
name: 'lint',
61+
description: 'Lint project',
62+
},
63+
args: {
64+
files: {
65+
type: 'positional',
66+
description: 'Files to lint',
67+
required: false,
68+
},
69+
},
70+
run: () => {},
71+
});
8372

84-
for (const [o, config] of command.options.entries()) {
85-
if (o === '--port') {
86-
config.handler = () => {
87-
return [
88-
{ value: '3000', description: 'Development server port' },
89-
{ value: '8080', description: 'Alternative port' },
90-
];
91-
};
92-
}
93-
if (o === '--host') {
94-
config.handler = () => {
95-
return [
96-
{ value: 'localhost', description: 'Localhost' },
97-
{ value: '0.0.0.0', description: 'All interfaces' },
98-
];
99-
};
100-
}
101-
if (o === '--config') {
102-
config.handler = () => {
103-
return [
104-
{ value: 'vite.config.ts', description: 'Vite config file' },
105-
{ value: 'vite.config.js', description: 'Vite config file' },
106-
];
107-
};
108-
}
109-
if (o === '--mode') {
110-
config.handler = () => {
111-
return [
112-
{ value: 'development', description: 'Development mode' },
113-
{ value: 'production', description: 'Production mode' },
114-
];
115-
};
73+
main.subCommands = {
74+
dev: devCommand,
75+
build: buildCommand,
76+
lint: lintCommand,
77+
} as Record<string, CommandDef<ArgsDef>>;
78+
79+
// Use the config object approach for completions
80+
const completion = await tab(main, {
81+
// Root level options
82+
options: {
83+
config: {
84+
handler: () => [
85+
{ value: 'vite.config.ts', description: 'Vite config file' },
86+
{ value: 'vite.config.js', description: 'Vite config file' },
87+
]
88+
},
89+
mode: {
90+
handler: () => [
91+
{ value: 'development', description: 'Development mode' },
92+
{ value: 'production', description: 'Production mode' },
93+
]
94+
},
95+
logLevel: {
96+
handler: () => [
97+
{ value: 'info', description: 'Info level' },
98+
{ value: 'warn', description: 'Warn level' },
99+
{ value: 'error', description: 'Error level' },
100+
{ value: 'silent', description: 'Silent level' },
101+
]
116102
}
117-
if (o === '--logLevel') {
118-
config.handler = () => {
119-
return [
120-
{ value: 'info', description: 'Info level' },
121-
{ value: 'warn', description: 'Warn level' },
122-
{ value: 'error', description: 'Error level' },
123-
{ value: 'silent', description: 'Silent level' },
124-
];
125-
};
103+
},
104+
// Subcommands and their options
105+
subCommands: {
106+
lint: {
107+
handler: () => [
108+
{ value: 'main.ts', description: 'Main file' },
109+
{ value: 'index.ts', description: 'Index file' },
110+
]
111+
},
112+
dev: {
113+
options: {
114+
port: {
115+
handler: () => [
116+
{ value: '3000', description: 'Development server port' },
117+
{ value: '8080', description: 'Alternative port' },
118+
]
119+
},
120+
host: {
121+
handler: () => [
122+
{ value: 'localhost', description: 'Localhost' },
123+
{ value: '0.0.0.0', description: 'All interfaces' },
124+
]
125+
}
126+
}
126127
}
127128
}
128-
}
129+
});
129130

130131
// Create the CLI and run it
131132
const cli = createMain(main);

tests/__snapshots__/cli.test.ts.snap

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -108,17 +108,20 @@ lint Lint project
108108
`;
109109

110110
exports[`cli completion tests for citty > cli option completion tests > should complete option for partial input '{ partial: '--p', expected: '--port' }' 1`] = `
111-
":4
111+
"--port Specify port
112+
:4
112113
"
113114
`;
114115

115116
exports[`cli completion tests for citty > cli option completion tests > should complete option for partial input '{ partial: '-H', expected: '-H' }' 1`] = `
116-
":4
117+
"-H Specify hostname
118+
:4
117119
"
118120
`;
119121

120122
exports[`cli completion tests for citty > cli option completion tests > should complete option for partial input '{ partial: '-p', expected: '-p' }' 1`] = `
121-
":4
123+
"-p Specify port
124+
:4
122125
"
123126
`;
124127

@@ -145,22 +148,28 @@ vite.config.js Vite config file
145148
`;
146149

147150
exports[`cli completion tests for citty > cli option value handling > should resolve port value correctly 1`] = `
148-
":4
151+
"--port=3000 Development server port
152+
:4
149153
"
150154
`;
151155

152156
exports[`cli completion tests for citty > edge case completions for end with space > should keep suggesting the --port option if user typed partial but didn't end with space 1`] = `
153-
":4
157+
"--port Specify port
158+
:4
154159
"
155160
`;
156161

157162
exports[`cli completion tests for citty > edge case completions for end with space > should suggest port values if user ends with space after \`--port\` 1`] = `
158-
":4
163+
"3000 Development server port
164+
8080 Alternative port
165+
:4
159166
"
160167
`;
161168

162169
exports[`cli completion tests for citty > edge case completions for end with space > should suggest port values if user typed \`--port=\` and hasn't typed a space or value yet 1`] = `
163-
":4
170+
"--port=3000 Development server port
171+
--port=8080 Alternative port
172+
:4
164173
"
165174
`;
166175

@@ -170,7 +179,8 @@ exports[`cli completion tests for citty > short flag handling > should handle gl
170179
`;
171180

172181
exports[`cli completion tests for citty > short flag handling > should handle short flag value completion 1`] = `
173-
":4
182+
"-p Specify port
183+
:4
174184
"
175185
`;
176186

tests/cli.test.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ describe.each(cliTools)('cli completion tests for %s', (cliTool) => {
2525
? `pnpm tsx examples/demo.${cliTool}.ts complete`
2626
: `pnpm tsx examples/demo.${cliTool}.ts complete --`;
2727

28+
// Use 'dev' for citty and 'serve' for other tools
29+
const commandName = cliTool === 'citty' ? 'dev' : 'serve';
30+
2831
it.runIf(!shouldSkipTest)('should complete cli options', async () => {
2932
const output = await runCommand(`${commandPrefix}`);
3033
expect(output).toMatchSnapshot();
@@ -40,7 +43,7 @@ describe.each(cliTools)('cli completion tests for %s', (cliTool) => {
4043
test.each(optionTests)(
4144
"should complete option for partial input '%s'",
4245
async ({ partial }) => {
43-
const command = `${commandPrefix} serve ${partial}`;
46+
const command = `${commandPrefix} ${commandName} ${partial}`;
4447
const output = await runCommand(command);
4548
expect(output).toMatchSnapshot();
4649
}
@@ -64,7 +67,7 @@ describe.each(cliTools)('cli completion tests for %s', (cliTool) => {
6467

6568
describe.runIf(!shouldSkipTest)('cli option value handling', () => {
6669
it('should resolve port value correctly', async () => {
67-
const command = `${commandPrefix} serve --port=3`;
70+
const command = `${commandPrefix} ${commandName} --port=3`;
6871
const output = await runCommand(command);
6972
expect(output).toMatchSnapshot();
7073
});
@@ -92,19 +95,19 @@ describe.each(cliTools)('cli completion tests for %s', (cliTool) => {
9295
'edge case completions for end with space',
9396
() => {
9497
it('should suggest port values if user ends with space after `--port`', async () => {
95-
const command = `${commandPrefix} serve --port ""`;
98+
const command = `${commandPrefix} ${commandName} --port ""`;
9699
const output = await runCommand(command);
97100
expect(output).toMatchSnapshot();
98101
});
99102

100103
it("should keep suggesting the --port option if user typed partial but didn't end with space", async () => {
101-
const command = `${commandPrefix} serve --po`;
104+
const command = `${commandPrefix} ${commandName} --po`;
102105
const output = await runCommand(command);
103106
expect(output).toMatchSnapshot();
104107
});
105108

106109
it("should suggest port values if user typed `--port=` and hasn't typed a space or value yet", async () => {
107-
const command = `${commandPrefix} serve --port=`;
110+
const command = `${commandPrefix} ${commandName} --port=`;
108111
const output = await runCommand(command);
109112
expect(output).toMatchSnapshot();
110113
});
@@ -113,13 +116,13 @@ describe.each(cliTools)('cli completion tests for %s', (cliTool) => {
113116

114117
describe.runIf(!shouldSkipTest)('short flag handling', () => {
115118
it('should handle short flag value completion', async () => {
116-
const command = `${commandPrefix} serve -p `;
119+
const command = `${commandPrefix} ${commandName} -p `;
117120
const output = await runCommand(command);
118121
expect(output).toMatchSnapshot();
119122
});
120123

121124
it('should handle short flag with equals sign', async () => {
122-
const command = `${commandPrefix} serve -p=3`;
125+
const command = `${commandPrefix} ${commandName} -p=3`;
123126
const output = await runCommand(command);
124127
expect(output).toMatchSnapshot();
125128
});

0 commit comments

Comments
 (0)