| import * as path from "node:path"; | |
| /** Return a forward-slash relative path when `candidate` is inside `root`. */ | |
| export function relativeFsPath(root: string, candidate: string): string | undefined { | |
| const paths = isWindowsPath(root) || isWindowsPath(candidate) ? path.win32 : path; | |
| const relativePath = paths.relative(paths.resolve(root), paths.resolve(candidate)); | |
| if ( | |
| relativePath === "" || | |
| (!relativePath.startsWith(`..${paths.sep}`) && relativePath !== ".." && !paths.isAbsolute(relativePath)) | |
| ) { | |
| return relativePath.split(paths.sep).join("/"); | |
| } | |
| return undefined; | |
| } | |
| /** Whether two native filesystem paths identify the same location. */ | |
| export function areSameFsPath(left: string, right: string): boolean { | |
| return relativeFsPath(left, right) === ""; | |
| } | |
| /** Whether `candidate` is `root` or a descendant using native path rules. */ | |
| export function isFsPathInsideOrEqual(root: string, candidate: string): boolean { | |
| return relativeFsPath(root, candidate) !== undefined; | |
| } | |
| function isWindowsPath(value: string): boolean { | |
| return /^[A-Za-z]:[\\/]/.test(value) || /^[\\/]{2}[^\\/]+[\\/][^\\/]+/.test(value); | |
| } | |