( root: string, topFolder: NoteFolder, subpath: string )
| 3469 | * the leaf name. |
| 3470 | */ |
| 3471 | export async function duplicateFolder( |
| 3472 | root: string, |
| 3473 | topFolder: NoteFolder, |
| 3474 | subpath: string |
| 3475 | ): Promise<string> { |
| 3476 | const clean = subpath.replace(/^\/+|\/+$/g, '') |
| 3477 | if (!clean) throw new Error('Cannot duplicate the top-level folder') |
| 3478 | const topRoot = await folderRoot(root, topFolder) |
| 3479 | const oldAbs = resolveSafe(topRoot, clean) |
| 3480 | const parentAbs = path.dirname(oldAbs) |
| 3481 | const baseName = path.basename(oldAbs) |
| 3482 | let copyName = `${baseName} copy` |
| 3483 | let n = 1 |
| 3484 | while (true) { |
| 3485 | try { |
| 3486 | await fs.access(path.join(parentAbs, copyName)) |
| 3487 | n += 1 |
| 3488 | copyName = `${baseName} copy ${n}` |
| 3489 | } catch { |
| 3490 | break |
| 3491 | } |
| 3492 | } |
| 3493 | const newAbs = path.join(parentAbs, copyName) |
| 3494 | await fs.cp(oldAbs, newAbs, { recursive: true }) |
| 3495 | const newSubpath = path.relative(topRoot, newAbs).split(path.sep).join('/') |
| 3496 | const settings = await getVaultSettings(root) |
| 3497 | const nextSettings: VaultSettings = { |
| 3498 | ...settings, |
| 3499 | folderIcons: duplicateFolderIcons(settings.folderIcons, topFolder, clean, newSubpath) |
| 3500 | } |
| 3501 | await setVaultSettings(root, nextSettings) |
| 3502 | invalidateNoteMetaCache(root) |
| 3503 | invalidateVaultTextSearchCache(root) |
| 3504 | return newSubpath |
| 3505 | } |
| 3506 | |
| 3507 | /** Build the absolute on-disk path for a vault folder / subfolder. */ |
| 3508 | export function folderAbsolutePath( |
no test coverage detected