@@ -24,16 +24,6 @@ import type {
2424 deleteSync as deleteSyncType ,
2525} from './external/del'
2626
27- let _del :
28- | { deleteAsync : typeof deleteAsyncType ; deleteSync : typeof deleteSyncType }
29- | undefined
30- /*@__NO_SIDE_EFFECTS__ */
31- function getDel ( ) {
32- if ( _del === undefined ) {
33- _del = /*@__PURE__ */ require ( './external/del' )
34- }
35- return _del !
36- }
3727import { pRetry } from './promises'
3828import { defaultIgnore , getGlobMatcher } from './globs'
3929import type { JsonReviver } from './json/types'
@@ -312,6 +302,22 @@ export interface WriteJsonOptions extends WriteOptions {
312302 spaces ?: number | string | undefined
313303}
314304
305+ /**
306+ * Result of file readability validation.
307+ * Contains lists of valid and invalid file paths.
308+ */
309+ export interface ValidateFilesResult {
310+ /**
311+ * File paths that passed validation and are readable.
312+ */
313+ validPaths : string [ ]
314+ /**
315+ * File paths that failed validation (unreadable, permission denied, or non-existent).
316+ * Common with Yarn Berry PnP virtual filesystem, pnpm symlinks, or filesystem race conditions.
317+ */
318+ invalidPaths : string [ ]
319+ }
320+
315321const defaultRemoveOptions = objectFreeze ( {
316322 __proto__ : null ,
317323 force : true ,
@@ -320,8 +326,14 @@ const defaultRemoveOptions = objectFreeze({
320326 retryDelay : 200 ,
321327} )
322328
329+ let _del :
330+ | { deleteAsync : typeof deleteAsyncType ; deleteSync : typeof deleteSyncType }
331+ | undefined
323332// Cache for resolved allowed directories
324333let _cachedAllowedDirs : string [ ] | undefined
334+ let _buffer : typeof import ( 'node:buffer' ) | undefined
335+ let _fs : typeof import ( 'node:fs' ) | undefined
336+ let _path : typeof import ( 'node:path' ) | undefined
325337
326338/**
327339 * Get resolved allowed directories for safe deletion with lazy caching.
@@ -341,7 +353,6 @@ function getAllowedDirectories(): string[] {
341353 return _cachedAllowedDirs
342354}
343355
344- let _buffer : typeof import ( 'node:buffer' ) | undefined
345356/**
346357 * Lazily load the buffer module.
347358 *
@@ -360,7 +371,14 @@ function getBuffer() {
360371 return _buffer as typeof import ( 'node:buffer' )
361372}
362373
363- let _fs : typeof import ( 'node:fs' ) | undefined
374+ /*@__NO_SIDE_EFFECTS__ */
375+ function getDel ( ) {
376+ if ( _del === undefined ) {
377+ _del = /*@__PURE__ */ require ( './external/del' )
378+ }
379+ return _del !
380+ }
381+
364382/**
365383 * Lazily load the fs module to avoid Webpack errors.
366384 * Uses non-'node:' prefixed require to prevent Webpack bundling issues.
@@ -377,7 +395,6 @@ function getFs() {
377395 return _fs as typeof import ( 'node:fs' )
378396}
379397
380- let _path : typeof import ( 'node:path' ) | undefined
381398/**
382399 * Lazily load the path module to avoid Webpack errors.
383400 * Uses non-'node:' prefixed require to prevent Webpack bundling issues.
@@ -623,9 +640,6 @@ export function invalidatePathCache(): void {
623640 _cachedAllowedDirs = undefined
624641}
625642
626- // Register cache invalidation with the rewire module
627- registerCacheInvalidation ( invalidatePathCache )
628-
629643/**
630644 * Check if a path is a directory asynchronously.
631645 * Returns `true` for directories, `false` for files or non-existent paths.
@@ -645,25 +659,6 @@ export async function isDir(filepath: PathLike) {
645659 return ! ! ( await safeStats ( filepath ) ) ?. isDirectory ( )
646660}
647661
648- /**
649- * Check if a path is a directory synchronously.
650- * Returns `true` for directories, `false` for files or non-existent paths.
651- *
652- * @param filepath - Path to check
653- * @returns `true` if path is a directory, `false` otherwise
654- *
655- * @example
656- * ```ts
657- * if (isDirSync('./src')) {
658- * console.log('src is a directory')
659- * }
660- * ```
661- */
662- /*@__NO_SIDE_EFFECTS__ */
663- export function isDirSync ( filepath : PathLike ) {
664- return ! ! safeStatsSync ( filepath ) ?. isDirectory ( )
665- }
666-
667662/**
668663 * Check if a directory is empty synchronously.
669664 * A directory is considered empty if it contains no files after applying ignore patterns.
@@ -718,6 +713,25 @@ export function isDirEmptySync(
718713 }
719714}
720715
716+ /**
717+ * Check if a path is a directory synchronously.
718+ * Returns `true` for directories, `false` for files or non-existent paths.
719+ *
720+ * @param filepath - Path to check
721+ * @returns `true` if path is a directory, `false` otherwise
722+ *
723+ * @example
724+ * ```ts
725+ * if (isDirSync('./src')) {
726+ * console.log('src is a directory')
727+ * }
728+ * ```
729+ */
730+ /*@__NO_SIDE_EFFECTS__ */
731+ export function isDirSync ( filepath : PathLike ) {
732+ return ! ! safeStatsSync ( filepath ) ?. isDirectory ( )
733+ }
734+
721735/**
722736 * Check if a path is a symbolic link synchronously.
723737 * Uses `lstat` to check the link itself, not the target.
@@ -982,67 +996,67 @@ export async function readFileBinary(
982996}
983997
984998/**
985- * Read a file as UTF-8 text asynchronously .
986- * Returns a string with the file contents decoded as UTF-8 .
987- * This is the most common way to read text files .
999+ * Read a file as binary data synchronously .
1000+ * Returns a Buffer without encoding the contents.
1001+ * Useful for reading images, archives, or other binary formats .
9881002 *
9891003 * @param filepath - Path to file
990- * @param options - Read options including encoding and abort signal
991- * @returns Promise resolving to string containing file contents
1004+ * @param options - Read options ( encoding is forced to null for binary)
1005+ * @returns Buffer containing file contents
9921006 *
9931007 * @example
9941008 * ```ts
995- * // Read a text file
996- * const content = await readFileUtf8 ('./README.md ')
1009+ * // Read an image file
1010+ * const imageBuffer = readFileBinarySync ('./logo.png ')
9971011 *
998- * // Read with custom encoding
999- * const content = await readFileUtf8 ('./data.txt', { encoding: 'utf-8' } )
1012+ * // Read a compressed file
1013+ * const gzipData = readFileBinarySync ('./archive.gz' )
10001014 * ```
10011015 */
10021016/*@__NO_SIDE_EFFECTS__ */
1003- export async function readFileUtf8 (
1017+ export function readFileBinarySync (
10041018 filepath : PathLike ,
10051019 options ?: ReadFileOptions | undefined ,
10061020) {
1021+ // Don't specify encoding to get a Buffer
10071022 const opts = typeof options === 'string' ? { encoding : options } : options
10081023 const fs = getFs ( )
1009- return await fs . promises . readFile ( filepath , {
1010- signal : abortSignal ,
1024+ return fs . readFileSync ( filepath , {
10111025 ...opts ,
1012- encoding : 'utf8' ,
1013- } )
1026+ encoding : null ,
1027+ } as ObjectEncodingOptions )
10141028}
10151029
10161030/**
1017- * Read a file as binary data synchronously .
1018- * Returns a Buffer without encoding the contents.
1019- * Useful for reading images, archives, or other binary formats .
1031+ * Read a file as UTF-8 text asynchronously .
1032+ * Returns a string with the file contents decoded as UTF-8 .
1033+ * This is the most common way to read text files .
10201034 *
10211035 * @param filepath - Path to file
1022- * @param options - Read options ( encoding is forced to null for binary)
1023- * @returns Buffer containing file contents
1036+ * @param options - Read options including encoding and abort signal
1037+ * @returns Promise resolving to string containing file contents
10241038 *
10251039 * @example
10261040 * ```ts
1027- * // Read an image file
1028- * const imageBuffer = readFileBinarySync ('./logo.png ')
1041+ * // Read a text file
1042+ * const content = await readFileUtf8 ('./README.md ')
10291043 *
1030- * // Read a compressed file
1031- * const gzipData = readFileBinarySync ('./archive.gz' )
1044+ * // Read with custom encoding
1045+ * const content = await readFileUtf8 ('./data.txt', { encoding: 'utf-8' } )
10321046 * ```
10331047 */
10341048/*@__NO_SIDE_EFFECTS__ */
1035- export function readFileBinarySync (
1049+ export async function readFileUtf8 (
10361050 filepath : PathLike ,
10371051 options ?: ReadFileOptions | undefined ,
10381052) {
1039- // Don't specify encoding to get a Buffer
10401053 const opts = typeof options === 'string' ? { encoding : options } : options
10411054 const fs = getFs ( )
1042- return fs . readFileSync ( filepath , {
1055+ return await fs . promises . readFile ( filepath , {
1056+ signal : abortSignal ,
10431057 ...opts ,
1044- encoding : null ,
1045- } as ObjectEncodingOptions )
1058+ encoding : 'utf8' ,
1059+ } )
10461060}
10471061
10481062/**
@@ -1778,22 +1792,6 @@ export function uniqueSync(filepath: PathLike): string {
17781792 return normalizePath ( uniquePath )
17791793}
17801794
1781- /**
1782- * Result of file readability validation.
1783- * Contains lists of valid and invalid file paths.
1784- */
1785- export interface ValidateFilesResult {
1786- /**
1787- * File paths that passed validation and are readable.
1788- */
1789- validPaths : string [ ]
1790- /**
1791- * File paths that failed validation (unreadable, permission denied, or non-existent).
1792- * Common with Yarn Berry PnP virtual filesystem, pnpm symlinks, or filesystem race conditions.
1793- */
1794- invalidPaths : string [ ]
1795- }
1796-
17971795/**
17981796 * Validate that file paths are readable before processing.
17991797 * Filters out files from glob results that cannot be accessed (common with
@@ -1947,3 +1945,6 @@ export function writeJsonSync(
19471945 __proto__ : null ,
19481946 } as WriteFileOptions )
19491947}
1948+
1949+ // Register cache invalidation with the rewire module
1950+ registerCacheInvalidation ( invalidatePathCache )
0 commit comments