UNPKG

8.51 kBMarkdownView Raw
1# mkdirp
2
3Like `mkdir -p`, but in Node.js!
4
5Now with a modern API and no\* bugs!
6
7<small>\* may contain some bugs</small>
8
9# example
10
11## pow.js
12
13```js
14const mkdirp = require('mkdirp')
15
16// return value is a Promise resolving to the first directory created
17mkdirp('/tmp/foo/bar/baz').then(made =>
18 console.log(`made directories, starting with ${made}`))
19```
20
21Output (where `/tmp/foo` already exists)
22
23```
24made directories, starting with /tmp/foo/bar
25```
26
27Or, if you don't have time to wait around for promises:
28
29```js
30const mkdirp = require('mkdirp')
31
32// return value is the first directory created
33const made = mkdirp.sync('/tmp/foo/bar/baz')
34console.log(`made directories, starting with ${made}`)
35```
36
37And now /tmp/foo/bar/baz exists, huzzah!
38
39# methods
40
41```js
42const mkdirp = require('mkdirp')
43```
44
45## mkdirp(dir, [opts]) -> Promise<String | undefined>
46
47Create a new directory and any necessary subdirectories at `dir` with octal
48permission string `opts.mode`. If `opts` is a string or number, it will be
49treated as the `opts.mode`.
50
51If `opts.mode` isn't specified, it defaults to `0o777 &
52(~process.umask())`.
53
54Promise resolves to first directory `made` that had to be created, or
55`undefined` if everything already exists. Promise rejects if any errors
56are encountered. Note that, in the case of promise rejection, some
57directories _may_ have been created, as recursive directory creation is not
58an atomic operation.
59
60You can optionally pass in an alternate `fs` implementation by passing in
61`opts.fs`. Your implementation should have `opts.fs.mkdir(path, opts, cb)`
62and `opts.fs.stat(path, cb)`.
63
64You can also override just one or the other of `mkdir` and `stat` by
65passing in `opts.stat` or `opts.mkdir`, or providing an `fs` option that
66only overrides one of these.
67
68## mkdirp.sync(dir, opts) -> String|null
69
70Synchronously create a new directory and any necessary subdirectories at
71`dir` with octal permission string `opts.mode`. If `opts` is a string or
72number, it will be treated as the `opts.mode`.
73
74If `opts.mode` isn't specified, it defaults to `0o777 &
75(~process.umask())`.
76
77Returns the first directory that had to be created, or undefined if
78everything already exists.
79
80You can optionally pass in an alternate `fs` implementation by passing in
81`opts.fs`. Your implementation should have `opts.fs.mkdirSync(path, mode)`
82and `opts.fs.statSync(path)`.
83
84You can also override just one or the other of `mkdirSync` and `statSync`
85by passing in `opts.statSync` or `opts.mkdirSync`, or providing an `fs`
86option that only overrides one of these.
87
88## mkdirp.manual, mkdirp.manualSync
89
90Use the manual implementation (not the native one). This is the default
91when the native implementation is not available or the stat/mkdir
92implementation is overridden.
93
94## mkdirp.native, mkdirp.nativeSync
95
96Use the native implementation (not the manual one). This is the default
97when the native implementation is available and stat/mkdir are not
98overridden.
99
100# implementation
101
102On Node.js v10.12.0 and above, use the native `fs.mkdir(p,
103{recursive:true})` option, unless `fs.mkdir`/`fs.mkdirSync` has been
104overridden by an option.
105
106## native implementation
107
108- If the path is a root directory, then pass it to the underlying
109 implementation and return the result/error. (In this case, it'll either
110 succeed or fail, but we aren't actually creating any dirs.)
111- Walk up the path statting each directory, to find the first path that
112 will be created, `made`.
113- Call `fs.mkdir(path, { recursive: true })` (or `fs.mkdirSync`)
114- If error, raise it to the caller.
115- Return `made`.
116
117## manual implementation
118
119- Call underlying `fs.mkdir` implementation, with `recursive: false`
120- If error:
121 - If path is a root directory, raise to the caller and do not handle it
122 - If ENOENT, mkdirp parent dir, store result as `made`
123 - stat(path)
124 - If error, raise original `mkdir` error
125 - If directory, return `made`
126 - Else, raise original `mkdir` error
127- else
128 - return `undefined` if a root dir, or `made` if set, or `path`
129
130## windows vs unix caveat
131
132On Windows file systems, attempts to create a root directory (ie, a drive
133letter or root UNC path) will fail. If the root directory exists, then it
134will fail with `EPERM`. If the root directory does not exist, then it will
135fail with `ENOENT`.
136
137On posix file systems, attempts to create a root directory (in recursive
138mode) will succeed silently, as it is treated like just another directory
139that already exists. (In non-recursive mode, of course, it fails with
140`EEXIST`.)
141
142In order to preserve this system-specific behavior (and because it's not as
143if we can create the parent of a root directory anyway), attempts to create
144a root directory are passed directly to the `fs` implementation, and any
145errors encountered are not handled.
146
147## native error caveat
148
149The native implementation (as of at least Node.js v13.4.0) does not provide
150appropriate errors in some cases (see
151[nodejs/node#31481](https://github.com/nodejs/node/issues/31481) and
152[nodejs/node#28015](https://github.com/nodejs/node/issues/28015)).
153
154In order to work around this issue, the native implementation will fall
155back to the manual implementation if an `ENOENT` error is encountered.
156
157# choosing a recursive mkdir implementation
158
159There are a few to choose from! Use the one that suits your needs best :D
160
161## use `fs.mkdir(path, {recursive: true}, cb)` if:
162
163- You wish to optimize performance even at the expense of other factors.
164- You don't need to know the first dir created.
165- You are ok with getting `ENOENT` as the error when some other problem is
166 the actual cause.
167- You can limit your platforms to Node.js v10.12 and above.
168- You're ok with using callbacks instead of promises.
169- You don't need/want a CLI.
170- You don't need to override the `fs` methods in use.
171
172## use this module (mkdirp 1.x) if:
173
174- You need to know the first directory that was created.
175- You wish to use the native implementation if available, but fall back
176 when it's not.
177- You prefer promise-returning APIs to callback-taking APIs.
178- You want more useful error messages than the native recursive mkdir
179 provides (at least as of Node.js v13.4), and are ok with re-trying on
180 `ENOENT` to achieve this.
181- You need (or at least, are ok with) a CLI.
182- You need to override the `fs` methods in use.
183
184## use [`make-dir`](http://npm.im/make-dir) if:
185
186- You do not need to know the first dir created (and wish to save a few
187 `stat` calls when using the native implementation for this reason).
188- You wish to use the native implementation if available, but fall back
189 when it's not.
190- You prefer promise-returning APIs to callback-taking APIs.
191- You are ok with occasionally getting `ENOENT` errors for failures that
192 are actually related to something other than a missing file system entry.
193- You don't need/want a CLI.
194- You need to override the `fs` methods in use.
195
196## use mkdirp 0.x if:
197
198- You need to know the first directory that was created.
199- You need (or at least, are ok with) a CLI.
200- You need to override the `fs` methods in use.
201- You're ok with using callbacks instead of promises.
202- You are not running on Windows, where the root-level ENOENT errors can
203 lead to infinite regress.
204- You think vinyl just sounds warmer and richer for some weird reason.
205- You are supporting truly ancient Node.js versions, before even the advent
206 of a `Promise` language primitive. (Please don't. You deserve better.)
207
208# cli
209
210This package also ships with a `mkdirp` command.
211
212```
213$ mkdirp -h
214
215usage: mkdirp [DIR1,DIR2..] {OPTIONS}
216
217 Create each supplied directory including any necessary parent directories
218 that don't yet exist.
219
220 If the directory already exists, do nothing.
221
222OPTIONS are:
223
224 -m<mode> If a directory needs to be created, set the mode as an octal
225 --mode=<mode> permission string.
226
227 -v --version Print the mkdirp version number
228
229 -h --help Print this helpful banner
230
231 -p --print Print the first directories created for each path provided
232
233 --manual Use manual implementation, even if native is available
234```
235
236# install
237
238With [npm](http://npmjs.org) do:
239
240```
241npm install mkdirp
242```
243
244to get the library locally, or
245
246```
247npm install -g mkdirp
248```
249
250to get the command everywhere, or
251
252```
253npx mkdirp ...
254```
255
256to run the command without installing it globally.
257
258# platform support
259
260This module works on node v8, but only v10 and above are officially
261supported, as Node v8 reached its LTS end of life 2020-01-01, which is in
262the past, as of this writing.
263
264# license
265
266MIT