Skip to content

Commit 22be69b

Browse files
committed
added a better incremental recursive rename fn
1 parent 8b66efb commit 22be69b

File tree

3 files changed

+79
-13
lines changed

3 files changed

+79
-13
lines changed

eslint.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export default [
1515
sourceType: 'module',
1616
},
1717
plugins: {
18-
import: pluginImport,
18+
1919

2020
'simple-import-sort': is,
2121
},

lib/process-one-file.js

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,16 @@
11
import fs from 'node:fs/promises'
22
import path from 'node:path'
3-
3+
import returnSafeFilepath from './return-safe-filepath.js'
44
import exists from './exists.js'
55

66
const processOneFile = async (fileObject, rename = true) => {
77
try {
8-
// !global.silent && console.log(`${f.old} -> ${f.new}`)
8+
99

1010
if (await exists(fileObject.new)) {
1111
if (rename === true) {
12-
//ambiguous !global.silent && console.log(`file will be renamed: ${fileObj.new}`)
13-
let index = 1
14-
let parsed = path.parse(fileObject.new)
15-
let newName = `${parsed.name}-${index}${parsed.ext}`
16-
while (await exists(path.join(parsed.dir, newName))) {
17-
index++
18-
newName = `${parsed.name}-${index}${parsed.ext}`
19-
}
20-
fileObject.new = path.resolve(path.join(parsed.dir, newName))
21-
await fs.rename(fileObject.old, fileObject.new)
12+
let newPath = await returnSafeFilepath(fileObject.new)
13+
await fs.rename(fileObject.old, newPath)
2214
} else {
2315
console.warn(
2416
`file already exists, doing nothing: ${fileObject.new}`

lib/return-safe-filepath.js

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import exists from "./exists.js"
2+
import fs from "node:fs/promises"
3+
import path from "node:path"
4+
5+
const isDirectoryWithCatch = async (destination) => {
6+
let isDir = false
7+
try {
8+
let ii = await fs.stat(destination)
9+
isDir = ii.isDirectory()
10+
} catch (error) {
11+
if (error.code === "ENOENT") {
12+
isDir = false
13+
} else {
14+
throw error
15+
}
16+
}
17+
return isDir
18+
}
19+
20+
21+
function getBasenameAndSuffix(str) {
22+
let theName
23+
let theSuffix = ""
24+
let theDashed = str.split("-")
25+
if (theDashed.length === 1) {
26+
theName = str
27+
return { name: theName, suffix: theSuffix }
28+
} else {
29+
let possibleSuffix = theDashed[theDashed.length - 1]
30+
let possibleSuffixNumber = parseInt(possibleSuffix)
31+
if (isNaN(possibleSuffixNumber)) {
32+
theName = str
33+
return { name: theName, suffix: theSuffix }
34+
} else {
35+
theName = theDashed.slice(0, -1).join("-")
36+
theSuffix = possibleSuffix
37+
return { basename: theName, suffix: theSuffix }
38+
}
39+
}
40+
}
41+
42+
const splitFileIntoThePartsINeed = (file, directory) => {
43+
let [originalBasename, extension] = file.split(".")
44+
let { basename, suffix } = getBasenameAndSuffix(originalBasename)
45+
return { basename, suffix, extension, directory }
46+
}
47+
48+
const returnSafeFilePath = async (destination) => {
49+
if (await isDirectoryWithCatch(destination)) {
50+
throw new Error("destination is a directory")
51+
}
52+
destination = path.resolve(destination)
53+
let file = path.basename(destination)
54+
let directory = path.dirname(destination)
55+
if ((await exists(destination)) === false) {
56+
return destination
57+
}
58+
59+
let { basename, suffix, extension } = splitFileIntoThePartsINeed(
60+
file,
61+
directory
62+
)
63+
64+
let count = suffix
65+
while ((await exists(destination)) === true) {
66+
let currentSuffix = `-${count}`
67+
file = `${basename}${currentSuffix}.${extension}`
68+
destination = path.join(directory, file)
69+
count++
70+
}
71+
return destination
72+
}
73+
74+
export default returnSafeFilePath

0 commit comments

Comments
 (0)