{"action":"created","comment":{"url":"https://api.github.com/repos/types/npm-vinyl/pulls/comments/84158198","pull_request_review_id":4953289,"id":84158198,"diff_hunk":"@@ -1,661 +1,1617 @@\n-\n-import File = require('vinyl');\n-import * as Stream from 'stream';\n import * as fs from 'fs';\n+import * as path from 'path';\n+import expect = require('expect');\n \n-new File({\n-  cwd: '/',\n-  base: '/test/',\n-  path: '/test/file.ts',\n-  contents: new Buffer('test = 123')\n-});\n+import miss = require('mississippi');\n+import cloneable = require('cloneable-readable');\n+\n+import Vinyl = require('../index');\n+\n+\n+const pipe = <any> miss.pipe;\n+const from = <any> miss.from;\n+const concat = <any> miss.concat;\n+const isCloneable = <(obj: any) => boolean> (<any> cloneable).isCloneable;\n+\n+const isWin = process.platform === 'win32';\n+\n+describe('File', function() {\n+\n+  describe('isVinyl()', function() {\n+\n+    it('returns true for a Vinyl object', function(done) {\n+      const file = new Vinyl();\n+      const result = Vinyl.isVinyl(file);\n+      expect(result).toEqual(true);\n+      done();\n+    });\n+\n+    it('returns false for a normal object', function(done) {\n+      const result = Vinyl.isVinyl({});\n+      expect(result).toEqual(false);\n+      done();\n+    });\n+\n+    it('returns false for null', function(done) {\n+      const result = Vinyl.isVinyl(null);\n+      expect(result).toEqual(false);\n+      done();\n+    });\n+\n+    it('returns false for a string', function(done) {\n+      const result = Vinyl.isVinyl('foobar');\n+      expect(result).toEqual(false);\n+      done();\n+    });\n+\n+    it('returns false for a String object', function(done) {\n+      const result = Vinyl.isVinyl(new String('foobar'));\n+      expect(result).toEqual(false);\n+      done();\n+    });\n+\n+    it('returns false for a number', function(done) {\n+      const result = Vinyl.isVinyl(1);\n+      expect(result).toEqual(false);\n+      done();\n+    });\n+\n+    it('returns false for a Number object', function(done) {\n+      const result = Vinyl.isVinyl(new Number(1));\n+      expect(result).toEqual(false);\n+      done();\n+    });\n \n-let fakeStream: NodeJS.ReadWriteStream;\n+    // This is based on current implementation\n+    // A test was added to document and make aware during internal changes\n+    // TODO: decide if this should be leak-able\n+    it('returns true for a mocked object', function(done) {\n+      const result = Vinyl.isVinyl({ _isVinyl: true });\n+      expect(result).toEqual(true);\n+      done();\n+    });\n+  });\n \n-describe('File', () => {\n+  describe('defaults', function() {\n \n-  describe('constructor()', () => {\n+    it('defaults cwd to process.cwd', function(done) {\n+      const file = new Vinyl();\n+      expect(file.cwd).toEqual(process.cwd());\n+      done();\n+    });\n \n-    it('should default cwd to process.cwd', done => {\n-      const file = new File();\n-      file.cwd.should.equal(process.cwd());\n+    it('defaults base to process.cwd', function(done) {\n+      const file = new Vinyl();\n+      expect(file.base).toEqual(process.cwd());\n       done();\n     });\n \n-    it('should default base to cwd', done => {\n-      const cwd = '/';\n-      const file = new File({ cwd: cwd });\n-      file.basename.should.equal(cwd);\n+    it('defaults base to cwd property', function(done) {\n+      const cwd = path.normalize('/');\n+      const file = new Vinyl({ cwd: cwd });\n+      expect(file.base).toEqual(cwd);\n       done();\n     });\n \n-    it('should default base to cwd even when none is given', done => {\n-      const file = new File();\n-      file.basename.should.equal(process.cwd());\n+    it('defaults path to null', function(done) {\n+      const file = new Vinyl();\n+      expect(file.path).toNotExist();\n+      expect(file.path).toEqual(null);\n       done();\n     });\n \n-    it('should default path to null', done => {\n-      const file = new File();\n-      should.not.exist(file.path);\n+    it('defaults history to an empty array', function(done) {\n+      const file = new Vinyl();\n+      expect(file.history).toEqual([]);\n       done();\n     });\n \n-    it('should default stat to null', done => {\n-      const file = new File();\n-      should.not.exist(file.stat);\n+    it('defaults stat to null', function(done) {\n+      const file = new Vinyl();\n+      expect(file.stat).toNotExist();\n+      expect(file.stat).toEqual(null);\n       done();\n     });\n \n-    it('should default contents to null', done => {\n-      const file = new File();\n-      should.not.exist(file.contents);\n+    it('defaults contents to null', function(done) {\n+      const file = new Vinyl();\n+      expect(file.contents).toNotExist();\n+      expect(file.contents).toEqual(null);\n       done();\n     });\n+  });\n \n-    it('should set base to given value', done => {\n-      const val = '/';\n-      const file = new File({ base: val });\n-      file.basename.should.equal(val);\n+  describe('constructor()', function() {\n+\n+    it('sets base', function(done) {\n+      const val = path.normalize('/');\n+      const file = new Vinyl({ base: val });\n+      expect(file.base).toEqual(val);\n       done();\n     });\n \n-    it('should set cwd to given value', done => {\n-      const val = '/';\n-      const file = new File({ cwd: val });\n-      file.cwd.should.equal(val);\n+    it('sets cwd', function(done) {\n+      const val = path.normalize('/');\n+      const file = new Vinyl({ cwd: val });\n+      expect(file.cwd).toEqual(val);\n       done();\n     });\n \n-    it('should set path to given value', done => {\n-      const val = '/test.coffee';\n-      const file = new File({ path: val });\n-      file.path.should.equal(val);\n+    it('sets path (and history)', function(done) {\n+      const val = path.normalize('/test.coffee');\n+      const file = new Vinyl({ path: val });\n+      expect(file.path).toEqual(val);\n+      expect(file.history).toEqual([val]);\n       done();\n     });\n \n-    it('should set stat to given value', done => {\n-      const val = {};\n-      const file = new File(<fs.Stats><any>{ stat: val });\n-      file.stat.should.equal(val);\n+    it('sets history (and path)', function(done) {\n+      const val = path.normalize('/test.coffee');\n+      const file = new Vinyl({ history: [val] });\n+      expect(file.path).toEqual(val);\n+      expect(file.history).toEqual([val]);\n       done();\n     });\n \n-    it('should set contents to given value', done => {\n+    it('sets stat', function(done) {\n+      const val: any = {};\n+      const file = new Vinyl({ stat: val });\n+      expect(file.stat).toEqual(val);\n+      done();\n+    });\n+\n+    it('sets contents', function(done) {\n       const val = new Buffer('test');\n-      const file = new File({ contents: val });\n-      file.contents.should.equal(val);\n+      const file = new Vinyl({ contents: val });\n+      expect(file.contents).toEqual(val);\n       done();\n     });\n \n-    it('should default basename to cwd', done => {\n-      const cwd = '/';\n-      const file = new File({ cwd: cwd });\n-      file.basename.should.equal(cwd);\n+    it('sets custom properties', function(done) {\n+      const sourceMap = {};\n+      const file = <Vinyl & {sourceMap: {}}> new Vinyl(<any> { sourceMap: sourceMap });\n+      expect(file.sourceMap).toEqual(sourceMap);\n       done();\n     });\n \n-    it('should default basename to cwd even when none is given', done => {\n-      const file = new File();\n-      file.basename.should.equal(process.cwd());\n+    it('normalizes path', function(done) {\n+      const val = '/test/foo/../test.coffee';\n+      const expected = path.normalize(val);\n+      const file = new Vinyl({ path: val });\n+      expect(file.path).toEqual(expected);\n+      expect(file.history).toEqual([expected]);\n       done();\n     });\n \n-    it('should set basename to given value', done => {\n-      const val = '/';\n-      const file = new File({ base: val });\n-      file.basename.should.equal(val);\n+    it('normalizes and removes trailing separator from path', function(done) {\n+      const val = '/test/foo/../foo/';\n+      const expected = path.normalize(val.slice(0, -1));\n+      const file = new Vinyl({ path: val });\n+      expect(file.path).toEqual(expected);\n       done();\n     });\n \n-    it('should default extname to null', done => {\n-      const cwd = '/';\n-      const file = new File({ cwd: cwd });\n-      should.not.exist(file.path);\n+    it('normalizes history', function(done) {\n+      const val = [\n+        '/test/bar/../bar/test.coffee',\n+        '/test/foo/../test.coffee',\n+      ];\n+      const expected = val.map((p) => {\n+        return path.normalize(p);\n+      });\n+      const file = new Vinyl({ history: val });\n+      expect(file.path).toEqual(expected[1]);\n+      expect(file.history).toEqual(expected);\n       done();\n     });\n \n-    it('should default dirname to null', done => {\n-      const cwd = '/';\n-      const file = new File({ cwd: cwd });\n-      should.not.exist(file.dirname);\n+    it('normalizes and removes trailing separator from history', function(done) {\n+      const val = [\n+        '/test/foo/../foo/',\n+        '/test/bar/../bar/',\n+      ];\n+      const expected = val.map((p) => {\n+        return path.normalize(p.slice(0, -1));\n+      });\n+      const file = new Vinyl({ history: val });\n+      expect(file.history).toEqual(expected);\n       done();\n     });\n \n+    it('appends path to history if both exist and different from last', function(done) {\n+      const val = path.normalize('/test/baz/test.coffee');\n+      const history = [\n+        path.normalize('/test/bar/test.coffee'),\n+        path.normalize('/test/foo/test.coffee'),\n+      ];\n+      const file = new Vinyl({ path: val, history: history });\n+\n+      const expectedHistory = history.concat(val);\n+\n+      expect(file.path).toEqual(val);\n+      expect(file.history).toEqual(expectedHistory);\n+      done();\n+    });\n+\n+    it('does not append path to history if both exist and same as last', function(done) {\n+      const val = path.normalize('/test/baz/test.coffee');\n+      const history = [\n+        path.normalize('/test/bar/test.coffee'),\n+        path.normalize('/test/foo/test.coffee'),\n+        val,\n+      ];\n+      const file = new Vinyl({ path: val, history: history });\n+\n+      expect(file.path).toEqual(val);\n+      expect(file.history).toEqual(history);\n+      done();\n+    });\n+\n+    it('does not mutate history array passed in', function(done) {\n+      const val = path.normalize('/test/baz/test.coffee');\n+      const history = [\n+        path.normalize('/test/bar/test.coffee'),\n+        path.normalize('/test/foo/test.coffee'),\n+      ];\n+      const historyCopy = Array.prototype.slice.call(history);\n+      const file = new Vinyl({ path: val, history: history });\n+\n+      const expectedHistory = history.concat(val);\n+\n+      expect(file.path).toEqual(val);\n+      expect(file.history).toEqual(expectedHistory);\n+      expect(history).toEqual(historyCopy);\n+      done();\n+    });\n   });\n \n-  describe('isBuffer()', () => {\n-    it('should return true when the contents are a Buffer', done => {\n+  describe('isBuffer()', function() {\n+\n+    it('returns true when the contents are a Buffer', function(done) {\n       const val = new Buffer('test');\n-      const file = new File({ contents: val });\n-      file.isBuffer().should.equal(true);\n+      const file = new Vinyl({ contents: val });\n+      expect(file.isBuffer()).toEqual(true);\n       done();\n     });\n \n-    it('should return false when the contents are a Stream', done => {\n-      const file = new File({ contents: fakeStream });\n-      file.isBuffer().should.equal(false);\n+    it('returns false when the contents are a Stream', function(done) {\n+      const val = from([]);\n+      const file = new Vinyl({ contents: val });\n+      expect(file.isBuffer()).toEqual(false);\n       done();\n     });\n \n-    it('should return false when the contents are a null', done => {\n-      const file = new File({ contents: null });\n-      file.isBuffer().should.equal(false);\n+    it('returns false when the contents are null', function(done) {\n+      const file = new Vinyl({ contents: null });\n+      expect(file.isBuffer()).toEqual(false);\n       done();\n     });\n   });\n \n-  describe('isStream()', () => {\n-    it('should return false when the contents are a Buffer', done => {\n+  describe('isStream()', function() {\n+\n+    it('returns false when the contents are a Buffer', function(done) {\n       const val = new Buffer('test');\n-      const file = new File({ contents: val });\n-      file.isStream().should.equal(false);\n+      const file = new Vinyl({ contents: val });\n+      expect(file.isStream()).toEqual(false);\n       done();\n     });\n \n-    it('should return true when the contents are a Stream', done => {\n-      const file = new File({ contents: fakeStream });\n-      file.isStream().should.equal(true);\n+    it('returns true when the contents are a Stream', function(done) {\n+      const val = from([]);\n+      const file = new Vinyl({ contents: val });\n+      expect(file.isStream()).toEqual(true);\n       done();\n     });\n \n-    it('should return false when the contents are a null', done => {\n-      const file = new File({ contents: null });\n-      file.isStream().should.equal(false);\n+    it('returns false when the contents are null', function(done) {\n+      const file = new Vinyl({ contents: null });\n+      expect(file.isStream()).toEqual(false);\n       done();\n     });\n   });\n \n-  describe('isNull()', () => {\n-    it('should return false when the contents are a Buffer', done => {\n+  describe('isNull()', function() {\n+\n+    it('returns false when the contents are a Buffer', function(done) {\n       const val = new Buffer('test');\n-      const file = new File({ contents: val });\n-      file.isNull().should.equal(false);\n+      const file = new Vinyl({ contents: val });\n+      expect(file.isNull()).toEqual(false);\n       done();\n     });\n \n-    it('should return false when the contents are a Stream', done => {\n-      const file = new File({ contents: fakeStream });\n-      file.isNull().should.equal(false);\n+    it('returns false when the contents are a Stream', function(done) {\n+      const val = from([]);\n+      const file = new Vinyl({ contents: val });\n+      expect(file.isNull()).toEqual(false);\n       done();\n     });\n \n-    it('should return true when the contents are a null', done => {\n-      const file = new File({ contents: null });\n-      file.isNull().should.equal(true);\n+    it('returns true when the contents are null', function(done) {\n+      const file = new Vinyl({ contents: null });\n+      expect(file.isNull()).toEqual(true);\n       done();\n     });\n   });\n \n-  describe('clone()', () => {\n-    it('should copy all attributes over with Buffer', done => {\n-      const options = {\n-        cwd: '/',\n-        base: '/test/',\n-        path: '/test/test.coffee',\n-        contents: new Buffer('test')\n-      };\n-      const file = new File(options);\n-      const file2 = file.clone();\n+  describe('isDirectory()', function() {\n+    const fakeStat: fs.Stats = <any> {\n+      isDirectory: () => {\n+        return true;\n+      },\n+    };\n \n-      file2.should.not.equal(file, 'refs should be different');\n-      file2.cwd.should.equal(file.cwd);\n-      file2.basename.should.equal(file.basename);\n-      file2.path.should.equal(file.path);\n+    it('returns false when the contents are a Buffer', function(done) {\n+      const val = new Buffer('test');\n+      const file = new Vinyl({ contents: val, stat: fakeStat });\n+      expect(file.isDirectory()).toEqual(false);\n+      done();\n+    });\n \n-      let fileContents = file.contents;\n-      let file2Contents = file2.contents;\n+    it('returns false when the contents are a Stream', function(done) {\n+      const val = from([]);\n+      const file = new Vinyl({ contents: val, stat: fakeStat });\n+      expect(file.isDirectory()).toEqual(false);\n+      done();\n+    });\n \n-      file2Contents.should.not.equal(fileContents, 'buffer ref should be different');\n+    it('returns true when the contents are null & stat.isDirectory is true', function(done) {\n+      const file = new Vinyl({ contents: null, stat: fakeStat });\n+      expect(file.isDirectory()).toEqual(true);\n+      done();\n+    });\n \n-      let fileUtf8Contents = fileContents instanceof Buffer ?\n-        fileContents.toString('utf8') :\n-        (<NodeJS.ReadableStream>fileContents).toString();\n-      let file2Utf8Contents = file2Contents instanceof Buffer ?\n-        file2Contents.toString('utf8') :\n-        (<NodeJS.ReadableStream>file2Contents).toString();\n+    it('returns false when stat exists but does not contain an isDirectory method', function(done) {\n+      const file = new Vinyl({ contents: null, stat: <fs.Stats> {} });\n+      expect(file.isDirectory()).toEqual(false);\n+      done();\n+    });\n \n-      file2Utf8Contents.should.equal(fileUtf8Contents);\n+    it('returns false when stat does not exist', function(done) {\n+      const file = new Vinyl({ contents: null });\n+      expect(file.isDirectory()).toEqual(false);\n       done();\n     });\n+  });\n \n-    it('should copy all attributes over with Stream', done => {\n-      const options = {\n-        cwd: '/',\n-        base: '/test/',\n-        path: '/test/test.coffee',\n-        contents: fakeStream\n-      };\n-      const file = new File(options);\n-      const file2 = file.clone();\n+  describe('isSymbolic()', function() {\n+    const fakeStat: fs.Stats = <any> {\n+      isSymbolicLink: () => {\n+        return true;\n+      },\n+    };\n+\n+    it('returns false when the contents are a Buffer', function(done) {\n+      const val = new Buffer('test');\n+      const file = new Vinyl({ contents: val, stat: fakeStat });\n+      expect(file.isSymbolic()).toEqual(false);\n+      done();\n+    });\n+\n+    it('returns false when the contents are a Stream', function(done) {\n+      const val = from([]);\n+      const file = new Vinyl({ contents: val, stat: fakeStat });\n+      expect(file.isSymbolic()).toEqual(false);\n+      done();\n+    });\n+\n+    it('returns true when the contents are null & stat.isSymbolicLink is true', function(done) {\n+      const file = new Vinyl({ contents: null, stat: fakeStat });\n+      expect(file.isSymbolic()).toEqual(true);\n+      done();\n+    });\n+\n+    it('returns false when stat exists but does not contain an isSymbolicLink method', function(done) {\n+      const file = new Vinyl({ contents: null, stat: <fs.Stats> {} });\n+      expect(file.isSymbolic()).toEqual(false);\n+      done();\n+    });\n \n-      file2.should.not.equal(file, 'refs should be different');\n-      file2.cwd.should.equal(file.cwd);\n-      file2.basename.should.equal(file.basename);\n-      file2.path.should.equal(file.path);\n-      file2.contents.should.equal(file.contents, 'stream ref should be the same');\n+    it('returns false when stat does not exist', function(done) {\n+      const file = new Vinyl({ contents: null });\n+      expect(file.isSymbolic()).toEqual(false);\n       done();\n     });\n+  });\n+\n+  describe('clone()', function() {\n \n-    it('should copy all attributes over with null', done => {\n+    it('copies all attributes over with Buffer contents', function(done) {\n       const options = {\n         cwd: '/',\n         base: '/test/',\n         path: '/test/test.coffee',\n-        contents: fakeStream\n+        contents: new Buffer('test'),\n       };\n-      const file = new File(options);\n+      const file = new Vinyl(options);\n       const file2 = file.clone();\n \n-      file2.should.not.equal(file, 'refs should be different');\n-      file2.cwd.should.equal(file.cwd);\n-      file2.basename.should.equal(file.basename);\n-      file2.path.should.equal(file.path);\n-      should.not.exist(file2.contents);\n+      expect(file2).toNotBe(file);\n+      expect(file2.cwd).toEqual(file.cwd);\n+      expect(file2.base).toEqual(file.base);\n+      expect(file2.path).toEqual(file.path);\n+      expect(file2.contents).toNotBe(file.contents);\n+      expect((<Buffer> file2.contents).toString('utf8')).toEqual((<Buffer> file.contents).toString('utf8'));\n       done();\n     });\n \n-    it('should properly clone the `stat` property', done => {\n+    it('assigns Buffer content reference when contents option is false', function(done) {\n       const options = {\n         cwd: '/',\n         base: '/test/',\n         path: '/test/test.js',\n         contents: new Buffer('test'),\n-        stat: fs.statSync(__filename)\n       };\n+      const file = new Vinyl(options);\n \n-      const file = new File(options);\n-      const copy = file.clone();\n+      const copy1 = file.clone({ contents: false });\n+      expect(copy1.contents).toBe(file.contents);\n \n-      // ReSharper disable WrongExpressionStatement\n-      copy.stat.isFile().should.be.true;\n-      // ReSharper restore WrongExpressionStatement\n+      const copy2 = file.clone();\n+      expect(copy2.contents).toNotBe(file.contents);\n \n+      const copy3 = file.clone({ contents: <any> 'invalid' });\n+      expect(copy3.contents).toNotBe(file.contents);\n       done();\n     });\n-  });\n \n-  describe('pipe()', () => {\n-    it('should write to stream with Buffer', done => {\n+    it('copies all attributes over with Stream contents', function(done) {\n       const options = {\n         cwd: '/',\n         base: '/test/',\n         path: '/test/test.coffee',\n-        contents: new Buffer('test')\n+        contents: from(['wa', 'dup']),\n       };\n-      const file = new File(options);\n-      const stream = new Stream.PassThrough();\n-      stream.on('data', (chunk: any) => {\n-        should.exist(chunk);\n-        (chunk instanceof Buffer).should.equal(true, 'should write as a buffer');\n-        chunk.toString('utf8').should.equal(options.contents.toString('utf8'));\n+      const file = new Vinyl(options);\n+      const file2 = file.clone();\n+\n+      expect(file2).toNotBe(file);\n+      expect(file2.cwd).toEqual(file.cwd);\n+      expect(file2.base).toEqual(file.base);\n+      expect(file2.path).toEqual(file.path);\n+      expect(file2.contents).toNotBe(file.contents);\n+\n+      let ends = 2;\n+      let data: Buffer = null;\n+      let data2: Buffer = null;\n+\n+      function assert(err: Error) {\n+        if (err) {\n+          done(err);\n+          return;\n+        }\n+\n+        if (--ends === 0) {\n+          expect(data).toNotBe(data2);\n+          expect(data.toString('utf8')).toEqual(data2.toString('utf8'));\n+          done();\n+        }\n+      }\n+\n+      pipe([\n+        file.contents,\n+        concat((d: Buffer) => {\n+          data = d;\n+        }),\n+      ], assert);\n+\n+      pipe([\n+        file2.contents,\n+        concat((d: Buffer) => {\n+          data2 = d;\n+        }),\n+      ], assert);\n+    });\n+\n+    it('does not start flowing until all clones flows (data)', function(done) {\n+      const options = {\n+        cwd: '/',\n+        base: '/test/',\n+        path: '/test/test.coffee',\n+        contents: from(['wa', 'dup']),\n+      };\n+      const file = new Vinyl(options);\n+      const file2 = file.clone();\n+      let ends = 2;\n+\n+      let data = '';\n+      let data2 = '';\n+\n+      function assert() {\n+        if (--ends === 0) {\n+          expect(data).toEqual(data2);\n+          done();\n+        }\n+      }\n+\n+      // Start flowing file2\n+      (<NodeJS.ReadableStream> file2.contents).on('data', (chunk: Buffer) => {\n+        data2 += chunk.toString('utf8');\n       });\n-      stream.on('end', () => {\n-        done();\n+\n+      process.nextTick(function() {\n+        // Nothing was written yet\n+        expect(data).toEqual('');\n+        expect(data2).toEqual('');\n+\n+        // Starts flowing file\n+        (<NodeJS.ReadableStream> file.contents).on('data', (chunk: Buffer) => {\n+          data += chunk.toString('utf8');\n+        });\n       });\n-      const ret = file.pipe(stream);\n-      ret.should.equal(stream, 'should return the stream');\n+\n+      (<NodeJS.ReadableStream> file2.contents).on('end', assert);\n+      (<NodeJS.ReadableStream> file.contents).on('end', assert);\n     });\n \n-    it('should pipe to stream with Stream', done => {\n-      const testChunk = new Buffer('test');\n+    it('does not start flowing until all clones flows (readable)', (done) => {\n       const options = {\n         cwd: '/',\n         base: '/test/',\n         path: '/test/test.coffee',\n-        contents: new Stream.PassThrough()\n+        contents: from(['wa', 'dup']),\n       };\n-      const file = new File(options);\n-      const stream = new Stream.PassThrough();\n-      stream.on('data', (chunk: any) => {\n-        should.exist(chunk);\n-        (chunk instanceof Buffer).should.equal(true, 'should write as a buffer');\n-        chunk.toString('utf8').should.equal(testChunk.toString('utf8'));\n-        done();\n-      });\n-      const ret = file.pipe(stream);\n-      ret.should.equal(stream, 'should return the stream');\n-\n-      let fileContents = file.contents;\n-      if (fileContents instanceof Buffer) {\n-        fileContents.write(testChunk.toString());\n+      const file = new Vinyl(options);\n+      const file2 = file.clone();\n+\n+      let data2 = '';\n+\n+      function assert(data: Buffer) {\n+        expect(data.toString('utf8')).toEqual(data2);\n       }\n+\n+      // Start flowing file2\n+      (<NodeJS.ReadableStream> file2.contents).on('readable', () => {\n+        let chunk: Buffer;\n+        while ((chunk = this.read()) !== null) {\n+          data2 += chunk.toString();\n+        }\n+      });\n+\n+      pipe([\n+        file.contents,\n+        concat(assert),\n+      ], done);\n     });\n \n-    it('should do nothing with null', done => {\n+    it('copies all attributes over with null contents', function(done) {\n       const options = {\n         cwd: '/',\n         base: '/test/',\n         path: '/test/test.coffee',\n-        contents: fakeStream\n+        contents: <Buffer> null,","path":"source-test/File.ts","position":767,"original_position":767,"commit_id":"004704d6484cd3f188e0cb29d6351037de2865ee","original_commit_id":"004704d6484cd3f188e0cb29d6351037de2865ee","user":{"login":"felixfbecker","id":10532611,"avatar_url":"https://avatars.githubusercontent.com/u/10532611?v=3","gravatar_id":"","url":"https://api.github.com/users/felixfbecker","html_url":"https://github.com/felixfbecker","followers_url":"https://api.github.com/users/felixfbecker/followers","following_url":"https://api.github.com/users/felixfbecker/following{/other_user}","gists_url":"https://api.github.com/users/felixfbecker/gists{/gist_id}","starred_url":"https://api.github.com/users/felixfbecker/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/felixfbecker/subscriptions","organizations_url":"https://api.github.com/users/felixfbecker/orgs","repos_url":"https://api.github.com/users/felixfbecker/repos","events_url":"https://api.github.com/users/felixfbecker/events{/privacy}","received_events_url":"https://api.github.com/users/felixfbecker/received_events","type":"User","site_admin":false},"body":"`null` is neither one in TS2, `null` is `null`","created_at":"2016-10-19T20:20:25Z","updated_at":"2016-10-19T20:20:25Z","html_url":"https://github.com/types/npm-vinyl/pull/5#discussion_r84158198","pull_request_url":"https://api.github.com/repos/types/npm-vinyl/pulls/5","_links":{"self":{"href":"https://api.github.com/repos/types/npm-vinyl/pulls/comments/84158198"},"html":{"href":"https://github.com/types/npm-vinyl/pull/5#discussion_r84158198"},"pull_request":{"href":"https://api.github.com/repos/types/npm-vinyl/pulls/5"}}},"pull_request":{"url":"https://api.github.com/repos/types/npm-vinyl/pulls/5","id":90018059,"html_url":"https://github.com/types/npm-vinyl/pull/5","diff_url":"https://github.com/types/npm-vinyl/pull/5.diff","patch_url":"https://github.com/types/npm-vinyl/pull/5.patch","issue_url":"https://api.github.com/repos/types/npm-vinyl/issues/5","number":5,"state":"open","locked":false,"title":"Update to `vinyl@2.0.0`","user":{"login":"demurgos","id":2262218,"avatar_url":"https://avatars.githubusercontent.com/u/2262218?v=3","gravatar_id":"","url":"https://api.github.com/users/demurgos","html_url":"https://github.com/demurgos","followers_url":"https://api.github.com/users/demurgos/followers","following_url":"https://api.github.com/users/demurgos/following{/other_user}","gists_url":"https://api.github.com/users/demurgos/gists{/gist_id}","starred_url":"https://api.github.com/users/demurgos/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/demurgos/subscriptions","organizations_url":"https://api.github.com/users/demurgos/orgs","repos_url":"https://api.github.com/users/demurgos/repos","events_url":"https://api.github.com/users/demurgos/events{/privacy}","received_events_url":"https://api.github.com/users/demurgos/received_events","type":"User","site_admin":false},"body":"Update major version of `vinyl`:\r\n\r\n- **Breaking change**: remove `PipeOptions` interface\r\n- **Breaking change**: remove `pipe` method\r\n- Update documentation\r\n- Update source-tests\r\n\r\nThis PR still contains the undocumented `stat` property.\r\n\r\nAs @felixfbecker said it in https://github.com/types/npm-vinyl/pull/2#issuecomment-254422414, please create a branch for `1.x` before updating the typings for `vinyl@2.0.0`","created_at":"2016-10-19T14:14:31Z","updated_at":"2016-10-19T20:20:25Z","closed_at":null,"merged_at":null,"merge_commit_sha":"b868068b857c6d34dde7e619b2cba5c9ffb29599","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/types/npm-vinyl/pulls/5/commits","review_comments_url":"https://api.github.com/repos/types/npm-vinyl/pulls/5/comments","review_comment_url":"https://api.github.com/repos/types/npm-vinyl/pulls/comments{/number}","comments_url":"https://api.github.com/repos/types/npm-vinyl/issues/5/comments","statuses_url":"https://api.github.com/repos/types/npm-vinyl/statuses/004704d6484cd3f188e0cb29d6351037de2865ee","head":{"label":"demurgos:v2","ref":"v2","sha":"004704d6484cd3f188e0cb29d6351037de2865ee","user":{"login":"demurgos","id":2262218,"avatar_url":"https://avatars.githubusercontent.com/u/2262218?v=3","gravatar_id":"","url":"https://api.github.com/users/demurgos","html_url":"https://github.com/demurgos","followers_url":"https://api.github.com/users/demurgos/followers","following_url":"https://api.github.com/users/demurgos/following{/other_user}","gists_url":"https://api.github.com/users/demurgos/gists{/gist_id}","starred_url":"https://api.github.com/users/demurgos/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/demurgos/subscriptions","organizations_url":"https://api.github.com/users/demurgos/orgs","repos_url":"https://api.github.com/users/demurgos/repos","events_url":"https://api.github.com/users/demurgos/events{/privacy}","received_events_url":"https://api.github.com/users/demurgos/received_events","type":"User","site_admin":false},"repo":{"id":71238754,"name":"npm-vinyl","full_name":"demurgos/npm-vinyl","owner":{"login":"demurgos","id":2262218,"avatar_url":"https://avatars.githubusercontent.com/u/2262218?v=3","gravatar_id":"","url":"https://api.github.com/users/demurgos","html_url":"https://github.com/demurgos","followers_url":"https://api.github.com/users/demurgos/followers","following_url":"https://api.github.com/users/demurgos/following{/other_user}","gists_url":"https://api.github.com/users/demurgos/gists{/gist_id}","starred_url":"https://api.github.com/users/demurgos/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/demurgos/subscriptions","organizations_url":"https://api.github.com/users/demurgos/orgs","repos_url":"https://api.github.com/users/demurgos/repos","events_url":"https://api.github.com/users/demurgos/events{/privacy}","received_events_url":"https://api.github.com/users/demurgos/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/demurgos/npm-vinyl","description":"Typings for vinyl","fork":true,"url":"https://api.github.com/repos/demurgos/npm-vinyl","forks_url":"https://api.github.com/repos/demurgos/npm-vinyl/forks","keys_url":"https://api.github.com/repos/demurgos/npm-vinyl/keys{/key_id}","collaborators_url":"https://api.github.com/repos/demurgos/npm-vinyl/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/demurgos/npm-vinyl/teams","hooks_url":"https://api.github.com/repos/demurgos/npm-vinyl/hooks","issue_events_url":"https://api.github.com/repos/demurgos/npm-vinyl/issues/events{/number}","events_url":"https://api.github.com/repos/demurgos/npm-vinyl/events","assignees_url":"https://api.github.com/repos/demurgos/npm-vinyl/assignees{/user}","branches_url":"https://api.github.com/repos/demurgos/npm-vinyl/branches{/branch}","tags_url":"https://api.github.com/repos/demurgos/npm-vinyl/tags","blobs_url":"https://api.github.com/repos/demurgos/npm-vinyl/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/demurgos/npm-vinyl/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/demurgos/npm-vinyl/git/refs{/sha}","trees_url":"https://api.github.com/repos/demurgos/npm-vinyl/git/trees{/sha}","statuses_url":"https://api.github.com/repos/demurgos/npm-vinyl/statuses/{sha}","languages_url":"https://api.github.com/repos/demurgos/npm-vinyl/languages","stargazers_url":"https://api.github.com/repos/demurgos/npm-vinyl/stargazers","contributors_url":"https://api.github.com/repos/demurgos/npm-vinyl/contributors","subscribers_url":"https://api.github.com/repos/demurgos/npm-vinyl/subscribers","subscription_url":"https://api.github.com/repos/demurgos/npm-vinyl/subscription","commits_url":"https://api.github.com/repos/demurgos/npm-vinyl/commits{/sha}","git_commits_url":"https://api.github.com/repos/demurgos/npm-vinyl/git/commits{/sha}","comments_url":"https://api.github.com/repos/demurgos/npm-vinyl/comments{/number}","issue_comment_url":"https://api.github.com/repos/demurgos/npm-vinyl/issues/comments{/number}","contents_url":"https://api.github.com/repos/demurgos/npm-vinyl/contents/{+path}","compare_url":"https://api.github.com/repos/demurgos/npm-vinyl/compare/{base}...{head}","merges_url":"https://api.github.com/repos/demurgos/npm-vinyl/merges","archive_url":"https://api.github.com/repos/demurgos/npm-vinyl/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/demurgos/npm-vinyl/downloads","issues_url":"https://api.github.com/repos/demurgos/npm-vinyl/issues{/number}","pulls_url":"https://api.github.com/repos/demurgos/npm-vinyl/pulls{/number}","milestones_url":"https://api.github.com/repos/demurgos/npm-vinyl/milestones{/number}","notifications_url":"https://api.github.com/repos/demurgos/npm-vinyl/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/demurgos/npm-vinyl/labels{/name}","releases_url":"https://api.github.com/repos/demurgos/npm-vinyl/releases{/id}","deployments_url":"https://api.github.com/repos/demurgos/npm-vinyl/deployments","created_at":"2016-10-18T10:54:04Z","updated_at":"2016-10-18T10:54:05Z","pushed_at":"2016-10-19T17:00:09Z","git_url":"git://github.com/demurgos/npm-vinyl.git","ssh_url":"git@github.com:demurgos/npm-vinyl.git","clone_url":"https://github.com/demurgos/npm-vinyl.git","svn_url":"https://github.com/demurgos/npm-vinyl","homepage":null,"size":27,"stargazers_count":0,"watchers_count":0,"language":"TypeScript","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"types:master","ref":"master","sha":"dad6419700d1fcc8c29ff2e00f43863af8ea32b4","user":{"login":"types","id":17114560,"avatar_url":"https://avatars.githubusercontent.com/u/17114560?v=3","gravatar_id":"","url":"https://api.github.com/users/types","html_url":"https://github.com/types","followers_url":"https://api.github.com/users/types/followers","following_url":"https://api.github.com/users/types/following{/other_user}","gists_url":"https://api.github.com/users/types/gists{/gist_id}","starred_url":"https://api.github.com/users/types/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/types/subscriptions","organizations_url":"https://api.github.com/users/types/orgs","repos_url":"https://api.github.com/users/types/repos","events_url":"https://api.github.com/users/types/events{/privacy}","received_events_url":"https://api.github.com/users/types/received_events","type":"Organization","site_admin":false},"repo":{"id":65893961,"name":"npm-vinyl","full_name":"types/npm-vinyl","owner":{"login":"types","id":17114560,"avatar_url":"https://avatars.githubusercontent.com/u/17114560?v=3","gravatar_id":"","url":"https://api.github.com/users/types","html_url":"https://github.com/types","followers_url":"https://api.github.com/users/types/followers","following_url":"https://api.github.com/users/types/following{/other_user}","gists_url":"https://api.github.com/users/types/gists{/gist_id}","starred_url":"https://api.github.com/users/types/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/types/subscriptions","organizations_url":"https://api.github.com/users/types/orgs","repos_url":"https://api.github.com/users/types/repos","events_url":"https://api.github.com/users/types/events{/privacy}","received_events_url":"https://api.github.com/users/types/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/types/npm-vinyl","description":"Typings for vinyl","fork":false,"url":"https://api.github.com/repos/types/npm-vinyl","forks_url":"https://api.github.com/repos/types/npm-vinyl/forks","keys_url":"https://api.github.com/repos/types/npm-vinyl/keys{/key_id}","collaborators_url":"https://api.github.com/repos/types/npm-vinyl/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/types/npm-vinyl/teams","hooks_url":"https://api.github.com/repos/types/npm-vinyl/hooks","issue_events_url":"https://api.github.com/repos/types/npm-vinyl/issues/events{/number}","events_url":"https://api.github.com/repos/types/npm-vinyl/events","assignees_url":"https://api.github.com/repos/types/npm-vinyl/assignees{/user}","branches_url":"https://api.github.com/repos/types/npm-vinyl/branches{/branch}","tags_url":"https://api.github.com/repos/types/npm-vinyl/tags","blobs_url":"https://api.github.com/repos/types/npm-vinyl/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/types/npm-vinyl/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/types/npm-vinyl/git/refs{/sha}","trees_url":"https://api.github.com/repos/types/npm-vinyl/git/trees{/sha}","statuses_url":"https://api.github.com/repos/types/npm-vinyl/statuses/{sha}","languages_url":"https://api.github.com/repos/types/npm-vinyl/languages","stargazers_url":"https://api.github.com/repos/types/npm-vinyl/stargazers","contributors_url":"https://api.github.com/repos/types/npm-vinyl/contributors","subscribers_url":"https://api.github.com/repos/types/npm-vinyl/subscribers","subscription_url":"https://api.github.com/repos/types/npm-vinyl/subscription","commits_url":"https://api.github.com/repos/types/npm-vinyl/commits{/sha}","git_commits_url":"https://api.github.com/repos/types/npm-vinyl/git/commits{/sha}","comments_url":"https://api.github.com/repos/types/npm-vinyl/comments{/number}","issue_comment_url":"https://api.github.com/repos/types/npm-vinyl/issues/comments{/number}","contents_url":"https://api.github.com/repos/types/npm-vinyl/contents/{+path}","compare_url":"https://api.github.com/repos/types/npm-vinyl/compare/{base}...{head}","merges_url":"https://api.github.com/repos/types/npm-vinyl/merges","archive_url":"https://api.github.com/repos/types/npm-vinyl/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/types/npm-vinyl/downloads","issues_url":"https://api.github.com/repos/types/npm-vinyl/issues{/number}","pulls_url":"https://api.github.com/repos/types/npm-vinyl/pulls{/number}","milestones_url":"https://api.github.com/repos/types/npm-vinyl/milestones{/number}","notifications_url":"https://api.github.com/repos/types/npm-vinyl/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/types/npm-vinyl/labels{/name}","releases_url":"https://api.github.com/repos/types/npm-vinyl/releases{/id}","deployments_url":"https://api.github.com/repos/types/npm-vinyl/deployments","created_at":"2016-08-17T09:20:24Z","updated_at":"2016-08-17T09:20:49Z","pushed_at":"2016-10-19T17:00:09Z","git_url":"git://github.com/types/npm-vinyl.git","ssh_url":"git@github.com:types/npm-vinyl.git","clone_url":"https://github.com/types/npm-vinyl.git","svn_url":"https://github.com/types/npm-vinyl","homepage":null,"size":23,"stargazers_count":0,"watchers_count":0,"language":"TypeScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":1,"forks":1,"open_issues":1,"watchers":0,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/types/npm-vinyl/pulls/5"},"html":{"href":"https://github.com/types/npm-vinyl/pull/5"},"issue":{"href":"https://api.github.com/repos/types/npm-vinyl/issues/5"},"comments":{"href":"https://api.github.com/repos/types/npm-vinyl/issues/5/comments"},"review_comments":{"href":"https://api.github.com/repos/types/npm-vinyl/pulls/5/comments"},"review_comment":{"href":"https://api.github.com/repos/types/npm-vinyl/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/types/npm-vinyl/pulls/5/commits"},"statuses":{"href":"https://api.github.com/repos/types/npm-vinyl/statuses/004704d6484cd3f188e0cb29d6351037de2865ee"}}}}
{"actor":{"display_login":"felixfbecker"}}