├── .github └── FUNDING.yml ├── .npmignore ├── Tangular.js ├── Tangular.min.js ├── license.txt ├── minify.json ├── minify.sh ├── package.json ├── readme.md └── test.js /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | patreon: totaljs 4 | open_collective: totalplatform 5 | ko_fi: totaljs 6 | liberapay: totaljs 7 | buy_me_a_coffee: totaljs 8 | custom: https://www.totaljs.com/support/ 9 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | Tangular.min.js 2 | minify.sh 3 | test.js -------------------------------------------------------------------------------- /Tangular.js: -------------------------------------------------------------------------------- 1 | (function(W) { 2 | 3 | if (W.Tangular) 4 | return; 5 | 6 | var Tangular = {}; 7 | var Thelpers = Tangular.helpers = {}; 8 | 9 | Tangular.version = 'v5.0.5'; 10 | Tangular.cache = {}; 11 | 12 | W.Ta = W.Tangular = Tangular; 13 | W.Thelpers = Thelpers; 14 | 15 | var SKIP = { 'null': true, 'undefined': true, 'true': true, 'false': true, 'Object': 1, 'String': 1, 'Number': 1, 'Boolean': 1, 'Date': 1, 'Array': 1, 'window': 1, 'global': 1, 'arguments': 1, 'eval': 1, 'Function': 1, 'function': 1, 'var': 1, 'let': 1, 'const': 1, 'delete': 1 }; 16 | var REG_CMDFIND = /\{\{.*?\}\}/g; 17 | var REG_CMDCLEAN = /\{\{|\}\}/g; 18 | var REG_ENCODE = /[<>&"]/g; 19 | var REG_TRIM = /\n$/g; 20 | 21 | function parseInlineVariables(line, blacklist) { 22 | 23 | var tmp = ''; 24 | var variables = []; 25 | var skip = 0; 26 | 27 | for (var i = 0; i < line.length; i++) { 28 | 29 | var c = line.charCodeAt(i); 30 | 31 | if (!skip) { 32 | 33 | if ((tmp && c > 47 && c < 58) || (c > 64 && c < 91) || (c > 96 && c < 123) || (c === 95 || c === 36)) { 34 | tmp += line.charAt(i); 35 | continue; 36 | } 37 | 38 | if (tmp) { 39 | if (!SKIP[tmp] && variables.indexOf(tmp) === -1 && (!blacklist || blacklist.indexOf(tmp) === -1)) 40 | variables.push(tmp); 41 | tmp = ''; 42 | } 43 | } 44 | 45 | if (c === 46 || c === 124) { // "." or "|" 46 | skip = c; 47 | } else if ((skip === 46 || skip === 124) && c === 40) { // ("." or "|") and "(" 48 | skip = 0; 49 | } else if (c === 96 || c === 34 || c === 39) { // "`" or "'" or "\"" 50 | if (c === skip) 51 | skip = 0; 52 | else 53 | skip = c; 54 | } 55 | } 56 | 57 | if (tmp && !SKIP[tmp] && variables.indexOf(tmp) === -1 && (!blacklist || blacklist.indexOf(tmp) === -1)) 58 | variables.push(tmp); 59 | 60 | return variables; 61 | } 62 | 63 | Tangular.toArray = function(obj) { 64 | var keys = Object.keys(obj); 65 | var arr = []; 66 | for (var i = 0, length = keys.length; i < length; i++) 67 | arr.push({ key: keys[i], value: obj[keys[i]] }); 68 | return arr; 69 | }; 70 | 71 | function Template() { 72 | this.commands; 73 | this.variables; 74 | this.builder; 75 | this.split = '\0'; 76 | } 77 | 78 | Template.prototype.compile = function(template, tagbeg, tagend) { 79 | 80 | var self = this; 81 | var ifcount = 0; 82 | var loopcount = 0; 83 | var loops = []; 84 | var reg_find = REG_CMDFIND; 85 | var reg_clean = REG_CMDCLEAN; 86 | var tmp; 87 | 88 | if (tagbeg && tagend) { 89 | reg_find = new RegExp(tagbeg + '.*?' + tagend, 'g'); 90 | reg_clean = new RegExp(tagbeg + '|' + tagend, 'g'); 91 | } 92 | 93 | self.template = template; 94 | 95 | template = template.replace(/\|\|/g, '\1'); 96 | 97 | self.variables = {}; 98 | self.commands = []; 99 | 100 | self.builder = template.replace(reg_find, function(text) { 101 | 102 | var cmd = text.replace(reg_clean, '').trim(); 103 | var variable = null; 104 | var helpers = null; 105 | var index; 106 | var isif = false; 107 | var isloop = false; 108 | var iscode = true; 109 | 110 | if (cmd === 'fi') { 111 | ifcount--; 112 | // end of condition 113 | } else if (cmd === 'end') { 114 | loopcount--; 115 | // end of loop 116 | loops.pop(); 117 | } else if (cmd.substring(0, 3) === 'if ') { 118 | // condition 119 | ifcount++; 120 | variable = parseInlineVariables(cmd.substring(3), loops); 121 | if (variable.length) { 122 | for (var i = 0; i < variable.length; i++) { 123 | var name = variable[i]; 124 | if (self.variables[name]) 125 | self.variables[name]++; 126 | else 127 | self.variables[name] = 1; 128 | } 129 | } else 130 | variable = null; 131 | isif = true; 132 | iscode = true; 133 | } else if (cmd.substring(0, 8) === 'foreach ') { 134 | 135 | loopcount++; 136 | // loop 137 | 138 | tmp = cmd.substring(8).split(' '); 139 | loops.push(tmp[0].trim()); 140 | 141 | index = tmp[2].indexOf('.'); 142 | if (index !== -1) 143 | tmp[2] = tmp[2].substring(0, index); 144 | 145 | variable = tmp[2].trim(); 146 | 147 | if (loops.indexOf(variable) === -1) { 148 | if (self.variables[variable]) 149 | self.variables[variable]++; 150 | else 151 | self.variables[variable] = 1; 152 | variable = [variable]; 153 | } 154 | else 155 | variable = null; 156 | 157 | isloop = true; 158 | } else if (cmd.substring(0, 8) === 'else if ') { 159 | // else if 160 | variable = parseInlineVariables(cmd.substring(8), loops); 161 | if (variable.length) { 162 | for (var i = 0; i < variable.length; i++) { 163 | var name = variable[i]; 164 | if (self.variables[name]) 165 | self.variables[name]++; 166 | else 167 | self.variables[name] = 1; 168 | } 169 | } else 170 | variable = null; 171 | isif = true; 172 | } else if (cmd !== 'continue' && cmd !== 'break' && cmd !== 'else') { 173 | 174 | variable = parseInlineVariables(cmd); 175 | 176 | var ishelper = false; 177 | 178 | for (var i = 0; i < variable.length; i++) { 179 | var v = variable[i]; 180 | 181 | if (v + '(' === cmd.substring(0, v.length + 1)) { 182 | ishelper = true; 183 | continue; 184 | } 185 | 186 | if (self.variables[v]) 187 | self.variables[v]++; 188 | else 189 | self.variables[v] = 1; 190 | } 191 | 192 | if (!variable.length) 193 | variable = null; 194 | 195 | var hindex = cmd.indexOf('|'); 196 | var fnhelper = null; 197 | 198 | if (ishelper) { 199 | fnhelper = cmd.substring(0, hindex === -1 ? cmd.length : hindex); 200 | if (hindex === -1) 201 | cmd = ''; 202 | else 203 | cmd = '' + cmd.substring(index); 204 | } else if (!ishelper && hindex === -1) 205 | cmd += ' | encode'; 206 | 207 | helpers = cmd.split('|'); 208 | cmd = helpers[0]; 209 | helpers = helpers.slice(1); 210 | 211 | if (ishelper) 212 | helpers.unshift(fnhelper); 213 | 214 | if (helpers.length) { 215 | for (var i = 0; i < helpers.length; i++) { 216 | var helper = helpers[i].trim(); 217 | var ishelperfirst = ishelper && !i; 218 | index = helper.indexOf('('); 219 | if (index === -1) { 220 | helper = 'Thelpers.$execute($helpers,model,\'' + helper + '\',' + (ishelperfirst ? '' : '\7)'); 221 | } else 222 | helper = 'Thelpers.$execute($helpers,model,\'' + helper.substring(0, index) + '\',' + (ishelperfirst ? '' : '\7,') + helper.substring(index + 1); 223 | helpers[i] = helper; 224 | } 225 | } else 226 | helpers = null; 227 | 228 | cmd = self.safe(cmd.trim() || 'model'); 229 | iscode = false; 230 | } 231 | 232 | self.commands.push({ index: self.commands.length, cmd: cmd, ifcount: ifcount, loopcount: loopcount, variable: variable, helpers: helpers, isloop: isloop, isif: isif, iscode: iscode }); 233 | 234 | return self.split; 235 | 236 | }).split(self.split); 237 | 238 | for (var i = 0; i < self.builder.length; i++) { 239 | var m = self.builder[i]; 240 | self.builder[i] = m ? m.replace(REG_TRIM, '') : m; 241 | } 242 | 243 | return self.make(); 244 | }; 245 | 246 | Template.prototype.safe = function(cmd) { 247 | 248 | var arr = cmd.split('.'); 249 | var output = []; 250 | 251 | for (var i = 1; i < arr.length; i++) { 252 | var k = arr.slice(0, i).join('.'); 253 | output.push(k + '==null?\'\':'); 254 | } 255 | return output.join('') + arr.join('.'); 256 | }; 257 | 258 | Template.prototype.make = function() { 259 | 260 | var self = this; 261 | var builder = ['var $output=$text[0];var $tmp;var $index=0;']; 262 | 263 | for (var i = 0, length = self.commands.length; i < length; i++) { 264 | 265 | var cmd = self.commands[i]; 266 | var tmp; 267 | 268 | i && builder.push('$output+=$text[' + i + '];'); 269 | 270 | if (cmd.iscode) { 271 | 272 | if (cmd.isloop) { 273 | 274 | var name = '$i' + Math.random().toString(16).substring(3, 6); 275 | var namea = name + 'a'; 276 | var index = cmd.cmd.lastIndexOf(' in '); 277 | if (index === -1) 278 | index = cmd.cmd.lastIndexOf(' of '); 279 | tmp = cmd.cmd.substring(index + 4).trim(); 280 | tmp = namea + '=' + self.safe(tmp) + ';if(!(' + namea + ' instanceof Array)){if(' + namea + '&&typeof(' + namea + ')===\'object\')' + namea + '=Tangular.toArray(' + namea + ')}if(' + namea + ' instanceof Array&&' + namea + '.length){for(var ' + name + '=0,' + name + 'l=' + namea + '.length;' + name + '<' + name + 'l;' + name + '++){$index=' + name + ';var ' + cmd.cmd.split(' ')[1] + '=' + namea + '[' + name + '];'; 281 | builder.push(tmp); 282 | 283 | } else if (cmd.isif) { 284 | if (cmd.cmd.substring(0, 8) === 'else if ') 285 | builder.push('}' + cmd.cmd.substring(0, 8).trim() + '(' + cmd.cmd.substring(8).trim() + '){'); 286 | else 287 | builder.push(cmd.cmd.substring(0, 3).trim() + '(' + cmd.cmd.substring(3).trim() + '){'); 288 | } else { 289 | switch (cmd.cmd) { 290 | case 'else': 291 | builder.push('}else{'); 292 | break; 293 | case 'end': 294 | builder.push('}}'); 295 | break; 296 | case 'fi': 297 | builder.push('}'); 298 | break; 299 | case 'break': 300 | builder.push('break;'); 301 | break; 302 | case 'continue': 303 | builder.push('continue;'); 304 | break; 305 | } 306 | } 307 | 308 | } else { 309 | if (cmd.helpers) { 310 | var str = ''; 311 | for (var j = 0; j < cmd.helpers.length; j++) { 312 | var helper = cmd.helpers[j]; 313 | if (j === 0) 314 | str = helper.replace('\7', cmd.cmd.trim()).trim(); 315 | else 316 | str = helper.replace('\7', str.trim()); 317 | } 318 | builder.push('$tmp=' + str + ';if($tmp!=null)$output+=$tmp;'); 319 | } else 320 | builder.push('if(' + cmd.cmd + '!=null)$output+=' + cmd.cmd + ';'); 321 | } 322 | } 323 | 324 | builder.push((length ? ('$output+=$text[' + length + '];') : '') + 'return $output.charAt(0) === \'\\n\'?$output.substring(1):$output;'); 325 | delete self.variables.$; 326 | var variables = Object.keys(self.variables); 327 | var names = ['$helpers||{}', '$||{}', 'model']; 328 | 329 | for (var i = 0; i < variables.length; i++) 330 | names.push('model.' + variables[i]); 331 | 332 | for (var i = 0; i < self.builder.length; i++) 333 | self.builder[i] = self.builder[i].replace(/\1/g, '||'); 334 | 335 | var code = 'var tangular=function($helpers,$,model' + (variables.length ? (',' + variables.join(',')) : '') + '){' + builder.join('') + '};return function(model,$,$helpers){try{return tangular(' + names.join(',') + ')}catch(e){console.error(\'Tangular error:\',e + \'\',$template)}}'; 336 | return (new Function('$text', '$template', code.replace(/\1/g, '||')))(self.builder, self.template); 337 | }; 338 | 339 | Thelpers.$execute = function(helpers, model, name, a, b, c, d, e, f, g, h) { 340 | 341 | var fn = helpers[name] || Thelpers[name]; 342 | 343 | if (!fn) { 344 | console && console.warn('Tangular: missing helper', '"' + name + '"'); 345 | return a; 346 | } 347 | 348 | return fn.call(model, a, b, c, d, e, f, g, h); 349 | }; 350 | 351 | Thelpers.encode = function(value, type) { 352 | 353 | if (type) { 354 | 355 | if (typeof(type) === 'function') 356 | return type(value); 357 | 358 | if (type === 'json') 359 | return JSON.stringify(value); 360 | 361 | if (type === 'json2') 362 | return JSON.stringify(value, null, '\t'); 363 | 364 | if (type === 'url' || type === 'urlencoded') 365 | return encodeURIComponent(value); 366 | 367 | if (type === 'querify') 368 | return QUERIFY(value); 369 | } 370 | 371 | return value == null ? '' : (value + '').replace(REG_ENCODE, function(c) { 372 | switch (c) { 373 | case '&': return '&'; 374 | case '<': return '<'; 375 | case '>': return '>'; 376 | case '"': return '"'; 377 | } 378 | return c; 379 | }); 380 | }; 381 | 382 | Thelpers.raw = function(value) { 383 | return value; 384 | }; 385 | 386 | Tangular.render = function(template, model, repository, helpers) { 387 | var template = new Template().compile(template); 388 | return template(model == null ? {} : model, repository, helpers); 389 | }; 390 | 391 | Tangular.compile = function(template, tagbeg, tagend) { 392 | return new Template().compile(template, tagbeg, tagend); 393 | }; 394 | 395 | Tangular.register = function(name, fn) { 396 | Thelpers[name] = fn; 397 | return Tangular; 398 | }; 399 | 400 | })(typeof(window)==='undefined'?global:window); -------------------------------------------------------------------------------- /Tangular.min.js: -------------------------------------------------------------------------------- 1 | (function(e){if(e.Tangular)return;var t={};var v=t.helpers={};t.version='v5.0.5';t.cache={};e.Ta=e.Tangular=t;e.Thelpers=v;var s={null:true,undefined:true,true:true,false:true,Object:1,String:1,Number:1,Boolean:1,Date:1,Array:1,window:1,global:1,arguments:1,eval:1,Function:1,function:1,var:1,let:1,const:1,delete:1};var l=/\{\{.*?\}\}/g;var u=/\{\{|\}\}/g;var n=/[<>&"]/g;var o=/\n$/g;function w(e,r){var t='';var n=[];var i=0;for(var a=0;a47&&l<58||l>64&&l<91||l>96&&l<123||(l===95||l===36)){t+=e.charAt(a);continue}if(t){if(!s[t]&&n.indexOf(t)===-1&&(!r||r.indexOf(t)===-1))n.push(t);t=''}}if(l===46||l===124){i=l}else if((i===46||i===124)&&l===40){i=0}else if(l===96||l===34||l===39){if(l===i)i=0;else i=l}}if(t&&!s[t]&&n.indexOf(t)===-1&&(!r||r.indexOf(t)===-1))n.push(t);return n}t.toArray=function(e){var r=Object.keys(e);var t=[];for(var n=0,i=r.length;n':return'>';case'"':return'"'}return e})};v.raw=function(e){return e};t.render=function(e,r,t,n){var e=(new i).compile(e);return e(r==null?{}:r,t,n)};t.compile=function(e,r,t){return(new i).compile(e,r,t)};t.register=function(e,r){v[e]=r;return t}})(typeof window==='undefined'?global:window); -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright 2012-2023 (c) Peter Širka 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a 6 | copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to permit 10 | persons to whom the Software is furnished to do so, subject to the 11 | following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included 14 | in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 19 | NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 20 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 21 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 22 | USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /minify.json: -------------------------------------------------------------------------------- 1 | { 2 | "mangle": true, 3 | "output": { "quote_style": 1 } 4 | } -------------------------------------------------------------------------------- /minify.sh: -------------------------------------------------------------------------------- 1 | ECHO "[COMPILING]" 2 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) 3 | cd $DIR 4 | uglifyjs Tangular.js --config-file minify.json -o Tangular.min.js -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tangular", 3 | "version": "4.0.0", 4 | "description": "A simple template engine like Angular.js for JavaScript or node.js", 5 | "main": "./Tangular.js", 6 | "keywords": [ 7 | "Angular", 8 | "Handlebars", 9 | "Mustache", 10 | "view engine", 11 | "template" 12 | ], 13 | "engines": { 14 | "node": ">=0.8.0" 15 | }, 16 | "scripts": { 17 | "test": "echo \"Error: no test specified\" && exit 1" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "git+https://github.com/petersirka/Tangular.git" 22 | }, 23 | "author": "Peter Širka", 24 | "bugs": { 25 | "url": "https://github.com/petersirka/Tangular/issues" 26 | }, 27 | "homepage": "https://github.com/petersirka/Tangular#readme", 28 | "license": "MIT", 29 | "contributors": [{ 30 | "name": "Peter Širka", 31 | "email": "petersirka@gmail.com" 32 | }, { 33 | "name": "Константин", 34 | "email": "" 35 | }] 36 | } 37 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | [![MIT License][license-image]][license-url] 2 | 3 | # Tangular 4 | 5 | [![Made in EU](https://cdn.componentator.com/eu-small.png)](https://european-union.europa.eu/) 6 | 7 | > A simple template engine like Angular.js for JavaScript or node.js 8 | 9 | - only __2.0 kB__ minified + gziped 10 | - syntax like __Angular.js__ templates 11 | - supports custom helpers 12 | - supports conditions (+ nested conditions) 13 | - supports loops (+ nested loops) 14 | - __supports two models__ 15 | - no dependencies 16 | - IE `>= 9` 17 | - best of use with [www.totaljs.com - web framework for Node.js](http://www.totaljs.com) 18 | - Live example on [JSFiddle / Tangular](http://jsfiddle.net/petersirka/ftfvba65/2/) 19 | - __One of the fastest template engine in the world__ 20 | 21 | __YOU MUST SEE:__ 22 | 23 | - [jComponent - A component library for jQuery](https://github.com/petersirka/jComponent) 24 | - [jRouting - HTML 5 routing via History API](https://github.com/petersirka/jRouting) 25 | - [jQuery two way bindings](https://github.com/petersirka/jquery.bindings) 26 | 27 | 28 | ## Node.js 29 | 30 | ```bash 31 | npm install tangular 32 | ``` 33 | 34 | ```javascript 35 | require('tangular'); 36 | // Inits Tangular and registers "Tangular" keyword as a global variable 37 | // console.log(Tangular); 38 | ``` 39 | 40 | ## Example 41 | 42 | ```javascript 43 | var output = Tangular.render('Hello {{name}} and {{name | raw}}!', { name: 'world' }); 44 | // Hello <b>world</b> and world! 45 | ``` 46 | 47 | ## Second model 48 | 49 | - very helpful, you don't have to change the base model 50 | - second model can be used in the template via `$` character, e.g. `{{ $.property_name }}` 51 | 52 | ```javascript 53 | var output = Tangular.render('Hello {{ name }} and {{ $.name }}!', { name: 'MODEL 1' }, { name: 'MODEL 2'}); 54 | // Hello MODEL 1 and MODEL 2 55 | ``` 56 | 57 | 58 | ## Best performance with pre-compile 59 | 60 | ```javascript 61 | // cache 62 | var template = Tangular.compile('Hello {{name}} and {{name | raw}}!'); 63 | 64 | // render 65 | // template(model, [model2]) 66 | var output = template({ name: 'Peter' }); 67 | ``` 68 | 69 | ## Conditions 70 | 71 | - supports `else if` 72 | 73 | ```html 74 | {{if name.length > 0}} 75 |
OK
76 | {{else}} 77 |
NO
78 | {{fi}} 79 | ``` 80 | 81 | ```html 82 | {{if name !== null}} 83 |
NOT NULL
84 | {{fi}} 85 | ``` 86 | 87 | ## Looping 88 | 89 | ```html 90 | {{foreach m in orders}} 91 |

