From d7336b7d63ad9a8a753e6f07033b83d8f5aab111 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benoi=CC=82t=20Rouleau?= Date: Sun, 14 Aug 2016 20:17:39 -0400 Subject: [PATCH] Add relativePath option, fixes #15, closes #22 --- README.md | 2 ++ index.js | 8 +++-- test/main.js | 85 ++++++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 77 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index a7bc991..9c64639 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,8 @@ gulp.task('default', function() { - `options.formatter` (function, optional): the function responsible for serializing the hashes data structure into the string content of the output file. It takes the value returned from the `transform` function as the first argument and must return a string. Defaults to `JSON.stringify`. +- `options.relativePath` (string, optional): the part of the path, relative to the project root, that should be omitted from the hashes object. Defaults to the project root—more specifically `process.cwd`. gulp defaults the `process.cwd` to where the gulpfile is located. + **Note:** all of the options which accept a function can be run asynchronously by returning a promise (or *thenable*). If the given option has a return value constraint, the constraint will still be applied to the promise's fulfillment value. ## Integrating with Web applications diff --git a/index.js b/index.js index 01b6c24..51ff71f 100644 --- a/index.js +++ b/index.js @@ -13,6 +13,7 @@ var DEFAULT_OPTIONS = { length: 0, transform: Object, formatter: JSON.stringify, + relativePath: '.', }; var OPTION_TYPES = { fileName: ['String'], @@ -20,6 +21,7 @@ var OPTION_TYPES = { length: ['Number'], transform: ['Function'], formatter: ['Function'], + relativePath: ['String'], }; var hashesStore = {}; // options.fileName: { relativePath: hash } @@ -42,8 +44,8 @@ function sliceHash(hash, options) { : hash; } -function relativePath(projectPath, filePath) { - return path.relative(projectPath, filePath).replace(/\\/g, '/'); +function relativePath(projectPath, relativePath, filePath) { + return path.relative(path.join(projectPath, relativePath), filePath).replace(/\\/g, '/'); } function getType(value) { @@ -75,7 +77,7 @@ module.exports = exports = function(options) { hashingPromises.push( Promise.try(hash.bind(undefined, file, options)).then(function(hashed) { if (typeof hashed !== 'string') throw error('Return/fulfill value of `options.algo` must be a string'); - hashes[relativePath(file.cwd, file.path)] = sliceHash(hashed, options); + hashes[relativePath(file.cwd, options.relativePath, file.path)] = sliceHash(hashed, options); }) ); } diff --git a/test/main.js b/test/main.js index 5d900dd..7fc89f3 100644 --- a/test/main.js +++ b/test/main.js @@ -25,12 +25,17 @@ var fileBinary = new gutil.File({ path: 'C:/users/ult/test/file2.js', contents: new Buffer([0x80]), // `Buffer.from` is not supported in Node 0.10 }); -var fileBustPath = bust._relativePath(file.cwd, file.path); -var file2BustPath = bust._relativePath(file2.cwd, file2.path); +var fileBustPath = bust._relativePath(file.cwd, '.', file.path); +var fileBustPathRelative = bust._relativePath(file.cwd, 'test/', file.path); +var file2BustPath = bust._relativePath(file2.cwd, '.', file2.path); var fileHash = bust._hash(file, bust._DEFAULT_OPTIONS); var file2Hash = bust._hash(file2, bust._DEFAULT_OPTIONS); var fileBinaryHash = bust._hash(fileBinary, bust._DEFAULT_OPTIONS); +var parseFile = function(file) { + return JSON.parse(file.contents.toString()); +}; + beforeEach(bust._reset); describe('Configuration-independent internal methods', function() { @@ -42,7 +47,7 @@ describe('Configuration-independent internal methods', function() { describe('_relativePath()', function() { it('should return a path relative to project root', function() { - bust._relativePath('/projectRoot/', '/projectRoot/folder/file.ext').should.equal('folder/file.ext'); + bust._relativePath('/projectRoot/', '.', '/projectRoot/folder/file.ext').should.equal('folder/file.ext'); }); }); @@ -111,7 +116,7 @@ describe('Core', function() { expectedObj[fileBustPath] = fileHash; expectedObj[file2BustPath] = file2Hash; - JSON.parse(newFile.contents.toString()).should.eql(expectedObj); + parseFile(newFile).should.eql(expectedObj); Buffer.isBuffer(newFile.contents).should.be.true(); done(); }); @@ -125,13 +130,13 @@ describe('Core', function() { var testedOutputs = 0; stream.on('data', function(newFile) { - var obj = JSON.parse(newFile.contents.toString()); + var obj = parseFile(newFile); obj.should.have.property(fileBustPath); obj.should.not.have.property(file2BustPath); if (++testedOutputs === 2) done(); }); stream2.on('data', function(newFile) { - var obj = JSON.parse(newFile.contents.toString()); + var obj = parseFile(newFile); obj.should.not.have.property(fileBustPath); obj.should.have.property(file2BustPath); if (++testedOutputs === 2) done(); @@ -146,7 +151,7 @@ describe('Core', function() { var testedOutputs = 0; function runAssertion(newFile) { - var obj = JSON.parse(newFile.contents.toString()); + var obj = parseFile(newFile); obj.should.have.property(fileBustPath); obj.should.have.property(file2BustPath); done(); @@ -163,7 +168,7 @@ describe('Core', function() { it('should return an empty hashes object file when receiving an empty buffers stream', function(done) { var stream = bust(); stream.on('data', function(newFile) { - JSON.parse(newFile.contents.toString()).should.eql({}); + parseFile(newFile).should.eql({}); done(); }); stream.end(); @@ -188,7 +193,7 @@ describe('Configuration options', function() { it('should accept a hashing algorithm name string', function(done) { var stream = bust({ algo: 'sha1' }); stream.on('data', function(newFile) { - JSON.parse(newFile.contents.toString())[fileBustPath].should.be.a.String().with.lengthOf(40); + parseFile(newFile)[fileBustPath].should.be.a.String().with.lengthOf(40); done(); }); stream.end(file); @@ -214,7 +219,7 @@ describe('Configuration options', function() { }, }); stream.on('data', function(newFile) { - JSON.parse(newFile.contents.toString())[fileBustPath].should.equal(fileContentStr); + parseFile(newFile)[fileBustPath].should.equal(fileContentStr); done(); }); stream.end(file); @@ -232,7 +237,7 @@ describe('Configuration options', function() { }, }); stream.on('data', function(newFile) { - JSON.parse(newFile.contents.toString())[fileBustPath].should.equal(fileContentStr); + parseFile(newFile)[fileBustPath].should.equal(fileContentStr); done(); }); stream.end(file); @@ -269,7 +274,7 @@ describe('Configuration options', function() { fileHash.length.should.be.greaterThan(expectedLength); stream.on('data', function(newFile) { - JSON.parse(newFile.contents.toString())[fileBustPath].should.equal(fileHash.slice(0, expectedLength)); + parseFile(newFile)[fileBustPath].should.equal(fileHash.slice(0, expectedLength)); done(); }); stream.end(file); @@ -282,7 +287,7 @@ describe('Configuration options', function() { fileHash.length.should.be.greaterThan(expectedLength); stream.on('data', function(newFile) { - JSON.parse(newFile.contents.toString())[fileBustPath].should.equal(fileHash.slice(-expectedLength)); + parseFile(newFile)[fileBustPath].should.equal(fileHash.slice(-expectedLength)); done(); }); stream.end(file); @@ -300,7 +305,7 @@ describe('Configuration options', function() { }; var stream = bust(options); stream.on('data', function(newFile) { - JSON.parse(newFile.contents.toString())[0].should.equal(fileHash + suffix); + parseFile(newFile)[0].should.equal(fileHash + suffix); done(); }); stream.end(file); @@ -320,7 +325,7 @@ describe('Configuration options', function() { }; var stream = bust(options); stream.on('data', function(newFile) { - JSON.parse(newFile.contents.toString())[0].should.equal(fileHash + suffix); + parseFile(newFile)[0].should.equal(fileHash + suffix); done(); }); stream.end(file); @@ -384,4 +389,54 @@ describe('Configuration options', function() { stream.end(file); }); }); + + describe('relativePath', function() { + it('should not include this path in the hashes object', function(done) { + var options = { + relativePath: 'test/', + }; + var stream = bust(options); + stream.on('data', function(newFile) { + parseFile(newFile).should.have.property(fileBustPathRelative); + done(); + }); + stream.end(file); + }); + + it('should accept a leading slash', function(done) { + var options = { + relativePath: '/test/', + }; + var stream = bust(options); + stream.on('data', function(newFile) { + parseFile(newFile).should.have.property(fileBustPathRelative); + done(); + }); + stream.end(file); + }); + + it('should not require a trailing slash', function(done) { + var options = { + relativePath: 'test', + }; + var stream = bust(options); + stream.on('data', function(newFile) { + parseFile(newFile).should.have.property(fileBustPathRelative); + done(); + }); + stream.end(file); + }); + + it('should accept just a slash', function(done) { + var options = { + relativePath: '/', + }; + var stream = bust(options); + stream.on('data', function(newFile) { + parseFile(newFile).should.have.property(fileBustPath); + done(); + }); + stream.end(file); + }); + }); });