diff --git a/lib/dest/prepare.js b/lib/dest/prepare.js index 11c8f4a0..b3ea3d47 100644 --- a/lib/dest/prepare.js +++ b/lib/dest/prepare.js @@ -16,6 +16,11 @@ function prepareWrite(folderResolver, optResolver) { return cb(new Error('Received a non-Vinyl object in `dest()`')); } + // TODO: Remove this after people upgrade vinyl/transition from gulp-util + if (typeof file.isSymbolic !== 'function') { + file = new Vinyl(file); + } + var outFolderPath = folderResolver.resolve('outFolder', file); if (!outFolderPath) { return cb(new Error('Invalid output folder')); diff --git a/lib/symlink/prepare.js b/lib/symlink/prepare.js index ffc5b7d1..dd2ec1ad 100644 --- a/lib/symlink/prepare.js +++ b/lib/symlink/prepare.js @@ -16,6 +16,11 @@ function prepareSymlink(folderResolver, optResolver) { return cb(new Error('Received a non-Vinyl object in `symlink()`')); } + // TODO: Remove this after people upgrade vinyl/transition from gulp-util + if (typeof file.isSymbolic !== 'function') { + file = new Vinyl(file); + } + var cwd = path.resolve(optResolver.resolve('cwd', file)); var outFolderPath = folderResolver.resolve('outFolder', file); diff --git a/test/dest.js b/test/dest.js index 85f438e3..af8dcf5c 100644 --- a/test/dest.js +++ b/test/dest.js @@ -16,6 +16,7 @@ var applyUmask = require('./utils/apply-umask'); var testStreams = require('./utils/test-streams'); var always = require('./utils/always'); var testConstants = require('./utils/test-constants'); +var breakPrototype = require('./utils/break-prototype'); var from = miss.from; var pipe = miss.pipe; @@ -1018,4 +1019,48 @@ describe('.dest()', function() { concat(assert), ], done); }); + + it('does not marshall a Vinyl object with isSymbolic method', function(done) { + var file = new File({ + base: outputBase, + path: outputPath, + }); + + function assert(files) { + expect(files.length).toEqual(1); + // Avoid comparing stats because they get reflected + delete files[0].stat; + expect(files[0]).toMatch(file); + expect(files[0]).toBe(file); + } + + pipe([ + from.obj([file]), + vfs.dest(outputBase), + concat(assert), + ], done); + }); + + it('marshalls a Vinyl object without isSymbolic to a newer Vinyl', function(done) { + var file = new File({ + base: outputBase, + path: outputPath, + }); + + breakPrototype(file); + + function assert(files) { + expect(files.length).toEqual(1); + // Avoid comparing stats because they get reflected + delete files[0].stat; + expect(files[0]).toMatch(file); + expect(files[0]).toNotBe(file); + } + + pipe([ + from.obj([file]), + vfs.dest(outputBase), + concat(assert), + ], done); + }); }); diff --git a/test/symlink.js b/test/symlink.js index dc728610..606d92de 100644 --- a/test/symlink.js +++ b/test/symlink.js @@ -14,6 +14,7 @@ var isWindows = require('./utils/is-windows'); var testStreams = require('./utils/test-streams'); var always = require('./utils/always'); var testConstants = require('./utils/test-constants'); +var breakPrototype = require('./utils/break-prototype'); var from = miss.from; var pipe = miss.pipe; @@ -940,4 +941,50 @@ describe('symlink stream', function() { concat(assert), ], done); }); + + it('does not marshall a Vinyl object with isSymbolic method', function(done) { + var file = new File({ + base: outputBase, + path: outputPath, + }); + + function assert(files) { + expect(files.length).toEqual(1); + // Avoid comparing stats because they get reflected + delete files[0].stat; + expect(files[0]).toMatch(file); + expect(files[0]).toBe(file); + } + + pipe([ + from.obj([file]), + vfs.symlink(outputBase), + concat(assert), + ], done); + }); + + it('marshalls a Vinyl object without isSymbolic to a newer Vinyl', function(done) { + var file = new File({ + base: outputBase, + path: outputPath, + // Pre-set this because it is set by symlink + symlink: outputPath, + }); + + breakPrototype(file); + + function assert(files) { + expect(files.length).toEqual(1); + // Avoid comparing stats because they get reflected + delete files[0].stat; + expect(files[0]).toMatch(file); + expect(files[0]).toNotBe(file); + } + + pipe([ + from.obj([file]), + vfs.symlink(outputBase), + concat(assert), + ], done); + }); }); diff --git a/test/utils/break-prototype.js b/test/utils/break-prototype.js new file mode 100644 index 00000000..9ced60e9 --- /dev/null +++ b/test/utils/break-prototype.js @@ -0,0 +1,23 @@ +'use strict'; + +var File = require('vinyl'); + +function breakPrototype(file) { + // Set up a broken prototype + var oldProto = {}; + Object.getOwnPropertyNames(File.prototype).forEach(function(key) { + if (key !== 'isSymbolic') { + var desc = Object.getOwnPropertyDescriptor(File.prototype, key); + Object.defineProperty(oldProto, key, desc); + } + }); + + // Assign the broken prototype to our instance + if (typeof Object.setPrototypeOf === 'function') { + Object.setPrototypeOf(file, oldProto); + } else { + file.__proto__ = oldProto; + } +} + +module.exports = breakPrototype;