From ba7cdfdeee32accc07b2d14ac5d37c26a6fbc658 Mon Sep 17 00:00:00 2001 From: Brian Muenzenmeyer Date: Fri, 4 Dec 2015 15:40:01 -0600 Subject: [PATCH] Merge pull request #199 from geoffp/pattern-engines PatternEngines ongoing work, round 3 --- packages/patternengine-node-twig/.eslintrc | 4 +- packages/patternengine-node-twig/.travis.yml | 2 + packages/patternengine-node-twig/CHANGELOG | 10 + .../patternengine-node-twig/CONTRIBUTING.md | 2 +- packages/patternengine-node-twig/README.md | 13 +- .../builder/lineage_hunter.js | 11 +- .../builder/list_item_hunter.js | 17 +- .../builder/media_hunter.js | 2 +- .../builder/object_factory.js | 55 +-- .../builder/parameter_hunter.js | 14 +- .../builder/pattern_assembler.js | 91 +---- .../pattern_engines/engine_mustache.js | 22 +- .../pattern_engines/pattern_engines.js | 31 ++ .../builder/pattern_exporter.js | 2 +- .../builder/patternlab.js | 11 +- .../builder/patternlab_grunt.js | 2 +- .../builder/patternlab_gulp.js | 2 +- .../builder/pseudopattern_hunter.js | 30 +- .../builder/style_modifier_hunter.js | 19 +- .../patternengine-node-twig/builder/util.js | 22 -- .../builder/utilities.js | 65 ++++ .../patternengine-node-twig/package.gulp.json | 24 +- packages/patternengine-node-twig/package.json | 26 +- .../_patterns/00-test/03-styled-atom.mustache | 3 + .../files/_patterns/00-test/04-group.mustache | 6 + .../_patterns/00-test/05-group2.mustache | 6 + .../files/_patterns/00-test/06-mixed.mustache | 6 + .../00-test/07-mixed-params.mustache | 6 + .../00-test/08-bookend-params.mustache | 6 + .../_patterns/00-test/09-bookend.mustache | 6 + .../test/lineage_hunter_tests.js | 42 +-- .../test/list_item_hunter_tests.js | 340 ++++++------------ .../test/pattern_assembler_tests.js | 289 ++++++++++++--- .../test/pattern_engines_tests.js | 53 ++- .../test/style_modifier_hunter_tests.js | 38 ++ 35 files changed, 748 insertions(+), 530 deletions(-) delete mode 100644 packages/patternengine-node-twig/builder/util.js create mode 100644 packages/patternengine-node-twig/builder/utilities.js create mode 100644 packages/patternengine-node-twig/test/files/_patterns/00-test/03-styled-atom.mustache create mode 100644 packages/patternengine-node-twig/test/files/_patterns/00-test/04-group.mustache create mode 100644 packages/patternengine-node-twig/test/files/_patterns/00-test/05-group2.mustache create mode 100644 packages/patternengine-node-twig/test/files/_patterns/00-test/06-mixed.mustache create mode 100644 packages/patternengine-node-twig/test/files/_patterns/00-test/07-mixed-params.mustache create mode 100644 packages/patternengine-node-twig/test/files/_patterns/00-test/08-bookend-params.mustache create mode 100644 packages/patternengine-node-twig/test/files/_patterns/00-test/09-bookend.mustache diff --git a/packages/patternengine-node-twig/.eslintrc b/packages/patternengine-node-twig/.eslintrc index 61dcc48db..9f090e1e2 100644 --- a/packages/patternengine-node-twig/.eslintrc +++ b/packages/patternengine-node-twig/.eslintrc @@ -15,7 +15,7 @@ "all" ], "dot-notation": [ - 2, + 1, { "allowKeywords": true } @@ -29,6 +29,7 @@ "never" ], "guard-for-in": 2, + "key-spacing": 1, "new-cap": 0, "no-bitwise": 2, "no-caller": 2, @@ -52,6 +53,7 @@ "no-sequences": 2, "no-shadow": 2, "no-undef": 2, + "no-underscore-dangle": 1, "no-unused-vars": 2, "no-with": 2, "quotes": [ diff --git a/packages/patternengine-node-twig/.travis.yml b/packages/patternengine-node-twig/.travis.yml index 25b0a05cd..611cfd7d6 100644 --- a/packages/patternengine-node-twig/.travis.yml +++ b/packages/patternengine-node-twig/.travis.yml @@ -1,6 +1,8 @@ language: node_js node_js: + - stable + - 4.0 - 0.12 - 0.11 diff --git a/packages/patternengine-node-twig/CHANGELOG b/packages/patternengine-node-twig/CHANGELOG index 79c3cc66f..6e29f56f0 100644 --- a/packages/patternengine-node-twig/CHANGELOG +++ b/packages/patternengine-node-twig/CHANGELOG @@ -1,5 +1,15 @@ THIS CHANGELOG IS AN ATTEMPT TO DOCUMENT CHANGES TO THIS PROJECT. +PL-node-v0.15.1 +- FIX: Resolve issue with styleModifiers not being replaced when the partial has spaces in it. +- ADD: Support multiple styleModifier classes using the | pipe syntax +- FIX: Resolve issue with styleModifiers not being applied correctly when mixed with pattern parameters +- THX: Thanks @theorise for the issue reports! + +PL-node-v0.15.0 +- CHG: Updated package.json devDependencies for Node 4.X and 5.X support. +- CHG: Updated package.gulp.json devDependencies for Node 4.X and 5.X support. + PL-node-v0.14.0 - ADD: Support for style modifiers - ADD: Support for styleGuideExcludes diff --git a/packages/patternengine-node-twig/CONTRIBUTING.md b/packages/patternengine-node-twig/CONTRIBUTING.md index dcaef2d3d..87af6849d 100644 --- a/packages/patternengine-node-twig/CONTRIBUTING.md +++ b/packages/patternengine-node-twig/CONTRIBUTING.md @@ -1,7 +1,7 @@ #Contributing to Patternlab - Node If you'd like to contribute to patternlab - node, please do so! There is always a lot of ground to cover, with patternlab - php being so feature-rich. -No pull request is too small. +No pull request is too small. Check out any [up for grabs issues](https://github.com/pattern-lab/patternlab-node/labels/up%20for%20grabs) as a good way to get your feet wet. ##Guidelines 1. Please keep your pull requests concise and limited to **ONE** substantive change at a time. diff --git a/packages/patternengine-node-twig/README.md b/packages/patternengine-node-twig/README.md index a3a7d742a..c628bf065 100644 --- a/packages/patternengine-node-twig/README.md +++ b/packages/patternengine-node-twig/README.md @@ -10,14 +10,12 @@ This repository contains the vanilla builder logic, grunt and gulp configuration * Download the [latest release of patternlab-node](https://github.com/pattern-lab/patternlab-node/releases/latest) from Github * Via npm, run `npm install patternlab-node` (Note this will auto install the grunt version currently. see below) -* **NOTE** Node version 4.X is not officially supported yet, citing [a lot of Windows issues](https://github.com/nodejs/node-gyp/issues/629), including [mine](https://github.com/pattern-lab/patternlab-node/issues/162). Upgrade node at your own risk until otherwise stated. +* **NOTE** Node version 4.X and 5.X have tentative support, citing [a lot of Windows issues](https://github.com/nodejs/node-gyp/issues/629), including [mine](https://github.com/pattern-lab/patternlab-node/issues/162). Upgrade node at your own risk until otherwise stated. I've tried to catalog some issues and troubleshooting steps on the [wiki](https://github.com/pattern-lab/patternlab-node/wiki/Windows-Issues). ### Choose Your Adventure! Now Vanilla, Grunt & Gulp This repository ships with two `package.json` files, a `Gruntfile.js`, and a `gulpfile.js`. The default is grunt currently. The core builder is not dependent on either. -**HELP WANTED** Please help me test both of the configurations by [reporting](https://github.com/pattern-lab/patternlab-node/blob/dev/CONTRIBUTING.md) any issues encountered. - ### Getting Started - Grunt To run patternlab-node using grunt, do the following in the directory you downloaded and extracted the zipped release: @@ -27,7 +25,7 @@ To run patternlab-node using grunt, do the following in the directory you downlo * Not deleting `builder/patternlab_gulp.js` may cause a harmless error when running grunt. Delete it. 3. Run `grunt` or `grunt serve` from the command line -This creates all patterns, the styleguide, and the pattern lab site. It's strongly recommended to run `grunt serve` to see have BrowserSync spin up and serve the files to you. +This creates all patterns, the styleguide, and the pattern lab site. It's strongly recommended to run `grunt serve` to have BrowserSync spin up and serve the files to you. ### Getting Started - Gulp @@ -51,7 +49,7 @@ It's not expected to toggle between the two build systems, but for those migrati ### Upgrading -You can find some simple upgrade documenation in it's current home here (unreleased but confirmed to work): [https://github.com/pattern-lab/website/blob/dev/patternlabsite/docs/node/upgrading.md](https://github.com/pattern-lab/website/blob/dev/patternlabsite/docs/node/upgrading.md) +You can find instructions on how to upgrade from version to version of Pattern Lab Node here: [https://github.com/pattern-lab/patternlab-node/wiki/Upgrading](https://github.com/pattern-lab/patternlab-node/wiki/Upgrading) ### Command Line Interface @@ -214,6 +212,11 @@ Once rendered, it looks like this: ``` +You may also specify multiple classes using a pipe character (|). + +``` +{{> atoms-message:error|is-on }} +``` diff --git a/packages/patternengine-node-twig/builder/lineage_hunter.js b/packages/patternengine-node-twig/builder/lineage_hunter.js index 5109c03ef..dc13a859c 100644 --- a/packages/patternengine-node-twig/builder/lineage_hunter.js +++ b/packages/patternengine-node-twig/builder/lineage_hunter.js @@ -1,6 +1,6 @@ -/* - * patternlab-node - v0.14.0 - 2015 - * +/* + * patternlab-node - v0.15.1 - 2015 + * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. * @@ -17,9 +17,12 @@ var pa = require('./pattern_assembler'); var pattern_assembler = new pa(); + var config = require('../config.json'); //find the {{> template-name }} within patterns - console.log('===\n', pattern, '\n==='); + if (config.debug) { + console.log('===\n', pattern, '\n==='); + } var matches = pattern.findPartials(); if(matches !== null){ matches.forEach(function(match, index, matches){ diff --git a/packages/patternengine-node-twig/builder/list_item_hunter.js b/packages/patternengine-node-twig/builder/list_item_hunter.js index ba9f8097c..75118e2ce 100644 --- a/packages/patternengine-node-twig/builder/list_item_hunter.js +++ b/packages/patternengine-node-twig/builder/list_item_hunter.js @@ -1,6 +1,6 @@ -/* - * patternlab-node - v0.14.0 - 2015 - * +/* + * patternlab-node - v0.15.1 - 2015 + * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. * @@ -16,6 +16,7 @@ var extend = require('util')._extend, pa = require('./pattern_assembler'), smh = require('./style_modifier_hunter'), + plutils = require('./utilities'), config = require('../config.json'), of = require('./object_factory'); @@ -42,13 +43,15 @@ var repeatedBlockTemplate = []; var repeatedBlockHtml = ''; for(var i = 0; i < items.indexOf(loopNumberString); i++){ - console.log('adding', patternBlock, 'to repeatedBlockTemplate'); + if (config.debug) { + console.log('list item(s) in pattern', pattern.patternName, 'adding', patternBlock, 'to repeatedBlockTemplate'); + } repeatedBlockTemplate.push(patternBlock); } //check for a local listitems.json file var listData = JSON.parse(JSON.stringify(patternlab.listitems)); - listData = pattern_assembler.merge_data(listData, pattern.listitems); + listData = plutils.mergeData(listData, pattern.listitems); //iterate over each copied block, rendering its contents along with pattenlab.listitems[i] for(var i = 0; i < repeatedBlockTemplate.length; i++){ @@ -61,8 +64,8 @@ var globalData = JSON.parse(JSON.stringify(patternlab.data)); var localData = JSON.parse(JSON.stringify(pattern.jsonFileData)); - var allData = pattern_assembler.merge_data(globalData, localData); - allData = pattern_assembler.merge_data(allData, itemData != undefined ? itemData[i] : {}); //itemData could be undefined if the listblock contains no partial, just markup + var allData = plutils.mergeData(globalData, localData); + allData = plutils.mergeData(allData, itemData != undefined ? itemData[i] : {}); //itemData could be undefined if the listblock contains no partial, just markup allData.link = extend({}, patternlab.data.link); //check for partials within the repeated block diff --git a/packages/patternengine-node-twig/builder/media_hunter.js b/packages/patternengine-node-twig/builder/media_hunter.js index 9eddbbac4..d5ada91ce 100644 --- a/packages/patternengine-node-twig/builder/media_hunter.js +++ b/packages/patternengine-node-twig/builder/media_hunter.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.14.0 - 2015 + * patternlab-node - v0.15.1 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. diff --git a/packages/patternengine-node-twig/builder/object_factory.js b/packages/patternengine-node-twig/builder/object_factory.js index 54b910961..6a9f646e4 100644 --- a/packages/patternengine-node-twig/builder/object_factory.js +++ b/packages/patternengine-node-twig/builder/object_factory.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.14.0 - 2015 + * patternlab-node - v0.15.1 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. @@ -19,7 +19,7 @@ // oPattern properties - var oPattern = function(abspath, subdir, filename, data){ + var oPattern = function(abspath, subdir, filename, data) { if (config.debug) { console.log('=== NEW OPATTERN.', '\nabsPath:', abspath, '\nsubdir:', subdir, '\nfilename:', filename, '\ndata:\n', data); } @@ -50,27 +50,38 @@ // oPattern methods - // render method on oPatterns; this acts as a proxy for the PatternEngine's - // render function - oPattern.prototype.render = function (data, partials) { - if (config.debug && this.isPseudoPattern) { - console.log('===', this.name + ' IS A PSEUDO-PATTERN ==='); + oPattern.prototype = { + + // render method on oPatterns; this acts as a proxy for the PatternEngine's + // render function + render: function (data, partials) { + if (config.debug && this.isPseudoPattern) { + console.log('===', this.name + ' IS A PSEUDO-PATTERN ==='); + } + return this.engine.renderPattern(this.extendedTemplate, data, partials); + }, + + // the finders all delegate to the PatternEngine, which also encapsulates all + // appropriate regexes + findPartials: function () { + return this.engine.findPartials(this); + }, + + findPartialsWithStyleModifiers: function () { + return this.engine.findPartialsWithStyleModifiers(this); + }, + + findPartialsWithPatternParameters: function () { + return this.engine.findPartialsWithPatternParameters(this); + }, + + findListItems: function () { + return this.engine.findListItems(this); + }, + + getPartialKey: function (partialString) { + return this.engine.getPartialKey(this, partialString); } - return this.engine.renderPattern(this.extendedTemplate, data, partials); - }; - // the finders all delegate to the PatternEngine, which also encapsulates all - // appropriate regexes - oPattern.prototype.findPartials = function () { - return this.engine.findPartials(this); - }; - oPattern.prototype.findPartialsWithStyleModifiers = function () { - return this.engine.findPartialsWithStyleModifiers(this); - }; - oPattern.prototype.findPartialsWithPatternParameters = function () { - return this.engine.findPartialsWithPatternParameters(this); - }; - oPattern.prototype.findListItems = function () { - return this.engine.findListItems(this); }; // oPattern static methods diff --git a/packages/patternengine-node-twig/builder/parameter_hunter.js b/packages/patternengine-node-twig/builder/parameter_hunter.js index ef70bead5..fe2d61ea7 100644 --- a/packages/patternengine-node-twig/builder/parameter_hunter.js +++ b/packages/patternengine-node-twig/builder/parameter_hunter.js @@ -1,6 +1,6 @@ -/* - * patternlab-node - v0.14.0 - 2015 - * +/* + * patternlab-node - v0.15.1 - 2015 + * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. * @@ -15,8 +15,8 @@ var extend = require('util')._extend, pa = require('./pattern_assembler'), - mustache = require('mustache'), smh = require('./style_modifier_hunter'), + plutils = require('./utilities'), style_modifier_hunter = new smh(), pattern_assembler = new pa(); @@ -28,6 +28,8 @@ //find the partial's name and retrieve it var partialName = pMatch.match(/([\w\-\.\/~]+)/g)[0]; var partialPattern = pattern_assembler.get_pattern_by_key(partialName, patternlab); + //if we retrieved a pattern we should make sure that its extendedTemplate is reset. looks to fix #190 + partialPattern.extendedTemplate = partialPattern.template; if(patternlab.config.debug){ console.log('found patternParameters for ' + partialName); @@ -44,8 +46,8 @@ var globalData = JSON.parse(JSON.stringify(patternlab.data)); var localData = JSON.parse(JSON.stringify(pattern.jsonFileData || {})); - var allData = pattern_assembler.merge_data(globalData, localData); - allData = pattern_assembler.merge_data(allData, paramData); + var allData = plutils.mergeData(globalData, localData); + allData = plutils.mergeData(allData, paramData); //if partial has style modifier data, replace the styleModifier value if(pattern.stylePartials && pattern.stylePartials.length > 0){ diff --git a/packages/patternengine-node-twig/builder/pattern_assembler.js b/packages/patternengine-node-twig/builder/pattern_assembler.js index e488d8a73..52f975f9b 100644 --- a/packages/patternengine-node-twig/builder/pattern_assembler.js +++ b/packages/patternengine-node-twig/builder/pattern_assembler.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.14.0 - 2015 + * patternlab-node - v0.15.1 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. @@ -15,19 +15,10 @@ var fs = require('fs-extra'), of = require('./object_factory'), - path = require('path'), + plutils = require('./utilities'), patternEngines = require('./pattern_engines/pattern_engines'), config = fs.readJSONSync('./config.json'); - function isObjectEmpty(obj) { - for(var prop in obj) { - if(obj.hasOwnProperty(prop)) - return false; - } - - return true; - } - function setState(pattern, patternlab){ if(patternlab.config.patternStates[pattern.patternName]){ pattern.patternState = patternlab.config.patternStates[pattern.patternName]; @@ -74,24 +65,6 @@ } } - // takes a filename string, not a full path; a basename (plus extension) - // ignore _underscored patterns, dotfiles, and anything not recognized by a - // loaded pattern engine. Pseudo-pattern .json files ARE considered to be - // pattern files! - function isPatternFile(filename) { - // skip hidden patterns/files without a second thought - var extension = path.extname(filename); - if(filename.charAt(0) === '.' || - filename.charAt(0) === '_' || - (extension === '.json' && filename.indexOf('~') === -1)) { - return false; - } - - // not a hidden pattern, let's dig deeper - var supportedPatternFileExtensions = patternEngines.getSupportedFileExtensions(); - return (supportedPatternFileExtensions.lastIndexOf(extension) !== -1); - } - function processPatternIterative(file, patternlab){ var fs = require('fs-extra'), of = require('./object_factory'), @@ -107,7 +80,7 @@ } // skip non-pattern files - if (!isPatternFile(filename, patternlab)) { return; } + if (!patternEngines.isPatternFile(filename, patternlab)) { return; } if (config.debug) { console.log('processPatternIterative:', 'found pattern', file); } @@ -116,7 +89,7 @@ var currentPattern = new of.oPattern(file, subdir, filename); //if file is named in the syntax for variants - if(ext === '.json' && filename.indexOf('~') > -1){ + if(patternEngines.isPseudoPatternJSON(filename)){ //add current pattern to patternlab object with minimal data //processPatternRecursive() will run find_pseudopatterns() to fill out //the object in the next diveSync @@ -172,6 +145,8 @@ addPattern(currentPattern, patternlab); } + + function processPatternRecursive(file, patternlab, additionalData){ var lh = require('./lineage_hunter'), ph = require('./parameter_hunter'), @@ -219,7 +194,7 @@ //do something with the regular old partials for(i = 0; i < foundPatternPartials.length; i++){ - var partialKey = foundPatternPartials[i].replace(/{{>([ ])?([\w\-\.\/~]+)(:[A-z-_]+)?(?:\:[A-Za-z0-9-]+)?(?:(| )\(.*)?([ ])?}}/g, '$2'); + var partialKey = currentPattern.getPartialKey(foundPatternPartials[i]); var partialPath; @@ -274,40 +249,7 @@ throw 'Could not find pattern with key ' + key; } - /** - * 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 { - // 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. - if(typeof obj2[p] === 'undefined'){ - obj2[p] = obj1[p]; - } - } - } - return obj2; - } + function buildListItems(container){ //combine all list items into one structure @@ -317,7 +259,7 @@ list.push(container.listitems[item]); } } - container.listItemArray = shuffle(list); + container.listItemArray = plutils.shuffle(list); for(var i = 1; i <= container.listItemArray.length; i++){ var tempItems = []; @@ -333,11 +275,7 @@ } } - //http://stackoverflow.com/questions/6274339/how-can-i-shuffle-an-array-in-javascript - function shuffle(o){ - for(var j, x, i = o.length; i; j = Math.floor(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x); - return o; - } + return { find_pattern_partials: function(pattern){ @@ -370,16 +308,9 @@ get_pattern_by_key: function(key, patternlab){ return getpatternbykey(key, patternlab); }, - merge_data: function(existingData, newData){ - return mergeData(existingData, newData); - }, combine_listItems: function(patternlab){ buildListItems(patternlab); - }, - is_object_empty: function(obj){ - return isObjectEmpty(obj); - }, - is_pattern_file: isPatternFile + } }; }; diff --git a/packages/patternengine-node-twig/builder/pattern_engines/engine_mustache.js b/packages/patternengine-node-twig/builder/pattern_engines/engine_mustache.js index 23692ae5d..a13043a87 100644 --- a/packages/patternengine-node-twig/builder/pattern_engines/engine_mustache.js +++ b/packages/patternengine-node-twig/builder/pattern_engines/engine_mustache.js @@ -19,10 +19,11 @@ engineFileExtension: '.mustache', // regexes, stored here so they're only compiled once - findPartialsRE: /{{>([ ])?([A-Za-z0-9-]+)(?:\:[A-Za-z0-9-]+)?(?:(| )\(.*)?([ ])?}}/g, - findPartialsWithStyleModifiersRE: /{{>([ ])?([\w\-\.\/~]+)(?!\()(\:[A-Za-z0-9-_]+)+(?:(| )\(.*)?([ ])?}}/g, - findPartialsWithPatternParametersRE: /{{>([ ])?([\w\-\.\/~]+)(?:\:[A-Za-z0-9-_]+)?(?:(| )\(.*)+([ ])?}}/g, + findPartialsRE: /{{>\s*((?:\d+-[\w-]+\/)+(\d+-[\w-]+(\.\w+)?)|[A-Za-z0-9-]+)(\:[\w-]+)?(\(\s*\w+\s*:\s*(?:'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*")\))?\s*}}/g, + findPartialsWithStyleModifiersRE: /{{>([ ])?([\w\-\.\/~]+)(?!\()(\:[A-Za-z0-9-_|]+)+(?:(| )\(.*)?([ ])?}}/g, + findPartialsWithPatternParametersRE: /{{>([ ])?([\w\-\.\/~]+)(?:\:[A-Za-z0-9-_|]+)?(?:(| )\(.*)+([ ])?}}/g, findListItemsRE: /({{#( )?)(list(I|i)tems.)(one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen|eighteen|nineteen|twenty)( )?}}/g, + getPartialKeyRE: /{{>([ ])?([\w\-\.\/~]+)(:[A-z-_|]+)?(?:\:[A-Za-z0-9-_]+)?(?:(| )\(.*)?([ ])?}}/g, // render it renderPattern: function renderPattern(template, data, partials) { @@ -37,18 +38,25 @@ var matches = pattern.template.match(this.findPartialsRE); return matches; }, - findPartialsWithStyleModifiers: function(pattern){ + findPartialsWithStyleModifiers: function(pattern) { var matches = pattern.template.match(this.findPartialsWithStyleModifiersRE); return matches; }, - // returns any patterns that match {{> value(foo:"bar") }} or {{> value:mod(foo:"bar") }} within the pattern - findPartialsWithPatternParameters: function(pattern){ + // returns any patterns that match {{> value(foo:"bar") }} or {{> + // value:mod(foo:"bar") }} within the pattern + findPartialsWithPatternParameters: function(pattern) { var matches = pattern.template.match(this.findPartialsWithPatternParametersRE); return matches; }, - findListItems: function(pattern){ + findListItems: function(pattern) { var matches = pattern.template.match(this.findListItemsRE); return matches; + }, + // given a pattern, and a partial string, tease out the "pattern key" and + // return it. + getPartialKey: function(pattern, partialString) { + var partialKey = partialString.replace(this.getPartialKeyRE, '$2'); + return partialKey; } }; diff --git a/packages/patternengine-node-twig/builder/pattern_engines/pattern_engines.js b/packages/patternengine-node-twig/builder/pattern_engines/pattern_engines.js index 8a0711f99..13ef654f0 100644 --- a/packages/patternengine-node-twig/builder/pattern_engines/pattern_engines.js +++ b/packages/patternengine-node-twig/builder/pattern_engines/pattern_engines.js @@ -12,6 +12,8 @@ (function () { 'use strict'; + var path = require('path'); + // list of supported pattern engines var supportedPatternEngineNames = [ 'mustache', @@ -42,6 +44,7 @@ // accordingly return 'mustache'; }, + getEngineForPattern: function (pattern) { if (pattern.isPseudoPattern) { return this.getEngineForPattern(pattern.basePattern); @@ -50,15 +53,43 @@ return this[engineName]; } }, + getSupportedFileExtensions: function () { var engineNames = Object.keys(PatternEngines); return engineNames.map(function (engineName) { return PatternEngines[engineName].engineFileExtension; }); }, + isFileExtensionSupported: function (fileExtension) { var supportedExtensions = PatternEngines.getSupportedFileExtensions(); return (supportedExtensions.lastIndexOf(fileExtension) !== -1); + }, + + // given a filename, return a boolean: whether or not the filename indicates + // that the file is pseudopattern JSON + isPseudoPatternJSON: function (filename) { + var extension = path.extname(filename); + return (extension === '.json' && filename.indexOf('~') > -1); + }, + + // takes a filename string, not a full path; a basename (plus extension) + // ignore _underscored patterns, dotfiles, and anything not recognized by a + // loaded pattern engine. Pseudo-pattern .json files ARE considered to be + // pattern files! + isPatternFile: function (filename) { + // skip hidden patterns/files without a second thought + var extension = path.extname(filename); + if(filename.charAt(0) === '.' || + filename.charAt(0) === '_' || + (extension === '.json' && !PatternEngines.isPseudoPatternJSON(filename))) { + return false; + } + + // not a hidden pattern, let's dig deeper + var supportedPatternFileExtensions = PatternEngines.getSupportedFileExtensions(); + return (supportedPatternFileExtensions.lastIndexOf(extension) !== -1 || + PatternEngines.isPseudoPatternJSON(filename)); } }); diff --git a/packages/patternengine-node-twig/builder/pattern_exporter.js b/packages/patternengine-node-twig/builder/pattern_exporter.js index 816a1d0ab..90915ec86 100644 --- a/packages/patternengine-node-twig/builder/pattern_exporter.js +++ b/packages/patternengine-node-twig/builder/pattern_exporter.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.14.0 - 2015 + * patternlab-node - v0.15.1 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. diff --git a/packages/patternengine-node-twig/builder/patternlab.js b/packages/patternengine-node-twig/builder/patternlab.js index 1b64e990e..2d9f5f940 100644 --- a/packages/patternengine-node-twig/builder/patternlab.js +++ b/packages/patternengine-node-twig/builder/patternlab.js @@ -1,6 +1,6 @@ -/* - * patternlab-node - v0.14.0 - 2015 - * +/* + * patternlab-node - v0.15.1 - 2015 + * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. * @@ -13,14 +13,13 @@ var patternlab_engine = function () { var path = require('path'), fs = require('fs-extra'), - extend = require('util')._extend, diveSync = require('diveSync'), - glob = require('glob'), of = require('./object_factory'), pa = require('./pattern_assembler'), mh = require('./media_hunter'), pe = require('./pattern_exporter'), he = require('html-entities').AllHtmlEntities, + plutils = require('./utilities'), patternlab = {}; patternlab.package = fs.readJSONSync('./package.json'); @@ -122,7 +121,7 @@ var patternlab_engine = function () { patternlab.patterns.forEach(function(pattern, index, patterns){ //render the pattern, but first consolidate any data we may have var allData = JSON.parse(JSON.stringify(patternlab.data)); - allData = pattern_assembler.merge_data(allData, pattern.jsonFileData); + allData = plutils.mergeData(allData, pattern.jsonFileData); pattern.patternPartial = pattern_assembler.renderPattern(pattern, allData); diff --git a/packages/patternengine-node-twig/builder/patternlab_grunt.js b/packages/patternengine-node-twig/builder/patternlab_grunt.js index 7cb6bb7d7..843dd07f1 100644 --- a/packages/patternengine-node-twig/builder/patternlab_grunt.js +++ b/packages/patternengine-node-twig/builder/patternlab_grunt.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.14.0 - 2015 + * patternlab-node - v0.15.1 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. diff --git a/packages/patternengine-node-twig/builder/patternlab_gulp.js b/packages/patternengine-node-twig/builder/patternlab_gulp.js index eceabee57..d4014cb79 100644 --- a/packages/patternengine-node-twig/builder/patternlab_gulp.js +++ b/packages/patternengine-node-twig/builder/patternlab_gulp.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.14.0 - 2015 + * patternlab-node - v0.15.1 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. diff --git a/packages/patternengine-node-twig/builder/pseudopattern_hunter.js b/packages/patternengine-node-twig/builder/pseudopattern_hunter.js index 7615d03d6..937dffa4f 100644 --- a/packages/patternengine-node-twig/builder/pseudopattern_hunter.js +++ b/packages/patternengine-node-twig/builder/pseudopattern_hunter.js @@ -1,6 +1,6 @@ -/* - * patternlab-node - v0.14.0 - 2015 - * +/* + * patternlab-node - v0.15.1 - 2015 + * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. * @@ -20,8 +20,7 @@ pa = require('./pattern_assembler'), lh = require('./lineage_hunter'), of = require('./object_factory'), - patternEngines = require('./pattern_engines/pattern_engines'), - mustache = require('mustache'); + plutils = require('./utilities'); var pattern_assembler = new pa(); var lineage_hunter = new lh(); @@ -40,6 +39,7 @@ for(var i = 0; i < pseudoPatterns.length; i++){ if(patternlab.config.debug){ + debugger; console.log('found pseudoPattern variant of ' + currentPattern.key); } @@ -47,24 +47,24 @@ var variantFileData = fs.readJSONSync('source/_patterns/' + pseudoPatterns[i]); //extend any existing data with variant data - variantFileData = pattern_assembler.merge_data(currentPattern.jsonFileData, variantFileData); + variantFileData = plutils.mergeData(currentPattern.jsonFileData, variantFileData); - // GTP: mustache-specific stuff here var variantName = pseudoPatterns[i].substring(pseudoPatterns[i].indexOf('~') + 1).split('.')[0]; var variantFilePath = 'source/_patterns/' + currentPattern.subdir + '/' + currentPattern.fileName + '~' + variantName + '.json'; var variantFileName = currentPattern.fileName + '-' + variantName + '.'; - var patternVariant = new of.oPattern(variantFilePath, currentPattern.subdir, variantFileName, variantFileData); + var patternVariant = of.oPattern.create(variantFilePath, currentPattern.subdir, variantFileName, variantFileData, { + //use the same template as the non-variant + template: currentPattern.template, + extendedTemplate: currentPattern.extendedTemplate, + isPseudoPattern: true, + basePattern: currentPattern, + // use the same template engine as the non-variant + engine: currentPattern.engine + }); //see if this file has a state pattern_assembler.setPatternState(patternVariant, patternlab); - //use the same template as the non-variant - patternVariant.template = currentPattern.template; - patternVariant.extendedTemplate = currentPattern.extendedTemplate; - patternVariant.isPseudoPattern = true; - patternVariant.basePattern = currentPattern; - patternVariant.engine = patternVariant.basePattern.engine; - //find pattern lineage lineage_hunter.find_lineage(patternVariant, patternlab); diff --git a/packages/patternengine-node-twig/builder/style_modifier_hunter.js b/packages/patternengine-node-twig/builder/style_modifier_hunter.js index 38e0de440..9baa6f0aa 100644 --- a/packages/patternengine-node-twig/builder/style_modifier_hunter.js +++ b/packages/patternengine-node-twig/builder/style_modifier_hunter.js @@ -1,10 +1,10 @@ -/* - * patternlab-node - v0.14.0 - 2015 - * +/* + * patternlab-node - v0.15.1 - 2015 + * * Brian Muenzenmeyer, and the web community. - * Licensed under the MIT license. - * - * Many thanks to Brad Frost and Dave Olsen for inspiration, encouragement, and advice. + * Licensed under the MIT license. + * + * Many thanks to Brad Frost and Dave Olsen for inspiration, encouragement, and advice. * */ @@ -16,15 +16,18 @@ function consumestylemodifier(pattern, partial, patternlab){ //extract the classname from the stylemodifier which comes in the format of :className - var styleModifier = partial.match(/:([\w\-_])+/g) ? partial.match(/:([\w\-_])+/g)[0].slice(1) : null; + var styleModifier = partial.match(/:([\w\-_|])+/g) ? partial.match(/:([\w\-_|])+/g)[0].slice(1) : null; if(styleModifier){ + //replace the special character pipe | used to separate multiple classes with a space + styleModifier = styleModifier.replace(/\|/g, ' '); + if(patternlab.config.debug){ console.log('found partial styleModifier within pattern ' + pattern.key); } //replace the stylemodifier placeholder with the class name - pattern.extendedTemplate = pattern.extendedTemplate.replace('{{styleModifier}}', styleModifier); + pattern.extendedTemplate = pattern.extendedTemplate.replace(/{{[ ]?styleModifier[ ]?}}/i, styleModifier); } } diff --git a/packages/patternengine-node-twig/builder/util.js b/packages/patternengine-node-twig/builder/util.js deleted file mode 100644 index 53ab39a3b..000000000 --- a/packages/patternengine-node-twig/builder/util.js +++ /dev/null @@ -1,22 +0,0 @@ -/* - * patternlab-node - v0.14.0 - 2015 - * - * Brian Muenzenmeyer, Geoffrey Pursell and the web community. - * Licensed under the MIT license. - * - * Many thanks to Brad Frost and Dave Olsen for inspiration, encouragement, and advice. - * - */ - -(function () { - var path = require('path'); - - var util = { - // takes a string of the filename or path, and will tell you if it refers to - isPseudoPattern: function () { - - } - }; - - module.exports = util; -}()); diff --git a/packages/patternengine-node-twig/builder/utilities.js b/packages/patternengine-node-twig/builder/utilities.js new file mode 100644 index 000000000..64d5190ed --- /dev/null +++ b/packages/patternengine-node-twig/builder/utilities.js @@ -0,0 +1,65 @@ +/* + * patternlab-node - v0.14.0 - 2015 + * + * Brian Muenzenmeyer, Geoffrey Pursell and the web community. + * Licensed under the MIT license. + * + * Many thanks to Brad Frost and Dave Olsen for inspiration, encouragement, and advice. + * + */ + +(function () { + var path = require('path'); + + var util = { + // http://stackoverflow.com/questions/6274339/how-can-i-shuffle-an-array-in-javascript + shuffle: function (o) { + for(var j, x, i = o.length; i; j = Math.floor(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x); + return o; + }, + + /** + * 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 + */ + mergeData: function (obj1, obj2) { + if(typeof obj2 === 'undefined'){ + obj2 = {}; + } + for(var p in obj1){ + try { + // 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] = util.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. + if(typeof obj2[p] === 'undefined'){ + obj2[p] = obj1[p]; + } + } + } + return obj2; + }, + + isObjectEmpty: function (obj) { + for(var prop in obj) { + if(obj.hasOwnProperty(prop)) { return false; } + } + return true; + } + }; + + module.exports = util; +}()); diff --git a/packages/patternengine-node-twig/package.gulp.json b/packages/patternengine-node-twig/package.gulp.json index 1ee3ab48b..099c8d907 100644 --- a/packages/patternengine-node-twig/package.gulp.json +++ b/packages/patternengine-node-twig/package.gulp.json @@ -1,34 +1,36 @@ { "name": "patternlab-node", "description": "Pattern Lab is a collection of tools to help you create atomic design systems. This is the node command line interface (CLI).", - "version": "0.14.0", + "version": "0.15.1", "devDependencies": { - "browser-sync": "^2.8.2", - "del": "^1.2.1", - "diveSync": "^0.2.1", - "fs-extra": "^0.14.0", - "glob": "^4.3.5", - "gulp": "^3.8.8", - "gulp-connect": "^2.0.6", + "browser-sync": "^2.10.0", + "del": "^2.0.2", + "diveSync": "^0.3.0", + "fs-extra": "^0.26.2", + "glob": "^6.0.1", + "gulp": "^3.9.0", + "gulp-connect": "^2.2.0", "gulp-copy": "0.0.2", - "gulp-header": "^1.0.5", + "gulp-header": "^1.7.1", "gulp-load": "^0.1.1", "gulp-nodeunit": "0.0.5", "gulp-strip-banner": "0.0.2", - "html-entities": "^1.1.1", - "mustache": "^1.0.0" + "html-entities": "^1.2.0", + "mustache": "^2.2.0" }, "keywords": [ "Pattern Lab", "Atomic Web Design", "Node", "Grunt", + "Gulp", "Javascript" ], "repository": { "type": "git", "url": "git://github.com/pattern-lab/patternlab-node.git" }, + "bugs": "https://github.com/pattern-lab/patternlab-node/issues", "author": "Brian Muenzenmeyer", "license": "MIT", "scripts": { diff --git a/packages/patternengine-node-twig/package.json b/packages/patternengine-node-twig/package.json index 75ab5d5e8..8d3953d22 100644 --- a/packages/patternengine-node-twig/package.json +++ b/packages/patternengine-node-twig/package.json @@ -1,33 +1,35 @@ { "name": "patternlab-node", "description": "Pattern Lab is a collection of tools to help you create atomic design systems. This is the node command line interface (CLI).", - "version": "0.14.0", + "version": "0.15.1", "devDependencies": { - "bs-html-injector": "^2.0.4", - "diveSync": "^0.2.1", - "fs-extra": "^0.24.0", - "glob": "^4.3.5", - "grunt": "~0.4.0", - "grunt-browser-sync": "^2.1.3", - "grunt-contrib-concat": "^0.5.0", - "grunt-contrib-copy": "^0.7.0", + "bs-html-injector": "^3.0.0", + "diveSync": "^0.3.0", + "fs-extra": "^0.26.2", + "glob": "^6.0.1", + "grunt": "~0.4.5", + "grunt-browser-sync": "^2.2.0", + "grunt-contrib-concat": "^0.5.1", + "grunt-contrib-copy": "^0.8.2", "grunt-contrib-nodeunit": "^0.4.1", "grunt-contrib-watch": "^0.6.1", - "html-entities": "^1.1.1", - "matchdep": "^0.3.0", - "mustache": "^1.0.0" + "html-entities": "^1.2.0", + "matchdep": "^1.0.0", + "mustache": "^2.2.0" }, "keywords": [ "Pattern Lab", "Atomic Web Design", "Node", "Grunt", + "Gulp", "Javascript" ], "repository": { "type": "git", "url": "git://github.com/pattern-lab/patternlab-node.git" }, + "bugs": "https://github.com/pattern-lab/patternlab-node/issues", "author": "Brian Muenzenmeyer", "license": "MIT", "scripts": { diff --git a/packages/patternengine-node-twig/test/files/_patterns/00-test/03-styled-atom.mustache b/packages/patternengine-node-twig/test/files/_patterns/00-test/03-styled-atom.mustache new file mode 100644 index 000000000..b736c06aa --- /dev/null +++ b/packages/patternengine-node-twig/test/files/_patterns/00-test/03-styled-atom.mustache @@ -0,0 +1,3 @@ + + {{message}} + diff --git a/packages/patternengine-node-twig/test/files/_patterns/00-test/04-group.mustache b/packages/patternengine-node-twig/test/files/_patterns/00-test/04-group.mustache new file mode 100644 index 000000000..24ee58979 --- /dev/null +++ b/packages/patternengine-node-twig/test/files/_patterns/00-test/04-group.mustache @@ -0,0 +1,6 @@ +
+ {{> test-styled-atom:test_1 }} + {{> test-styled-atom:test_2 }} + {{> test-styled-atom:test_3 }} + {{> test-styled-atom:test_4 }} +
diff --git a/packages/patternengine-node-twig/test/files/_patterns/00-test/05-group2.mustache b/packages/patternengine-node-twig/test/files/_patterns/00-test/05-group2.mustache new file mode 100644 index 000000000..a3986a1b5 --- /dev/null +++ b/packages/patternengine-node-twig/test/files/_patterns/00-test/05-group2.mustache @@ -0,0 +1,6 @@ +
+ {{> test-styled-atom:test_1(message: "1" ) }} + {{> test-styled-atom:test_2(message: "2" ) }} + {{> test-styled-atom:test_3(message: "3" ) }} + {{> test-styled-atom:test_4(message: "4" ) }} +
diff --git a/packages/patternengine-node-twig/test/files/_patterns/00-test/06-mixed.mustache b/packages/patternengine-node-twig/test/files/_patterns/00-test/06-mixed.mustache new file mode 100644 index 000000000..b0c6d610f --- /dev/null +++ b/packages/patternengine-node-twig/test/files/_patterns/00-test/06-mixed.mustache @@ -0,0 +1,6 @@ +
+ {{> test-styled-atom }} + {{> test-styled-atom:test_2 }} + {{> test-styled-atom:test_3 }} + {{> test-styled-atom:test_4 }} +
diff --git a/packages/patternengine-node-twig/test/files/_patterns/00-test/07-mixed-params.mustache b/packages/patternengine-node-twig/test/files/_patterns/00-test/07-mixed-params.mustache new file mode 100644 index 000000000..408b3f1e4 --- /dev/null +++ b/packages/patternengine-node-twig/test/files/_patterns/00-test/07-mixed-params.mustache @@ -0,0 +1,6 @@ +
+ {{> test-styled-atom }} + {{> test-styled-atom:test_2(message: '2') }} + {{> test-styled-atom:test_3(message: '3') }} + {{> test-styled-atom:test_4(message: '4') }} +
diff --git a/packages/patternengine-node-twig/test/files/_patterns/00-test/08-bookend-params.mustache b/packages/patternengine-node-twig/test/files/_patterns/00-test/08-bookend-params.mustache new file mode 100644 index 000000000..d2d0b4081 --- /dev/null +++ b/packages/patternengine-node-twig/test/files/_patterns/00-test/08-bookend-params.mustache @@ -0,0 +1,6 @@ +
+ {{> test-styled-atom }} + {{> test-styled-atom:test_2(message: '2') }} + {{> test-styled-atom:test_3(message: '3') }} + {{> test-styled-atom }} +
diff --git a/packages/patternengine-node-twig/test/files/_patterns/00-test/09-bookend.mustache b/packages/patternengine-node-twig/test/files/_patterns/00-test/09-bookend.mustache new file mode 100644 index 000000000..74fc3451b --- /dev/null +++ b/packages/patternengine-node-twig/test/files/_patterns/00-test/09-bookend.mustache @@ -0,0 +1,6 @@ +
+ {{> test-styled-atom }} + {{> test-styled-atom:test_2 }} + {{> test-styled-atom:test_3 }} + {{> test-styled-atom}} +
diff --git a/packages/patternengine-node-twig/test/lineage_hunter_tests.js b/packages/patternengine-node-twig/test/lineage_hunter_tests.js index 7c00ce415..f95e92de8 100644 --- a/packages/patternengine-node-twig/test/lineage_hunter_tests.js +++ b/packages/patternengine-node-twig/test/lineage_hunter_tests.js @@ -104,30 +104,22 @@ //setup current pattern from what we would have during execution var currentPattern = createFakeEmptyErrorPattern(); extend(currentPattern, { - "template": "{{> atoms-error(message: 'That\'s no moon...') }}", - "patternPartial": "{{> atoms-error(message: 'That\'s no moon...') }}" + "template": "{{> atoms-error(message: 'That\\'s no moon...') }}", + "patternPartial": "{{> atoms-error(message: 'That\\'s no moon...') }}" }); var patternlab = { patterns: [ - { - "name": "01-atoms-05-alerts-00-error", - "subdir": "01-atoms\\05-alerts", - "filename": "00-error.mustache", - "data": null, - "template": "

