UNPKG

49.1 kBMarkdownView Raw
1<!-- This document was generated from README.vash -->
2
3
4Vash
5====
6
7_"... the 60 billion double-dollar template-maker!"_ ~ The previous README, and no one else, ever.
8
9Vash is a template engine that offers a swift flow between code and content using [Razor Syntax][] <sup id="fnref:razor-ms">
10 <a rel="footnote" href="#fn:razor-ms">1</a>
11 </sup>. This document <sup id="fnref:this-doc">
12 <a rel="footnote" href="#fn:this-doc">2</a>
13 </sup> is intended for users of Vash, and also serves as a reference for Vash's implementation of Razor Syntax.
14
15[Razor Syntax]: http://www.asp.net/web-pages/tutorials/basics/2-introduction-to-asp-net-web-programming-using-the-razor-syntax
16
17[![Build Status](https://secure.travis-ci.org/kirbysayshi/vash.png?branch=master)](https://travis-ci.org/kirbysayshi/vash)
18
19[![NPM](https://nodei.co/npm/vash.png?downloads=true&stars=true)](https://nodei.co/npm/vash/) [![NPM](https://nodei.co/npm-dl/vash.png)](https://nodei.co/npm/vash/)
20
21[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/kirbysayshi/vash/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
22
23
24- [Features](#features)
25- [Syntax Example](#syntax-example)
26- [Quick Start](#quick-start)
27 - [nodejs](#nodejs)
28 - [express](#express)
29 - [Browser - Vanilla](#browser---vanilla)
30 - [Browser - Browserify et al](#browser---browserify-et-al)
31 - [Browser - RequireJS](#browser---requirejs)
32- [Playground](#playground)
33- [Syntax](#syntax)
34 - [The Transition Character: @](#the-transition-character)
35 - [Expressions](#expressions)
36 - [Advanced Expressions](#advanced-expressions)
37 - [Explicit Expressions](#explicit-expressions)
38 - [Code Blocks](#code-blocks)
39 - [Keyword Blocks](#keyword-blocks)
40 - [Comments](#comments)
41 - [HTML Escaping](#html-escaping)
42 - [Explicit Markup](#explicit-markup)
43- [Configuration](#configuration)
44 - [vash.config.useWith](#vash-config-usewith)
45 - [vash.config.modelName](#vash-config-modelname)
46 - [vash.config.helpersName](#vash-config-helpersname)
47 - [vash.config.htmlEscape](#vash-config-htmlescape)
48 - [vash.config.debug](#vash-config-debug)
49 - [vash.config.debugParser](#vash-config-debugparser)
50 - [vash.config.debugCompiler](#vash-config-debugcompiler)
51 - [vash.config.simple](#vash-config-simple)
52 - [vash.config.favorText](#vash-config-favortext)
53- [Template Options](#template-options)
54 - [asContext](#ascontext)
55 - [onRenderEnd](#onrenderend)
56- [Helper System](#helper-system)
57- [Built-in Helpers](#built-in-helpers)
58 - [vash.helpers.raw](#vash-helpers-raw)
59 - [vash.helpers.escape](#vash-helpers-escape)
60 - [vash.helpers.tplcache](#vash-helpers-tplcache)
61- [Layout Helpers](#layout-helpers)
62 - [vash.helpers.extend](#vash-helpers-extend)
63 - [vash.helpers.block](#vash-helpers-block)
64 - [vash.helpers.append](#vash-helpers-append)
65 - [vash.helpers.prepend](#vash-helpers-prepend)
66 - [vash.helpers.include](#vash-helpers-include)
67- [Compiled Helpers](#compiled-helpers)
68- [Buffer API](#buffer-api)
69- [Precompiling Templates](#precompiling-templates)
70- [Vash Runtime (Browser)](#vash-runtime-browser)
71- [Compile-time API](#compile-time-api)
72 - [vash.compile](#vash-compile)
73 - [vash.compileHelper](#vash-compilehelper)
74 - [vash.compileBatch](#vash-compilebatch)
75- [Runtime API](#runtime-api)
76 - [vash.link](#vash-link)
77 - [vash.lookup](#vash-lookup)
78 - [vash.install](#vash-install)
79 - [vash.uninstall](#vash-uninstall)
80- [vash(1)](#vash-1)
81 - [Installation](#installation)
82 - [--target-namespace](#vash1--target-namespace)
83 - [--property-name](#vash1--property-name)
84 - [--helper](#vash1--helper)
85- [Contributing / Building](#contributing-building)
86- [Getting Help](#getting-help)
87- [Special Thanks](#special-thanks)
88- [License](#license)
89
90
91<a name="features"></a>Features
92================
93
94* Mix code and content without ugly delineators, like `<?`, `<%`, or `{{`.
95* No new language to learn: Vash is just HTML-aware JavaScript.
96* Great with markup, but can be used with nearly any other language as well (even Markdown!).
97* Helpers API allows for extensibility and meta programming.
98* Works in the browser or in node.
99* Comes with a Jade-inspired layout engine (block, include, extend, append/prepend), which even works in the browser.
100
101<a name="syntax-example"></a>Syntax Example
102======================
103
104 <p>How are you @model.name? Today is a sunny day on the planet Gunsmoke.</p>
105
106 <ul class="@(model.active ? 'highlight' : '')">
107 @model.forEach(function(m){
108 <li>@m.name</li>
109 })
110 </ul>
111
112<a name="quick-start"></a>Quick Start
113===================
114
115<a name="nodejs"></a>nodejs
116--------------
117
118 var vash = require('vash');
119 var tpl = vash.compile('<p>I am a @model.t!</p>');
120
121 var out = tpl({ t: 'template' });
122 // <p>I am a template!</p>
123
124<a name="express"></a>express
125--------------------
126
127Check out [vash-express-example][] for a full example of hooking up vash as a view engine for express 3. But it's basically as simple as:
128
129 var express = require('express');
130
131 var app = express();
132 app.set('view engine', 'vash');
133
134More information is also available in the [Layout Helpers][] sections.
135
136[vash-express-example]: https://github.com/kirbysayshi/vash-express-example
137
138<a name="browser---vanilla"></a>Browser - Vanilla
139-------------------------
140
141 <script type="text/javascript" src="vash.min.js"></script>
142
143 var tpl = vash.compile( '<p>I am a @model.t!</p>' );
144 document.querySelector('#content').innerHTML = tpl({ t: 'template' });
145
146<a name="browser---browserify-et-al"></a>Browser - Browserify et al
147----------------------------------
148
149Just `require` Vash, and compile. If you want something fancier, try [vashify](https://www.npmjs.com/package/vashify)!
150
151<a name="browser---requirejs"></a>Browser - RequireJS
152---------------------------
153
154RequireJS support has been recently dropped. However Vash does support CJS environments, so as long as you configure RequireJS to consume Vash as a CJS project (including `node_modules` resolution), everything should work.
155
156<a name="playground"></a>Playground
157==================
158
159Vash now has [a playground][] of sorts at [CodePen.io][]. It uses the current version of `vash.js` from the `build` folder. Fork it to test your own template ideas!
160
161[a playground]: http://codepen.io/kirbysayshi/full/IjrFw
162[CodePen.io]: http://codepen.io
163
164<a name="syntax"></a>Syntax
165==============
166
167For the following examples, assume a model is passed into the compiled function. If a model is explicitly defined, it will appear as:
168
169 // model = { what: 'hello!' }
170
171<a name="the-transition-character"></a>The Transition Character: @
172------------------------------------
173
174Vash uses the `@` symbol to transition between code and markup. To escape and print a literal `@`, use a double `@`, like this: `@@`.
175
176<a name="expressions"></a>Expressions
177-------------------
178
179The most basic usage of Vash is an implicit expression. Vash is smart enough to know what's valid JS and what's not, and can usually do what you want it to do. An expression is an @ followed by a valid JS identifier. This is then interpolated automatically.
180
181input:
182
183 // model = { what: 'hello!' }
184 <p>@what</p>
185
186output:
187
188 <p>hello!</p>
189
190The `model` comment is just to show that the object passed into the compiled template contains a key that matches the expression.
191
192To allow for the fastest render time possible, Vash by default requires the model to be addressed explicitly. This is to avoid using a `with` statment in the compiled template, which is approximately 25 times slower. The above example then becomes:
193
194input:
195
196 <p>@model.what</p>
197
198output:
199
200 <p>hello!</p>
201
202As you can see, the output is exactly the same. The name used to reference the model is configurable via [vash.config.modelName][]. Typical values are `model` and `it`.
203
204
205<a name="advanced-expressions"></a>Advanced Expressions
206----------------------------
207
208Vash typically knows when an expression ends, even when the expression is complex. For example:
209
210input:
211
212 <p>@model.what().who[2]('are you sure')('yes, it\'s ok')( model.complex ? 'FULL POWER' : '' )</p>
213
214This will work just fine, assuming you have a model that actually contains that complexity! I hope you don't, and if so, I feel bad.
215
216Callbacks work as well:
217
218input:
219
220 // model = ['a', 'b']
221 @model.forEach(function(item){
222 <li>@item</li>
223 })
224
225outputs:
226
227 <li>a</li><li>b</li>
228
229Vash also knows the difference between JS dot notation and a period.
230
231input:
232
233 // model = { description: 'living' }
234 <p>Plants are @model.description.</p>
235
236output:
237
238 <p>Plants are living.</p>
239
240And empty brackets, because they're not valid JS:
241
242input:
243
244 // model = { formName: 'addresses' }
245 <input type="text" name="@model.formName[]" />
246
247output:
248
249 <input type="text" name="addresses[]" />
250
251Email addresses, to an extent, are fine as well. Vash makes a trade-off. It uses the following regex to validate an email address:
252
253 /^([a-zA-Z0-9.%]+@[a-zA-Z0-9.\-]+\.(?:ca|co\.uk|com|edu|net|org))\b/
254
255Email addresses can actually contain many more valid characters, and are [really hard to validate][]. Vash can handle a typical email address with ease:
256
257input:
258
259 <a href="mailto:vash@planetgunsmoke.com">Email Me</a>
260
261output:
262
263 <a href="mailto:vash@planetgunsmoke.com">Email Me</a>
264
265If you have a complex email address that confuses Vash, then you should use an [explicit expression](#explicit-expressions) instead.
266
267[really hard to validate]: http://www.regular-expressions.info/email.html
268
269<a name="explicit-expressions"></a>Explicit Expressions
270----------------------------
271
272An explicit expression is simply an expression that, instead of being composed of `@` and a valid JS identifier, is surrounded by parenthesis.
273
274input:
275
276 <p>@(model.what)</p>
277
278output:
279
280 <p>hello!</p>
281
282Why would you ever need this? Perhaps you want to do something like:
283
284input:
285
286 // model = { hasIceCream: true }
287 <p class="@( model.hasIceCream ? 'ice-cream' : '')">Ice Cream<p>
288
289output:
290
291 <p class="ice-cream">Ice Cream<p>
292
293You could even create an anonymous function.
294
295input:
296
297 @(function(type){ return type + ' cream'; }('banana'))
298
299output:
300
301 banana creme
302
303As you can see, Vash does not require a model to be referenced, or even passed in.
304
305<a name="code-blocks"></a>Code Blocks
306-------------------
307
308Sometimes, AGAINST ALL ODDS, a template may need some quick computation of values to avoid repeating yourself. Unlike expressions and explicit expressions, a code block does not directly output. To compare to PHP, expressions are like `<?= $what ?>`, while a code block is like `<? $what = 'what' ?>`.
309
310A code block is simply `@{ }`.
311
312input:
313
314 @{ var rideOn = 'shooting star'; }
315
316output:
317
318That's right, _nothing_! Here's a better example:
319
320input:
321
322 @{
323 var total = model.price + model.tax;
324 }
325
326 <p>Your total is: $@total</p>
327
328output:
329
330 <p>Your total is: $2.70</p>
331
332Anything is valid within a code block, such as function declarations or even something as complex as defining a prototype. You can also use markup within a code block, and it will behave as expected:
333
334input:
335
336 @{ <p>This works!</p> }
337
338output:
339
340 <p>This works!</p>
341
342A code block just tells Vash, "expect the next stuff to be code until otherwise".
343
344<a name="keyword-blocks"></a>Keyword Blocks
345----------------------
346
347Vash is aware of keywords, and will open a code block automatically for you.
348
349input:
350
351 // model = { type: 'banana' }
352 @if(model.type){
353 <p>I'm a @model.type!</p>
354 } else if(model.name){
355 <p>My name is @model.name.</p>
356 } else {
357 <p>I DON'T KNOW WHO OR WHAT I AM...</p>
358 }
359
360output:
361
362 <p>I'm a banana!</p>
363
364This also works for `while`, `for`, `do`, `try/catch`, `with`, `switch`, `function`, and other keywords.
365
366You don't even need to worry about whitespace or newlines:
367
368input:
369
370 // model = 1
371 @switch(model){case 1:<p></p>break;case 2:<b></b>break;}
372
373output:
374
375 <p></p>
376
377<a name="comments"></a>Comments
378----------------
379
380Vash also supports comments that are not compiled into the template. These are delineated with `@*` and `*@`
381
382input:
383
384 @* I am a comment that extends
385 over multiple lines *@
386 <p>BANANA!</p>
387
388output:
389
390 <p>BANANA!</p>
391
392<a name="html-escaping"></a>HTML Escaping
393---------------------
394
395By default, Vash escapes any HTML-like values before outputting them.
396
397input:
398
399 // model = { what: '<img />' }
400 <p>@model.what</p>
401
402output:
403
404 <p>&lt;img /&gt;</p>
405
406If you are sure that you trust the content and/or need to display HTML-like values, you can escape the HTML escaping via a call to Vash's [helper system][]: `html.raw`.
407
408input:
409
410 // model = { what: '<img />' }
411 <p>@html.raw(model.what)</p>
412
413output:
414
415 <p><img /></p>
416
417This behavior can be disabled using [vash.config.htmlEscape][].
418
419<a name="explicit-markup"></a>Explicit Markup
420-----------------------
421
422Sometimes you may wish to tell Vash that what you're typing is markup or content, as opposed to code. Take the following example:
423
424input:
425
426 // model = ['a']
427 @model.forEach(function(item){
428 item
429 })
430
431output:
432
433 (empty string)
434
435In this situation, you have two options. The first is the `@:` (at colon) escape. It tells Vash that until it sees a newline, treat the input as content, not code.
436
437input:
438
439 // model = ['a']
440 @model.forEach(function(item){
441 @: item
442 })
443
444output:
445
446 a
447
448The other option, in the event that more than one line is needed, is by using an imaginary HTML tag named `<text>`. When Vash sees this tag, it switches to content mode, and discards the tag. This means that the tag will never be output.
449
450input:
451
452 // model = ['Indeed!']
453 @model.forEach(function(item){
454 <text>
455 This is some longer content that you
456 apparently wanted on multiple lines,
457 multiple times! @item
458 </text>
459 })
460
461output:
462
463 This is some longer content that you
464 apparently wanted on multiple lines,
465 multiple times! Indeed!
466
467<a name="configuration"></a>Configuration
468=====================
469
470Vash has a few compilation options that are configurable either by setting the relevant value in `vash.config` or by passing in an object with that key/value to [vash.compile][], [vash.compileBatch][], or [vash.compileHelper][].
471
472For example:
473
474 vash.config.debug = true;
475
476Is the global version of:
477
478 vash.compile('<p>My tpl</p>', { debug: true });
479
480<a name="vash-config-usewith"></a>vash.config.useWith
481---------------------------
482
483 Default: false
484
485If `useWith` is set to `true`, then Vash will wrap a `with` block around the contents of the compiled function.
486
487 // vash.config.useWith == true
488 <li>@description</li>
489
490vs
491
492 // vash.config.useWith == false
493 <li>@model.description</li>
494
495Rendering is the same regardless:
496
497 tpl( { description: 'I am a banana!' } );
498 // outputs:
499 // <li>I'm a banana!</li>
500
501_Tech note: using a `with` block comes at a severe performance penalty (at least 25x slower!)._
502
503<a name="vash-config-modelname"></a>vash.config.modelName
504-----------------------------
505
506 Default: 'model'
507
508If [vash.config.useWith][] is `false` (default), then this property is used to determine what the name of the default free variable will be. Example:
509
510 // vash.config.useWith == false
511 <li>@model.description</li>
512
513vs
514
515 // vash.config.useWith == false
516 // vash.config.modelName == 'whatwhat'
517 <li>@whatwhat.description</li>
518
519Again, rendering is the same regardless:
520
521 tpl( { description: 'I am a banana!' } );
522 // outputs:
523 // <li>I'm a banana!</li>
524
525A common alternative to `model` is `it`.
526
527<a name="vash-config-helpersname"></a>vash.config.helpersName
528-------------------------------
529
530 Default: 'html'
531
532Determines the name of the free variable through which registered helper methods can be reached. Example:
533
534 <li>@html.raw(model.description)</li>
535
536vs
537
538 // vash.config.helpersName == "help";
539 <li>@help.raw(model.description)</li>
540
541Again, rendering is the same regardless:
542
543 tpl( { description : '<strong>Raw</strong> content!' } );
544 // outputs:
545 // <li><strong>Raw</strong> content!</li>
546
547<a name="vash-config-htmlescape"></a>vash.config.htmlEscape
548------------------------------
549
550 Default: true
551
552As of version 0.4x, Vash automatically HTML encodes values generated by an explicit or implicit expression. To disable this behavior, set `htmlEscape` to `false`. For an more in depth example, see [HTML Escaping][].
553
554If a value _should not_ be escaped, simply wrap it in a call to [vash.helpers.raw][].
555
556<a name="vash-config-debug"></a>vash.config.debug
557-------------------------
558
559 Default: true
560
561By default, templates are compiled with extensive debugging information, so if an error is thrown while rendering a template (not compiling), exact location (line, character) information can be given.
562
563Using the following template:
564
565 <p></p>
566
567A template with `debug` set to `true` (default):
568
569 function anonymous(model,html,__vopts,vash) {
570 try {
571 var __vbuffer = html.buffer;
572 html.options = __vopts;
573 model = model || {};
574 html.vl = 1, html.vc = 0;
575 __vbuffer.push('<p>');
576 html.vl = 1, html.vc = 3;
577 __vbuffer.push('</p>');
578 html.vl = 1, html.vc = 7;
579 __vbuffer.push('\n');
580 (__vopts && __vopts.onRenderEnd && __vopts.onRenderEnd(null, html));
581 return (__vopts && __vopts.asContext)
582 ? html
583 : html.toString();
584 } catch( e ){
585 html.reportError( e, html.vl, html.vc, "<p></p>!LB!" );
586 }
587 }
588
589And that same template with `debug` set to `false`:
590
591 function anonymous(model,html,__vopts,vash) {
592 var __vbuffer = html.buffer;
593 html.options = __vopts;
594 model = model || {};
595 __vbuffer.push('<p></p>\n');
596 (__vopts && __vopts.onRenderEnd && __vopts.onRenderEnd(null, html));
597 return (__vopts && __vopts.asContext)
598 ? html
599 : html.toString();
600 }
601
602As you can see, the difference, especially in code size and instruction size is significant. For production apps, templates should be precompiled with `debug` as `false`.
603
604<a name="vash-config-debugparser"></a>vash.config.debugParser
605-------------------------------
606
607 Default: false
608
609Vash's parser will output useful debugging infomation if `debugParser` is `true`:
610
611* Tokens and what mode they were processed as
612* A textual representation of the fully parsed AST
613
614<a name="vash-config-debugcompiler"></a>vash.config.debugCompiler
615---------------------------------
616
617 Default: false
618
619Vash's compiler will output useful debugging information if `debugCompiler` is `true`:
620
621* The text content of the template function before it is passed into [vash.link][] for actual evaluation
622* The options passed into the compiler. This is useful for debugging [vash.compileBatch][] and [vash.compileHelper][].
623
624<a name="vash-config-simple"></a>vash.config.simple
625--------------------------
626
627 Default: false
628
629If `true`, the template is compiled in "fast path" mode. This disables several advanced features for the sake of speed:
630
631* [onRenderEnd][] callbacks are completely ignored.
632* The [Helper System][] instance normally available within a running template as `html` is no longer an instance of `vash.helpers.constructor`, and thus the entire buffer API and helpers are missing. Instead it is a plain object with the following properties:
633 * `buffer`: a plain array
634 * `escape`: [vash.helpers.escape][]
635 * `raw`: [vash.helpers.raw][]
636* The [asContext][] runtime option is completely ignored.
637* [vash.config.htmlEscape][], [vash.config.useWith][], and [vash.config.debug][] still behave as expected.
638
639While standard Vash templates are definitely not slow, using `true` for this option decreases render time by 15% - 25% depending on the size of the template.
640
641[vash-benchgraph](https://github.com/kirbysayshi/vash-benchgraph) can be used to show the speed increase:
642
643 node benches.js --tinclude 004.vash,007.vash --vinclude '0.6.2-2482' --chart vashv,ops
644
645<a name="vash-config-favortext"></a>vash.config.favorText
646-----------------------------
647
648 Default: false
649
650When Vash encounters text that directly follows an opening brace of a block, it assumes that unless it encounters an HTML tag, the text is JS code. For example:
651
652 @it.forEach(function(a){
653 var b = a; // vash assumes this line is code
654 })
655
656When `favorText` is set to `true`, Vash will instead assume that most things are content (not code) unless it's very explicit.
657
658 @it.forEach(function(a){
659 var b = a; // vash.config.favorText assumes this line is content
660 })
661
662This option is __EXPERIMENTAL__, and should be treated as such. It allows Vash to be used in a context like [Markdown](http://daringfireball.net/projects/markdown/syntax), where HTML tags, which typically help Vash tell the difference between code and content, are rare.
663
664<a name="template-options"></a>Template Options
665========================
666
667These options concern rendering a template, after it has already been compiled. For options related to compiling templates, see [Configuration][].
668
669The compiled templates themselves have three signatures.
670
671 tpl(model) -> string
672
673The most basic form accepts a single argument, `model`, that can be any value: Number, Boolean, Object, Array, undefined, null, etc. It returns the rendered template as a string.
674
675 tpl(model, function(){}) -> string
676
677The second form accepts a function callback as its second parameter, which is called [onRenderEnd][] (see below).
678
679 tpl(model, options) -> string
680
681The third form allows for options in addition to [onRenderEnd][]. There are two options that can affect a template while rendering:
682
683<a name="ascontext"></a>asContext
684-----------------
685
686 tpl(model, { asContext: true }) -> vash.helpers.constructor
687
688This option tells the template that instead of returning a string, it should return the "render context", otherwise known as an instance of `vash.helpers.constructor` ([Helper System][]).
689
690<a name="onrenderend"></a>onRenderEnd
691-------------------
692
693 tpl(model, { onRenderEnd: function(){} }) -> string
694
695This option is effectively a callback for once primary execution of the rendering template has finished. The arguments passed to the callback are: `( err, html )`, where `err` is always `null` (for now), and `html` is the render context (instance of `vash.helpers.constructor`). This callback is not required, and is only called if defined (and has no default definition). The [Layout Helpers][] use this to know when all includes, prepends, appends, blocks, and extend calls have finished.
696
697[onRenderEnd][] can also be defined as a property of the model:
698
699 var model = { hey: 'what', onRenderEnd: function(err, ctx){ ... } }
700
701<a name="helper-system"></a>Helper System
702===============
703
704Vash's primary point of expandability lies in its Helper API. When a template is rendering, there is a free variable avaiable. This variable is, by default, named `html`. This name can be changed with the [vash.config.helpersName][] option. `html` is an instance of the prototype that is attached to `vash.helpers`. It's a bit confusing, but this is how it kind of works:
705
706 var Helpers = function(){}
707 vash.helpers = Helpers.prototype;
708 vash.helpers.constructor = Helpers;
709
710What this means is that any function that is attached to `vash.helpers` is available within a rendering template via `html`. For example:
711
712 // defined in a JS file or script tag somewhere
713 vash.helpers.echo = function(arg){ return arg; }
714
715input:
716
717 <p>@html.echo('hello!')</p>
718
719output:
720
721 <p>hello!</p>
722
723Here is a simple helper that converts text like "This is a holdup!" to "this-is-a-holdup":
724
725 vash.helpers.mdHref = function(text){
726 return text
727 .toLowerCase()
728 .replace(/[^a-zA-Z0-9-_]+/g, '-')
729 .replace(/^-+|\n|-+$/g, '');
730 }
731
732Notice how it's just JavaScript. Within a template, it could be accessed via `html.mdHref("This is a holdup!")`.
733
734<a name="built-in-helpers"></a>Built-in Helpers
735========================
736
737<a name="vash-helpers-raw"></a>vash.helpers.raw
738------------------------
739
740Available as `html.raw` within an executing template. By default, all content that passes from a model to a template is HTML encoded. In the event that the text is trusted (or is already encoded), wrap the text in this function. For an example, see [HTML Escaping][];
741
742<a name="vash-helpers-escape"></a>vash.helpers.escape
743---------------------------
744
745Available as `html.escape` within an executing template, this is the method Vash uses to HTML encode model values. It can also be used manually.
746
747<a name="vash-helpers-tplcache"></a>vash.helpers.tplcache
748-----------------------------
749
750The `tplcache` is just that, a place to put a global index of templates. This is used primarily for the more "view engine" aspects that Vash provides, as well as a default location for [precompiled templates][--target-namespace] using [vash(1)][].
751
752<a name="layout-helpers"></a>Layout Helpers
753======================
754
755Vash provides a relatively simple but powerful view engine whose API is borrowed directly from [Jade][]. Below is the API, but an example can be found at [vash-express-example][].
756
757Callbacks are used to maintain compatibility with typical JS syntax.
758
759When running in [nodejs][] and using [express][], Vash will automatically resolve and load templates using the same conventions as express itself, specifically [app.engine][]. When in the browser, Vash uses the same rules, but looks in [vash.helpers.tplcache][] instead.
760
761[nodejs]: http://nodejs.org
762[express]: http://expressjs.com
763[app.engine]: http://expressjs.com/api.html#app.engine
764[Jade]: http://jade-lang.com
765[vash-express-example]: https://github.com/kirbysayshi/vash-express-example/tree/master/views
766[layout.vash]: https://github.com/kirbysayshi/vash-express-example/blob/master/views/layout.vash
767[Layout.vash]: https://github.com/kirbysayshi/vash-express-example/blob/master/views/layout.vash
768
769
770
771<a name="vash-helpers-extend"></a>vash.helpers.extend
772---------------------------
773
774 vash.helpers.extend(parent_path, cb)
775
776This is Vash's main form of inheritance for view templates. `parent_path` is the location or name of the template to be extended.
777
778A template can define various locations in itself that can be [overridden](#vash-helpers-block) or [added to](#vash-helpers-append). In addition, a template that calls `extend` can even be extended itself!
779
780In the following example, this template extends another named [layout.vash][]. [Layout.vash][] defines an empty [block](#vash-helpers-block) named 'content', which is overrided in this example.
781
782 @html.extend('layout', function(model){
783 @html.block('content', function(model){
784 <h1 class="name">Welcome to </h1>
785 })
786 })
787
788_Tech note: due to the way JS scoping works, the `model` parameter of the `cb` function must be explicitely defined as above if it is referenced in the content. This may change in a future version of Vash._
789
790
791<a name="vash-helpers-block"></a>vash.helpers.block
792--------------------------
793
794 vash.helpers.block(name)
795
796A block is essentially a placeholder within a template that can be overridden via another call to [vash.helpers.block][], or modified using [vash.helpers.append][] and [vash.helpers.prepend][].
797
798 vash.helpers.block(name, cb)
799
800If `cb` is defined, then it becomes default content for the block. The eventual contents of the block can still be overridden by a subsequent call to [vash.helpers.block][] using the same `name` value, either within the current template (silly) or in a template that extends this one using [vash.helpers.extend][]. If [vash.helpers.append][] or [vash.helpers.prepend][] are later called, their content is _added_ to the content defined in `cb`.
801
802 @html.block('main', function(model){
803 <p>Hello, I'm default content. It's nice to meet you.</p>
804 })
805
806_Tech note: due to the way JS scoping works, the `model` parameter of the `cb` function must be explicitely defined as above if it is referenced in the content. This may change in a future version of Vash._
807
808
809<a name="vash-helpers-append"></a>vash.helpers.append
810---------------------------
811
812 vash.helpers.append(name, cb)
813
814[vash.helpers.append][] is a way to control the content of a block from within an extending template. In this way, it allows templates to invert control over content "above" them.
815
816An example is a navigation area. Perhaps there is a default navigation list that templates can add to:
817
818 // layout.vash
819 <ul>
820 @html.block('main-nav', function(model){
821 <li><a href="/">Home</a></li>
822 })
823 </ul>
824
825 // another.vash
826 @html.extend('layout', function(model){
827 @html.append('main-nav', function(){
828 <li><a href="/another">Another Link</a></li>
829 })
830 })
831
832This would output when fully rendered:
833
834 <li><a href="/">Home</a></li>
835 <li><a href="/another">Another Link</a></li>
836
837_Tech note: due to the way JS scoping works, the `model` parameter of the `cb` function must be explicitely defined as above if it is referenced in the content. This may change in a future version of Vash._
838
839
840<a name="vash-helpers-prepend"></a>vash.helpers.prepend
841----------------------------
842
843 vash.helpers.prepend(name, cb)
844
845[vash.helpers.prepend][] behaves nearly the same as [vash.helpers.append][] except that it places content at the beginning of a block instead of at the end. The previous example, if `prepend` were substituted for `append`, would render as:
846
847 <li><a href="/another">Another Link</a></li>
848 <li><a href="/">Home</a></li>
849
850_Tech note: due to the way JS scoping works, the `model` parameter of the `cb` function must be explicitely defined as above if it is referenced in the content. This may change in a future version of Vash._
851
852
853<a name="vash-helpers-include"></a>vash.helpers.include
854----------------------------
855
856 vash.helpers.include(name, model)
857
858This grabs the template `name` and executes it using `model` as the... model. [vash.helpers.include][] is used to literally include the contents of another template. It is analogous to a "partial" in other view engines. Except that there is a hidden power here... as included templates share the same "view engine scope" as other templates, and can thus call all of the layout helper functions, and it will _just work_. Thus, a block within an included template can append to a block defined in a parent. It can even use [vash.helpers.extend][]!
859
860<a name="compiled-helpers"></a>Compiled Helpers
861========================
862
863A relatively new feature in Vash (added in 0.6), compiled helpers are a bit meta. They allow a developer to write a helper using Vash syntax instead of the manual buffer API. The below buffer API example `imgfigure` could be rewritten:
864
865 vash.helpers.imgfigure = function(path, caption){
866 vash.helpers.imgfigure.figcount = vash.helpers.imgfigure.figcount || 0;
867 var figcount = vash.helpers.imgfigure.figcount;
868 <figure id="fig-@(figcount++)">
869 <img src="@path" alt="@caption" />
870 <figcaption>Fig. @figcount: @caption</figcaption>
871 </figure>
872 }
873
874There are two ways to compile a helper. The first is using [vash.compileHelper][], the second is using [vash(1)][]'s [--helper][] option.
875
876<a name="buffer-api"></a>Buffer API
877==================
878
879Within a helper (not a template), `this` refers to the current `Helpers` instance. Every instance has a `Buffer` that has methods to help easily add, subtract, or mark content put there by the rendering template.
880
881Adding to the buffer:
882
883 vash.helpers.imgfigure = function(path, caption){
884 vash.helpers.imgfigure.figcount = vash.helpers.imgfigure.figcount || 0;
885 var figcount = vash.helpers.imgfigure.figcount++;
886 this.buffer.push('<figure id="fig-' + figcount + '">';
887 this.buffer.push('<img src="' + path + '" alt="' + caption + '" />';
888 this.buffer.push('<figcaption>Fig.' + figcount + ':' + caption + '</figcaption>';
889 this.buffer.push('</figure>');
890 }
891
892Here is a more advanced example, which is [contained within Vash](https://github.com/kirbysayshi/vash/blob/master/src/vhelpers.js):
893
894 vash.helpers.highlight = function(lang, cb){
895
896 // context (this) is an instance of Helpers, aka a rendering context
897
898 // mark() returns an internal `Mark` object
899 // Use it to easily capture output...
900 var startMark = this.buffer.mark();
901
902 // cb() is simply a user-defined function. It could (and should) contain
903 // buffer additions, so we call it...
904 cb();
905
906 // ... and then use fromMark() to grab the output added by cb().
907 var cbOutLines = this.buffer.fromMark(startMark);
908
909 // The internal buffer should now be back to where it was before this
910 // helper started, and the output is completely contained within cbOutLines.
911
912 this.buffer.push( '<pre><code>' );
913
914 if( helpers.config.highlighter ){
915 this.buffer.push( helpers.config.highlighter(lang, cbOutLines.join('')).value );
916 } else {
917 this.buffer.push( cbOutLines );
918 }
919
920 this.buffer.push( '</code></pre>' );
921
922 // returning is allowed, but could cause surprising effects. A return
923 // value will be directly added to the output directly following the above.
924 }
925
926A `Mark` is effectively a placeholder that can be used to literally mark the rendered content, and later do something with that mark. Possibilities include inserting content at the mark, deleting content that follows a mark, and more. It is an internal constructor that is only ever created through the `Buffer#mark` method within a helper. Examples of `Mark` usage can be found in the [layout helpers code][].
927
928[layout helpers code]: https://github.com/kirbysayshi/vash/blob/master/src/vhelpers.layout.js
929
930TODO: Explain the Buffer methods:
931
932* mark
933* fromMark
934* spliceMark
935* empty
936* push
937* pushConcat
938* indexOf
939* lastIndexOf
940* splice
941* index
942* flush
943* toString
944* toHtmlString
945
946<a name="precompiling-templates"></a>Precompiling Templates
947==============================
948
949To save both processing time (compiling templates is not trivial) as well as bandwidth (no need to send the whole compiler to the client), Vash supports precompilation of templates. Any template that Vash compiles is given a method called `toClientString`. This method returns a string that can either be `eval`ed or sent to a remote client. For example:
950
951 <p>Hello</p>
952
953Compiles to a function:
954
955 function anonymous(model,html,__vopts,vash) {
956 var __vbuffer = html.buffer;
957 html.options = __vopts;
958 model = model || {};
959 __vbuffer.push('<p></p>\n');
960 (__vopts && __vopts.onRenderEnd && __vopts.onRenderEnd(null, html));
961 return (__vopts && __vopts.asContext)
962 ? html
963 : html.toString();
964 }
965
966If `toClientString` is called on that function, the following is returned:
967
968 vash.link( function anonymous(model,html,__vopts,vash) {
969 var __vbuffer = html.buffer;
970 html.options = __vopts;
971 model = model || {};
972 __vbuffer.push('<p></p>\n');
973 (__vopts && __vopts.onRenderEnd && __vopts.onRenderEnd(null, html));
974 return (__vopts && __vopts.asContext)
975 ? html
976 : html.toString();
977 }, {"simple":false,"modelName":"model","helpersName":"html"} )
978
979This string could then be sent to the client (probably prefixed with something like `TPLCACHE["name-of-template"] = `). [vash(1)][] helps to automate this easily.
980
981Note: this assumes that `vash` is available globally. A future version of Vash will hopefully remove this assumption.
982
983<a name="vash-runtime-browser"></a>Vash Runtime (Browser)
984====================
985
986The Vash runtime is a set of functions that every executing template expects to be available. The runtime is automatically packaged with full Vash builds. However, if only precompiled templates are sent to the browser, then only the runtime must be sent. The runtime includes all helpers and a few standard functions, such as [HTML Escaping][].
987
988There are two runtime builds:
989
990* [vash-runtime.min.js][]: This is the basic runtime. It contains everything a standard Vash template needs to execute.
991* [vash-runtime-all.min.js][]: This also includes the [Layout Helpers][]. It is roughly twice as large as `vash-runtime.min.js`. Unless you're using the Vash view system in the browser, this is probably not necessary.
992
993If you're in a Browserify-like environemnt, you should be able to:
994
995```js
996var vashruntime = require('vash/runtime');
997```
998
999..and have access to the [Runtime API][].
1000
1001[vash-runtime.min.js]: https://github.com/kirbysayshi/vash/blob/master/build/vash-runtime.min.js
1002[vash-runtime-all.min.js]: https://github.com/kirbysayshi/vash/blob/master/build/vash-runtime-all.min.js
1003
1004<a name="compile-time-api"></a>Compile-time API
1005=============
1006
1007<a name="vash-compile"></a>vash.compile
1008-----------------------------------------------
1009
1010 vash.compile(str_template, opt_options) -> Function
1011
1012At its core, Vash has a `compile` function that accepts a string and options, and returns a function, otherwise known as a compiled template. That function, when called with a parameter (otherwise known as a _model_), will use that parameter to fill in the template. A model can be any value, including `undefined`, objects, arrays, strings, and booleans.
1013
1014<a name="vash-compilehelper"></a>vash.compileHelper
1015-----------------------------------------------------
1016
1017 vash.compileHelper(str_template, opt_options) -> Object
1018
1019See [Compiled Helpers][] for more detail.
1020
1021<a name="vash-compilebatch"></a>vash.compileBatch
1022----------------------------------------------------
1023
1024 vash.compileBatch(str_template, opt_options) -> Object
1025
1026This function can take a single string containing many named templates, and output an object containing the compiled versions of those templates. A "named template" is of the form (similar to a `sourceURL`):
1027
1028 //@batch = div
1029 <div>@model</div>\n'
1030
1031 //@batch = a
1032 <a>@model</a>'
1033
1034This example contains two named templates, "div" and "a". If this example were passed as a single string to `compileBatch`:
1035
1036 var tpls = vash.compileBatch(theTplString);
1037
1038One could be called:
1039
1040 tpls.div('yes!');
1041 // returns: <div>yes!</div>
1042
1043This is meant as a convenience function for developers. Putting each template in a separate file can get old, especially if a template is small. Instead, templates can be grouped together. The object returned also has a custom `toClientString` function, which serializes each template in the object automatically.
1044
1045Aside from the newline following the "name" of the template, whitespace is ignored:
1046
1047 //@ batch = div
1048 //@batch=div
1049 // @batch =div
1050
1051Each is treated the same.
1052
1053<a name="runtime-api"></a>Runtime API
1054===================
1055
1056<a name="vash-link"></a>vash.link
1057---------------------------------------------------------
1058
1059 vash.link(str_tpl, options) -> Function
1060 vash.link(func_tpl, options) -> Function
1061
1062This is primarily an internal function, and has relatively complex behavioral differences depending on what options are passed in. It takes either a decompiled string function or function instance and "links" it by wrapping it in a closure that provides access to Vash's runtime functions. It also sets up things like `toClientString` and `toString`. It makes precompiled functions possible. As a developer working on Vash, it's best to take a look at the [source itself][].
1063
1064[source itself]: https://github.com/kirbysayshi/vash/blob/master/src/vruntime.js
1065
1066<a name="vash-lookup"></a>vash.lookup
1067-------------------
1068
1069 vash.lookup(str_path) -> Function
1070
1071Attempts to grab a template from `vash.helpers.tplcache[str_path]`, and throws an exception if it is not found.
1072
1073 vash.lookup(str_path, model) -> Function
1074
1075If `model` is passed and the template is found, the template is automatically executed and returned using `model` as the model.
1076
1077<a name="vash-install"></a>vash.install
1078--------------------
1079
1080`vash.install` accepts a few signatures:
1081
1082 vash.install(str_path, func_tpl) -> func_tpl
1083
1084"Saves" the template at `vash.helpers.tplcache[str_path]`.
1085
1086 vash.install(str_path, str_tpl) -> func_tpl
1087
1088If `vash.compile` is available (meaning the entire compiler is available, not just the runtime), then the string is automatically compiled. and saved at `vash.helpers.tplcache[str_path]`.
1089
1090 vash.install(obj) -> obj
1091
1092If an object containing string keys pointing at template functions is passed, then the object's keys are used as the keys for `vash.helpers.tplcache`. This is especially useful when using [vash.compileBatch][], as the result can be directly passed.
1093
1094<a name="vash-uninstall"></a>vash.uninstall
1095----------------------
1096
1097 vash.uninstall(str_path) -> bool
1098
1099Deletes the key named `str_path` from `vash.helpers.tplcache`.
1100
1101 vash.uninstall(func_tpl) -> bool
1102
1103Loops through all templates in `vash.helpers.tplcache`, and if a strict equality is successful, deletes that reference.
1104
1105<a name="vash-1"></a>vash(1)
1106===============
1107
1108Vash also includes a commandline tool that enables easy integration of templates into a unix toolchain. For example, to compile this documentation, the following command is used:
1109
1110 bin/vash <README2.vash --render --helpers <(bin/vash <docs/helpers/* --helper) > README2.md
1111
1112This first grabs all files in `docs/helpers/`, and compiles them as Vash helpers using the [--helper][] option. These compiled helpers are then fed via a temporary named pipe into the `--helpers` option, which accepts a file. This option user the file (temporary, in this case) as helpers, and they are added to the rendering context's prototype (see [Helper System][]. Next, `README2.vash` is fed into [vash(1)][], which is told to both compile the input as a template, and render it immediately, using the `--render` option. Granted, this is not how bash actually handles it, but this explanation will suffice.
1113
1114In short, this loads and compiles helpers necessary for this document, grabs the file, and renders the whole thing as plain markdown.
1115
1116`vash(1)` has many options:
1117
1118 -h, --help output usage information
1119 -t, --target-namespace <namespace> Assign template to a <namespace>. Recommended is `vash.helpers.tplcache` for view engine compatibility
1120 -p, --property-name [name] Assign template to property named <name>. Defaults to filename, and requires --target-namespace.
1121 -f, --file <file> Compile the template in <file>
1122 -j, --json <json> Pass options to the Vash compiler. See docs for valid options.
1123 -o, --out <path> Write template into <path> directory
1124 -u, --uglify Uglify the template, safely
1125 -a, --no-autolink Wrap each template in `vash.link`.
1126 -r, --render [json] Render the template using <json> as the model. If <json> is not valid json, assume a filename and load those contents as json.
1127 -s, --separator [separator] Templates are auto-named by concatenating the file path with [separator]
1128 --helper Assume the input is a to-be-compiled helper
1129 --helpers <file> Execute these compiled helpers
1130
1131Some of the options are explained in greater detail below.
1132
1133<a name="installation"></a>Installation
1134--------------------
1135
1136[vash(1)][] comes with Vash, so it will always be within `node_modules/vash/bin/`. However, a global install is also supported, which can be accomplished via:
1137
1138 npm install -g vash
1139
1140<a name="vash1--target-namespace"></a>--target-namespace
1141---------------------------------------------------
1142
1143Assigns the compiled template to a specific "namespace". This value only supports simple namespaces, such as `blah.who.what.something`.
1144
1145Using this option while piping into [vash(1)][] __REQUIRES__ [--property-name][] to also be specified.
1146
1147Example:
1148
1149 $ echo 'function(){}' | bin/vash \
1150 --target-namespace "vash.helpers.tplcache" \
1151 --property-name 'myTpl'
1152
1153 vash = vash || {};
1154 vash.helpers = vash.helpers || {};
1155 vash.helpers.tplcache = vash.helpers.tplcache || {};
1156 vash.helpers.tplcache["myTpl"]=vash.link( ... )
1157
1158<a name="vash1--property-name"></a>--property-name
1159-----------------------------------------------
1160
1161Specifies what name to use when assigning the compiled template. Defaults to the filename specified with `--file`. If content is piped into [vash(1)][], then this option is __MANDATORY__.
1162
1163<a name="vash1--helper"></a>--helper
1164----------------
1165
1166This instructs [vash(1)][] to call [vash.compileHelper][] instead of [vash.compile][], and assumes the input is a template that is meant to be a compiled helper.
1167
1168An empty helper:
1169
1170 $ echo 'vash.helpers.who = function(){}' | bin/vash --helper --json '{"debug":false}'
1171
1172 vash.link( function anonymous() {
1173 var __vbuffer = this.buffer;
1174 var model = this.model;
1175 var html = this;
1176 {}
1177 }, {"simple":false,"modelName":"model","helpersName":"html","args":[""],"asHelper":"who"} )
1178
1179And without `--helper`, `vash(1)` just outputs an empty template:
1180
1181 $ echo 'vash.helpers.who = function(){}' | bin/vash --json '{"debug":false}'
1182
1183 vash.link( function anonymous(model,html,__vopts,vash) {
1184 var __vbuffer = html.buffer;
1185 html.options = __vopts;
1186 model = model || {};
1187 __vbuffer.push('vash.helpers.who = function(){}\n');
1188 (__vopts && __vopts.onRenderEnd && __vopts.onRenderEnd(null, html));
1189 return (__vopts && __vopts.asContext)
1190 ? html
1191 : html.toString();
1192 }, {"simple":false,"modelName":"model","helpersName":"html"} )
1193
1194<a name="contributing-building"></a>Contributing / Building
1195====================
1196
1197Please see [CONTRIBUTING.md][]. In general, if you want something that Vash doesn't have, file a ticket. Pull Requests are also _always_ welcome!
1198
1199[CONTRIBUTING.md]: https://github.com/kirbysayshi/vash/CONTRIBUTING.md
1200
1201<a name="getting-help"></a>Getting Help
1202====================
1203
1204File a ticket! Or hit me up on Twitter: @KirbySaysHi
1205
1206<a name="special-thanks"></a>Special Thanks
1207======================
1208
1209Extreme thanks goes to TJ Holowaychuck and his template engine [Jade](http://jade-lang.com). It was the original inspiration for Vash's lexer, [Layout Helpers][], and error reporting, and has been a constant source of inspiration and motivation.
1210
1211Some of the techniques Vash's compiler uses were directly inspired from [doT](https://github.com/olado/doT).
1212
1213Dev doc styling (gfm.css) from https://gist.github.com/andyferra/2554919.
1214
1215And of course to Vash's [contributors][].
1216
1217[contributors]: https://github.com/kirbysayshi/vash/AUTHORS
1218
1219<a name="license"></a>License
1220===============
1221
1222[MIT](https://github.com/kirbysayshi/vash/LICENSE)
1223
1224[Features]: #features
1225[Syntax Example]: #syntax-example
1226[Quick Start]: #quick-start
1227[nodejs]: #nodejs
1228[express]: #express
1229[Browser - Vanilla]: #browser---vanilla
1230[Browser - Browserify et al]: #browser---browserify-et-al
1231[Browser - RequireJS]: #browser---requirejs
1232[Playground]: #playground
1233[Syntax]: #syntax
1234[The Transition Character: @]: #the-transition-character
1235[Expressions]: #expressions
1236[Advanced Expressions]: #advanced-expressions
1237[Explicit Expressions]: #explicit-expressions
1238[Code Blocks]: #code-blocks
1239[Keyword Blocks]: #keyword-blocks
1240[Comments]: #comments
1241[HTML Escaping]: #html-escaping
1242[Explicit Markup]: #explicit-markup
1243[Configuration]: #configuration
1244[vash.config.useWith]: #vash-config-usewith
1245[vash.config.modelName]: #vash-config-modelname
1246[vash.config.helpersName]: #vash-config-helpersname
1247[vash.config.htmlEscape]: #vash-config-htmlescape
1248[vash.config.debug]: #vash-config-debug
1249[vash.config.debugParser]: #vash-config-debugparser
1250[vash.config.debugCompiler]: #vash-config-debugcompiler
1251[vash.config.simple]: #vash-config-simple
1252[vash.config.favorText]: #vash-config-favortext
1253[Template Options]: #template-options
1254[asContext]: #ascontext
1255[onRenderEnd]: #onrenderend
1256[Helper System]: #helper-system
1257[Built-in Helpers]: #built-in-helpers
1258[vash.helpers.raw]: #vash-helpers-raw
1259[vash.helpers.escape]: #vash-helpers-escape
1260[vash.helpers.tplcache]: #vash-helpers-tplcache
1261[Layout Helpers]: #layout-helpers
1262[vash.helpers.extend]: #vash-helpers-extend
1263[vash.helpers.block]: #vash-helpers-block
1264[vash.helpers.append]: #vash-helpers-append
1265[vash.helpers.prepend]: #vash-helpers-prepend
1266[vash.helpers.include]: #vash-helpers-include
1267[Compiled Helpers]: #compiled-helpers
1268[Buffer API]: #buffer-api
1269[Precompiling Templates]: #precompiling-templates
1270[Vash Runtime (Browser)]: #vash-runtime-browser
1271[Compile-time API]: #compile-time-api
1272[vash.compile]: #vash-compile
1273[vash.compileHelper]: #vash-compilehelper
1274[vash.compileBatch]: #vash-compilebatch
1275[Runtime API]: #runtime-api
1276[vash.link]: #vash-link
1277[vash.lookup]: #vash-lookup
1278[vash.install]: #vash-install
1279[vash.uninstall]: #vash-uninstall
1280[vash(1)]: #vash-1
1281[Installation]: #installation
1282[--target-namespace]: #vash1--target-namespace
1283[--property-name]: #vash1--property-name
1284[--helper]: #vash1--helper
1285[Contributing / Building]: #contributing-building
1286[Getting Help]: #getting-help
1287[Special Thanks]: #special-thanks
1288[License]: #license
1289
1290
1291<hr /><ol class="footnotes">
1292 <li id="fn:razor-ms">
1293 Razor syntax was developed at Microsoft, and typically refers to their Razor View Engine, which ships with ASP.NET MVC 3 and above. In this document, "Razor" will refer to the Razor View Engine, while "syntax" or "Vash syntax" refers to Vash's implementation.
1294 <a rev="footnote" href="#fnref:razor-ms">&#8617;</a>
1295 </li>
1296
1297<li id="fn:this-doc">
1298 This document starts off as a [Vash template][] that is then compiled and rendered via [vash(1)][] into markdown! It uses several custom helpers that are not shipped with Vash, but are of course available [for perusal][]. They include things like these footnotes and an autogenerated and linked table of contents.
1299 <a rev="footnote" href="#fnref:this-doc">&#8617;</a>
1300 </li>
1301
1302
1303 </ol>
1304
1305[Vash template]: https://github.com/kirbysayshi/vash/README.vash
1306[for perusal]: https://github.com/kirbysayshi/vash/docs/helpers/md.vash