{"id":17715671,"url":"https://github.com/jmjuanes/mikel","last_synced_at":"2026-02-19T01:02:44.276Z","repository":{"id":229048695,"uuid":"618117474","full_name":"jmjuanes/mikel","owner":"jmjuanes","description":":hamster: Micro templating library with zero dependencies","archived":false,"fork":false,"pushed_at":"2024-09-11T19:01:22.000Z","size":80,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-09-15T10:27:44.523Z","etag":null,"topics":["templates","templating","templating-engine"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jmjuanes.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-03-23T19:39:45.000Z","updated_at":"2024-09-11T19:01:10.000Z","dependencies_parsed_at":"2024-04-08T17:48:07.996Z","dependency_job_id":"f9fd40d1-5cb7-404a-8e50-25cd2bd9f2f7","html_url":"https://github.com/jmjuanes/mikel","commit_stats":null,"previous_names":["jmjuanes/mikel"],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jmjuanes%2Fmikel","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jmjuanes%2Fmikel/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jmjuanes%2Fmikel/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jmjuanes%2Fmikel/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jmjuanes","download_url":"https://codeload.github.com/jmjuanes/mikel/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223849431,"owners_count":17213640,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["templates","templating","templating-engine"],"created_at":"2024-10-25T12:06:41.471Z","updated_at":"2026-02-19T01:02:44.257Z","avatar_url":"https://github.com/jmjuanes.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Mikel\n\n![npm version](https://badgen.net/npm/v/mikel?labelColor=1d2734\u0026color=21bf81)\n![license](https://badgen.net/github/license/jmjuanes/mikel?labelColor=1d2734\u0026color=21bf81)\n\nMikel is a lightweight templating library based on the [Mustache](https://mustache.github.io) syntax, designed to be concise and easy to use. It provides a simple way to render templates using data objects, supporting features such as variables, partials, conditional sections, and looping. With a focus on simplicity and minimalism, Mikel offers a tiny yet powerful solution for generating dynamic content in JavaScript applications.\n\n## Installation\n\nYou can install Mikel via npm or yarn:\n\n```bash\n## Install using npm\n$ npm install mikel\n\n## Install using yarn\n$ yarn add mikel\n```\n\n## Syntax\n\nMikel supports the following syntax for rendering templates:\n\n### Variables\n\nUse double curly braces `{{ }}` to insert variables into your template. Variables will be replaced with the corresponding values from the data object.\n\n#### Fallback values\n\n\u003e Added in `v0.14.0`.\n\nYou can specify a value as a fallback, using the double OR `||` operator and followed by the fallback value.\n\n```javascript\nconst result = m(`Hello {{name || \"World\"}}!`, {});\n// Output: 'Hello World!'\n```\n\n### Comments\n\n\u003e This feature was added in `v0.27.0`.\n\nAny content between `{{!--` and `--}}` will be completely ignored during template rendering. Comments can span multiple lines and are not included in the output or parsed AST.\n\n```\n{{!-- This is a comment --}}\n```\n\n\u003e **Note**: Nested comments are not supported. The first closing `--}}` encountered will terminate the comment block.\n\n### Sections\n\nSections allow for conditional rendering of blocks of content based on the presence or absence of a value in the data object. Use the pound symbol `#` to start a section and the caret `^` to denote an inverted section. End the section with a forward slash `/`.\n\nExample:\n\n```javascript\nconst data = {\n    isAdmin: true,\n};\nconst result = m(\"{{#isAdmin}}You are Admin{{/isAdmin}}\", data);\n// Output: 'You are Admin'\n```\n\nYou can also use sections for looping over arrays. When looping over array of strings, you can use a dot `.` or the `this` word to reference the current item in the loop.\n\nExample:\n\n```javascript\nconst data = {\n    users: [\n        { name: \"John\" },\n        { name: \"Alice\" },\n        { name: \"Bob\" }\n    ],\n};\n\nconst result = m(\"Users:{{# users }} {{ name }},{{/ users }}\", data);\n// Output: 'Users: John, Alice, Bob,'\n```\n\nInverted sections render their block of content if the value is falsy or the key does not exist in the data object.\n\nExample:\n\n```javascript\nconst data = {\n    isAdmin: false,\n};\nconst result = m(\"{{^isAdmin}}You are not Admin{{/isAdmin}}\", data);\n// Output: 'You are not Admin'\n```\n\n### Partials \n\n\u003e This feature was added in `v0.3.0`\n\nPartials allow you to include separate templates within your main template. Use the greater than symbol `\u003e` followed by the partial name inside double curly braces `{{\u003e partialName }}`.\n\nExample:\n\n```javascript\nconst data = {\n    name: \"Bob\",\n};\n\nconst partials = {\n    hello: \"Hello {{name}}!\",\n};\n\nconst result = m(\"{{\u003e hello}}\", data, {partials});\n// Output: 'Hello Bob!'\n```\n\n#### Custom context in partials\n\n\u003e This feature was added in `v0.3.1`.\n\nYou can provide a custom context for the partial by specifying a field of the data: `{{\u003e partialName dataField}}`.\n\n```javascript\nconst data = {\n    currentUser: {\n        name: \"John Doe\",\n        email: \"john@example.com\",\n    },\n};\nconst partials = {\n    user: \"{{name}} \u003c{{email}}\u003e\",\n};\n\nconst result = m(\"User: {{\u003e user currentUser}}\", data, {partials});\n// Output: 'User: John Doe \u003cjohn@example.com\u003e'\n```\n\n#### Keyword arguments in partials\n\n\u003e This feature was added in `v0.13.0`.\n\nYou can provide keyword arguments in partials to generate a new context object using the provided keywords.\n\n```javascript\nconst data = {\n    name: \"John Doe\",\n    email: \"john@example.com\",\n};\nconst partials = {\n    user: \"{{userName}} \u003c{{userEmail}}\u003e\",\n};\n\nconst result = m(\"User: {{\u003euser userName=name userEmail=email }}\", data, {partials});\n// Output: 'User: John Doe \u003cjohn@example.com\u003e'\n```\n\nPlease note that providing keyword arguments and a custom context to a partial is not supported. On this situation, the partial will be evaluated only with the custom context.\n\n#### Expand partial arguments using the spread operator\n\n\u003e This feature was added in `v0.20.0`.\n\nYou can use the spread operator `...` to expand the keyword arguments of a partial. This allows you to pass an object as individual keyword arguments to the partial.\n\nExample:\n\n```javascript\nconst data = {\n    user: {\n        name: \"John Doe\",\n        email: \"john@example.com\",\n    },\n};\nconst partials = {\n    user: \"{{userName}} \u003c{{userEmail}}\u003e\",\n};\n\nconst result = m(\"User: {{\u003euser ...user}}\", data, {partials});\nconsole.log(result); // --\u003e 'User: John Doe \u003cjohn@example.com\u003e'\n```\n\n#### Partial blocks\n\n\u003e This feature was added in `v0.16.0`.\n\nYou can pass a block to a partial using a double greather than symbol `\u003e\u003e` followed by the partial name to start the partial block, and a slash followed by the partial name to end the partial block. The provided block content will be available in the `@content` variable.\n\nExample:\n\n```javascript\nconst options = {\n    partials: {\n        foo: \"Hello {{@content}}!\",\n    },\n};\n\nconst result = m(\"{{\u003e\u003efoo}}Bob{{/foo}}\", {}, options);\n// Output: 'Hello Bob!'\n```\n\n#### Partials data\n\n\u003e This feature was added in `v0.18.0`.\n\nPartials allows you to define custom data. Instead of providing a string with the partial content, you can provide an object with the following keys:\n\n- `body`: a string with the partial content.\n- `data`: an object with your custom data for the partial. You can also use `attributes` as an alias.\n\nCustom data will be available in the partial content in the `@partial.attributes` variable.\n\nExample:\n\n```javascript\nconst options = {\n    partials: {\n        foo: {\n            body: \"Hello {{@partial.attributes.name}}!\",\n            data: {\n                name: \"Bob\",\n            },\n        },\n    },\n};\n\nconst result = m(\"{{\u003efoo}}\", {}, options);\n// Output: 'Hello Bob!'\n```\n\n#### Accessing to partial metadata using the `@partial` variable\n\n\u003e Added in `v0.28.0`.\n\nPartial metadata can be accessed using the `@partial` variable inside the partial. It contains the following fields:\n\n- `@partial.name`: the name of the partial being rendered.\n- `@partial.args`: an array containing the positional arguments provided to the partial (if any).\n- `@partial.options`: an object containing the keyword arguments provided to the partial (if any).\n- `@partial.attributes`: the custom data provided to the partial (if any).\n- `@partial.context`: the current rendering context.\n\n### Inline partials\n\n\u003e Added in `v0.28.0`.\n\nInline partials allows you to define partials directly in your template. Use `\u003e*` followed by the partial name to start the partial definition, and end the partial definition with a slash `/` followed by the partial name. For example, `{{\u003e*foo}}` begins a partial definition called `foo`, and `{{/foo}}` ends it.\n\nExample:\n\n```javascript\nconst result = m(`{{\u003e*foo}}Hello {{name}}!{{/foo}}{{\u003efoo name=\"Bob\"}}`, {});\n// Output: 'Hello Bob!'\n```\n\n### Helpers\n\n\u003e Added in `v0.4.0`.\n\nHelpers allows you to execute special functions within blocks or sections of your template. Mikel currently supports the following built-in helpers:\n\n#### each\n\nThe `each` helper iterates over an array and renders the block for each item in the array.\n\nSyntax: `{{#each arrayName}} ... {{/each}}`.\n\nExample:\n\n```javascript\nconst data = {\n    users: [\"John\", \"Alice\", \"Bob\"],\n};\n\nconsole.log(m(\"{{#each users}}{{this}}, {{/each}}\", data)); // --\u003e 'John, Alice, Bob, '\n```\n\nWhen looping throug arrays, you can use the variable `@index` to access to the current index of the item in the array:\n\n```javascript\nconst data = {\n    users: [\"John\", \"Alice\", \"Bob\"],\n};\n\nconsole.log(m(\"{{#each users}}{{@index}}: {{this}}, {{/each}}\", data)); // --\u003e '0: John, 1: Alice, 2: Bob, '\n```\n\nThe `each` helper can also iterate over objects:\n\n```javascript\nconst data = {\n    values: {\n        foo: \"bar\",\n    },\n};\n\nconsole.log(m(\"{{#each values}}{{this}}{{/each}}\", data)); // --\u003e 'bar'\n```\n\nWhen looping throug objects, you can use the variable `@key` to access to the current key in the object, and the variable `@value` to access to the corresponding value:\n\n```javascript\nconst data = {\n    values: {\n        foo: \"0\",\n        bar: \"1\",\n    },\n};\n\nconsole.log(m(\"{{#each values}}{{@key}}: {{@value}}, {{/each}}\", data)); // --\u003e 'foo: 0, bar: 1, '\n```\n\nThe `each` helper also supports the following options, provided as keyword arguments:\n- `skip`: number of first items to skip (default is `0`).\n- `limit`: allows to limit the number of items to display (default equals to the length of the items list).\n\nExample:\n\n```javascript\nconsole.log(m(\"{{each values limit=2}}{{this}}{{/each}}\", {values: [0, 1, 2, 3]})); // --\u003e '01'\n```\n\n\n#### if\n\nThe `if` helper renders the block only if the condition is truthy.\n\nSyntax: `{{#if condition}} ... {{/if}}`\n\nExample:\n\n```javascript\nconst data = {\n    isAdmin: true,\n};\n\nconsole.log(m(\"{{#if isAdmin}}Hello admin{{/if}}\", data)); // --\u003e 'Hello admin'\n```\n\n#### unless\n\nThe `unless` helper renders the block only if the condition is falsy.\n\nSyntax: `{{#unless condition}} ... {{/unless}}`\n\nExample:\n\n```javascript\nconst data = {\n    isAdmin: false,\n};\n\nconsole.log(m(\"{{#unless isAdmin}}Hello guest{{/unless}}\", data)); // --\u003e 'Hello guest'\n```\n\n#### eq\n\n\u003e Added in `v0.9.0`.\n\nThe `eq` helper renders the blocks only if the two values provided as argument are equal. Example:\n\n```javascript\nconsole.log(m(`{{#eq name \"bob\"}}Hello bob{{/eq}}`, {name: \"bob\"})); // --\u003e 'Hello bob'\n```\n\n#### ne\n\n\u003e Added in `v0.9.0`.\n\nThe `ne` helper renders the block only if the two values provided as argument are not equal. Example:\n\n```javascript\nconsole.log(m(`{{#ne name \"bob\"}}Not bob{{/ne}}`, {name: \"John\"})); // --\u003e 'Not bob'\n```\n\n#### with\n\n\u003e Added in `v0.10.0`.\n\nThe `with` helper allows to change the data context of the block.\n\n```javascript\nconst data = {\n    autor: {\n        name: \"Bob\",\n        email: \"bob@email.com\",\n    },\n};\n\nconsole.log(m(\"{{#with autor}}{{name}} \u003c{{email}}\u003e{{/with}}\", data)); // --\u003e 'Bob \u003cbob@email.com\u003e'\n```\n\n#### escape\n\n\u003e Added in `v0.17.0`.\n\nThe `escape` helper allows to escape the provided block content.\n\n```javascript\nconsole.log(m(\"{{#escape}}\u003cb\u003eHello World!\u003c/b\u003e{{/escape}}\")); // --\u003e '\u0026lt;b\u0026gt;Hello World!\u0026lt;/b\u0026gt;\n```\n\n#### raw\n\n\u003e Added in `v0.23.0`.\n\nThe `raw` helper allows to render the content of the block without evaluating it. All the stuff inside the block will be rendered as is, without processing any variables or helpers.\n\n```javascript\nconsole.log(m(\"{{#raw}}Hello {{name}}!{{/raw}}\", {name: \"Bob\"})); // --\u003e 'Hello {{name}}!'\n```\n\n#### slot\n\n\u003e Added in `v0.33.0`.\n\nThe `slot` helper allows you to capture a block of template content and store it under a named key. Captured slots become available through the special `@slot` state variable.\n    \n```javascript\nconst template = `\n{{#slot \"name\"}}Bob{{/slot}}\n\nHello {{@slot.name}}!\n`;\n\nconsole.log(m(template, {})); // --\u003e 'Hello Bob!'\n```\n\nSlots are evaluated at render time, so they can contain variables, helpers, or any other template expressions. If the same slot name is defined more than once, **the last definition wins**.\n\n#### macro\n\n\u003e Added in `v0.33.0`.\n\nThe `macro` allows you to define partials directly in your template. Use `#macro` followed by the name to assign to the new partial to start the partial definition.\n\nExample:\n\n```javascript\nconst template = `\n{{#macro \"foo\"}}\nHello {{name}}!\n{{/macro}}\n\n{{\u003efoo name=\"Bob\"}}\n`;\n\nconsole.log(m(template, {})); // --\u003e 'Hello Bob!'\n```\n\n### Custom Helpers\n\n\u003e Added in `v0.5.0`.\n\u003e Breaking change introduced in `v0.12.0`.\n\nCustom helpers should be provided as an object in the `options.helpers` field, where each key represents the name of the helper and the corresponding value is a function defining the helper's behavior.\n\nExample:\n\n```javascript\nconst template = \"{{#greeting name}}{{/greeting}}\";\nconst data = {\n    name: \"World!\",\n};\nconst options = {\n    helpers: {\n        customHelper: params =\u003e {\n            return `Hello, ${params.args[0]}!`;\n        },\n    },\n};\n\nconst result = m(template, data, options);\nconsole.log(result); // Output: \"Hello, World!\"\n```\n\nCustom helper functions receive a single `params` object as argument, containing the following fields:\n\n- `args`: an array containing the variables with the helper is called in the template.\n- `options`: an object containing the keyword arguments provided to the helper.\n- `data`: the current data where the helper has been executed.\n- `state`: an object containing the state variables available in the current context (e.g., `@root`, `@index`, etc.).\n- `fn`: a function that executes the template provided in the helper block and returns a string with the evaluated template in the provided context.\n\nThe helper function must return a string, which will be injected into the result string. Example:\n\n```javascript\nconst data = {\n    items: [\n        { name: \"John\" },\n        { name: \"Alice\" },\n        { name: \"Bob\" },\n    ],\n};\nconst options = {\n    helpers: {\n        customEach: ({args, fn}) =\u003e {\n            return args[0].map((item, index) =\u003e fn({ ...item, index: index})).join(\"\");\n        },\n    },\n};\n\nconst result = m(\"{{#customEach items}}{{index}}: {{name}}, {{/customEach}}\", data, options);\nconsole.log(result); // --\u003e \"0: John, 1: Alice, 2: Bob,\"\n```\n\n#### Expand helper arguments using the spread operator\n\n\u003e This feature was added in `v0.20.0`.\n\nYou can use the spread operator `...` to expand the arguments of a helper. This allows you to pass an array of values as individual arguments to the helper, or to pass an object as keyword arguments.\n\nExample:\n\n```javascript\nconst data = {\n    items: [\"John\", \"Alice\", \"Bob\"],\n    options: {\n        separator: \", \",\n    },\n};\nconst options = {\n    helpers: {\n        join: params =\u003e {\n            return params.args.join(params.opt.separator);\n        }\n    },\n};\n\nconst result = m(\"{{#join ...items ...options}}{{/join}}\", data, options);\nconsole.log(result); // --\u003e \"John, Alice, Bob\"\n```\n\n#### Accessing to helper metadata using the `@helper` variable\n\n\u003e Introduced in `v0.28.0`.\n\nInside any helper block, you can access metadata about the current invocation through the `@helper` variable. It exposes the following fields:\n\n- `@helper.name`: the name of the helper being invoked.\n- `@helper.args`: an array of positional arguments passed to the helper.\n- `@helper.options`: an object containing named (key-value) arguments.\n- `@helper.context`: the current rendering context.\n\n### State Variables\n\n\u003e Added in `v0.4.0`.\n\nState Variables in Mikel provide convenient access to special values within your templates. These variables, denoted by the `@` symbol, allow users to interact with specific data contexts or values at runtime. State variables are usually generated by helpers like `#each`.\n\n#### @root\n\nThe `@root` variable grants access to the root data context provided to the template. It is always defined and enables users to retrieve values from the top-level data object.\n\nExample:\n\n```javascript\nconst data = {\n    name: \"World\",\n};\n\nconsole.log(m(\"Hello, {{@root.name}}!\", data)); // -\u003e 'Hello, World!'\n```\n\n#### @index\n\nThe `@index` variable facilitates access to the current index of the item when iterating over an array using the `#each` helper. It aids in dynamic rendering and indexing within loops.\n\n#### @key\n\nThe `@key` variable allows users to retrieve the current key of the object entry when looping through an object using the `#each` helper. It provides access to object keys for dynamic rendering and customization.\n\n#### @value\n\nThe `@value` variable allows users to retrieve the current value of the object entry when iterating over an object using the `#each` helper. It simplifies access to object values for dynamic rendering and data manipulation.\n\n#### @first\n\n\u003e Added in `v0.7.0`.\n\nThe `@first` variable allows to check if the current iteration using the `#each` helper is the first item in the array or object.\n\n```\n{{#each items}} {{.}}: {{#if @first}}first item!{{/if}}{{#unless @first}}not first{{/if}} {{/each}}\n```\n\n#### @last\n\n\u003e Added in `v0.7.0`.\n\nThe `@last` variable allows to check if the current iteration using the `#each` helper is the last item in the array or object.\n\n```\n{{#each items}}{{@index}}:{{.}} {{#unless @last}},{{/unless}}{{/each}}\n```\n\n### Functions\n\n\u003e Added in `v0.8.0`.\n\u003e Breaking change introduced in `v0.12.0`.\n\nMikel allows users to define custom functions that can be used within templates to perform dynamic operations. Functions can be invoked in the template using the `=` character, followed by the function name and the variables to be provided to the function. Variables should be separated by spaces.\n\nFunctions should be provided in the `options.functions` field of the options object when rendering a template. Each function is defined by a name and a corresponding function that performs the desired operation.\n\nFunctions will receive a single `params` object as argument, containing the following keys:\n\n- `args`: an array containing the variables with the function is called in the template.\n- `options`: an object containing the keyword arguments provided to the function.\n- `data`: the current data object where the function has been executed.\n- `state`: an object containing the state variables available in the current context (e.g., `@root`, `@index`, etc.).\n\nExample:\n\n```javascript\nconst data = {\n    user: {\n        firstName: \"John\",\n        lastName: \"Doe\",\n    },\n};\nconst options = {\n    functions: {\n        fullName: ({args}) =\u003e {\n            return `${args[0]} ${args[1]}`;\n        }\n    },\n};\n\nconst result = m(\"My name is: {{=fullName user.firstName user.lastName}}\", data, options);\nconsole.log(result); // --\u003e \"My name is: John Doe\"\n```\n\n#### Expand function arguments using the spread operator\n\n\u003e This feature was added in `v0.20.0`.\n\nYou can use the spread operator `...` to expand the arguments of a function. This allows you to pass an array of values as individual arguments to the function, or to pass an object as keyword arguments.\n\n\nExample with an **array**:\n\n```javascript\nconst data = {\n    items: [\"John\", \"Alice\", \"Bob\"],\n};\n\nconst options = {\n    functions: {\n        join: params =\u003e {\n            return params.args.join(\", \");\n        }\n    },\n};\n\nconst result = m(\"{{=join ...items}}\", data, options);\nconsole.log(result); // --\u003e \"John, Alice, Bob\"\n```\n\nExample with an **object**:\n\n```javascript\nconst data = {\n    user1: {\n        firstName: \"John\",\n        lastName: \"Doe\",\n    },\n    user2: {\n        firstName: \"Alice\",\n        lastName: \"Smith\",\n    },\n};\nconst options = {\n    functions: {\n        fullName: params =\u003e {\n            return `${params.options.firstName} ${params.options.lastName}`;\n        }\n    },\n};\n\nconst result = m(\"Users: {{=fullName ...user1}} and {{=fullName ...user2}}\", data, options);\nconsole.log(result); // --\u003e \"Users: John Doe and Alice Smith\"\n```\n\nOf course, Jose — here’s a version of the **Subexpressions** documentation written to perfectly match the tone, structure, and formatting conventions of the current README.  \nIt follows the same patterns: short intro, version note, examples, concise explanations, no extra fluff.\n\n### Subexpressions  \n\n\u003e Added in `v0.30.0`.\n\nSubexpressions allow you to evaluate a function call inside another function call. They are written using parentheses, and can be used anywhere a normal function argument is allowed. Example:\n\n```hbs\n{{=sum (sum 3 4) 3}}\n```\n\nIn this example, the inner expression is evaluated first:\n\n- `(sum 3 4)` → `7`  \n- `sum 7 3` → `10`\n\nResult:\n\n```\n10\n```\n\n#### Nested subexpressions\n\nSubexpressions can be nested to any depth:\n\n```hbs\n{{=sum (sum 1 (sum 2 3)) 4}}\n```\n\n#### Using strings inside subexpressions\n\nStrings behave the same way inside subexpressions, including quoted strings with spaces:\n\n```hbs\n{{=concat \"Hello \" (upper name)}}\n```\n\nIf `name = \"world\"`:\n\n```\nHello WORLD\n```\n\n#### Variables inside subexpresspressions\n\nYou can reference variables or paths normally:\n\n```hbs\n{{=sum (sum price tax) shipping}}\n```\n\n#### Limitations\n\n- Subexpressions are currently supported **only for functions** (`{{=...}}`).\n- Subexpressions inside helper arguments are not yet supported.\n- Parentheses must be balanced; malformed expressions will throw an error.\n\n\n## API\n\n### `mikel(template, data[, options])`\n\nRender the given template string with the provided data object and options.\n\n- `template` (string): the template string.\n- `data` (object): the data object containing the values to render.\n- `options` (object): an object containing the following optional values:\n    - `partials` (object): an object containing the available partials.\n    - `helpers` (object): an object containing custom helpers.\n    - `functions` (object): and object containing custom functions.\n\nReturns: A string with the rendered output.\n\n```javascript\nimport mikel from \"mikel\";\n\nconst data = {\n    name: \"World\",\n};\n\nconst result = mikel(\"Hello, {{name}}!\", data);\nconsole.log(result); // Output: \"Hello, World!\"\n```\n\n### `mikel.create(options)`\n\n\u003e Removed `template` argument in `v0.24.0`.\n\nAllows to create an isolated instance of mikel, useful when you want to use the same options for multiple templates without passing them every time. You can pass an `options` object with the same structure as the one used in the `mikel` function, which will be used for all templates compiled with this instance.\n\nIt returns a function that you can call with the template and data to compile the template.\n\n```javascript\nimport mikel from \"mikel\";\n\nconst mk = mikel.create({\n    partials: {\n        hello: \"Hello, {{name}}!\",\n    },\n});\n\nconsole.log(mk(\"{{\u003ehello}}\", {name: \"Bob\"})); // --\u003e \"Hello, Bob!\"\nconsole.log(mk(\"{{\u003ehello}}\", {name: \"Susan\"})); // --\u003e \"Hello, Susan!\"\n```\n\nIt also exposes the following additional methods:\n\n#### `mk.use(options)`\n\n\u003e Added in `v0.19.0`.\n\nAllows to extend the templating with custom **helpers**, **functions**, and **partials**.\n\n```javascript\nmk.use({\n    partials: {\n        foo: \"bar\",\n    },\n});\n```\n\n#### `mk.addHelper(helperName, helperFn)`\n\nAllows to register a new helper instead of using the `options` object.\n\n```javascript\nmk.addHelper(\"foo\", () =\u003e { ... });\n```\n\n#### `mk.removeHelper(helperName)`\n\nRemoves a previously added helper.\n\n```javascript\nmk.removeHelper(\"foo\");\n```\n\n#### `mk.addPartial(partialName, partialCode)`\n\nRegisters a new partial instead of using the `options` object.\n\n```javascript\nmk.addPartial(\"bar\", \" ... \");\n```\n\n#### `mk.removePartial(partialName)`\n\nRemoves a previously added partial.\n\n```javascript\nmk.removePartial(\"bar\");\n```\n\n#### `mk.addFunction(fnName, fn)`\n\nRegisters a new function instead of using the `options` object.\n\n```javascript\nmk.addFunction(\"foo\", () =\u003e \"...\");\n```\n\n#### `mk.removeFunction(fnName)`\n\nRemoves a previously added function.\n\n```javascript\nmk.removeFunction(\"foo\");\n```\n\n### `mikel.escape(str)`\n\nThis function converts special HTML characters `\u0026`, `\u003c`, `\u003e`, `\"`, and `'` to their corresponding HTML entities.\n\n### `mikel.get(object, path)`\n\nThis function returns the value in `object` following the provided `path` string.\n\n## License\n\nThis project is licensed under the [MIT License](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjmjuanes%2Fmikel","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjmjuanes%2Fmikel","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjmjuanes%2Fmikel/lists"}