|
6 | 6 | import type { Abortable } from 'node:events' |
7 | 7 | import type { |
8 | 8 | Dirent, |
| 9 | + MakeDirectoryOptions, |
9 | 10 | ObjectEncodingOptions, |
10 | 11 | OpenMode, |
11 | 12 | PathLike, |
@@ -1275,6 +1276,99 @@ export function safeDeleteSync( |
1275 | 1276 | }) |
1276 | 1277 | } |
1277 | 1278 |
|
| 1279 | +/** |
| 1280 | + * Safely create a directory asynchronously, ignoring EEXIST errors. |
| 1281 | + * This function wraps fs.promises.mkdir and handles the race condition where |
| 1282 | + * the directory might already exist, which is common in concurrent code. |
| 1283 | + * |
| 1284 | + * Unlike fs.promises.mkdir with recursive:true, this function: |
| 1285 | + * - Silently ignores EEXIST errors (directory already exists) |
| 1286 | + * - Re-throws all other errors (permissions, invalid path, etc.) |
| 1287 | + * - Works reliably in multi-process/concurrent scenarios |
| 1288 | + * |
| 1289 | + * @param path - Directory path to create |
| 1290 | + * @param options - Options including recursive and mode settings |
| 1291 | + * @returns Promise that resolves when directory is created or already exists |
| 1292 | + * |
| 1293 | + * @example |
| 1294 | + * ```ts |
| 1295 | + * // Create a directory, no error if it exists |
| 1296 | + * await safeMkdir('./config') |
| 1297 | + * |
| 1298 | + * // Create nested directories |
| 1299 | + * await safeMkdir('./data/cache/temp', { recursive: true }) |
| 1300 | + * |
| 1301 | + * // Create with specific permissions |
| 1302 | + * await safeMkdir('./secure', { mode: 0o700 }) |
| 1303 | + * ``` |
| 1304 | + */ |
| 1305 | +/*@__NO_SIDE_EFFECTS__*/ |
| 1306 | +export async function safeMkdir( |
| 1307 | + path: PathLike, |
| 1308 | + options?: MakeDirectoryOptions | undefined, |
| 1309 | +): Promise<void> { |
| 1310 | + const fs = getFs() |
| 1311 | + try { |
| 1312 | + await fs.promises.mkdir(path, options) |
| 1313 | + } catch (e: unknown) { |
| 1314 | + // Ignore EEXIST error - directory already exists. |
| 1315 | + if ( |
| 1316 | + typeof e === 'object' && |
| 1317 | + e !== null && |
| 1318 | + 'code' in e && |
| 1319 | + e.code !== 'EEXIST' |
| 1320 | + ) { |
| 1321 | + throw e |
| 1322 | + } |
| 1323 | + } |
| 1324 | +} |
| 1325 | + |
| 1326 | +/** |
| 1327 | + * Safely create a directory synchronously, ignoring EEXIST errors. |
| 1328 | + * This function wraps fs.mkdirSync and handles the race condition where |
| 1329 | + * the directory might already exist, which is common in concurrent code. |
| 1330 | + * |
| 1331 | + * Unlike fs.mkdirSync with recursive:true, this function: |
| 1332 | + * - Silently ignores EEXIST errors (directory already exists) |
| 1333 | + * - Re-throws all other errors (permissions, invalid path, etc.) |
| 1334 | + * - Works reliably in multi-process/concurrent scenarios |
| 1335 | + * |
| 1336 | + * @param path - Directory path to create |
| 1337 | + * @param options - Options including recursive and mode settings |
| 1338 | + * |
| 1339 | + * @example |
| 1340 | + * ```ts |
| 1341 | + * // Create a directory, no error if it exists |
| 1342 | + * safeMkdirSync('./config') |
| 1343 | + * |
| 1344 | + * // Create nested directories |
| 1345 | + * safeMkdirSync('./data/cache/temp', { recursive: true }) |
| 1346 | + * |
| 1347 | + * // Create with specific permissions |
| 1348 | + * safeMkdirSync('./secure', { mode: 0o700 }) |
| 1349 | + * ``` |
| 1350 | + */ |
| 1351 | +/*@__NO_SIDE_EFFECTS__*/ |
| 1352 | +export function safeMkdirSync( |
| 1353 | + path: PathLike, |
| 1354 | + options?: MakeDirectoryOptions | undefined, |
| 1355 | +): void { |
| 1356 | + const fs = getFs() |
| 1357 | + try { |
| 1358 | + fs.mkdirSync(path, options) |
| 1359 | + } catch (e: unknown) { |
| 1360 | + // Ignore EEXIST error - directory already exists. |
| 1361 | + if ( |
| 1362 | + typeof e === 'object' && |
| 1363 | + e !== null && |
| 1364 | + 'code' in e && |
| 1365 | + e.code !== 'EEXIST' |
| 1366 | + ) { |
| 1367 | + throw e |
| 1368 | + } |
| 1369 | + } |
| 1370 | +} |
| 1371 | + |
1278 | 1372 | /** |
1279 | 1373 | * Safely read a file asynchronously, returning undefined on error. |
1280 | 1374 | * Useful when you want to attempt reading a file without handling errors explicitly. |
|
0 commit comments