├── fixtures
├── a.txt
├── b.txt
├── c.txt
├── a.hbs
├── b.hbs
├── c.hbs
├── a.tmpl
├── b.tmpl
└── c.tmpl
├── .gitattributes
├── .travis.yml
├── .editorconfig
├── .gitignore
├── gulpfile.js
├── utils.js
├── LICENSE
├── examples
├── app.js
└── collection.js
├── .verb.md
├── package.json
├── .eslintrc.json
├── index.js
├── README.md
└── test.js
/fixtures/a.txt:
--------------------------------------------------------------------------------
1 | This is AAA
--------------------------------------------------------------------------------
/fixtures/b.txt:
--------------------------------------------------------------------------------
1 | This is BBB
--------------------------------------------------------------------------------
/fixtures/c.txt:
--------------------------------------------------------------------------------
1 | This is CCC
--------------------------------------------------------------------------------
/fixtures/a.hbs:
--------------------------------------------------------------------------------
1 | ---
2 | title: AAA
3 | ---
4 |
{{title}}
5 | {{name}}
--------------------------------------------------------------------------------
/fixtures/b.hbs:
--------------------------------------------------------------------------------
1 | ---
2 | title: BBB
3 | ---
4 | {{title}}
5 | {{name}}
--------------------------------------------------------------------------------
/fixtures/c.hbs:
--------------------------------------------------------------------------------
1 | ---
2 | title: CCC
3 | ---
4 | {{title}}
5 | {{name}}
--------------------------------------------------------------------------------
/fixtures/a.tmpl:
--------------------------------------------------------------------------------
1 | ---
2 | title: AAA
3 | ---
4 | <%= title %>
5 | <%= name %>
--------------------------------------------------------------------------------
/fixtures/b.tmpl:
--------------------------------------------------------------------------------
1 | ---
2 | title: BBB
3 | ---
4 | <%= title %>
5 | <%= name %>
--------------------------------------------------------------------------------
/fixtures/c.tmpl:
--------------------------------------------------------------------------------
1 | ---
2 | title: BBB
3 | ---
4 | <%= title %>
5 | <%= name %>
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Enforce Unix newlines
2 | * text eol=lf
3 |
4 | # binaries
5 | *.ai binary
6 | *.psd binary
7 | *.jpg binary
8 | *.gif binary
9 | *.png binary
10 | *.jpeg binary
11 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 | os:
3 | - linux
4 | - osx
5 | language: node_js
6 | node_js:
7 | - node
8 | - '6'
9 | - '4'
10 | - '0.12'
11 | - '0.10'
12 | matrix:
13 | allow_failures:
14 | - node_js: '4'
15 | - node_js: '0.12'
16 | - node_js: '0.10'
17 |
--------------------------------------------------------------------------------
/.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
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var gulp = require('gulp');
4 | var mocha = require('gulp-mocha');
5 | var istanbul = require('gulp-istanbul');
6 | var eslint = require('gulp-eslint');
7 |
8 | gulp.task('coverage', function() {
9 | return gulp.src(['index.js', 'utils.js'])
10 | .pipe(istanbul({includeUntested: true}))
11 | .pipe(istanbul.hookRequire());
12 | });
13 |
14 | gulp.task('mocha', ['coverage'], function() {
15 | return gulp.src('test.js')
16 | .pipe(mocha())
17 | .pipe(istanbul.writeReports({
18 | reporters: ['html', 'text', 'text-summary'],
19 | reportOpts: {dir: 'coverage', file: 'summary.txt'}
20 | }));
21 | });
22 |
23 | gulp.task('eslint', function() {
24 | return gulp.src('*.js')
25 | .pipe(eslint())
26 | .pipe(eslint.format());
27 | });
28 |
29 | gulp.task('default', ['mocha', 'eslint']);
30 |
--------------------------------------------------------------------------------
/utils.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var utils = require('lazy-cache')(require);
4 |
5 | /**
6 | * Lazily required module dependencies
7 | */
8 |
9 | var fn = require;
10 | require = utils;
11 | require('extend-shallow', 'extend');
12 | require('file-contents', 'contents');
13 | require('is-registered');
14 | require('is-valid-glob');
15 | require('is-valid-instance');
16 | require('isobject', 'isObject');
17 | require('load-templates', 'Loader');
18 | require = fn;
19 |
20 | /**
21 | * Return true if app is a valid instance
22 | */
23 |
24 | utils.isValid = function(app) {
25 | if (!utils.isValidInstance(app)) {
26 | return false;
27 | }
28 | if (utils.isRegistered(app, 'assemble-loader')) {
29 | return false;
30 | }
31 | return true;
32 | };
33 |
34 | /**
35 | * Return true if obj is a View instance
36 | */
37 |
38 | utils.isView = function(obj) {
39 | return utils.isObject(obj) && (obj.path || obj.contents || obj.isView || obj.isItem);
40 | };
41 |
42 | /**
43 | * Expose utils
44 | */
45 |
46 | module.exports = utils;
47 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015-2017, Jon Schlinkert
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/examples/app.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs');
2 | var path = require('path');
3 | var matter = require('parser-front-matter');
4 | var templates = require('templates');
5 | var loader = require('..');
6 |
7 | var app = templates()
8 | .use(loader())
9 |
10 | app.engine('tmpl', require('engine-base'));
11 | app.engine('hbs', require('engine-handlebars'));
12 |
13 | app.renameKey(function(key) {
14 | return path.basename(key);
15 | });
16 |
17 | app.onLoad(/\.(hbs|tmpl)$/, function(view, next) {
18 | matter.parse(view, next);
19 | });
20 |
21 |
22 | var posts = app
23 | .create('posts')
24 | .load(path.join(__dirname, '../fixtures/*.hbs'));
25 |
26 |
27 | var pages = app
28 | .create('pages')
29 | .load(path.join(__dirname, '../fixtures/*.tmpl'));
30 |
31 | app.posts.getView('a.hbs')
32 | .set('data.title', 'A')
33 | .set('data.name', 'Halle')
34 | .render(function(err, res) {
35 | if (err) return console.log(err.stack);
36 | console.log(res.content)
37 | });
38 |
39 | app.posts.getView('b.hbs')
40 | .set('data.name', 'Brooke')
41 | .render(function(err, res) {
42 | if (err) return console.log(err.stack);
43 | console.log(res.content)
44 | });
45 |
46 | app.pages.getView('a.tmpl')
47 | .set('data.name', 'Brian')
48 | .render(function(err, res) {
49 | if (err) return console.log(err.stack);
50 | console.log(res.content)
51 | });
52 |
--------------------------------------------------------------------------------
/examples/collection.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs');
2 | var path = require('path');
3 | var matter = require('parser-front-matter');
4 | var templates = require('templates');
5 | var loader = require('..');
6 |
7 | var app = templates();
8 |
9 | app.engine('tmpl', require('engine-base'));
10 | app.engine('hbs', require('engine-handlebars'));
11 |
12 | app.renameKey(function (key) {
13 | return path.basename(key);
14 | });
15 |
16 | app.onLoad(/\.(hbs|tmpl)$/, function (view, next) {
17 | matter.parse(view, next);
18 | });
19 |
20 | var posts = app
21 | .create('posts')
22 | .use(loader(path.join(__dirname, '../fixtures/*.hbs')))
23 | // .load('fixtures/*.hbs');
24 |
25 | var pages = app
26 | .create('pages')
27 | .use(loader())
28 | .load('fixtures/*.tmpl');
29 |
30 |
31 | app.posts.getView('a.hbs')
32 | .set('data.title', 'A')
33 | .set('data.name', 'Halle')
34 | .render(function (err, res) {
35 | if (err) return console.log(err.stack);
36 | console.log(res.content)
37 | });
38 |
39 | app.posts.getView('b.hbs')
40 | .set('data.name', 'Brooke')
41 | .render(function (err, res) {
42 | if (err) return console.log(err.stack);
43 | console.log(res.content)
44 | });
45 |
46 | app.pages.getView('a.tmpl')
47 | .set('data.name', 'Brian')
48 | .render(function (err, res) {
49 | if (err) return console.log(err.stack);
50 | console.log(res.content)
51 | });
52 |
--------------------------------------------------------------------------------
/.verb.md:
--------------------------------------------------------------------------------
1 | ## Usage
2 |
3 | ```js
4 | var assemble = require('assemble');
5 | var loader = require('{%= name %}');
6 | var app = assemble()
7 | app.use(loader());
8 |
9 | app.create('pages', {cwd: 'src/pages'});
10 | app.create('partials', {cwd: 'src/partials'});
11 |
12 | // you can now load globs of templates onto any collection
13 | app.pages('*.hbs');
14 | app.partials('*.hbs');
15 | ```
16 |
17 |
18 | ## API
19 |
20 | ```js
21 | var assemble = require('assemble');
22 | var loader = require('{%= name %}');
23 | var app = assemble()
24 |
25 | // use the plugin
26 | app.use(loader());
27 | ```
28 |
29 | Optionally pass glob patterns to the plugin:
30 |
31 | ```js
32 | var app = assemble();
33 | // this can only be done once when the plugin is registered
34 | app.use(loader('foo/*.hbs'));
35 |
36 | // you can use the `.loadViews()` method any number of times
37 | app.create('pages')
38 | .use(loader('foo/*.hbs'))
39 | .loadViews('bar/*.hbs')
40 | .loadViews('baz/*.hbs')
41 | .loadViews('qux/*.hbs');
42 | ```
43 |
44 | ## Collections
45 |
46 | **All collections**
47 |
48 | When the plugin is added to the `app` instance (as in the previous example), a `.load` method will also be added to every collection created.
49 |
50 | ```js
51 | var app = assemble()
52 | .use(loader());
53 |
54 | // cache views on `app.views.posts`
55 | app.create('posts')
56 | .load('content/*.md');
57 |
58 | // cache views on `app.views.docs`
59 | app.create('docs')
60 | .load('docs/*.md');
61 | ```
62 |
63 | **Specific collections**
64 |
65 | If you only want to add the loader to a specific collection, you can pass the plugin to the `.use` method on the collection.
66 |
67 | ```js
68 | var app = assemble();
69 |
70 | // `create` returns the collection instance
71 | app.create('posts')
72 | .use(loader())
73 | .load('content/*.md');
74 |
75 | // this works too, since `create` adds methods to `app`
76 | // for the collection
77 | app.posts
78 | .load('*.hbs')
79 | .load('*.txt');
80 | ```
81 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "assemble-loader",
3 | "description": "Assemble plugin (^0.6.0) for loading globs of views onto custom view collections. Also works with verb or other Templates.js based applications.",
4 | "version": "1.0.5",
5 | "homepage": "https://github.com/assemble/assemble-loader",
6 | "author": "Jon Schlinkert (https://github.com/jonschlinkert)",
7 | "repository": "assemble/assemble-loader",
8 | "bugs": {
9 | "url": "https://github.com/assemble/assemble-loader/issues"
10 | },
11 | "license": "MIT",
12 | "files": [
13 | "index.js",
14 | "utils.js"
15 | ],
16 | "main": "index.js",
17 | "engines": {
18 | "node": ">=0.10.0"
19 | },
20 | "scripts": {
21 | "test": "mocha"
22 | },
23 | "dependencies": {
24 | "extend-shallow": "^2.0.1",
25 | "file-contents": "^1.0.1",
26 | "is-registered": "^0.1.5",
27 | "is-valid-glob": "^0.3.0",
28 | "is-valid-instance": "^0.2.0",
29 | "isobject": "^3.0.0",
30 | "lazy-cache": "^2.0.2",
31 | "load-templates": "^1.0.2"
32 | },
33 | "devDependencies": {
34 | "engine-base": "^0.1.2",
35 | "engine-handlebars": "^0.8.0",
36 | "gulp": "^3.9.1",
37 | "gulp-eslint": "^3.0.1",
38 | "gulp-format-md": "^0.1.11",
39 | "gulp-istanbul": "^1.1.1",
40 | "gulp-mocha": "^3.0.1",
41 | "mocha": "^3.2.0",
42 | "parser-front-matter": "^1.6.2",
43 | "should": "^11.2.0",
44 | "templates": "^1.2.4"
45 | },
46 | "keywords": [
47 | "assemble",
48 | "assembleplugin",
49 | "blog",
50 | "boilerplate",
51 | "build",
52 | "cli",
53 | "cli-app",
54 | "collection",
55 | "command-line",
56 | "create",
57 | "dev",
58 | "development",
59 | "framework",
60 | "front",
61 | "frontend",
62 | "loader",
63 | "page",
64 | "plugin",
65 | "post",
66 | "project",
67 | "projects",
68 | "scaffold",
69 | "scaffolder",
70 | "scaffolding",
71 | "site",
72 | "template",
73 | "templates",
74 | "view",
75 | "webapp",
76 | "yeoman",
77 | "yo"
78 | ],
79 | "verb": {
80 | "toc": false,
81 | "layout": "default",
82 | "tasks": [
83 | "readme"
84 | ],
85 | "plugins": [
86 | "gulp-format-md"
87 | ],
88 | "related": {
89 | "list": [
90 | "load-templates",
91 | "matched",
92 | "micromatch"
93 | ]
94 | },
95 | "reflinks": [
96 | "verb"
97 | ],
98 | "lint": {
99 | "reflinks": true
100 | }
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var path = require('path');
4 | var utils = require('./utils');
5 |
6 | function loader(patterns, config) {
7 | if (utils.isObject(patterns)) {
8 | config = patterns;
9 | patterns = undefined;
10 | }
11 |
12 | return function plugin(app) {
13 | if (utils.isRegistered(this, 'assemble-loader')) return;
14 |
15 | // register the plugin on an "app"
16 | if (utils.isValidInstance(this)) {
17 | appLoader(this, config);
18 |
19 | // if patterns are passed to the plugin, load them now
20 | if (utils.isValidGlob(patterns)) {
21 | this.load(patterns);
22 | }
23 | }
24 |
25 | // register the plugin on a "collection"
26 | if (utils.isValidInstance(this, ['collection'])) {
27 | collectionLoader(this, config);
28 |
29 | // if patterns are passed to the plugin, load them now
30 | if (utils.isValidGlob(patterns)) {
31 | this.load(patterns);
32 | }
33 | }
34 |
35 | return plugin;
36 | };
37 | }
38 |
39 | /**
40 | * Adds a `.load` method to the "app" instance for loading views that
41 | * that don't belong to any particular collection. It just returns the
42 | * object of views instead of caching them.
43 | *
44 | * ```js
45 | * var loader = require('assemble-loader');
46 | * var assemble = require('assemble');
47 | * var app = assemble();
48 | * app.use(loader());
49 | *
50 | * var views = app.load('foo/*.hbs');
51 | * console.log(views);
52 | * ```
53 | * @param {Object} `app` application instance (e.g. assemble, verb, etc)
54 | * @param {Object} `config` Settings to use when registering the plugin
55 | * @return {Object} Returns an object of _un-cached_ views, from a glob, string, array of strings, or objects.
56 | * @api public
57 | */
58 |
59 | function appLoader(app, config) {
60 | app.define('load', load('view', config));
61 | var fn = app.view;
62 |
63 | app.define('view', function() {
64 | var view = fn.apply(this, arguments);
65 | utils.contents.sync(view);
66 | return view;
67 | });
68 | }
69 |
70 | /**
71 | * Collection loaders
72 | */
73 |
74 | function collectionLoader(collection, config) {
75 | collection._addView = collection.addView.bind(collection);
76 | var fn = collection.view;
77 |
78 | collection.define('view', function() {
79 | var view = fn.apply(this, arguments);
80 | utils.contents.sync(view);
81 | return view;
82 | });
83 |
84 | /**
85 | * Patches the `.addViews` method to support glob patterns.
86 | *
87 | * @param {Object|String} `key` View name or object.
88 | * @param {Object} `value` View options, when key is a string.
89 | * @return {Object}
90 | */
91 |
92 | collection.define('addView', function(key, value) {
93 | return this._addView.apply(this, arguments);
94 | });
95 |
96 | /**
97 | * Patches the `.addViews` method to support glob patterns.
98 | *
99 | * @param {Object|String} `key` View name or object.
100 | * @param {Object} `value` View options, when key is a string.
101 | * @return {Object}
102 | */
103 |
104 | collection.define('addViews', function(key, value) {
105 | this.load.apply(this, arguments);
106 | return this;
107 | });
108 |
109 | collection.define('loadView', function(filepath, options) {
110 | this.load.apply(this, arguments);
111 | return this;
112 | });
113 |
114 | collection.define('loadViews', function(patterns, options) {
115 | this.load.apply(this, arguments);
116 | return this;
117 | });
118 |
119 | collection.define('load', function() {
120 | return load('_addView', config).apply(this, arguments);
121 | });
122 | }
123 |
124 | /**
125 | * Create options from:
126 | * + `config` - settings passed when registering plugin
127 | * + `app.options` - options set on the instance
128 | * + `options` - options passed when calling a loader method
129 | */
130 |
131 | function mergeOptions(app, config, options) {
132 | if (utils.isView(options)) options = {};
133 | var opts = utils.extend({}, config, app.options, options);
134 | opts.cwd = path.resolve(opts.cwd || app.cwd || process.cwd());
135 | return opts;
136 | }
137 |
138 | /**
139 | * Create a `Loader` instance with a `loaderfn` bound
140 | * to the app or collection instance.
141 | */
142 |
143 | function createLoader(options, fn) {
144 | var loader = new utils.Loader(options);
145 | return function() {
146 | if (!this.isApp) loader.cache = this.views;
147 | loader.options.loaderFn = fn.bind(this);
148 | loader.load.apply(loader, arguments);
149 | return loader.cache;
150 | };
151 | }
152 |
153 | /**
154 | * Create a function for loading views using the given
155 | * `method` on the collection or app.
156 | */
157 |
158 | function load(method, config) {
159 | return function(patterns, options) {
160 | var opts = mergeOptions(this, config, options);
161 | var loader = createLoader(opts, this[method]);
162 | return loader.apply(this, arguments);
163 | };
164 | }
165 |
166 | /**
167 | * Expose `loader`
168 | */
169 |
170 | module.exports = loader;
171 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # assemble-loader [](https://www.npmjs.com/package/assemble-loader) [](https://npmjs.org/package/assemble-loader) [](https://npmjs.org/package/assemble-loader) [](https://travis-ci.org/assemble/assemble-loader)
2 |
3 | > Assemble plugin (^0.6.0) for loading globs of views onto custom view collections. Also works with verb or other Templates.js based applications.
4 |
5 | ## Install
6 |
7 | Install with [npm](https://www.npmjs.com/):
8 |
9 | ```sh
10 | $ npm install --save assemble-loader
11 | ```
12 |
13 | ## Usage
14 |
15 | ```js
16 | var assemble = require('assemble');
17 | var loader = require('assemble-loader');
18 | var app = assemble()
19 | app.use(loader());
20 |
21 | app.create('pages', {cwd: 'src/pages'});
22 | app.create('partials', {cwd: 'src/partials'});
23 |
24 | // you can now load globs of templates onto any collection
25 | app.pages('*.hbs');
26 | app.partials('*.hbs');
27 | ```
28 |
29 | ## API
30 |
31 | ```js
32 | var assemble = require('assemble');
33 | var loader = require('assemble-loader');
34 | var app = assemble()
35 |
36 | // use the plugin
37 | app.use(loader());
38 | ```
39 |
40 | Optionally pass glob patterns to the plugin:
41 |
42 | ```js
43 | var app = assemble();
44 | // this can only be done once when the plugin is registered
45 | app.use(loader('foo/*.hbs'));
46 |
47 | // you can use the `.loadViews()` method any number of times
48 | app.create('pages')
49 | .use(loader('foo/*.hbs'))
50 | .loadViews('bar/*.hbs')
51 | .loadViews('baz/*.hbs')
52 | .loadViews('qux/*.hbs');
53 | ```
54 |
55 | ## Collections
56 |
57 | **All collections**
58 |
59 | When the plugin is added to the `app` instance (as in the previous example), a `.load` method will also be added to every collection created.
60 |
61 | ```js
62 | var app = assemble()
63 | .use(loader());
64 |
65 | // cache views on `app.views.posts`
66 | app.create('posts')
67 | .load('content/*.md');
68 |
69 | // cache views on `app.views.docs`
70 | app.create('docs')
71 | .load('docs/*.md');
72 | ```
73 |
74 | **Specific collections**
75 |
76 | If you only want to add the loader to a specific collection, you can pass the plugin to the `.use` method on the collection.
77 |
78 | ```js
79 | var app = assemble();
80 |
81 | // `create` returns the collection instance
82 | app.create('posts')
83 | .use(loader())
84 | .load('content/*.md');
85 |
86 | // this works too, since `create` adds methods to `app`
87 | // for the collection
88 | app.posts
89 | .load('*.hbs')
90 | .load('*.txt');
91 | ```
92 |
93 | ## About
94 |
95 | ### Related projects
96 |
97 | * [load-templates](https://www.npmjs.com/package/load-templates): Load templates/views using globs, file paths, objects, arrays, or key-value pairs. | [homepage](https://github.com/jonschlinkert/load-templates "Load templates/views using globs, file paths, objects, arrays, or key-value pairs.")
98 | * [matched](https://www.npmjs.com/package/matched): Adds array support to node-glob, sync and async. Also supports tilde expansion (user home) and… [more](https://github.com/jonschlinkert/matched) | [homepage](https://github.com/jonschlinkert/matched "Adds array support to node-glob, sync and async. Also supports tilde expansion (user home) and resolving to global npm modules.")
99 | * [micromatch](https://www.npmjs.com/package/micromatch): Glob matching for javascript/node.js. A drop-in replacement and faster alternative to minimatch and multimatch. | [homepage](https://github.com/jonschlinkert/micromatch "Glob matching for javascript/node.js. A drop-in replacement and faster alternative to minimatch and multimatch.")
100 |
101 | ### Contributing
102 |
103 | Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new).
104 |
105 | ### Building docs
106 |
107 | _(This project's readme.md is generated by [verb](https://github.com/verbose/verb-generate-readme), please don't edit the readme directly. Any changes to the readme must be made in the [.verb.md](.verb.md) readme template.)_
108 |
109 | To generate the readme, run the following command:
110 |
111 | ```sh
112 | $ npm install -g verbose/verb#dev verb-generate-readme && verb
113 | ```
114 |
115 | ### Running tests
116 |
117 | Running and reviewing unit tests is a great way to get familiarized with a library and its API. You can install dependencies and run tests with the following command:
118 |
119 | ```sh
120 | $ npm install && npm test
121 | ```
122 |
123 | ### Author
124 |
125 | **Jon Schlinkert**
126 |
127 | * [github/jonschlinkert](https://github.com/jonschlinkert)
128 | * [twitter/jonschlinkert](https://twitter.com/jonschlinkert)
129 |
130 | ### License
131 |
132 | Copyright © 2017, [Jon Schlinkert](https://github.com/jonschlinkert).
133 | MIT
134 |
135 | ***
136 |
137 | _This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.4.2, on February 20, 2017._
--------------------------------------------------------------------------------
/test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | require('mocha');
4 | require('should');
5 | var path = require('path');
6 | var assert = require('assert');
7 | var App = require('templates');
8 | var Views = App.Views;
9 | var loader = require('./');
10 | var collection;
11 | var app;
12 |
13 | function res(fp) {
14 | return path.resolve(fp);
15 | }
16 |
17 | describe('loader', function() {
18 | describe('app.load()', function() {
19 | beforeEach(function() {
20 | app = new App();
21 | });
22 |
23 | it('should return a function:', function() {
24 | assert.equal(typeof loader(), 'function');
25 | });
26 |
27 | it('should decorate `.load` onto the app instance', function() {
28 | app.use(loader());
29 | var view = app.view({path: 'index.js'});
30 |
31 | var collection = app.load('*.js', {cwd: __dirname});
32 | assert(collection.hasOwnProperty(res('index.js')));
33 | });
34 |
35 | it('should take options on loader', function() {
36 | app.use(loader({cwd: 'fixtures'}));
37 | var collection = app.load('*.txt');
38 | assert(collection.hasOwnProperty(res('fixtures/a.txt')));
39 | });
40 |
41 | it('should take options on load', function() {
42 | app.use(loader());
43 | var collection = app.load('*.txt', {cwd: 'fixtures'});
44 | assert(collection.hasOwnProperty(res('fixtures/a.txt')));
45 | });
46 |
47 | it('should use the renameKey options on load', function() {
48 | app.use(loader());
49 | var collection = app.load('*.txt', {
50 | cwd: 'fixtures',
51 | renameKey: function(file) {
52 | return file.path;
53 | }
54 | });
55 | assert(collection.hasOwnProperty(res('fixtures/a.txt')));
56 | });
57 | });
58 |
59 | describe('collection.loadViews()', function() {
60 | beforeEach(function() {
61 | app = new App();
62 | app.on('error', function(err) {
63 | console.log(err);
64 | process.exit(1);
65 | });
66 | });
67 |
68 | it('should decorate `loadViews` onto collections', function() {
69 | app.use(loader());
70 | app.create('pages');
71 |
72 | app.pages.loadViews('*.js');
73 | assert(app.views.pages.hasOwnProperty(res('index.js')));
74 | });
75 |
76 | it('should use a cwd defined on the collection options:', function() {
77 | app.use(loader());
78 | app.create('pages')
79 | .option('cwd', 'fixtures')
80 | .loadViews('*.tmpl');
81 |
82 | assert(app.views.pages.hasOwnProperty(res('fixtures/a.tmpl')));
83 | });
84 |
85 | it('should use a cwd defined on create:', function() {
86 | app.use(loader());
87 | app.create('pages', {cwd: 'fixtures'})
88 | .loadViews('*.tmpl');
89 |
90 | assert(app.views.pages.hasOwnProperty(res('fixtures/a.tmpl')));
91 | });
92 |
93 | it('should use a cwd defined on create with collection loader', function() {
94 | app.use(loader());
95 | app.create('pages', {cwd: 'fixtures'});
96 | app.pages('*.tmpl');
97 |
98 | assert(app.views.pages.hasOwnProperty(res('fixtures/a.tmpl')));
99 | });
100 | });
101 |
102 | describe('collection loader function', function() {
103 | beforeEach(function() {
104 | app = new App();
105 | });
106 |
107 | it('should work as a collection plugin:', function() {
108 | app.create('pages')
109 | .use(loader('*.json'));
110 | assert(app.views.pages.hasOwnProperty(res('package.json')));
111 | });
112 |
113 | it('should decorate `load` on the collection:', function() {
114 | app.create('files')
115 | .use(loader());
116 |
117 | app.files.load('*.json');
118 | assert(app.views.files.hasOwnProperty(res('package.json')));
119 | });
120 |
121 | it('should be chainable:', function() {
122 | app.create('pages')
123 | .use(loader())
124 | .loadViews('*.json')
125 | .loadViews('*.js');
126 |
127 | assert(app.views.pages.hasOwnProperty(res('index.js')));
128 | assert(app.views.pages.hasOwnProperty(res('package.json')));
129 | });
130 |
131 | it('should add the `loadViews` method to a collection:', function() {
132 | app.create('pages')
133 | .use(loader());
134 |
135 | app.pages.loadViews('fixtures/*.txt');
136 | assert(app.views.pages.hasOwnProperty(res('fixtures/a.txt')));
137 | });
138 |
139 | it('collection.loadViews should be chainable', function() {
140 | app.create('pages')
141 | .use(loader())
142 | .loadViews('*.json')
143 | .loadViews('*.js');
144 |
145 | assert(app.views.pages.hasOwnProperty(res('index.js')));
146 | assert(app.views.pages.hasOwnProperty(res('package.json')));
147 | });
148 |
149 | it('should patch `addViews` to support globs:', function() {
150 | app.create('pages')
151 | .use(loader());
152 |
153 | app.pages.addViews('fixtures/*.txt');
154 | assert(app.views.pages.hasOwnProperty(res('fixtures/a.txt')));
155 | });
156 |
157 | it('should load globs with app collection methods:', function() {
158 | app.create('pages')
159 | .use(loader());
160 |
161 | app.pages('fixtures/*.txt');
162 | assert(app.views.pages.hasOwnProperty(res('fixtures/a.txt')));
163 | });
164 |
165 | it('should load glob arrays with app collection methods:', function() {
166 | app.create('pages')
167 | .use(loader());
168 |
169 | app.pages(['fixtures/*.txt']);
170 | assert(app.views.pages.hasOwnProperty(res('fixtures/a.txt')));
171 | });
172 |
173 | it('should not change native behavior with addView:', function() {
174 | app.create('pages')
175 | .use(loader());
176 |
177 | app.page('a', {content: '...'});
178 | app.page('b', {content: '...'});
179 | app.page('c', {content: '...'});
180 |
181 | assert(app.views.pages.hasOwnProperty('a'));
182 | assert(app.views.pages.hasOwnProperty('b'));
183 | assert(app.views.pages.hasOwnProperty('c'));
184 | });
185 |
186 | it('should maintain backwards compatibility with addViews:', function() {
187 | app.create('pages')
188 | .use(loader());
189 |
190 | app.pages({
191 | a: {contents: '...'},
192 | b: {contents: '...'},
193 | c: {contents: '...'}
194 | });
195 |
196 | assert(app.views.pages.hasOwnProperty('a'));
197 | assert(app.views.pages.hasOwnProperty('b'));
198 | assert(app.views.pages.hasOwnProperty('c'));
199 | });
200 |
201 | it('should get the contents for a view:', function() {
202 | app.create('pages')
203 | .use(loader());
204 |
205 | app.pages(['fixtures/*.txt']);
206 | var page = app.pages.getView('fixtures/a.txt');
207 | assert.equal(page.contents.toString(), 'This is AAA');
208 | });
209 |
210 | it('should take a custom renameKey function on the options:', function() {
211 | app.create('pages')
212 | .use(loader());
213 |
214 | app.pages.option('renameKey', function(key, file) {
215 | return path.basename(key);
216 | });
217 |
218 | app.pages.loadViews('fixtures/*.txt');
219 | assert(app.views.pages.hasOwnProperty('a.txt'));
220 | });
221 |
222 | it('should keep collection options separate:', function() {
223 | app.use(loader());
224 | app.create('pages');
225 | app.create('partials', {viewType: 'partial'});
226 | app.create('layouts', {viewType: 'layout'});
227 |
228 | app.on('page', function(view, type) {
229 | assert.equal(view.options.viewType.length, 1);
230 | assert.equal(view.options.viewType[0], 'renderable');
231 | });
232 | app.on('layout', function(view, type) {
233 | assert.equal(view.options.viewType.length, 1);
234 | assert.equal(view.options.viewType[0], 'layout');
235 | });
236 | app.on('partial', function(view, type) {
237 | assert.equal(view.options.viewType.length, 1);
238 | assert.equal(view.options.viewType[0], 'partial');
239 | });
240 |
241 | app.pages.option('renameKey', function(key, file) {
242 | return path.basename(key);
243 | });
244 | app.layouts.option('renameKey', function(key, file) {
245 | return path.basename(key);
246 | });
247 | app.partials.option('renameKey', function(key, file) {
248 | return path.basename(key);
249 | });
250 |
251 | app.pages('fixtures/*.txt');
252 | app.layouts('fixtures/*.hbs');
253 | app.partials('fixtures/*.tmpl');
254 |
255 | assert(app.views.pages.hasOwnProperty('a.txt'));
256 | });
257 | });
258 |
259 | describe('loadView', function() {
260 | beforeEach(function() {
261 | collection = new Views({
262 | renameKey: function(key) {
263 | return path.basename(key);
264 | }
265 | });
266 | collection.use(loader());
267 | });
268 |
269 | it('should load a file and add it to `views`:', function() {
270 | collection.loadView('fixtures/a.tmpl');
271 | collection.views.should.have.property('a.tmpl');
272 | });
273 |
274 | it('should use a cwd defined on the collection:', function() {
275 | collection.option('cwd', 'fixtures');
276 | collection.loadView('a.tmpl');
277 | collection.views.should.have.property('a.tmpl');
278 | });
279 |
280 | it('should handle files with no extension:', function() {
281 | collection.loadView('LICENSE');
282 | collection.views.should.have.property('LICENSE');
283 | });
284 | });
285 |
286 | describe('loadViews', function() {
287 | beforeEach(function() {
288 | collection = new Views({
289 | renameKey: function(key) {
290 | return path.basename(key);
291 | }
292 | });
293 | collection.use(loader());
294 | });
295 |
296 | it('should load a view from a filepath:', function() {
297 | collection.loadViews('fixtures/a.tmpl');
298 | collection.views.should.have.property('a.tmpl');
299 | });
300 |
301 | it('should load views from a glob:', function() {
302 | collection.loadViews('fixtures/*.tmpl');
303 | collection.views.should.have.property('a.tmpl');
304 | });
305 |
306 | it('should load views an array globs:', function() {
307 | collection.loadViews(['fixtures/*.tmpl']);
308 | collection.views.should.have.property('a.tmpl');
309 | });
310 |
311 | it('should use a cwd defined on the collection:', function() {
312 | collection.option('cwd', 'fixtures');
313 | collection.loadViews('*.tmpl');
314 | collection.views.should.have.property('a.tmpl');
315 | });
316 |
317 | it('should handle files with no extension:', function() {
318 | collection.loadViews('LICENSE');
319 | collection.views.should.have.property('LICENSE');
320 | });
321 | });
322 | });
323 |
--------------------------------------------------------------------------------