Skip to content

Commit b636474

Browse files
queckezzyyx990803
authored andcommittedMay 9, 2016
register handlebars helpers (#95)
* allow meta.js file and custom handlebars helpers * document meta.js and handlebars helper registration * final doc tweaks
1 parent 26985d6 commit b636474

File tree

6 files changed

+93
-8
lines changed

6 files changed

+93
-8
lines changed
 

Diff for: ‎README.md

+21-3
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ vue init ~/fs/path/to-custom-template my-project
6868

6969
- A template repo **must** have a `template` directory that holds the template files.
7070

71-
- A template repo **may** have a `meta.json` file that provides metadata for the template. The `meta.json` can contain the following fields:
71+
- A template repo **may** have a metadata file for the template which can be either a `meta.js` or `meta.json` file. It can contain the following fields:
7272

7373
- `prompts`: used to collect user options data;
7474

@@ -78,7 +78,7 @@ vue init ~/fs/path/to-custom-template my-project
7878

7979
#### prompts
8080

81-
The `prompts` field in `meta.json` should be an object hash containing prompts for the user. For each entry, the key is the variable name and the value is an [Inquirer.js question object](https://github.com/SBoudrias/Inquirer.js/#question). Example:
81+
The `prompts` field in the metadata file should be an object hash containing prompts for the user. For each entry, the key is the variable name and the value is an [Inquirer.js question object](https://github.com/SBoudrias/Inquirer.js/#question). Example:
8282

8383
``` json
8484
{
@@ -129,9 +129,27 @@ Two commonly used Handlebars helpers, `if_eq` and `unless_eq` are pre-registered
129129
{{#if_eq lintConfig "airbnb"}};{{/if_eq}}
130130
```
131131

132+
##### Custom Handlebars Helpers
133+
134+
You may want to register additional Handlebars helpers using the `helpers` property in the metadata file. The object key is the helper name:
135+
136+
``` js
137+
module.exports = {
138+
helpers: {
139+
lowercase: str => str.toLowerCase()
140+
}
141+
}
142+
```
143+
144+
Upon registration, they can be used as follows:
145+
146+
``` handlebars
147+
{{ lowercase name }}
148+
```
149+
132150
#### File filters
133151

134-
The `filters` field in `meta.json` should be an object hash containing file filtering rules. For each entry, the key is a [minimatch glob pattern](https://github.com/isaacs/minimatch) and the value is a JavaScript expression evaluated in the context of prompt answers data. Example:
152+
The `filters` field in the metadata file should be an object hash containing file filtering rules. For each entry, the key is a [minimatch glob pattern](https://github.com/isaacs/minimatch) and the value is a JavaScript expression evaluated in the context of prompt answers data. Example:
135153

136154
``` json
137155
{

Diff for: ‎lib/generate.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ var getOptions = require('./options')
77
var ask = require('./ask')
88
var filter = require('./filter')
99

10-
// register hendlebars helper
10+
// register handlebars helper
1111
Handlebars.registerHelper('if_eq', function (a, b, opts) {
1212
return a === b
1313
? opts.fn(this)
@@ -36,6 +36,9 @@ module.exports = function generate (name, src, dest, done) {
3636
destDirName: name,
3737
noEscape: true
3838
})
39+
opts.helpers && Object.keys(opts.helpers).map(function (key) {
40+
Handlebars.registerHelper(key, opts.helpers[key])
41+
})
3942
metalsmith
4043
.use(askQuestions(opts.prompts))
4144
.use(filterFiles(opts.filters))

Diff for: ‎lib/options.js

+26-4
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,7 @@ var validateName = require('validate-npm-package-name')
1212
*/
1313

1414
module.exports = function options (name, dir) {
15-
var file = path.join(dir, 'meta.json')
16-
var opts = exists(file)
17-
? metadata.sync(file)
18-
: {}
15+
var opts = getMetadata(dir)
1916

2017
setDefault(opts, 'name', name)
2118
setValidateName(opts)
@@ -28,6 +25,31 @@ module.exports = function options (name, dir) {
2825
return opts
2926
}
3027

28+
/**
29+
* Gets the metadata from either a meta.json or meta.js file.
30+
*
31+
* @param {String} dir
32+
* @return {Object}
33+
*/
34+
35+
function getMetadata (dir) {
36+
var json = path.join(dir, 'meta.json')
37+
var js = path.join(dir, 'meta.js')
38+
var opts = {}
39+
40+
if (exists(json)) {
41+
opts = metadata.sync(json)
42+
} else if (exists(js)) {
43+
var req = require(js)
44+
if (req !== Object(req)) {
45+
throw new Error('meta.js needs to expose an object')
46+
}
47+
opts = req
48+
}
49+
50+
return opts
51+
}
52+
3153
/**
3254
* Set the default value for a prompt question
3355
*

Diff for: ‎test/e2e/mock-metadata-repo-js/meta.js

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
2+
module.exports = {
3+
prompts: {
4+
description: {
5+
type: 'string',
6+
required: true,
7+
message: 'Project description'
8+
}
9+
},
10+
helpers: {
11+
uppercase: function (str) {
12+
return str.toUpperCase()
13+
}
14+
}
15+
}

Diff for: ‎test/e2e/mock-metadata-repo-js/template/readme.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{{ uppercase name}}

Diff for: ‎test/e2e/test.js

+26
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const inquirer = require('inquirer')
99
const async = require('async')
1010
const extend = Object.assign || require('util')._extend
1111
const generate = require('../../lib/generate')
12+
const metadata = require('../../lib/options')
1213

1314
const MOCK_TEMPLATE_REPO_PATH = './test/e2e/mock-template-repo'
1415
const MOCK_TEMPLATE_BUILD_PATH = path.resolve('./test/e2e/mock-template-build')
@@ -41,6 +42,31 @@ describe('vue-cli', () => {
4142
noEscape: true
4243
}
4344

45+
it('read metadata from json', done => {
46+
const meta = metadata('test-pkg', MOCK_TEMPLATE_REPO_PATH)
47+
expect(meta).to.be.an('object')
48+
expect(meta.prompts).to.have.property('description')
49+
done()
50+
})
51+
52+
it('read metadata from js', done => {
53+
const meta = metadata('test-pkg', __dirname + '/mock-metadata-repo-js')
54+
expect(meta).to.be.an('object')
55+
expect(meta.prompts).to.have.property('description')
56+
done()
57+
})
58+
59+
it('helpers', done => {
60+
monkeyPatchInquirer(answers)
61+
const buildPath = __dirname + '/mock-metadata-repo-js'
62+
generate('test', buildPath, MOCK_TEMPLATE_BUILD_PATH, err => {
63+
if (err) done(err)
64+
const contents = fs.readFileSync(`${MOCK_TEMPLATE_BUILD_PATH}/readme.md`, 'utf-8')
65+
expect(contents).to.equal(answers.name.toUpperCase())
66+
done()
67+
})
68+
})
69+
4470
it('template generation', done => {
4571
monkeyPatchInquirer(answers)
4672
generate('test', MOCK_TEMPLATE_REPO_PATH, MOCK_TEMPLATE_BUILD_PATH, err => {

0 commit comments

Comments
 (0)
Please sign in to comment.