You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					157 lines
				
				3.1 KiB
			
		
		
			
		
	
	
					157 lines
				
				3.1 KiB
			| 
								 
											4 years ago
										 
									 | 
							
								'use strict';
							 | 
						||
| 
								 | 
							
								const fs = require('fs');
							 | 
						||
| 
								 | 
							
								const path = require('path');
							 | 
						||
| 
								 | 
							
								const {promisify} = require('util');
							 | 
						||
| 
								 | 
							
								const semver = require('semver');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const useNativeRecursiveOption = semver.satisfies(process.version, '>=10.12.0');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// https://github.com/nodejs/node/issues/8987
							 | 
						||
| 
								 | 
							
								// https://github.com/libuv/libuv/pull/1088
							 | 
						||
| 
								 | 
							
								const checkPath = pth => {
							 | 
						||
| 
								 | 
							
									if (process.platform === 'win32') {
							 | 
						||
| 
								 | 
							
										const pathHasInvalidWinCharacters = /[<>:"|?*]/.test(pth.replace(path.parse(pth).root, ''));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (pathHasInvalidWinCharacters) {
							 | 
						||
| 
								 | 
							
											const error = new Error(`Path contains invalid characters: ${pth}`);
							 | 
						||
| 
								 | 
							
											error.code = 'EINVAL';
							 | 
						||
| 
								 | 
							
											throw error;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const processOptions = options => {
							 | 
						||
| 
								 | 
							
									// https://github.com/sindresorhus/make-dir/issues/18
							 | 
						||
| 
								 | 
							
									const defaults = {
							 | 
						||
| 
								 | 
							
										mode: 0o777,
							 | 
						||
| 
								 | 
							
										fs
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return {
							 | 
						||
| 
								 | 
							
										...defaults,
							 | 
						||
| 
								 | 
							
										...options
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const permissionError = pth => {
							 | 
						||
| 
								 | 
							
									// This replicates the exception of `fs.mkdir` with native the
							 | 
						||
| 
								 | 
							
									// `recusive` option when run on an invalid drive under Windows.
							 | 
						||
| 
								 | 
							
									const error = new Error(`operation not permitted, mkdir '${pth}'`);
							 | 
						||
| 
								 | 
							
									error.code = 'EPERM';
							 | 
						||
| 
								 | 
							
									error.errno = -4048;
							 | 
						||
| 
								 | 
							
									error.path = pth;
							 | 
						||
| 
								 | 
							
									error.syscall = 'mkdir';
							 | 
						||
| 
								 | 
							
									return error;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const makeDir = async (input, options) => {
							 | 
						||
| 
								 | 
							
									checkPath(input);
							 | 
						||
| 
								 | 
							
									options = processOptions(options);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									const mkdir = promisify(options.fs.mkdir);
							 | 
						||
| 
								 | 
							
									const stat = promisify(options.fs.stat);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (useNativeRecursiveOption && options.fs.mkdir === fs.mkdir) {
							 | 
						||
| 
								 | 
							
										const pth = path.resolve(input);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										await mkdir(pth, {
							 | 
						||
| 
								 | 
							
											mode: options.mode,
							 | 
						||
| 
								 | 
							
											recursive: true
							 | 
						||
| 
								 | 
							
										});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return pth;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									const make = async pth => {
							 | 
						||
| 
								 | 
							
										try {
							 | 
						||
| 
								 | 
							
											await mkdir(pth, options.mode);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											return pth;
							 | 
						||
| 
								 | 
							
										} catch (error) {
							 | 
						||
| 
								 | 
							
											if (error.code === 'EPERM') {
							 | 
						||
| 
								 | 
							
												throw error;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if (error.code === 'ENOENT') {
							 | 
						||
| 
								 | 
							
												if (path.dirname(pth) === pth) {
							 | 
						||
| 
								 | 
							
													throw permissionError(pth);
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												if (error.message.includes('null bytes')) {
							 | 
						||
| 
								 | 
							
													throw error;
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												await make(path.dirname(pth));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												return make(pth);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											try {
							 | 
						||
| 
								 | 
							
												const stats = await stat(pth);
							 | 
						||
| 
								 | 
							
												if (!stats.isDirectory()) {
							 | 
						||
| 
								 | 
							
													throw new Error('The path is not a directory');
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
											} catch (_) {
							 | 
						||
| 
								 | 
							
												throw error;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											return pth;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return make(path.resolve(input));
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								module.exports = makeDir;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								module.exports.sync = (input, options) => {
							 | 
						||
| 
								 | 
							
									checkPath(input);
							 | 
						||
| 
								 | 
							
									options = processOptions(options);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (useNativeRecursiveOption && options.fs.mkdirSync === fs.mkdirSync) {
							 | 
						||
| 
								 | 
							
										const pth = path.resolve(input);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										fs.mkdirSync(pth, {
							 | 
						||
| 
								 | 
							
											mode: options.mode,
							 | 
						||
| 
								 | 
							
											recursive: true
							 | 
						||
| 
								 | 
							
										});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return pth;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									const make = pth => {
							 | 
						||
| 
								 | 
							
										try {
							 | 
						||
| 
								 | 
							
											options.fs.mkdirSync(pth, options.mode);
							 | 
						||
| 
								 | 
							
										} catch (error) {
							 | 
						||
| 
								 | 
							
											if (error.code === 'EPERM') {
							 | 
						||
| 
								 | 
							
												throw error;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if (error.code === 'ENOENT') {
							 | 
						||
| 
								 | 
							
												if (path.dirname(pth) === pth) {
							 | 
						||
| 
								 | 
							
													throw permissionError(pth);
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												if (error.message.includes('null bytes')) {
							 | 
						||
| 
								 | 
							
													throw error;
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												make(path.dirname(pth));
							 | 
						||
| 
								 | 
							
												return make(pth);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											try {
							 | 
						||
| 
								 | 
							
												if (!options.fs.statSync(pth).isDirectory()) {
							 | 
						||
| 
								 | 
							
													throw new Error('The path is not a directory');
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
											} catch (_) {
							 | 
						||
| 
								 | 
							
												throw error;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return pth;
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return make(path.resolve(input));
							 | 
						||
| 
								 | 
							
								};
							 |