MCPcopy Create free account
hub / github.com/ZenNotes/zennotes / renameFolder

Function renameFolder

apps/desktop/src/main/vault.ts:3375–3440  ·  view source on GitHub ↗
(
  root: string,
  topFolder: NoteFolder,
  oldSubpath: string,
  newSubpath: string
)

Source from the content-addressed store, hash-verified

3373 * descendant, and refuses to touch the top-level folder.
3374 */
3375export async function renameFolder(
3376 root: string,
3377 topFolder: NoteFolder,
3378 oldSubpath: string,
3379 newSubpath: string
3380): Promise<string> {
3381 const oldClean = oldSubpath.replace(/^\/+|\/+$/g, '')
3382 const newClean = newSubpath.replace(/^\/+|\/+$/g, '')
3383 if (!oldClean) throw new Error('Cannot rename the top-level folder')
3384 if (!newClean) throw new Error('Target folder name is required')
3385
3386 const topRoot = await folderRoot(root, topFolder)
3387 const oldAbs = resolveSafe(topRoot, oldClean)
3388 const newAbs = resolveSafe(topRoot, newClean)
3389 if (newAbs === oldAbs) return newClean
3390
3391 const sep = path.sep
3392 if ((newAbs + sep).startsWith(oldAbs + sep)) {
3393 throw new Error('Cannot move a folder into itself')
3394 }
3395
3396 // Refuse to overwrite a different existing folder.
3397 // On case-insensitive filesystems (macOS), a case-only rename
3398 // (e.g. "Work" → "work") is fine — same underlying directory.
3399 try {
3400 await fs.access(newAbs)
3401 // Check if old and new are the same file (case-only rename)
3402 const [oldStat, newStat] = await Promise.all([fs.stat(oldAbs), fs.stat(newAbs)])
3403 if (oldStat.ino !== newStat.ino) {
3404 throw new Error(`A folder already exists at "${newClean}"`)
3405 }
3406 } catch (e) {
3407 if ((e as NodeJS.ErrnoException).code !== 'ENOENT') throw e
3408 }
3409
3410 await fs.mkdir(path.dirname(newAbs), { recursive: true })
3411 // On case-insensitive filesystems, a direct rename('AI','ai') may
3412 // not change the case. Use a two-step rename via a temp name.
3413 if (oldAbs.toLowerCase() === newAbs.toLowerCase() && oldAbs !== newAbs) {
3414 const tmpAbs = oldAbs + '_rename_tmp_' + Date.now()
3415 await fs.rename(oldAbs, tmpAbs)
3416 await fs.rename(tmpAbs, newAbs)
3417 } else {
3418 await fs.rename(oldAbs, newAbs)
3419 }
3420 const settings = await getVaultSettings(root)
3421 const nextSettings: VaultSettings = {
3422 ...settings,
3423 folderIcons: rewriteFolderIconsForRename(
3424 settings.folderIcons,
3425 topFolder,
3426 oldClean,
3427 newClean
3428 ),
3429 folderColors: rewriteFolderColorsForRename(
3430 settings.folderColors,
3431 topFolder,
3432 oldClean,

Callers 3

vault.test.tsFile · 0.90
registerIpcFunction · 0.90
cmdFolderRenameFunction · 0.50

Calls 8

invalidateNoteMetaCacheFunction · 0.85
folderRootFunction · 0.70
resolveSafeFunction · 0.70
getVaultSettingsFunction · 0.70
setVaultSettingsFunction · 0.70

Tested by

no test coverage detected