@wrote/ensure-path
Version:
Create all directories on the way to the path.
78 lines (73 loc) • 2.11 kB
JavaScript
const { mkdir, mkdirSync } = require('fs');
const makePromise = require('makepromise');
const { dirname } = require('path');
/**
* Makes sure that a file can be created by creating all directories to which it belongs to, e.g., `ensurePath('~/path/to/wrote.data')` will attempt to create `~/path/to` directory recursively.
* @param {string} path The path to the file.
* @throws {Error} When the first folder in the path is non-executable.
*/
async function ensurePath(path) {
const dir = dirname(path)
try {
await make(dir)
return path
} catch (err) {
if (/EEXIST/.test(err.message) && err.message.indexOf(dir) != -1) {
return path
}
throw err
}
}
/**
* Recursive promise-based mkdir.
* @param {string} dir Path to the directory to be created
*/
async function make(dir) {
try {
await makePromise(mkdir, dir)
} catch (err) {
if (err.code == 'ENOENT') {
const parentDir = dirname(dir)
await make(parentDir)
await make(dir)
} else if (err.code != 'EEXIST') { // created in parallel
throw err
}
}
}
/**
* Makes sure that a file can be created by creating all directories to which it belongs to synchronously, e.g., `ensurePath('~/path/to/wrote.data')` will attempt to create `~/path/to` directory recursively.
* @param {string} path The path to the file.
* @throws {Error} When the first folder in the path is non-executable.
*/
function ensurePathSync(path) {
const dir = dirname(path)
try {
makeSync(dir)
return path
} catch (err) {
if (/EEXIST/.test(err.message) && err.message.indexOf(dir) != -1) {
return path
}
throw err
}
}
/**
* Recursive promise-based mkdir.
* @param {string} dir Path to the directory to be created
*/
function makeSync(dir) {
try {
mkdirSync(dir)
} catch (err) {
if (err.code == 'ENOENT') {
const parentDir = dirname(dir)
makeSync(parentDir)
makeSync(dir)
} else if (err.code != 'EEXIST') { // created in parallel
throw err
}
}
}
module.exports = ensurePath
module.exports.ensurePathSync = ensurePathSync