├── .gitignore ├── .npmignore ├── History.md ├── Makefile ├── Readme.md ├── bin └── minstache ├── component.json ├── index.js ├── package.json └── test └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | template 3 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | support 2 | test 3 | examples 4 | *.sock 5 | -------------------------------------------------------------------------------- /History.md: -------------------------------------------------------------------------------- 1 | 2 | 1.2.0 / 2014-06-17 3 | ================== 4 | 5 | * add iteration support. Closes #10 6 | 7 | 1.1.0 / 2013-07-04 8 | ================== 9 | 10 | * add unescaped property support 11 | * remove support for single braces 12 | 13 | 0.0.1 / 2010-01-03 14 | ================== 15 | 16 | * Initial release 17 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | test: 3 | @./node_modules/.bin/mocha \ 4 | --require should \ 5 | --reporter spec 6 | 7 | .PHONY: test -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | 2 | # minstache 3 | 4 | Mini mustache template engine. 5 | 6 | ## Installation 7 | 8 | $ npm install minstache 9 | $ component install visionmedia/minstache 10 | 11 | ## minstache(1) 12 | 13 | The `minstache(1)` executable can compile a file to a valid 14 | stand-alone commonjs module for you, there's no need to have minstache 15 | as a dependency: 16 | 17 | hello.mustache: 18 | 19 | ``` 20 | Hello {{name}}! {{^authenticated}}login{{/authenticated}} 21 | ``` 22 | 23 | convert it: 24 | 25 | ``` 26 | $ minstache < hello.mustache > hello.js 27 | ``` 28 | 29 | hello.js: 30 | 31 | ```js 32 | module.exports = function anonymous(obj) { 33 | 34 | function escape(html) { 35 | return String(html) 36 | .replace(/&/g, '&') 37 | .replace(/"/g, '"') 38 | .replace(//g, '>'); 40 | }; 41 | 42 | function section(obj, prop, negate, str) { 43 | var val = obj[prop]; 44 | if ('function' == typeof val) return val.call(obj, str); 45 | if (negate) val = !val; 46 | if (val) return str; 47 | return ''; 48 | }; 49 | 50 | return "Hello " + escape(obj.name) + "! " + section(obj, "authenticated", true, "login") + "\n" 51 | } 52 | ``` 53 | 54 | ## API 55 | 56 | ### minstache(string, [obj]) 57 | 58 | Compile and render the given mustache `string` with optional context `obj`. 59 | 60 | ### minstache.compile(string) 61 | 62 | Compile the mustache `string` to a stand-alone `Function` accepting a context `obj`. 63 | 64 | ## Divergence 65 | 66 | Partials are not supported, this lib is meant to be a small template engine solution for stand-alone [component](http://github.com/component) templates. If your template takes "partials" then pass other rendered strings to it. If you need a full-blown mustache solution Hogan.js is still great. 67 | 68 | Minstache uses `{{!name}}` for unescaped properties. 69 | 70 | ## License 71 | 72 | MIT 73 | -------------------------------------------------------------------------------- /bin/minstache: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | var program = require('commander') 8 | , mm = require('..'); 9 | 10 | // options 11 | 12 | program 13 | .usage('< template > js') 14 | .version(require('../package.json').version) 15 | .parse(process.argv); 16 | 17 | // read stdin 18 | 19 | var str = ''; 20 | process.stdin.setEncoding('utf8'); 21 | process.stdin.on('data', function(chunk){ str += chunk; }); 22 | process.stdin.on('end', done); 23 | process.stdin.resume(); 24 | 25 | function done() { 26 | var fn = mm.compile(str).toString(); 27 | process.stdout.write('module.exports = ' + fn); 28 | } -------------------------------------------------------------------------------- /component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "minstache", 3 | "version": "1.2.0", 4 | "description": "Mini mustache template engine", 5 | "keywords": ["mustache", "template", "engine"], 6 | "scripts": ["index.js"] 7 | } 8 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Expose `render()`.` 4 | */ 5 | 6 | exports = module.exports = render; 7 | 8 | /** 9 | * Expose `compile()`. 10 | */ 11 | 12 | exports.compile = compile; 13 | 14 | /** 15 | * Render the given mustache `str` with `obj`. 16 | * 17 | * @param {String} str 18 | * @param {Object} obj 19 | * @return {String} 20 | * @api public 21 | */ 22 | 23 | function render(str, obj) { 24 | obj = obj || {}; 25 | var fn = compile(str); 26 | return fn(obj); 27 | } 28 | 29 | /** 30 | * Compile the given `str` to a `Function`. 31 | * 32 | * @param {String} str 33 | * @return {Function} 34 | * @api public 35 | */ 36 | 37 | function compile(str) { 38 | var js = []; 39 | var toks = parse(str); 40 | var tok; 41 | 42 | for (var i = 0; i < toks.length; ++i) { 43 | tok = toks[i]; 44 | if (i % 2 == 0) { 45 | js.push('"' + tok.replace(/"/g, '\\"') + '"'); 46 | } else { 47 | switch (tok[0]) { 48 | case '/': 49 | tok = tok.slice(1); 50 | js.push(' }) + '); 51 | break; 52 | case '^': 53 | tok = tok.slice(1); 54 | assertProperty(tok); 55 | js.push(' + section(obj, "' + tok + '", true, function(obj){ return '); 56 | break; 57 | case '#': 58 | tok = tok.slice(1); 59 | assertProperty(tok); 60 | js.push(' + section(obj, "' + tok + '", false, function(obj){ return '); 61 | break; 62 | case '!': 63 | tok = tok.slice(1); 64 | assertProperty(tok); 65 | js.push(' + obj.' + tok + ' + '); 66 | break; 67 | default: 68 | assertProperty(tok); 69 | js.push(' + escape(obj.' + tok + ') + '); 70 | } 71 | } 72 | } 73 | 74 | js = '\n' 75 | + indent(escape.toString()) + ';\n\n' 76 | + indent(section.toString()) + ';\n\n' 77 | + ' return ' + js.join('').replace(/\n/g, '\\n'); 78 | 79 | return new Function('obj', js); 80 | } 81 | 82 | /** 83 | * Assert that `prop` is a valid property. 84 | * 85 | * @param {String} prop 86 | * @api private 87 | */ 88 | 89 | function assertProperty(prop) { 90 | if (!prop.match(/^[\w.]+$/)) throw new Error('invalid property "' + prop + '"'); 91 | } 92 | 93 | /** 94 | * Parse `str`. 95 | * 96 | * @param {String} str 97 | * @return {Array} 98 | * @api private 99 | */ 100 | 101 | function parse(str) { 102 | return str.split(/\{\{|\}\}/); 103 | } 104 | 105 | /** 106 | * Indent `str`. 107 | * 108 | * @param {String} str 109 | * @return {String} 110 | * @api private 111 | */ 112 | 113 | function indent(str) { 114 | return str.replace(/^/gm, ' '); 115 | } 116 | 117 | /** 118 | * Section handler. 119 | * 120 | * @param {Object} context obj 121 | * @param {String} prop 122 | * @param {Function} thunk 123 | * @param {Boolean} negate 124 | * @api private 125 | */ 126 | 127 | function section(obj, prop, negate, thunk) { 128 | var val = obj[prop]; 129 | if (Array.isArray(val)) return val.map(thunk).join(''); 130 | if ('function' == typeof val) return val.call(obj, thunk(obj)); 131 | if (negate) val = !val; 132 | if (val) return thunk(obj); 133 | return ''; 134 | } 135 | 136 | /** 137 | * Escape the given `html`. 138 | * 139 | * @param {String} html 140 | * @return {String} 141 | * @api private 142 | */ 143 | 144 | function escape(html) { 145 | return String(html) 146 | .replace(/&/g, '&') 147 | .replace(/"/g, '"') 148 | .replace(//g, '>'); 150 | } 151 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "minstache", 3 | "version": "1.2.0", 4 | "description": "Mini mustache template engine", 5 | "keywords": ["mustache", "template", "engine"], 6 | "author": "TJ Holowaychuk ", 7 | "dependencies": { 8 | "commander": "1.0.4" 9 | }, 10 | "devDependencies": { 11 | "mocha": "*", 12 | "should": "*" 13 | }, 14 | "bin": { 15 | "minstache": "bin/minstache" 16 | }, 17 | "main": "index" 18 | } 19 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Module dependencies. 4 | */ 5 | 6 | var mm = require('..'); 7 | 8 | describe('{id}', function(){ 9 | it('should not work', function(){ 10 | var user = { name: 'tobi' }; 11 | mm('hi {name}.', user).should.equal('hi {name}.'); 12 | }) 13 | }) 14 | 15 | describe('{{id}}', function(){ 16 | it('should buffer', function(){ 17 | var user = { name: 'tobi' }; 18 | mm('hi {{name}}.', user).should.equal('hi tobi.'); 19 | }) 20 | 21 | it('should escape', function(){ 22 | var user = { name: '