From 7ebf78b7d2cd075459b522384257682ba5ad550a Mon Sep 17 00:00:00 2001 From: johnjbarton Date: Mon, 10 Feb 2020 09:53:59 -0800 Subject: [PATCH] feat(preprocessor): obey Pattern.isBinary when set Add support for isBinary. If set, use it and don't probe file to detect binary status. Fixes #3405 --- lib/config.js | 3 ++- lib/file-list.js | 4 ++-- lib/file.js | 5 ++++- lib/preprocessor.js | 6 +++++- test/unit/preprocessor.spec.js | 38 ++++++++++++++++++++++++++++++++++ 5 files changed, 51 insertions(+), 5 deletions(-) diff --git a/lib/config.js b/lib/config.js index eec445dc5..956577f65 100644 --- a/lib/config.js +++ b/lib/config.js @@ -32,7 +32,7 @@ try { } catch (e) {} class Pattern { - constructor (pattern, served, included, watched, nocache, type) { + constructor (pattern, served, included, watched, nocache, type, isBinary) { this.pattern = pattern this.served = helper.isDefined(served) ? served : true this.included = helper.isDefined(included) ? included : true @@ -40,6 +40,7 @@ class Pattern { this.nocache = helper.isDefined(nocache) ? nocache : false this.weight = helper.mmPatternWeight(pattern) this.type = type + this.isBinary = isBinary } compare (other) { diff --git a/lib/file-list.js b/lib/file-list.js index 99cc72595..19d0cb180 100644 --- a/lib/file-list.js +++ b/lib/file-list.js @@ -61,7 +61,7 @@ class FileList { let lastCompletedRefresh = this._refreshing lastCompletedRefresh = Promise - .map(this._patterns, async ({ pattern, type, nocache }) => { + .map(this._patterns, async ({ pattern, type, nocache, isBinary }) => { if (helper.isUrlAbsolute(pattern)) { this.buckets.set(pattern, [new Url(pattern, type)]) return @@ -81,7 +81,7 @@ class FileList { return true } }) - .map((path) => new File(path, mg.statCache[path].mtime, nocache, type)) + .map((path) => new File(path, mg.statCache[path].mtime, nocache, type, isBinary)) if (nocache) { log.debug(`Not preprocessing "${pattern}" due to nocache`) diff --git a/lib/file.js b/lib/file.js index 8689db103..69f245b91 100644 --- a/lib/file.js +++ b/lib/file.js @@ -4,7 +4,7 @@ * File object used for tracking files in `file-list.js`. */ class File { - constructor (path, mtime, doNotCache, type) { + constructor (path, mtime, doNotCache, type, isBinary) { // used for serving (processed path, eg some/file.coffee -> some/file.coffee.js) this.path = path @@ -24,6 +24,9 @@ class File { this.doNotCache = doNotCache === undefined ? false : doNotCache this.type = type + + // Tri state: null means probe file for binary. + this.isBinary = isBinary === undefined ? null : isBinary } toString () { diff --git a/lib/preprocessor.js b/lib/preprocessor.js index a8fa3a892..7b9051814 100644 --- a/lib/preprocessor.js +++ b/lib/preprocessor.js @@ -102,7 +102,11 @@ function createPriorityPreprocessor (config = {}, preprocessorPriority, basePath return async function preprocess (file) { const buffer = await tryToRead(file.originalPath, log) - const isBinary = await isBinaryFile(buffer, buffer.length) + let isBinary = file.isBinary + if (isBinary == null) { + // Pattern did not specify, probe for it. + isBinary = await isBinaryFile(buffer, buffer.length) + } const preprocessorNames = Object.keys(config).reduce((ppNames, pattern) => { if (mm(file.originalPath, pattern, { dot: true })) { diff --git a/test/unit/preprocessor.spec.js b/test/unit/preprocessor.spec.js index 667d1fca0..f001c4ec1 100644 --- a/test/unit/preprocessor.spec.js +++ b/test/unit/preprocessor.spec.js @@ -21,6 +21,7 @@ describe('preprocessor', () => { 'a.txt': mocks.fs.file(0, 'some-text'), 'photo.png': mocks.fs.file(0, binarydata), 'CAM_PHOTO.JPG': mocks.fs.file(0, binarydata), + 'proto.pb': mocks.fs.file(0, Buffer.from('mixed-content', 'utf8')), '.dir': { 'a.js': mocks.fs.file(0, 'content') } @@ -325,6 +326,43 @@ describe('preprocessor', () => { expect(file.content).to.be.an.instanceof(Buffer) }) + it('should not preprocess files configured to be binary', async () => { + const fakePreprocessor = sinon.spy((content, file, done) => { + done(null, content) + }) + + const injector = new di.Injector([{ + 'preprocessor:fake': ['factory', function () { return fakePreprocessor }] + }, emitterSetting]) + + const pp = m.createPriorityPreprocessor({ '**/*': ['fake'] }, {}, null, injector) + + const file = { originalPath: '/some/proto.pb', path: 'path', isBinary: true } + + await pp(file) + expect(fakePreprocessor).not.to.have.been.called + expect(file.content).to.be.an.instanceof(Buffer) + }) + + it('should preprocess files configured not to be binary', async () => { + const fakePreprocessor = sinon.spy((content, file, done) => { + done(null, content) + }) + + const injector = new di.Injector([{ + 'preprocessor:fake': ['factory', function () { return fakePreprocessor }] + }, emitterSetting]) + + const pp = m.createPriorityPreprocessor({ '**/*': ['fake'] }, {}, null, injector) + + // Explicit false for isBinary + const file = { originalPath: '/some/proto.pb', path: 'path', isBinary: false } + + await pp(file) + expect(fakePreprocessor).to.have.been.calledOnce + expect(typeof file.content).to.equal('string') + }) + it('should preprocess binary files if handleBinaryFiles=true', async () => { const fakePreprocessor = sinon.spy((content, file, done) => { done(null, content)