Skip to content

Commit 5355263

Browse files
chore: wip
1 parent 146e617 commit 5355263

File tree

10 files changed

+87
-51
lines changed

10 files changed

+87
-51
lines changed

packages/ts/benchmarks/cli-performance.bench.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,23 @@
44
* Run with: bun test benchmarks/cli-performance.bench.ts
55
*/
66

7-
import { bench, describe } from 'bun:test'
8-
import { cli } from '../src/CLI'
7+
import { describe, it } from 'bun:test'
98
import { cliCache } from '../src/cache'
9+
import { cli } from '../src/CLI'
1010

1111
describe('CLI Performance', () => {
12-
bench('CLI instantiation', () => {
13-
const testCli = cli('test')
12+
it('CLI instantiation', () => {
13+
cli('test')
1414
})
1515

16-
bench('Command registration (10 commands)', () => {
16+
it('Command registration (10 commands)', () => {
1717
const testCli = cli('test')
1818
for (let i = 0; i < 10; i++) {
1919
testCli.command(`cmd${i}`, `Description ${i}`)
2020
}
2121
})
2222

23-
bench('Command registration with options (10 commands)', () => {
23+
it('Command registration with options (10 commands)', () => {
2424
const testCli = cli('test')
2525
for (let i = 0; i < 10; i++) {
2626
testCli
@@ -30,7 +30,7 @@ describe('CLI Performance', () => {
3030
}
3131
})
3232

33-
bench('Help text generation', () => {
33+
it('Help text generation', () => {
3434
const testCli = cli('test')
3535
testCli.command('test', 'Test command')
3636
testCli.help()
@@ -42,13 +42,13 @@ describe('CLI Performance', () => {
4242
})
4343

4444
describe('Cache Performance', () => {
45-
bench('Cache set (1000 items)', () => {
45+
it('Cache set (1000 items)', () => {
4646
for (let i = 0; i < 1000; i++) {
4747
cliCache.set(`key${i}`, `value${i}`, 5000)
4848
}
4949
})
5050

51-
bench('Cache get (1000 items)', () => {
51+
it('Cache get (1000 items)', () => {
5252
// Pre-populate
5353
for (let i = 0; i < 1000; i++) {
5454
cliCache.set(`key${i}`, `value${i}`, 5000)
@@ -60,7 +60,7 @@ describe('Cache Performance', () => {
6060
}
6161
})
6262

63-
bench('Cache has (1000 items)', () => {
63+
it('Cache has (1000 items)', () => {
6464
// Pre-populate
6565
for (let i = 0; i < 1000; i++) {
6666
cliCache.set(`key${i}`, `value${i}`, 5000)
@@ -72,7 +72,7 @@ describe('Cache Performance', () => {
7272
}
7373
})
7474

75-
bench('Cache cleanup (1000 items)', () => {
75+
it('Cache cleanup (1000 items)', () => {
7676
// Pre-populate with expired items
7777
for (let i = 0; i < 1000; i++) {
7878
cliCache.set(`key${i}`, `value${i}`, 1) // 1ms TTL
@@ -87,7 +87,7 @@ describe('Cache Performance', () => {
8787
})
8888

8989
describe('Namespace Extraction', () => {
90-
bench('Namespace extraction (1000 commands)', () => {
90+
it('Namespace extraction (1000 commands)', () => {
9191
const testCli = cli('test')
9292
for (let i = 0; i < 1000; i++) {
9393
// This will trigger namespace extraction
@@ -97,14 +97,14 @@ describe('Namespace Extraction', () => {
9797
})
9898

9999
describe('Argument Parsing', () => {
100-
bench('Parse simple args (no options)', () => {
100+
it('Parse simple args (no options)', () => {
101101
const testCli = cli('test')
102102
testCli.command('test <arg1> <arg2>', 'Test command')
103103
.action(() => {})
104104
testCli.parse(['node', 'cli', 'test', 'value1', 'value2'], { run: false })
105105
})
106106

107-
bench('Parse args with multiple options', () => {
107+
it('Parse args with multiple options', () => {
108108
const testCli = cli('test')
109109
testCli.command('test <arg>', 'Test command')
110110
.option('-f, --flag', 'Flag')

packages/ts/src/CLI.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import type { CommandConfig, CommandExample, HelpCallback } from './Command'
22
import type { OptionConfig } from './Option'
33
import { EventEmitter } from 'node:events'
4+
import process from 'node:process'
45
import mri from 'mri'
56
import Command, { GlobalCommand } from './Command'
67
import { processArgs } from './runtimes/node'
7-
import { camelcaseOptionName, findSimilarCommands, getFileName, getMriOptions, setByType, setDotProp } from './utils'
88
import { style } from './style'
9+
import { camelcaseOptionName, findSimilarCommands, getFileName, getMriOptions, setByType, setDotProp } from './utils'
910

1011
interface ParsedArgv {
1112
args: ReadonlyArray<string>
@@ -37,7 +38,7 @@ export class CLI extends EventEmitter {
3738
showHelpOnExit?: boolean
3839
showVersionOnExit?: boolean
3940
enableDidYouMean = true
40-
private signalHandlersSet = false
41+
signalHandlersSet = false
4142

4243
/** Whether verbose mode is enabled */
4344
isVerbose = false
@@ -93,6 +94,7 @@ export class CLI extends EventEmitter {
9394
}
9495

9596
const handleSignal = async (signal: string) => {
97+
// eslint-disable-next-line no-console
9698
console.log(`\n\nReceived ${signal}, cleaning up...`)
9799

98100
if (cleanup) {
@@ -334,6 +336,7 @@ export class CLI extends EventEmitter {
334336
* Show "did you mean?" error for unknown commands
335337
*/
336338
showCommandNotFound(input: string): void {
339+
// eslint-disable-next-line no-console
337340
console.log(style.red(`\n✗ Command "${input}" not found.\n`))
338341

339342
if (this.enableDidYouMean) {
@@ -350,12 +353,16 @@ export class CLI extends EventEmitter {
350353

351354
const suggestions = findSimilarCommands(input, allCommandNames)
352355
if (suggestions.length > 0) {
356+
// eslint-disable-next-line no-console
353357
console.log(style.yellow('Did you mean one of these?'))
358+
// eslint-disable-next-line no-console
354359
suggestions.forEach(cmd => console.log(` ${style.dim('•')} ${this.name} ${cmd}`))
360+
// eslint-disable-next-line no-console
355361
console.log('')
356362
}
357363
}
358364

365+
// eslint-disable-next-line no-console
359366
console.log(style.dim('Run'), `${this.name} --help`, style.dim('to see all available commands'))
360367
process.exit(1)
361368
}

packages/ts/src/Command.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -363,11 +363,11 @@ export class Command {
363363
if (this.cli.args.length < minimalArgsCount) {
364364
const requiredArgs = this.args.filter(arg => arg.required)
365365
const missingArgs = requiredArgs.slice(this.cli.args.length)
366-
const argNames = missingArgs.map(arg => `<${arg.name}>`).join(' ')
366+
const argNames = missingArgs.map(arg => `<${arg.value}>`).join(' ')
367367

368368
throw new ClappError(
369-
`Missing required argument${missingArgs.length > 1 ? 's' : ''}: ${argNames}\n\n` +
370-
`Run \`${this.cli.name} ${this.rawName} --help\` for usage information.`,
369+
`Missing required argument${missingArgs.length > 1 ? 's' : ''}: ${argNames}\n\n`
370+
+ `Run \`${this.cli.name} ${this.rawName} --help\` for usage information.`,
371371
)
372372
}
373373
}
@@ -427,8 +427,8 @@ export class Command {
427427
)
428428
if (value === true || (value === false && !hasNegated)) {
429429
throw new ClappError(
430-
`Option \`${option.rawName}\` requires a value.\n\n` +
431-
`Example: ${this.cli.name} ${this.rawName} ${option.rawName} <value>`,
430+
`Option \`${option.rawName}\` requires a value.\n\n`
431+
+ `Example: ${this.cli.name} ${this.rawName} ${option.rawName} <value>`,
432432
)
433433
}
434434
}

packages/ts/src/cache.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ class CLICache {
141141
}
142142

143143
// Global cache instance
144-
export const cliCache = new CLICache()
144+
export const cliCache: CLICache = new CLICache()
145145

146146
// Auto cleanup every 30 seconds
147147
setInterval(() => {

packages/ts/src/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import { cli } from './CLI'
22

3+
export * from './cache'
34
export * from './CLI'
45
export * from './Command'
56
export * from './Option'
6-
7-
export * from './cache'
87
export * from './prompts'
98
export * from './style'
109
export * from './telemetry'

packages/ts/src/prompts/path.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ export function path(opts: PathOptions): Promise<string | symbol> {
7272
value: item.path,
7373
}))
7474
}
75-
catch {
75+
catch (error) {
76+
console.error('Error reading directory:', error)
7677
return []
7778
}
7879
},

packages/ts/src/telemetry.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { existsSync } from 'node:fs'
1111
import fs from 'node:fs/promises'
1212
import os from 'node:os'
1313
import path from 'node:path'
14+
import process from 'node:process'
1415

1516
export interface TelemetryEvent {
1617
event: string
@@ -155,6 +156,7 @@ class Telemetry {
155156
}
156157
catch (error) {
157158
// Silently fail - telemetry should never break the CLI
159+
console.error('Error sending telemetry:', error)
158160
this.events = []
159161
}
160162
}
@@ -195,6 +197,7 @@ class Telemetry {
195197
}
196198
catch (error) {
197199
// Ignore errors
200+
console.error('Error loading telemetry config:', error)
198201
}
199202

200203
// Default config (disabled by default)
@@ -221,11 +224,12 @@ class Telemetry {
221224
await fs.writeFile(
222225
this.configPath,
223226
JSON.stringify(config, null, 2),
224-
'utf-8'
227+
'utf-8',
225228
)
226229
}
227230
catch (error) {
228231
// Ignore errors
232+
console.error('Error saving telemetry config:', error)
229233
}
230234
}
231235

@@ -240,4 +244,4 @@ class Telemetry {
240244
}
241245

242246
// Global telemetry instance
243-
export const telemetry = new Telemetry()
247+
export const telemetry: Telemetry = new Telemetry()

packages/ts/test/did-you-mean.test.ts

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,28 +19,32 @@ describe('Did You Mean Suggestions', () => {
1919

2020
// Mock console.log to capture output
2121
const logs: string[] = []
22+
// eslint-disable-next-line no-console
2223
const originalLog = console.log
2324
const originalExit = process.exit
2425

26+
// eslint-disable-next-line no-console
2527
console.log = (...args: any[]) => {
2628
logs.push(args.join(' '))
2729
}
2830

2931
let exitCode: number | undefined
30-
// @ts-expect-error - mocking process.exit
3132
process.exit = (code?: number) => {
3233
exitCode = code
3334
throw new Error('process.exit called')
3435
}
3536

3637
try {
3738
await app.parse(['node', 'test', 'buil'], { run: true })
38-
} catch (e: any) {
39+
}
40+
catch (e: any) {
3941
// Expected to throw due to mocked process.exit
4042
if (e.message !== 'process.exit called') {
4143
throw e
4244
}
43-
} finally {
45+
}
46+
finally {
47+
// eslint-disable-next-line no-console
4448
console.log = originalLog
4549
process.exit = originalExit
4650
}
@@ -64,25 +68,29 @@ describe('Did You Mean Suggestions', () => {
6468
.action(() => {})
6569

6670
const logs: string[] = []
71+
// eslint-disable-next-line no-console
6772
const originalLog = console.log
6873
const originalExit = process.exit
6974

75+
// eslint-disable-next-line no-console
7076
console.log = (...args: any[]) => {
7177
logs.push(args.join(' '))
7278
}
7379

74-
// @ts-expect-error - mocking process.exit
7580
process.exit = () => {
7681
throw new Error('process.exit called')
7782
}
7883

7984
try {
8085
await app.parse(['node', 'test', 'xyz123'], { run: true })
81-
} catch (e: any) {
86+
}
87+
catch (e: any) {
8288
if (e.message !== 'process.exit called') {
8389
throw e
8490
}
85-
} finally {
91+
}
92+
finally {
93+
// eslint-disable-next-line no-console
8694
console.log = originalLog
8795
process.exit = originalExit
8896
}
@@ -101,25 +109,29 @@ describe('Did You Mean Suggestions', () => {
101109
.action(() => {})
102110

103111
const logs: string[] = []
112+
// eslint-disable-next-line no-console
104113
const originalLog = console.log
105114
const originalExit = process.exit
106115

116+
// eslint-disable-next-line no-console
107117
console.log = (...args: any[]) => {
108118
logs.push(args.join(' '))
109119
}
110120

111-
// @ts-expect-error - mocking process.exit
112121
process.exit = () => {
113122
throw new Error('process.exit called')
114123
}
115124

116125
try {
117126
await app.parse(['node', 'test', 'buil'], { run: true })
118-
} catch (e: any) {
127+
}
128+
catch (e: any) {
119129
if (e.message !== 'process.exit called') {
120130
throw e
121131
}
122-
} finally {
132+
}
133+
finally {
134+
// eslint-disable-next-line no-console
123135
console.log = originalLog
124136
process.exit = originalExit
125137
}
@@ -138,25 +150,29 @@ describe('Did You Mean Suggestions', () => {
138150
.action(() => {})
139151

140152
const logs: string[] = []
153+
// eslint-disable-next-line no-console
141154
const originalLog = console.log
142155
const originalExit = process.exit
143156

157+
// eslint-disable-next-line no-console
144158
console.log = (...args: any[]) => {
145159
logs.push(args.join(' '))
146160
}
147161

148-
// @ts-expect-error - mocking process.exit
149162
process.exit = () => {
150163
throw new Error('process.exit called')
151164
}
152165

153166
try {
154167
await app.parse(['node', 'test-app', 'ts'], { run: true })
155-
} catch (e: any) {
168+
}
169+
catch (e: any) {
156170
if (e.message !== 'process.exit called') {
157171
throw e
158172
}
159-
} finally {
173+
}
174+
finally {
175+
// eslint-disable-next-line no-console
160176
console.log = originalLog
161177
process.exit = originalExit
162178
}

0 commit comments

Comments
 (0)