Skip to content

Commit ee6898f

Browse files
Copilotfranky47
andauthored
test: Add comprehensive CLI interface testing with action objects (#10)
Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: franky47 <[email protected]>
1 parent 01ecb76 commit ee6898f

4 files changed

Lines changed: 344 additions & 84 deletions

File tree

packages/mtsv/src/cli.ts

Lines changed: 55 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
#!/usr/bin/env node
2-
import { Command } from 'commander'
32
import { readdirSync, readFileSync, statSync } from 'node:fs'
43
import { join, resolve } from 'node:path'
54
import type { InputSources } from './lib/input-sources.ts'
65
import { BinarySearchSequencer } from './lib/sequencers.ts'
76
import { fetchTypeScriptVersions } from './lib/services.ts'
87
import { TypeScriptCDNCache } from './lib/typescript-cache.ts'
98
import { testAgainstTypeScriptVersion } from './lib/typescript.ts'
9+
import type { CacheActions, RootActions } from './lib/cli-actions.ts'
10+
import { createCacheCommand, createRootCommand } from './lib/cli-factories.ts'
1011

1112
function collectSources(path: string): InputSources {
1213
const abs = resolve(path)
@@ -54,98 +55,68 @@ async function checkSources(sources: InputSources, verbose: boolean) {
5455
console.log(`Minimum TypeScript version: ${best}`)
5556
}
5657

57-
async function handleRootCommand(targets: string[], options: { verbose?: boolean; dependencies?: boolean }) {
58-
console.log('mtsv: Root command called')
59-
console.log('Targets:', targets.length > 0 ? targets : ['current working directory'])
60-
console.log('Options:', options)
58+
// Action implementations
59+
const rootActions: RootActions = {
60+
async onTargets(targets: string[], options: { verbose?: boolean; dependencies?: boolean }, command) {
61+
console.log('mtsv: Root command called')
62+
console.log('Targets:', targets.length > 0 ? targets : ['current working directory'])
63+
console.log('Options:', options)
6164

62-
if (options.dependencies) {
63-
console.log('Would check node_modules for dependencies\' mtsv')
64-
return
65-
}
65+
if (options.dependencies) {
66+
console.log('Would check node_modules for dependencies\' mtsv')
67+
return
68+
}
6669

67-
// Handle different types of targets
68-
for (const target of targets.length > 0 ? targets : ['.']) {
69-
if (target.startsWith('npm:')) {
70-
console.log(`Would check NPM package: ${target}`)
71-
} else if (target.startsWith('jsr:')) {
72-
console.log(`Would check JSR package: ${target}`)
73-
} else if (target.startsWith('https://')) {
74-
console.log(`Would check tarball URL: ${target}`)
75-
} else if (target.endsWith('package.json')) {
76-
console.log(`Would check package.json exports: ${target}`)
77-
} else {
78-
// File or directory - use existing functionality
79-
try {
80-
const sources = collectSources(target)
81-
await checkSources(sources, options.verbose || false)
82-
} catch (error) {
83-
console.error(`Error processing ${target}:`, error instanceof Error ? error.message : error)
70+
// Handle different types of targets
71+
for (const target of targets.length > 0 ? targets : ['.']) {
72+
if (target.startsWith('npm:')) {
73+
console.log(`Would check NPM package: ${target}`)
74+
} else if (target.startsWith('jsr:')) {
75+
console.log(`Would check JSR package: ${target}`)
76+
} else if (target.startsWith('https://')) {
77+
console.log(`Would check tarball URL: ${target}`)
78+
} else if (target.endsWith('package.json')) {
79+
console.log(`Would check package.json exports: ${target}`)
80+
} else {
81+
// File or directory - use existing functionality
82+
try {
83+
const sources = collectSources(target)
84+
await checkSources(sources, options.verbose || false)
85+
} catch (error) {
86+
console.error(`Error processing ${target}:`, error instanceof Error ? error.message : error)
87+
}
8488
}
8589
}
8690
}
8791
}
8892

89-
function handleCacheCommand() {
90-
console.log('Cache contents:')
91-
console.log('v1.2.3')
92-
console.log('v4.5.6')
93-
}
94-
95-
function handleCachePathCommand() {
96-
console.log('/tmp/mtsv-cache')
97-
}
98-
99-
function handleCachePruneCommand() {
100-
console.log('v1.2.3 deleted')
101-
console.log('v4.5.6 deleted')
102-
}
103-
104-
function handleCacheDeleteCommand(version: string) {
105-
if (version.includes('.')) {
106-
// Specific version or partial version
107-
console.log(`${version.startsWith('v') ? '' : 'v'}${version} deleted`)
108-
} else {
109-
// Major version - delete all matching
110-
console.log(`All ${version}.x.x versions deleted`)
93+
const cacheActions: CacheActions = {
94+
async onRoot(options, command) {
95+
console.log('Cache contents:')
96+
console.log('v1.2.3')
97+
console.log('v4.5.6')
98+
},
99+
async onPath(options, command) {
100+
console.log('/tmp/mtsv-cache')
101+
},
102+
async onPrune(options, command) {
103+
console.log('v1.2.3 deleted')
104+
console.log('v4.5.6 deleted')
105+
},
106+
async onDelete(version: string, options, command) {
107+
if (version.includes('.')) {
108+
// Specific version or partial version
109+
console.log(`${version.startsWith('v') ? '' : 'v'}${version} deleted`)
110+
} else {
111+
// Major version - delete all matching
112+
console.log(`All ${version}.x.x versions deleted`)
113+
}
111114
}
112115
}
113116

114-
const program = new Command()
115-
116-
program
117-
.name('mtsv')
118-
.description('Find the Minimum TypeScript Version needed to compile a project')
119-
.version('0.0.0')
120-
121-
// Root command
122-
program
123-
.argument('[targets...]', 'Files, directories, or packages to check')
124-
.option('-v, --verbose', 'Enable verbose output')
125-
.option('-d, --dependencies', 'Check node_modules for dependencies\' mtsv')
126-
.action(handleRootCommand)
127-
128-
// Cache command
129-
const cacheCommand = program
130-
.command('cache')
131-
.description('Manage TypeScript version cache')
132-
133-
cacheCommand
134-
.action(handleCacheCommand)
135-
136-
cacheCommand
137-
.command('path')
138-
.description('Print the current path of the cache')
139-
.action(handleCachePathCommand)
140-
141-
cacheCommand
142-
.command('prune')
143-
.description('Delete all cached TypeScript versions')
144-
.action(handleCachePruneCommand)
145-
146-
cacheCommand
147-
.command('delete <version>')
148-
.description('Delete specific TypeScript version(s) from cache')
149-
.action(handleCacheDeleteCommand)
117+
// Create and configure the CLI
118+
const program = createRootCommand(rootActions)
119+
const cacheCommand = createCacheCommand(cacheActions)
120+
program.addCommand(cacheCommand)
150121

151122
program.parse()
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* Action interfaces for CLI commands
3+
* These define the handlers that will be called for different CLI operations
4+
*/
5+
6+
import type { Command } from 'commander'
7+
8+
export interface RootActions {
9+
onTargets(
10+
targets: string[],
11+
options: { verbose?: boolean; dependencies?: boolean },
12+
command: Command
13+
): Promise<void>
14+
}
15+
16+
export interface CacheActions {
17+
onRoot(options: object, command: Command): Promise<void>
18+
onPath(options: object, command: Command): Promise<void>
19+
onPrune(options: object, command: Command): Promise<void>
20+
onDelete(version: string, options: object, command: Command): Promise<void>
21+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { Command } from 'commander'
2+
import type { CacheActions, RootActions } from './cli-actions.js'
3+
4+
/**
5+
* Creates the root command with the provided actions
6+
*/
7+
export function createRootCommand(actions: RootActions): Command {
8+
const program = new Command()
9+
10+
program
11+
.name('mtsv')
12+
.description(
13+
'Find the Minimum TypeScript Version needed to compile a project'
14+
)
15+
.version('0.0.0')
16+
17+
// Root command
18+
program
19+
.argument('[targets...]', 'Files, directories, or packages to check')
20+
.option('-v, --verbose', 'Enable verbose output')
21+
.option('-d, --dependencies', "Check node_modules for dependencies' mtsv")
22+
.action(actions.onTargets)
23+
24+
return program
25+
}
26+
27+
/**
28+
* Creates the cache command with the provided actions
29+
*/
30+
export function createCacheCommand(actions: CacheActions): Command {
31+
const cacheCommand = new Command('cache').description(
32+
'Manage TypeScript version cache'
33+
)
34+
35+
cacheCommand.action(actions.onRoot)
36+
37+
cacheCommand
38+
.command('path')
39+
.description('Print the current path of the cache')
40+
.action(actions.onPath)
41+
42+
cacheCommand
43+
.command('prune')
44+
.description('Delete all cached TypeScript versions')
45+
.action(actions.onPrune)
46+
47+
cacheCommand
48+
.command('delete <version>')
49+
.description('Delete specific TypeScript version(s) from cache')
50+
.action(actions.onDelete)
51+
52+
return cacheCommand
53+
}

0 commit comments

Comments
 (0)