├── .editorconfig
├── .eslintrc.json
├── .gitattributes
├── .gitignore
├── .travis.yml
├── .verb.md
├── LICENSE
├── README.md
├── docs
└── toc.md
├── index.js
├── lib
├── helpers
│ ├── array.js
│ ├── code.js
│ ├── collection.js
│ ├── conditional.js
│ ├── fs.js
│ ├── html.js
│ ├── index.js
│ ├── math.js
│ ├── object.js
│ ├── path.js
│ └── string.js
├── iterator.js
└── utils.js
├── package.json
├── recipes
└── tips-and-tricks.md
├── test
├── array.js
├── code.js
├── collection.js
├── conditional.js
├── fixtures
│ ├── README.md
│ ├── a.js
│ ├── a.md
│ └── b.js
├── fs.js
├── html.js
├── math.js
├── object.js
├── path.js
├── string.js
└── test.js
└── verbfile.js
/.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}/**/*.*]
12 | trim_trailing_whitespace = false
13 | insert_final_newline = false
14 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "eslint:recommended"
4 | ],
5 |
6 | "env": {
7 | "browser": false,
8 | "es6": true,
9 | "node": true,
10 | "mocha": true
11 | },
12 |
13 | "parserOptions":{
14 | "ecmaVersion": 9,
15 | "sourceType": "module",
16 | "ecmaFeatures": {
17 | "modules": true,
18 | "experimentalObjectRestSpread": true
19 | }
20 | },
21 |
22 | "globals": {
23 | "document": false,
24 | "navigator": false,
25 | "window": false
26 | },
27 |
28 | "rules": {
29 | "accessor-pairs": 2,
30 | "arrow-spacing": [2, { "before": true, "after": true }],
31 | "block-spacing": [2, "always"],
32 | "brace-style": [2, "1tbs", { "allowSingleLine": true }],
33 | "comma-dangle": [2, "never"],
34 | "comma-spacing": [2, { "before": false, "after": true }],
35 | "comma-style": [2, "last"],
36 | "constructor-super": 2,
37 | "curly": [2, "multi-line"],
38 | "dot-location": [2, "property"],
39 | "eol-last": 2,
40 | "eqeqeq": [2, "allow-null"],
41 | "generator-star-spacing": [2, { "before": true, "after": true }],
42 | "handle-callback-err": [2, "^(err|error)$" ],
43 | "indent": [2, 2, { "SwitchCase": 1 }],
44 | "key-spacing": [2, { "beforeColon": false, "afterColon": true }],
45 | "keyword-spacing": [2, { "before": true, "after": true }],
46 | "new-cap": [2, { "newIsCap": true, "capIsNew": false }],
47 | "new-parens": 2,
48 | "no-array-constructor": 2,
49 | "no-caller": 2,
50 | "no-class-assign": 2,
51 | "no-cond-assign": 2,
52 | "no-const-assign": 2,
53 | "no-control-regex": 2,
54 | "no-debugger": 2,
55 | "no-delete-var": 2,
56 | "no-dupe-args": 2,
57 | "no-dupe-class-members": 2,
58 | "no-dupe-keys": 2,
59 | "no-duplicate-case": 2,
60 | "no-empty-character-class": 2,
61 | "no-eval": 2,
62 | "no-ex-assign": 2,
63 | "no-extend-native": 2,
64 | "no-extra-bind": 2,
65 | "no-extra-boolean-cast": 2,
66 | "no-extra-parens": [2, "functions"],
67 | "no-fallthrough": 2,
68 | "no-floating-decimal": 2,
69 | "no-func-assign": 2,
70 | "no-implied-eval": 2,
71 | "no-inner-declarations": [2, "functions"],
72 | "no-invalid-regexp": 2,
73 | "no-irregular-whitespace": 2,
74 | "no-iterator": 2,
75 | "no-label-var": 2,
76 | "no-labels": 2,
77 | "no-lone-blocks": 2,
78 | "no-mixed-spaces-and-tabs": 2,
79 | "no-multi-spaces": 2,
80 | "no-multi-str": 2,
81 | "no-multiple-empty-lines": [2, { "max": 1 }],
82 | "no-native-reassign": 0,
83 | "no-negated-in-lhs": 2,
84 | "no-new": 2,
85 | "no-new-func": 2,
86 | "no-new-object": 2,
87 | "no-new-require": 2,
88 | "no-new-wrappers": 2,
89 | "no-obj-calls": 2,
90 | "no-octal": 2,
91 | "no-octal-escape": 2,
92 | "no-proto": 0,
93 | "no-redeclare": 2,
94 | "no-regex-spaces": 2,
95 | "no-return-assign": 2,
96 | "no-self-compare": 2,
97 | "no-sequences": 2,
98 | "no-shadow-restricted-names": 2,
99 | "no-spaced-func": 2,
100 | "no-sparse-arrays": 2,
101 | "no-this-before-super": 2,
102 | "no-throw-literal": 2,
103 | "no-trailing-spaces": 0,
104 | "no-undef": 2,
105 | "no-undef-init": 2,
106 | "no-unexpected-multiline": 2,
107 | "no-unneeded-ternary": [2, { "defaultAssignment": false }],
108 | "no-unreachable": 2,
109 | "no-unused-vars": [2, { "vars": "all", "args": "none" }],
110 | "no-useless-call": 0,
111 | "no-with": 2,
112 | "one-var": [0, { "initialized": "never" }],
113 | "operator-linebreak": [0, "after", { "overrides": { "?": "before", ":": "before" } }],
114 | "padded-blocks": [0, "never"],
115 | "quotes": [2, "single", "avoid-escape"],
116 | "radix": 2,
117 | "semi": [2, "always"],
118 | "semi-spacing": [2, { "before": false, "after": true }],
119 | "space-before-blocks": [2, "always"],
120 | "space-before-function-paren": [2, "never"],
121 | "space-in-parens": [2, "never"],
122 | "space-infix-ops": 2,
123 | "space-unary-ops": [2, { "words": true, "nonwords": false }],
124 | "spaced-comment": [0, "always", { "markers": ["global", "globals", "eslint", "eslint-disable", "*package", "!", ","] }],
125 | "use-isnan": 2,
126 | "valid-typeof": 2,
127 | "wrap-iife": [2, "any"],
128 | "yoda": [2, "never"]
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/.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
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.DS_Store
2 | *.DS_store
3 | *.sublime-*
4 | _gh_pages
5 | bower_components
6 | node_modules
7 | npm-debug.log
8 | actual
9 | test/actual
10 | temp
11 | tmp
12 | TODO.md
13 | vendor
14 | staging
15 | coverage
16 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 | os:
3 | - linux
4 | - osx
5 | - windows
6 | language: node_js
7 | node_js:
8 | - 'node'
9 | - '11'
10 | - '10'
11 | - '9'
12 | - '8'
13 | - '7'
14 | - '6'
15 |
--------------------------------------------------------------------------------
/.verb.md:
--------------------------------------------------------------------------------
1 | ## Usage
2 |
3 | To get all helpers:
4 |
5 | ```js
6 | const helpers = require('{%= name %}')();
7 | console.log(helpers);
8 | ```
9 |
10 | **Get a specific helper category**
11 |
12 | ```js
13 | // get only the math helpers
14 | const helpers = require('{%= name %}')('math');
15 | ```
16 |
17 | **Get multiple helper categories**
18 |
19 | ```js
20 | // get only the math helpers
21 | const helpers = require('{%= name %}')(['math', 'string']);
22 | ```
23 |
24 | ### Template-engine agnostic
25 |
26 | **Lo-Dash Example**
27 |
28 | ```js
29 | const helpers = require('{%= name %}')('array');
30 |
31 | // pass helpers on `imports`
32 | const imports = { imports: helpers };
33 |
34 | // compile a template
35 | const fn = _.template('<%= first(foo) %>', imports);
36 |
37 | // render
38 | fn({ foo: ['a', 'b', 'c'] });
39 | //=> 'a'
40 | ```
41 |
42 | ### Namespacing
43 |
44 | Handlebars and Lo-Dash both allow **dot notation** to be used for referencing helpers. I'd be happy to add examples for other engines if someone wants to do a PR.
45 |
46 | **Example**
47 |
48 | ```js
49 | <%= path.dirname("a/b/c/d.js") %>
50 | ```
51 |
52 | This can be used as a way of working around potential naming conflicts.
53 |
54 | ## Helpers
55 |
56 | _(The following **API Table of Contents** is generated by [verb][]. See the [verbfile.js](verbfile.js) for more details.)_
57 |
58 | {%= include("docs/toc.md") %}
59 |
60 | ### array
61 |
62 | {%= increaseHeadings(apidocs("lib/helpers/array.js")) %}
63 |
64 | ### code
65 |
66 | {%= increaseHeadings(apidocs("lib/helpers/code.js")) %}
67 |
68 | ### collection
69 |
70 | {%= increaseHeadings(apidocs("lib/helpers/collection.js")) %}
71 |
72 | ### conditional
73 |
74 | {%= increaseHeadings(apidocs("lib/helpers/conditional.js")) %}
75 |
76 | ### fs
77 |
78 | {%= increaseHeadings(apidocs("lib/helpers/fs.js")) %}
79 |
80 | ### html
81 |
82 | {%= increaseHeadings(apidocs("lib/helpers/html.js")) %}
83 |
84 | ### index
85 |
86 | {%= increaseHeadings(apidocs("lib/helpers/index.js")) %}
87 |
88 | ### math
89 |
90 | {%= increaseHeadings(apidocs("lib/helpers/math.js")) %}
91 |
92 | ### object
93 |
94 | {%= increaseHeadings(apidocs("lib/helpers/object.js")) %}
95 |
96 | ### path
97 |
98 | {%= increaseHeadings(apidocs("lib/helpers/path.js")) %}
99 |
100 | ### string
101 |
102 | {%= increaseHeadings(apidocs("lib/helpers/string.js")) %}
103 |
104 | ## Coverage
105 |
106 | ```
107 | {%= coverage("coverage/summary.txt") %}
108 | ```
109 |
110 | [path]: https://nodejs.org/api/path.html
111 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015-present, 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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # template-helpers [](https://www.npmjs.com/package/template-helpers) [](https://npmjs.org/package/template-helpers) [](https://npmjs.org/package/template-helpers) [](https://travis-ci.org/jonschlinkert/template-helpers)
2 |
3 | > Generic JavaScript helpers that can be used with any template engine. Handlebars, Lo-Dash, Underscore, or any engine that supports helper functions.
4 |
5 | Please consider following this project's author, [Jon Schlinkert](https://github.com/jonschlinkert), and consider starring the project to show your :heart: and support.
6 |
7 | - [Install](#install)
8 | - [Usage](#usage)
9 | * [Template-engine agnostic](#template-engine-agnostic)
10 | * [Namespacing](#namespacing)
11 | - [Helpers](#helpers)
12 | * [array](#array)
13 | * [code](#code)
14 | * [collection](#collection)
15 | * [conditional](#conditional)
16 | * [fs](#fs)
17 | * [html](#html)
18 | * [index](#index)
19 | * [math](#math)
20 | * [object](#object)
21 | * [path](#path)
22 | * [string](#string)
23 | - [Coverage](#coverage)
24 | - [About](#about)
25 |
26 | ## Install
27 |
28 | Install with [npm](https://www.npmjs.com/):
29 |
30 | ```sh
31 | $ npm install --save template-helpers
32 | ```
33 |
34 | ## Usage
35 |
36 | To get all helpers:
37 |
38 | ```js
39 | const helpers = require('template-helpers')();
40 | console.log(helpers);
41 | ```
42 |
43 | **Get a specific helper category**
44 |
45 | ```js
46 | // get only the math helpers
47 | const helpers = require('template-helpers')('math');
48 | ```
49 |
50 | **Get multiple helper categories**
51 |
52 | ```js
53 | // get only the math helpers
54 | const helpers = require('template-helpers')(['math', 'string']);
55 | ```
56 |
57 | ### Template-engine agnostic
58 |
59 | **Lo-Dash Example**
60 |
61 | ```js
62 | const helpers = require('template-helpers')('array');
63 |
64 | // pass helpers on `imports`
65 | const imports = { imports: helpers };
66 |
67 | // compile a template
68 | const fn = _.template('<%= first(foo) %>', imports);
69 |
70 | // render
71 | fn({ foo: ['a', 'b', 'c'] });
72 | //=> 'a'
73 | ```
74 |
75 | ### Namespacing
76 |
77 | Handlebars and Lo-Dash both allow **dot notation** to be used for referencing helpers. I'd be happy to add examples for other engines if someone wants to do a PR.
78 |
79 | **Example**
80 |
81 | ```js
82 | <%= path.dirname("a/b/c/d.js") %>
83 | ```
84 |
85 | This can be used as a way of working around potential naming conflicts.
86 |
87 | ## Helpers
88 |
89 | _(The following **API Table of Contents** is generated by [verb](https://github.com/verbose/verb). See the [verbfile.js](verbfile.js) for more details.)_
90 |
91 | ## Categories
92 |
93 | Currently **101 helpers** in **10 categories**:
94 |
95 | * **[array](#array)** ([code](lib/helpers/array.js) | [unit tests](test/array.js))
96 | * **[code](#code)** ([code](lib/helpers/code.js) | [unit tests](test/code.js))
97 | * **[collection](#collection)** ([code](lib/helpers/collection.js) | [unit tests](test/collection.js))
98 | * **[conditional](#conditional)** ([code](lib/helpers/conditional.js) | [unit tests](test/conditional.js))
99 | * **[fs](#fs)** ([code](lib/helpers/fs.js) | [unit tests](test/fs.js))
100 | * **[html](#html)** ([code](lib/helpers/html.js) | [unit tests](test/html.js))
101 | * **[math](#math)** ([code](lib/helpers/math.js) | [unit tests](test/math.js))
102 | * **[object](#object)** ([code](lib/helpers/object.js) | [unit tests](test/object.js))
103 | * **[path](#path)** ([code](lib/helpers/path.js) | [unit tests](test/path.js))
104 | * **[string](#string)** ([code](lib/helpers/string.js) | [unit tests](test/string.js))
105 |
106 | ## All helpers
107 |
108 | ### [array helpers](#array)
109 |
110 | Visit the: [code](lib/helpers/array.js) | [unit tests](test/array.js) | [issues](https://github.com/jonschlinkert/template-helpers/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+array+helpers))
111 |
112 | * **[isArray](#isArray)** ([code](lib/helpers/array.js#L21) | [unit tests](test/array.js#L18))
113 | * **[arrayify](#arrayify)** ([code](lib/helpers/array.js#L42) | [unit tests](test/array.js#L25))
114 | * **[first](#first)** ([code](lib/helpers/array.js#L58) | [unit tests](test/array.js#L32))
115 | * **[last](#last)** ([code](lib/helpers/array.js#L79) | [unit tests](test/array.js#L48))
116 | * **[before](#before)** ([code](lib/helpers/array.js#L102) | [unit tests](test/array.js#L61))
117 | * **[after](#after)** ([code](lib/helpers/array.js#L121) | [unit tests](test/array.js#L71))
118 | * **[each](#each)** ([code](lib/helpers/array.js#L147) | [unit tests](test/array.js#L98))
119 | * **[map](#map)** ([code](lib/helpers/array.js#L188) | [unit tests](test/array.js#L122))
120 | * **[join](#join)** ([code](lib/helpers/array.js#L218) | [unit tests](test/array.js#L82))
121 | * **[sort](#sort)** ([code](lib/helpers/array.js#L241) | [unit tests](test/array.js#L137))
122 | * **[length](#length)** ([code](lib/helpers/array.js#L272) | [unit tests](test/array.js#L162))
123 | * **[compact](#compact)** ([code](lib/helpers/array.js#L289) | [unit tests](test/array.js#L178))
124 | * **[difference](#difference)** ([code](lib/helpers/array.js#L307) | [unit tests](test/array.js#L189))
125 | * **[unique](#unique)** ([code](lib/helpers/array.js#L344) | [unit tests](test/array.js#L205))
126 | * **[union](#union)** ([code](lib/helpers/array.js#L373) | [unit tests](test/array.js#L215))
127 | * **[shuffle](#shuffle)** ([code](lib/helpers/array.js#L389) | [no tests])
128 |
129 | ### [code helpers](#code)
130 |
131 | Visit the: [code](lib/helpers/code.js) | [unit tests](test/code.js) | [issues](https://github.com/jonschlinkert/template-helpers/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+code+helpers))
132 |
133 | * **[embed](#embed)** ([code](lib/helpers/code.js#L23) | [unit tests](test/code.js#L33))
134 | * **[jsfiddle](#jsfiddle)** ([code](lib/helpers/code.js#L45) | [unit tests](test/code.js#L24))
135 |
136 | ### [collection helpers](#collection)
137 |
138 | Visit the: [code](lib/helpers/collection.js) | [unit tests](test/collection.js) | [issues](https://github.com/jonschlinkert/template-helpers/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+collection+helpers))
139 |
140 | * **[any](#any)** ([code](lib/helpers/collection.js#L17) | [unit tests](test/collection.js#L17))
141 | * **[filter](#filter)** ([code](lib/helpers/collection.js#L32) | [unit tests](test/collection.js#L34))
142 |
143 | ### [conditional helpers](#conditional)
144 |
145 | Visit the: [code](lib/helpers/conditional.js) | [unit tests](test/conditional.js) | [issues](https://github.com/jonschlinkert/template-helpers/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+conditional+helpers))
146 |
147 | * **[and](#and)** ([code](lib/helpers/conditional.js#L13) | [no tests])
148 | * **[compare](#compare)** ([code](lib/helpers/conditional.js#L30) | [unit tests](test/conditional.js#L35))
149 | * **[find](#find)** ([code](lib/helpers/conditional.js#L72) | [no tests])
150 | * **[every](#every)** ([code](lib/helpers/conditional.js#L83) | [no tests])
151 | * **[gt](#gt)** ([code](lib/helpers/conditional.js#L98) | [no tests])
152 | * **[gte](#gte)** ([code](lib/helpers/conditional.js#L110) | [no tests])
153 | * **[_if](#_if)** ([code](lib/helpers/conditional.js#L122) | [no tests])
154 | * **[is](#is)** ([code](lib/helpers/conditional.js#L142) | [unit tests](test/conditional.js#L47))
155 | * **[eq](#eq)** ([code](lib/helpers/conditional.js#L157) | [no tests])
156 | * **[isnt](#isnt)** ([code](lib/helpers/conditional.js#L169) | [unit tests](test/conditional.js#L59))
157 | * **[notEq](#notEq)** ([code](lib/helpers/conditional.js#L183) | [no tests])
158 | * **[lt](#lt)** ([code](lib/helpers/conditional.js#L195) | [no tests])
159 | * **[lte](#lte)** ([code](lib/helpers/conditional.js#L207) | [no tests])
160 | * **[or](#or)** ([code](lib/helpers/conditional.js#L219) | [no tests])
161 | * **[some](#some)** ([code](lib/helpers/conditional.js#L230) | [no tests])
162 |
163 | ### [fs helpers](#fs)
164 |
165 | Visit the: [code](lib/helpers/fs.js) | [unit tests](test/fs.js) | [issues](https://github.com/jonschlinkert/template-helpers/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+fs+helpers))
166 |
167 | * **[exists](#exists)** ([code](lib/helpers/fs.js#L16) | [unit tests](test/fs.js#L17))
168 | * **[read](#read)** ([code](lib/helpers/fs.js#L29) | [unit tests](test/fs.js#L23))
169 |
170 | ### [html helpers](#html)
171 |
172 | Visit the: [code](lib/helpers/html.js) | [unit tests](test/html.js) | [issues](https://github.com/jonschlinkert/template-helpers/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+html+helpers))
173 |
174 | * **[escapeHtml](#escapeHtml)** ([code](lib/helpers/html.js#L18) | [unit tests](test/html.js#L17))
175 | * **[sanitize](#sanitize)** ([code](lib/helpers/html.js#L46) | [unit tests](test/html.js#L27))
176 |
177 | ### [math helpers](#math)
178 |
179 | Visit the: [code](lib/helpers/math.js) | [unit tests](test/math.js) | [issues](https://github.com/jonschlinkert/template-helpers/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+math+helpers))
180 |
181 | * **[add](#add)** ([code](lib/helpers/math.js#L17) | [unit tests](test/math.js#L17))
182 | * **[subtract](#subtract)** ([code](lib/helpers/math.js#L31) | [unit tests](test/math.js#L23))
183 | * **[divide](#divide)** ([code](lib/helpers/math.js#L46) | [unit tests](test/math.js#L29))
184 | * **[multiply](#multiply)** ([code](lib/helpers/math.js#L61) | [unit tests](test/math.js#L35))
185 | * **[floor](#floor)** ([code](lib/helpers/math.js#L76) | [unit tests](test/math.js#L41))
186 | * **[ceil](#ceil)** ([code](lib/helpers/math.js#L91) | [unit tests](test/math.js#L47))
187 | * **[round](#round)** ([code](lib/helpers/math.js#L109) | [unit tests](test/math.js#L53))
188 | * **[sum](#sum)** ([code](lib/helpers/math.js#L123) | [unit tests](test/math.js#L60))
189 |
190 | ### [object helpers](#object)
191 |
192 | Visit the: [code](lib/helpers/object.js) | [unit tests](test/object.js) | [issues](https://github.com/jonschlinkert/template-helpers/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+object+helpers))
193 |
194 | * **[fallback](#fallback)** ([code](lib/helpers/object.js#L22) | [unit tests](test/object.js#L18))
195 | * **[stringify](#stringify)** ([code](lib/helpers/object.js#L36) | [unit tests](test/object.js#L26))
196 | * **[parse](#parse)** ([code](lib/helpers/object.js#L50) | [unit tests](test/object.js#L33))
197 | * **[get](#get)** ([code](lib/helpers/object.js#L65) | [no tests])
198 | * **[keys](#keys)** ([code](lib/helpers/object.js#L79) | [unit tests](test/object.js#L64))
199 | * **[isObject](#isObject)** ([code](lib/helpers/object.js#L97) | [unit tests](test/object.js#L40))
200 | * **[isPlainObject](#isPlainObject)** ([code](lib/helpers/object.js#L117) | [unit tests](test/object.js#L48))
201 | * **[hasOwn](#hasOwn)** ([code](lib/helpers/object.js#L129) | [unit tests](test/object.js#L57))
202 | * **[omit](#omit)** ([code](lib/helpers/object.js#L144) | [unit tests](test/object.js#L98))
203 | * **[forIn](#forIn)** ([code](lib/helpers/object.js#L163) | [unit tests](test/object.js#L70))
204 | * **[forOwn](#forOwn)** ([code](lib/helpers/object.js#L188) | [unit tests](test/object.js#L84))
205 | * **[extend](#extend)** ([code](lib/helpers/object.js#L205) | [unit tests](test/object.js#L105))
206 | * **[merge](#merge)** ([code](lib/helpers/object.js#L241) | [unit tests](test/object.js#L132))
207 |
208 | ### [path helpers](#path)
209 |
210 | Visit the: [code](lib/helpers/path.js) | [unit tests](test/path.js) | [issues](https://github.com/jonschlinkert/template-helpers/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+path+helpers))
211 |
212 | * **[dirname](#dirname)** ([code](lib/helpers/path.js#L19) | [unit tests](test/path.js#L17))
213 | * **[basename](#basename)** ([code](lib/helpers/path.js#L34) | [unit tests](test/path.js#L23))
214 | * **[filename](#filename)** ([code](lib/helpers/path.js#L49) | [unit tests](test/path.js#L29))
215 | * **[stem](#stem)** ([code](lib/helpers/path.js#L65) | [no tests])
216 | * **[extname](#extname)** ([code](lib/helpers/path.js#L80) | [unit tests](test/path.js#L35))
217 | * **[ext](#ext)** ([code](lib/helpers/path.js#L80) | [unit tests](test/path.js#L35))
218 | * **[resolve](#resolve)** ([code](lib/helpers/path.js#L110) | [unit tests](test/path.js#L47))
219 | * **[relative](#relative)** ([code](lib/helpers/path.js#L126) | [unit tests](test/path.js#L53))
220 | * **[segments](#segments)** ([code](lib/helpers/path.js#L162) | [unit tests](test/path.js#L107))
221 | * **[join](#join)** ([code](lib/helpers/path.js#L183) | [unit tests](test/path.js#L100))
222 | * **[isAbsolute](#isAbsolute)** ([code](lib/helpers/path.js#L215) | [unit tests](test/path.js#L81))
223 | * **[isRelative](#isRelative)** ([code](lib/helpers/path.js#L247) | [unit tests](test/path.js#L62))
224 |
225 | ### [string helpers](#string)
226 |
227 | Visit the: [code](lib/helpers/string.js) | [unit tests](test/string.js) | [issues](https://github.com/jonschlinkert/template-helpers/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+string+helpers))
228 |
229 | * **[camelcase](#camelcase)** ([code](lib/helpers/string.js#L24) | [unit tests](test/string.js#L98))
230 | * **[centerAlign](#centerAlign)** ([code](lib/helpers/string.js#L46) | [no tests])
231 | * **[chop](#chop)** ([code](lib/helpers/string.js#L69) | [unit tests](test/string.js#L50))
232 | * **[count](#count)** ([code](lib/helpers/string.js#L88) | [unit tests](test/string.js#L277))
233 | * **[dotcase](#dotcase)** ([code](lib/helpers/string.js#L107) | [unit tests](test/string.js#L162))
234 | * **[ellipsis](#ellipsis)** ([code](lib/helpers/string.js#L128) | [unit tests](test/string.js#L368))
235 | * **[isString](#isString)** ([code](lib/helpers/string.js#L147) | [no tests])
236 | * **[lower](#lower)** ([code](lib/helpers/string.js#L161) | [unit tests](test/string.js#L16))
237 | * **[lowercase](#lowercase)** ([code](lib/helpers/string.js#L161) | [unit tests](test/string.js#L16))
238 | * **[pascalcase](#pascalcase)** ([code](lib/helpers/string.js#L177) | [unit tests](test/string.js#L119))
239 | * **[snakecase](#snakecase)** ([code](lib/helpers/string.js#L196) | [unit tests](test/string.js#L141))
240 | * **[split](#split)** ([code](lib/helpers/string.js#L214) | [no tests])
241 | * **[strip](#strip)** ([code](lib/helpers/string.js#L230) | [unit tests](test/string.js#L72))
242 | * **[stripIndent](#stripIndent)** ([code](lib/helpers/string.js#L248) | [unit tests](test/string.js#L86))
243 | * **[trim](#trim)** ([code](lib/helpers/string.js#L275) | [unit tests](test/string.js#L36))
244 | * **[dashcase](#dashcase)** ([code](lib/helpers/string.js#L291) | [unit tests](test/string.js#L183))
245 | * **[pathcase](#pathcase)** ([code](lib/helpers/string.js#L309) | [unit tests](test/string.js#L204))
246 | * **[sentencecase](#sentencecase)** ([code](lib/helpers/string.js#L327) | [unit tests](test/string.js#L225))
247 | * **[hyphenate](#hyphenate)** ([code](lib/helpers/string.js#L345) | [unit tests](test/string.js#L239))
248 | * **[slugify](#slugify)** ([code](lib/helpers/string.js#L363) | [unit tests](test/string.js#L257))
249 | * **[reverse](#reverse)** ([code](lib/helpers/string.js#L377) | [unit tests](test/string.js#L291))
250 | * **[rightAlign](#rightAlign)** ([code](lib/helpers/string.js#L394) | [no tests])
251 | * **[replace](#replace)** ([code](lib/helpers/string.js#L412) | [unit tests](test/string.js#L330))
252 | * **[titleize](#titleize)** ([code](lib/helpers/string.js#Lundefined) | [no tests])
253 | * **[titlecase](#titlecase)** ([code](lib/helpers/string.js#L433) | [unit tests](test/string.js#L348))
254 | * **[truncate](#truncate)** ([code](lib/helpers/string.js#L451) | [unit tests](test/string.js#L358))
255 | * **[upper](#upper)** ([code](lib/helpers/string.js#L467) | [unit tests](test/string.js#L26))
256 | * **[uppercase](#uppercase)** ([code](lib/helpers/string.js#L467) | [unit tests](test/string.js#L26))
257 | * **[wordwrap](#wordwrap)** ([code](lib/helpers/string.js#L484) | [unit tests](test/string.js#L300))
258 |
259 | ### array
260 |
261 | #### [isArray](lib/helpers/array.js#L21)
262 |
263 | Returns true if `value` is an array.
264 |
265 | **Params**
266 |
267 | * `value` **{any}**: The value to test.
268 | * `returns` **{Boolean}**
269 |
270 | **Example**
271 |
272 | ```js
273 | <%= isArray('a, b, c') %>
274 | //=> 'false'
275 |
276 | <%= isArray(['a, b, c']) %>
277 | //=> 'true'
278 | ```
279 |
280 | #### [arrayify](lib/helpers/array.js#L42)
281 |
282 | Cast `val` to an array.
283 |
284 | **Params**
285 |
286 | * `val` **{any}**: The value to arrayify.
287 | * `returns` **{Array}**: An array.
288 | * `returns` **{Array}**
289 |
290 | **Example**
291 |
292 | ```js
293 | <%= arrayify('a') %>
294 | //=> '["a"]'
295 |
296 | <%= arrayify({a: 'b'}) %>
297 | //=> '[{a: "b"}]'
298 |
299 | <%= arrayify(['a']) %>
300 | //=> '["a"]'
301 | ```
302 |
303 | #### [first](lib/helpers/array.js#L58)
304 |
305 | Returns the first item, or first `n` items of an array.
306 |
307 | **Params**
308 |
309 | * `array` **{Array}**
310 | * `n` **{Number}**: Number of items to return, starting at `0`.
311 | * `returns` **{Array}**
312 |
313 | **Example**
314 |
315 | ```js
316 | <%= first(['a', 'b', 'c', 'd', 'e'], 2) %>
317 | //=> '["a", "b"]'
318 | ```
319 |
320 | #### [last](lib/helpers/array.js#L79)
321 |
322 | Returns the last item, or last `n` items of an array.
323 |
324 | **Params**
325 |
326 | * `array` **{Array}**
327 | * `n` **{Number}**: Number of items to return, starting with the last item.
328 | * `returns` **{Array}**
329 |
330 | **Example**
331 |
332 | ```js
333 | <%= last(['a', 'b', 'c', 'd', 'e'], 2) %>
334 | //=> '["d", "e"]'
335 | ```
336 |
337 | #### [before](lib/helpers/array.js#L102)
338 |
339 | Returns all of the items in an array up to the specified number Opposite of `<%= after() %`.
340 |
341 | **Params**
342 |
343 | * `array` **{Array}**
344 | * `n` **{Number}**
345 | * `returns` **{Array}**: Array excluding items after the given number.
346 |
347 | **Example**
348 |
349 | ```js
350 | <%= before(['a', 'b', 'c'], 2) %>
351 | //=> '["a", "b"]'
352 | ```
353 |
354 | #### [after](lib/helpers/array.js#L121)
355 |
356 | Returns all of the items in an arry after the specified index. Opposite of `<%= before() %`.
357 |
358 | **Params**
359 |
360 | * `array` **{Array}**: Collection
361 | * `n` **{Number}**: Starting index (number of items to exclude)
362 | * `returns` **{Array}**: Array exluding `n` items.
363 |
364 | **Example**
365 |
366 | ```js
367 | <%= after(['a', 'b', 'c'], 1) %>
368 | //=> '["c"]'
369 | ```
370 |
371 | #### [each](lib/helpers/array.js#L147)
372 |
373 | Calling `fn` on each element of the given `array` with the given `context`.
374 |
375 | Assuming that `double` has been registered as a helper:
376 |
377 | **Params**
378 |
379 | * `array` **{Array}**
380 | * `fn` **{String}**: The function to call on each element in the given array.
381 | * `returns` **{String}**
382 |
383 | **Examples**
384 |
385 | ```js
386 | function double(str) {
387 | return str + str;
388 | }
389 | ```
390 |
391 | ```js
392 | <%= each(['a', 'b', 'c'], double, ctx) %>
393 | //=> '["aa", "bb", "cc"]'
394 | ```
395 |
396 | #### [map](lib/helpers/array.js#L188)
397 |
398 | Returns a new array, created by calling `function` on each element of the given `array`.
399 |
400 | Assuming that `double` has been registered as a helper:
401 |
402 | **Params**
403 |
404 | * `array` **{Array}**
405 | * `fn` **{String}**: The function to call on each element in the given array.
406 | * `returns` **{String}**
407 |
408 | **Examples**
409 |
410 | ```js
411 | function double(str) {
412 | return str + str;
413 | }
414 | ```
415 |
416 | ```js
417 | <%= map(['a', 'b', 'c'], double) %>
418 | //=> '["aa", "bb", "cc"]'
419 | ```
420 |
421 | #### [join](lib/helpers/array.js#L218)
422 |
423 | Join all elements of array into a string, optionally using a given separator.
424 |
425 | **Params**
426 |
427 | * `array` **{Array}**
428 | * `sep` **{String}**: The separator to use.
429 | * `returns` **{String}**
430 |
431 | **Example**
432 |
433 | ```js
434 | <%= join(['a', 'b', 'c']) %>
435 | //=> 'a, b, c'
436 |
437 | <%= join(['a', 'b', 'c'], '-') %>
438 | //=> 'a-b-c'
439 | ```
440 |
441 | #### [sort](lib/helpers/array.js#L241)
442 |
443 | Sort the given `array`. If an array of objects is passed, you may optionally pass a `key` to sort on as the second argument. You may alternatively pass a sorting function as the second argument.
444 |
445 | **Params**
446 |
447 | * `array` **{Array}**: the array to sort.
448 | * `key` **{String|Function}**: The object key to sort by, or sorting function.
449 |
450 | **Example**
451 |
452 | ```js
453 | <%= sort(["b", "a", "c"]) %>
454 | //=> 'a,b,c'
455 |
456 | <%= sort([{a: "zzz"}, {a: "aaa"}], "a") %>
457 | //=> '[{"a":"aaa"},{"a":"zzz"}]'
458 | ```
459 |
460 | #### [length](lib/helpers/array.js#L272)
461 |
462 | Returns the length of the given array.
463 |
464 | **Params**
465 |
466 | * `array` **{Array}**
467 | * `returns` **{Number}**: The length of the array.
468 |
469 | **Example**
470 |
471 | ```js
472 | <%= length(['a', 'b', 'c']) %>
473 | //=> 3
474 | ```
475 |
476 | #### [compact](lib/helpers/array.js#L289)
477 |
478 | Returns an array with all falsey values removed.
479 |
480 | **Params**
481 |
482 | * `arr` **{Array}**
483 | * `returns` **{Array}**
484 |
485 | **Example**
486 |
487 | ```js
488 | <%= compact([null, a, undefined, 0, false, b, c, '']) %>
489 | //=> '["a", "b", "c"]'
490 | ```
491 |
492 | #### [difference](lib/helpers/array.js#L307)
493 |
494 | Return the difference between the first array and additional arrays.
495 |
496 | **Params**
497 |
498 | * `array` **{Array}**: The array to compare againts.
499 | * `arrays` **{Array}**: One or more additional arrays.
500 | * `returns` **{Array}**
501 |
502 | **Example**
503 |
504 | ```js
505 | <%= difference(["a", "c"], ["a", "b"]) %>
506 | //=> '["c"]'
507 | ```
508 |
509 | #### [unique](lib/helpers/array.js#L344)
510 |
511 | Return an array, free of duplicate values.
512 |
513 | **Params**
514 |
515 | * `array` **{Array}**: The array to uniquify
516 | * `returns` **{Array}**: Duplicate-free array
517 |
518 | **Example**
519 |
520 | ```js
521 | <%= unique(['a', 'b', 'c', 'c']) %
522 | => '["a", "b", "c"]'
523 | ```
524 |
525 | #### [union](lib/helpers/array.js#L373)
526 |
527 | Returns an array of unique values using strict equality for comparisons.
528 |
529 | **Params**
530 |
531 | * `arr` **{Array}**
532 | * `returns` **{Array}**
533 |
534 | **Example**
535 |
536 | ```js
537 | <%= union(["a"], ["b"], ["c"]) %>
538 | //=> '["a", "b", "c"]'
539 | ```
540 |
541 | #### [shuffle](lib/helpers/array.js#L389)
542 |
543 | Shuffle the items in an array.
544 |
545 | **Params**
546 |
547 | * `arr` **{Array}**
548 | * `returns` **{Array}**
549 |
550 | **Example**
551 |
552 | ```js
553 | <%= shuffle(["a", "b", "c"]) %>
554 | //=> ["c", "a", "b"]
555 | ```
556 |
557 | ### code
558 |
559 | #### [embed](lib/helpers/code.js#L23)
560 |
561 | Embed code from an external file as preformatted text.
562 |
563 | **Params**
564 |
565 | * `fp` **{String}**: filepath to the file to embed.
566 | * `language` **{String}**: Optionally specify the language to use for syntax highlighting.
567 | * `returns` **{String}**
568 |
569 | **Example**
570 |
571 | ```js
572 | <%= embed('path/to/file.js') %>
573 |
574 | // specify the language to use
575 | <%= embed('path/to/file.hbs', 'html') %>
576 | ```
577 |
578 | #### [jsfiddle](lib/helpers/code.js#L45)
579 |
580 | Generate the HTML for a jsFiddle link with the given `params`
581 |
582 | **Params**
583 |
584 | * `params` **{Object}**
585 | * `returns` **{String}**
586 |
587 | **Example**
588 |
589 | ```js
590 | <%= jsfiddle({id: '0dfk10ks', {tabs: true}}) %>
591 | ```
592 |
593 | ### collection
594 |
595 | #### [any](lib/helpers/collection.js#L17)
596 |
597 | Returns `true` if `value` exists in the given string, array
598 | or object. See [any](https://github.com/jonschlinkert/any) for documentation.
599 |
600 | **Params**
601 |
602 | * `value` **{any}**
603 | * `target` **{any}**
604 | * `options` **{Object}**
605 |
606 | #### [filter](lib/helpers/collection.js#L32)
607 |
608 | Filter the given array or object to contain only the matching values.
609 |
610 | **Params**
611 |
612 | * `arr` **{Array}**
613 | * `returns` **{Array}**
614 |
615 | **Example**
616 |
617 | ```js
618 | <%= filter(['foo', 'bar', 'baz']) %>
619 | //=> '["a", "b", "c"]'
620 | ```
621 |
622 | ### conditional
623 |
624 | #### [and](lib/helpers/conditional.js#L13)
625 |
626 | Returns true when both `valueA` and `valueB` are truthy.
627 |
628 | **Params**
629 |
630 | * `valueA` **{any}**
631 | * `valueB` **{any}**
632 | * `returns` **{Boolean}**
633 |
634 | #### [compare](lib/helpers/conditional.js#L30)
635 |
636 | Render a block when a comparison of the first and third arguments returns true.
637 |
638 | **Params**
639 |
640 | * `valueA` **{String}**
641 | * `operator` **{String}**: The operator to use for the comparison (must be a quoted string).
642 | * `valueB` **{String}**
643 | * `returns` **{Boolean}**
644 |
645 | **Example**
646 |
647 | ```js
648 | <%= compare("foo", "!==", "bar") %>
649 | ```
650 |
651 | #### [find](lib/helpers/conditional.js#L72)
652 |
653 | Returns the first truthy value.
654 |
655 | **Params**
656 |
657 | * `...values` **{...args}**
658 | * `returns` **{any}**
659 |
660 | #### [every](lib/helpers/conditional.js#L83)
661 |
662 | Returns true when all provided values are truthy.
663 |
664 | **Params**
665 |
666 | * `...values` **{...any}**
667 | * `returns` **{Boolean}**
668 |
669 | #### [gt](lib/helpers/conditional.js#L98)
670 |
671 | Returns true when `valueA` is greater than `valueB`.
672 |
673 | **Params**
674 |
675 | * `valueA` **{String}**
676 | * `valueB` **{String}**
677 | * `returns` **{Boolean}**
678 |
679 | #### [gte](lib/helpers/conditional.js#L110)
680 |
681 | Returns true when `valueA` is greater than or equal to `valueB`.
682 |
683 | **Params**
684 |
685 | * `valueA` **{String}**
686 | * `valueB` **{String}**
687 | * `returns` **{Boolean}**
688 |
689 | #### [_if](lib/helpers/conditional.js#L122)
690 |
691 | Return true if `key` is an own, enumerable property
692 | of the given `obj`.
693 |
694 | **Params**
695 |
696 | * `object` **{Object}**
697 | * `key` **{String}**
698 | * `returns` **{Boolean}**
699 |
700 | #### [is](lib/helpers/conditional.js#L142)
701 |
702 | Returns true when `valueA` equals `valueB`.
703 |
704 | **Params**
705 |
706 | * `valueA` **{String}**
707 | * `valueB` **{String}**
708 | * `strict` **{String}**
709 | * `returns` **{Boolean}**
710 |
711 | #### [eq](lib/helpers/conditional.js#L157)
712 |
713 | Alias for [is](#is).
714 |
715 | **Params**
716 |
717 | * `valueA` **{String}**
718 | * `valueB` **{String}**
719 | * `strict` **{String}**
720 | * `returns` **{Boolean}**
721 |
722 | #### [isnt](lib/helpers/conditional.js#L169)
723 |
724 | Returns true when `valueA` does not equal `valueB`.
725 |
726 | **Params**
727 |
728 | * `valueA` **{String}**
729 | * `valueB` **{String}**
730 | * `returns` **{Boolean}**
731 |
732 | #### [notEq](lib/helpers/conditional.js#L183)
733 |
734 | Alias for [isnt](#isnt).
735 |
736 | **Params**
737 |
738 | * `valueA` **{String}**
739 | * `valueB` **{String}**
740 | * `returns` **{Boolean}**
741 |
742 | #### [lt](lib/helpers/conditional.js#L195)
743 |
744 | Returns true when `valueA` is less than `valueB`.
745 |
746 | **Params**
747 |
748 | * `valueA` **{String}**
749 | * `valueB` **{String}**
750 | * `returns` **{Boolean}**
751 |
752 | #### [lte](lib/helpers/conditional.js#L207)
753 |
754 | Returns true when `valueA` is less than or equal to `valueB`.
755 |
756 | **Params**
757 |
758 | * `valueA` **{String}**
759 | * `valueB` **{String}**
760 | * `returns` **{Boolean}**
761 |
762 | #### [or](lib/helpers/conditional.js#L219)
763 |
764 | Returns `valueA` if thruthy, otherwise `valueB`.
765 |
766 | **Params**
767 |
768 | * `valueA` **{any}**
769 | * `valueB` **{any}**
770 | * `returns` **{any}**
771 |
772 | #### [some](lib/helpers/conditional.js#L230)
773 |
774 | Returns true when at least one value is truthy.
775 |
776 | **Params**
777 |
778 | * `...values` **{...any}**
779 | * `returns` **{Boolean}**
780 |
781 | ### fs
782 |
783 | #### [exists](lib/helpers/fs.js#L16)
784 |
785 | Return true if a file exists
786 |
787 | **Params**
788 |
789 | * `filepath` **{String}**: Path of the file to check.
790 | * `returns` **{Boolean}**: True if the file exists
791 |
792 | **Example**
793 |
794 | ```js
795 | <%= exists("foo.js") %>
796 | ```
797 |
798 | #### [read](lib/helpers/fs.js#L29)
799 |
800 | Read a file from the file system and inject its content
801 |
802 | **Params**
803 |
804 | * `filepath` **{String}**: Path of the file to read.
805 | * `returns` **{String}**: Contents of the given file.
806 |
807 | **Example**
808 |
809 | ```js
810 | <%= read("foo.js") %>
811 | ```
812 |
813 | ### html
814 |
815 | #### [escapeHtml](lib/helpers/html.js#L18)
816 |
817 | Escape HTML characters in a string.
818 |
819 | **Params**
820 |
821 | * `str` **{String}**: String of HTML with characters to escape.
822 | * `returns` **{String}**
823 |
824 | **Example**
825 |
826 | ```js
827 | <%= escapeHtml("foo") %>
828 | //=> <span>foo</span>
829 | ```
830 |
831 | #### [sanitize](lib/helpers/html.js#L46)
832 |
833 | Strip HTML tags from a string, so that only the text nodes are preserved.
834 |
835 | **Params**
836 |
837 | * `str` **{String}**: The string of HTML to sanitize.
838 | * `returns` **{String}**
839 |
840 | **Example**
841 |
842 | ```js
843 | <%= sanitize("foo") %>
844 | //=> 'foo'
845 | ```
846 |
847 | ### math
848 |
849 | #### [add](lib/helpers/math.js#L17)
850 |
851 | Return the product of `a` plus `b`.
852 |
853 | **Params**
854 |
855 | * `a` **{Number}**
856 | * `b` **{Number}**
857 |
858 | **Example**
859 |
860 | ```js
861 | <%= add(1, 2) %>
862 | //=> '3'
863 | ```
864 |
865 | #### [subtract](lib/helpers/math.js#L31)
866 |
867 | Subtract `b` from `a`.
868 |
869 | **Params**
870 |
871 | * `a` **{Number}**
872 | * `b` **{Number}**
873 |
874 | **Example**
875 |
876 | ```js
877 | <%= subtract(5, 2) %>
878 | //=> '3'
879 | ```
880 |
881 | #### [divide](lib/helpers/math.js#L46)
882 |
883 | Divide `a` (the numerator) by `b` (the divisor).
884 |
885 | **Params**
886 |
887 | * `a` **{Number}**: the numerator.
888 | * `b` **{Number}**: the divisor.
889 | * `returns` **{Number}**: The quotient of `a` divided by `b`.
890 |
891 | **Example**
892 |
893 | ```js
894 | <%= divide(10, 2) %>
895 | //=> '5'
896 | ```
897 |
898 | #### [multiply](lib/helpers/math.js#L61)
899 |
900 | Multiply `a` by `b`.
901 |
902 | **Params**
903 |
904 | * `a` **{Number}**
905 | * `b` **{Number}**
906 | * `returns` **{Number}**: The product of `a` times `b`.
907 |
908 | **Example**
909 |
910 | ```js
911 | <%= divide(10, 2) %>
912 | //=> '5'
913 | ```
914 |
915 | #### [floor](lib/helpers/math.js#L76)
916 |
917 | Returns the largest integer less than or equal to the given `number`.
918 |
919 | **Params**
920 |
921 | * `number` **{Number}**
922 | * `returns` **{Number}**
923 |
924 | **Example**
925 |
926 | ```js
927 | <%= floor(10.6) %>
928 | //=> '10'
929 | ```
930 |
931 | #### [ceil](lib/helpers/math.js#L91)
932 |
933 | Returns the smallest integer greater than or equal to the given `number`.
934 |
935 | **Params**
936 |
937 | * `number` **{Number}**
938 | * `returns` **{Number}**
939 |
940 | **Example**
941 |
942 | ```js
943 | <%= ceil(10.1) %>
944 | //=> '11'
945 | ```
946 |
947 | #### [round](lib/helpers/math.js#L109)
948 |
949 | Returns the value of the given `number` rounded to the nearest integer.
950 |
951 | **Params**
952 |
953 | * `number` **{Number}**
954 | * `returns` **{Number}**
955 |
956 | **Example**
957 |
958 | ```js
959 | <%= round(10.1) %>
960 | //=> '10'
961 |
962 | <%= round(10.5) %>
963 | //=> '11'
964 | ```
965 |
966 | #### [sum](lib/helpers/math.js#L123)
967 |
968 | Returns the sum of all numbers in the given array.
969 |
970 | **Params**
971 |
972 | * `number` **{Number}**
973 | * `returns` **{Number}**
974 |
975 | **Example**
976 |
977 | ```js
978 | <%= sum([1, 2, 3, 4, 5]) %>
979 | //=> '15'
980 | ```
981 |
982 | ### object
983 |
984 | #### [fallback](lib/helpers/object.js#L22)
985 |
986 | Specify a fallback value to use when the desired value is undefined. Note that undefined variables that are _not object properties_ with throw an error.
987 |
988 | **Params**
989 |
990 | * `a` **{any}**: The desired value.
991 | * `b` **{any}**: The fallback ("default") value
992 | * `returns` **{any}**: Either `a` or `b`
993 |
994 | **Example**
995 |
996 | ```js
997 | // when `title` is undefined, use the generic `site.title`
998 | <%= fallback(page.title, site.title) %>
999 | ```
1000 |
1001 | #### [stringify](lib/helpers/object.js#L36)
1002 |
1003 | Stringify an object using `JSON.stringify()`.
1004 |
1005 | **Params**
1006 |
1007 | * `object` **{Object}**
1008 | * `returns` **{String}**
1009 |
1010 | **Example**
1011 |
1012 | ```js
1013 | <%= stringify({a: "a"}) %>
1014 | //=> '{"a":"a"}'
1015 | ```
1016 |
1017 | #### [parse](lib/helpers/object.js#L50)
1018 |
1019 | Parse a string into an object using `JSON.parse()`.
1020 |
1021 | **Params**
1022 |
1023 | * `str` **{String}**: The string to parse.
1024 | * `returns` **{Object}**: The parsed object.
1025 |
1026 | **Example**
1027 |
1028 | ```js
1029 | <%= parse('{"foo":"bar"}')["foo"] %>
1030 | //=> 'bar'
1031 | ```
1032 |
1033 | #### [get](lib/helpers/object.js#L65)
1034 |
1035 | Use property paths (`a.b.c`) get a nested value from an object.
1036 |
1037 | **Params**
1038 |
1039 | * `object` **{Object}**
1040 | * `path` **{String}**: Dot notation for the property to get.
1041 | * `returns` **{String}**
1042 |
1043 | **Example**
1044 |
1045 | ```js
1046 | <%= get({a: {b: 'c'}}, 'a.b') %>
1047 | //=> 'c'
1048 | ```
1049 |
1050 | #### [keys](lib/helpers/object.js#L79)
1051 |
1052 | Returns an array of keys from the given `object`.
1053 |
1054 | **Params**
1055 |
1056 | * `object` **{Object}**
1057 | * `returns` **{Array}**: Keys from `object`
1058 |
1059 | **Example**
1060 |
1061 | ```js
1062 | <%= keys({a: 'b', c: 'd'}) %>
1063 | //=> '["a", "c"]'
1064 | ```
1065 |
1066 | #### [isObject](lib/helpers/object.js#L97)
1067 |
1068 | Return true if the given `value` is an object, and not `null` or an array.
1069 |
1070 | **Params**
1071 |
1072 | * `value` **{Object}**: The value to check.
1073 | * `returns` **{Boolean}**
1074 |
1075 | **Example**
1076 |
1077 | ```js
1078 | <%= isObject(['a', 'b', 'c']) %>
1079 | //=> 'false'
1080 |
1081 | <%= isObject({a: 'b'}) %>
1082 | //=> 'true'
1083 | ```
1084 |
1085 | #### [isPlainObject](lib/helpers/object.js#L117)
1086 |
1087 | Return true if the given `value` is a plain object.
1088 |
1089 | **Params**
1090 |
1091 | * `value` **{Object}**: The value to check.
1092 | * `returns` **{Boolean}**
1093 |
1094 | **Example**
1095 |
1096 | ```js
1097 | <%= isPlainObject(['a', 'b', 'c']) %>
1098 | //=> 'false'
1099 |
1100 | <%= isPlainObject({a: 'b'}) %>
1101 | //=> 'true'
1102 |
1103 | <%= isPlainObject(/foo/g) %>
1104 | //=> 'false'
1105 | ```
1106 |
1107 | #### [hasOwn](lib/helpers/object.js#L129)
1108 |
1109 | Return true if `key` is an own, enumerable property
1110 | of the given `obj`.
1111 |
1112 | **Params**
1113 |
1114 | * `object` **{Object}**
1115 | * `key` **{String}**
1116 | * `returns` **{Boolean}**
1117 |
1118 | #### [omit](lib/helpers/object.js#L144)
1119 |
1120 | Return a copy of `object` exclusing the given `keys`.
1121 |
1122 | **Params**
1123 |
1124 | * `object` **{Object}**: Object with keys to omit.
1125 | * `keys` **{String}**: Keys to omit.
1126 | * `returns` **{Boolean}**
1127 |
1128 | **Example**
1129 |
1130 | ```js
1131 | <%= omit({a: 'a', b: 'b', c: 'c'}, ['a', 'c']) %>
1132 | //=> '{b: "b"}'
1133 | ```
1134 |
1135 | #### [forIn](lib/helpers/object.js#L163)
1136 |
1137 | Iterate over the own and inherited enumerable properties of an object, and return an object with properties that evaluate to true from the callback. Exit early by returning `false`.
1138 |
1139 | **Params**
1140 |
1141 | * `object` **{Object}**: Object with keys to omit.
1142 | * `keys` **{String}**: Keys to omit.
1143 | * `returns` **{Boolean}**
1144 |
1145 | **Example**
1146 |
1147 | ```js
1148 | const context = { values: { a: 'b', c: 'd' } };
1149 | const str = '<% forIn(values, function(val, key) { %><%= val %><% }) %>';
1150 | const fn = _.template(str, { imports: helpers });
1151 | assert.equal(fn(context), 'bd');
1152 | ```
1153 |
1154 | #### [forOwn](lib/helpers/object.js#L188)
1155 |
1156 | Iterate over the own enumerable properties of an object, and return an object with properties that evaluate to true from the callback. Exit early by returning `false`
1157 |
1158 | **Params**
1159 |
1160 | * `object` **{Object}**: Object with keys to omit.
1161 | * `keys` **{String}**: Keys to omit.
1162 | * `returns` **{Boolean}**
1163 |
1164 | **Example**
1165 |
1166 | ```js
1167 | const context = { values: { a: 'b', c: 'd' } };
1168 | const str = '<% forOwn(values, function(val, key) { %><%= key %><% }) %>';
1169 | const fn = _.template(str, { imports: helpers });
1170 | console.log(fn(context)) //=> 'ac'
1171 | ```
1172 |
1173 | #### [extend](lib/helpers/object.js#L205)
1174 |
1175 | Extend `o` with properties of other `objects`.
1176 |
1177 | **Params**
1178 |
1179 | * `o` **{Object}**: The target object. Pass an empty object to shallow clone.
1180 | * `objects` **{Object}**
1181 | * `returns` **{Object}**
1182 |
1183 | #### [merge](lib/helpers/object.js#L241)
1184 |
1185 | Recursively combine the properties of `o` with the
1186 | properties of other `objects`.
1187 |
1188 | **Params**
1189 |
1190 | * `o` **{Object}**: The target object. Pass an empty object to shallow clone.
1191 | * `objects` **{Object}**
1192 | * `returns` **{Object}**
1193 |
1194 | ### path
1195 |
1196 | #### [dirname](lib/helpers/path.js#L19)
1197 |
1198 | Return the dirname for the given `filepath`. Uses the node.js [path](https://nodejs.org/api/path.html) module.
1199 |
1200 | **Params**
1201 |
1202 | * `filepath` **{String}**
1203 | * `returns` **{String}**: Returns the directory part of the file path.
1204 |
1205 | **Example**
1206 |
1207 | ```js
1208 | <%= dirname("a/b/c/d") %>
1209 | //=> 'a/b/c'
1210 | ```
1211 |
1212 | #### [basename](lib/helpers/path.js#L34)
1213 |
1214 | Return the basename for the given `filepath`. Uses the node.js [path](https://nodejs.org/api/path.html) module.
1215 |
1216 | **Params**
1217 |
1218 | * `filepath` **{String}**
1219 | * `returns` **{String}**: Returns the basename part of the file path.
1220 |
1221 | **Example**
1222 |
1223 | ```js
1224 | <%= basename("a/b/c/d.js") %>
1225 | //=> 'd.js'
1226 | ```
1227 |
1228 | #### [filename](lib/helpers/path.js#L49)
1229 |
1230 | Returns the filename for the given `filepath`, excluding extension. Aliased as `stem`.
1231 |
1232 | **Params**
1233 |
1234 | * `filepath` **{String}**
1235 | * `returns` **{String}**: Returns the file name part of the file path.
1236 |
1237 | **Example**
1238 |
1239 | ```js
1240 | <%= filename("a/b/c/d.js") %>
1241 | //=> 'd'
1242 | ```
1243 |
1244 | #### [stem](lib/helpers/path.js#L65)
1245 |
1246 | Alias for [filename](#filename).
1247 |
1248 | **Params**
1249 |
1250 | * `filepath` **{String}**
1251 | * `returns` **{String}**: Returns the file name part of the file path.
1252 |
1253 | **Example**
1254 |
1255 | ```js
1256 | <%= stem("a/b/c/d.js") %>
1257 | //=> 'd'
1258 | ```
1259 |
1260 | #### [extname](lib/helpers/path.js#L80)
1261 |
1262 | Return the file extension for the given `filepath`. Uses the node.js [path](https://nodejs.org/api/path.html) module.
1263 |
1264 | **Params**
1265 |
1266 | * `filepath` **{String}**
1267 | * `returns` **{String}**: Returns a file extension
1268 |
1269 | **Example**
1270 |
1271 | ```js
1272 | <%= extname("foo.js") %>
1273 | //=> '.js'
1274 | ```
1275 |
1276 | #### [ext](lib/helpers/path.js#L95)
1277 |
1278 | Return the file extension for the given `filepath`, excluding the `.`.
1279 |
1280 | **Params**
1281 |
1282 | * `filepath` **{String}**
1283 | * `returns` **{String}**: Returns a file extension without dot.
1284 |
1285 | **Example**
1286 |
1287 | ```js
1288 | <%= ext("foo.js") %>
1289 | //=> 'js'
1290 | ```
1291 |
1292 | #### [resolve](lib/helpers/path.js#L110)
1293 |
1294 | Resolves the given paths to an absolute path. Uses the node.js [path](https://nodejs.org/api/path.html) module.
1295 |
1296 | **Params**
1297 |
1298 | * `filepath` **{String}**
1299 | * `returns` **{String}**: Returns a resolve
1300 |
1301 | **Example**
1302 |
1303 | ```js
1304 | <%= resolve('/foo/bar', './baz') %>
1305 | //=> '/foo/bar/baz'
1306 | ```
1307 |
1308 | #### [relative](lib/helpers/path.js#L126)
1309 |
1310 | Get the relative path from file `a` to file `b`. Typically `a` and `b` would be variables passed on the context. Uses the node.js [path](https://nodejs.org/api/path.html) module.
1311 |
1312 | **Params**
1313 |
1314 | * `a` **{String}**: The "from" file path.
1315 | * `b` **{String}**: The "to" file path.
1316 | * `returns` **{String}**: Returns a relative path.
1317 |
1318 | **Example**
1319 |
1320 | ```js
1321 | <%= relative(a, b) %>
1322 | ```
1323 |
1324 | #### [segments](lib/helpers/path.js#L162)
1325 |
1326 | Get specific (joined) segments of a file path by passing a range of array indices.
1327 |
1328 | **Params**
1329 |
1330 | * `filepath` **{String}**: The file path to split into segments.
1331 | * `returns` **{String}**: Returns a single, joined file path.
1332 |
1333 | **Example**
1334 |
1335 | ```js
1336 | <%= segments("a/b/c/d", "2", "3") %>
1337 | //=> 'c/d'
1338 |
1339 | <%= segments("a/b/c/d", "1", "3") %>
1340 | //=> 'b/c/d'
1341 |
1342 | <%= segments("a/b/c/d", "1", "2") %>
1343 | //=> 'b/c'
1344 | ```
1345 |
1346 | #### [join](lib/helpers/path.js#L183)
1347 |
1348 | Join all arguments together and normalize the resulting `filepath`. Uses the node.js [path](https://nodejs.org/api/path.html) module.
1349 |
1350 | **Note**: there is also a `join()` array helper, dot notation
1351 | can be used with helpers to differentiate. Example: `<%= path.join() %>`.
1352 |
1353 | **Params**
1354 |
1355 | * `filepaths` **{String}**: List of file paths.
1356 | * `returns` **{String}**: Returns a single, joined file path.
1357 |
1358 | **Example**
1359 |
1360 | ```js
1361 | <%= join("a", "b") %>
1362 | //=> 'a/b'
1363 | ```
1364 |
1365 | #### [isAbsolute](lib/helpers/path.js#L215)
1366 |
1367 | Returns true if a file path is an absolute path. An absolute path will always resolve to the same location, regardless of the working directory. Uses the node.js [path](https://nodejs.org/api/path.html) module.
1368 |
1369 | **Params**
1370 |
1371 | * `filepath` **{String}**
1372 | * `returns` **{String}**: Returns a resolve
1373 |
1374 | **Example**
1375 |
1376 | ```js
1377 | // posix
1378 | <%= isAbsolute('/foo/bar') %>
1379 | //=> 'true'
1380 | <%= isAbsolute('qux/') %>
1381 | //=> 'false'
1382 | <%= isAbsolute('.') %>
1383 | //=> 'false'
1384 |
1385 | // Windows
1386 | <%= isAbsolute('//server') %>
1387 | //=> 'true'
1388 | <%= isAbsolute('C:/foo/..') %>
1389 | //=> 'true'
1390 | <%= isAbsolute('bar\\baz') %>
1391 | //=> 'false'
1392 | <%= isAbsolute('.') %>
1393 | //=> 'false'
1394 | ```
1395 |
1396 | #### [isRelative](lib/helpers/path.js#L247)
1397 |
1398 | Returns true if a file path is an absolute path. An absolute path will always resolve to the same location, regardless of the working directory. Uses the node.js [path](https://nodejs.org/api/path.html) module.
1399 |
1400 | **Params**
1401 |
1402 | * `filepath` **{String}**
1403 | * `returns` **{String}**: Returns a resolve
1404 |
1405 | **Example**
1406 |
1407 | ```js
1408 | // posix
1409 | <%= isRelative('/foo/bar') %>
1410 | //=> 'false'
1411 | <%= isRelative('qux/') %>
1412 | //=> 'true'
1413 | <%= isRelative('.') %>
1414 | //=> 'true'
1415 |
1416 | // Windows
1417 | <%= isRelative('//server') %>
1418 | //=> 'false'
1419 | <%= isRelative('C:/foo/..') %>
1420 | //=> 'false'
1421 | <%= isRelative('bar\\baz') %>
1422 | //=> 'true'
1423 | <%= isRelative('.') %>
1424 | //=> 'true'
1425 | ```
1426 |
1427 | ### string
1428 |
1429 | #### [camelcase](lib/helpers/string.js#L24)
1430 |
1431 | camelCase the characters in `string`.
1432 |
1433 | **Params**
1434 |
1435 | * `string` **{String}**: The string to camelcase.
1436 | * `returns` **{String}**
1437 |
1438 | **Example**
1439 |
1440 | ```js
1441 | <%= camelcase("foo bar baz") %>
1442 | //=> 'fooBarBaz'
1443 | ```
1444 |
1445 | #### [centerAlign](lib/helpers/string.js#L46)
1446 |
1447 | Center align the characters in a string using non-breaking spaces.
1448 |
1449 | **Params**
1450 |
1451 | * `str` **{String}**: The string to reverse.
1452 | * `returns` **{String}**: Centered string.
1453 |
1454 | **Example**
1455 |
1456 | ```js
1457 | <%= centerAlign("abc") %>
1458 | ```
1459 |
1460 | #### [chop](lib/helpers/string.js#L69)
1461 |
1462 | Like trim, but removes both extraneous whitespace and non-word characters from the beginning and end of a string.
1463 |
1464 | **Params**
1465 |
1466 | * `string` **{String}**: The string to chop.
1467 | * `returns` **{String}**
1468 |
1469 | **Example**
1470 |
1471 | ```js
1472 | <%= chop("_ABC_") %>
1473 | //=> 'ABC'
1474 |
1475 | <%= chop("-ABC-") %>
1476 | //=> 'ABC'
1477 |
1478 | <%= chop(" ABC ") %>
1479 | //=> 'ABC'
1480 | ```
1481 |
1482 | #### [count](lib/helpers/string.js#L88)
1483 |
1484 | Count the number of occurrances of a substring within a string.
1485 |
1486 | **Params**
1487 |
1488 | * `string` **{String}**
1489 | * `substring` **{String}**
1490 | * `returns` **{Number}**: The occurances of `substring` in `string`
1491 |
1492 | **Example**
1493 |
1494 | ```js
1495 | <%= count("abcabcabc", "a") %>
1496 | //=> '3'
1497 | ```
1498 |
1499 | #### [dotcase](lib/helpers/string.js#L107)
1500 |
1501 | dot.case the characters in `string`.
1502 |
1503 | **Params**
1504 |
1505 | * `string` **{String}**
1506 | * `returns` **{String}**
1507 |
1508 | **Example**
1509 |
1510 | ```js
1511 | <%= dotcase("a-b-c d_e") %>
1512 | //=> 'a.b.c.d.e'
1513 | ```
1514 |
1515 | #### [ellipsis](lib/helpers/string.js#L128)
1516 |
1517 | Truncate a string to the specified `length`, and append it with an elipsis, `…`.
1518 |
1519 | **Params**
1520 |
1521 | * `str` **{String}**
1522 | * `length` **{Number}**: The desired length of the returned string.
1523 | * `ch` **{String}**: Optionally pass custom characters to append. Default is `…`.
1524 | * `returns` **{String}**: The truncated string.
1525 |
1526 | **Example**
1527 |
1528 | ```js
1529 | <%= ellipsis("foo bar baz", 7) %>
1530 | //=> 'foo bar…'
1531 | ```
1532 |
1533 | #### [isString](lib/helpers/string.js#L147)
1534 |
1535 | Returns true if the value is a string.
1536 |
1537 | **Params**
1538 |
1539 | * `val` **{String}**
1540 | * `returns` **{Boolean}**: True if the value is a string.
1541 |
1542 | **Example**
1543 |
1544 | ```js
1545 | <%= isString('abc') %>
1546 | //=> 'true'
1547 |
1548 | <%= isString(null) %>
1549 | //=> 'false'
1550 | ```
1551 |
1552 | #### [lowercase](lib/helpers/string.js#L161)
1553 |
1554 | Lowercase the characters in the given `string`.
1555 |
1556 | **Params**
1557 |
1558 | * `string` **{String}**: The string to lowercase.
1559 | * `returns` **{String}**
1560 |
1561 | **Example**
1562 |
1563 | ```js
1564 | <%= lowercase("ABC") %>
1565 | //=> 'abc'
1566 | ```
1567 |
1568 | #### [pascalcase](lib/helpers/string.js#L177)
1569 |
1570 | PascalCase the characters in `string`.
1571 |
1572 | **Params**
1573 |
1574 | * `string` **{String}**
1575 | * `returns` **{String}**
1576 |
1577 | **Example**
1578 |
1579 | ```js
1580 | <%= pascalcase("foo bar baz") %>
1581 | //=> 'FooBarBaz'
1582 | ```
1583 |
1584 | #### [snakecase](lib/helpers/string.js#L196)
1585 |
1586 | snake_case the characters in `string`.
1587 |
1588 | **Params**
1589 |
1590 | * `string` **{String}**
1591 | * `returns` **{String}**
1592 |
1593 | **Example**
1594 |
1595 | ```js
1596 | <%= snakecase("a-b-c d_e") %>
1597 | //=> 'a_b_c_d_e'
1598 | ```
1599 |
1600 | #### [split](lib/helpers/string.js#L214)
1601 |
1602 | Split `string` by the given `character`.
1603 |
1604 | **Params**
1605 |
1606 | * `string` **{String}**: The string to split.
1607 | * `returns` **{String}** `character`: Default is `,`
1608 |
1609 | **Example**
1610 |
1611 | ```js
1612 | <%= split("a,b,c", ",") %>
1613 | //=> ['a', 'b', 'c']
1614 | ```
1615 |
1616 | #### [strip](lib/helpers/string.js#L230)
1617 |
1618 | Strip `substring` from the given `string`.
1619 |
1620 | **Params**
1621 |
1622 | * `substring` **{String|RegExp}**: The string or regex pattern of the substring to remove.
1623 | * `string` **{String}**: The target string.
1624 |
1625 | **Example**
1626 |
1627 | ```js
1628 | <%= strip("foo-bar", "foo-") %>
1629 | //=> 'bar'
1630 | ```
1631 |
1632 | #### [stripIndent](lib/helpers/string.js#L248)
1633 |
1634 | Strip the indentation from a `string`.
1635 |
1636 | **Params**
1637 |
1638 | * `string` **{String}**: The string to strip indentation from.
1639 | * `returns` **{String}**
1640 |
1641 | **Example**
1642 |
1643 | ```js
1644 | <%= stripIndent(" _ABC_") %>
1645 | //=> 'ABC'
1646 | ```
1647 |
1648 | #### [trim](lib/helpers/string.js#L275)
1649 |
1650 | Trim extraneous whitespace from the beginning and end of a string.
1651 |
1652 | **Params**
1653 |
1654 | * `string` **{String}**: The string to trim.
1655 | * `returns` **{String}**
1656 |
1657 | **Example**
1658 |
1659 | ```js
1660 | <%= trim(" ABC ") %>
1661 | //=> 'ABC'
1662 | ```
1663 |
1664 | #### [dashcase](lib/helpers/string.js#L291)
1665 |
1666 | dash-case the characters in `string`. This is similar to [slugify](https://github.com/simov/slugify), but [slugify](https://github.com/simov/slugify) makes the string compatible to be used as a URL slug.
1667 |
1668 | **Params**
1669 |
1670 | * `string` **{String}**
1671 | * `returns` **{String}**
1672 |
1673 | **Example**
1674 |
1675 | ```js
1676 | <%= dashcase("a b.c d_e") %>
1677 | //=> 'a-b-c-d-e'
1678 | ```
1679 |
1680 | #### [pathcase](lib/helpers/string.js#L309)
1681 |
1682 | path/case the characters in `string`.
1683 |
1684 | **Params**
1685 |
1686 | * `string` **{String}**
1687 | * `returns` **{String}**
1688 |
1689 | **Example**
1690 |
1691 | ```js
1692 | <%= pathcase("a-b-c d_e") %>
1693 | //=> 'a/b/c/d/e'
1694 | ```
1695 |
1696 | #### [sentencecase](lib/helpers/string.js#L327)
1697 |
1698 | Sentence-case the characters in `string`.
1699 |
1700 | **Params**
1701 |
1702 | * `string` **{String}**
1703 | * `returns` **{String}**
1704 |
1705 | **Example**
1706 |
1707 | ```js
1708 | <%= sentencecase("foo bar baz.") %>
1709 | //=> 'Foo bar baz.'
1710 | ```
1711 |
1712 | #### [hyphenate](lib/helpers/string.js#L345)
1713 |
1714 | Replace spaces in a string with hyphens. This
1715 |
1716 | **Params**
1717 |
1718 | * `string` **{String}**
1719 | * `returns` **{String}**
1720 |
1721 | **Example**
1722 |
1723 | ```js
1724 | <%= hyphenate("a b c") %>
1725 | //=> 'a-b-c'
1726 | ```
1727 |
1728 | #### [reverse](lib/helpers/string.js#L377)
1729 |
1730 | Reverse the characters in a string.
1731 |
1732 | **Params**
1733 |
1734 | * `str` **{String}**: The string to reverse.
1735 | * `returns` **{String}**
1736 |
1737 | **Example**
1738 |
1739 | ```js
1740 | <%= reverse("abc") %>
1741 | //=> 'cba'
1742 | ```
1743 |
1744 | #### [rightAlign](lib/helpers/string.js#L394)
1745 |
1746 | Right align the characters in a string using non-breaking spaces.
1747 |
1748 | **Params**
1749 |
1750 | * `str` **{String}**: The string to reverse.
1751 | * `returns` **{String}**: Right-aligned string.
1752 |
1753 | **Example**
1754 |
1755 | ```js
1756 | <%= rightAlign(str) %>
1757 | ```
1758 |
1759 | #### [replace](lib/helpers/string.js#L412)
1760 |
1761 | Replace occurrences of `a` with `b`.
1762 |
1763 | **Params**
1764 |
1765 | * `str` **{String}**
1766 | * `a` **{String|RegExp}**: Can be a string or regexp.
1767 | * `b` **{String}**
1768 | * `returns` **{String}**
1769 |
1770 | **Example**
1771 |
1772 | ```js
1773 | <%= replace("abcabc", /a/, "z") %>
1774 | //=> 'zbczbc'
1775 | ```
1776 |
1777 | #### [titlecase](lib/helpers/string.js#L433)
1778 |
1779 | Truncate a string by removing all HTML tags and limiting the result to the specified `length`.
1780 |
1781 | **Params**
1782 |
1783 | * `str` **{String}**
1784 | * `length` **{Number}**: The desired length of the returned string.
1785 | * `returns` **{String}**: The truncated string.
1786 |
1787 | **Example**
1788 |
1789 | ```js
1790 | <%= titlecase("big deal") %>
1791 | //=> 'foo bar'
1792 | ```
1793 |
1794 | #### [truncate](lib/helpers/string.js#L451)
1795 |
1796 | Truncate a string by removing all HTML tags and limiting the result to the specified `length`.
1797 |
1798 | **Params**
1799 |
1800 | * `str` **{String}**
1801 | * `length` **{Number}**: The desired length of the returned string.
1802 | * `returns` **{String}**: The truncated string.
1803 |
1804 | **Example**
1805 |
1806 | ```js
1807 | <%= truncate("foo bar baz", 7) %>
1808 | //=> 'foo bar'
1809 | ```
1810 |
1811 | #### [uppercase](lib/helpers/string.js#L467)
1812 |
1813 | Uppercase the characters in a string.
1814 |
1815 | **Params**
1816 |
1817 | * `string` **{String}**: The string to uppercase.
1818 | * `returns` **{String}**
1819 |
1820 | **Example**
1821 |
1822 | ```js
1823 | <%= uppercase("abc") %>
1824 | //=> 'ABC'
1825 | ```
1826 |
1827 | #### [wordwrap](lib/helpers/string.js#L484)
1828 |
1829 | Wrap words to a specified width using [word-wrap](https://github.com/jonschlinkert/word-wrap).
1830 |
1831 | **Params**
1832 |
1833 | * `string` **{String}**: The string with words to wrap.
1834 | * `object` **{Options}**: Options to pass to [word-wrap](https://github.com/jonschlinkert/word-wrap)
1835 | * `returns` **{String}**: Formatted string.
1836 |
1837 | **Example**
1838 |
1839 | ```js
1840 | <%= wordwrap("a b c d e f", {width: 5, newline: '
'}) %>
1841 | //=> ' a b c
d e f'
1842 | ```
1843 |
1844 | ## Coverage
1845 |
1846 | ```
1847 | Statements : 94.61% ( 439/464 )
1848 | Branches : 88.37% ( 190/215 )
1849 | Functions : 96.94% ( 95/98 )
1850 | Lines : 94.42% ( 389/412 )
1851 | ```
1852 |
1853 | ## About
1854 |
1855 |
1856 | Contributing
1857 |
1858 | Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new).
1859 |
1860 |
1861 |
1862 |
1863 | Running Tests
1864 |
1865 | 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:
1866 |
1867 | ```sh
1868 | $ npm install && npm test
1869 | ```
1870 |
1871 |
1872 |
1873 |
1874 | Building docs
1875 |
1876 | _(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.)_
1877 |
1878 | To generate the readme, run the following command:
1879 |
1880 | ```sh
1881 | $ npm install -g verbose/verb#dev verb-generate-readme && verb
1882 | ```
1883 |
1884 |
1885 |
1886 | ### Related projects
1887 |
1888 | You might also be interested in the following projects (also visit the [github.com/helpers](https://github.com/helpers), where you can find 60+ additional standalone helpers!):
1889 |
1890 | * [assemble](https://www.npmjs.com/package/assemble): Get the rocks out of your socks! Assemble makes you fast at creating web projects… [more](https://github.com/assemble/assemble) | [homepage](https://github.com/assemble/assemble "Get the rocks out of your socks! Assemble makes you fast at creating web projects. Assemble is used by thousands of projects for rapid prototyping, creating themes, scaffolds, boilerplates, e-books, UI components, API documentation, blogs, building websit")
1891 | * [handlebars-helpers](https://www.npmjs.com/package/handlebars-helpers): More than 130 Handlebars helpers in ~20 categories. Helpers can be used with Assemble, Generate… [more](https://github.com/helpers/handlebars-helpers) | [homepage](https://github.com/helpers/handlebars-helpers "More than 130 Handlebars helpers in ~20 categories. Helpers can be used with Assemble, Generate, Verb, Ghost, gulp-handlebars, grunt-handlebars, consolidate, or any node.js/Handlebars project.")
1892 | * [templates](https://www.npmjs.com/package/templates): System for creating and managing template collections, and rendering templates with any node.js template engine… [more](https://github.com/jonschlinkert/templates) | [homepage](https://github.com/jonschlinkert/templates "System for creating and managing template collections, and rendering templates with any node.js template engine. Can be used as the basis for creating a static site generator or blog framework.")
1893 |
1894 | ### Contributors
1895 |
1896 | ### Author
1897 |
1898 | **Jon Schlinkert**
1899 |
1900 | * [GitHub Profile](https://github.com/jonschlinkert)
1901 | * [Twitter Profile](https://twitter.com/jonschlinkert)
1902 | * [LinkedIn Profile](https://linkedin.com/in/jonschlinkert)
1903 |
1904 | ### License
1905 |
1906 | Copyright © 2018, [Jon Schlinkert](https://github.com/jonschlinkert).
1907 | Released under the [MIT License](LICENSE).
1908 |
1909 | ***
1910 |
1911 | _This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.8.0, on November 24, 2018._
--------------------------------------------------------------------------------
/docs/toc.md:
--------------------------------------------------------------------------------
1 | ## Categories
2 |
3 | Currently **{%= total.helpers %} helpers** in **{%= total.categories %} categories**:
4 |
5 | {% Object.keys(methods).forEach(function(key) { %}{% var file = methods[key] %}
6 | - **{%= anchor(file) %}** ({%= link("code", file.path) %} | {%= link("unit tests", file.test.path) %}) {% }) %}
7 |
8 | ## All helpers
9 |
10 | {% Object.keys(methods).forEach(function(key) { %}
11 | {% var file = methods[key] %}
12 |
13 | ### {%= link(key + ' helpers', '#' + file.stem) %}
14 | Visit the: {%= link("code", file.path) %} | {%= link("unit tests", file.test.path) %} | {%= sectionIssue(file.stem) %})
15 | {% Object.keys(file.data.methods).forEach(function(k) { %}{% var obj = file.data.methods[k] %}
16 | {%= bullet(obj) %} ({%= codeLink(obj) %} | {%= testLink(obj) %}){% }) %}
17 | {% }) %}
18 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /*!
4 | * template-helpers
5 | *
6 | * Copyright (c) 2015-present, Jon Schlinkert.
7 | * Licensed under the MIT License.
8 | */
9 |
10 | const helpers = require('./lib/helpers');
11 |
12 | module.exports = key => {
13 | let res = {};
14 |
15 | if (typeof key === 'string') {
16 | res = helpers[key];
17 | res[key] = res;
18 | return res;
19 | }
20 |
21 | if (Array.isArray(key)) {
22 | return key.reduce((acc, k) => {
23 | acc[k] = helpers[k];
24 | for (let prop of Object.keys(acc[k])) {
25 | acc[prop] = acc[k][prop];
26 | }
27 | return acc;
28 | }, {});
29 | }
30 |
31 | for (let prop of Object.keys(helpers)) {
32 | let group = helpers[prop];
33 | res[prop] = group;
34 |
35 | for (let k of Object.keys(group)) {
36 | res[k] = group[k];
37 | }
38 | }
39 | return res;
40 | };
41 |
--------------------------------------------------------------------------------
/lib/helpers/array.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const object = require('./object');
4 | const utils = require('../utils');
5 |
6 | /**
7 | * Returns true if `value` is an array.
8 | *
9 | * ```js
10 | * <%= isArray('a, b, c') %>
11 | * //=> 'false'
12 | *
13 | * <%= isArray(['a, b, c']) %>
14 | * //=> 'true'
15 | * ```
16 | * @param {*} `value` The value to test.
17 | * @return {Boolean}
18 | * @api public
19 | */
20 |
21 | exports.isArray = val => Array.isArray(val);
22 |
23 | /**
24 | * Cast `val` to an array.
25 | *
26 | * ```js
27 | * <%= arrayify('a') %>
28 | * //=> '["a"]'
29 | *
30 | * <%= arrayify({a: 'b'}) %>
31 | * //=> '[{a: "b"}]'
32 | *
33 | * <%= arrayify(['a']) %>
34 | * //=> '["a"]'
35 | * ```
36 | * @param {*} `val` The value to arrayify.
37 | * @return {Array} An array.
38 | * @return {Array}
39 | * @api public
40 | */
41 |
42 | exports.arrayify = val => [].concat(val != null ? val : []);
43 |
44 | /**
45 | * Returns the first item, or first `n` items of an array.
46 | *
47 | * ```js
48 | * <%= first(['a', 'b', 'c', 'd', 'e'], 2) %>
49 | * //=> '["a", "b"]'
50 | * ```
51 | * @name .first
52 | * @param {Array} `array`
53 | * @param {Number} `n` Number of items to return, starting at `0`.
54 | * @return {Array}
55 | * @api public
56 | */
57 |
58 | exports.first = (arr, n) => {
59 | if (utils.isEmpty(arr)) return '';
60 | if (utils.isNumber(n)) {
61 | return arr.slice(0, n);
62 | }
63 | return arr[0];
64 | };
65 |
66 | /**
67 | * Returns the last item, or last `n` items of an array.
68 | *
69 | * ```js
70 | * <%= last(['a', 'b', 'c', 'd', 'e'], 2) %>
71 | * //=> '["d", "e"]'
72 | * ```
73 | * @param {Array} `array`
74 | * @param {Number} `n` Number of items to return, starting with the last item.
75 | * @return {Array}
76 | * @api public
77 | */
78 |
79 | exports.last = (arr, n) => {
80 | if (utils.isEmpty(arr)) return '';
81 | if (!utils.isNumber(n)) {
82 | return arr[arr.length - 1];
83 | }
84 | return arr.slice(-n);
85 | };
86 |
87 | /**
88 | * Returns all of the items in an array up to the specified number
89 | * Opposite of `<%= after() %`.
90 | *
91 | * ```js
92 | * <%= before(['a', 'b', 'c'], 2) %>
93 | * //=> '["a", "b"]'
94 | * ```
95 | * @param {Array} `array`
96 | * @param {Number} `n`
97 | * @return {Array} Array excluding items after the given number.
98 | * @crosslink after
99 | * @api public
100 | */
101 |
102 | exports.before = (arr, n) => {
103 | return !utils.isEmpty(arr) ? arr.slice(0, -n) : '';
104 | };
105 |
106 | /**
107 | * Returns all of the items in an arry after the specified index.
108 | * Opposite of `<%= before() %`.
109 | *
110 | * ```js
111 | * <%= after(['a', 'b', 'c'], 1) %>
112 | * //=> '["c"]'
113 | * ```
114 | * @param {Array} `array` Collection
115 | * @param {Number} `n` Starting index (number of items to exclude)
116 | * @return {Array} Array exluding `n` items.
117 | * @crosslink before
118 | * @api public
119 | */
120 |
121 | exports.after = (arr, n) => {
122 | return !utils.isEmpty(arr) ? arr.slice(n) : '';
123 | };
124 |
125 | /**
126 | * Calling `fn` on each element of the given `array` with
127 | * the given `context`.
128 | *
129 | * ```js
130 | * function double(str) {
131 | * return str + str;
132 | * }
133 | * ```
134 | *
135 | * Assuming that `double` has been registered as a helper:
136 | *
137 | * ```js
138 | * <%= each(['a', 'b', 'c'], double, ctx) %>
139 | * //=> '["aa", "bb", "cc"]'
140 | * ```
141 | * @param {Array} `array`
142 | * @param {String} `fn` The function to call on each element in the given array.
143 | * @return {String}
144 | * @api public
145 | */
146 |
147 | exports.each = (arr, fn, context) => {
148 | if (utils.isEmpty(arr)) {
149 | return '';
150 | }
151 |
152 | let len = arr.length;
153 | let idx = -1;
154 | let res = '';
155 | let val;
156 |
157 | while (++idx < len) {
158 | if ((val = fn.call(context, arr[idx], idx, arr)) === false) {
159 | break;
160 | }
161 | res += val;
162 | }
163 | return res;
164 | };
165 |
166 | /**
167 | * Returns a new array, created by calling `function`
168 | * on each element of the given `array`.
169 | *
170 | * ```js
171 | * function double(str) {
172 | * return str + str;
173 | * }
174 | * ```
175 | *
176 | * Assuming that `double` has been registered as a helper:
177 | *
178 | * ```js
179 | * <%= map(['a', 'b', 'c'], double) %>
180 | * //=> '["aa", "bb", "cc"]'
181 | * ```
182 | * @param {Array} `array`
183 | * @param {String} `fn` The function to call on each element in the given array.
184 | * @return {String}
185 | * @api public
186 | */
187 |
188 | exports.map = (arr, fn, context) => {
189 | if (utils.isEmpty(arr)) return '';
190 |
191 | let len = arr.length;
192 | let res = new Array(len);
193 | let idx = -1;
194 |
195 | while (++idx < len) {
196 | res[idx] = fn.call(context, arr[idx], idx, arr);
197 | }
198 | return res;
199 | };
200 |
201 | /**
202 | * Join all elements of array into a string, optionally using a
203 | * given separator.
204 | *
205 | * ```js
206 | * <%= join(['a', 'b', 'c']) %>
207 | * //=> 'a, b, c'
208 | *
209 | * <%= join(['a', 'b', 'c'], '-') %>
210 | * //=> 'a-b-c'
211 | * ```
212 | * @param {Array} `array`
213 | * @param {String} `sep` The separator to use.
214 | * @return {String}
215 | * @api public
216 | */
217 |
218 | exports.join = (arr, sep) => {
219 | if (utils.isEmpty(arr)) return '';
220 | return arr.join(typeof sep !== 'string' ? ', ' : sep);
221 | };
222 |
223 | /**
224 | * Sort the given `array`. If an array of objects is passed,
225 | * you may optionally pass a `key` to sort on as the second
226 | * argument. You may alternatively pass a sorting function as
227 | * the second argument.
228 | *
229 | * ```js
230 | * <%= sort(["b", "a", "c"]) %>
231 | * //=> 'a,b,c'
232 | *
233 | * <%= sort([{a: "zzz"}, {a: "aaa"}], "a") %>
234 | * //=> '[{"a":"aaa"},{"a":"zzz"}]'
235 | * ```
236 | * @param {Array} `array` the array to sort.
237 | * @param {String|Function} `key` The object key to sort by, or sorting function.
238 | * @api public
239 | */
240 |
241 | exports.sort = (arr, key) => {
242 | if (utils.isEmpty(arr)) return '';
243 | if (typeof key === 'function') {
244 | return arr.sort(key);
245 | }
246 | if (typeof key !== 'string') {
247 | return arr.sort();
248 | }
249 | return arr.sort((a, b) => {
250 | if (object.isObject(a) && typeof a[key] === 'string') {
251 | return a[key].localeCompare(b[key]);
252 | }
253 | if (typeof a === 'string') {
254 | return a.localeCompare(b);
255 | }
256 | return a > b;
257 | });
258 | };
259 |
260 | /**
261 | * Returns the length of the given array.
262 | *
263 | * ```js
264 | * <%= length(['a', 'b', 'c']) %>
265 | * //=> 3
266 | * ```
267 | * @param {Array} `array`
268 | * @return {Number} The length of the array.
269 | * @api public
270 | */
271 |
272 | exports.length = arr => {
273 | if (utils.isEmpty(arr)) return '';
274 | return Array.isArray(arr) ? arr.length : 0;
275 | };
276 |
277 | /**
278 | * Returns an array with all falsey values removed.
279 | *
280 | * ```js
281 | * <%= compact([null, a, undefined, 0, false, b, c, '']) %>
282 | * //=> '["a", "b", "c"]'
283 | * ```
284 | * @param {Array} `arr`
285 | * @return {Array}
286 | * @api public
287 | */
288 |
289 | exports.compact = arr => {
290 | return !utils.isEmpty(arr) ? arr.filter(Boolean) : '';
291 | };
292 |
293 | /**
294 | * Return the difference between the first array and
295 | * additional arrays.
296 | *
297 | * ```js
298 | * <%= difference(["a", "c"], ["a", "b"]) %>
299 | * //=> '["c"]'
300 | * ```
301 | * @param {Array} `array` The array to compare againts.
302 | * @param {Array} `arrays` One or more additional arrays.
303 | * @return {Array}
304 | * @api public
305 | */
306 |
307 | exports.difference = (...args) => {
308 | if (utils.isEmpty(args)) return '';
309 | let [ a, b, c ] = args;
310 | let len = a.length;
311 | let arr = [];
312 | let rest;
313 |
314 | if (b == null) {
315 | return a;
316 | }
317 |
318 | if (c == null) {
319 | rest = b;
320 | } else {
321 | rest = utils.flatten(args.slice(1));
322 | }
323 |
324 | while (len--) {
325 | if (rest.indexOf(a[len]) === -1) {
326 | arr.unshift(a[len]);
327 | }
328 | }
329 | return arr;
330 | };
331 |
332 | /**
333 | * Return an array, free of duplicate values.
334 | *
335 | * ```js
336 | * <%= unique(['a', 'b', 'c', 'c']) %
337 | * => '["a", "b", "c"]'
338 | * ```
339 | * @param {Array} `array` The array to uniquify
340 | * @return {Array} Duplicate-free array
341 | * @api public
342 | */
343 |
344 | exports.unique = arr => {
345 | if (utils.isEmpty(arr)) return '';
346 | let len = arr.length;
347 | let i = -1;
348 |
349 | while (i++ < len) {
350 | let j = i + 1;
351 |
352 | for (; j < arr.length; ++j) {
353 | if (arr[i] === arr[j]) {
354 | arr.splice(j--, 1);
355 | }
356 | }
357 | }
358 | return arr;
359 | };
360 |
361 | /**
362 | * Returns an array of unique values using strict equality for comparisons.
363 | *
364 | * ```js
365 | * <%= union(["a"], ["b"], ["c"]) %>
366 | * //=> '["a", "b", "c"]'
367 | * ```
368 | * @param {Array} `arr`
369 | * @return {Array}
370 | * @api public
371 | */
372 |
373 | exports.union = (...args) => {
374 | return !utils.isEmpty(args) ? utils.union([], [].concat.apply([], args)) : '';
375 | };
376 |
377 | /**
378 | * Shuffle the items in an array.
379 | *
380 | * ```js
381 | * <%= shuffle(["a", "b", "c"]) %>
382 | * //=> ["c", "a", "b"]
383 | * ```
384 | * @param {Array} `arr`
385 | * @return {Array}
386 | * @api public
387 | */
388 |
389 | exports.shuffle = arr => {
390 | let len = arr.length;
391 | let res = new Array(len);
392 | let i = -1;
393 |
394 | while (++i < len) {
395 | let rand = utils.random(0, i);
396 | if (i !== rand) {
397 | res[i] = res[rand];
398 | }
399 | res[rand] = arr[i];
400 | }
401 | return res;
402 | };
403 |
--------------------------------------------------------------------------------
/lib/helpers/code.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const fs = require('fs');
4 | const path = require('path');
5 | const utils = require('../utils');
6 | const object = require('./object');
7 |
8 | /**
9 | * Embed code from an external file as preformatted text.
10 | *
11 | * ```js
12 | * <%= embed('path/to/file.js') %>
13 | *
14 | * // specify the language to use
15 | * <%= embed('path/to/file.hbs', 'html') %>
16 | * ```
17 | * @param {String} `fp` filepath to the file to embed.
18 | * @param {String} `language` Optionally specify the language to use for syntax highlighting.
19 | * @return {String}
20 | * @api public
21 | */
22 |
23 | exports.embed = (fp, ext) => {
24 | ext = typeof ext !== 'string' ? path.extname(fp).slice(1) : ext;
25 | let code = fs.readFileSync(fp, 'utf8');
26 |
27 | // if the string is markdown, escape backticks
28 | if (ext === 'markdown' || ext === 'md') {
29 | code = code.split('`').join('`');
30 | }
31 | return utils.toCodeBlock(code, ext) + '\n';
32 | };
33 |
34 | /**
35 | * Generate the HTML for a jsFiddle link with the given `params`
36 | *
37 | * ```js
38 | * <%= jsfiddle({id: '0dfk10ks', {tabs: true}}) %>
39 | * ```
40 | * @param {Object} `params`
41 | * @return {String}
42 | * @api public
43 | */
44 |
45 | exports.jsfiddle = attr => {
46 | if (!attr || !object.isPlainObject(attr)) return '';
47 | attr.id = 'http://jsfiddle.net/' + (attr.id || '');
48 | attr.width = attr.width || '100%';
49 | attr.height = attr.height || '300';
50 | attr.skin = attr.skin || '/presentation/';
51 | attr.tabs = (attr.tabs || 'result,js,html,css') + attr.skin;
52 | attr.src = attr.id + '/embedded/' + attr.tabs;
53 | attr.allowfullscreen = attr.allowfullscreen || 'allowfullscreen';
54 | attr.frameborder = attr.frameborder || '0';
55 | attr = object.omit(attr, ['id', 'tabs', 'skin']);
56 | return '';
57 | };
58 |
--------------------------------------------------------------------------------
/lib/helpers/collection.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const any = require('any');
4 | const iterator = require('../iterator');
5 | const utils = require('../utils');
6 |
7 | /**
8 | * Returns `true` if `value` exists in the given string, array
9 | * or object. See [any] for documentation.
10 | *
11 | * @param {*} `value`
12 | * @param {*} `target`
13 | * @param {Object} `options`
14 | * @api public
15 | */
16 |
17 | exports.any = any;
18 |
19 | /**
20 | * Filter the given array or object to contain only the matching values.
21 | *
22 | * ```js
23 | * <%= filter(['foo', 'bar', 'baz']) %>
24 | * //=> '["a", "b", "c"]'
25 | * ```
26 | *
27 | * @param {Array} `arr`
28 | * @return {Array}
29 | * @api public
30 | */
31 |
32 | exports.filter = (val, fn, context) => {
33 | if (utils.isEmpty(val)) return '';
34 | let iter = () => {};
35 |
36 | if (typeof fn === 'string') {
37 | let prop = fn;
38 | iter = target => {
39 | return typeof target === 'string' ? target === prop : target[prop];
40 | };
41 | } else {
42 | iter = iterator(fn, context);
43 | }
44 |
45 | if (typeof val === 'string') {
46 | return iter(val);
47 | }
48 |
49 | if (Array.isArray(val)) {
50 | return val.filter(iter);
51 | }
52 |
53 | if (utils.isObject(val)) {
54 | let obj = val;
55 | let res = {};
56 | for (let key in obj) {
57 | if (obj.hasOwnProperty(key) && iter(key)) {
58 | res[key] = obj[key];
59 | }
60 | }
61 | return res;
62 | }
63 | };
64 |
--------------------------------------------------------------------------------
/lib/helpers/conditional.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * Returns true when both `valueA` and `valueB` are truthy.
5 | *
6 | * @name .and
7 | * @param {any} `valueA`
8 | * @param {any} `valueB`
9 | * @return {Boolean}
10 | * @api public
11 | */
12 |
13 | exports.and = (valueA, valueB) => !!valueA && !!valueB;
14 |
15 | /**
16 | * Render a block when a comparison of the first and third arguments
17 | * returns true.
18 | *
19 | * ```js
20 | * <%= compare("foo", "!==", "bar") %>
21 | * ```
22 | * @name .compare
23 | * @param {String} `valueA`
24 | * @param {String} `operator` The operator to use for the comparison (must be a quoted string).
25 | * @param {String} `valueB`
26 | * @return {Boolean}
27 | * @api public
28 | */
29 |
30 | exports.compare = function(a, operator, b) {
31 | /* eslint-disable eqeqeq */
32 |
33 | if (arguments.length < 3) {
34 | throw new Error('"compare" helper - expected 3 arguments');
35 | }
36 |
37 | switch (operator) {
38 | case '!=':
39 | return a != b;
40 | case '!==':
41 | return a !== b;
42 | case '<':
43 | return a < b;
44 | case '<=':
45 | return a <= b;
46 | case '==':
47 | return a == b;
48 | case '===':
49 | return a === b;
50 | case '>':
51 | return a > b;
52 | case '>=':
53 | return a >= b;
54 | case 'typeof':
55 | return typeof a === b;
56 | default: {
57 | throw new Error(`"compare" helper - invalid operator: "${operator}"`);
58 | }
59 | }
60 | return false;
61 | };
62 |
63 | /**
64 | * Returns the first truthy value.
65 | *
66 | * @name .find
67 | * @param {...args} `...values`
68 | * @return {any}
69 | * @api public
70 | */
71 |
72 | exports.find = (...values) => values.find(v => !!v);
73 |
74 | /**
75 | * Returns true when all provided values are truthy.
76 | *
77 | * @name .every
78 | * @param {...any} `...values`
79 | * @return {Boolean}
80 | * @api public
81 | */
82 |
83 | exports.every = (...args) => {
84 | for (let ele of args) if (!ele) return false;
85 | return true;
86 | };
87 |
88 | /**
89 | * Returns true when `valueA` is greater than `valueB`.
90 | *
91 | * @name .gt
92 | * @param {String} `valueA`
93 | * @param {String} `valueB`
94 | * @return {Boolean}
95 | * @api public
96 | */
97 |
98 | exports.gt = (a, b) => a > b;
99 |
100 | /**
101 | * Returns true when `valueA` is greater than or equal to `valueB`.
102 | *
103 | * @name .gte
104 | * @param {String} `valueA`
105 | * @param {String} `valueB`
106 | * @return {Boolean}
107 | * @api public
108 | */
109 |
110 | exports.gte = (a, b) => a >= b;
111 |
112 | /**
113 | * Return true if `key` is an own, enumerable property
114 | * of the given `obj`.
115 | *
116 | * @param {Object} `object`
117 | * @param {String} `key`
118 | * @return {Boolean}
119 | * @api public
120 | */
121 |
122 | exports._if = function if_(fn, a, b, thisArg) {
123 | if (typeof fn !== 'function') return '';
124 |
125 | thisArg = thisArg || this || null;
126 | let res = fn.call(thisArg, a, b);
127 | if (res) return a;
128 | return b;
129 | };
130 |
131 | /**
132 | * Returns true when `valueA` equals `valueB`.
133 | *
134 | * @name .is
135 | * @param {String} `valueA`
136 | * @param {String} `valueB`
137 | * @param {String} `strict`
138 | * @return {Boolean}
139 | * @api public
140 | */
141 |
142 | exports.is = (a, b, strict = true) => {
143 | return strict ? a === b : a == b;
144 | };
145 |
146 | /**
147 | * Alias for [is](#is).
148 | *
149 | * @name .eq
150 | * @param {String} `valueA`
151 | * @param {String} `valueB`
152 | * @param {String} `strict`
153 | * @return {Boolean}
154 | * @api public
155 | */
156 |
157 | exports.eq = exports.is;
158 |
159 | /**
160 | * Returns true when `valueA` does not equal `valueB`.
161 | *
162 | * @name .isnt
163 | * @param {String} `valueA`
164 | * @param {String} `valueB`
165 | * @return {Boolean}
166 | * @api public
167 | */
168 |
169 | exports.isnt = (a, b, strict = true) => {
170 | return strict ? a !== b : a != b;
171 | };
172 |
173 | /**
174 | * Alias for [isnt](#isnt).
175 | *
176 | * @name .notEq
177 | * @param {String} `valueA`
178 | * @param {String} `valueB`
179 | * @return {Boolean}
180 | * @api public
181 | */
182 |
183 | exports.notEq = exports.isnt;
184 |
185 | /**
186 | * Returns true when `valueA` is less than `valueB`.
187 | *
188 | * @name .lt
189 | * @param {String} `valueA`
190 | * @param {String} `valueB`
191 | * @return {Boolean}
192 | * @api public
193 | */
194 |
195 | exports.lt = (a, b) => a < b;
196 |
197 | /**
198 | * Returns true when `valueA` is less than or equal to `valueB`.
199 | *
200 | * @name .lte
201 | * @param {String} `valueA`
202 | * @param {String} `valueB`
203 | * @return {Boolean}
204 | * @api public
205 | */
206 |
207 | exports.lte = (a, b) => a <= b;
208 |
209 | /**
210 | * Returns `valueA` if thruthy, otherwise `valueB`.
211 | *
212 | * @name .or
213 | * @param {any} `valueA`
214 | * @param {any} `valueB`
215 | * @return {any}
216 | * @api public
217 | */
218 |
219 | exports.or = (valueA, valueB) => !!valueA ? valueA : valueB;
220 |
221 | /**
222 | * Returns true when at least one value is truthy.
223 | *
224 | * @name .some
225 | * @param {...any} `...values`
226 | * @return {Boolean}
227 | * @api public
228 | */
229 |
230 | exports.some = (...args) => {
231 | for (let ele of args) if (!!ele) return true;
232 | return false;
233 | };
234 |
--------------------------------------------------------------------------------
/lib/helpers/fs.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const fs = require('fs');
4 |
5 | /**
6 | * Return true if a file exists
7 | *
8 | * ```js
9 | * <%= exists("foo.js") %>
10 | * ```
11 | * @param {String} `filepath` Path of the file to check.
12 | * @return {Boolean} True if the file exists
13 | * @api public
14 | */
15 |
16 | exports.exists = filepath => filepath && fs.existsSync(filepath);
17 |
18 | /**
19 | * Read a file from the file system and inject its content
20 | *
21 | * ```js
22 | * <%= read("foo.js") %>
23 | * ```
24 | * @param {String} `filepath` Path of the file to read.
25 | * @return {String} Contents of the given file.
26 | * @api public
27 | */
28 |
29 | exports.read = filepath => {
30 | if (!exports.exists(filepath)) return '';
31 | return fs.readFileSync(filepath, 'utf8');
32 | };
33 |
--------------------------------------------------------------------------------
/lib/helpers/html.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const string = require('./string');
4 |
5 | /**
6 | * Escape HTML characters in a string.
7 | *
8 | * ```js
9 | * <%= escapeHtml("foo") %>
10 | * //=> <span>foo</span>
11 | * ```
12 | *
13 | * @param {String} `str` String of HTML with characters to escape.
14 | * @return {String}
15 | * @api public
16 | */
17 |
18 | exports.escapeHtml = str => {
19 | if (!string.isString(str)) return '';
20 | return str.replace(/[/"'&<>]/g, ch => {
21 | return ({
22 | '"': '"',
23 | '&': '&',
24 | '/': '/',
25 | '<': '<',
26 | '>': '>',
27 | '\'': '''
28 | })[ch];
29 | });
30 | };
31 |
32 | /**
33 | * Strip HTML tags from a string, so that only the text nodes
34 | * are preserved.
35 | *
36 | * ```js
37 | * <%= sanitize("foo") %>
38 | * //=> 'foo'
39 | * ```
40 | *
41 | * @param {String} `str` The string of HTML to sanitize.
42 | * @return {String}
43 | * @api public
44 | */
45 |
46 | exports.sanitize = str => {
47 | return string.isString(str) ? str.replace(/(<([^>]+)>)/g, '').trim() : '';
48 | };
49 |
--------------------------------------------------------------------------------
/lib/helpers/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const define = (obj, k, fn) => {
4 | Reflect.defineProperty(obj, k, {
5 | enumerable: true,
6 | get: fn
7 | });
8 | };
9 |
10 | define(exports, 'string', () => require('./string'));
11 | define(exports, 'path', () => require('./path'));
12 | define(exports, 'object', () => require('./object'));
13 | define(exports, 'math', () => require('./math'));
14 | define(exports, 'html', () => require('./html'));
15 | define(exports, 'fs', () => require('./fs'));
16 | define(exports, 'conditional', () => require('./conditional'));
17 | define(exports, 'collection', () => require('./collection'));
18 | define(exports, 'code', () => require('./code'));
19 | define(exports, 'array', () => require('./array'));
20 |
--------------------------------------------------------------------------------
/lib/helpers/math.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const utils = require('../utils');
4 |
5 | /**
6 | * Return the product of `a` plus `b`.
7 | *
8 | * ```js
9 | * <%= add(1, 2) %>
10 | * //=> '3'
11 | * ```
12 | * @param {Number} `a`
13 | * @param {Number} `b`
14 | * @api public
15 | */
16 |
17 | exports.add = (a, b) => a + b;
18 |
19 | /**
20 | * Subtract `b` from `a`.
21 | *
22 | * ```js
23 | * <%= subtract(5, 2) %>
24 | * //=> '3'
25 | * ```
26 | * @param {Number} `a`
27 | * @param {Number} `b`
28 | * @api public
29 | */
30 |
31 | exports.subtract = (a, b) => Number(a) - Number(b);
32 |
33 | /**
34 | * Divide `a` (the numerator) by `b` (the divisor).
35 | *
36 | * ```js
37 | * <%= divide(10, 2) %>
38 | * //=> '5'
39 | * ```
40 | * @param {Number} `a` the numerator.
41 | * @param {Number} `b` the divisor.
42 | * @return {Number} The quotient of `a` divided by `b`.
43 | * @api public
44 | */
45 |
46 | exports.divide = (a, b) => Number(a) / Number(b);
47 |
48 | /**
49 | * Multiply `a` by `b`.
50 | *
51 | * ```js
52 | * <%= divide(10, 2) %>
53 | * //=> '5'
54 | * ```
55 | * @param {Number} `a`
56 | * @param {Number} `b`
57 | * @return {Number} The product of `a` times `b`.
58 | * @api public
59 | */
60 |
61 | exports.multiply = (a, b) => Number(a) * Number(b);
62 |
63 | /**
64 | * Returns the largest integer less than or equal to the
65 | * given `number`.
66 | *
67 | * ```js
68 | * <%= floor(10.6) %>
69 | * //=> '10'
70 | * ```
71 | * @param {Number} `number`
72 | * @return {Number}
73 | * @api public
74 | */
75 |
76 | exports.floor = n => Math.floor(n);
77 |
78 | /**
79 | * Returns the smallest integer greater than or equal to the
80 | * given `number`.
81 | *
82 | * ```js
83 | * <%= ceil(10.1) %>
84 | * //=> '11'
85 | * ```
86 | * @param {Number} `number`
87 | * @return {Number}
88 | * @api public
89 | */
90 |
91 | exports.ceil = n => Math.ceil(n);
92 |
93 | /**
94 | * Returns the value of the given `number` rounded to the
95 | * nearest integer.
96 | *
97 | * ```js
98 | * <%= round(10.1) %>
99 | * //=> '10'
100 | *
101 | * <%= round(10.5) %>
102 | * //=> '11'
103 | * ```
104 | * @param {Number} `number`
105 | * @return {Number}
106 | * @api public
107 | */
108 |
109 | exports.round = n => Math.round(n);
110 |
111 | /**
112 | * Returns the sum of all numbers in the given array.
113 | *
114 | * ```js
115 | * <%= sum([1, 2, 3, 4, 5]) %>
116 | * //=> '15'
117 | * ```
118 | * @param {Number} `number`
119 | * @return {Number}
120 | * @api public
121 | */
122 |
123 | exports.sum = (...args) => {
124 | let arr = [].concat.apply([], args);
125 | let len = arr.length;
126 | let idx = -1;
127 | let num = 0;
128 |
129 | while (++idx < len) {
130 | if (!utils.isNumber(arr[idx])) {
131 | continue;
132 | }
133 | num += (+arr[idx]);
134 | }
135 | return num;
136 | };
137 |
--------------------------------------------------------------------------------
/lib/helpers/object.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const hasOwn = Object.prototype.hasOwnProperty;
4 | const get = require('get-value');
5 | const utils = require('../utils');
6 |
7 | /**
8 | * Specify a fallback value to use when the desired
9 | * value is undefined. Note that undefined variables
10 | * that are _not object properties_ with throw an error.
11 | *
12 | * ```js
13 | * // when `title` is undefined, use the generic `site.title`
14 | * <%= fallback(page.title, site.title) %>
15 | * ```
16 | * @param {*} `a` The desired value.
17 | * @param {*} `b` The fallback ("default") value
18 | * @return {*} Either `a` or `b`
19 | * @api public
20 | */
21 |
22 | exports.fallback = (a, b) => a != null ? a : b;
23 |
24 | /**
25 | * Stringify an object using `JSON.stringify()`.
26 | *
27 | * ```js
28 | * <%= stringify({a: "a"}) %>
29 | * //=> '{"a":"a"}'
30 | * ```
31 | * @param {Object} `object`
32 | * @return {String}
33 | * @api public
34 | */
35 |
36 | exports.stringify = obj => JSON.stringify(obj);
37 |
38 | /**
39 | * Parse a string into an object using `JSON.parse()`.
40 | *
41 | * ```js
42 | * <%= parse('{"foo":"bar"}')["foo"] %>
43 | * //=> 'bar'
44 | * ```
45 | * @param {String} `str` The string to parse.
46 | * @return {Object} The parsed object.
47 | * @api public
48 | */
49 |
50 | exports.parse = str => utils.isString(str) ? JSON.parse(str) : void 0;
51 |
52 | /**
53 | * Use property paths (`a.b.c`) get a nested value from an object.
54 | *
55 | * ```js
56 | * <%= get({a: {b: 'c'}}, 'a.b') %>
57 | * //=> 'c'
58 | * ```
59 | * @param {Object} `object`
60 | * @param {String} `path` Dot notation for the property to get.
61 | * @return {String}
62 | * @api public
63 | */
64 |
65 | exports.get = (obj, prop, options) => get(obj, prop, options);
66 |
67 | /**
68 | * Returns an array of keys from the given `object`.
69 | *
70 | * ```js
71 | * <%= keys({a: 'b', c: 'd'}) %>
72 | * //=> '["a", "c"]'
73 | * ```
74 | * @param {Object} `object`
75 | * @return {Array} Keys from `object`
76 | * @api public
77 | */
78 |
79 | exports.keys = obj => Object.keys(obj);
80 |
81 | /**
82 | * Return true if the given `value` is an object, and
83 | * not `null` or an array.
84 | *
85 | * ```js
86 | * <%= isObject(['a', 'b', 'c']) %>
87 | * //=> 'false'
88 | *
89 | * <%= isObject({a: 'b'}) %>
90 | * //=> 'true'
91 | * ```
92 | * @param {Object} `value` The value to check.
93 | * @return {Boolean}
94 | * @api public
95 | */
96 |
97 | exports.isObject = utils.isObject;
98 |
99 | /**
100 | * Return true if the given `value` is a plain object.
101 | *
102 | * ```js
103 | * <%= isPlainObject(['a', 'b', 'c']) %>
104 | * //=> 'false'
105 | *
106 | * <%= isPlainObject({a: 'b'}) %>
107 | * //=> 'true'
108 | *
109 | * <%= isPlainObject(/foo/g) %>
110 | * //=> 'false'
111 | * ```
112 | * @param {Object} `value` The value to check.
113 | * @return {Boolean}
114 | * @api public
115 | */
116 |
117 | exports.isPlainObject = val => utils.isPlainObject(val);
118 |
119 | /**
120 | * Return true if `key` is an own, enumerable property
121 | * of the given `obj`.
122 | *
123 | * @param {Object} `object`
124 | * @param {String} `key`
125 | * @return {Boolean}
126 | * @api public
127 | */
128 |
129 | exports.hasOwn = (obj, key) => hasOwn.call(obj, key);
130 |
131 | /**
132 | * Return a copy of `object` exclusing the given `keys`.
133 | *
134 | * ```js
135 | * <%= omit({a: 'a', b: 'b', c: 'c'}, ['a', 'c']) %>
136 | * //=> '{b: "b"}'
137 | * ```
138 | * @param {Object} `object` Object with keys to omit.
139 | * @param {String} `keys` Keys to omit.
140 | * @return {Boolean}
141 | * @api public
142 | */
143 |
144 | exports.omit = (obj, keys) => utils.omit(obj, keys);
145 |
146 | /**
147 | * Iterate over the own and inherited enumerable properties of an object,
148 | * and return an object with properties that evaluate to true from the
149 | * callback. Exit early by returning `false`.
150 | *
151 | * ```js
152 | * const context = { values: { a: 'b', c: 'd' } };
153 | * const str = '<% forIn(values, function(val, key) { %><%= val %><% }) %>';
154 | * const fn = _.template(str, { imports: helpers });
155 | * assert.equal(fn(context), 'bd');
156 | * ```
157 | * @param {Object} `object` Object with keys to omit.
158 | * @param {String} `keys` Keys to omit.
159 | * @return {Boolean}
160 | * @api public
161 | */
162 |
163 | exports.forIn = (obj, fn, context) => {
164 | for (let key in obj) {
165 | if (fn.call(context, obj[key], key, obj) === false) {
166 | break;
167 | }
168 | }
169 | };
170 |
171 | /**
172 | * Iterate over the own enumerable properties of an object,
173 | * and return an object with properties that evaluate to true
174 | * from the callback. Exit early by returning `false`
175 | *
176 | * ```js
177 | * const context = { values: { a: 'b', c: 'd' } };
178 | * const str = '<% forOwn(values, function(val, key) { %><%= key %><% }) %>';
179 | * const fn = _.template(str, { imports: helpers });
180 | * console.log(fn(context)) //=> 'ac'
181 | * ```
182 | * @param {Object} `object` Object with keys to omit.
183 | * @param {String} `keys` Keys to omit.
184 | * @return {Boolean}
185 | * @api public
186 | */
187 |
188 | exports.forOwn = (obj, fn, context) => {
189 | exports.forIn(obj, (val, key) => {
190 | if (hasOwn.call(obj, key)) {
191 | return fn.call(context, obj[key], key, obj);
192 | }
193 | });
194 | };
195 |
196 | /**
197 | * Extend `o` with properties of other `objects`.
198 | *
199 | * @param {Object} `o` The target object. Pass an empty object to shallow clone.
200 | * @param {Object} `objects`
201 | * @return {Object}
202 | * @api public
203 | */
204 |
205 | exports.extend = (obj, ...rest) => {
206 | if (!utils.isObject(obj)) return '';
207 | let last = rest[rest.length - 1];
208 |
209 | if (utils.isObject(last) && last.hash) {
210 | rest.pop();
211 | }
212 |
213 | let len = rest.length;
214 | if (len === 0) {
215 | return obj;
216 | }
217 |
218 | for (let ele of rest) {
219 | if (utils.isObject(ele)) {
220 | for (let key in ele) {
221 | if (exports.hasOwn(ele, key)) {
222 | obj[key] = ele[key];
223 | }
224 | }
225 | }
226 | }
227 |
228 | return obj;
229 | };
230 |
231 | /**
232 | * Recursively combine the properties of `o` with the
233 | * properties of other `objects`.
234 | *
235 | * @param {Object} `o` The target object. Pass an empty object to shallow clone.
236 | * @param {Object} `objects`
237 | * @return {Object}
238 | * @api public
239 | */
240 |
241 | exports.merge = (obj, ...rest) => {
242 | if (!utils.isObject(obj)) return '';
243 | let last = rest[rest.length - 1];
244 |
245 | if (utils.isObject(last) && last.hash) {
246 | rest.pop();
247 | }
248 |
249 | let len = rest.length;
250 | if (len === 0) {
251 | return obj;
252 | }
253 |
254 | for (let ele of rest) {
255 | if (utils.isObject(ele)) {
256 | for (let key in ele) {
257 | if (exports.hasOwn(ele, key)) {
258 | if (utils.isObject(ele[key])) {
259 | obj[key] = exports.merge(obj[key], ele[key]);
260 | } else {
261 | obj[key] = ele[key];
262 | }
263 | }
264 | }
265 | }
266 | }
267 |
268 | return obj;
269 | };
270 |
--------------------------------------------------------------------------------
/lib/helpers/path.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 | const relative = require('relative');
5 |
6 | /**
7 | * Return the dirname for the given `filepath`. Uses
8 | * the node.js [path] module.
9 | *
10 | * ```js
11 | * <%= dirname("a/b/c/d") %>
12 | * //=> 'a/b/c'
13 | * ```
14 | * @param {String} `filepath`
15 | * @return {String} Returns the directory part of the file path.
16 | * @api public
17 | */
18 |
19 | exports.dirname = path.dirname;
20 |
21 | /**
22 | * Return the basename for the given `filepath`. Uses
23 | * the node.js [path] module.
24 | *
25 | * ```js
26 | * <%= basename("a/b/c/d.js") %>
27 | * //=> 'd.js'
28 | * ```
29 | * @param {String} `filepath`
30 | * @return {String} Returns the basename part of the file path.
31 | * @api public
32 | */
33 |
34 | exports.basename = path.basename;
35 |
36 | /**
37 | * Returns the filename for the given `filepath`, excluding
38 | * extension. Aliased as `stem`.
39 | *
40 | * ```js
41 | * <%= filename("a/b/c/d.js") %>
42 | * //=> 'd'
43 | * ```
44 | * @param {String} `filepath`
45 | * @return {String} Returns the file name part of the file path.
46 | * @api public
47 | */
48 |
49 | exports.filename = filepath => {
50 | return path.basename(filepath, path.extname(filepath));
51 | };
52 |
53 | /**
54 | * Alias for [filename](#filename).
55 | *
56 | * ```js
57 | * <%= stem("a/b/c/d.js") %>
58 | * //=> 'd'
59 | * ```
60 | * @param {String} `filepath`
61 | * @return {String} Returns the file name part of the file path.
62 | * @api public
63 | */
64 |
65 | exports.stem = exports.filename;
66 |
67 | /**
68 | * Return the file extension for the given `filepath`.
69 | * Uses the node.js [path] module.
70 | *
71 | * ```js
72 | * <%= extname("foo.js") %>
73 | * //=> '.js'
74 | * ```
75 | * @param {String} `filepath`
76 | * @return {String} Returns a file extension
77 | * @api public
78 | */
79 |
80 | exports.extname = path.extname;
81 |
82 | /**
83 | * Return the file extension for the given `filepath`,
84 | * excluding the `.`.
85 | *
86 | * ```js
87 | * <%= ext("foo.js") %>
88 | * //=> 'js'
89 | * ```
90 | * @param {String} `filepath`
91 | * @return {String} Returns a file extension without dot.
92 | * @api public
93 | */
94 |
95 | exports.ext = filepath => path.extname(filepath).replace(/^\./, '');
96 |
97 | /**
98 | * Resolves the given paths to an absolute path. Uses
99 | * the node.js [path] module.
100 | *
101 | * ```js
102 | * <%= resolve('/foo/bar', './baz') %>
103 | * //=> '/foo/bar/baz'
104 | * ```
105 | * @param {String} `filepath`
106 | * @return {String} Returns a resolve
107 | * @api public
108 | */
109 |
110 | exports.resolve = path.resolve;
111 |
112 | /**
113 | * Get the relative path from file `a` to file `b`.
114 | * Typically `a` and `b` would be variables passed
115 | * on the context. Uses the node.js [path] module.
116 | *
117 | * ```js
118 | * <%= relative(a, b) %>
119 | * ```
120 | * @param {String} `a` The "from" file path.
121 | * @param {String} `b` The "to" file path.
122 | * @return {String} Returns a relative path.
123 | * @api public
124 | */
125 |
126 | exports.relative = (a, b) => {
127 | if (b === void 0) {
128 | b = a;
129 |
130 | if (typeof process !== 'undefined' && typeof process.cwd === 'function') {
131 | a = process.cwd();
132 | } else {
133 | a = '.';
134 | }
135 | }
136 |
137 | a = a || '';
138 | b = b || '';
139 | let rel = relative(a, b);
140 | return rel === '.' ? './' : rel;
141 | };
142 |
143 | /**
144 | * Get specific (joined) segments of a file path by passing a
145 | * range of array indices.
146 | *
147 | * ```js
148 | * <%= segments("a/b/c/d", "2", "3") %>
149 | * //=> 'c/d'
150 | *
151 | * <%= segments("a/b/c/d", "1", "3") %>
152 | * //=> 'b/c/d'
153 | *
154 | * <%= segments("a/b/c/d", "1", "2") %>
155 | * //=> 'b/c'
156 | * ```
157 | * @param {String} `filepath` The file path to split into segments.
158 | * @return {String} Returns a single, joined file path.
159 | * @api public
160 | */
161 |
162 | exports.segments = (filepath, a, b) => {
163 | return filepath.split(/[\\/]+/).slice(a, b).join('/');
164 | };
165 |
166 | /**
167 | * Join all arguments together and normalize the resulting
168 | * `filepath`. Uses the node.js [path] module.
169 | *
170 | * **Note**: there is also a `join()` array helper, dot notation
171 | * can be used with helpers to differentiate. Example: `<%= path.join() %>`.
172 | *
173 | *
174 | * ```js
175 | * <%= join("a", "b") %>
176 | * //=> 'a/b'
177 | * ```
178 | * @param {String} `filepaths` List of file paths.
179 | * @return {String} Returns a single, joined file path.
180 | * @api public
181 | */
182 |
183 | exports.join = path.join;
184 |
185 | /**
186 | * Returns true if a file path is an absolute path. An
187 | * absolute path will always resolve to the same location,
188 | * regardless of the working directory. Uses the node.js
189 | * [path] module.
190 | *
191 | * ```js
192 | * // posix
193 | * <%= isAbsolute('/foo/bar') %>
194 | * //=> 'true'
195 | * <%= isAbsolute('qux/') %>
196 | * //=> 'false'
197 | * <%= isAbsolute('.') %>
198 | * //=> 'false'
199 | *
200 | * // Windows
201 | * <%= isAbsolute('//server') %>
202 | * //=> 'true'
203 | * <%= isAbsolute('C:/foo/..') %>
204 | * //=> 'true'
205 | * <%= isAbsolute('bar\\baz') %>
206 | * //=> 'false'
207 | * <%= isAbsolute('.') %>
208 | * //=> 'false'
209 | * ```
210 | * @param {String} `filepath`
211 | * @return {String} Returns a resolve
212 | * @api public
213 | */
214 |
215 | exports.isAbsolute = path.isAbsolute;
216 |
217 | /**
218 | * Returns true if a file path is an absolute path. An
219 | * absolute path will always resolve to the same location,
220 | * regardless of the working directory. Uses the node.js
221 | * [path] module.
222 | *
223 | * ```js
224 | * // posix
225 | * <%= isRelative('/foo/bar') %>
226 | * //=> 'false'
227 | * <%= isRelative('qux/') %>
228 | * //=> 'true'
229 | * <%= isRelative('.') %>
230 | * //=> 'true'
231 | *
232 | * // Windows
233 | * <%= isRelative('//server') %>
234 | * //=> 'false'
235 | * <%= isRelative('C:/foo/..') %>
236 | * //=> 'false'
237 | * <%= isRelative('bar\\baz') %>
238 | * //=> 'true'
239 | * <%= isRelative('.') %>
240 | * //=> 'true'
241 | * ```
242 | * @param {String} `filepath`
243 | * @return {String} Returns a resolve
244 | * @api public
245 | */
246 |
247 | exports.isRelative = filepath => !path.isAbsolute(filepath);
248 |
--------------------------------------------------------------------------------
/lib/helpers/string.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const wrap = require('word-wrap');
4 | const slugify = require('helper-slugify');
5 | const alignCenter = require('center-align');
6 | const alignRight = require('right-align');
7 | const titlecase = require('titlecase');
8 | const { isString } = require('../utils');
9 | const chopRe = () => /^[-_.\W\s]+|[-_.\W\s]+$/g;
10 | const nonWordRe = () => /[-_.\W\s]+(\w|$)/g;
11 |
12 | /**
13 | * camelCase the characters in `string`.
14 | *
15 | * ```js
16 | * <%= camelcase("foo bar baz") %>
17 | * //=> 'fooBarBaz'
18 | * ```
19 | * @param {String} `string` The string to camelcase.
20 | * @return {String}
21 | * @api public
22 | */
23 |
24 | exports.camelcase = input => {
25 | if (!isString(input)) return '';
26 | if (input.length === 1) {
27 | return input.toLowerCase();
28 | }
29 | let str = exports.chop(input).toLowerCase();
30 | return str.replace(nonWordRe(), (_, ch) => ch.toUpperCase());
31 | };
32 |
33 | /**
34 | * Center align the characters in a string using
35 | * non-breaking spaces.
36 | *
37 | * ```js
38 | * <%= centerAlign("abc") %>
39 | * ```
40 | * @param {String} `str` The string to reverse.
41 | * @return {String} Centered string.
42 | * @related rightAlign
43 | * @api public
44 | */
45 |
46 | exports.centerAlign = str => {
47 | return isString(str) ? alignCenter(str, ' ') : '';
48 | };
49 |
50 | /**
51 | * Like trim, but removes both extraneous whitespace and
52 | * non-word characters from the beginning and end of a string.
53 | *
54 | * ```js
55 | * <%= chop("_ABC_") %>
56 | * //=> 'ABC'
57 | *
58 | * <%= chop("-ABC-") %>
59 | * //=> 'ABC'
60 | *
61 | * <%= chop(" ABC ") %>
62 | * //=> 'ABC'
63 | * ```
64 | * @param {String} `string` The string to chop.
65 | * @return {String}
66 | * @api public
67 | */
68 |
69 | exports.chop = str => {
70 | if (!isString(str)) return '';
71 | return str.trim().replace(chopRe(), '');
72 | };
73 |
74 | /**
75 | * Count the number of occurrances of a substring
76 | * within a string.
77 | *
78 | * ```js
79 | * <%= count("abcabcabc", "a") %>
80 | * //=> '3'
81 | * ```
82 | * @param {String} `string`
83 | * @param {String} `substring`
84 | * @return {Number} The occurances of `substring` in `string`
85 | * @api public
86 | */
87 |
88 | exports.count = (str, sub) => {
89 | if (isString(str)) {
90 | return (sub ? (str.split(sub).length - 1) : '0');
91 | }
92 | return '';
93 | };
94 |
95 | /**
96 | * dot.case the characters in `string`.
97 | *
98 | * ```js
99 | * <%= dotcase("a-b-c d_e") %>
100 | * //=> 'a.b.c.d.e'
101 | * ```
102 | * @param {String} `string`
103 | * @return {String}
104 | * @api public
105 | */
106 |
107 | exports.dotcase = str => {
108 | if (!isString(str)) return '';
109 | if (str.length === 1) return str.toLowerCase();
110 | return exports.chop(str).replace(nonWordRe(), (_, ch) => '.' + ch);
111 | };
112 |
113 | /**
114 | * Truncate a string to the specified `length`, and append
115 | * it with an elipsis, `…`.
116 | *
117 | * ```js
118 | * <%= ellipsis("foo bar baz", 7) %>
119 | * //=> 'foo bar…'
120 | * ```
121 | * @param {String} `str`
122 | * @param {Number} `length` The desired length of the returned string.
123 | * @param {String} `ch` Optionally pass custom characters to append. Default is `…`.
124 | * @return {String} The truncated string.
125 | * @api public
126 | */
127 |
128 | exports.ellipsis = (str, limit, ch) => {
129 | return isString(str) ? (exports.truncate(str, limit) + (ch || '…')) : '';
130 | };
131 |
132 | /**
133 | * Returns true if the value is a string.
134 | *
135 | * ```js
136 | * <%= isString('abc') %>
137 | * //=> 'true'
138 | *
139 | * <%= isString(null) %>
140 | * //=> 'false'
141 | * ```
142 | * @param {String} `val`
143 | * @return {Boolean} True if the value is a string.
144 | * @api public
145 | */
146 |
147 | exports.isString = isString;
148 |
149 | /**
150 | * Lowercase the characters in the given `string`.
151 | *
152 | * ```js
153 | * <%= lowercase("ABC") %>
154 | * //=> 'abc'
155 | * ```
156 | * @param {String} `string` The string to lowercase.
157 | * @return {String}
158 | * @api public
159 | */
160 |
161 | exports.lowercase = exports.lower = str => {
162 | return isString(str) ? str.toLowerCase() : '';
163 | };
164 |
165 | /**
166 | * PascalCase the characters in `string`.
167 | *
168 | * ```js
169 | * <%= pascalcase("foo bar baz") %>
170 | * //=> 'FooBarBaz'
171 | * ```
172 | * @param {String} `string`
173 | * @return {String}
174 | * @api public
175 | */
176 |
177 | exports.pascalcase = input => {
178 | if (!isString(input)) return '';
179 | if (input.length === 1) { return input.toUpperCase(); }
180 | let str = exports.camelcase(input);
181 | return str[0].toUpperCase() + str.slice(1);
182 | };
183 |
184 | /**
185 | * snake_case the characters in `string`.
186 | *
187 | * ```js
188 | * <%= snakecase("a-b-c d_e") %>
189 | * //=> 'a_b_c_d_e'
190 | * ```
191 | * @param {String} `string`
192 | * @return {String}
193 | * @api public
194 | */
195 |
196 | exports.snakecase = str => {
197 | if (!isString(str)) return '';
198 | if (str.length === 1) return str.toLowerCase();
199 | return exports.chop(str).replace(nonWordRe(), (_, ch) => '_' + ch);
200 | };
201 |
202 | /**
203 | * Split `string` by the given `character`.
204 | *
205 | * ```js
206 | * <%= split("a,b,c", ",") %>
207 | * //=> ['a', 'b', 'c']
208 | * ```
209 | * @param {String} `string` The string to split.
210 | * @return {String} `character` Default is `,`
211 | * @api public
212 | */
213 |
214 | exports.split = (str, ch) => {
215 | return isString(str) ? str.split(ch || ',') : '';
216 | };
217 |
218 | /**
219 | * Strip `substring` from the given `string`.
220 | *
221 | * ```js
222 | * <%= strip("foo-bar", "foo-") %>
223 | * //=> 'bar'
224 | * ```
225 | * @param {String|RegExp} `substring` The string or regex pattern of the substring to remove.
226 | * @param {String} `string` The target string.
227 | * @api public
228 | */
229 |
230 | exports.strip = (val, str) => {
231 | if (!isString(val) && !(val instanceof RegExp)) return '';
232 | if (!isString(str)) return '';
233 | return str.split(val).join('');
234 | };
235 |
236 | /**
237 | * Strip the indentation from a `string`.
238 | *
239 | * ```js
240 | * <%= stripIndent(" _ABC_") %>
241 | * //=> 'ABC'
242 | * ```
243 | * @param {String} `string` The string to strip indentation from.
244 | * @return {String}
245 | * @api public
246 | */
247 |
248 | exports.stripIndent = str => {
249 | if (!isString(str)) return '';
250 | let matches = str.match(/^[ \t]+(?!\s)/gm);
251 | if (!matches) return str;
252 |
253 | let whitespace = matches.reverse().pop();
254 | let len = whitespace.length;
255 | if (len) {
256 | let re = new RegExp(`^[ \\t]{${len}}`, 'gm');
257 | return str.replace(re, '');
258 | }
259 | return str;
260 | };
261 |
262 | /**
263 | * Trim extraneous whitespace from the beginning and end
264 | * of a string.
265 | *
266 | * ```js
267 | * <%= trim(" ABC ") %>
268 | * //=> 'ABC'
269 | * ```
270 | * @param {String} `string` The string to trim.
271 | * @return {String}
272 | * @api public
273 | */
274 |
275 | exports.trim = str => isString(str) ? str.trim() : '';
276 |
277 | /**
278 | * dash-case the characters in `string`. This is similar to [slugify],
279 | * but [slugify] makes the string compatible to be used as a URL slug.
280 | *
281 | * ```js
282 | * <%= dashcase("a b.c d_e") %>
283 | * //=> 'a-b-c-d-e'
284 | * ```
285 | * @param {String} `string`
286 | * @return {String}
287 | * @tags dasherize, dashify, hyphenate, case
288 | * @api public
289 | */
290 |
291 | exports.dashcase = str => {
292 | if (!isString(str)) return '';
293 | if (str.length === 1) return str.toLowerCase();
294 | return exports.chop(str).replace(nonWordRe(), (_, ch) => '-' + ch);
295 | };
296 |
297 | /**
298 | * path/case the characters in `string`.
299 | *
300 | * ```js
301 | * <%= pathcase("a-b-c d_e") %>
302 | * //=> 'a/b/c/d/e'
303 | * ```
304 | * @param {String} `string`
305 | * @return {String}
306 | * @api public
307 | */
308 |
309 | exports.pathcase = str => {
310 | if (!isString(str)) return '';
311 | if (str.length === 1) { return str.toLowerCase(); }
312 | return exports.chop(str).replace(nonWordRe(), (_, ch) => '/' + ch);
313 | };
314 |
315 | /**
316 | * Sentence-case the characters in `string`.
317 | *
318 | * ```js
319 | * <%= sentencecase("foo bar baz.") %>
320 | * //=> 'Foo bar baz.'
321 | * ```
322 | * @param {String} `string`
323 | * @return {String}
324 | * @api public
325 | */
326 |
327 | exports.sentencecase = str => {
328 | if (!isString(str)) return '';
329 | if (str.length === 1) { return str.toUpperCase(); }
330 | return str.charAt(0).toUpperCase() + str.slice(1);
331 | };
332 |
333 | /**
334 | * Replace spaces in a string with hyphens. This
335 | *
336 | * ```js
337 | * <%= hyphenate("a b c") %>
338 | * //=> 'a-b-c'
339 | * ```
340 | * @param {String} `string`
341 | * @return {String}
342 | * @api public
343 | */
344 |
345 | exports.hyphenate = str => {
346 | return isString(str) ? exports.chop(str).split(' ').join('-') : '';
347 | };
348 |
349 | /**
350 | * TODO: Need to use a proper slugifier for this.
351 | * I don't want to use `node-slug`, it's way too
352 | * huge for this.
353 | *
354 | * ```js
355 | * <%= slugify('This is a post title.') %>
356 | * //=> 'this-is-a-post-title'
357 | * ```
358 | * @param {String} `string` The string to slugify.
359 | * @return {String} Slug.
360 | * @api draft
361 | */
362 |
363 | exports.slugify = slugify;
364 |
365 | /**
366 | * Reverse the characters in a string.
367 | *
368 | * ```js
369 | * <%= reverse("abc") %>
370 | * //=> 'cba'
371 | * ```
372 | * @param {String} `str` The string to reverse.
373 | * @return {String}
374 | * @api public
375 | */
376 |
377 | exports.reverse = str => {
378 | return isString(str) ? str.split('').reverse().join('') : '';
379 | };
380 |
381 | /**
382 | * Right align the characters in a string using
383 | * non-breaking spaces.
384 | *
385 | * ```js
386 | * <%= rightAlign(str) %>
387 | * ```
388 | * @param {String} `str` The string to reverse.
389 | * @return {String} Right-aligned string.
390 | * @related centerAlign
391 | * @api public
392 | */
393 |
394 | exports.rightAlign = str => {
395 | return isString(str) ? alignRight(str) : '';
396 | };
397 |
398 | /**
399 | * Replace occurrences of `a` with `b`.
400 | *
401 | * ```js
402 | * <%= replace("abcabc", /a/, "z") %>
403 | * //=> 'zbczbc'
404 | * ```
405 | * @param {String} `str`
406 | * @param {String|RegExp} `a` Can be a string or regexp.
407 | * @param {String} `b`
408 | * @return {String}
409 | * @api public
410 | */
411 |
412 | exports.replace = (str, a, b) => {
413 | if (!isString(str)) return '';
414 | if (!a) { return str; }
415 | if (!b) { b = ''; }
416 | return str.split(a).join(b);
417 | };
418 |
419 | /**
420 | * Truncate a string by removing all HTML tags and limiting the result
421 | * to the specified `length`.
422 | *
423 | * ```js
424 | * <%= titlecase("big deal") %>
425 | * //=> 'foo bar'
426 | * ```
427 | * @param {String} `str`
428 | * @param {Number} `length` The desired length of the returned string.
429 | * @return {String} The truncated string.
430 | * @api public
431 | */
432 |
433 | exports.titlecase = exports.titleize = (str, length) => {
434 | return isString(str) ? titlecase(str) : '';
435 | };
436 |
437 | /**
438 | * Truncate a string by removing all HTML tags and limiting the result
439 | * to the specified `length`.
440 | *
441 | * ```js
442 | * <%= truncate("foo bar baz", 7) %>
443 | * //=> 'foo bar'
444 | * ```
445 | * @param {String} `str`
446 | * @param {Number} `length` The desired length of the returned string.
447 | * @return {String} The truncated string.
448 | * @api public
449 | */
450 |
451 | exports.truncate = (str, length) => {
452 | return isString(str) ? str.substr(0, length) : '';
453 | };
454 |
455 | /**
456 | * Uppercase the characters in a string.
457 | *
458 | * ```js
459 | * <%= uppercase("abc") %>
460 | * //=> 'ABC'
461 | * ```
462 | * @param {String} `string` The string to uppercase.
463 | * @return {String}
464 | * @api public
465 | */
466 |
467 | exports.uppercase = exports.upper = str => {
468 | return isString(str) ? str.toUpperCase() : '';
469 | };
470 |
471 | /**
472 | * Wrap words to a specified width using [word-wrap].
473 | *
474 | * ```js
475 | * <%= wordwrap("a b c d e f", {width: 5, newline: '
'}) %>
476 | * //=> ' a b c
d e f'
477 | * ```
478 | * @param {String} `string` The string with words to wrap.
479 | * @param {Options} `object` Options to pass to [word-wrap]
480 | * @return {String} Formatted string.
481 | * @api public
482 | */
483 |
484 | exports.wordwrap = (str, options) => {
485 | return isString(str) ? wrap(str, options) : '';
486 | };
487 |
--------------------------------------------------------------------------------
/lib/iterator.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const typeOf = require('kind-of');
4 | const prop = name => obj => obj[name];
5 | const noop = val => val;
6 |
7 | module.exports = (target, thisArg) => {
8 | const invoke = (val, i, arr) => target.call(thisArg, val, i, arr);
9 | switch (typeOf(target)) {
10 | case 'undefined':
11 | case 'null':
12 | return noop;
13 | case 'function':
14 | return (thisArg === void 0) ? target : invoke;
15 | case 'object':
16 | return val => isMatch(val, target);
17 | case 'regexp':
18 | return str => target.test(str);
19 | case 'string':
20 | case 'number':
21 | default: {
22 | return prop(target);
23 | }
24 | }
25 | };
26 |
27 | function containsMatch(array, value) {
28 | for (let i = 0; i < array.length; i++) {
29 | if (isMatch(array[i], value)) {
30 | return true;
31 | }
32 | }
33 | return false;
34 | }
35 |
36 | function matchArray(array, value) {
37 | for (let i = 0; i < array.length; i++) {
38 | if (!containsMatch(array, value[i])) {
39 | return false;
40 | }
41 | }
42 | return true;
43 | }
44 |
45 | function matchObject(obj, value) {
46 | for (let key in value) {
47 | if (value.hasOwnProperty(key)) {
48 | if (isMatch(obj[key], value[key]) === false) {
49 | return false;
50 | }
51 | }
52 | }
53 | return true;
54 | }
55 |
56 | function isMatch(val, value) {
57 | if (typeOf(val) === 'object') {
58 | if (Array.isArray(val) && Array.isArray(value)) {
59 | return matchArray(val, value);
60 | }
61 | return matchObject(val, value);
62 | }
63 | return val === value;
64 | }
65 |
--------------------------------------------------------------------------------
/lib/utils.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const typeOf = require('kind-of');
4 |
5 | exports.isEmpty = val => {
6 | if (typeof val === 'function') {
7 | return false;
8 | }
9 | if (exports.isObject(val)) {
10 | val = Object.keys(val);
11 | }
12 | if (Array.isArray(val)) {
13 | return val.length === 0;
14 | }
15 | if (typeof val === 'undefined') {
16 | return true;
17 | }
18 | if (val === 0) {
19 | return false;
20 | }
21 | if (val == null) {
22 | return true;
23 | }
24 | };
25 |
26 | exports.omit = (obj, keys = []) => {
27 | let res = {};
28 |
29 | for (let key of Object.keys(obj)) {
30 | if (!keys.includes(key)) {
31 | res[key] = obj[key];
32 | }
33 | }
34 |
35 | return res;
36 | };
37 |
38 | /**
39 | * Get the "title" from a markdown link
40 | */
41 |
42 | exports.getTitle = str => {
43 | if (/^\[[^\]]+\]\(/.test(str)) {
44 | let m = /^\[([^\]]+)\]/.exec(str);
45 | if (m) return m[1];
46 | }
47 | return str;
48 | };
49 |
50 | exports.isString = str => str !== '' && typeof str === 'string';
51 |
52 | exports.isNumber = num => {
53 | if (typeof num === 'number') {
54 | return num - num === 0;
55 | }
56 | if (typeof num === 'string' && num.trim() !== '') {
57 | return Number.isFinite ? Number.isFinite(+num) : isFinite(+num);
58 | }
59 | return false;
60 | };
61 |
62 | exports.isObject = val => typeOf(val) === 'object';
63 |
64 | exports.isPlainObject = val => {
65 | return exports.isObject(val) && val.constructor === Object;
66 | };
67 |
68 | /**
69 | * Returns true if the given `val` is an object.
70 | *
71 | * ```js
72 | * utils.isObject('foo');
73 | * //=> false
74 | *
75 | * utils.isObject({});
76 | * //=> true
77 | * ```
78 | * @param {any} `val`
79 | * @return {Boolean}
80 | * @api public
81 | */
82 |
83 | exports.isObject = val => {
84 | return typeOf(val) === 'object';
85 | };
86 |
87 | /**
88 | * Stringify HTML tag attributes from the given `object`.
89 | *
90 | * @param {Object} `object` Object of attributes as key-value pairs.
91 | * @return {String} Stringified attributes, e.g. `foo="bar"`
92 | * @api public
93 | */
94 |
95 | exports.toAttributes = obj => {
96 | return Object.keys(obj).map(key => `${key}="${obj[key]}"`).join(' ');
97 | };
98 |
99 | exports.toCodeBlock = (str, lang) => {
100 | if (typeof str !== 'string') {
101 | throw new TypeError('expected a string.');
102 | }
103 | let code = '';
104 | code += '```' + (typeof lang === 'string' ? lang : '');
105 | code += '\n';
106 | code += str;
107 | code += '\n';
108 | code += '```';
109 | return code;
110 | };
111 |
112 | /**
113 | * Generate a random number
114 | *
115 | * @param {Number} `min`
116 | * @param {Number} `max`
117 | * @return {Number}
118 | */
119 |
120 | exports.random = (min, max) => {
121 | return min + Math.floor(Math.random() * (max - min + 1));
122 | };
123 |
124 | exports.flatten = arr => {
125 | const flat = (a, res) => {
126 | let len = a.length;
127 | let i = -1;
128 | while (len--) {
129 | let cur = a[++i];
130 | if (Array.isArray(cur)) {
131 | flat(cur, res);
132 | } else {
133 | res.push(cur);
134 | }
135 | }
136 | return res;
137 | };
138 | return flat(arr, []);
139 | };
140 |
141 | exports.union = (...args) => {
142 | return [...new Set(exports.flatten(args))];
143 | };
144 |
145 | /**
146 | * Expose `exports` modules
147 | */
148 |
149 | module.exports = exports;
150 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "template-helpers",
3 | "description": "Generic JavaScript helpers that can be used with any template engine. Handlebars, Lo-Dash, Underscore, or any engine that supports helper functions.",
4 | "version": "1.0.1",
5 | "homepage": "https://github.com/jonschlinkert/template-helpers",
6 | "author": "Jon Schlinkert (https://github.com/jonschlinkert)",
7 | "repository": "jonschlinkert/template-helpers",
8 | "bugs": {
9 | "url": "https://github.com/jonschlinkert/template-helpers/issues"
10 | },
11 | "license": "MIT",
12 | "files": [
13 | "index.js",
14 | "lib"
15 | ],
16 | "main": "index.js",
17 | "engines": {
18 | "node": ">=6"
19 | },
20 | "scripts": {
21 | "test": "mocha"
22 | },
23 | "dependencies": {
24 | "any": "^1.0.0",
25 | "center-align": "^1.0.1",
26 | "get-value": "^3.0.1",
27 | "helper-slugify": "^0.2.0",
28 | "kind-of": "^6.0.2",
29 | "relative": "^3.0.2",
30 | "right-align": "^0.1.3",
31 | "titlecase": "^1.1.2",
32 | "word-wrap": "^1.2.3"
33 | },
34 | "devDependencies": {
35 | "gulp-format-md": "^2.0.0",
36 | "helper-coverage": "^0.1.3",
37 | "lodash.template": "^4.4.0",
38 | "markdown-link": "^0.1.1",
39 | "mocha": "^5.2.0",
40 | "through2": "^3.0.0",
41 | "verb-generate-readme": "^0.8.0"
42 | },
43 | "keywords": [
44 | "compile",
45 | "engine",
46 | "helper",
47 | "helpers",
48 | "imports",
49 | "lodash",
50 | "process",
51 | "render",
52 | "template",
53 | "underscore"
54 | ],
55 | "verb": {
56 | "toc": true,
57 | "layout": "default",
58 | "tasks": [
59 | "readme"
60 | ],
61 | "plugins": [
62 | "gulp-format-md"
63 | ],
64 | "helpers": [
65 | "helper-coverage"
66 | ],
67 | "related": {
68 | "description": "You might also be interested in the following projects (also visit the [github.com/helpers](https://github.com/helpers), where you can find 60+ additional standalone helpers!):",
69 | "list": [
70 | "assemble",
71 | "handlebars-helpers",
72 | "templates"
73 | ]
74 | },
75 | "lint": {
76 | "reflinks": true
77 | },
78 | "reflinks": [
79 | "any",
80 | "slugify",
81 | "verb",
82 | "word-wrap"
83 | ]
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/recipes/tips-and-tricks.md:
--------------------------------------------------------------------------------
1 | # Tips and tricks
2 |
3 | > Some things you might not know you can do with helpers ;)
4 |
5 | Some of these only work with one template engine, others can be used anywhere. Please make sure to read any notes and pay special attention to the **Engines** section of each tip.
6 |
7 |
8 | ## Define a variable
9 |
10 | Add a variable to the context, but only for a single template.
11 |
12 | **Lo-Dash Example**
13 |
14 | ```js
15 | // define the variable
16 | <% foo = "bar" %>
17 |
18 | // use it
19 | <%= foo %>
20 | //=> "bar"
21 | ```
22 |
23 | Works with non-string variables too, of course.
24 |
25 | **Engines**
26 |
27 | Should work with:
28 |
29 | - [Lo-dash]
30 |
31 |
32 | ## Vanilla node.js libs as helpers
33 |
34 | Here is a trick for using any plain old node.js library as a helper on-the-fly. To do so, we'll create a special helper that isn't in the library:
35 |
36 | **The `require` helper**
37 |
38 | ```js
39 | var helpers = {
40 | require: function() {
41 | // take whatever args are passed
42 | return require.apply(require, arguments);
43 | };
44 | };
45 | ```
46 |
47 | **Lo-Dash Example**
48 |
49 | Now you can use the `require` helper in your templates, allowing you to use any other node.js library without registering it as a helper first.
50 |
51 | ```js
52 | // globbing is already included in this lib, but this is a good example
53 | _.template('<%= require("glob").sync("*.js") %>', {imports: helpers});
54 | ```
55 |
56 | **Engines**
57 |
58 | Should work with:
59 |
60 | - [Lo-Dash]
61 |
62 |
63 |
64 | ## Chain helpers
65 |
66 | Each helper should only have a single responsibility. Chaining allows us to stick to that rule and keep things simple.
67 |
68 | **Lo-Dash Example**
69 |
70 | 1. Read a file from the file system (that happens to be markdown)
71 | 2. Convert it to HTML
72 |
73 | ```js
74 | <%= markdown(read("README.md")) %>
75 | ```
76 |
77 | **Engines**
78 |
79 | Should work with:
80 |
81 | - Any
82 |
83 |
84 | ***
85 |
86 | # Contributing
87 |
88 | If you contribute to this page, please follow the conventions. Thanks!
89 |
--------------------------------------------------------------------------------
/test/array.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * template-helpers
3 | *
4 | * Copyright (c) 2015, Jon Schlinkert.
5 | * Licensed under the MIT License.
6 | */
7 |
8 | 'use strict';
9 |
10 | require('mocha');
11 | var assert = require('assert');
12 | var helpers = require('..')('array');
13 | var template = require('lodash.template');
14 |
15 | var context = {arr: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']};
16 | var imports = {imports: helpers};
17 |
18 | describe('isArray', function() {
19 | it('should return true if the value is an array.', function() {
20 | assert.equal(template('<%= isArray("foo") %>', imports)(), 'false');
21 | assert.equal(template('<%= isArray(["foo"]) %>', imports)(), 'true');
22 | });
23 | });
24 |
25 | describe('arrayify', function() {
26 | it('should coerce a value to an array.', function() {
27 | assert.equal(template('<%= isArray(arrayify("foo")) %>', imports)(), 'true');
28 | assert.equal(template('<%= isArray(arrayify(["foo"])) %>', imports)(), 'true');
29 | });
30 | });
31 |
32 | describe('first', function() {
33 | it('should return an empty string when undefined.', function() {
34 | assert.equal(template('<%= first() %>', imports)(), '');
35 | });
36 |
37 | it('should return the first item in an array.', function() {
38 | var fn = template('<%= first(foo) %>', imports);
39 | assert.equal(fn({foo: ['a', 'b', 'c']}), 'a');
40 | });
41 |
42 | it('should return an array with the first two items in an array.', function() {
43 | var fn = template('<%= first(foo, 2) %>', imports);
44 | assert.deepEqual(fn({foo: ['a', 'b', 'c']}), ['a', 'b'].toString());
45 | });
46 | });
47 |
48 | describe('last', function() {
49 | it('should return an empty string when undefined.', function() {
50 | assert.equal(template('<%= last() %>', imports)(), '');
51 | });
52 |
53 | it('should return the last item in an array.', function() {
54 | assert.equal(template('<%= last(arr) %>', imports)(context), 'h');
55 | });
56 | it('should return an array with the last two items in an array.', function() {
57 | assert.deepEqual(template('<%= last(arr, 2) %>', imports)(context), ['g', 'h'].toString());
58 | });
59 | });
60 |
61 | describe('before', function() {
62 | it('should return an empty string when undefined.', function() {
63 | assert.equal(template('<%= before() %>', imports)(), '');
64 | });
65 | it('should return all of the items in an array before the given index.', function() {
66 | var fn = template('<%= before(arr, 5) %>', imports);
67 | assert.deepEqual(fn(context), ['a', 'b', 'c'].toString());
68 | });
69 | });
70 |
71 | describe('after', function() {
72 | it('should return an empty string when undefined.', function() {
73 | assert.equal(template('<%= after() %>', imports)(), '');
74 | });
75 |
76 | it('should return all of the items in an array after the given index.', function() {
77 | var fn = template('<%= after(arr, 5) %>', imports);
78 | assert.deepEqual(fn(context), ['f', 'g', 'h'].toString());
79 | });
80 | });
81 |
82 | describe('join', function() {
83 | it('should return an empty string when undefined.', function() {
84 | assert.equal(template('<%= join() %>', imports)(), '');
85 | });
86 |
87 | it('should return all items in an array joined by the default separator.', function() {
88 | var fn = template('<%= join(arr) %>', imports);
89 | assert.equal(fn(context), 'a, b, c, d, e, f, g, h');
90 | });
91 |
92 | it('should return all items in an array joined by the given separator.', function() {
93 | var fn = template('<%= join(arr, " | ") %>', imports);
94 | assert.equal(fn(context), 'a | b | c | d | e | f | g | h');
95 | });
96 | });
97 |
98 | describe('each', function() {
99 | it('should return an empty string when undefined.', function() {
100 | assert.equal(template('<%= each() %>', imports)(), '');
101 | });
102 |
103 | it('should iterate over items in the array and return new values.', function() {
104 | var o = {};
105 | o.double = function(str) {
106 | return str + str;
107 | };
108 | var fn = template('<%= each(["a","b","c"], double) %>', imports);
109 | assert.equal(fn(o), 'aabbcc');
110 | });
111 |
112 | it('should expose the given context to each item', function() {
113 | var o = {ctx: {sep: ' '}};
114 | o.double = function(str) {
115 | return str + this.sep + str;
116 | };
117 | var fn = template('<%= each(["a","b","c"], double, ctx) %>', imports);
118 | assert.equal(fn(o), 'a ab bc c');
119 | });
120 | });
121 |
122 | describe('map', function() {
123 | it('should return an empty string when undefined.', function() {
124 | assert.equal(template('<%= map() %>', imports)(), '');
125 | });
126 |
127 | it('should map the items in the array and return new values.', function() {
128 | var o = {};
129 | o.double = function(str) {
130 | return str + str;
131 | };
132 | var fn = template('<%= map(["a","b","c"], double) %>', imports);
133 | assert.equal(fn(o), 'aa,bb,cc');
134 | });
135 | });
136 |
137 | describe('sort', function() {
138 | it('should return an empty string when undefined.', function() {
139 | assert.equal(template('<%= sort() %>', imports)(), '');
140 | });
141 |
142 | it('should sort the items in an array.', function() {
143 | var fn = template('<%= sort(["b", "c", "a"]) %>', imports);
144 | assert.equal(fn(context), 'a,b,c');
145 | });
146 |
147 | it('should take a compare function.', function() {
148 | var o = {};
149 | o.compare = function(a, b) {
150 | return b.localeCompare(a);
151 | };
152 | var fn = template('<%= sort(["b", "c", "a"], compare) %>', imports);
153 | assert.equal(fn(o), 'c,b,a');
154 | });
155 |
156 | it('should sort based on object key:', function() {
157 | var fn = template('<%= JSON.stringify(sort([{a: "zzz"}, {a: "aaa"}], "a")) %>', imports);
158 | assert.equal(fn(), '[{"a":"aaa"},{"a":"zzz"}]');
159 | });
160 | });
161 |
162 | describe('length', function() {
163 | it('should return an empty string when undefined.', function() {
164 | assert.equal(template('<%= length() %>', imports)(), '');
165 | });
166 |
167 | it('should return zero when the value is not an array.', function() {
168 | var fn = template('<%= length("foo") %>', imports);
169 | assert.equal(fn(context), '0');
170 | });
171 |
172 | it('should return the length of an array.', function() {
173 | var fn = template('<%= length(["b", "c", "a"]) %>', imports);
174 | assert.equal(fn(context), '3');
175 | });
176 | });
177 |
178 | describe('compact', function() {
179 | it('should return an empty string when undefined.', function() {
180 | assert.equal(template('<%= compact() %>', imports)(), '');
181 | });
182 |
183 | it('should remove falsey values from an array.', function() {
184 | var fn = template('<%= compact([null, "a", undefined, 0, false, "b", "c", ""]) %>', imports);
185 | assert.equal(fn(context), 'a,b,c');
186 | });
187 | });
188 |
189 | describe('difference', function() {
190 | it('should return an empty string when undefined.', function() {
191 | assert.equal(template('<%= difference() %>', imports)(), '');
192 | });
193 |
194 | it('should return the difference from multiple arrays', function() {
195 | var o = {};
196 | o.a = ['a', 'b', 'c', 'd'];
197 | o.b = ['b', 'c'];
198 | o.c = ['x', 'y'];
199 | assert.equal(template('<%= difference(a, b, c) %>', imports)(o), 'a,d');
200 | assert.equal(template('<%= difference(a, b) %>', imports)(o), 'a,d');
201 | assert.equal(template('<%= difference(a) %>', imports)(o), 'a,b,c,d');
202 | });
203 | });
204 |
205 | describe('unique', function() {
206 | it('should return an empty string when undefined.', function() {
207 | assert.equal(template('<%= unique() %>', imports)(), '');
208 | });
209 | it('should unique items from multiple arrays:', function() {
210 | var fn = template('<%= unique(["a", "b", "c", "c"]) %>', imports);
211 | assert.equal(fn(context), 'a,b,c');
212 | });
213 | });
214 |
215 | describe('union', function() {
216 | it('should return an empty string when undefined.', function() {
217 | assert.equal(template('<%= union() %>', imports)(), '');
218 | });
219 |
220 | it('should union items from multiple arrays:', function() {
221 | var fn = template('<%= union(["a", "c"], ["b", "b"]) %>', imports);
222 | assert.equal(fn(context), 'a,c,b');
223 | });
224 |
225 | it('should union items from multiple arrays:', function() {
226 | var fn = template('<%= union(["a"], ["b"]) %>', imports);
227 | assert.equal(fn(context), 'a,b');
228 | });
229 | });
230 |
--------------------------------------------------------------------------------
/test/code.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * template-helpers
3 | *
4 | * Copyright (c) 2015, Jon Schlinkert.
5 | * Licensed under the MIT License.
6 | */
7 |
8 | 'use strict';
9 |
10 | var helpers = require('..')('code');
11 | var assert = require('assert');
12 | var template = require('lodash.template');
13 | var imports = {imports: helpers};
14 |
15 | describe('code', function() {
16 | var orig = process.cwd();
17 | before(function() {
18 | process.chdir(__dirname + '/fixtures');
19 | });
20 | after(function() {
21 | process.chdir(orig);
22 | });
23 |
24 | describe('jsfiddle', function() {
25 | it('should return an empty string with no args.', function() {
26 | assert.equal(template('<%= jsfiddle() %>', imports)(), '');
27 | });
28 |
29 | it('should return create a jsfiddle link.', function() {
30 | assert.equal(template('<%= jsfiddle({id: "c0th6weq", tabs: true}) %>', imports)(), '');
31 | });
32 | });
33 | describe('embed', function() {
34 | it('should return create a code example from the given file.', function() {
35 | assert.equal(template('<%= embed("a.js") %>', imports)({}), [
36 | '```js',
37 | 'function foo(a, b, c) {',
38 | ' return a + b + c;',
39 | '}',
40 | '```\n'
41 | ].join('\n'));
42 | });
43 |
44 | it('should use the extension specified as a second argument.', function() {
45 | assert.equal(template('<%= embed("a.js", "javascript") %>', imports)(), [
46 | '```javascript',
47 | 'function foo(a, b, c) {',
48 | ' return a + b + c;',
49 | '}',
50 | '```\n'
51 | ].join('\n'));
52 | });
53 |
54 | it('should escape backticks in markdown.', function() {
55 | assert.equal(template('<%= embed("a.md", "md") %>', imports)(), [
56 | '```md',
57 | '```',
58 | 'foo',
59 | '```',
60 | '```\n'
61 | ].join('\n'));
62 | });
63 | });
64 | });
65 |
--------------------------------------------------------------------------------
/test/collection.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * template-helpers
3 | *
4 | * Copyright (c) 2015, Jon Schlinkert.
5 | * Licensed under the MIT License.
6 | */
7 |
8 | 'use strict';
9 |
10 | var assert = require('assert');
11 | var helpers = require('..')(['collection', 'object']);
12 | var template = require('lodash.template');
13 |
14 | var imports = {imports: helpers};
15 |
16 | describe('collections', function() {
17 | describe('any', function() {
18 | it('should be false undefined.', function() {
19 | assert.equal(template('<%= any() %>', imports)(), 'false');
20 | });
21 | it('should return if a value exists in the given string.', function() {
22 | assert.equal(template('<%= any("a-b-c", "a") %>', imports)(context), 'true');
23 | assert.equal(template('<%= any("a-b-c", "d") %>', imports)(context), 'false');
24 | });
25 | it('should return if a value exists in the given object.', function() {
26 | assert.equal(template('<%= any({a: "b", c: "d"}, "a") %>', imports)(context), 'true');
27 | assert.equal(template('<%= any([{a: "b", c: "d"}], {a: "b"}) %>', imports)(context), 'true');
28 | });
29 | it('should return if a value exists in the given array.', function() {
30 | assert.equal(template('<%= any("a-b-c", "d") %>', imports)(context), 'false');
31 | });
32 | });
33 |
34 | describe('filter', function() {
35 | it('should return an empty string when undefined.', function() {
36 | assert.equal(template('<%= filter() %>', imports)(), '');
37 | });
38 | it('should return a string value if it exists in the given array', function() {
39 | assert.equal(template('<%= filter(["a", "b", "c"], "a") %>', imports)(context), 'a');
40 | });
41 | it('should return an empty string if a string value does not exists', function() {
42 | assert.equal(template('<%= filter(["a", "b", "c"], "d") %>', imports)(context), '');
43 | });
44 | it('should filter out values that match the given regex', function() {
45 | assert.equal(template('<%= filter(["a", "b", "c", "d", "z"], /[a-c]/) %>', imports)(context), 'a,b,c');
46 | });
47 | it('should filter out values using a function', function() {
48 | assert.equal(template('<%= filter(["a", "b", "c", "d", "z"], function(key) { return /(a|z)/.test(key) }) %>', imports)(context), 'a,z');
49 | });
50 | it('should return true if the value equals given string', function() {
51 | assert.equal(template('<%= filter("a", "a") %>', imports)(context), 'true');
52 | });
53 | it('should return false if the value does not equal the given string', function() {
54 | assert.equal(template('<%= filter("a-b-c", "d") %>', imports)(context), 'false');
55 | });
56 | it('should filter out properties that match the given value', function() {
57 | assert.equal(template('<%= stringify(filter({a: "b", c: "d"}, "a")) %>', imports)(context), '{"a":"b"}');
58 | });
59 | it('should filter out objects that match the given value', function() {
60 | assert.equal(template('<%= stringify(filter([{a: "b", c: "d"}], {a: "b"})) %>', imports)(context), '[{"a":"b","c":"d"}]');
61 | });
62 | });
63 | });
64 |
--------------------------------------------------------------------------------
/test/conditional.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * template-helpers
3 | *
4 | * Copyright (c) 2015, Jon Schlinkert.
5 | * Licensed under the MIT License.
6 | */
7 |
8 | 'use strict';
9 |
10 | var assert = require('assert');
11 | var helpers = require('..')('conditional');
12 | var template = require('lodash.template');
13 |
14 | var imports = {imports: helpers};
15 | var context = {
16 | fn: function(a, b) {
17 | return this && this.foo === 'abc';
18 | },
19 | thisArg: {foo: 'abc', bar: 'xyz'}
20 | };
21 |
22 | describe('conditional', function() {
23 | describe('if', function() {
24 | it('should return an empty string when the first arg is not a function.', function() {
25 | assert.equal(template('<%= _if("foo", "bar", thisArg) %>', imports)(context), '');
26 | });
27 | it('should return the first value when `fn` returns true.', function() {
28 | assert.equal(template('<%= _if(fn, "foo", "bar", thisArg) %>', imports)(context), 'foo');
29 | });
30 | it('should return the second value when `fn` returns false.', function() {
31 | assert.equal(template('<%= _if(fn, "foo", "bar") %>', imports)(context), 'bar');
32 | });
33 | });
34 |
35 | describe('compare', function() {
36 | it('should be true when values are equal', function() {
37 | assert.equal(template('<%= compare("foo", "===", "foo") %>', imports)(context), 'true');
38 | assert.equal(template('<%= compare("foo", "==", "foo") %>', imports)(context), 'true');
39 | });
40 |
41 | it('should be false when values are not equal', function() {
42 | assert.equal(template('<%= compare("foo", "===", "bar") %>', imports)(context), 'false');
43 | assert.equal(template('<%= compare("foo", "==", "bar") %>', imports)(context), 'false');
44 | });
45 | });
46 |
47 | describe('is / eq', function() {
48 | it('should be true when values are equal', function() {
49 | assert.equal(template('<%= is("foo", "foo") %>', imports)(context), 'true');
50 | assert.equal(template('<%= eq("foo", "foo") %>', imports)(context), 'true');
51 | });
52 |
53 | it('should be false when values are not equal', function() {
54 | assert.equal(template('<%= is("foo", "bar") %>', imports)(context), 'false');
55 | assert.equal(template('<%= eq("foo", "bar") %>', imports)(context), 'false');
56 | });
57 | });
58 |
59 | describe('isnt / notEq', function() {
60 | it('should be false when values are equal', function() {
61 | assert.equal(template('<%= isnt("foo", "foo") %>', imports)(context), 'false');
62 | assert.equal(template('<%= notEq("foo", "foo") %>', imports)(context), 'false');
63 | });
64 |
65 | it('should be true when values are not equal', function() {
66 | assert.equal(template('<%= isnt("foo", "bar") %>', imports)(context), 'true');
67 | assert.equal(template('<%= notEq("foo", "bar") %>', imports)(context), 'true');
68 | });
69 | });
70 | });
71 |
--------------------------------------------------------------------------------
/test/fixtures/README.md:
--------------------------------------------------------------------------------
1 | # template-helpers [](http://badge.fury.io/js/template-helpers) [](https://travis-ci.org/jonschlinkert/template-helpers)
2 |
3 | > Generic JavaScript helpers that can be used with any template engine. Handlebars, Lo-Dash, Underscore, or any engine that supports helper functions.
4 |
5 | ## Install with [npm](npmjs.org)
6 |
7 | ```bash
8 | npm i template-helpers --save
9 | ```
10 |
11 | ## TOC
12 |
13 |
14 |
15 | - [Usage](#usage)
16 | * [Use with any template engine](#use-with-any-template-engine)
17 | * [Namespacing](#namespacing)
18 | - [Helpers](#helpers)
19 | - [Docs](#docs)
20 | - [Run tests](#run-tests)
21 | - [Related](#related)
22 |
23 |
24 |
25 | ## Usage
26 |
27 | To get all helpers grouped by collection:
28 |
29 | ```js
30 | var helpers = require('template-helpers');
31 |
32 | // All helpers are on the `_` property
33 | console.log(helpers._);
34 | ```
35 |
36 | **Get a specific collection**
37 |
38 | ```js
39 | var helpers = require('template-helpers');
40 |
41 | // get only the math helpers
42 | var math = helpers.math;
43 | ```
44 |
45 | ### Use with any template engine
46 |
47 | **Lo-Dash Example**
48 |
49 | ```js
50 | var context = {arr: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']};
51 |
52 | // pass helpers on `imports`
53 | var imports = {imports: helpers.arrays};
54 | var template = _.template('<%= first(foo) %>', imports);
55 |
56 | // pass context
57 | template({foo: ['a', 'b', 'c']});
58 | //=> 'a'
59 | ```
60 |
61 | ### Namespacing
62 |
63 | Handlebars and Lo-Dash both allow **dot notation** to be used for referencing helpers. Other engines may allow this too, I'd be happy to add this information to readme if someone wants to do a PR.
64 |
65 | **Example**
66 |
67 | ```js
68 | <%= path.dirname("a/b/c/d.js") %>
69 | ```
70 |
71 | This can be used as a way of working around potential naming conflicts.
72 |
73 |
74 | ## Helpers
75 | Currently 87 helpers:
76 |
77 | + **[array](lib/array.js)**
78 | - [after](lib/array.js#L131)
79 | - [arrayify](lib/array.js#L44)
80 | - [before](lib/array.js#L110)
81 | - [compact](lib/array.js#L260)
82 | - [difference](lib/array.js#L280)
83 | - [first](lib/array.js#L62)
84 | - [isArray](lib/array.js#L21)
85 | - [join](lib/array.js#L191)
86 | - [last](lib/array.js#L85)
87 | - [length](lib/array.js#L242)
88 | - [map](lib/array.js#L159)
89 | - [sort](lib/array.js#L217)
90 | - [union](lib/array.js#L347)
91 | - [unique](lib/array.js#L316)
92 | + **[code](lib/code.js)**
93 | - [embed](lib/code.js#L25)
94 | - [jsfiddle](lib/code.js#L51)
95 | + **[collection](lib/collection.js)**
96 | - [any](lib/collection.js#L15)
97 | + **[conditional](lib/conditional.js)**
98 | - [_if](lib/conditional.js#L13)
99 | + **[fs](lib/fs.js)**
100 | - [concat](lib/fs.js#L40)
101 | - [read](lib/fs.js#L19)
102 | + **[html](lib/html.js)**
103 | - [escapeHtml](lib/html.js#L18)
104 | - [sanitize](lib/html.js#L46)
105 | + **[math](lib/math.js)**
106 | - [add](lib/math.js#L19)
107 | - [ceil](lib/math.js#L108)
108 | - [divide](lib/math.js#L54)
109 | - [floor](lib/math.js#L90)
110 | - [multiply](lib/math.js#L72)
111 | - [round](lib/math.js#L129)
112 | - [subtract](lib/math.js#L36)
113 | - [sum](lib/math.js#L146)
114 | + **[object](lib/object.js)**
115 | - [extend](lib/object.js#L224)
116 | - [fallback](lib/object.js#L25)
117 | - [forIn](lib/object.js#L187)
118 | - [forOwn](lib/object.js#L207)
119 | - [get](lib/object.js#L77)
120 | - [hasOwn](lib/object.js#L152)
121 | - [isObject](lib/object.js#L115)
122 | - [isPlainObject](lib/object.js#L138)
123 | - [keys](lib/object.js#L94)
124 | - [merge](lib/object.js#L253)
125 | - [omit](lib/object.js#L170)
126 | - [parse](lib/object.js#L59)
127 | - [stringify](lib/object.js#L42)
128 | + **[path](lib/path.js)**
129 | - [basename](lib/path.js#L38)
130 | - [dirname](lib/path.js#L20)
131 | - [ext](lib/path.js#L92)
132 | - [extname](lib/path.js#L74)
133 | - [filename](lib/path.js#L56)
134 | - [isAbsolute](lib/path.js#L210)
135 | - [isRelative](lib/path.js#L245)
136 | - [join](lib/path.js#L175)
137 | - [relative](lib/path.js#L129)
138 | - [resolve](lib/path.js#L110)
139 | - [segments](lib/path.js#L153)
140 | + **[string](lib/string.js)**
141 | - [camelcase](lib/string.js#L142)
142 | - [centerAlign](lib/string.js#L408)
143 | - [chop](lib/string.js#L123)
144 | - [count](lib/string.js#L352)
145 | - [dashcase](lib/string.js#L230)
146 | - [dotcase](lib/string.js#L206)
147 | - [ellipsis](lib/string.js#L476)
148 | - [hyphenate](lib/string.js#L293)
149 | - [isString](lib/string.js#L23)
150 | - [lowercase](lib/string.js#L61)
151 | - [pascalcase](lib/string.js#L164)
152 | - [pathcase](lib/string.js#L252)
153 | - [replace](lib/string.js#L428)
154 | - [reverse](lib/string.js#L370)
155 | - [rightAlign](lib/string.js#L389)
156 | - [sentencecase](lib/string.js#L274)
157 | - [slugify](lib/string.js#L313)
158 | - [snakecase](lib/string.js#L184)
159 | - [toString](lib/string.js#L44)
160 | - [trim](lib/string.js#L98)
161 | - [truncate](lib/string.js#L455)
162 | - [uppercase](lib/string.js#L79)
163 | - [wordwrap](lib/string.js#L332)
164 |
165 | ## Docs
166 |
167 |
168 | ## Run tests
169 | Install dev dependencies.
170 |
171 | ```bash
172 | npm i -d && npm test
173 | ```
174 |
175 | ## Related
176 | * [handlebars-helpers](https://github.com/assemble/handlebars-helpers): 120+ Handlebars helpers in ~20 categories, for Assemble, YUI, Ghost or any Handlebars project. Includes helpers like {{i18}}, {{markdown}}, {{relative}}, {{extend}}, {{moment}}, and so on.
177 |
178 | ## Contributing
179 | Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](https://github.com/jonschlinkert/template-helpers/issues)
180 |
181 | ## Author
182 |
183 | **Jon Schlinkert**
184 |
185 | + [github/jonschlinkert](https://github.com/jonschlinkert)
186 | + [twitter/jonschlinkert](http://twitter.com/jonschlinkert)
187 |
188 | ## License
189 | Copyright (c) 2015 Jon Schlinkert
190 | Released under the MIT license
191 |
192 | ***
193 |
194 | _This file was generated by [verb-cli](https://github.com/assemble/verb-cli) on March 11, 2015._
195 |
196 | [assemble]: https://github.com/assemble/assemble
197 | [verb]: https://github.com/assemble/verb
198 | [template]: https://github.com/jonschlinkert/template
199 | [word-wrap]: https://github.com/jonschlinkert/word-wrap
200 | [helper-concat]: https://github.com/helpers/helper-concat
201 | [path]: https://nodejs.org/api/path.html
202 |
--------------------------------------------------------------------------------
/test/fixtures/a.js:
--------------------------------------------------------------------------------
1 | function foo(a, b, c) {
2 | return a + b + c;
3 | }
--------------------------------------------------------------------------------
/test/fixtures/a.md:
--------------------------------------------------------------------------------
1 | ```
2 | foo
3 | ```
--------------------------------------------------------------------------------
/test/fixtures/b.js:
--------------------------------------------------------------------------------
1 | function bar(x, y, z) {
2 | return x + y + z;
3 | }
--------------------------------------------------------------------------------
/test/fs.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * template-helpers
3 | *
4 | * Copyright (c) 2015, Jon Schlinkert.
5 | * Licensed under the MIT License.
6 | */
7 |
8 | 'use strict';
9 |
10 | var assert = require('assert');
11 | var helpers = require('..')('fs');
12 | var template = require('lodash.template');
13 |
14 | var imports = { imports: helpers };
15 |
16 | describe('fs', function() {
17 | describe('exists', function() {
18 | it('should return false when the file does not exist.', function() {
19 | assert.equal(template('<%= exists("fooosos.js") %>', imports)(), 'false');
20 | });
21 | });
22 |
23 | describe('read', function() {
24 | it('should return an empty string when the file does not exist.', function() {
25 | assert.equal(template('<%= read("fooosos.js") %>', imports)(), '');
26 | });
27 |
28 | it('should read a file and inject its content.', function() {
29 | assert.equal(template('<%= read("test/fixtures/a.js") %>', imports)(), [
30 | 'function foo(a, b, c) {',
31 | ' return a + b + c;',
32 | '}'
33 | ].join('\n'));
34 | });
35 | });
36 | });
37 |
--------------------------------------------------------------------------------
/test/html.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * template-helpers
3 | *
4 | * Copyright (c) 2015, Jon Schlinkert.
5 | * Licensed under the MIT License.
6 | */
7 |
8 | 'use strict';
9 |
10 | var assert = require('assert');
11 | var helpers = require('..')('html');
12 | var template = require('lodash.template');
13 |
14 | var imports = {imports: helpers};
15 |
16 | describe('html', function() {
17 | describe('escapeHtml', function() {
18 | it('should return an empty string when undefined.', function() {
19 | assert.equal(template('<%= escapeHtml() %>', imports)(), '');
20 | });
21 |
22 | it('should return create a code example from the given file.', function() {
23 | assert.equal(template('<%= escapeHtml("foo") %>', imports)(), '<span>foo</span>');
24 | });
25 | });
26 |
27 | describe('sanitize', function() {
28 | it('should return an empty string when undefined.', function() {
29 | assert.equal(template('<%= sanitize() %>', imports)(), '');
30 | });
31 | it('should strip html from a string.', function() {
32 | var actual = template('<%= sanitize("foo") %>', imports)();
33 | assert.equal(actual, 'foo');
34 | });
35 | });
36 | });
37 |
--------------------------------------------------------------------------------
/test/math.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * template-helpers
3 | *
4 | * Copyright (c) 2015, Jon Schlinkert.
5 | * Licensed under the MIT License.
6 | */
7 |
8 | 'use strict';
9 |
10 | var assert = require('assert');
11 | var helpers = require('..')('math');
12 | var template = require('lodash.template');
13 |
14 | var imports = {imports: helpers};
15 |
16 | describe('math helpers', function() {
17 | describe('add', function() {
18 | it('should return a plus b', function() {
19 | assert.equal(template('<%= add(5, 5) %>', imports)(), '10');
20 | });
21 | });
22 |
23 | describe('subtract', function() {
24 | it('should return a minus b.', function() {
25 | assert.equal(template('<%= subtract(10, 2) %>', imports)(), '8');
26 | });
27 | });
28 |
29 | describe('divide', function() {
30 | it('should divide a by b.', function() {
31 | assert.equal(template('<%= divide(30, 10) %>', imports)(), '3');
32 | });
33 | });
34 |
35 | describe('multiply', function() {
36 | it('should multiply a by b.', function() {
37 | assert.equal(template('<%= multiply(30, 10) %>', imports)(), '300');
38 | });
39 | });
40 |
41 | describe('floor', function() {
42 | it('should floor `num`.', function() {
43 | assert.equal(template('<%= floor(55.5) %>', imports)(), '55');
44 | });
45 | });
46 |
47 | describe('ceil', function() {
48 | it('should ceil `num`.', function() {
49 | assert.equal(template('<%= ceil(55.5) %>', imports)(), '56');
50 | });
51 | });
52 |
53 | describe('round', function() {
54 | it('should round a number.', function() {
55 | assert.equal(template('<%= round(21.1) %>', imports)(), '21');
56 | assert.equal(template('<%= round(21.5) %>', imports)(), '22');
57 | });
58 | });
59 |
60 | describe('sum.', function() {
61 | it('should reduce-sum the numbers in the array.', function() {
62 | assert.equal(template('<%= sum([1, 2, 3, 4, 5]) %>', imports)(), '15');
63 | });
64 | it('should ignore non-numbers.', function() {
65 | assert.equal(template('<%= sum([1, 2, "foo", 3, 4, 5]) %>', imports)(), '15');
66 | });
67 | });
68 | });
69 |
--------------------------------------------------------------------------------
/test/object.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * template-helpers
3 | *
4 | * Copyright (c) 2015, Jon Schlinkert.
5 | * Licensed under the MIT License.
6 | */
7 |
8 | 'use strict';
9 |
10 | var assert = require('assert');
11 | var helpers = require('..')('object');
12 | var template = require('lodash.template');
13 |
14 | var context = {obj: {a: 'a', b: 'b', c: {d: {e: 'e'}}}};
15 | var imports = {imports: helpers};
16 |
17 | describe('objects', function() {
18 | describe('fallback', function() {
19 | it('should use the fallback value when the first value is undefined.', function() {
20 | assert.equal(template('<%= fallback(a.b) %>', imports)({a: {b: 'b'}}), 'b');
21 | assert.equal(template('<%= fallback(a.z, a.b) %>', imports)({a: {b: 'b'}}), 'b');
22 | assert.equal(template('<%= fallback(x.k, x.z) %>', imports)({x: {z: 'z'}}), 'z');
23 | });
24 | });
25 |
26 | describe('stringify', function() {
27 | it('should stringify an object.', function() {
28 | assert.equal(template('<%= stringify({a: "a"}) %>', imports)(context), '{"a":"a"}');
29 | assert.equal(template('<%= stringify(obj.c) %>', imports)(context), '{"d":{"e":"e"}}');
30 | });
31 | });
32 |
33 | describe('parse', function() {
34 | it('should parse a string to an object:', function() {
35 | assert.equal(template('<%= parse(\'{"foo":"bar"}\') %>', imports)(context), '[object Object]');
36 | assert.equal(template('<%= parse(\'{"foo":"bar"}\')["foo"] %>', imports)(context), 'bar');
37 | });
38 | });
39 |
40 | describe('isObject', function() {
41 | it('should return true if the value is an object.', function() {
42 | assert.equal(template('<%= isObject(obj) %>', imports)(context), 'true');
43 | assert.equal(template('<%= isObject([]) %>', imports)(context), 'false');
44 | assert.equal(template('<%= isObject("foo") %>', imports)(context), 'false');
45 | });
46 | });
47 |
48 | describe('isPlainObject', function() {
49 | it('should return true if the value is a plain object.', function() {
50 | assert.equal(template('<%= isPlainObject(obj) %>', imports)(context), 'true');
51 | assert.equal(template('<%= isPlainObject([]) %>', imports)(context), 'false');
52 | assert.equal(template('<%= isPlainObject(/foo/) %>', imports)(context), 'false');
53 | assert.equal(template('<%= isPlainObject("foo") %>', imports)(context), 'false');
54 | });
55 | });
56 |
57 | describe('hasOwn', function() {
58 | it('should return true when an object has own property `key`.', function() {
59 | assert.equal(template('<%= hasOwn(obj, "a") %>', imports)(context), 'true');
60 | assert.equal(template('<%= hasOwn(obj, "k") %>', imports)(context), 'false');
61 | });
62 | });
63 |
64 | describe('keys', function() {
65 | it('should return the keys of an object.', function() {
66 | assert.equal(template('<%= keys(obj) %>', imports)(context), ['a', 'b', 'c'].toString());
67 | });
68 | });
69 |
70 | describe('forIn', function() {
71 | it('should expose the keys on an object.', function() {
72 | var context = {values: {a: 'b', c: 'd'}}
73 | var actual = template('<% forIn(values, function(val, key) { %><%= key %><% }) %>', imports)(context);
74 | assert.equal(actual, 'ac');
75 | });
76 |
77 | it('should expose the values on an object.', function() {
78 | var context = {values: {a: 'b', c: 'd'}}
79 | var actual = template('<% forIn(values, function(val, key) { %><%= val %><% }) %>', imports)(context);
80 | assert.equal(actual, 'bd');
81 | });
82 | });
83 |
84 | describe('forOwn', function() {
85 | it('should expose the keys on an object.', function() {
86 | var context = { values: { a: 'b', c: 'd' } };
87 | var actual = template('<% forOwn(values, function(val, key) { %><%= key %><% }) %>', imports)(context);
88 | assert.equal(actual, 'ac');
89 | });
90 |
91 | it('should expose the values on an object.', function() {
92 | var context = {values: {a: 'b', c: 'd'}}
93 | var actual = template('<% forOwn(values, function(val, key) { %><%= val %><% }) %>', imports)(context);
94 | assert.equal(actual, 'bd');
95 | });
96 | });
97 |
98 | describe('omit', function() {
99 | it('should omit keys from an object.', function() {
100 | var actual = template('<%= stringify(omit(obj, ["b", "c"])) %>', imports)(context);
101 | assert.equal(actual, '{"a":"a"}');
102 | });
103 | });
104 |
105 | describe('extend', function() {
106 | beforeEach(function() {
107 | context.foo = {aaa: 'bbb'};
108 | context.bar = {ccc: 'ddd'};
109 | });
110 | it('should return an empty string when undefined.', function() {
111 | assert.equal(template('<%= extend() %>', imports)(), '');
112 | });
113 |
114 | it('should ignore non-objects.', function() {
115 | var actual = template('<%= stringify(extend(foo, bar, "baz")) %>', imports)(context);
116 | assert.equal(actual, '{"aaa":"bbb","ccc":"ddd"}');
117 | });
118 |
119 | it('should extend the first object with the second.', function() {
120 | var actual = template('<%= stringify(extend(foo, bar)) %>', imports)(context);
121 | assert.equal(actual, '{"aaa":"bbb","ccc":"ddd"}');
122 | });
123 |
124 | it('should use the extended object as context.', function() {
125 | // overwrite `foo`
126 | context.bar = {aaa: 'ddd'};
127 | var actual = template('<%= get(extend(foo, bar), "aaa") %>', imports)(context);
128 | assert.equal(actual, 'ddd');
129 | });
130 | });
131 |
132 | describe('merge', function() {
133 | beforeEach(function() {
134 | context.foo = {aaa: 'bbb', bbb: {ccc: {ddd: 'eee'}}};
135 | context.bar = {aaa: 'bbb', bbb: {ccc: {eee: 'fff'}}};
136 | context.baz = {aaa: 'bbb', bbb: {ccc: {fff: 'ggg'}}};
137 | });
138 | it('should return an empty string when undefined.', function() {
139 | assert.equal(template('<%= merge() %>', imports)(), '');
140 | });
141 | it('should merge objects.', function() {
142 | var actual = template('<%= stringify(merge(foo, bar)) %>', imports)(context);
143 | assert.equal(actual, '{"aaa":"bbb","bbb":{"ccc":{"ddd":"eee","eee":"fff"}}}');
144 | });
145 | it('should merge multiple objects:', function() {
146 | var actual = template('<%= stringify(merge(foo, bar, baz)) %>', imports)(context);
147 | assert.equal(actual, '{"aaa":"bbb","bbb":{"ccc":{"ddd":"eee","eee":"fff","fff":"ggg"}}}');
148 | });
149 | });
150 | });
151 |
--------------------------------------------------------------------------------
/test/path.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * template-helpers
3 | *
4 | * Copyright (c) 2015, Jon Schlinkert.
5 | * Licensed under the MIT License.
6 | */
7 |
8 | 'use strict';
9 |
10 | const path = require('path');
11 | const assert = require('assert');
12 | const template = require('lodash.template');
13 | const helpers = require('..')('path');
14 | const imports = { imports: helpers };
15 |
16 | describe('path helpers', function() {
17 | if (process.platform === 'win32') {
18 | this.skip();
19 | return;
20 | }
21 |
22 | describe('dirname', function() {
23 | it('should return the dirname:', function() {
24 | assert.strictEqual(template('<%= dirname("a/b/c/e.js") %>', imports)(), 'a/b/c');
25 | assert.strictEqual(template('<%= path.dirname("a/b/c/e.js") %>', imports)(), 'a/b/c');
26 | });
27 | });
28 | describe('basename', function() {
29 | it('should return the basename:', function() {
30 | assert.strictEqual(template('<%= basename("a/b/c/e.js") %>', imports)(), 'e.js');
31 | assert.strictEqual(template('<%= path.basename("a/b/c/e.js") %>', imports)(), 'e.js');
32 | });
33 | });
34 | describe('filename', function() {
35 | it('should return the filename:', function() {
36 | assert.strictEqual(template('<%= filename("a/b/c/e.js") %>', imports)(), 'e');
37 | assert.strictEqual(template('<%= path.filename("a/b/c/e.js") %>', imports)(), 'e');
38 | });
39 | });
40 | describe('extname', function() {
41 | it('should return the extname with dot:', function() {
42 | assert.strictEqual(template('<%= extname("a/b/c/e.js") %>', imports)(), '.js');
43 | assert.strictEqual(template('<%= path.extname("a/b/c/e.js") %>', imports)(), '.js');
44 | });
45 | });
46 | describe('ext', function() {
47 | it('should return the extension without dot:', function() {
48 | assert.strictEqual(template('<%= ext("a/b/c/e.js") %>', imports)(), 'js');
49 | assert.strictEqual(template('<%= path.ext("a/b/c/e.js") %>', imports)(), 'js');
50 | });
51 | });
52 | describe('resolve', function() {
53 | it('should resolve the given path(s):', function() {
54 | assert.strictEqual(template('<%= resolve("c/e.js") %>', imports)(), path.resolve('c/e.js'));
55 | assert.strictEqual(template('<%= path.resolve("c/e.js") %>', imports)(), path.resolve('c/e.js'));
56 | });
57 | });
58 | describe('relative', function() {
59 | it('should return a relative file path:', function() {
60 | assert.strictEqual(template('<%= relative("docs/", "docs/a/b.js") %>', imports)(), 'a/b.js');
61 | assert.strictEqual(template('<%= path.relative("docs/", "docs/a/b.js") %>', imports)(), 'a/b.js');
62 | assert.strictEqual(template('<%= relative("docs/a/b.js", "docs/") %>', imports)(), '..');
63 | assert.strictEqual(template('<%= path.relative("docs/a/b.js", "docs/") %>', imports)(), '..');
64 | });
65 | });
66 |
67 | describe('isRelative', function() {
68 | it('should return true if a file path is isRelative:', function() {
69 | assert.strictEqual(template('<%= isRelative("/foo/bar") %>', imports)(), 'false');
70 | assert.strictEqual(template('<%= path.isRelative("/foo/bar") %>', imports)(), 'false');
71 | assert.strictEqual(template('<%= isRelative("/baz/..") %>', imports)(), 'false');
72 | assert.strictEqual(template('<%= path.isRelative("/baz/..") %>', imports)(), 'false');
73 | assert.strictEqual(template('<%= isRelative("qux/") %>', imports)(), 'true');
74 | assert.strictEqual(template('<%= path.isRelative("qux/") %>', imports)(), 'true');
75 | assert.strictEqual(template('<%= isRelative(".") %>', imports)(), 'true');
76 | assert.strictEqual(template('<%= path.isRelative(".") %>', imports)(), 'true');
77 | assert.strictEqual(template('<%= isRelative("//server") %>', imports)(), 'false');
78 | assert.strictEqual(template('<%= path.isRelative("//server") %>', imports)(), 'false');
79 | assert.strictEqual(template('<%= isRelative("bar\\baz") %>', imports)(), 'true');
80 | assert.strictEqual(template('<%= path.isRelative("bar\\baz") %>', imports)(), 'true');
81 | assert.strictEqual(template('<%= isRelative(".") %>', imports)(), 'true');
82 | assert.strictEqual(template('<%= path.isRelative(".") %>', imports)(), 'true');
83 | });
84 | });
85 |
86 | describe('isAbsolute', function() {
87 | it('should return true if a file path is absolute:', function() {
88 | assert.strictEqual(template('<%= isAbsolute("/foo/bar") %>', imports)(), 'true');
89 | assert.strictEqual(template('<%= path.isAbsolute("/foo/bar") %>', imports)(), 'true');
90 | assert.strictEqual(template('<%= isAbsolute("/baz/..") %>', imports)(), 'true');
91 | assert.strictEqual(template('<%= path.isAbsolute("/baz/..") %>', imports)(), 'true');
92 | assert.strictEqual(template('<%= isAbsolute("qux/") %>', imports)(), 'false');
93 | assert.strictEqual(template('<%= path.isAbsolute("qux/") %>', imports)(), 'false');
94 | assert.strictEqual(template('<%= isAbsolute(".") %>', imports)(), 'false');
95 | assert.strictEqual(template('<%= path.isAbsolute(".") %>', imports)(), 'false');
96 | assert.strictEqual(template('<%= isAbsolute("//server") %>', imports)(), 'true');
97 | assert.strictEqual(template('<%= path.isAbsolute("//server") %>', imports)(), 'true');
98 | assert.strictEqual(template('<%= isAbsolute("bar\\baz") %>', imports)(), 'false');
99 | assert.strictEqual(template('<%= path.isAbsolute("bar\\baz") %>', imports)(), 'false');
100 | assert.strictEqual(template('<%= isAbsolute(".") %>', imports)(), 'false');
101 | assert.strictEqual(template('<%= path.isAbsolute(".") %>', imports)(), 'false');
102 | });
103 | });
104 |
105 | describe('join', function() {
106 | it('should join the given paths:', function() {
107 | assert.strictEqual(template('<%= join("a", "b") %>', imports)(), 'a/b');
108 | assert.strictEqual(template('<%= path.join("a", "b") %>', imports)(), 'a/b');
109 | });
110 | });
111 |
112 | describe('segments', function() {
113 | it('should return specified path segments:', function() {
114 | assert.strictEqual(template('<%= segments("a/b/c/e.js", 1, 3) %>', imports)(), 'b/c');
115 | assert.strictEqual(template('<%= path.segments("a/b/c/e.js", 1, 3) %>', imports)(), 'b/c');
116 | assert.strictEqual(template('<%= segments("a/b/c/e.js", 1, 2) %>', imports)(), 'b');
117 | assert.strictEqual(template('<%= path.segments("a/b/c/e.js", 1, 2) %>', imports)(), 'b');
118 | assert.strictEqual(template('<%= segments("a/b/c/e.js", 0, 3) %>', imports)(), 'a/b/c');
119 | assert.strictEqual(template('<%= path.segments("a/b/c/e.js", 0, 3) %>', imports)(), 'a/b/c');
120 | assert.strictEqual(template('<%= segments("a/b/c/e.js", 2, 3) %>', imports)(), 'c');
121 | assert.strictEqual(template('<%= path.segments("a/b/c/e.js", 2, 3) %>', imports)(), 'c');
122 | assert.strictEqual(template('<%= segments("a/b/c/e.js", 0, 3) %>', imports)(), 'a/b/c');
123 | assert.strictEqual(template('<%= path.segments("a/b/c/e.js", 0, 3) %>', imports)(), 'a/b/c');
124 | });
125 |
126 | it('should disregard extra slashes:', function() {
127 | assert.strictEqual(template('<%= segments("a///b\\/c\\/e.js", 1, 3) %>', imports)(), 'b/c');
128 | assert.strictEqual(template('<%= path.segments("a///b\\/c\\/e.js", 1, 3) %>', imports)(), 'b/c');
129 | assert.strictEqual(template('<%= segments("a///b/\\//c/e.js", 1, 2) %>', imports)(), 'b');
130 | assert.strictEqual(template('<%= path.segments("a///b/\\//c/e.js", 1, 2) %>', imports)(), 'b');
131 | });
132 | });
133 | });
134 |
--------------------------------------------------------------------------------
/test/string.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * template-helpers
3 | *
4 | * Copyright (c) 2015, Jon Schlinkert.
5 | * Licensed under the MIT License.
6 | */
7 |
8 | 'use strict';
9 |
10 | const assert = require('assert');
11 | const template = require('lodash.template');
12 | const helpers = require('..')(['string', 'html']);
13 | const imports = { imports: helpers };
14 |
15 | describe('string helpers', function() {
16 | describe('lowercase', function() {
17 | it('should return an empty string when undefined.', function() {
18 | assert.equal(template('<%= lowercase() %>', imports)(), '');
19 | });
20 | it('should lower case the characters in a string.', function() {
21 | var fn = template('<%= lowercase("ABC") %>', imports);
22 | assert.equal(fn(), 'abc');
23 | });
24 | });
25 |
26 | describe('uppercase', function() {
27 | it('should return an empty string when undefined.', function() {
28 | assert.equal(template('<%= uppercase() %>', imports)(), '');
29 | });
30 | it('should upper case the characters in a string.', function() {
31 | var fn = template('<%= uppercase("abc") %>', imports);
32 | assert.equal(fn(), 'ABC');
33 | });
34 | });
35 |
36 | describe('trim', function() {
37 | it('should return an empty string when undefined.', function() {
38 | assert.equal(template('<%= trim() %>', imports)(), '');
39 | });
40 | it('should strip leading whitespace from a string.', function() {
41 | var fn = template('<%= trim(" abc") %>', imports);
42 | assert.equal(fn(), 'abc');
43 | });
44 | it('should strip trailing whitespace from a string.', function() {
45 | var fn = template('<%= trim("abc ") %>', imports);
46 | assert.equal(fn(), 'abc');
47 | });
48 | });
49 |
50 | describe('chop', function() {
51 | it('should return an empty string when undefined.', function() {
52 | assert.equal(template('<%= chop() %>', imports)(), '');
53 | });
54 | it('should strip leading whitespace from a string.', function() {
55 | var fn = template('<%= chop(" abc") %>', imports);
56 | assert.equal(fn(), 'abc');
57 | });
58 | it('should strip trailing whitespace from a string.', function() {
59 | var fn = template('<%= chop("abc ") %>', imports);
60 | assert.equal(fn(), 'abc');
61 | });
62 | it('should strip leading non-word characters from a string.', function() {
63 | var fn = template('<%= chop("_-abc") %>', imports);
64 | assert.equal(fn(), 'abc');
65 | });
66 | it('should strip trailing non-word characters from a string.', function() {
67 | var fn = template('<%= chop("abc_-") %>', imports);
68 | assert.equal(fn(), 'abc');
69 | });
70 | });
71 |
72 | describe('strip', function() {
73 | it('should return an empty string when undefined.', function() {
74 | assert.equal(template('<%= strip() %>', imports)(), '');
75 | });
76 | it('should strip the given substring from a string.', function() {
77 | var fn = template('<%= strip("foo", "foobar") %>', imports);
78 | assert.equal(fn(), 'bar');
79 | });
80 | it('should strip the given regex match from a string.', function() {
81 | var fn = template('<%= strip(/^foo/, "foobarfoo") %>', imports);
82 | assert.equal(fn(), 'barfoo');
83 | });
84 | });
85 |
86 | describe('stripIndent', function() {
87 | it('should return an empty string when undefined.', function() {
88 | assert.equal(template('<%= stripIndent() %>', imports)(), '');
89 | });
90 | it('should strip indentation from a string.', function() {
91 | var str = template('<%= stripIndent(str) %>', imports)({
92 | str: [' - a', ' - b', ' * c', ' * d', ' + e', ' + f'].join('\n')
93 | });
94 | assert.equal(str, ['- a', '- b', ' * c', ' * d', ' + e', ' + f'].join('\n'));
95 | });
96 | });
97 |
98 | describe('camelcase', function() {
99 | it('should return an empty string when undefined.', function() {
100 | assert.equal(template('<%= camelcase() %>', imports)(), '');
101 | });
102 | it('should camel-case the characters in a string.', function() {
103 | assert.equal(template('<%= camelcase("foo bar baz") %>', imports)(), 'fooBarBaz');
104 | });
105 | it('should camel-case the characters in a string.', function() {
106 | assert.equal(template('<%= camelcase("A") %>', imports)(), 'a');
107 | });
108 | it('should work with hyphens.', function() {
109 | assert.equal(template('<%= camelcase("foo-bar-baz") %>', imports)(), 'fooBarBaz');
110 | assert.equal(template('<%= camelcase("-foo bar baz-") %>', imports)(), 'fooBarBaz');
111 | });
112 |
113 | it('should work with other non-word characters.', function() {
114 | assert.equal(template('<%= camelcase("9foo-bar_baz") %>', imports)(), '9fooBarBaz');
115 | assert.equal(template('<%= camelcase("_foo_bar_baz-") %>', imports)(), 'fooBarBaz');
116 | });
117 | });
118 |
119 | describe('pascalcase', function() {
120 | it('should return an empty string when undefined.', function() {
121 | assert.equal(template('<%= pascalcase() %>', imports)(), '');
122 | });
123 | it('should camel-case the characters in a string.', function() {
124 | assert.equal(template('<%= pascalcase("a") %>', imports)(), 'A');
125 | assert.equal(template('<%= pascalcase("A") %>', imports)(), 'A');
126 | });
127 | it('should pascal-case the characters in a string.', function() {
128 | assert.equal(template('<%= pascalcase("foo bar baz") %>', imports)(), 'FooBarBaz');
129 | });
130 | it('should work with hyphens.', function() {
131 | assert.equal(template('<%= pascalcase("foo-bar-baz") %>', imports)(), 'FooBarBaz');
132 | assert.equal(template('<%= pascalcase("-foo bar baz-") %>', imports)(), 'FooBarBaz');
133 | });
134 |
135 | it('should work with other non-word characters.', function() {
136 | assert.equal(template('<%= pascalcase("9foo-bar_baz") %>', imports)(), '9fooBarBaz');
137 | assert.equal(template('<%= pascalcase("_foo_bar_baz-") %>', imports)(), 'FooBarBaz');
138 | });
139 | });
140 |
141 | describe('snakecase', function() {
142 | it('should return an empty string when undefined.', function() {
143 | assert.equal(template('<%= snakecase() %>', imports)(), '');
144 | });
145 | it('should camel-case the characters in a string.', function() {
146 | assert.equal(template('<%= snakecase("A") %>', imports)(), 'a');
147 | });
148 | it('should snake-case the characters in a string.', function() {
149 | assert.equal(template('<%= snakecase("foo bar baz") %>', imports)(), 'foo_bar_baz');
150 | });
151 | it('should work with hyphens.', function() {
152 | assert.equal(template('<%= snakecase("foo-bar-baz") %>', imports)(), 'foo_bar_baz');
153 | assert.equal(template('<%= snakecase("-foo bar baz-") %>', imports)(), 'foo_bar_baz');
154 | });
155 |
156 | it('should work with other non-word characters.', function() {
157 | assert.equal(template('<%= snakecase("9foo-bar_baz") %>', imports)(), '9foo_bar_baz');
158 | assert.equal(template('<%= snakecase("_foo_bar_baz-") %>', imports)(), 'foo_bar_baz');
159 | });
160 | });
161 |
162 | describe('dotcase', function() {
163 | it('should return an empty string when undefined.', function() {
164 | assert.equal(template('<%= dotcase() %>', imports)(), '');
165 | });
166 | it('should camel-case the characters in a string.', function() {
167 | assert.equal(template('<%= dotcase("A") %>', imports)(), 'a');
168 | });
169 | it('should dot-case the characters in a string.', function() {
170 | assert.equal(template('<%= dotcase("foo bar baz") %>', imports)(), 'foo.bar.baz');
171 | });
172 | it('should work with hyphens.', function() {
173 | assert.equal(template('<%= dotcase("foo-bar-baz") %>', imports)(), 'foo.bar.baz');
174 | assert.equal(template('<%= dotcase("-foo bar baz-") %>', imports)(), 'foo.bar.baz');
175 | });
176 |
177 | it('should work with other non-word characters.', function() {
178 | assert.equal(template('<%= dotcase("9foo-bar_baz") %>', imports)(), '9foo.bar.baz');
179 | assert.equal(template('<%= dotcase("_foo_bar_baz-") %>', imports)(), 'foo.bar.baz');
180 | });
181 | });
182 |
183 | describe('dashcase', function() {
184 | it('should return an empty string when undefined.', function() {
185 | assert.equal(template('<%= dashcase() %>', imports)(), '');
186 | });
187 | it('should camel-case the characters in a string.', function() {
188 | assert.equal(template('<%= dashcase("A") %>', imports)(), 'a');
189 | });
190 | it('should dash-case the characters in a string.', function() {
191 | assert.equal(template('<%= dashcase("foo bar baz") %>', imports)(), 'foo-bar-baz');
192 | });
193 | it('should work with hyphens.', function() {
194 | assert.equal(template('<%= dashcase("foo-bar-baz") %>', imports)(), 'foo-bar-baz');
195 | assert.equal(template('<%= dashcase("-foo bar baz-") %>', imports)(), 'foo-bar-baz');
196 | });
197 |
198 | it('should work with other non-word characters.', function() {
199 | assert.equal(template('<%= dashcase("9foo-bar_baz") %>', imports)(), '9foo-bar-baz');
200 | assert.equal(template('<%= dashcase("_foo_bar_baz-") %>', imports)(), 'foo-bar-baz');
201 | });
202 | });
203 |
204 | describe('pathcase', function() {
205 | it('should return an empty string when undefined.', function() {
206 | assert.equal(template('<%= pathcase() %>', imports)(), '');
207 | });
208 | it('should camel-case the characters in a string.', function() {
209 | assert.equal(template('<%= pathcase("A") %>', imports)(), 'a');
210 | });
211 | it('should path-case the characters in a string.', function() {
212 | assert.equal(template('<%= pathcase("foo bar baz") %>', imports)(), 'foo/bar/baz');
213 | });
214 | it('should work with hyphens.', function() {
215 | assert.equal(template('<%= pathcase("foo-bar-baz") %>', imports)(), 'foo/bar/baz');
216 | assert.equal(template('<%= pathcase("-foo bar baz-") %>', imports)(), 'foo/bar/baz');
217 | });
218 |
219 | it('should work with other non-word characters.', function() {
220 | assert.equal(template('<%= pathcase("9foo-bar_baz") %>', imports)(), '9foo/bar/baz');
221 | assert.equal(template('<%= pathcase("_foo_bar_baz-") %>', imports)(), 'foo/bar/baz');
222 | });
223 | });
224 |
225 | describe('sentencecase', function() {
226 | it('should return an empty string when undefined.', function() {
227 | assert.equal(template('<%= sentencecase() %>', imports)(), '');
228 | });
229 | it('should camel-case the characters in a string.', function() {
230 | assert.equal(template('<%= sentencecase("A") %>', imports)(), 'A');
231 | assert.equal(template('<%= sentencecase("a") %>', imports)(), 'A');
232 | });
233 | it('should sentence-case the characters in a string.', function() {
234 | assert.equal(template('<%= sentencecase("foo bar baz.") %>', imports)(), 'Foo bar baz.');
235 | assert.equal(template('<%= sentencecase("a") %>', imports)(), 'A');
236 | });
237 | });
238 |
239 | describe('hyphenate', function() {
240 | it('should return an empty string when undefined.', function() {
241 | assert.equal(template('<%= hyphenate() %>', imports)(), '');
242 | });
243 | it('should hyphenate the characters in a string.', function() {
244 | assert.equal(template('<%= hyphenate("foo bar baz") %>', imports)(), 'foo-bar-baz');
245 | });
246 | it('should work with hyphens.', function() {
247 | assert.equal(template('<%= hyphenate("foo-bar-baz") %>', imports)(), 'foo-bar-baz');
248 | assert.equal(template('<%= hyphenate("-foo bar baz-") %>', imports)(), 'foo-bar-baz');
249 | });
250 |
251 | it('should work with other non-word characters.', function() {
252 | assert.equal(template('<%= hyphenate("9foo-bar_baz") %>', imports)(), '9foo-bar_baz');
253 | assert.equal(template('<%= hyphenate("_foo_bar_baz-") %>', imports)(), 'foo_bar_baz');
254 | });
255 | });
256 |
257 | describe('slugify', function() {
258 | it('should return an empty string when undefined.', function() {
259 | assert.equal(template('<%= slugify() %>', imports)(), '');
260 | });
261 |
262 | it('should slugify the characters in a string.', function() {
263 | assert.equal(template('<%= slugify("foo bar baz") %>', imports)(), 'foo-bar-baz');
264 | });
265 |
266 | it('should work with hyphens.', function() {
267 | assert.equal(template('<%= slugify("foo-bar-baz") %>', imports)(), 'foo-bar-baz');
268 | assert.equal(template('<%= slugify("-foo bar baz-") %>', imports)(), '-foo-bar-baz-');
269 | });
270 |
271 | it('should work with other non-word characters.', function() {
272 | assert.equal(template('<%= slugify("9foo-bar_baz") %>', imports)(), '9foo-bar_baz');
273 | assert.equal(template('<%= slugify("_foo_bar_baz-") %>', imports)(), '_foo_bar_baz-');
274 | });
275 | });
276 |
277 | describe('count', function() {
278 | it('should return an empty string when undefined.', function() {
279 | assert.equal(template('<%= count() %>', imports)(), '');
280 | });
281 | it('should return zero when the substring is undefined.', function() {
282 | assert.equal(template('<%= count("ababa") %>', imports)(), '0');
283 | });
284 | it('should count the occurrances of a substring.', function() {
285 | assert.equal(template('<%= count("ababa", "a") %>', imports)(), '3');
286 | assert.equal(template('<%= count("abab", "a") %>', imports)(), '2');
287 | assert.equal(template('<%= count("ababaa", "a") %>', imports)(), '4');
288 | });
289 | });
290 |
291 | describe('reverse', function() {
292 | it('should return an empty string when undefined.', function() {
293 | assert.equal(template('<%= reverse() %>', imports)(), '');
294 | });
295 | it('should reverse the characters in a string.', function() {
296 | assert.equal(template('<%= reverse("abc") %>', imports)(), 'cba');
297 | });
298 | });
299 |
300 | describe('wordwrap', function() {
301 | it('should return an empty string when undefined.', function() {
302 | assert.equal(template('<%= wordwrap() %>', imports)(), '');
303 | });
304 | it('should wrap words to the specified width.', function() {
305 | var actual = template('<%= wordwrap("a b c d e f", {width: 5}) %>', imports)();
306 | assert.equal(actual, ' a b c \n d e f');
307 | });
308 |
309 | it('should use custom newline characters.', function() {
310 | var actual = template('<%= wordwrap("a b c d e f", {width: 5, newline: "
"}) %>', imports)();
311 | assert.equal(actual, ' a b c
d e f');
312 | });
313 | });
314 |
315 | describe('align', function() {
316 | it('should return an empty string when undefined.', function() {
317 | assert.equal(template('<%= rightAlign() %>', imports)(), '');
318 | assert.equal(template('<%= centerAlign() %>', imports)(), '');
319 | });
320 | it('should right align the characters in a string.', function() {
321 | var actual = template('<%= rightAlign("foo\\nbarbazb") %>', imports)();
322 | assert.equal(actual, ' foo\nbarbazb');
323 | });
324 | it('should center align the characters in a string.', function() {
325 | var actual = template('<%= centerAlign("foo\\nbarbazb") %>', imports)();
326 | assert.equal(actual, ' foo\nbarbazb');
327 | });
328 | });
329 |
330 | describe('replace', function() {
331 | it('should return an empty string when undefined.', function() {
332 | assert.equal(template('<%= replace() %>', imports)(), '');
333 | });
334 | it('should return the string when no replacement pattern is passed.', function() {
335 | var actual = template('<%= replace("abcabc") %>', imports)();
336 | assert.equal(actual, 'abcabc');
337 | });
338 | it('should replace characters in a string with nothing.', function() {
339 | var actual = template('<%= replace("abcabc", "a") %>', imports)();
340 | assert.equal(actual, 'bcbc');
341 | });
342 | it('should replace characters in a string with a string', function() {
343 | var actual = template('<%= replace("abcabc", "a", "z") %>', imports)();
344 | assert.equal(actual, 'zbczbc');
345 | });
346 | });
347 |
348 | describe('titlecase', function() {
349 | it('should return an empty string when undefined.', function() {
350 | assert.equal(template('<%= titlecase("foo") %>', imports)(), 'Foo');
351 | });
352 | it('should upper case the characters in a string.', function() {
353 | var fn = template('<%= titlecase("one two three") %>', imports);
354 | assert.equal(fn(), 'One Two Three');
355 | });
356 | });
357 |
358 | describe('truncate', function() {
359 | it('should return an empty string when undefined.', function() {
360 | assert.equal(template('<%= truncate() %>', imports)(), '');
361 | });
362 | it('should truncate a string to the specified `length`', function() {
363 | assert.equal(template('<%= truncate("foo bar baz", 7) %>', imports)(), 'foo bar');
364 | assert.equal(template('<%= truncate(sanitize("foo bar baz"), 7) %>', imports)(), 'foo bar');
365 | });
366 | });
367 |
368 | describe('ellipsis', function() {
369 | it('should return an empty string when undefined.', function() {
370 | assert.equal(template('<%= ellipsis() %>', imports)(), '');
371 | });
372 | it('should truncate a string to the specified `length` and add an ellipsis.', function() {
373 | assert.equal(template('<%= ellipsis("foo bar baz", 7) %>', imports)(), 'foo bar…');
374 | assert.equal(template('<%= ellipsis(sanitize("foo bar baz"), 7) %>', imports)(), 'foo bar…');
375 | });
376 | });
377 | });
378 |
--------------------------------------------------------------------------------
/test/test.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * template-helpers
3 | *
4 | * Copyright (c) 2015, Jon Schlinkert.
5 | * Licensed under the MIT License.
6 | */
7 |
8 | 'use strict';
9 |
10 | const assert = require('assert');
11 | const lib = require('..');
12 | let helpers;
13 |
14 | describe('helpers', function() {
15 | before(function() {
16 | helpers = lib();
17 | });
18 |
19 | it('should expose all helpers on main export', function() {
20 | let keys = Object.keys(helpers);
21 | assert(keys.length > 70);
22 | });
23 |
24 | it('should expose array helpers on `array`', function() {
25 | assert(helpers.array);
26 | assert(typeof helpers.array === 'object');
27 | });
28 |
29 | it('should filter out array helpers when passed as an argument to lib', function() {
30 | let array = lib('array');
31 | assert(typeof array === 'object');
32 | });
33 |
34 | it('should expose code helpers on `code`', function() {
35 | assert(helpers.code);
36 | assert(typeof helpers.code === 'object');
37 | });
38 |
39 | it('should filter out code helpers when passed as an argument to lib', function() {
40 | let code = lib('code');
41 | assert(typeof code === 'object');
42 | });
43 |
44 | it('should expose collection helpers on `collection`', function() {
45 | assert(helpers.collection);
46 | assert(typeof helpers.collection === 'object');
47 | });
48 |
49 | it('should filter out collection helpers when passed as an argument to lib', function() {
50 | let collection = lib('collection');
51 | assert(typeof collection === 'object');
52 | });
53 |
54 | it('should expose conditional helpers on `conditional`', function() {
55 | assert(helpers.conditional);
56 | assert(typeof helpers.conditional === 'object');
57 | });
58 |
59 | it('should filter out conditional helpers when passed as an argument to lib', function() {
60 | let conditional = lib('conditional');
61 | assert(typeof conditional === 'object');
62 | });
63 |
64 | it('should expose fs helpers on `fs`', function() {
65 | assert(helpers.fs);
66 | assert(typeof helpers.fs === 'object');
67 | });
68 |
69 | it('should filter out fs helpers when passed as an argument to lib', function() {
70 | let fs = lib('fs');
71 | assert(typeof fs === 'object');
72 | });
73 |
74 | it('should expose html helpers on `html`', function() {
75 | assert(helpers.html);
76 | assert(typeof helpers.html === 'object');
77 | });
78 |
79 | it('should filter out html helpers when passed as an argument to lib', function() {
80 | let html = lib('html');
81 | assert(typeof html === 'object');
82 | });
83 |
84 | it('should expose math helpers on `math`', function() {
85 | assert(helpers.math);
86 | assert(typeof helpers.math === 'object');
87 | });
88 |
89 | it('should filter out math helpers when passed as an argument to lib', function() {
90 | let math = lib('math');
91 | assert(typeof math === 'object');
92 | });
93 |
94 | it('should expose object helpers on `object`', function() {
95 | assert(helpers.object);
96 | assert(typeof helpers.object === 'object');
97 | });
98 |
99 | it('should filter out object helpers when passed as an argument to lib', function() {
100 | let object = lib('object');
101 | assert(typeof object === 'object');
102 | });
103 |
104 | it('should expose path helpers on `path`', function() {
105 | assert(helpers.path);
106 | assert(typeof helpers.path === 'object');
107 | });
108 |
109 | it('should filter out path helpers when passed as an argument to lib', function() {
110 | let path = lib('path');
111 | assert(typeof path === 'object');
112 | });
113 |
114 | it('should expose string helpers on `string`', function() {
115 | assert(helpers.string);
116 | assert(typeof helpers.string === 'object');
117 | });
118 |
119 | it('should filter out string helpers when passed as an argument to lib', function() {
120 | let string = lib('string');
121 | assert(typeof string === 'object');
122 | assert(typeof string.lower === 'function');
123 | assert(typeof string.upper === 'function');
124 | });
125 |
126 | it('should filter out an array of groups', function() {
127 | let helpers = lib(['string', 'array']);
128 | assert(typeof helpers === 'object');
129 | assert(typeof helpers.last === 'function');
130 | assert(typeof helpers.upper === 'function');
131 | });
132 | });
133 |
--------------------------------------------------------------------------------
/verbfile.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const fs = require('fs');
4 | const path = require('path');
5 | const link = require('markdown-link');
6 | const through = require('through2');
7 | const cache = {};
8 |
9 | /**
10 | * TODO: externalize to `verb-generate-toc`
11 | */
12 |
13 | module.exports = function(verb, base, env) {
14 | verb.on('error', console.log);
15 |
16 | verb.use(require('verb-generate-readme'));
17 | verb.helpers(require('./')());
18 | helpers(verb);
19 |
20 | verb.preRender(/\.md$/, function(file, next) {
21 | file.options.stripEmpty = false;
22 | next();
23 | });
24 |
25 | verb.task('toc', function(cb) {
26 | let total = { categories: 0, helpers: 0 };
27 | let sections = [];
28 | let summary = [];
29 | let methods = {};
30 | let toc = [];
31 |
32 | return verb.src('lib/helpers/*.js')
33 | .pipe(through.obj(function(file, enc, next) {
34 | if (file.stem === 'index') {
35 | next();
36 | return;
37 | }
38 |
39 | try {
40 | file.base = verb.cwd;
41 | file.code = require(file.path);
42 | let heading = listItem(file);
43 | let newFile = {
44 | methods: require(file.path),
45 | test: {
46 | path: path.join('test', file.basename),
47 | code: {}
48 | },
49 | code: {},
50 | path: file.relative,
51 | base: file.base,
52 | cwd: file.cwd,
53 | relative: file.relative,
54 | stem: file.stem || path.basename(file.path, path.extname(filepath)),
55 | data: {
56 | methods: {}
57 | }
58 | };
59 |
60 | let testLine = matchTest(newFile.test.path);
61 | let codeLine = matchCode(newFile.path);
62 |
63 | for (let key in newFile.methods) {
64 | total.helpers++;
65 | if (newFile.methods.hasOwnProperty(key)) {
66 | newFile.data.methods[key] = {
67 | method: newFile.stem,
68 | stem: key,
69 | code: {
70 | path: newFile.relative,
71 | line: codeLine(key)
72 | },
73 | test: {
74 | path: newFile.test.path,
75 | line: testLine(key)
76 | }
77 | };
78 | }
79 | }
80 |
81 | methods[newFile.stem] = newFile;
82 | total.categories++;
83 | next();
84 | } catch (err) {
85 | next(err);
86 | }
87 | }, function(next) {
88 | verb.data({ total });
89 | verb.data({ methods });
90 | next();
91 | }));
92 | });
93 |
94 | verb.task('sectionToc', function() {
95 | let toc = '';
96 | return verb.src('lib/helpers/*.js')
97 | .pipe(through.obj(function(file, enc, next) {
98 | if (file.stem !== 'index') {
99 | file.base = verb.cwd;
100 | toc += '- ' + link(file.stem, '#' + file.stem) + ' ';
101 | toc += '(code '+ link(file.stem, file.relative) + ')\n';
102 | }
103 | next();
104 | }, function(next) {
105 | // create an `include` from the toc
106 | verb.include('toc.md', { contents: Buffer.from(toc) });
107 | next();
108 | }))
109 | .pipe(verb.dest('.'));
110 | });
111 |
112 | verb.task('fix-headings', function() {
113 | return verb.src('README.md')
114 | .pipe(through.obj(function(file, enc, next) {
115 | let str = file.contents.toString();
116 | str = str.replace(/\n### index/, '');
117 | str = str.replace(/^(#{2,}\s*\[)\./gm, '$1');
118 | file.contents = Buffer.from(str);
119 | next(null, file);
120 | }))
121 | .pipe(verb.dest('.'));
122 | });
123 |
124 | verb.task('default', ['toc', 'readme', 'fix-headings']);
125 | };
126 |
127 | function section(name) {
128 | return `## ${name}\n{%= apidocs("lib/helpers/${name}.js") %}`;
129 | }
130 |
131 | function matchTest(fp) {
132 | if (!fp || !fs.existsSync(fp)) return function() {};
133 | let str = fs.readFileSync(fp, 'utf8');
134 | let lines = str.split('\n');
135 | return function(method) {
136 | let re = new RegExp('\\s*(describe|it)\\([\'"]\\.?(' + method + ')');
137 | let len = lines.length, i = -1;
138 | while (++i < len) {
139 | let line = lines[i];
140 | if (re.test(line)) {
141 | return i + 1;
142 | }
143 | }
144 | return;
145 | };
146 | }
147 |
148 | function matchCode(fp) {
149 | if (!fp || !fs.existsSync(fp)) return function() {};
150 | let str = fs.readFileSync(fp, 'utf8');
151 | let lines = str.split('\n');
152 | return method => {
153 | let re = new RegExp(`^exports\\.(${method})`, 'gm');
154 | let len = lines.length, i = -1;
155 | while (++i < len) {
156 | let line = lines[i];
157 | if (re.test(line)) {
158 | return i + 1;
159 | }
160 | }
161 | };
162 | }
163 |
164 | function helpers(app) {
165 | app.helper('bullet', function(file) {
166 | return '- **' + link(file.stem, '#' + file.stem) + '**';
167 | });
168 |
169 | app.helper('issue', function(name) {
170 | let repo = app.cache.data.repository;
171 | return '[create issue](https://github.com/' + repo + '/issues/new?title=' + name + '%20helper)';
172 | });
173 |
174 | app.helper('sectionIssue', function(section) {
175 | let repo = app.cache.data.repository;
176 | let url = 'https://github.com/' + repo + '/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+';
177 | return '[issues](' + url + section + '+helpers)';
178 | });
179 |
180 | app.helper('anchor', function(file) {
181 | return link(file.stem, '#' + file.stem);
182 | });
183 |
184 | app.helper('codeLink', function(file) {
185 | return codeLink('code', file.code.path, file.code.line);
186 | });
187 |
188 | app.helper('testLink', function(file) {
189 | let line = file.test.line;
190 | return line ? codeLink('unit tests', file.test.path, line) : '[no tests]';
191 | });
192 |
193 | app.helper('link', function(name, filepath) {
194 | return link(name, filepath);
195 | });
196 | }
197 |
198 | function listItem(file) {
199 | return '- **' + link(file.stem, '#' + file.stem) + '** (code ' + link(file.stem, file.relative) + ')';
200 | }
201 |
202 | function codeLink(title, path, start) {
203 | return link(title, path + '#L' + start);
204 | }
205 |
206 |
--------------------------------------------------------------------------------