# FAQ URL: /docs/about/FAQ *** id: FAQ title: FAQ ---------- ## Does it only work with HTML? It works with HTML, but you can also use it to generate templates of any language, like Markdown. ## How big is Squirrelly? Squirrelly is about 4KB gzipped, which is quite lightweight for a template engine library. ## Why should I use Squirrelly instead of another template engine like Handlebars or Pug? Squirrelly has a number of features that set it apart from the competition: * It's faster than most templating engines * It supports user-defined helpers and native helpers * It supports filters * It supports partials * It's incredibly lightweight: in comparison: the full version only weighs about **4 KB gzipped**, compared to Pug's **237 KB** and Handlebars' **21.5 KB** * It works with other languages than HTML * It's not whitespace sensitive For more information, see [Why Squirrelly?](about/why-squirrelly.md) # How Squirrelly Works URL: /docs/about/how-squirrelly-works *** id: how-squirrelly-works title: How Squirrelly Works --------------------------- Unlike many pieces of software, we like our users to understand what their programs are doing behind the scenes. ## TL;DR Squirrelly uses Regular Expressions to turn a template into a function which can be called with a specific set of options. Since all of the parsing is done beforehand, the function (called a "Precompiled" function) just does string interpolation and is incredibly fast. ## Long Version: 1. Squirrelly uses a big RegExp with inline tokenization to **parse** the template by looping through each valid tag (ex. `{{...}}`) in the template. It creates a simple syntax tree which it passes to `compile` 2. During compilation, Squirrelly creates a function string from the syntax tree, then uses `Function` to bring it to life. 3. This explanation is really lacking. Just read the source code :) # Introduction URL: /docs/about/introduction *** id: introduction title: Introduction ------------------- Squirrelly is a template engine written in JavaScript. With Squirrelly, you can write templates that are blazing fast and can be rendered in milliseconds, server-side or client-side. Squirrelly doesn't just limit you to HTML--you can use it with any language, and custom delimiters make it so there aren't parsing errors. It's also tiny (**\~4 KB gzipped**), has **0 dependencies**, and is **blazing fast**. ![](https://img.shields.io/bundlephobia/minzip/squirrelly.svg) :::note Did you know that Squirrelly is consistently faster than most other template engines, according to benchmarks? ::: # Performance URL: /docs/about/performance *** id: performance title: Performance ------------------ ## TL;DR Squirrelly's faster than virtually all other template engines out there. ## Benchmarks * [https://github.com/nebrelbug/squirrelly-benchmarks](https://github.com/nebrelbug/squirrelly-benchmarks) ## Run tests in your browser! [https://ghcdn.rawgit.org/squirrellyjs/squirrelly/master/browser-tests/benchmark.html](https://ghcdn.rawgit.org/squirrellyjs/squirrelly/master/browser-tests/benchmark.html) # Why Pick Squirrelly? URL: /docs/about/why-squirrelly *** id: why-squirrelly title: Why Pick Squirrelly? --------------------------- ## Features Squirrelly has a number of features that set it apart from the competition. It is: * Faster than most templating engines * Supports user-defined helpers and native helpers * Supports filters * Supports partials * Supports custom tags (delimiters) * Incredibly lightweight: in comparison: the full version only weighs about **4 KB gzipped**, compared to Pug's **237 KB** and Handlebars' **21.5 KB** * Works with other languages than HTML * Not white-space sensitive, but white-space-trimming configurable * Syntax accessible to non-JavaScript programmers * Supports comments and quotes containing ending delimiter (e.g. `{{! /* commented out {{something}} \*/}}`) | **Feature** | **Squirrelly** | Handlebars | Pug | Marko | Dust | Swig | | :------------------- | :------------- | :--------- | :--- | :---- | :--- | :--- | | Auto Escape | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | Whitespace sensitive | No | No | Yes | No | No | No | | Content Type | All | All | HTML | HTML | All | All | # Your First Template URL: /docs/get-started/first-template *** id: first-template title: Your First Template -------------------------- ## Install Squirrelly See [Install](install) to learn how. In this guide, we'll assume that Squirrelly is stored in a variable called `Sqrl`. ## Create a Template This is just a regular string. ```js var myTemplate = 'My favorite template engine is {{it.favorite}}.' ``` ## Define Data ```js var data = { favorite: 'Squirrelly' } ``` ## Render! ```js var result = Sqrl.render(myTemplate, data) // My favorite template engine is Squirrelly. ``` ## Try Different Data ```js var result2 = Sqrl.render(myTemplate, { favorite: 'Squirrelly, definitely' }) // My favorite template engine is Squirrelly, definitely. ``` ## Full Code ```js var myTemplate = 'My favorite template engine is {{it.favorite}}.' var result = Sqrl.render(myTemplate, { favorite: 'Squirrelly, definitely' }) ``` # Installation URL: /docs/get-started/install *** id: install title: Installation sidebar\_label: Installation description: How to install Squirrelly for use in Node.js or the browser ------------------------------------------------------------------------ Squirrelly tries to follow best practices, and provides a UMD build to support most JS loading options, like ES modules, CommonJS, and AMD. ## Install Squirrelly ```sh npm install squirrelly --save ``` Or if you prefer Yarn: ```sh yarn add squirrelly ``` ### Importing / Requiring Sqrl is packaged as a UMD module, so you can require with CommonJS, import using ES Modules, or use AMD. ```js import * as Sqrl from 'squirrelly' // or var Sqrl = require('squirrelly') ``` ### Unpkg ```html ``` ### JSDelivr ```html ``` This makes Squirrelly available through the global `Sqrl` variable, and importable using ES modules, CommonJS, and AMD. # Overview URL: /docs/get-started/overview *** id: overview title: Overview slug: / ------- Congratulations on deciding to use Squirrelly! These docs will be your guide as you learn how to use this tool. ## For people who learn by example We recommend going [here](get-started/first-template) to find tutorials and lots of example code! ## For API lovers Browse the API! ## Check out the source code Go to the [GitHub Repository](https://github.com/squirrellyjs/squirrelly) # Security URL: /docs/get-started/security *** id: security title: Security --------------- ## Escaping See the page on [HTML-Escaping](../syntax/auto-escaping) to learn how to guard against XSS attacks. ## Code Injection :::caution Since Squirrelly compiles to pure JavaScript, you should **never** run *untrusted* templates on your server, unless you use a good sandboxed environment. Plans are in the works to create safe user-defined templates, but for now, they are unsafe. ::: # Compilation URL: /docs/api/compilation *** id: compilation title: Compilation ------------------ ## `Sqrl.compile` Compiles a string into a template function. [TypeDoc doc page](https://squirrellyjs.github.io/squirrelly/modules/_compile_.html#compile) **Syntax** ```js Sqrl.compile (str, options) // returns a function that can be called with (data, options, [cb]) // note: options must be a valid config object ``` See the page on [options](./configuration) **Example** ```js var myTemplate = "Hi, my name is {{it.name}}"; var compiled = Sqrl.compile(myTemplate); // Returns a function: // function anonymous(it,c,cb ) { var tR='';tR+='Hi, my name is ';tR+=c.l('F','e')(it.name);if(cb){cb(null,tR)} return tR } compiled({ name: "Johnny Appleseed" }, Sqrl.defaultConfig); //Returns "Hi, my name is Johnny Appleseed" ``` :::note Many template engines offer you the option to Compile (which just renders your template) or Precompile (which turns your template into a function ahead of time). Squirrelly precompiles automatically, but is still faster than other engines. ::: # Configuration URL: /docs/api/configuration *** id: configuration title: Configuration -------------------- Similarly to many other libraries, Squirrelly allows you to customize its behavior via options. [TypeDoc doc page](https://squirrellyjs.github.io/squirrelly/interfaces/_config_.sqrlconfig.html) ## List of options | Option | Description | Type | Default | Required? | | --------------- | :------------------------------------------------- | :-------------------: | :---------------------: | :-------: | | `async` | Whether to generate async templates | `boolean` | `false` | Yes | | `autoEscape` | Whether to automatically XML-escape | `boolean` | | Yes | | `autoTrim` | Configure automatic whitespace trimming | [autoTrim](#autotrim) | `[false, "nl"`] | Yes | | `cache` | Cache templates by `name` or `filename` | `boolean` | | Yes | | `defaultFilter` | Pass all interpolates through a function | `false \| Function` | `false` | Yes | | `filename` | Absolute filepath of template (for caching) | `string` | `undefined` | No | | `l` | Function that returns helpers. See [l](#l) | `Function` | `defaultConfig.l` | Yes | | `name` | Template name (for caching) | `string` | `undefined` | No | | `plugins` | Plugins object | [plugins](#plugins) | `defaultConfig.plugins` | Yes | | `root` | Base filepath. Defaults to `"\"` internally | `string` | `undefined` | No | | `storage` | Object containing templates, helpers, filters | [storage](#storage) | `defaultConfig.storage` | Yes | | `tags` | Template delimiters. [CAVEATS](#delimiter-caveats) | `[string, string]` | `["{{", "}}"]` | Yes | | `useWith` | Use `with(){}` to have data scope as global | `boolean` | `undefined` | No | | `varName` | Name of data object | `string` | `"it"` | Yes | | `view cache` | Overrides `cache` | `boolean` | `undefined` | No | | `views` | Absolute filepath to views directory | `string` | `undefined` | No | ### Delimiter Caveats Closing delimiters (like `{{`) can't have any of `(`, `)`, `|`, or `=>`. Delimiters must be RegExp-escaped. ### `autoTrim` `autoTrim` controls whitespace trimming. **Signature** `"nl" | "slurp" | boolean | ["nl" | "slurp" | boolean, "nl" | "slurp" | boolean]` **Options** * `"nl"` trims first character * `"slurp"` trims all leading/trailing whitespace * `true` is equivalent to `"slurp"` When an array is passed, Squirrelly uses the equivalent options on the left or right side of the string ### `l` `l` is a function that is used inside template functions to fetch filters and helpers. **Signature** `(container: "H" | "F", name: string) => Function` **Default** ```js function (container, name) { if (container === 'H') { var hRet = helpers.get(name) if (hRet) { return hRet } else { throw SqrlErr("Can't find helper '" + name + "'") } } else if (container === 'F') { var fRet = filters.get(name) if (fRet) { return fRet } else { throw SqrlErr("Can't find filter '" + name + "'") } } }, ``` ### `plugins` `plugins` is an object with the following properties: | Property | Description | Type | Default | | ----------------- | :------------------------------------------------------------- | :-------------: | :-----: | | `processAST` | List of functions that manipulate Squirrelly syntax tree | `Array` | `[]` | | `processFnString` | List of functions that manipulate Squirrelly template function | `Array` | `[]` | ### `storage` `storage` points to helpers, native helpers, filters, and templates. It's an object with the following properties: | Property | Description | Type | Default | | --------------- | :------------------- | :----------------------------: | :------------------: | | `filters` | Filters cache | `Cacher` | `Sqrl.filters` | | `helpers` | Helpers cache | `Cacher` | `Sqrl.helpers` | | `nativeHelpers` | Native helpers cache | `Cacher` | `Sqrl.nativeHelpers` | | `templates` | Templates cache | `Cacher` | `Sqrl.templates` | You only need to modify it if you want to create environments with different caches. ## `defaultConfig` `Sqrl.defaultConfig` returns the default configuration. See above. ## `getConfig` `getConfig` takes some config options and merges them with the default. It optionally takes a third parameter, which it merges with the default first. High-level APIs like `render` and `compile` call `getConfig` internally, but you should call lower-level APIs (like `compileToString`) with a valid config object, which you can get from this function. ### Syntax [TypeDoc doc page](https://squirrellyjs.github.io/squirrelly/modules/_config_.html#getconfig) ### Example ```js Sqrl.compileToString(myTemplate, Sqrl.getConfig({ tags: ["<%", "%>"] })); ``` # Containers URL: /docs/api/containers *** id: containers title: Containers ----------------- Templates, filters, helpers, and native helpers are all stored in storage objects (internally exposed as `Cacher`) with a similar syntax. ## Syntax [TypeDoc doc page](https://squirrellyjs.github.io/squirrelly/classes/_storage_.cacher.html) ## TL;DR To get a cache item, call `[cache].get('name')`. To define a cache item, run `[cache].define('name', value)`. To load an entire cache object, run `[cache].load(cacheObj)`. To reset a cache, run `[cache].clear()`. ## Examples ```js Sqrl.templates.define("my-partial", Sqrl.compile("This is a partial speaking")); console.log(Sqrl.templates.get("my-partial")); Sqrl.filters.define("capitalize", function(str) { return str.toUpperCase(); }); Sqrl.filters.clear(); ``` # File Handling URL: /docs/api/file-handling *** id: file-handling title: File Handling -------------------- :::note Squirrelly works out-of-the-box with Express.js. ```js app.engine('html', require('squirrelly').renderFile) // Or, if you want to use the .squirrelly file extension app.set('view engine', 'squirrelly') ``` ::: ## Syntax ```js ``` # Filters API URL: /docs/api/filters *** id: filter-api title: Filters API ------------------ Filters let you pass a value through functions. ## Examples **Simple example** ```js var myTemplate = "Hi, my name is {{it.name | reverse}}"; Sqrl.filters.define("reverse", function(str) { return s .split("") .reverse() .join(""); }); Sqrl.render(myTemplate, { name: "Ben" }); // Hi, my name is neB ``` **With filter parameters** ```js var myTemplate = "{{it.bio | replace('apples', 'watermelons') }}"; Sqrl.filters.define("replace", function(str, search, replace) { return str.replace(search, replace); }); Sqrl.render(myTemplate, { bio: "I like to eat apples" }); // I like to eat watermelons ``` # Helpers API URL: /docs/api/helpers *** id: helper-api title: Helpers API ------------------ Helpers let you call external functions with portions of your template! ## Syntax [TypeDoc doc page](https://squirrellyjs.github.io/squirrelly/modules/_containers_.html#helpers) ## Examples *Here's the `extends` helper behind-the-scenes* ```js Sqrl.helpers.define("extends", function(content, blocks, config) { var data = content.params[1] || {}; data.content = content.exec(); // Loop through each block for (var i = 0; i < blocks.length; i++) { var currentBlock = blocks[i]; // set data[blockName] to the compiled value of the current block data[currentBlock.name] = currentBlock.exec(); } var template = config.storage.templates.get(content.params[0]); if (!template) { throw SqrlErr('Could not fetch template "' + content.params[0] + '"'); } return template(data, config); }); ``` *Here's the `foreach` helper behind-the-scenes* ```js Sqrl.helpers.define("foreach", function(content) { var res = ""; var param = content.params[0]; // the first param is the object we want to loop over for (var key in param) { if (!hasOwnProp(param, key)) continue; res += content.exec(key, param[key]); } return res; }); ``` # Native Helpers API URL: /docs/api/native-helpers *** id: native-helper-api title: Native Helpers API ------------------------- Native helpers let you output code directly into your template function. :::caution Native helpers are complicated and kind of messy. If you can implement something with a regular helper, do that instead ::: ## Syntax ## Examples *This is the `if` native helper, behind-the-scenes* ```js Sqrl.nativeHelpers.define('if', function (buffer, env) { // buffer.d is buffer content, in AST form var returnStr = 'if(' + buffer.p + '){' + Sqrl.compileScope(buffer.d, env) + '}' if (buffer.b) { // b stands for blocks // Loop through each helper block for (var i = 0; i < buffer.b.length; i++) { var currentBlock = buffer.b[i] if (currentBlock.n === 'else') { returnStr += 'else{' + Sqrl.compileScope(currentBlock.d, env) + '}' } else if (currentBlock.n === 'elif') { returnStr += 'else if(' + currentBlock.p + '){' + Sqrl.compileScope(currentBlock.d, env) + '}' } } } return returnStr }) ``` # API Overview URL: /docs/api/overview *** id: overview title: API Overview ------------------- :::note You can view the TypeDoc API documentation for Squirrelly at [https://squirrellyjs.github.io/squirrelly/modules/\_index\_.html](https://squirrellyjs.github.io/squirrelly/modules/_index_.html). ::: ## Big list of API options * `__express` (alias for `renderFile`) * `compile` * `compileScope` * `compileScopeIntoFunction` * `compileToString` * `defaultConfig` * `filters` * `getConfig` * `helpers` * `loadFile` * `nativeHelpers` * `parse` (see [Parsing](./parsing)) * `render` (see [Rendering](./rendering)) * `renderFile` * `templates` # Parsing URL: /docs/api/parsing *** id: parsing title: Parsing -------------- :::note You won't need to use or understand Parsing unless you're writing native helpers or plugins. ::: ## Syntax [TypeDoc doc page](https://squirrellyjs.github.io/squirrelly/modules/_parse_.html#parse) ## Examples ```js var myTemplate = 'Hi, my name is {{it.name}}' var compiled = Sqrl.parse(myTemplate) //Returns a Squirrelly syntax tree (like an AST): // ['Hi, my name is ', { f: [], c: 'it.name', t: 'r' }] ``` # Rendering URL: /docs/api/rendering *** id: rendering title: Rendering ---------------- Rendering a template compiles a template and then calls it with the data you pass to it. ## Syntax [TypeDoc doc page](https://squirrellyjs.github.io/squirrelly/modules/_render_.html#render) ## Example ```js var myTemplate = "Hi, my name is {{it.name}}"; Sqrl.render(myTemplate, { name: "Johnny Appleseed" }); //Returns "Hi, my name is Johnny Appleseed" ``` # Partials & Layouts URL: /docs/api/templates *** id: templates-partials-layouts title: Partials & Layouts ------------------------- Templates, partials, and layouts are all stored in one object (exposed as `Sqrl.templates`). ## Loading templates / partials / layouts If you just call `render` or `compile` with `name` or `filename` in options, Squirrelly will load your template. ## Defining Partials ```js Sqrl.templates.define("my-partial", Sqrl.compile("This is a partial speaking")); Sqrl.render('... {{@include("my-partial")/}}', {}); // ... This is a partial speaking // To call a partial w/ data: Sqrl.templates.define("my-partial-2", Sqrl.compile("Name: {{it.name}}")); Sqrl.render( '... {{@include("my-partial", {name: it.name})/}}', // The 2nd argument passed to `include` is the data. You could also pass `it` to forward all data { name: "Ben" } ); // ... Name: Ben ``` ## Layouts See [https://stackblitz.com/edit/squirrelly-layouts?file=index.js](https://stackblitz.com/edit/squirrelly-layouts?file=index.js) for an example of how to use layouts. # Integrations URL: /docs/resources/integrations *** id: integrations title: Integrations ------------------- :::caution None of these are: * Officially supported * Vetted for security * Guaranteed to work Use at your own risk! ::: ## Integrations * [Consolidate.js](https://www.npmjs.com/package/consolidate) supports Squirrelly v7 and will soon support v8 * [fastify-squirrelly](https://github.com/scottkipfer/fastify-squirrelly) adds Squirrelly support to Fastify # Async Support URL: /docs/learn/async *** id: async title: Async Support -------------------- :::note Async support is still in-progress for environments not supporting `async`/`await`. ::: ## Syntax ```js function resolveAfter2Seconds () { return new Promise(resolve => { setTimeout(() => { resolve('HI FROM ASYNC') }, 2000) }) } Sqrl.helpers.define('async-test', resolveAfter2Seconds) async function doAsyncStuff () { console.log( await Sqrl.render( '{{@async async-test()/}}', {}, { async: true, asyncHelpers: ['async-test'] } ) ) // logs 'HI FROM ASYNC' after 2 seconds } // ALTERNATIVELY, WITH CALLBACKS: Sqrl.render( '{{@async async-test()/}}', {}, { async: true, asyncHelpers: ['async-test'] }, function (err, res) { console.log(res) // logs 'HI FROM ASYNC' after 2 seconds } ) ``` # Async Helpers & Filters URL: /docs/syntax/async *** id: async title: Async Helpers & Filters ------------------------------ Squirrelly supports optional async support using the `async` and `await` keywords (to support ES5 and lower, use a plugin or transpiler). ## Basic Syntax Essentially, just put an `async` in front of a helper or filter name. ## Examples ``` {{@ async helpername(parameters) => var1 }} {{/helpername}} ``` ``` {{val | filter1 | async filter2}} ``` ``` {{@async include("mypartial") /}} ``` # Auto XML-Escaping URL: /docs/syntax/auto-escaping *** id: auto-escaping title: Auto XML-Escaping ------------------------ Auto-escaping is an important feature of Squirrelly. When it's enabled, every reference without the `safe` filter or `*` prefix will be HTML-escaped, to provide some protection against XSS. :::caution Squirrelly has **not** been vetted for security, and autoEscaping is probably not completely foolproof. We use the same function as many other template engines, like Mustache and Handlebars, but there's still the possibility that there's some vulnerability. ::: ```js Sqrl.defaultConfig.autoEscape = true // Turns autoEscaping on Sqrl.defaultConfig.autoEscape = false // Turns autoEscaping off // autoEscaping is on by default ``` ## Disabling To avoid escaping a specific reference, you can pass it through the `safe` filter. *Example*: `{{someref | safe}}` You can also put an asterisk (`*`) after the opening delimiters and whitespace control tags. *Examples*: `{{* someref}}`, `{{_ * someref}}` :::note Auto-escaping can be helpful, but it also negatively impacts performance. For best results, autoEscape data before you store it or attempt to render it in a template. ::: # Built-in Helpers URL: /docs/syntax/builtin-helpers *** id: builtin-helpers title: Built-in Helpers ----------------------- Builtin helpers are helpers that come as part of the Squirrelly library. They can always be overwritten if desired, but they provide simple, no-setup logic within templates. ## if/else ```hbs {{@if(it.somevalue === 1)}} Display this {{#else}} Display this {{/if}} ``` *This is a native helper* ## each ```hbs {{@each(it.somearray) => val, index}} Display this The current array element is {{val}} The current index is {{index}} {{/each}} ``` ### Helper References: * `val`: the current array element * `index`: the index of the array element **Note that `val, index` are both optional and can be renamed. Ex. `=> item` or `=> item, number`** ## foreach ```hbs {{@foreach(it.someobject) => key, val}} This loops over each of an objects keys and values. The value of the current child is {{val}} The current key is {{key}} {{/foreach}} ``` ### Helper References: * `key`: the key of the current object child * `val`: the value of the current child **Note that `val, index` are both optional and can be renamed. Ex. `=> item` or `=> item, number`** ## try-catch ```hbs {{@try}} This won't work: {{ *it.hi | validate}} {{#catch => err}} Uh-oh, error! Message was '{{err.message}}' {{/try}} ``` ### Helper References: * `err`: the error # Caveats URL: /docs/syntax/caveats *** id: caveats title: Caveats -------------- ## Reserved variable names *Don't use these variables in your templates* * `it` * `tR` * `cb` * `c` ## Parsing * Using RegExp literals inside your templates has a high likelihood of making them fail. Please, put that logic in a helper or something. If you really must, use `new RegExp('a|b')` instead. ## Delimiters * Delimiters have to be regular-expression escaped * Your closing delimiter can't contain `(`, `)`, `|`, or `=>`. *This is due to our parsing algorithm needing to figure out when helper parameters have been closed, filters started, etc.* # Cheatsheet URL: /docs/syntax/cheatsheet *** id: cheatsheet title: Cheatsheet ----------------- ## Conditionals ```hbs {{@if(it.someval === "someothervalue")}} Display this! {{#else}} They don't equal {{/if}} ``` ## Looping over arrays ```hbs {{@each(it.someArray) => val, index}} The current array item is {{val}}, the current index is {{index}} {{/each}} ``` ## Looping over objects ``` {{@foreach(it.someObject) => key, val}} The current object key is {{key}}, and the value is {{val}} {{/foreach}} ``` ## Logging to the console ``` {{!console.log("The value of it.num is: " + it.num);}} ``` **Note: you must include a semicolon (`;`) or template compilation will fail** # Filters URL: /docs/syntax/filters *** id: filters title: Filters -------------- Filters let you pipe content through some predefined functions. ## Basic Syntax ```hbs {{somereference | somefilter |anotherfilter}} ``` Squirrelly has a filter syntax similar to Nunjucks or Swig. Just put a `|` and then the filter name. You can pipe to multiple filters if you want. Filters can also accept parameters. ## Example ```hbs {{! /* Basic filters */}} {{mystring | reverse | capitalize}} {{! /* With Parameters */}} {{it.someArray | join(", ")}} ``` :::note Defining Filters Remember, you'll need to [define each filter](../api/filter-api) before you use it. ::: ## The `safe` flag To disable autoescaping, you can write ```hbs {{myreference | safe}} ``` This isn't a true filter, it just acts as a flag to let Squirrelly know not to autoescape. # Helpers URL: /docs/syntax/helpers *** id: helpers title: Helpers -------------- Helpers are an easy way to include logic within a template. Conditionals, looping, and partials are all implemented using helpers. ## Basic Syntax ``` {{@helpername(parameters) => [var1, var2]}} Content goes here {{#helperblock}} {{/helpername}} ``` You can have as many blocks as you want within a helper. ## Example ``` {{@portfolio( {userID: 3838357} )}} Joe Edrick {{#tagline}} Cool Coder Person {{#hobbies}} Eating delicious food {{#img}} {{@user.img}} {{/portfolio}} ``` ## Self-Closing Helpers Self-Closing Helpers are helpers that have no content, and are just called with parameters. ### Basic Syntax ``` {{@helpername(parameters) /}} ``` ### Examples ``` {{@include("mypartial")/}} ``` # References (Interpolate) URL: /docs/syntax/interpolate *** id: interpolate title: References (Interpolate) ------------------------------- A reference (what doT would call an interpolation) outputs data into the template. ## Basic Syntax ```hbs {{ reference }} ``` ## Overview Put a reference between the opening and closing delimiters (by default `{{`and `}}`). **The data you call a template with is stored in an object named `it` by default.** Since Squirrelly templates parse into JavaScript, you can write a reference using dot notation: `