{{message}}

", - "patternPartial": "

{{message}}

", - "patternName": "error", - "patternLink": "01-atoms-05-alerts-00-error/01-atoms-05-alerts-00-error.html", - "patternGroup": "atoms", - "patternSubGroup": "atoms\\05-alerts", - "flatPatternPath": "01-atoms\\05-alerts", - "patternState": "", - "lineage": [], - "lineageIndex": [], - "lineageR": [], - "lineageRIndex": [] - } + of.oPattern.create( + '/home/fakeuser/pl/source/_patterns/00-atoms/05-alerts/00-error.mustache', + '00-atoms\\05-alerts', + '00-error.mustache', + null, + { + "template": "

{{message}}

", + "patternPartial": "

{{message}}

" + } + ) ] }; @@ -144,8 +136,8 @@ //setup current pattern from what we would have during execution var currentPattern = createFakeEmptyErrorPattern(); extend(currentPattern, { - "template": "{{>atoms-error(message: 'That\'s no moon...')}}", - "patternPartial": "{{>atoms-error(message: 'That\'s no moon...')}}", + "template": "{{>atoms-error(message: 'That\\'s no moon...')}}", + "patternPartial": "{{>atoms-error(message: 'That\\'s no moon...')}}" }); var patternlab = { @@ -186,8 +178,8 @@ //setup current pattern from what we would have during execution var currentPattern = createFakeEmptyErrorPattern(); extend(currentPattern, { - "template": "{{>atoms-error(message: 'That\'s no moon...')}}", - "patternPartial": "{{>atoms-error(message: 'That\'s no moon...')}}" + "template": "{{>atoms-error(message: 'That\\'s no moon...')}}", + "patternPartial": "{{>atoms-error(message: 'That\\'s no moon...')}}" }); var patternlab = { patterns: [ @@ -227,4 +219,4 @@ }; -}()); +})(); diff --git a/packages/patternengine-node-twig/test/list_item_hunter_tests.js b/packages/patternengine-node-twig/test/list_item_hunter_tests.js index aa0529b74..a0e583f36 100644 --- a/packages/patternengine-node-twig/test/list_item_hunter_tests.js +++ b/packages/patternengine-node-twig/test/list_item_hunter_tests.js @@ -18,8 +18,29 @@ return extend(pattern, customProps); } + function createFakePatternLab(customProps) { + var pl = { + "listitems": { + "1": [ + { "title": "Foo" } + ], + "2": [ + { "title": "Foo" }, + { "title": "Bar" } + ] + }, + "data": { + "link": {}, + "partials": [] + }, + "config": {"debug": false} + }; + + return extend(pl, customProps); + } + exports['list_item_hunter'] = { - 'process_list_item_partials finds and outputs basic repeating blocks' : function(test){ + 'process_list_item_partials finds and outputs basic repeating blocks': function(test){ //arrange //setup current pattern from what we would have during execution var currentPattern = createFakeListPattern({ @@ -27,30 +48,7 @@ "extendedTemplate": "{{#listItems.two}}{{ title }}{{/listItems.two}}", "key": "test-patternName" }); - - var patternlab = { - "listitems": { - "1": [ - { - "title": "Foo" - } - ], - "2": [ - { - "title": "Foo" - }, - { - "title": "Bar" - } - ] - }, - "data": { - "link": {}, - "partials": [] - }, - "config": {"debug": false} - }; - + var patternlab = createFakePatternLab(); var list_item_hunter = new lih(); //act @@ -70,30 +68,7 @@ "extendedTemplate" : "{{#listitems.two}}{{ title }}{{/listitems.two}}", "key": "test-patternName" }); - - var patternlab = { - "listitems": { - "1": [ - { - "title": "Foo" - } - ], - "2": [ - { - "title": "Foo" - }, - { - "title": "Bar" - } - ] - }, - "data": { - "link": {}, - "partials": [] - }, - "config": {"debug": false} - }; - + var patternlab = createFakePatternLab(); var list_item_hunter = new lih(); //act @@ -105,45 +80,25 @@ test.done(); }, - 'process_list_item_partials finds partials and outputs repeated renders' : function(test){ + 'process_list_item_partials finds partials and outputs repeated renders': function(test){ //arrange //setup current pattern from what we would have during execution var currentPattern = createFakeListPattern({ "template": "{{#listItems.two}}{{ title }}{{/listItems.two}}", - "extendedTemplate" : "{{#listItems.two}}{{> test-simple }}{{/listItems.two}}", + "extendedTemplate": "{{#listItems.two}}{{> test-simple }}{{/listItems.two}}", "key": "test-patternName" }); - var patternlab = { - "listitems": { - "1": [ - { - "title": "Foo" - } - ], - "2": [ - { - "title": "Foo" - }, - { - "title": "Bar" - } - ] - }, - "data": { - "link": {}, - "partials": [] - }, - "config": {"debug": false}, + var patternlab = createFakePatternLab({ "patterns": [ { - "template": "{{ title }}", - "extendedTemplate" : "{{ title }}", - "key": "test-simple", - "jsonFileData" : {} + "template": "{{ title }}", + "extendedTemplate" : "{{ title }}", + "key": "test-simple", + "jsonFileData" : {} } ] - }; + }); var list_item_hunter = new lih(); @@ -158,51 +113,29 @@ 'process_list_item_partials finds verbose partials and outputs repeated renders' : function(test){ var pattern1 = createFakeListPattern({ - "template": "{{#listItems.one}}{{> 00-test/00-foo }}{{/listItems.one}}", - "extendedTemplate" : "{{#listItems.one}}{{> 00-test/00-foo }}{{/listItems.one}}", + "template": "{{#listItems.one}}{{> 00-atoms/00-test/00-foo.mustache }}{{/listItems.one}}", + "extendedTemplate" : "{{#listItems.one}}{{> 00-atoms/00-test/00-foo.mustache }}{{/listItems.one}}", "key": "test-patternName1" }); var pattern2 = createFakeListPattern({ - "template": "{{#listItems.two}}{{> 00-test/01-bar.mustache }}{{/listItems.two}}", - "extendedTemplate" : "{{#listItems.two}}{{> 00-test/01-bar.mustache }}{{/listItems.two}}", + "template": "{{#listItems.two}}{{> 00-atoms/00-test/00-bar.mustache }}{{/listItems.two}}", + "extendedTemplate" : "{{#listItems.two}}{{> 00-atoms/00-test/00-bar.mustache }}{{/listItems.two}}", "key": "test-patternName2" }); - var patternlab = { - "listitems": { - "1": [ - { - "title": "Foo" - } - ], - "2": [ - { - "title": "Foo" - }, - { - "title": "Bar" - } - ] - }, - "data": { - "link": {}, - "partials": [] - }, - "config": {"debug": false}, + var patternlab = createFakePatternLab({ "patterns": [ - of.oPattern.create(null, "00-test", "00-foo", null, { + of.oPattern.create('/home/fakeuser/pl/source/_patterns/00-atoms/00-test/00-foo.mustache', "00-atoms/00-test", "00-foo.mustache", null, { "template": "{{ title }}", - "extendedTemplate": "{{ title }}", - "jsonFileData": {} + "extendedTemplate": "{{ title }}" }), - of.oPattern.create(null, "00-test", "00-bar", null, { + of.oPattern.create('/home/fakeuser/pl/source/_patterns/00-atoms/00-test/00-bar.mustache', "00-atoms/00-test", "00-bar.mustache", null, { "template": "{{ title }}", - "extendedTemplate": "{{ title }}", - "jsonFileData": {} + "extendedTemplate": "{{ title }}" }) ] - }; + }); var list_item_hunter = new lih(); @@ -217,57 +150,31 @@ test.done(); }, - 'process_list_item_partials overwrites listItem property if that property is in local .listitem.json' : 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 = { - "template": "{{#listItems.two}}{{ title }}{{/listItems.two}}", - "extendedTemplate" : "{{#listItems.two}}{{> test-simple }}{{/listItems.two}}", - "key": "test-patternName", - "jsonFileData" : {}, - "listitems" : { - "2": [ - { - "title": "One" - }, - { - "title": "Two" - }, - ] - } - }; - - var patternlab = { + var currentPattern = createFakeListPattern({ + "template": "{{#listItems.two}}{{ title }}{{/listItems.two}}", + "extendedTemplate": "{{#listItems.two}}{{> test-simple }}{{/listItems.two}}", + "key": "test-patternName", + "jsonFileData": {}, "listitems": { - "1": [ - { - "title": "Foo" - } - ], "2": [ - { - "title": "Foo" - }, - { - "title": "Bar" - } + { "title": "One" }, + { "title": "Two" } ] - }, - "data": { - "link": {}, - "partials": [] - }, - "config": {"debug": false}, + } + }); + var patternlab = createFakePatternLab({ "patterns": [ - { - "template": "{{ title }}", - "extendedTemplate" : "{{ title }}", - "key": "test-simple", - "jsonFileData" : {} - } + createFakeListPattern({ + "template": "{{ title }}", + "extendedTemplate": "{{ title }}", + "key": "test-simple", + "jsonFileData": {} + }) ] - }; - + }); var list_item_hunter = new lih(); //act @@ -282,54 +189,28 @@ '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" : {}, - "listitems" : { - "2": [ - { - "title": "One" - }, - { - "title": "Two" - }, - ] - } - }; - - var patternlab = { + var currentPattern = createFakeListPattern({ + "template": "{{#listItems.one}}{{ title }}{{/listItems.one}}", + "extendedTemplate": "{{#listItems.one}}{{> test-simple }}{{/listItems.one}}", + "key": "test-patternName", + "jsonFileData": {}, "listitems": { - "1": [ - { - "title": "Foo" - } - ], "2": [ - { - "title": "Foo" - }, - { - "title": "Bar" - } + { "title": "One" }, + { "title": "Two" } ] - }, - "data": { - "link": {}, - "partials": [] - }, - "config": {"debug": false}, + } + }); + var patternlab = createFakePatternLab({ "patterns": [ - { - "template": "{{ title }}", - "extendedTemplate" : "{{ title }}", - "key": "test-simple", - "jsonFileData" : {} - } + createFakeListPattern({ + "template": "{{ title }}", + "extendedTemplate": "{{ title }}", + "key": "test-simple", + "jsonFileData" : {} + }) ] - }; - + }); var list_item_hunter = new lih(); //act @@ -344,53 +225,33 @@ '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" : {}, - "listitems" : { - "1": [ - { - "title": "One" - } - ], - "2": [ - { - "title": "One" - }, - { - "title": "Two" - }, - ] - } - }; - - var patternlab = { + var currentPattern = createFakeListPattern({ + "template": "{{#listItems.one}}{{ title }}{{/listItems.one}}", + "extendedTemplate": "{{#listItems.one}}{{> test-simple }}{{/listItems.one}}", + "key": "test-patternName", + "jsonFileData": {}, "listitems": { + "1": [ + { "title": "One" } + ], "2": [ - { - "title": "Foo" - }, - { - "title": "Bar" - } + { "title": "One" }, + { "title": "Two" } ] - }, - "data": { - "link": {}, - "partials": [] - }, - "config": {"debug": false}, + } + }); + + var patternlab = createFakePatternLab({ "patterns": [ - { - "template": "{{ title }}", - "extendedTemplate" : "{{ title }}", - "key": "test-simple", - "jsonFileData" : {} - } + createFakeListPattern({ + "template": "{{ title }}", + "extendedTemplate": "{{ title }}", + "key": "test-simple", + "jsonFileData": {} + }) ] - }; + }); + delete patternlab.listitems["1"]; // remove the "1" list var list_item_hunter = new lih(); @@ -398,6 +259,7 @@ list_item_hunter.process_list_item_partials(currentPattern, patternlab); //assert + test.equals(typeof patternlab.listitems["1"], "undefined"); test.equals(currentPattern.extendedTemplate, "One" ); test.done(); @@ -405,4 +267,4 @@ }; -}()); +})(); diff --git a/packages/patternengine-node-twig/test/pattern_assembler_tests.js b/packages/patternengine-node-twig/test/pattern_assembler_tests.js index 5ff9d1ab2..dfede2a5e 100644 --- a/packages/patternengine-node-twig/test/pattern_assembler_tests.js +++ b/packages/patternengine-node-twig/test/pattern_assembler_tests.js @@ -2,26 +2,68 @@ "use strict"; var pa = require('../builder/pattern_assembler'); - var of = require('../builder/object_factory'); + var object_factory = require('../builder/object_factory'); exports['pattern_assembler'] = { 'find_pattern_partials finds partials' : function(test){ - test.expect(3); - - //setup current pattern from what we would have during execution - var currentPattern = new of.oPattern( + // NOTES from GTP: + // it's nice to have so much test coverage, but it retrospect, I'm not + // happy with the structure I wound up with in this test; it's too + // difficult to add test cases and test failure reporting is not very + // granular. + + test.expect(16); + + // setup current pattern from what we would have during execution + // docs on partial syntax are here: + // http://patternlab.io/docs/pattern-including.html + var currentPattern = object_factory.oPattern.create( '/home/fakeuser/pl/source/_patterns/01-molecules/00-testing/00-test-mol.mustache', // abspath '01-molecules\\00-testing', // subdir '00-test-mol.mustache', // filename, - null // data + null, // data + { + template: "{{> molecules-comment-header}}asdfasdf" + + "{{> molecules-comment-header}}" + + "{{> \n molecules-comment-header\n}}" + + "{{> }}" + + "{{> molecules-weird-spacing }}" + + "{{> molecules-ba_d-cha*rs }}" + + "{{> molecules-single-comment(description: 'A life isn\\'t like a garden. Perfect moments can be had, but not preserved, except in memory.') }}" + + '{{> molecules-single-comment(description: "A life is like a \\"garden\\". Perfect moments can be had, but not preserved, except in memory.") }}' + + "{{> molecules-single-comment:foo }}" + + // verbose partial syntax, introduced in v0.12.0, with file extension + "{{> 01-molecules/06-components/03-comment-header.mustache }}" + + "{{> 01-molecules/06-components/02-single-comment.mustache(description: 'A life is like a garden. Perfect moments can be had, but not preserved, except in memory.') }}" + + "{{> molecules-single-comment:foo }}" + + "{{>atoms-error(message: 'That\\'s no moon...')}}" + + '{{>atoms-error(message: \'That\\\'s no moon...\')}}' + + "{{> 00-atoms/00-global/ }}" + + // verbose partial syntax, introduced in v0.12.0, no file extension + "{{> 00-atoms/00-global/06-test }}" + + "{{> molecules-single-comment:foo_1 }}" + + "{{> molecules-single-comment:foo-1 }}" + } ); - currentPattern.template = "

{{> molecules-comment-header}}

{{> molecules-single-comment(description: 'A life is like a garden. Perfect moments can be had, but not preserved, except in memory.') }}
"; var results = currentPattern.findPartials(); - test.equals(results.length, 2); - test.equals(results[0], '{{> molecules-comment-header}}'); - test.equals(results[1], '{{> molecules-single-comment(description: \'A life is like a garden. Perfect moments can be had, but not preserved, except in memory.\') }}'); - + console.log(results); + test.equals(results.length, 15); + test.equals(results[0], "{{> molecules-comment-header}}"); + test.equals(results[1], "{{> molecules-comment-header}}"); + test.equals(results[2], "{{> \n molecules-comment-header\n}}"); + test.equals(results[3], "{{> molecules-weird-spacing }}"); + test.equals(results[4], "{{> molecules-single-comment(description: 'A life isn\\'t like a garden. Perfect moments can be had, but not preserved, except in memory.') }}"); + test.equals(results[5], '{{> molecules-single-comment(description: "A life is like a \\"garden\\". Perfect moments can be had, but not preserved, except in memory.") }}'); + test.equals(results[6], "{{> molecules-single-comment:foo }}"); + test.equals(results[7], "{{> 01-molecules/06-components/03-comment-header.mustache }}"); + test.equals(results[8], "{{> 01-molecules/06-components/02-single-comment.mustache(description: 'A life is like a garden. Perfect moments can be had, but not preserved, except in memory.') }}"); + test.equals(results[9], "{{> molecules-single-comment:foo }}"); + test.equals(results[10], "{{>atoms-error(message: 'That\\'s no moon...')}}"); + test.equals(results[11], "{{>atoms-error(message: 'That\\'s no moon...')}}"); + test.equals(results[12], "{{> 00-atoms/00-global/06-test }}"); + test.equals(results[13], '{{> molecules-single-comment:foo_1 }}'); + test.equals(results[14], '{{> molecules-single-comment:foo-1 }}'); test.done(); }, @@ -29,37 +71,39 @@ test.expect(3); //setup current pattern from what we would have during execution - var currentPattern = new of.oPattern( + var currentPattern = new object_factory.oPattern( '/home/fakeuser/pl/source/_patterns/01-molecules/00-testing/00-test-mol.mustache', // abspath '01-molecules\\00-testing', // subdir '00-test-mol.mustache', // filename, null // data ); - currentPattern.template = "

{{> 01-molecules/06-components/03-comment-header.mustache }}

{{> 01-molecules/06-components/02-single-comment(description: 'A life is like a garden. Perfect moments can be had, but not preserved, except in memory.') }}
"; + currentPattern.template = "

{{> 01-molecules/06-components/03-comment-header.mustache }}

{{> 01-molecules/06-components/02-single-comment.mustache(description: 'A life is like a garden. Perfect moments can be had, but not preserved, except in memory.') }}
"; var results = currentPattern.findPartials(); test.equals(results.length, 2); test.equals(results[0], '{{> 01-molecules/06-components/03-comment-header.mustache }}'); - test.equals(results[1], '{{> 01-molecules/06-components/02-single-comment(description: \'A life is like a garden. Perfect moments can be had, but not preserved, except in memory.\') }}'); + test.equals(results[1], '{{> 01-molecules/06-components/02-single-comment.mustache(description: \'A life is like a garden. Perfect moments can be had, but not preserved, except in memory.\') }}'); test.done(); }, 'find_pattern_partials_with_style_modifiers finds style modifiers' : function(test){ - test.expect(2); + test.expect(4); //setup current pattern from what we would have during execution - var currentPattern = new of.oPattern( + var currentPattern = new object_factory.oPattern( '/home/fakeuser/pl/source/_patterns/01-molecules/00-testing/00-test-mol.mustache', // abspath '01-molecules\\00-testing', // subdir '00-test-mol.mustache', // filename, null // data ); - currentPattern.template = "

{{> molecules-comment-header}}

{{> molecules-single-comment:foo }}
"; + currentPattern.template = "

{{> molecules-comment-header}}

{{> molecules-single-comment:foo }}
{{> molecules-single-comment:foo_1 }}
{{> molecules-single-comment:foo-1 }}
"; var results = currentPattern.findPartialsWithStyleModifiers(); - test.equals(results.length, 1); + test.equals(results.length, 3); test.equals(results[0], '{{> molecules-single-comment:foo }}'); + test.equals(results[1], '{{> molecules-single-comment:foo_1 }}'); + test.equals(results[2], '{{> molecules-single-comment:foo-1 }}'); test.done(); }, @@ -69,7 +113,7 @@ //setup current pattern from what we would have during execution - var currentPattern = new of.oPattern( + var currentPattern = new object_factory.oPattern( '/home/fakeuser/pl/source/_patterns/01-molecules/00-testing/00-test-mol.mustache', // abspath '01-molecules\\00-testing', // subdir '00-test-mol.mustache', // filename, @@ -88,7 +132,7 @@ test.expect(2); //setup current pattern from what we would have during execution - var currentPattern = new of.oPattern( + var currentPattern = new object_factory.oPattern( '/home/fakeuser/pl/source/_patterns/01-molecules/00-testing/00-test-mol.mustache', // abspath '01-molecules\\00-testing', // subdir '00-test-mol.mustache', // filename, @@ -107,7 +151,7 @@ test.expect(1); //setup current pattern from what we would have during execution - var currentPattern = new of.oPattern( + var currentPattern = new object_factory.oPattern( '/home/fakeuser/pl/source/_patterns/01-molecules/00-testing/00-test-mol.mustache', // abspath '01-molecules\\00-testing', // subdir '00-test-mol.mustache', // filename, @@ -125,7 +169,7 @@ test.expect(1); //setup current pattern from what we would have during execution - var currentPattern = new of.oPattern( + var currentPattern = new object_factory.oPattern( '/home/fakeuser/pl/source/_patterns/01-molecules/00-testing/00-test-mol.mustache', // abspath '01-molecules\\00-testing', // subdir '00-test-mol.mustache', // filename, @@ -143,7 +187,7 @@ test.expect(2); //setup current pattern from what we would have during execution - var currentPattern = new of.oPattern( + var currentPattern = new object_factory.oPattern( '/home/fakeuser/pl/source/_patterns/01-molecules/00-testing/00-test-mol.mustache', // abspath '01-molecules\\00-testing', // subdir '00-test-mol.mustache', // filename, @@ -163,7 +207,7 @@ test.expect(2); //setup current pattern from what we would have during execution - var currentPattern = new of.oPattern( + var currentPattern = new object_factory.oPattern( '/home/fakeuser/pl/source/_patterns/01-molecules/00-testing/00-test-mol.mustache', // abspath '01-molecules\\00-testing', // subdir '00-test-mol.mustache', // filename, @@ -182,7 +226,7 @@ test.expect(2); //setup current pattern from what we would have during execution - var currentPattern = new of.oPattern( + var currentPattern = new object_factory.oPattern( '/home/fakeuser/pl/source/_patterns/01-molecules/00-testing/00-test-mol.mustache', // abspath '01-molecules\\00-testing', // subdir '00-test-mol.mustache', // filename, @@ -201,7 +245,7 @@ test.expect(1); //setup current pattern from what we would have during execution - var currentPattern = new of.oPattern( + var currentPattern = new object_factory.oPattern( '/home/fakeuser/pl/source/_patterns/01-molecules/00-testing/00-test-mol.mustache', // abspath '01-molecules\\00-testing', // subdir '00-test-mol.mustache', // filename, @@ -219,7 +263,7 @@ test.expect(1); //setup current pattern from what we would have during execution - var currentPattern = new of.oPattern( + var currentPattern = new object_factory.oPattern( '/home/fakeuser/pl/source/_patterns/01-molecules/00-testing/00-test-mol.mustache', // abspath '01-molecules\\00-testing', // subdir '00-test-mol.mustache', // filename, @@ -321,33 +365,172 @@ test.done(); }, + 'processPatternRecursive - correctly replaces all stylemodifiers when multiple duplicate patterns with different stylemodifiers found' : function(test){ + //arrange + var fs = require('fs-extra'); + var pattern_assembler = new pa(); + + var pl = {}; + pl.config = {}; + pl.data = {}; + pl.data.link = {}; + pl.config.debug = false; + pl.patterns = []; + var patterns_dir = './test/files/_patterns'; + + var atomPattern = new object_factory.oPattern('test/files/_patterns/00-test/03-styled-atom.mustache', '00-test', '03-styled-atom.mustache'); + atomPattern.template = fs.readFileSync(patterns_dir + '/00-test/03-styled-atom.mustache', 'utf8'); + atomPattern.stylePartials = pattern_assembler.find_pattern_partials_with_style_modifiers(atomPattern); + + var groupPattern = new object_factory.oPattern('test/files/_patterns/00-test/04-group.mustache', '00-test', '04-group.mustache'); + groupPattern.template = fs.readFileSync(patterns_dir + '/00-test/04-group.mustache', 'utf8'); + groupPattern.stylePartials = pattern_assembler.find_pattern_partials_with_style_modifiers(groupPattern); + + pl.patterns.push(atomPattern); + pl.patterns.push(groupPattern); + + //act + pattern_assembler.process_pattern_recursive('test/files/_patterns/00-test/04-group.mustache', pl, {}); + + //assert + var expectedValue = '
{{message}} {{message}} {{message}} {{message}}
'; + test.equals(groupPattern.extendedTemplate.replace(/\s\s+/g, ' ').replace(/\n/g, ' ').trim(), expectedValue.trim()); + test.done(); + }, + 'processPatternRecursive - correctly ignores a partial without a style modifier when the same partial later has a style modifier' : function(test){ + //arrange + var fs = require('fs-extra'); + var pattern_assembler = new pa(); + + var pl = {}; + pl.config = {}; + pl.data = {}; + pl.data.link = {}; + pl.config.debug = false; + pl.patterns = []; + var patterns_dir = './test/files/_patterns'; + + var atomPattern = new object_factory.oPattern('test/files/_patterns/00-test/03-styled-atom.mustache', '00-test', '03-styled-atom.mustache'); + atomPattern.template = fs.readFileSync(patterns_dir + '/00-test/03-styled-atom.mustache', 'utf8'); + atomPattern.stylePartials = pattern_assembler.find_pattern_partials_with_style_modifiers(atomPattern); + + var mixedPattern = new object_factory.oPattern('test/files/_patterns/00-test/06-mixed.mustache', '00-test', '06-mixed.mustache'); + mixedPattern.template = fs.readFileSync(patterns_dir + '/00-test/06-mixed.mustache', 'utf8'); + mixedPattern.stylePartials = pattern_assembler.find_pattern_partials_with_style_modifiers(mixedPattern); + + pl.patterns.push(atomPattern); + pl.patterns.push(mixedPattern); + + //act + pattern_assembler.process_pattern_recursive('test/files/_patterns/00-test/06-mixed.mustache', pl, {}); + + //assert. here we expect {{styleModifier}} to be in the first group, since it was not replaced by anything. rendering with data will then remove this (correctly) + var expectedValue = '
{{message}} {{message}} {{message}} {{message}}
'; + test.equals(mixedPattern.extendedTemplate.replace(/\s\s+/g, ' ').replace(/\n/g, ' ').trim(), expectedValue.trim()); + test.done(); + }, + 'processPatternRecursive - correctly ignores bookended partials without a style modifier when the same partial has a style modifier between' : function(test){ + //arrange + var fs = require('fs-extra'); + var pattern_assembler = new pa(); + + var pl = {}; + pl.config = {}; + pl.data = {}; + pl.data.link = {}; + pl.config.debug = false; + pl.patterns = []; + var patterns_dir = './test/files/_patterns'; + + var atomPattern = new object_factory.oPattern('test/files/_patterns/00-test/03-styled-atom.mustache', '00-test', '03-styled-atom.mustache'); + atomPattern.template = fs.readFileSync(patterns_dir + '/00-test/03-styled-atom.mustache', 'utf8'); + atomPattern.stylePartials = pattern_assembler.find_pattern_partials_with_style_modifiers(atomPattern); + + var bookendPattern = new object_factory.oPattern('test/files/_patterns/00-test/09-bookend.mustache', '00-test', '09-bookend.mustache'); + bookendPattern.template = fs.readFileSync(patterns_dir + '/00-test/09-bookend.mustache', 'utf8'); + bookendPattern.stylePartials = pattern_assembler.find_pattern_partials_with_style_modifiers(bookendPattern); + + pl.patterns.push(atomPattern); + pl.patterns.push(bookendPattern); + + debugger; + + //act + pattern_assembler.process_pattern_recursive('test/files/_patterns/00-test/09-bookend.mustache', pl, {}); + + //assert. here we expect {{styleModifier}} to be in the first and last group, since it was not replaced by anything. rendering with data will then remove this (correctly) + var expectedValue = '
{{message}} {{message}} {{message}} {{message}}
'; + var actualValue = bookendPattern.extendedTemplate.replace(/\s\s+/g, ' ').replace(/\n/g, ' '); + test.equals(actualValue.trim(), expectedValue.trim(), 'actual value:\n' + actualValue + '\nexpected value:\n' + expectedValue); + test.done(); + }, + 'processPatternRecursive - correctly ignores a partial without a style modifier when the same partial later has a style modifier and pattern parameters' : function(test){ + //arrange + var fs = require('fs-extra'); + var pattern_assembler = new pa(); + + var pl = {}; + pl.config = {}; + pl.data = {}; + pl.data.link = {}; + pl.config.debug = false; + pl.patterns = []; + var patterns_dir = './test/files/_patterns'; + + var atomPattern = new object_factory.oPattern('test/files/_patterns/00-test/03-styled-atom.mustache', '00-test', '03-styled-atom.mustache'); + atomPattern.template = fs.readFileSync(patterns_dir + '/00-test/03-styled-atom.mustache', 'utf8'); + atomPattern.stylePartials = pattern_assembler.find_pattern_partials_with_style_modifiers(atomPattern); + atomPattern.parameteredPartials = pattern_assembler.find_pattern_partials_with_parameters(atomPattern); + + var mixedPattern = new object_factory.oPattern('test/files/_patterns/00-test/07-mixed-params.mustache', '00-test', '07-mixed-params.mustache'); + mixedPattern.template = fs.readFileSync(patterns_dir + '/00-test/07-mixed-params.mustache', 'utf8'); + mixedPattern.stylePartials = pattern_assembler.find_pattern_partials_with_style_modifiers(mixedPattern); + mixedPattern.parameteredPartials = pattern_assembler.find_pattern_partials_with_parameters(mixedPattern); + + pl.patterns.push(atomPattern); + pl.patterns.push(mixedPattern); + + //act + pattern_assembler.process_pattern_recursive('test/files/_patterns/00-test/07-mixed-params.mustache', pl, {}); + + //assert. here we expect {{styleModifier}} to be in the first span, since it was not replaced by anything. rendering with data will then remove this (correctly) + var expectedValue = '
{{message}} 2 3 4
'; + test.equals(mixedPattern.extendedTemplate.replace(/\s\s+/g, ' ').replace(/\n/g, ' ').trim(), expectedValue.trim()); + test.done(); + }, + 'processPatternRecursive - correctly ignores bookended partials without a style modifier when the same partial has a style modifier and pattern parameters between' : function(test){ + //arrange + var fs = require('fs-extra'); + var pattern_assembler = new pa(); + + var pl = {}; + pl.config = {}; + pl.data = {}; + pl.data.link = {}; + pl.config.debug = false; + pl.patterns = []; + var patterns_dir = './test/files/_patterns'; + + var atomPattern = new object_factory.oPattern('test/files/_patterns/00-test/03-styled-atom.mustache', '00-test', '03-styled-atom.mustache'); + atomPattern.template = fs.readFileSync(patterns_dir + '/00-test/03-styled-atom.mustache', 'utf8'); + atomPattern.stylePartials = pattern_assembler.find_pattern_partials_with_style_modifiers(atomPattern); + atomPattern.parameteredPartials = pattern_assembler.find_pattern_partials_with_parameters(atomPattern); + + var bookendPattern = new object_factory.oPattern('test/files/_patterns/00-test/08-bookend-params.mustache', '00-test', '08-bookend-params.mustache'); + bookendPattern.template = fs.readFileSync(patterns_dir + '/00-test/08-bookend-params.mustache', 'utf8'); + bookendPattern.stylePartials = pattern_assembler.find_pattern_partials_with_style_modifiers(bookendPattern); + bookendPattern.parameteredPartials = pattern_assembler.find_pattern_partials_with_parameters(bookendPattern); + + pl.patterns.push(atomPattern); + pl.patterns.push(bookendPattern); + + //act + pattern_assembler.process_pattern_recursive('test/files/_patterns/00-test/08-bookend-params.mustache', pl, {}); - 'isPatternFile correctly identifies pattern files and rejects non-pattern files': function(test){ - var pattern_assembler = new pa(); - - // each test case - var filenames = { - '00-comment-thread.mustache': true, - '00-comment-thread.fakeextthatdoesntexist': false, - '00-comment-thread': false, - '_00-comment-thread.mustache': false, - '.00-comment-thread.mustache': false, - '00-comment-thread.json': false, - '00-homepage~emergency.json': false - }; - // expect one test per test case - test.expect(Object.keys(filenames).length); - - // loop over each test case and test it - Object.keys(filenames).forEach(function (filename) { - var expectedResult = filenames[filename], - actualResult = pattern_assembler.is_pattern_file(filename), - testMessage = 'isPatternFile should return ' + expectedResult + ' for ' + filename; - test.strictEqual(actualResult, expectedResult, testMessage); - }); - - // done + //assert. here we expect {{styleModifier}} to be in the first and last span, since it was not replaced by anything. rendering with data will then remove this (correctly) + var expectedValue = '
{{message}} 2 3 {{message}}
'; + test.equals(bookendPattern.extendedTemplate.replace(/\s\s+/g, ' ').replace(/\n/g, ' ').trim(), expectedValue.trim()); test.done(); } }; -}()); +})(); diff --git a/packages/patternengine-node-twig/test/pattern_engines_tests.js b/packages/patternengine-node-twig/test/pattern_engines_tests.js index 34eb5228a..87810ecf7 100644 --- a/packages/patternengine-node-twig/test/pattern_engines_tests.js +++ b/packages/patternengine-node-twig/test/pattern_engines_tests.js @@ -27,7 +27,6 @@ 'getEngineNameForPattern returns "mustache" for an artificial empty template': function (test) { test.expect(1); var emptyPattern = of.oPattern.createEmpty(); - console.log(emptyPattern); test.equals(patternEngines.getEngineNameForPattern(emptyPattern), 'mustache'); test.done(); }, @@ -40,7 +39,57 @@ var engine = patternEngines.getEngineForPattern(mustacheTestPseudoPattern); test.equals(engine, patternEngines.mustache); test.done(); - } + }, + 'isPseudoPatternJSON correctly identifies pseudo-pattern JSON filenames': function(test) { + // each test case + var filenames = { + '00-homepage~emergency.json': true, + '~emergency.json': true, + '00-homepage~emergency.js': false, + '00-homepage-emergency.js': false, + '00-homepage.hbs': false, + '00-homepage.json': false, + 'greatpic.jpg': false + }; + // expect one test per test case + test.expect(Object.keys(filenames).length); + + // loop over each test case and test it + Object.keys(filenames).forEach(function (filename) { + var expectedResult = filenames[filename], + actualResult = patternEngines.isPseudoPatternJSON(filename), + testMessage = 'isPseudoPatternJSON should return ' + expectedResult + ' for ' + filename; + test.strictEqual(actualResult, expectedResult, testMessage); + }); + + // done + test.done(); + }, + 'isPatternFile correctly identifies pattern files and rejects non-pattern files': function(test){ + // each test case + var filenames = { + '00-comment-thread.mustache': true, + '00-comment-thread.fakeextthatdoesntexist': false, + '00-comment-thread': false, + '_00-comment-thread.mustache': false, + '.00-comment-thread.mustache': false, + '00-comment-thread.json': false, + '00-homepage~emergency.json': true + }; + // expect one test per test case + test.expect(Object.keys(filenames).length); + + // loop over each test case and test it + Object.keys(filenames).forEach(function (filename) { + var expectedResult = filenames[filename], + actualResult = patternEngines.isPatternFile(filename), + testMessage = 'isPatternFile should return ' + expectedResult + ' for ' + filename; + test.strictEqual(actualResult, expectedResult, testMessage); + }); + + // done + test.done(); + } }; // testProps() utility function: given an object, and a hash of expected diff --git a/packages/patternengine-node-twig/test/style_modifier_hunter_tests.js b/packages/patternengine-node-twig/test/style_modifier_hunter_tests.js index 0245c7349..4951dde18 100644 --- a/packages/patternengine-node-twig/test/style_modifier_hunter_tests.js +++ b/packages/patternengine-node-twig/test/style_modifier_hunter_tests.js @@ -23,6 +23,44 @@ test.equals(pattern.extendedTemplate, '
'); test.done(); }, + 'replaces style modifiers with spaces in the syntax' : function(test){ + //arrange + var pl = {}; + pl.config = {}; + pl.config.debug = false; + + var pattern = { + extendedTemplate: '
' + }; + + var style_modifier_hunter = new smh(); + + //act + style_modifier_hunter.consume_style_modifier(pattern, '{{> partial:bar}}', pl); + + //assert + test.equals(pattern.extendedTemplate, '
'); + test.done(); + }, + 'replaces multiple style modifiers' : function(test){ + //arrange + var pl = {}; + pl.config = {}; + pl.config.debug = false; + + var pattern = { + extendedTemplate: '
' + }; + + var style_modifier_hunter = new smh(); + + //act + style_modifier_hunter.consume_style_modifier(pattern, '{{> partial:bar|baz|dum}}', pl); + + //assert + test.equals(pattern.extendedTemplate, '
'); + test.done(); + }, 'does not alter pattern extendedTemplate if styleModifier not found in partial' : function(test){ //arrange var pl = {};