Skip to content

Commit ba6897e

Browse files
committed
feat: add fn remove command
1 parent bf5cd05 commit ba6897e

File tree

3 files changed

+136
-0
lines changed

3 files changed

+136
-0
lines changed

packages/radashi-helper/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,20 @@ pnpm radashi fn override number/sum
9797

9898
 
9999

100+
### `radashi fn remove [name]`
101+
102+
Remove the files for a custom function.
103+
104+
```sh
105+
# Interactive mode
106+
pnpm radashi fn remove
107+
108+
# Remove the files for "number/sum"
109+
pnpm radashi fn remove number/sum
110+
```
111+
112+
 
113+
100114
### `radashi pr import <pr-id>`
101115

102116
Copy the files for a Radashi “pull request” into your project.

packages/radashi-helper/src/cli.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,19 @@ app
8383
await addOverride(query ?? '', flags)
8484
})
8585

86+
fn.command('remove [funcPath]', 'Remove a function')
87+
.alias('rm')
88+
.alias('delete')
89+
.alias('del')
90+
.action(async (funcPath, flags) => {
91+
const { removeFunction } = await import('./fn-remove')
92+
await removeFunction({ ...flags, funcPath })
93+
94+
log.warn(
95+
'This command has only removed the files. It didn‘t edit the codebase or commit the changes.',
96+
)
97+
})
98+
8699
await execute(fn, app.rawArgs.slice(1))
87100
})
88101

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import { existsSync } from 'node:fs'
2+
import fs, { readdir, rm } from 'node:fs/promises'
3+
import { dirname, join, relative } from 'node:path'
4+
import { objectify } from 'radashi'
5+
import type { CommonOptions } from './cli/options'
6+
import { getEnv } from './env'
7+
import { cwdRelative } from './util/cwdRelative'
8+
import { debug } from './util/debug'
9+
import { EarlyExitError, RadashiError } from './util/error'
10+
import { findSources } from './util/findSources'
11+
import { log } from './util/log'
12+
import { projectFolders } from './util/projectFolders'
13+
import { prompt } from './util/prompt'
14+
15+
export interface RemoveFunctionOptions extends CommonOptions {
16+
/**
17+
* The function to be removed. You must include the group and function
18+
* name, separated by a slash.
19+
*
20+
* If not provided, the user will be prompted to select a function
21+
* to remove.
22+
*/
23+
funcPath?: string
24+
}
25+
26+
export async function removeFunction(options: RemoveFunctionOptions = {}) {
27+
const env = options.env ?? getEnv(options.dir)
28+
29+
let oldFuncPath = options.funcPath
30+
31+
if (!oldFuncPath) {
32+
const pathsInside = await findSources(env, ['src', 'overrides'])
33+
debug('pathsInside:', pathsInside)
34+
35+
const { src: sourceFuncs = [], overrides: overrideFuncs = [] } = objectify(
36+
Object.entries(pathsInside),
37+
([type]) => type,
38+
([type, sourcePaths]) => {
39+
const sourceRoot = join(
40+
type === 'src' ? env.root : env.overrideDir,
41+
'src',
42+
)
43+
return sourcePaths?.map(sourcePath =>
44+
relative(sourceRoot, sourcePath).replace(/\.ts$/, ''),
45+
)
46+
},
47+
)
48+
49+
debug('sourceFuncs:', sourceFuncs)
50+
debug('overrideFuncs:', overrideFuncs)
51+
52+
const selectedFunc = await prompt({
53+
type: 'autocomplete',
54+
name: 'selectedFunc',
55+
message: 'Select a function to remove:',
56+
choices: [...sourceFuncs, ...overrideFuncs].sort().map(funcPath => ({
57+
title: funcPath,
58+
value: funcPath,
59+
})),
60+
})
61+
62+
if (!selectedFunc) {
63+
throw new EarlyExitError('No function selected. Exiting...')
64+
}
65+
66+
oldFuncPath = selectedFunc
67+
}
68+
69+
const checkFile = (folderPrefix: string) =>
70+
existsSync(join(folderPrefix, oldFuncPath + '.ts'))
71+
72+
const folderPrefix = checkFile(join(env.root, 'src'))
73+
? env.root
74+
: checkFile(join(env.overrideDir, 'src'))
75+
? env.overrideDir
76+
: null
77+
78+
if (!folderPrefix) {
79+
throw new RadashiError(
80+
`Function ${oldFuncPath} was not found in ${env.root}/src or the overrides folder`,
81+
)
82+
}
83+
84+
const [oldGroup, oldFuncName] = oldFuncPath.split('/')
85+
86+
87+
for (const folder of projectFolders) {
88+
const prevPath = join(
89+
folderPrefix,
90+
folder.name,
91+
oldGroup,
92+
oldFuncName + folder.extension,
93+
)
94+
if (!existsSync(prevPath)) {
95+
continue
96+
}
97+
98+
99+
log(`Removing ${cwdRelative(prevPath)}`)
100+
await rm(prevPath)
101+
102+
// Remove the directory if it's empty after removing the file
103+
const prevDir = dirname(prevPath)
104+
if ((await readdir(prevDir)).length === 0) {
105+
log(`Removing empty directory: ${cwdRelative(prevDir)}`)
106+
await fs.rm(prevDir, { recursive: true })
107+
}
108+
}
109+
}

0 commit comments

Comments
 (0)