From 03e85a76e0b5a9708e0de4344465a0e19b76c02b Mon Sep 17 00:00:00 2001 From: BRIAN MUENZENMEYER Date: Wed, 9 Mar 2016 10:40:55 -0600 Subject: [PATCH 1/3] Implement pattern state lowest common denominator closes #203 --- README.md | 20 +- core/lib/lineage_hunter.js | 85 ++- core/lib/pattern_assembler.js | 4 +- core/lib/patternlab.js | 18 + patternlab-config.json | 5 +- test/lineage_hunter_tests.js | 1008 ++++++++++++++++++------------- test/pattern_assembler_tests.js | 8 +- 7 files changed, 705 insertions(+), 443 deletions(-) diff --git a/README.md b/README.md index ce7d394b6..398df1c2a 100644 --- a/README.md +++ b/README.md @@ -148,12 +148,26 @@ You can set the state of a pattern by including it in `patternlab-config.json` t Pattern states should be lowercase and use hyphens where spaces are present. ``` "patternStates": { - "colors" : "inprogress", - "fonts" : "inreview", - "three-up" : "complete" + "atoms-colors" : "complete", + "molecules-primary-nav" : "inreview", + "organisms-header" : "inprogress" } ``` +Note that patterns inherit the lowest common denominator pattern state of their lineage. +Consider: +``` +"patternStates": { + "molecules-single-comment" : "complete", + "organisms-sticky-comment" : "inreview", + "templates-article" : "complete" +} +``` +In this case, two things are of note: + +* templates-article will display inreview since it inherits `organisms-sticky-comment` +* pages-article will not display any pattern state, as it does not define one + ##### Pattern Export `patternlab-config.json` also has two properties that work together to export completed patterns for use in a production environment. Provide an array of keys and an output directory. Pattern Lab doesn't ship with any pattern export keys, but the default directory is `"./pattern_exports/"` created inside the install directory. diff --git a/core/lib/lineage_hunter.js b/core/lib/lineage_hunter.js index 65a0e35cc..6463c038c 100644 --- a/core/lib/lineage_hunter.js +++ b/core/lib/lineage_hunter.js @@ -12,9 +12,10 @@ var lineage_hunter = function () { + var pa = require('./pattern_assembler'); + function findlineage(pattern, patternlab) { - var pa = require('./pattern_assembler'); var pattern_assembler = new pa(); //find the {{> template-name }} within patterns @@ -50,7 +51,11 @@ var lineage_hunter = function () { "lineagePattern": ancestorPattern.key, "lineagePath": "../../patterns/" + ancestorPattern.patternLink }; - pattern.lineage.push(JSON.stringify(l)); + if (ancestorPattern.patternState) { + l.lineageState = ancestorPattern.patternState; + } + + pattern.lineage.push(l); //also, add the lineageR entry if it doesn't exist if (ancestorPattern.lineageRIndex.indexOf(pattern.key) === -1) { @@ -61,16 +66,90 @@ var lineage_hunter = function () { "lineagePattern": pattern.key, "lineagePath": "../../patterns/" + pattern.patternLink }; - ancestorPattern.lineageR.push(JSON.stringify(lr)); + if (pattern.patternState) { + lr.lineageState = pattern.patternState; + } + + ancestorPattern.lineageR.push(lr); } } }); } } + function setPatternState(direction, pattern, targetPattern) { + // if the request came from the past, apply target pattern state to current pattern lineage + if (direction === 'fromPast') { + for (var i = 0; i < pattern.lineageIndex.length; i++) { + if (pattern.lineageIndex[i] === targetPattern.key) { + pattern.lineage[i].lineageState = targetPattern.patternState; + } + } + } else { + //the request came from the future, apply target pattern state to current pattern reverse lineage + for (var i = 0; i < pattern.lineageRIndex.length; i++) { + if (pattern.lineageRIndex[i] === targetPattern.key) { + pattern.lineageR[i].lineageState = targetPattern.patternState; + } + } + } + } + + + function cascadePatternStates(patternlab) { + + var pattern_assembler = new pa(); + + for (var i = 0; i < patternlab.patterns.length; i++) { + var pattern = patternlab.patterns[i]; + + //for each pattern with a defined state + if (pattern.patternState) { + + if (pattern.lineageIndex && pattern.lineageIndex.length > 0) { + + //find all lineage - patterns being consumed by this one + for (var h = 0; h < pattern.lineageIndex.length; h++) { + var lineagePattern = pattern_assembler.get_pattern_by_key(pattern.lineageIndex[h], patternlab); + setPatternState('fromFuture', lineagePattern, pattern); + } + } + + if (pattern.lineageRIndex && pattern.lineageRIndex.length > 0) { + + //find all reverse lineage - that is, patterns consuming this one + for (var j = 0; j < pattern.lineageRIndex.length; j++) { + + var lineageRPattern = pattern_assembler.get_pattern_by_key(pattern.lineageRIndex[j], patternlab); + + //only set patternState if pattern.patternState "is less than" the lineageRPattern.patternstate + //this makes patternlab apply the lowest common ancestor denominator + if (patternlab.config.patternStateCascade.indexOf(pattern.patternState) + < patternlab.config.patternStateCascade.indexOf(lineageRPattern.patternState)) { + + if (patternlab.config.debug) { + console.log('Found a lower common denominator pattern state: ' + pattern.patternState + ' on ' + pattern.key + '. Setting reverse lineage pattern ' + lineageRPattern.key + ' from ' + lineageRPattern.patternState); + } + + lineageRPattern.patternState = pattern.patternState; + + //take this opportunity to overwrite the lineageRPattern's lineage state too + setPatternState('fromPast', lineageRPattern, pattern); + } else { + setPatternState('fromPast', pattern, lineageRPattern); + } + } + } + } + } + } + return { find_lineage: function (pattern, patternlab) { findlineage(pattern, patternlab); + }, + cascade_pattern_states : function (patternlab) { + cascadePatternStates(patternlab); } }; diff --git a/core/lib/pattern_assembler.js b/core/lib/pattern_assembler.js index 2d40c1544..df6129c30 100644 --- a/core/lib/pattern_assembler.js +++ b/core/lib/pattern_assembler.js @@ -36,8 +36,8 @@ var pattern_assembler = function () { } function setState(pattern, patternlab) { - if (patternlab.config.patternStates && patternlab.config.patternStates[pattern.patternName]) { - pattern.patternState = patternlab.config.patternStates[pattern.patternName]; + if (patternlab.config.patternStates && patternlab.config.patternStates[pattern.key]) { + pattern.patternState = patternlab.config.patternStates[pattern.key]; } else { pattern.patternState = ""; } diff --git a/core/lib/patternlab.js b/core/lib/patternlab.js index c09f0986d..45e8b4e05 100644 --- a/core/lib/patternlab.js +++ b/core/lib/patternlab.js @@ -18,6 +18,7 @@ var patternlab_engine = function (config) { pa = require('./pattern_assembler'), mh = require('./media_hunter'), pe = require('./pattern_exporter'), + lh = require('./lineage_hunter'), he = require('html-entities').AllHtmlEntities, patternlab = {}; @@ -80,6 +81,7 @@ var patternlab_engine = function (config) { var pattern_assembler = new pa(), entity_encoder = new he(), pattern_exporter = new pe(), + lineage_hunter = new lh(), patterns_dir = paths.source.patterns; pattern_assembler.combine_listItems(patternlab); @@ -154,6 +156,9 @@ var patternlab_engine = function (config) { //we need to do this before expanding patterns & partials into extendedTemplates, otherwise we could lose the data -> partial reference pattern_assembler.parse_data_links(patternlab); + //cascade any patternStates + lineage_hunter.cascade_pattern_states(patternlab); + //delete the contents of config.patterns.public before writing if (deletePatternDir) { fs.emptyDirSync(paths.public.patterns); @@ -172,6 +177,19 @@ var patternlab_engine = function (config) { pattern.header = head; + //json stringify lineage and lineageR + var lineageArray = []; + for (var i = 0; i < pattern.lineage.length; i++) { + lineageArray.push(JSON.stringify(pattern.lineage[i])); + } + pattern.lineage = lineageArray; + + var lineageRArray = []; + for (var i = 0; i < pattern.lineageR.length; i++) { + lineageRArray.push(JSON.stringify(pattern.lineageR[i])); + } + pattern.lineageR = lineageRArray; + //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); diff --git a/patternlab-config.json b/patternlab-config.json index c66bc914c..42d13071a 100644 --- a/patternlab-config.json +++ b/patternlab-config.json @@ -49,8 +49,11 @@ "tools-shortcuts": true, "tools-docs": true }, + "patternStateCascade": ["inprogress", "inreview", "complete"], "patternStates": { - "homepage-emergency" : "inprogress" + "molecules-single-comment" : "complete", + "organisms-sticky-comment" : "inreview", + "templates-article" : "complete" }, "patternExportKeys": [], "patternExportDirectory": "./pattern_exports/", diff --git a/test/lineage_hunter_tests.js b/test/lineage_hunter_tests.js index 490c704ec..60ee018a6 100644 --- a/test/lineage_hunter_tests.js +++ b/test/lineage_hunter_tests.js @@ -1,433 +1,581 @@ (function () { - "use strict"; - - var lh = require('../core/lib/lineage_hunter'); - - exports['lineage hunter '] = { - 'find_lineage - finds lineage' : function(test){ - - //setup current pattern from what we would have during execution - var currentPattern = { - "name": "02-organisms-00-global-00-header", - "subdir": "02-organisms\\00-global", - "filename": "00-header.mustache", - "data": null, - "template": "\r\n
\r\n\t{{> atoms-logo }}\r\n\tSearch\r\n\tMenu\r\n\t{{> molecules-primary-nav }}\r\n\t{{> molecules-search }}\r\n
\r\n\r\n", - "patternPartial": "\r\n
\r\n\"Logo\tSearch\r\n\tMenu\r\n\r\n
\r\n
\r\n\t Search\r\n\t \r\n\t \r\n\t \r\n
\r\n
\r\n\r\n", - "patternName": "header", - "patternLink": "02-organisms-00-global-00-header/02-organisms-00-global-00-header.html", - "patternGroup": "organisms", - "patternSubGroup": "organisms\\00-global", - "flatPatternPath": "02-organisms\\00-global", - "key": "organisms-header", - "patternState": "", - "lineage": [], - "lineageIndex": [], - "lineageR": [], - "lineageRIndex": [] - }; - var patternlab = { - patterns: [ - { - "name": "00-atoms-03-images-00-logo", - "subdir": "00-atoms\\03-images", - "filename": "00-logo.mustache", - "data": null, - "template": "\"Logo", - "patternPartial": "\"Logo", - "patternName": "logo", - "patternLink": "00-atoms-03-images-00-logo/00-atoms-03-images-00-logo.html", - "patternGroup": "atoms", - "patternSubGroup": "atoms\\03-images", - "flatPatternPath": "00-atoms\\03-images", - "key": "atoms-logo", - "patternState": "", - "lineage": [], - "lineageIndex": [], - "lineageR": [], - "lineageRIndex": [] - }, - { - "name": "01-molecules-05-navigation-00-primary-nav", - "subdir": "01-molecules\\05-navigation", - "filename": "00-primary-nav.mustache", - "data": null, - "template": "\r\n", - "patternPartial": "\r\n", - "patternName": "primary-nav", - "patternLink": "01-molecules-05-navigation-00-primary-nav/01-molecules-05-navigation-00-primary-nav.html", - "patternGroup": "molecules", - "patternSubGroup": "molecules\\05-navigation", - "flatPatternPath": "01-molecules\\05-navigation", - "key": "molecules-primary-nav", - "patternState": "", - "lineage": [], - "lineageIndex": [], - "lineageR": [], - "lineageRIndex": [] - }, - { - "name": "01-molecules-04-forms-00-search", - "subdir": "01-molecules\\04-forms", - "filename": "00-search.mustache", - "data": null, - "template": "
\r\n
\r\n\t Search\r\n\t \r\n\t \r\n\t \r\n
\r\n
", - "patternPartial": "
\r\n
\r\n\t Search\r\n\t \r\n\t \r\n\t \r\n
\r\n
", - "patternName": "search", - "patternLink": "01-molecules-04-forms-00-search/01-molecules-04-forms-00-search.html", - "patternGroup": "molecules", - "patternSubGroup": "molecules\\04-forms", - "flatPatternPath": "01-molecules\\04-forms", - "key": "molecules-search", - "patternState": "", - "lineage": [], - "lineageIndex": [], - "lineageR": [], - "lineageRIndex": [] - } - ] - }; - - var lineage_hunter = new lh(); - lineage_hunter.find_lineage(currentPattern, patternlab); - - test.equals(currentPattern.lineageIndex.length, 3); - test.equals(currentPattern.lineageIndex[0], "atoms-logo"); - test.equals(currentPattern.lineageIndex[1], "molecules-primary-nav"); - test.equals(currentPattern.lineageIndex[2], "molecules-search"); - - test.done(); - }, - - 'find_lineage - finds lineage with spaced pattern parameters' : function(test){ - //setup current pattern from what we would have during execution - var currentPattern = { - "name": "01-molecules-01-toast-00-error", - "subdir": "01-molecules\\01-toast", - "filename": "00-error.mustache", - "data": null, - "template": "{{> atoms-error(message: 'That\'s no moon...') }}", - "patternPartial": "{{> atoms-error(message: 'That\'s no moon...') }}", - "patternName": "error", - "patternLink": "01-molecules-01-toast-00-error/01-molecules-01-toast-00-error.html", - "patternGroup": "molecules", - "patternSubGroup": "molecules\\01-toast", - "flatPatternPath": "01-molecules\\01-toast", - "key": "molecules-error", - "patternState": "", - "lineage": [], - "lineageIndex": [], - "lineageR": [], - "lineageRIndex": [] - }; - 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", - "key": "atoms-error", - "patternState": "", - "lineage": [], - "lineageIndex": [], - "lineageR": [], - "lineageRIndex": [] - } - ] - }; - - var lineage_hunter = new lh(); - lineage_hunter.find_lineage(currentPattern, patternlab); - - test.equals(currentPattern.lineageIndex.length, 1); - test.equals(currentPattern.lineageIndex[0], "atoms-error"); - - test.done(); - }, - - 'find_lineage - finds lineage with unspaced pattern parameters' : function(test){ - //setup current pattern from what we would have during execution - var currentPattern = { - "name": "01-molecules-01-toast-00-error", - "subdir": "01-molecules\\01-toast", - "filename": "00-error.mustache", - "data": null, - "template": "{{>atoms-error(message: 'That\'s no moon...')}}", - "patternPartial": "{{>atoms-error(message: 'That\'s no moon...')}}", - "patternName": "error", - "patternLink": "01-molecules-01-toast-00-error/01-molecules-01-toast-00-error.html", - "patternGroup": "molecules", - "patternSubGroup": "molecules\\01-toast", - "flatPatternPath": "01-molecules\\01-toast", - "key": "molecules-error", - "patternState": "", - "lineage": [], - "lineageIndex": [], - "lineageR": [], - "lineageRIndex": [] - }; - 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", - "key": "atoms-error", - "patternState": "", - "lineage": [], - "lineageIndex": [], - "lineageR": [], - "lineageRIndex": [] - } - ] - }; - - var lineage_hunter = new lh(); - lineage_hunter.find_lineage(currentPattern, patternlab); - - test.equals(currentPattern.lineageIndex.length, 1); - test.equals(currentPattern.lineageIndex[0], "atoms-error"); - test.equals(patternlab.patterns[0].lineageRIndex.length, 1); - test.equals(JSON.parse(patternlab.patterns[0].lineageR).lineagePattern, 'molecules-error'); - - test.done(); - }, - - 'find_lineage - finds lineage with spaced styleModifier' : function(test){ - //setup current pattern from what we would have during execution - var currentPattern = { - "name": "01-molecules-01-toast-00-error", - "subdir": "01-molecules\\01-toast", - "filename": "00-error.mustache", - "data": null, - "template": "{{> atoms-error:foo }}", - "patternPartial": "{{> atoms-error:foo }}", - "patternName": "error", - "patternLink": "01-molecules-01-toast-00-error/01-molecules-01-toast-00-error.html", - "patternGroup": "molecules", - "patternSubGroup": "molecules\\01-toast", - "flatPatternPath": "01-molecules\\01-toast", - "key": "molecules-error", - "patternState": "", - "lineage": [], - "lineageIndex": [], - "lineageR": [], - "lineageRIndex": [] - }; - 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", - "key": "atoms-error", - "patternState": "", - "lineage": [], - "lineageIndex": [], - "lineageR": [], - "lineageRIndex": [] - } - ] - }; - - var lineage_hunter = new lh(); - lineage_hunter.find_lineage(currentPattern, patternlab); - - test.equals(currentPattern.lineageIndex.length, 1); - test.equals(currentPattern.lineageIndex[0], "atoms-error"); - - test.done(); - }, - - 'find_lineage - finds lineage with unspaced styleModifier' : function(test){ - //setup current pattern from what we would have during execution - var currentPattern = { - "name": "01-molecules-01-toast-00-error", - "subdir": "01-molecules\\01-toast", - "filename": "00-error.mustache", - "data": null, - "template": "{{> atoms-error:foo }}", - "patternPartial": "{{>atoms-error:foo}}", - "patternName": "error", - "patternLink": "01-molecules-01-toast-00-error/01-molecules-01-toast-00-error.html", - "patternGroup": "molecules", - "patternSubGroup": "molecules\\01-toast", - "flatPatternPath": "01-molecules\\01-toast", - "key": "molecules-error", - "patternState": "", - "lineage": [], - "lineageIndex": [], - "lineageR": [], - "lineageRIndex": [] - }; - 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", - "key": "atoms-error", - "patternState": "", - "lineage": [], - "lineageIndex": [], - "lineageR": [], - "lineageRIndex": [] - } - ] - }; - - var lineage_hunter = new lh(); - lineage_hunter.find_lineage(currentPattern, patternlab); - - test.equals(currentPattern.lineageIndex.length, 1); - test.equals(currentPattern.lineageIndex[0], "atoms-error"); - - test.done(); - }, - - 'find_lineage - finds lineage with fuzzy partial with styleModifier' : function(test){ - //setup current pattern from what we would have during execution - var currentPattern = { - "name": "01-molecules-01-toast-00-error", - "subdir": "01-molecules\\01-toast", - "filename": "00-error.mustache", - "data": null, - "template": "{{> atoms-e:foo }}", - "patternPartial": "{{>atoms-e:foo}}", - "patternName": "error", - "patternLink": "01-molecules-01-toast-00-error/01-molecules-01-toast-00-error.html", - "patternGroup": "molecules", - "patternSubGroup": "molecules\\01-toast", - "flatPatternPath": "01-molecules\\01-toast", - "key": "molecules-error", - "patternState": "", - "lineage": [], - "lineageIndex": [], - "lineageR": [], - "lineageRIndex": [] - }; - 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", - "key": "atoms-error", - "patternState": "", - "lineage": [], - "lineageIndex": [], - "lineageR": [], - "lineageRIndex": [] - } - ] - }; - - var lineage_hunter = new lh(); - lineage_hunter.find_lineage(currentPattern, patternlab); - - test.equals(currentPattern.lineageIndex.length, 1); - test.equals(currentPattern.lineageIndex[0], "atoms-error"); - - test.done(); - }, - - 'find_lineage - does not apply lineage twice' : function(test){ - //setup current pattern from what we would have during execution - var currentPattern = { - "name": "01-molecules-01-toast-00-error", - "subdir": "01-molecules\\01-toast", - "filename": "00-error.mustache", - "data": null, - "template": "{{>atoms-error(message: 'That\'s no moon...')}}", - "patternPartial": "{{>atoms-error(message: 'That\'s no moon...')}}", - "patternName": "error", - "patternLink": "01-molecules-01-toast-00-error/01-molecules-01-toast-00-error.html", - "patternGroup": "molecules", - "patternSubGroup": "molecules\\01-toast", - "flatPatternPath": "01-molecules\\01-toast", - "key": "molecules-error", - "patternState": "", - "lineage": [], - "lineageIndex": [], - "lineageR": [], - "lineageRIndex": [] - }; - 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", - "key": "atoms-error", - "patternState": "", - "lineage": [], - "lineageIndex": [], - "lineageR": [], - "lineageRIndex": [] - } - ] - }; - - var lineage_hunter = new lh(); - lineage_hunter.find_lineage(currentPattern, patternlab); - lineage_hunter.find_lineage(currentPattern, patternlab); - - test.equals(currentPattern.lineageIndex.length, 1); - test.equals(currentPattern.lineageIndex[0], "atoms-error"); - test.equals(patternlab.patterns[0].lineageRIndex.length, 1); - test.equals(JSON.parse(patternlab.patterns[0].lineageR).lineagePattern, 'molecules-error'); - - test.done(); - } - - }; + "use strict"; + + var lh = require('../core/lib/lineage_hunter'); + var pa = require('../core/lib/pattern_assembler'); + var object_factory = require('../core/lib/object_factory'); + + var fs = require('fs-extra'); + var pattern_assembler = new pa(); + var lineage_hunter = new lh(); + + function createBasePatternLabObject() { + var patterns_dir = './test/files/_patterns/'; + var pl = {}; + pl.config = { + paths: { + source: { + patterns: patterns_dir + } + } + }; + pl.data = {}; + pl.data.link = {}; + pl.config.debug = false; + pl.patterns = []; + pl.partials = {}; + pl.config.patternStateCascade = ["inprogress", "inreview", "complete"]; + return pl; + } + + exports['lineage hunter '] = { + 'find_lineage - finds lineage' : function(test){ + + //setup current pattern from what we would have during execution + var currentPattern = { + "name": "02-organisms-00-global-00-header", + "subdir": "02-organisms\\00-global", + "filename": "00-header.mustache", + "data": null, + "template": "\r\n
\r\n\t{{> atoms-logo }}\r\n\tSearch\r\n\tMenu\r\n\t{{> molecules-primary-nav }}\r\n\t{{> molecules-search }}\r\n
\r\n\r\n", + "patternPartial": "\r\n
\r\n\"Logo\tSearch\r\n\tMenu\r\n\r\n
\r\n
\r\n\t Search\r\n\t \r\n\t \r\n\t \r\n
\r\n
\r\n\r\n", + "patternName": "header", + "patternLink": "02-organisms-00-global-00-header/02-organisms-00-global-00-header.html", + "patternGroup": "organisms", + "patternSubGroup": "organisms\\00-global", + "flatPatternPath": "02-organisms\\00-global", + "key": "organisms-header", + "patternState": "", + "lineage": [], + "lineageIndex": [], + "lineageR": [], + "lineageRIndex": [] + }; + var patternlab = { + patterns: [ + { + "name": "00-atoms-03-images-00-logo", + "subdir": "00-atoms\\03-images", + "filename": "00-logo.mustache", + "data": null, + "template": "\"Logo", + "patternPartial": "\"Logo", + "patternName": "logo", + "patternLink": "00-atoms-03-images-00-logo/00-atoms-03-images-00-logo.html", + "patternGroup": "atoms", + "patternSubGroup": "atoms\\03-images", + "flatPatternPath": "00-atoms\\03-images", + "key": "atoms-logo", + "patternState": "", + "lineage": [], + "lineageIndex": [], + "lineageR": [], + "lineageRIndex": [] + }, + { + "name": "01-molecules-05-navigation-00-primary-nav", + "subdir": "01-molecules\\05-navigation", + "filename": "00-primary-nav.mustache", + "data": null, + "template": "\r\n", + "patternPartial": "\r\n", + "patternName": "primary-nav", + "patternLink": "01-molecules-05-navigation-00-primary-nav/01-molecules-05-navigation-00-primary-nav.html", + "patternGroup": "molecules", + "patternSubGroup": "molecules\\05-navigation", + "flatPatternPath": "01-molecules\\05-navigation", + "key": "molecules-primary-nav", + "patternState": "", + "lineage": [], + "lineageIndex": [], + "lineageR": [], + "lineageRIndex": [] + }, + { + "name": "01-molecules-04-forms-00-search", + "subdir": "01-molecules\\04-forms", + "filename": "00-search.mustache", + "data": null, + "template": "
\r\n
\r\n\t Search\r\n\t \r\n\t \r\n\t \r\n
\r\n
", + "patternPartial": "
\r\n
\r\n\t Search\r\n\t \r\n\t \r\n\t \r\n
\r\n
", + "patternName": "search", + "patternLink": "01-molecules-04-forms-00-search/01-molecules-04-forms-00-search.html", + "patternGroup": "molecules", + "patternSubGroup": "molecules\\04-forms", + "flatPatternPath": "01-molecules\\04-forms", + "key": "molecules-search", + "patternState": "", + "lineage": [], + "lineageIndex": [], + "lineageR": [], + "lineageRIndex": [] + } + ] + }; + + lineage_hunter.find_lineage(currentPattern, patternlab); + + test.equals(currentPattern.lineageIndex.length, 3); + test.equals(currentPattern.lineageIndex[0], "atoms-logo"); + test.equals(currentPattern.lineageIndex[1], "molecules-primary-nav"); + test.equals(currentPattern.lineageIndex[2], "molecules-search"); + + test.done(); + }, + + 'find_lineage - finds lineage with spaced pattern parameters' : function(test){ + //setup current pattern from what we would have during execution + var currentPattern = { + "name": "01-molecules-01-toast-00-error", + "subdir": "01-molecules\\01-toast", + "filename": "00-error.mustache", + "data": null, + "template": "{{> atoms-error(message: 'That\'s no moon...') }}", + "patternPartial": "{{> atoms-error(message: 'That\'s no moon...') }}", + "patternName": "error", + "patternLink": "01-molecules-01-toast-00-error/01-molecules-01-toast-00-error.html", + "patternGroup": "molecules", + "patternSubGroup": "molecules\\01-toast", + "flatPatternPath": "01-molecules\\01-toast", + "key": "molecules-error", + "patternState": "", + "lineage": [], + "lineageIndex": [], + "lineageR": [], + "lineageRIndex": [] + }; + 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", + "key": "atoms-error", + "patternState": "", + "lineage": [], + "lineageIndex": [], + "lineageR": [], + "lineageRIndex": [] + } + ] + }; + + lineage_hunter.find_lineage(currentPattern, patternlab); + + test.equals(currentPattern.lineageIndex.length, 1); + test.equals(currentPattern.lineageIndex[0], "atoms-error"); + + test.done(); + }, + + 'find_lineage - finds lineage with unspaced pattern parameters' : function(test){ + //setup current pattern from what we would have during execution + var currentPattern = { + "name": "01-molecules-01-toast-00-error", + "subdir": "01-molecules\\01-toast", + "filename": "00-error.mustache", + "data": null, + "template": "{{>atoms-error(message: 'That\'s no moon...')}}", + "patternPartial": "{{>atoms-error(message: 'That\'s no moon...')}}", + "patternName": "error", + "patternLink": "01-molecules-01-toast-00-error/01-molecules-01-toast-00-error.html", + "patternGroup": "molecules", + "patternSubGroup": "molecules\\01-toast", + "flatPatternPath": "01-molecules\\01-toast", + "key": "molecules-error", + "patternState": "", + "lineage": [], + "lineageIndex": [], + "lineageR": [], + "lineageRIndex": [] + }; + 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", + "key": "atoms-error", + "patternState": "", + "lineage": [], + "lineageIndex": [], + "lineageR": [], + "lineageRIndex": [] + } + ] + }; + + lineage_hunter.find_lineage(currentPattern, patternlab); + + test.equals(currentPattern.lineageIndex.length, 1); + test.equals(currentPattern.lineageIndex[0], "atoms-error"); + test.equals(patternlab.patterns[0].lineageRIndex.length, 1); + test.equals(patternlab.patterns[0].lineageR[0].lineagePattern, 'molecules-error'); + + test.done(); + }, + + 'find_lineage - finds lineage with spaced styleModifier' : function(test){ + //setup current pattern from what we would have during execution + var currentPattern = { + "name": "01-molecules-01-toast-00-error", + "subdir": "01-molecules\\01-toast", + "filename": "00-error.mustache", + "data": null, + "template": "{{> atoms-error:foo }}", + "patternPartial": "{{> atoms-error:foo }}", + "patternName": "error", + "patternLink": "01-molecules-01-toast-00-error/01-molecules-01-toast-00-error.html", + "patternGroup": "molecules", + "patternSubGroup": "molecules\\01-toast", + "flatPatternPath": "01-molecules\\01-toast", + "key": "molecules-error", + "patternState": "", + "lineage": [], + "lineageIndex": [], + "lineageR": [], + "lineageRIndex": [] + }; + 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", + "key": "atoms-error", + "patternState": "", + "lineage": [], + "lineageIndex": [], + "lineageR": [], + "lineageRIndex": [] + } + ] + }; + + lineage_hunter.find_lineage(currentPattern, patternlab); + + test.equals(currentPattern.lineageIndex.length, 1); + test.equals(currentPattern.lineageIndex[0], "atoms-error"); + + test.done(); + }, + + 'find_lineage - finds lineage with unspaced styleModifier' : function(test){ + //setup current pattern from what we would have during execution + var currentPattern = { + "name": "01-molecules-01-toast-00-error", + "subdir": "01-molecules\\01-toast", + "filename": "00-error.mustache", + "data": null, + "template": "{{> atoms-error:foo }}", + "patternPartial": "{{>atoms-error:foo}}", + "patternName": "error", + "patternLink": "01-molecules-01-toast-00-error/01-molecules-01-toast-00-error.html", + "patternGroup": "molecules", + "patternSubGroup": "molecules\\01-toast", + "flatPatternPath": "01-molecules\\01-toast", + "key": "molecules-error", + "patternState": "", + "lineage": [], + "lineageIndex": [], + "lineageR": [], + "lineageRIndex": [] + }; + 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", + "key": "atoms-error", + "patternState": "", + "lineage": [], + "lineageIndex": [], + "lineageR": [], + "lineageRIndex": [] + } + ] + }; + + lineage_hunter.find_lineage(currentPattern, patternlab); + + test.equals(currentPattern.lineageIndex.length, 1); + test.equals(currentPattern.lineageIndex[0], "atoms-error"); + + test.done(); + }, + + 'find_lineage - finds lineage with fuzzy partial with styleModifier' : function(test){ + //setup current pattern from what we would have during execution + var currentPattern = { + "name": "01-molecules-01-toast-00-error", + "subdir": "01-molecules\\01-toast", + "filename": "00-error.mustache", + "data": null, + "template": "{{> atoms-e:foo }}", + "patternPartial": "{{>atoms-e:foo}}", + "patternName": "error", + "patternLink": "01-molecules-01-toast-00-error/01-molecules-01-toast-00-error.html", + "patternGroup": "molecules", + "patternSubGroup": "molecules\\01-toast", + "flatPatternPath": "01-molecules\\01-toast", + "key": "molecules-error", + "patternState": "", + "lineage": [], + "lineageIndex": [], + "lineageR": [], + "lineageRIndex": [] + }; + 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", + "key": "atoms-error", + "patternState": "", + "lineage": [], + "lineageIndex": [], + "lineageR": [], + "lineageRIndex": [] + } + ] + }; + + lineage_hunter.find_lineage(currentPattern, patternlab); + + test.equals(currentPattern.lineageIndex.length, 1); + test.equals(currentPattern.lineageIndex[0], "atoms-error"); + + test.done(); + }, + + 'find_lineage - does not apply lineage twice' : function(test){ + //setup current pattern from what we would have during execution + var currentPattern = { + "name": "01-molecules-01-toast-00-error", + "subdir": "01-molecules\\01-toast", + "filename": "00-error.mustache", + "data": null, + "template": "{{>atoms-error(message: 'That\'s no moon...')}}", + "patternPartial": "{{>atoms-error(message: 'That\'s no moon...')}}", + "patternName": "error", + "patternLink": "01-molecules-01-toast-00-error/01-molecules-01-toast-00-error.html", + "patternGroup": "molecules", + "patternSubGroup": "molecules\\01-toast", + "flatPatternPath": "01-molecules\\01-toast", + "key": "molecules-error", + "patternState": "", + "lineage": [], + "lineageIndex": [], + "lineageR": [], + "lineageRIndex": [] + }; + 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", + "key": "atoms-error", + "patternState": "", + "lineage": [], + "lineageIndex": [], + "lineageR": [], + "lineageRIndex": [] + } + ] + }; + + lineage_hunter.find_lineage(currentPattern, patternlab); + lineage_hunter.find_lineage(currentPattern, patternlab); + + test.equals(currentPattern.lineageIndex.length, 1); + test.equals(currentPattern.lineageIndex[0], "atoms-error"); + test.equals(patternlab.patterns[0].lineageRIndex.length, 1); + test.equals(patternlab.patterns[0].lineageR[0].lineagePattern, 'molecules-error'); + + test.done(); + }, + + 'cascade_pattern_states promotes a lower pattern state up to the consumer' : function(test){ + //arrange + var pl = createBasePatternLabObject(); + pl.config.patternStates = { + "test-foo" : "complete", + "test-bar" : "inreview" + }; + + var atomPattern = new object_factory.oPattern('test/files/_patterns/00-test/01-bar.mustache', '00-test', '01-bar.mustache'); + atomPattern.template = fs.readFileSync(pl.config.paths.source.patterns + '00-test/01-bar.mustache', 'utf8'); + atomPattern.extendedTemplate = atomPattern.template; + + pattern_assembler.setPatternState(atomPattern, pl); + pattern_assembler.addPattern(atomPattern, pl); + + var consumerPattern = new object_factory.oPattern('test/files/_patterns/00-test/00-foo.mustache', '00-test', '00-foo.mustache'); + consumerPattern.template = fs.readFileSync(pl.config.paths.source.patterns + '00-test/00-foo.mustache', 'utf8'); + consumerPattern.extendedTemplate = consumerPattern.template; + pattern_assembler.setPatternState(consumerPattern, pl); + pattern_assembler.addPattern(consumerPattern, pl); + + lineage_hunter.find_lineage(consumerPattern, pl); + + //act + lineage_hunter.cascade_pattern_states(pl); + + //assert + var consumerPatternReturned = pattern_assembler.get_pattern_by_key('test-foo', pl); + test.equals(consumerPatternReturned.patternState, 'inreview'); + test.done(); + }, + + 'cascade_pattern_states promotes a lower pattern state up to the consumers lineage' : function(test){ + //arrange + var pl = createBasePatternLabObject(); + pl.config.patternStates = { + "test-foo" : "complete", + "test-bar" : "inreview" + }; + + var atomPattern = new object_factory.oPattern('test/files/_patterns/00-test/01-bar.mustache', '00-test', '01-bar.mustache'); + atomPattern.template = fs.readFileSync(pl.config.paths.source.patterns + '00-test/01-bar.mustache', 'utf8'); + atomPattern.extendedTemplate = atomPattern.template; + + pattern_assembler.setPatternState(atomPattern, pl); + pattern_assembler.addPattern(atomPattern, pl); + + var consumerPattern = new object_factory.oPattern('test/files/_patterns/00-test/00-foo.mustache', '00-test', '00-foo.mustache'); + consumerPattern.template = fs.readFileSync(pl.config.paths.source.patterns + '00-test/00-foo.mustache', 'utf8'); + consumerPattern.extendedTemplate = consumerPattern.template; + pattern_assembler.setPatternState(consumerPattern, pl); + pattern_assembler.addPattern(consumerPattern, pl); + + lineage_hunter.find_lineage(consumerPattern, pl); + + //act + lineage_hunter.cascade_pattern_states(pl); + + //assert + var consumerPatternReturned = pattern_assembler.get_pattern_by_key('test-foo', pl); + test.equals(consumerPatternReturned.lineage[0].lineageState, 'inreview'); + test.done(); + }, + + 'cascade_pattern_states sets the pattern state on any lineage patterns reverse lineage' : function(test){ + //arrange + var pl = createBasePatternLabObject(); + pl.config.patternStates = { + "test-foo" : "complete", + "test-bar" : "inreview" + }; + + var atomPattern = new object_factory.oPattern('test/files/_patterns/00-test/01-bar.mustache', '00-test', '01-bar.mustache'); + atomPattern.template = fs.readFileSync(pl.config.paths.source.patterns + '00-test/01-bar.mustache', 'utf8'); + atomPattern.extendedTemplate = atomPattern.template; + + pattern_assembler.setPatternState(atomPattern, pl); + pattern_assembler.addPattern(atomPattern, pl); + + var consumerPattern = new object_factory.oPattern('test/files/_patterns/00-test/00-foo.mustache', '00-test', '00-foo.mustache'); + consumerPattern.template = fs.readFileSync(pl.config.paths.source.patterns + '00-test/00-foo.mustache', 'utf8'); + consumerPattern.extendedTemplate = consumerPattern.template; + pattern_assembler.setPatternState(consumerPattern, pl); + pattern_assembler.addPattern(consumerPattern, pl); + + lineage_hunter.find_lineage(consumerPattern, pl); + + //act + lineage_hunter.cascade_pattern_states(pl); + + //assert + var consumedPatternReturned = pattern_assembler.get_pattern_by_key('test-bar', pl); + test.equals(consumedPatternReturned.lineageR[0].lineageState, 'inreview'); + + test.done(); + }, + + 'cascade_pattern_states does not promote lower pattern state when consumer does not display its own state' : function(test){ + //arrange + var pl = createBasePatternLabObject(); + pl.config.patternStates = { + "test-bar" : "inreview" + }; + + var atomPattern = new object_factory.oPattern('test/files/_patterns/00-test/01-bar.mustache', '00-test', '01-bar.mustache'); + atomPattern.template = fs.readFileSync(pl.config.paths.source.patterns + '00-test/01-bar.mustache', 'utf8'); + atomPattern.extendedTemplate = atomPattern.template; + + pattern_assembler.setPatternState(atomPattern, pl); + pattern_assembler.addPattern(atomPattern, pl); + + var consumerPattern = new object_factory.oPattern('test/files/_patterns/00-test/00-foo.mustache', '00-test', '00-foo.mustache'); + consumerPattern.template = fs.readFileSync(pl.config.paths.source.patterns + '00-test/00-foo.mustache', 'utf8'); + consumerPattern.extendedTemplate = consumerPattern.template; + pattern_assembler.setPatternState(consumerPattern, pl); + pattern_assembler.addPattern(consumerPattern, pl); + + lineage_hunter.find_lineage(consumerPattern, pl); + + //act + lineage_hunter.cascade_pattern_states(pl); + + //assert + var consumerPatternReturned = pattern_assembler.get_pattern_by_key('test-foo', pl); + test.equals(consumerPatternReturned.lineage.length, 1); + test.equals(consumerPatternReturned.lineage[0].lineageState, 'inreview'); + test.equals(consumerPatternReturned.patternState, ''); + test.done(); + } + + }; }()); diff --git a/test/pattern_assembler_tests.js b/test/pattern_assembler_tests.js index 14d6cc3f7..d85933a92 100644 --- a/test/pattern_assembler_tests.js +++ b/test/pattern_assembler_tests.js @@ -576,10 +576,10 @@ var patternlab = {}; patternlab.config = {}; patternlab.config.patternStates = {}; - patternlab.config.patternStates["homepage-emergency"] = "inprogress"; + patternlab.config.patternStates["pages-homepage-emergency"] = "inprogress"; var pattern = { - patternName: "homepage-emergency" + key: "pages-homepage-emergency" }; //act @@ -596,10 +596,10 @@ var patternlab = {}; patternlab.config = {}; patternlab.config.patternStates = {}; - patternlab.config.patternStates["homepage-emergency"] = "inprogress"; + patternlab.config.patternStates["pages-homepage-emergency"] = "inprogress"; var pattern = { - patternName: "homepage" + patternName: "pages-homepage" }; //act From 5090a2639218b951728c231ff81fe2f5c0fa3fb8 Mon Sep 17 00:00:00 2001 From: BRIAN MUENZENMEYER Date: Wed, 9 Mar 2016 21:55:38 -0600 Subject: [PATCH 2/3] futher clarify pattern states --- README.md | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 398df1c2a..307a5bd06 100644 --- a/README.md +++ b/README.md @@ -144,8 +144,7 @@ The current selection is as follows. } ``` ##### Pattern States -You can set the state of a pattern by including it in `patternlab-config.json` too. The out of the box styles are in progress (orange), in review (yellow), and complete (green). -Pattern states should be lowercase and use hyphens where spaces are present. +You can set the state of a pattern by including its key in the `patternStates` object in `patternlab-config.json`, along with a style defined inside `patternStateCascade`. The out of the box styles are in progress (orange), in review (yellow), and complete (green). ``` "patternStates": { "atoms-colors" : "complete", @@ -168,6 +167,30 @@ In this case, two things are of note: * templates-article will display inreview since it inherits `organisms-sticky-comment` * pages-article will not display any pattern state, as it does not define one +The `patternStateCascade` array is important in that the order is hierarchical. +The default is below: + +``` +"patternStateCascade": ["inprogress", "inreview", "complete"], +``` + +which correspond to classes defined inside `./core/styleguide/css/styleguide.css` + +``` +/* pattern states */ +.inprogress:before { + color: #FF4136 !important; +} + +.inreview:before { + color: #FFCC00 !important; +} + +.complete:before { + color: #2ECC40 !important; +} +``` + ##### Pattern Export `patternlab-config.json` also has two properties that work together to export completed patterns for use in a production environment. Provide an array of keys and an output directory. Pattern Lab doesn't ship with any pattern export keys, but the default directory is `"./pattern_exports/"` created inside the install directory. From 9ceb4ed1360583d48f56798c9e993156f2dd1099 Mon Sep 17 00:00:00 2001 From: BRIAN MUENZENMEYER Date: Wed, 9 Mar 2016 22:01:42 -0600 Subject: [PATCH 3/3] fix an errant typo in a unit test --- test/pattern_assembler_tests.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/pattern_assembler_tests.js b/test/pattern_assembler_tests.js index d85933a92..2b42a95e6 100644 --- a/test/pattern_assembler_tests.js +++ b/test/pattern_assembler_tests.js @@ -599,7 +599,7 @@ patternlab.config.patternStates["pages-homepage-emergency"] = "inprogress"; var pattern = { - patternName: "pages-homepage" + key: "pages-homepage" }; //act