Skip to content

Commit

Permalink
Improve ensurefile error (#744)
Browse files Browse the repository at this point in the history
* Check createFileSync gives clear error if node in directory tree is a file

* Make error code check work in Node.js 6

* Throw ENOTDIR error when dir doesn't exist

* Add test for createFile

* Throw ENOTDIR error when dir doesn't exist for makeFile async

* Make stat call on parent directory instead of first checking exists

Co-authored-by: Luke Childs <lukechilds123@gmail.com>
  • Loading branch information
RyanZim and lukechilds committed Jan 31, 2020
1 parent 76e48cb commit 5d3f533
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 10 deletions.
26 changes: 26 additions & 0 deletions lib/ensure/__tests__/create.test.js
Expand Up @@ -42,6 +42,18 @@ describe('fs-extra', () => {
done()
})
})

it('should give clear error if node in directory tree is a file', done => {
const existingFile = path.join(TEST_DIR, Math.random() + 'ts-e', Math.random() + '.txt')
fse.mkdirsSync(path.dirname(existingFile))
fs.writeFileSync(existingFile)

const file = path.join(existingFile, Math.random() + '.txt')
fse.createFile(file, err => {
assert.strictEqual(err.code, 'ENOTDIR')
done()
})
})
})
})

Expand All @@ -63,6 +75,20 @@ describe('fs-extra', () => {
fse.createFileSync(file)
assert.strictEqual(fs.readFileSync(file, 'utf8'), 'hello world')
})

it('should give clear error if node in directory tree is a file', () => {
const existingFile = path.join(TEST_DIR, Math.random() + 'ts-e', Math.random() + '.txt')
fse.mkdirsSync(path.dirname(existingFile))
fs.writeFileSync(existingFile)

const file = path.join(existingFile, Math.random() + '.txt')
try {
fse.createFileSync(file)
assert.fail()
} catch (err) {
assert.strictEqual(err.code, 'ENOTDIR')
}
})
})
})
})
40 changes: 30 additions & 10 deletions lib/ensure/file.js
Expand Up @@ -4,7 +4,6 @@ const u = require('universalify').fromCallback
const path = require('path')
const fs = require('graceful-fs')
const mkdir = require('../mkdirs')
const pathExists = require('../path-exists').pathExists

function createFile (file, callback) {
function makeFile () {
Expand All @@ -17,13 +16,26 @@ function createFile (file, callback) {
fs.stat(file, (err, stats) => { // eslint-disable-line handle-callback-err
if (!err && stats.isFile()) return callback()
const dir = path.dirname(file)
pathExists(dir, (err, dirExists) => {
if (err) return callback(err)
if (dirExists) return makeFile()
mkdir.mkdirs(dir, err => {
if (err) return callback(err)
makeFile()
})
fs.stat(dir, (err, stats) => {
if (err) {
// if the directory doesn't exist, make it
if (err.code === 'ENOENT') {
return mkdir.mkdirs(dir, err => {
if (err) return callback(err)
makeFile()
})
}
return callback(err)
}

if (stats.isDirectory()) makeFile()
else {
// parent is not a directory
// This is just to cause an internal ENOTDIR error to be thrown
fs.readdir(dir, err => {
if (err) return callback(err)
})
}
})
})
}
Expand All @@ -36,8 +48,16 @@ function createFileSync (file) {
if (stats && stats.isFile()) return

const dir = path.dirname(file)
if (!fs.existsSync(dir)) {
mkdir.mkdirsSync(dir)
try {
if (!fs.statSync(dir).isDirectory()) {
// parent is not a directory
// This is just to cause an internal ENOTDIR error to be thrown
fs.readdirSync(dir)
}
} catch (err) {
// If the stat call above failed because the directory doesn't exist, create it
if (err && err.code === 'ENOENT') mkdir.mkdirsSync(dir)
else throw err
}

fs.writeFileSync(file, '')
Expand Down

0 comments on commit 5d3f533

Please sign in to comment.