├── .coveralls.yml ├── .gitignore ├── .jshintrc ├── .npmignore ├── .travis.yml ├── LICENSE ├── README.md ├── example ├── gulpfile.js ├── index-data.json ├── index-json.twig ├── index.html ├── index.twig └── layout.twig ├── index.js ├── package.json └── test ├── expected ├── file-noopts.html └── file.html ├── main.js └── templates └── file.twig /.coveralls.yml: -------------------------------------------------------------------------------- 1 | repo_token: sVtt2Tr2ZfndPLuvCq9cdn4VSoaNOccta 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_store 2 | npm-debug.log 3 | node_modules 4 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "browser": true, 4 | "esnext": true, 5 | "bitwise": true, 6 | "camelcase": true, 7 | "curly": true, 8 | "eqeqeq": true, 9 | "immed": true, 10 | "indent": 4, 11 | "latedef": true, 12 | "newcap": true, 13 | "noarg": true, 14 | "quotmark": "single", 15 | "undef": true, 16 | "unused": true, 17 | "strict": true, 18 | "trailing": true, 19 | "smarttabs": true, 20 | "globals": [ "require" ] 21 | } 22 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .DS_store 2 | npm-debug.log 3 | node_modules 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 4 4 | - 6 5 | before_install: 6 | - npm install -g istanbul 7 | - npm install -g codeclimate-test-reporter 8 | after_script: 9 | - istanbul cover node_modules/.bin/_mocha 10 | - CODECLIMATE_REPO_TOKEN=6104446f9f5bb3d1929ac114cf679f7d134d2caaae2bd548a1de8c3f508cfb75 codeclimate < coverage/lcov.info 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Simon de Turck www.zimmen.com 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/zimmen/gulp-twig.png?branch=master)](https://travis-ci.org/zimmen/gulp-twig) 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
Packagegulp-twig
DescriptionTwig plugin for gulp.js, The streaming build system
Node Version>= 4
Gulp Version3.x
20 | 21 | 22 | Compile [Twig.js](https://github.com/justjohn/twig.js) templates with Gulp. Build upon [Twig.js](https://github.com/justjohn/twig.js) , the JS port of the Twig templating language by John Roepke. 23 | 24 | You can use this plugin with [gulp-data](https://www.npmjs.com/package/gulp-data). 25 | 26 | ## Usage 27 | 28 | ### Install 29 | 30 | ```bash 31 | npm install gulp-twig --save 32 | ``` 33 | ### Example 34 | 35 | ```html 36 | {# index.twig #} 37 | {% extends "layout.twig" %} 38 | 39 | {% block page %} 40 |
41 |

Gulp and Twig.js

42 |
43 |

44 | This page is generated by Twig.js using the gulp-twig gulp plugin. 45 |

46 | 51 | {% endblock %} 52 | ``` 53 | 54 | ```html 55 | {# layout.twig #} 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | {{ title }} 66 | 67 | 68 | 69 |
70 | {% block page %}{% endblock %} 71 |
72 | 73 | 74 | ``` 75 | 76 | ```javascript 77 | var gulp = require('gulp'); 78 | 79 | gulp.task('compile', function () { 80 | 'use strict'; 81 | var twig = require('gulp-twig'); 82 | return gulp.src('./index.twig') 83 | .pipe(twig({ 84 | data: { 85 | title: 'Gulp and Twig', 86 | benefits: [ 87 | 'Fast', 88 | 'Flexible', 89 | 'Secure' 90 | ] 91 | } 92 | })) 93 | .pipe(gulp.dest('./')); 94 | }); 95 | 96 | gulp.task('default', ['compile']); 97 | ``` 98 | 99 | ### Options: 100 | **data**: [object| *The data that is exposed in the twig files. Or use gulp-data to pipe files directly into gulp-twig* 101 | 102 | **base**: [string] *sets the views base folder. Extends can be loaded relative to this path* 103 | 104 | **errorLogToConsole**: [true|false] *logs errors to console (defaults to false)* 105 | 106 | **onError**: [function] *handle error yourself* 107 | 108 | **cache**: [true|false] *enables the Twig cache. (defaults to false)* 109 | 110 | **debug**: [true|false] *enables debug info logging (defaults to false)* 111 | 112 | **trace**: [true|false] *enables tracing info logging (defaults to false)* 113 | 114 | **extend**: [function (Twig)] *extends Twig with new tags types. The Twig attribute is Twig.js's internal object. [Read more here](https://github.com/justjohn/twig.js/wiki/Extending-twig.js-With-Custom-Tags)* 115 | 116 | **extname**: [string|true|false] *output file extension including the '.' like path.extname(filename). Use `true` to keep source extname and a "falsy" value to drop the file extension* 117 | 118 | **useFileContents**: [true|false] *use file contents instead of file path (defaults to false) [Read more here](https://github.com/zimmen/gulp-twig/issues/30)* 119 | 120 | **functions**: [array] *extends Twig with given function objects. (default to undefined)* 121 | ```javascript 122 | [ 123 | { 124 | name: "nameOfFunction", 125 | func: function (args) { 126 | return "the function"; 127 | } 128 | } 129 | ] 130 | ``` 131 | 132 | **filters**: [array] *extends Twig with given filter objects. (default to undefined)* 133 | ```javascript 134 | [ 135 | { 136 | name: "nameOfFilter", 137 | func: function (args) { 138 | return "the filter"; 139 | } 140 | } 141 | ] 142 | ``` 143 | ### LICENSE 144 | 145 | (MIT License) 146 | 147 | Copyright (c) 2015 Simon de Turck www.zimmen.com 148 | 149 | Permission is hereby granted, free of charge, to any person obtaining 150 | a copy of this software and associated documentation files (the 151 | "Software"), to deal in the Software without restriction, including 152 | without limitation the rights to use, copy, modify, merge, publish, 153 | distribute, sublicense, and/or sell copies of the Software, and to 154 | permit persons to whom the Software is furnished to do so, subject to 155 | the following conditions: 156 | 157 | The above copyright notice and this permission notice shall be 158 | included in all copies or substantial portions of the Software. 159 | 160 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 161 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 162 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 163 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 164 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 165 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 166 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 167 | 168 | -------------------------------------------------------------------------------- /example/gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | 3 | gulp.task('compile', function () { 4 | 'use strict'; 5 | var twig = require('gulp-twig'); 6 | return gulp.src('./index.twig') 7 | .pipe(twig({ 8 | data: { 9 | title: 'Gulp and Twig', 10 | benefits: [ 11 | 'Fast', 12 | 'Flexible', 13 | 'Secure' 14 | ] 15 | } 16 | })) 17 | .pipe(gulp.dest('./')); 18 | }); 19 | 20 | 21 | gulp.task('data-example', function () { 22 | 'use strict'; 23 | 24 | var twig = require('gulp-twig'); 25 | var data = require('gulp-data'); 26 | 27 | return gulp.src('./index-json.twig') 28 | .pipe(data(function(file) { 29 | return require('./example/index-data.json'); 30 | })) 31 | .pipe(twig()) 32 | .pipe(gulp.dest('./')); 33 | }); 34 | 35 | 36 | gulp.task('default', ['compile', 'data-example']); 37 | -------------------------------------------------------------------------------- /example/index-data.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": 'Gulp and Twig', 3 | "benefits": [ 4 | 'Fast', 5 | 'Flexible', 6 | 'Secure' 7 | ] 8 | } -------------------------------------------------------------------------------- /example/index-json.twig: -------------------------------------------------------------------------------- 1 | {% extends "layout.twig" %} 2 | 3 | {% block page %} 4 |
5 |

Gulp and Twig.js

6 |
7 |

8 | This page is generated by Twig.js using the gulp-twig gulp plugin. 9 |

10 | 15 | {% endblock %} 16 | -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Gulp and Twig 11 | 12 | 13 |
14 |
15 |

Gulp and Twig.js

16 |
17 |

18 | This page is generated by Twig.js using the gulp-twig gulp plugin. 19 |

20 |
    21 |
  • Fast
  • 22 |
  • Flexible
  • 23 |
  • Secure
  • 24 |
25 |
26 |
27 |

28 | Source file: index.twig
29 | Target file: index.html 30 |

31 |
32 | 33 | 34 | -------------------------------------------------------------------------------- /example/index.twig: -------------------------------------------------------------------------------- 1 | {% extends "layout.twig" %} 2 | 3 | {% block page %} 4 |
5 |

Gulp and Twig.js

6 |
7 |

8 | This page is generated by Twig.js using the gulp-twig gulp plugin. 9 |

10 | 15 | {% endblock %} 16 | -------------------------------------------------------------------------------- /example/layout.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | {{ title }} 11 | 12 | 13 | 14 |
15 | {% block page %}{% endblock %} 16 |
17 |
18 |

19 | Source file: {{ _file.relative }}
20 | Target file: {{ _target.relative }} 21 |

22 |
23 | 24 | 25 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var map = require('map-stream'); 2 | var rext = require('replace-ext'); 3 | var log = require('fancy-log'); 4 | var PluginError = require('plugin-error'); 5 | 6 | const PLUGIN_NAME = 'gulp-twig'; 7 | 8 | module.exports = function (options) { 9 | 'use strict'; 10 | options = Object.assign({}, { 11 | changeExt: true, 12 | extname: '.html', 13 | useFileContents: false, 14 | 15 | }, options || {}); 16 | 17 | function modifyContents(file, cb) { 18 | var data = file.data || Object.assign({}, options.data); 19 | 20 | if (file.isNull()) { 21 | return cb(null, file); 22 | } 23 | 24 | if (file.isStream()) { 25 | return cb(new PluginError(PLUGIN_NAME, 'Streaming not supported!')); 26 | } 27 | 28 | data._file = file; 29 | if(options.changeExt === false || options.extname === true){ 30 | data._target = { 31 | path: file.path, 32 | relative: file.relative 33 | } 34 | }else{ 35 | data._target = { 36 | path: rext(file.path, options.extname || ''), 37 | relative: rext(file.relative, options.extname || '') 38 | } 39 | } 40 | 41 | var Twig = require('twig'), 42 | twig = Twig.twig, 43 | twigOpts = { 44 | path: file.path, 45 | async: false 46 | }, 47 | template; 48 | 49 | if (options.debug !== undefined) { 50 | twigOpts.debug = options.debug; 51 | } 52 | if (options.trace !== undefined) { 53 | twigOpts.trace = options.trace; 54 | } 55 | if (options.base !== undefined) { 56 | twigOpts.base = options.base; 57 | } 58 | if (options.namespaces !== undefined) { 59 | twigOpts.namespaces = options.namespaces; 60 | } 61 | if (options.cache !== true) { 62 | Twig.cache(false); 63 | } 64 | 65 | if (options.functions) { 66 | options.functions.forEach(function (func) { 67 | Twig.extendFunction(func.name, func.func); 68 | }); 69 | } 70 | 71 | if (options.filters) { 72 | options.filters.forEach(function (filter) { 73 | Twig.extendFilter(filter.name, filter.func); 74 | }); 75 | } 76 | 77 | if(options.extend) { 78 | Twig.extend(options.extend); 79 | delete options.extend; 80 | } 81 | 82 | if (options.useFileContents) { 83 | var fileContents = file.contents.toString(); 84 | twigOpts.data = fileContents 85 | } 86 | 87 | template = twig(twigOpts); 88 | 89 | try { 90 | file.contents = new Buffer(template.render(data)); 91 | }catch(e){ 92 | if (options.errorLogToConsole) { 93 | log(PLUGIN_NAME + ' ' + e); 94 | return cb(); 95 | } 96 | 97 | if (typeof options.onError === 'function') { 98 | options.onError(e); 99 | return cb(); 100 | } 101 | return cb(new PluginError(PLUGIN_NAME, e)); 102 | } 103 | 104 | file.path = data._target.path; 105 | cb(null, file); 106 | } 107 | 108 | return map(modifyContents); 109 | }; 110 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gulp-twig", 3 | "description": "Twig.js plugin for gulp.js (gulpjs.com)", 4 | "version": "1.2.0", 5 | "homepage": "http://github.com/zimmen/gulp-twig", 6 | "repository": { 7 | "type": "git", 8 | "url": "http://github.com/zimmen/gulp-twig.git" 9 | }, 10 | "author": "Simon de Turck (http://www.zimmen.com)", 11 | "main": "./index.js", 12 | "dependencies": { 13 | "fancy-log": "^1.3.2", 14 | "map-stream": "^0.1.0", 15 | "plugin-error": "^0.1.2", 16 | "replace-ext": "^1.0.0", 17 | "twig": "^1.10.5" 18 | }, 19 | "devDependencies": { 20 | "mocha": "*", 21 | "should": "*", 22 | "vinyl": "^2.1.0" 23 | }, 24 | "scripts": { 25 | "test": "mocha -R spec" 26 | }, 27 | "engines": { 28 | "node": ">=4.0" 29 | }, 30 | "keywords": [ 31 | "twig", 32 | "twig.js", 33 | "gulp", 34 | "gulpplugin", 35 | "gulp-plugin" 36 | ], 37 | "licenses": [ 38 | { 39 | "type": "MIT", 40 | "url": "http://github.com/zimmen/gulp-twig/raw/master/LICENSE" 41 | } 42 | ] 43 | } 44 | -------------------------------------------------------------------------------- /test/expected/file-noopts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | test no options 6 | 7 | 8 | 9 |
10 |

11 | Source file: templates/file.twig
12 | Target file: templates/file.html 13 |

14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /test/expected/file.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | test twig 6 | 7 | 8 | 9 |
10 |

11 | Source file: templates/file.twig
12 | Target file: templates/file.html 13 |

14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /test/main.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var path = require('path'); 3 | var should = require('should'); 4 | var Vinyl = require('vinyl'); 5 | var twig = require('../'); 6 | 7 | require('mocha'); 8 | 9 | describe('gulp-twig', function () { 10 | 11 | it('should compile twig templates to html files', function (done) { 12 | var twg = twig({ 13 | data: { 14 | title: 'twig' 15 | } 16 | }); 17 | 18 | var fakeFile = new Vinyl({ 19 | base: 'test/', 20 | cwd: 'test/', 21 | path: path.join(__dirname, '/templates/file.twig'), 22 | contents: fs.readFileSync(__dirname + '/templates/file.twig') 23 | }); 24 | 25 | twg.on('data', function (newFile) { 26 | should.exist(newFile); 27 | should.exist(newFile.contents); 28 | should.exist(newFile.path); 29 | String(newFile.contents).should.equal(fs.readFileSync(__dirname + '/expected/file.html', 'utf8')); 30 | done(); 31 | }); 32 | twg.write(fakeFile); 33 | }); 34 | 35 | it('should compile twig templates to html files without options', function (done) { 36 | var twg = twig(); 37 | 38 | var fakeFile = new Vinyl({ 39 | base: 'test/', 40 | cwd: 'test/', 41 | path: path.join(__dirname, '/templates/file.twig'), 42 | contents: fs.readFileSync(__dirname + '/templates/file.twig') 43 | }); 44 | 45 | twg.on('data', function (newFile) { 46 | should.exist(newFile); 47 | should.exist(newFile.contents); 48 | should.exist(newFile.path); 49 | String(newFile.contents).should.equal(fs.readFileSync(__dirname + '/expected/file-noopts.html', 'utf8')); 50 | done(); 51 | }); 52 | twg.write(fakeFile); 53 | }); 54 | 55 | it('should return \'null\' file when no file put in', function (done) { 56 | var twg = twig(); 57 | 58 | var fakeFile = new Vinyl({ 59 | base: 'test/', 60 | cwd: 'test/' 61 | }); 62 | 63 | twg.on('data', function (newFile) { 64 | should.exist(newFile); 65 | should.not.exist(newFile.contents); 66 | should.not.exist(newFile.path); 67 | String(newFile.contents).should.equal('null'); 68 | done(); 69 | }); 70 | twg.write(fakeFile); 71 | }); 72 | 73 | it('should accept data from file.data', function (done) { 74 | var twg = twig(); 75 | 76 | var fakeFile = new Vinyl({ 77 | base: 'test/', 78 | cwd: 'test/', 79 | path: path.join(__dirname, '/templates/file.twig'), 80 | contents: fs.readFileSync(__dirname + '/templates/file.twig'), 81 | }); 82 | 83 | // simulate data attribute being added by gulp-data plugin 84 | fakeFile['data'] = { 85 | title: 'twig' 86 | }; 87 | 88 | twg.on('data', function (newFile) { 89 | should.exist(newFile); 90 | should.exist(newFile.contents); 91 | should.exist(newFile.path); 92 | String(newFile.contents).should.equal(fs.readFileSync(__dirname + '/expected/file.html', 'utf8')); 93 | done(); 94 | }); 95 | twg.write(fakeFile); 96 | }); 97 | 98 | it('should consider extname option', function (done) { 99 | var twg = twig({ 100 | extname: '.md' 101 | }); 102 | 103 | var fakeFile = new Vinyl({ 104 | base: 'test/', 105 | cwd: 'test/', 106 | path: path.join(__dirname, '/templates/file.twig'), 107 | contents: fs.readFileSync(__dirname + '/templates/file.twig') 108 | }); 109 | 110 | twg.on('data', function (newFile) { 111 | path.extname(newFile.path).should.equal('.md'); 112 | done(); 113 | }); 114 | twg.write(fakeFile); 115 | }); 116 | 117 | it('should drop extname option when passing "falsy"', function (done) { 118 | var twg = twig({ 119 | extname: false 120 | }); 121 | 122 | var fakeFile = new Vinyl({ 123 | base: 'test/', 124 | cwd: 'test/', 125 | path: path.join(__dirname, '/templates/file.twig'), 126 | contents: fs.readFileSync(__dirname + '/templates/file.twig') 127 | }); 128 | 129 | twg.on('data', function (newFile) { 130 | path.basename(newFile.path).should.equal('file'); 131 | done(); 132 | }); 133 | twg.write(fakeFile); 134 | }); 135 | 136 | it('should inherit extname option when passing true', function (done) { 137 | var twg = twig({ 138 | extname: true 139 | }); 140 | 141 | var fakeFile = new Vinyl({ 142 | base: 'test/', 143 | cwd: 'test/', 144 | path: path.join(__dirname, '/templates/file.twig'), 145 | contents: fs.readFileSync(__dirname + '/templates/file.twig') 146 | }); 147 | 148 | twg.on('data', function (newFile) { 149 | path.basename(newFile.path).should.equal('file.twig'); 150 | done(); 151 | }); 152 | twg.write(fakeFile); 153 | }); 154 | 155 | it('should use file contents if useFileContents option is enabled', function (done) { 156 | var twg = twig({ 157 | useFileContents: true, 158 | data: { 159 | title: 'twig', 160 | }, 161 | }); 162 | 163 | var fakeFile = new Vinyl({ 164 | base: 'test/', 165 | cwd: 'test/', 166 | path: path.join(__dirname, '/templates/file.twig'), 167 | contents: new Buffer('{{ title }}'), 168 | }); 169 | 170 | twg.on('data', function (newFile) { 171 | String(newFile.contents).should.equal('twig'); 172 | done(); 173 | }); 174 | twg.write(fakeFile); 175 | }); 176 | 177 | }); 178 | -------------------------------------------------------------------------------- /test/templates/file.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | test {{ title|default('no options') }} 6 | 7 | 8 | 9 | 15 | 16 | 17 | --------------------------------------------------------------------------------