User's last name: {{it.user.lastName}}` or bracket notation: `

User's last name: {{it.user['lastName']}}`. :::note You can unescape a reference by putting `*` after the opening delimiters (ex. `{{* unescapedSomething }}`) ::: :::caution There can be spaces after the tag start (default `{{`) and before a tag close (default `}}`) ::: # Native Code (Evaluate) URL: /docs/syntax/native-code *** id: native-code title: Native Code (Evaluate) ----------------------------- A native code tag inserts its contents into the template function. (It's what doT would call evaluation). ## Basic Syntax ```hbs {{! ... }} ``` ## Overview Put valid JavaScript code between the tag delimiters. ## Comments Comments are written with native code syntax. *Example*: ```hbs {{! /* this is a comment */}} ``` ## Console.log You can log to the console with native code syntax. *Example*: ```hbs {{! console.log("Hi"); }} ``` :::caution Make sure you include semicolons when needed! Ex. `{{! console.log('x'); }}` In general, semicolons are needed after calling functions. ::: # Syntax Overview URL: /docs/syntax/overview *** id: overview title: Syntax Overview ---------------------- ## Definitions We're going to call something between the set delimiters a tag. Ex: `{{...}}`, where `{{` and `}}` are called "delimiters" ## Language Items There are 5 language items in Squirrelly: * [Interpolation tags](interpolate) place the value of the code inside them into the rendered template.
*Example*: Rendering `Hi {{it.name}}` with `{name: "Ben"}` will return `"Hi Ben"`.
The data you call a template with is referenced using `it`, similarly to doT.js. * [Evaluation tags](native-code) start with `!` and place the code inside them into the template function.
*Examples*: Comments are written using evaluation tags (`{{! /*comment */}}`), as are JS function calls (`{{! console.log('hi') }}`).
It's usually discouraged to use evaluation tags for complex functions and logic, which helpers are ideal for. * [Helpers](helpers) start with `@` and are for logic in the template. Loops and conditionals are both implemented as native helpers, a special kind of helper that compiles into native JS code before rendering.
Helpers use blocks (that start with `#`) for logical separation.
*Examples*: * If/Else: ``` {{ @if (it.number === 3) }} Number is three {{ #elif (it.number === 4) }} Number is four {{ #else }} Number is five {{ /if}}` ``` * [Filters](filters) are for post-processing values such as references and helpers. You can define your own that do anything from capitalizing letters to emojifying strings.
*Example*: `{{someref | capitalize}}` ## Inspiration Squirrelly takes inspiration from Mustache, Handlebars, EJS, Nunjucks, Swig, doT.js, and many other great template engines. # Partials and Template Inheritance URL: /docs/syntax/partials *** id: partials-layouts title: Partials and Template Inheritance ---------------------------------------- ## Partials Partials are implemented behind-the-scenes as [native helpers](../api/native-helper-api), and the syntax is the same as a [self-closing helper](helpers#self-closing-helpers). There are 2 types of partials: **registered partials** and **file partials**. ### Registered Partials Registered partials work both in the browser and in Node.js. They must first be "registered", or defined, using `Sqrl.templates.define(...)` **Syntax** ``` {{@include('mypartial', data) /}} ``` **Example** Note that in this example we pass `it` as the data object to the partial. This allows it to access the data the template is called with. ```js let mypartial = `My name is {{it.name}}` Sqrl.templates.define('mypartial', Sqrl.compile(mypartial)) Sqrl.render("This is a partial: {{@include('mypartial', it) /}}", { name: 'Ben', }) // This is a partial: My name is Ben ``` ### File Partials File partials work only in Node.js. They do not have to be defined first. **Syntax** ``` {{@includeFile('path-to-partial', data) /}} ``` **Example** Note that in this example we pass `it` as the data object to the partial. This allows it to access the data the template is called with. ```handlebars {{! /* src/partial.sqrl */}} This is a partial speaking: "My name is {{it.name}}" ``` ```js // src/index.js Sqrl.render("{{@includeFile('./partial', it) /}}", { name: 'Ben', }) // This is a partial speaking: "My name is {{it.name}}" ``` # Whitespace Control URL: /docs/syntax/whitespace-trimming *** id: whitespace-control title: Whitespace Control ------------------------- Squirrelly allows you to control the whitespace before or after tags. :::note Squirrelly borrows its whitespace control syntax from EJS ::: ## Basic Syntax Opening delimiters can be followed with `-` or `_`, and closing delimiters can be prefixed with `-` or `_` `_` at the beginning of a tag will trim all whitespace before it, and `_` at the end of a tag will trim all whitespace after it. `-` at the beginning of a tag will trim 1 character of whitespace before it, and `-` at the end of a tag will trim 1 character of whitespace after it. ## Examples ```hbs Hi {{- it.myname }} ``` ```hbs {{_ ~if (it.num) _}} {{/if}} ``` :::note Configuration By default, Squirrelly removes the first whitespace character after each tag. This can be [configured](../api/configuration) :::