Comparing version 1.1.1 to 2.0.0
170
index.js
@@ -9,12 +9,12 @@ 'use strict'; | ||
const defaultDirMode = parseInt('0777', 8) & (~process.umask()); | ||
const defaultFileMode = parseInt('0666', 8) & (~process.umask()); | ||
const defaultDirMode = 0o777 & (~process.umask()); | ||
const defaultFileMode = 0o666 & (~process.umask()); | ||
const padNum = function(n, width, z) { | ||
z = z || '0'; | ||
n += ''; | ||
n = String(n); | ||
return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n; | ||
}; | ||
const writeAll = function(fd, buffer, offset, length, position, cb) { | ||
function writeAll(fd, buffer, offset, length, position, cb) { | ||
fs.write(fd, buffer, offset, length, position, (writeErr, written) => { | ||
@@ -32,46 +32,43 @@ if (writeErr) { | ||
}); | ||
}; | ||
} | ||
const mkdirp = function(p, mode, cb) { | ||
fs.mkdir(p, mode, err => { | ||
if (!err) { | ||
cb(); | ||
} else if (err.code === 'ENOENT') { | ||
mkdirp(path.dirname(p), mode, err => { | ||
if (err) { | ||
cb(err); | ||
} else { | ||
mkdirp(p, mode, cb); | ||
} | ||
}); | ||
} else if (err.code === 'EEXIST') { | ||
cb(); | ||
} else { | ||
cb(err); | ||
} | ||
}); | ||
}; | ||
function writeAllAsync(fd, buffer, offset, length, position) { | ||
return new Promise((resolve, reject) => { | ||
writeAll(fd, buffer, offset, length, position, err => { | ||
if (err) { | ||
return reject(err); | ||
} | ||
const openUniqueHandler = function(tryNum, fileParts, options, cb) { | ||
resolve(); | ||
}) | ||
}) | ||
} | ||
async function openUniqueHandler(tryNum, fileParts, options) { | ||
const file = options.simple ? fileParts.tail : tryNum ? (fileParts.head + fileParts.padLeft + padNum(tryNum, fileParts.pad) + fileParts.padRight + fileParts.tail) : (fileParts.head + fileParts.tail); | ||
const newPath = path.join(fileParts.path, file); | ||
fs.open(newPath, options.flags || 'w', options.mode || defaultFileMode, (err, fd) => { | ||
if (err && err.code === 'EEXIST' && !options.simple) { | ||
openUniqueHandler(++tryNum, fileParts, options, cb); | ||
} else if (err && err.code === 'ENOENT' && options.force) { | ||
mkdirp(fileParts.path, defaultDirMode, ere => { | ||
if (ere) { | ||
cb(ere); | ||
} else { | ||
openUniqueHandler(tryNum, fileParts, options, cb); | ||
} | ||
try { | ||
const fd = await fs.promises.open(newPath, options.flags || 'w', options.mode || defaultFileMode); | ||
return { | ||
fd: fd.fd, | ||
path: newPath | ||
}; | ||
} catch (err) { | ||
if (err.code === 'EEXIST' && !options.simple) { | ||
return openUniqueHandler(++tryNum, fileParts, options); | ||
} else if (err.code === 'ENOENT' && options.force) { | ||
await fs.promises.mkdir(fileParts.path, { | ||
mode: defaultDirMode, | ||
recursive: true | ||
}); | ||
} else { | ||
cb(err, fd, newPath); | ||
return openUniqueHandler(tryNum, fileParts, options); | ||
} | ||
}); | ||
}; | ||
const openUnique = function(file, options, cb) { | ||
throw err; | ||
} | ||
} | ||
function openUnique(file, options) { | ||
file = path.resolve(file); | ||
@@ -85,70 +82,51 @@ const filePath = path.dirname(file); | ||
options.simple = true; | ||
openUniqueHandler(0, { | ||
return openUniqueHandler(0, { | ||
path: filePath, | ||
tail: fileName | ||
}, options, cb); | ||
} else { | ||
options.simple = false; | ||
options.flags = 'wx'; | ||
openUniqueHandler(0, { | ||
path: filePath, | ||
head: fileParts[1] || '', | ||
padLeft: fileParts[2], | ||
pad: fileParts[3].length, | ||
padRight: fileParts[4], | ||
tail: fileParts[5] || '' | ||
}, options, cb); | ||
}, options); | ||
} | ||
}; | ||
const writeFileUnique = function(filename, data, options, cb) { | ||
if (cb === undefined) { | ||
cb = options; | ||
options = { | ||
encoding: 'utf8', | ||
mode: defaultFileMode, | ||
flags: 'w' | ||
}; | ||
} | ||
options.simple = false; | ||
options.flags = 'wx'; | ||
return openUniqueHandler(0, { | ||
path: filePath, | ||
head: fileParts[1] || '', | ||
padLeft: fileParts[2], | ||
pad: fileParts[3].length, | ||
padRight: fileParts[4], | ||
tail: fileParts[5] || '' | ||
}, options); | ||
} | ||
openUnique(filename, options, (err, fd, newPath) => { | ||
if (err) { | ||
cb(err); | ||
} else { | ||
const buffer = Buffer.isBuffer(data) ? data : Buffer.from(String(data), options.encoding || 'utf8'); | ||
writeAll(fd, buffer, 0, buffer.length, 0, err => cb(err, newPath)); | ||
} | ||
}); | ||
}; | ||
async function writeFileUnique(filename, data, options = { encoding: 'utf8', mode: defaultFileMode, flags: 'w' }) { | ||
const { fd, path } = await openUnique(filename, options); | ||
const buffer = Buffer.isBuffer(data) ? data : Buffer.from(String(data), options.encoding || 'utf8'); | ||
await writeAllAsync(fd, buffer, 0, buffer.length, 0); | ||
return path; | ||
} | ||
// stream | ||
const WriteStreamUnique = function(file, options) { | ||
if (options && options.force) { | ||
this.force = options.force; | ||
delete options.force; | ||
} | ||
function WriteStreamUnique(file, options = {}) { | ||
this.force = options.force; | ||
WriteStream.call(this, file, options); | ||
}; | ||
} | ||
inherits(WriteStreamUnique, WriteStream); | ||
WriteStreamUnique.prototype.open = function() { | ||
openUnique(this.path, { | ||
flags: this.flags, | ||
mode: this.mode, | ||
force: this.force | ||
}, (err, fd, newPath) => { | ||
if (err) { | ||
this.destroy(); | ||
this.emit('error', err); | ||
return; | ||
} | ||
this.path = newPath; | ||
WriteStreamUnique.prototype.open = async function() { | ||
try { | ||
const { fd, path } = await openUnique(this.path, { | ||
flags: this.flags, | ||
mode: this.mode, | ||
force: this.force | ||
}); | ||
this.path = path; | ||
this.fd = fd; | ||
this.emit('open', fd); | ||
}); | ||
}; | ||
this.emit('open', this.fd); | ||
} catch (e) { | ||
this.destroy(); | ||
this.emit('error', e); | ||
} | ||
} | ||
const createWriteStreamUnique = function(file, options) { | ||
return new WriteStreamUnique(file, options); | ||
}; | ||
const createWriteStreamUnique = (file, options) => new WriteStreamUnique(file, options); | ||
@@ -155,0 +133,0 @@ module.exports = { |
@@ -26,7 +26,7 @@ { | ||
}, | ||
"version": "1.1.1", | ||
"version": "2.0.0", | ||
"devDependencies": { | ||
"ava": "^0.25.0", | ||
"del": "^3.0.0", | ||
"nyc": "^11.7.1" | ||
"ava": "^2.0.0", | ||
"del": "^5.0.0", | ||
"nyc": "^14.0.0" | ||
}, | ||
@@ -33,0 +33,0 @@ "scripts": { |
@@ -13,3 +13,3 @@ # fsu (fs unique) | ||
## openUnique(path, [mode], callback) | ||
## async openUnique(path, [mode]) | ||
Same as [fs.open](http://nodejs.org/api/fs.html#fs_fs_open_path_flags_mode_callback) but open for writing and creates unique filename. | ||
@@ -20,8 +20,7 @@ | ||
fsu.openUnique("text{_###}.txt", (err, fd, path) => { | ||
//now we can use file descriptor as usual | ||
}); | ||
const { fd, path } = await fsu.openUnique("text{_###}.txt", [options]); | ||
``` | ||
## writeFileUnique(path, data, [options], callback) | ||
## async writeFileUnique(path, data, [options]) | ||
Same as [fs.writeFile](http://nodejs.org/api/fs.html#fs_fs_writefile_filename_data_options_callback) but creates unique filename. | ||
@@ -32,5 +31,4 @@ | ||
fsu.writeFileUnique("text{_###}.txt", "test", (err, path) => { | ||
console.log("Done", path); | ||
}); | ||
const path = await fsu.writeFileUnique("text{_###}.txt", "test"); | ||
``` | ||
@@ -37,0 +35,0 @@ |
37
test.js
@@ -11,15 +11,14 @@ 'use strict'; | ||
test.serial.cb('write unique file with callbacks', t => { | ||
fsu.writeFileUnique(path.join('test', 'test{_file###}.txt'), 'test', { force: true }, (err, path) => { | ||
if (err) { | ||
t.fail(err); | ||
} else { | ||
t.true(path.endsWith('test.txt')); | ||
} | ||
t.end(); | ||
}); | ||
test.serial('write unique file', async t => { | ||
const filePath = await fsu.writeFileUnique(path.join('test', 'test{_file###}.txt'), 'test', { force: true }); | ||
t.true(filePath.endsWith('test.txt')); | ||
}); | ||
test.serial.cb('write unique file and stream with callbacks', t => { | ||
const stream = fsu.createWriteStreamUnique(path.join('test', 'test{_stream###}.txt')); | ||
test.serial('write file with a file name without pattern', async t => { | ||
const filePath = await fsu.writeFileUnique(path.join('test', 'test1.txt'), 'test', { force: true }); | ||
t.true(filePath.endsWith('test1.txt')); | ||
}); | ||
test.serial.cb('writes unique file with fs stream', t => { | ||
const stream = fsu.createWriteStreamUnique(path.join('test', 'test{_stream###}.txt'), { force: true }); | ||
fs.createReadStream('readme.md').pipe(stream).on('finish', () => { | ||
@@ -31,1 +30,17 @@ t.true(stream.path.endsWith('test_stream001.txt')); | ||
test.serial.cb('fails to write unique file with a stream to non existed directory', t => { | ||
const stream = fsu.createWriteStreamUnique(path.join('nonexisted', 'test{_stream###}.txt')); | ||
fs.createReadStream('readme.md').pipe(stream) | ||
.on('finish', () => t.fail()) | ||
.on('error', () => t.end()) | ||
}); | ||
test.serial.cb('writes big unique file with fs stream', t => { | ||
const stream = fsu.createWriteStreamUnique(path.join('test', 'test{_stream###}.txt'), { force: true }); | ||
fs.createReadStream('package-lock.json') | ||
.pipe(stream) | ||
.on('finish', () => { | ||
t.true(stream.path.endsWith('test_stream002.txt')); | ||
t.end(); | ||
}); | ||
}); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
9286
153
59