Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Allow compilation of templates to Javascript functions, wrapped for J…

…ST or AMD.

Closes gh-14.
  • Loading branch information...
commit 732d57e935a7cfb80d62c3d1d90da0f1ac51a0e9 1 parent b5bec81
@mereskin mereskin authored tkellen committed
View
37 Gruntfile.js
@@ -43,6 +43,43 @@ module.exports = function(grunt) {
year: '<%= grunt.template.today("yyyy") %>'
}
}
+ },
+
+ compile_amd: {
+ files: {
+ 'tmp/amd/jade.js': ['test/fixtures/jade.jade'],
+ 'tmp/amd/jade2.js': ['test/fixtures/jade2.jade'],
+ 'tmp/amd/jadeInclude.js': ['test/fixtures/jadeInclude.jade'],
+ 'tmp/amd/jadeTemplate.js': ['test/fixtures/jadeTemplate.jade']
+ },
+ options: {
+ client: true,
+ amd: true,
+ namespace: false,
+ compileDebug: false,
+ data: {
+ test: true,
+ year: '<%= grunt.template.today("yyyy") %>'
+ }
+ }
+ },
+
+ compile_jst: {
+ files: {
+ 'tmp/jst/jade.js': ['test/fixtures/jade.jade'],
+ 'tmp/jst/jade2.js': ['test/fixtures/jade2.jade'],
+ 'tmp/jst/jadeInclude.js': ['test/fixtures/jadeInclude.jade'],
+ 'tmp/jst/jadeTemplate.js': ['test/fixtures/jadeTemplate.jade']
+ },
+ options: {
+ client: true,
+ compileDebug: false,
+ processName: function(str) { return str.match(/^test\/fixtures\/(.*)\.jade$/)[1]; },
+ data: {
+ test: true,
+ year: '<%= grunt.template.today("yyyy") %>'
+ }
+ }
}
},
View
45 README.md
@@ -40,6 +40,49 @@ Type: `Object`
Sets the data passed to `jade` during template compilation. Any data can be passed to the template (including `grunt` templates).
+#### comileDebug
+Type: `Boolean`
+
+Set `compileDebug: fase` to remove `jade` debug instructions in javascript templates.
+
+#### namespace
+Type: `String` `false`
+Default: 'JST'
+
+The namespace in which the precompiled templates will be assigned. *Use dot notation (e.g. App.Templates) for nested namespaces or false for no namespace wrapping.* When false with `amd` option set `true`, templates will be returned directly from the AMD wrapper.
+
+Example:
+```js
+options: {
+ namespace: 'MyApp.Templates'
+}
+```
+
+#### amd
+Type: `Boolean`
+default: `false`
+
+Wraps the output file with an AMD define function and returns the compiled template namespace unless namespace has been explicitly set to false in which case the template function will be returned directly.
+
+```js
+define(function() {
+ //...//
+ returns this['[template namespace]'];
+});
+```
+
+#### processName
+Type: `function`
+
+This option accepts a function which takes one argument (the template filepath) and returns a string which will be used as the key for the precompiled template object. The example below stores all templates on the default JST namespace in capital letters.
+
+```js
+options: {
+ processName: function(filename) {
+ return filename.toUpperCase();
+ }
+}
+```
### Usage Examples
```js
@@ -134,4 +177,4 @@ jade: {
Task submitted by [Eric Woroshow](http://ericw.ca/)
-*This file was generated on Wed Feb 20 2013 12:35:52.*
+*This file was generated on Wed Mar 06 2013 17:45:50.*
View
44 docs/jade-options.md
@@ -10,3 +10,47 @@ Output indented HTML.
Type: `Object`
Sets the data passed to `jade` during template compilation. Any data can be passed to the template (including `grunt` templates).
+
+## comileDebug
+Type: `Boolean`
+
+Set `compileDebug: fase` to remove `jade` debug instructions in javascript templates.
+
+## namespace
+Type: `String` `false`
+Default: 'JST'
+
+The namespace in which the precompiled templates will be assigned. *Use dot notation (e.g. App.Templates) for nested namespaces or false for no namespace wrapping.* When false with `amd` option set `true`, templates will be returned directly from the AMD wrapper.
+
+Example:
+```js
+options: {
+ namespace: 'MyApp.Templates'
+}
+```
+
+## amd
+Type: `Boolean`
+default: `false`
+
+Wraps the output file with an AMD define function and returns the compiled template namespace unless namespace has been explicitly set to false in which case the template function will be returned directly.
+
+```js
+define(function() {
+ //...//
+ returns this['[template namespace]'];
+});
+```
+
+## processName
+Type: `function`
+
+This option accepts a function which takes one argument (the template filepath) and returns a string which will be used as the key for the precompiled template object. The example below stores all templates on the default JST namespace in capital letters.
+
+```js
+options: {
+ processName: function(filename) {
+ return filename.toUpperCase();
+ }
+}
+```
View
3  package.json
@@ -28,7 +28,8 @@
"test": "grunt test"
},
"dependencies": {
- "jade": "~0.27.2"
+ "jade": "~0.27.2",
+ "grunt-lib-contrib": "~0.5.1"
},
"devDependencies": {
"grunt-contrib-jshint": "~0.2.0",
View
117 tasks/jade.js
@@ -9,39 +9,114 @@
'use strict';
module.exports = function(grunt) {
+ var _ = grunt.util._;
+ var helpers = require('grunt-lib-contrib').init(grunt);
- grunt.registerMultiTask('jade', 'Compile Jade templates into HTML.', function() {
+ // content conversion for templates
+ var defaultProcessContent = function(content) { return content; };
+
+ // filename conversion for templates
+ var defaultProcessName = function(name) { return name.replace('.jade', ''); };
+
+ grunt.registerMultiTask('jade', 'Compile jade templates.', function() {
var options = this.options({
- data: {}
+ namespace: 'JST',
+ separator: grunt.util.linefeed + grunt.util.linefeed,
+ amd: false
});
-
grunt.verbose.writeflags(options, 'Options');
+ var data = options.data;
+ delete options.data;
+
+ var nsInfo;
+
+ if(options.namespace !== false){
+ nsInfo = helpers.getNamespaceDeclaration(options.namespace);
+ }
+
+ // assign transformation functions
+ var processContent = options.processContent || defaultProcessContent;
+ var processName = options.processName || defaultProcessName;
+
this.files.forEach(function(f) {
- var output = f.src.map(function(file) {
- return compileJade(file, options, options.data);
- }).join(grunt.util.normalizelf(grunt.util.linefeed));
+ var templates = [];
+
+ f.src.filter(function(filepath) {
+ // Warn on and remove invalid source files (if nonull was set).
+ if (!grunt.file.exists(filepath)) {
+ grunt.log.warn('Source file "' + filepath + '" not found.');
+ return false;
+ } else {
+ return true;
+ }
+ })
+ .forEach(function(filepath) {
+ var src = processContent(grunt.file.read(filepath));
+ var compiled, filename;
+ filename = processName(filepath);
+
+ options = grunt.util._.extend(options, { filename: filepath });
+
+ try {
+ compiled = require('jade').compile(src, options);
+ // if in client mode, return function source
+ if (options.client) {
+ compiled = compiled.toString();
+ } else {
+ compiled = compiled(data);
+ }
+
+ // if configured for amd and the namespace has been explicitly set
+ // to false, the jade template will be directly returned
+ if (options.client && options.amd && options.namespace === false) {
+ compiled = 'return ' + compiled;
+ }
+ } catch (e) {
+ grunt.log.error(e);
+ grunt.fail.warn('Jade failed to compile '+filepath+'.');
+ }
+ if (options.client && options.namespace !== false) {
+ templates.push(nsInfo.namespace+'['+JSON.stringify(filename)+'] = '+compiled+';');
+ } else {
+ templates.push(compiled);
+ }
+ });
+
+ var output = templates;
if (output.length < 1) {
grunt.log.warn('Destination not written because compiled files were empty.');
} else {
- grunt.file.write(f.dest, output);
- grunt.log.writeln('File ' + f.dest.cyan + ' created.');
+ if (options.client && options.namespace !== false) {
+ output.unshift(nsInfo.declaration);
+
+ if (options.node) {
+ output.unshift('var jade = jade || require(\'jade\').runtime;');
+
+ var nodeExport = 'if (typeof exports === \'object\' && exports) {';
+ nodeExport += 'module.exports = ' + nsInfo.namespace + ';}';
+
+ output.push(nodeExport);
+ }
+ }
+
+ if (options.amd) {
+ // Wrap the file in an AMD define fn.
+ output.unshift("define(['jade'], function(jade) { if(jade && jade['runtime'] !== undefined) { jade = jade.runtime; }");
+ if (options.namespace !== false) {
+ // Namespace has not been explicitly set to false; the AMD
+ // wrapper will return the object containing the template.
+ output.push("return "+nsInfo.namespace+";");
+ }
+ output.push("});");
+ }
+
+ grunt.file.write(f.dest, output.join(grunt.util.normalizelf(options.separator)));
+ grunt.log.writeln('File "' + f.dest + '" created.');
}
});
- });
-
- var compileJade = function(srcFile, options, data) {
- options = grunt.util._.extend({filename: srcFile}, options);
- delete options.data;
- var srcCode = grunt.file.read(srcFile);
+ });
- try {
- return require('jade').compile(srcCode, options)(data);
- } catch (e) {
- grunt.log.error(e);
- grunt.fail.warn('Jade failed to compile.');
- }
- };
};
View
18 test/expected/amd/jade.js
@@ -0,0 +1,18 @@
+define(['jade'], function(jade) { if(jade && jade['runtime'] !== undefined) { jade = jade.runtime; }
+
+return function anonymous(locals, attrs, escape, rethrow, merge) {
+attrs = attrs || jade.attrs; escape = escape || jade.escape; rethrow = rethrow || jade.rethrow; merge = merge || jade.merge;
+var buf = [];
+with (locals || {}) {
+var interp;
+buf.push('<div id="test" class="test"><span id="data">data</span>');
+if ( test)
+{
+buf.push('<div>testing</div>');
+}
+buf.push('</div>');
+}
+return buf.join("");
+}
+
+});
View
18 test/expected/amd/jade2.js
@@ -0,0 +1,18 @@
+define(['jade'], function(jade) { if(jade && jade['runtime'] !== undefined) { jade = jade.runtime; }
+
+return function anonymous(locals, attrs, escape, rethrow, merge) {
+attrs = attrs || jade.attrs; escape = escape || jade.escape; rethrow = rethrow || jade.rethrow; merge = merge || jade.merge;
+var buf = [];
+with (locals || {}) {
+var interp;
+buf.push('<div id="test" class="test"><span id="data">data</span>');
+if ( test)
+{
+buf.push('<div>testing 2</div>');
+}
+buf.push('</div>');
+}
+return buf.join("");
+}
+
+});
View
18 test/expected/amd/jadeInclude.js
@@ -0,0 +1,18 @@
+define(['jade'], function(jade) { if(jade && jade['runtime'] !== undefined) { jade = jade.runtime; }
+
+return function anonymous(locals, attrs, escape, rethrow, merge) {
+attrs = attrs || jade.attrs; escape = escape || jade.escape; rethrow = rethrow || jade.rethrow; merge = merge || jade.merge;
+var buf = [];
+with (locals || {}) {
+var interp;
+buf.push('<html><head><title>TEST</title></head><body></body></html>');
+ var a = 'hello jade test'
+buf.push('<p>');
+var __val__ = a
+buf.push(escape(null == __val__ ? "" : __val__));
+buf.push('</p>');
+}
+return buf.join("");
+}
+
+});
View
16 test/expected/amd/jadeTemplate.js
@@ -0,0 +1,16 @@
+define(['jade'], function(jade) { if(jade && jade['runtime'] !== undefined) { jade = jade.runtime; }
+
+return function anonymous(locals, attrs, escape, rethrow, merge) {
+attrs = attrs || jade.attrs; escape = escape || jade.escape; rethrow = rethrow || jade.rethrow; merge = merge || jade.merge;
+var buf = [];
+with (locals || {}) {
+var interp;
+buf.push('<div>');
+var __val__ = year
+buf.push(escape(null == __val__ ? "" : __val__));
+buf.push('</div>');
+}
+return buf.join("");
+}
+
+});
View
16 test/expected/jst/jade.js
@@ -0,0 +1,16 @@
+this["JST"] = this["JST"] || {};
+
+this["JST"]["jade"] = function anonymous(locals, attrs, escape, rethrow, merge) {
+attrs = attrs || jade.attrs; escape = escape || jade.escape; rethrow = rethrow || jade.rethrow; merge = merge || jade.merge;
+var buf = [];
+with (locals || {}) {
+var interp;
+buf.push('<div id="test" class="test"><span id="data">data</span>');
+if ( test)
+{
+buf.push('<div>testing</div>');
+}
+buf.push('</div>');
+}
+return buf.join("");
+};
View
16 test/expected/jst/jade2.js
@@ -0,0 +1,16 @@
+this["JST"] = this["JST"] || {};
+
+this["JST"]["jade2"] = function anonymous(locals, attrs, escape, rethrow, merge) {
+attrs = attrs || jade.attrs; escape = escape || jade.escape; rethrow = rethrow || jade.rethrow; merge = merge || jade.merge;
+var buf = [];
+with (locals || {}) {
+var interp;
+buf.push('<div id="test" class="test"><span id="data">data</span>');
+if ( test)
+{
+buf.push('<div>testing 2</div>');
+}
+buf.push('</div>');
+}
+return buf.join("");
+};
View
16 test/expected/jst/jadeInclude.js
@@ -0,0 +1,16 @@
+this["JST"] = this["JST"] || {};
+
+this["JST"]["jadeInclude"] = function anonymous(locals, attrs, escape, rethrow, merge) {
+attrs = attrs || jade.attrs; escape = escape || jade.escape; rethrow = rethrow || jade.rethrow; merge = merge || jade.merge;
+var buf = [];
+with (locals || {}) {
+var interp;
+buf.push('<html><head><title>TEST</title></head><body></body></html>');
+ var a = 'hello jade test'
+buf.push('<p>');
+var __val__ = a
+buf.push(escape(null == __val__ ? "" : __val__));
+buf.push('</p>');
+}
+return buf.join("");
+};
View
14 test/expected/jst/jadeTemplate.js
@@ -0,0 +1,14 @@
+this["JST"] = this["JST"] || {};
+
+this["JST"]["jadeTemplate"] = function anonymous(locals, attrs, escape, rethrow, merge) {
+attrs = attrs || jade.attrs; escape = escape || jade.escape; rethrow = rethrow || jade.rethrow; merge = merge || jade.merge;
+var buf = [];
+with (locals || {}) {
+var interp;
+buf.push('<div>');
+var __val__ = year
+buf.push(escape(null == __val__ ? "" : __val__));
+buf.push('</div>');
+}
+return buf.join("");
+};
View
27 test/jade_amd_test.js
@@ -0,0 +1,27 @@
+var grunt = require('grunt');
+
+exports.jade = {
+ compile: function(test) {
+ 'use strict';
+
+ test.expect(4);
+
+ var actual = grunt.file.read('tmp/amd/jade.js');
+ var expected = grunt.file.read('test/expected/amd/jade.js');
+ test.equal(expected, actual, 'should compile jade templates to js');
+
+ actual = grunt.file.read('tmp/amd/jade2.js');
+ expected = grunt.file.read('test/expected/amd/jade2.js');
+ test.equal(expected, actual, 'should compile jade templates to js (multiple files support)');
+
+ actual = grunt.file.read('tmp/amd/jadeInclude.js');
+ expected = grunt.file.read('test/expected/amd/jadeInclude.js');
+ test.equal(expected, actual, 'should compile jade templates to js with an include');
+
+ actual = grunt.file.read('tmp/amd/jadeTemplate.js');
+ expected = grunt.file.read('test/expected/amd/jadeTemplate.js');
+ test.equal(expected, actual, 'should compile jade templates to js with grunt template support');
+
+ test.done();
+ }
+};
View
27 test/jade_jst_test.js
@@ -0,0 +1,27 @@
+var grunt = require('grunt');
+
+exports.jade = {
+ compile: function(test) {
+ 'use strict';
+
+ test.expect(4);
+
+ var actual = grunt.file.read('tmp/jst/jade.js');
+ var expected = grunt.file.read('test/expected/jst/jade.js');
+ test.equal(expected, actual, 'should compile jade templates to JST template');
+
+ actual = grunt.file.read('tmp/jst/jade2.js');
+ expected = grunt.file.read('test/expected/jst/jade2.js');
+ test.equal(expected, actual, 'should compile jade templates to JST template (multiple files support)');
+
+ actual = grunt.file.read('tmp/jst/jadeInclude.js');
+ expected = grunt.file.read('test/expected/jst/jadeInclude.js');
+ test.equal(expected, actual, 'should compile jade templates to JST template with an include');
+
+ actual = grunt.file.read('tmp/jst/jadeTemplate.js');
+ expected = grunt.file.read('test/expected/jst/jadeTemplate.js');
+ test.equal(expected, actual, 'should compile jade templates to JST template with grunt template support');
+
+ test.done();
+ }
+};
Please sign in to comment.
Something went wrong with that request. Please try again.