From 90a23cb5b915279b9bbd1003f53cfc5b8954779e Mon Sep 17 00:00:00 2001 From: Richie Bendall Date: Thu, 30 Jul 2020 03:31:28 +1200 Subject: [PATCH 1/2] Refactor Signed-off-by: Richie Bendall --- .gitignore | 3 + .jscsrc | 5 -- .jshintrc | 15 ----- .npmrc | 1 + .travis.yml | 8 +-- index.d.ts | 31 +++++++++++ index.js | 151 +++++++-------------------------------------------- package.json | 27 +++++---- readme.md | 42 +++++--------- test.js | 108 ++++++++---------------------------- 10 files changed, 112 insertions(+), 279 deletions(-) delete mode 100644 .jscsrc delete mode 100644 .jshintrc create mode 100644 .npmrc create mode 100644 index.d.ts diff --git a/.gitignore b/.gitignore index cccf84c..fb44afa 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +.nyc_output +yarn.lock +package-lock.json /node_modules/ npm-debug.log .idea diff --git a/.jscsrc b/.jscsrc deleted file mode 100644 index 703fb35..0000000 --- a/.jscsrc +++ /dev/null @@ -1,5 +0,0 @@ -{ - "preset": "google", - "maximumLineLength": null, - "excludeFiles": ["node_modules/**"] -} diff --git a/.jshintrc b/.jshintrc deleted file mode 100644 index 2cb788b..0000000 --- a/.jshintrc +++ /dev/null @@ -1,15 +0,0 @@ -{ - "boss": true, - "curly": true, - "eqeqeq": true, - "eqnull": true, - "immed": true, - "latedef": true, - "mocha" : true, - "newcap": true, - "noarg": true, - "node": true, - "sub": true, - "undef": true, - "unused": true -} diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..43c97e7 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +package-lock=false diff --git a/.travis.yml b/.travis.yml index bd5ce43..363674d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ sudo: false language: node_js node_js: - - 'iojs' - - '0.12' - - '0.10' -after_script: NODE_ENV=test istanbul cover ./node_modules/mocha/bin/_mocha -- -R spec && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage + - "14" + - "12" + +after_success: npm run coverage diff --git a/index.d.ts b/index.d.ts new file mode 100644 index 0000000..26440c2 --- /dev/null +++ b/index.d.ts @@ -0,0 +1,31 @@ +declare const prependFile: { + /** + Synchronously prepend data to a file, creating it if it doesn't exist. + @param filename The file to prepend the `data` to. + @param data The data to prepend. + @example + ``` + const prependFile = require('prepend-file'); + + prependFile.sync('message.txt', 'some data'); + ``` + */ + sync: (filename: string, data: string | Buffer) => void; + + /** + Prepend data to a file, creating it if it doesn't exist. + @param filename The file to prepend the `data` to. + @param data The data to prepend. + @example + ``` + const prependFile = require('prepend-file'); + + (async () => { + await prependFile('message.txt', 'some data'); + }); + ``` + */ + (filename: string, data: string | Buffer): Promise; +}; + +export = prependFile; diff --git a/index.js b/index.js index c67451d..01dc961 100644 --- a/index.js +++ b/index.js @@ -1,136 +1,27 @@ 'use strict'; -var fs = require('fs'); -var util = require('util'); -var tmp = require('tmp'); - -var DEBUG = process.env.NODE_DEBUG && /fs/.test(process.env.NODE_DEBUG); - -function rethrow() { - // Only enable in debug mode. A backtrace uses ~1000 bytes of heap space and is fairly slow to generate. - if (DEBUG) { - var backtrace = new Error(); - return function(err) { - if (err) { - backtrace.stack = err.name + ': ' + err.message + - backtrace.stack.substr(backtrace.name.length); - err = backtrace; - throw err; - } - }; - } - - return function(err) { - if (err) { - throw err; // Forgot a callback but don't know where? Use NODE_DEBUG=fs - } - }; -} - -function maybeCallback(callback) { - return typeof callback === 'function' ? callback : rethrow(); -} - -module.exports = function prependFile(path, data, options) { - var callback = maybeCallback(arguments[arguments.length - 1]); - - if (typeof options === 'function' || !options) { - options = { - encoding: 'utf8', - mode: 438 /*=0666*/ - }; - } else if (util.isString(options)) { - options = { - encoding: options, - mode: 438 - }; - } else if (!util.isObject(options)) { - throw new TypeError('Bad arguments'); +const fs = require('fs'); +const {promisify} = require('util'); +const tempWrite = require('temp-write'); +const pathExists = require('path-exists'); +const pipeline = promisify(require('stream').pipeline); + +module.exports = async (filename, data) => { + if (await pathExists(filename)) { + const temporaryFile = await tempWrite(data); + + await pipeline(fs.createReadStream(filename), fs.createWriteStream(temporaryFile, {flags: 'a'})); + await pipeline(fs.createReadStream(temporaryFile), fs.createWriteStream(filename)); + + await fs.promises.unlink(temporaryFile); + } else { + await fs.promises.writeFile(filename, data); } - - var appendOptions = { - encoding: options.encoding, - mode: options.mode, - flags: 'a' - }; - - // a temp file is written even if dist file does not exist. PR welcome for better implementation. - tmp - .file(function (err, tempFilePath, fd, cleanupCallback) { - if (err) { - callback(err); - return; - } - - fs.writeFile(tempFilePath, data, options, function (err) { - if (err) { - callback(err); - return; - } - - fs.createReadStream(path, options) - .on('error', function(err) { - if (err.code === 'ENOENT' /*file does not exist*/) { - fs.writeFile(path, data, options, function (err) { - if (err) { - callback(err); - } else { - callback(); - } - }); - } else { - callback(err); - } - }) - .pipe(fs.createWriteStream(tempFilePath, appendOptions)) - .on('error', function(err) { - callback(err); - }) - .on('finish', function() { - fs.createReadStream(tempFilePath, options) - .on('error', function(err) { - callback(err); - }) - .pipe(fs.createWriteStream(path, options)) - .on('error', function(err) { - callback(err); - }) - .on('finish', function() { - cleanupCallback(); - callback(); - }); - }); - }); - }); }; -module.exports.sync = function sync(path, data, options) { - if (!options) { - options = { - encoding: 'utf8', - mode: 438 /*=0666*/ - }; - } else if (util.isString(options)) { - options = { - encoding: options, - mode: 438 - }; - } else if (!util.isObject(options)) { - throw new TypeError('Bad arguments'); - } - - var currentFileData; - - var appendOptions = { - encoding: options.encoding, - mode: options.mode, - flags: 'w' - }; - - try { - currentFileData = fs.readFileSync(path, options); - } catch (err) { - currentFileData = ''; +module.exports.sync = (filename, data) => { + if (pathExists.sync(filename)) { + fs.writeFileSync(filename, Buffer.concat([Buffer.from(data), fs.readFileSync(filename)])); + } else { + fs.writeFileSync(filename, data); } - - fs.writeFileSync(path, data + currentFileData, appendOptions); }; diff --git a/package.json b/package.json index e29898b..9169fe9 100644 --- a/package.json +++ b/package.json @@ -10,29 +10,32 @@ "url": "http://h3manth.com" }, "engines": { - "node": ">=0.10.0" + "node": ">=10.17 <11 || >=11.14" }, "scripts": { - "coverage": "istanbul cover _mocha -- -R spec && rm -rf ./coverage", - "lint": "jshint *.js --exclude node_modules && jscs *.js", - "test": "mocha" + "coverage": "nyc report --reporter=text-lcov | coveralls", + "test": "xo && nyc ava" }, "files": [ - "index.js" + "index.js", + "index.d.ts" ], "keywords": [ "fs", "file", "prepend" ], + "dependencies": { + "path-exists": "^4.0.0", + "temp-write": "^4.0.0" + }, "devDependencies": { - "coveralls": "^2.11.2", - "istanbul": "^0.3.13", - "jscs": "^1.13.1", - "jshint": "^2.6.3", - "mocha": "*" + "ava": "^3.11.0", + "coveralls": "^3.1.0", + "nyc": "^15.1.0", + "xo": "^0.32.1" }, - "dependencies": { - "tmp": "0.0.31" + "xo": { + "space": 2 } } diff --git a/readme.md b/readme.md index f4d25f3..9a9c2fc 100644 --- a/readme.md +++ b/readme.md @@ -1,56 +1,40 @@ # [![NPM version][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Dependency Status][daviddm-image]][daviddm-url] -> Prepend data to a file, creating the file if it not yet exists. - +> Prepend data to a file, creating it if it doesn't exist. ## Install ```sh -$ npm install --save prepend-file +npm install prepend-file ``` ## Usage ```js -var prependFile = require('prepend-file'); - -prependFile('message.txt', 'data to prepend', function (err) { - if (err) { - // Error - } +const prependFile = require('prepend-file'); - // Success - console.log('The "data to prepend" was prepended to file!'); +(async () => { + await prependFile('message.txt', 'some data'); }); ``` ## API -### prependFile(filename, data, [options], callback) - -``` - * filename String - * data String | Buffer - * options Object - encoding String | Null default = 'utf8' - mode Number default = 438 (aka 0666 in Octal) - * callback Function -``` - -Asynchronously prepend data to a file, creating the file if it not yet exists. The `data` can be a string or a buffer. +### prependFile(filename, data) -### prependFile.sync(filename, data, [options]) +### prependFile.sync(filename, data) -The synchronous version of `prependFile`. Returns `undefined`. +#### filename -## Related +Type: `string` -* [prepend-file-cli](https://github.com/martinvd/prepend-file-cli) +The file to prepend the `data` to. -## License +#### data -MIT © [Hemanth.HM](http://h3manth.com) +Type: `string | Buffer` +The data to prepend. [npm-image]: https://badge.fury.io/js/prepend-file.svg [npm-url]: https://npmjs.org/package/prepend-file diff --git a/test.js b/test.js index 32926b1..2dda954 100644 --- a/test.js +++ b/test.js @@ -1,95 +1,35 @@ -var assert = require('assert'); -var fs = require('fs'); -var prependFile = require('./'); +const prependFile = require('.'); +const fs = require('fs'); +const test = require('ava'); -describe('prependFile', function() { - var tmp = '.temp1'; +const {promises: fsP} = fs; - after(function(cb) { - fs.unlink(tmp, cb); - }); +const temporaryFile = '.temp1'; +const syncTemporaryFile = '.temp2'; - it('should create an empty file and have content added', function(cb) { - prependFile(tmp, 'Hello', function(err) { - if (err) { - cb(err); - } - var fileData = fs.readFileSync(tmp).toString(); - assert.strictEqual(fileData, 'Hello'); - cb(); - }); - }); - - it('should prepend data to a non empty file', function(cb) { - prependFile(tmp, 'What', function(err) { - if (err) { - cb(err); - } - var fileData = fs.readFileSync(tmp).toString(); - assert.strictEqual(fileData, 'WhatHello'); - cb(); - }); - }); - - it('should accepts buffers', function(cb) { - var buf = new Buffer('abc', 'utf8'); - prependFile(tmp, buf, function(err) { - if (err) { - cb(err); - } - var fileData = fs.readFileSync(tmp).toString(); - assert.strictEqual(fileData, 'abcWhatHello'); - cb(); - }); - }); - - it('should accepts numbers', function(cb) { - var number = 220; - prependFile(tmp, number, function(err) { - if (err) { - cb(err); - } - var st = fs.statSync(tmp); - assert.strictEqual(st.mode & 0700, 0600); - var fileData = fs.readFileSync(tmp).toString(); - assert.strictEqual(fileData, '220abcWhatHello'); - cb(); - }); - }); +test.after.always(async () => { + await fsP.unlink(temporaryFile); + await fsP.unlink(syncTemporaryFile); }); -describe('prependFile.sync', function() { - var tmp = '.temp2'; +test('main', async t => { + await prependFile(temporaryFile, 'World'); + t.is(await fsP.readFile(temporaryFile, 'utf8'), 'World'); - after(function(cb) { - fs.unlink(tmp, cb); - }); + await prependFile(temporaryFile, 'Hello '); + t.is(await fsP.readFile(temporaryFile, 'utf8'), 'Hello World'); - it('should create an empty file and have content added', function() { - prependFile.sync(tmp, 'Hello'); - var content = fs.readFileSync(tmp).toString(); - assert.strictEqual(content, 'Hello'); - }); + await prependFile(temporaryFile, Buffer.from('Yes ')); + t.is(await fsP.readFile(temporaryFile, 'utf8'), 'Yes Hello World'); +}); - it('should prepend data to a non empty file', function() { - prependFile.sync(tmp, 'What'); - var content = fs.readFileSync(tmp).toString(); - assert.strictEqual(content, 'WhatHello'); - }); +test('.sync', t => { + prependFile.sync(syncTemporaryFile, 'World'); + t.is(fs.readFileSync(syncTemporaryFile, 'utf8'), 'World'); - it('should accepts buffers', function() { - var buf = new Buffer('abc', 'utf8'); - prependFile.sync(tmp, buf); - var fileData = fs.readFileSync(tmp).toString(); - assert.strictEqual(fileData, 'abcWhatHello'); - }); + prependFile.sync(syncTemporaryFile, 'Hello '); + t.is(fs.readFileSync(syncTemporaryFile, 'utf8'), 'Hello World'); - it('should accepts numbers', function() { - var number = 220; - prependFile.sync(tmp, number); - var st = fs.statSync(tmp); - assert.strictEqual(st.mode & 0700, 0600); - var fileData = fs.readFileSync(tmp).toString(); - assert.strictEqual(fileData, '220abcWhatHello'); - }); + prependFile.sync(syncTemporaryFile, Buffer.from('Yes ')); + t.is(fs.readFileSync(syncTemporaryFile, 'utf8'), 'Yes Hello World'); }); From e660df7db0c6e70a11ad439d892fecf34d9fee8e Mon Sep 17 00:00:00 2001 From: Richie Bendall Date: Thu, 30 Jul 2020 03:36:31 +1200 Subject: [PATCH 2/2] Update title Signed-off-by: Richie Bendall --- readme.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/readme.md b/readme.md index 9a9c2fc..77c44e6 100644 --- a/readme.md +++ b/readme.md @@ -1,4 +1,4 @@ -# [![NPM version][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Dependency Status][daviddm-image]][daviddm-url] +# prepend-file [![Build Status][travis-image]][travis-url] [![Code Coverage][coveralls-image]][coveralls-url] > Prepend data to a file, creating it if it doesn't exist. @@ -36,11 +36,7 @@ Type: `string | Buffer` The data to prepend. -[npm-image]: https://badge.fury.io/js/prepend-file.svg -[npm-url]: https://npmjs.org/package/prepend-file [travis-image]: https://travis-ci.org/hemanth/node-prepend-file.svg?branch=master [travis-url]: https://travis-ci.org/hemanth/node-prepend-file -[daviddm-image]: https://david-dm.org/hemanth/node-prepend-file.svg?theme=shields.io -[daviddm-url]: https://david-dm.org/hemanth/node-prepend-file [coveralls-image]: https://coveralls.io/repos/hemanth/node-prepend-file/badge.svg [coveralls-url]: https://coveralls.io/r/hemanth/node-prepend-file