diff --git a/builder/pattern_assembler.js b/builder/pattern_assembler.js index 65e80eb5b..791f4fe06 100644 --- a/builder/pattern_assembler.js +++ b/builder/pattern_assembler.js @@ -167,24 +167,39 @@ throw 'Could not find pattern with key ' + key; } - - var self = this; - function mergeData(obj1, obj2) { - for (var p in obj2) { + /** + * Recursively merge properties of two objects. + * + * @param {Object} obj1 If obj1 has properties obj2 doesn't, add to obj2. + * @param {Object} obj2 This object's properties have priority over obj1. + * @returns {Object} obj2 + */ + function mergeData(obj1, obj2){ + if(typeof obj2 === 'undefined'){ + obj2 = {}; + } + for(var p in obj1){ try { - // Property in destination object set; update its value. - if ( obj2[p].constructor == Object ) { - obj1[p] = self.merge_data(obj1[p], obj2[p]); - - } else { - obj1[p] = obj2[p]; + // Only recurse if obj1[p] is an object. + if(obj1[p].constructor === Object){ + // Requires 2 objects as params; create obj2[p] if undefined. + if(typeof obj2[p] === 'undefined'){ + obj2[p] = {}; + } + obj2[p] = mergeData(obj1[p], obj2[p]); + // Pop when recursion meets a non-object. If obj1[p] is a non-object, + // only copy to undefined obj2[p]. This way, obj2 maintains priority. + } else if(typeof obj2[p] === 'undefined'){ + obj2[p] = obj1[p]; } } catch(e) { // Property in destination object not set; create it and set its value. - obj1[p] = obj2[p]; + if(typeof obj2[p] === 'undefined'){ + obj2[p] = obj1[p]; + } } } - return obj1; + return obj2; } function buildListItems(patternlab){ diff --git a/builder/pseudopattern_hunter.js b/builder/pseudopattern_hunter.js index 9f0a33a4e..2ec038bb6 100644 --- a/builder/pseudopattern_hunter.js +++ b/builder/pseudopattern_hunter.js @@ -45,7 +45,7 @@ var variantFileData = fs.readJSONSync('source/_patterns/' + pseudoPatterns[i]); //extend any existing data with variant data - variantFileData = pattern_assembler.merge_data(variantFileData, currentPattern.jsonFileData); + variantFileData = pattern_assembler.merge_data(currentPattern.jsonFileData, variantFileData); var variantName = pseudoPatterns[i].substring(pseudoPatterns[i].indexOf('~') + 1).split('.')[0]; var patternVariant = new of.oPattern(currentPattern.subdir, currentPattern.fileName + '-' + variantName + '.mustache', variantFileData); diff --git a/test/list_item_hunter_tests.js b/test/list_item_hunter_tests.js index 0da3c9288..7f41cee88 100644 --- a/test/list_item_hunter_tests.js +++ b/test/list_item_hunter_tests.js @@ -100,7 +100,7 @@ test.done(); }, - 'process_list_item_partials overwrites listItem data if local .listitem.json is found' : function(test){ + 'process_list_item_partials overwrites listItem property if that property is in local .listitem.json' : function(test){ //arrange //setup current pattern from what we would have during execution var currentPattern = { @@ -117,7 +117,7 @@ "title": "Two" }, ] - } + } }; var patternlab = { @@ -155,10 +155,134 @@ //act list_item_hunter.process_list_item_partials(currentPattern, patternlab); - + //assert test.equals(currentPattern.extendedTemplate, "OneTwo" ); + test.done(); + }, + + 'process_list_item_partials keeps listItem property if that property is not in local .listitem.json' : function(test){ + //arrange + //setup current pattern from what we would have during execution + var currentPattern = { + "template": "{{#listItems.one}}{{ title }}{{/listItems.one}}", + "extendedTemplate" : "{{#listItems.one}}{{> test-simple }}{{/listItems.one}}", + "key": "test-patternName", + "jsonFileData" : {}, + "patternSpecificListJson" : { + "2": [ + { + "title": "One" + }, + { + "title": "Two" + }, + ] + } + }; + + var patternlab = { + "listitems": { + "1": [ + { + "title": "Foo" + } + ], + "2": [ + { + "title": "Foo" + }, + { + "title": "Bar" + } + ] + }, + "data": { + "link": {}, + "partials": [] + }, + "config": {"debug": false}, + "patterns": [ + { + "template": "{{ title }}", + "extendedTemplate" : "{{ title }}", + "key": "test-simple", + "jsonFileData" : {} + } + ] + }; + + var list_item_hunter = new lih(); + + //act + list_item_hunter.process_list_item_partials(currentPattern, patternlab); + + //assert + test.equals(currentPattern.extendedTemplate, "Foo" ); + + test.done(); + }, + + 'process_list_item_partials uses local listItem property if that property is not set globally' : function(test){ + //arrange + //setup current pattern from what we would have during execution + var currentPattern = { + "template": "{{#listItems.one}}{{ title }}{{/listItems.one}}", + "extendedTemplate" : "{{#listItems.one}}{{> test-simple }}{{/listItems.one}}", + "key": "test-patternName", + "jsonFileData" : {}, + "patternSpecificListJson" : { + "1": [ + { + "title": "One" + } + ], + "2": [ + { + "title": "One" + }, + { + "title": "Two" + }, + ] + } + }; + + var patternlab = { + "listitems": { + "2": [ + { + "title": "Foo" + }, + { + "title": "Bar" + } + ] + }, + "data": { + "link": {}, + "partials": [] + }, + "config": {"debug": false}, + "patterns": [ + { + "template": "{{ title }}", + "extendedTemplate" : "{{ title }}", + "key": "test-simple", + "jsonFileData" : {} + } + ] + }; + + var list_item_hunter = new lih(); + + //act + list_item_hunter.process_list_item_partials(currentPattern, patternlab); + + //assert + test.equals(currentPattern.extendedTemplate, "One" ); + test.done(); }