npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

solid-mustache

v4.5.0

Published

{{mustache}} templates compiling to Solidity

Downloads

19

Readme

Solid Mustache

{{mustache}} templates compiling to Solidity

Content type agnostic

Mustache templates are agnostic to the content type of the template document, meaning you can use solid-mustache to generate templates for a wide variety of use cases.

Logic-less

The expressiveness of the template syntax is deliberately limited, forcing you to put logic elsewhere and promoting separation of concerns.

Automatic and manual type narrowing

Since Solidity is statically typed, the input values for the template need type definitions. solid-mustache automatically derives types for template inputs, so you don't have to worry about this aspect. However, it also supports optional annotations in template expressions for using more gas efficient fixed length types. Learn more about it in section "Input data types".

How to use

Installation

Add solid-mustache as a dev dependency. With npm:

npm install --save-dev solid-mustache

Or with yarn:

yarn add -D solid-mustache

Compile template file

To compile a template file to Solidity, run:

npm run solid-mustache ./path/to/template.hbs

The compiled template library will be written to ./path/to/template.sol.

Writing templates

Template expressions

solid-mustache uses the mustache syntax of double curly braces for template expressions:

Hello {{firstName}} {{lastName}}!

This template compiles to a library with a render function taking an input argument of the following type:

struct __Input {
  string firstName;
  string lastName;
}

Template expressions can also contain path expressions, like:

{{planets[i].name}}

Warning: Contrarily to handlebars.js, interpolations won't be escaped automatically in solid-mustache. If necessary, this must be taken care of before passing the interpolation values to the template's render function.

Conditionals

For conditional rendering use if block expressions:

