Skip to content

Commit dc1f191

Browse files
committed
Enhance fs and path helpers
1 parent efc3349 commit dc1f191

File tree

4 files changed

+87
-37
lines changed

4 files changed

+87
-37
lines changed

registry/lib/fs.d.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,9 @@ declare type WriteJsonOptions = Remap<
6565
}
6666
>
6767
declare const Fs: {
68+
isDirSync: (filepath: PathLike) => boolean
6869
isDirEmptySync: (
69-
dirname: string,
70+
dirname: PathLike,
7071
options?: IsDirEmptyOptions | undefined
7172
) => boolean
7273
isSymLinkSync(filepath: PathLike): boolean
@@ -75,7 +76,7 @@ declare const Fs: {
7576
options?: ReadDirOptions | undefined
7677
): Promise<string[]>
7778
readDirNamesSync: (
78-
dirname: string,
79+
dirname: PathLike,
7980
options?: ReadDirOptions | undefined
8081
) => string[]
8182
readFileBinary(
@@ -144,12 +145,12 @@ declare const Fs: {
144145
uniqueSync(filepath: PathLike): string
145146
writeJson(
146147
filepath: PathLike,
147-
json: JsonContent,
148+
jsonContent: JsonContent,
148149
options?: WriteJsonOptions | undefined
149150
): Promise<void>
150151
writeJsonSync(
151152
filepath: PathLike,
152-
json: JsonContent,
153+
jsonContent: JsonContent,
153154
options?: WriteJsonOptions | undefined
154155
): void
155156
}

registry/lib/fs.js

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const { freeze: ObjectFreeze } = Object
44

55
const { getGlobMatcher } = /*@__PURE__*/ require('./globs')
66
const { naturalCompare } = /*@__PURE__*/ require('./sorts')
7+
const { pathLikeToString } = /*@__PURE__*/ require('./path')
78
const { stripBom } = /*@__PURE__*/ require('./strings')
89

910
const defaultIgnore = ObjectFreeze([
@@ -111,7 +112,7 @@ function isDirEmptySync(dirname, options) {
111112
if (length === 0) {
112113
return true
113114
}
114-
const matcher = getGlobMatcher(ignore, { cwd: dirname })
115+
const matcher = getGlobMatcher(ignore, { cwd: pathLikeToString(dirname) })
115116
let ignoredCount = 0
116117
for (let i = 0; i < length; i += 1) {
117118
if (matcher(files[i])) {
@@ -135,9 +136,9 @@ function isSymLinkSync(filepath) {
135136

136137
/*@__NO_SIDE_EFFECTS__*/
137138
function parse(filepath, content, reviver, shouldThrow) {
138-
const str = Buffer.isBuffer(content) ? content.toString('utf8') : content
139+
const jsonStr = Buffer.isBuffer(content) ? content.toString('utf8') : content
139140
try {
140-
return JSON.parse(stripBom(str), reviver)
141+
return JSON.parse(stripBom(jsonStr), reviver)
141142
} catch (e) {
142143
if (shouldThrow) {
143144
if (e) {
@@ -323,7 +324,7 @@ function uniqueSync(filepath) {
323324
}
324325

325326
/*@__NO_SIDE_EFFECTS__*/
326-
async function writeJson(filepath, json, options) {
327+
async function writeJson(filepath, jsonContent, options) {
327328
if (typeof options === 'string') {
328329
options = { encoding: options }
329330
}
@@ -332,16 +333,16 @@ async function writeJson(filepath, json, options) {
332333
...options
333334
}
334335
const fs = getFs()
335-
const str = stringify(json, EOL, finalEOL, replacer, spaces)
336-
await fs.promises.writeFile(filepath, str, {
336+
const jsonString = stringify(jsonContent, EOL, finalEOL, replacer, spaces)
337+
await fs.promises.writeFile(filepath, jsonString, {
337338
__proto__: null,
338339
encoding: 'utf8',
339340
...fsOptions
340341
})
341342
}
342343

343344
/*@__NO_SIDE_EFFECTS__*/
344-
function writeJsonSync(filepath, json, options) {
345+
function writeJsonSync(filepath, jsonContent, options) {
345346
if (typeof options === 'string') {
346347
options = { encoding: options }
347348
}
@@ -350,8 +351,8 @@ function writeJsonSync(filepath, json, options) {
350351
...options
351352
}
352353
const fs = getFs()
353-
const str = stringify(json, EOL, finalEOL, replacer, spaces)
354-
fs.writeFileSync(filepath, str, {
354+
const jsonString = stringify(jsonContent, EOL, finalEOL, replacer, spaces)
355+
fs.writeFileSync(filepath, jsonString, {
355356
__proto__: null,
356357
encoding: 'utf8',
357358
...fsOptions

registry/lib/path.d.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1+
/// <reference types="node" />
2+
import { PathLike } from 'node:fs'
3+
14
declare const Path: {
2-
isNodes(filepath: string): boolean
3-
isRelative(filepath: string): boolean
4-
normalizePath(filePath: string): string
5-
splitPath(filepath: string): string[]
6-
trimLeadingDotSlash(filepath: string): string
5+
isNodeModules(pathLike: PathLike): boolean
6+
isRelative(pathLike: PathLike): boolean
7+
normalizePath(pathLike: PathLike): string
8+
pathLikeToString(pathLike: PathLike): string
9+
splitPath(pathLike: PathLike): string[]
10+
trimLeadingDotSlash(pathLike: PathLike): string
711
}
812
declare namespace Path {}
913
export = Path

registry/lib/path.js

Lines changed: 63 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,37 @@ const leadingDotSlashRegExp = /^\.\.?[/\\]/
66
const slashRegExp = /[/\\]/
77
const nodeModulesPathRegExp = /(?:^|[/\\])node_modules(?:[/\\]|$)/
88

9+
let _buffer
910
/*@__NO_SIDE_EFFECTS__*/
10-
function isNodeModules(filepath) {
11+
function getBuffer() {
12+
if (_buffer === undefined) {
13+
// Use non-'node:' prefixed require to avoid Webpack errors.
14+
// eslint-disable-next-line n/prefer-node-protocol
15+
_buffer = /*@__PURE__*/ require('buffer')
16+
}
17+
return _buffer
18+
}
19+
20+
let _url
21+
/*@__NO_SIDE_EFFECTS__*/
22+
function getUrl() {
23+
if (_url === undefined) {
24+
// Use non-'node:' prefixed require to avoid Webpack errors.
25+
// eslint-disable-next-line n/prefer-node-protocol
26+
_url = /*@__PURE__*/ require('url')
27+
}
28+
return _url
29+
}
30+
31+
/*@__NO_SIDE_EFFECTS__*/
32+
function isNodeModules(pathLike) {
33+
const filepath = pathLikeToString(pathLike)
1134
return nodeModulesPathRegExp.test(filepath)
1235
}
1336

1437
/*@__NO_SIDE_EFFECTS__*/
15-
function isRelative(filepath) {
38+
function isRelative(pathLike) {
39+
const filepath = pathLikeToString(pathLike)
1640
if (typeof filepath !== 'string') {
1741
return false
1842
}
@@ -34,12 +58,13 @@ function isRelative(filepath) {
3458
}
3559

3660
/*@__NO_SIDE_EFFECTS__*/
37-
function normalizePath(filePath) {
38-
const { length } = filePath
61+
function normalizePath(pathLike) {
62+
const filepath = pathLikeToString(pathLike)
63+
const { length } = filepath
3964
if (length < 2) {
40-
return length === 1 && filePath.charCodeAt(0) === 92 /*'\\'*/
65+
return length === 1 && filepath.charCodeAt(0) === 92 /*'\\'*/
4166
? '/'
42-
: filePath
67+
: filepath
4368
}
4469

4570
let code = 0
@@ -53,13 +78,13 @@ function normalizePath(filePath) {
5378
// are okay to convert to forward slashes.
5479
// https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#naming-conventions
5580
let prefix = ''
56-
if (length > 4 && filePath.charCodeAt(3) === 92 /*'\\'*/) {
57-
const code2 = filePath.charCodeAt(2)
81+
if (length > 4 && filepath.charCodeAt(3) === 92 /*'\\'*/) {
82+
const code2 = filepath.charCodeAt(2)
5883
// Look for \\?\ or \\.\
5984
if (
6085
(code2 === 63 /*'?'*/ || code2 === 46) /*'.'*/ &&
61-
filePath.charCodeAt(0) === 92 /*'\\'*/ &&
62-
filePath.charCodeAt(1) === 92 /*'\\'*/
86+
filepath.charCodeAt(0) === 92 /*'\\'*/ &&
87+
filepath.charCodeAt(1) === 92 /*'\\'*/
6388
) {
6489
start = 2
6590
prefix = '//'
@@ -68,7 +93,7 @@ function normalizePath(filePath) {
6893
if (start === 0) {
6994
// Trim leading slashes
7095
while (
71-
((code = filePath.charCodeAt(start)),
96+
((code = filepath.charCodeAt(start)),
7297
code === 47 /*'/'*/ || code === 92) /*'\\'*/
7398
) {
7499
start += 1
@@ -77,44 +102,63 @@ function normalizePath(filePath) {
77102
prefix = '/'
78103
}
79104
}
80-
let nextIndex = search(filePath, slashRegExp, start)
105+
let nextIndex = search(filepath, slashRegExp, start)
81106
if (nextIndex === -1) {
82-
return prefix + filePath.slice(start)
107+
return prefix + filepath.slice(start)
83108
}
84109
// Discard any empty string segments by collapsing repeated segment separator slashes.
85110
while (nextIndex !== -1) {
86-
const segment = filePath.slice(start, nextIndex)
111+
const segment = filepath.slice(start, nextIndex)
87112
collapsed = collapsed + (collapsed.length === 0 ? '' : '/') + segment
88113
start = nextIndex + 1
89114
while (
90-
((code = filePath.charCodeAt(start)),
115+
((code = filepath.charCodeAt(start)),
91116
code === 47 /*'/'*/ || code === 92) /*'\\'*/
92117
) {
93118
start += 1
94119
}
95-
nextIndex = search(filePath, slashRegExp, start)
120+
nextIndex = search(filepath, slashRegExp, start)
96121
}
97-
const lastSegment = filePath.slice(start)
122+
const lastSegment = filepath.slice(start)
98123
if (lastSegment.length !== 0) {
99124
collapsed = collapsed + '/' + lastSegment
100125
}
101126
return prefix + collapsed
102127
}
103128

104129
/*@__NO_SIDE_EFFECTS__*/
105-
function splitPath(filepath) {
130+
function pathLikeToString(pathLike) {
131+
if (typeof pathLike === 'string') {
132+
return pathLike
133+
}
134+
const Buffer = getBuffer()
135+
if (Buffer.isBuffer(pathLike)) {
136+
return pathLike.toString('utf8')
137+
}
138+
const url = getUrl()
139+
if (pathLike instanceof URL) {
140+
return url.fileURLToPath(pathLike)
141+
}
142+
return String(pathLike)
143+
}
144+
145+
/*@__NO_SIDE_EFFECTS__*/
146+
function splitPath(pathLike) {
147+
const filepath = pathLikeToString(pathLike)
106148
return filepath.split(slashRegExp)
107149
}
108150

109151
/*@__NO_SIDE_EFFECTS__*/
110-
function trimLeadingDotSlash(filepath) {
152+
function trimLeadingDotSlash(pathLike) {
153+
const filepath = pathLikeToString(pathLike)
111154
return filepath.replace(leadingDotSlashRegExp, '')
112155
}
113156

114157
module.exports = {
115158
isNodeModules,
116159
isRelative,
117160
normalizePath,
161+
pathLikeToString,
118162
splitPath,
119163
trimLeadingDotSlash
120164
}

0 commit comments

Comments
 (0)