Skip to content

Commit 175b5da

Browse files
committed
conditional file generation
1 parent b1de5bd commit 175b5da

File tree

7 files changed

+97
-17
lines changed

7 files changed

+97
-17
lines changed

lib/filter.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
var match = require('minimatch')
2+
var chalk = require('chalk')
3+
4+
module.exports = function (files, filters, data, done) {
5+
if (!filters) {
6+
return done()
7+
}
8+
var fileNames = Object.keys(files)
9+
Object.keys(filters).forEach(function (glob) {
10+
fileNames.forEach(function (file) {
11+
if (match(file, glob)) {
12+
var condition = filters[glob]
13+
if (!evalualte(condition, data)) {
14+
delete files[file]
15+
}
16+
}
17+
})
18+
})
19+
done()
20+
}
21+
22+
function evalualte (exp, data) {
23+
/* eslint-disable no-new-func */
24+
var fn = new Function('data', 'with (data) { return ' + exp + '}')
25+
try {
26+
return fn(data)
27+
} catch (e) {
28+
console.error(chalk.red('Error when evaluating filter condition: ' + exp))
29+
}
30+
}

lib/generate.js

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ var async = require('async')
33
var render = require('consolidate').handlebars.render
44
var path = require('path')
55
var getOptions = require('./options')
6-
var askQuestions = require('./ask')
6+
var ask = require('./ask')
7+
var filter = require('./filter')
78

89
/**
910
* Generate a template given a `src` and `dest`.
@@ -17,9 +18,8 @@ var askQuestions = require('./ask')
1718
module.exports = function generate (name, src, dest, done) {
1819
var opts = getOptions(name, src)
1920
Metalsmith(path.join(src, 'template'))
20-
.use(function (files, metalsmith, done) {
21-
askQuestions(opts.schema, metalsmith.metadata(), done)
22-
})
21+
.use(askQuestions(opts.schema))
22+
.use(filterFiles(opts.filters))
2323
.use(renderTemplateFiles)
2424
.clean(false)
2525
.source('.') // start from template root instead of `./src` which is Metalsmith's default for `source`
@@ -30,6 +30,32 @@ module.exports = function generate (name, src, dest, done) {
3030
})
3131
}
3232

33+
/**
34+
* Create a middleware for asking questions.
35+
*
36+
* @param {Object} schema
37+
* @return {Function}
38+
*/
39+
40+
function askQuestions (schema) {
41+
return function (files, metalsmith, done) {
42+
ask(schema, metalsmith.metadata(), done)
43+
}
44+
}
45+
46+
/**
47+
* Create a middleware for filtering files.
48+
*
49+
* @param {Object} filters
50+
* @return {Function}
51+
*/
52+
53+
function filterFiles (filters) {
54+
return function (files, metalsmith, done) {
55+
filter(files, filters, metalsmith.metadata(), done)
56+
}
57+
}
58+
3359
/**
3460
* Template in place plugin.
3561
*
@@ -41,7 +67,7 @@ module.exports = function generate (name, src, dest, done) {
4167
function renderTemplateFiles (files, metalsmith, done) {
4268
var keys = Object.keys(files)
4369
var metalsmithMetadata = metalsmith.metadata()
44-
70+
metalsmithMetadata.noEscape = true
4571
async.each(keys, function (file, next) {
4672
var str = files[file].contents.toString()
4773
// do not attempt to render files that do not have mustaches

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
"main": "lib/index.js",
2525
"scripts": {
2626
"test": "npm run lint && npm run e2e",
27-
"lint": "eslint test lib bin/* --env mocha",
27+
"lint": "eslint test/test.js lib bin/* --env mocha",
2828
"e2e": "rimraf test/e2e/mock-template-build/*.* && BABEL_ENV=development mocha test/e2e/test.js --slow 1000 --compilers js:babel-core/register"
2929
},
3030
"dependencies": {
@@ -36,6 +36,7 @@
3636
"handlebars": "^4.0.5",
3737
"inquirer": "^0.12.0",
3838
"metalsmith": "^2.1.0",
39+
"minimatch": "^3.0.0",
3940
"ora": "^0.2.1",
4041
"read-metadata": "^1.0.0",
4142
"request": "^2.67.0",

test/e2e/mock-template-repo/meta.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,17 @@
2626
"less",
2727
"sass"
2828
]
29+
},
30+
"pick": {
31+
"type": "list",
32+
"choices": [
33+
"yes",
34+
"no"
35+
]
2936
}
37+
},
38+
"filters": {
39+
"src/*.js": "pick === 'yes'",
40+
"**/*.vue": "pick === 'no'"
3041
}
3142
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
console.log('no.')
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<template>
2+
\{{yes}} {{pick}}
3+
</template>