{{#if active}}
  ON
{{/if}}

For the parameter following #if any kind of path to a boolean value may be used, but boolean expressions are not supported. You can however realize else constructs using the negated #unless block expression:

{{#unless active}}
  OFF
{{/unless}}

Iterators

The #each block expressions allows you to iterate array type inputs, rendering a block of content repeatedly for each item:

{{#each planets}}
  {{name}}
{{/each}}

Note that using an #each block spawns a new context for its content block. Any path expression within the content block is evaluated relative to the current item of the iteratee. So in the example above {{name}} is evaluated as planets[index].name.

Input data types

The compiler auto-generates a struct type for the input data argument to the template's render function. It uses some heuristics for choosing appropriate types for struct fields:

| condition | example | type chosen | | :------------------------------------- | :---------------- | :------------------------------------------------------------------------- | | simple output | {{title}} | string title; | | reference to field in path expression | {{person.name}} | Person person; creates new struct: struct Person { string name; } | | reference via index in path expression | {{items[0]}} | string[] items; | | iterator | {{#each items}} | string[] items; | | conditional | {{#if active}} | bool active; |

For gas cost reasons it might be preferable to use fixed length types when possible. This can be achieved by using built-in helper syntax:

| condition | example | type chosen | | :------------------------------ | :------------------------- | :----------------- | | iterator with length hash arg | {{#each items length=4}} | string[4] title; | | bytes<N> helper | {{bytes8 title}} | bytes8 title; |

Templates also support integer to string conversion, so that input fields can be marked as uint/int:

| condition | example | type chosen | | :--------------- | :----------------- | :-------------- | | uint<N> helper | {{uint number}} | uint number; | | int<N> helper | {{int16 number}} | int16 number; |

The integer to string conversion even allows printing integers with a fixed number of decimal places, for example:

| expression | myNumber value | printed result | | :------------------------------ | :--------------- | :------------- | | {{uint8 myNumber decimals=2}} | 123 | 1.23 | | {{int16 myNumber decimals=3}} | -9 | -0.009 |

Partials

Partials allow reusing templates from other templates. Any normal template can be used as a partial. In order to make it available, a partial must be registered under a name using the partials option when compiling.

You can then call the partial through the partial call syntax:

{{> myPartial}}

It's possible to execute partials on a custom context by passing a path expression to the partial call:

{{> myPartial myStructField}}

Partials are useful for splitting large templates into multiple Solidity libraries to keep each one of them within the EVM contract size limit. This is achieved using the extra hash param, specifiying the name for the extra library to split out for the partial:

{{> myPartial extra="MyPartial" }}

Configuration

solid-mustache uses cosmiconfig for configuration file support. This means you can configure it using any of the following ways:

  • A "solid-mustache" key in your package.json
  • A .solid-mustacherc file in JSON format.
  • A .solid-mustacherc.json file.
  • A .solid-mustacherc.js, .solid-mustacherc.cjs, solid-mustache.config.js, or solid-mustache.config.cjs file that exports an object using module.exports.

The configuration file will be resolved starting from the location of the template file and searching up the file tree until a config file is found.

All configuration options can also be specified as CLI arguments. CLI arguments override values from configuration files. Config files are not read if using solid-mustache via the JavaScript API.

Options

Name

Specify the name of the generated Solidity library or template.

| Default | Config field | CLI Override | | ------------ | ---------------- | ----------------- | | "Template" | name: <string> | --name <string> |

Solidity pragma

Define the Solidity pragma for the compiled .sol file.

| Default | Config field | CLI Override | | ----------- | -------------------------- | ---------------------------- | | "^0.8.6"" | solidityPragma: <string> | --solidity-pragma <string> |

Header

Define a custom header for the .sol file.

| Default | Config field | CLI Override | | ------------------------------------------- | ------------------ | ------------------- | | "// SPDX-License-Identifier: UNLICENSED"" | header: <string> | --header <string> |

Condense whitespace

Condense sequences of consecutive whitespace characters into a single space character.

| Default | Config field | CLI Override | | ------- | ---------------------------- | ------------ | | false | condenseWhitespace: <bool> | --condense |

Partials

Register partials.

When using the CLI, partials are specified as paths to the partial template files. The partials are registered under their respective file names (without extension). By default, a glob pattern is used based on the dirname of the template file and the filename pattern **.partial.hbs.

When using the API, partials are specified as an object, where keys are the partial names and values are the partial template strings.

| Default | Config field | CLI Override | | ------- | ----------------------------------------- | ------------------- | | | partials: { <name0>: <template0>, ... } | --partials <glob> |

Deduplication

Extract duplicate template substrings longer than the specified threshold into constants to potentially reduce the bytecode size.

| Default | Config field | CLI Override | | ------- | ------------------------ | -------------------------- | | | dedupeThreshold: <int> | --dedupe-threshold <int> |

Print Width

Specify the line length that the printer will wrap on.

| Default | Config field | CLI Override | | ------- | ------------------- | --------------------- | | 80 | printWidth: <int> | --print-width <int> |

Tab Width

Specify the number of spaces per indentation-level.

| Default | Config field | CLI Override | | ------- | ----------------- | ------------------- | | 2 | tabWidth: <int> | --tab-width <int> |

Tabs

Indent lines with tabs instead of spaces.

| Default | Config field | CLI Override | | ------- | ----------------- | ------------ | | false | useTabs: <bool> | --use-tabs |

Quotes

Use single quotes instead of double quotes.

| Default | Config field | CLI Override | | ------- | --------------------- | ---------------- | | false | singleQuote: <bool> | --single-quote |

Bracket Spacing

Print spaces between brackets.

| Default | Config field | CLI Override | | ------- | ------------------------ | ---------------------- | | true | bracketSpacing: <bool> | --no-bracket-spacing |

Explicit Types

Use explicit types (uint256) rather than aliases (uint).

| Default | Config field | CLI Override | | ------- | ----------------------- | --------------------- | | true | explicitTypes: <bool> | --no-explicit-types |

API

CLI

solid-mustache <template_file> [options]

The compiled .sol file will be written to the directory containing the template file. By default it will use the template's filename, but with a .sol extension.

For writing to a different path, use the --output <path> option.

Additionally, all general options can be specified.

JavaScript

compile(template: string, options?: Options): string

The first argument (template) is the template string to compile.

The optional second argument allows customizing the compile options.

Contribute

This package aims to be compatible with handlebars. Specifically, every template that can be compiled with solid-mustache shall also be supported in handlebars. The inverse is not necessary, but we aim for it as far as it's reasonable. If you see unexpected rendering results for your templates, submit an issue or, even better, create a PR adding your template as new test case in test/cases.

How test cases are structured

Each test case is represented by a folder, the folder name is the test case name. In the folder there is a single template file. The file name must start with template and end with .hbs, e.g.: template.svg.hbs.

The folder also contains one or more json files with different test inputs. These json files must be named with incrementing index starting at 0: 0.json, 1.json, 2.json, ...

When running the tests, the template will be rendered for each input json and the result snapshot is written to a new file in that same folder. For example, the template.svg.hbs with input 0.json is written to 0.svg.

To update result snapshots, run yarn test:update.