Files
tolaria/src/utils/vaultPathContainment.ts
2026-05-13 10:29:22 +02:00

43 lines
1.7 KiB
TypeScript

function normalizeVaultContainmentPath(path: string): string {
return path.replace(/\\/g, '/').replace(/\/+$/, '')
}
function tildeRootSuffix(path: string): string | null {
if (path === '~') return ''
return path.startsWith('~/') ? path.slice(1) : null
}
function expandTildeRootFromTarget(targetPath: string, rootPath: string): string {
const suffix = tildeRootSuffix(rootPath)
if (suffix === null || suffix === '') return rootPath
const suffixIndex = targetPath.indexOf(suffix)
return suffixIndex > 0 ? `${targetPath.slice(0, suffixIndex)}${suffix}` : rootPath
}
function compareVaultContainmentPath(path: string, vaultPath: string): [string, string] {
const normalizedPath = normalizeVaultContainmentPath(path)
const normalizedVaultPath = expandTildeRootFromTarget(
normalizedPath,
normalizeVaultContainmentPath(vaultPath),
)
const hasWindowsDrive = /^[a-z]:/i.test(normalizedPath) || /^[a-z]:/i.test(normalizedVaultPath)
return hasWindowsDrive
? [normalizedPath.toLowerCase(), normalizedVaultPath.toLowerCase()]
: [normalizedPath, normalizedVaultPath]
}
export function isPathInsideVaultRoot(path: string, vaultPath: string): boolean {
const trimmedVaultPath = vaultPath.trim()
if (!trimmedVaultPath) return true
const [targetPath, rootPath] = compareVaultContainmentPath(path, trimmedVaultPath)
if (!rootPath || !targetPath) return false
return targetPath === rootPath || targetPath.startsWith(`${rootPath}/`)
}
export function canWritePathToVault(path: string, vaultPath: string | readonly string[]): boolean {
if (typeof vaultPath !== 'string') {
return vaultPath.some((candidate) => canWritePathToVault(path, candidate))
}
return isPathInsideVaultRoot(path, vaultPath)
}