test/e2e/test.js

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const exists = require('fs').existsSync
66
const crypto = require('crypto')
77
const render = require('consolidate').handlebars.render
88
const inquirer = require('inquirer')
9+
const async = require('async')
910
const generate = require('../../lib/generate')
1011

1112
const MOCK_TEMPLATE_REPO_PATH = './test/e2e/mock-template-repo'
@@ -19,7 +20,8 @@ describe('vue-cli', () => {
1920
preprocessor: {
2021
less: true,
2122
sass: true
22-
}
23+
},
24+
pick: 'no'
2325
}
2426

2527
// monkey patch inquirer
@@ -32,18 +34,24 @@ describe('vue-cli', () => {
3234

3335
it('template generation', done => {
3436
generate('test', MOCK_TEMPLATE_REPO_PATH, MOCK_TEMPLATE_BUILD_PATH, err => {
35-
if (err) done()
37+
if (err) done(err)
3638

37-
const handlebarsPackageJsonFile = fs.readFileSync(`${MOCK_TEMPLATE_REPO_PATH}/template/package.json`, 'utf8')
38-
const generatedPackageJsonFile = fs.readFileSync(`${MOCK_TEMPLATE_BUILD_PATH}/package.json`, 'utf8')
39+
expect(exists(`${MOCK_TEMPLATE_BUILD_PATH}/src/yes.vue`)).to.equal(true)
40+
expect(exists(`${MOCK_TEMPLATE_BUILD_PATH}/src/no.js`)).to.equal(false)
3941

40-
render(handlebarsPackageJsonFile, answers, (err, res) => {
41-
if (err) return done(err)
42+
async.eachSeries([
43+
'package.json',
44+
'src/yes.vue'
45+
], function (file, next) {
46+
const template = fs.readFileSync(`${MOCK_TEMPLATE_REPO_PATH}/template/${file}`, 'utf8')
47+
const generated = fs.readFileSync(`${MOCK_TEMPLATE_BUILD_PATH}/${file}`, 'utf8')
4248

43-
// compare if vue-cli generate returns same as passing options directly to handlebars
44-
expect(res).to.equal(generatedPackageJsonFile)
45-
done()
46-
})
49+
render(template, answers, (err, res) => {
50+
if (err) return next(err)
51+
expect(res).to.equal(generated)
52+
next()
53+
})
54+
}, done)
4755
})
4856
})
4957

@@ -54,7 +62,7 @@ describe('vue-cli', () => {
5462
wstream.end()
5563

5664
generate('test', MOCK_TEMPLATE_REPO_PATH, MOCK_TEMPLATE_BUILD_PATH, err => {
57-
if (err) done()
65+
if (err) done(err)
5866

5967
const handlebarsPackageJsonFile = fs.readFileSync(`${MOCK_TEMPLATE_REPO_PATH}/template/package.json`, 'utf8')
6068
const generatedPackageJsonFile = fs.readFileSync(`${MOCK_TEMPLATE_BUILD_PATH}/package.json`, 'utf8')

0 commit comments

Comments
 (0)