|
|
'use strict'; |
|
|
|
|
|
|
|
|
|
|
|
function assertPath(path) { |
|
|
if (typeof path !== "string") { |
|
|
throw new TypeError(`Path must be a string, received "${JSON.stringify(path)}"`); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function stripSuffix(name, suffix) { |
|
|
if (suffix.length >= name.length) { |
|
|
return name; |
|
|
} |
|
|
const lenDiff = name.length - suffix.length; |
|
|
for(let i = suffix.length - 1; i >= 0; --i){ |
|
|
if (name.charCodeAt(lenDiff + i) !== suffix.charCodeAt(i)) { |
|
|
return name; |
|
|
} |
|
|
} |
|
|
return name.slice(0, -suffix.length); |
|
|
} |
|
|
function lastPathSegment(path, isSep, start = 0) { |
|
|
let matchedNonSeparator = false; |
|
|
let end = path.length; |
|
|
for(let i = path.length - 1; i >= start; --i){ |
|
|
if (isSep(path.charCodeAt(i))) { |
|
|
if (matchedNonSeparator) { |
|
|
start = i + 1; |
|
|
break; |
|
|
} |
|
|
} else if (!matchedNonSeparator) { |
|
|
matchedNonSeparator = true; |
|
|
end = i + 1; |
|
|
} |
|
|
} |
|
|
return path.slice(start, end); |
|
|
} |
|
|
function assertArgs$1(path, suffix) { |
|
|
assertPath(path); |
|
|
if (path.length === 0) return path; |
|
|
if (typeof suffix !== "string") { |
|
|
throw new TypeError(`Suffix must be a string, received "${JSON.stringify(suffix)}"`); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const CHAR_UPPERCASE_A = 65; |
|
|
const CHAR_LOWERCASE_A = 97; |
|
|
const CHAR_UPPERCASE_Z = 90; |
|
|
const CHAR_LOWERCASE_Z = 122; |
|
|
|
|
|
const CHAR_DOT = 46; |
|
|
const CHAR_FORWARD_SLASH = 47; |
|
|
const CHAR_BACKWARD_SLASH = 92; |
|
|
const CHAR_COLON = 58; |
|
|
const CHAR_QUESTION_MARK = 63; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function stripTrailingSeparators(segment, isSep) { |
|
|
if (segment.length <= 1) { |
|
|
return segment; |
|
|
} |
|
|
let end = segment.length; |
|
|
for(let i = segment.length - 1; i > 0; i--){ |
|
|
if (isSep(segment.charCodeAt(i))) { |
|
|
end = i; |
|
|
} else { |
|
|
break; |
|
|
} |
|
|
} |
|
|
return segment.slice(0, end); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function isPosixPathSeparator(code) { |
|
|
return code === CHAR_FORWARD_SLASH; |
|
|
} |
|
|
function isPathSeparator(code) { |
|
|
return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH; |
|
|
} |
|
|
function isWindowsDeviceRoot(code) { |
|
|
return code >= CHAR_LOWERCASE_A && code <= CHAR_LOWERCASE_Z || code >= CHAR_UPPERCASE_A && code <= CHAR_UPPERCASE_Z; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function basename(path, suffix = "") { |
|
|
assertArgs$1(path, suffix); |
|
|
|
|
|
|
|
|
|
|
|
let start = 0; |
|
|
if (path.length >= 2) { |
|
|
const drive = path.charCodeAt(0); |
|
|
if (isWindowsDeviceRoot(drive)) { |
|
|
if (path.charCodeAt(1) === CHAR_COLON) start = 2; |
|
|
} |
|
|
} |
|
|
const lastSegment = lastPathSegment(path, isPathSeparator, start); |
|
|
const strippedSegment = stripTrailingSeparators(lastSegment, isPathSeparator); |
|
|
return suffix ? stripSuffix(strippedSegment, suffix) : strippedSegment; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const DELIMITER = ";"; |
|
|
|
|
|
|
|
|
const SEPARATOR = "\\"; |
|
|
|
|
|
|
|
|
const SEPARATOR_PATTERN = /[\\/]+/; |
|
|
|
|
|
|
|
|
|
|
|
function assertArg$3(path) { |
|
|
assertPath(path); |
|
|
if (path.length === 0) return "."; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function dirname(path) { |
|
|
assertArg$3(path); |
|
|
const len = path.length; |
|
|
let rootEnd = -1; |
|
|
let end = -1; |
|
|
let matchedSlash = true; |
|
|
let offset = 0; |
|
|
const code = path.charCodeAt(0); |
|
|
|
|
|
if (len > 1) { |
|
|
if (isPathSeparator(code)) { |
|
|
|
|
|
rootEnd = offset = 1; |
|
|
if (isPathSeparator(path.charCodeAt(1))) { |
|
|
|
|
|
let j = 2; |
|
|
let last = j; |
|
|
|
|
|
for(; j < len; ++j){ |
|
|
if (isPathSeparator(path.charCodeAt(j))) break; |
|
|
} |
|
|
if (j < len && j !== last) { |
|
|
|
|
|
last = j; |
|
|
|
|
|
for(; j < len; ++j){ |
|
|
if (!isPathSeparator(path.charCodeAt(j))) break; |
|
|
} |
|
|
if (j < len && j !== last) { |
|
|
|
|
|
last = j; |
|
|
|
|
|
for(; j < len; ++j){ |
|
|
if (isPathSeparator(path.charCodeAt(j))) break; |
|
|
} |
|
|
if (j === len) { |
|
|
|
|
|
return path; |
|
|
} |
|
|
if (j !== last) { |
|
|
|
|
|
|
|
|
|
|
|
rootEnd = offset = j + 1; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} else if (isWindowsDeviceRoot(code)) { |
|
|
|
|
|
if (path.charCodeAt(1) === CHAR_COLON) { |
|
|
rootEnd = offset = 2; |
|
|
if (len > 2) { |
|
|
if (isPathSeparator(path.charCodeAt(2))) rootEnd = offset = 3; |
|
|
} |
|
|
} |
|
|
} |
|
|
} else if (isPathSeparator(code)) { |
|
|
|
|
|
|
|
|
return path; |
|
|
} |
|
|
for(let i = len - 1; i >= offset; --i){ |
|
|
if (isPathSeparator(path.charCodeAt(i))) { |
|
|
if (!matchedSlash) { |
|
|
end = i; |
|
|
break; |
|
|
} |
|
|
} else { |
|
|
|
|
|
matchedSlash = false; |
|
|
} |
|
|
} |
|
|
if (end === -1) { |
|
|
if (rootEnd === -1) return "."; |
|
|
else end = rootEnd; |
|
|
} |
|
|
return stripTrailingSeparators(path.slice(0, end), isPosixPathSeparator); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function extname(path) { |
|
|
assertPath(path); |
|
|
let start = 0; |
|
|
let startDot = -1; |
|
|
let startPart = 0; |
|
|
let end = -1; |
|
|
let matchedSlash = true; |
|
|
|
|
|
|
|
|
let preDotState = 0; |
|
|
|
|
|
|
|
|
|
|
|
if (path.length >= 2 && path.charCodeAt(1) === CHAR_COLON && isWindowsDeviceRoot(path.charCodeAt(0))) { |
|
|
start = startPart = 2; |
|
|
} |
|
|
for(let i = path.length - 1; i >= start; --i){ |
|
|
const code = path.charCodeAt(i); |
|
|
if (isPathSeparator(code)) { |
|
|
|
|
|
|
|
|
if (!matchedSlash) { |
|
|
startPart = i + 1; |
|
|
break; |
|
|
} |
|
|
continue; |
|
|
} |
|
|
if (end === -1) { |
|
|
|
|
|
|
|
|
matchedSlash = false; |
|
|
end = i + 1; |
|
|
} |
|
|
if (code === CHAR_DOT) { |
|
|
|
|
|
if (startDot === -1) startDot = i; |
|
|
else if (preDotState !== 1) preDotState = 1; |
|
|
} else if (startDot !== -1) { |
|
|
|
|
|
|
|
|
preDotState = -1; |
|
|
} |
|
|
} |
|
|
if (startDot === -1 || end === -1 || |
|
|
preDotState === 0 || |
|
|
preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) { |
|
|
return ""; |
|
|
} |
|
|
return path.slice(startDot, end); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function _format(sep, pathObject) { |
|
|
const dir = pathObject.dir || pathObject.root; |
|
|
const base = pathObject.base || (pathObject.name ?? "") + (pathObject.ext ?? ""); |
|
|
if (!dir) return base; |
|
|
if (base === sep) return dir; |
|
|
if (dir === pathObject.root) return dir + base; |
|
|
return dir + sep + base; |
|
|
} |
|
|
function assertArg$2(pathObject) { |
|
|
if (pathObject === null || typeof pathObject !== "object") { |
|
|
throw new TypeError(`The "pathObject" argument must be of type Object, received type "${typeof pathObject}"`); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function format(pathObject) { |
|
|
assertArg$2(pathObject); |
|
|
return _format("\\", pathObject); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function assertArg$1(url) { |
|
|
url = url instanceof URL ? url : new URL(url); |
|
|
if (url.protocol !== "file:") { |
|
|
throw new TypeError(`URL must be a file URL: received "${url.protocol}"`); |
|
|
} |
|
|
return url; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function fromFileUrl(url) { |
|
|
url = assertArg$1(url); |
|
|
let path = decodeURIComponent(url.pathname.replace(/\//g, "\\").replace(/%(?![0-9A-Fa-f]{2})/g, "%25")).replace(/^\\*([A-Za-z]:)(\\|$)/, "$1\\"); |
|
|
if (url.hostname !== "") { |
|
|
|
|
|
|
|
|
|
|
|
path = `\\\\${url.hostname}${path}`; |
|
|
} |
|
|
return path; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function isAbsolute(path) { |
|
|
assertPath(path); |
|
|
const len = path.length; |
|
|
if (len === 0) return false; |
|
|
const code = path.charCodeAt(0); |
|
|
if (isPathSeparator(code)) { |
|
|
return true; |
|
|
} else if (isWindowsDeviceRoot(code)) { |
|
|
|
|
|
if (len > 2 && path.charCodeAt(1) === CHAR_COLON) { |
|
|
if (isPathSeparator(path.charCodeAt(2))) return true; |
|
|
} |
|
|
} |
|
|
return false; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function assertArg(path) { |
|
|
assertPath(path); |
|
|
if (path.length === 0) return "."; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function normalizeString(path, allowAboveRoot, separator, isPathSeparator) { |
|
|
let res = ""; |
|
|
let lastSegmentLength = 0; |
|
|
let lastSlash = -1; |
|
|
let dots = 0; |
|
|
let code; |
|
|
for(let i = 0; i <= path.length; ++i){ |
|
|
if (i < path.length) code = path.charCodeAt(i); |
|
|
else if (isPathSeparator(code)) break; |
|
|
else code = CHAR_FORWARD_SLASH; |
|
|
if (isPathSeparator(code)) { |
|
|
if (lastSlash === i - 1 || dots === 1) ; else if (lastSlash !== i - 1 && dots === 2) { |
|
|
if (res.length < 2 || lastSegmentLength !== 2 || res.charCodeAt(res.length - 1) !== CHAR_DOT || res.charCodeAt(res.length - 2) !== CHAR_DOT) { |
|
|
if (res.length > 2) { |
|
|
const lastSlashIndex = res.lastIndexOf(separator); |
|
|
if (lastSlashIndex === -1) { |
|
|
res = ""; |
|
|
lastSegmentLength = 0; |
|
|
} else { |
|
|
res = res.slice(0, lastSlashIndex); |
|
|
lastSegmentLength = res.length - 1 - res.lastIndexOf(separator); |
|
|
} |
|
|
lastSlash = i; |
|
|
dots = 0; |
|
|
continue; |
|
|
} else if (res.length === 2 || res.length === 1) { |
|
|
res = ""; |
|
|
lastSegmentLength = 0; |
|
|
lastSlash = i; |
|
|
dots = 0; |
|
|
continue; |
|
|
} |
|
|
} |
|
|
if (allowAboveRoot) { |
|
|
if (res.length > 0) res += `${separator}..`; |
|
|
else res = ".."; |
|
|
lastSegmentLength = 2; |
|
|
} |
|
|
} else { |
|
|
if (res.length > 0) res += separator + path.slice(lastSlash + 1, i); |
|
|
else res = path.slice(lastSlash + 1, i); |
|
|
lastSegmentLength = i - lastSlash - 1; |
|
|
} |
|
|
lastSlash = i; |
|
|
dots = 0; |
|
|
} else if (code === CHAR_DOT && dots !== -1) { |
|
|
++dots; |
|
|
} else { |
|
|
dots = -1; |
|
|
} |
|
|
} |
|
|
return res; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function normalize(path) { |
|
|
assertArg(path); |
|
|
const len = path.length; |
|
|
let rootEnd = 0; |
|
|
let device; |
|
|
let isAbsolute = false; |
|
|
const code = path.charCodeAt(0); |
|
|
|
|
|
if (len > 1) { |
|
|
if (isPathSeparator(code)) { |
|
|
|
|
|
|
|
|
|
|
|
isAbsolute = true; |
|
|
if (isPathSeparator(path.charCodeAt(1))) { |
|
|
|
|
|
let j = 2; |
|
|
let last = j; |
|
|
|
|
|
for(; j < len; ++j){ |
|
|
if (isPathSeparator(path.charCodeAt(j))) break; |
|
|
} |
|
|
if (j < len && j !== last) { |
|
|
const firstPart = path.slice(last, j); |
|
|
|
|
|
last = j; |
|
|
|
|
|
for(; j < len; ++j){ |
|
|
if (!isPathSeparator(path.charCodeAt(j))) break; |
|
|
} |
|
|
if (j < len && j !== last) { |
|
|
|
|
|
last = j; |
|
|
|
|
|
for(; j < len; ++j){ |
|
|
if (isPathSeparator(path.charCodeAt(j))) break; |
|
|
} |
|
|
if (j === len) { |
|
|
|
|
|
|
|
|
|
|
|
return `\\\\${firstPart}\\${path.slice(last)}\\`; |
|
|
} else if (j !== last) { |
|
|
|
|
|
device = `\\\\${firstPart}\\${path.slice(last, j)}`; |
|
|
rootEnd = j; |
|
|
} |
|
|
} |
|
|
} |
|
|
} else { |
|
|
rootEnd = 1; |
|
|
} |
|
|
} else if (isWindowsDeviceRoot(code)) { |
|
|
|
|
|
if (path.charCodeAt(1) === CHAR_COLON) { |
|
|
device = path.slice(0, 2); |
|
|
rootEnd = 2; |
|
|
if (len > 2) { |
|
|
if (isPathSeparator(path.charCodeAt(2))) { |
|
|
|
|
|
|
|
|
isAbsolute = true; |
|
|
rootEnd = 3; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} else if (isPathSeparator(code)) { |
|
|
|
|
|
|
|
|
return "\\"; |
|
|
} |
|
|
let tail; |
|
|
if (rootEnd < len) { |
|
|
tail = normalizeString(path.slice(rootEnd), !isAbsolute, "\\", isPathSeparator); |
|
|
} else { |
|
|
tail = ""; |
|
|
} |
|
|
if (tail.length === 0 && !isAbsolute) tail = "."; |
|
|
if (tail.length > 0 && isPathSeparator(path.charCodeAt(len - 1))) { |
|
|
tail += "\\"; |
|
|
} |
|
|
if (device === undefined) { |
|
|
if (isAbsolute) { |
|
|
if (tail.length > 0) return `\\${tail}`; |
|
|
else return "\\"; |
|
|
} |
|
|
return tail; |
|
|
} else if (isAbsolute) { |
|
|
if (tail.length > 0) return `${device}\\${tail}`; |
|
|
else return `${device}\\`; |
|
|
} |
|
|
return device + tail; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function join(...paths) { |
|
|
paths.forEach((path)=>assertPath(path)); |
|
|
paths = paths.filter((path)=>path.length > 0); |
|
|
if (paths.length === 0) return "."; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let needsReplace = true; |
|
|
let slashCount = 0; |
|
|
const firstPart = paths[0]; |
|
|
if (isPathSeparator(firstPart.charCodeAt(0))) { |
|
|
++slashCount; |
|
|
const firstLen = firstPart.length; |
|
|
if (firstLen > 1) { |
|
|
if (isPathSeparator(firstPart.charCodeAt(1))) { |
|
|
++slashCount; |
|
|
if (firstLen > 2) { |
|
|
if (isPathSeparator(firstPart.charCodeAt(2))) ++slashCount; |
|
|
else { |
|
|
|
|
|
needsReplace = false; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
let joined = paths.join("\\"); |
|
|
if (needsReplace) { |
|
|
|
|
|
for(; slashCount < joined.length; ++slashCount){ |
|
|
if (!isPathSeparator(joined.charCodeAt(slashCount))) break; |
|
|
} |
|
|
|
|
|
if (slashCount >= 2) joined = `\\${joined.slice(slashCount)}`; |
|
|
} |
|
|
return normalize(joined); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function parse(path) { |
|
|
assertPath(path); |
|
|
const ret = { |
|
|
root: "", |
|
|
dir: "", |
|
|
base: "", |
|
|
ext: "", |
|
|
name: "" |
|
|
}; |
|
|
const len = path.length; |
|
|
if (len === 0) return ret; |
|
|
let rootEnd = 0; |
|
|
let code = path.charCodeAt(0); |
|
|
|
|
|
if (len > 1) { |
|
|
if (isPathSeparator(code)) { |
|
|
|
|
|
rootEnd = 1; |
|
|
if (isPathSeparator(path.charCodeAt(1))) { |
|
|
|
|
|
let j = 2; |
|
|
let last = j; |
|
|
|
|
|
for(; j < len; ++j){ |
|
|
if (isPathSeparator(path.charCodeAt(j))) break; |
|
|
} |
|
|
if (j < len && j !== last) { |
|
|
|
|
|
last = j; |
|
|
|
|
|
for(; j < len; ++j){ |
|
|
if (!isPathSeparator(path.charCodeAt(j))) break; |
|
|
} |
|
|
if (j < len && j !== last) { |
|
|
|
|
|
last = j; |
|
|
|
|
|
for(; j < len; ++j){ |
|
|
if (isPathSeparator(path.charCodeAt(j))) break; |
|
|
} |
|
|
if (j === len) { |
|
|
|
|
|
rootEnd = j; |
|
|
} else if (j !== last) { |
|
|
|
|
|
rootEnd = j + 1; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} else if (isWindowsDeviceRoot(code)) { |
|
|
|
|
|
if (path.charCodeAt(1) === CHAR_COLON) { |
|
|
rootEnd = 2; |
|
|
if (len > 2) { |
|
|
if (isPathSeparator(path.charCodeAt(2))) { |
|
|
if (len === 3) { |
|
|
|
|
|
|
|
|
ret.root = ret.dir = path; |
|
|
ret.base = "\\"; |
|
|
return ret; |
|
|
} |
|
|
rootEnd = 3; |
|
|
} |
|
|
} else { |
|
|
|
|
|
|
|
|
ret.root = ret.dir = path; |
|
|
return ret; |
|
|
} |
|
|
} |
|
|
} |
|
|
} else if (isPathSeparator(code)) { |
|
|
|
|
|
|
|
|
ret.root = ret.dir = path; |
|
|
ret.base = "\\"; |
|
|
return ret; |
|
|
} |
|
|
if (rootEnd > 0) ret.root = path.slice(0, rootEnd); |
|
|
let startDot = -1; |
|
|
let startPart = rootEnd; |
|
|
let end = -1; |
|
|
let matchedSlash = true; |
|
|
let i = path.length - 1; |
|
|
|
|
|
|
|
|
let preDotState = 0; |
|
|
|
|
|
for(; i >= rootEnd; --i){ |
|
|
code = path.charCodeAt(i); |
|
|
if (isPathSeparator(code)) { |
|
|
|
|
|
|
|
|
if (!matchedSlash) { |
|
|
startPart = i + 1; |
|
|
break; |
|
|
} |
|
|
continue; |
|
|
} |
|
|
if (end === -1) { |
|
|
|
|
|
|
|
|
matchedSlash = false; |
|
|
end = i + 1; |
|
|
} |
|
|
if (code === CHAR_DOT) { |
|
|
|
|
|
if (startDot === -1) startDot = i; |
|
|
else if (preDotState !== 1) preDotState = 1; |
|
|
} else if (startDot !== -1) { |
|
|
|
|
|
|
|
|
preDotState = -1; |
|
|
} |
|
|
} |
|
|
if (startDot === -1 || end === -1 || |
|
|
preDotState === 0 || |
|
|
preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) { |
|
|
if (end !== -1) { |
|
|
ret.base = ret.name = path.slice(startPart, end); |
|
|
} |
|
|
} else { |
|
|
ret.name = path.slice(startPart, startDot); |
|
|
ret.base = path.slice(startPart, end); |
|
|
ret.ext = path.slice(startDot, end); |
|
|
} |
|
|
|
|
|
ret.base = ret.base || "\\"; |
|
|
|
|
|
|
|
|
|
|
|
if (startPart > 0 && startPart !== rootEnd) { |
|
|
ret.dir = path.slice(0, startPart - 1); |
|
|
} else ret.dir = ret.root; |
|
|
return ret; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function resolve(...pathSegments) { |
|
|
let resolvedDevice = ""; |
|
|
let resolvedTail = ""; |
|
|
let resolvedAbsolute = false; |
|
|
for(let i = pathSegments.length - 1; i >= -1; i--){ |
|
|
let path; |
|
|
|
|
|
const { Deno } = globalThis; |
|
|
if (i >= 0) { |
|
|
path = pathSegments[i]; |
|
|
} else if (!resolvedDevice) { |
|
|
if (typeof Deno?.cwd !== "function") { |
|
|
throw new TypeError("Resolved a drive-letter-less path without a current working directory (CWD)"); |
|
|
} |
|
|
path = Deno.cwd(); |
|
|
} else { |
|
|
if (typeof Deno?.env?.get !== "function" || typeof Deno?.cwd !== "function") { |
|
|
throw new TypeError("Resolved a relative path without a current working directory (CWD)"); |
|
|
} |
|
|
path = Deno.cwd(); |
|
|
|
|
|
|
|
|
if (path === undefined || path.slice(0, 3).toLowerCase() !== `${resolvedDevice.toLowerCase()}\\`) { |
|
|
path = `${resolvedDevice}\\`; |
|
|
} |
|
|
} |
|
|
assertPath(path); |
|
|
const len = path.length; |
|
|
|
|
|
if (len === 0) continue; |
|
|
let rootEnd = 0; |
|
|
let device = ""; |
|
|
let isAbsolute = false; |
|
|
const code = path.charCodeAt(0); |
|
|
|
|
|
if (len > 1) { |
|
|
if (isPathSeparator(code)) { |
|
|
|
|
|
|
|
|
|
|
|
isAbsolute = true; |
|
|
if (isPathSeparator(path.charCodeAt(1))) { |
|
|
|
|
|
let j = 2; |
|
|
let last = j; |
|
|
|
|
|
for(; j < len; ++j){ |
|
|
if (isPathSeparator(path.charCodeAt(j))) break; |
|
|
} |
|
|
if (j < len && j !== last) { |
|
|
const firstPart = path.slice(last, j); |
|
|
|
|
|
last = j; |
|
|
|
|
|
for(; j < len; ++j){ |
|
|
if (!isPathSeparator(path.charCodeAt(j))) break; |
|
|
} |
|
|
if (j < len && j !== last) { |
|
|
|
|
|
last = j; |
|
|
|
|
|
for(; j < len; ++j){ |
|
|
if (isPathSeparator(path.charCodeAt(j))) break; |
|
|
} |
|
|
if (j === len) { |
|
|
|
|
|
device = `\\\\${firstPart}\\${path.slice(last)}`; |
|
|
rootEnd = j; |
|
|
} else if (j !== last) { |
|
|
|
|
|
device = `\\\\${firstPart}\\${path.slice(last, j)}`; |
|
|
rootEnd = j; |
|
|
} |
|
|
} |
|
|
} |
|
|
} else { |
|
|
rootEnd = 1; |
|
|
} |
|
|
} else if (isWindowsDeviceRoot(code)) { |
|
|
|
|
|
if (path.charCodeAt(1) === CHAR_COLON) { |
|
|
device = path.slice(0, 2); |
|
|
rootEnd = 2; |
|
|
if (len > 2) { |
|
|
if (isPathSeparator(path.charCodeAt(2))) { |
|
|
|
|
|
|
|
|
isAbsolute = true; |
|
|
rootEnd = 3; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} else if (isPathSeparator(code)) { |
|
|
|
|
|
rootEnd = 1; |
|
|
isAbsolute = true; |
|
|
} |
|
|
if (device.length > 0 && resolvedDevice.length > 0 && device.toLowerCase() !== resolvedDevice.toLowerCase()) { |
|
|
continue; |
|
|
} |
|
|
if (resolvedDevice.length === 0 && device.length > 0) { |
|
|
resolvedDevice = device; |
|
|
} |
|
|
if (!resolvedAbsolute) { |
|
|
resolvedTail = `${path.slice(rootEnd)}\\${resolvedTail}`; |
|
|
resolvedAbsolute = isAbsolute; |
|
|
} |
|
|
if (resolvedAbsolute && resolvedDevice.length > 0) break; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resolvedTail = normalizeString(resolvedTail, !resolvedAbsolute, "\\", isPathSeparator); |
|
|
return resolvedDevice + (resolvedAbsolute ? "\\" : "") + resolvedTail || "."; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function assertArgs(from, to) { |
|
|
assertPath(from); |
|
|
assertPath(to); |
|
|
if (from === to) return ""; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function relative(from, to) { |
|
|
assertArgs(from, to); |
|
|
const fromOrig = resolve(from); |
|
|
const toOrig = resolve(to); |
|
|
if (fromOrig === toOrig) return ""; |
|
|
from = fromOrig.toLowerCase(); |
|
|
to = toOrig.toLowerCase(); |
|
|
if (from === to) return ""; |
|
|
|
|
|
let fromStart = 0; |
|
|
let fromEnd = from.length; |
|
|
for(; fromStart < fromEnd; ++fromStart){ |
|
|
if (from.charCodeAt(fromStart) !== CHAR_BACKWARD_SLASH) break; |
|
|
} |
|
|
|
|
|
for(; fromEnd - 1 > fromStart; --fromEnd){ |
|
|
if (from.charCodeAt(fromEnd - 1) !== CHAR_BACKWARD_SLASH) break; |
|
|
} |
|
|
const fromLen = fromEnd - fromStart; |
|
|
|
|
|
let toStart = 0; |
|
|
let toEnd = to.length; |
|
|
for(; toStart < toEnd; ++toStart){ |
|
|
if (to.charCodeAt(toStart) !== CHAR_BACKWARD_SLASH) break; |
|
|
} |
|
|
|
|
|
for(; toEnd - 1 > toStart; --toEnd){ |
|
|
if (to.charCodeAt(toEnd - 1) !== CHAR_BACKWARD_SLASH) break; |
|
|
} |
|
|
const toLen = toEnd - toStart; |
|
|
|
|
|
const length = fromLen < toLen ? fromLen : toLen; |
|
|
let lastCommonSep = -1; |
|
|
let i = 0; |
|
|
for(; i <= length; ++i){ |
|
|
if (i === length) { |
|
|
if (toLen > length) { |
|
|
if (to.charCodeAt(toStart + i) === CHAR_BACKWARD_SLASH) { |
|
|
|
|
|
|
|
|
return toOrig.slice(toStart + i + 1); |
|
|
} else if (i === 2) { |
|
|
|
|
|
|
|
|
return toOrig.slice(toStart + i); |
|
|
} |
|
|
} |
|
|
if (fromLen > length) { |
|
|
if (from.charCodeAt(fromStart + i) === CHAR_BACKWARD_SLASH) { |
|
|
|
|
|
|
|
|
lastCommonSep = i; |
|
|
} else if (i === 2) { |
|
|
|
|
|
|
|
|
lastCommonSep = 3; |
|
|
} |
|
|
} |
|
|
break; |
|
|
} |
|
|
const fromCode = from.charCodeAt(fromStart + i); |
|
|
const toCode = to.charCodeAt(toStart + i); |
|
|
if (fromCode !== toCode) break; |
|
|
else if (fromCode === CHAR_BACKWARD_SLASH) lastCommonSep = i; |
|
|
} |
|
|
|
|
|
|
|
|
if (i !== length && lastCommonSep === -1) { |
|
|
return toOrig; |
|
|
} |
|
|
let out = ""; |
|
|
if (lastCommonSep === -1) lastCommonSep = 0; |
|
|
|
|
|
|
|
|
for(i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i){ |
|
|
if (i === fromEnd || from.charCodeAt(i) === CHAR_BACKWARD_SLASH) { |
|
|
if (out.length === 0) out += ".."; |
|
|
else out += "\\.."; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (out.length > 0) { |
|
|
return out + toOrig.slice(toStart + lastCommonSep, toEnd); |
|
|
} else { |
|
|
toStart += lastCommonSep; |
|
|
if (toOrig.charCodeAt(toStart) === CHAR_BACKWARD_SLASH) ++toStart; |
|
|
return toOrig.slice(toStart, toEnd); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const WHITESPACE_ENCODINGS = { |
|
|
"\u0009": "%09", |
|
|
"\u000A": "%0A", |
|
|
"\u000B": "%0B", |
|
|
"\u000C": "%0C", |
|
|
"\u000D": "%0D", |
|
|
"\u0020": "%20" |
|
|
}; |
|
|
function encodeWhitespace(string) { |
|
|
return string.replaceAll(/[\s]/g, (c)=>{ |
|
|
return WHITESPACE_ENCODINGS[c] ?? c; |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function toFileUrl(path) { |
|
|
if (!isAbsolute(path)) { |
|
|
throw new TypeError(`Path must be absolute: received "${path}"`); |
|
|
} |
|
|
const [, hostname, pathname] = path.match(/^(?:[/\\]{2}([^/\\]+)(?=[/\\](?:[^/\\]|$)))?(.*)/); |
|
|
const url = new URL("file:///"); |
|
|
url.pathname = encodeWhitespace(pathname.replace(/%/g, "%25")); |
|
|
if (hostname !== undefined && hostname !== "localhost") { |
|
|
url.hostname = hostname; |
|
|
if (!url.hostname) { |
|
|
throw new TypeError(`Invalid hostname: "${url.hostname}"`); |
|
|
} |
|
|
} |
|
|
return url; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function toNamespacedPath(path) { |
|
|
|
|
|
if (typeof path !== "string") return path; |
|
|
if (path.length === 0) return ""; |
|
|
const resolvedPath = resolve(path); |
|
|
if (resolvedPath.length >= 3) { |
|
|
if (resolvedPath.charCodeAt(0) === CHAR_BACKWARD_SLASH) { |
|
|
|
|
|
if (resolvedPath.charCodeAt(1) === CHAR_BACKWARD_SLASH) { |
|
|
const code = resolvedPath.charCodeAt(2); |
|
|
if (code !== CHAR_QUESTION_MARK && code !== CHAR_DOT) { |
|
|
|
|
|
return `\\\\?\\UNC\\${resolvedPath.slice(2)}`; |
|
|
} |
|
|
} |
|
|
} else if (isWindowsDeviceRoot(resolvedPath.charCodeAt(0))) { |
|
|
|
|
|
if (resolvedPath.charCodeAt(1) === CHAR_COLON && resolvedPath.charCodeAt(2) === CHAR_BACKWARD_SLASH) { |
|
|
|
|
|
return `\\\\?\\${resolvedPath}`; |
|
|
} |
|
|
} |
|
|
} |
|
|
return path; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function common$1(paths, sep) { |
|
|
const [first = "", ...remaining] = paths; |
|
|
const parts = first.split(sep); |
|
|
let endOfPrefix = parts.length; |
|
|
let append = ""; |
|
|
for (const path of remaining){ |
|
|
const compare = path.split(sep); |
|
|
if (compare.length <= endOfPrefix) { |
|
|
endOfPrefix = compare.length; |
|
|
append = ""; |
|
|
} |
|
|
for(let i = 0; i < endOfPrefix; i++){ |
|
|
if (compare[i] !== parts[i]) { |
|
|
endOfPrefix = i; |
|
|
append = i === 0 ? "" : sep; |
|
|
break; |
|
|
} |
|
|
} |
|
|
} |
|
|
return parts.slice(0, endOfPrefix).join(sep) + append; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function common(paths) { |
|
|
return common$1(paths, SEPARATOR); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const REG_EXP_ESCAPE_CHARS = [ |
|
|
"!", |
|
|
"$", |
|
|
"(", |
|
|
")", |
|
|
"*", |
|
|
"+", |
|
|
".", |
|
|
"=", |
|
|
"?", |
|
|
"[", |
|
|
"\\", |
|
|
"^", |
|
|
"{", |
|
|
"|" |
|
|
]; |
|
|
const RANGE_ESCAPE_CHARS = [ |
|
|
"-", |
|
|
"\\", |
|
|
"]" |
|
|
]; |
|
|
function _globToRegExp(c, glob, { extended = true, globstar: globstarOption = true, // os = osType, |
|
|
caseInsensitive = false } = {}) { |
|
|
if (glob === "") { |
|
|
return /(?!)/; |
|
|
} |
|
|
|
|
|
let newLength = glob.length; |
|
|
for(; newLength > 1 && c.seps.includes(glob[newLength - 1]); newLength--); |
|
|
glob = glob.slice(0, newLength); |
|
|
let regExpString = ""; |
|
|
|
|
|
for(let j = 0; j < glob.length;){ |
|
|
let segment = ""; |
|
|
const groupStack = []; |
|
|
let inRange = false; |
|
|
let inEscape = false; |
|
|
let endsWithSep = false; |
|
|
let i = j; |
|
|
|
|
|
for(; i < glob.length && !c.seps.includes(glob[i]); i++){ |
|
|
if (inEscape) { |
|
|
inEscape = false; |
|
|
const escapeChars = inRange ? RANGE_ESCAPE_CHARS : REG_EXP_ESCAPE_CHARS; |
|
|
segment += escapeChars.includes(glob[i]) ? `\\${glob[i]}` : glob[i]; |
|
|
continue; |
|
|
} |
|
|
if (glob[i] === c.escapePrefix) { |
|
|
inEscape = true; |
|
|
continue; |
|
|
} |
|
|
if (glob[i] === "[") { |
|
|
if (!inRange) { |
|
|
inRange = true; |
|
|
segment += "["; |
|
|
if (glob[i + 1] === "!") { |
|
|
i++; |
|
|
segment += "^"; |
|
|
} else if (glob[i + 1] === "^") { |
|
|
i++; |
|
|
segment += "\\^"; |
|
|
} |
|
|
continue; |
|
|
} else if (glob[i + 1] === ":") { |
|
|
let k = i + 1; |
|
|
let value = ""; |
|
|
while(glob[k + 1] !== undefined && glob[k + 1] !== ":"){ |
|
|
value += glob[k + 1]; |
|
|
k++; |
|
|
} |
|
|
if (glob[k + 1] === ":" && glob[k + 2] === "]") { |
|
|
i = k + 2; |
|
|
if (value === "alnum") segment += "\\dA-Za-z"; |
|
|
else if (value === "alpha") segment += "A-Za-z"; |
|
|
else if (value === "ascii") segment += "\x00-\x7F"; |
|
|
else if (value === "blank") segment += "\t "; |
|
|
else if (value === "cntrl") segment += "\x00-\x1F\x7F"; |
|
|
else if (value === "digit") segment += "\\d"; |
|
|
else if (value === "graph") segment += "\x21-\x7E"; |
|
|
else if (value === "lower") segment += "a-z"; |
|
|
else if (value === "print") segment += "\x20-\x7E"; |
|
|
else if (value === "punct") { |
|
|
segment += "!\"#$%&'()*+,\\-./:;<=>?@[\\\\\\]^_‘{|}~"; |
|
|
} else if (value === "space") segment += "\\s\v"; |
|
|
else if (value === "upper") segment += "A-Z"; |
|
|
else if (value === "word") segment += "\\w"; |
|
|
else if (value === "xdigit") segment += "\\dA-Fa-f"; |
|
|
continue; |
|
|
} |
|
|
} |
|
|
} |
|
|
if (glob[i] === "]" && inRange) { |
|
|
inRange = false; |
|
|
segment += "]"; |
|
|
continue; |
|
|
} |
|
|
if (inRange) { |
|
|
segment += glob[i]; |
|
|
continue; |
|
|
} |
|
|
if (glob[i] === ")" && groupStack.length > 0 && groupStack[groupStack.length - 1] !== "BRACE") { |
|
|
segment += ")"; |
|
|
const type = groupStack.pop(); |
|
|
if (type === "!") { |
|
|
segment += c.wildcard; |
|
|
} else if (type !== "@") { |
|
|
segment += type; |
|
|
} |
|
|
continue; |
|
|
} |
|
|
if (glob[i] === "|" && groupStack.length > 0 && groupStack[groupStack.length - 1] !== "BRACE") { |
|
|
segment += "|"; |
|
|
continue; |
|
|
} |
|
|
if (glob[i] === "+" && extended && glob[i + 1] === "(") { |
|
|
i++; |
|
|
groupStack.push("+"); |
|
|
segment += "(?:"; |
|
|
continue; |
|
|
} |
|
|
if (glob[i] === "@" && extended && glob[i + 1] === "(") { |
|
|
i++; |
|
|
groupStack.push("@"); |
|
|
segment += "(?:"; |
|
|
continue; |
|
|
} |
|
|
if (glob[i] === "?") { |
|
|
if (extended && glob[i + 1] === "(") { |
|
|
i++; |
|
|
groupStack.push("?"); |
|
|
segment += "(?:"; |
|
|
} else { |
|
|
segment += "."; |
|
|
} |
|
|
continue; |
|
|
} |
|
|
if (glob[i] === "!" && extended && glob[i + 1] === "(") { |
|
|
i++; |
|
|
groupStack.push("!"); |
|
|
segment += "(?!"; |
|
|
continue; |
|
|
} |
|
|
if (glob[i] === "{") { |
|
|
groupStack.push("BRACE"); |
|
|
segment += "(?:"; |
|
|
continue; |
|
|
} |
|
|
if (glob[i] === "}" && groupStack[groupStack.length - 1] === "BRACE") { |
|
|
groupStack.pop(); |
|
|
segment += ")"; |
|
|
continue; |
|
|
} |
|
|
if (glob[i] === "," && groupStack[groupStack.length - 1] === "BRACE") { |
|
|
segment += "|"; |
|
|
continue; |
|
|
} |
|
|
if (glob[i] === "*") { |
|
|
if (extended && glob[i + 1] === "(") { |
|
|
i++; |
|
|
groupStack.push("*"); |
|
|
segment += "(?:"; |
|
|
} else { |
|
|
const prevChar = glob[i - 1]; |
|
|
let numStars = 1; |
|
|
while(glob[i + 1] === "*"){ |
|
|
i++; |
|
|
numStars++; |
|
|
} |
|
|
const nextChar = glob[i + 1]; |
|
|
if (globstarOption && numStars === 2 && [ |
|
|
...c.seps, |
|
|
undefined |
|
|
].includes(prevChar) && [ |
|
|
...c.seps, |
|
|
undefined |
|
|
].includes(nextChar)) { |
|
|
segment += c.globstar; |
|
|
endsWithSep = true; |
|
|
} else { |
|
|
segment += c.wildcard; |
|
|
} |
|
|
} |
|
|
continue; |
|
|
} |
|
|
segment += REG_EXP_ESCAPE_CHARS.includes(glob[i]) ? `\\${glob[i]}` : glob[i]; |
|
|
} |
|
|
|
|
|
if (groupStack.length > 0 || inRange || inEscape) { |
|
|
|
|
|
segment = ""; |
|
|
for (const c of glob.slice(j, i)){ |
|
|
segment += REG_EXP_ESCAPE_CHARS.includes(c) ? `\\${c}` : c; |
|
|
endsWithSep = false; |
|
|
} |
|
|
} |
|
|
regExpString += segment; |
|
|
if (!endsWithSep) { |
|
|
regExpString += i < glob.length ? c.sep : c.sepMaybe; |
|
|
endsWithSep = true; |
|
|
} |
|
|
|
|
|
while(c.seps.includes(glob[i]))i++; |
|
|
j = i; |
|
|
} |
|
|
regExpString = `^${regExpString}$`; |
|
|
return new RegExp(regExpString, caseInsensitive ? "i" : ""); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const constants = { |
|
|
sep: "(?:\\\\|/)+", |
|
|
sepMaybe: "(?:\\\\|/)*", |
|
|
seps: [ |
|
|
"\\", |
|
|
"/" |
|
|
], |
|
|
globstar: "(?:[^\\\\/]*(?:\\\\|/|$)+)*", |
|
|
wildcard: "[^\\\\/]*", |
|
|
escapePrefix: "`" |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function globToRegExp(glob, options = {}) { |
|
|
return _globToRegExp(constants, glob, options); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function isGlob(str) { |
|
|
const chars = { |
|
|
"{": "}", |
|
|
"(": ")", |
|
|
"[": "]" |
|
|
}; |
|
|
const regex = /\\(.)|(^!|\*|\?|[\].+)]\?|\[[^\\\]]+\]|\{[^\\}]+\}|\(\?[:!=][^\\)]+\)|\([^|]+\|[^\\)]+\))/; |
|
|
if (str === "") { |
|
|
return false; |
|
|
} |
|
|
let match; |
|
|
while(match = regex.exec(str)){ |
|
|
if (match[2]) return true; |
|
|
let idx = match.index + match[0].length; |
|
|
|
|
|
|
|
|
const open = match[1]; |
|
|
const close = open ? chars[open] : null; |
|
|
if (open && close) { |
|
|
const n = str.indexOf(close, idx); |
|
|
if (n !== -1) { |
|
|
idx = n + 1; |
|
|
} |
|
|
} |
|
|
str = str.slice(idx); |
|
|
} |
|
|
return false; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function normalizeGlob(glob, options = {}) { |
|
|
const { globstar = false } = options; |
|
|
if (glob.match(/\0/g)) { |
|
|
throw new Error(`Glob contains invalid characters: "${glob}"`); |
|
|
} |
|
|
if (!globstar) { |
|
|
return normalize(glob); |
|
|
} |
|
|
const s = SEPARATOR_PATTERN.source; |
|
|
const badParentPattern = new RegExp(`(?<=(${s}|^)\\*\\*${s})\\.\\.(?=${s}|$)`, "g"); |
|
|
return normalize(glob.replace(badParentPattern, "\0")).replace(/\0/g, ".."); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function joinGlobs(globs, options = {}) { |
|
|
const { globstar = false } = options; |
|
|
if (!globstar || globs.length === 0) { |
|
|
return join(...globs); |
|
|
} |
|
|
let joined; |
|
|
for (const glob of globs){ |
|
|
const path = glob; |
|
|
if (path.length > 0) { |
|
|
if (!joined) joined = path; |
|
|
else joined += `${SEPARATOR}${path}`; |
|
|
} |
|
|
} |
|
|
if (!joined) return "."; |
|
|
return normalizeGlob(joined, { |
|
|
globstar |
|
|
}); |
|
|
} |
|
|
|
|
|
exports.DELIMITER = DELIMITER; |
|
|
exports.SEPARATOR = SEPARATOR; |
|
|
exports.SEPARATOR_PATTERN = SEPARATOR_PATTERN; |
|
|
exports.basename = basename; |
|
|
exports.common = common; |
|
|
exports.dirname = dirname; |
|
|
exports.extname = extname; |
|
|
exports.format = format; |
|
|
exports.fromFileUrl = fromFileUrl; |
|
|
exports.globToRegExp = globToRegExp; |
|
|
exports.isAbsolute = isAbsolute; |
|
|
exports.isGlob = isGlob; |
|
|
exports.join = join; |
|
|
exports.joinGlobs = joinGlobs; |
|
|
exports.normalize = normalize; |
|
|
exports.normalizeGlob = normalizeGlob; |
|
|
exports.parse = parse; |
|
|
exports.relative = relative; |
|
|
exports.resolve = resolve; |
|
|
exports.toFileUrl = toFileUrl; |
|
|
exports.toNamespacedPath = toNamespacedPath; |
|
|
|