Skip to content

Commit

Permalink
Add mergeArrays option to disable default array merging [#16]
Browse files Browse the repository at this point in the history
  • Loading branch information
joshswan committed Feb 14, 2017
1 parent 7a9ade3 commit 98bfe02
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 29 deletions.
24 changes: 17 additions & 7 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,23 @@ const through = require('through');

const PLUGIN_NAME = 'gulp-merge-json';

function merge(a, b, concatArrays) {
function merge(a, b, concatArrays, mergeArrays) {
if (Array.isArray(a) && concatArrays) {
return a.concat(b);
}

return _.mergeWith(a, b, (objValue, srcValue) => (
Array.isArray(objValue) && concatArrays ? objValue.concat(srcValue) : undefined
));
return _.mergeWith(a, b, (objValue, srcValue) => {
// Handle array merging
if (Array.isArray(objValue) && Array.isArray(srcValue)) {
if (concatArrays) {
return objValue.concat(srcValue);
} else if (!mergeArrays) {
return srcValue;
}
}

return undefined;
});
}

module.exports = function mergeJson(fileName, edit, startObj, endObj, exportModule, concatArrays) {
Expand All @@ -34,6 +43,7 @@ module.exports = function mergeJson(fileName, edit, startObj, endObj, exportModu
endObj: null,
exportModule: false,
concatArrays: false,
mergeArrays: true,
jsonReplacer: null,
jsonSpace: '\t',
json5: false,
Expand Down Expand Up @@ -67,7 +77,7 @@ module.exports = function mergeJson(fileName, edit, startObj, endObj, exportModu

const obj = options.edit;

options.edit = json => merge(json, obj, options.concatArrays);
options.edit = json => merge(json, obj, options.concatArrays, options.mergeArrays);
}

let merged = options.startObj;
Expand Down Expand Up @@ -96,7 +106,7 @@ module.exports = function mergeJson(fileName, edit, startObj, endObj, exportModu
}

try {
merged = merge(merged, options.edit(parsed, file), options.concatArrays);
merged = merge(merged, options.edit(parsed, file), options.concatArrays, options.mergeArrays);
} catch (err) {
return this.emit('error', new gutil.PluginError(PLUGIN_NAME, err));
}
Expand All @@ -108,7 +118,7 @@ module.exports = function mergeJson(fileName, edit, startObj, endObj, exportModu
}

if (options.endObj) {
merged = merge(merged, options.endObj, options.concatArrays);
merged = merge(merged, options.endObj, options.concatArrays, options.mergeArrays);
}

let contents = jsonLib.stringify(merged, options.jsonReplacer, options.jsonSpace);
Expand Down
2 changes: 1 addition & 1 deletion test/json/test1.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
"pet": {
"name": "Indy"
},
"tags": ["cool"]
"tags": ["cool", "fun"]
}
56 changes: 35 additions & 21 deletions test/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ it('should combine JSON files', (done) => {
const stream = gulp.src(['test/json/test1.json', 'test/json/test2.json']).pipe(merge('combined.json'));

stream.on('data', (file) => {
const expected = ['{', '\t"name": "Josh",', '\t"pet": {', '\t\t"name": "Indy"', '\t},', '\t"tags": [', '\t\t"awesome"', '\t],', '\t"place": "San Francisco",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '}'].join('\n');
const expected = ['{', '\t"name": "Josh",', '\t"pet": {', '\t\t"name": "Indy"', '\t},', '\t"tags": [', '\t\t"awesome",', '\t\t"fun"', '\t],', '\t"place": "San Francisco",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '}'].join('\n');

file.contents.toString().should.eql(expected);

Expand All @@ -38,7 +38,7 @@ it('should modify property based on input function', (done) => {
}));

stream.on('data', (file) => {
const expected = ['{', '\t"name": "Josh",', '\t"pet": {', '\t\t"name": "Indy"', '\t},', '\t"tags": [', '\t\t"awesome"', '\t],', '\t"place": "New York",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '}'].join('\n');
const expected = ['{', '\t"name": "Josh",', '\t"pet": {', '\t\t"name": "Indy"', '\t},', '\t"tags": [', '\t\t"awesome",', '\t\t"fun"', '\t],', '\t"place": "New York",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '}'].join('\n');

file.contents.toString().should.eql(expected);

Expand All @@ -56,7 +56,7 @@ it('should add property based on input function', (done) => {
}));

stream.on('data', (file) => {
const expected = ['{', '\t"name": "Josh",', '\t"pet": {', '\t\t"name": "Indy"', '\t},', '\t"tags": [', '\t\t"awesome"', '\t],', '\t"place": "San Francisco",', '\t"settings": {', '\t\t"likesSleep": true,', '\t\t"timezone": "PST"', '\t}', '}'].join('\n');
const expected = ['{', '\t"name": "Josh",', '\t"pet": {', '\t\t"name": "Indy"', '\t},', '\t"tags": [', '\t\t"awesome",', '\t\t"fun"', '\t],', '\t"place": "San Francisco",', '\t"settings": {', '\t\t"likesSleep": true,', '\t\t"timezone": "PST"', '\t}', '}'].join('\n');

file.contents.toString().should.eql(expected);

Expand All @@ -74,7 +74,7 @@ it('should delete property based on input function', (done) => {
}));

stream.on('data', (file) => {
const expected = ['{', '\t"name": "Josh",', '\t"tags": [', '\t\t"awesome"', '\t],', '\t"place": "San Francisco",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '}'].join('\n');
const expected = ['{', '\t"name": "Josh",', '\t"tags": [', '\t\t"awesome",', '\t\t"fun"', '\t],', '\t"place": "San Francisco",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '}'].join('\n');

file.contents.toString().should.eql(expected);

Expand All @@ -86,7 +86,7 @@ it('should merge object if given as input function', (done) => {
const stream = gulp.src(['test/json/test1.json', 'test/json/test2.json']).pipe(merge('combined.json', { testing: true }));

stream.on('data', (file) => {
const expected = ['{', '\t"name": "Josh",', '\t"pet": {', '\t\t"name": "Indy"', '\t},', '\t"tags": [', '\t\t"awesome"', '\t],', '\t"testing": true,', '\t"place": "San Francisco",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '}'].join('\n');
const expected = ['{', '\t"name": "Josh",', '\t"pet": {', '\t\t"name": "Indy"', '\t},', '\t"tags": [', '\t\t"awesome",', '\t\t"fun"', '\t],', '\t"testing": true,', '\t"place": "San Francisco",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '}'].join('\n');

file.contents.toString().should.eql(expected);

Expand All @@ -98,7 +98,7 @@ it('should use supplied start object as base', (done) => {
const stream = gulp.src(['test/json/test1.json', 'test/json/test2.json']).pipe(merge('combined.json', false, { initial: 'value' }));

stream.on('data', (file) => {
const expected = ['{', '\t"initial": "value",', '\t"name": "Josh",', '\t"pet": {', '\t\t"name": "Indy"', '\t},', '\t"tags": [', '\t\t"awesome"', '\t],', '\t"place": "San Francisco",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '}'].join('\n');
const expected = ['{', '\t"initial": "value",', '\t"name": "Josh",', '\t"pet": {', '\t\t"name": "Indy"', '\t},', '\t"tags": [', '\t\t"awesome",', '\t\t"fun"', '\t],', '\t"place": "San Francisco",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '}'].join('\n');

file.contents.toString().should.eql(expected);

Expand All @@ -110,7 +110,7 @@ it('should use supplied final object to overwrite', (done) => {
const stream = gulp.src(['test/json/test1.json', 'test/json/test2.json']).pipe(merge('combined.json', false, false, { place: 'Las Vegas' }));

stream.on('data', (file) => {
const expected = ['{', '\t"name": "Josh",', '\t"pet": {', '\t\t"name": "Indy"', '\t},', '\t"tags": [', '\t\t"awesome"', '\t],', '\t"place": "Las Vegas",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '}'].join('\n');
const expected = ['{', '\t"name": "Josh",', '\t"pet": {', '\t\t"name": "Indy"', '\t},', '\t"tags": [', '\t\t"awesome",', '\t\t"fun"', '\t],', '\t"place": "Las Vegas",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '}'].join('\n');

file.contents.toString().should.eql(expected);

Expand All @@ -122,7 +122,7 @@ it('should output a node module when true is passed as the exportModule param',
const stream = gulp.src(['test/json/test1.json', 'test/json/test2.json']).pipe(merge('combined.json', false, false, false, true));

stream.on('data', (file) => {
const expected = `module.exports = ${['{', '\t"name": "Josh",', '\t"pet": {', '\t\t"name": "Indy"', '\t},', '\t"tags": [', '\t\t"awesome"', '\t],', '\t"place": "San Francisco",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '};'].join('\n')}`;
const expected = `module.exports = ${['{', '\t"name": "Josh",', '\t"pet": {', '\t\t"name": "Indy"', '\t},', '\t"tags": [', '\t\t"awesome",', '\t\t"fun"', '\t],', '\t"place": "San Francisco",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '};'].join('\n')}`;

file.contents.toString().should.eql(expected);

Expand All @@ -134,7 +134,7 @@ it('should not output a node module when false is passed as the exportModule par
const stream = gulp.src(['test/json/test1.json', 'test/json/test2.json']).pipe(merge('combined.json', false, false, false, false));

stream.on('data', (file) => {
const expected = ['{', '\t"name": "Josh",', '\t"pet": {', '\t\t"name": "Indy"', '\t},', '\t"tags": [', '\t\t"awesome"', '\t],', '\t"place": "San Francisco",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '}'].join('\n');
const expected = ['{', '\t"name": "Josh",', '\t"pet": {', '\t\t"name": "Indy"', '\t},', '\t"tags": [', '\t\t"awesome",', '\t\t"fun"', '\t],', '\t"place": "San Francisco",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '}'].join('\n');

file.contents.toString().should.eql(expected);

Expand All @@ -146,7 +146,7 @@ it('should not output a node module when nothing is passed as the exportModule p
const stream = gulp.src(['test/json/test1.json', 'test/json/test2.json']).pipe(merge('combined.json', false, false, false));

stream.on('data', (file) => {
const expected = ['{', '\t"name": "Josh",', '\t"pet": {', '\t\t"name": "Indy"', '\t},', '\t"tags": [', '\t\t"awesome"', '\t],', '\t"place": "San Francisco",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '}'].join('\n');
const expected = ['{', '\t"name": "Josh",', '\t"pet": {', '\t\t"name": "Indy"', '\t},', '\t"tags": [', '\t\t"awesome",', '\t\t"fun"', '\t],', '\t"place": "San Francisco",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '}'].join('\n');

file.contents.toString().should.eql(expected);

Expand All @@ -158,7 +158,7 @@ it('should not output a node module when empty string is passed as the exportMod
const stream = gulp.src(['test/json/test1.json', 'test/json/test2.json']).pipe(merge('combined.json', false, false, false, ''));

stream.on('data', (file) => {
const expected = ['{', '\t"name": "Josh",', '\t"pet": {', '\t\t"name": "Indy"', '\t},', '\t"tags": [', '\t\t"awesome"', '\t],', '\t"place": "San Francisco",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '}'].join('\n');
const expected = ['{', '\t"name": "Josh",', '\t"pet": {', '\t\t"name": "Indy"', '\t},', '\t"tags": [', '\t\t"awesome",', '\t\t"fun"', '\t],', '\t"place": "San Francisco",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '}'].join('\n');

file.contents.toString().should.eql(expected);

Expand All @@ -170,7 +170,7 @@ it('should output the passed variable when a name is passed as the exportModule
const stream = gulp.src(['test/json/test1.json', 'test/json/test2.json']).pipe(merge('combined.json', false, false, false, 'varname'));

stream.on('data', (file) => {
const expected = `varname = ${['{', '\t"name": "Josh",', '\t"pet": {', '\t\t"name": "Indy"', '\t},', '\t"tags": [', '\t\t"awesome"', '\t],', '\t"place": "San Francisco",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '};'].join('\n')}`;
const expected = `varname = ${['{', '\t"name": "Josh",', '\t"pet": {', '\t\t"name": "Indy"', '\t},', '\t"tags": [', '\t\t"awesome",', '\t\t"fun"', '\t],', '\t"place": "San Francisco",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '};'].join('\n')}`;

file.contents.toString().should.eql(expected);

Expand All @@ -182,7 +182,21 @@ it('should concat arrays if enabled', (done) => {
const stream = gulp.src(['test/json/test1.json', 'test/json/test2.json']).pipe(merge('combined.json', false, false, false, false, true));

stream.on('data', (file) => {
const expected = ['{', '\t"name": "Josh",', '\t"pet": {', '\t\t"name": "Indy"', '\t},', '\t"tags": [', '\t\t"cool",', '\t\t"awesome"', '\t],', '\t"place": "San Francisco",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '}'].join('\n');
const expected = ['{', '\t"name": "Josh",', '\t"pet": {', '\t\t"name": "Indy"', '\t},', '\t"tags": [', '\t\t"cool",', '\t\t"fun",', '\t\t"awesome"', '\t],', '\t"place": "San Francisco",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '}'].join('\n');

file.contents.toString().should.eql(expected);

done();
});
});

it('should not merge arrays if disabled', (done) => {
const stream = gulp.src(['test/json/test1.json', 'test/json/test2.json']).pipe(merge({
mergeArrays: false,
}));

stream.on('data', (file) => {
const expected = ['{', '\t"name": "Josh",', '\t"pet": {', '\t\t"name": "Indy"', '\t},', '\t"tags": [', '\t\t"awesome"', '\t],', '\t"place": "San Francisco",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '}'].join('\n');

file.contents.toString().should.eql(expected);

Expand Down Expand Up @@ -284,7 +298,7 @@ it('should merge when file is passed in options object', (done) => {
const stream = gulp.src(['test/json/test1.json', 'test/json/test2.json']).pipe(merge({ fileName: 'combined.json' }));

stream.on('data', (file) => {
const expected = ['{', '\t"name": "Josh",', '\t"pet": {', '\t\t"name": "Indy"', '\t},', '\t"tags": [', '\t\t"awesome"', '\t],', '\t"place": "San Francisco",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '}'].join('\n');
const expected = ['{', '\t"name": "Josh",', '\t"pet": {', '\t\t"name": "Indy"', '\t},', '\t"tags": [', '\t\t"awesome",', '\t\t"fun"', '\t],', '\t"place": "San Francisco",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '}'].join('\n');

file.contents.toString().should.eql(expected);

Expand All @@ -306,7 +320,7 @@ it('should allow the editor function in options object', (done) => {
}));

stream.on('data', (file) => {
const expected = ['{', '\t"name": "Josh",', '\t"pet": {', '\t\t"name": "Indy"', '\t},', '\t"tags": [', '\t\t"awesome"', '\t],', '\t"place": "New York",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '}'].join('\n');
const expected = ['{', '\t"name": "Josh",', '\t"pet": {', '\t\t"name": "Indy"', '\t},', '\t"tags": [', '\t\t"awesome",', '\t\t"fun"', '\t],', '\t"place": "New York",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '}'].join('\n');

file.contents.toString().should.eql(expected);

Expand All @@ -321,7 +335,7 @@ it('should use supplied start object as base when passed in options object', (do
}));

stream.on('data', (file) => {
const expected = ['{', '\t"initial": "value",', '\t"name": "Josh",', '\t"pet": {', '\t\t"name": "Indy"', '\t},', '\t"tags": [', '\t\t"awesome"', '\t],', '\t"place": "San Francisco",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '}'].join('\n');
const expected = ['{', '\t"initial": "value",', '\t"name": "Josh",', '\t"pet": {', '\t\t"name": "Indy"', '\t},', '\t"tags": [', '\t\t"awesome",', '\t\t"fun"', '\t],', '\t"place": "San Francisco",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '}'].join('\n');

file.contents.toString().should.eql(expected);

Expand All @@ -336,7 +350,7 @@ it('should use supplied final object to overwrite when passed in options object'
}));

stream.on('data', (file) => {
const expected = ['{', '\t"name": "Josh",', '\t"pet": {', '\t\t"name": "Indy"', '\t},', '\t"tags": [', '\t\t"awesome"', '\t],', '\t"place": "Las Vegas",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '}'].join('\n');
const expected = ['{', '\t"name": "Josh",', '\t"pet": {', '\t\t"name": "Indy"', '\t},', '\t"tags": [', '\t\t"awesome",', '\t\t"fun"', '\t],', '\t"place": "Las Vegas",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '}'].join('\n');

file.contents.toString().should.eql(expected);

Expand All @@ -351,7 +365,7 @@ it('should output a node module when exportModule is true in options object', (d
}));

stream.on('data', (file) => {
const expected = `module.exports = ${['{', '\t"name": "Josh",', '\t"pet": {', '\t\t"name": "Indy"', '\t},', '\t"tags": [', '\t\t"awesome"', '\t],', '\t"place": "San Francisco",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '};'].join('\n')}`;
const expected = `module.exports = ${['{', '\t"name": "Josh",', '\t"pet": {', '\t\t"name": "Indy"', '\t},', '\t"tags": [', '\t\t"awesome",', '\t\t"fun"', '\t],', '\t"place": "San Francisco",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '};'].join('\n')}`;

file.contents.toString().should.eql(expected);

Expand All @@ -372,7 +386,7 @@ it('should use jsonReplacer when stringifying if passed in options object', (don
}));

stream.on('data', (file) => {
const expected = ['{', '\t"name": "Josh",', '\t"tags": [', '\t\t"awesome"', '\t],', '\t"place": "San Francisco",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '}'].join('\n');
const expected = ['{', '\t"name": "Josh",', '\t"tags": [', '\t\t"awesome",', '\t\t"fun"', '\t],', '\t"place": "San Francisco",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '}'].join('\n');

file.contents.toString().should.eql(expected);

Expand All @@ -387,7 +401,7 @@ it('should use jsonSpace when stringifying if passed in options object', (done)
}));

stream.on('data', (file) => {
const expected = ['{', ' "name": "Josh",', ' "pet": {', ' "name": "Indy"', ' },', ' "tags": [', ' "awesome"', ' ],', ' "place": "San Francisco",', ' "settings": {', ' "likesSleep": true', ' }', '}'].join('\n');
const expected = ['{', ' "name": "Josh",', ' "pet": {', ' "name": "Indy"', ' },', ' "tags": [', ' "awesome",', ' "fun"', ' ],', ' "place": "San Francisco",', ' "settings": {', ' "likesSleep": true', ' }', '}'].join('\n');

file.contents.toString().should.eql(expected);

Expand All @@ -402,7 +416,7 @@ it('should concat arrays if enabled in options object', (done) => {
}));

stream.on('data', (file) => {
const expected = ['{', '\t"name": "Josh",', '\t"pet": {', '\t\t"name": "Indy"', '\t},', '\t"tags": [', '\t\t"cool",', '\t\t"awesome"', '\t],', '\t"place": "San Francisco",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '}'].join('\n');
const expected = ['{', '\t"name": "Josh",', '\t"pet": {', '\t\t"name": "Indy"', '\t},', '\t"tags": [', '\t\t"cool",', '\t\t"fun",', '\t\t"awesome"', '\t],', '\t"place": "San Francisco",', '\t"settings": {', '\t\t"likesSleep": true', '\t}', '}'].join('\n');

file.contents.toString().should.eql(expected);

Expand Down

0 comments on commit 98bfe02

Please sign in to comment.