123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513 |
- const os = require('bare-os')
- const { normalizeString } = require('./shared')
- const {
- CHAR_UPPERCASE_A,
- CHAR_LOWERCASE_A,
- CHAR_UPPERCASE_Z,
- CHAR_LOWERCASE_Z,
- CHAR_DOT,
- CHAR_FORWARD_SLASH,
- CHAR_BACKWARD_SLASH,
- CHAR_COLON,
- CHAR_QUESTION_MARK
- } = require('./constants')
- function isWindowsPathSeparator (code) {
- return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH
- }
- function isWindowsDeviceRoot (code) {
- return (code >= CHAR_UPPERCASE_A && code <= CHAR_UPPERCASE_Z) ||
- (code >= CHAR_LOWERCASE_A && code <= CHAR_LOWERCASE_Z)
- }
- exports.posix = require('./posix')
- exports.win32 = exports
- exports.sep = '\\'
- exports.delimiter = ';'
- exports.resolve = function resolve (...args) {
- let resolvedDevice = ''
- let resolvedTail = ''
- let resolvedAbsolute = false
- for (let i = args.length - 1; i >= -1; i--) {
- let path
- if (i >= 0) {
- path = args[i]
- if (path.length === 0) continue
- } else if (resolvedDevice.length === 0) {
- path = os.cwd()
- } else {
- path = os.getEnv(`=${resolvedDevice}`) || os.cwd()
- if (path === undefined || (path.substring(0, 2).toLowerCase() !== resolvedDevice.toLowerCase() && path.charCodeAt(2) === CHAR_BACKWARD_SLASH)) {
- path = `${resolvedDevice}\\`
- }
- }
- const len = path.length
- let rootEnd = 0
- let device = ''
- let isAbsolute = false
- const code = path.charCodeAt(0)
- if (len === 1) {
- if (isWindowsPathSeparator(code)) {
- rootEnd = 1
- isAbsolute = true
- }
- } else if (isWindowsPathSeparator(code)) {
- isAbsolute = true
- if (isWindowsPathSeparator(path.charCodeAt(1))) {
- let j = 2
- let last = j
- while (j < len && !isWindowsPathSeparator(path.charCodeAt(j))) {
- j++
- }
- if (j < len && j !== last) {
- const firstPart = path.substring(last, j)
- last = j
- while (j < len && isWindowsPathSeparator(path.charCodeAt(j))) {
- j++
- }
- if (j < len && j !== last) {
- last = j
- while (j < len && !isWindowsPathSeparator(path.charCodeAt(j))) {
- j++
- }
- if (j === len || j !== last) {
- device = `\\\\${firstPart}\\${path.substring(last, j)}`
- rootEnd = j
- }
- }
- }
- } else {
- rootEnd = 1
- }
- } else if (isWindowsDeviceRoot(code) && path.charCodeAt(1) === CHAR_COLON) {
- device = path.substring(0, 2)
- rootEnd = 2
- if (len > 2 && isWindowsPathSeparator(path.charCodeAt(2))) {
- isAbsolute = true
- rootEnd = 3
- }
- }
- if (device.length > 0) {
- if (resolvedDevice.length > 0) {
- if (device.toLowerCase() !== resolvedDevice.toLowerCase()) { continue }
- } else {
- resolvedDevice = device
- }
- }
- if (resolvedAbsolute) {
- if (resolvedDevice.length > 0) { break }
- } else {
- resolvedTail = `${path.substring(rootEnd)}\\${resolvedTail}`
- resolvedAbsolute = isAbsolute
- if (isAbsolute && resolvedDevice.length > 0) {
- break
- }
- }
- }
- resolvedTail = normalizeString(resolvedTail, !resolvedAbsolute, '\\', isWindowsPathSeparator)
- return resolvedAbsolute ? `${resolvedDevice}\\${resolvedTail}` : `${resolvedDevice}${resolvedTail}` || '.'
- }
- exports.normalize = function normalize (path) {
- const len = path.length
- if (len === 0) return '.'
- let rootEnd = 0
- let device
- let isAbsolute = false
- const code = path.charCodeAt(0)
- if (len === 1) {
- return code === CHAR_FORWARD_SLASH ? '\\' : path
- }
- if (isWindowsPathSeparator(code)) {
- isAbsolute = true
- if (isWindowsPathSeparator(path.charCodeAt(1))) {
- let j = 2
- let last = j
- while (j < len && !isWindowsPathSeparator(path.charCodeAt(j))) {
- j++
- }
- if (j < len && j !== last) {
- const firstPart = path.substring(last, j)
- last = j
- while (j < len && isWindowsPathSeparator(path.charCodeAt(j))) {
- j++
- }
- if (j < len && j !== last) {
- last = j
- while (j < len && !isWindowsPathSeparator(path.charCodeAt(j))) {
- j++
- }
- if (j === len) {
- return `\\\\${firstPart}\\${path.substring(last)}\\`
- }
- if (j !== last) {
- device = `\\\\${firstPart}\\${path.substring(last, j)}`
- rootEnd = j
- }
- }
- }
- } else {
- rootEnd = 1
- }
- } else if (isWindowsDeviceRoot(code) && path.charCodeAt(1) === CHAR_COLON) {
- device = path.substring(0, 2)
- rootEnd = 2
- if (len > 2 && isWindowsPathSeparator(path.charCodeAt(2))) {
- isAbsolute = true
- rootEnd = 3
- }
- }
- let tail = rootEnd < len ? normalizeString(path.substring(rootEnd), !isAbsolute, '\\', isWindowsPathSeparator) : ''
- if (tail.length === 0 && !isAbsolute) {
- tail = '.'
- }
- if (tail.length > 0 && isWindowsPathSeparator(path.charCodeAt(len - 1))) {
- tail += '\\'
- }
- if (device === undefined) {
- return isAbsolute ? `\\${tail}` : tail
- }
- return isAbsolute ? `${device}\\${tail}` : `${device}${tail}`
- }
- exports.isAbsolute = function isAbsolute (path) {
- const len = path.length
- if (len === 0) return false
- const code = path.charCodeAt(0)
- return isWindowsPathSeparator(code) || (len > 2 && isWindowsDeviceRoot(code) && path.charCodeAt(1) === CHAR_COLON && isWindowsPathSeparator(path.charCodeAt(2)))
- }
- exports.join = function join (...args) {
- if (args.length === 0) return '.'
- let joined
- let firstPart
- for (let i = 0; i < args.length; ++i) {
- const arg = args[i]
- if (arg.length > 0) {
- if (joined === undefined) joined = firstPart = arg
- else joined += `\\${arg}`
- }
- }
- if (joined === undefined) return '.'
- let needsReplace = true
- let slashCount = 0
- if (isWindowsPathSeparator(firstPart.charCodeAt(0))) {
- ++slashCount
- const firstLen = firstPart.length
- if (firstLen > 1 && isWindowsPathSeparator(firstPart.charCodeAt(1))) {
- ++slashCount
- if (firstLen > 2) {
- if (isWindowsPathSeparator(firstPart.charCodeAt(2))) {
- ++slashCount
- } else {
- needsReplace = false
- }
- }
- }
- }
- if (needsReplace) {
- while (slashCount < joined.length && isWindowsPathSeparator(joined.charCodeAt(slashCount))) {
- slashCount++
- }
- if (slashCount >= 2) {
- joined = `\\${joined.substring(slashCount)}`
- }
- }
- return exports.normalize(joined)
- }
- exports.relative = function relative (from, to) {
- if (from === to) return ''
- const fromOrig = exports.resolve(from)
- const toOrig = exports.resolve(to)
- if (fromOrig === toOrig) return ''
- from = fromOrig.toLowerCase()
- to = toOrig.toLowerCase()
- if (from === to) return ''
- let fromStart = 0
- while (fromStart < from.length && from.charCodeAt(fromStart) === CHAR_BACKWARD_SLASH) {
- fromStart++
- }
- let fromEnd = from.length
- while (fromEnd - 1 > fromStart && from.charCodeAt(fromEnd - 1) === CHAR_BACKWARD_SLASH) {
- fromEnd--
- }
- const fromLen = fromEnd - fromStart
- let toStart = 0
- while (toStart < to.length && to.charCodeAt(toStart) === CHAR_BACKWARD_SLASH) {
- toStart++
- }
- let toEnd = to.length
- while (toEnd - 1 > toStart && to.charCodeAt(toEnd - 1) === CHAR_BACKWARD_SLASH) {
- toEnd--
- }
- const toLen = toEnd - toStart
- const length = fromLen < toLen ? fromLen : toLen
- let lastCommonSep = -1
- let i = 0
- for (; i < length; i++) {
- const fromCode = from.charCodeAt(fromStart + i)
- if (fromCode !== to.charCodeAt(toStart + i)) {
- break
- } else if (fromCode === CHAR_BACKWARD_SLASH) {
- lastCommonSep = i
- }
- }
- if (i !== length) {
- if (lastCommonSep === -1) return toOrig
- } else {
- if (toLen > length) {
- if (to.charCodeAt(toStart + i) === CHAR_BACKWARD_SLASH) {
- return toOrig.substring(toStart + i + 1)
- }
- if (i === 2) {
- return toOrig.substring(toStart + i)
- }
- }
- if (fromLen > length) {
- if (from.charCodeAt(fromStart + i) === CHAR_BACKWARD_SLASH) {
- lastCommonSep = i
- } else if (i === 2) {
- lastCommonSep = 3
- }
- }
- if (lastCommonSep === -1) lastCommonSep = 0
- }
- let out = ''
- for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) {
- if (i === fromEnd || from.charCodeAt(i) === CHAR_BACKWARD_SLASH) {
- out += out.length === 0 ? '..' : '\\..'
- }
- }
- toStart += lastCommonSep
- if (out.length > 0) {
- return `${out}${toOrig.substring(toStart, toEnd)}`
- }
- if (toOrig.charCodeAt(toStart) === CHAR_BACKWARD_SLASH) {
- ++toStart
- }
- return toOrig.substring(toStart, toEnd)
- }
- exports.toNamespacedPath = function toNamespacedPath (path) {
- if (path.length === 0) return path
- const resolvedPath = exports.resolve(path)
- if (resolvedPath.length <= 2) return path
- 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.substring(2)}`
- }
- }
- } else if (
- isWindowsDeviceRoot(resolvedPath.charCodeAt(0)) &&
- resolvedPath.charCodeAt(1) === CHAR_COLON &&
- resolvedPath.charCodeAt(2) === CHAR_BACKWARD_SLASH
- ) {
- return `\\\\?\\${resolvedPath}`
- }
- return path
- }
- exports.dirname = function dirname (path) {
- const len = path.length
- if (len === 0) return '.'
- let rootEnd = -1
- let offset = 0
- const code = path.charCodeAt(0)
- if (len === 1) {
- return isWindowsPathSeparator(code) ? path : '.'
- }
- if (isWindowsPathSeparator(code)) {
- rootEnd = offset = 1
- if (isWindowsPathSeparator(path.charCodeAt(1))) {
- let j = 2
- let last = j
- while (j < len && !isWindowsPathSeparator(path.charCodeAt(j))) {
- j++
- }
- if (j < len && j !== last) {
- last = j
- while (j < len && isWindowsPathSeparator(path.charCodeAt(j))) {
- j++
- }
- if (j < len && j !== last) {
- last = j
- while (j < len && !isWindowsPathSeparator(path.charCodeAt(j))) {
- j++
- }
- if (j === len) {
- return path
- }
- if (j !== last) {
- rootEnd = offset = j + 1
- }
- }
- }
- }
- } else if (isWindowsDeviceRoot(code) && path.charCodeAt(1) === CHAR_COLON) {
- rootEnd = len > 2 && isWindowsPathSeparator(path.charCodeAt(2)) ? 3 : 2
- offset = rootEnd
- }
- let end = -1
- let matchedSlash = true
- for (let i = len - 1; i >= offset; --i) {
- if (isWindowsPathSeparator(path.charCodeAt(i))) {
- if (!matchedSlash) {
- end = i
- break
- }
- } else {
- matchedSlash = false
- }
- }
- if (end === -1) {
- if (rootEnd === -1) return '.'
- end = rootEnd
- }
- return path.substring(0, end)
- }
- exports.basename = function basename (path, suffix) {
- let start = 0
- let end = -1
- let matchedSlash = true
- if (path.length >= 2 && isWindowsDeviceRoot(path.charCodeAt(0)) && path.charCodeAt(1) === CHAR_COLON) {
- start = 2
- }
- if (suffix !== undefined && suffix.length > 0 && suffix.length <= path.length) {
- if (suffix === path) return ''
- let extIdx = suffix.length - 1
- let firstNonSlashEnd = -1
- for (let i = path.length - 1; i >= start; --i) {
- const code = path.charCodeAt(i)
- if (isWindowsPathSeparator(code)) {
- if (!matchedSlash) {
- start = i + 1
- break
- }
- } else {
- if (firstNonSlashEnd === -1) {
- matchedSlash = false
- firstNonSlashEnd = i + 1
- }
- if (extIdx >= 0) {
- if (code === suffix.charCodeAt(extIdx)) {
- if (--extIdx === -1) {
- end = i
- }
- } else {
- extIdx = -1
- end = firstNonSlashEnd
- }
- }
- }
- }
- if (start === end) end = firstNonSlashEnd
- else if (end === -1) end = path.length
- return path.substring(start, end)
- }
- for (let i = path.length - 1; i >= start; --i) {
- if (isWindowsPathSeparator(path.charCodeAt(i))) {
- if (!matchedSlash) {
- start = i + 1
- break
- }
- } else if (end === -1) {
- matchedSlash = false
- end = i + 1
- }
- }
- if (end === -1) return ''
- return path.substring(start, end)
- }
- exports.extname = function extname (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 (isWindowsPathSeparator(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.substring(startDot, end)
- }
|