├── .github
├── CODEOWNERS
├── FUNDING.yml
└── workflows
│ ├── ci.yml
│ ├── commit-if-modified.sh
│ ├── copyright-year.sh
│ ├── isaacs-makework.yml
│ ├── package-json-repo.js
│ ├── static.yml
│ └── typedoc.yml
├── .gitignore
├── .prettierignore
├── CHANGELOG.md
├── LICENSE
├── fixup.sh
├── package-lock.json
├── package.json
├── readme.markdown
├── src
├── bin.ts
├── find-made.ts
├── index.ts
├── mkdirp-manual.ts
├── mkdirp-native.ts
├── opts-arg.ts
├── path-arg.ts
└── use-native.ts
├── tap-snapshots
├── test-cmd.js-TAP.test.js
└── test
│ └── cmd.ts.test.cjs
├── test
├── cmd.ts
├── find-made.ts
├── index.ts
├── mkdirp-manual.ts
├── mkdirp-native.ts
├── opts-arg.ts
├── path-arg.ts
└── use-native.ts
├── tsconfig-base.json
├── tsconfig-esm.json
├── tsconfig.json
└── typedoc.json
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * isaacs
2 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: [isaacs, substack]
2 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: Node CI
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | build:
7 | strategy:
8 | fail-fast: false
9 | matrix:
10 | node-version: [16.x, 18.x, 19.x]
11 | platform:
12 | - os: ubuntu-latest
13 | shell: bash
14 | - os: macos-latest
15 | shell: bash
16 | - os: windows-latest
17 | shell: powershell
18 |
19 | runs-on: ${{ matrix.platform.os }}
20 | defaults:
21 | run:
22 | shell: ${{ matrix.platform.shell }}
23 |
24 | steps:
25 | # Checkout the npm/cli repo
26 | - uses: actions/checkout@v3
27 |
28 | # Installs the specific version of Node.js
29 | - name: Use Node.js ${{ matrix.node-version }}
30 | uses: actions/setup-node@v3
31 | with:
32 | node-version: ${{ matrix.node-version }}
33 | cache: npm
34 |
35 | # Run the installer script
36 | - name: Install dependencies
37 | run: npm ci
38 |
39 | # Run the tests
40 | - name: Run Tap tests
41 | run: npm test -- -t0 -c
42 |
--------------------------------------------------------------------------------
/.github/workflows/commit-if-modified.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | git config --global user.email "$1"
3 | shift
4 | git config --global user.name "$1"
5 | shift
6 | message="$1"
7 | shift
8 | if [ $(git status --porcelain "$@" | egrep '^ M' | wc -l) -gt 0 ]; then
9 | git add "$@"
10 | git commit -m "$message"
11 | git push || git pull --rebase
12 | git push
13 | fi
14 |
--------------------------------------------------------------------------------
/.github/workflows/copyright-year.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | dir=${1:-$PWD}
3 | dates=($(git log --date=format:%Y --pretty=format:'%ad' --reverse | sort | uniq))
4 | if [ "${#dates[@]}" -eq 1 ]; then
5 | datestr="${dates}"
6 | else
7 | datestr="${dates}-${dates[${#dates[@]}-1]}"
8 | fi
9 |
10 | stripDate='s/^((.*)Copyright\b(.*?))((?:,\s*)?(([0-9]{4}\s*-\s*[0-9]{4})|(([0-9]{4},\s*)*[0-9]{4})))(?:,)?\s*(.*)\n$/$1$9\n/g'
11 | addDate='s/^.*Copyright(?:\s*\(c\))? /Copyright \(c\) '$datestr' /g'
12 | for l in $dir/LICENSE*; do
13 | perl -pi -e "$stripDate" $l
14 | perl -pi -e "$addDate" $l
15 | done
16 |
--------------------------------------------------------------------------------
/.github/workflows/isaacs-makework.yml:
--------------------------------------------------------------------------------
1 | name: "various tidying up tasks to silence nagging"
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | workflow_dispatch:
8 |
9 | jobs:
10 | makework:
11 | runs-on: ubuntu-latest
12 | steps:
13 | - uses: actions/checkout@v3
14 | with:
15 | fetch-depth: 0
16 | - name: Use Node.js
17 | uses: actions/setup-node@v3
18 | with:
19 | node-version: 16.x
20 | - name: put repo in package.json
21 | run: node .github/workflows/package-json-repo.js
22 | - name: check in package.json if modified
23 | run: |
24 | bash -x .github/workflows/commit-if-modified.sh \
25 | "package-json-repo-bot@example.com" \
26 | "package.json Repo Bot" \
27 | "chore: add repo to package.json" \
28 | package.json package-lock.json
29 | - name: put all dates in license copyright line
30 | run: bash .github/workflows/copyright-year.sh
31 | - name: check in licenses if modified
32 | run: |
33 | bash .github/workflows/commit-if-modified.sh \
34 | "license-year-bot@example.com" \
35 | "License Year Bot" \
36 | "chore: add copyright year to license" \
37 | LICENSE*
38 |
--------------------------------------------------------------------------------
/.github/workflows/package-json-repo.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | const pf = require.resolve(`${process.cwd()}/package.json`)
4 | const pj = require(pf)
5 |
6 | if (!pj.repository && process.env.GITHUB_REPOSITORY) {
7 | const fs = require('fs')
8 | const server = process.env.GITHUB_SERVER_URL || 'https://github.com'
9 | const repo = `${server}/${process.env.GITHUB_REPOSITORY}`
10 | pj.repository = repo
11 | const json = fs.readFileSync(pf, 'utf8')
12 | const match = json.match(/^\s*\{[\r\n]+([ \t]*)"/)
13 | const indent = match[1]
14 | const output = JSON.stringify(pj, null, indent || 2) + '\n'
15 | fs.writeFileSync(pf, output)
16 | }
17 |
--------------------------------------------------------------------------------
/.github/workflows/static.yml:
--------------------------------------------------------------------------------
1 | # Simple workflow for deploying static content to GitHub Pages
2 | name: Deploy static content to Pages
3 |
4 | on:
5 | # Runs on pushes targeting the default branch
6 | push:
7 | branches: ["main"]
8 |
9 | # Allows you to run this workflow manually from the Actions tab
10 | workflow_dispatch:
11 |
12 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
13 | permissions:
14 | contents: read
15 | pages: write
16 | id-token: write
17 |
18 | # Allow one concurrent deployment
19 | concurrency:
20 | group: "pages"
21 | cancel-in-progress: true
22 |
23 | jobs:
24 | # Single deploy job since we're just deploying
25 | deploy:
26 | environment:
27 | name: github-pages
28 | url: ${{ steps.deployment.outputs.page_url }}
29 | runs-on: ubuntu-latest
30 | steps:
31 | - name: Checkout
32 | uses: actions/checkout@v3
33 | - name: Use Nodejs
34 | uses: actions/setup-node@v3
35 | with:
36 | node-version: 18.x
37 | cache: npm
38 | - name: Install dependencies
39 | run: npm ci
40 | - name: Generate typedocs
41 | run: npm run typedoc
42 | - name: Setup Pages
43 | uses: actions/configure-pages@v3
44 | - name: Upload artifact
45 | uses: actions/upload-pages-artifact@v1
46 | with:
47 | path: './docs'
48 | - name: Deploy to GitHub Pages
49 | id: deployment
50 | uses: actions/deploy-pages@v1
51 |
--------------------------------------------------------------------------------
/.github/workflows/typedoc.yml:
--------------------------------------------------------------------------------
1 | # Simple workflow for deploying static content to GitHub Pages
2 | name: Deploy static content to Pages
3 |
4 | on:
5 | # Runs on pushes targeting the default branch
6 | push:
7 | branches: ["main"]
8 |
9 | # Allows you to run this workflow manually from the Actions tab
10 | workflow_dispatch:
11 |
12 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
13 | permissions:
14 | contents: read
15 | pages: write
16 | id-token: write
17 |
18 | # Allow one concurrent deployment
19 | concurrency:
20 | group: "pages"
21 | cancel-in-progress: true
22 |
23 | jobs:
24 | # Single deploy job since we're just deploying
25 | deploy:
26 | environment:
27 | name: github-pages
28 | url: ${{ steps.deployment.outputs.page_url }}
29 | runs-on: ubuntu-latest
30 | steps:
31 | - name: Checkout
32 | uses: actions/checkout@v3
33 | - name: Use Nodejs
34 | uses: actions/setup-node@v3
35 | with:
36 | node-version: 18.x
37 | cache: npm
38 | - name: Install dependencies
39 | run: npm ci
40 | - name: Generate typedocs
41 | run: npm run typedoc
42 |
43 | - name: Setup Pages
44 | uses: actions/configure-pages@v3
45 | - name: Upload artifact
46 | uses: actions/upload-pages-artifact@v1
47 | with:
48 | path: './docs'
49 | - name: Deploy to GitHub Pages
50 | id: deployment
51 | uses: actions/deploy-pages@v1
52 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # ignore most things, include some others
2 | /*
3 | /.*
4 | !src/
5 | !.github
6 | !bin/
7 | !docs/
8 | !package.json
9 | !package-lock.json
10 | !README.md
11 | !CONTRIBUTING.md
12 | !LICENSE
13 | !CHANGELOG.md
14 | !example/
15 | !scripts/
16 | !tap-snapshots/
17 | !test/
18 | !.travis.yml
19 | !.gitignore
20 | !.gitattributes
21 | !/tsconfig*.json
22 | !/fixup.sh
23 | !/.prettierignore
24 | !/typedoc.json
25 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | /example
3 | /.github
4 | /dist
5 | .env
6 | /tap-snapshots
7 | /.nyc_output
8 | /coverage
9 | /benchmark
10 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changers Lorgs!
2 |
3 | ## 3.0
4 |
5 | No default exports, just a named export.
6 |
7 | ## 2.1
8 |
9 | Export CommonJS module without a `.default` dangly wart. (A
10 | synthetic `.default` has been added just in case anyone is already
11 | relying on that from v2.0.)
12 |
13 | ## 2.0
14 |
15 | Export hybrid module with TypeScript types.
16 |
17 | ## 1.0
18 |
19 | Full rewrite. Essentially a brand new module.
20 |
21 | - Return a promise instead of taking a callback.
22 | - Use native `fs.mkdir(path, { recursive: true })` when available.
23 | - Drop support for outdated Node.js versions. (Technically still works on
24 | Node.js v8, but only 10 and above are officially supported.)
25 |
26 | ## 0.x
27 |
28 | Original and most widely used recursive directory creation implementation
29 | in JavaScript, dating back to 2010.
30 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2011-2023 James Halliday (mail@substack.net) and Isaac Z. Schlueter (i@izs.me)
2 |
3 | This project is free software released under the MIT license:
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/fixup.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | cat >dist/cjs/package.json <dist/mjs/package.json <=10"
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/readme.markdown:
--------------------------------------------------------------------------------
1 | # mkdirp
2 |
3 | Like `mkdir -p`, but in Node.js!
4 |
5 | Now with a modern API and no\* bugs!
6 |
7 | \* may contain some bugs
8 |
9 | # example
10 |
11 | ## pow.js
12 |
13 | ```js
14 | // hybrid module, import or require() both work
15 | import { mkdirp } from 'mkdirp'
16 | // or:
17 | const { mkdirp } = require('mkdirp')
18 |
19 | // return value is a Promise resolving to the first directory created
20 | mkdirp('/tmp/foo/bar/baz').then(made =>
21 | console.log(`made directories, starting with ${made}`)
22 | )
23 | ```
24 |
25 | Output (where `/tmp/foo` already exists)
26 |
27 | ```
28 | made directories, starting with /tmp/foo/bar
29 | ```
30 |
31 | Or, if you don't have time to wait around for promises:
32 |
33 | ```js
34 | import { mkdirp } from 'mkdirp'
35 |
36 | // return value is the first directory created
37 | const made = mkdirp.sync('/tmp/foo/bar/baz')
38 | console.log(`made directories, starting with ${made}`)
39 | ```
40 |
41 | And now /tmp/foo/bar/baz exists, huzzah!
42 |
43 | # methods
44 |
45 | ```js
46 | import { mkdirp } from 'mkdirp'
47 | ```
48 |
49 | ## `mkdirp(dir: string, opts?: MkdirpOptions) => Promise`
50 |
51 | Create a new directory and any necessary subdirectories at `dir`
52 | with octal permission string `opts.mode`. If `opts` is a string
53 | or number, it will be treated as the `opts.mode`.
54 |
55 | If `opts.mode` isn't specified, it defaults to `0o777`.
56 |
57 | Promise resolves to first directory `made` that had to be
58 | created, or `undefined` if everything already exists. Promise
59 | rejects if any errors are encountered. Note that, in the case of
60 | promise rejection, some directories _may_ have been created, as
61 | recursive directory creation is not an atomic operation.
62 |
63 | You can optionally pass in an alternate `fs` implementation by
64 | passing in `opts.fs`. Your implementation should have
65 | `opts.fs.mkdir(path, opts, cb)` and `opts.fs.stat(path, cb)`.
66 |
67 | You can also override just one or the other of `mkdir` and `stat`
68 | by passing in `opts.stat` or `opts.mkdir`, or providing an `fs`
69 | option that only overrides one of these.
70 |
71 | ## `mkdirp.sync(dir: string, opts: MkdirpOptions) => string|undefined`
72 |
73 | Synchronously create a new directory and any necessary
74 | subdirectories at `dir` with octal permission string `opts.mode`.
75 | If `opts` is a string or number, it will be treated as the
76 | `opts.mode`.
77 |
78 | If `opts.mode` isn't specified, it defaults to `0o777`.
79 |
80 | Returns the first directory that had to be created, or undefined
81 | if everything already exists.
82 |
83 | You can optionally pass in an alternate `fs` implementation by
84 | passing in `opts.fs`. Your implementation should have
85 | `opts.fs.mkdirSync(path, mode)` and `opts.fs.statSync(path)`.
86 |
87 | You can also override just one or the other of `mkdirSync` and
88 | `statSync` by passing in `opts.statSync` or `opts.mkdirSync`, or
89 | providing an `fs` option that only overrides one of these.
90 |
91 | ## `mkdirp.manual`, `mkdirp.manualSync`
92 |
93 | Use the manual implementation (not the native one). This is the
94 | default when the native implementation is not available or the
95 | stat/mkdir implementation is overridden.
96 |
97 | ## `mkdirp.native`, `mkdirp.nativeSync`
98 |
99 | Use the native implementation (not the manual one). This is the
100 | default when the native implementation is available and
101 | stat/mkdir are not overridden.
102 |
103 | # implementation
104 |
105 | On Node.js v10.12.0 and above, use the native `fs.mkdir(p,
106 | {recursive:true})` option, unless `fs.mkdir`/`fs.mkdirSync` has
107 | been overridden by an option.
108 |
109 | ## native implementation
110 |
111 | - If the path is a root directory, then pass it to the underlying
112 | implementation and return the result/error. (In this case,
113 | it'll either succeed or fail, but we aren't actually creating
114 | any dirs.)
115 | - Walk up the path statting each directory, to find the first
116 | path that will be created, `made`.
117 | - Call `fs.mkdir(path, { recursive: true })` (or `fs.mkdirSync`)
118 | - If error, raise it to the caller.
119 | - Return `made`.
120 |
121 | ## manual implementation
122 |
123 | - Call underlying `fs.mkdir` implementation, with `recursive:
124 | false`
125 | - If error:
126 | - If path is a root directory, raise to the caller and do not
127 | handle it
128 | - If ENOENT, mkdirp parent dir, store result as `made`
129 | - stat(path)
130 | - If error, raise original `mkdir` error
131 | - If directory, return `made`
132 | - Else, raise original `mkdir` error
133 | - else
134 | - return `undefined` if a root dir, or `made` if set, or `path`
135 |
136 | ## windows vs unix caveat
137 |
138 | On Windows file systems, attempts to create a root directory (ie,
139 | a drive letter or root UNC path) will fail. If the root
140 | directory exists, then it will fail with `EPERM`. If the root
141 | directory does not exist, then it will fail with `ENOENT`.
142 |
143 | On posix file systems, attempts to create a root directory (in
144 | recursive mode) will succeed silently, as it is treated like just
145 | another directory that already exists. (In non-recursive mode,
146 | of course, it fails with `EEXIST`.)
147 |
148 | In order to preserve this system-specific behavior (and because
149 | it's not as if we can create the parent of a root directory
150 | anyway), attempts to create a root directory are passed directly
151 | to the `fs` implementation, and any errors encountered are not
152 | handled.
153 |
154 | ## native error caveat
155 |
156 | The native implementation (as of at least Node.js v13.4.0) does
157 | not provide appropriate errors in some cases (see
158 | [nodejs/node#31481](https://github.com/nodejs/node/issues/31481)
159 | and
160 | [nodejs/node#28015](https://github.com/nodejs/node/issues/28015)).
161 |
162 | In order to work around this issue, the native implementation
163 | will fall back to the manual implementation if an `ENOENT` error
164 | is encountered.
165 |
166 | # choosing a recursive mkdir implementation
167 |
168 | There are a few to choose from! Use the one that suits your
169 | needs best :D
170 |
171 | ## use `fs.mkdir(path, {recursive: true}, cb)` if:
172 |
173 | - You wish to optimize performance even at the expense of other
174 | factors.
175 | - You don't need to know the first dir created.
176 | - You are ok with getting `ENOENT` as the error when some other
177 | problem is the actual cause.
178 | - You can limit your platforms to Node.js v10.12 and above.
179 | - You're ok with using callbacks instead of promises.
180 | - You don't need/want a CLI.
181 | - You don't need to override the `fs` methods in use.
182 |
183 | ## use this module (mkdirp 1.x or 2.x) if:
184 |
185 | - You need to know the first directory that was created.
186 | - You wish to use the native implementation if available, but
187 | fall back when it's not.
188 | - You prefer promise-returning APIs to callback-taking APIs.
189 | - You want more useful error messages than the native recursive
190 | mkdir provides (at least as of Node.js v13.4), and are ok with
191 | re-trying on `ENOENT` to achieve this.
192 | - You need (or at least, are ok with) a CLI.
193 | - You need to override the `fs` methods in use.
194 |
195 | ## use [`make-dir`](http://npm.im/make-dir) if:
196 |
197 | - You do not need to know the first dir created (and wish to save
198 | a few `stat` calls when using the native implementation for
199 | this reason).
200 | - You wish to use the native implementation if available, but
201 | fall back when it's not.
202 | - You prefer promise-returning APIs to callback-taking APIs.
203 | - You are ok with occasionally getting `ENOENT` errors for
204 | failures that are actually related to something other than a
205 | missing file system entry.
206 | - You don't need/want a CLI.
207 | - You need to override the `fs` methods in use.
208 |
209 | ## use mkdirp 0.x if:
210 |
211 | - You need to know the first directory that was created.
212 | - You need (or at least, are ok with) a CLI.
213 | - You need to override the `fs` methods in use.
214 | - You're ok with using callbacks instead of promises.
215 | - You are not running on Windows, where the root-level ENOENT
216 | errors can lead to infinite regress.
217 | - You think vinyl just sounds warmer and richer for some weird
218 | reason.
219 | - You are supporting truly ancient Node.js versions, before even
220 | the advent of a `Promise` language primitive. (Please don't.
221 | You deserve better.)
222 |
223 | # cli
224 |
225 | This package also ships with a `mkdirp` command.
226 |
227 | ```
228 | $ mkdirp -h
229 |
230 | usage: mkdirp [DIR1,DIR2..] {OPTIONS}
231 |
232 | Create each supplied directory including any necessary parent directories
233 | that don't yet exist.
234 |
235 | If the directory already exists, do nothing.
236 |
237 | OPTIONS are:
238 |
239 | -m If a directory needs to be created, set the mode as an octal
240 | --mode= permission string.
241 |
242 | -v --version Print the mkdirp version number
243 |
244 | -h --help Print this helpful banner
245 |
246 | -p --print Print the first directories created for each path provided
247 |
248 | --manual Use manual implementation, even if native is available
249 | ```
250 |
251 | # install
252 |
253 | With [npm](http://npmjs.org) do:
254 |
255 | ```
256 | npm install mkdirp
257 | ```
258 |
259 | to get the library locally, or
260 |
261 | ```
262 | npm install -g mkdirp
263 | ```
264 |
265 | to get the command everywhere, or
266 |
267 | ```
268 | npx mkdirp ...
269 | ```
270 |
271 | to run the command without installing it globally.
272 |
273 | # platform support
274 |
275 | This module works on node v8, but only v10 and above are officially
276 | supported, as Node v8 reached its LTS end of life 2020-01-01, which is in
277 | the past, as of this writing.
278 |
279 | # license
280 |
281 | MIT
282 |
--------------------------------------------------------------------------------
/src/bin.ts:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | import { version } from '../package.json'
4 | import { MkdirpOptions } from './opts-arg.js'
5 |
6 | const usage = () => `
7 | usage: mkdirp [DIR1,DIR2..] {OPTIONS}
8 |
9 | Create each supplied directory including any necessary parent directories
10 | that don't yet exist.
11 |
12 | If the directory already exists, do nothing.
13 |
14 | OPTIONS are:
15 |
16 | -m If a directory needs to be created, set the mode as an octal
17 | --mode= permission string.
18 |
19 | -v --version Print the mkdirp version number
20 |
21 | -h --help Print this helpful banner
22 |
23 | -p --print Print the first directories created for each path provided
24 |
25 | --manual Use manual implementation, even if native is available
26 | `
27 |
28 | const dirs: string[] = []
29 | const opts: MkdirpOptions = {}
30 | let doPrint: boolean = false
31 | let dashdash = false
32 | let manual = false
33 | for (const arg of process.argv.slice(2)) {
34 | if (dashdash) dirs.push(arg)
35 | else if (arg === '--') dashdash = true
36 | else if (arg === '--manual') manual = true
37 | else if (/^-h/.test(arg) || /^--help/.test(arg)) {
38 | console.log(usage())
39 | process.exit(0)
40 | } else if (arg === '-v' || arg === '--version') {
41 | console.log(version)
42 | process.exit(0)
43 | } else if (arg === '-p' || arg === '--print') {
44 | doPrint = true
45 | } else if (/^-m/.test(arg) || /^--mode=/.test(arg)) {
46 | // these don't get covered in CI, but work locally
47 | // weird because the tests below show as passing in the output.
48 | /* c8 ignore start */
49 | const mode = parseInt(arg.replace(/^(-m|--mode=)/, ''), 8)
50 | if (isNaN(mode)) {
51 | console.error(`invalid mode argument: ${arg}\nMust be an octal number.`)
52 | process.exit(1)
53 | }
54 | /* c8 ignore stop */
55 | opts.mode = mode
56 | } else dirs.push(arg)
57 | }
58 |
59 | import { mkdirp } from './index.js'
60 | const impl = manual ? mkdirp.manual : mkdirp
61 | if (dirs.length === 0) {
62 | console.error(usage())
63 | }
64 |
65 | // these don't get covered in CI, but work locally
66 | /* c8 ignore start */
67 | Promise.all(dirs.map(dir => impl(dir, opts)))
68 | .then(made => (doPrint ? made.forEach(m => m && console.log(m)) : null))
69 | .catch(er => {
70 | console.error(er.message)
71 | if (er.code) console.error(' code: ' + er.code)
72 | process.exit(1)
73 | })
74 | /* c8 ignore stop */
75 |
--------------------------------------------------------------------------------
/src/find-made.ts:
--------------------------------------------------------------------------------
1 | import { dirname } from 'path'
2 | import { MkdirpOptionsResolved } from './opts-arg.js'
3 |
4 | export const findMade = async (
5 | opts: MkdirpOptionsResolved,
6 | parent: string,
7 | path?: string
8 | ): Promise => {
9 | // we never want the 'made' return value to be a root directory
10 | if (path === parent) {
11 | return
12 | }
13 |
14 | return opts.statAsync(parent).then(
15 | st => (st.isDirectory() ? path : undefined), // will fail later
16 | er => {
17 | const fer = er as NodeJS.ErrnoException
18 | return fer && fer.code === 'ENOENT'
19 | ? findMade(opts, dirname(parent), parent)
20 | : undefined
21 | }
22 | )
23 | }
24 |
25 | export const findMadeSync = (
26 | opts: MkdirpOptionsResolved,
27 | parent: string,
28 | path?: string
29 | ): undefined | string => {
30 | if (path === parent) {
31 | return undefined
32 | }
33 |
34 | try {
35 | return opts.statSync(parent).isDirectory() ? path : undefined
36 | } catch (er) {
37 | const fer = er as NodeJS.ErrnoException
38 | return fer && fer.code === 'ENOENT'
39 | ? findMadeSync(opts, dirname(parent), parent)
40 | : undefined
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import { mkdirpManual, mkdirpManualSync } from './mkdirp-manual.js'
2 | import { mkdirpNative, mkdirpNativeSync } from './mkdirp-native.js'
3 | import { MkdirpOptions, optsArg } from './opts-arg.js'
4 | import { pathArg } from './path-arg.js'
5 | import { useNative, useNativeSync } from './use-native.js'
6 | /* c8 ignore start */
7 | export { mkdirpManual, mkdirpManualSync } from './mkdirp-manual.js'
8 | export { mkdirpNative, mkdirpNativeSync } from './mkdirp-native.js'
9 | export { useNative, useNativeSync } from './use-native.js'
10 | /* c8 ignore stop */
11 |
12 | export const mkdirpSync = (path: string, opts?: MkdirpOptions) => {
13 | path = pathArg(path)
14 | const resolved = optsArg(opts)
15 | return useNativeSync(resolved)
16 | ? mkdirpNativeSync(path, resolved)
17 | : mkdirpManualSync(path, resolved)
18 | }
19 |
20 | export const sync = mkdirpSync
21 | export const manual = mkdirpManual
22 | export const manualSync = mkdirpManualSync
23 | export const native = mkdirpNative
24 | export const nativeSync = mkdirpNativeSync
25 | export const mkdirp = Object.assign(
26 | async (path: string, opts?: MkdirpOptions) => {
27 | path = pathArg(path)
28 | const resolved = optsArg(opts)
29 | return useNative(resolved)
30 | ? mkdirpNative(path, resolved)
31 | : mkdirpManual(path, resolved)
32 | },
33 | {
34 | mkdirpSync,
35 | mkdirpNative,
36 | mkdirpNativeSync,
37 | mkdirpManual,
38 | mkdirpManualSync,
39 |
40 | sync: mkdirpSync,
41 | native: mkdirpNative,
42 | nativeSync: mkdirpNativeSync,
43 | manual: mkdirpManual,
44 | manualSync: mkdirpManualSync,
45 | useNative,
46 | useNativeSync,
47 | }
48 | )
49 |
--------------------------------------------------------------------------------
/src/mkdirp-manual.ts:
--------------------------------------------------------------------------------
1 | import { dirname } from 'path'
2 | import { MkdirpOptions, optsArg } from './opts-arg.js'
3 |
4 | export const mkdirpManualSync = (
5 | path: string,
6 | options?: MkdirpOptions,
7 | made?: string | undefined | void
8 | ): string | undefined | void => {
9 | const parent = dirname(path)
10 | const opts = { ...optsArg(options), recursive: false }
11 |
12 | if (parent === path) {
13 | try {
14 | return opts.mkdirSync(path, opts)
15 | } catch (er) {
16 | // swallowed by recursive implementation on posix systems
17 | // any other error is a failure
18 | const fer = er as NodeJS.ErrnoException
19 | if (fer && fer.code !== 'EISDIR') {
20 | throw er
21 | }
22 | return
23 | }
24 | }
25 |
26 | try {
27 | opts.mkdirSync(path, opts)
28 | return made || path
29 | } catch (er) {
30 | const fer = er as NodeJS.ErrnoException
31 | if (fer && fer.code === 'ENOENT') {
32 | return mkdirpManualSync(path, opts, mkdirpManualSync(parent, opts, made))
33 | }
34 | if (fer && fer.code !== 'EEXIST' && fer && fer.code !== 'EROFS') {
35 | throw er
36 | }
37 | try {
38 | if (!opts.statSync(path).isDirectory()) throw er
39 | } catch (_) {
40 | throw er
41 | }
42 | }
43 | }
44 |
45 | export const mkdirpManual = Object.assign(
46 | async (
47 | path: string,
48 | options?: MkdirpOptions,
49 | made?: string | undefined | void
50 | ): Promise => {
51 | const opts = optsArg(options)
52 | opts.recursive = false
53 | const parent = dirname(path)
54 | if (parent === path) {
55 | return opts.mkdirAsync(path, opts).catch(er => {
56 | // swallowed by recursive implementation on posix systems
57 | // any other error is a failure
58 | const fer = er as NodeJS.ErrnoException
59 | if (fer && fer.code !== 'EISDIR') {
60 | throw er
61 | }
62 | })
63 | }
64 |
65 | return opts.mkdirAsync(path, opts).then(
66 | () => made || path,
67 | async er => {
68 | const fer = er as NodeJS.ErrnoException
69 | if (fer && fer.code === 'ENOENT') {
70 | return mkdirpManual(parent, opts).then(
71 | (made?: string | undefined | void) => mkdirpManual(path, opts, made)
72 | )
73 | }
74 | if (fer && fer.code !== 'EEXIST' && fer.code !== 'EROFS') {
75 | throw er
76 | }
77 | return opts.statAsync(path).then(
78 | st => {
79 | if (st.isDirectory()) {
80 | return made
81 | } else {
82 | throw er
83 | }
84 | },
85 | () => {
86 | throw er
87 | }
88 | )
89 | }
90 | )
91 | },
92 | { sync: mkdirpManualSync }
93 | )
94 |
--------------------------------------------------------------------------------
/src/mkdirp-native.ts:
--------------------------------------------------------------------------------
1 | import { dirname } from 'path'
2 | import { findMade, findMadeSync } from './find-made.js'
3 | import { mkdirpManual, mkdirpManualSync } from './mkdirp-manual.js'
4 | import { MkdirpOptions, optsArg } from './opts-arg.js'
5 |
6 | export const mkdirpNativeSync = (
7 | path: string,
8 | options?: MkdirpOptions
9 | ): string | void | undefined => {
10 | const opts = optsArg(options)
11 | opts.recursive = true
12 | const parent = dirname(path)
13 | if (parent === path) {
14 | return opts.mkdirSync(path, opts)
15 | }
16 |
17 | const made = findMadeSync(opts, path)
18 | try {
19 | opts.mkdirSync(path, opts)
20 | return made
21 | } catch (er) {
22 | const fer = er as NodeJS.ErrnoException
23 | if (fer && fer.code === 'ENOENT') {
24 | return mkdirpManualSync(path, opts)
25 | } else {
26 | throw er
27 | }
28 | }
29 | }
30 |
31 | export const mkdirpNative = Object.assign(
32 | async (
33 | path: string,
34 | options?: MkdirpOptions
35 | ): Promise => {
36 | const opts = { ...optsArg(options), recursive: true }
37 | const parent = dirname(path)
38 | if (parent === path) {
39 | return await opts.mkdirAsync(path, opts)
40 | }
41 |
42 | return findMade(opts, path).then((made?: string | undefined) =>
43 | opts
44 | .mkdirAsync(path, opts)
45 | .then(m => made || m)
46 | .catch(er => {
47 | const fer = er as NodeJS.ErrnoException
48 | if (fer && fer.code === 'ENOENT') {
49 | return mkdirpManual(path, opts)
50 | } else {
51 | throw er
52 | }
53 | })
54 | )
55 | },
56 | { sync: mkdirpNativeSync }
57 | )
58 |
--------------------------------------------------------------------------------
/src/opts-arg.ts:
--------------------------------------------------------------------------------
1 | import {
2 | MakeDirectoryOptions,
3 | mkdir,
4 | mkdirSync,
5 | stat,
6 | Stats,
7 | statSync,
8 | } from 'fs'
9 |
10 | export interface FsProvider {
11 | stat?: (
12 | path: string,
13 | callback: (err: NodeJS.ErrnoException | null, stats: Stats) => any
14 | ) => any
15 | mkdir?: (
16 | path: string,
17 | opts: MakeDirectoryOptions & { recursive?: boolean },
18 | callback: (err: NodeJS.ErrnoException | null, made?: string) => any
19 | ) => any
20 | statSync?: (path: string) => Stats
21 | mkdirSync?: (
22 | path: string,
23 | opts: MakeDirectoryOptions & { recursive?: boolean }
24 | ) => string | undefined
25 | }
26 |
27 | interface Options extends FsProvider {
28 | mode?: number | string
29 | fs?: FsProvider
30 | mkdirAsync?: (
31 | path: string,
32 | opts: MakeDirectoryOptions & { recursive?: boolean }
33 | ) => Promise
34 | statAsync?: (path: string) => Promise
35 | }
36 |
37 | export type MkdirpOptions = Options | number | string
38 |
39 | export interface MkdirpOptionsResolved {
40 | mode: number
41 | fs: FsProvider
42 | mkdirAsync: (
43 | path: string,
44 | opts: MakeDirectoryOptions & { recursive?: boolean }
45 | ) => Promise
46 | statAsync: (path: string) => Promise
47 | stat: (
48 | path: string,
49 | callback: (err: NodeJS.ErrnoException | null, stats: Stats) => any
50 | ) => any
51 | mkdir: (
52 | path: string,
53 | opts: MakeDirectoryOptions & { recursive?: boolean },
54 | callback: (err: NodeJS.ErrnoException | null, made?: string) => any
55 | ) => any
56 | statSync: (path: string) => Stats
57 | mkdirSync: (
58 | path: string,
59 | opts: MakeDirectoryOptions & { recursive?: boolean }
60 | ) => string | undefined
61 | recursive?: boolean
62 | }
63 |
64 | export const optsArg = (opts?: MkdirpOptions): MkdirpOptionsResolved => {
65 | if (!opts) {
66 | opts = { mode: 0o777 }
67 | } else if (typeof opts === 'object') {
68 | opts = { mode: 0o777, ...opts }
69 | } else if (typeof opts === 'number') {
70 | opts = { mode: opts }
71 | } else if (typeof opts === 'string') {
72 | opts = { mode: parseInt(opts, 8) }
73 | } else {
74 | throw new TypeError('invalid options argument')
75 | }
76 |
77 | const resolved = opts as MkdirpOptionsResolved
78 | const optsFs = opts.fs || {}
79 |
80 | opts.mkdir = opts.mkdir || optsFs.mkdir || mkdir
81 |
82 | opts.mkdirAsync = opts.mkdirAsync
83 | ? opts.mkdirAsync
84 | : async (
85 | path: string,
86 | options: MakeDirectoryOptions & { recursive?: boolean }
87 | ): Promise => {
88 | return new Promise((res, rej) =>
89 | resolved.mkdir(path, options, (er, made) =>
90 | er ? rej(er) : res(made)
91 | )
92 | )
93 | }
94 |
95 | opts.stat = opts.stat || optsFs.stat || stat
96 | opts.statAsync = opts.statAsync
97 | ? opts.statAsync
98 | : async (path: string) =>
99 | new Promise((res, rej) =>
100 | resolved.stat(path, (err, stats) => (err ? rej(err) : res(stats)))
101 | )
102 |
103 | opts.statSync = opts.statSync || optsFs.statSync || statSync
104 | opts.mkdirSync = opts.mkdirSync || optsFs.mkdirSync || mkdirSync
105 |
106 | return resolved
107 | }
108 |
--------------------------------------------------------------------------------
/src/path-arg.ts:
--------------------------------------------------------------------------------
1 | const platform = process.env.__TESTING_MKDIRP_PLATFORM__ || process.platform
2 | import { parse, resolve } from 'path'
3 | export const pathArg = (path: string) => {
4 | if (/\0/.test(path)) {
5 | // simulate same failure that node raises
6 | throw Object.assign(
7 | new TypeError('path must be a string without null bytes'),
8 | {
9 | path,
10 | code: 'ERR_INVALID_ARG_VALUE',
11 | }
12 | )
13 | }
14 |
15 | path = resolve(path)
16 | if (platform === 'win32') {
17 | const badWinChars = /[*|"<>?:]/
18 | const { root } = parse(path)
19 | if (badWinChars.test(path.substring(root.length))) {
20 | throw Object.assign(new Error('Illegal characters in path.'), {
21 | path,
22 | code: 'EINVAL',
23 | })
24 | }
25 | }
26 |
27 | return path
28 | }
29 |
--------------------------------------------------------------------------------
/src/use-native.ts:
--------------------------------------------------------------------------------
1 | import { mkdir, mkdirSync } from 'fs'
2 | import { MkdirpOptions, optsArg } from './opts-arg.js'
3 |
4 | const version = process.env.__TESTING_MKDIRP_NODE_VERSION__ || process.version
5 | const versArr = version.replace(/^v/, '').split('.')
6 | const hasNative = +versArr[0] > 10 || (+versArr[0] === 10 && +versArr[1] >= 12)
7 |
8 | export const useNativeSync = !hasNative
9 | ? () => false
10 | : (opts?: MkdirpOptions) => optsArg(opts).mkdirSync === mkdirSync
11 |
12 | export const useNative = Object.assign(
13 | !hasNative
14 | ? () => false
15 | : (opts?: MkdirpOptions) => optsArg(opts).mkdir === mkdir,
16 | {
17 | sync: useNativeSync,
18 | }
19 | )
20 |
--------------------------------------------------------------------------------
/tap-snapshots/test-cmd.js-TAP.test.js:
--------------------------------------------------------------------------------
1 | /* IMPORTANT
2 | * This snapshot file is auto-generated, but designed for humans.
3 | * It should be checked into source control and tracked carefully.
4 | * Re-generate by setting TAP_SNAPSHOT=1 and running tests.
5 | * Make sure to inspect the output below. Do not ignore changes!
6 | */
7 | 'use strict'
8 | exports[`test/cmd.js TAP -h --help prints usage > --help output 1`] = `
9 | Object {
10 | "code": 0,
11 | "signal": null,
12 | "stderr": "",
13 | "stdout": "\\nusage: mkdirp [DIR1,DIR2..] {OPTIONS}\\n\\n Create each supplied directory including any necessary parent directories\\n that don't yet exist.\\n\\n If the directory already exists, do nothing.\\n\\nOPTIONS are:\\n\\n -m If a directory needs to be created, set the mode as an octal\\n --mode= permission string.\\n\\n -v --version Print the mkdirp version number\\n\\n -h --help Print this helpful banner\\n\\n -p --print Print the first directories created for each path provided\\n\\n --manual Use manual implementation, even if native is available\\n\\n",
14 | }
15 | `
16 |
17 | exports[`test/cmd.js TAP -v --version prints version > --version output 1`] = `
18 | Object {
19 | "code": 0,
20 | "signal": null,
21 | "stderr": "",
22 | "stdout": "4.2.0-69.lol\\n",
23 | }
24 | `
25 |
26 | exports[`test/cmd.js TAP failures > expect resolving Promise 1`] = `
27 | Array [
28 | Object {
29 | "code": 1,
30 | "signal": null,
31 | "stderr": "nope\\n",
32 | "stdout": "",
33 | },
34 | Object {
35 | "code": 1,
36 | "signal": null,
37 | "stderr": "fail\\n code: EFAIL\\n",
38 | "stdout": "",
39 | },
40 | ]
41 | `
42 |
43 | exports[`test/cmd.js TAP invalid mode > expect resolving Promise 1`] = `
44 | Object {
45 | "code": 1,
46 | "signal": null,
47 | "stderr": "invalid mode argument: --mode=XYZ\\nMust be an octal number.\\n",
48 | "stdout": "",
49 | }
50 | `
51 |
52 | exports[`test/cmd.js TAP make dir named --help > expect resolving Promise 1`] = `
53 | Object {
54 | "code": 0,
55 | "signal": null,
56 | "stderr": "",
57 | "stdout": "--help 0\\n",
58 | }
59 | `
60 |
61 | exports[`test/cmd.js TAP making dirs > expect resolving Promise 1`] = `
62 | Object {
63 | "code": 0,
64 | "signal": null,
65 | "stderr": "",
66 | "stdout": "",
67 | }
68 | `
69 |
70 | exports[`test/cmd.js TAP manual > expect resolving Promise 1`] = `
71 | Object {
72 | "code": 0,
73 | "signal": null,
74 | "stderr": "",
75 | "stdout": "MANUAL a 0\\nMANUAL b/c/d 0\\n",
76 | }
77 | `
78 |
79 | exports[`test/cmd.js TAP no dirs -> stderr usage > expect resolving Promise 1`] = `
80 | Object {
81 | "code": 0,
82 | "signal": null,
83 | "stderr": "\\nusage: mkdirp [DIR1,DIR2..] {OPTIONS}\\n\\n Create each supplied directory including any necessary parent directories\\n that don't yet exist.\\n\\n If the directory already exists, do nothing.\\n\\nOPTIONS are:\\n\\n -m If a directory needs to be created, set the mode as an octal\\n --mode= permission string.\\n\\n -v --version Print the mkdirp version number\\n\\n -h --help Print this helpful banner\\n\\n -p --print Print the first directories created for each path provided\\n\\n --manual Use manual implementation, even if native is available\\n\\n",
84 | "stdout": "",
85 | }
86 | `
87 |
88 | exports[`test/cmd.js TAP noisily > expect resolving Promise 1`] = `
89 | Object {
90 | "code": 0,
91 | "signal": null,
92 | "stderr": "",
93 | "stdout": "a 0\\nb/c/d 0\\n",
94 | }
95 | `
96 |
97 | exports[`test/cmd.js TAP print modes > expect resolving Promise 1`] = `
98 | Object {
99 | "code": 0,
100 | "signal": null,
101 | "stderr": "",
102 | "stdout": "a 509\\n",
103 | }
104 | `
105 |
--------------------------------------------------------------------------------
/tap-snapshots/test/cmd.ts.test.cjs:
--------------------------------------------------------------------------------
1 | /* IMPORTANT
2 | * This snapshot file is auto-generated, but designed for humans.
3 | * It should be checked into source control and tracked carefully.
4 | * Re-generate by setting TAP_SNAPSHOT=1 and running tests.
5 | * Make sure to inspect the output below. Do not ignore changes!
6 | */
7 | 'use strict'
8 | exports[`test/cmd.ts TAP -h --help prints usage > --help output 1`] = `
9 | Object {
10 | "code": 0,
11 | "signal": null,
12 | "stderr": "",
13 | "stdout": String(
14 |
15 | usage: mkdirp [DIR1,DIR2..] {OPTIONS}
16 |
17 | Create each supplied directory including any necessary parent directories
18 | that don't yet exist.
19 |
20 | If the directory already exists, do nothing.
21 |
22 | OPTIONS are:
23 |
24 | -m If a directory needs to be created, set the mode as an octal
25 | --mode= permission string.
26 |
27 | -v --version Print the mkdirp version number
28 |
29 | -h --help Print this helpful banner
30 |
31 | -p --print Print the first directories created for each path provided
32 |
33 | --manual Use manual implementation, even if native is available
34 |
35 |
36 | ),
37 | }
38 | `
39 |
40 | exports[`test/cmd.ts TAP -v --version prints version > --version output 1`] = `
41 | Object {
42 | "code": 0,
43 | "signal": null,
44 | "stderr": "",
45 | "stdout": "4.2.0-69.lol\\n",
46 | }
47 | `
48 |
49 | exports[`test/cmd.ts TAP failures > expect resolving Promise 1`] = `
50 | Array [
51 | Object {
52 | "code": 1,
53 | "signal": null,
54 | "stderr": "nope\\n",
55 | "stdout": "",
56 | },
57 | Object {
58 | "code": 1,
59 | "signal": null,
60 | "stderr": String(
61 | fail
62 | code: EFAIL
63 |
64 | ),
65 | "stdout": "",
66 | },
67 | ]
68 | `
69 |
70 | exports[`test/cmd.ts TAP invalid mode > expect resolving Promise 1`] = `
71 | Object {
72 | "code": 1,
73 | "signal": null,
74 | "stderr": String(
75 | invalid mode argument: --mode=XYZ
76 | Must be an octal number.
77 |
78 | ),
79 | "stdout": "",
80 | }
81 | `
82 |
83 | exports[`test/cmd.ts TAP make dir named --help > expect resolving Promise 1`] = `
84 | Object {
85 | "code": 0,
86 | "signal": null,
87 | "stderr": "",
88 | "stdout": "--help 0\\n",
89 | }
90 | `
91 |
92 | exports[`test/cmd.ts TAP making dirs > expect resolving Promise 1`] = `
93 | Object {
94 | "code": 0,
95 | "signal": null,
96 | "stderr": "",
97 | "stdout": "",
98 | }
99 | `
100 |
101 | exports[`test/cmd.ts TAP manual > expect resolving Promise 1`] = `
102 | Object {
103 | "code": 0,
104 | "signal": null,
105 | "stderr": "",
106 | "stdout": String(
107 | MANUAL a 0
108 | MANUAL b/c/d 0
109 |
110 | ),
111 | }
112 | `
113 |
114 | exports[`test/cmd.ts TAP no dirs -> stderr usage > expect resolving Promise 1`] = `
115 | Object {
116 | "code": 0,
117 | "signal": null,
118 | "stderr": String(
119 |
120 | usage: mkdirp [DIR1,DIR2..] {OPTIONS}
121 |
122 | Create each supplied directory including any necessary parent directories
123 | that don't yet exist.
124 |
125 | If the directory already exists, do nothing.
126 |
127 | OPTIONS are:
128 |
129 | -m If a directory needs to be created, set the mode as an octal
130 | --mode= permission string.
131 |
132 | -v --version Print the mkdirp version number
133 |
134 | -h --help Print this helpful banner
135 |
136 | -p --print Print the first directories created for each path provided
137 |
138 | --manual Use manual implementation, even if native is available
139 |
140 |
141 | ),
142 | "stdout": "",
143 | }
144 | `
145 |
146 | exports[`test/cmd.ts TAP noisily > expect resolving Promise 1`] = `
147 | Object {
148 | "code": 0,
149 | "signal": null,
150 | "stderr": "",
151 | "stdout": String(
152 | a 0
153 | b/c/d 0
154 |
155 | ),
156 | }
157 | `
158 |
159 | exports[`test/cmd.ts TAP print modes > expect resolving Promise 1`] = `
160 | Object {
161 | "code": 0,
162 | "signal": null,
163 | "stderr": "",
164 | "stdout": "a 509\\n",
165 | }
166 | `
167 |
--------------------------------------------------------------------------------
/test/cmd.ts:
--------------------------------------------------------------------------------
1 | const cmd = require.resolve('../dist/cjs/src/bin.js')
2 | import t from 'tap'
3 | import { MkdirpOptions } from '../src/opts-arg'
4 |
5 | import { spawn } from 'child_process'
6 | import { basename } from 'path'
7 |
8 | const fakeMkdirp = (path: string, opts: MkdirpOptions) =>
9 | basename(path) === 'ERROR'
10 | ? Promise.reject(new Error('nope'))
11 | : basename(path) === 'EFAIL'
12 | ? Promise.reject(Object.assign(new Error('fail'), { code: 'EFAIL' }))
13 | : opts && typeof opts === 'object'
14 | ? Promise.resolve(`${path} ${opts.mode || 0}`)
15 | : Promise.reject('wtf')
16 |
17 | fakeMkdirp.manual = (path: string, opts: MkdirpOptions) =>
18 | fakeMkdirp(`MANUAL ${path}`, opts)
19 | fakeMkdirp.mkdirp = fakeMkdirp
20 |
21 | if (process.argv[2] === 'RUN') {
22 | process.argv = [process.execPath, cmd, ...process.argv.slice(3)]
23 | t.mock(cmd, {
24 | '../dist/cjs/src/index.js': { mkdirp: fakeMkdirp },
25 | '../dist/cjs/package.json': {
26 | version: '4.2.0-69.lol',
27 | },
28 | })
29 | } else {
30 | const run = (...args: string[]) =>
31 | new Promise(res => {
32 | const proc = spawn(process.execPath, [
33 | ...process.execArgv,
34 | __filename,
35 | 'RUN',
36 | ...args,
37 | ])
38 | const out: Buffer[] = []
39 | const err: Buffer[] = []
40 | proc.stdout.on('data', c => out.push(c))
41 | proc.stderr.on('data', c => err.push(c))
42 | proc.on('close', (code, signal) => {
43 | res({
44 | code,
45 | signal,
46 | stdout: Buffer.concat(out).toString('utf8'),
47 | stderr: Buffer.concat(err).toString('utf8'),
48 | })
49 | })
50 | })
51 |
52 | t.test('-h --help prints usage', t =>
53 | Promise.all([run('-h'), run('--help')]).then(res => {
54 | t.strictSame(res[0], res[1], 'same for -h and --help')
55 | t.matchSnapshot(res[0], '--help output')
56 | })
57 | )
58 |
59 | t.test('no dirs -> stderr usage', t => t.resolveMatchSnapshot(run()))
60 |
61 | t.test('-v --version prints version', t =>
62 | Promise.all([run('-v'), run('--version')]).then(res => {
63 | t.strictSame(res[0], res[1], 'same for -v and --version')
64 | t.matchSnapshot(res[0], '--version output')
65 | })
66 | )
67 |
68 | t.test('making dirs', t => t.resolveMatchSnapshot(run('a', 'b/c/d', 'e')))
69 | t.test('noisily', t => t.resolveMatchSnapshot(run('a', 'b/c/d', '--print')))
70 | t.test('manual', t =>
71 | t.resolveMatchSnapshot(run('a', 'b/c/d', '-p', '--manual'))
72 | )
73 | t.test('print modes', t => t.resolveMatchSnapshot(run('a', '-m775', '-p')))
74 | t.test('invalid mode', t => t.resolveMatchSnapshot(run('--mode=XYZ')))
75 | t.test('make dir named --help', t =>
76 | t.resolveMatchSnapshot(run('-p', '--', '--help'))
77 | )
78 | t.test('failures', t =>
79 | t.resolveMatchSnapshot(Promise.all([run('x/ERROR'), run('x/EFAIL')]))
80 | )
81 | }
82 |
--------------------------------------------------------------------------------
/test/find-made.ts:
--------------------------------------------------------------------------------
1 | import t from 'tap'
2 |
3 | import * as fs from 'fs'
4 | import { basename, posix } from 'path'
5 | import { promisify } from 'util'
6 |
7 | const statAsync = (path: string) =>
8 | basename(path) === 'error'
9 | ? Promise.reject(new Error('not a real error'))
10 | : promisify(fs.stat)(path)
11 |
12 | const statSync = (path: string) => {
13 | if (basename(path) === 'error') {
14 | throw new Error('not a real error')
15 | } else {
16 | return fs.statSync(path)
17 | }
18 | }
19 |
20 | const { findMade, findMadeSync } = t.mock('../dist/cjs/src/find-made.js', {
21 | path: posix,
22 | })
23 |
24 | t.test('find what dir will be made', async t => {
25 | const dir = t.testdir({
26 | file: 'txt',
27 | subdir: {},
28 | })
29 |
30 | const o = { statAsync, statSync }
31 |
32 | t.equal(findMadeSync(o, `${dir}/subdir/x/y/z`), `${dir}/subdir/x`)
33 | t.equal(findMadeSync(o, `${dir}/subdir`), undefined)
34 | t.equal(findMadeSync(o, `${dir}/file/x/y/z`), undefined)
35 | t.equal(findMadeSync(o, `${dir}/file`, `${dir}/file/x`), undefined)
36 | t.equal(findMadeSync(o, `${dir}/subdir/error`), undefined)
37 | t.equal(findMadeSync(o, '/', '/'), undefined)
38 | return Promise.all([
39 | findMade(o, `${dir}/subdir/x/y/z`),
40 | findMade(o, `${dir}/subdir`),
41 | findMade(o, `${dir}/file/x/y/z`),
42 | findMade(o, `${dir}/file`, `${dir}/file/x`),
43 | findMade(o, `${dir}/subdir/error`),
44 | findMade(o, '/', '/'),
45 | ]).then(made =>
46 | t.strictSame(made, [
47 | `${dir}/subdir/x`,
48 | undefined,
49 | undefined,
50 | undefined,
51 | undefined,
52 | undefined,
53 | ])
54 | )
55 | })
56 |
--------------------------------------------------------------------------------
/test/index.ts:
--------------------------------------------------------------------------------
1 | import { mkdir, mkdirSync, statSync } from 'fs'
2 | import t from 'tap'
3 | import { mkdirp } from '../dist/cjs/src/index.js'
4 | import {
5 | MkdirpOptions,
6 | MkdirpOptionsResolved,
7 | } from '../dist/cjs/src/opts-arg.js'
8 |
9 | const s = (s: any) => (typeof s !== 'string' ? s : s.replace(/\\/g, '/'))
10 |
11 | // node before 10.13 didn't native recursive mkdir
12 | const doNative = !/^v([0-8]\.|10.([0-9]\.|10\.|11\.([0-9]|1[01])$))/.test(
13 | process.version
14 | )
15 |
16 | t.test('module shape', t => {
17 | t.type(mkdirp, Function)
18 | t.type(mkdirp.sync, Function)
19 | t.type(mkdirp.manual, Function)
20 | t.type(mkdirp.manualSync, Function)
21 | if (doNative) {
22 | t.type(mkdirp.native, Function)
23 | t.type(mkdirp.nativeSync, Function)
24 | }
25 | t.end()
26 | })
27 |
28 | t.test('basic making of dirs should work', async t => {
29 | const dir = t.testdir({ a: {} })
30 | const check = (d: string) => t.ok(statSync(d).isDirectory())
31 | t.equal(s(mkdirp.sync(`${dir}/a/sync`)), s(`${dir}/a/sync`))
32 | check(`${dir}/a/sync`)
33 | t.equal(mkdirp.sync(`${dir}/a/sync`), undefined)
34 |
35 | t.equal(
36 | s(mkdirp.manualSync(`${dir}/a/manual-sync`)),
37 | s(`${dir}/a/manual-sync`)
38 | )
39 | check(`${dir}/a/manual-sync`)
40 | t.equal(s(mkdirp.manualSync(`${dir}/a/manual-sync`)), undefined)
41 |
42 | if (doNative) {
43 | t.equal(
44 | s(mkdirp.nativeSync(`${dir}/a/native-sync`)),
45 | s(`${dir}/a/native-sync`)
46 | )
47 | check(`${dir}/a/native-sync`)
48 | t.equal(mkdirp.nativeSync(`${dir}/a/native-sync`), undefined)
49 | }
50 |
51 | // override to force the manual option
52 | const myMkdir = (
53 | path: string,
54 | opts: MkdirpOptionsResolved,
55 | cb: (er: NodeJS.ErrnoException, made: string | undefined | void) => void
56 | //@ts-ignore
57 | ) => mkdir(path, opts, cb)
58 | const myMkdirSync = (path: string, opts: MkdirpOptions) =>
59 | mkdirSync(path, opts)
60 | const opts = { mkdir: myMkdir, mkdirSync: myMkdirSync }
61 | //@ts-ignore
62 | t.equal(s(mkdirp.sync(`${dir}/a/custom-sync`, opts)), s(`${dir}/a/custom-sync`))
63 | check(`${dir}/a/custom-sync`)
64 | //@ts-ignore
65 | t.equal(s(mkdirp.sync(`${dir}/a/custom-sync`, opts)), undefined)
66 |
67 | return Promise.all([
68 | mkdirp(`${dir}/a/async`),
69 | mkdirp.manual(`${dir}/a/manual-async`),
70 | doNative && mkdirp.native(`${dir}/a/native-async`),
71 | //@ts-ignore
72 | mkdirp(`${dir}/a/custom-async`, opts),
73 | ])
74 | .then(made => {
75 | t.strictSame(
76 | made.map(m => s(m)),
77 | [
78 | `${dir}/a/async`,
79 | `${dir}/a/manual-async`,
80 | doNative && `${dir}/a/native-async`,
81 | `${dir}/a/custom-async`,
82 | ].map(m => s(m))
83 | )
84 | check(`${dir}/a/async`)
85 | check(`${dir}/a/manual-async`)
86 | doNative && check(`${dir}/a/native-async`)
87 | check(`${dir}/a/custom-async`)
88 | return Promise.all([
89 | mkdirp(`${dir}/a/async`),
90 | mkdirp.manual(`${dir}/a/manual-async`),
91 | doNative ? mkdirp.native(`${dir}/a/native-async`) : undefined,
92 | //@ts-ignore
93 | mkdirp(`${dir}/a/custom-async`, opts),
94 | ])
95 | })
96 | .then(made =>
97 | t.strictSame(made, [undefined, undefined, undefined, undefined])
98 | )
99 | })
100 |
--------------------------------------------------------------------------------
/test/mkdirp-manual.ts:
--------------------------------------------------------------------------------
1 | import t from 'tap'
2 | import { promisify } from 'util'
3 |
4 | import { mkdir, mkdirSync, stat, statSync } from 'fs'
5 | const statAsync = promisify(stat)
6 | const mkdirAsync = promisify(mkdir)
7 |
8 | import { posix as path } from 'path'
9 |
10 | const { mkdirpManual, mkdirpManualSync } = t.mock(
11 | '../dist/cjs/src/mkdirp-manual.js',
12 | {
13 | path,
14 | }
15 | )
16 |
17 | t.test('mkdirpManual / just calls implementation', t => {
18 | t.test('success is fine, of course', t => {
19 | const opt = {
20 | mkdirAsync: () => Promise.resolve('mkdirAsync impl'),
21 | mkdirSync: () => 'mkdirSync impl',
22 | recursive: true,
23 | }
24 | t.equal(mkdirpManualSync('/', opt), 'mkdirSync impl')
25 | //@ts-ignore
26 | t.equal(opt.recursive, true)
27 | return mkdirpManual('/', opt).then((res: string) => {
28 | t.equal(res, 'mkdirAsync impl')
29 | //@ts-ignore
30 | t.equal(opt.recursive, true)
31 | })
32 | })
33 |
34 | t.test('EISDIR is expected and ignored', t => {
35 | const opt = {
36 | mkdirAsync: () =>
37 | Promise.reject(Object.assign(new Error('is dir'), { code: 'EISDIR' })),
38 | mkdirSync: () => {
39 | throw Object.assign(new Error('is dir'), { code: 'EISDIR' })
40 | },
41 | recursive: true,
42 | }
43 | t.equal(mkdirpManualSync('/', opt), undefined)
44 | t.equal(opt.recursive, true)
45 | opt.recursive = true
46 | return mkdirpManual('/', opt).then((made: string) => {
47 | t.equal(made, undefined)
48 | t.equal(opt.recursive, true)
49 | })
50 | })
51 |
52 | t.test('other failures are failures', t => {
53 | const opt = {
54 | mkdirAsync: () =>
55 | Promise.reject(Object.assign(new Error('grolb'), { code: 'blorg' })),
56 | mkdirSync: () => {
57 | throw Object.assign(new Error('grolb'), { code: 'blorg' })
58 | },
59 | recursive: true,
60 | }
61 | t.throws(() => mkdirpManualSync('/', opt), { code: 'blorg' })
62 | return t.rejects(mkdirpManual('/', opt), { code: 'blorg' })
63 | })
64 |
65 | t.end()
66 | })
67 |
68 | t.test('read-only file system, still succeed if dir exists', t => {
69 | const dir = t.testdir({ foo: {} })
70 | const opt = {
71 | stat,
72 | statAsync,
73 | statSync,
74 | mkdir,
75 | mkdirAsync: () =>
76 | Promise.reject(
77 | Object.assign(new Error('EROFS'), {
78 | code: 'EROFS',
79 | })
80 | ),
81 | mkdirSync: () => {
82 | throw Object.assign(new Error('EROFS'), {
83 | code: 'EROFS',
84 | })
85 | },
86 | }
87 | t.equal(mkdirpManualSync(`${dir}/foo`, opt), undefined)
88 | return mkdirpManual(`${dir}/foo`, opt).then((made: string) =>
89 | t.equal(made, undefined)
90 | )
91 | })
92 |
93 | t.test('recurse and return first dir made', t => {
94 | const dir = t.testdir()
95 | const opt = {
96 | stat,
97 | statAsync,
98 | statSync,
99 | mkdir,
100 | mkdirAsync,
101 | mkdirSync,
102 | }
103 |
104 | t.equal(mkdirpManualSync(`${dir}/sync/a/b`, opt), `${dir}/sync`)
105 | t.equal(statSync(`${dir}/sync/a/b`).isDirectory(), true, 'made dir')
106 | t.equal(mkdirpManualSync(`${dir}/sync/a/b`, opt), undefined)
107 |
108 | return mkdirpManual(`${dir}/async/a/b`, opt)
109 | .then((made: string) => {
110 | t.equal(made, `${dir}/async`)
111 | return mkdirpManual(`${dir}/async/a/b`, opt)
112 | })
113 | .then((made: string | undefined) => t.equal(made, undefined))
114 | })
115 |
116 | t.test('unknown failure types are failures', t => {
117 | const opt = {
118 | mkdirAsync: () =>
119 | Promise.reject(Object.assign(new Error('grolb'), { code: 'blorg' })),
120 | mkdirSync: () => {
121 | throw Object.assign(new Error('grolb'), { code: 'blorg' })
122 | },
123 | // ensure it gets reset
124 | recursive: true,
125 | }
126 | t.throws(() => mkdirpManualSync('/x/y/z', opt), { code: 'blorg' })
127 | return t.rejects(mkdirpManual('/x/y/z', opt), { code: 'blorg' })
128 | })
129 |
130 | t.test('cannot make dir over a file', t => {
131 | const dir = t.testdir({ file: 'txt' })
132 | const opt = {
133 | stat,
134 | statAsync,
135 | statSync,
136 | mkdir,
137 | mkdirAsync,
138 | mkdirSync,
139 | }
140 |
141 | t.throws(() => mkdirpManualSync(`${dir}/file`, opt), { code: 'EEXIST' })
142 | return t.rejects(mkdirpManual(`${dir}/file`, opt), { code: 'EEXIST' })
143 | })
144 |
145 | t.test('try to overwrite a file, then fail to stat it', t => {
146 | const dir = t.testdir({ file: 'txt' })
147 | const file = `${dir}/file`
148 | const er = Object.assign(new Error('nope'), { code: 'grob' })
149 | const opt = {
150 | statAsync: (path: string) =>
151 | path === file ? Promise.reject(er) : statAsync(path),
152 | statSync: (path: string) => {
153 | if (path === file) throw er
154 | else return statSync(path)
155 | },
156 | mkdirAsync,
157 | mkdirSync,
158 | }
159 |
160 | t.throws(() => mkdirpManualSync(`${dir}/file`, opt), { code: 'EEXIST' })
161 | return t.rejects(mkdirpManual(`${dir}/file`, opt), { code: 'EEXIST' })
162 | })
163 |
--------------------------------------------------------------------------------
/test/mkdirp-native.ts:
--------------------------------------------------------------------------------
1 | import { stat, statSync } from 'fs'
2 | import t from 'tap'
3 | import { promisify } from 'util'
4 | const statAsync = promisify(stat)
5 |
6 | import { posix as path } from 'path'
7 | const { mkdirpNative, mkdirpNativeSync } = t.mock(
8 | '../dist/cjs/src/mkdirp-native.js',
9 | {
10 | // just return an indicator that it was called
11 | '../dist/cjs/src/mkdirp-manual.js': {
12 | mkdirpManual: () => 'mkdirpManual',
13 | mkdirpManualSync: () => 'mkdirpManualSync',
14 | },
15 | path,
16 | }
17 | )
18 |
19 | t.test('mkdirpNative / just calls implementation', async t => {
20 | const opt = {
21 | mkdirAsync: () => 'mkdirAsync impl',
22 | mkdirSync: () => 'mkdirSync impl',
23 | }
24 | t.equal(await mkdirpNative('/', opt), 'mkdirAsync impl')
25 | //@ts-ignore
26 | t.equal(opt.recursive, undefined)
27 | t.equal(mkdirpNativeSync('/', opt), 'mkdirSync impl')
28 | //@ts-ignore
29 | t.equal(opt.recursive, undefined)
30 | })
31 |
32 | t.test('mkdirpNative calls impl and returns findMade', t => {
33 | const opt = {
34 | mkdirAsync: () => Promise.resolve(),
35 | mkdirSync: () => undefined,
36 | statAsync,
37 | statSync,
38 | }
39 |
40 | const dir = t.testdir()
41 | t.equal(mkdirpNativeSync(`${dir}/sync/a/b/c`, opt), `${dir}/sync`)
42 | return mkdirpNative(`${dir}/async/a/b/c`, opt).then((made: string) =>
43 | t.equal(made, `${dir}/async`)
44 | )
45 | })
46 |
47 | t.test('ENOENT error falls back to manual', t => {
48 | const opt = {
49 | mkdirAsync: () =>
50 | Promise.reject(Object.assign(new Error('poo'), { code: 'ENOENT' })),
51 | mkdirSync: () => {
52 | throw Object.assign(new Error('poo'), { code: 'ENOENT' })
53 | },
54 | statAsync,
55 | statSync,
56 | }
57 |
58 | const dir = t.testdir()
59 | t.equal(mkdirpNativeSync(`${dir}/sync/a/b/c`, opt), 'mkdirpManualSync')
60 | return mkdirpNative(`${dir}/async/a/b/c`, opt).then((made: string) =>
61 | t.equal(made, 'mkdirpManual')
62 | )
63 | })
64 |
65 | t.test('other errors are raised to caller', t => {
66 | const opt = {
67 | mkdirAsync: () =>
68 | Promise.reject(Object.assign(new Error('poo'), { code: 'blorg' })),
69 | mkdirSync: () => {
70 | throw Object.assign(new Error('poo'), { code: 'blorg' })
71 | },
72 | statAsync,
73 | statSync,
74 | }
75 |
76 | t.throws(() => mkdirpNativeSync('anything', opt), { code: 'blorg' })
77 | return t.rejects(mkdirpNative('at/all', opt), { code: 'blorg' })
78 | })
79 |
--------------------------------------------------------------------------------
/test/opts-arg.ts:
--------------------------------------------------------------------------------
1 | import * as fs from 'fs'
2 | import t from 'tap'
3 | import { optsArg } from '../dist/cjs/src/opts-arg.js'
4 | const mode = 0o777
5 |
6 | const defFs = {
7 | mkdir: fs.mkdir,
8 | mkdirSync: fs.mkdirSync,
9 | stat: fs.stat,
10 | statSync: fs.statSync,
11 | }
12 |
13 | const stat = () => {}
14 | stat.fake = true
15 | const statSync = () => {}
16 | statSync.fake = true
17 |
18 | // arg, expect
19 | const cases = {
20 | null: [null, { mode, ...defFs }],
21 | false: [false, { mode, ...defFs }],
22 | undefined: [undefined, { mode, ...defFs }],
23 | 'empty object': [{}, { mode, ...defFs }],
24 | 'numeric mode': [0o775, { mode: 0o775, ...defFs }],
25 | 'string mode': ['775', { mode: 0o775, ...defFs }],
26 | 'empty custom fs': [{ fs: {} }, { mode, ...defFs, fs: {} }],
27 | 'custom stat/statSync': [
28 | { stat, statSync },
29 | { mode, ...defFs, stat, statSync },
30 | ],
31 | 'custom fs with stat/statSync': [
32 | { fs: { stat, statSync } },
33 | { mode, ...defFs, fs: { stat, statSync }, stat, statSync },
34 | ],
35 | }
36 |
37 | for (const [name, c] of Object.entries(cases)) {
38 | const [arg, expect] = c
39 | //@ts-ignore
40 | t.match(optsArg(arg), expect, name)
41 | }
42 |
43 | //@ts-ignore
44 | t.throws(() => optsArg(() => {}), TypeError('invalid options argument'))
45 |
--------------------------------------------------------------------------------
/test/path-arg.ts:
--------------------------------------------------------------------------------
1 | import t from 'tap'
2 |
3 | if (!process.env.__TESTING_MKDIRP_PLATFORM__) {
4 | const fake = process.platform === 'win32' ? 'posix' : 'win32'
5 | //@ts-ignore
6 | t.spawn(process.execPath, [...process.execArgv, __filename], {
7 | env: {
8 | ...process.env,
9 | __TESTING_MKDIRP_PLATFORM__: fake,
10 | },
11 | })
12 | }
13 |
14 | const platform = process.env.__TESTING_MKDIRP_PLATFORM__ || process.platform
15 | const path = require('path').platform || require('path')
16 | const { pathArg } = t.mock('../dist/cjs/src/path-arg.js', {
17 | path,
18 | })
19 | const { resolve } = path
20 |
21 | t.equal(pathArg('a/b/c'), resolve('a/b/c'))
22 | t.throws(
23 | () => pathArg('a\0b'),
24 | Error('path must be a string without null bytes')
25 | )
26 | if (platform === 'win32') {
27 | const badPaths = [
28 | 'c:\\a\\b:c',
29 | 'c:\\a\\b*c',
30 | 'c:\\a\\b?c',
31 | 'c:\\a\\bc',
33 | 'c:\\a\\b|c',
34 | 'c:\\a\\b"c',
35 | ]
36 | for (const path of badPaths) {
37 | const er = Object.assign(new Error('Illegal characters in path'), {
38 | path,
39 | code: 'EINVAL',
40 | })
41 | t.throws(() => pathArg(path), er)
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/test/use-native.ts:
--------------------------------------------------------------------------------
1 | import { mkdir, mkdirSync } from 'fs'
2 | import t from 'tap'
3 | import { useNative, useNativeSync } from '../dist/cjs/src/use-native.js'
4 | // node before 10.13 didn't native recursive mkdir
5 | if (/^v([0-8]\.|10.([0-9]\.|10\.|11\.([0-9]|1[01])$))/.test(process.version)) {
6 | t.plan(0, 'no native recursive mkdirp in this node version')
7 | process.exit(0)
8 | }
9 |
10 | if (!process.env.__TESTING_MKDIRP_NODE_VERSION__) {
11 | //@ts-ignore
12 | t.spawn(process.execPath, [...process.execArgv, __filename], {
13 | env: {
14 | ...process.env,
15 | __TESTING_MKDIRP_NODE_VERSION__: 'v10.11.12',
16 | },
17 | })
18 |
19 | //@ts-ignore
20 | t.spawn(process.execPath, [...process.execArgv, __filename], {
21 | env: {
22 | ...process.env,
23 | __TESTING_MKDIRP_NODE_VERSION__: 'v8.9.10',
24 | },
25 | })
26 |
27 | // this one has the native impl
28 | t.equal(useNative({ mkdir }), true)
29 | //@ts-ignore
30 | t.equal(useNative({ mkdir: 1243 }), false)
31 | t.equal(useNativeSync({ mkdirSync }), true)
32 | //@ts-ignore
33 | t.equal(useNativeSync({ mkdirSync: 1243 }), false)
34 | } else {
35 | t.equal(useNative({ mkdir }), false)
36 | //@ts-ignore
37 | t.equal(useNative({ mkdir: 1243 }), false)
38 | t.equal(useNativeSync({ mkdirSync }), false)
39 | //@ts-ignore
40 | t.equal(useNativeSync({ mkdirSync: 1243 }), false)
41 | }
42 |
--------------------------------------------------------------------------------
/tsconfig-base.json:
--------------------------------------------------------------------------------
1 | {
2 | "exclude": ["./test", "./tap-snapshots"],
3 | "include": ["src/**/*.ts"],
4 | "compilerOptions": {
5 | "allowSyntheticDefaultImports": true,
6 | "declaration": true,
7 | "inlineSources": true,
8 | "declarationMap": true,
9 | "esModuleInterop": true,
10 | "forceConsistentCasingInFileNames": true,
11 | "isolatedModules": true,
12 | "moduleResolution": "node",
13 | "resolveJsonModule": true,
14 | "skipLibCheck": true,
15 | "sourceMap": true,
16 | "strict": true,
17 | "target": "es2022"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/tsconfig-esm.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig-base.json",
3 | "exclude": ["./test", "./tap-snapshots", "src/bin.ts"],
4 | "compilerOptions": {
5 | "module": "esnext",
6 | "outDir": "dist/mjs"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig-base.json",
3 | "compilerOptions": {
4 | "module": "commonjs",
5 | "outDir": "dist/cjs",
6 | "moduleResolution": "Node"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/typedoc.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationLinks": {
3 | "GitHub": "https://github.com/isaacs/node-mkdirp",
4 | "isaacs projects": "https://isaacs.github.io/"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------