├── .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: '