mirror of https://github.com/Budibase/budibase.git
49 changed files with 2474 additions and 325 deletions
@ -1,10 +1,12 @@ |
|||
import CodeMirror from "codemirror" |
|||
import "codemirror/lib/codemirror.css" |
|||
import "codemirror/theme/tomorrow-night-eighties.css" |
|||
import "codemirror/addon/hint/show-hint.css" |
|||
import "codemirror/theme/neo.css" |
|||
import "codemirror/mode/sql/sql" |
|||
import "codemirror/mode/css/css" |
|||
import "codemirror/mode/handlebars/handlebars" |
|||
import "codemirror/mode/javascript/javascript" |
|||
import "codemirror/addon/hint/show-hint" |
|||
|
|||
export default CodeMirror |
|||
|
|||
@ -0,0 +1,15 @@ |
|||
import { getManifest } from "@budibase/string-templates" |
|||
|
|||
export function handlebarsCompletions() { |
|||
const manifest = getManifest() |
|||
|
|||
return Object.keys(manifest).flatMap(key => |
|||
Object.entries(manifest[key]).map(([helperName, helperConfig]) => ({ |
|||
text: helperName, |
|||
path: helperName, |
|||
label: helperName, |
|||
displayText: helperName, |
|||
description: helperConfig.description, |
|||
})) |
|||
) |
|||
} |
|||
@ -0,0 +1,173 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="en"> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<title>Budibase self hosting️</title> |
|||
<style> |
|||
body { |
|||
font-family: Inter, -apple-system, BlinkMacSystemFont, Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; |
|||
height: 100%; |
|||
width: 100%; |
|||
margin: 0; |
|||
padding: 0; |
|||
background: #fafafa; |
|||
} |
|||
|
|||
.main { |
|||
padding: 0 20px; |
|||
margin: 30px auto; |
|||
width: 60%; |
|||
} |
|||
|
|||
h2 { |
|||
font-size: clamp(24px, 1.5vw, 30px); |
|||
text-align: center; |
|||
line-height: 1.3; |
|||
font-weight: bold; |
|||
} |
|||
|
|||
.card-grid { |
|||
display: grid; |
|||
grid-template-columns: 1fr 1fr; |
|||
gap: 3rem; |
|||
} |
|||
|
|||
.card { |
|||
display: grid; |
|||
background-color: #222222; |
|||
grid-template-columns: 1fr; |
|||
align-items: center; |
|||
padding: 2.5rem 1.75rem; |
|||
border-radius: 12px; |
|||
color: white; |
|||
} |
|||
|
|||
.card h3 { |
|||
margin: 0; |
|||
font-size: 24px; |
|||
font-family: sans-serif; |
|||
font-weight: 600; |
|||
} |
|||
|
|||
.card h3 b { |
|||
text-wrap: normal; |
|||
font-size: 36px; |
|||
padding-right: 14px; |
|||
} |
|||
|
|||
.card p { |
|||
color: #ffffff; |
|||
opacity: 0.8; |
|||
font-size: 18px; |
|||
text-align: left; |
|||
line-height: 1.3; |
|||
margin-top: 1rem; |
|||
} |
|||
|
|||
.logo { |
|||
width: 60px; |
|||
height: 60px; |
|||
margin: auto; |
|||
} |
|||
|
|||
.top-text { |
|||
text-align: center; |
|||
color: #707070; |
|||
margin: 0 0 1.5rem 0; |
|||
} |
|||
|
|||
.button { |
|||
cursor: pointer; |
|||
display: block; |
|||
background: #4285f4; |
|||
color: white; |
|||
padding: 12px 16px; |
|||
font-size: 16px; |
|||
font-weight: 600; |
|||
border-radius: 6px; |
|||
max-width: 120px; |
|||
text-align: center; |
|||
transition: 200ms background ease; |
|||
text-decoration: none; |
|||
} |
|||
|
|||
.info { |
|||
background: #f5f5f5; |
|||
padding: 1rem 1rem 1rem 1rem; |
|||
border: #ccc 1px solid; |
|||
border-radius: 6px; |
|||
margin-top: 40px; |
|||
display: flex; |
|||
align-items: center; |
|||
} |
|||
|
|||
.info p { |
|||
margin-left: 20px; |
|||
color: #222222; |
|||
font-family: sans-serif; |
|||
} |
|||
|
|||
.info p { |
|||
margin-right: 20px; |
|||
} |
|||
|
|||
.info svg { |
|||
margin-left: 20px; |
|||
} |
|||
|
|||
.info a { |
|||
color: #4285f4; |
|||
} |
|||
</style> |
|||
</head> |
|||
<body> |
|||
<div class="main"> |
|||
<div class="logo"> |
|||
{{logo}} |
|||
</div> |
|||
<h2>Get started with Budibase Self Hosting</h2> |
|||
<p class="top-text">Use the address <b id="url"></b> in your Builder</p> |
|||
<div class="card-grid"> |
|||
<div class="card"> |
|||
<h3><b>📚</b>Documentation</h3> |
|||
<p> |
|||
Find out more about your self hosted platform. |
|||
</p> |
|||
<a class="button" |
|||
href="https://docs.budibase.com/self-hosting/introduction-to-self-hosting"> |
|||
Documentation |
|||
</a> |
|||
</div> |
|||
<div class="card"> |
|||
<h3><b>💻</b>Next steps</h3> |
|||
<p> |
|||
Find out how to make use of your self hosted Budibase platform. |
|||
</p> |
|||
<a class="button" |
|||
href="https://docs.budibase.com/self-hosting/builder-settings"> |
|||
Next steps |
|||
</a> |
|||
</div> |
|||
</div> |
|||
<div class="info"> |
|||
<svg preserveAspectRatio="xMidYMid meet" height="28px" width="28px" fill="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" |
|||
xmlns:xlink="http://www.w3.org/1999/xlink" stroke="none" class="icon-7f6730be--text-3f89f380"> |
|||
<g> |
|||
<path d="M12.2 8.98c.06-.01.12-.03.18-.06.06-.02.12-.05.18-.09l.15-.12c.18-.19.29-.45.29-.71 0-.06-.01-.13-.02-.19a.603.603 0 0 0-.06-.19.757.757 0 0 0-.09-.18c-.03-.05-.08-.1-.12-.15-.28-.27-.72-.37-1.09-.21-.13.05-.23.12-.33.21-.04.05-.09.1-.12.15-.04.06-.07.12-.09.18-.03.06-.05.12-.06.19-.01.06-.02.13-.02.19 0 .26.11.52.29.71.1.09.2.16.33.21.12.05.25.08.38.08.06 0 .13-.01.2-.02M13 16v-4a1 1 0 1 0-2 0v4a1 1 0 1 0 2 0M12 3c-4.962 0-9 4.038-9 9 0 4.963 4.038 9 9 9 4.963 0 9-4.037 9-9 0-4.962-4.037-9-9-9m0 20C5.935 23 1 18.065 1 12S5.935 1 12 1c6.066 0 11 4.935 11 11s-4.934 11-11 11" fill-rule="evenodd"> |
|||
</path> |
|||
</g> |
|||
</svg> |
|||
<p>A <b>Hosting Key</b> will also be required, this can be found in your hosting properties, info found <a href="https://docs.budibase.com/self-hosting/hosting-settings">here</a>.</p> |
|||
</div> |
|||
</div> |
|||
<script> |
|||
window.addEventListener("load", () => { |
|||
let url = document.URL.split("//")[1] |
|||
if (url.substring(url.length - 1) === "/") { |
|||
url = url.substring(0, url.length - 1) |
|||
} |
|||
document.getElementById("url").innerHTML = url |
|||
}) |
|||
</script> |
|||
</body> |
|||
</html> |
|||
|
After Width: | Height: | Size: 4.6 KiB |
@ -0,0 +1,92 @@ |
|||
# String templating |
|||
This package provides a common system for string templating across the Budibase Builder, client and server. |
|||
The templating is provided through the use of [Handlebars](https://handlebarsjs.com/) an extension of Mustache |
|||
which is capable of carrying out logic. We have also extended the base Handlebars functionality through the use |
|||
of a set of helpers provided through the [handlebars-helpers](https://github.com/helpers/handlebars-helpers) package. |
|||
|
|||
We have not implemented all the helpers provided by the helpers package as some of them provide functionality |
|||
we felt would not be beneficial. The following collections of helpers have been implemented: |
|||
1. [Math](https://github.com/helpers/handlebars-helpers/tree/master#math) - a set of useful helpers for |
|||
carrying out logic pertaining to numbers e.g. `avg`, `add`, `abs` and so on. |
|||
2. [Array](https://github.com/helpers/handlebars-helpers/tree/master#array) - some very specific helpers |
|||
for use with arrays, useful for example in automations. Helpers like `first`, `last`, `after` and `join` |
|||
can be useful for getting particular portions of arrays or turning them into strings. |
|||
3. [Number](https://github.com/helpers/handlebars-helpers/tree/master#number) - unlike the math helpers these |
|||
are useful for converting numbers into useful formats for display, e.g. `bytes`, `addCommas` and `toPrecision`. |
|||
4. [URL](https://github.com/helpers/handlebars-helpers/tree/master#url) - very specific helpers for dealing with URLs, |
|||
such as `encodeURI`, `escape`, `stripQueryString` and `stripProtocol`. These are primarily useful |
|||
for building up particular URLs to hit as say part of an automation. |
|||
5. [String](https://github.com/helpers/handlebars-helpers/tree/master#string) - these helpers are useful for building |
|||
strings and preparing them for display, e.g. `append`, `camelcase`, `capitalize` and `ellipsis`. |
|||
6. [Comparison](https://github.com/helpers/handlebars-helpers/tree/master#comparison) - these helpers are mainly for |
|||
building strings when particular conditions are met, for example `and`, `or`, `gt`, `lt`, `not` and so on. This is a very |
|||
extensive set of helpers but is mostly as would be expected from a set of logical operators. |
|||
7. [Date](https://github.com/helpers/helper-date) - last but certainly not least is a moment based date helper, which can |
|||
format ISO/timestamp based dates into something human-readable. An example of this would be `{{date dateProperty "DD-MM-YYYY"}}`. |
|||
|
|||
## Date formatting |
|||
This package uses the standard method for formatting date times, using the following syntax: |
|||
| Input | Example | Description | |
|||
| ----- | ------- | ----------- | |
|||
| YYYY | 2014 | 4 or 2 digit year. Note: Only 4 digit can be parsed on strict mode | |
|||
| YY | 14 | 2 digit year | |
|||
| Y | -25 | Year with any number of digits and sign | |
|||
| Q | 1..4 | Quarter of year. Sets month to first month in quarter. | |
|||
| M MM | 1..12 | Month number | |
|||
| MMM MMMM | Jan..December | Month name in locale set by moment.locale() | |
|||
| D DD | 1..31 | Day of month | |
|||
| Do | 1st..31st | Day of month with ordinal | |
|||
| DDD DDDD | 1..365 | Day of year | |
|||
| X | 1410715640.579 | Unix timestamp | |
|||
| x | 1410715640579 | Unix ms timestamp | |
|||
|
|||
## Template format |
|||
There are two main ways that the templating system can be used, the first is very similar to that which |
|||
would be produced by Mustache - a single statement: |
|||
``` |
|||
Hello I'm building a {{uppercase adjective}} string with Handlebars! |
|||
``` |
|||
In the statement above provided a context of `{adjective: "cool"}` will produce a string of `Hello I'm building a COOL string with Handlebars!`. |
|||
Here we can see an example of how string helpers can be used to make a string exactly as we need it. These statements are relatively |
|||
simple; we can also stack helpers as such: `{{ uppercase (remove string "bad") }}` with the use of parenthesis. |
|||
|
|||
The other type of statement that can be made with the templating system is conditional ones, that appear as such: |
|||
``` |
|||
Hello I'm building a {{ #gte score "50" }}Great{{ else }}Bad{{ /gte }} string with Handlebars! |
|||
``` |
|||
In this string we can see that the string `Great` or `Bad` will be inserted depending on the state of the |
|||
`score` context variable. The comparison, string and array helpers all provide some conditional operators which can be used |
|||
in this way. There will also be some operators which will be built with a very similar syntax but will produce an |
|||
iterative operation, like a for each - an example of this would be the `forEach` array helper. |
|||
|
|||
## Usage |
|||
Usage of this templating package is through one of the primary functions provided by the package - these functions are |
|||
as follows: |
|||
1. `processString` - `async (string, object)` - given a template string and a context object this will build a string |
|||
using our pre-processors, post-processors and handlebars. |
|||
2. `processObject` - `async (object, object)` - carries out the functionality provided by `processString` for any string |
|||
inside the given object. This will recurse deeply into the provided object so for very large objects this could be slow. |
|||
3. `processStringSync` - `(string, object)` - a reduced functionality processing of strings which is synchronous, like |
|||
functions provided by Node (e.g. `readdirSync`) |
|||
4. `processObjectSync` - `(object, object)` - as with the sync'd string, recurses an object to process it synchronously. |
|||
5. `makePropSafe` - `(string)` - some properties cannot be handled by Handlebars, for example `Table 1` is not valid due |
|||
to spaces found in the property name. This will update the property name to `[Table 1]` wrapping it in literal |
|||
specifiers so that it is safe for use in Handlebars. Ideally this function should be called for every level of an object |
|||
being accessed, for example `[Table 1].[property name]` is the syntax that is required for Handlebars. |
|||
6. `isValid` - `(string)` - checks the given string for any templates and provides a boolean stating whether it is a valid |
|||
template. |
|||
7. `getManifest` - returns the manifest JSON which has been generated for the helpers, describing them and their params. |
|||
|
|||
## Development |
|||
This library is built with [Rollup](https://rollupjs.org/guide/en/) as many of the packages built by Budibase are. We have |
|||
built the string templating package as a UMD so that it can be used by Node and Browser based applications. This package also |
|||
builds Typescript stubs which when making use of the library will be used by your IDE to provide code completion. The following |
|||
commands are provided for development purposes: |
|||
1. `yarn build` - will build the Typescript stubs and the bundle into the `dist` directory. |
|||
2. `yarn test` - runs the test suite which will check various helpers are still functioning as |
|||
expected and a few expected use cases. |
|||
3. `yarn dev:builder` - an internal command which is used by lerna to watch and build any changes |
|||
to the package as part of the main `yarn dev` of the repo. |
|||
|
|||
It is also important to note this package is managed in the same manner as all other in the mono-repo, |
|||
through lerna. |
|||
@ -0,0 +1,986 @@ |
|||
{ |
|||
"math": { |
|||
"abs": { |
|||
"args": [ |
|||
"a" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>Return the magnitude of <code>a</code>.</p>\n" |
|||
}, |
|||
"add": { |
|||
"args": [ |
|||
"a", |
|||
"b" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Return the sum of <code>a</code> plus <code>b</code>.</p>\n" |
|||
}, |
|||
"avg": { |
|||
"args": [ |
|||
"array" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>Returns the average of all numbers in the given array.</p>\n" |
|||
}, |
|||
"ceil": { |
|||
"args": [ |
|||
"value" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>Get the <code>Math.ceil()</code> of the given value.</p>\n" |
|||
}, |
|||
"divide": { |
|||
"args": [ |
|||
"a", |
|||
"b" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Divide <code>a</code> by <code>b</code></p>\n" |
|||
}, |
|||
"floor": { |
|||
"args": [ |
|||
"value" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>Get the <code>Math.floor()</code> of the given value.</p>\n" |
|||
}, |
|||
"minus": { |
|||
"args": [ |
|||
"a", |
|||
"b" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Return the product of <code>a</code> minus <code>b</code>.</p>\n" |
|||
}, |
|||
"modulo": { |
|||
"args": [ |
|||
"a", |
|||
"b" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Get the remainder of a division operation.</p>\n" |
|||
}, |
|||
"multiply": { |
|||
"args": [ |
|||
"a", |
|||
"b" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Return the product of <code>a</code> times <code>b</code>.</p>\n" |
|||
}, |
|||
"plus": { |
|||
"args": [ |
|||
"a", |
|||
"b" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Add <code>a</code> by <code>b</code>.</p>\n" |
|||
}, |
|||
"random": { |
|||
"args": [ |
|||
"min", |
|||
"max" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Generate a random number between two values</p>\n" |
|||
}, |
|||
"remainder": { |
|||
"args": [ |
|||
"a", |
|||
"b" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Get the remainder when <code>a</code> is divided by <code>b</code>.</p>\n" |
|||
}, |
|||
"round": { |
|||
"args": [ |
|||
"number" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>Round the given number.</p>\n" |
|||
}, |
|||
"subtract": { |
|||
"args": [ |
|||
"a", |
|||
"b" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Return the product of <code>a</code> minus <code>b</code>.</p>\n" |
|||
}, |
|||
"sum": { |
|||
"args": [ |
|||
"array" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>Returns the sum of all numbers in the given array.</p>\n" |
|||
}, |
|||
"times": { |
|||
"args": [ |
|||
"a", |
|||
"b" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Multiply number <code>a</code> by number <code>b</code>.</p>\n" |
|||
} |
|||
}, |
|||
"array": { |
|||
"after": { |
|||
"args": [ |
|||
"array", |
|||
"n" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Returns all of the items in an array after the specified index. Opposite of <a href=\"#before\">before</a>.</p>\n" |
|||
}, |
|||
"arrayify": { |
|||
"args": [ |
|||
"value" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>Cast the given <code>value</code> to an array.</p>\n" |
|||
}, |
|||
"before": { |
|||
"args": [ |
|||
"array", |
|||
"n" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Return all of the items in the collection before the specified count. Opposite of <a href=\"#after\">after</a>.</p>\n" |
|||
}, |
|||
"eachIndex": { |
|||
"args": [ |
|||
"array", |
|||
"options" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Iterates the array, listing an item and the index of it.</p>\n" |
|||
}, |
|||
"filter": { |
|||
"args": [ |
|||
"array", |
|||
"value", |
|||
"options" |
|||
], |
|||
"numArgs": 3, |
|||
"description": "<p>Block helper that filters the given array and renders the block for values that evaluate to <code>true</code>, otherwise the inverse block is returned.</p>\n" |
|||
}, |
|||
"first": { |
|||
"args": [ |
|||
"array", |
|||
"n" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Returns the first item, or first <code>n</code> items of an array.</p>\n" |
|||
}, |
|||
"forEach": { |
|||
"args": [ |
|||
"array" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>Iterates over each item in an array and exposes the current item in the array as context to the inner block. In addition to the current array item, the helper exposes the following variables to the inner block: - <code>index</code> - <code>total</code> - <code>isFirst</code> - <code>isLast</code> Also, <code>@index</code> is exposed as a private variable, and additional private variables may be defined as hash arguments.</p>\n" |
|||
}, |
|||
"inArray": { |
|||
"args": [ |
|||
"array", |
|||
"value", |
|||
"options" |
|||
], |
|||
"numArgs": 3, |
|||
"description": "<p>Block helper that renders the block if an array has the given <code>value</code>. Optionally specify an inverse block to render when the array does not have the given value.</p>\n" |
|||
}, |
|||
"isArray": { |
|||
"args": [ |
|||
"value" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>Returns true if <code>value</code> is an es5 array.</p>\n" |
|||
}, |
|||
"itemAt": { |
|||
"args": [ |
|||
"array", |
|||
"idx" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Returns the item from <code>array</code> at index <code>idx</code>.</p>\n" |
|||
}, |
|||
"join": { |
|||
"args": [ |
|||
"array", |
|||
"separator" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Join all elements of array into a string, optionally using a given separator.</p>\n" |
|||
}, |
|||
"equalsLength": { |
|||
"args": [ |
|||
"value", |
|||
"length", |
|||
"options" |
|||
], |
|||
"numArgs": 3, |
|||
"description": "<p>Returns true if the the length of the given <code>value</code> is equal to the given <code>length</code>. Can be used as a block or inline helper.</p>\n" |
|||
}, |
|||
"last": { |
|||
"args": [ |
|||
"value", |
|||
"n" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Returns the last item, or last <code>n</code> items of an array or string. Opposite of <a href=\"#first\">first</a>.</p>\n" |
|||
}, |
|||
"length": { |
|||
"args": [ |
|||
"value" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>Returns the length of the given string or array.</p>\n" |
|||
}, |
|||
"lengthEqual": { |
|||
"args": [ |
|||
"value", |
|||
"length", |
|||
"options" |
|||
], |
|||
"numArgs": 3, |
|||
"description": "<p>Returns true if the the length of the given <code>value</code> is equal to the given <code>length</code>. Can be used as a block or inline helper.</p>\n" |
|||
}, |
|||
"map": { |
|||
"args": [ |
|||
"array", |
|||
"fn" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Returns a new array, created by calling <code>function</code> on each element of the given <code>array</code>. For example,</p>\n" |
|||
}, |
|||
"pluck": { |
|||
"args": [ |
|||
"collection", |
|||
"prop" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Map over the given object or array or objects and create an array of values from the given <code>prop</code>. Dot-notation may be used (as a string) to get nested properties.</p>\n" |
|||
}, |
|||
"reverse": { |
|||
"args": [ |
|||
"value" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>Reverse the elements in an array, or the characters in a string.</p>\n" |
|||
}, |
|||
"some": { |
|||
"args": [ |
|||
"array", |
|||
"iter", |
|||
"provided" |
|||
], |
|||
"numArgs": 3, |
|||
"description": "<p>Block helper that returns the block if the callback returns true for some value in the given array.</p>\n" |
|||
}, |
|||
"sort": { |
|||
"args": [ |
|||
"array", |
|||
"key" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Sort the given <code>array</code>. If an array of objects is passed, you may optionally pass a <code>key</code> to sort on as the second argument. You may alternatively pass a sorting function as the second argument.</p>\n" |
|||
}, |
|||
"sortBy": { |
|||
"args": [ |
|||
"array", |
|||
"props" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Sort an <code>array</code>. If an array of objects is passed, you may optionally pass a <code>key</code> to sort on as the second argument. You may alternatively pass a sorting function as the second argument.</p>\n" |
|||
}, |
|||
"withAfter": { |
|||
"args": [ |
|||
"array", |
|||
"idx", |
|||
"options" |
|||
], |
|||
"numArgs": 3, |
|||
"description": "<p>Use the items in the array <em>after</em> the specified index as context inside a block. Opposite of <a href=\"#withBefore\">withBefore</a>.</p>\n" |
|||
}, |
|||
"withBefore": { |
|||
"args": [ |
|||
"array", |
|||
"idx", |
|||
"options" |
|||
], |
|||
"numArgs": 3, |
|||
"description": "<p>Use the items in the array <em>before</em> the specified index as context inside a block. Opposite of <a href=\"#withAfter\">withAfter</a>.</p>\n" |
|||
}, |
|||
"withFirst": { |
|||
"args": [ |
|||
"array", |
|||
"idx", |
|||
"options" |
|||
], |
|||
"numArgs": 3, |
|||
"description": "<p>Use the first item in a collection inside a handlebars block expression. Opposite of <a href=\"#withLast\">withLast</a>.</p>\n" |
|||
}, |
|||
"withGroup": { |
|||
"args": [ |
|||
"array", |
|||
"size", |
|||
"options" |
|||
], |
|||
"numArgs": 3, |
|||
"description": "<p>Block helper that groups array elements by given group <code>size</code>.</p>\n" |
|||
}, |
|||
"withLast": { |
|||
"args": [ |
|||
"array", |
|||
"idx", |
|||
"options" |
|||
], |
|||
"numArgs": 3, |
|||
"description": "<p>Use the last item or <code>n</code> items in an array as context inside a block. Opposite of <a href=\"#withFirst\">withFirst</a>.</p>\n" |
|||
}, |
|||
"withSort": { |
|||
"args": [ |
|||
"array", |
|||
"prop", |
|||
"options" |
|||
], |
|||
"numArgs": 3, |
|||
"description": "<p>Block helper that sorts a collection and exposes the sorted collection as context inside the block.</p>\n" |
|||
}, |
|||
"unique": { |
|||
"args": [ |
|||
"array", |
|||
"options" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Block helper that return an array with all duplicate values removed. Best used along with a <a href=\"#each\">each</a> helper.</p>\n" |
|||
} |
|||
}, |
|||
"number": { |
|||
"bytes": { |
|||
"args": [ |
|||
"number" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>Format a number to it's equivalent in bytes. If a string is passed, it's length will be formatted and returned. <strong>Examples:</strong> - <code>'foo' => 3 B</code> - <code>13661855 => 13.66 MB</code> - <code>825399 => 825.39 kB</code> - <code>1396 => 1.4 kB</code></p>\n" |
|||
}, |
|||
"addCommas": { |
|||
"args": [ |
|||
"num" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>Add commas to numbers</p>\n" |
|||
}, |
|||
"phoneNumber": { |
|||
"args": [ |
|||
"num" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>Convert a string or number to a formatted phone number.</p>\n" |
|||
}, |
|||
"toAbbr": { |
|||
"args": [ |
|||
"number", |
|||
"precision" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Abbreviate numbers to the given number of <code>precision</code>. This for general numbers, not size in bytes.</p>\n" |
|||
}, |
|||
"toExponential": { |
|||
"args": [ |
|||
"number", |
|||
"fractionDigits" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Returns a string representing the given number in exponential notation.</p>\n" |
|||
}, |
|||
"toFixed": { |
|||
"args": [ |
|||
"number", |
|||
"digits" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Formats the given number using fixed-point notation.</p>\n" |
|||
}, |
|||
"toFloat": { |
|||
"args": [ |
|||
"number" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>Convert input to a float.</p>\n" |
|||
}, |
|||
"toInt": { |
|||
"args": [ |
|||
"number" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>Convert input to an integer.</p>\n" |
|||
}, |
|||
"toPrecision": { |
|||
"args": [ |
|||
"number", |
|||
"precision" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Returns a string representing the <code>Number</code> object to the specified precision.</p>\n" |
|||
} |
|||
}, |
|||
"url": { |
|||
"encodeURI": { |
|||
"args": [ |
|||
"str" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>Encodes a Uniform Resource Identifier (URI) component by replacing each instance of certain characters by one, two, three, or four escape sequences representing the UTF-8 encoding of the character.</p>\n" |
|||
}, |
|||
"escape": { |
|||
"args": [ |
|||
"str" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>Escape the given string by replacing characters with escape sequences. Useful for allowing the string to be used in a URL, etc.</p>\n" |
|||
}, |
|||
"decodeURI": { |
|||
"args": [ |
|||
"str" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>Decode a Uniform Resource Identifier (URI) component.</p>\n" |
|||
}, |
|||
"url_encode": { |
|||
"args": [], |
|||
"numArgs": 0, |
|||
"description": "<p>Alias for <a href=\"#encodeuri\">encodeURI</a>.</p>\n" |
|||
}, |
|||
"url_decode": { |
|||
"args": [], |
|||
"numArgs": 0, |
|||
"description": "<p>Alias for <a href=\"#decodeuri\">decodeURI</a>.</p>\n" |
|||
}, |
|||
"urlResolve": { |
|||
"args": [ |
|||
"base", |
|||
"href" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Take a base URL, and a href URL, and resolve them as a browser would for an anchor tag.</p>\n" |
|||
}, |
|||
"urlParse": { |
|||
"args": [ |
|||
"str" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>Parses a <code>url</code> string into an object.</p>\n" |
|||
}, |
|||
"stripQuerystring": { |
|||
"args": [ |
|||
"url" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>Strip the query string from the given <code>url</code>.</p>\n" |
|||
}, |
|||
"stripProtocol": { |
|||
"args": [ |
|||
"str" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>Strip protocol from a <code>url</code>. Useful for displaying media that may have an 'http' protocol on secure connections.</p>\n" |
|||
} |
|||
}, |
|||
"string": { |
|||
"append": { |
|||
"args": [ |
|||
"str", |
|||
"suffix" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Append the specified <code>suffix</code> to the given string.</p>\n" |
|||
}, |
|||
"camelcase": { |
|||
"args": [ |
|||
"string" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>camelCase the characters in the given <code>string</code>.</p>\n" |
|||
}, |
|||
"capitalize": { |
|||
"args": [ |
|||
"str" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>Capitalize the first word in a sentence.</p>\n" |
|||
}, |
|||
"capitalizeAll": { |
|||
"args": [ |
|||
"str" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>Capitalize all words in a string.</p>\n" |
|||
}, |
|||
"center": { |
|||
"args": [ |
|||
"str", |
|||
"spaces" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Center a string using non-breaking spaces</p>\n" |
|||
}, |
|||
"chop": { |
|||
"args": [ |
|||
"string" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>Like trim, but removes both extraneous whitespace <strong>and non-word characters</strong> from the beginning and end of a string.</p>\n" |
|||
}, |
|||
"dashcase": { |
|||
"args": [ |
|||
"string" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>dash-case the characters in <code>string</code>. Replaces non-word characters and periods with hyphens.</p>\n" |
|||
}, |
|||
"dotcase": { |
|||
"args": [ |
|||
"string" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>dot.case the characters in <code>string</code>.</p>\n" |
|||
}, |
|||
"downcase": { |
|||
"args": [ |
|||
"string" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>Lowercase all of the characters in the given string. Alias for <a href=\"#lowercase\">lowercase</a>.</p>\n" |
|||
}, |
|||
"ellipsis": { |
|||
"args": [ |
|||
"str", |
|||
"length" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Truncates a string to the specified <code>length</code>, and appends it with an elipsis, <code>…</code>.</p>\n" |
|||
}, |
|||
"hyphenate": { |
|||
"args": [ |
|||
"str" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>Replace spaces in a string with hyphens.</p>\n" |
|||
}, |
|||
"isString": { |
|||
"args": [ |
|||
"value" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>Return true if <code>value</code> is a string.</p>\n" |
|||
}, |
|||
"lowercase": { |
|||
"args": [ |
|||
"str" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>Lowercase all characters in the given string.</p>\n" |
|||
}, |
|||
"occurrences": { |
|||
"args": [ |
|||
"str", |
|||
"substring" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Return the number of occurrences of <code>substring</code> within the given <code>string</code>.</p>\n" |
|||
}, |
|||
"pascalcase": { |
|||
"args": [ |
|||
"string" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>PascalCase the characters in <code>string</code>.</p>\n" |
|||
}, |
|||
"pathcase": { |
|||
"args": [ |
|||
"string" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>path/case the characters in <code>string</code>.</p>\n" |
|||
}, |
|||
"plusify": { |
|||
"args": [ |
|||
"str" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>Replace spaces in the given string with pluses.</p>\n" |
|||
}, |
|||
"prepend": { |
|||
"args": [ |
|||
"str", |
|||
"prefix" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Prepends the given <code>string</code> with the specified <code>prefix</code>.</p>\n" |
|||
}, |
|||
"raw": { |
|||
"args": [ |
|||
"options" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>Render a block without processing mustache templates inside the block.</p>\n" |
|||
}, |
|||
"remove": { |
|||
"args": [ |
|||
"str", |
|||
"substring" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Remove all occurrences of <code>substring</code> from the given <code>str</code>.</p>\n" |
|||
}, |
|||
"removeFirst": { |
|||
"args": [ |
|||
"str", |
|||
"substring" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Remove the first occurrence of <code>substring</code> from the given <code>str</code>.</p>\n" |
|||
}, |
|||
"replace": { |
|||
"args": [ |
|||
"str", |
|||
"a", |
|||
"b" |
|||
], |
|||
"numArgs": 3, |
|||
"description": "<p>Replace all occurrences of substring <code>a</code> with substring <code>b</code>.</p>\n" |
|||
}, |
|||
"replaceFirst": { |
|||
"args": [ |
|||
"str", |
|||
"a", |
|||
"b" |
|||
], |
|||
"numArgs": 3, |
|||
"description": "<p>Replace the first occurrence of substring <code>a</code> with substring <code>b</code>.</p>\n" |
|||
}, |
|||
"sentence": { |
|||
"args": [ |
|||
"str" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>Sentence case the given string</p>\n" |
|||
}, |
|||
"snakecase": { |
|||
"args": [ |
|||
"string" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>snake_case the characters in the given <code>string</code>.</p>\n" |
|||
}, |
|||
"split": { |
|||
"args": [ |
|||
"string" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>Split <code>string</code> by the given <code>character</code>.</p>\n" |
|||
}, |
|||
"startsWith": { |
|||
"args": [ |
|||
"prefix", |
|||
"testString", |
|||
"options" |
|||
], |
|||
"numArgs": 3, |
|||
"description": "<p>Tests whether a string begins with the given prefix.</p>\n" |
|||
}, |
|||
"titleize": { |
|||
"args": [ |
|||
"str" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>Title case the given string.</p>\n" |
|||
}, |
|||
"trim": { |
|||
"args": [ |
|||
"string" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>Removes extraneous whitespace from the beginning and end of a string.</p>\n" |
|||
}, |
|||
"trimLeft": { |
|||
"args": [ |
|||
"string" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>Removes extraneous whitespace from the beginning of a string.</p>\n" |
|||
}, |
|||
"trimRight": { |
|||
"args": [ |
|||
"string" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>Removes extraneous whitespace from the end of a string.</p>\n" |
|||
}, |
|||
"truncate": { |
|||
"args": [ |
|||
"str", |
|||
"limit", |
|||
"suffix" |
|||
], |
|||
"numArgs": 3, |
|||
"description": "<p>Truncate a string to the specified <code>length</code>. Also see <a href=\"#ellipsis\">ellipsis</a>.</p>\n" |
|||
}, |
|||
"truncateWords": { |
|||
"args": [ |
|||
"str", |
|||
"limit", |
|||
"suffix" |
|||
], |
|||
"numArgs": 3, |
|||
"description": "<p>Truncate a string to have the specified number of words. Also see <a href=\"#truncate\">truncate</a>.</p>\n" |
|||
}, |
|||
"upcase": { |
|||
"args": [ |
|||
"string" |
|||
], |
|||
"numArgs": 1, |
|||
"description": "<p>Uppercase all of the characters in the given string. Alias for <a href=\"#uppercase\">uppercase</a>.</p>\n" |
|||
}, |
|||
"uppercase": { |
|||
"args": [ |
|||
"str", |
|||
"options" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Uppercase all of the characters in the given string. If used as a block helper it will uppercase the entire block. This helper does not support inverse blocks.</p>\n" |
|||
} |
|||
}, |
|||
"comparison": { |
|||
"and": { |
|||
"args": [ |
|||
"a", |
|||
"b", |
|||
"options" |
|||
], |
|||
"numArgs": 3, |
|||
"description": "<p>Helper that renders the block if <strong>both</strong> of the given values are truthy. If an inverse block is specified it will be rendered when falsy. Works as a block helper, inline helper or subexpression.</p>\n" |
|||
}, |
|||
"compare": { |
|||
"args": [ |
|||
"a", |
|||
"operator", |
|||
"b", |
|||
"options" |
|||
], |
|||
"numArgs": 4, |
|||
"description": "<p>Render a block when a comparison of the first and third arguments returns true. The second argument is the [arithemetic operator][operators] to use. You may also optionally specify an inverse block to render when falsy.</p>\n" |
|||
}, |
|||
"contains": { |
|||
"args": [ |
|||
"collection", |
|||
"value", |
|||
"[startIndex=0]", |
|||
"options" |
|||
], |
|||
"numArgs": 4, |
|||
"description": "<p>Block helper that renders the block if <code>collection</code> has the given <code>value</code>, using strict equality (<code>===</code>) for comparison, otherwise the inverse block is rendered (if specified). If a <code>startIndex</code> is specified and is negative, it is used as the offset from the end of the collection.</p>\n" |
|||
}, |
|||
"default": { |
|||
"args": [ |
|||
"value", |
|||
"defaultValue" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Returns the first value that is not undefined, otherwise the "default" value is returned.</p>\n" |
|||
}, |
|||
"eq": { |
|||
"args": [ |
|||
"a", |
|||
"b", |
|||
"options" |
|||
], |
|||
"numArgs": 3, |
|||
"description": "<p>Block helper that renders a block if <code>a</code> is <strong>equal to</strong> <code>b</code>. If an inverse block is specified it will be rendered when falsy. You may optionally use the <code>compare=""</code> hash argument for the second value.</p>\n" |
|||
}, |
|||
"gt": { |
|||
"args": [ |
|||
"a", |
|||
"b", |
|||
"options" |
|||
], |
|||
"numArgs": 3, |
|||
"description": "<p>Block helper that renders a block if <code>a</code> is <strong>greater than</strong> <code>b</code>. If an inverse block is specified it will be rendered when falsy. You may optionally use the <code>compare=""</code> hash argument for the second value.</p>\n" |
|||
}, |
|||
"gte": { |
|||
"args": [ |
|||
"a", |
|||
"b", |
|||
"options" |
|||
], |
|||
"numArgs": 3, |
|||
"description": "<p>Block helper that renders a block if <code>a</code> is <strong>greater than or equal to</strong> <code>b</code>. If an inverse block is specified it will be rendered when falsy. You may optionally use the <code>compare=""</code> hash argument for the second value.</p>\n" |
|||
}, |
|||
"has": { |
|||
"args": [ |
|||
"val", |
|||
"pattern", |
|||
"options" |
|||
], |
|||
"numArgs": 3, |
|||
"description": "<p>Block helper that renders a block if <code>value</code> has <code>pattern</code>. If an inverse block is specified it will be rendered when falsy.</p>\n" |
|||
}, |
|||
"isFalsey": { |
|||
"args": [ |
|||
"val", |
|||
"options" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Returns true if the given <code>value</code> is falsey. Uses the [falsey][] library for comparisons. Please see that library for more information or to report bugs with this helper.</p>\n" |
|||
}, |
|||
"isTruthy": { |
|||
"args": [ |
|||
"val", |
|||
"options" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Returns true if the given <code>value</code> is truthy. Uses the [falsey][] library for comparisons. Please see that library for more information or to report bugs with this helper.</p>\n" |
|||
}, |
|||
"ifEven": { |
|||
"args": [ |
|||
"number", |
|||
"options" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Return true if the given value is an even number.</p>\n" |
|||
}, |
|||
"ifNth": { |
|||
"args": [ |
|||
"a", |
|||
"b", |
|||
"options" |
|||
], |
|||
"numArgs": 3, |
|||
"description": "<p>Conditionally renders a block if the remainder is zero when <code>a</code> operand is divided by <code>b</code>. If an inverse block is specified it will be rendered when the remainder is <strong>not zero</strong>.</p>\n" |
|||
}, |
|||
"ifOdd": { |
|||
"args": [ |
|||
"value", |
|||
"options" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Block helper that renders a block if <code>value</code> is <strong>an odd number</strong>. If an inverse block is specified it will be rendered when falsy.</p>\n" |
|||
}, |
|||
"is": { |
|||
"args": [ |
|||
"a", |
|||
"b", |
|||
"options" |
|||
], |
|||
"numArgs": 3, |
|||
"description": "<p>Block helper that renders a block if <code>a</code> is <strong>equal to</strong> <code>b</code>. If an inverse block is specified it will be rendered when falsy. Similar to <a href=\"#eq\">eq</a> but does not do strict equality.</p>\n" |
|||
}, |
|||
"isnt": { |
|||
"args": [ |
|||
"a", |
|||
"b", |
|||
"options" |
|||
], |
|||
"numArgs": 3, |
|||
"description": "<p>Block helper that renders a block if <code>a</code> is <strong>not equal to</strong> <code>b</code>. If an inverse block is specified it will be rendered when falsy. Similar to <a href=\"#unlesseq\">unlessEq</a> but does not use strict equality for comparisons.</p>\n" |
|||
}, |
|||
"lt": { |
|||
"args": [ |
|||
"context", |
|||
"options" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Block helper that renders a block if <code>a</code> is <strong>less than</strong> <code>b</code>. If an inverse block is specified it will be rendered when falsy. You may optionally use the <code>compare=""</code> hash argument for the second value.</p>\n" |
|||
}, |
|||
"lte": { |
|||
"args": [ |
|||
"a", |
|||
"b", |
|||
"options" |
|||
], |
|||
"numArgs": 3, |
|||
"description": "<p>Block helper that renders a block if <code>a</code> is <strong>less than or equal to</strong> <code>b</code>. If an inverse block is specified it will be rendered when falsy. You may optionally use the <code>compare=""</code> hash argument for the second value.</p>\n" |
|||
}, |
|||
"neither": { |
|||
"args": [ |
|||
"a", |
|||
"b", |
|||
"options" |
|||
], |
|||
"numArgs": 3, |
|||
"description": "<p>Block helper that renders a block if <strong>neither of</strong> the given values are truthy. If an inverse block is specified it will be rendered when falsy.</p>\n" |
|||
}, |
|||
"not": { |
|||
"args": [ |
|||
"val", |
|||
"options" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Returns true if <code>val</code> is falsey. Works as a block or inline helper.</p>\n" |
|||
}, |
|||
"or": { |
|||
"args": [ |
|||
"arguments", |
|||
"options" |
|||
], |
|||
"numArgs": 2, |
|||
"description": "<p>Block helper that renders a block if <strong>any of</strong> the given values is truthy. If an inverse block is specified it will be rendered when falsy.</p>\n" |
|||
}, |
|||
"unlessEq": { |
|||
"args": [ |
|||
"a", |
|||
"b", |
|||
"options" |
|||
], |
|||
"numArgs": 3, |
|||
"description": "<p>Block helper that always renders the inverse block <strong>unless <code>a</code> is equal to <code>b</code></strong>.</p>\n" |
|||
}, |
|||
"unlessGt": { |
|||
"args": [ |
|||
"a", |
|||
"b", |
|||
"options" |
|||
], |
|||
"numArgs": 3, |
|||
"description": "<p>Block helper that always renders the inverse block <strong>unless <code>a</code> is greater than <code>b</code></strong>.</p>\n" |
|||
}, |
|||
"unlessLt": { |
|||
"args": [ |
|||
"a", |
|||
"b", |
|||
"options" |
|||
], |
|||
"numArgs": 3, |
|||
"description": "<p>Block helper that always renders the inverse block <strong>unless <code>a</code> is less than <code>b</code></strong>.</p>\n" |
|||
}, |
|||
"unlessGteq": { |
|||
"args": [ |
|||
"a", |
|||
"b", |
|||
"options" |
|||
], |
|||
"numArgs": 3, |
|||
"description": "<p>Block helper that always renders the inverse block <strong>unless <code>a</code> is greater than or equal to <code>b</code></strong>.</p>\n" |
|||
}, |
|||
"unlessLteq": { |
|||
"args": [ |
|||
"a", |
|||
"b", |
|||
"options" |
|||
], |
|||
"numArgs": 3, |
|||
"description": "<p>Block helper that always renders the inverse block <strong>unless <code>a</code> is less than or equal to <code>b</code></strong>.</p>\n" |
|||
} |
|||
}, |
|||
"date": { |
|||
"date": { |
|||
"args": [ |
|||
"datetime", |
|||
"format" |
|||
], |
|||
"numArgs": 2, |
|||
"example": "{{date now \"YYYY\"}}", |
|||
"description": "<p>Format a date using moment.js data formatting.</p>\n" |
|||
} |
|||
} |
|||
} |
|||
@ -1,28 +1,32 @@ |
|||
import commonjs from "rollup-plugin-commonjs" |
|||
import commonjs from "@rollup/plugin-commonjs" |
|||
import resolve from "rollup-plugin-node-resolve" |
|||
import builtins from "rollup-plugin-node-builtins" |
|||
import globals from "rollup-plugin-node-globals" |
|||
import json from "@rollup/plugin-json" |
|||
import { terser } from "rollup-plugin-terser" |
|||
|
|||
const production = !process.env.ROLLUP_WATCH |
|||
export default { |
|||
input: "src/index.js", |
|||
input: "src/esIndex.js", |
|||
output: [ |
|||
{ |
|||
sourcemap: true, |
|||
format: "umd", |
|||
format: "esm", |
|||
file: "./dist/bundle.js", |
|||
name: "string-templates", |
|||
name: "templates", |
|||
exports: "named", |
|||
}, |
|||
], |
|||
plugins: [ |
|||
resolve({ |
|||
mainFields: ["module", "main"], |
|||
preferBuiltins: true, |
|||
browser: true, |
|||
}), |
|||
commonjs(), |
|||
globals(), |
|||
builtins(), |
|||
production && terser(), |
|||
json(), |
|||
], |
|||
} |
|||
|
|||
@ -0,0 +1,155 @@ |
|||
const HELPER_LIBRARY = "@budibase/handlebars-helpers" |
|||
const helpers = require(HELPER_LIBRARY) |
|||
const { HelperFunctionBuiltin } = require("../src/helpers/constants") |
|||
const fs = require("fs") |
|||
const doctrine = require("doctrine") |
|||
const marked = require("marked") |
|||
|
|||
const DIRECTORY = fs.existsSync("node_modules") ? "." : ".." |
|||
|
|||
const FILENAME = `${DIRECTORY}/manifest.json` |
|||
|
|||
/** |
|||
* full list of supported helpers can be found here: |
|||
* https://github.com/helpers/handlebars-helpers
|
|||
*/ |
|||
|
|||
const COLLECTIONS = ["math", "array", "number", "url", "string", "comparison"] |
|||
|
|||
const outputJSON = {} |
|||
|
|||
function fixSpecialCases(name, obj) { |
|||
const args = obj.args |
|||
if (name === "ifNth") { |
|||
args[0] = "a" |
|||
args[1] = "b" |
|||
} |
|||
if (name === "eachIndex") { |
|||
obj.description = "Iterates the array, listing an item and the index of it." |
|||
} |
|||
if (name === "toFloat") { |
|||
obj.description = "Convert input to a float." |
|||
} |
|||
if (name === "toInt") { |
|||
obj.description = "Convert input to an integer." |
|||
} |
|||
return obj |
|||
} |
|||
|
|||
function lookForward(lines, funcLines, idx) { |
|||
const funcLen = funcLines.length |
|||
for (let i = idx, j = 0; i < idx + funcLen; ++i, j++) { |
|||
if (!lines[i].includes(funcLines[j])) { |
|||
return false |
|||
} |
|||
} |
|||
return true |
|||
} |
|||
|
|||
function getCommentInfo(file, func) { |
|||
const lines = file.split("\n") |
|||
const funcLines = func.split("\n") |
|||
let comment = null |
|||
for (let idx = 0; idx < lines.length; ++idx) { |
|||
// from here work back until we have the comment
|
|||
if (lookForward(lines, funcLines, idx)) { |
|||
let fromIdx = idx |
|||
let start = 0, |
|||
end = 0 |
|||
do { |
|||
if (lines[fromIdx].includes("*/")) { |
|||
end = fromIdx |
|||
} else if (lines[fromIdx].includes("/*")) { |
|||
start = fromIdx |
|||
} |
|||
if (start && end) { |
|||
break |
|||
} |
|||
fromIdx-- |
|||
} while (fromIdx > 0) |
|||
comment = lines.slice(start, end + 1).join("\n") |
|||
} |
|||
} |
|||
if (comment == null) { |
|||
return { description: "" } |
|||
} |
|||
const docs = doctrine.parse(comment, { unwrap: true }) |
|||
// some hacky fixes
|
|||
docs.description = docs.description.replace(/\n/g, " ") |
|||
docs.description = docs.description.replace(/[ ]{2,}/g, " ") |
|||
docs.description = docs.description.replace(/is is/g, "is") |
|||
const examples = docs.tags |
|||
.filter(el => el.title === "example") |
|||
.map(el => el.description) |
|||
const blocks = docs.description.split("```") |
|||
if (examples.length > 0) { |
|||
docs.example = examples.join(" ") |
|||
} |
|||
docs.description = blocks[0].trim() |
|||
return docs |
|||
} |
|||
|
|||
/** |
|||
* This script is very specific to purpose, parsing the handlebars-helpers files to attempt to get information about them. |
|||
*/ |
|||
function run() { |
|||
const foundNames = [] |
|||
for (let collection of COLLECTIONS) { |
|||
const collectionFile = fs.readFileSync( |
|||
`${DIRECTORY}/node_modules/${HELPER_LIBRARY}/lib/${collection}.js`, |
|||
"utf8" |
|||
) |
|||
const collectionInfo = {} |
|||
// collect information about helper
|
|||
let hbsHelperInfo = helpers[collection]() |
|||
for (let entry of Object.entries(hbsHelperInfo)) { |
|||
const name = entry[0] |
|||
// skip built in functions and ones seen already
|
|||
if ( |
|||
HelperFunctionBuiltin.indexOf(name) !== -1 || |
|||
foundNames.indexOf(name) !== -1 |
|||
) { |
|||
continue |
|||
} |
|||
foundNames.push(name) |
|||
// this is ridiculous, but it parse the function header
|
|||
const fnc = entry[1].toString() |
|||
const jsDocInfo = getCommentInfo(collectionFile, fnc) |
|||
let args = jsDocInfo.tags |
|||
.filter(tag => tag.title === "param") |
|||
.map( |
|||
tag => |
|||
tag.description && |
|||
tag.description |
|||
.replace(/`/g, "") |
|||
.split(" ")[0] |
|||
.trim() |
|||
) |
|||
collectionInfo[name] = fixSpecialCases(name, { |
|||
args, |
|||
numArgs: args.length, |
|||
example: jsDocInfo.example || undefined, |
|||
description: jsDocInfo.description, |
|||
}) |
|||
} |
|||
outputJSON[collection] = collectionInfo |
|||
} |
|||
// add the date helper
|
|||
outputJSON["date"] = { |
|||
date: { |
|||
args: ["datetime", "format"], |
|||
numArgs: 2, |
|||
example: '{{date now "YYYY"}}', |
|||
description: "Format a date using moment.js data formatting.", |
|||
}, |
|||
} |
|||
// convert all markdown to HTML
|
|||
for (let collection of Object.values(outputJSON)) { |
|||
for (let helper of Object.values(collection)) { |
|||
helper.description = marked(helper.description) |
|||
} |
|||
} |
|||
fs.writeFileSync(FILENAME, JSON.stringify(outputJSON, null, 2)) |
|||
} |
|||
|
|||
run() |
|||
@ -0,0 +1,12 @@ |
|||
import templates from "./index" |
|||
|
|||
/** |
|||
* This file is simply an entrypoint for rollup - makes a lot of cjs problems go away |
|||
*/ |
|||
export const isValid = templates.isValid |
|||
export const makePropSafe = templates.makePropSafe |
|||
export const getManifest = templates.getManifest |
|||
export const processStringSync = templates.processStringSync |
|||
export const processObjectSync = templates.processObjectSync |
|||
export const processString = templates.processString |
|||
export const processObject = templates.processObject |
|||
@ -1,9 +1,43 @@ |
|||
const { LITERAL_MARKER } = require("../helpers/constants") |
|||
|
|||
const PostProcessorNames = { |
|||
CONVERT_LITERALS: "convert-literals", |
|||
} |
|||
|
|||
/* eslint-disable no-unused-vars */ |
|||
class Postprocessor { |
|||
constructor(name, fn) { |
|||
this.name = name |
|||
this.fn = fn |
|||
} |
|||
|
|||
process(statement) { |
|||
return this.fn(statement) |
|||
} |
|||
} |
|||
|
|||
module.exports.processors = [] |
|||
module.exports.processors = [ |
|||
new Postprocessor(PostProcessorNames.CONVERT_LITERALS, statement => { |
|||
if (!statement.includes(LITERAL_MARKER)) { |
|||
return statement |
|||
} |
|||
|
|||
const components = statement.split("-") |
|||
// pop and shift remove the empty array elements from the first and last dash
|
|||
components.pop() |
|||
components.shift() |
|||
const type = components[1] |
|||
const value = components[2] |
|||
switch (type) { |
|||
case "string": |
|||
return value |
|||
case "number": |
|||
return parseFloat(value) |
|||
case "boolean": |
|||
return value === "true" |
|||
case "object": |
|||
return JSON.parse(value) |
|||
} |
|||
return value |
|||
}), |
|||
] |
|||
|
|||
Loading…
Reference in new issue