Repository: gulpjs/vinyl-fs (js)

Issue:
Overwriting on a per-file basis?
I have been working on a peculiar case: a client has developers working on different editors, and no-one bothered setting their editors / IDEs for tabs and spaces. That client also doesn't really care about style guides and as a result they introduced jsbeautify in their building process: source files are overwritten with their prettified contents. This is of course not editor friendly (causes files to be reloaded, or editors to prompt for reloads) but this is how that client does it.

The build process has been recently converted to Gulp (using Gulp 4), and to try to make the process more editor-friendly, I introduced a piece of pipeline which prettifies file contents, compare the prettified version with its original and only copy if different.

The issue I have is that I bypass gulp.dest() and use fs.writeFile() instead inside that piece of pipeline. I would prefer if I had a piece of pipeline which would prettify and set an `overwrite` flag to true if different, and then pass it to gulp.dest().

[https://github.com/wearefractal/vinyl-fs/blob/master/lib/prepareWrite.js#L15](https://github.com/wearefractal/vinyl-fs/blob/master/lib/prepareWrite.js#L15) could become:

    var overwrite = (file.overwrite !== undefined ? file.overwrite : options.overwrite);
    options.flag = (overwrite ? 'w' : 'wx');

Should I go ahead with a pull request?

Pull request description:
allow a function to be used as value for the overwrite option - closes #68
@contra PRed for review

Patch:
diff --git a/README.md b/README.md
index dd1412a..79f15d6 100644
--- a/README.md
+++ b/README.md
@@ -89,6 +89,7 @@ _Note:_ UTF-8 BOM will be stripped from all UTF-8 files read with `.src`.
 
   - overwrite - Specify if existing files with the same path should be overwritten or not.
     - Default is `true`, to always overwrite existing files.
+    - Can also be a function that takes in a file and returns `true` or `false`.
 
   - sourcemaps -
     - Default is `null` aka do not write sourcemaps.
diff --git a/lib/prepareWrite.js b/lib/prepareWrite.js
index 9779c70..621d9b5 100644
--- a/lib/prepareWrite.js
+++ b/lib/prepareWrite.js
@@ -5,6 +5,14 @@ var path = require('path');
 var mkdirp = require('mkdirp');
 var fs = require('graceful-fs');
 
+function booleanOrFunc(v, file) {
+  if (typeof v !== 'boolean' && typeof v !== 'function') {
+    return null;
+  }
+
+  return typeof v === 'boolean' ? v : v(file);
+}
+
 function stringOrFunc(v, file) {
   if (typeof v !== 'string' && typeof v !== 'function') {
     return null;
@@ -20,7 +28,8 @@ function prepareWrite(outFolder, file, opt, cb) {
     dirMode: null,
     overwrite: true
   }, opt);
-  options.flag = (options.overwrite ? 'w' : 'wx');
+  var overwrite = booleanOrFunc(options.overwrite, file);
+  options.flag = (overwrite ? 'w' : 'wx');
 
   var cwd = path.resolve(options.cwd);
   var outFolderPath = stringOrFunc(outFolder, file);


Test patch:
diff --git a/test/dest.js b/test/dest.js
index 7b41146..edd4e3d 100644
--- a/test/dest.js
+++ b/test/dest.js
@@ -903,6 +903,76 @@ describe('dest stream', function() {
     stream.end();
   });
 
+  it('should not overwrite files with overwrite option set to a function that returns false', function(done) {
+    var inputPath = path.join(__dirname, './fixtures/test.coffee');
+    var inputBase = path.join(__dirname, './fixtures/');
+    var inputContents = fs.readFileSync(inputPath);
+
+    var expectedPath = path.join(__dirname, './out-fixtures/test.coffee');
+    var expectedBase = path.join(__dirname, './out-fixtures');
+    var existingContents = 'Lorem Ipsum';
+
+    var inputFile = new File({
+      base: inputBase,
+      cwd: __dirname,
+      path: inputPath,
+      contents: inputContents
+    });
+
+    var onEnd = function(){
+      buffered.length.should.equal(1);
+      bufEqual(fs.readFileSync(expectedPath), new Buffer(existingContents)).should.equal(true);
+      done();
+    };
+
+    // Write expected file which should not be overwritten
+    fs.mkdirSync(expectedBase);
+    fs.writeFileSync(expectedPath, existingContents);
+
+    var stream = vfs.dest('./out-fixtures/', {cwd: __dirname, overwrite: function() { return false; }});
+
+    var buffered = [];
+    bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd);
+    stream.pipe(bufferStream);
+    stream.write(inputFile);
+    stream.end();
+  });
+
+  it('should overwrite files with overwrite option set to a function that returns true', function(done) {
+    var inputPath = path.join(__dirname, './fixtures/test.coffee');
+    var inputBase = path.join(__dirname, './fixtures/');
+    var inputContents = fs.readFileSync(inputPath);
+
+    var expectedPath = path.join(__dirname, './out-fixtures/test.coffee');
+    var expectedBase = path.join(__dirname, './out-fixtures');
+    var existingContents = 'Lorem Ipsum';
+
+    var inputFile = new File({
+      base: inputBase,
+      cwd: __dirname,
+      path: inputPath,
+      contents: inputContents
+    });
+
+    var onEnd = function(){
+      buffered.length.should.equal(1);
+      bufEqual(fs.readFileSync(expectedPath), new Buffer(inputContents)).should.equal(true);
+      done();
+    };
+
+    // This should be overwritten
+    fs.mkdirSync(expectedBase);
+    fs.writeFileSync(expectedPath, existingContents);
+
+    var stream = vfs.dest('./out-fixtures/', {cwd: __dirname, overwrite: function() { return true; }});
+
+    var buffered = [];
+    bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd);
+    stream.pipe(bufferStream);
+    stream.write(inputFile);
+    stream.end();
+  });
+
   it('should create symlinks when the `symlink` attribute is set on the file', function (done) {
     var inputPath = path.join(__dirname, './fixtures/test-create-dir-symlink');
     var inputBase = path.join(__dirname, './fixtures/');