function appendExtension(path, extension) { return path + "." + extension; } function appendForwardSlash(path) { return path.endsWith("/") ? path : path + "/"; } function prependForwardSlash(path) { return path[0] === "/" ? path : "/" + path; } function collapseDuplicateSlashes(path) { return path.replace(/(? { if (i === 0) { return removeTrailingForwardSlash(path); } else if (i === paths.length - 1) { return removeLeadingForwardSlash(path); } else { return trimSlashes(path); } }).join("/"); } function removeFileExtension(path) { let idx = path.lastIndexOf("."); return idx === -1 ? path : path.slice(0, idx); } function removeQueryString(path) { const index = path.lastIndexOf("?"); return index > 0 ? path.substring(0, index) : path; } function isRemotePath(src) { if (!src) return false; const trimmed = src.trim(); if (!trimmed) return false; let decoded = trimmed; let previousDecoded = ""; let maxIterations = 10; while (decoded !== previousDecoded && maxIterations > 0) { previousDecoded = decoded; try { decoded = decodeURIComponent(decoded); } catch { break; } maxIterations--; } if (/^[a-zA-Z]:/.test(decoded)) { return false; } if (decoded[0] === "/" && decoded[1] !== "/" && decoded[1] !== "\\") { return false; } if (decoded[0] === "\\") { return true; } if (decoded.startsWith("//")) { return true; } try { const url = new URL(decoded, "http://n"); if (url.username || url.password) { return true; } if (decoded.includes("@") && !url.pathname.includes("@") && !url.search.includes("@")) { return true; } if (url.origin !== "http://n") { const protocol = url.protocol.toLowerCase(); if (protocol === "file:") { return false; } return true; } if (URL.canParse(decoded)) { return true; } return false; } catch { return true; } } function isParentDirectory(parentPath, childPath) { if (!parentPath || !childPath) { return false; } if (parentPath.includes("://") || childPath.includes("://")) { return false; } if (isRemotePath(parentPath) || isRemotePath(childPath)) { return false; } if (parentPath.includes("..") || childPath.includes("..")) { return false; } if (parentPath.includes("\0") || childPath.includes("\0")) { return false; } const normalizedParent = appendForwardSlash(slash(parentPath).toLowerCase()); const normalizedChild = slash(childPath).toLowerCase(); if (normalizedParent === normalizedChild || normalizedParent === normalizedChild + "/") { return false; } return normalizedChild.startsWith(normalizedParent); } function slash(path) { return path.replace(/\\/g, "/"); } function fileExtension(path) { const ext = path.split(".").pop(); return ext !== path ? `.${ext}` : ""; } function removeBase(path, base) { if (path.startsWith(base)) { return path.slice(removeTrailingForwardSlash(base).length); } return path; } const WITH_FILE_EXT = /\/[^/]+\.\w+$/; function hasFileExtension(path) { return WITH_FILE_EXT.test(path); } export { MANY_TRAILING_SLASHES, appendExtension, appendForwardSlash, collapseDuplicateSlashes, collapseDuplicateTrailingSlashes, fileExtension, hasFileExtension, isAbsolutePath, isInternalPath, isParentDirectory, isRelativePath, isRemotePath, joinPaths, prependForwardSlash, removeBase, removeFileExtension, removeLeadingForwardSlash, removeLeadingForwardSlashWindows, removeQueryString, removeTrailingForwardSlash, slash, startsWithDotDotSlash, startsWithDotSlash, startsWithForwardSlash, trimSlashes };