pax_global_header00006660000000000000000000000064136210556360014521gustar00rootroot0000000000000052 comment=66ba0d9def1b32054bbb94eaeb27a345e35abdd7 make-dir-3.0.2/000077500000000000000000000000001362105563600132145ustar00rootroot00000000000000make-dir-3.0.2/.editorconfig000066400000000000000000000002571362105563600156750ustar00rootroot00000000000000root = true [*] indent_style = tab end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true [*.yml] indent_style = space indent_size = 2 make-dir-3.0.2/.gitattributes000066400000000000000000000000231362105563600161020ustar00rootroot00000000000000* text=auto eol=lf make-dir-3.0.2/.github/000077500000000000000000000000001362105563600145545ustar00rootroot00000000000000make-dir-3.0.2/.github/funding.yml000066400000000000000000000001621362105563600167300ustar00rootroot00000000000000github: sindresorhus open_collective: sindresorhus tidelift: npm/make-dir custom: https://sindresorhus.com/donate make-dir-3.0.2/.github/security.md000066400000000000000000000002631362105563600167460ustar00rootroot00000000000000# Security Policy To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure. make-dir-3.0.2/.gitignore000066400000000000000000000000431362105563600152010ustar00rootroot00000000000000node_modules yarn.lock .nyc_output make-dir-3.0.2/.npmrc000066400000000000000000000000231362105563600143270ustar00rootroot00000000000000package-lock=false make-dir-3.0.2/.travis.yml000066400000000000000000000003171362105563600153260ustar00rootroot00000000000000os: - linux - osx - windows language: node_js node_js: - '12' - '10' - '8' after_success: - './node_modules/.bin/nyc report --reporter=text-lcov > coverage.lcov && ./node_modules/.bin/codecov' make-dir-3.0.2/index.d.ts000066400000000000000000000030231362105563600151130ustar00rootroot00000000000000/// import * as fs from 'fs'; declare namespace makeDir { interface Options { /** Directory [permissions](https://x-team.com/blog/file-system-permissions-umask-node-js/). @default 0o777 & (~process.umask()) */ readonly mode?: number; /** Use a custom `fs` implementation. For example [`graceful-fs`](https://github.com/isaacs/node-graceful-fs). Using a custom `fs` implementation will block the use of the native `recursive` option if `fs.mkdir` or `fs.mkdirSync` is not the native function. @default require('fs') */ readonly fs?: typeof fs; } } declare const makeDir: { /** Make a directory and its parents if needed - Think `mkdir -p`. @param path - Directory to create. @returns The path to the created directory. @example ``` import makeDir = require('make-dir'); (async () => { const path = await makeDir('unicorn/rainbow/cake'); console.log(path); //=> '/Users/sindresorhus/fun/unicorn/rainbow/cake' // Multiple directories: const paths = await Promise.all([ makeDir('unicorn/rainbow'), makeDir('foo/bar') ]); console.log(paths); // [ // '/Users/sindresorhus/fun/unicorn/rainbow', // '/Users/sindresorhus/fun/foo/bar' // ] })(); ``` */ (path: string, options?: makeDir.Options): Promise; /** Synchronously make a directory and its parents if needed - Think `mkdir -p`. @param path - Directory to create. @returns The path to the created directory. */ sync(path: string, options?: makeDir.Options): string; }; export = makeDir; make-dir-3.0.2/index.js000066400000000000000000000061111362105563600146600ustar00rootroot00000000000000'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 & (~process.umask()), 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)); }; make-dir-3.0.2/index.test-d.ts000066400000000000000000000013511362105563600160720ustar00rootroot00000000000000import {expectType} from 'tsd'; import makeDir = require('.'); import {sync as makeDirSync} from '.'; import * as fs from 'fs'; import * as gfs from 'graceful-fs'; // MakeDir expectType>(makeDir('path/to/somewhere')); expectType>( makeDir('path/to/somewhere', {mode: parseInt('777', 8)}) ); expectType>(makeDir('path/to/somewhere', {fs})); expectType>(makeDir('path/to/somewhere', {fs: gfs})); // MakeDir (sync) expectType(makeDirSync('path/to/somewhere')); expectType( makeDirSync('path/to/somewhere', {mode: parseInt('777', 8)}) ); expectType(makeDirSync('path/to/somewhere', {fs})); expectType(makeDirSync('path/to/somewhere', {fs: gfs})); make-dir-3.0.2/license000066400000000000000000000021251362105563600145610ustar00rootroot00000000000000MIT License Copyright (c) Sindre Sorhus (sindresorhus.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. make-dir-3.0.2/package.json000066400000000000000000000020331362105563600155000ustar00rootroot00000000000000{ "name": "make-dir", "version": "3.0.2", "description": "Make a directory and its parents if needed - Think `mkdir -p`", "license": "MIT", "repository": "sindresorhus/make-dir", "funding": "https://github.com/sponsors/sindresorhus", "author": { "name": "Sindre Sorhus", "email": "sindresorhus@gmail.com", "url": "sindresorhus.com" }, "engines": { "node": ">=8" }, "scripts": { "test": "xo && nyc ava && tsd" }, "files": [ "index.js", "index.d.ts" ], "keywords": [ "mkdir", "mkdirp", "make", "directories", "dir", "dirs", "folders", "directory", "folder", "path", "parent", "parents", "intermediate", "recursively", "recursive", "create", "fs", "filesystem", "file-system" ], "dependencies": { "semver": "^6.0.0" }, "devDependencies": { "@types/graceful-fs": "^4.1.3", "@types/node": "^13.7.1", "ava": "^1.4.0", "codecov": "^3.2.0", "graceful-fs": "^4.1.15", "nyc": "^15.0.0", "path-type": "^4.0.0", "tempy": "^0.2.1", "tsd": "^0.11.0", "xo": "^0.25.4" } } make-dir-3.0.2/readme.md000066400000000000000000000062551362105563600150030ustar00rootroot00000000000000# make-dir [![Build Status](https://travis-ci.org/sindresorhus/make-dir.svg?branch=master)](https://travis-ci.org/sindresorhus/make-dir) [![codecov](https://codecov.io/gh/sindresorhus/make-dir/branch/master/graph/badge.svg)](https://codecov.io/gh/sindresorhus/make-dir) > Make a directory and its parents if needed - Think `mkdir -p` ## Advantages over [`mkdirp`](https://github.com/substack/node-mkdirp) - Promise API *(Async/await ready!)* - Fixes many `mkdirp` issues: [#96](https://github.com/substack/node-mkdirp/pull/96) [#70](https://github.com/substack/node-mkdirp/issues/70) [#66](https://github.com/substack/node-mkdirp/issues/66) - 100% test coverage - CI-tested on macOS, Linux, and Windows - Actively maintained - Doesn't bundle a CLI - Uses native the `fs.mkdir/mkdirSync` [`recursive` option](https://nodejs.org/dist/latest/docs/api/fs.html#fs_fs_mkdir_path_options_callback) in Node.js >=10.12.0 unless [overridden](#fs) ## Install ``` $ npm install make-dir ``` ## Usage ``` $ pwd /Users/sindresorhus/fun $ tree . ``` ```js const makeDir = require('make-dir'); (async () => { const path = await makeDir('unicorn/rainbow/cake'); console.log(path); //=> '/Users/sindresorhus/fun/unicorn/rainbow/cake' })(); ``` ``` $ tree . └── unicorn └── rainbow └── cake ``` Multiple directories: ```js const makeDir = require('make-dir'); (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' ] */ })(); ``` ## API ### makeDir(path, options?) Returns a `Promise` for the path to the created directory. ### makeDir.sync(path, options?) Returns the path to the created directory. #### path Type: `string` Directory to create. #### options Type: `object` ##### mode Type: `integer`\ Default: `0o777 & (~process.umask())` Directory [permissions](https://x-team.com/blog/file-system-permissions-umask-node-js/). ##### fs Type: `object`\ Default: `require('fs')` Use a custom `fs` implementation. For example [`graceful-fs`](https://github.com/isaacs/node-graceful-fs). Using a custom `fs` implementation will block the use of the native `recursive` option if `fs.mkdir` or `fs.mkdirSync` is not the native function. ## Related - [make-dir-cli](https://github.com/sindresorhus/make-dir-cli) - CLI for this module - [del](https://github.com/sindresorhus/del) - Delete files and directories - [globby](https://github.com/sindresorhus/globby) - User-friendly glob matching - [cpy](https://github.com/sindresorhus/cpy) - Copy files - [cpy-cli](https://github.com/sindresorhus/cpy-cli) - Copy files on the command-line - [move-file](https://github.com/sindresorhus/move-file) - Move a file ---
Get professional support for this package with a Tidelift subscription
Tidelift helps make open source sustainable for maintainers while giving companies
assurances about security, maintenance, and licensing for their dependencies.
make-dir-3.0.2/test/000077500000000000000000000000001362105563600141735ustar00rootroot00000000000000make-dir-3.0.2/test/async.js000066400000000000000000000063501362105563600156520ustar00rootroot00000000000000import fs from 'fs'; import path from 'path'; import test from 'ava'; import tempy from 'tempy'; import gracefulFs from 'graceful-fs'; import semver from 'semver'; import {getFixture, assertDirectory, customFsOptions} from './helpers/util'; import makeDir from '..'; test('main', async t => { const dir = getFixture(); const madeDir = await makeDir(dir); t.true(madeDir.length > 0); assertDirectory(t, madeDir); }); test('`fs` option - graceful-fs', async t => { const dir = getFixture(); await makeDir(dir, {fs: gracefulFs}); assertDirectory(t, dir); }); test('`fs` option - custom', async t => { const dir = getFixture(); const madeDir = await makeDir(dir, customFsOptions); t.true(madeDir.length > 0); assertDirectory(t, madeDir); }); test('`mode` option', async t => { const dir = getFixture(); const mode = 0o744; await makeDir(dir, {mode}); assertDirectory(t, dir, mode); // Ensure it's writable await makeDir(dir); assertDirectory(t, dir, mode); }); test('dir exists', async t => { const dir = await makeDir(tempy.directory()); t.true(dir.length > 0); assertDirectory(t, dir); }); test('file exits', async t => { const fp = tempy.file(); fs.writeFileSync(fp, ''); await t.throwsAsync(makeDir(fp), {code: 'EEXIST'}); }); test('parent dir is file', async t => { const fp = tempy.file(); fs.writeFileSync(fp, ''); const error = await t.throwsAsync(makeDir(fp + '/sub/dir')); t.regex(error.code, /ENOTDIR|EEXIST/); }); test('root dir', async t => { if (process.platform === 'win32') { // Do not assume that `C:` is current drive await t.throwsAsync(makeDir('/'), { code: 'EPERM', message: /operation not permitted, mkdir '[A-Za-z]:\\'/ }); } else { const mode = fs.statSync('/').mode & 0o777; const dir = await makeDir('/'); t.true(dir.length > 0); assertDirectory(t, dir, mode); } }); test('race two', async t => { const dir = getFixture(); await Promise.all([makeDir(dir), makeDir(dir)]); assertDirectory(t, dir); }); test('race many', async t => { const dir = getFixture(); const all = []; for (let i = 0; i < 100; i++) { all.push(makeDir(dir)); } await Promise.all(all); assertDirectory(t, dir); }); test('handles null bytes in path', async t => { const dir = path.join(tempy.directory(), 'foo\u0000bar'); 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 => { // We do this to please `nyc` const {platform} = process; Object.defineProperty(process, 'platform', { value: 'win32' }); // Also to please `nyc` await makeDir(tempy.directory()); const dir = path.join(tempy.directory(), 'foo"bar'); await t.throwsAsync(makeDir(dir), { code: 'EINVAL', message: /invalid characters/ }); Object.defineProperty(process, 'platform', { value: platform }); }); if (process.platform === 'win32') { test('handles non-existent root', async t => { const expectedError = semver.satisfies(process.version, '>=12') ? { code: 'ENOENT', message: /no such file or directory, mkdir/ } : { code: 'EPERM', message: /operation not permitted, mkdir/ }; // We assume the `o:\` drive doesn't exist on Windows. await t.throwsAsync(makeDir('o:\\foo'), expectedError); }); } make-dir-3.0.2/test/helpers/000077500000000000000000000000001362105563600156355ustar00rootroot00000000000000make-dir-3.0.2/test/helpers/util.js000066400000000000000000000014711362105563600171530ustar00rootroot00000000000000import fs from 'fs'; import path from 'path'; import tempy from 'tempy'; import pathType from 'path-type'; export const getFixture = () => path.join(tempy.directory(), 'a/b/c/unicorn_unicorn_unicorn/d/e/f/g/h'); export const assertDirectory = (t, directory, mode = 0o777 & (~process.umask())) => { // Setting `mode` on `fs.mkdir` on Windows doesn't seem to work if (process.platform === 'win32') { mode = 0o666; } t.true(pathType.isDirectorySync(directory)); t.is(fs.statSync(directory).mode & 0o777, mode); }; // Using this forces test coverage of legacy method on latest versions of Node.js export const customFsOptions = { fs: { mkdir: (...args) => fs.mkdir(...args), stat: (...args) => fs.stat(...args), mkdirSync: (...args) => fs.mkdirSync(...args), statSync: (...args) => fs.statSync(...args) } }; make-dir-3.0.2/test/sync.js000066400000000000000000000052651362105563600155150ustar00rootroot00000000000000import fs from 'fs'; import path from 'path'; import test from 'ava'; import tempy from 'tempy'; import gracefulFs from 'graceful-fs'; import semver from 'semver'; import {getFixture, assertDirectory, customFsOptions} from './helpers/util'; import makeDir from '..'; test('main', t => { const dir = getFixture(); const madeDir = makeDir.sync(dir); t.true(madeDir.length > 0); assertDirectory(t, madeDir); }); test('`fs` option - graceful-fs', t => { const dir = getFixture(); makeDir.sync(dir, {fs: gracefulFs}); assertDirectory(t, dir); }); test('`fs` option - custom', t => { const dir = getFixture(); const madeDir = makeDir.sync(dir, customFsOptions); t.true(madeDir.length > 0); assertDirectory(t, madeDir); }); test('`mode` option', t => { const dir = getFixture(); const mode = 0o744; makeDir.sync(dir, {mode}); assertDirectory(t, dir, mode); // Ensure it's writable makeDir.sync(dir); assertDirectory(t, dir, mode); }); test('dir exists', t => { const dir = makeDir.sync(tempy.directory()); t.true(dir.length > 0); assertDirectory(t, dir); }); test('file exits', t => { const fp = tempy.file(); fs.writeFileSync(fp, ''); t.throws(() => { makeDir.sync(fp); }, {code: 'EEXIST'}); }); test('parent dir is file', t => { const fp = tempy.file(); fs.writeFileSync(fp, ''); const error = t.throws(() => { makeDir.sync(fp + '/sub/dir'); }); t.regex(error.code, /ENOTDIR|EEXIST/); }); test('root dir', t => { if (process.platform === 'win32') { // Do not assume that `C:` is current drive t.throws(() => { makeDir.sync('/'); }, { code: 'EPERM', message: /operation not permitted, mkdir '[A-Za-z]:\\'/ }); } else { const mode = fs.statSync('/').mode & 0o777; const dir = makeDir.sync('/'); t.true(dir.length > 0); assertDirectory(t, dir, mode); } }); test('race two', t => { const dir = getFixture(); makeDir.sync(dir); makeDir.sync(dir); assertDirectory(t, dir); }); test('race many', t => { const dir = getFixture(); for (let i = 0; i < 100; i++) { makeDir.sync(dir); } assertDirectory(t, dir); }); test('handles null bytes in path', t => { const dir = path.join(tempy.directory(), 'foo\u0000bar'); const error = t.throws(() => { makeDir.sync(dir); }, /null bytes/); t.regex(error.code, /ERR_INVALID_ARG_VALUE|ENOENT/); }); if (process.platform === 'win32') { test('handles non-existent root', t => { const expectedError = semver.satisfies(process.version, '>=12') ? { code: 'ENOENT', message: /no such file or directory, mkdir/ } : { code: 'EPERM', message: /operation not permitted, mkdir/ }; // We assume the `o:\` drive doesn't exist on Windows. t.throws(() => { makeDir.sync('o:\\foo'); }, expectedError); }); } make-dir-3.0.2/test/umask.js000066400000000000000000000006361362105563600156560ustar00rootroot00000000000000import test from 'ava'; import {getFixture, assertDirectory} from './helpers/util'; import makeDir from '..'; test.before(() => { process.umask(0); }); test('async', async t => { const dir = getFixture(); await makeDir(dir); assertDirectory(t, dir, 0o777 & (~process.umask())); }); test('sync', t => { const dir = getFixture(); makeDir.sync(dir); assertDirectory(t, dir, 0o777 & (~process.umask())); });