@@ -301,6 +301,26 @@ const defaultRemoveOptions = objectFreeze({
301301 retryDelay : 200 ,
302302} )
303303
304+ let _buffer : typeof import ( 'node:buffer' ) | undefined
305+ /**
306+ * Lazily load the buffer module.
307+ *
308+ * Performs on-demand loading of Node.js buffer module to avoid initialization
309+ * overhead and potential Webpack bundling errors.
310+ *
311+ * @private
312+ * @returns {typeof import('node:buffer') } The buffer module
313+ */
314+ /*@__NO_SIDE_EFFECTS__ */
315+ function getBuffer ( ) {
316+ if ( _buffer === undefined ) {
317+ // Use non-'node:' prefixed require to avoid Webpack errors.
318+
319+ _buffer = /*@__PURE__ */ require ( 'node:buffer' )
320+ }
321+ return _buffer as typeof import ( 'node:buffer' )
322+ }
323+
304324let _fs : typeof import ( 'fs' ) | undefined
305325/**
306326 * Lazily load the fs module to avoid Webpack errors.
@@ -983,8 +1003,8 @@ export async function readJson(
9831003 try {
9841004 content = await fs . promises . readFile ( filepath , {
9851005 __proto__ : null ,
986- encoding : 'utf8' ,
9871006 ...fsOptions ,
1007+ encoding : 'utf8' ,
9881008 } as unknown as Parameters < typeof fs . promises . readFile > [ 1 ] & {
9891009 encoding : string
9901010 } )
@@ -1060,8 +1080,8 @@ export function readJsonSync(
10601080 try {
10611081 content = fs . readFileSync ( filepath , {
10621082 __proto__ : null ,
1063- encoding : 'utf8' ,
10641083 ...fsOptions ,
1084+ encoding : 'utf8' ,
10651085 } as unknown as Parameters < typeof fs . readFileSync > [ 1 ] & {
10661086 encoding : string
10671087 } )
@@ -1381,74 +1401,133 @@ export function safeMkdirSync(
13811401 * Safely read a file asynchronously, returning undefined on error.
13821402 * Useful when you want to attempt reading a file without handling errors explicitly.
13831403 * Returns undefined for any error (file not found, permission denied, etc.).
1404+ * Defaults to UTF-8 encoding, returning a string unless encoding is explicitly set to null.
13841405 *
13851406 * @param filepath - Path to file
13861407 * @param options - Read options including encoding and default value
1387- * @returns Promise resolving to file contents, or undefined on error
1408+ * @returns Promise resolving to file contents (string by default) , or undefined on error
13881409 *
13891410 * @example
13901411 * ```ts
1391- * // Try to read a file, get undefined if it doesn't exist
1412+ * // Try to read a file as UTF-8 string (default) , get undefined if it doesn't exist
13921413 * const content = await safeReadFile('./optional-config.txt')
13931414 * if (content) {
13941415 * console.log('Config found:', content)
13951416 * }
13961417 *
13971418 * // Read with specific encoding
13981419 * const data = await safeReadFile('./data.txt', { encoding: 'utf8' })
1420+ *
1421+ * // Read as Buffer by setting encoding to null
1422+ * const buffer = await safeReadFile('./binary.dat', { encoding: null })
13991423 * ```
14001424 */
14011425/*@__NO_SIDE_EFFECTS__ */
1426+ export async function safeReadFile (
1427+ filepath : PathLike ,
1428+ options : SafeReadOptions & { encoding : null } ,
1429+ ) : Promise < Buffer | undefined >
1430+ /*@__NO_SIDE_EFFECTS__ */
14021431export async function safeReadFile (
14031432 filepath : PathLike ,
14041433 options ?: SafeReadOptions | undefined ,
1405- ) {
1406- const opts = typeof options === 'string' ? { encoding : options } : options
1434+ ) : Promise < string | undefined >
1435+ /*@__NO_SIDE_EFFECTS__ */
1436+ export async function safeReadFile (
1437+ filepath : PathLike ,
1438+ options ?: SafeReadOptions | undefined ,
1439+ ) : Promise < string | Buffer | undefined > {
1440+ const opts =
1441+ typeof options === 'string'
1442+ ? { __proto__ : null , encoding : options }
1443+ : ( { __proto__ : null , ...options } as SafeReadOptions )
1444+ const { defaultValue, ...rawReadOpts } = opts as SafeReadOptions
1445+ const readOpts = { __proto__ : null , ...rawReadOpts } as ReadOptions
1446+ const { encoding = 'utf8' } = readOpts
1447+ const shouldReturnBuffer = encoding === null
14071448 const fs = getFs ( )
14081449 try {
14091450 return await fs . promises . readFile ( filepath , {
1451+ __proto__ : null ,
14101452 signal : abortSignal ,
1411- ...opts ,
1453+ ...readOpts ,
1454+ encoding,
14121455 } as Abortable )
14131456 } catch { }
1414- return undefined
1457+ if ( defaultValue === undefined ) {
1458+ return undefined
1459+ }
1460+ if ( shouldReturnBuffer ) {
1461+ const { Buffer } = getBuffer ( )
1462+ return Buffer . isBuffer ( defaultValue ) ? defaultValue : undefined
1463+ }
1464+ return typeof defaultValue === 'string' ? defaultValue : String ( defaultValue )
14151465}
14161466
14171467/**
14181468 * Safely read a file synchronously, returning undefined on error.
14191469 * Useful when you want to attempt reading a file without handling errors explicitly.
14201470 * Returns undefined for any error (file not found, permission denied, etc.).
1471+ * Defaults to UTF-8 encoding, returning a string unless encoding is explicitly set to null.
14211472 *
14221473 * @param filepath - Path to file
14231474 * @param options - Read options including encoding and default value
1424- * @returns File contents, or undefined on error
1475+ * @returns File contents (string by default) , or undefined on error
14251476 *
14261477 * @example
14271478 * ```ts
1428- * // Try to read a config file
1479+ * // Try to read a config file as UTF-8 string (default)
14291480 * const config = safeReadFileSync('./config.txt')
14301481 * if (config) {
14311482 * console.log('Config loaded successfully')
14321483 * }
14331484 *
1434- * // Read binary file safely
1485+ * // Read with explicit encoding
1486+ * const data = safeReadFileSync('./data.txt', { encoding: 'utf8' })
1487+ *
1488+ * // Read binary file by setting encoding to null
14351489 * const buffer = safeReadFileSync('./image.png', { encoding: null })
14361490 * ```
14371491 */
14381492/*@__NO_SIDE_EFFECTS__ */
1493+ export function safeReadFileSync (
1494+ filepath : PathLike ,
1495+ options : SafeReadOptions & { encoding : null } ,
1496+ ) : Buffer | undefined
1497+ /*@__NO_SIDE_EFFECTS__ */
14391498export function safeReadFileSync (
14401499 filepath : PathLike ,
14411500 options ?: SafeReadOptions | undefined ,
1442- ) {
1443- const opts = typeof options === 'string' ? { encoding : options } : options
1501+ ) : string | undefined
1502+ /*@__NO_SIDE_EFFECTS__ */
1503+ export function safeReadFileSync (
1504+ filepath : PathLike ,
1505+ options ?: SafeReadOptions | undefined ,
1506+ ) : string | Buffer | undefined {
1507+ const opts =
1508+ typeof options === 'string'
1509+ ? { __proto__ : null , encoding : options }
1510+ : ( { __proto__ : null , ...options } as SafeReadOptions )
1511+ const { defaultValue, ...rawReadOpts } = opts as SafeReadOptions
1512+ const readOpts = { __proto__ : null , ...rawReadOpts } as ReadOptions
1513+ const { encoding = 'utf8' } = readOpts
1514+ const shouldReturnBuffer = encoding === null
14441515 const fs = getFs ( )
14451516 try {
14461517 return fs . readFileSync ( filepath , {
14471518 __proto__ : null ,
1448- ...opts ,
1519+ ...readOpts ,
1520+ encoding,
14491521 } as ObjectEncodingOptions )
14501522 } catch { }
1451- return undefined
1523+ if ( defaultValue === undefined ) {
1524+ return undefined
1525+ }
1526+ if ( shouldReturnBuffer ) {
1527+ const { Buffer } = getBuffer ( )
1528+ return Buffer . isBuffer ( defaultValue ) ? defaultValue : undefined
1529+ }
1530+ return typeof defaultValue === 'string' ? defaultValue : String ( defaultValue )
14521531}
14531532
14541533/**
0 commit comments