Order num.{{m.number}} (current index: {{$index}})

92 |
{{m.name}}
93 | {{end}} 94 | ``` 95 | 96 | ## Custom helpers 97 | 98 | ```javascript 99 | Tangular.register('currency', function(value, decimals) { 100 | // this === MODEL/OBJECT 101 | // console.log(this); 102 | // example 103 | return value.format(decimals || 0); 104 | }); 105 | 106 | Tangular.register('plus', function(value, count) { 107 | return value + (count || 1); 108 | }); 109 | 110 | // Calling custom helper in JavaScript, e.g.: 111 | Tangular.helpers.currency(100, 2); 112 | ``` 113 | 114 | ```html 115 |
{{ amount | currency }}
116 |
{{ amount | currency(2) }}
117 | 118 | 119 |
{{ count | plus | plus(2) | plus | plus(3) }}
120 | ``` 121 | 122 | ## Built-in helpers 123 | 124 | ```html 125 |
{{ name }} = VALUE IS ENCODED BY DEFAULT
126 |
{{ name | raw }} = VALUE IS NOT ENCODED
127 | ``` 128 | 129 | ## Miracles 130 | 131 | ```javascript 132 | var template = Tangular.compile('Encoded value {{}} and raw value {{ | raw }}.'); 133 | console.log(template('Tangular')); 134 | ``` 135 | 136 | ## Alias: Tangular is too long as word 137 | 138 | ```javascript 139 | // use alias: 140 | // Ta === Tangular 141 | Ta.compile(''); 142 | ``` 143 | 144 | ## Contributors 145 | 146 | | Contributor | Type | E-mail | 147 | |-------------|------|--------| 148 | | [Peter Širka](https://www.petersirka.eu) | author | | 149 | | [Константин](https://github.com/bashkos) | contributor | 150 | 151 | [license-image]: http://img.shields.io/badge/license-MIT-blue.svg?style=flat 152 | [license-url]: license.txt 153 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | var Tangular = require('./tangular'); 2 | var output = Tangular.render('Hello {{ | raw }}', 'Peter'); 3 | // Hello MODEL 1 and MODEL 2 4 | console.log(output); 5 | --------------------------------------------------------------------------------