Skip to content

Commit

Permalink
Meta tweaks
Browse files Browse the repository at this point in the history
  • Loading branch information
sindresorhus committed Dec 31, 2018
1 parent d1d3929 commit f38a1b7
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 73 deletions.
3 changes: 1 addition & 2 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
* text=auto
*.js text eol=lf
* text=auto eol=lf
44 changes: 22 additions & 22 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,28 +15,28 @@ const checkPath = pth => {
const pathHasInvalidWinCharacters = /[<>:"|?*]/.test(pth.replace(path.parse(pth).root, ''));

if (pathHasInvalidWinCharacters) {
const err = new Error(`Path contains invalid characters: ${pth}`);
err.code = 'EINVAL';
throw err;
const error = new Error(`Path contains invalid characters: ${pth}`);
error.code = 'EINVAL';
throw error;
}
}
};

module.exports = (input, opts) => Promise.resolve().then(() => {
module.exports = (input, options) => Promise.resolve().then(() => {
checkPath(input);
opts = Object.assign({}, defaults, opts);
options = Object.assign({}, defaults, options);

// TODO: Use util.promisify when targeting Node.js 8
const mkdir = pify(opts.fs.mkdir);
const stat = pify(opts.fs.stat);
const mkdir = pify(options.fs.mkdir);
const stat = pify(options.fs.stat);

const make = pth => {
return mkdir(pth, opts.mode)
return mkdir(pth, options.mode)
.then(() => pth)
.catch(err => {
if (err.code === 'ENOENT') {
if (err.message.includes('null bytes') || path.dirname(pth) === pth) {
throw err;
.catch(error => {
if (error.code === 'ENOENT') {
if (error.message.includes('null bytes') || path.dirname(pth) === pth) {
throw error;
}

return make(path.dirname(pth)).then(() => make(pth));
Expand All @@ -45,37 +45,37 @@ module.exports = (input, opts) => Promise.resolve().then(() => {
return stat(pth)
.then(stats => stats.isDirectory() ? pth : Promise.reject())
.catch(() => {
throw err;
throw error;
});
});
};

return make(path.resolve(input));
});

module.exports.sync = (input, opts) => {
module.exports.sync = (input, options) => {
checkPath(input);
opts = Object.assign({}, defaults, opts);
options = Object.assign({}, defaults, options);

const make = pth => {
try {
opts.fs.mkdirSync(pth, opts.mode);
} catch (err) {
if (err.code === 'ENOENT') {
if (err.message.includes('null bytes') || path.dirname(pth) === pth) {
throw err;
options.fs.mkdirSync(pth, options.mode);
} catch (error) {
if (error.code === 'ENOENT') {
if (error.message.includes('null bytes') || path.dirname(pth) === pth) {
throw error;
}

make(path.dirname(pth));
return make(pth);
}

try {
if (!opts.fs.statSync(pth).isDirectory()) {
if (!options.fs.statSync(pth).isDirectory()) {
throw new Error('The path is not a directory');
}
} catch (_) {
throw err;
throw error;
}
}

Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@
"pify": "^4.0.1"
},
"devDependencies": {
"ava": "*",
"ava": "^1.0.1",
"codecov": "^3.0.0",
"graceful-fs": "^4.1.11",
"nyc": "^11.3.0",
"nyc": "^13.1.0",
"path-type": "^3.0.0",
"tempy": "^0.2.1",
"xo": "*"
"xo": "^0.23.0"
}
}
18 changes: 11 additions & 7 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,12 @@ $ tree
```js
const makeDir = require('make-dir');

makeDir('unicorn/rainbow/cake').then(path => {
(async () => {
const path = await makeDir('unicorn/rainbow/cake');

console.log(path);
//=> '/Users/sindresorhus/fun/unicorn/rainbow/cake'
});
})();
```

```
Expand All @@ -51,18 +53,20 @@ Multiple directories:
```js
const makeDir = require('make-dir');

Promise.all([
makeDir('unicorn/rainbow')
makeDir('foo/bar')
]).then(paths => {
(async () => {
const paths = await Promise.all([
makeDir('unicorn/rainbow')
makeDir('foo/bar')
]);

console.log(paths);
/*
[
'/Users/sindresorhus/fun/unicorn/rainbow',
'/Users/sindresorhus/fun/foo/bar'
]
*/
});
})();
```


Expand Down
40 changes: 22 additions & 18 deletions test/async.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,55 +4,54 @@ import test from 'ava';
import tempy from 'tempy';
import gracefulFs from 'graceful-fs';
import {getFixture, assertDir} from './helpers/util';
import m from '..';
import makeDir from '..';

test('main', async t => {
const dir = getFixture();
const madeDir = await m(dir);
const madeDir = await makeDir(dir);
t.true(madeDir.length > 0);
assertDir(t, madeDir);
});

test('`fs` option', async t => {
const dir = getFixture();
await m(dir, {fs: gracefulFs});
await makeDir(dir, {fs: gracefulFs});
assertDir(t, dir);
});

test('`mode` option', async t => {
const dir = getFixture();
const mode = 0o744;
await m(dir, {mode});
await makeDir(dir, {mode});
assertDir(t, dir, mode);

// Ensure it's writable
await m(dir);
await makeDir(dir);
assertDir(t, dir, mode);
});

test('dir exists', async t => {
const dir = await m(tempy.directory());
const dir = await makeDir(tempy.directory());
t.true(dir.length > 0);
assertDir(t, dir);
});

test('file exits', async t => {
const fp = tempy.file();
fs.writeFileSync(fp, '');
const err = await t.throwsAsync(m(fp));
t.is(err.code, 'EEXIST');
await t.throwsAsync(makeDir(fp), {code: 'EEXIST'});
});

test('root dir', async t => {
const mode = fs.statSync('/').mode & 0o777;
const dir = await m('/');
const dir = await makeDir('/');
t.true(dir.length > 0);
assertDir(t, dir, mode);
});

test('race two', async t => {
const dir = getFixture();
await Promise.all([m(dir), m(dir)]);
await Promise.all([makeDir(dir), makeDir(dir)]);
assertDir(t, dir);
});

Expand All @@ -61,7 +60,7 @@ test('race many', async t => {
const all = [];

for (let i = 0; i < 100; i++) {
all.push(m(dir));
all.push(makeDir(dir));
}

await Promise.all(all);
Expand All @@ -70,8 +69,8 @@ test('race many', async t => {

test('handles null bytes in path', async t => {
const dir = path.join(tempy.directory(), 'foo\u0000bar');
const err = await t.throwsAsync(m(dir), /null bytes/);
t.regex(err.code, /ERR_INVALID_ARG_VALUE|ENOENT/);
const error = await t.throwsAsync(makeDir(dir), /null bytes/);
t.regex(error.code, /ERR_INVALID_ARG_VALUE|ENOENT/);
});

test.serial('handles invalid path characters', async t => {
Expand All @@ -82,11 +81,14 @@ test.serial('handles invalid path characters', async t => {
});

// Also to please `nyc`
await m(tempy.directory());
await makeDir(tempy.directory());

const dir = path.join(tempy.directory(), 'foo"bar');
const err = await t.throwsAsync(m(dir), /invalid characters/);
t.is(err.code, 'EINVAL');

await t.throwsAsync(makeDir(dir), {
code: 'EINVAL',
message: /invalid characters/
});

Object.defineProperty(process, 'platform', {
value: platform
Expand All @@ -96,7 +98,9 @@ test.serial('handles invalid path characters', async t => {
if (process.platform === 'win32') {
test('handles non-existent root', async t => {
// We assume the `o:\` drive doesn't exist on Windows
const err = await t.throwsAsync(m('o:\\foo'), /no such file or directory/);
t.is(err.code, 'ENOENT');
await t.throwsAsync(makeDir('o:\\foo'), {
code: 'ENOENT',
message: /no such file or directory/
});
});
}
44 changes: 23 additions & 21 deletions test/sync.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,85 +4,87 @@ import test from 'ava';
import tempy from 'tempy';
import gracefulFs from 'graceful-fs';
import {getFixture, assertDir} from './helpers/util';
import m from '..';
import makeDir from '..';

test('main', t => {
const dir = getFixture();
const madeDir = m.sync(dir);
const madeDir = makeDir.sync(dir);
t.true(madeDir.length > 0);
assertDir(t, madeDir);
});

test('`fs` option', t => {
const dir = getFixture();
m.sync(dir, {fs: gracefulFs});
makeDir.sync(dir, {fs: gracefulFs});
assertDir(t, dir);
});

test('`mode` option', t => {
const dir = getFixture();
const mode = 0o744;
m.sync(dir, {mode});
makeDir.sync(dir, {mode});
assertDir(t, dir, mode);

// Ensure it's writable
m.sync(dir);
makeDir.sync(dir);
assertDir(t, dir, mode);
});

test('dir exists', t => {
const dir = m.sync(tempy.directory());
const dir = makeDir.sync(tempy.directory());
t.true(dir.length > 0);
assertDir(t, dir);
});

test('file exits', t => {
const fp = tempy.file();
fs.writeFileSync(fp, '');
const err = t.throws(() => {
m.sync(fp);
});
t.is(err.code, 'EEXIST');
t.throws(() => {
makeDir.sync(fp);
}, {code: 'EEXIST'});
});

test('root dir', t => {
const mode = fs.statSync('/').mode & 0o777;
const dir = m.sync('/');
const dir = makeDir.sync('/');
t.true(dir.length > 0);
assertDir(t, dir, mode);
});

test('race two', t => {
const dir = getFixture();
m.sync(dir);
m.sync(dir);
makeDir.sync(dir);
makeDir.sync(dir);
assertDir(t, dir);
});

test('race many', t => {
const dir = getFixture();

for (let i = 0; i < 100; i++) {
m.sync(dir);
makeDir.sync(dir);
}

assertDir(t, dir);
});

test('handles null bytes in path', t => {
const dir = path.join(tempy.directory(), 'foo\u0000bar');
const err = t.throws(() => {
m.sync(dir);

const error = t.throws(() => {
makeDir.sync(dir);
}, /null bytes/);
t.regex(err.code, /ERR_INVALID_ARG_VALUE|ENOENT/);
t.regex(error.code, /ERR_INVALID_ARG_VALUE|ENOENT/);
});

if (process.platform === 'win32') {
test('handles non-existent root', t => {
// We assume the `o:\` drive doesn't exist on Windows
const err = t.throws(() => {
m.sync('o:\\foo');
}, /no such file or directory/);
t.is(err.code, 'ENOENT');
t.throws(() => {
makeDir.sync('o:\\foo');
}, {
code: 'ENOENT',
message: /no such file or directory/
});
});
}

0 comments on commit f38a1b7

Please sign in to comment.