-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdirname.mts
146 lines (124 loc) · 3.63 KB
/
dirname.mts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/**
* @file dirname
* @module pathe/lib/dirname
*/
import canParseURL from '#internal/can-parse-url'
import { DRIVE_PATH_REGEX } from '#internal/constants'
import validateURLString from '#internal/validate-url-string'
import delimiter from '#lib/delimiter'
import dot from '#lib/dot'
import isSep from '#lib/is-sep'
import sep from '#lib/sep'
import toPosix from '#lib/to-posix'
/**
* Get the directory name of `input`, similar to the Unix `dirname` command.
*
* Trailing [directory separators][sep] are ignored.
*
* [sep]: https://nodejs.org/api/path.html#pathsep
*
* @category
* core
*
* @this {void}
*
* @param {URL | string} input
* The {@linkcode URL}, URL string, or path to handle
* @return {string}
* Directory name of `input`
*/
function dirname(this: void, input: URL | string): string {
validateURLString(input, 'input')
input = String(toPosix(input))
/**
* End index of directory name.
*
* @var {number} end
*/
let end: number = -1
/**
* End index of root.
*
* @var {number} rootEnd
*/
let rootEnd: number = -1
if (input.length > 1) {
/**
* Index to stop searching for directory name.
*
* @var {number} offset
*/
let offset: number = 0
if (canParseURL(input)) {
rootEnd = offset = input.lastIndexOf(new URL(input).pathname)
// input url does not include pathname -> input url is a url scheme
if (offset === -1) rootEnd = offset = input.length
// check for drive path so as not to mistake
// next path separator as beginning of absolute path
if (DRIVE_PATH_REGEX.test(input.slice(offset + 1))) offset++
}
if (isSep(input[offset])) {
rootEnd = ++offset
if (isSep(input[offset])) {
/**
* Current position in {@linkcode input}.
*
* @var {number} j
*/
let j: number = offset + 1
/**
* Last visited position in {@linkcode input}.
*
* @var {number} last
*/
let last: number = j
// match 1 or more non-path separators
while (j < input.length && !isSep(input[j])) j++
if (j < input.length && j !== last) {
last = j
// match 1 or more path separators
while (j < input.length && isSep(input[j])) j++
if (j < input.length && j !== last) {
last = j
// match 1 or more non-path separators
while (j < input.length && !isSep(input[j])) j++
// matched UNC root only
if (j === input.length) return input
// matched UNC root with leftovers.
// offset by 1 to include the separator after the UNC root to
// treat it as a "normal root" on top of a (UNC) root
if (j !== last) rootEnd = offset = j + 1
}
}
}
} else if (DRIVE_PATH_REGEX.test(input.slice(offset))) {
rootEnd = offset = input.indexOf(delimiter, offset) + 1
if (input.length > 2 && isSep(input[offset])) rootEnd = ++offset
}
/**
* Boolean indicating a path separator was seen.
*
* @var {boolean} separator
*/
let separator: boolean = true
for (let i = input.length - 1; i >= offset; --i) {
if (isSep(input[i])) {
if (!separator) {
end = i
break
}
} else {
// reached first character that is not a path separator
separator = false
}
}
}
return end === -1 && rootEnd === end
? input.length === 1 && isSep(input)
? sep
: dot
: isSep(input[0]) && end === 1
? sep + sep
: input.slice(0, end === -1 ? rootEnd : end)
}
export default dirname