├── .assemblerc ├── .editorconfig ├── .eslintrc.json ├── .gitattributes ├── .github ├── FUNDING.yml └── contributing.md ├── .gitignore ├── .travis.yml ├── .verbrc.md ├── CHANGELOG ├── Gruntfile.js ├── LICENSE ├── README.md ├── appveyor.yml ├── bower.json ├── docs ├── examples.md ├── getting-started.md ├── middleware.json ├── options.md └── v6-diffs.md ├── lib ├── assemble.js ├── collection.js ├── engine.js ├── helpers.js ├── plugins.js ├── plugins │ ├── page-collection-properties.js │ ├── pagination.js │ └── postprocess.js └── utils.js ├── package.json ├── tasks └── assemble.js └── test ├── actual ├── assets_base.html ├── assets_blank_path.html ├── assets_dot_slash.html ├── assets_nested.html ├── assets_trailing_slash.html ├── collections │ ├── asc │ │ ├── alert.html │ │ ├── collections-categories.html │ │ ├── collections-pages.html │ │ ├── collections-tags.html │ │ ├── collections.html │ │ ├── complex.html │ │ ├── context.html │ │ ├── debug-helpers.html │ │ ├── example.html │ │ ├── gist-helper.html │ │ ├── lodash.html │ │ ├── md-helper.html │ │ ├── no-yfm-data.html │ │ ├── no-yfm.html │ │ ├── yfm-context.html │ │ └── yfm.html │ ├── complex │ │ ├── alert.html │ │ ├── collections-categories.html │ │ ├── collections-pages.html │ │ ├── collections-tags.html │ │ ├── collections.html │ │ ├── complex.html │ │ ├── context.html │ │ ├── debug-helpers.html │ │ ├── example.html │ │ ├── gist-helper.html │ │ ├── lodash.html │ │ ├── md-helper.html │ │ ├── no-yfm-data.html │ │ ├── no-yfm.html │ │ ├── yfm-context.html │ │ └── yfm.html │ ├── custom │ │ ├── alert.html │ │ ├── collections-categories.html │ │ ├── collections-pages.html │ │ ├── collections-tags.html │ │ ├── collections.html │ │ ├── complex.html │ │ ├── context.html │ │ ├── debug-helpers.html │ │ ├── example.html │ │ ├── gist-helper.html │ │ ├── lodash.html │ │ ├── md-helper.html │ │ ├── no-yfm-data.html │ │ ├── no-yfm.html │ │ ├── yfm-context.html │ │ └── yfm.html │ └── desc │ │ ├── alert.html │ │ ├── collections-categories.html │ │ ├── collections-pages.html │ │ ├── collections-tags.html │ │ ├── collections.html │ │ ├── complex.html │ │ ├── context.html │ │ ├── debug-helpers.html │ │ ├── example.html │ │ ├── gist-helper.html │ │ ├── lodash.html │ │ ├── md-helper.html │ │ ├── no-yfm-data.html │ │ ├── no-yfm.html │ │ ├── yfm-context.html │ │ └── yfm.html ├── custom_helpers │ ├── bar.html │ ├── foo.html │ └── opt.html ├── globlayout │ ├── multi.html │ └── simple.html ├── layout_ext │ └── layoutext.html ├── nested_layouts │ ├── deep-nested-layouts.html │ └── nested-layouts.html ├── no_layout │ ├── no-layout-none.html │ └── no-layout.html ├── not_real.html ├── noyfm │ ├── no-yfm-data.html │ ├── no-yfm-datafile.html │ └── no-yfm.html ├── pages_array │ ├── index.html │ ├── post1.html │ ├── post2.html │ └── post3.html ├── pages_metadata │ ├── index.html │ ├── meta-awesome-blog-post-2.html │ ├── meta-super-sweet-and-awesome-blog-post-3.html │ └── meta-sweet-blog-post-1.html ├── pages_object │ ├── awesome-blog-post-2.html │ ├── index.html │ ├── super-sweet-and-awesome-blog-post-3.html │ └── sweet-blog-post-1.html ├── paths │ ├── alert.html │ ├── collections-categories.html │ ├── collections-pages.html │ ├── collections-tags.html │ ├── collections.html │ ├── complex.html │ ├── context.html │ ├── debug-helpers.html │ ├── example.html │ ├── gist-helper.html │ ├── lodash.html │ ├── md-helper.html │ ├── no-yfm-data.html │ ├── no-yfm.html │ ├── yfm-context.html │ └── yfm.html ├── plugin_after.html ├── plugin_before.html ├── plugin_pre_page.html ├── plugin_preprocess │ ├── alert.html │ ├── collections-categories.html │ ├── collections-pages.html │ ├── collections-tags.html │ ├── collections.html │ ├── complex.html │ ├── context.html │ ├── debug-helpers.html │ ├── example.html │ ├── gist-helper.html │ ├── lodash.html │ ├── md-helper.html │ ├── no-yfm-data.html │ ├── no-yfm.html │ ├── yfm-context.html │ └── yfm.html ├── plugin_untitled.html ├── single_page.html └── yfm │ ├── associative-arrays.html │ ├── block-literals.html │ ├── comments.html │ ├── data-files.html │ ├── data-types.html │ ├── document.html │ ├── lists.html │ ├── relational-trees.html │ ├── underscore.html │ └── variables.html ├── assemble_test.js ├── assets ├── gist.css ├── nested │ └── validation.css └── validation.css ├── collection_tests.js ├── engine_test.js ├── fixtures ├── assets_path │ └── assets.hbs ├── data │ ├── _site.yml │ ├── animal.json │ ├── blog.json │ ├── collections │ │ ├── expected-sortby-item-asc.json │ │ ├── expected-sortby-item-desc.json │ │ ├── expected-sortby-page-property-asc.json │ │ ├── expected-sortby-page-property-desc.json │ │ └── fakeCollection.json │ ├── config.json │ ├── contact.yml │ ├── data.yml │ ├── example.json │ ├── example.yml │ ├── home.json │ ├── noyfm.yml │ └── person.yml ├── helpers │ ├── bar.hbs │ ├── baz.hbs │ ├── foo.hbs │ └── opt.hbs ├── layouts │ ├── default.hbs │ ├── globlayout │ │ └── nested │ │ │ └── layout-globlayout.hbs │ ├── noext.hbs │ ├── one.hbs │ ├── post.hbs │ ├── preprocess.hbs │ ├── three.hbs │ └── two.hbs ├── mocha │ ├── complex.hbs │ ├── simple1.yml │ ├── simple2.yml │ └── yfm.hbs ├── pages │ ├── alert.hbs │ ├── blog │ │ └── index.hbs │ ├── collections-categories.hbs │ ├── collections-pages.hbs │ ├── collections-tags.hbs │ ├── collections.hbs │ ├── complex.hbs │ ├── context.hbs │ ├── debug-helpers.hbs │ ├── example.hbs │ ├── gist-helper.hbs │ ├── globlayout │ │ └── globlayout.hbs │ ├── layoutext │ │ └── layoutext.hbs │ ├── lodash.hbs │ ├── md-helper.hbs │ ├── md.md │ ├── nested │ │ ├── deep-nested-layouts.hbs │ │ └── nested-layouts.hbs │ ├── no-yfm-data.hbs │ ├── no-yfm.hbs │ ├── nolayout │ │ ├── no-layout-none.hbs │ │ └── no-layout.hbs │ ├── postprocess │ │ ├── postprocess.hbs │ │ └── postprocess2.hbs │ ├── yfm-context.hbs │ ├── yfm.hbs │ └── yfm │ │ ├── associative-arrays.hbs │ │ ├── block-literals.hbs │ │ ├── comments.hbs │ │ ├── data-files.hbs │ │ ├── data-types.hbs │ │ ├── document.hbs │ │ ├── lists.hbs │ │ ├── relational-trees.hbs │ │ ├── underscore.hbs │ │ └── variables.hbs ├── partials │ ├── alert.hbs │ ├── collections-categories.hbs │ ├── collections-custom.hbs │ ├── collections-tags.hbs │ └── nav-main.hbs ├── permalinks │ └── post.hbs └── plugins │ ├── after.hbs │ ├── before.hbs │ └── untitled.hbs ├── helpers ├── helpers-with-register.js ├── helpers.js ├── logging.js ├── markdown.js ├── nav.js ├── pager.js ├── rel.js └── utils │ ├── getext.js │ ├── index.js │ ├── isUndefined.js │ ├── parseAttributes.js │ ├── switchOutput.js │ ├── toString.js │ └── utils.js ├── mocha.opts ├── plugins ├── not_real.js ├── page_collection_preprocessing.js ├── plugin_after.js ├── plugin_before.js ├── plugin_one.js ├── plugin_pre_page.js └── untitled.js ├── plugins_test.js └── yfm_test.js /.assemblerc: -------------------------------------------------------------------------------- 1 | { 2 | "marked": { 3 | "breaks": false, 4 | "gfm": true, 5 | "langPrefix": "language-", 6 | "pedantic": false, 7 | "sanitize": false, 8 | "silent": false, 9 | "smartLists": false, 10 | "smartypants": false, 11 | "tables": true 12 | }, 13 | "flatten": true, 14 | "layout": "layout.hbs", 15 | "layoutdir": "test/templates/layouts", 16 | "helpers": "test/helpers/*.js", 17 | "assets": "test/actual/assets" 18 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | end_of_line = lf 6 | charset = utf-8 7 | indent_size = 2 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [{**/{actual,fixtures,expected,templates}/**,*.md}] 12 | trim_trailing_whitespace = false 13 | insert_final_newline = false -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "ecmaFeatures": { 3 | "modules": true, 4 | "experimentalObjectRestSpread": true 5 | }, 6 | 7 | "env": { 8 | "browser": false, 9 | "es6": true, 10 | "node": true, 11 | "mocha": true 12 | }, 13 | 14 | "globals": { 15 | "document": false, 16 | "navigator": false, 17 | "window": false 18 | }, 19 | 20 | "rules": { 21 | "accessor-pairs": 2, 22 | "arrow-spacing": [2, { "before": true, "after": true }], 23 | "block-spacing": [2, "always"], 24 | "brace-style": [2, "1tbs", { "allowSingleLine": true }], 25 | "comma-dangle": [2, "never"], 26 | "comma-spacing": [2, { "before": false, "after": true }], 27 | "comma-style": [2, "last"], 28 | "constructor-super": 2, 29 | "curly": [2, "multi-line"], 30 | "dot-location": [2, "property"], 31 | "eol-last": 2, 32 | "eqeqeq": [2, "allow-null"], 33 | "generator-star-spacing": [2, { "before": true, "after": true }], 34 | "handle-callback-err": [2, "^(err|error)$" ], 35 | "indent": [2, 2, { "SwitchCase": 1 }], 36 | "key-spacing": [2, { "beforeColon": false, "afterColon": true }], 37 | "keyword-spacing": [2, { "before": true, "after": true }], 38 | "new-cap": [2, { "newIsCap": true, "capIsNew": false }], 39 | "new-parens": 2, 40 | "no-array-constructor": 2, 41 | "no-caller": 2, 42 | "no-class-assign": 2, 43 | "no-cond-assign": 2, 44 | "no-const-assign": 2, 45 | "no-control-regex": 2, 46 | "no-debugger": 2, 47 | "no-delete-var": 2, 48 | "no-dupe-args": 2, 49 | "no-dupe-class-members": 2, 50 | "no-dupe-keys": 2, 51 | "no-duplicate-case": 2, 52 | "no-empty-character-class": 2, 53 | "no-eval": 2, 54 | "no-ex-assign": 2, 55 | "no-extend-native": 2, 56 | "no-extra-bind": 2, 57 | "no-extra-boolean-cast": 2, 58 | "no-extra-parens": [2, "functions"], 59 | "no-fallthrough": 2, 60 | "no-floating-decimal": 2, 61 | "no-func-assign": 2, 62 | "no-implied-eval": 2, 63 | "no-inner-declarations": [2, "functions"], 64 | "no-invalid-regexp": 2, 65 | "no-irregular-whitespace": 2, 66 | "no-iterator": 2, 67 | "no-label-var": 2, 68 | "no-labels": 2, 69 | "no-lone-blocks": 2, 70 | "no-mixed-spaces-and-tabs": 2, 71 | "no-multi-spaces": 2, 72 | "no-multi-str": 2, 73 | "no-multiple-empty-lines": [2, { "max": 1 }], 74 | "no-native-reassign": 0, 75 | "no-negated-in-lhs": 2, 76 | "no-new": 2, 77 | "no-new-func": 2, 78 | "no-new-object": 2, 79 | "no-new-require": 2, 80 | "no-new-wrappers": 2, 81 | "no-obj-calls": 2, 82 | "no-octal": 2, 83 | "no-octal-escape": 2, 84 | "no-proto": 0, 85 | "no-redeclare": 2, 86 | "no-regex-spaces": 2, 87 | "no-return-assign": 2, 88 | "no-self-compare": 2, 89 | "no-sequences": 2, 90 | "no-shadow-restricted-names": 2, 91 | "no-spaced-func": 2, 92 | "no-sparse-arrays": 2, 93 | "no-this-before-super": 2, 94 | "no-throw-literal": 2, 95 | "no-trailing-spaces": 0, 96 | "no-undef": 2, 97 | "no-undef-init": 2, 98 | "no-unexpected-multiline": 2, 99 | "no-unneeded-ternary": [2, { "defaultAssignment": false }], 100 | "no-unreachable": 2, 101 | "no-unused-vars": [2, { "vars": "all", "args": "none" }], 102 | "no-useless-call": 0, 103 | "no-with": 2, 104 | "one-var": [0, { "initialized": "never" }], 105 | "operator-linebreak": [0, "after", { "overrides": { "?": "before", ":": "before" } }], 106 | "padded-blocks": [0, "never"], 107 | "quotes": [2, "single", "avoid-escape"], 108 | "radix": 2, 109 | "semi": [2, "always"], 110 | "semi-spacing": [2, { "before": false, "after": true }], 111 | "space-before-blocks": [2, "always"], 112 | "space-before-function-paren": [2, "never"], 113 | "space-in-parens": [2, "never"], 114 | "space-infix-ops": 2, 115 | "space-unary-ops": [2, { "words": true, "nonwords": false }], 116 | "spaced-comment": [0, "always", { "markers": ["global", "globals", "eslint", "eslint-disable", "*package", "!", ","] }], 117 | "use-isnan": 2, 118 | "valid-typeof": 2, 119 | "wrap-iife": [2, "any"], 120 | "yoda": [2, "never"] 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set default behaviour, in case users don't have core.autocrlf set. 2 | * text=lf 3 | * text eol=lf 4 | *.* eol=lf 5 | 6 | *.jpg binary 7 | *.gif binary 8 | *.png binary 9 | *.jpeg binary -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [jonschlinkert, doowb] 2 | tidelift: npm/grunt-assemble 3 | -------------------------------------------------------------------------------- /.github/contributing.md: -------------------------------------------------------------------------------- 1 | Please see the [Contributing to Assemble](http://assemble.io/contributing) guide for information on contributing to this project. 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # always ignore files 2 | *.DS_Store 3 | *.sublime-* 4 | 5 | # test related, or directories generated by tests 6 | test/actual 7 | actual 8 | coverage 9 | .nyc* 10 | 11 | # npm 12 | node_modules 13 | npm-debug.log 14 | 15 | # yarn 16 | yarn.lock 17 | yarn-error.log 18 | 19 | # misc 20 | _gh_pages 21 | _draft 22 | _drafts 23 | bower_components 24 | vendor 25 | temp 26 | tmp 27 | TODO.md 28 | 29 | examples/*/dist 30 | examples/*/site 31 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | os: 3 | - linux 4 | - osx 5 | language: node_js 6 | node_js: 7 | - node 8 | - iojs 9 | - '7' 10 | - '6' 11 | - '5' 12 | - '4' 13 | - '0.12' 14 | - '0.10' 15 | git: 16 | depth: 10 17 | -------------------------------------------------------------------------------- /.verbrc.md: -------------------------------------------------------------------------------- 1 | --- 2 | author: 'Jon Schlinkert, Brian Woodward' 3 | --- 4 | # {%= name %} {%= badge("fury") %} {%= badge("travis") %} 5 | 6 | > {%= description %} 7 | 8 | ### [Visit the website →](http://assemble.io) 9 | 10 | ### Warning! 11 | 12 | > Versions of `grunt-assemble` below `0.2.0` have been deprecated and can be found on the [`0.1.15-deprecated` branch](https://github.com/assemble/grunt-assemble/tree/0.1.15-deprecated). 13 | Versions of `grunt-assemble` at and above `0.2.0` contain the code from the original `assemble` up to version `0.4.42`. 14 | 15 | > See the [migration](#migrations) section for instructions on what to do when upgrading to a new version. 16 | 17 | ## Why use Assemble? 18 | 19 | 1. Most popular site generator for Grunt.js and Yeoman. Assemble is used to build hundreds of web projects, ranging in size from a single page to 14,000 pages (that we're aware of!). [Let us know if you use Assemble](https://github.com/assemble/assemble/issues/300). 20 | 1. Allows you to carve your HTML up into reusable fragments: partials, includes, sections, snippets... Whatever you prefer to call them, Assemble does that. 21 | 1. Optionally use `layouts` to wrap your pages with commonly used elements and content. 22 | 1. "Pages" can either be defined as HTML/templates, JSON or YAML, or directly inside the Gruntfile. 23 | 1. It's awesome. Lol just kidding. But seriously, Assemble... is... awesome! and it's fun to use. 24 | 25 | ...and of course, we use Assemble to build the project's own documentation [http://assemble.io](http://assemble.io): 26 | 27 | **For more:** hear Jon Schlinkert and Brian Woodward discuss Assemble on **Episode 98 of the [Javascript Jabber Podcast](http://javascriptjabber.com/098-jsj-assemble-io-with-brian-woodward-and-jon-schlinkert/)**. 28 | 29 | 30 | ![image](https://f.cloud.github.com/assets/383994/1463257/f031bcfe-4525-11e3-9a03-89a17eee7518.png) 31 | 32 | ## The "assemble" task 33 | 34 | ### Getting Started 35 | {%= docs("getting-started") %} 36 | 37 | ### Options 38 | {%= docs("options") %} 39 | 40 | ### Usage Examples 41 | {%= docs("examples") %} 42 | 43 | ### Migrations 44 | {%= docs("v6-diffs") %} 45 | 46 | ## Contributing 47 | {%= include("contributing") %} 48 | 49 | ## Assemble plugins 50 | {%= include("assemble/repos-list") %} 51 | 52 | ## Authors 53 | {%= include("authors", { 54 | authors: [ 55 | { 56 | name: 'Jon Schlinkert', 57 | username: 'jonschlinkert' 58 | }, 59 | { 60 | name: 'Brian Woodward', 61 | username: 'doowb' 62 | } 63 | ] 64 | }) %} 65 | 66 | ## Release History 67 | {%= changelog() %} 68 | 69 | ## License 70 | {%= copyright() %} 71 | {%= license() %} 72 | 73 | *** 74 | 75 | {%= include("footer") %} 76 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | v0.4.41: 2 | date: "2014-07-07" 3 | changes: 4 | - Updating resolve-dep dependency. 5 | v0.4.38: 6 | date: "2014-06-13" 7 | changes: 8 | - Use gray-matter instead of assemble-yaml. 9 | - Updates dependencies. Minor refactoring and new utils to get rid of a couple of dependencies. 10 | - Update the loaders for plugins and helpers to use resolve-dep. Should be more reliable now. 11 | v0.4.17: 12 | date: "2013-10-25" 13 | changes: 14 | - Adds a params object to the call to `helper.register` allowing grunt and assemble to be passed in and used from inside helpers. 15 | v0.4.16: 16 | date: "2013-10-24" 17 | changes: 18 | - Adds support for using wildcards with plugins stages. 19 | v0.4.15: 20 | date: "2013-10-24" 21 | changes: 22 | - Implements multiple plugin stages. 23 | v0.4.14: 24 | date: "2013-10-21" 25 | changes: 26 | - Adds support for plugins running once, before and after (thanks @adjohnson916). 27 | - Adds pagination! 28 | - Thanks to @xzyfer, `options.data` can now also directly accept an object of data. 29 | v0.4.13: 30 | date: "2013-10-12" 31 | changes: 32 | - Adds `originalAssets` property to root context to store the pre-calculated assets path 33 | v0.4.12: 34 | date: "2013-10-05" 35 | changes: 36 | - Fixes plugins resolving for devDependencies. 37 | v0.4.11: 38 | date: "2013-10-03" 39 | changes: 40 | - Adds filePair to page object. thanks @adjohnson916! 41 | v0.4.10: 42 | date: "2013-10-02" 43 | changes: 44 | - Adds plugin support to Assemble using the `plugins` option. thanks @adjohnson916! 45 | v0.4.9: 46 | date: "2013-10-02" 47 | changes: 48 | - Adds `layoutext` and `postprocess` options. 49 | v0.4.8: 50 | date: "2013-09-30" 51 | changes: 52 | - Assemble now builds 30-50% faster due to some refactoring to async and how context is calculated. 53 | v0.4.7: 54 | date: "2013-09-20" 55 | changes: 56 | - Adds grunt-readme to make it easier to keep the readme updated using templates. 57 | - Keep options.partials intact so they can be used in helpers. 58 | v0.4.6: 59 | date: "2013-09-15" 60 | changes: 61 | - Updating how the assets path is calculated. 62 | - Adding resolve-dep and ability to load helpers from node modules using minimatch patterns 63 | v0.4.5: 64 | date: "2013-09-03" 65 | changes: 66 | - "Bug fix: allow page content containing $." 67 | - Add alias metadata for data on pages configuration object. 68 | v0.4.4: 69 | date: "2013-08-01" 70 | changes: 71 | - Adds "nested layouts" 72 | - Adds option for pages in JSON/YAML collections to be defined as either objects or keys in an array. 73 | v0.4.3: 74 | date: "2013-08-01" 75 | changes: 76 | - Adds "options.pages" for passing in an array of pages in JSON or YAML format. 77 | v0.4.0: 78 | date: "2013-06-20" 79 | changes: 80 | - Adds "layoutdir" option for defining the directory to be used for layouts. If layoutdir is defined, then layouts may be defined using only the name of the layout. 81 | v0.3.81: 82 | date: "2013-06-10" 83 | changes: 84 | - Adds additional ways to load custom helpers. Now it's possible to use a glob pattern that points to a list of scripts with helpers to load. 85 | - Adds examples and tests on how to use the new custom helper loading methods. 86 | v0.3.80: 87 | date: "2013-06-01" 88 | changes: 89 | - Fixing bug with null value in engine 90 | v0.3.77: 91 | date: "2013-05-07" 92 | changes: 93 | - Updated README with info about assemble methods 94 | v0.3.74: 95 | date: "2013-04-28" 96 | changes: 97 | - Updating the assemble library to use the assemble-utils repo and unnecessary code. 98 | v0.3.73: 99 | date: "2013-04-21" 100 | changes: 101 | - Fixing how the relative path helper worked and showing an example in the footer of the layout. This example is hidden, but can be seen by doing view source. 102 | v0.3.72: 103 | date: "2013-04-20" 104 | changes: 105 | - Fixing the layout override issue happening in the page yaml headers. Something was missed during refactoring. 106 | v0.3.9: 107 | date: "2013-04-19" 108 | changes: 109 | - Adds tags and categories to the root context and ensure that the current page context values don't override the root context values. 110 | v0.3.8: 111 | date: "2013-04-18" 112 | changes: 113 | - Updating to use actual assets property from current page. 114 | v0.3.7: 115 | date: "2013-04-17" 116 | changes: 117 | - Cleaning up some unused folders and tests 118 | v0.3.6: 119 | date: "2013-04-16" 120 | changes: 121 | - Fixed missing assets property. 122 | v0.3.5: 123 | date: "2013-04-16" 124 | changes: 125 | - Adds a sections array to the template engine so it can be used in helpers. 126 | v0.3.4: 127 | date: "2013-04-11" 128 | changes: 129 | - More tests for helpers and global variables, organized tests. A number of bug fixes. 130 | v0.3.3: 131 | date: "2013-04-06" 132 | changes: 133 | - helper-lib properly externalized and wired up. Global variables for filename, ext and pages 134 | v0.3.22: 135 | date: "2013-03-22" 136 | changes: 137 | - Merged global and target level options so data and partial files can be joined 138 | v0.3.21: 139 | date: "2013-03-22" 140 | changes: 141 | - Valid YAML now allowed in options.data object (along with JSON) 142 | v0.3.14: 143 | date: "2013-03-18" 144 | changes: 145 | - new relative helper for resolving relative paths 146 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Jon Schlinkert, Brian Woodward, contributors. 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # Test against this version of Node.js 2 | environment: 3 | matrix: 4 | # node.js 5 | - nodejs_version: "6.0" 6 | - nodejs_version: "5.0" 7 | - nodejs_version: "4.0" 8 | - nodejs_version: "0.12" 9 | - nodejs_version: "0.10" 10 | 11 | # Install scripts. (runs after repo cloning) 12 | install: 13 | # Get the latest stable version of Node.js or io.js 14 | - ps: Install-Product node $env:nodejs_version 15 | # install modules 16 | - npm install 17 | 18 | # Post-install test scripts. 19 | test_script: 20 | # Output useful info for debugging. 21 | - node --version 22 | - npm --version 23 | # run tests 24 | - npm test 25 | 26 | # Don't actually build. 27 | build: off 28 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "grunt-assemble", 3 | "version": "0.6.0", 4 | "main": [ 5 | "./lib/assemble" 6 | ], 7 | "description": "Static site generator for Grunt.js, Yeoman and Node.js. Used by Zurb Foundation, Zurb Ink, H5BP/Effeckt, Less.js / lesscss.org, Topcoat, Web Experience Toolkit, and hundreds of other projects to build sites, themes, components, documentation, blogs and gh-pages.", 8 | "homepage": "http://assemble.io", 9 | "contributors": [ 10 | "Brian Woodward (https://github.com/doowb)", 11 | "Jon Schlinkert (https://github.com/jonschlinkert)" 12 | ], 13 | "repository": "assemble/grunt-assemble", 14 | "bugs": { 15 | "url": "https://github.com/assemble/grunt-assemble/issues" 16 | }, 17 | "dependencies": { 18 | "assemble-handlebars": "^0.4.0", 19 | "async": "^0.9.0", 20 | "gray-matter": "^0.4.2", 21 | "inflection": "^1.3.6", 22 | "lodash": "^2.4.1", 23 | "resolve-dep": "^0.5.3" 24 | }, 25 | "devDependencies": { 26 | "chai": "^1.9.1", 27 | "grunt": "^0.4.5", 28 | "grunt-cli": "^0.1.13", 29 | "grunt-contrib-clean": "^0.5.0", 30 | "grunt-contrib-jshint": "^0.10.0", 31 | "grunt-mocha-test": "^0.11.0", 32 | "grunt-sync-pkg": "^0.1.2", 33 | "grunt-verb": "^0.2.4", 34 | "gruntify-eslint": "^3.1.0", 35 | "handlebars-helper-eachitems": "^0.1.2", 36 | "relative": "^0.1.4", 37 | "sort-object": "^3.0.2", 38 | "time-grunt": "^0.3.2" 39 | }, 40 | "keywords": [ 41 | "alternative", 42 | "blog", 43 | "boilerplate", 44 | "boilerplates", 45 | "bootstrap", 46 | "build", 47 | "builder", 48 | "components", 49 | "deployment", 50 | "front", 51 | "generator", 52 | "generators", 53 | "grunt", 54 | "gruntplugin", 55 | "handlebars", 56 | "handlebars-helper-eachitems", 57 | "helpers", 58 | "HTML", 59 | "javascript", 60 | "jekyll", 61 | "matter", 62 | "node", 63 | "node.js", 64 | "pages", 65 | "partial", 66 | "partials", 67 | "scaffold", 68 | "scaffolds", 69 | "site", 70 | "static", 71 | "task", 72 | "templates", 73 | "templating", 74 | "website", 75 | "yaml", 76 | "yeoman" 77 | ], 78 | "authors": [ 79 | "Assemble (https://github.com/assemble/assemble)" 80 | ], 81 | "license": "MIT", 82 | "ignore": [ 83 | "actual", 84 | "bower_components", 85 | "fixtures", 86 | "node_modules", 87 | "temp", 88 | "test", 89 | "test.js", 90 | "tmp" 91 | ], 92 | "files": [ 93 | "lib" 94 | ] 95 | } -------------------------------------------------------------------------------- /docs/examples.md: -------------------------------------------------------------------------------- 1 | Simple example of using data files in both `.json` and `.yml` format to build Handlebars templates. 2 | 3 | ```javascript 4 | assemble: { 5 | options: { 6 | data: 'src/data/**/*.{json,yml}' 7 | }, 8 | docs: { 9 | files: { 10 | 'dist/': ['src/templates/**/*.hbs'] 11 | } 12 | } 13 | } 14 | ``` 15 | 16 | ### Using multiple targets 17 | 18 | ```js 19 | assemble: { 20 | options: { 21 | assets: 'assets', 22 | layoutdir: 'docs/layouts' 23 | partials: ['docs/includes/**/*.hbs'], 24 | data: ['docs/data/**/*.{json,yml}'] 25 | }, 26 | site: { 27 | options: { 28 | layout: 'default.hbs' 29 | }, 30 | src: ['templates/site/*.hbs'], 31 | dest: './' 32 | }, 33 | blog: { 34 | options: { 35 | layout: 'blog-layout.hbs' 36 | }, 37 | src: ['templates/blog/*.hbs'], 38 | dest: 'articles/' 39 | }, 40 | docs: { 41 | options: { 42 | layout: 'docs-layout.hbs' 43 | }, 44 | src: ['templates/docs/*.hbs'], 45 | dest: 'docs/' 46 | } 47 | }, 48 | ``` 49 | 50 | Visit [Assemble's documentation](http://assemble.io) for many more examples and pointers on getting started. -------------------------------------------------------------------------------- /docs/getting-started.md: -------------------------------------------------------------------------------- 1 | Assemble requires Grunt `~0.4.1` 2 | 3 | _If you haven't used [grunt][] before, be sure to check out the [Getting Started][] guide._ 4 | 5 | From the same directory as your project's [Gruntfile][Getting Started] and [package.json][], install Assemble with the following command: 6 | 7 | ```bash 8 | npm install {%= name %} --save-dev 9 | ``` 10 | 11 | Once that's done, add this line to your project's Gruntfile: 12 | 13 | ```js 14 | grunt.loadNpmTasks('{%= name %}'); 15 | ``` 16 | 17 | ## The "assemble" task 18 | _Run the "assemble" task with the `grunt assemble` command._ 19 | 20 | Task targets, files and options may be specified according to the grunt [Configuring tasks](http://gruntjs.com/configuring-tasks) guide. 21 | 22 | In your project's Gruntfile, add a section named `assemble` to the data object passed into `grunt.initConfig()`. 23 | 24 | ```js 25 | assemble: { 26 | options: { 27 | assets: 'assets', 28 | plugins: ['permalinks'], 29 | partials: ['includes/**/*.hbs'], 30 | layout: ['layouts/default.hbs'], 31 | data: ['data/*.{json,yml}'] 32 | }, 33 | site: { 34 | src: ['docs/*.hbs'], 35 | dest: './' 36 | } 37 | }, 38 | ``` 39 | 40 | [grunt]: http://gruntjs.com/ 41 | [Getting Started]: https://github.com/gruntjs/grunt/blob/devel/docs/getting_started.md 42 | [package.json]: https://npmjs.org/doc/json.html 43 | -------------------------------------------------------------------------------- /docs/options.md: -------------------------------------------------------------------------------- 1 | See the documentation for [Options](http://assemble.io/docs/Options.html) for more information. 2 | 3 | ## [assets](http://assemble.io/docs/options-assets.html) 4 | Type: `String` 5 | Default: `undefined` 6 | 7 | Used with the `{{assets}}` variable to resolve the relative path from the _dest file_ to the _assets_ folder. 8 | 9 | ## [data](http://assemble.io/docs/options-data.html) 10 | Type: `String|Array|Object` 11 | Default: `src/data` 12 | 13 | Specify the data to supply to your templates. Data may be formatted in `JSON`, `YAML`, [YAML front matter](http://assemble.io/docs/YAML-front-matter.html), or passed directly as an object. Wildcard patterns may also be used. 14 | 15 | The filenames of the selected files must not collide with the [configuration options key names](http://assemble.io/docs/Options.html#configuration-options) for the assemble build task. For example, the files must not be called `assets.yml`,`collections.json`,…. 16 | 17 | ## [layoutdir](http://assemble.io/docs/options-layoutdir.html) 18 | Type: `String` 19 | Default: `undefined` 20 | 21 | The directory to use as the "cwd" for [layouts](http://assemble.io/docs/options-layout.html). When this option is defined, layouts may be defined using only the name of the layout. 22 | 23 | ## [layouts](http://assemble.io/docs/options-layouts.html) 24 | Type: `String|Array` 25 | Default: `undefined` 26 | 27 | A glob pattern to be used to find layouts. When this option is defined, the `layoutdir` option is ignored and layouts specified in templates will be searched for using the specified glob pattern(s). 28 | 29 | ## [layout](http://assemble.io/docs/options-layout.html) 30 | Type: `String` 31 | Default: `undefined` 32 | 33 | If set, this defines the layout file to use for the [task or target][tasks-and-targets]. However, when specifying a layout, unlike Jekyll, _Assemble requires a file extension_ since you are not limited to using a single file type. 34 | 35 | ## layoutext 36 | Type: `String` 37 | Default: `undefined` 38 | 39 | Specify the extension to use for layouts, enabling layouts in YAML front matter to be defined without an extension: 40 | 41 | ```yaml 42 | --- 43 | layout: default 44 | --- 45 | ``` 46 | 47 | [tasks-and-targets]: http://gruntjs.com/configuring-tasks#task-configuration-and-targets 48 | 49 | ## [partials](http://assemble.io/docs/options-partials.html) 50 | Type: `String|Array` 51 | Default: `undefined` 52 | 53 | Specifies the Handlebars partials files, or paths to the directories of files to be used. 54 | 55 | ## [plugins](http://assemble.io/plugins/) 56 | Type: `String|Array` 57 | Default: `undefined` 58 | 59 | Name of the npm module to use and/or the path(s) to any custom plugins to use. Wildcard patterns may also be used. 60 | 61 | See the [docs for plugins](http://assemble.io/plugins/). 62 | 63 | ## [helpers](http://assemble.io/docs/options-helpers.html) 64 | Type: `String|Array` 65 | Default: [handlebars-helpers](http://github.com/assemble/handlebars-helpers) 66 | 67 | Name of the npm module to use and/or the path(s) to any custom helpers to use with the current template engine. Wildcard patterns may also be used. 68 | 69 | By default, Assemble includes [handlebars-helpers]((http://assemble.io/helpers/)) as a dependency, so any helpers from that library are already available to be used in your templates. 70 | 71 | See the [docs for helpers](http://assemble.io/helpers/). 72 | 73 | ## [ext](http://assemble.io/docs/options-ext.html) 74 | Type: `String` 75 | Default: `.html` 76 | 77 | Specify the file extension for destination files. Example: 78 | 79 | ## [marked](http://assemble.io/docs/options-marked.html) 80 | Type: `Object` 81 | Default: [Marked.js defaults](https://github.com/chjj/marked#options-1) 82 | 83 | Specify the [Marked.js options](https://github.com/chjj/marked#options-1) for the `{{#markdown}}{{/markdown}}` and `{{md ""}}` helpers to use when converting content. 84 | 85 | ## [engine](http://assemble.io/docs/options-engine.html) 86 | Type: `String` 87 | Default: `Handlebars` 88 | 89 | Specify the engine to use for compiling templates **if you are not using Handlebars**. 90 | 91 | Also see [assemble-swig](https://github.com/assemble/assemble-swig) for compiling [Swig Templates](https://github.com/paularmstrong). 92 | 93 | ## flatten 94 | Type: `Boolean` 95 | Default: `false` 96 | 97 | Remove anything after (and including) the first `.` in the destination path, then append this value. In other words, when files are generated from different source folders this "flattens" them into the same destination directory. See [building the files object dynamically](http://gruntjs.com/configuring-tasks#building-the-files-object-dynamically) for more information on `files` formats. 98 | 99 | Visit [Assemble's documentation](http://assemble.io) for more information about options. 100 | -------------------------------------------------------------------------------- /docs/v6-diffs.md: -------------------------------------------------------------------------------- 1 | 2 | ### Breaking changes between versions `0.5.0` and `0.6.0` 3 | 4 | Version 6 is using [assemble-handlebars][] version `0.4.0` which updates [handlebars-helpers][] to version `0.6.0`. Due to this update, there are some breaking changes with how some helpers are loaded and some missing/added helpers. 5 | 6 | The following list contains the breaking changes that we have noticed that may require updates to existing templates. 7 | 8 | **helpers loaded from package.json** 9 | 10 | Any helpers declared in `dependencies` or `devDependencies` and have their name in the `keywords` property will no longer be loaded automatically. To load the helpers, just include the package name in the `helpers` option for your `grunt-assemble` target: 11 | 12 | ```js 13 | assemble: { 14 | options: { 15 | helpers: ['handlebars-helper-eachitems'] 16 | } 17 | } 18 | ``` 19 | 20 | **new path helpers** 21 | 22 | Helpers have been added that map to methods on the built-in `path` module. Some of these helpers are also properties that `grunt-assemble` adds automatically to `page` properties. To use the page property, use the `this` keyword before the property name. To use the helper, use it like any other helper. 23 | 24 | ```handlebars 25 | {{! page property "basename" }} 26 | {{this.basename}} 27 | 28 | {{! new helper "basename" }} 29 | {{basename this.path}} 30 | ``` 31 | 32 | **missing helper "inspect"** 33 | 34 | The "inspect" helper has been removed from `handlebars-helpers`. The test fixtures in this project use the "inspect" helper so it has been recreated [here](./test/helpers/logging.js). 35 | 36 | **missing helper "unless_eq"** 37 | 38 | The "unless_eq" helper has been renamed to "unlessEq". 39 | 40 | **missing helper "md" or "markdown"** 41 | 42 | There is a bug in `handlebars-helpers@0.6` that causes the `md` and `markdown` helpers to not be registered correctly. This has been fixed in newer versions of `handlebars-helpers`, however those changes have not made it here yet. There is currently a refactor of `grunt-assemble` that will include the fix, but for now, use the following work-around: 43 | 44 | Create a file and register the helpers manually: 45 | 46 | ```js 47 | // helpers/markdown.js 48 | module.exports.register = function (Handlebars) { 49 | 'use strict'; 50 | 51 | Handlebars.registerHelper('markdown', require('helper-markdown')()); 52 | Handlebars.registerHelper('md', require('helper-md').sync); 53 | }; 54 | ``` 55 | 56 | ```js 57 | // Gruntfile.js 58 | assemble: { 59 | options: { 60 | helpers: ['./helpers/*.js'] 61 | } 62 | } 63 | ``` 64 | 65 | **handlebars 4 changed how context depths are handled** 66 | 67 | `assemble-handlebars` is also using a newer version of handlebars that changed how the context depth is handled. Some of the block helpers that would create a new depth, no longer create the depth. This requires changing some templates that use the `{{../}}` syntax to reduce the amount of `../` segments used. This can be seen in block helpers that don't modify the context, like `{{#if}}{{/if}}` and `{{#is}}{{/is}}`. 68 | 69 | 70 | [assemble-handlebars]: https://github.com/assemble/assemble-handlebars 71 | [handlebars-helpers]: https://github.com/assemble/handlebars-helpers 72 | -------------------------------------------------------------------------------- /lib/assemble.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * Assemble 4 | * 5 | * Copyright (c) 2014, Jon Schlinkert, Brian Woodward, contributors. 6 | * Licensed under the MIT License (MIT). 7 | */ 8 | 9 | var path = require('path'); 10 | var _ = require('lodash'); 11 | 12 | /** 13 | * Assemble 14 | */ 15 | 16 | var Assemble = function() { 17 | 18 | var engineUtils = require('./engine'); 19 | var collection = require('./collection'); 20 | var plugins = require('./plugins'); 21 | var utils = require('./utils'); 22 | 23 | var steps = []; 24 | 25 | var init = function(task, grunt) { 26 | 27 | this.grunt = grunt; 28 | this.task = task; 29 | this.options = task.options({ 30 | layoutdir: '', 31 | layout: '', 32 | layoutext: '', 33 | partials: [], 34 | data: [], 35 | assets: '', 36 | ext: '.html' 37 | }); 38 | 39 | this.options.originalAssets = this.options.assets; 40 | this.options.originalLayout = this.options.layout; 41 | 42 | this.options.data = mergeOptionsObjects.apply(this, [task.target, 'data']); 43 | this.options.dataFiles = mergeGlobArrays.apply(this, [task.target, 'data']); 44 | this.options.partials = mergeOptionsArrays.apply(this, [task.target, 'partials']); 45 | this.options.collections = mergeOptionsArrays.apply(this, [task.target, 'collections']); 46 | 47 | // add default collections 48 | this.options.collections = _.union(['tags', 'categories', { name: 'pages' }], this.options.collections); 49 | this.options.collections = collection.normalize(this.options.collections); 50 | 51 | // if there is a pages property and it's an array, turn it into an object 52 | if (this.options.pages && Array.isArray(this.options.pages)) { 53 | var pages = {}; 54 | _.forEach(this.options.pages, function(page) { 55 | if (page.filename && page.filename.length > 0) { 56 | pages[page.filename] = page; 57 | } 58 | }); 59 | this.options.pages = _.cloneDeep(pages); 60 | } 61 | 62 | // add default plugins 63 | var corePlugins = path.relative(process.cwd(), path.join(__dirname, 'plugins/*.js')); 64 | this.options.plugins = _.union(utils.arrayify(this.options.plugins || []), [corePlugins]); 65 | 66 | // save original plugins option 67 | this.options._plugins = this.options.plugins; 68 | this.options.plugins = plugins.resolve(this.options.plugins, this.options); 69 | 70 | this.files = task.files; 71 | steps = []; 72 | 73 | return this; 74 | }; 75 | 76 | var step = function(fn) { 77 | steps.push(fn); 78 | return this; 79 | }; 80 | 81 | var build = function(callback) { 82 | this.grunt.verbose.writeln('Assembling'); 83 | var self = this; 84 | this.grunt.verbose.writeln('Steps: ' + steps.length); 85 | if (steps.length === 0) { 86 | if (callback) { 87 | callback(null, true); 88 | } 89 | return true; 90 | } 91 | 92 | var step = 0, totalSteps = steps.length; 93 | steps[step++](self, function next(assemble) { 94 | assemble.grunt.verbose.writeln('\nStep ' + step + ' assembled.'); 95 | if (step < totalSteps) { 96 | assemble.grunt.verbose.writeln('Calling step ' + (step + 1)); 97 | steps[step++](self, next); 98 | } else { 99 | assemble.grunt.verbose.writeln('Build completed. Returning'); 100 | if (callback) { 101 | callback(null, true); 102 | } 103 | return true; 104 | } 105 | }); 106 | }; 107 | 108 | var mergeOptionsObjects = function(target, name) { 109 | var global = this.grunt.config(['assemble', 'options', name]); 110 | var targetData = this.grunt.config(['assemble', target, 'options', name]); 111 | return _.extend( 112 | {}, 113 | _.isPlainObject(global) ? global : {}, 114 | _.isPlainObject(targetData) ? targetData : {} 115 | ); 116 | }; 117 | 118 | var mergeGlobArrays = function(target, name) { 119 | var globalArray = this.grunt.config(['assemble', 'options', name]) || []; 120 | var targetArray = this.grunt.config(['assemble', target, 'options', name]) || []; 121 | // skip plain objects -> contains JSON data 122 | globalArray = _.isPlainObject(globalArray) ? [] : utils.arrayify(globalArray); 123 | targetArray = _.isPlainObject(targetArray) ? [] : utils.arrayify(targetArray); 124 | return _.flatten(globalArray.concat(targetArray)); 125 | }; 126 | 127 | var mergeOptionsArrays = function(target, name) { 128 | var globalArray = this.grunt.config(['assemble', 'options', name]) || []; 129 | var targetArray = this.grunt.config(['assemble', target, 'options', name]) || []; 130 | return _.flatten(utils.arrayify(globalArray).concat(utils.arrayify(targetArray))); 131 | }; 132 | 133 | return { 134 | init: init, 135 | step: step, 136 | build: build, 137 | plugins: plugins, 138 | engine: engineUtils, 139 | util: collection 140 | }; 141 | 142 | }; 143 | 144 | module.exports = exports = new Assemble(); 145 | -------------------------------------------------------------------------------- /lib/collection.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Assemble 3 | * 4 | * Copyright (c) 2014, Jon Schlinkert, Brian Woodward, contributors. 5 | * Licensed under the MIT License (MIT). 6 | */ 7 | 8 | var _ = require('lodash'); 9 | var inflection = require('inflection'); 10 | var utils = require('./utils'); 11 | 12 | /** 13 | * Export `collection` 14 | */ 15 | 16 | var collection = module.exports = {}; 17 | 18 | collection.update = function(col, page, context) { 19 | 'use strict'; 20 | 21 | if (!context[col.name]) { 22 | return col; 23 | } 24 | 25 | var singularName = col.inflection || inflection.singularize(col.name); 26 | var pageCol = context[col.name] || []; 27 | if (utils.toString.call(pageCol) !== '[object Array]') { 28 | pageCol = [pageCol]; 29 | } 30 | 31 | pageCol.forEach(function(pageItem) { 32 | var i = _.findIndex(col.items, function(item) { 33 | return item[singularName] === pageItem; 34 | }); 35 | 36 | if (i === -1) { 37 | var obj = {}; 38 | obj[singularName] = pageItem; 39 | obj.pages = [page]; 40 | col.items.push(obj); 41 | } else { 42 | col.items[i].pages.push(page); 43 | } 44 | }); 45 | return col; 46 | }; 47 | 48 | function compare(a, b) { 49 | 50 | if (a && b) { 51 | if (a < b) { 52 | return -1; 53 | } else if (a > b) { 54 | return 1; 55 | } else { 56 | return 0; 57 | } 58 | } else { 59 | // pages without {sortby} field will at the end of collection 60 | if (!a && !b) { 61 | return 0; 62 | } 63 | if (!a) { 64 | return 1; 65 | } 66 | return -1; 67 | } 68 | } 69 | 70 | collection.sort = function(col) { 71 | 'use strict'; 72 | 73 | var descMap = ['desc', 'descending']; 74 | var itemMap = ['this', '']; 75 | 76 | var sortby = _.contains(itemMap, (col.sortby || '')) ? '' : col.sortby; 77 | var sortorder = _.contains(descMap, (col.sortorder || 'ASC').toLowerCase()) ? 'DESC' : 'ASC'; 78 | 79 | if (sortby === '') { 80 | 81 | // sort items by the actual item 82 | col.items.sort(function(a, b) { 83 | return compare(a[col.inflection], b[col.inflection]); 84 | }); 85 | 86 | if (sortorder !== 'ASC') { 87 | col.items.reverse(); 88 | } 89 | 90 | } else { 91 | 92 | // for each item sort the pages by the page.data property 93 | col.items.forEach(function(item) { 94 | 95 | item.pages.sort(function(a, b) { 96 | return compare(a.data[sortby], b.data[sortby]); 97 | }); 98 | 99 | if (sortorder !== 'ASC') { 100 | item.pages.reverse(); 101 | } 102 | 103 | }); 104 | 105 | // now sort the items by the first page in each item 106 | col.items.sort(function(a, b) { 107 | if (a.pages.length > 0 && b.pages.length > 0) { 108 | if (a.pages[0].data[sortby] && b.pages[0].data[sortby]) { 109 | if (a.pages[0].data[sortby] < b.pages[0].data[sortby]) { 110 | return -1; 111 | } else if (a.pages[0].data[sortby] > b.pages[0].data[sortby]) { 112 | return 1; 113 | } else { 114 | return 0; 115 | } 116 | } 117 | } else { 118 | return 0; 119 | } 120 | }); 121 | 122 | if (sortorder !== 'ASC') { 123 | col.items.reverse(); 124 | } 125 | 126 | } 127 | 128 | return col; 129 | 130 | }; 131 | 132 | /** 133 | * Takes in a list of collection definitions and normalizes 134 | * them to a be all objects with smart defaults 135 | * @param {Array} collections: List of collections as either strings or objects 136 | * @return {Array} Return list of collections, all as objects 137 | */ 138 | collection.normalize = function(collections) { 139 | 'use strict'; 140 | 141 | var rtn = {}; 142 | collections.forEach(function(item) { 143 | 144 | if (typeof item === 'string') { 145 | if (rtn[item]) { 146 | item = rtn[item]; 147 | } else { 148 | item = { 149 | name: item, 150 | inflection: inflection.singularize(item), 151 | sortorder: 'ASC', 152 | sortby: '', 153 | items: [] 154 | }; 155 | } 156 | } else { 157 | item.items = []; 158 | } 159 | 160 | if (item.name === 'pages') { 161 | item.inflection = '_page'; 162 | item.sortby = (item.sortby || '') === '' ? 'name' : item.sortby; 163 | item.items = [{ 164 | '_page': 'all', 165 | pages: [] 166 | }]; 167 | } 168 | 169 | rtn[item.name] = item; 170 | 171 | }); 172 | return rtn; 173 | }; 174 | 175 | collection.filterProperties = function(opts) { 176 | return _.omit(opts, [ 177 | 'defaultLayout', 178 | 'initializeEngine', 179 | 'registerFunctions', 180 | 'registerPartial' 181 | ]); 182 | }; 183 | -------------------------------------------------------------------------------- /lib/engine.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Assemble 3 | * 4 | * Copyright (c) 2014, Jon Schlinkert, Brian Woodward, contributors. 5 | * Licensed under the MIT License (MIT). 6 | */ 7 | 'use strict'; 8 | 9 | var grunt = require('grunt'); 10 | var helpers = require('./helpers'); 11 | 12 | var EngineFactory = function() { 13 | var engineName = ''; 14 | 15 | var tryRequireEngine = function(eng, obj) { 16 | try { 17 | obj.engine = require('assemble-' + eng); 18 | } catch (e) { 19 | try { 20 | obj.engine = require(eng); 21 | } catch (err) { 22 | grunt.log.writeln('Error loading engine: ' + eng); 23 | grunt.log.writeln(err); 24 | grunt.log.writeln('Run `npm install assemble-' + eng + '` to use ' + eng); 25 | } 26 | } 27 | }; 28 | 29 | var load = function(eng) { 30 | engineName = eng; 31 | tryRequireEngine(eng, this); 32 | if (!this.engine) { 33 | return false; 34 | } 35 | 36 | // set some defaults 37 | this.startDelimiter = this.engine.startDelimiter || '{{'; 38 | this.endDelimiter = this.engine.endDelimiter || '}}'; 39 | 40 | var search = this.startDelimiter + '\\s*body\\s*' + this.endDelimiter; 41 | this.bodyRegex = new RegExp(search, 'i'); 42 | return this; 43 | }; 44 | 45 | var init = function(options, params) { 46 | if (typeof this.engine.init === 'function') { 47 | this.engine.init(options, params); 48 | } 49 | if (options && typeof options.helpers !== 'undefined') { 50 | if (!Array.isArray(options.helpers)) { 51 | options.helpers = [options.helpers]; 52 | } 53 | var engineInstance = this.engine[engineName] || this.engine; 54 | options.helpers.forEach(function(patterns) { 55 | helpers.register(patterns, this.engine, engineInstance, options, params); 56 | }, this); 57 | } 58 | }; 59 | 60 | var compile = function(src, options, callback) { 61 | if (typeof this.engine.compile !== 'function') { 62 | grunt.log.writeln(engineName, 'does not support compile.'); 63 | callback(engineName + ' does not support compile.', null); 64 | } 65 | this.engine.compile(src, options, callback); 66 | }; 67 | 68 | var render = function(tmpl, options, callback) { 69 | if (typeof this.engine.render !== 'function') { 70 | grunt.log.writeln(engineName, 'does not support render.'); 71 | callback(engineName + ' does not support render.', null); 72 | } 73 | this.engine.render(tmpl, options, callback); 74 | }; 75 | 76 | // Helpers, filters etc. depending on template engine 77 | var registerFunctions = function(helperFunctions) { 78 | if (typeof this.engine.registerFunctions === 'function') { 79 | this.engine.registerFunctions(helperFunctions); 80 | } 81 | }; 82 | 83 | var registerPartial = function(filename, content) { 84 | if (typeof this.engine.registerPartial === 'function') { 85 | this.engine.registerPartial(filename, content); 86 | } 87 | }; 88 | 89 | return { 90 | load: load, 91 | init: init, 92 | compile: compile, 93 | render: render, 94 | registerFunctions: registerFunctions, 95 | registerPartial: registerPartial 96 | }; 97 | 98 | }; 99 | 100 | module.exports = exports = new EngineFactory(); 101 | -------------------------------------------------------------------------------- /lib/helpers.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Assemble 3 | * 4 | * Copyright (c) 2014, Jon Schlinkert, Brian Woodward, contributors. 5 | * Licensed under the MIT License (MIT). 6 | */ 7 | 'use strict'; 8 | 9 | var path = require('path'); 10 | var resolve = require('resolve-dep'); 11 | var grunt = require('grunt'); 12 | 13 | module.exports.register = function(patterns, currentEngine, engineInstance, options, params) { 14 | resolve(patterns).forEach(function(filepath) { 15 | var fn = null; 16 | try { 17 | fn = require(path.resolve(filepath)); 18 | if (typeof fn !== 'undefined') { 19 | if (typeof fn === 'object' && Object.keys(fn).length >= 1) { 20 | if (typeof fn.register !== 'undefined') { 21 | fn.register(engineInstance, options, params); 22 | } else { 23 | currentEngine.registerFunctions(fn, options, params); 24 | } 25 | } 26 | } 27 | } catch (err) { 28 | grunt.log.writeln('Error loading helpers from file: ' + filepath); 29 | grunt.log.writeln(err); 30 | } 31 | }); 32 | }; 33 | -------------------------------------------------------------------------------- /lib/plugins.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Assemble 3 | * 4 | * Copyright (c) 2014, Jon Schlinkert, Brian Woodward, contributors. 5 | * Licensed under the MIT License (MIT). 6 | */ 7 | 8 | var resolve = require('resolve-dep'); 9 | var grunt = require('grunt'); 10 | var async = require('async'); 11 | var _ = require('lodash'); 12 | 13 | // The module to be exported. 14 | var plugins = module.exports = {}; 15 | 16 | plugins.resolve = function(_plugins, options) { 17 | options = options || {}; 18 | var resolved = resolve(_plugins).map(function(plugin) { 19 | try { 20 | return require(plugin); 21 | } catch (e) { 22 | return plugin; 23 | } 24 | }); 25 | 26 | // set plugin options 27 | resolved.forEach(function(plugin) { 28 | plugin.options = _.extend({}, { 29 | stage: 'render:pre:page' 30 | }, plugin.options); 31 | }); 32 | return resolved; 33 | }; 34 | 35 | /** 36 | * ## .isStageMatch(a, b) 37 | * 38 | * Return true if segments match, or if `*` is defined. 39 | * 40 | * @method isStageMatch 41 | * @param {Array} `a` 42 | * @param {Array} `b` 43 | * @return {Boolean} 44 | */ 45 | 46 | var isStageMatch = function(a, b) { 47 | return ((a[0] === b[0]) || (a[0] === '*')) && 48 | ((a[1] === b[1]) || (a[1] === '*')) && 49 | ((a[2] === b[2]) || (a[2] === '*')); 50 | }; 51 | 52 | plugins.runner = function(stage, params) { 53 | params.stage = stage; 54 | var assemble = params.assemble; 55 | 56 | var pluginsOfType = _.filter(assemble.options.plugins, function(plugin) { 57 | var pluginParts = plugin.options.stage.split(':'); 58 | var stageParts = stage.split(':'); 59 | return isStageMatch(pluginParts, stageParts); 60 | }); 61 | 62 | return function(done) { 63 | async.forEachSeries(pluginsOfType, function(plugin, next) { 64 | if (typeof plugin === 'function') { 65 | plugin(params, next); 66 | } else { 67 | next(); 68 | } 69 | }, 70 | function(err) { 71 | if (err) { 72 | grunt.log.error(err); 73 | done(err); 74 | } else { 75 | done(); 76 | } 77 | }); 78 | }; 79 | }; 80 | 81 | plugins.buildStep = function(stage, params) { 82 | return function(assemble, next) { 83 | plugins.runner(stage, params)(function() { 84 | next(assemble); 85 | }); 86 | }; 87 | }; 88 | 89 | -------------------------------------------------------------------------------- /lib/plugins/page-collection-properties.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Assemble 3 | * 4 | * Copyright (c) 2014, Jon Schlinkert, Brian Woodward, contributors. 5 | * Licensed under the MIT License (MIT). 6 | */ 7 | 'use strict'; 8 | 9 | var path = require('path'); 10 | var _ = require('lodash'); 11 | 12 | var options = { 13 | stage: 'render:pre:page' 14 | }; 15 | 16 | /** 17 | * ## Page colleciton properties 18 | * 19 | * This plugin will run before each page is rendered and will loop 20 | * over the pages collection, calling any registered callback function 21 | * passing in the current page context (to be rendered) and the current 22 | * page (from the pages collection) allowing additional relative page 23 | * properties to be added. 24 | */ 25 | 26 | var defaults = [ 27 | // add an isCurrentPage flag to the page if the dest matches 28 | function isCurrentPage(page, context) { 29 | page.isCurrentPage = (page.dest === context.page.dest); 30 | }, 31 | 32 | // add a relative link from the "current page" to the 33 | // page in the collection 34 | function relativeLink(page, context) { 35 | var relativePath = path.relative(path.dirname(context.page.dest), path.dirname(page.dest)); 36 | relativePath = path.join(relativePath, path.basename(page.dest)); 37 | page.relativeLink = relativePath.replace(/\\/g, '/'); 38 | } 39 | ]; 40 | 41 | var plugin = function(params, next) { 42 | var options = params.assemble.options; 43 | var pageCollectionOpts = options.pageCollection || {}; 44 | var callbacks = pageCollectionOpts.preprocess || []; 45 | 46 | if (!_.isArray(callbacks)) { 47 | callbacks = [callbacks]; 48 | } 49 | 50 | callbacks = _.union(callbacks, defaults); 51 | 52 | _.map(params.context.pages, function(page) { 53 | _.map(callbacks, function(callback) { 54 | callback(page, params.context); 55 | }); 56 | }); 57 | 58 | next(); 59 | }; 60 | 61 | // export options 62 | plugin.options = options; 63 | module.exports = plugin; 64 | 65 | -------------------------------------------------------------------------------- /lib/plugins/pagination.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Assemble 3 | * 4 | * Copyright (c) 2014, Jon Schlinkert, Brian Woodward, contributors. 5 | * Licensed under the MIT License (MIT). 6 | */ 7 | 'use strict'; 8 | 9 | var options = { 10 | stage: 'render:pre:*' 11 | }; 12 | 13 | /** 14 | * ## Pagination 15 | * 16 | * This plugin will run before the pages are rendered to 17 | * generate a pagination object that can be used to find 18 | * the previous and next pages 19 | */ 20 | 21 | var plugin = function(params, next) { 22 | 23 | var buildPaginationInfo = function() { 24 | var pages = params.assemble.options.pages; 25 | 26 | var i = 0; 27 | var prevPage = null; 28 | 29 | for (var j = pages.length; i < j; i++) { 30 | var page = pages[i]; 31 | 32 | // Index and actual page number 33 | page.index = i; 34 | page.number = i + 1; 35 | 36 | // First page 37 | page.first = (i === 0); 38 | 39 | // Previous page 40 | if (prevPage != null) { 41 | page.prev = prevPage; 42 | } 43 | 44 | // Middle pages 45 | page.middle = i > 0 && i < (j - 1); 46 | 47 | // Next page 48 | if (i < pages.length - 1) { 49 | page.next = i + 1; 50 | } 51 | 52 | // Last page 53 | page.last = i === (j - 1); 54 | prevPage = i; 55 | } 56 | }; 57 | 58 | var addPaginationInfoToContext = function() { 59 | var context = params.context; 60 | var pages = context.pages; 61 | var currentPage = context.page; 62 | 63 | params.context.pagination = { 64 | first: pages[currentPage.first || 0], 65 | prev: pages[currentPage.prev || 0], 66 | middle: pages[currentPage.middle], 67 | next: pages[currentPage.next || (pages.length - 1)], 68 | last: pages[currentPage.last || (pages.length - 1)], 69 | 70 | index: pages[currentPage.index], 71 | number: currentPage.index + 1, 72 | currentPage: currentPage.index + 1, 73 | totalPages: pages.length 74 | }; 75 | }; 76 | 77 | if (params.stage === 'render:pre:pages') { 78 | buildPaginationInfo(); 79 | } else if (params.stage === 'render:pre:page') { 80 | addPaginationInfoToContext(); 81 | } 82 | next(); 83 | }; 84 | 85 | // export options 86 | plugin.options = options; 87 | module.exports = plugin; 88 | -------------------------------------------------------------------------------- /lib/plugins/postprocess.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Assemble 3 | * 4 | * Copyright (c) 2014, Jon Schlinkert, Brian Woodward, contributors. 5 | * Licensed under the MIT License (MIT). 6 | */ 7 | 'use strict'; 8 | 9 | var options = { 10 | stage: 'render:post:page' 11 | }; 12 | 13 | /** 14 | * ## Postprocess 15 | * 16 | * @param {Object} params 17 | * @param {Function} callback 18 | */ 19 | 20 | module.exports = function(params, callback) { 21 | 22 | var grunt = params.grunt; 23 | 24 | grunt.verbose.subhead('Running:'.bold, '"assemble-contrib-postprocess"'); 25 | grunt.verbose.writeln('Stage: '.bold, '"render:post:page"\n'); 26 | 27 | var content = params.content; 28 | var p = params.assemble.options.postprocess; 29 | 30 | function postprocess(src, fn) { 31 | return fn(src); 32 | } 33 | var processFn = function(src) { 34 | return src; 35 | }; 36 | 37 | params.content = postprocess(content, p || processFn); 38 | callback(); 39 | }; 40 | 41 | module.exports.options = options; 42 | -------------------------------------------------------------------------------- /lib/utils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Assemble 3 | * 4 | * Copyright (c) 2014, Jon Schlinkert, Brian Woodward, contributors. 5 | * Licensed under the MIT License (MIT). 6 | */ 7 | 'use strict'; 8 | 9 | var path = require('path'); 10 | var grunt = require('grunt'); 11 | var _ = require('lodash'); 12 | 13 | var utils = module.exports = {}; 14 | 15 | utils.arrayify = function(arr) { 16 | return !Array.isArray(arr) ? [arr] : arr; 17 | }; 18 | 19 | var toString = function(val) { 20 | if (val == null) { 21 | return ''; 22 | } else { 23 | return val.toString(); 24 | } 25 | }; 26 | utils.toString = Object.prototype.toString; 27 | 28 | utils.lowerCase = function(str) { 29 | str = toString(str); 30 | return str.toLowerCase(); 31 | }; 32 | 33 | utils.isUndefined = function(value) { 34 | return value === 'undefined' || utils.toString.call(value) === '[object Function]' || (value.hash != null); 35 | }; 36 | 37 | // Windows? (from grunt.file) 38 | var win32 = process.platform === 'win32'; 39 | utils.pathNormalize = function(urlString) { 40 | if (win32) { 41 | return urlString.replace(/\\/g, '/'); 42 | } else { 43 | return urlString; 44 | } 45 | }; 46 | 47 | utils.filenameRegex = /[^\\\/:*?"<>|\r\n]+$/i; 48 | 49 | utils.extension = function(filename) { 50 | grunt.verbose.writeln('extension'); 51 | grunt.verbose.writeln(filename); 52 | if (grunt.util.kindOf(filename) === 'array' && filename.length > 0) { 53 | filename = filename[0]; 54 | } 55 | return _(filename.match(/[^.]*$/)).last(); 56 | }; 57 | 58 | /** 59 | * Check if the give file path ends with a slash. 60 | * @param {String} filepath 61 | * @return {Boolean} 62 | */ 63 | utils.endsWithSlash = function(filepath) { 64 | return /[\\\/]$/.test(filepath); 65 | }; 66 | var endsWithSlash = utils.endsWithSlash; 67 | 68 | /** 69 | * Check if the give file path ends with a dot. 70 | * @param {String} filepath 71 | * @return {Boolean} 72 | */ 73 | 74 | utils.endsWithDot = function(str) { 75 | return str[str.length - 1] === '.'; 76 | }; 77 | 78 | /** 79 | * Check if the give file path ends with a dot. 80 | * @param {String} filepath 81 | * @return {Boolean} 82 | */ 83 | 84 | utils.endsWith = function(str, end) { 85 | return str[str.length - 1] === end; 86 | }; 87 | 88 | /** 89 | * Re-calculate the path from dest file to the given directory 90 | * defined in the assemble options, such as `assets`. 91 | * @param {String} dest Destination of the file. 92 | * @param {String} toPath Calculated "new" path. 93 | * @param {String} origPath Stored original path to check against. 94 | * @return {String} 95 | */ 96 | 97 | utils.calculatePath = function(destdir, toPath, origPath) { 98 | var relativePath = path.relative(path.resolve(destdir), path.resolve(toPath)); 99 | toPath = utils.pathNormalize(relativePath); 100 | // if the relative path is blank, then it's the same folder 101 | // so update to be '' or './' 102 | if (!toPath || toPath.length === 0) { 103 | // if the original path had a trailing slash 104 | if (endsWithSlash(origPath)) { 105 | // return './' 106 | toPath = './'; 107 | } else { 108 | // otherwise return '' 109 | toPath = '.'; 110 | } 111 | } 112 | // if the original path had a trailing slash and the calculated 113 | // path does not, add a trailing slash 114 | if (endsWithSlash(origPath) && !endsWithSlash(toPath)) { 115 | toPath += '/'; 116 | // Otherwise, if the original path did not have a trailing slash 117 | // and the calculated path does, remove the trailing slash 118 | } else if (!endsWithSlash(origPath) && endsWithSlash(toPath)) { 119 | toPath = toPath.substring(0, toPath.length - 2); 120 | } 121 | return toPath; 122 | }; 123 | 124 | /** 125 | * Returns 'directory' or 'file' based on the given path. 126 | * @param {String} file path 127 | */ 128 | 129 | utils.detectDestType = function(dest) { 130 | if (utils.endsWith(dest, '/') || grunt.file.isDir(dest)) { 131 | return 'directory'; 132 | } else if (grunt.file.isFile(dest)) { 133 | if (grunt.file.exists(dest)) { 134 | return 'file'; 135 | } else { 136 | throw new Error('Invalid file path.'); 137 | } 138 | } 139 | }; 140 | 141 | utils.findBasePath = function(srcFiles, basePath) { 142 | if (basePath === false) { 143 | return ''; 144 | } 145 | if (grunt.util.kindOf(basePath) === 'string' && basePath.length >= 1) { 146 | return _(path.normalize(basePath)).trim(path.sep); 147 | } 148 | var foundPath, basePaths = [], dirName; 149 | srcFiles.forEach(function(srcFile) { 150 | srcFile = path.normalize(srcFile); 151 | dirName = path.dirname(srcFile); 152 | basePaths.push(dirName.split(path.sep)); 153 | }); 154 | basePaths = _.intersection.apply([], basePaths); 155 | foundPath = path.join.apply(path, basePaths); 156 | if (foundPath === '.') { 157 | foundPath = ''; 158 | } 159 | return foundPath; 160 | }; 161 | 162 | /** 163 | * Read in the given data file based on the file extension. 164 | * @param {String} ext The file extension to check. 165 | * @return {Object} JSON data object. 166 | */ 167 | utils.dataFileReaderFactory = function(ext) { 168 | var reader = grunt.file.readJSON; 169 | switch (ext) { 170 | case '.json': 171 | reader = grunt.file.readJSON; 172 | break; 173 | case '.yml': 174 | case '.yaml': 175 | reader = grunt.file.readYAML; 176 | break; 177 | } 178 | return reader; 179 | }; 180 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "grunt-assemble", 3 | "description": "Static site generator for Grunt.js, Yeoman and Node.js. Used by Zurb Foundation, Zurb Ink, H5BP/Effeckt, Less.js / lesscss.org, Topcoat, Web Experience Toolkit, and hundreds of other projects to build sites, themes, components, documentation, blogs and gh-pages.", 4 | "version": "0.6.3", 5 | "homepage": "http://assemble.io", 6 | "author": "Assemble (https://github.com/assemble/assemble)", 7 | "contributors": [ 8 | "Ain Tohvri (http://tekkie.flashbit.net)", 9 | "Alex Sanz (https://github.com/asans)", 10 | "Anders D. Johnson (https://andrz.me)", 11 | "Ben Drucker (http://www.bendrucker.me)", 12 | "Brian Woodward (https://twitter.com/doowb)", 13 | "Carl A. Bauer (http://carlbauer.org)", 14 | "Casey Garland (https://github.com/caseyg1204)", 15 | "Dane Petersen (https://thegreatsunra.com)", 16 | "Daniel Rauber (https://danielrauber.de)", 17 | "Gion Kunz (https://github.com/gionkunz)", 18 | "Jon Schlinkert (http://twitter.com/jonschlinkert)", 19 | "Jordan Thomas (http://jordanthomas.me)", 20 | "Justin Heideman (http://fiddlyio.com)", 21 | "Laurent Goderre (https://github.com/LaurentGoderre)", 22 | "Michael Mifsud (https://github.com/xzyfer)", 23 | "Mikko Tapionlinna (http://mikko.tapionlinna.fi)", 24 | "Munim Abdul (http://www.munim.net)", 25 | "Patrick Burtchaell (https://pburtchaell.com)", 26 | "Sam Morrison (http://cnstechgroup.com)", 27 | "Steven Black (http://stevenblack.com)", 28 | "Thomas Parisot (https://oncletom.io)", 29 | "Thomas Traub (http://thomastraub.com)", 30 | "Tyler Howarth (twitter.com/tylr)" 31 | ], 32 | "repository": "assemble/grunt-assemble", 33 | "bugs": { 34 | "url": "https://github.com/assemble/grunt-assemble/issues" 35 | }, 36 | "license": "MIT", 37 | "files": [ 38 | "lib", 39 | "tasks" 40 | ], 41 | "main": "./lib/assemble", 42 | "engines": { 43 | "node": ">= 0.10.0" 44 | }, 45 | "scripts": { 46 | "test": "grunt mochaTest" 47 | }, 48 | "dependencies": { 49 | "assemble-handlebars": "^0.4.1", 50 | "async": "^0.9.0", 51 | "gray-matter": "^0.4.2", 52 | "inflection": "^1.3.6", 53 | "lodash": "^2.4.1", 54 | "resolve-dep": "^0.5.3" 55 | }, 56 | "devDependencies": { 57 | "chai": "^1.9.1", 58 | "grunt": "^0.4.5", 59 | "grunt-cli": "^0.1.13", 60 | "grunt-contrib-clean": "^0.5.0", 61 | "grunt-contrib-jshint": "^0.10.0", 62 | "grunt-mocha-test": "^0.11.0", 63 | "grunt-sync-pkg": "^0.1.2", 64 | "grunt-verb": "^0.2.4", 65 | "gruntify-eslint": "^3.1.0", 66 | "handlebars-helper-eachitems": "^0.1.2", 67 | "helper-markdown": "^0.2.1", 68 | "helper-md": "^0.2.1", 69 | "relative": "^0.1.4", 70 | "sort-object": "^3.0.2", 71 | "time-grunt": "^0.3.2" 72 | }, 73 | "keywords": [ 74 | "alternative", 75 | "blog", 76 | "boilerplate", 77 | "boilerplates", 78 | "bootstrap", 79 | "build", 80 | "builder", 81 | "components", 82 | "deployment", 83 | "front", 84 | "generator", 85 | "generators", 86 | "grunt", 87 | "gruntplugin", 88 | "handlebars", 89 | "handlebars-helper-eachitems", 90 | "helpers", 91 | "HTML", 92 | "javascript", 93 | "jekyll", 94 | "matter", 95 | "node", 96 | "node.js", 97 | "pages", 98 | "partial", 99 | "partials", 100 | "scaffold", 101 | "scaffolds", 102 | "site", 103 | "static", 104 | "task", 105 | "templates", 106 | "templating", 107 | "website", 108 | "yaml", 109 | "yeoman" 110 | ] 111 | } 112 | -------------------------------------------------------------------------------- /test/actual/custom_helpers/bar.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Custom Helpers example 6 | 7 | 8 |

Example using the bar helper

9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /test/actual/custom_helpers/foo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Custom Helpers example 6 | 7 | 8 |

Example using the foo helper

9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /test/actual/custom_helpers/opt.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Custom Helpers example 6 | 7 | 8 |

Example using the "opt" helper

9 |
Version: grunt-assemble
10 | 11 | 12 | -------------------------------------------------------------------------------- /test/actual/globlayout/multi.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Layout name: 'layout-globlayout.hbs' 5 | 6 | 7 | 8 | 9 |
10 |
11 |

Layout: layout-globlayout.hbs

12 |

Template: test/fixtures/pages/globlayout/globlayout.hbs

13 |

layout one

14 | 15 |

Layout: layout-globlayout.hbs

16 |

This is some random content before the body of the actual page.

17 | 18 | 19 |

Hello: Using a glob layout

20 | 21 |

This is some random content after the body of the actual page.

22 |

Layout: layout-globlayout.hbs

23 | 24 |

layout one

25 |
26 | 27 | 28 | -------------------------------------------------------------------------------- /test/actual/globlayout/simple.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Layout name: 'layout-globlayout.hbs' 5 | 6 | 7 | 8 | 9 |
10 |
11 |

Layout: layout-globlayout.hbs

12 |

Template: test/fixtures/pages/globlayout/globlayout.hbs

13 |

layout one

14 | 15 |

Layout: layout-globlayout.hbs

16 |

This is some random content before the body of the actual page.

17 | 18 | 19 |

Hello: Using a glob layout

20 | 21 |

This is some random content after the body of the actual page.

22 |

Layout: layout-globlayout.hbs

23 | 24 |

layout one

25 |
26 | 27 | 28 | -------------------------------------------------------------------------------- /test/actual/layout_ext/layoutext.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Layout name: 'noext' 6 | 7 | 8 | 9 | 10 |
11 |
12 |
13 | 14 |
15 | 49 |
50 | 51 |
52 |
53 |
54 |

Layout: noext

55 |

Template: test/fixtures/pages/layoutext/layoutext.hbs

56 |
57 | 58 |

options.layoutext

59 |

Allows a layout to be defined without an extension

60 |
61 |
62 |
63 |
64 | 65 | 66 | -------------------------------------------------------------------------------- /test/actual/nested_layouts/deep-nested-layouts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Layout name: 'three.hbs' 5 | 6 | 7 | 8 | 9 |
10 |
11 |

Layout: three.hbs

12 |

Template: test/fixtures/pages/nested/deep-nested-layouts.hbs

13 |

layout one

14 | 15 |

Layout: three.hbs

16 |

This is some random content before the body of the actual page.

17 | 18 | 19 |

Layout: three.hbs

20 |

This is some random content before the body of the actual page.

21 | 22 | 23 |

Hello: Three layouts deep

24 | 25 |

This is some random content after the body of the actual page.

26 |

Layout: three.hbs

27 | 28 | 29 |

This is some random content after the body of the actual page.

30 |

Layout: three.hbs

31 | 32 |

layout one

33 |
34 | 35 | 36 | -------------------------------------------------------------------------------- /test/actual/nested_layouts/nested-layouts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Layout name: 'two.hbs' 5 | 6 | 7 | 8 | 9 |
10 |
11 |

Layout: two.hbs

12 |

Template: test/fixtures/pages/nested/nested-layouts.hbs

13 |

layout one

14 | 15 |

Layout: two.hbs

16 |

This is some random content before the body of the actual page.

17 | 18 | 19 |

Hello: Home Page

20 | 21 |

This is some random content after the body of the actual page.

22 |

Layout: two.hbs

23 | 24 |

layout one

25 |
26 | 27 | 28 | -------------------------------------------------------------------------------- /test/actual/no_layout/no-layout-none.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Has no layout 6 | 7 | 8 |
Page with layout: 'none' defined.
9 | 10 | 11 | -------------------------------------------------------------------------------- /test/actual/no_layout/no-layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Has no layout 6 | 7 | 8 |
Page with layout: false defined.
9 | 10 | 11 | -------------------------------------------------------------------------------- /test/actual/not_real.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Blah blah. -------------------------------------------------------------------------------- /test/actual/pages_array/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Layout name: 'test/fixtures/pages/blog/index.hbs' | Layout: false 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 |
16 | 17 |
18 | 61 |
62 | 63 |
64 |
65 |
66 |

Template: test/fixtures/pages/blog/index.hbs

67 |

Layout: false

68 |
69 |
70 |
71 |

72 |
73 |
74 |
75 |
76 |

77 |
78 |
79 |
80 |
81 |

82 |
83 |
84 |
85 |
86 |
87 |
88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /test/actual/pages_array/post1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Layout name: '' 7 | 8 | 9 | 10 | 11 |
12 |
13 |
14 | 15 |
16 | 59 |
60 | 61 |
62 |
63 |
64 |

Layout: No layout was used.

65 |

Template: post1

66 |
67 | <script src="https://gist.github.com/5898072.js"></script> 68 | This "content" property is optional and would get passed into the `body` tag. But if you only need to pass the page"s metadata to the layout then the content property is unnecessary. 69 |
70 |
71 |
72 |
73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /test/actual/pages_array/post2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Layout name: '' 7 | 8 | 9 | 10 | 11 |
12 |
13 |
14 | 15 |
16 | 59 |
60 | 61 |
62 |
63 |
64 |

Layout: No layout was used.

65 |

Template: post2

66 |
67 | <script src="https://gist.github.com/5898077.js"></script> 68 | <script src="https://gist.github.com/5898078.js"></script> 69 |

Blog Post #2 | A Blog

70 |
ALERT! This is an alert message. >
This project is brought to you by grunt-assemble. 71 |
72 |
73 |
74 |
75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /test/actual/pages_array/post3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Layout name: '' 7 | 8 | 9 | 10 | 11 |
12 |
13 |
14 | 15 |
16 | 59 |
60 | 61 |
62 |
63 |
64 |

Layout: No layout was used.

65 |

Template: post3

66 |
67 | <script src="https://gist.github.com/5909393.js"></script> 68 |
69 |
70 |
71 |
72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /test/actual/pages_metadata/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Layout name: 'test/fixtures/pages/blog/index.hbs' | Layout: false 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 |
16 | 17 |
18 | 61 |
62 | 63 |
64 |
65 |
66 |

Template: test/fixtures/pages/blog/index.hbs

67 |

Layout: false

68 |
69 |
70 |
71 |

72 |
73 |
74 |
75 |
76 |

77 |
78 |
79 |
80 |
81 |

82 |
83 |
84 |
85 |
86 |
87 |
88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /test/actual/pages_metadata/meta-awesome-blog-post-2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Layout name: '' 7 | 8 | 9 | 10 | 11 |
12 |
13 |
14 | 15 |
16 | 59 |
60 | 61 |
62 |
63 |
64 |

Layout: No layout was used.

65 |

Template: meta-awesome-blog-post-2

66 |
67 | <script src="https://gist.github.com/5898077.js"></script> 68 | <script src="https://gist.github.com/5898078.js"></script> 69 |

Awesome Blog Post #2 | Another Blog with Meta

70 |
ALERT! This is an alert message. >
This project is brought to you by grunt-assemble. 71 |
72 |
73 |
74 |
75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /test/actual/pages_metadata/meta-super-sweet-and-awesome-blog-post-3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Layout name: '' 7 | 8 | 9 | 10 | 11 |
12 |
13 |
14 | 15 |
16 | 59 |
60 | 61 |
62 |
63 |
64 |

Layout: No layout was used.

65 |

Template: meta-super-sweet-and-awesome-blog-post-3

66 |
67 | <script src="https://gist.github.com/5898072.js"></script> 68 |
69 |
70 |
71 |
72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /test/actual/pages_metadata/meta-sweet-blog-post-1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Layout name: '' 7 | 8 | 9 | 10 | 11 |
12 |
13 |
14 | 15 |
16 | 59 |
60 | 61 |
62 |
63 |
64 |

Layout: No layout was used.

65 |

Template: meta-sweet-blog-post-1

66 |
67 | <script src="https://gist.github.com/5898072.js"></script> 68 | This 'content' property is optional and would get passed into the `body` tag. But if you only need to pass the page"s metadata to the layout then the content property is unnecessary. 69 |
70 |
71 |
72 |
73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /test/actual/pages_object/awesome-blog-post-2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Layout name: '' 7 | 8 | 9 | 10 | 11 |
12 |
13 |
14 | 15 |
16 | 59 |
60 | 61 |
62 |
63 |
64 |

Layout: No layout was used.

65 |

Template: awesome-blog-post-2

66 |
67 | <script src="https://gist.github.com/5898077.js"></script> 68 | <script src="https://gist.github.com/5898078.js"></script> 69 |

Awesome Blog Post #2 | Another Blog

70 |
ALERT! This is an alert message. >
This project is brought to you by grunt-assemble. 71 |
72 |
73 |
74 |
75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /test/actual/pages_object/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Layout name: 'test/fixtures/pages/blog/index.hbs' | Layout: false 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 |
16 | 17 |
18 | 61 |
62 | 63 |
64 |
65 |
66 |

Template: test/fixtures/pages/blog/index.hbs

67 |

Layout: false

68 |
69 |
70 |
71 |

72 |
73 |
74 |
75 |
76 |

77 |
78 |
79 |
80 |
81 |

82 |
83 |
84 |
85 |
86 |
87 |
88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /test/actual/pages_object/super-sweet-and-awesome-blog-post-3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Layout name: '' 7 | 8 | 9 | 10 | 11 |
12 |
13 |
14 | 15 |
16 | 59 |
60 | 61 |
62 |
63 |
64 |

Layout: No layout was used.

65 |

Template: super-sweet-and-awesome-blog-post-3

66 |
67 | <script src="https://gist.github.com/5898072.js"></script> 68 |
69 |
70 |
71 |
72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /test/actual/pages_object/sweet-blog-post-1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Layout name: '' 7 | 8 | 9 | 10 | 11 |
12 |
13 |
14 | 15 |
16 | 59 |
60 | 61 |
62 |
63 |
64 |

Layout: No layout was used.

65 |

Template: sweet-blog-post-1

66 |
67 | <script src="https://gist.github.com/5898072.js"></script> 68 | This 'content' property is optional and would get passed into the `body` tag. But if you only need to pass the page"s metadata to the layout then the content property is unnecessary. 69 |
70 |
71 |
72 |
73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /test/actual/plugin_after.html: -------------------------------------------------------------------------------- 1 | AFTER OVERWRITE 1 -------------------------------------------------------------------------------- /test/actual/plugin_before.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | BEFORE TITLE 1 -------------------------------------------------------------------------------- /test/actual/plugin_pre_page.html: -------------------------------------------------------------------------------- 1 | W00T!!! -------------------------------------------------------------------------------- /test/actual/plugin_untitled.html: -------------------------------------------------------------------------------- 1 | 2 |

Untitled

3 |

this page doesn't have a title in the YFM

4 | -------------------------------------------------------------------------------- /test/assemble_test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Assemble 3 | * 4 | * Copyright (c) 2014, Jon Schlinkert, Brian Woodward, contributors. 5 | * Licensed under the MIT License (MIT). 6 | */ 7 | 8 | var expect = require('chai').expect; 9 | 10 | describe('awesome', function() { 11 | it('should run an awesome test', function() { 12 | expect(1).to.equal(1); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /test/assets/gist.css: -------------------------------------------------------------------------------- 1 | .panel ul { 2 | list-style: disc !important; 3 | } 4 | .panel ol li, 5 | .panel ul li { 6 | padding-left: 15px !important; 7 | margin: 0 0 25px 25px !important; 8 | } 9 | .panel ol ol, 10 | .panel ul ul { 11 | list-style-type: circle !important; 12 | } 13 | body .gist { 14 | color: #333333; 15 | } 16 | body .gist blockquote { 17 | margin-left: 0; 18 | } 19 | body .gist pre { 20 | color: #A2A8A8; 21 | font: inherit; 22 | font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; 23 | line-height: 1.7em; 24 | padding: 25px; 25 | white-space: pre; 26 | } 27 | body .gist .highlight { 28 | display: block; 29 | padding: 0; 30 | margin: 1em 0 3em; 31 | background: transparent; 32 | border: none; 33 | border-radius: 0; 34 | } 35 | body .gist .highlight pre { 36 | color: #A2A8A8; 37 | padding: 25px; 38 | margin: 1em 0 3em; 39 | font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; 40 | font-size: 14px; 41 | line-height: 1.7em; 42 | background-color: #f9f9f9; 43 | border: 1px solid #ddd; 44 | border-radius: 2px; 45 | } 46 | body .gist .gist-file { 47 | margin-bottom: 3em; 48 | font-family: 'Assemble SSm A', 'Assemble SSm B', 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; 49 | border: none; 50 | } 51 | body .gist .gist-file .gist-data { 52 | overflow: auto; 53 | font-size: 100%; 54 | word-wrap: normal; 55 | background-color: transparent; 56 | border-bottom: none; 57 | } 58 | body .gist .gist-file .gist-data .line-data { 59 | padding: 0.5em !important; 60 | } 61 | body .gist .gist-file .gist-data .line-pre { 62 | padding: 0 !important; 63 | margin: 0 !important; 64 | font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; 65 | background: transparent !important; 66 | border: none !important; 67 | } 68 | body .gist .gist-file .gist-data .gist-highlight { 69 | background: transparent !important; 70 | } 71 | body .gist .gist-file .gist-data .line-numbers { 72 | padding: 0.5em; 73 | color: #aaa; 74 | text-align: right; 75 | background-color: #ececec; 76 | border-right: 1px solid #ddd; 77 | } 78 | body .gist .gist-file .gist-data .line-numbers .line-number { 79 | display: block; 80 | clear: right; 81 | } 82 | body .gist-syntax { 83 | background: #ffffff; 84 | overflow: hidden; 85 | } 86 | body .gist-syntax .c { 87 | color: #999988; 88 | font-style: italic; 89 | } 90 | body .gist-syntax .err { 91 | color: #a61717; 92 | background-color: #e3d2d2; 93 | } 94 | body .gist-syntax .k { 95 | color: #333333; 96 | font-weight: bold; 97 | } 98 | body .gist-syntax .o { 99 | color: #333333; 100 | font-weight: bold; 101 | } 102 | body .gist-syntax .cm { 103 | color: #999988; 104 | font-style: italic; 105 | } 106 | body .gist-syntax .cp { 107 | color: #999999; 108 | font-weight: bold; 109 | } 110 | body .gist-syntax .c1 { 111 | color: #999988; 112 | font-style: italic; 113 | } 114 | body .gist-syntax .cs { 115 | color: #999999; 116 | font-style: italic; 117 | font-weight: bold; 118 | } 119 | body .gist-syntax .gd { 120 | color: #333333; 121 | background-color: #ffdddd; 122 | } 123 | body .gist-syntax .gd .x { 124 | color: #333333; 125 | background-color: #ffaaaa; 126 | } 127 | body .gist-syntax .ge { 128 | color: #333333; 129 | font-style: italic; 130 | } 131 | body .gist-syntax .gr { 132 | color: #aa0000; 133 | } 134 | body .gist-syntax .gh { 135 | color: #999999; 136 | } 137 | body .gist-syntax .gi { 138 | color: #333333; 139 | background-color: #ddffdd; 140 | } 141 | body .gist-syntax .gi .x { 142 | color: #333333; 143 | background-color: #aaffaa; 144 | } 145 | body .gist-syntax .go { 146 | color: #888888; 147 | } 148 | body .gist-syntax .gp { 149 | color: #555555; 150 | } 151 | body .gist-syntax .gs { 152 | font-weight: bold; 153 | } 154 | body .gist-syntax .gu { 155 | color: #aaaaaa; 156 | } 157 | body .gist-syntax .gt { 158 | color: #aa0000; 159 | } 160 | body .gist-syntax .kc { 161 | color: #333333; 162 | font-weight: bold; 163 | } 164 | body .gist-syntax .kd { 165 | color: #333333; 166 | font-weight: bold; 167 | } 168 | body .gist-syntax .kp { 169 | color: #333333; 170 | font-weight: bold; 171 | } 172 | body .gist-syntax .kr { 173 | color: #333333; 174 | font-weight: bold; 175 | } 176 | body .gist-syntax .kt { 177 | color: #445588; 178 | font-weight: bold; 179 | } 180 | body .gist-syntax .m { 181 | color: #009999; 182 | } 183 | body .gist-syntax .s { 184 | color: #dd1144; 185 | } 186 | body .gist-syntax .na { 187 | color: #008080; 188 | } 189 | body .gist-syntax .nb { 190 | color: #0086b3; 191 | } 192 | body .gist-syntax .nc { 193 | color: #445588; 194 | font-weight: bold; 195 | } 196 | body .gist-syntax .no { 197 | color: #008080; 198 | } 199 | body .gist-syntax .ni { 200 | color: #800080; 201 | } 202 | body .gist-syntax .ne { 203 | color: #990000; 204 | font-weight: bold; 205 | } 206 | body .gist-syntax .nf { 207 | color: #990000; 208 | font-weight: bold; 209 | } 210 | body .gist-syntax .nn { 211 | color: #555555; 212 | } 213 | body .gist-syntax .nt { 214 | color: #000080; 215 | } 216 | body .gist-syntax .nv { 217 | color: #008080; 218 | } 219 | body .gist-syntax .ow { 220 | color: #333333; 221 | font-weight: bold; 222 | } 223 | body .gist-syntax .w { 224 | color: #bbbbbb; 225 | } 226 | body .gist-syntax .mf { 227 | color: #009999; 228 | } 229 | body .gist-syntax .mh { 230 | color: #009999; 231 | } 232 | body .gist-syntax .mi { 233 | color: #009999; 234 | } 235 | body .gist-syntax .mo { 236 | color: #009999; 237 | } 238 | body .gist-syntax .sb { 239 | color: #dd1144; 240 | } 241 | body .gist-syntax .sc { 242 | color: #dd1144; 243 | } 244 | body .gist-syntax .sd { 245 | color: #dd1144; 246 | } 247 | body .gist-syntax .s2 { 248 | color: #dd1144; 249 | } 250 | body .gist-syntax .se { 251 | color: #dd1144; 252 | } 253 | body .gist-syntax .sh { 254 | color: #dd1144; 255 | } 256 | body .gist-syntax .si { 257 | color: #dd1144; 258 | } 259 | body .gist-syntax .sx { 260 | color: #dd1144; 261 | } 262 | body .gist-syntax .sr { 263 | color: #009926; 264 | } 265 | body .gist-syntax .s1 { 266 | color: #dd1144; 267 | } 268 | body .gist-syntax .ss { 269 | color: #990073; 270 | } 271 | body .gist-syntax .bp { 272 | color: #999999; 273 | } 274 | body .gist-syntax .vc { 275 | color: #008080; 276 | } 277 | body .gist-syntax .vg { 278 | color: #008080; 279 | } 280 | body .gist-syntax .vi { 281 | color: #008080; 282 | } 283 | body .gist-syntax .il { 284 | color: #009999; 285 | } 286 | body .gist .gist-file .gist-meta { 287 | display: none !important; 288 | padding: 0.5em; 289 | overflow: hidden; 290 | font-family: 'Assemble SSm A', 'Assemble SSm B', 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; 291 | font-size: 85%; 292 | color: #666; 293 | background-color: #eaeaea; 294 | } 295 | body .gist .gist-file .gist-meta a { 296 | color: #33b5e5; 297 | } 298 | body .gist .gist-file .gist-meta a:visited { 299 | color: #773377; 300 | } 301 | -------------------------------------------------------------------------------- /test/assets/nested/validation.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Scaffolding 3 | * 4 | * Basic resets for tests 5 | */ 6 | 7 | body { 8 | padding: 60px 0 80px; 9 | } 10 | .justified { 11 | width: 100%; 12 | } 13 | .justified > li { 14 | float: none; 15 | } 16 | .justified > li > a { 17 | text-align: center; 18 | margin-bottom: 5px; 19 | } 20 | @media (min-width: 768px) { 21 | .justified > li { 22 | display: table-cell; 23 | width: 1%; 24 | } 25 | } 26 | .justified > li > a { 27 | width: 100%; 28 | } 29 | .justified > li + li > a { 30 | border-left: none 31 | } 32 | .justified > li:nth-child(2) > a { 33 | border-left: 1px solid #DDD; 34 | } 35 | 36 | 37 | 38 | /* 39 | * Validation styles 40 | */ 41 | #validate:before { 42 | display: block; 43 | content: "\2713 assets path works!"; 44 | font-size: 15px; 45 | font-weight: bold; 46 | padding: 15px; 47 | margin-bottom: 20px; 48 | color: #569C57; 49 | background-color: #e0f7d7; 50 | border: 1px solid #d1ecc2; 51 | border-radius: 4px; 52 | } 53 | 54 | 55 | .nav > li:after { 56 | position: absolute; 57 | top: 9px; 58 | right: 10px; 59 | content: "class='" attr(class) "'"; 60 | font-family: Monaco, Menlo, Consolas, "Courier New", monospace; 61 | padding: 2px 4px; 62 | margin-left: 10px; 63 | font-size: 90%; 64 | color: #C7254E; 65 | white-space: nowrap; 66 | background-color: #F9F2F4; 67 | border-radius: 4px; 68 | clear: both; 69 | } 70 | 71 | .pager-heading { 72 | position: relative; 73 | display: block; 74 | padding: 10px 15px; 75 | } 76 | 77 | .pager > .active > a, 78 | .pager > .active > span, 79 | .pager > .active > a:hover, 80 | .pager > .active > span:hover, 81 | .pager > .active > a:focus, 82 | .pager > .active > span:focus { 83 | z-index: 2; 84 | color: #ffffff; 85 | background-color: #428bca; 86 | border-color: #428bca; 87 | cursor: default; 88 | } 89 | 90 | /* Blockquotes */ 91 | .callout { 92 | margin: 20px 0; 93 | padding: 20px; 94 | border-left: 3px solid #eee; 95 | } 96 | .callout h4 { 97 | margin-top: 0; 98 | margin-bottom: 5px; 99 | } 100 | .callout p:last-child { 101 | margin-bottom: 0; 102 | } 103 | .callout-success { 104 | background-color: #fdf7f7; 105 | border-color: #eed3d7; 106 | } 107 | .callout-success h4 { 108 | color: #eed3d7; 109 | } 110 | .callout-info { 111 | background-color: #f4f8fa; 112 | border-color: #bce8f1; 113 | } 114 | .callout-info h4 { 115 | color: #3a87ad; 116 | } 117 | .callout-warning { 118 | background-color: #faf8f0; 119 | border-color: #faebcc; 120 | } 121 | .callout-warning h4 { 122 | color: #c09853; 123 | } 124 | .callout-danger { 125 | background-color: #fdf7f7; 126 | border-color: #eed3d7; 127 | } 128 | .callout-danger h4 { 129 | color: #b94a48; 130 | } 131 | 132 | 133 | -------------------------------------------------------------------------------- /test/assets/validation.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Scaffolding 3 | * 4 | * Basic resets for tests 5 | */ 6 | 7 | body { 8 | padding: 60px 0 80px; 9 | } 10 | 11 | 12 | 13 | 14 | .justified { 15 | width: 100%; 16 | } 17 | .justified > li { 18 | float: none; 19 | } 20 | .justified > li > a { 21 | text-align: center; 22 | margin-bottom: 5px; 23 | } 24 | @media (min-width: 768px) { 25 | .justified > li { 26 | display: table-cell; 27 | width: 1%; 28 | } 29 | } 30 | .justified > li > a { 31 | width: 100%; 32 | } 33 | .justified > li + li > a { 34 | border-left: none 35 | } 36 | .justified > li:nth-child(2) > a { 37 | border-left: 1px solid #DDD; 38 | } 39 | 40 | 41 | /* Badges */ 42 | .badge-info { 43 | background-color: #5bc0de; 44 | } 45 | .badge-success { 46 | background-color: #5cb85c; 47 | } 48 | .badge-warning { 49 | background-color: #f0ad4e; 50 | } 51 | .badge-danger { 52 | background-color: #d9534f; 53 | } 54 | 55 | 56 | .pager li.pager-middle { 57 | display: none; 58 | } 59 | 60 | @media (min-width: 1040px) { 61 | .pager li.pager-middle { 62 | display: inline-block; 63 | } 64 | } 65 | 66 | 67 | /* 68 | * Validation styles 69 | */ 70 | #validate:before { 71 | display: block; 72 | content: "\2713 assets path works!"; 73 | font-size: 15px; 74 | font-weight: bold; 75 | padding: 15px; 76 | margin-bottom: 20px; 77 | color: #569C57; 78 | background-color: #e0f7d7; 79 | border: 1px solid #d1ecc2; 80 | border-radius: 4px; 81 | } 82 | 83 | 84 | .nav > li:after { 85 | position: absolute; 86 | top: 9px; 87 | right: 10px; 88 | content: "class='" attr(class) "'"; 89 | font-family: Monaco, Menlo, Consolas, "Courier New", monospace; 90 | padding: 2px 4px; 91 | margin-left: 10px; 92 | font-size: 90%; 93 | color: #C7254E; 94 | white-space: nowrap; 95 | background-color: #F9F2F4; 96 | border-radius: 4px; 97 | clear: both; 98 | } 99 | 100 | .pager-heading { 101 | position: relative; 102 | display: block; 103 | padding: 10px 15px; 104 | } 105 | 106 | .pager > .active > a, 107 | .pager > .active > span, 108 | .pager > .active > a:hover, 109 | .pager > .active > span:hover, 110 | .pager > .active > a:focus, 111 | .pager > .active > span:focus { 112 | z-index: 2; 113 | color: #ffffff; 114 | background-color: #428bca; 115 | border-color: #428bca; 116 | cursor: default; 117 | } 118 | 119 | /* Blockquotes */ 120 | .callout { 121 | margin: 20px 0; 122 | padding: 20px; 123 | border-left: 3px solid #eee; 124 | } 125 | .callout h4 { 126 | margin-top: 0; 127 | margin-bottom: 5px; 128 | } 129 | .callout p:last-child { 130 | margin-bottom: 0; 131 | } 132 | .callout-success { 133 | background-color: #fdf7f7; 134 | border-color: #eed3d7; 135 | } 136 | .callout-success h4 { 137 | color: #eed3d7; 138 | } 139 | .callout-info { 140 | background-color: #f4f8fa; 141 | border-color: #bce8f1; 142 | } 143 | .callout-info h4 { 144 | color: #3a87ad; 145 | } 146 | .callout-warning { 147 | background-color: #faf8f0; 148 | border-color: #faebcc; 149 | } 150 | .callout-warning h4 { 151 | color: #c09853; 152 | } 153 | .callout-danger { 154 | background-color: #fdf7f7; 155 | border-color: #eed3d7; 156 | } 157 | .callout-danger h4 { 158 | color: #b94a48; 159 | } 160 | 161 | 162 | -------------------------------------------------------------------------------- /test/collection_tests.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Assemble 3 | * 4 | * Copyright (c) 2014, Jon Schlinkert, Brian Woodward, contributors. 5 | * Licensed under the MIT License (MIT). 6 | */ 7 | 8 | var collection = require('../lib/collection'); 9 | var expect = require('chai').expect; 10 | var grunt = require('grunt'); 11 | var path = require('path'); 12 | var _ = require('lodash'); 13 | 14 | var getCollection = function(file) { 15 | return grunt.file.readJSON(path.join('./test/fixtures/data/collections', file)); 16 | }; 17 | 18 | var fakeCollection = getCollection('fakeCollection.json'); 19 | 20 | describe('Collections', function() { 21 | 22 | describe('Sorts', function() { 23 | 24 | it('by item name asc', function(done) { 25 | var expected = getCollection('expected-sortby-item-asc.json'); 26 | var col = _.cloneDeep(fakeCollection); 27 | var actual = collection.sort(col); 28 | grunt.verbose.writeln(require('util').inspect(actual, null, 10)); 29 | expect(actual).to.deep.equal(expected); 30 | done(); 31 | }); 32 | 33 | it('by item name desc', function(done) { 34 | var expected = getCollection('expected-sortby-item-desc.json'); 35 | var col = _.cloneDeep(fakeCollection); 36 | col.sortorder = 'DESC'; 37 | var actual = collection.sort(col); 38 | grunt.verbose.writeln(require('util').inspect(actual, null, 10)); 39 | expect(actual).to.deep.equal(expected); 40 | done(); 41 | }); 42 | 43 | it('by page property asc', function(done) { 44 | var expected = getCollection('expected-sortby-page-property-asc.json'); 45 | var col = _.cloneDeep(fakeCollection); 46 | col.sortby = 'title'; 47 | var actual = collection.sort(col); 48 | grunt.verbose.writeln(require('util').inspect(actual, null, 10)); 49 | expect(actual).to.deep.equal(expected); 50 | done(); 51 | }); 52 | 53 | it('by page property desc', function(done) { 54 | var expected = getCollection('expected-sortby-page-property-desc.json'); 55 | var col = _.cloneDeep(fakeCollection); 56 | col.sortorder = 'DESC'; 57 | col.sortby = 'title'; 58 | var actual = collection.sort(col); 59 | grunt.verbose.writeln(require('util').inspect(actual, null, 10)); 60 | expect(actual).to.deep.equal(expected); 61 | done(); 62 | }); 63 | 64 | }); 65 | 66 | }); 67 | 68 | -------------------------------------------------------------------------------- /test/engine_test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Assemble 3 | * 4 | * Copyright (c) 2014, Jon Schlinkert, Brian Woodward, contributors. 5 | * Licensed under the MIT License (MIT). 6 | */ 7 | 8 | var assembleEngine = require('../lib/engine'); 9 | var expect = require('chai').expect; 10 | 11 | var pluginParams = { 12 | grunt: require('grunt') 13 | }; 14 | 15 | describe('Loading default handlebars engine', function() { 16 | 17 | it('loads handlebars engine', function(done) { 18 | done(); 19 | }); 20 | 21 | it('compiles a handlebars template', function(done) { 22 | var engine = assembleEngine.load('handlebars'); 23 | engine.compile('{{foo}}', {}, function(err, tmpl) { 24 | if (err) { 25 | return done(err); 26 | } 27 | done(); 28 | }); 29 | }); 30 | 31 | it('renders a template', function(done) { 32 | var engine = assembleEngine.load('handlebars'); 33 | var expected = 'bar'; 34 | engine.compile('{{baz}}', {}, function(err, tmpl) { 35 | if (err) { 36 | return done(err); 37 | } 38 | engine.render(tmpl, {baz: 'bar'}, function(err, content) { 39 | if (err) { 40 | return done(err); 41 | } 42 | expect(content).to.equal(expected); 43 | done(); 44 | }); 45 | }); 46 | }); 47 | 48 | describe('Loading custom helpers', function() { 49 | 50 | var runTest = function(engine, done) { 51 | var expected = '\n'; 52 | engine.compile("{{{bar 'bar'}}}", {}, function(err, tmpl) { 53 | if (err) { 54 | return done(err); 55 | } 56 | engine.render(tmpl, {}, function(err, content) { 57 | if (err) { 58 | return done(err); 59 | } 60 | expect(content).to.equal(expected); 61 | done(); 62 | }); 63 | }); 64 | }; 65 | 66 | it('loads a custom helper from a file path', function(done) { 67 | var engine = assembleEngine.load('handlebars'); 68 | engine.init({ 69 | helpers: './test/helpers/helpers.js' 70 | }, pluginParams); 71 | runTest(engine, done); 72 | }); 73 | 74 | it('loads a custom helper from a glob pattern', function(done) { 75 | var engine = assembleEngine.load('handlebars'); 76 | engine.init({ 77 | helpers: './test/helpers/helpers.js' 78 | }, pluginParams); 79 | runTest(engine, done); 80 | }); 81 | 82 | it('loads a custom helper from the given path', function(done) { 83 | var engine = assembleEngine.load('handlebars'); 84 | engine.init({helpers: './test/helpers/*.js'}, pluginParams); 85 | var expected = ''; 86 | 87 | engine.compile("{{{foo 'bar'}}}", {}, function(err, tmpl) { 88 | if (err) { 89 | return done(err); 90 | } 91 | engine.render(tmpl, {}, function(err, content) { 92 | if (err) { 93 | return done(err); 94 | } 95 | expect(content).to.equal(expected); 96 | done(); 97 | }); 98 | }); 99 | }); 100 | 101 | }); 102 | }); 103 | -------------------------------------------------------------------------------- /test/fixtures/assets_path/assets.hbs: -------------------------------------------------------------------------------- 1 |

Examples to test the "relative" and "assets" variables, and to show how they work

2 | 3 | {{#assets_nested}} 4 |

"Public" Folder

5 |

Public (assets) folder is in the project root

6 |
 7 | originalAssets: {{originalAssets}}
 8 | assets: {{assets}}
 9 | dest: {{dest}}
10 | src: {{src}}
11 | assets_nested: {
12 |   options: {assets: 'test/actual/public'},
13 |   files: {'test/actual/assets_nested.html': ['test/files/assets.hbs']}
14 | },
15 | 
16 | {{/assets_nested}} 17 | 18 | 19 | {{#assets_base}} 20 |

Same Folder

21 |

Assets folder is in the same dir as dest files.

22 |
23 | assets_base: {
24 |   options: {assets: 'test/actual'},
25 |   files: {'test/actual/assets_base.html': ['test/files/assets.hbs']}
26 | },
27 | 
28 | {{/assets_base}} 29 | 30 | 31 | {{#assets_trailing_slash}} 32 |

Project Root

33 |

Assets folder is in the project root, which is not the same dir as dest files.

34 |
35 | assets_trailing_slash: {
36 |   options: {assets: ''},
37 |   files: {'test/actual/assets_trailing_slash.html': ['test/files/assets.hbs']}
38 | }
39 | 
40 | {{/assets_trailing_slash}} 41 | 42 | 43 | {{#assets_dot_slash}} 44 |

Project Root With Slash

45 |

Assets folder is in the project rool, which is not the same dir as the dest files.

46 |
47 | assets_dot_slash: {
48 |   options: {assets: './'},
49 |   files: {'test/actual/assets_dot_slash.html': ['test/files/assets.hbs']}
50 | }
51 | 
52 | {{/assets_dot_slash}} 53 | 54 | 55 | {{#assets_blank_path}} 56 |

Same Folder With Slash

57 |

Assets folder is in the same dir as dest files

58 |
59 | assets_blank_path: {
60 |   options: {assets: 'test/actual'},
61 |   files: {'test/actual/assets_blank_path.html': ['test/files/assets.hbs']}
62 | }
63 | 
64 | {{/assets_blank_path}} -------------------------------------------------------------------------------- /test/fixtures/data/_site.yml: -------------------------------------------------------------------------------- 1 | title: Assemble 2 | description: <%= pkg.description %> 3 | authors: Jon Schlinkert | Brian Woodward -------------------------------------------------------------------------------- /test/fixtures/data/animal.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Aardvark", 3 | "description": "Kind of like an ant eater?" 4 | } 5 | -------------------------------------------------------------------------------- /test/fixtures/data/blog.json: -------------------------------------------------------------------------------- 1 | { 2 | "articles": [ 3 | { 4 | "filename": "post1", 5 | "data": { 6 | "title": "Blog Post #1", 7 | "gists": [ 8 | "5898072" 9 | ] 10 | }, 11 | "content": "This \"content\" property is optional and would get passed into the `body` tag. But if you only need to pass the page's metadata to the layout then the content property isn't required." 12 | }, 13 | { 14 | "filename": "post2", 15 | "data": { 16 | "title": "Blog Post #2", 17 | "subtitle": "", 18 | "gists": [ 19 | "5898077", 20 | "5898078" 21 | ] 22 | }, 23 | "content": "

{{title}} | {{site.title}}

\n {{> alert }} This project is brought to you by <%= pkg.name %>." 24 | }, 25 | { 26 | "filename": "post3", 27 | "data": { 28 | "title": "Blog Post #3", 29 | "gists": [ 30 | "5909393" 31 | ] 32 | } 33 | } 34 | ] 35 | } -------------------------------------------------------------------------------- /test/fixtures/data/collections/expected-sortby-item-asc.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tags", 3 | "inflection": "tag", 4 | "sortorder": "ASC", 5 | "sortby": "", 6 | "items": [ 7 | { 8 | "tag": "bug", 9 | "pages": [ 10 | { "data": { "title": "a" } }, 11 | { "data": { "title": "b" } }, 12 | { "data": { "title": "c" } } 13 | ] 14 | }, 15 | { 16 | "tag": "feature", 17 | "pages": [ 18 | { "data": { "title": "z" } }, 19 | { "data": { "title": "x" } }, 20 | { "data": { "title": "y" } } 21 | ] 22 | }, 23 | { 24 | "tag": "priority", 25 | "pages": [ 26 | { "data": { "title": "m" } }, 27 | { "data": { "title": "d" } }, 28 | { "data": { "title": "w" } } 29 | ] 30 | } 31 | ] 32 | } -------------------------------------------------------------------------------- /test/fixtures/data/collections/expected-sortby-item-desc.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tags", 3 | "inflection": "tag", 4 | "sortorder": "DESC", 5 | "sortby": "", 6 | "items": [ 7 | { 8 | "tag": "priority", 9 | "pages": [ 10 | { "data": { "title": "m" } }, 11 | { "data": { "title": "d" } }, 12 | { "data": { "title": "w" } } 13 | ] 14 | }, 15 | { 16 | "tag": "feature", 17 | "pages": [ 18 | { "data": { "title": "z" } }, 19 | { "data": { "title": "x" } }, 20 | { "data": { "title": "y" } } 21 | ] 22 | }, 23 | { 24 | "tag": "bug", 25 | "pages": [ 26 | { "data": { "title": "a" } }, 27 | { "data": { "title": "b" } }, 28 | { "data": { "title": "c" } } 29 | ] 30 | } 31 | ] 32 | } -------------------------------------------------------------------------------- /test/fixtures/data/collections/expected-sortby-page-property-asc.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tags", 3 | "inflection": "tag", 4 | "sortorder": "ASC", 5 | "sortby": "title", 6 | "items": [ 7 | { 8 | "tag": "bug", 9 | "pages": [ 10 | { "data": { "title": "a" } }, 11 | { "data": { "title": "b" } }, 12 | { "data": { "title": "c" } } 13 | ] 14 | }, 15 | { 16 | "tag": "priority", 17 | "pages": [ 18 | { "data": { "title": "d" } }, 19 | { "data": { "title": "m" } }, 20 | { "data": { "title": "w" } } 21 | ] 22 | }, 23 | { 24 | "tag": "feature", 25 | "pages": [ 26 | { "data": { "title": "x" } }, 27 | { "data": { "title": "y" } }, 28 | { "data": { "title": "z" } } 29 | ] 30 | } 31 | ] 32 | } -------------------------------------------------------------------------------- /test/fixtures/data/collections/expected-sortby-page-property-desc.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tags", 3 | "inflection": "tag", 4 | "sortorder": "DESC", 5 | "sortby": "title", 6 | "items": [ 7 | { 8 | "tag": "feature", 9 | "pages": [ 10 | { "data": { "title": "z" } }, 11 | { "data": { "title": "y" } }, 12 | { "data": { "title": "x" } } 13 | ] 14 | }, 15 | { 16 | "tag": "priority", 17 | "pages": [ 18 | { "data": { "title": "w" } }, 19 | { "data": { "title": "m" } }, 20 | { "data": { "title": "d" } } 21 | ] 22 | }, 23 | { 24 | "tag": "bug", 25 | "pages": [ 26 | { "data": { "title": "c" } }, 27 | { "data": { "title": "b" } }, 28 | { "data": { "title": "a" } } 29 | ] 30 | } 31 | ] 32 | } -------------------------------------------------------------------------------- /test/fixtures/data/collections/fakeCollection.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tags", 3 | "inflection": "tag", 4 | "sortorder": "ASC", 5 | "sortby": "", 6 | "items": [ 7 | { 8 | "tag": "feature", 9 | "pages": [ 10 | { "data": { "title": "z" } }, 11 | { "data": { "title": "x" } }, 12 | { "data": { "title": "y" } } 13 | ] 14 | }, 15 | { 16 | "tag": "bug", 17 | "pages": [ 18 | { "data": { "title": "a" } }, 19 | { "data": { "title": "b" } }, 20 | { "data": { "title": "c" } } 21 | ] 22 | }, 23 | { 24 | "tag": "priority", 25 | "pages": [ 26 | { "data": { "title": "m" } }, 27 | { "data": { "title": "d" } }, 28 | { "data": { "title": "w" } } 29 | ] 30 | } 31 | ] 32 | } -------------------------------------------------------------------------------- /test/fixtures/data/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages": { 3 | "one": [ 4 | { 5 | "filename": "post1", 6 | "data": { 7 | "title": "Blog Post #1", 8 | "gists": ["5898072"] 9 | }, 10 | "content": "This \"content\" property is optional and would get passed into the `body` tag. But if you only need to pass the page\"s metadata to the layout then the content property is unnecessary." 11 | }, 12 | { 13 | "filename": "post2", 14 | "data": { 15 | "title": "Blog Post #2", 16 | "subtitle": "", 17 | "gists": ["5898077", "5898078"] 18 | }, 19 | "content": "

{{title}} | {{site.title}}

\n {{> <%= component.one %> }} This project is brought to you by <%= pkg.name %>." 20 | }, 21 | { 22 | "filename": "post3", 23 | "data": { 24 | "title": "Blog Post #3", 25 | "gists": ["5909393"] 26 | } 27 | } 28 | ], 29 | "two": { 30 | "sweet-blog-post-1": { 31 | "data": { 32 | "title": "Sweet Blog Post #1", 33 | "gists": ["5898072"] 34 | }, 35 | "content": "This 'content' property is optional and would get passed into the `body` tag. But if you only need to pass the page\"s metadata to the layout then the content property is unnecessary." 36 | }, 37 | "awesome-blog-post-2": { 38 | "data": { 39 | "title": "Awesome Blog Post #2", 40 | "subtitle": "", 41 | "gists": ["5898077", "5898078"] 42 | }, 43 | "content": "

{{title}} | {{site.title}}

\n {{> <%= component.one %> }} This project is brought to you by <%= pkg.name %>." 44 | }, 45 | "super-sweet-and-awesome-blog-post-3": { 46 | "data": { 47 | "title": "Super Sweet and Awesome Blog Post #3", 48 | "gists": ["5898072"] 49 | } 50 | } 51 | }, 52 | "three": { 53 | "meta-sweet-blog-post-1": { 54 | "metadata": { 55 | "title": "Sweet Blog Post #1", 56 | "gists": ["5898072"] 57 | }, 58 | "content": "This 'content' property is optional and would get passed into the `body` tag. But if you only need to pass the page\"s metadata to the layout then the content property is unnecessary." 59 | }, 60 | "meta-awesome-blog-post-2": { 61 | "data": { 62 | "title": "Awesome Blog Post #2", 63 | "subtitle": "", 64 | "gists": ["5898077", "5898078"] 65 | }, 66 | "content": "

{{title}} | {{site.title}}

\n {{> <%= component.one %> }} This project is brought to you by <%= pkg.name %>." 67 | }, 68 | "meta-super-sweet-and-awesome-blog-post-3": { 69 | "metadata": { 70 | "title": "Super Sweet and Awesome Blog Post #3", 71 | "gists": ["5898072"] 72 | } 73 | } 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /test/fixtures/data/contact.yml: -------------------------------------------------------------------------------- 1 | phone: 8005551212 -------------------------------------------------------------------------------- /test/fixtures/data/data.yml: -------------------------------------------------------------------------------- 1 | # "data.yml" or "data.json" provides access to the root of the context, 2 | # which means that variables in a "data" file may be used your templates as-is, 3 | # so you can do this: {{one}} instead of this: {{data.one}} 4 | one: first 5 | two: second 6 | three: third 7 | -------------------------------------------------------------------------------- /test/fixtures/data/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "This is the title from example.json", 3 | "text": "This is text from example.json." 4 | } 5 | -------------------------------------------------------------------------------- /test/fixtures/data/example.yml: -------------------------------------------------------------------------------- 1 | info: Congratulations! This is data from example.yml. 2 | -------------------------------------------------------------------------------- /test/fixtures/data/home.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "This title is from a JSON file.", 3 | "description": "This description is from a JSON file." 4 | } -------------------------------------------------------------------------------- /test/fixtures/data/noyfm.yml: -------------------------------------------------------------------------------- 1 | one: Variable number one 2 | two: Variable number two -------------------------------------------------------------------------------- /test/fixtures/data/person.yml: -------------------------------------------------------------------------------- 1 | name: Jon Schlinkert -------------------------------------------------------------------------------- /test/fixtures/helpers/bar.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | layout: none 3 | --- 4 | 5 | 6 | 7 | Custom Helpers example 8 | 9 | 10 |

Example using the bar helper

11 | {{{bar 'Below is an example of using the opt helper and getting the name property from the passed-in assemble.options'}}} 12 | 13 | 14 | -------------------------------------------------------------------------------- /test/fixtures/helpers/baz.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | layout: none 3 | --- 4 | {{baz 'this should be uppercase'}} -------------------------------------------------------------------------------- /test/fixtures/helpers/foo.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | layout: none 3 | --- 4 | 5 | 6 | 7 | Custom Helpers example 8 | 9 | 10 |

Example using the foo helper

11 | {{{foo 'Below is an example of using the opt helper and getting the name property from the passed-in assemble.options'}}} 12 | 13 | 14 | -------------------------------------------------------------------------------- /test/fixtures/helpers/opt.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | layout: none 3 | --- 4 | 5 | 6 | 7 | Custom Helpers example 8 | 9 | 10 |

Example using the "opt" helper

11 |
Version: {{opt 'name'}}
12 | 13 | 14 | -------------------------------------------------------------------------------- /test/fixtures/layouts/default.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Layout filename: '{{layout}}' 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 |
14 |
15 |
16 |

{{page.src}}{{page.dest}}

17 |
18 |
19 |
20 | 21 | {{pager pagination}} 22 |
23 | 24 |
25 | 26 |
27 | 31 |
32 | 33 |
34 |
35 |
36 |

Page layout: {{default originalLayout '(no layout defined)'}}

37 |

Page src: {{page.src}}

38 |

Page dest: {{page.dest}}

39 |

Dest filename: {{page.filename}}

40 |

Dest basename: {{page.basename}}

41 |

Page title: {{default title '(no title defined)'}}

42 |
43 | 44 |
45 |
46 |
47 | 48 | {{#if categories}} 49 | {{> collections-categories }} 50 | {{/if}} 51 |
52 |
53 | {{#if tags}} 54 | {{> collections-tags }} 55 | {{/if}} 56 |
57 |
58 | 59 |
60 | 61 | {{> body }} 62 | 63 |
64 |

Content

65 |
66 |
    67 | {{#each pages}} 68 |
  • {{filename}}
  • 69 | {{/each}} 70 |
71 | 72 |
73 |
74 | 75 |

Page

76 | 110 |

Each pages

111 |
    112 | {{#each pages}} 113 |
  • {{filename}}
  • 114 | 145 | {{/each}} 146 |
147 | 148 |

Debug Info

149 | {{{inspect page 'json'}}} 150 |
151 |
152 |
153 |
154 |
155 | 156 | 157 | 158 | -------------------------------------------------------------------------------- /test/fixtures/layouts/globlayout/nested/layout-globlayout.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | layout: one.hbs 3 | --- 4 |

Layout: {{default this.layout 'No layout was used.'}}

5 |

This is some random content before the body of the actual page.

6 | 7 | {{> body }} 8 | 9 |

This is some random content after the body of the actual page.

10 |

Layout: {{default this.layout 'No layout was used.'}}

11 | -------------------------------------------------------------------------------- /test/fixtures/layouts/noext.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Layout name: '{{layout}}' 6 | 7 | 8 | 9 | 10 |
11 |
12 |
13 | 14 |
15 | 19 |
20 | 21 |
22 |
23 |
24 |

Layout: {{default this.layout 'No layout was used.'}}

25 |

Template: {{page.src}}

26 |
27 | {{> body }} 28 |
29 |
30 |
31 |
32 | 33 | 34 | -------------------------------------------------------------------------------- /test/fixtures/layouts/one.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Layout name: '{{layout}}' 5 | 6 | 7 | 8 | 9 |
10 |
11 |

Layout: {{default this.layout 'No layout was used.'}}

12 |

Template: {{page.src}}

13 |

layout one

14 | {{> body }} 15 |

layout one

16 |
17 | 18 | 19 | -------------------------------------------------------------------------------- /test/fixtures/layouts/post.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Layout name: '{{layout}}' 7 | 8 | 9 | 10 | 11 |
12 |
13 |
14 | 15 |
16 | 20 |
21 | 22 |
23 |
24 |
25 |

Layout: {{default this.layout 'No layout was used.'}}

26 |

Template: {{page.src}}

27 |
28 | {{#each gists}} 29 | {{gist this}} 30 | {{/each}} 31 | {{> body }} 32 |
33 |
34 |
35 |
36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /test/fixtures/layouts/preprocess.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Layout filename: '{{layout}}' 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 |
14 |
15 |
16 |

{{page.src}}{{page.dest}}

17 |
18 |
19 |
20 | 21 | {{pager pagination}} 22 |
23 | 24 |
25 | 26 |
27 | 31 |
32 | 33 |
34 |
35 |
36 |

Page layout: {{default originalLayout '(no layout defined)'}}

37 |

Page src: {{page.src}}

38 |

Page dest: {{page.dest}}

39 |

Dest filename: {{page.filename}}

40 |

Dest basename: {{page.basename}}

41 |

Page title: {{default title '(no title defined)'}}

42 |
43 | 44 |
45 |
46 |
47 | 48 | {{#if categories}} 49 | {{> collections-categories }} 50 | {{/if}} 51 |
52 |
53 | {{#if tags}} 54 | {{> collections-tags }} 55 | {{/if}} 56 |
57 |
58 | 59 |
60 | 61 | {{> body }} 62 | 63 |
64 |

Content

65 |
66 |
    67 | {{#each pages}} 68 |
  • {{filename}}
  • 69 | {{/each}} 70 |
71 | 72 |
73 |
74 | 75 |

Page

76 |

Each pages

77 | 118 | 119 |

Debug Info

120 | {{{inspect page 'json'}}} 121 |
122 |
123 |
124 |
125 |
126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /test/fixtures/layouts/three.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | layout: two.hbs 3 | --- 4 |

Layout: {{default this.layout 'No layout was used.'}}

5 |

This is some random content before the body of the actual page.

6 | 7 | {{> body }} 8 | 9 |

This is some random content after the body of the actual page.

10 |

Layout: {{default this.layout 'No layout was used.'}}

11 | -------------------------------------------------------------------------------- /test/fixtures/layouts/two.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | layout: one.hbs 3 | --- 4 |

Layout: {{default this.layout 'No layout was used.'}}

5 |

This is some random content before the body of the actual page.

6 | 7 | {{> body }} 8 | 9 |

This is some random content after the body of the actual page.

10 |

Layout: {{default this.layout 'No layout was used.'}}

11 | -------------------------------------------------------------------------------- /test/fixtures/mocha/complex.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | foo: bar 3 | version: 2 4 | categories: 5 | - pages 6 | tags: 7 | - tests 8 | - examples 9 | - complex 10 | --- 11 | 12 |
This is an alert
13 | -------------------------------------------------------------------------------- /test/fixtures/mocha/simple1.yml: -------------------------------------------------------------------------------- 1 | --- 2 | foo: bar 3 | -------------------------------------------------------------------------------- /test/fixtures/mocha/simple2.yml: -------------------------------------------------------------------------------- 1 | --- 2 | foo: bar 3 | --- 4 | -------------------------------------------------------------------------------- /test/fixtures/mocha/yfm.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | foo: bar 3 | --- 4 | 5 |
This is an alert
6 | -------------------------------------------------------------------------------- /test/fixtures/pages/alert.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | title: Title for "alert.hbs" 3 | one: 4 | two: This is an alert 5 | categories: 6 | - components 7 | tags: 8 | - alert 9 | - bootstrap 10 | items: 11 | - collections 12 | - custom 13 | --- 14 | 15 |

{{{title}}}

16 |
{{{one.two}}}
17 | -------------------------------------------------------------------------------- /test/fixtures/pages/blog/index.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | layout: false 3 | --- 4 | 5 | 6 | 7 | 8 | 9 | Layout name: 'test/fixtures/pages/blog/index.hbs' | Layout: {{layout}} 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |
18 | 19 |
20 | 24 |
25 | 26 |
27 |
28 |
29 |

Template: {{page.src}}

30 |

Layout: {{default this.layout 'No layout was used.'}}

31 |
32 | {{#each pages}} 33 | {{#unlessEq ../filename compare=filename}} 34 |
35 |
36 |

{{../data.title}}

37 |
38 | {{#each ../data.gists}} 39 | {{gist this}} 40 | {{/each}} 41 |
42 | {{/unlessEq}} 43 | {{/each}} 44 |
45 |
46 |
47 |
48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /test/fixtures/pages/collections-categories.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | title: Collections Categories 3 | categories: 4 | - collections 5 | - categories 6 | - one 7 | - two 8 | - three 9 | --- 10 |
11 |
12 |

Categories

13 |
14 |
15 | {{#categories}} 16 | {{category}} 17 | {{/categories}} 18 |
19 |
-------------------------------------------------------------------------------- /test/fixtures/pages/collections-pages.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | title: Pages Collection 3 | tags: 4 | - pages 5 | --- 6 |
7 |
8 |

{{title}}

9 |
10 |
11 | {{#each pages}} 12 | {{{data.title}}} 13 | {{/each}} 14 |
15 |
-------------------------------------------------------------------------------- /test/fixtures/pages/collections-tags.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | title: Tags Test 3 | tags: 4 | - tags 5 | - collections 6 | - one 7 | - two 8 | - three 9 | --- 10 |
11 |
12 |

Tags

13 |
14 |
15 | {{#tags}} 16 | {{tag}} 17 | {{/tags}} 18 |
19 |
-------------------------------------------------------------------------------- /test/fixtures/pages/collections.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | title: Collections 3 | tags: 4 | - tags 5 | - collections 6 | - one 7 | items: 8 | - collections 9 | - custom 10 | --- 11 | {{title}} 12 |
    13 | {{#tags}} 14 |
  • {{tag}}
  • 15 | {{/tags}} 16 |
17 | 18 |
    19 | {{#categories}} 20 |
  • {{categories}}
  • 21 | {{/categories}} 22 |
23 | 24 |
    25 | {{#pages}} 26 |
  • {{this.basename}}
  • 27 | {{/pages}} 28 |
29 | -------------------------------------------------------------------------------- /test/fixtures/pages/complex.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | title: Complex YFM 3 | foo: bar 4 | version: 2 5 | categories: 6 | - pages 7 | tags: 8 | - tests 9 | - examples 10 | - complex 11 | items: 12 | - alpha 13 | - beta 14 | --- 15 | 16 |
This is an alert
17 | -------------------------------------------------------------------------------- /test/fixtures/pages/context.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | title: Context 3 | description: The variables on this page are in shown in different contexts. 4 | categories: 5 | - context 6 | - pages 7 | - fixtures 8 | items: 9 | - alpha 10 | - omega 11 | --- 12 | 34 | 35 |

If a list item is empty, or rather only has a label and no link, then the variable did not populate a value.

36 | 37 | 43 | 44 |
45 | 46 | 52 | 53 |
54 | 55 | 64 | 65 |
66 | 67 | 76 | -------------------------------------------------------------------------------- /test/fixtures/pages/debug-helpers.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | title: Debug Helper 3 | --- 4 | {{#markdown}} 5 | 6 | ### \{{debug}} helper 7 | Uncomment the `debug` helper below, run `grunt assemble`, and watch the output in the command line to see how it works. 8 | {{!debug text}} 9 | 10 | {{/markdown}} 11 | -------------------------------------------------------------------------------- /test/fixtures/pages/example.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | title: Title from YFM of "example.hbs" 3 | categories: 4 | - yaml 5 | - yfm 6 | tags: 7 | - example 8 | items: 9 | - omega 10 | - gamma 11 | --- 12 | 13 | This example shows that the properties from "example.json" and "example.hbs" are on the page object. 14 | 15 |
16 | 17 |
{{page.title}}
18 |
{{page.text}}
19 | 20 |
21 | 22 |
{{title}}
23 | -------------------------------------------------------------------------------- /test/fixtures/pages/gist-helper.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | title: Gist Helper 3 | --- 4 | {{#markdown}} 5 | 6 | # \{{gist}} helper 7 | {{gist '5193239'}} 8 | 9 | {{/markdown}} -------------------------------------------------------------------------------- /test/fixtures/pages/globlayout/globlayout.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | title: Using a glob layout 3 | layout: layout-globlayout.hbs 4 | --- 5 |

Hello: {{title}}

-------------------------------------------------------------------------------- /test/fixtures/pages/layoutext/layoutext.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | title: options.layoutext 3 | layout: noext 4 | description: Allows a layout to be defined without an extension 5 | --- 6 |

{{title}}

7 |

{{description}}

-------------------------------------------------------------------------------- /test/fixtures/pages/lodash.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | title: <%= site.title %> 3 | description: <%= site.description %> 4 | --- 5 |

{{title}}

6 |

{{description}}

7 | -------------------------------------------------------------------------------- /test/fixtures/pages/md-helper.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | title: md helper 3 | description: Use the {{md}} helper to include external markdown files. 4 | categories: 5 | - markdown 6 | - helper 7 | tags: 8 | - test 9 | - md 10 | - markdown 11 | items: 12 | - gamma 13 | - beta 14 | --- 15 | 16 | 20 | 21 |

{{{md './test/fixtures/pages/md.md'}}}

22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /test/fixtures/pages/md.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Markdown 3 | --- 4 | ## Some Markdown 5 | 6 | - one 7 | - two 8 | - three 9 | 10 | [Click here](http://github.com) 11 | -------------------------------------------------------------------------------- /test/fixtures/pages/nested/deep-nested-layouts.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | title: Three layouts deep 3 | layout: three.hbs 4 | --- 5 |

Hello: {{title}}

-------------------------------------------------------------------------------- /test/fixtures/pages/nested/nested-layouts.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | title: Home Page 3 | layout: two.hbs 4 | categories: 5 | - layouts 6 | --- 7 |

Hello: {{title}}

-------------------------------------------------------------------------------- /test/fixtures/pages/no-yfm-data.hbs: -------------------------------------------------------------------------------- 1 | There is no YAML front matter in this page. 2 | 3 |
    4 |
  • {{one}}
  • 5 |
  • {{two}}
  • 6 |
  • {{three}}
  • 7 |
  • {{global1}}
  • 8 |
9 | -------------------------------------------------------------------------------- /test/fixtures/pages/no-yfm.hbs: -------------------------------------------------------------------------------- 1 | There is no YAML front matter in this page. 2 | 3 |
{{noyfm.one}}
4 |
{{noyfm.two}}
5 | 6 | 7 | -------------------------------------------------------------------------------- /test/fixtures/pages/nolayout/no-layout-none.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | layout: none 3 | categories: 4 | - layouts 5 | --- 6 | 7 | 8 | 9 | Has no layout 10 | 11 | 12 |
Page with layout: 'none' defined.
13 | 14 | 15 | -------------------------------------------------------------------------------- /test/fixtures/pages/nolayout/no-layout.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | layout: false 3 | categories: 4 | - layouts 5 | --- 6 | 7 | 8 | 9 | Has no layout 10 | 11 | 12 |
Page with layout: false defined.
13 | 14 | 15 | -------------------------------------------------------------------------------- /test/fixtures/pages/postprocess/postprocess.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | layout: none 3 | title: The Canterbury Tales 4 | chapter: Prologue 5 | categories: 6 | - postprocess 7 | - options 8 | --- 9 |

{{title}}

10 |

{{chapter}}

11 |

Modern English

12 | 13 | But none the less, whilst I have time and space, 14 | Before yet farther in this tale I pace, 15 | It seems to me accordant with reason 16 | To inform you of the condition 17 | Of all of these, as it seemed to me, 18 | And who they were, and what was their degree, 19 | And even how arrayed there at the inn; 20 | And with a knight thus will I first begin. -------------------------------------------------------------------------------- /test/fixtures/pages/postprocess/postprocess2.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | layout: none 3 | title: Post-Process function 4 | description: this page should be prettified. 5 | categories: 6 | - postprocess 7 | - options 8 | - prettify 9 | --- 10 | {{title}} {{> nav-main }} {{{description}}} 11 | 12 | -------------------------------------------------------------------------------- /test/fixtures/pages/yfm-context.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | title: This title is from the YFM of the current page 3 | description: This description is from the YFM of the current page 4 | categories: 5 | - yfm 6 | - yaml 7 | - context 8 | --- 9 | 10 | 14 | 15 |
16 | 17 | 21 | 22 |
23 | 24 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /test/fixtures/pages/yfm.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | title: YFM 3 | foo: bar 4 | items: 5 | - alpha 6 | - omega 7 | --- 8 | 9 |
This is an alert
10 | -------------------------------------------------------------------------------- /test/fixtures/pages/yfm/associative-arrays.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | title: Associative arrays 3 | 4 | # Indented Blocks, common in YAML data files, use indentation and new lines to separate the '''key: value''' pairs 5 | people: 6 | name: John Smith 7 | age: 33 8 | 9 | # Inline Blocks, common in YAML data streams, use comma+space to separate the '''key: value''' pairs between braces 10 | morePeople: {name: Grace Jones, age: 21} 11 | --- 12 | 15 | 16 |
17 |

Associative arrays

18 |
19 | {{#people}} 20 |
Name:
{{name}}
21 |
Age:
{{age}}
22 | {{/people}} 23 | {{#morePeople}} 24 |
Name:
{{name}}
25 |
Age:
{{age}}
26 | {{/morePeople}} 27 |
28 |
-------------------------------------------------------------------------------- /test/fixtures/pages/yfm/block-literals.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | title: Block Literals 3 | 4 | # Newlines Preserved 5 | poem: | 6 | old pond . . . 7 | a frog leaps in 8 | water’s sound 9 | 10 | # Newlines Folded 11 | another: > 12 | old pond . . . 13 | a frog leaps in 14 | water’s sound 15 | --- 16 | 19 | 20 |

Newlines preserved

21 |
22 | {{{poem}}} 23 |
24 | 25 |

Newlines folded

26 |
27 | {{{another}}} 28 |
-------------------------------------------------------------------------------- /test/fixtures/pages/yfm/comments.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | # This is a Comment 3 | title: Comments in YAML front matter 4 | --- 5 | 8 | 9 | Nothing. -------------------------------------------------------------------------------- /test/fixtures/pages/yfm/data-files.hbs: -------------------------------------------------------------------------------- 1 |

Note that templates \{{one}}, \{{two}} and \{{three}} get their data from "test/fixtures/data.yml". 2 | When a data file is created with the name "data", it gives you access to the root of the context.

3 | 4 | 9 | 10 |
11 |

person.yml

12 |
{{person.name}}
13 |
14 | 15 |
16 |

contact.yml

17 |
{{contact.phone}}
18 |
19 | 20 |
21 |

animal.json

22 |
{{animal.type}}
23 |

{{animal.description}}

24 |
25 | 26 |
27 |

example.json

28 |
{{example.content}}
29 |
30 | 31 |
32 |

example.yml

33 |
{{example.info}}
34 |
35 | -------------------------------------------------------------------------------- /test/fixtures/pages/yfm/data-types.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | title: Data Types 3 | 4 | dataTypes: 5 | a: 123 # an integer 6 | b: "123" # a string, disambiguated by quotes 7 | c: 123.0 # a float 8 | # d throws an error 9 | # d: !!float 123 # also a float via explicit data type prefixed by (!!) 10 | e: !!str 123 # a string, disambiguated by explicit type 11 | f: !!str Yes # a string via explicit type 12 | g: Yes # a boolean True 13 | h: Yes we have No bananas # a string, "Yes" and "No" disambiguated by context. 14 | --- 15 | 18 | 19 |
20 |

Casting data types

21 |
22 | {{#dataTypes}} 23 |
a.
{{{a}}}
24 |
b.
{{{b}}}
25 |
c.
{{{c}}}
26 |
d.
{{{d}}}
27 |
e.
{{{e}}}
28 |
f.
{{{f}}}
29 |
g.
{{{g}}}
30 |
h.
{{{h}}}
31 | {{/dataTypes}} 32 |
33 |
-------------------------------------------------------------------------------- /test/fixtures/pages/yfm/document.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | receipt: Oz-Ware Purchase Invoice 3 | date: 2007-08-06 4 | prettyDate: <%= grunt.template.date(date, 'yyyy-mm-dd') %> 5 | customer: 6 | given: Dorothy 7 | family: Gale 8 | 9 | items: 10 | - part_no: A4786 11 | descrip: Water Bucket (Filled) 12 | price: 1.47 13 | quantity: 4 14 | 15 | - part_no: E1628 16 | descrip: High Heeled "Ruby" Slippers 17 | size: 8 18 | price: 100.27 19 | quantity: 1 20 | 21 | bill-to: &id001 22 | street: | 23 | 123 Tornado Alley 24 | Suite 16 25 | city: East Centerville 26 | state: KS 27 | 28 | ship-to: *id001 29 | 30 | specialDelivery: > 31 | Follow the Yellow Brick 32 | Road to the Emerald City. 33 | Pay no attention to the 34 | man behind the curtain. 35 | --- 36 | 39 | 40 | 41 | 43 |
44 |

Customer Information

45 |
46 |
Receipt:
47 |
{{receipt}}
48 | 49 |
Date:
50 |
{{prettyDate}}
51 | 52 |
First Name:
53 |
{{customer.given}}
54 | 55 |
Last Name:
56 |
{{customer.family}}
57 |
58 |
59 | 60 |
61 | 62 | 64 |
65 |

Order Information

66 |
67 |
Items:
68 | {{#each items}} 69 |
70 | Item #{{@index}} 71 |
72 |
Part No:
73 |
{{part_no}}
74 |
Description:
75 |
{{descrip}}
76 |
Price:
77 |
${{price}}
78 |
Qty:
79 |
{{quantity}}
80 |
81 |
82 | {{/each}} 83 |
84 |
85 |
86 | 87 | 89 |
90 |

Address Information

91 | Bill To: 92 |
93 |
Billing Street:
94 |
{{bill-to.street}}
95 |
Billing City:
96 |
{{bill-to.city}}
97 |
Billing State:
98 |
{{bill-to.state}}
99 |
100 | Ship To: 101 |
102 |
Shipping Street:
103 |
{{ship-to.street}}
104 |
Shipping City:
105 |
{{ship-to.city}}
106 |
Shipping State:
107 |
{{ship-to.state}}
108 | 109 |
110 |
111 | 112 | 114 |
115 |

Delivery Instructions

116 |

{{{specialDelivery}}}

117 |
-------------------------------------------------------------------------------- /test/fixtures/pages/yfm/lists.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | # This is a Comment 3 | title: Almost a Haiku 4 | 5 | attributes: 6 | - attr1 7 | - attr2 8 | - attr3 9 | methods: [ getter, setter ] 10 | 11 | # Favorite Movies 12 | movies: 13 | - Casablanca 14 | - North by Northwest 15 | - The Man Who Wasn't There 16 | 17 | groceries: [milk, pumpkin pie, eggs, juice] 18 | 19 | people: 20 | - {name: John Smith, age: 33} 21 | - name: Mary Smith 22 | age: 27 23 | 24 | men: [John Smith, Bill Jones] 25 | women: 26 | - Mary Smith 27 | - Susan Williams 28 | --- 29 | 32 | 33 |
34 |

Attributes

35 |
    36 | {{#each attributes}}
  • {{.}}
  • 37 | {{/each}} 38 |
39 |
40 | 41 |
42 | 43 |
44 |

Methods

45 |
    46 | {{#each methods}}
  • {{.}}
  • 47 | {{/each}} 48 |
49 |
50 | 51 |
52 | 53 |
54 |

Lists

55 |

Movies

56 |
57 | {{#each movies}} 58 |
Movie:
{{.}}
59 | {{/each}} 60 |
61 | 62 |

Groceries

63 |
64 | {{#each groceries}} 65 |
Item:
{{.}}
66 | {{/each}} 67 |
68 |
69 | 70 |
71 | 72 |
73 |

Hierarchical combinations of elements

74 |

Lists of associative arrays

75 |
76 | {{#each people}} 77 |
Name:
{{name}}
78 |
Age:
{{age}}
79 | {{/each}} 80 |
81 | 82 |

Associative arrays of lists

83 |
84 |
Men
85 | {{#each men}}
Name:
{{.}}
{{/each}} 86 |
Women
87 | {{#each women}}
Name:
{{.}}
{{/each}} 88 |
89 |
-------------------------------------------------------------------------------- /test/fixtures/pages/yfm/relational-trees.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | title: Relational Trees - References 3 | 4 | # References Example: sequencer protocols for Laser eye surgery 5 | steps: 6 | - step: &id001 # defines anchor label &id001 7 | instrument: Lasik 2000 8 | pulseEnergy: 5.4 9 | pulseDuration: 12 10 | repetition: 1000 11 | spotSize: 1mm 12 | 13 | - step: &id002 14 | instrument: Lasik 2000 15 | pulseEnergy: 5.0 16 | pulseDuration: 10 17 | repetition: 500 18 | spotSize: 2mm 19 | 20 | - step: *id001 # refers to the first step (with anchor &id001) 21 | - step: *id002 # refers to the second step 22 | - step: *id001 23 | - step: *id002 24 | --- 25 | 28 | 29 |
30 |

Associative arrays

31 |
32 | {{#each steps}} 33 | {{#each step}} 34 |
{{@key}}
35 |
{{.}}
36 | {{/each}} 37 |
38 | {{/each}} 39 |
40 |
-------------------------------------------------------------------------------- /test/fixtures/pages/yfm/underscore.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | jon: <%= person.name %> 3 | --- 4 |

Note that templates \{{one}}, \{{two}} and \{{three}} get their data from "test/fixtures/data.yml". 5 | When a data file is created with the name "data", it gives you access to the root of the context.

6 | 7 | 12 | 13 |
14 |

person.yml

15 |
{{person.name}}
16 |
17 | 18 |
19 |

person.yml - YFM

20 |
jon: {{jon}}
21 |
page.jon: {{page.jon}}
22 |
underscore.jon: {{underscore.jon}}
23 |
data.jon: {{data.jon}}
24 |
underscore.data.jon: {{underscore.data.jon}}
25 |
26 | 27 |
28 |

contact.yml

29 |
{{contact.phone}}
30 |
31 | 32 |
33 |

animal.json

34 |
{{animal.type}}
35 |

{{animal.description}}

36 |
37 | 38 |
39 |

example.json

40 |
{{example.content}}
41 |
42 | 43 |
44 |

example.yml

45 |
{{example.info}}
46 |
47 | -------------------------------------------------------------------------------- /test/fixtures/pages/yfm/variables.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | title: YAML Variables 3 | 4 | one: &DOOWB This is an example YAML variable. Variables need to be the first thing in the line. If it shows up in the result, it worked! 5 | two: *DOOWB 6 | --- 7 | 10 | 11 | {{{two}}} 12 | 13 | {{#markdown}} 14 | This would output the variable as literal text. 15 | ``` yaml 16 | three: But this doesn't work. *DOOWB 17 | ``` 18 | And this would throw an error: 19 | 20 | ``` yaml 21 | three: *DOOWB But this doesn't work. 22 | ``` 23 | 24 | YAML supports **variables**, or **repeated nodes**. The simplest explanation is that you define something as a variable by preceding it with "&NAME value" and you can refer to it with "*NAME" e.g.: 25 | 26 | ``` yaml 27 | # YAML 28 | some_thing: &NAME foobar 29 | other_thing: *NAME 30 | ``` 31 | Parses to: 32 | ``` json 33 | {"other_thing": "foobar", "some_thing": "foobar"} 34 | ``` 35 | {{/markdown}} -------------------------------------------------------------------------------- /test/fixtures/partials/alert.hbs: -------------------------------------------------------------------------------- 1 |
ALERT! This is an alert message. >
-------------------------------------------------------------------------------- /test/fixtures/partials/collections-categories.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | title: Categories 3 | description: Different ways to use categories collections. 4 | categories: 5 | - collections 6 | tags: 7 | - categories 8 | - collections 9 | - tags 10 | - pages 11 | --- 12 | 13 |
14 |
15 |

categories on this page: {{default page.categories.length 0}}

16 |
17 |
18 | {{#if page.categories}} 19 | {{#page.categories}} 20 | {{.}} 21 | {{/page.categories}} 22 | {{else}} 23 | No categories defined on this page. 24 | {{/if}} 25 |
26 |
27 | 28 |
29 | 30 |
31 |
32 |

All categories: {{default categories.length 0}}

33 |
34 |
35 | {{#if categories}} 36 | {{#categories}} 37 | {{category}} 38 | {{/categories}} 39 | {{else}} 40 | No categories defined. 41 | {{/if}} 42 |
43 |
44 | 45 |
46 | 47 |
48 |
49 |

Pages related to each category

50 |
51 |
52 | {{#each categories}} 53 |
Related pages for: {{category}}
54 | 65 | {{/each}} 66 |
67 |
68 | -------------------------------------------------------------------------------- /test/fixtures/partials/collections-custom.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | title: Items 3 | description: Custom collection examples. 4 | --- 5 | 9 | 10 | 11 | All items 12 | 13 | 18 | 19 | 20 | Items on this page 21 | 22 |

{{#if page.items}}{{page.items.length}}{{else}}0{{/if}} items

23 | 30 | -------------------------------------------------------------------------------- /test/fixtures/partials/collections-tags.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | title: Tags 3 | description: Different ways to use tags collections. 4 | --- 5 | 6 |
7 |
8 |

Tags on this page: {{default page.tags.length 0}}

9 |
10 |
11 | {{#if page.tags}} 12 | {{#page.tags}} 13 | {{.}} 14 | {{/page.tags}} 15 | {{else}} 16 | No tags defined on this page. 17 | {{/if}} 18 |
19 |
20 | 21 |
22 | 23 |
24 |
25 |

All tags: {{default tags.length 0}}

26 |
27 |
28 | {{#if tags}} 29 | {{#tags}} 30 | {{{tag}}} 31 | {{/tags}} 32 | {{else}} 33 | No tags have been defined. 34 | {{/if}} 35 |
36 |
37 | 38 |
39 | 40 |
41 |
42 |

Pages related to each tag

43 |
44 |
45 | {{#each tags}} 46 |
Related pages for: {{tag}}
47 | 58 | {{/each}} 59 |
60 |
61 | -------------------------------------------------------------------------------- /test/fixtures/partials/nav-main.hbs: -------------------------------------------------------------------------------- 1 | 21 | -------------------------------------------------------------------------------- /test/fixtures/permalinks/post.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | title: Snowshoe Crabs Are Swarthy and Devious 3 | date: 03-13-2013 3:45 PM 4 | description: This is an example blog post. 5 | 6 | # Dynamically build the slug for example 7 | one: alpha 8 | two: beta 9 | three: gamma 10 | slug: <%= one %>-<%= two %>-<%= three %> 11 | 12 | categories: 13 | - node.js 14 | --- 15 |

{{{data.title}}}

16 |

{{{description}}}

-------------------------------------------------------------------------------- /test/fixtures/plugins/after.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | layout: none 3 | --- 4 | 5 | Blah blah. -------------------------------------------------------------------------------- /test/fixtures/plugins/before.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | layout: none 3 | title: Overide me 4 | --- 5 | 6 | {{title}} -------------------------------------------------------------------------------- /test/fixtures/plugins/untitled.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | layout: none 3 | description: this page doesn't have a title in the YFM 4 | slug: assemble 5 | date: 2013-10-09 6 | --- 7 |

{{{page.title}}}

8 |

{{{description}}}

9 | -------------------------------------------------------------------------------- /test/helpers/helpers-with-register.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Assemble 3 | * 4 | * Copyright (c) 2014, Jon Schlinkert, Brian Woodward, contributors. 5 | * Licensed under the MIT License (MIT). 6 | */ 7 | 8 | module.exports.register = function(Handlebars, options) { 9 | 'use strict'; 10 | 11 | Handlebars.registerHelper('foo', function(msg) { 12 | return ''; 13 | }); 14 | 15 | Handlebars.registerHelper('opt', function(key) { 16 | return options[key] || ''; 17 | }); 18 | 19 | }; 20 | -------------------------------------------------------------------------------- /test/helpers/helpers.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Assemble 3 | * 4 | * Copyright (c) 2014, Jon Schlinkert, Brian Woodward, contributors. 5 | * Licensed under the MIT License (MIT). 6 | */ 7 | 8 | var bar = function(msg) { 9 | return '\n'; 10 | }; 11 | 12 | module.exports.bar = bar; 13 | -------------------------------------------------------------------------------- /test/helpers/logging.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Assemble 3 | * 4 | * Copyright (c) 2014-2017, Jon Schlinkert, Brian Woodward, contributors. 5 | * Licensed under the MIT License (MIT). 6 | */ 7 | 8 | var sort = require('sort-object'); 9 | 10 | module.exports.register = function(Handlebars) { 11 | 'use strict'; 12 | 13 | Handlebars.registerHelper('inspect', function(context, options) { 14 | var hash = options.hash || {}; 15 | var ext = hash.ext || '.html'; 16 | context = JSON.stringify(sort(context), null, 2); 17 | 18 | // Wrap the returned JSON in either markdown code fences 19 | // or HTML, depending on the extension. 20 | var md = '\n```json\n' + context + '\n```'; 21 | var html = '
\n' + context + '\n
'; 22 | var result = switchOutput(ext, md, html); 23 | return new Handlebars.SafeString(result); 24 | }); 25 | }; 26 | 27 | function switchOutput(ext, markdown, html) { 28 | var output; 29 | switch (ext) { 30 | // return markdown 31 | case '.markdown': 32 | case '.md': 33 | output = markdown; 34 | break; 35 | 36 | // return HTML 37 | case '.html': 38 | case '.htm': 39 | output = html; 40 | break; 41 | 42 | default: 43 | output = html; 44 | } 45 | return output; 46 | } 47 | -------------------------------------------------------------------------------- /test/helpers/markdown.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Assemble 3 | * 4 | * Copyright (c) 2014-2017, Jon Schlinkert, Brian Woodward, contributors. 5 | * Licensed under the MIT License (MIT). 6 | */ 7 | 8 | module.exports.register = function(Handlebars) { 9 | 'use strict'; 10 | 11 | Handlebars.registerHelper('markdown', require('helper-markdown')()); 12 | Handlebars.registerHelper('md', require('helper-md').sync); 13 | }; 14 | -------------------------------------------------------------------------------- /test/helpers/nav.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Assemble 3 | * 4 | * Copyright (c) 2014, Jon Schlinkert, Brian Woodward, contributors. 5 | * Licensed under the MIT License (MIT). 6 | */ 7 | 8 | var _ = require('lodash'); 9 | 10 | // Export helpers 11 | module.exports.register = function(Handlebars, options) { 12 | 'use strict'; 13 | 14 | var opts = options || {}; 15 | 16 | /** 17 | * {{nav}} 18 | */ 19 | exports.nav = function(context, options) { 20 | options = options || {}; 21 | options.hash = options.hash || {}; 22 | context = _.extend({modifier: ''}, context, opts.data, this, options.hash); 23 | 24 | var template = [ 25 | '' 70 | ].join('\n'); 71 | 72 | return new Handlebars.SafeString(Handlebars.compile(template)(context)); 73 | }; 74 | 75 | for (var helper in exports) { 76 | if (exports.hasOwnProperty(helper)) { 77 | Handlebars.registerHelper(helper, exports[helper]); 78 | } 79 | } 80 | }; 81 | -------------------------------------------------------------------------------- /test/helpers/pager.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Assemble 3 | * 4 | * Copyright (c) 2014, Jon Schlinkert, Brian Woodward, contributors. 5 | * Licensed under the MIT License (MIT). 6 | */ 7 | 8 | var _ = require('lodash'); 9 | 10 | module.exports.register = function(Handlebars, options) { 11 | 'use strict'; 12 | 13 | var opts = options || {}; 14 | 15 | /** 16 | * {{pager}} 17 | * Adds a pager to enable navigating to prev and next page/post. 18 | * @param {Object} context Context to pass to the helper, most likely `pagination`. 19 | * @param {Object} options Pass a modifier class to the helper. 20 | * @return {String} The pagination, HTML. 21 | */ 22 | 23 | Handlebars.registerHelper('pager', function(context, options) { 24 | options = options || {}; 25 | options.hash = options.hash || {}; 26 | context = _.extend({modifier: ''}, context, opts.data, this, options.hash); 27 | 28 | var template = [ 29 | '
    ', 30 | '', 31 | ' {{#is pagination.currentPage 1}}', 32 | ' ', 35 | ' ', 38 | ' {{/is}}', 39 | '', 40 | ' {{#isnt pagination.currentPage 1}}', 41 | ' ', 44 | ' ', 47 | ' {{/isnt}}', 48 | '', 49 | ' {{#eachItems pages}}', 50 | '
  • ', 51 | ' {{@number}}', 52 | '
  • ', 53 | ' {{/eachItems}}', 54 | '', 55 | ' {{#isnt pagination.currentPage pagination.totalPages}}', 56 | ' ', 59 | ' ', 62 | ' {{/isnt}}', 63 | '', 64 | ' {{#is pagination.currentPage pagination.totalPages}}', 65 | ' ', 68 | ' ', 71 | ' {{/is}}', 72 | '', 73 | '
' 74 | ].join('\n'); 75 | 76 | var styles = [ 77 | '' 86 | ].join('\n'); 87 | 88 | return new Handlebars.SafeString(Handlebars.compile(template)(context) + styles); 89 | }); 90 | }; 91 | -------------------------------------------------------------------------------- /test/helpers/rel.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Assemble 3 | * 4 | * Copyright (c) 2014, Jon Schlinkert, Brian Woodward, contributors. 5 | * Licensed under the MIT License (MIT). 6 | */ 7 | 8 | var path = require('path'); 9 | 10 | module.exports.register = function(Handlebars) { 11 | 'use strict'; 12 | 13 | Handlebars.registerHelper('rel', function(context) { 14 | var newDest = this.dest; 15 | var destDirname = path.dirname(context); 16 | var relativePath = path.relative(path.resolve(destDirname), path.resolve(newDest)); 17 | 18 | return relativePath.replace(/\\/g, '/'); 19 | }); 20 | }; 21 | -------------------------------------------------------------------------------- /test/helpers/utils/getext.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Assemble 3 | * 4 | * Copyright (c) 2014, Jon Schlinkert, Brian Woodward, contributors. 5 | * Licensed under the MIT License (MIT). 6 | */ 7 | 'use strict'; 8 | 9 | /** 10 | * ## Get extension 11 | * 12 | * Assemble 13 | * Copyright (c) 2013 Upstage. 14 | * Licensed under the MIT License (MIT). 15 | */ 16 | 17 | var path = require('path'); 18 | 19 | module.exports = function(str) { 20 | if (path.extname(str)) { 21 | str = path.extname(str); 22 | } 23 | if (str[0] === '.') { 24 | str = str.substring(1); 25 | } 26 | return str; 27 | }; 28 | -------------------------------------------------------------------------------- /test/helpers/utils/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Assemble 3 | * 4 | * Copyright (c) 2014, Jon Schlinkert, Brian Woodward, contributors. 5 | * Licensed under the MIT License (MIT). 6 | */ 7 | 'use strict'; 8 | 9 | module.exports = { 10 | getext: require('./getext'), 11 | isUndefined: require('./isUndefined'), 12 | parseAttributes: require('./parseAttributes'), 13 | switchOutput: require('./switchOutput'), 14 | toString: require('./toString') 15 | }; 16 | -------------------------------------------------------------------------------- /test/helpers/utils/isUndefined.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Assemble 3 | * 4 | * Copyright (c) 2014, Jon Schlinkert, Brian Woodward, contributors. 5 | * Licensed under the MIT License (MIT). 6 | */ 7 | 8 | var utils = require('./utils'); 9 | 10 | /** 11 | * isUndefined 12 | * @param {[type]} value [description] 13 | * @return {[type]} [description] 14 | */ 15 | 16 | module.exports = function(value) { 17 | 'use strict'; 18 | /*jshint eqnull: true */ 19 | return value === 'undefined' || utils.toString.call(value) === '[object Function]' || (value.hash != null); 20 | }; 21 | -------------------------------------------------------------------------------- /test/helpers/utils/parseAttributes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * parseAttributes 3 | * @param {[type]} hash [description] 4 | * @return {[type]} [description] 5 | */ 6 | 7 | 'use strict'; 8 | 9 | module.exports = function(hash) { 10 | return Object.keys(hash).map(function(key) { 11 | return '' + key + '="' + hash[key] + '"'; 12 | }).join(' '); 13 | }; 14 | -------------------------------------------------------------------------------- /test/helpers/utils/switchOutput.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Assemble 3 | * 4 | * Copyright (c) 2014, Jon Schlinkert, Brian Woodward, contributors. 5 | * Licensed under the MIT License (MIT). 6 | */ 7 | 'use strict'; 8 | 9 | /** 10 | * switchOutput 11 | */ 12 | module.exports = function(ext, md, html) { 13 | var output; 14 | switch (ext) { 15 | case '': 16 | case '.md': 17 | output = md; 18 | break; 19 | case '.html': 20 | case '.htm': 21 | output = html; 22 | } 23 | return output; 24 | }; 25 | -------------------------------------------------------------------------------- /test/helpers/utils/toString.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Assemble 3 | * 4 | * Copyright (c) 2014, Jon Schlinkert, Brian Woodward, contributors. 5 | * Licensed under the MIT License (MIT). 6 | */ 7 | 'use strict'; 8 | 9 | /** 10 | * toString 11 | * @param {[type]} val [description] 12 | * @return {[type]} [description] 13 | */ 14 | module.exports = function(val) { 15 | /*jshint eqnull: true */ 16 | 17 | if (val == null) { 18 | return ''; 19 | } else { 20 | return val.toString(); 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /test/helpers/utils/utils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Assemble 3 | * 4 | * Copyright (c) 2014, Jon Schlinkert, Brian Woodward, contributors. 5 | * Licensed under the MIT License (MIT). 6 | */ 7 | 'use strict'; 8 | 9 | var utils = module.exports = {}; 10 | 11 | var toString = function(val) { 12 | if (val == null) { 13 | return ''; 14 | } else { 15 | return val.toString(); 16 | } 17 | }; 18 | utils.toString = Object.prototype.toString; 19 | 20 | utils.lowerCase = function(str) { 21 | return toString(str).toLowerCase(); 22 | }; 23 | 24 | utils.isUndefined = function(value) { 25 | return value === 'undefined' || Object.toString.call(value) === '[object Function]' || (value.hash != null); 26 | }; 27 | -------------------------------------------------------------------------------- /test/mocha.opts: -------------------------------------------------------------------------------- 1 | --reporter spec -------------------------------------------------------------------------------- /test/plugins/not_real.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/assemble/grunt-assemble/7ee67edba760c9c008aad65aa3c15ec708d0d11e/test/plugins/not_real.js -------------------------------------------------------------------------------- /test/plugins/page_collection_preprocessing.js: -------------------------------------------------------------------------------- 1 | 2 | // list of functions to do pre processing on the pages 3 | // in the pages collection 4 | 5 | var relative = require('relative'); 6 | 7 | module.exports = [ 8 | 9 | // add an isCurrentPage flag to the page if the dest matches 10 | function isCurrentPage(page, context) { 11 | page.isCurrentPage = (page.dest === context.page.dest); 12 | }, 13 | 14 | // add a relative link from the "current page" to the 15 | // page in the collection 16 | function relativeLink(page, context) { 17 | page.relativeLink = relative(context.page.dest, page.dest); 18 | } 19 | ]; 20 | -------------------------------------------------------------------------------- /test/plugins/plugin_after.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Assemble 3 | * Created and maintained by Jon Schlinkert and Brian Woodward 4 | * 5 | * Copyright (c) 2013 Upstage. 6 | * Licensed under the MIT License (MIT). 7 | */ 8 | 9 | var runCount = 0; 10 | 11 | var after = function(params, next) { 12 | runCount++; 13 | params.assemble.options.pages.forEach(function(page) { 14 | params.grunt.file.write(page.dest, 'AFTER OVERWRITE ' + runCount); 15 | }); 16 | next(); 17 | }; 18 | 19 | // export options 20 | after.options = { 21 | stage: 'render:post:pages' 22 | }; 23 | 24 | module.exports = after; 25 | -------------------------------------------------------------------------------- /test/plugins/plugin_before.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Assemble 3 | * Created and maintained by Jon Schlinkert and Brian Woodward 4 | * 5 | * Copyright (c) 2013 Upstage. 6 | * Licensed under the MIT License (MIT). 7 | */ 8 | 9 | var runCount = 0; 10 | 11 | var before = function(params, next) { 12 | runCount++; 13 | params.assemble.options.pages.forEach(function(page) { 14 | page.data.title = 'BEFORE TITLE ' + runCount; 15 | }); 16 | next(); 17 | }; 18 | 19 | // export options 20 | before.options = { 21 | stage: 'render:pre:pages' 22 | }; 23 | 24 | module.exports = before; 25 | -------------------------------------------------------------------------------- /test/plugins/plugin_one.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Assemble 3 | * Created and maintained by Jon Schlinkert and Brian Woodward 4 | * 5 | * Copyright (c) 2013 Upstage. 6 | * Licensed under the MIT License (MIT). 7 | */ 8 | 9 | var one = function(params, next) { 10 | next(); 11 | }; 12 | 13 | module.exports = one; 14 | -------------------------------------------------------------------------------- /test/plugins/plugin_pre_page.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Assemble 3 | * Created and maintained by Jon Schlinkert and Brian Woodward 4 | * 5 | * Copyright (c) 2013 Upstage. 6 | * Licensed under the MIT License (MIT). 7 | */ 8 | 9 | var plugin = function(params, next) { 10 | params.context.page.page = 'W00T!!!'; 11 | next(); 12 | }; 13 | 14 | // export options 15 | plugin.options = { 16 | stage: 'render:pre:page' 17 | }; 18 | 19 | module.exports = plugin; 20 | -------------------------------------------------------------------------------- /test/plugins/untitled.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Adds "Untitled" to any page that doesn't have a title in the page context. 3 | * Use `page.title` in your templates. 4 | * @author: https://github.com/adjohnson916, 5 | * https://github.com/assemble/assemble/pull/325#issuecomment-25510116 6 | * @param {[type]} params [description] 7 | * @param {Function} callback [description] 8 | * @return {[type]} [description] 9 | */ 10 | 11 | var _ = require('lodash'); 12 | 13 | var untitled = function(params, callback) { 14 | var context = params.context; 15 | context.page.data = context.page.data || {}; 16 | context.page.data.title = context.page.data.title || 'Untitled'; 17 | _.extend(context.page, context.page.data); 18 | _.extend(context, context.page.data); 19 | callback(); 20 | }; 21 | 22 | module.exports = untitled; 23 | -------------------------------------------------------------------------------- /test/plugins_test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Assemble 3 | * 4 | * Copyright (c) 2014, Jon Schlinkert, Brian Woodward, contributors. 5 | * Licensed under the MIT License (MIT). 6 | */ 7 | 8 | var grunt = require('grunt'); 9 | var assemble = require('../lib/assemble'); 10 | var expect = require('chai').expect; 11 | 12 | describe('plugins', function() { 13 | 14 | describe('core', function() { 15 | it('should load plugins from glob', function() { 16 | var plugins = assemble.plugins.resolve(['./test/plugins/*one.js']); 17 | expect(plugins.length).to.equal(1); 18 | expect(plugins[0]).to.be.a('function'); 19 | }); 20 | 21 | xit('should directly load a function', function() { 22 | var plugin = function() {}; 23 | var plugins = assemble.plugins.resolve([plugin]); 24 | expect(plugins.length).to.equal(1); 25 | expect(plugins[0]).to.be.a('function'); 26 | }); 27 | 28 | it('should load plugins from node_modules', function() { 29 | // mock a npm module as plugins 30 | var plugins = assemble.plugins.resolve(['gray-matter']); 31 | expect(plugins.length).to.equal(1); 32 | }); 33 | }); 34 | 35 | describe('examples: ', function() { 36 | describe('before :', function() { 37 | it('should run once and first', function() { 38 | var contents = grunt.file.read('./test/actual/plugin_before.html'); 39 | expect(contents.trim()).to.equal('BEFORE TITLE 1'); 40 | }); 41 | }); 42 | 43 | describe('after :', function() { 44 | it('should run once and last', function() { 45 | var contents = grunt.file.read('./test/actual/plugin_after.html'); 46 | expect(contents).to.equal('AFTER OVERWRITE 1'); 47 | }); 48 | }); 49 | }); 50 | 51 | }); 52 | 53 | -------------------------------------------------------------------------------- /test/yfm_test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Assemble 3 | * 4 | * Copyright (c) 2014, Jon Schlinkert, Brian Woodward, contributors. 5 | * Licensed under the MIT License (MIT). 6 | */ 7 | 8 | var matter = require('gray-matter'); 9 | var expect = require('chai').expect; 10 | 11 | describe('Reading From Files', function() { 12 | 13 | var simpleExpected = { 14 | data: { 15 | foo: 'bar' 16 | } 17 | }; 18 | 19 | var complexExpected = { 20 | original: '---\nfoo: bar\nversion: 2\ncategories:\n- pages\ntags:\n- tests\n- examples\n- complex\n---\n\n
This is an alert
\n', 21 | content: '\n\n
This is an alert
\n', 22 | data: { 23 | 'foo': 'bar', 24 | 'version': 2, 25 | 'categories': [ 26 | 'pages' 27 | ], 28 | 'tags': [ 29 | 'tests', 30 | 'examples', 31 | 'complex' 32 | ] 33 | } 34 | }; 35 | 36 | it('yaml file starts and ends with --- has content', function(done) { 37 | var page = matter.read('./test/fixtures/mocha/yfm.hbs'); 38 | expect(simpleExpected.data).to.deep.equal(page.data); 39 | done(); 40 | }); 41 | 42 | it('hbs file with complex yaml data and content', function(done) { 43 | var page = matter.read('./test/fixtures/mocha/complex.hbs'); 44 | expect(complexExpected).to.deep.equal(page); 45 | done(); 46 | }); 47 | 48 | }); 49 | 50 | describe('Reading From Strings', function() { 51 | var simple1 = '---\nfoo: bar\n'; 52 | var simple2 = '---\nfoo: bar\n---'; 53 | var simple3 = '---\nfoo: bar\n---\n\n
This is an alert
\n'; 54 | 55 | var simpleExpected = { 56 | data: { 57 | foo: 'bar' 58 | } 59 | }; 60 | 61 | var complex = '---\nfoo: bar\nversion: 2\n---\n\n
This is an alert
\n'; 62 | 63 | var complexExpected = { 64 | original: '---\nfoo: bar\nversion: 2\n---\n\n
This is an alert
\n', 65 | content: '\n\n
This is an alert
\n', 66 | data: { 67 | 'foo': 'bar', 68 | 'version': 2 69 | } 70 | }; 71 | 72 | it('yaml string starts with --- no content', function(done) { 73 | var page = matter(simple1); 74 | expect({}).to.deep.equal(page.data); 75 | done(); 76 | }); 77 | 78 | it('yaml string starts and ends with --- no content', function(done) { 79 | var page = matter(simple2); 80 | expect(simpleExpected.data).to.deep.equal(page.data); 81 | done(); 82 | }); 83 | 84 | it('yaml string starts and ends with --- has content', function(done) { 85 | var page = matter(simple3); 86 | expect(simpleExpected.data).to.deep.equal(page.data); 87 | done(); 88 | }); 89 | 90 | it('hbs string with complex yaml data and content', function(done) { 91 | var page = matter(complex); 92 | expect(complexExpected).to.deep.equal(page); 93 | done(); 94 | }); 95 | 96 | }); 97 | --------------------------------------------------------------------------------