diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..8951c3929 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +# editorconfig.org +root = true + +[*] +indent_style = space +indent_size = 2 +tab_width = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 000000000..d52103feb --- /dev/null +++ b/.eslintrc @@ -0,0 +1,83 @@ +{ + "env": { + "node": true, + "builtin": true + }, + "globals": {}, + "rules": { + "block-scoped-var": 0, + "camelcase": 0, + "comma-spacing": [1, {"before": false, "after": true}], + "consistent-return": 2, + "curly": [2, "all"], + "dot-notation": [1, { "allowKeywords": true }], + "eqeqeq": [2, "allow-null"], + "global-strict": [0, "never"], + "guard-for-in": 2, + "indent": [2, 2, {"SwitchCase": 1, "VariableDeclarator": 1}], + "lines-around-comment": [2, { + "beforeBlockComment": true, + "beforeLineComment": true, + "allowBlockStart": true, + "allowObjectStart": true, + "allowArrayStart": true + }], + "key-spacing": 0, + "keyword-spacing": 1, + "new-cap": 0, + "no-alert": 2, + "no-bitwise": 2, + "no-caller": 2, + "no-cond-assign": [2, "except-parens"], + "no-debugger": 2, + "no-dupe-args": 2, + "no-dupe-keys": 2, + "no-empty": 2, + "no-eval": 2, + "no-extend-native": 2, + "no-extra-bind": 2, + "no-extra-parens": 0, + "no-extra-semi": 2, + "no-func-assign": 2, + "no-implied-eval": 2, + "no-invalid-regexp": 2, + "no-irregular-whitespace": 1, + "no-iterator": 2, + "no-loop-func": 2, + "no-mixed-requires": 0, + "no-multi-str": 2, + "no-multi-spaces": 1, + "no-native-reassign": 2, + "no-new": 2, + "no-param-reassign": 1, + "no-proto": 2, + "no-redeclare": 0, + "no-script-url": 2, + "no-self-assign": 2, + "no-self-compare": 2, + "no-sequences": 2, + "no-shadow": 2, + "no-undef": 2, + "no-underscore-dangle": 0, + "no-unreachable": 1, + "no-unused-vars": 1, + "no-use-before-define": 1, + "no-useless-call": 2, + "no-useless-concat": 2, + "no-with": 2, + "quotes": [0, "single"], + "radix": 2, + "semi": [0, "never"], + "strict": 0, + "space-before-blocks": 1, + "space-before-function-paren": [1, { + "anonymous": "always", + "named": "never" + }], + "space-in-parens": [1, "never"], + "space-infix-ops": 1, + "valid-typeof": 2, + "vars-on-top": 0, + "wrap-iife": [2, "inside"] + } +} diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 7edd1a3d0..8598cddb2 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,5 +1,5 @@ # Contributing to Patternlab Node -If you'd like to contribute to Pattern Lab Node, please do so! There is always a lot of ground to cover and something for your wheelhouse. +If you'd like to contribute to Pattern Lab Node, please do so! There is always a lot of ground to cover and something for your wheelhouse. 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, or add some more unit tests. @@ -9,4 +9,7 @@ No pull request is too small. Check out any [up for grabs issues](https://github 3. If you can, add some unit tests using the existing patterns in the `./test` directory ##Coding style -Regarding code style like indentation and whitespace, follow the conventions you see used in the source already. Add enough source code comments to help the next person. +Two files combine within the project to define and maintain our coding style. + +* The `.editorconfig` controls spaces / tabs within supported editors. Check out their [site](http://editorconfig.org/). +* The `.eslintrc` defines our javascript standards. Some editors will evaluate this real-time - otherwise it's run using `grunt|gulp build` diff --git a/.jslintrc b/.jslintrc deleted file mode 100644 index 8ac6b2e37..000000000 --- a/.jslintrc +++ /dev/null @@ -1,36 +0,0 @@ -{ - "ass": false, - "bitwise": false, - "browser": false, - "closure": false, - "continue": false, - "couch": false, - "debug": false, - "devel": true, - "eqeq": false, - "eval": true, - "evil": false, - "forin": false, - "indent": 2, - "maxerr": 50, - "maxlen": false, - "newcap": false, - "node": true, - "nomen": false, - "passfail": false, - "plusplus": false, - "predef": [ - "node", - "$", - "require" - ], - "regexp": false, - "rhino": false, - "sloppy": false, - "stupid": false, - "sub": false, - "todo": false, - "unparam": true, - "vars": false, - "white": true -} diff --git a/Gruntfile.js b/Gruntfile.js index 4eef71c14..2dfa9be8a 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -1,161 +1,167 @@ -module.exports = function(grunt) { +module.exports = function (grunt) { - var path = require('path'); + var path = require('path'); - // Project configuration. - grunt.initConfig({ - pkg: grunt.file.readJSON('package.json'), - concat: { - options: { - stripBanners: true, - banner: '/* \n * <%= pkg.name %> - v<%= pkg.version %> - <%= grunt.template.today("yyyy") %> \n * \n * <%= pkg.author %>, and the web community.\n * Licensed under the <%= pkg.license %> license. \n * \n * Many thanks to Brad Frost and Dave Olsen for inspiration, encouragement, and advice. \n *\n */\n\n', - }, - patternlab: { - src: './builder/patternlab.js', - dest: './builder/patternlab.js' - }, - object_factory: { - src: './builder/object_factory.js', - dest: './builder/object_factory.js' - }, - lineage: { - src: './builder/lineage_hunter.js', - dest: './builder/lineage_hunter.js' - }, - media_hunter: { - src: './builder/media_hunter.js', - dest: './builder/media_hunter.js' - }, - patternlab_grunt: { - src: './builder/patternlab_grunt.js', - dest: './builder/patternlab_grunt.js' - }, - patternlab_gulp: { - src: './builder/patternlab_gulp.js', - dest: './builder/patternlab_gulp.js' - }, - parameter_hunter: { - src: './builder/parameter_hunter.js', - dest: './builder/parameter_hunter.js' - }, - pattern_exporter: { - src: './builder/pattern_exporter.js', - dest: './builder/pattern_exporter.js' - }, - pattern_assembler: { - src: './builder/pattern_assembler.js', - dest: './builder/pattern_assembler.js' - }, - pseudopattern_hunter: { - src: './builder/pseudopattern_hunter.js', - dest: './builder/pseudopattern_hunter.js' - }, - list_item_hunter: { - src: './builder/list_item_hunter.js', - dest: './builder/list_item_hunter.js' - }, - style_modifier_hunter: { - src: './builder/style_modifier_hunter.js', - dest: './builder/style_modifier_hunter.js' - } - }, - copy: { - main: { - files: [ - { expand: true, cwd: path.resolve(paths().source.js), src: '*.js', dest: path.resolve(paths().public.js) }, - { expand: true, cwd: path.resolve(paths().source.css), src: '*.css', dest: path.resolve(paths().public.css) }, - { expand: true, cwd: path.resolve(paths().source.images), src: ['**/*.png', '**/*.jpg', '**/*.gif', '**/*.jpeg'], dest: path.resolve(paths().public.images) }, - { expand: true, cwd: path.resolve(paths().source.fonts), src: '*', dest: path.resolve(paths().public.fonts) }, - { expand: true, cwd: path.resolve(paths().source.data), src: 'annotations.js', dest: path.resolve(paths().public.data) } - ] - }, - styleguide: { - files: [ - { expand: true, cwd: path.resolve(paths().source.styleguide), src: ['*.*', '**/*.*'], dest: path.resolve(paths().public.styleguide) } - ] - } - }, - watch: { - all: { - files: [ - path.resolve(paths().source.css + '**/*.css'), - path.resolve(paths().source.styleguide + 'css/*.css'), - path.resolve(paths().source.patterns + '**/*.mustache'), - path.resolve(paths().source.patterns + '**/*.json'), - path.resolve(paths().source.fonts + '/*'), - path.resolve(paths().source.images + '/*'), - path.resolve(paths().source.data + '*.json') - ], - tasks: ['default', 'bsReload:css'] - } - }, - nodeunit: { - all: ['test/*_tests.js'] - }, - browserSync: { - dev: { - options: { - server: path.resolve(paths().public.root), - watchTask: true, - watchOptions: { - ignoreInitial: true, - ignored: '*.html' - }, - snippetOptions: { - // Ignore all HTML files within the templates folder - blacklist: ['/index.html', '/', '/?*'] - }, - plugins: [ - { - module: 'bs-html-injector', - options: { - files: [path.resolve(paths().public.root + '/index.html'), path.resolve(paths().public.styleguide + '/styleguide.html')] - } - } - ], - notify: { - styles: [ - 'display: none', - 'padding: 15px', - 'font-family: sans-serif', - 'position: fixed', - 'font-size: 1em', - 'z-index: 9999', - 'bottom: 0px', - 'right: 0px', - 'border-top-left-radius: 5px', - 'background-color: #1B2032', - 'opacity: 0.4', - 'margin: 0', - 'color: white', - 'text-align: center' - ] - } - } - } - }, - bsReload: { - css: path.resolve(paths().public.root + '**/*.css') - } - }); + function paths() { + return require('./config.json').paths; + } - function paths () { - return require('./config.json').paths; - } + // Project configuration. + grunt.initConfig({ + pkg: grunt.file.readJSON('package.json'), + concat: { + options: { + stripBanners: true, + banner: '/* \n * <%= pkg.name %> - v<%= pkg.version %> - <%= grunt.template.today("yyyy") %> \n * \n * <%= pkg.author %>, and the web community.\n * Licensed under the <%= pkg.license %> license. \n * \n * Many thanks to Brad Frost and Dave Olsen for inspiration, encouragement, and advice. \n *\n */\n\n', + }, + patternlab: { + src: './builder/patternlab.js', + dest: './builder/patternlab.js' + }, + object_factory: { + src: './builder/object_factory.js', + dest: './builder/object_factory.js' + }, + lineage: { + src: './builder/lineage_hunter.js', + dest: './builder/lineage_hunter.js' + }, + media_hunter: { + src: './builder/media_hunter.js', + dest: './builder/media_hunter.js' + }, + patternlab_grunt: { + src: './builder/patternlab_grunt.js', + dest: './builder/patternlab_grunt.js' + }, + patternlab_gulp: { + src: './builder/patternlab_gulp.js', + dest: './builder/patternlab_gulp.js' + }, + parameter_hunter: { + src: './builder/parameter_hunter.js', + dest: './builder/parameter_hunter.js' + }, + pattern_exporter: { + src: './builder/pattern_exporter.js', + dest: './builder/pattern_exporter.js' + }, + pattern_assembler: { + src: './builder/pattern_assembler.js', + dest: './builder/pattern_assembler.js' + }, + pseudopattern_hunter: { + src: './builder/pseudopattern_hunter.js', + dest: './builder/pseudopattern_hunter.js' + }, + list_item_hunter: { + src: './builder/list_item_hunter.js', + dest: './builder/list_item_hunter.js' + }, + style_modifier_hunter: { + src: './builder/style_modifier_hunter.js', + dest: './builder/style_modifier_hunter.js' + } + }, + copy: { + main: { + files: [ + { expand: true, cwd: path.resolve(paths().source.js), src: '*.js', dest: path.resolve(paths().public.js) }, + { expand: true, cwd: path.resolve(paths().source.css), src: '*.css', dest: path.resolve(paths().public.css) }, + { expand: true, cwd: path.resolve(paths().source.images), src: ['**/*.png', '**/*.jpg', '**/*.gif', '**/*.jpeg'], dest: path.resolve(paths().public.images) }, + { expand: true, cwd: path.resolve(paths().source.fonts), src: '*', dest: path.resolve(paths().public.fonts) }, + { expand: true, cwd: path.resolve(paths().source.data), src: 'annotations.js', dest: path.resolve(paths().public.data) } + ] + }, + styleguide: { + files: [ + { expand: true, cwd: path.resolve(paths().source.styleguide), src: ['*.*', '**/*.*'], dest: path.resolve(paths().public.styleguide) } + ] + } + }, + watch: { + all: { + files: [ + path.resolve(paths().source.css + '**/*.css'), + path.resolve(paths().source.styleguide + 'css/*.css'), + path.resolve(paths().source.patterns + '**/*.mustache'), + path.resolve(paths().source.patterns + '**/*.json'), + path.resolve(paths().source.fonts + '/*'), + path.resolve(paths().source.images + '/*'), + path.resolve(paths().source.data + '*.json') + ], + tasks: ['default', 'bsReload:css'] + } + }, + nodeunit: { + all: ['test/*_tests.js'] + }, + browserSync: { + dev: { + options: { + server: path.resolve(paths().public.root), + watchTask: true, + watchOptions: { + ignoreInitial: true, + ignored: '*.html' + }, + snippetOptions: { + // Ignore all HTML files within the templates folder + blacklist: ['/index.html', '/', '/?*'] + }, + plugins: [ + { + module: 'bs-html-injector', + options: { + files: [path.resolve(paths().public.root + '/index.html'), path.resolve(paths().public.styleguide + '/styleguide.html')] + } + } + ], + notify: { + styles: [ + 'display: none', + 'padding: 15px', + 'font-family: sans-serif', + 'position: fixed', + 'font-size: 1em', + 'z-index: 9999', + 'bottom: 0px', + 'right: 0px', + 'border-top-left-radius: 5px', + 'background-color: #1B2032', + 'opacity: 0.4', + 'margin: 0', + 'color: white', + 'text-align: center' + ] + } + } + } + }, + eslint: { + options: { + configFile: './.eslintrc' + }, + target: ['./builder/*'] + }, + bsReload: { + css: path.resolve(paths().public.root + '**/*.css') + } + }); - // load all grunt tasks - require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks); + // load all grunt tasks + require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks); - //load the patternlab task - grunt.task.loadTasks('./builder/'); + //load the patternlab task + grunt.task.loadTasks('./builder/'); - grunt.registerTask('default', ['patternlab', 'copy:main', 'copy:styleguide']); + grunt.registerTask('default', ['patternlab', 'copy:main', 'copy:styleguide']); - //travis CI task - grunt.registerTask('travis', ['nodeunit', 'patternlab']); + //travis CI task + grunt.registerTask('travis', ['nodeunit', 'eslint', 'patternlab']); - grunt.registerTask('serve', ['patternlab', 'copy:main', 'copy:styleguide', 'browserSync', 'watch:all']); + grunt.registerTask('serve', ['patternlab', 'copy:main', 'copy:styleguide', 'browserSync', 'watch:all']); - grunt.registerTask('build', ['nodeunit', 'concat']); + grunt.registerTask('build', ['nodeunit', 'eslint', 'concat']); }; diff --git a/builder/lineage_hunter.js b/builder/lineage_hunter.js index 7325a5fde..65a0e35cc 100644 --- a/builder/lineage_hunter.js +++ b/builder/lineage_hunter.js @@ -1,76 +1,79 @@ -/* - * patternlab-node - v1.1.3 - 2016 - * +/* + * patternlab-node - v1.1.3 - 2016 + * * 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. * */ -(function () { - "use strict"; - - var lineage_hunter = function(){ - - function findlineage(pattern, patternlab){ - - var pa = require('./pattern_assembler'); - var pattern_assembler = new pa(); - - //find the {{> template-name }} within patterns - var matches = pattern_assembler.find_pattern_partials(pattern); - if(matches !== null){ - matches.forEach(function(match, index, matches){ - //strip out the template cruft - var foundPatternKey = match.replace("{{> ", "").replace(" }}", "").replace("{{>", "").replace("}}", ""); - - // remove any potential pattern parameters. this and the above are rather brutish but I didn't want to do a regex at the time - if(foundPatternKey.indexOf('(') > 0){ - foundPatternKey = foundPatternKey.substring(0, foundPatternKey.indexOf('(')); - } - - //remove any potential stylemodifiers. - foundPatternKey = foundPatternKey.split(':')[0]; - - //get the ancestorPattern - var ancestorPattern = pattern_assembler.get_pattern_by_key(foundPatternKey, patternlab); - - if (ancestorPattern && pattern.lineageIndex.indexOf(ancestorPattern.key) === -1){ - - //add it since it didnt exist - pattern.lineageIndex.push(ancestorPattern.key); - //create the more complex patternLineage object too - var l = { - "lineagePattern": ancestorPattern.key, - "lineagePath": "../../patterns/" + ancestorPattern.patternLink - }; - pattern.lineage.push(JSON.stringify(l)); - - //also, add the lineageR entry if it doesn't exist - if (ancestorPattern.lineageRIndex.indexOf(pattern.key) === -1){ - ancestorPattern.lineageRIndex.push(pattern.key); - - //create the more complex patternLineage object in reverse - var lr = { - "lineagePattern": pattern.key, - "lineagePath": "../../patterns/" + pattern.patternLink - }; - ancestorPattern.lineageR.push(JSON.stringify(lr)); - } - } - }); - } - } - - return { - find_lineage: function(pattern, patternlab){ - findlineage(pattern, patternlab); - } - }; - - }; - - module.exports = lineage_hunter; - -}()); +"use strict"; + +var lineage_hunter = function () { + + function findlineage(pattern, patternlab) { + + var pa = require('./pattern_assembler'); + var pattern_assembler = new pa(); + + //find the {{> template-name }} within patterns + var matches = pattern_assembler.find_pattern_partials(pattern); + if (matches !== null) { + matches.forEach(function (match) { + //strip out the template cruft + var foundPatternKey = match + .replace("{{> ", "") + .replace(" }}", "") + .replace("{{>", "") + .replace("}}", ""); + + // remove any potential pattern parameters. this and the above are + // rather brutish but I didn't want to do a regex at the time + if (foundPatternKey.indexOf('(') > 0) { + foundPatternKey = foundPatternKey.substring(0, foundPatternKey.indexOf('(')); + } + + //remove any potential stylemodifiers. + foundPatternKey = foundPatternKey.split(':')[0]; + + //get the ancestorPattern + var ancestorPattern = pattern_assembler.get_pattern_by_key(foundPatternKey, patternlab); + + if (ancestorPattern && pattern.lineageIndex.indexOf(ancestorPattern.key) === -1) { + + //add it since it didnt exist + pattern.lineageIndex.push(ancestorPattern.key); + + //create the more complex patternLineage object too + var l = { + "lineagePattern": ancestorPattern.key, + "lineagePath": "../../patterns/" + ancestorPattern.patternLink + }; + pattern.lineage.push(JSON.stringify(l)); + + //also, add the lineageR entry if it doesn't exist + if (ancestorPattern.lineageRIndex.indexOf(pattern.key) === -1) { + ancestorPattern.lineageRIndex.push(pattern.key); + + //create the more complex patternLineage object in reverse + var lr = { + "lineagePattern": pattern.key, + "lineagePath": "../../patterns/" + pattern.patternLink + }; + ancestorPattern.lineageR.push(JSON.stringify(lr)); + } + } + }); + } + } + + return { + find_lineage: function (pattern, patternlab) { + findlineage(pattern, patternlab); + } + }; + +}; + +module.exports = lineage_hunter; diff --git a/builder/list_item_hunter.js b/builder/list_item_hunter.js index 93aa57890..7fcf3d188 100644 --- a/builder/list_item_hunter.js +++ b/builder/list_item_hunter.js @@ -1,120 +1,115 @@ -/* - * patternlab-node - v1.1.3 - 2016 - * +/* + * patternlab-node - v1.1.3 - 2016 + * * 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. * */ -(function () { - "use strict"; - - var list_item_hunter = function(){ - - var extend = require('util')._extend, - pa = require('./pattern_assembler'), - smh = require('./style_modifier_hunter'), - mustache = require('mustache'), - pattern_assembler = new pa(), - style_modifier_hunter = new smh(), - items = [ 'zero','one','two','three','four','five','six','seven','eight','nine','ten','eleven','twelve','thirteen','fourteen','fifteen','sixteen','seventeen','eighteen','nineteen','twenty']; - - function processListItemPartials(pattern, patternlab){ - //find any listitem blocks - var matches = pattern_assembler.find_list_items(pattern, patternlab); - if(matches !== null){ - matches.forEach(function(liMatch, index, matches){ - - if(patternlab.config.debug){ - console.log('found listItem of size ' + liMatch + ' inside ' + pattern.key); - } - - //find the boundaries of the block - var loopNumberString = liMatch.split('.')[1].split('}')[0].trim(); - var end = liMatch.replace('#', '/'); - var patternBlock = pattern.template.substring(pattern.template.indexOf(liMatch) + liMatch.length, pattern.template.indexOf(end)).trim(); - //build arrays that repeat the block, however large we need to - var repeatedBlockTemplate = []; - var repeatedBlockHtml = ''; - for(var i = 0; i < items.indexOf(loopNumberString); i++){ - 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); - - //iterate over each copied block, rendering its contents along with pattenlab.listitems[i] - for(var i = 0; i < repeatedBlockTemplate.length; i++){ - - var thisBlockTemplate = repeatedBlockTemplate[i]; - var thisBlockHTML = ""; - - //combine listItem data with pattern data with global data - var itemData = listData['' + items.indexOf(loopNumberString)]; //this is a property like "2" - 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 - allData.link = extend({}, patternlab.data.link); - - //check for partials within the repeated block - var foundPartials = pattern_assembler.find_pattern_partials({ 'template' : thisBlockTemplate }); - - if(foundPartials && foundPartials.length > 0){ - - for(var j = 0; j < foundPartials.length; j++){ - - //get the partial - var partialName = foundPartials[j].match(/([\w\-\.\/~]+)/g)[0]; - var partialPattern = pattern_assembler.get_pattern_by_key(partialName, patternlab); - - //create a copy of the partial so as to not pollute it after the get_pattern_by_key call. - var cleanPartialPattern = JSON.parse(JSON.stringify(partialPattern)); - - //if partial has style modifier data, replace the styleModifier value - if(foundPartials[j].indexOf(':') > -1){ - style_modifier_hunter.consume_style_modifier(cleanPartialPattern, foundPartials[j], patternlab); - } - - //replace its reference within the block with the extended template - thisBlockTemplate = thisBlockTemplate.replace(foundPartials[j], cleanPartialPattern.extendedTemplate); - } - - //render with data - thisBlockHTML = pattern_assembler.renderPattern(thisBlockTemplate, allData, patternlab.partials); - - } else{ - //just render with mergedData - thisBlockHTML = pattern_assembler.renderPattern(thisBlockTemplate, allData, patternlab.partials); - } - - //add the rendered HTML to our string - repeatedBlockHtml = repeatedBlockHtml + thisBlockHTML; - } - - //replace the block with our generated HTML - var repeatingBlock = pattern.extendedTemplate.substring(pattern.extendedTemplate.indexOf(liMatch), pattern.extendedTemplate.indexOf(end) + end.length); - pattern.extendedTemplate = pattern.extendedTemplate.replace(repeatingBlock, repeatedBlockHtml); - - //update the extendedTemplate in the partials object in case this pattern is consumed later - patternlab.partials[pattern.key] = pattern.extendedTemplate; - - }); - } - } - - return { - process_list_item_partials: function(pattern, patternlab){ - processListItemPartials(pattern, patternlab); - } - }; - - }; - - module.exports = list_item_hunter; - -}()); +"use strict"; + +var list_item_hunter = function () { + + var extend = require('util')._extend, + pa = require('./pattern_assembler'), + smh = require('./style_modifier_hunter'), + pattern_assembler = new pa(), + style_modifier_hunter = new smh(), + items = [ 'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen', 'twenty']; + + function processListItemPartials(pattern, patternlab) { + //find any listitem blocks + var matches = pattern_assembler.find_list_items(pattern, patternlab); + if (matches !== null) { + matches.forEach(function (liMatch) { + + if (patternlab.config.debug) { + console.log('found listItem of size ' + liMatch + ' inside ' + pattern.key); + } + + //find the boundaries of the block + var loopNumberString = liMatch.split('.')[1].split('}')[0].trim(); + var end = liMatch.replace('#', '/'); + var patternBlock = pattern.template.substring(pattern.template.indexOf(liMatch) + liMatch.length, pattern.template.indexOf(end)).trim(); + + //build arrays that repeat the block, however large we need to + var repeatedBlockTemplate = []; + var repeatedBlockHtml = ''; + var i; // for loops + + for (i = 0; i < items.indexOf(loopNumberString); i++) { + 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); + + //iterate over each copied block, rendering its contents along with pattenlab.listitems[i] + for (i = 0; i < repeatedBlockTemplate.length; i++) { + var thisBlockTemplate = repeatedBlockTemplate[i]; + var thisBlockHTML = ""; + + //combine listItem data with pattern data with global data + var itemData = listData['' + items.indexOf(loopNumberString)]; //this is a property like "2" + 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 + allData.link = extend({}, patternlab.data.link); + + //check for partials within the repeated block + var foundPartials = pattern_assembler.find_pattern_partials({ 'template' : thisBlockTemplate }); + + if (foundPartials && foundPartials.length > 0) { + for (var j = 0; j < foundPartials.length; j++) { + //get the partial + var partialName = foundPartials[j].match(/([\w\-\.\/~]+)/g)[0]; + var partialPattern = pattern_assembler.get_pattern_by_key(partialName, patternlab); + + //create a copy of the partial so as to not pollute it after the get_pattern_by_key call. + var cleanPartialPattern = JSON.parse(JSON.stringify(partialPattern)); + + //if partial has style modifier data, replace the styleModifier value + if (foundPartials[j].indexOf(':') > -1) { + style_modifier_hunter.consume_style_modifier(cleanPartialPattern, foundPartials[j], patternlab); + } + + //replace its reference within the block with the extended template + thisBlockTemplate = thisBlockTemplate.replace(foundPartials[j], cleanPartialPattern.extendedTemplate); + } + + //render with data + thisBlockHTML = pattern_assembler.renderPattern(thisBlockTemplate, allData, patternlab.partials); + } else { + //just render with mergedData + thisBlockHTML = pattern_assembler.renderPattern(thisBlockTemplate, allData, patternlab.partials); + } + + //add the rendered HTML to our string + repeatedBlockHtml = repeatedBlockHtml + thisBlockHTML; + } + + //replace the block with our generated HTML + var repeatingBlock = pattern.extendedTemplate.substring(pattern.extendedTemplate.indexOf(liMatch), pattern.extendedTemplate.indexOf(end) + end.length); + pattern.extendedTemplate = pattern.extendedTemplate.replace(repeatingBlock, repeatedBlockHtml); + + //update the extendedTemplate in the partials object in case this pattern is consumed later + patternlab.partials[pattern.key] = pattern.extendedTemplate; + + }); + } + } + + return { + process_list_item_partials: function (pattern, patternlab) { + processListItemPartials(pattern, patternlab); + } + }; + +}; + +module.exports = list_item_hunter; diff --git a/builder/media_hunter.js b/builder/media_hunter.js index 3ee48f4fe..e8de9a81f 100644 --- a/builder/media_hunter.js +++ b/builder/media_hunter.js @@ -1,53 +1,51 @@ -/* - * patternlab-node - v1.1.3 - 2016 - * +/* + * patternlab-node - v1.1.3 - 2016 + * * 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. * */ -(function () { - "use strict"; - - var diveSync = require('diveSync'), - path = require('path'), - fs = require('fs-extra'); - - var media_hunter = function(){ - - function findMediaQueries(dir, patternlab){ - patternlab.mediaQueries = []; - - diveSync(dir, function(err, file){ - if(path.extname(file) === '.css'){ - var contents = fs.readFileSync(file, 'utf8'); - var safeContents = contents.replace("\r", " ").replace("\n", " "); - var matches = safeContents.match(/\((min|max)-width:([ ]+)?(([0-9]{1,5})(\.[0-9]{1,20}|)(px|em))/g); - for(var i = 0; i < matches.length; i++){ - var breakpoint = matches[i].substring(matches[i].indexOf(':') + 1).trimLeft(); - if(patternlab.mediaQueries.indexOf(breakpoint) === -1){ - patternlab.mediaQueries.push(breakpoint); - } - } - } - }); - patternlab.mediaQueries.sort(function(a,b){ - var integerPartA = a.match(/(?:\d*\.)?\d+/g); - var integerPartB = b.match(/(?:\d*\.)?\d+/g); - return parseInt(a,10) > parseInt(b,10); - }); - } - - return { - find_media_queries: function(dir, patternlab){ - findMediaQueries(dir, patternlab); - } - }; - - }; - - module.exports = media_hunter; - -}()); +"use strict"; + +var diveSync = require('diveSync'), + path = require('path'), + fs = require('fs-extra'); + +var media_hunter = function () { + + function findMediaQueries(dir, patternlab) { + patternlab.mediaQueries = []; + + diveSync(dir, function (err, file) { + if (path.extname(file) === '.css') { + var contents = fs.readFileSync(file, 'utf8'); + var safeContents = contents.replace("\r", " ").replace("\n", " "); + var matches = safeContents.match(/\((min|max)-width:([ ]+)?(([0-9]{1,5})(\.[0-9]{1,20}|)(px|em))/g); + for (var i = 0; i < matches.length; i++) { + var breakpoint = matches[i].substring(matches[i].indexOf(':') + 1).trimLeft(); + if (patternlab.mediaQueries.indexOf(breakpoint) === -1) { + patternlab.mediaQueries.push(breakpoint); + } + } + } + }); + patternlab.mediaQueries.sort(function (a, b) { + a.match(/(?:\d*\.)?\d+/g); + b.match(/(?:\d*\.)?\d+/g); + return parseInt(a, 10) > parseInt(b, 10); + }); + } + + return { + find_media_queries: function (dir, patternlab) { + findMediaQueries(dir, patternlab); + } + }; + +}; + +module.exports = media_hunter; + diff --git a/builder/object_factory.js b/builder/object_factory.js index 5526bdc18..c1e44ac38 100644 --- a/builder/object_factory.js +++ b/builder/object_factory.js @@ -8,65 +8,63 @@ * */ -(function () { - "use strict"; +"use strict"; - var oPattern = function(abspath, subdir, filename, data){ - this.fileName = filename.substring(0, filename.indexOf('.')); - this.abspath = abspath; - this.subdir = subdir; - this.name = subdir.replace(/[\/\\]/g, '-') + '-' + this.fileName; //this is the unique name with the subDir - this.jsonFileData = data || {}; - this.patternName = this.fileName.replace(/^\d*\-/, ''); - this.patternDisplayName = this.patternName.split('-').reduce(function(val, working){ - return val.charAt(0).toUpperCase() + val.slice(1) + ' ' + working.charAt(0).toUpperCase() + working.slice(1); - }, '').trim(); //this is the display name for the ui. strip numeric + hyphen prefixes - this.patternLink = this.name + '/' + this.name + '.html'; - this.patternGroup = this.name.substring(this.name.indexOf('-') + 1, this.name.indexOf('-', 4) + 1 - this.name.indexOf('-') + 1); - this.patternSubGroup = subdir.substring(subdir.indexOf('/') + 4); - this.flatPatternPath = subdir.replace(/[\/\\]/g, '-'); - this.key = this.patternGroup + '-' + this.patternName; - this.template = ''; - this.patternPartial = ''; - this.lineage = []; - this.lineageIndex = []; - this.lineageR = []; - this.lineageRIndex = []; - }; +var oPattern = function (abspath, subdir, filename, data) { + this.fileName = filename.substring(0, filename.indexOf('.')); + this.abspath = abspath; + this.subdir = subdir; + this.name = subdir.replace(/[\/\\]/g, '-') + '-' + this.fileName; //this is the unique name with the subDir + this.jsonFileData = data || {}; + this.patternName = this.fileName.replace(/^\d*\-/, ''); + this.patternDisplayName = this.patternName.split('-').reduce(function (val, working) { + return val.charAt(0).toUpperCase() + val.slice(1) + ' ' + working.charAt(0).toUpperCase() + working.slice(1); + }, '').trim(); //this is the display name for the ui. strip numeric + hyphen prefixes + this.patternLink = this.name + '/' + this.name + '.html'; + this.patternGroup = this.name.substring(this.name.indexOf('-') + 1, this.name.indexOf('-', 4) + 1 - this.name.indexOf('-') + 1); + this.patternSubGroup = subdir.substring(subdir.indexOf('/') + 4); + this.flatPatternPath = subdir.replace(/[\/\\]/g, '-'); + this.key = this.patternGroup + '-' + this.patternName; + this.template = ''; + this.patternPartial = ''; + this.lineage = []; + this.lineageIndex = []; + this.lineageR = []; + this.lineageRIndex = []; +}; - var oBucket = function(name){ - this.bucketNameLC = name; - this.bucketNameUC = name.split('-').reduce(function(val, working){ - return val.charAt(0).toUpperCase() + val.slice(1) + ' ' + working.charAt(0).toUpperCase() + working.slice(1); - }, '').trim(); - this.navItems = []; - this.navItemsIndex = []; - this.patternItems = []; - this.patternItemsIndex = []; - }; +var oBucket = function (name) { + this.bucketNameLC = name; + this.bucketNameUC = name.split('-').reduce(function (val, working) { + return val.charAt(0).toUpperCase() + val.slice(1) + ' ' + working.charAt(0).toUpperCase() + working.slice(1); + }, '').trim(); + this.navItems = []; + this.navItemsIndex = []; + this.patternItems = []; + this.patternItemsIndex = []; +}; - var oNavItem = function(name){ - this.sectionNameLC = name; - this.sectionNameUC = name.split('-').reduce(function(val, working){ - return val.charAt(0).toUpperCase() + val.slice(1) + ' ' + working.charAt(0).toUpperCase() + working.slice(1); - }, '').trim(); - this.navSubItems = []; - this.navSubItemsIndex = []; - }; +var oNavItem = function (name) { + this.sectionNameLC = name; + this.sectionNameUC = name.split('-').reduce(function (val, working) { + return val.charAt(0).toUpperCase() + val.slice(1) + ' ' + working.charAt(0).toUpperCase() + working.slice(1); + }, '').trim(); + this.navSubItems = []; + this.navSubItemsIndex = []; +}; - var oNavSubItem = function(name){ - this.patternPath = ''; - this.patternPartial = ''; - this.patternName = name.split(' ').reduce(function(val, working){ - return val.charAt(0).toUpperCase() + val.slice(1) + ' ' + working.charAt(0).toUpperCase() + working.slice(1); - }, '').trim(); - }; +var oNavSubItem = function (name) { + this.patternPath = ''; + this.patternPartial = ''; + this.patternName = name.split(' ').reduce(function (val, working) { + return val.charAt(0).toUpperCase() + val.slice(1) + ' ' + working.charAt(0).toUpperCase() + working.slice(1); + }, '').trim(); +}; - module.exports = { - oPattern: oPattern, - oBucket: oBucket, - oNavItem: oNavItem, - oNavSubItem: oNavSubItem - }; +module.exports = { + oPattern: oPattern, + oBucket: oBucket, + oNavItem: oNavItem, + oNavSubItem: oNavSubItem +}; -}()); diff --git a/builder/parameter_hunter.js b/builder/parameter_hunter.js index da08eee92..2f8738034 100644 --- a/builder/parameter_hunter.js +++ b/builder/parameter_hunter.js @@ -1,175 +1,189 @@ -/* - * patternlab-node - v1.1.3 - 2016 - * +/* + * patternlab-node - v1.1.3 - 2016 + * * 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. * */ -(function () { - "use strict"; - - var parameter_hunter = function(){ - - var extend = require('util')._extend, - pa = require('./pattern_assembler'), - mustache = require('mustache'), - smh = require('./style_modifier_hunter'), - style_modifier_hunter = new smh(), - pattern_assembler = new pa(); - - function paramToJson(paramString) { - var paramStringWellFormed = ''; - var paramStringTmp; - var colonPos; - var delimitPos; - var quotePos; - - do { - //if param key is wrapped in single quotes, replace with double quotes. - paramString = paramString.replace(/(^\s*[\{|\,]\s*)'([^']+)'(\s*\:)/, '$1"$2"$3'); - //if params key is not wrapped in any quotes, wrap in double quotes. - paramString = paramString.replace(/(^\s*[\{|\,]\s*)([^\s"'\:]+)(\s*\:)/, '$1"$2"$3'); - //move param key to paramStringWellFormed var. - colonPos = paramString.indexOf(':'); - //except to prevent infinite loops. - if (colonPos === -1) { - colonPos = paramString.length - 1; - } - else { - colonPos += 1; - } - paramStringWellFormed += paramString.substring(0, colonPos); - paramString = paramString.substring(colonPos, paramString.length).trim(); - - //if param value is wrapped in single quotes, replace with double quotes. - if (paramString[0] === '\'') { - quotePos = paramString.search(/[^\\]'/); - //except for unclosed quotes to prevent infinite loops. - if (quotePos === -1) { - quotePos = paramString.length - 1; - } - else { - quotePos += 2; - } - //prepare param value for move to paramStringWellFormed var. - paramStringTmp = paramString.substring(0, quotePos); - //unescape any escaped single quotes. - paramStringTmp = paramStringTmp.replace(/\\'/g, '\''); - //escape any double quotes. - paramStringTmp = paramStringTmp.replace(/"/g, '\\"'); - //replace the delimiting single quotes with double quotes. - paramStringTmp = paramStringTmp.replace(/^'/, '"'); - paramStringTmp = paramStringTmp.replace(/'$/, '"'); - //move param key to paramStringWellFormed var. - paramStringWellFormed += paramStringTmp; - paramString = paramString.substring(quotePos, paramString.length).trim(); - } - //if param value is wrapped in double quotes, just move to paramStringWellFormed var. - else if (paramString[0] === '"') { - quotePos = paramString.search(/[^\\]"/); - //except for unclosed quotes to prevent infinite loops. - if (quotePos === -1) { - quotePos = paramString.length - 1; - } - else { - quotePos += 2; - } - //move param key to paramStringWellFormed var. - paramStringWellFormed += paramString.substring(0, quotePos); - paramString = paramString.substring(quotePos, paramString.length).trim(); - } - //if param value is not wrapped in quotes, move everthing up to the delimiting comma to paramStringWellFormed var. - else { - delimitPos = paramString.indexOf(','); - //except to prevent infinite loops. - if (delimitPos === -1) { - delimitPos = paramString.length - 1; - } - else { - delimitPos += 1; - } - paramStringWellFormed += paramString.substring(0, delimitPos); - paramString = paramString.substring(delimitPos, paramString.length).trim(); - } - - //break at the end. - if (paramString.length === 1) { - paramStringWellFormed += paramString.trim(); - paramString = ''; - break; - } - - } while(paramString); - - return paramStringWellFormed; - } - - function findparameters(pattern, patternlab){ - - if(pattern.parameteredPartials && pattern.parameteredPartials.length > 0){ - //compile this partial immeadiately, essentially consuming it. - pattern.parameteredPartials.forEach(function(pMatch, index, matches){ - //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); - } - - //strip out the additional data, convert string to JSON. - var leftParen = pMatch.indexOf('('); - var rightParen = pMatch.indexOf(')'); - var paramString = '{' + pMatch.substring(leftParen + 1, rightParen) + '}'; - var paramStringWellFormed = paramToJson(paramString); - - var paramData = {}; - var globalData = {}; - var localData = {}; - - try { - paramData = JSON.parse(paramStringWellFormed); - globalData = JSON.parse(JSON.stringify(patternlab.data)); - localData = JSON.parse(JSON.stringify(pattern.jsonFileData || {})); - } catch(e){ - console.log(e); - } - - var allData = pattern_assembler.merge_data(globalData, localData); - allData = pattern_assembler.merge_data(allData, paramData); - - //if partial has style modifier data, replace the styleModifier value - if(pattern.stylePartials && pattern.stylePartials.length > 0){ - style_modifier_hunter.consume_style_modifier(partialPattern, pMatch, patternlab); - } - - //extend pattern data links into link for pattern link shortcuts to work. we do this locally and globally - allData.link = extend({}, patternlab.data.link); - - var renderedPartial = pattern_assembler.renderPattern(partialPattern.extendedTemplate, allData, patternlab.partials); - - //remove the parameter from the partial and replace it with the rendered partial + paramData - pattern.extendedTemplate = pattern.extendedTemplate.replace(pMatch, renderedPartial); - - //update the extendedTemplate in the partials object in case this pattern is consumed later - patternlab.partials[pattern.key] = pattern.extendedTemplate; - }); - } - } - - return { - find_parameters: function(pattern, patternlab){ - findparameters(pattern, patternlab); - } - }; - - }; - - module.exports = parameter_hunter; - -}()); +"use strict"; + +var parameter_hunter = function () { + + var extend = require('util')._extend, + pa = require('./pattern_assembler'), + smh = require('./style_modifier_hunter'), + style_modifier_hunter = new smh(), + pattern_assembler = new pa(); + + function paramToJson(pString) { + var paramStringWellFormed = ''; + var paramStringTmp; + var colonPos; + var delimitPos; + var quotePos; + var paramString = pString; + + do { + + //if param key is wrapped in single quotes, replace with double quotes. + paramString = paramString.replace(/(^\s*[\{|\,]\s*)'([^']+)'(\s*\:)/, '$1"$2"$3'); + + //if params key is not wrapped in any quotes, wrap in double quotes. + paramString = paramString.replace(/(^\s*[\{|\,]\s*)([^\s"'\:]+)(\s*\:)/, '$1"$2"$3'); + + //move param key to paramStringWellFormed var. + colonPos = paramString.indexOf(':'); + + //except to prevent infinite loops. + if (colonPos === -1) { + colonPos = paramString.length - 1; + } + else { + colonPos += 1; + } + paramStringWellFormed += paramString.substring(0, colonPos); + paramString = paramString.substring(colonPos, paramString.length).trim(); + + //if param value is wrapped in single quotes, replace with double quotes. + if (paramString[0] === '\'') { + quotePos = paramString.search(/[^\\]'/); + + //except for unclosed quotes to prevent infinite loops. + if (quotePos === -1) { + quotePos = paramString.length - 1; + } + else { + quotePos += 2; + } + + //prepare param value for move to paramStringWellFormed var. + paramStringTmp = paramString.substring(0, quotePos); + + //unescape any escaped single quotes. + paramStringTmp = paramStringTmp.replace(/\\'/g, '\''); + + //escape any double quotes. + paramStringTmp = paramStringTmp.replace(/"/g, '\\"'); + + //replace the delimiting single quotes with double quotes. + paramStringTmp = paramStringTmp.replace(/^'/, '"'); + paramStringTmp = paramStringTmp.replace(/'$/, '"'); + + //move param key to paramStringWellFormed var. + paramStringWellFormed += paramStringTmp; + paramString = paramString.substring(quotePos, paramString.length).trim(); + } + + //if param value is wrapped in double quotes, just move to paramStringWellFormed var. + else if (paramString[0] === '"') { + quotePos = paramString.search(/[^\\]"/); + + //except for unclosed quotes to prevent infinite loops. + if (quotePos === -1) { + quotePos = paramString.length - 1; + } + else { + quotePos += 2; + } + + //move param key to paramStringWellFormed var. + paramStringWellFormed += paramString.substring(0, quotePos); + paramString = paramString.substring(quotePos, paramString.length).trim(); + } + + //if param value is not wrapped in quotes, move everthing up to the delimiting comma to paramStringWellFormed var. + else { + delimitPos = paramString.indexOf(','); + + //except to prevent infinite loops. + if (delimitPos === -1) { + delimitPos = paramString.length - 1; + } + else { + delimitPos += 1; + } + paramStringWellFormed += paramString.substring(0, delimitPos); + paramString = paramString.substring(delimitPos, paramString.length).trim(); + } + + //break at the end. + if (paramString.length === 1) { + paramStringWellFormed += paramString.trim(); + paramString = ''; + break; + } + + } while (paramString); + + return paramStringWellFormed; + } + + function findparameters(pattern, patternlab) { + + if (pattern.parameteredPartials && pattern.parameteredPartials.length > 0) { + + //compile this partial immeadiately, essentially consuming it. + pattern.parameteredPartials.forEach(function (pMatch) { + //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); + } + + //strip out the additional data, convert string to JSON. + var leftParen = pMatch.indexOf('('); + var rightParen = pMatch.indexOf(')'); + var paramString = '{' + pMatch.substring(leftParen + 1, rightParen) + '}'; + var paramStringWellFormed = paramToJson(paramString); + + var paramData = {}; + var globalData = {}; + var localData = {}; + + try { + paramData = JSON.parse(paramStringWellFormed); + globalData = JSON.parse(JSON.stringify(patternlab.data)); + localData = JSON.parse(JSON.stringify(pattern.jsonFileData || {})); + } catch (e) { + console.log(e); + } + + var allData = pattern_assembler.merge_data(globalData, localData); + allData = pattern_assembler.merge_data(allData, paramData); + + //if partial has style modifier data, replace the styleModifier value + if (pattern.stylePartials && pattern.stylePartials.length > 0) { + style_modifier_hunter.consume_style_modifier(partialPattern, pMatch, patternlab); + } + + //extend pattern data links into link for pattern link shortcuts to work. we do this locally and globally + allData.link = extend({}, patternlab.data.link); + + var renderedPartial = pattern_assembler.renderPattern(partialPattern.extendedTemplate, allData, patternlab.partials); + + //remove the parameter from the partial and replace it with the rendered partial + paramData + pattern.extendedTemplate = pattern.extendedTemplate.replace(pMatch, renderedPartial); + + //update the extendedTemplate in the partials object in case this pattern is consumed later + patternlab.partials[pattern.key] = pattern.extendedTemplate; + }); + } + } + + return { + find_parameters: function (pattern, patternlab) { + findparameters(pattern, patternlab); + } + }; + +}; + +module.exports = parameter_hunter; diff --git a/builder/pattern_assembler.js b/builder/pattern_assembler.js index d200f059d..2d40c1544 100644 --- a/builder/pattern_assembler.js +++ b/builder/pattern_assembler.js @@ -1,425 +1,414 @@ -/* - * patternlab-node - v1.1.3 - 2016 - * +/* + * patternlab-node - v1.1.3 - 2016 + * * 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. * */ -(function () { - "use strict"; - - var pattern_assembler = function(){ - - function isObjectEmpty(obj) { - for(var prop in obj) { - if(obj.hasOwnProperty(prop)) - return false; - } - - return true; +"use strict"; + +var pattern_assembler = function () { + + // returns any patterns that match {{> value:mod }} or {{> value:mod(foo:"bar") }} within the pattern + function findPartialsWithStyleModifiers(pattern) { + var matches = pattern.template.match(/{{>([ ])?([\w\-\.\/~]+)(?!\()(\:[A-Za-z0-9-_|]+)+(?:(| )\(.*)?([ ])?}}/g); + return matches; + } + + // returns any patterns that match {{> value(foo:"bar") }} or {{> value:mod(foo:"bar") }} within the pattern + function findPartialsWithPatternParameters(pattern) { + var matches = pattern.template.match(/{{>([ ])?([\w\-\.\/~]+)(?:\:[A-Za-z0-9-_|]+)?(?:(| )\(.*)+([ ])?}}/g); + return matches; + } + + //find and return any {{> template-name* }} within pattern + function findPartials(pattern) { + var matches = pattern.template.match(/{{>([ ])?([\w\-\.\/~]+)(?:\:[A-Za-z0-9-_|]+)?(?:(| )\(.*)?([ ])?}}/g); + return matches; + } + + function findListItems(pattern) { + var matches = pattern.template.match(/({{#( )?)(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); + return matches; + } + + function setState(pattern, patternlab) { + if (patternlab.config.patternStates && patternlab.config.patternStates[pattern.patternName]) { + pattern.patternState = patternlab.config.patternStates[pattern.patternName]; + } else { + pattern.patternState = ""; } - - // returns any patterns that match {{> value:mod }} or {{> value:mod(foo:"bar") }} within the pattern - function findPartialsWithStyleModifiers(pattern){ - var matches = pattern.template.match(/{{>([ ])?([\w\-\.\/~]+)(?!\()(\:[A-Za-z0-9-_|]+)+(?:(| )\(.*)?([ ])?}}/g); - return matches; + } + + function addPattern(pattern, patternlab) { + //add the link to the global object + patternlab.data.link[pattern.patternGroup + '-' + pattern.patternName] = '/patterns/' + pattern.patternLink; + + //only push to array if the array doesn't contain this pattern + var isNew = true, i; + for (i = 0; i < patternlab.patterns.length; i++) { + //so we need the identifier to be unique, which patterns[i].abspath is + if (pattern.abspath === patternlab.patterns[i].abspath) { + //if abspath already exists, overwrite that element + patternlab.patterns[i] = pattern; + patternlab.partials[pattern.key] = pattern.extendedTemplate || pattern.template; + isNew = false; + break; + } } - // returns any patterns that match {{> value(foo:"bar") }} or {{> value:mod(foo:"bar") }} within the pattern - function findPartialsWithPatternParameters(pattern){ - var matches = pattern.template.match(/{{>([ ])?([\w\-\.\/~]+)(?:\:[A-Za-z0-9-_|]+)?(?:(| )\(.*)+([ ])?}}/g); - return matches; + //if the pattern is new, just push to the array + if (isNew) { + patternlab.patterns.push(pattern); + patternlab.partials[pattern.key] = pattern.extendedTemplate || pattern.template; } + } - //find and return any {{> template-name* }} within pattern - function findPartials(pattern){ - var matches = pattern.template.match(/{{>([ ])?([\w\-\.\/~]+)(?:\:[A-Za-z0-9-_|]+)?(?:(| )\(.*)?([ ])?}}/g); - return matches; - } + function renderPattern(template, data, partials) { + var mustache = require('mustache'); - function findListItems(pattern){ - var matches = pattern.template.match(/({{#( )?)(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); - return matches; + if (partials) { + return mustache.render(template, data, partials); + } else { + return mustache.render(template, data); } - - function setState(pattern, patternlab){ - if(patternlab.config.patternStates && patternlab.config.patternStates[pattern.patternName]){ - pattern.patternState = patternlab.config.patternStates[pattern.patternName]; - } else{ - pattern.patternState = ""; + } + + //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); //eslint-disable-line curly + return o; + } + + function buildListItems(container) { + //combine all list items into one structure + var list = []; + for (var item in container.listitems) { + if (container.listitems.hasOwnProperty(item)) { + list.push(container.listitems[item]); } } - - function addPattern(pattern, patternlab){ - //add the link to the global object - patternlab.data.link[pattern.patternGroup + '-' + pattern.patternName] = '/patterns/' + pattern.patternLink; - - //only push to array if the array doesn't contain this pattern - var isNew = true; - for(var i = 0; i < patternlab.patterns.length; i++){ - //so we need the identifier to be unique, which patterns[i].abspath is - if(pattern.abspath === patternlab.patterns[i].abspath){ - //if abspath already exists, overwrite that element - patternlab.patterns[i] = pattern; - patternlab.partials[pattern.key] = pattern.extendedTemplate || pattern.template; - isNew = false; - break; + container.listItemArray = shuffle(list); + + for (var i = 1; i <= container.listItemArray.length; i++) { + var tempItems = []; + if (i === 1) { + tempItems.push(container.listItemArray[0]); + container.listitems['' + i] = tempItems; + } else { + for (var c = 1; c <= i; c++) { + tempItems.push(container.listItemArray[c - 1]); + container.listitems['' + i] = tempItems; } } - //if the pattern is new, just push to the array - if(isNew){ - patternlab.patterns.push(pattern); - patternlab.partials[pattern.key] = pattern.extendedTemplate || pattern.template; + } + } + + function getpatternbykey(key, patternlab) { + var i; // for the for loops + + //look for exact key matches + for (i = 0; i < patternlab.patterns.length; i++) { + if (patternlab.patterns[i].key === key) { + return patternlab.patterns[i]; } } - function renderPattern(template, data, partials) { + //else look by verbose syntax + for (i = 0; i < patternlab.patterns.length; i++) { + switch (key) { + case patternlab.patterns[i].subdir + '/' + patternlab.patterns[i].fileName: + case patternlab.patterns[i].subdir + '/' + patternlab.patterns[i].fileName + '.mustache': + return patternlab.patterns[i]; + } + } - var mustache = require('mustache'); + //return the fuzzy match if all else fails + for (i = 0; i < patternlab.patterns.length; i++) { + var keyParts = key.split('-'), + keyType = keyParts[0], + keyName = keyParts.slice(1).join('-'); - if(partials) { - return mustache.render(template, data, partials); - } else{ - return mustache.render(template, data); + if (patternlab.patterns[i].key.split('-')[0] === keyType && patternlab.patterns[i].key.indexOf(keyName) > -1) { + return patternlab.patterns[i]; } } + throw 'Could not find pattern with key ' + key; + } - function processPatternIterative(file, patternlab){ - var fs = require('fs-extra'), + function processPatternIterative(file, patternlab) { + var fs = require('fs-extra'), of = require('./object_factory'), path = require('path'); - //extract some information - var subdir = path.dirname(path.relative(patternlab.config.paths.source.patterns, file)).replace('\\', '/'); - var filename = path.basename(file); - var ext = path.extname(filename); + //extract some information + var subdir = path.dirname(path.relative(patternlab.config.paths.source.patterns, file)).replace('\\', '/'); + var filename = path.basename(file); + var ext = path.extname(filename); - //ignore dotfiles, underscored files, and non-variant .json files - if(filename.charAt(0) === '.' || (ext === '.json' && filename.indexOf('~') === -1)){ - return; - } + //ignore dotfiles, underscored files, and non-variant .json files + if (filename.charAt(0) === '.' || (ext === '.json' && filename.indexOf('~') === -1)) { + return; + } - //make a new Pattern Object - var currentPattern = new of.oPattern(file, subdir, filename); + //make a new Pattern Object + var currentPattern = new of.oPattern(file, subdir, filename); - //if file is named in the syntax for variants, no need to process further - //processPatternRecursive() will run find_pseudopatterns() and look at each pattern for a variant - if(ext === '.json' && filename.indexOf('~') > -1){ - return; - } + //if file is named in the syntax for variants, no need to process further + //processPatternRecursive() will run find_pseudopatterns() and look at each pattern for a variant + if (ext === '.json' && filename.indexOf('~') > -1) { + return; + } - //can ignore all non-mustache files at this point - if(ext !== '.mustache'){ - return; - } + //can ignore all non-mustache files at this point + if (ext !== '.mustache') { + return; + } - //see if this file has a state - setState(currentPattern, patternlab); + //see if this file has a state + setState(currentPattern, patternlab); - //look for a json file for this template - try { - var jsonFilename = path.resolve(patternlab.config.paths.source.patterns, currentPattern.subdir, currentPattern.fileName + ".json"); - currentPattern.jsonFileData = fs.readJSONSync(jsonFilename); - if(patternlab.config.debug){ - console.log('found pattern-specific data.json for ' + currentPattern.key); - } - } - catch(e) { + //look for a json file for this template + try { + var jsonFilename = path.resolve(patternlab.config.paths.source.patterns, currentPattern.subdir, currentPattern.fileName + ".json"); + currentPattern.jsonFileData = fs.readJSONSync(jsonFilename); + if (patternlab.config.debug) { + console.log('found pattern-specific data.json for ' + currentPattern.key); } + } + catch (error) { + // do nothing + } - //look for a listitems.json file for this template - try { - var listJsonFileName = path.resolve(patternlab.config.paths.source.patterns, currentPattern.subdir,currentPattern.fileName + ".listitems.json"); - currentPattern.listitems = fs.readJSONSync(listJsonFileName); - buildListItems(currentPattern); - if(patternlab.config.debug){ - console.log('found pattern-specific listitems.json for ' + currentPattern.key); - } - } - catch(e) { + //look for a listitems.json file for this template + try { + var listJsonFileName = path.resolve(patternlab.config.paths.source.patterns, currentPattern.subdir, currentPattern.fileName + ".listitems.json"); + currentPattern.listitems = fs.readJSONSync(listJsonFileName); + buildListItems(currentPattern); + if (patternlab.config.debug) { + console.log('found pattern-specific listitems.json for ' + currentPattern.key); } + } + catch (err) { + // do nothing + } - //add the raw template to memory - currentPattern.template = fs.readFileSync(file, 'utf8'); - - //find any stylemodifiers that may be in the current pattern - currentPattern.stylePartials = findPartialsWithStyleModifiers(currentPattern); + //add the raw template to memory + currentPattern.template = fs.readFileSync(file, 'utf8'); - //find any pattern parameters that may be in the current pattern - currentPattern.parameteredPartials = findPartialsWithPatternParameters(currentPattern); + //find any stylemodifiers that may be in the current pattern + currentPattern.stylePartials = findPartialsWithStyleModifiers(currentPattern); - //add currentPattern to patternlab.patterns array - addPattern(currentPattern, patternlab); - } + //find any pattern parameters that may be in the current pattern + currentPattern.parameteredPartials = findPartialsWithPatternParameters(currentPattern); - function processPatternRecursive(file, patternlab, additionalData){ + //add currentPattern to patternlab.patterns array + addPattern(currentPattern, patternlab); + } - var fs = require('fs-extra'), - mustache = require('mustache'), - lh = require('./lineage_hunter'), + function processPatternRecursive(file, patternlab) { + var lh = require('./lineage_hunter'), ph = require('./parameter_hunter'), pph = require('./pseudopattern_hunter'), lih = require('./list_item_hunter'), - smh = require('./style_modifier_hunter'), - path = require('path'); + smh = require('./style_modifier_hunter'); - var parameter_hunter = new ph(), + var parameter_hunter = new ph(), lineage_hunter = new lh(), list_item_hunter = new lih(), style_modifier_hunter = new smh(), pseudopattern_hunter = new pph(); - //find current pattern in patternlab object using var file as a key - var currentPattern, + //find current pattern in patternlab object using var file as a key + var currentPattern, i; - for(i = 0; i < patternlab.patterns.length; i++){ - if(patternlab.patterns[i].abspath === file){ - currentPattern = patternlab.patterns[i]; - break; - } + for (i = 0; i < patternlab.patterns.length; i++) { + if (patternlab.patterns[i].abspath === file) { + currentPattern = patternlab.patterns[i]; + break; } + } - //return if processing an ignored file - if(typeof currentPattern === 'undefined'){ - return; - } + //return if processing an ignored file + if (typeof currentPattern === 'undefined') { + return; + } - currentPattern.extendedTemplate = currentPattern.template; + currentPattern.extendedTemplate = currentPattern.template; - //find how many partials there may be for the given pattern - var foundPatternPartials = findPartials(currentPattern); + //find how many partials there may be for the given pattern + var foundPatternPartials = findPartials(currentPattern); - if(foundPatternPartials !== null && foundPatternPartials.length > 0){ + if (foundPatternPartials !== null && foundPatternPartials.length > 0) { - if(patternlab.config.debug){ - console.log('found partials for ' + currentPattern.key); - } + if (patternlab.config.debug) { + console.log('found partials for ' + currentPattern.key); + } - //find any listItem blocks - list_item_hunter.process_list_item_partials(currentPattern, patternlab); + //find any listItem blocks + list_item_hunter.process_list_item_partials(currentPattern, patternlab); - //determine if the template contains any pattern parameters. if so they must be immediately consumed - parameter_hunter.find_parameters(currentPattern, patternlab); + //determine if the template contains any pattern parameters. if so they must be immediately consumed + parameter_hunter.find_parameters(currentPattern, patternlab); - //do something with the regular old partials - for(i = 0; i < foundPatternPartials.length; i++){ - var partialKey = foundPatternPartials[i].replace(/{{>([ ])?([\w\-\.\/~]+)(:[A-z0-9-_|]+)?(?:\:[A-Za-z0-9-_]+)?(?:(| )\(.*)?([ ])?}}/g, '$2'); + //do something with the regular old partials + for (i = 0; i < foundPatternPartials.length; i++) { + var partialKey = foundPatternPartials[i].replace(/{{>([ ])?([\w\-\.\/~]+)(:[A-z0-9-_|]+)?(?:\:[A-Za-z0-9-_]+)?(?:(| )\(.*)?([ ])?}}/g, '$2'); - var partialPath; + var partialPath; - //identify which pattern this partial corresponds to - for(var j = 0; j < patternlab.patterns.length; j++){ - if(patternlab.patterns[j].key === partialKey || - patternlab.patterns[j].abspath.indexOf(partialKey) > -1) - { - partialPath = patternlab.patterns[j].abspath; - } + //identify which pattern this partial corresponds tou + for (var j = 0; j < patternlab.patterns.length; j++) { + if (patternlab.patterns[j].key === partialKey || + patternlab.patterns[j].abspath.indexOf(partialKey) > -1) { + partialPath = patternlab.patterns[j].abspath; } + } - //recurse through nested partials to fill out this extended template. - processPatternRecursive(partialPath, patternlab); - - //complete assembly of extended template - var partialPattern = getpatternbykey(partialKey, patternlab); - - //if partial has style modifier data, replace the styleModifier value - if(currentPattern.stylePartials && currentPattern.stylePartials.length > 0){ - style_modifier_hunter.consume_style_modifier(partialPattern, foundPatternPartials[i], patternlab); - } + //recurse through nested partials to fill out this extended template. + processPatternRecursive(partialPath, patternlab); - currentPattern.extendedTemplate = currentPattern.extendedTemplate.replace(foundPatternPartials[i], partialPattern.extendedTemplate); + //complete assembly of extended template + var partialPattern = getpatternbykey(partialKey, patternlab); - //update the extendedTemplate in the partials object in case this pattern is consumed later - patternlab.partials[currentPattern.key] = currentPattern.extendedTemplate; + //if partial has style modifier data, replace the styleModifier value + if (currentPattern.stylePartials && currentPattern.stylePartials.length > 0) { + style_modifier_hunter.consume_style_modifier(partialPattern, foundPatternPartials[i], patternlab); } - } else{ - //find any listItem blocks that within the pattern, even if there are no partials - list_item_hunter.process_list_item_partials(currentPattern, patternlab); - } - - //find pattern lineage - lineage_hunter.find_lineage(currentPattern, patternlab); + currentPattern.extendedTemplate = currentPattern.extendedTemplate.replace(foundPatternPartials[i], partialPattern.extendedTemplate); - //add to patternlab object so we can look these up later. - addPattern(currentPattern, patternlab); + //update the extendedTemplate in the partials object in case this pattern is consumed later + patternlab.partials[currentPattern.key] = currentPattern.extendedTemplate; + } - //look for a pseudo pattern by checking if there is a file containing same name, with ~ in it, ending in .json - pseudopattern_hunter.find_pseudopatterns(currentPattern, patternlab); + } else { + //find any listItem blocks that within the pattern, even if there are no partials + list_item_hunter.process_list_item_partials(currentPattern, patternlab); } - function getpatternbykey(key, patternlab){ + //find pattern lineage + lineage_hunter.find_lineage(currentPattern, patternlab); - //look for exact key matches - for(var i = 0; i < patternlab.patterns.length; i++){ - if(patternlab.patterns[i].key === key){ - return patternlab.patterns[i]; - } - } + //add to patternlab object so we can look these up later. + addPattern(currentPattern, patternlab); - //else look by verbose syntax - for(var i = 0; i < patternlab.patterns.length; i++){ - switch(key){ - case patternlab.patterns[i].subdir + '/' + patternlab.patterns[i].fileName: - case patternlab.patterns[i].subdir + '/' + patternlab.patterns[i].fileName + '.mustache': - return patternlab.patterns[i]; - } - } + //look for a pseudo pattern by checking if there is a file containing same name, with ~ in it, ending in .json + pseudopattern_hunter.find_pseudopatterns(currentPattern, patternlab); + } - //return the fuzzy match if all else fails - for(var i = 0; i < patternlab.patterns.length; i++){ - var keyParts = key.split('-'), - keyType = keyParts[0], - keyName = keyParts.slice(1).join('-'); - if(patternlab.patterns[i].key.split('-')[0] === keyType && patternlab.patterns[i].key.indexOf(keyName) > -1){ - return patternlab.patterns[i]; - } - } - throw 'Could not find pattern with key ' + key; + function mergeData(obj1, obj2) { + if (typeof obj2 === 'undefined') { + obj2 = {}; //eslint-disable-line no-param-reassign } - 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]; + for (var p in obj1) { //eslint-disable-line guard-for-in + 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] = {}; } - } - } - return obj2; - } + obj2[p] = mergeData(obj1[p], obj2[p]); - function buildListItems(container){ - //combine all list items into one structure - var list = []; - for (var item in container.listitems) { - if( container.listitems.hasOwnProperty(item)) { - list.push(container.listitems[item]); + // 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]; } - } - container.listItemArray = shuffle(list); - - for(var i = 1; i <= container.listItemArray.length; i++){ - var tempItems = []; - if( i === 1){ - tempItems.push(container.listItemArray[0]); - container.listitems['' + i ] = tempItems; - } else{ - for(var c = 1; c <= i; c++){ - tempItems.push(container.listItemArray[c - 1]); - container.listitems['' + i ] = tempItems; - } + } catch (e) { + // Property in destination object not set; create it and set its value. + if (typeof obj2[p] === 'undefined') { + obj2[p] = obj1[p]; } } } - - //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; - } - - function parseDataLinksHelper (patternlab, obj, key) { - var linkRE, dataObjAsString, linkMatches, expandedLink; - - linkRE = /link\.[A-z0-9-_]+/g - dataObjAsString = JSON.stringify(obj); - linkMatches = dataObjAsString.match(linkRE) - - if(linkMatches) { - for (var i = 0; i < linkMatches.length; i++) { - expandedLink = patternlab.data.link[linkMatches[i].split('.')[1]]; - if (expandedLink) { - if(patternlab.config.debug){ - console.log('expanded data link from ' + linkMatches[i] + ' to ' + expandedLink + ' inside ' + key); - } - dataObjAsString = dataObjAsString.replace(linkMatches[i], expandedLink); + return obj2; + } + + function parseDataLinksHelper(patternlab, obj, key) { + var linkRE, dataObjAsString, linkMatches, expandedLink; + + linkRE = /link\.[A-z0-9-_]+/g; + dataObjAsString = JSON.stringify(obj); + linkMatches = dataObjAsString.match(linkRE); + + if (linkMatches) { + for (var i = 0; i < linkMatches.length; i++) { + expandedLink = patternlab.data.link[linkMatches[i].split('.')[1]]; + if (expandedLink) { + if (patternlab.config.debug) { + console.log('expanded data link from ' + linkMatches[i] + ' to ' + expandedLink + ' inside ' + key); } + dataObjAsString = dataObjAsString.replace(linkMatches[i], expandedLink); } } - return JSON.parse(dataObjAsString) } - //look for pattern links included in data files. - //these will be in the form of link.* WITHOUT {{}}, which would still be there from direct pattern inclusion - function parseDataLinks(patternlab) { - //look for link.* such as link.pages-blog as a value + return JSON.parse(dataObjAsString); + } - patternlab.data = parseDataLinksHelper(patternlab, patternlab.data, 'data.json') + //look for pattern links included in data files. + //these will be in the form of link.* WITHOUT {{}}, which would still be there from direct pattern inclusion + function parseDataLinks(patternlab) { + //look for link.* such as link.pages-blog as a value - //loop through all patterns - for (var i = 0; i < patternlab.patterns.length; i++) { - patternlab.patterns[i].jsonFileData = parseDataLinksHelper(patternlab, patternlab.patterns[i].jsonFileData, patternlab.patterns[i].key) - } + patternlab.data = parseDataLinksHelper(patternlab, patternlab.data, 'data.json'); + + //loop through all patterns + for (var i = 0; i < patternlab.patterns.length; i++) { + patternlab.patterns[i].jsonFileData = parseDataLinksHelper(patternlab, patternlab.patterns[i].jsonFileData, patternlab.patterns[i].key); + } + } + + return { + find_pattern_partials: function (pattern) { + return findPartials(pattern); + }, + find_pattern_partials_with_style_modifiers: function (pattern) { + return findPartialsWithStyleModifiers(pattern); + }, + find_pattern_partials_with_parameters: function (pattern) { + return findPartialsWithPatternParameters(pattern); + }, + find_list_items: function (pattern) { + return findListItems(pattern); + }, + setPatternState: function (pattern, patternlab) { + setState(pattern, patternlab); + }, + addPattern: function (pattern, patternlab) { + addPattern(pattern, patternlab); + }, + renderPattern: function (template, data, partials) { + return renderPattern(template, data, partials); + }, + process_pattern_iterative: function (file, patternlab) { + processPatternIterative(file, patternlab); + }, + process_pattern_recursive: function (file, patternlab, additionalData) { + processPatternRecursive(file, patternlab, additionalData); + }, + 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); + }, + parse_data_links: function (patternlab) { + parseDataLinks(patternlab); } + }; - return { - find_pattern_partials: function(pattern){ - return findPartials(pattern); - }, - find_pattern_partials_with_style_modifiers: function(pattern){ - return findPartialsWithStyleModifiers(pattern); - }, - find_pattern_partials_with_parameters: function(pattern){ - return findPartialsWithPatternParameters(pattern); - }, - find_list_items: function(pattern){ - return findListItems(pattern) - }, - setPatternState: function(pattern, patternlab){ - setState(pattern, patternlab); - }, - addPattern: function(pattern, patternlab){ - addPattern(pattern, patternlab); - }, - renderPattern: function(template, data, partials){ - return renderPattern(template, data, partials); - }, - process_pattern_iterative: function(file, patternlab){ - processPatternIterative(file, patternlab); - }, - process_pattern_recursive: function(file, patternlab, additionalData){ - processPatternRecursive(file, patternlab, additionalData); - }, - 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); - }, - parse_data_links: function(patternlab){ - parseDataLinks(patternlab); - } - }; +}; - }; +module.exports = pattern_assembler; - module.exports = pattern_assembler; -}()); diff --git a/builder/pattern_exporter.js b/builder/pattern_exporter.js index 3d04658d3..23c9777a4 100644 --- a/builder/pattern_exporter.js +++ b/builder/pattern_exporter.js @@ -1,45 +1,40 @@ -/* - * patternlab-node - v1.1.3 - 2016 - * +/* + * patternlab-node - v1.1.3 - 2016 + * * 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. * */ -(function () { - "use strict"; - - var fs = require('fs-extra'), - path = require('path'); +"use strict"; - var pattern_exporter = function(){ +var fs = require('fs-extra'); - function exportPatterns(patternlab){ +var pattern_exporter = function () { - //read the config export options - var exportKeys = patternlab.config.patternExportKeys; + function exportPatterns(patternlab) { + //read the config export options + var exportKeys = patternlab.config.patternExportKeys; - //find the chosen patterns to export - for (var i = 0; i < exportKeys.length; i++){ - for (var j = 0; j < patternlab.patterns.length; j++){ - if(exportKeys[i] === patternlab.patterns[j].key){ - //write matches to the desired location - fs.outputFileSync(patternlab.config.patternExportDirectory + patternlab.patterns[j].key + '.html', patternlab.patterns[j].patternPartial); - } + //find the chosen patterns to export + for (var i = 0; i < exportKeys.length; i++) { + for (var j = 0; j < patternlab.patterns.length; j++) { + if (exportKeys[i] === patternlab.patterns[j].key) { + //write matches to the desired location + fs.outputFileSync(patternlab.config.patternExportDirectory + patternlab.patterns[j].key + '.html', patternlab.patterns[j].patternPartial); } } } + } - return { - export_patterns: function(patternlab){ - exportPatterns(patternlab); - } - }; - + return { + export_patterns: function (patternlab) { + exportPatterns(patternlab); + } }; - module.exports = pattern_exporter; +}; -}()); +module.exports = pattern_exporter; diff --git a/builder/patternlab.js b/builder/patternlab.js index aae791f23..b4705deaf 100644 --- a/builder/patternlab.js +++ b/builder/patternlab.js @@ -1,10 +1,10 @@ -/* - * patternlab-node - v1.1.3 - 2016 - * +/* + * patternlab-node - v1.1.3 - 2016 + * * 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. * */ @@ -12,17 +12,14 @@ var patternlab_engine = function (config) { 'use strict'; var path = require('path'), - fs = require('fs-extra'), - extend = require('util')._extend, - diveSync = require('diveSync'), - mustache = require('mustache'), - glob = require('glob'), - of = require('./object_factory'), - pa = require('./pattern_assembler'), - mh = require('./media_hunter'), - pe = require('./pattern_exporter'), - he = require('html-entities').AllHtmlEntities, - patternlab = {}; + fs = require('fs-extra'), + diveSync = require('diveSync'), + of = require('./object_factory'), + pa = require('./pattern_assembler'), + mh = require('./media_hunter'), + pe = require('./pattern_exporter'), + he = require('html-entities').AllHtmlEntities, + patternlab = {}; patternlab.package = fs.readJSONSync('./package.json'); patternlab.config = config || fs.readJSONSync(path.resolve(__dirname, '../config.json')); @@ -34,7 +31,7 @@ var patternlab_engine = function (config) { console.log(patternlab.package.version); } - function help(){ + function help() { console.log('Patternlab Node Help'); console.log('==============================='); console.log('Command Line Arguments'); @@ -51,13 +48,13 @@ var patternlab_engine = function (config) { function printDebug() { //debug file can be written by setting flag on config.json - if(patternlab.config.debug){ + if (patternlab.config.debug) { console.log('writing patternlab debug file to ./patternlab.json'); fs.outputFileSync('./patternlab.json', JSON.stringify(patternlab, null, 3)); } } - function buildPatterns(deletePatternDir){ + function buildPatterns(deletePatternDir) { patternlab.data = fs.readJSONSync(path.resolve(paths.source.data, 'data.json')); patternlab.listitems = fs.readJSONSync(path.resolve(paths.source.data, 'listitems.json')); patternlab.header = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'pattern-header-footer/header.html'), 'utf8'); @@ -67,47 +64,52 @@ var patternlab_engine = function (config) { patternlab.data.link = {}; var pattern_assembler = new pa(), - entity_encoder = new he(), - pattern_exporter = new pe(), - patterns_dir = paths.source.patterns; + entity_encoder = new he(), + pattern_exporter = new pe(), + patterns_dir = paths.source.patterns; pattern_assembler.combine_listItems(patternlab); //diveSync once to perform iterative populating of patternlab object - diveSync(patterns_dir, { - filter: function(path, dir) { - if(dir){ - var remainingPath = path.replace(patterns_dir, ''); - var isValidPath = remainingPath.indexOf('/_') === -1; - return isValidPath; - } + diveSync( + patterns_dir, + { + filter: function (filePath, dir) { + if (dir) { + var remainingPath = filePath.replace(patterns_dir, ''); + var isValidPath = remainingPath.indexOf('/_') === -1; + return isValidPath; + } return true; } }, - function(err, file){ + function (err, file) { //log any errors - if(err){ + if (err) { console.log(err); return; } pattern_assembler.process_pattern_iterative(path.resolve(file), patternlab); - }); + } + ); //diveSync again to recursively include partials, filling out the //extendedTemplate property of the patternlab.patterns elements - diveSync(patterns_dir, { - filter: function(path, dir) { - if(dir){ - var remainingPath = path.replace(patterns_dir, ''); - var isValidPath = remainingPath.indexOf('/_') === -1; - return isValidPath; - } + diveSync( + patterns_dir, + { + filter: function (filePath, dir) { + if (dir) { + var remainingPath = filePath.replace(patterns_dir, ''); + var isValidPath = remainingPath.indexOf('/_') === -1; + return isValidPath; + } return true; } }, - function(err, file){ + function (err, file) { //log any errors - if(err){ + if (err) { console.log(err); return; } @@ -120,15 +122,15 @@ var patternlab_engine = function (config) { pattern_assembler.parse_data_links(patternlab); //delete the contents of config.patterns.public before writing - if(deletePatternDir){ + if (deletePatternDir) { fs.emptyDirSync(paths.public.patterns); } //render all patterns last, so lineageR works - patternlab.patterns.forEach(function(pattern, index, patterns){ + patternlab.patterns.forEach(function (pattern) { //render the pattern, but first consolidate any data we may have - var allData = JSON.parse(JSON.stringify(patternlab.data)); + var allData = JSON.parse(JSON.stringify(patternlab.data)); allData = pattern_assembler.merge_data(allData, pattern.jsonFileData); //render the extendedTemplate with all data @@ -149,27 +151,36 @@ var patternlab_engine = function (config) { //export patterns if necessary pattern_exporter.export_patterns(patternlab); + } + + function addToPatternPaths(bucketName, pattern) { + //this is messy, could use a refactor. + patternlab.patternPaths[bucketName][pattern.patternName] = pattern.subdir.replace(/\\/g, '/') + "/" + pattern.fileName; + } + //todo: refactor this as a method on the pattern object itself once we merge dev with pattern-engines branch + function isPatternExcluded(pattern) { + // returns whether or not the first character of the pattern filename is an underscore, or excluded + return pattern.fileName.charAt(0) === '_'; } - function buildFrontEnd(){ + function buildFrontEnd() { var pattern_assembler = new pa(), - media_hunter = new mh(), - styleGuideExcludes = patternlab.config.styleGuideExcludes, - styleguidePatterns = []; + media_hunter = new mh(), + styleGuideExcludes = patternlab.config.styleGuideExcludes, + styleguidePatterns = [], + i; // for loops + patternlab.buckets = []; patternlab.bucketIndex = []; patternlab.patternPaths = {}; patternlab.viewAllPaths = {}; //sort all patterns explicitly. - patternlab.patterns = patternlab.patterns.sort(function(a,b){ - if (a.name > b.name) { - return 1; - } - if (a.name < b.name) { - return -1; - } + patternlab.patterns = patternlab.patterns.sort(function (a, b) { + if (a.name > b.name) { return 1; } + if (a.name < b.name) { return -1; } + // a must be equal to b return 0; }); @@ -179,41 +190,41 @@ var patternlab_engine = function (config) { // check if patterns are excluded, if not add them to styleguidePatterns if (styleGuideExcludes && styleGuideExcludes.length) { - for (i = 0; i < patternlab.patterns.length; i++) { + for (i = 0; i < patternlab.patterns.length; i++) { - // skip underscore-prefixed files - if(isPatternExcluded(patternlab.patterns[i])){ - if(patternlab.config.debug){ - console.log('Omitting ' + patternlab.patterns[i].key + " from styleguide pattern exclusion."); - } - continue; + // skip underscore-prefixed files + if (isPatternExcluded(patternlab.patterns[i])) { + if (patternlab.config.debug) { + console.log('Omitting ' + patternlab.patterns[i].key + " from styleguide pattern exclusion."); } + continue; + } - var key = patternlab.patterns[i].key; - var typeKey = key.substring(0, key.indexOf('-')); - var isExcluded = (styleGuideExcludes.indexOf(typeKey) > -1); - if (!isExcluded) { - styleguidePatterns.push(patternlab.patterns[i]); - } + var key = patternlab.patterns[i].key; + var typeKey = key.substring(0, key.indexOf('-')); + var isExcluded = (styleGuideExcludes.indexOf(typeKey) > -1); + if (!isExcluded) { + styleguidePatterns.push(patternlab.patterns[i]); } + } } else { styleguidePatterns = patternlab.patterns; } //build the styleguide var styleguideTemplate = fs.readFileSync(path.resolve(paths.source.patternlabFiles, 'styleguide.mustache'), 'utf8'), - styleguideHtml = pattern_assembler.renderPattern(styleguideTemplate, {partials: styleguidePatterns}); + styleguideHtml = pattern_assembler.renderPattern(styleguideTemplate, {partials: styleguidePatterns}); + fs.outputFileSync(path.resolve(paths.public.styleguide, 'html/styleguide.html'), styleguideHtml); //build the viewall pages var prevSubdir = '', - prevGroup = '', - i; + prevGroup = ''; for (i = 0; i < patternlab.patterns.length; i++) { // skip underscore-prefixed files - if(isPatternExcluded(patternlab.patterns[i])){ - if(patternlab.config.debug){ + if (isPatternExcluded(patternlab.patterns[i])) { + if (patternlab.config.debug) { console.log('Omitting ' + patternlab.patterns[i].key + " from view all rendering."); } continue; @@ -223,18 +234,18 @@ var patternlab_engine = function (config) { //create the view all for the section // check if the current section is different from the previous one - if (pattern.patternGroup != prevGroup){ + if (pattern.patternGroup !== prevGroup) { prevGroup = pattern.patternGroup; var viewAllPatterns = [], - patternPartial = "viewall-" + pattern.patternGroup, - j; + patternPartial = "viewall-" + pattern.patternGroup, + j; for (j = 0; j < patternlab.patterns.length; j++) { if (patternlab.patterns[j].patternGroup === pattern.patternGroup) { //again, skip any sibling patterns to the current one that may have underscores - if(isPatternExcluded(patternlab.patterns[j])){ - if(patternlab.config.debug){ + if (isPatternExcluded(patternlab.patterns[j])) { + if (patternlab.config.debug) { console.log('Omitting ' + patternlab.patterns[j].key + " from view all sibling rendering."); } continue; @@ -249,25 +260,24 @@ var patternlab_engine = function (config) { fs.outputFileSync(paths.public.patterns + pattern.subdir.slice(0, pattern.subdir.indexOf(pattern.patternGroup) + pattern.patternGroup.length) + '/index.html', viewAllHtml); } - //create the view all for the subsection + // create the view all for the subsection // check if the current sub section is different from the previous one if (pattern.subdir !== prevSubdir) { prevSubdir = pattern.subdir; var viewAllPatterns = [], - patternPartial = "viewall-" + pattern.patternGroup + "-" + pattern.patternSubGroup, - j; + patternPartial = "viewall-" + pattern.patternGroup + "-" + pattern.patternSubGroup, + j; for (j = 0; j < patternlab.patterns.length; j++) { if (patternlab.patterns[j].subdir === pattern.subdir) { //again, skip any sibling patterns to the current one that may have underscores - if(isPatternExcluded(patternlab.patterns[j])){ - if(patternlab.config.debug){ + if (isPatternExcluded(patternlab.patterns[j])) { + if (patternlab.config.debug) { console.log('Omitting ' + patternlab.patterns[j].key + " from view all sibling rendering."); } continue; } - viewAllPatterns.push(patternlab.patterns[j]); } } @@ -283,17 +293,17 @@ var patternlab_engine = function (config) { //loop through all patterns.to build the navigation //todo: refactor this someday - for(var i = 0; i < patternlab.patterns.length; i++){ + for (i = 0; i < patternlab.patterns.length; i++) { var pattern = patternlab.patterns[i]; var bucketName = pattern.name.replace(/\\/g, '-').split('-')[1]; //check if the bucket already exists var bucketIndex = patternlab.bucketIndex.indexOf(bucketName); - if(bucketIndex === -1){ + if (bucketIndex === -1) { // skip underscore-prefixed files. don't create a bucket on account of an underscored pattern - if(isPatternExcluded(pattern)){ + if (isPatternExcluded(pattern)) { continue; } @@ -313,7 +323,7 @@ var patternlab_engine = function (config) { //test whether the pattern struture is flat or not - usually due to a template or page var flatPatternItem = false; - if(navItemName === bucketName){ + if (navItemName === bucketName) { flatPatternItem = true; } @@ -326,20 +336,18 @@ var patternlab_engine = function (config) { navSubItem.patternPartial = bucketName + "-" + pattern.patternName; //add the hyphenated name //add the patternState if it exists - if(pattern.patternState){ + if (pattern.patternState) { navSubItem.patternState = pattern.patternState; } //if it is flat - we should not add the pattern to patternPaths - if(flatPatternItem){ - + if (flatPatternItem) { bucket.patternItems.push(navSubItem); //add to patternPaths addToPatternPaths(bucketName, pattern); - } else{ - + } else { bucket.navItems.push(navItem); bucket.navItemsIndex.push(navItemName); navItem.navSubItems.push(navSubItem); @@ -354,8 +362,7 @@ var patternlab_engine = function (config) { navViewAllItem.patternPartial = "viewall-" + pattern.patternGroup; bucket.patternItems.push(navViewAllItem); - patternlab.viewAllPaths[bucketName]['viewall'] = pattern.subdir.slice(0, pattern.subdir.indexOf(pattern.patternGroup) + pattern.patternGroup.length); - + patternlab.viewAllPaths[bucketName].viewall = pattern.subdir.slice(0, pattern.subdir.indexOf(pattern.patternGroup) + pattern.patternGroup.length); } //add the bucket. @@ -364,7 +371,7 @@ var patternlab_engine = function (config) { //done - } else{ + } else { //find the bucket var bucket = patternlab.buckets[bucketIndex]; @@ -383,21 +390,21 @@ var patternlab_engine = function (config) { navSubItem.patternPartial = bucketName + "-" + pattern.patternName; //add the hyphenated name //add the patternState if it exists - if(pattern.patternState){ + if (pattern.patternState) { navSubItem.patternState = pattern.patternState; } //test whether the pattern struture is flat or not - usually due to a template or page var flatPatternItem = false; - if(navItemName === bucketName){ + if (navItemName === bucketName) { flatPatternItem = true; } //if it is flat - we should not add the pattern to patternPaths - if(flatPatternItem){ + if (flatPatternItem) { // skip underscore-prefixed files - if(isPatternExcluded(pattern)){ + if (isPatternExcluded(pattern)) { continue; } @@ -407,14 +414,13 @@ var patternlab_engine = function (config) { //add to patternPaths addToPatternPaths(bucketName, pattern); - } else{ + } else { // only do this if pattern is included - if(!isPatternExcluded(pattern)){ + if (!isPatternExcluded(pattern)) { //check to see if navItem exists var navItemIndex = bucket.navItemsIndex.indexOf(navItemName); - if(navItemIndex === -1){ - + if (navItemIndex === -1) { var navItem = new of.oNavItem(navItemName); //add the navItem and navSubItem @@ -423,7 +429,7 @@ var patternlab_engine = function (config) { bucket.navItems.push(navItem); bucket.navItemsIndex.push(navItemName); - } else{ + } else { //add the navSubItem var navItem = bucket.navItems[navItemIndex]; navItem.navSubItems.push(navSubItem); @@ -482,30 +488,19 @@ var patternlab_engine = function (config) { fs.outputFileSync(path.resolve(paths.public.root, 'index.html'), patternlabSiteHtml); } - function addToPatternPaths(bucketName, pattern){ - //this is messy, could use a refactor. - patternlab.patternPaths[bucketName][pattern.patternName] = pattern.subdir.replace(/\\/g, '/') + "/" + pattern.fileName; - } - - //todo: refactor this as a method on the pattern object itself once we merge dev with pattern-engines branch - function isPatternExcluded(pattern){ - // returns whether or not the first character of the pattern filename is an underscore, or excluded - return pattern.fileName.charAt(0) === '_'; - } - return { - version: function(){ + version: function () { return getVersion(); }, - build: function(deletePatternDir){ + build: function (deletePatternDir) { buildPatterns(deletePatternDir); buildFrontEnd(); printDebug(); }, - help: function(){ + help: function () { help(); }, - build_patterns_only: function(deletePatternDir){ + build_patterns_only: function (deletePatternDir) { buildPatterns(deletePatternDir); printDebug(); } diff --git a/builder/patternlab_grunt.js b/builder/patternlab_grunt.js index 93b50b1e7..69085c291 100644 --- a/builder/patternlab_grunt.js +++ b/builder/patternlab_grunt.js @@ -10,31 +10,29 @@ var patternlab_engine = require('./patternlab.js'); -module.exports = function(grunt) { - grunt.registerTask('patternlab', 'create design systems with atomic design', function(arg) { - - var patternlab = patternlab_engine(); - - if(arguments.length === 0){ - patternlab.build(true); - } - - if(arg && arg === 'v'){ - patternlab.version(); - } - - if(arg && arg === "only_patterns"){ - patternlab.build_patterns_only(true); - } - - if(arg && arg === "help"){ - patternlab.help(); - } - - if(arg && (arg !== "v" && arg !=="only_patterns" && arg !=="help")){ - patternlab.help(); - } - - }); +module.exports = function (grunt) { + grunt.registerTask('patternlab', 'create design systems with atomic design', function (arg) { + var patternlab = patternlab_engine(); + + if (arguments.length === 0) { + patternlab.build(true); + } + + if (arg && arg === 'v') { + patternlab.version(); + } + + if (arg && arg === "only_patterns") { + patternlab.build_patterns_only(true); + } + + if (arg && arg === "help") { + patternlab.help(); + } + + if (arg && (arg !== "v" && arg !== "only_patterns" && arg !== "help")) { + patternlab.help(); + } + }); }; diff --git a/builder/patternlab_gulp.js b/builder/patternlab_gulp.js index e036b1bb5..82cf2a4ce 100644 --- a/builder/patternlab_gulp.js +++ b/builder/patternlab_gulp.js @@ -1,36 +1,35 @@ -/* - * patternlab-node - v1.1.3 - 2016 - * +/* + * patternlab-node - v1.1.3 - 2016 + * * 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. * */ var patternlab_engine = require('./patternlab.js'); -module.exports = function(gulp) { +module.exports = function (gulp) { - gulp.task('patternlab', ['clean'], function(cb){ + gulp.task('patternlab', ['clean'], function (cb) { var patternlab = patternlab_engine(); patternlab.build(false); cb(); }); - gulp.task('patternlab:version', function(){ + gulp.task('patternlab:version', function () { var patternlab = patternlab_engine(); patternlab.version(); }); - gulp.task('patternlab:only_patterns', ['clean'], function(){ + gulp.task('patternlab:only_patterns', ['clean'], function () { var patternlab = patternlab_engine(); patternlab.build_patterns_only(false); }); - gulp.task('patternlab:help', function(){ + gulp.task('patternlab:help', function () { var patternlab = patternlab_engine(); patternlab.help(); }); - }; diff --git a/builder/pseudopattern_hunter.js b/builder/pseudopattern_hunter.js index 77773040e..6366be9e8 100644 --- a/builder/pseudopattern_hunter.js +++ b/builder/pseudopattern_hunter.js @@ -1,83 +1,76 @@ -/* - * patternlab-node - v1.1.3 - 2016 - * +/* + * patternlab-node - v1.1.3 - 2016 + * * 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. * */ -(function () { - "use strict"; - - var pseudopattern_hunter = function(){ - - function findpseudopatterns(currentPattern, patternlab){ - - var glob = require('glob'), - fs = require('fs-extra'), - pa = require('./pattern_assembler'), - lh = require('./lineage_hunter'), - of = require('./object_factory'), - path = require('path'); - - var pattern_assembler = new pa(); - var lineage_hunter = new lh(); - var paths = patternlab.config.paths; - - //look for a pseudo pattern by checking if there is a file containing same name, with ~ in it, ending in .json - var needle = currentPattern.subdir + '/' + currentPattern.fileName + '~*.json'; - var pseudoPatterns = glob.sync(needle, { - cwd: paths.source.patterns, - debug: false, - nodir: true, - }); +"use strict"; - if(pseudoPatterns.length > 0){ +var pseudopattern_hunter = function () { - for(var i = 0; i < pseudoPatterns.length; i++){ + function findpseudopatterns(currentPattern, patternlab) { + var glob = require('glob'), + fs = require('fs-extra'), + pa = require('./pattern_assembler'), + lh = require('./lineage_hunter'), + of = require('./object_factory'), + path = require('path'); - if(patternlab.config.debug){ - console.log('found pseudoPattern variant of ' + currentPattern.key); - } + var pattern_assembler = new pa(); + var lineage_hunter = new lh(); + var paths = patternlab.config.paths; - //we want to do everything we normally would here, except instead read the pseudoPattern data - var variantFileData = fs.readJSONSync(path.resolve(paths.source.patterns, pseudoPatterns[i])); + //look for a pseudo pattern by checking if there is a file containing same name, with ~ in it, ending in .json + var needle = currentPattern.subdir + '/' + currentPattern.fileName + '~*.json'; + var pseudoPatterns = glob.sync(needle, { + cwd: paths.source.patterns, + debug: false, + nodir: true + }); - //extend any existing data with variant data - variantFileData = pattern_assembler.merge_data(currentPattern.jsonFileData, variantFileData); + if (pseudoPatterns.length > 0) { + for (var i = 0; i < pseudoPatterns.length; i++) { + if (patternlab.config.debug) { + console.log('found pseudoPattern variant of ' + currentPattern.key); + } - var variantName = pseudoPatterns[i].substring(pseudoPatterns[i].indexOf('~') + 1).split('.')[0]; - var variantFilePath = path.resolve(paths.source.patterns, currentPattern.subdir, currentPattern.fileName + '~' + variantName + '.json'); - var variantFileName = currentPattern.fileName + '-' + variantName + '.'; - var patternVariant = new of.oPattern(variantFilePath, currentPattern.subdir, variantFileName, variantFileData); + //we want to do everything we normally would here, except instead read the pseudoPattern data + var variantFileData = fs.readJSONSync(path.resolve(paths.source.patterns, pseudoPatterns[i])); - //see if this file has a state - pattern_assembler.setPatternState(patternVariant, patternlab); + //extend any existing data with variant data + variantFileData = pattern_assembler.merge_data(currentPattern.jsonFileData, variantFileData); - //use the same template as the non-variant - patternVariant.template = currentPattern.template; - patternVariant.extendedTemplate = currentPattern.extendedTemplate; + var variantName = pseudoPatterns[i].substring(pseudoPatterns[i].indexOf('~') + 1).split('.')[0]; + var variantFilePath = path.resolve(paths.source.patterns, currentPattern.subdir, currentPattern.fileName + '~' + variantName + '.json'); + var variantFileName = currentPattern.fileName + '-' + variantName + '.'; + var patternVariant = new of.oPattern(variantFilePath, currentPattern.subdir, variantFileName, variantFileData); - //find pattern lineage - lineage_hunter.find_lineage(patternVariant, patternlab); + //see if this file has a state + pattern_assembler.setPatternState(patternVariant, patternlab); - //add to patternlab object so we can look these up later. - pattern_assembler.addPattern(patternVariant, patternlab); - } - } + //use the same template as the non-variant + patternVariant.template = currentPattern.template; + patternVariant.extendedTemplate = currentPattern.extendedTemplate; - } + //find pattern lineage + lineage_hunter.find_lineage(patternVariant, patternlab); - return { - find_pseudopatterns: function(pattern, patternlab){ - findpseudopatterns(pattern, patternlab); - } - }; + //add to patternlab object so we can look these up later. + pattern_assembler.addPattern(patternVariant, patternlab); + } + } + } - }; + return { + find_pseudopatterns: function (pattern, patternlab) { + findpseudopatterns(pattern, patternlab); + } + }; - module.exports = pseudopattern_hunter; +}; -}()); +module.exports = pseudopattern_hunter; diff --git a/builder/style_modifier_hunter.js b/builder/style_modifier_hunter.js index a19fbf081..742009ce4 100644 --- a/builder/style_modifier_hunter.js +++ b/builder/style_modifier_hunter.js @@ -1,47 +1,43 @@ -/* - * patternlab-node - v1.1.3 - 2016 - * +/* + * patternlab-node - v1.1.3 - 2016 + * * 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. * */ -(function () { - "use strict"; - - var style_modifier_hunter = function(){ - - function consumestylemodifier(pattern, partial, patternlab){ +"use strict"; - //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; - if(styleModifier){ +var style_modifier_hunter = function () { - //replace the special character pipe | used to separate multiple classes with a space - styleModifier = styleModifier.replace(/\|/g, ' '); + 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; - if(patternlab.config.debug){ - console.log('found partial styleModifier within pattern ' + pattern.key); - } + if (styleModifier) { + //replace the special character pipe | used to separate multiple classes with a space + styleModifier = styleModifier.replace(/\|/g, ' '); - //replace the stylemodifier placeholder with the class name - pattern.extendedTemplate = pattern.extendedTemplate.replace(/{{[ ]?styleModifier[ ]?}}/i, styleModifier); + if (patternlab.config.debug) { + console.log('found partial styleModifier within pattern ' + pattern.key); + } - //update the extendedTemplate in the partials object in case this pattern is consumed later - patternlab.partials[pattern.key] = pattern.extendedTemplate; - } - } + //replace the stylemodifier placeholder with the class name + pattern.extendedTemplate = pattern.extendedTemplate.replace(/{{[ ]?styleModifier[ ]?}}/i, styleModifier); - return { - consume_style_modifier: function(pattern, partial, patternlab){ - consumestylemodifier(pattern, partial, patternlab); - } - }; + //update the extendedTemplate in the partials object in case this pattern is consumed later + patternlab.partials[pattern.key] = pattern.extendedTemplate; + } + } - }; + return { + consume_style_modifier: function (pattern, partial, patternlab) { + consumestylemodifier(pattern, partial, patternlab); + } + }; - module.exports = style_modifier_hunter; +}; -}()); +module.exports = style_modifier_hunter; diff --git a/config.json b/config.json index 0ca6ef1f0..187e8955d 100644 --- a/config.json +++ b/config.json @@ -22,36 +22,36 @@ "css" : "./public/css" } }, - "styleGuideExcludes": [ - "templates", - "pages" - ], - "ignored-extensions" : ["scss", "DS_Store", "less"], - "ignored-directories" : ["scss"], - "debug": false, - "ishControlsVisible": { - "s": true, - "m": true, - "l": true, - "full": true, - "random": true, - "disco": true, - "hay": true, - "mqs": true, - "find": true, - "views-all": true, - "views-annotations": true, - "views-code": true, - "views-new": true, - "tools-all": true, - "tools-sync": true, - "tools-shortcuts": true, - "tools-docs": true - }, + "styleGuideExcludes": [ + "templates", + "pages" + ], + "ignored-extensions" : ["scss", "DS_Store", "less"], + "ignored-directories" : ["scss"], + "debug": false, + "ishControlsVisible": { + "s": true, + "m": true, + "l": true, + "full": true, + "random": true, + "disco": true, + "hay": true, + "mqs": true, + "find": true, + "views-all": true, + "views-annotations": true, + "views-code": true, + "views-new": true, + "tools-all": true, + "tools-sync": true, + "tools-shortcuts": true, + "tools-docs": true + }, "patternStates": { "homepage-emergency" : "inprogress" }, "patternExportKeys": [], "patternExportDirectory": "./pattern_exports/", "baseurl" : "" - } +} diff --git a/gulpfile.js b/gulpfile.js index fb5593def..a00019f2d 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,4 +1,5 @@ -// Special thanks to oscar-g (https://github.com/oscar-g) for starting this at https://github.com/oscar-g/patternlab-node/tree/dev-gulp +// Special thanks to oscar-g (https://github.com/oscar-g) for starting this at +// https://github.com/oscar-g/patternlab-node/tree/dev-gulp var pkg = require('./package.json'), gulp = require('gulp'), @@ -8,6 +9,7 @@ var pkg = require('./package.json'), strip_banner = require('gulp-strip-banner'), header = require('gulp-header'), nodeunit = require('gulp-nodeunit'), + eslint = require('gulp-eslint'), browserSync = require('browser-sync').create(); require('gulp-load')(gulp); @@ -20,21 +22,21 @@ var banner = [ '/** ', ' * Many thanks to Brad Frost and Dave Olsen for inspiration, encouragement, and advice.', ' * ', ' **/'].join(eol); -function paths () { +function paths() { return require('./config.json').paths; } //load patternlab-node tasks -gulp.loadTasks(__dirname+'/builder/patternlab_gulp.js'); +gulp.loadTasks(__dirname + '/builder/patternlab_gulp.js'); //clean patterns dir -gulp.task('clean', function(cb){ +gulp.task('clean', function (cb) { del.sync([path.resolve(paths().public.patterns, '*')], {force: true}); cb(); }); //build the banner -gulp.task('banner', function(){ +gulp.task('banner', function () { return gulp.src([ './builder/patternlab.js', './builder/object_factory.js', @@ -50,7 +52,7 @@ gulp.task('banner', function(){ './builder/style_modifier_hunter.js' ]) .pipe(strip_banner()) - .pipe(header( banner, { + .pipe(header(banner, { pkg : pkg, today : new Date().getFullYear() } )) @@ -61,40 +63,40 @@ gulp.task('banner', function(){ // COPY TASKS // JS copy -gulp.task('cp:js', function(){ - return gulp.src('**/*.js', {cwd: path.resolve(paths().source.js)} ) +gulp.task('cp:js', function () { + return gulp.src('**/*.js', {cwd: path.resolve(paths().source.js)}) .pipe(gulp.dest(path.resolve(paths().public.js))); }); // Images copy -gulp.task('cp:img', function(){ +gulp.task('cp:img', function () { return gulp.src( - [ '**/*.gif', '**/*.png', '**/*.jpg', '**/*.jpeg' ], - {cwd: path.resolve(paths().source.images)} ) + ['**/*.gif', '**/*.png', '**/*.jpg', '**/*.jpeg'], + {cwd: path.resolve(paths().source.images)}) .pipe(gulp.dest(path.resolve(paths().public.images))); }); // Fonts copy -gulp.task('cp:font', function(){ +gulp.task('cp:font', function () { return gulp.src('*', {cwd: path.resolve(paths().source.fonts)}) .pipe(gulp.dest(path.resolve(paths().public.fonts))); }); // Data copy -gulp.task('cp:data', function(){ +gulp.task('cp:data', function () { return gulp.src('annotations.js', {cwd: path.resolve(paths().source.data)}) .pipe(gulp.dest(path.resolve(paths().public.data))); }); // CSS Copy -gulp.task('cp:css', function(){ +gulp.task('cp:css', function () { return gulp.src(path.resolve(paths().source.css, 'style.css')) .pipe(gulp.dest(path.resolve(paths().public.css))) .pipe(browserSync.stream()); }); // Styleguide Copy -gulp.task('cp:styleguide', function(){ +gulp.task('cp:styleguide', function () { return gulp.src( ['**/*'], {cwd: path.resolve(paths().source.styleguide)}) @@ -150,14 +152,22 @@ gulp.task('connect', ['lab'], function () { }); +//lint +gulp.task('eslint', function () { + return gulp.src(['./builder/*.js', '!node_modules/**']) + .pipe(eslint()) + .pipe(eslint.format()) + .pipe(eslint.failAfterError()); +}); + //unit test -gulp.task('nodeunit', function(){ +gulp.task('nodeunit', function () { return gulp.src('./test/**/*_tests.js') .pipe(nodeunit()); }); -gulp.task('lab-pipe', ['lab'], function(cb){ +gulp.task('lab-pipe', ['lab'], function (cb) { cb(); browserSync.reload(); }); @@ -166,10 +176,10 @@ gulp.task('default', ['lab']); gulp.task('assets', ['cp:js', 'cp:img', 'cp:font', 'cp:data', 'cp:css', 'cp:styleguide' ]); gulp.task('prelab', ['clean', 'assets']); -gulp.task('lab', ['prelab', 'patternlab'], function(cb){cb();}); +gulp.task('lab', ['prelab', 'patternlab'], function (cb) { cb(); }); gulp.task('patterns', ['patternlab:only_patterns']); gulp.task('serve', ['lab', 'connect']); -gulp.task('travis', ['lab', 'nodeunit']); +gulp.task('build', ['eslint', 'nodeunit', 'banner']); gulp.task('version', ['patternlab:version']); gulp.task('help', ['patternlab:help']); diff --git a/package.gulp.json b/package.gulp.json index 7bdc7cb2c..87a4d0044 100644 --- a/package.gulp.json +++ b/package.gulp.json @@ -16,6 +16,7 @@ "gulp": "^3.9.0", "gulp-connect": "^2.3.1", "gulp-copy": "0.0.2", + "gulp-eslint": "^2.0.0", "gulp-header": "^1.7.1", "gulp-load": "^0.1.1", "gulp-nodeunit": "0.0.5", diff --git a/package.json b/package.json index 4cfbf8671..a62664b52 100644 --- a/package.json +++ b/package.json @@ -14,11 +14,12 @@ "devDependencies": { "bs-html-injector": "^3.0.0", "grunt": "~0.4.5", - "grunt-contrib-concat": "^0.5.1", "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" + "grunt-contrib-watch": "^0.6.1", + "grunt-eslint": "^18.0.0" }, "keywords": [ "Pattern Lab",