{"id":13492837,"url":"https://github.com/kirbysayshi/vash","last_synced_at":"2026-02-23T05:33:05.462Z","repository":{"id":416371,"uuid":"2028730","full_name":"kirbysayshi/vash","owner":"kirbysayshi","description":"Vash, the 60 billion double-dollar template-maker. Razor syntax, for JavaScript templates","archived":false,"fork":false,"pushed_at":"2022-06-22T05:30:21.000Z","size":1857,"stargazers_count":519,"open_issues_count":24,"forks_count":59,"subscribers_count":30,"default_branch":"master","last_synced_at":"2026-01-24T03:34:02.417Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kirbysayshi.png","metadata":{"files":{"readme":"README.md","changelog":"History.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2011-07-11T06:05:32.000Z","updated_at":"2025-11-12T08:05:41.000Z","dependencies_parsed_at":"2022-08-16T10:25:09.801Z","dependency_job_id":null,"html_url":"https://github.com/kirbysayshi/vash","commit_stats":null,"previous_names":[],"tags_count":66,"template":false,"template_full_name":null,"purl":"pkg:github/kirbysayshi/vash","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kirbysayshi%2Fvash","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kirbysayshi%2Fvash/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kirbysayshi%2Fvash/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kirbysayshi%2Fvash/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kirbysayshi","download_url":"https://codeload.github.com/kirbysayshi/vash/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kirbysayshi%2Fvash/sbom","scorecard":{"id":561166,"data":{"date":"2025-08-11","repo":{"name":"github.com/kirbysayshi/vash","commit":"71a14d72f92bb72fec329d2da71105dc25287e52"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.7,"checks":[{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":0,"reason":"Found 2/21 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":9,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Warn: project license file does not contain an FSF or OSI license."],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 12 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"21 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-x9w5-v3q2-3rhw","Warn: Project is vulnerable to: GHSA-wg6g-ppvx-927h","Warn: Project is vulnerable to: GHSA-gxpj-cx7g-858c","Warn: Project is vulnerable to: GHSA-vh7m-p724-62c2","Warn: Project is vulnerable to: GHSA-r9p9-mrjm-926w","Warn: Project is vulnerable to: GHSA-434g-2637-qmqr","Warn: Project is vulnerable to: GHSA-49q7-c7j4-3p7m","Warn: Project is vulnerable to: GHSA-977x-g7h5-7qgw","Warn: Project is vulnerable to: GHSA-f7q4-pwc6-w24p","Warn: Project is vulnerable to: GHSA-fc9h-whq2-v747","Warn: Project is vulnerable to: GHSA-vjh7-7g9h-fjfh","Warn: Project is vulnerable to: GHSA-5v2h-r2cx-5xgj","Warn: Project is vulnerable to: GHSA-rrrm-qjm4-v8hf","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-vh95-rmgr-6w4m","Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h","Warn: Project is vulnerable to: GHSA-hj48-42vr-x3v9","Warn: Project is vulnerable to: GHSA-h7cp-r72f-jxh6","Warn: Project is vulnerable to: GHSA-v62p-rq8g-8h59","Warn: Project is vulnerable to: GHSA-g4rg-993r-mgx7"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-20T13:44:24.787Z","repository_id":416371,"created_at":"2025-08-20T13:44:24.787Z","updated_at":"2025-08-20T13:44:24.787Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29738094,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-23T04:51:08.365Z","status":"ssl_error","status_checked_at":"2026-02-23T04:49:15.865Z","response_time":90,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T19:01:09.734Z","updated_at":"2026-02-23T05:33:05.443Z","avatar_url":"https://github.com/kirbysayshi.png","language":"JavaScript","funding_links":[],"categories":["NodeJS fullstack :tada: :tada: :tada:","JavaScript"],"sub_categories":["Express view engine :palm_tree: :palm_tree: :palm_tree:"],"readme":"\u003c!-- This document was generated from README.vash --\u003e\n\n\nVash\n====\n\n_\"... the 60 billion double-dollar template-maker!\"_ ~ The previous README, and no one else, ever.\n\nVash is a template engine that offers a swift flow between code and content using [Razor Syntax][] \u003csup id=\"fnref:razor-ms\"\u003e\n\t\t\t\u003ca rel=\"footnote\" href=\"#fn:razor-ms\"\u003e1\u003c/a\u003e\n\t\t\u003c/sup\u003e. This document \u003csup id=\"fnref:this-doc\"\u003e\n\t\t\t\u003ca rel=\"footnote\" href=\"#fn:this-doc\"\u003e2\u003c/a\u003e\n\t\t\u003c/sup\u003e is intended for users of Vash, and also serves as a reference for Vash's implementation of Razor Syntax.\n\n[Razor Syntax]: http://www.asp.net/web-pages/tutorials/basics/2-introduction-to-asp-net-web-programming-using-the-razor-syntax\n\n[![Build Status](https://secure.travis-ci.org/kirbysayshi/vash.png?branch=master)](https://travis-ci.org/kirbysayshi/vash)\n\n[![NPM](https://nodei.co/npm/vash.png?downloads=true\u0026stars=true)](https://nodei.co/npm/vash/) [![NPM](https://nodei.co/npm-dl/vash.png)](https://nodei.co/npm/vash/)\n\n[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/kirbysayshi/vash/trend.png)](https://bitdeli.com/free \"Bitdeli Badge\")\n\n\n- [Features](#features) \n- [Syntax Example](#syntax-example) \n- [Quick Start](#quick-start) \n  - [nodejs](#nodejs) \n  - [express](#express) \n  - [Browser - Vanilla](#browser---vanilla) \n  - [Browser - Browserify et al](#browser---browserify-et-al) \n  - [Browser - RequireJS](#browser---requirejs) \n- [Playground](#playground) \n- [Syntax](#syntax) \n  - [The Transition Character: @](#the-transition-character) \n  - [Expressions](#expressions) \n  - [Advanced Expressions](#advanced-expressions) \n  - [Explicit Expressions](#explicit-expressions) \n  - [Code Blocks](#code-blocks) \n  - [Keyword Blocks](#keyword-blocks) \n  - [Comments](#comments) \n  - [HTML Escaping](#html-escaping) \n  - [Explicit Markup](#explicit-markup) \n- [Configuration](#configuration) \n  - [vash.config.useWith](#vash-config-usewith) \n  - [vash.config.modelName](#vash-config-modelname) \n  - [vash.config.helpersName](#vash-config-helpersname) \n  - [vash.config.htmlEscape](#vash-config-htmlescape) \n  - [vash.config.debug](#vash-config-debug) \n  - [vash.config.debugParser](#vash-config-debugparser) \n  - [vash.config.debugCompiler](#vash-config-debugcompiler) \n  - [vash.config.simple](#vash-config-simple) \n  - [vash.config.favorText](#vash-config-favortext) \n- [Template Options](#template-options) \n  - [asContext](#ascontext) \n  - [onRenderEnd](#onrenderend) \n- [Helper System](#helper-system) \n- [Built-in Helpers](#built-in-helpers) \n  - [vash.helpers.raw](#vash-helpers-raw) \n  - [vash.helpers.escape](#vash-helpers-escape) \n  - [vash.helpers.tplcache](#vash-helpers-tplcache) \n- [Layout Helpers](#layout-helpers) \n  - [vash.helpers.extend](#vash-helpers-extend) \n  - [vash.helpers.block](#vash-helpers-block) \n  - [vash.helpers.append](#vash-helpers-append) \n  - [vash.helpers.prepend](#vash-helpers-prepend) \n  - [vash.helpers.include](#vash-helpers-include) \n- [Compiled Helpers](#compiled-helpers) \n- [Buffer API](#buffer-api) \n- [Precompiling Templates](#precompiling-templates) \n- [Vash Runtime (Browser)](#vash-runtime-browser) \n- [Compile-time API](#compile-time-api) \n  - [vash.compile](#vash-compile) \n  - [vash.compileHelper](#vash-compilehelper) \n  - [vash.compileBatch](#vash-compilebatch) \n- [Runtime API](#runtime-api) \n  - [vash.link](#vash-link) \n  - [vash.lookup](#vash-lookup) \n  - [vash.install](#vash-install) \n  - [vash.uninstall](#vash-uninstall) \n- [vash(1)](#vash-1) \n  - [Installation](#installation) \n  - [--target-namespace](#vash1--target-namespace) \n  - [--property-name](#vash1--property-name) \n  - [--helper](#vash1--helper) \n- [Contributing / Building](#contributing-building) \n- [Getting Help](#getting-help) \n- [Special Thanks](#special-thanks) \n- [License](#license) \n\n\n\u003ca name=\"features\"\u003e\u003c/a\u003eFeatures \n================\n\n* Mix code and content without ugly delineators, like `\u003c?`, `\u003c%`, or `{{`.\n* No new language to learn: Vash is just HTML-aware JavaScript.\n* Great with markup, but can be used with nearly any other language as well (even Markdown!).\n* Helpers API allows for extensibility and meta programming.\n* Works in the browser or in node.\n* Comes with a Jade-inspired layout engine (block, include, extend, append/prepend), which even works in the browser.\n\n\u003ca name=\"syntax-example\"\u003e\u003c/a\u003eSyntax Example \n======================\n\n\t\u003cp\u003eHow are you @model.name? Today is a sunny day on the planet Gunsmoke.\u003c/p\u003e\n\n\t\u003cul class=\"@(model.active ? 'highlight' : '')\"\u003e\n\t\t@model.forEach(function(m){\n\t\t\t\u003cli\u003e@m.name\u003c/li\u003e\n\t\t})\n\t\u003c/ul\u003e\n\n\u003ca name=\"quick-start\"\u003e\u003c/a\u003eQuick Start \n===================\n\n\u003ca name=\"nodejs\"\u003e\u003c/a\u003enodejs \n--------------\n\n\tvar vash = require('vash');\n\tvar tpl = vash.compile('\u003cp\u003eI am a @model.t!\u003c/p\u003e');\n\n\tvar out = tpl({ t: 'template' });\n\t// \u003cp\u003eI am a template!\u003c/p\u003e\n\n\u003ca name=\"express\"\u003e\u003c/a\u003eexpress \n--------------------\n\nCheck 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:\n\n\tvar express = require('express');\n\n\tvar app = express();\n\tapp.set('view engine', 'vash');\n\nMore information is also available in the [Layout Helpers][] sections.\n\n[vash-express-example]: https://github.com/kirbysayshi/vash-express-example\n\n\u003ca name=\"browser---vanilla\"\u003e\u003c/a\u003eBrowser - Vanilla \n-------------------------\n\n\t\u003cscript type=\"text/javascript\" src=\"build/vash.js\"\u003e\u003c/script\u003e\n\n\tvar tpl = vash.compile( '\u003cp\u003eI am a @model.t!\u003c/p\u003e' );\n\tdocument.querySelector('#content').innerHTML = tpl({ t: 'template' });\n\nBut you should probably be precompiling your templates. See [Precompiling Templates][] for more info. Then you can just include the Vash runtime instead of the entire compiler.\n\n\u003ca name=\"browser---browserify-et-al\"\u003e\u003c/a\u003eBrowser - Browserify et al \n----------------------------------\n\nJust `require` Vash, and compile. If you want something fancier, try [vashify](https://www.npmjs.com/package/vashify)! Then you can directly require any `.vash` file and it will be resolved as compiled template:\n\n\tvar tpl = require('my-awesome-template.vash');\n\tdocument.querySelector('#content').innerHTML = tpl({ t: 'template' });\n\n\u003ca name=\"browser---requirejs\"\u003e\u003c/a\u003eBrowser - RequireJS \n---------------------------\n\nRequireJS 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.\n\n\u003ca name=\"playground\"\u003e\u003c/a\u003ePlayground \n==================\n\nVash 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!\n\n[a playground]: http://codepen.io/kirbysayshi/full/IjrFw\n[CodePen.io]: http://codepen.io\n\n\u003ca name=\"syntax\"\u003e\u003c/a\u003eSyntax \n==============\n\nFor the following examples, assume a model is passed into the compiled function. If a model is explicitly defined, it will appear as:\n\n\t// model = { what: 'hello!' }\n\n\u003ca name=\"the-transition-character\"\u003e\u003c/a\u003eThe Transition Character: @ \n------------------------------------\n\nVash uses the `@` symbol to transition between code and markup. To escape and print a literal `@`, use a double `@`, like this: `@@`.\n\n\u003ca name=\"expressions\"\u003e\u003c/a\u003eExpressions \n-------------------\n\nThe 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.\n\ninput:\n\n\t// model = { what: 'hello!' }\n\t\u003cp\u003e@what\u003c/p\u003e\n\noutput:\n\n\t\u003cp\u003ehello!\u003c/p\u003e\n\nThe `model` comment is just to show that the object passed into the compiled template contains a key that matches the expression.\n\nTo 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:\n\ninput:\n\n\t\u003cp\u003e@model.what\u003c/p\u003e\n\noutput:\n\n\t\u003cp\u003ehello!\u003c/p\u003e\n\nAs 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`.\n\n\n\u003ca name=\"advanced-expressions\"\u003e\u003c/a\u003eAdvanced Expressions \n----------------------------\n\nVash typically knows when an expression ends, even when the expression is complex. For example:\n\ninput:\n\n\t\u003cp\u003e@model.what().who[2]('are you sure')('yes, it\\'s ok')( model.complex ? 'FULL POWER' : '' )\u003c/p\u003e\n\nThis 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.\n\nCallbacks work as well:\n\ninput:\n\n\t// model = ['a', 'b']\n\t@model.forEach(function(item){\n\t\t\u003cli\u003e@item\u003c/li\u003e\n\t})\n\noutputs:\n\n\t\u003cli\u003ea\u003c/li\u003e\u003cli\u003eb\u003c/li\u003e\n\nVash also knows the difference between JS dot notation and a period.\n\ninput:\n\n\t// model = { description: 'living' }\n\t\u003cp\u003ePlants are @model.description.\u003c/p\u003e\n\noutput:\n\n\t\u003cp\u003ePlants are living.\u003c/p\u003e\n\nAnd empty brackets, because they're not valid JS:\n\ninput:\n\n\t// model = { formName: 'addresses' }\n\t\u003cinput type=\"text\" name=\"@model.formName[]\" /\u003e\n\noutput:\n\n\t\u003cinput type=\"text\" name=\"addresses[]\" /\u003e\n\nEmail addresses, to an extent, are fine as well. Vash makes a trade-off. It uses the following regex to validate an email address:\n\n\t/^([a-zA-Z0-9.%]+@[a-zA-Z0-9.\\-]+\\.(?:ca|co\\.uk|com|edu|net|org))\\b/\n\nEmail addresses can actually contain many more valid characters, and are [really hard to validate][]. Vash can handle a typical email address with ease:\n\ninput:\n\n\t\u003ca href=\"mailto:vash@planetgunsmoke.com\"\u003eEmail Me\u003c/a\u003e\n\noutput:\n\n\t\u003ca href=\"mailto:vash@planetgunsmoke.com\"\u003eEmail Me\u003c/a\u003e\n\nIf you have a complex email address that confuses Vash, then you should use an [explicit expression](#explicit-expressions) instead.\n\n[really hard to validate]: http://www.regular-expressions.info/email.html\n\n\u003ca name=\"explicit-expressions\"\u003e\u003c/a\u003eExplicit Expressions \n----------------------------\n\nAn explicit expression is simply an expression that, instead of being composed of `@` and a valid JS identifier, is surrounded by parenthesis.\n\ninput:\n\n\t\u003cp\u003e@(model.what)\u003c/p\u003e\n\noutput:\n\n\t\u003cp\u003ehello!\u003c/p\u003e\n\nWhy would you ever need this? Perhaps you want to do something like:\n\ninput:\n\n\t// model = { hasIceCream: true }\n\t\u003cp class=\"@( model.hasIceCream ? 'ice-cream' : '')\"\u003eIce Cream\u003c/p\u003e\n\noutput:\n\n\t\u003cp class=\"ice-cream\"\u003eIce Cream\u003c/p\u003e\n\nYou could even create an anonymous function.\n\ninput:\n\n\t@(function(type){ return type + ' cream'; }('banana'))\n\noutput:\n\n\tbanana cream\n\nAs you can see, Vash does not require a model to be referenced, or even passed in.\n\n\u003ca name=\"code-blocks\"\u003e\u003c/a\u003eCode Blocks \n-------------------\n\nSometimes, 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 `\u003c?= $what ?\u003e`, while a code block is like `\u003c? $what = 'what' ?\u003e`.\n\nA code block is simply `@{  }`.\n\ninput:\n\n\t@{ var rideOn = 'shooting star'; }\n\noutput:\n\nThat's right, _nothing_! Here's a better example:\n\ninput:\n\n\t@{\n\t\tvar total = model.price + model.tax;\n\t}\n\n\t\u003cp\u003eYour total is: $@total\u003c/p\u003e\n\noutput:\n\n\t\u003cp\u003eYour total is: $2.70\u003c/p\u003e\n\nAnything 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:\n\ninput:\n\n\t@{ \u003cp\u003eThis works!\u003c/p\u003e }\n\noutput:\n\n\t\u003cp\u003eThis works!\u003c/p\u003e\n\nA code block just tells Vash, \"expect the next stuff to be code until otherwise\".\n\n\u003ca name=\"keyword-blocks\"\u003e\u003c/a\u003eKeyword Blocks \n----------------------\n\nVash is aware of keywords, and will open a code block automatically for you.\n\ninput:\n\n\t// model = { type: 'banana' }\n\t@if(model.type){\n\t\t\u003cp\u003eI'm a @model.type!\u003c/p\u003e\n\t} else if(model.name){\n\t\t\u003cp\u003eMy name is @model.name.\u003c/p\u003e\n\t} else {\n\t\t\u003cp\u003eI DON'T KNOW WHO OR WHAT I AM...\u003c/p\u003e\n\t}\n\noutput:\n\n\t\u003cp\u003eI'm a banana!\u003c/p\u003e\n\nThis also works for `while`, `for`, `do`, `try/catch`, `with`, `switch`, `function`, and other keywords.\n\nYou don't even need to worry about whitespace or newlines:\n\ninput:\n\n\t// model = 1\n\t@switch(model){case 1:\u003cp\u003e\u003c/p\u003ebreak;case 2:\u003cb\u003e\u003c/b\u003ebreak;}\n\noutput:\n\n\t\u003cp\u003e\u003c/p\u003e\n\n\u003ca name=\"comments\"\u003e\u003c/a\u003eComments \n----------------\n\nVash also supports comments that are not compiled into the template. These are delineated with `@*` and `*@`\n\ninput:\n\n\t@* I am a comment that extends\n\tover multiple lines *@\n\t\u003cp\u003eBANANA!\u003c/p\u003e\n\noutput:\n\n\t\u003cp\u003eBANANA!\u003c/p\u003e\n\n\u003ca name=\"html-escaping\"\u003e\u003c/a\u003eHTML Escaping \n---------------------\n\nBy default, Vash escapes any HTML-like values before outputting them.\n\ninput:\n\n\t// model = { what: '\u003cimg /\u003e' }\n\t\u003cp\u003e@model.what\u003c/p\u003e\n\noutput:\n\n\t\u003cp\u003e\u0026lt;img /\u0026gt;\u003c/p\u003e\n\nIf 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`.\n\ninput:\n\n\t// model = { what: '\u003cimg /\u003e' }\n\t\u003cp\u003e@html.raw(model.what)\u003c/p\u003e\n\noutput:\n\n\t\u003cp\u003e\u003cimg /\u003e\u003c/p\u003e\n\nThis behavior can be disabled using [vash.config.htmlEscape][].\n\n\u003ca name=\"explicit-markup\"\u003e\u003c/a\u003eExplicit Markup \n-----------------------\n\nSometimes you may wish to tell Vash that what you're typing is markup or content, as opposed to code. Take the following example:\n\ninput:\n\n\t// model = ['a']\n\t@model.forEach(function(item){\n\t\tthis should be content @item\n\t})\n\noutput:\n\n\t(Error when compiling)\n\nIn 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.\n\ninput:\n\n\t// model = ['a']\n\t@model.forEach(function(item){\n\t\t@: this should be content @item\n\t})\n\noutput:\n\n\tthis should be content a\n\nThe other option, in the event that more than one line is needed, is by using an imaginary HTML tag named `\u003ctext\u003e`. When Vash sees this tag, it switches to content mode, and discards the tag. This means that the tag will never be output.\n\ninput:\n\n\t// model = ['Indeed!']\n\t@model.forEach(function(item){\n\t\t\u003ctext\u003e\n\t\t\tThis is some longer content that you\n\t\t\tapparently wanted on multiple lines,\n\t\t\tmultiple times! @item\n\t\t\u003c/text\u003e\n\t})\n\noutput:\n\n\tThis is some longer content that you\n\tapparently wanted on multiple lines,\n\tmultiple times! Indeed!\n\n\u003ca name=\"configuration\"\u003e\u003c/a\u003eConfiguration \n=====================\n\nVash 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][].\n\nFor example:\n\n\tvash.config.debug = true;\n\nIs the global version of:\n\n\tvash.compile('\u003cp\u003eMy tpl\u003c/p\u003e', { debug: true });\n\n\u003ca name=\"vash-config-usewith\"\u003e\u003c/a\u003evash.config.useWith \n---------------------------\n\n\tDefault: false\n\nIf `useWith` is set to `true`, then Vash will wrap a `with` block around the contents of the compiled function.\n\n\t// vash.config.useWith == true\n\t\u003cli\u003e@description\u003c/li\u003e\n\nvs\n\n\t// vash.config.useWith == false\n\t\u003cli\u003e@model.description\u003c/li\u003e\n\nRendering is the same regardless:\n\n\ttpl( { description: 'I am a banana!' } );\n\t// outputs:\n\t// \u003cli\u003eI'm a banana!\u003c/li\u003e\n\n_Tech note: using a `with` block comes at a severe performance penalty (at least 25x slower!)._\n\n\u003ca name=\"vash-config-modelname\"\u003e\u003c/a\u003evash.config.modelName \n-----------------------------\n\n\tDefault: 'model'\n\nIf [vash.config.useWith][] is  `false` (default), then this property is used to determine what the name of the default free variable will be. Example:\n\n\t// vash.config.useWith == false\n\t\u003cli\u003e@model.description\u003c/li\u003e\n\nvs\n\n\t// vash.config.useWith == false\n\t// vash.config.modelName == 'whatwhat'\n\t\u003cli\u003e@whatwhat.description\u003c/li\u003e\n\nAgain, rendering is the same regardless:\n\n\ttpl( { description: 'I am a banana!' } );\n\t// outputs:\n\t// \u003cli\u003eI'm a banana!\u003c/li\u003e\n\nA common alternative to `model` is `it`.\n\n\u003ca name=\"vash-config-helpersname\"\u003e\u003c/a\u003evash.config.helpersName \n-------------------------------\n\n\tDefault: 'html'\n\nDetermines the name of the free variable through which registered helper methods can be reached. Example:\n\n\t\u003cli\u003e@html.raw(model.description)\u003c/li\u003e\n\nvs\n\n\t// vash.config.helpersName == \"help\";\n\t\u003cli\u003e@help.raw(model.description)\u003c/li\u003e\n\nAgain, rendering is the same regardless:\n\n\ttpl( { description : '\u003cstrong\u003eRaw\u003c/strong\u003e content!' } );\n\t// outputs:\n\t// \u003cli\u003e\u003cstrong\u003eRaw\u003c/strong\u003e content!\u003c/li\u003e\n\n\u003ca name=\"vash-config-htmlescape\"\u003e\u003c/a\u003evash.config.htmlEscape \n------------------------------\n\n\tDefault: true\n\nAs 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][].\n\nIf a value _should not_ be escaped, simply wrap it in a call to [vash.helpers.raw][].\n\n\u003ca name=\"vash-config-debug\"\u003e\u003c/a\u003evash.config.debug \n-------------------------\n\n\tDefault: true\n\nBy 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.\n\nUsing the following template:\n\n\t\u003cp\u003e\u003c/p\u003e\n\nA template with `debug` set to `true` (default):\n\n\tfunction anonymous(model,html,__vopts,vash) {\n\t\ttry {\n\t\t\tvar __vbuffer = html.buffer;\n\t\t\thtml.options = __vopts;\n\t\t\tmodel = model || {};\n\t\t\thtml.vl = 1, html.vc = 0;\n\t\t\t__vbuffer.push('\u003cp\u003e');\n\t\t\thtml.vl = 1, html.vc = 3;\n\t\t\t__vbuffer.push('\u003c/p\u003e');\n\t\t\thtml.vl = 1, html.vc = 7;\n\t\t\t__vbuffer.push('\\n');\n\t\t\t(__vopts \u0026\u0026 __vopts.onRenderEnd \u0026\u0026 __vopts.onRenderEnd(null, html));\n\t\t\treturn (__vopts \u0026\u0026 __vopts.asContext)\n\t\t\t\t? html\n\t\t\t\t: html.toString();\n\t\t} catch( e ){\n\t\t\thtml.reportError( e, html.vl, html.vc, \"\u003cp\u003e\u003c/p\u003e!LB!\" );\n\t\t}\n\t}\n\nAnd that same template with `debug` set to `false`:\n\n\tfunction anonymous(model,html,__vopts,vash) {\n\t\tvar __vbuffer = html.buffer;\n\t\thtml.options = __vopts;\n\t\tmodel = model || {};\n\t\t__vbuffer.push('\u003cp\u003e\u003c/p\u003e\\n');\n\t\t(__vopts \u0026\u0026 __vopts.onRenderEnd \u0026\u0026 __vopts.onRenderEnd(null, html));\n\t\treturn (__vopts \u0026\u0026 __vopts.asContext)\n\t\t\t? html\n\t\t\t: html.toString();\n\t}\n\nAs 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`.\n\n\u003ca name=\"vash-config-debugparser\"\u003e\u003c/a\u003evash.config.debugParser \n-------------------------------\n\n\tDefault: false\n\nVash's parser will output useful debugging infomation if `debugParser` is `true`:\n\n* Tokens and what mode they were processed as\n* A textual representation of the fully parsed AST\n\n\u003ca name=\"vash-config-debugcompiler\"\u003e\u003c/a\u003evash.config.debugCompiler \n---------------------------------\n\n\tDefault: false\n\nVash's compiler will output useful debugging information if `debugCompiler` is `true`:\n\n* The text content of the template function before it is passed into [vash.link][] for actual evaluation\n* The options passed into the compiler. This is useful for debugging [vash.compileBatch][] and [vash.compileHelper][].\n\n\u003ca name=\"vash-config-simple\"\u003e\u003c/a\u003evash.config.simple \n--------------------------\n\n\tDefault: false\n\nIf `true`, the template is compiled in \"fast path\" mode. This disables several advanced features for the sake of speed:\n\n* [onRenderEnd][] callbacks are completely ignored.\n* 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:\n  * `buffer`: a plain array\n  * `escape`: [vash.helpers.escape][]\n  * `raw`: [vash.helpers.raw][]\n* The [asContext][] runtime option is completely ignored.\n* [vash.config.htmlEscape][], [vash.config.useWith][], and [vash.config.debug][] still behave as expected.\n\nWhile 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.\n\n[vash-benchgraph](https://github.com/kirbysayshi/vash-benchgraph) can be used to show the speed increase:\n\n\tnode benches.js --tinclude 004.vash,007.vash --vinclude '0.6.2-2482' --chart vashv,ops\n\n\u003ca name=\"vash-config-favortext\"\u003e\u003c/a\u003evash.config.favorText \n-----------------------------\n\n\tDefault: false\n\nWhen 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:\n\n\t@it.forEach(function(a){\n\t\tvar b = a; // vash assumes this line is code\n\t})\n\nWhen `favorText` is set to `true`, Vash will instead assume that most things are content (not code) unless it's very explicit.\n\n\t@it.forEach(function(a){\n\t\tvar b = a; // vash.config.favorText assumes this line is content\n\t})\n\nThis 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.\n\n\u003ca name=\"template-options\"\u003e\u003c/a\u003eTemplate Options \n========================\n\nThese options concern rendering a template, after it has already been compiled. For options related to compiling templates, see [Configuration][].\n\nThe compiled templates themselves have three signatures.\n\n\ttpl(model) -\u003e string\n\nThe 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.\n\n\ttpl(model, function(){}) -\u003e string\n\nThe second form accepts a function callback as its second parameter, which is called [onRenderEnd][] (see below).\n\n\ttpl(model, options) -\u003e string\n\nThe third form allows for options in addition to [onRenderEnd][]. There are two options that can affect a template while rendering:\n\n\u003ca name=\"ascontext\"\u003e\u003c/a\u003easContext \n-----------------\n\n\ttpl(model, { asContext: true }) -\u003e vash.helpers.constructor\n\nThis 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][]).\n\n\u003ca name=\"onrenderend\"\u003e\u003c/a\u003eonRenderEnd \n-------------------\n\n\ttpl(model, { onRenderEnd: function(){} }) -\u003e string\n\nThis 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.\n\n[onRenderEnd][] can also be defined as a property of the model:\n\n\tvar model = { hey: 'what', onRenderEnd: function(err, ctx){ ... } }\n\n\u003ca name=\"helper-system\"\u003e\u003c/a\u003eHelper System \n===============\n\nVash'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:\n\n\tvar Helpers = function(){}\n\tvash.helpers = Helpers.prototype;\n\tvash.helpers.constructor = Helpers;\n\nWhat this means is that any function that is attached to `vash.helpers` is available within a rendering template via `html`. For example:\n\n\t// defined in a JS file or script tag somewhere\n\tvash.helpers.echo = function(arg){ return arg; }\n\ninput:\n\n\t\u003cp\u003e@html.echo('hello!')\u003c/p\u003e\n\noutput:\n\n\t\u003cp\u003ehello!\u003c/p\u003e\n\nHere is a simple helper that converts text like \"This is a holdup!\" to \"this-is-a-holdup\":\n\n\tvash.helpers.mdHref = function(text){\n\t\treturn text\n\t\t\t.toLowerCase()\n\t\t\t.replace(/[^a-zA-Z0-9-_]+/g, '-')\n\t\t\t.replace(/^-+|\\n|-+$/g, '');\n\t}\n\nNotice how it's just JavaScript. Within a template, it could be accessed via `html.mdHref(\"This is a holdup!\")`.\n\n\u003ca name=\"built-in-helpers\"\u003e\u003c/a\u003eBuilt-in Helpers \n========================\n\n\u003ca name=\"vash-helpers-raw\"\u003e\u003c/a\u003evash.helpers.raw \n------------------------\n\nAvailable 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][];\n\n\u003ca name=\"vash-helpers-escape\"\u003e\u003c/a\u003evash.helpers.escape \n---------------------------\n\nAvailable as `html.escape` within an executing template, this is the method Vash uses to HTML encode model values. It can also be used manually.\n\n\u003ca name=\"vash-helpers-tplcache\"\u003e\u003c/a\u003evash.helpers.tplcache \n-----------------------------\n\nThe `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)][].\n\n\u003ca name=\"layout-helpers\"\u003e\u003c/a\u003eLayout Helpers \n======================\n\nVash 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][].\n\nCallbacks are used to maintain compatibility with typical JS syntax.\n\nWhen 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.\n\n[nodejs]: http://nodejs.org\n[express]: http://expressjs.com\n[app.engine]: http://expressjs.com/api.html#app.engine\n[Jade]: http://jade-lang.com\n[vash-express-example]: https://github.com/kirbysayshi/vash-express-example/tree/master/views\n[layout.vash]: https://github.com/kirbysayshi/vash-express-example/blob/master/views/layout.vash\n[Layout.vash]: https://github.com/kirbysayshi/vash-express-example/blob/master/views/layout.vash\n\n\n\n\u003ca name=\"vash-helpers-extend\"\u003e\u003c/a\u003evash.helpers.extend \n---------------------------\n\n\tvash.helpers.extend(parent_path, cb)\n\nThis is Vash's main form of inheritance for view templates. `parent_path` is the location or name of the template to be extended.\n\nA 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!\n\nIn 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.\n\n\t@html.extend('layout', function(model){\n\t\t@html.block('content', function(model){\n\t\t\t\u003ch1 class=\"name\"\u003eWelcome to \u003c/h1\u003e\n\t\t})\n\t})\n\n_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._\n\n\n\u003ca name=\"vash-helpers-block\"\u003e\u003c/a\u003evash.helpers.block \n--------------------------\n\n\tvash.helpers.block(name)\n\nA 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][].\n\n\tvash.helpers.block(name, cb)\n\nIf `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`.\n\n\t@html.block('main', function(model){\n\t\t\u003cp\u003eHello, I'm default content. It's nice to meet you.\u003c/p\u003e\n\t})\n\n_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._\n\n\n\u003ca name=\"vash-helpers-append\"\u003e\u003c/a\u003evash.helpers.append \n---------------------------\n\n\tvash.helpers.append(name, cb)\n\n[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.\n\nAn example is a navigation area. Perhaps there is a default navigation list that templates can add to:\n\n\t// layout.vash\n\t\u003cul\u003e\n\t@html.block('main-nav', function(model){\n\t\t\u003cli\u003e\u003ca href=\"/\"\u003eHome\u003c/a\u003e\u003c/li\u003e\n\t})\n\t\u003c/ul\u003e\n\n\t// another.vash\n\t@html.extend('layout', function(model){\n\t\t@html.append('main-nav', function(){\n\t\t\t\u003cli\u003e\u003ca href=\"/another\"\u003eAnother Link\u003c/a\u003e\u003c/li\u003e\n\t\t})\n\t})\n\nThis would output when fully rendered:\n\n\t\u003cli\u003e\u003ca href=\"/\"\u003eHome\u003c/a\u003e\u003c/li\u003e\n\t\u003cli\u003e\u003ca href=\"/another\"\u003eAnother Link\u003c/a\u003e\u003c/li\u003e\n\n_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._\n\n\n\u003ca name=\"vash-helpers-prepend\"\u003e\u003c/a\u003evash.helpers.prepend \n----------------------------\n\n\tvash.helpers.prepend(name, cb)\n\n[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:\n\n\t\u003cli\u003e\u003ca href=\"/another\"\u003eAnother Link\u003c/a\u003e\u003c/li\u003e\n\t\u003cli\u003e\u003ca href=\"/\"\u003eHome\u003c/a\u003e\u003c/li\u003e\n\n_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._\n\n\n\u003ca name=\"vash-helpers-include\"\u003e\u003c/a\u003evash.helpers.include \n----------------------------\n\n\tvash.helpers.include(name, model)\n\nThis 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][]!\n\n\u003ca name=\"compiled-helpers\"\u003e\u003c/a\u003eCompiled Helpers \n========================\n\nA 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:\n\n\tvash.helpers.imgfigure = function(path, caption){\n\t\tvash.helpers.imgfigure.figcount = vash.helpers.imgfigure.figcount || 0;\n\t\tvar figcount = vash.helpers.imgfigure.figcount;\n\t\t\u003cfigure id=\"fig-@(figcount++)\"\u003e\n\t\t\t\u003cimg src=\"@path\" alt=\"@caption\" /\u003e\n\t\t\t\u003cfigcaption\u003eFig. @figcount: @caption\u003c/figcaption\u003e\n\t\t\u003c/figure\u003e\n\t}\n\nThere are two ways to compile a helper. The first is using [vash.compileHelper][], the second is using [vash(1)][]'s [--helper][] option.\n\n\u003ca name=\"buffer-api\"\u003e\u003c/a\u003eBuffer API \n==================\n\nWithin 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.\n\nAdding to the buffer:\n\n\tvash.helpers.imgfigure = function(path, caption){\n\t\tvash.helpers.imgfigure.figcount = vash.helpers.imgfigure.figcount || 0;\n\t\tvar figcount = vash.helpers.imgfigure.figcount++;\n\t\tthis.buffer.push('\u003cfigure id=\"fig-' + figcount + '\"\u003e';\n\t\tthis.buffer.push('\u003cimg src=\"' + path + '\" alt=\"' + caption + '\" /\u003e';\n\t\tthis.buffer.push('\u003cfigcaption\u003eFig.' + figcount + ':' + caption + '\u003c/figcaption\u003e';\n\t\tthis.buffer.push('\u003c/figure\u003e');\n\t}\n\nHere is a more advanced example, which is [contained within Vash](https://github.com/kirbysayshi/vash/blob/master/src/vhelpers.js):\n\n\tvash.helpers.highlight = function(lang, cb){\n\n\t\t// context (this) is an instance of Helpers, aka a rendering context\n\n\t\t// mark() returns an internal `Mark` object\n\t\t// Use it to easily capture output...\n\t\tvar startMark = this.buffer.mark();\n\n\t\t// cb() is simply a user-defined function. It could (and should) contain\n\t\t// buffer additions, so we call it...\n\t\tcb();\n\n\t\t// ... and then use fromMark() to grab the output added by cb().\n\t\tvar cbOutLines = this.buffer.fromMark(startMark);\n\n\t\t// The internal buffer should now be back to where it was before this\n\t\t// helper started, and the output is completely contained within cbOutLines.\n\n\t\tthis.buffer.push( '\u003cpre\u003e\u003ccode\u003e' );\n\n\t\tif( helpers.config.highlighter ){\n\t\t\tthis.buffer.push( helpers.config.highlighter(lang, cbOutLines.join('')).value );\n\t\t} else {\n\t\t\tthis.buffer.push( cbOutLines );\n\t\t}\n\n\t\tthis.buffer.push( '\u003c/code\u003e\u003c/pre\u003e' );\n\n\t\t// returning is allowed, but could cause surprising effects. A return\n\t\t// value will be directly added to the output directly following the above.\n\t}\n\nA `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][].\n\n[layout helpers code]: https://github.com/kirbysayshi/vash/blob/master/src/vhelpers.layout.js\n\nTODO: Explain the Buffer methods:\n\n* mark\n* fromMark\n* spliceMark\n* empty\n* push\n* pushConcat\n* indexOf\n* lastIndexOf\n* splice\n* index\n* flush\n* toString\n* toHtmlString\n\n\u003ca name=\"precompiling-templates\"\u003e\u003c/a\u003ePrecompiling Templates \n==============================\n\nTo 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:\n\n\t\u003cp\u003eHello\u003c/p\u003e\n\nCompiles to a function:\n\n\tfunction anonymous(model,html,__vopts,vash) {\n\t\tvar __vbuffer = html.buffer;\n\t\thtml.options = __vopts;\n\t\tmodel = model || {};\n\t\t__vbuffer.push('\u003cp\u003e\u003c/p\u003e\\n');\n\t\t(__vopts \u0026\u0026 __vopts.onRenderEnd \u0026\u0026 __vopts.onRenderEnd(null, html));\n\t\treturn (__vopts \u0026\u0026 __vopts.asContext)\n\t\t\t? html\n\t\t\t: html.toString();\n\t}\n\nIf `toClientString` is called on that function, the following is returned:\n\n\tvash.link( function anonymous(model,html,__vopts,vash) {\n\t\tvar __vbuffer = html.buffer;\n\t\thtml.options = __vopts;\n\t\tmodel = model || {};\n\t\t__vbuffer.push('\u003cp\u003e\u003c/p\u003e\\n');\n\t\t(__vopts \u0026\u0026 __vopts.onRenderEnd \u0026\u0026 __vopts.onRenderEnd(null, html));\n\t\treturn (__vopts \u0026\u0026 __vopts.asContext)\n\t\t\t? html\n\t\t\t: html.toString();\n\t}, {\"simple\":false,\"modelName\":\"model\",\"helpersName\":\"html\"} )\n\nThis string could then be sent to the client (probably prefixed with something like `TPLCACHE[\"name-of-template\"] = `). [vash(1)][] helps to automate this easily.\n\nNote: this assumes that `vash` is available globally. A future version of Vash will hopefully remove this assumption.\n\n\u003ca name=\"vash-runtime-browser\"\u003e\u003c/a\u003eVash Runtime (Browser) \n====================\n\nThe 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][].\n\nThere are two runtime builds:\n\n* [vash-runtime.js][]: This is the basic runtime. It contains everything a standard Vash template needs to execute.\n* [vash-runtime-all.js][]: This also includes the [Layout Helpers][]. It is roughly twice as large as `vash-runtime.js`. Unless you're using the Vash view system in the browser, this is probably not necessary.\n\nIf you're in a Browserify-like environemnt, you should be able to:\n\n```js\nvar vashruntime = require('vash/runtime');\n```\n\n..and have access to the [Runtime API][].\n\n[vash-runtime.js]: https://github.com/kirbysayshi/vash/blob/master/build/vash-runtime.js\n[vash-runtime-all.js]: https://github.com/kirbysayshi/vash/blob/master/build/vash-runtime-all.js\n\n\u003ca name=\"compile-time-api\"\u003e\u003c/a\u003eCompile-time API \n=============\n\n\u003ca name=\"vash-compile\"\u003e\u003c/a\u003evash.compile \n-----------------------------------------------\n\n\tvash.compile(str_template, opt_options) -\u003e Function\n\nAt 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.\n\n\u003ca name=\"vash-compilehelper\"\u003e\u003c/a\u003evash.compileHelper \n-----------------------------------------------------\n\n\tvash.compileHelper(str_template, opt_options) -\u003e Object\n\nSee [Compiled Helpers][] for more detail.\n\n\u003ca name=\"vash-compilebatch\"\u003e\u003c/a\u003evash.compileBatch \n----------------------------------------------------\n\n\tvash.compileBatch(str_template, opt_options) -\u003e Object\n\nThis 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`):\n\n\t//@batch = div\n\t\u003cdiv\u003e@model\u003c/div\u003e\\n'\n\n\t//@batch = a\n\t\u003ca\u003e@model\u003c/a\u003e'\n\nThis example contains two named templates, \"div\" and \"a\". If this example were passed as a single string to `compileBatch`:\n\n\tvar tpls = vash.compileBatch(theTplString);\n\nOne could be called:\n\n\ttpls.div('yes!');\n\t// returns: \u003cdiv\u003eyes!\u003c/div\u003e\n\nThis 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.\n\nAside from the newline following the \"name\" of the template, whitespace is ignored:\n\n\t//@              batch = div\n\t//@batch=div\n\t//         @batch =div\n\nEach is treated the same.\n\n\u003ca name=\"runtime-api\"\u003e\u003c/a\u003eRuntime API \n===================\n\n\u003ca name=\"vash-link\"\u003e\u003c/a\u003evash.link \n---------------------------------------------------------\n\n\tvash.link(str_tpl, options) -\u003e Function\n\tvash.link(func_tpl, options) -\u003e Function\n\nThis 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][].\n\n[source itself]: https://github.com/kirbysayshi/vash/blob/master/src/vruntime.js\n\n\u003ca name=\"vash-lookup\"\u003e\u003c/a\u003evash.lookup \n-------------------\n\n\tvash.lookup(str_path) -\u003e Function\n\nAttempts to grab a template from `vash.helpers.tplcache[str_path]`, and throws an exception if it is not found.\n\n\tvash.lookup(str_path, model) -\u003e Function\n\nIf `model` is passed and the template is found, the template is automatically executed and returned using `model` as the model.\n\n\u003ca name=\"vash-install\"\u003e\u003c/a\u003evash.install \n--------------------\n\n`vash.install` accepts a few signatures:\n\n\tvash.install(str_path, func_tpl) -\u003e func_tpl\n\n\"Saves\" the template at `vash.helpers.tplcache[str_path]`.\n\n\tvash.install(str_path, str_tpl) -\u003e func_tpl\n\nIf `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]`.\n\n\tvash.install(obj) -\u003e obj\n\nIf 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.\n\n\u003ca name=\"vash-uninstall\"\u003e\u003c/a\u003evash.uninstall \n----------------------\n\n\tvash.uninstall(str_path) -\u003e bool\n\nDeletes the key named `str_path` from `vash.helpers.tplcache`.\n\n\tvash.uninstall(func_tpl) -\u003e bool\n\nLoops through all templates in `vash.helpers.tplcache`, and if a strict equality is successful, deletes that reference.\n\n\u003ca name=\"vash-1\"\u003e\u003c/a\u003evash(1) \n===============\n\nVash 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:\n\n\tbin/vash \u003cREADME2.vash --render --helpers \u003c(bin/vash \u003cdocs/helpers/* --helper) \u003e README2.md\n\nThis 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.\n\nIn short, this loads and compiles helpers necessary for this document, grabs the file, and renders the whole thing as plain markdown.\n\n`vash(1)` has many options:\n\n    -h, --help                          output usage information\n    -t, --target-namespace \u003cnamespace\u003e  Assign template to a \u003cnamespace\u003e. Recommended is `vash.helpers.tplcache` for view engine compatibility\n    -p, --property-name [name]          Assign template to property named [name]. Defaults to filename, and requires --target-namespace.\n    -f, --file \u003cfile\u003e                   Compile the template in \u003cfile\u003e\n    -j, --json \u003cjson\u003e                   Pass options to the Vash compiler. See docs for valid options.\n    -o, --out \u003cpath\u003e                    Write template into \u003cpath\u003e directory\n    -u, --uglify                        Uglify the template, safely\n    -a, --no-autolink                   Wrap each template in `vash.link`.\n    -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.\n    -s, --separator [separator]         Templates are auto-named by concatenating the file path with [separator]\n    --helper                            Assume the input is a to-be-compiled helper\n    --helpers \u003cfile\u003e                    Execute these compiled helpers\n\nSome of the options are explained in greater detail below.\n\n\u003ca name=\"installation\"\u003e\u003c/a\u003eInstallation \n--------------------\n\n[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:\n\n\tnpm install -g vash\n\n\u003ca name=\"vash1--target-namespace\"\u003e\u003c/a\u003e--target-namespace \n---------------------------------------------------\n\nAssigns the compiled template to a specific \"namespace\". This value only supports simple namespaces, such as `blah.who.what.something`.\n\nUsing this option while piping into [vash(1)][] __REQUIRES__ [--property-name][] to also be specified.\n\nExample:\n\n\t$ echo 'function(){}' | bin/vash \\\n\t--target-namespace \"vash.helpers.tplcache\" \\\n\t--property-name 'myTpl'\n\n\tvash = vash || {};\n\tvash.helpers = vash.helpers || {};\n\tvash.helpers.tplcache = vash.helpers.tplcache || {};\n\tvash.helpers.tplcache[\"myTpl\"]=vash.link( ... )\n\n\u003ca name=\"vash1--property-name\"\u003e\u003c/a\u003e--property-name \n-----------------------------------------------\n\nSpecifies 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__.\n\n\u003ca name=\"vash1--helper\"\u003e\u003c/a\u003e--helper \n----------------\n\nThis 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.\n\nAn empty helper:\n\n\t$ echo 'vash.helpers.who = function(){}' | bin/vash --helper --json '{\"debug\":false}'\n\n\tvash.link( function anonymous() {\n\tvar __vbuffer = this.buffer;\n\tvar model = this.model;\n\tvar html = this;\n\t{}\n\t}, {\"simple\":false,\"modelName\":\"model\",\"helpersName\":\"html\",\"args\":[\"\"],\"asHelper\":\"who\"} )\n\nAnd without `--helper`, `vash(1)` just outputs an empty template:\n\n\t$ echo 'vash.helpers.who = function(){}' | bin/vash --json '{\"debug\":false}'\n\n\tvash.link( function anonymous(model,html,__vopts,vash) {\n\tvar __vbuffer = html.buffer;\n\thtml.options = __vopts;\n\tmodel = model || {};\n\t__vbuffer.push('vash.helpers.who = function(){}\\n');\n\t(__vopts \u0026\u0026 __vopts.onRenderEnd \u0026\u0026 __vopts.onRenderEnd(null, html));\n\treturn (__vopts \u0026\u0026 __vopts.asContext)\n\t  ? html\n\t  : html.toString();\n\t}, {\"simple\":false,\"modelName\":\"model\",\"helpersName\":\"html\"} )\n\n\u003ca name=\"contributing-building\"\u003e\u003c/a\u003eContributing / Building \n====================\n\nPlease see [CONTRIBUTING.md][]. In general, if you want something that Vash doesn't have, file a ticket. Pull Requests are also _always_ welcome!\n\n[CONTRIBUTING.md]: https://github.com/kirbysayshi/vash/CONTRIBUTING.md\n\n\u003ca name=\"getting-help\"\u003e\u003c/a\u003eGetting Help \n====================\n\nFile a ticket! Or hit me up on Twitter: @KirbySaysHi\n\n\u003ca name=\"special-thanks\"\u003e\u003c/a\u003eSpecial Thanks \n======================\n\nExtreme 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.\n\nSome of the techniques Vash's compiler uses were directly inspired from [doT](https://github.com/olado/doT).\n\nDev doc styling (gfm.css) from https://gist.github.com/andyferra/2554919.\n\nAnd of course to Vash's [contributors][].\n\n[contributors]: https://github.com/kirbysayshi/vash/AUTHORS\n\n\u003ca name=\"license\"\u003e\u003c/a\u003eLicense \n===============\n\n[MIT](https://github.com/kirbysayshi/vash/LICENSE)\n\n[Features]: #features\n[Syntax Example]: #syntax-example\n[Quick Start]: #quick-start\n[nodejs]: #nodejs\n[express]: #express\n[Browser - Vanilla]: #browser---vanilla\n[Browser - Browserify et al]: #browser---browserify-et-al\n[Browser - RequireJS]: #browser---requirejs\n[Playground]: #playground\n[Syntax]: #syntax\n[The Transition Character: @]: #the-transition-character\n[Expressions]: #expressions\n[Advanced Expressions]: #advanced-expressions\n[Explicit Expressions]: #explicit-expressions\n[Code Blocks]: #code-blocks\n[Keyword Blocks]: #keyword-blocks\n[Comments]: #comments\n[HTML Escaping]: #html-escaping\n[Explicit Markup]: #explicit-markup\n[Configuration]: #configuration\n[vash.config.useWith]: #vash-config-usewith\n[vash.config.modelName]: #vash-config-modelname\n[vash.config.helpersName]: #vash-config-helpersname\n[vash.config.htmlEscape]: #vash-config-htmlescape\n[vash.config.debug]: #vash-config-debug\n[vash.config.debugParser]: #vash-config-debugparser\n[vash.config.debugCompiler]: #vash-config-debugcompiler\n[vash.config.simple]: #vash-config-simple\n[vash.config.favorText]: #vash-config-favortext\n[Template Options]: #template-options\n[asContext]: #ascontext\n[onRenderEnd]: #onrenderend\n[Helper System]: #helper-system\n[Built-in Helpers]: #built-in-helpers\n[vash.helpers.raw]: #vash-helpers-raw\n[vash.helpers.escape]: #vash-helpers-escape\n[vash.helpers.tplcache]: #vash-helpers-tplcache\n[Layout Helpers]: #layout-helpers\n[vash.helpers.extend]: #vash-helpers-extend\n[vash.helpers.block]: #vash-helpers-block\n[vash.helpers.append]: #vash-helpers-append\n[vash.helpers.prepend]: #vash-helpers-prepend\n[vash.helpers.include]: #vash-helpers-include\n[Compiled Helpers]: #compiled-helpers\n[Buffer API]: #buffer-api\n[Precompiling Templates]: #precompiling-templates\n[Vash Runtime (Browser)]: #vash-runtime-browser\n[Compile-time API]: #compile-time-api\n[vash.compile]: #vash-compile\n[vash.compileHelper]: #vash-compilehelper\n[vash.compileBatch]: #vash-compilebatch\n[Runtime API]: #runtime-api\n[vash.link]: #vash-link\n[vash.lookup]: #vash-lookup\n[vash.install]: #vash-install\n[vash.uninstall]: #vash-uninstall\n[vash(1)]: #vash-1\n[Installation]: #installation\n[--target-namespace]: #vash1--target-namespace\n[--property-name]: #vash1--property-name\n[--helper]: #vash1--helper\n[Contributing / Building]: #contributing-building\n[Getting Help]: #getting-help\n[Special Thanks]: #special-thanks\n[License]: #license\n\n\n\u003chr /\u003e\u003col class=\"footnotes\"\u003e\n\t\u003cli id=\"fn:razor-ms\"\u003e\n\t\t\t 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.\n \u003ca rev=\"footnote\" href=\"#fnref:razor-ms\"\u003e\u0026#8617;\u003c/a\u003e\n\t\t\u003c/li\u003e\n\n\u003cli id=\"fn:this-doc\"\u003e\n\t\t\t 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.\n \u003ca rev=\"footnote\" href=\"#fnref:this-doc\"\u003e\u0026#8617;\u003c/a\u003e\n\t\t\u003c/li\u003e\n\n\n\t\u003c/ol\u003e\n\n[Vash template]: https://github.com/kirbysayshi/vash/README.vash\n[for perusal]: https://github.com/kirbysayshi/vash/docs/helpers/md.vash\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkirbysayshi%2Fvash","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkirbysayshi%2Fvash","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkirbysayshi%2Fvash/lists"}