• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict';
2const fs = require('fs');
3const path = require('path');
4const pify = require('pify');
5
6const defaults = {
7	mode: 0o777 & (~process.umask()),
8	fs
9};
10
11// https://github.com/nodejs/node/issues/8987
12// https://github.com/libuv/libuv/pull/1088
13const checkPath = pth => {
14	if (process.platform === 'win32') {
15		const pathHasInvalidWinCharacters = /[<>:"|?*]/.test(pth.replace(path.parse(pth).root, ''));
16
17		if (pathHasInvalidWinCharacters) {
18			const err = new Error(`Path contains invalid characters: ${pth}`);
19			err.code = 'EINVAL';
20			throw err;
21		}
22	}
23};
24
25module.exports = (input, opts) => Promise.resolve().then(() => {
26	checkPath(input);
27	opts = Object.assign({}, defaults, opts);
28
29	const mkdir = pify(opts.fs.mkdir);
30	const stat = pify(opts.fs.stat);
31
32	const make = pth => {
33		return mkdir(pth, opts.mode)
34			.then(() => pth)
35			.catch(err => {
36				if (err.code === 'ENOENT') {
37					if (err.message.includes('null bytes') || path.dirname(pth) === pth) {
38						throw err;
39					}
40
41					return make(path.dirname(pth)).then(() => make(pth));
42				}
43
44				return stat(pth)
45					.then(stats => stats.isDirectory() ? pth : Promise.reject())
46					.catch(() => {
47						throw err;
48					});
49			});
50	};
51
52	return make(path.resolve(input));
53});
54
55module.exports.sync = (input, opts) => {
56	checkPath(input);
57	opts = Object.assign({}, defaults, opts);
58
59	const make = pth => {
60		try {
61			opts.fs.mkdirSync(pth, opts.mode);
62		} catch (err) {
63			if (err.code === 'ENOENT') {
64				if (err.message.includes('null bytes') || path.dirname(pth) === pth) {
65					throw err;
66				}
67
68				make(path.dirname(pth));
69				return make(pth);
70			}
71
72			try {
73				if (!opts.fs.statSync(pth).isDirectory()) {
74					throw new Error('The path is not a directory');
75				}
76			} catch (_) {
77				throw err;
78			}
79		}
80
81		return pth;
82	};
83
84	return make(path.resolve(input));
85};
86