
Security Fundamentals
Obfuscation 101: Unmasking the Tricks Behind Malicious Code
Attackers use obfuscation to hide malware in open source packages. Learn how to spot these techniques across npm, PyPI, Maven, and more.
This is a template engine.
It's like "tmpl", only with an "F" instead of a "T". Use your funning imagination to figure out what the "F" stands for.
npm install fmpl
This solves a singular goal. That goal is to precompile templates into an independent callable function. Only pug/ejs seem to do that but pug is for HTML and ejs doesn't support template inheritance.
This library is NOT:
I mean, it works, and the tests pass (100% coverage), but the parser is kinda naive and you can jam it up if you try really hard. I use it for precompiling HTML email templates. I wouldn't recommend it as a replacement for a more "real" template engine like pug, ejs, nunjucks or dust.
If you want minimal dependencies and standalone precompilation, this is the library for you.
const {Fmpl} = require('fmpl');
import {Fmpl} from 'fmpl'; // typescript
//fancy usage
const fmpl = new Fmpl();
const fn = fmpl.compile(someTemplateString);
console.log(fn({ dem: 'vars' }));
//less fancy usage
console.log(Fmpl.render(someTemplateString, { dem: 'vars' }));
fmpl
comes with a cli utility called fmpl
. Run it from node_modules/.bin/fmpl
.
fmpl [--verbose|-v] [--help|-h] [file] [file...]
fmpl is a fucking template engine that accepts a file and spits out a
stringified JavaScript function to stdout. If no file is specified
then it reads from stdin. If "-" is given for the filename it will read
from stdin.
Options
--verbose|-v show debugging messages
--help|-g show this message
--render json compile and render the template
Brief syntax overview:
{{ expression }} echo the result of a JavaScript expression
{$ expression $} execute a JavaScript expression
{% if expression %}{% endif %} basic if statement
{% for expression %}{% endfor %} basic for loop
{% while expression %}{% endwhile %} basic while loop
{% block name %}{% endblock %} create a block
{% include name %} include another template
Append "-" to any of the above opening tags will trim previous whitespace.
Returns 0 if it worked, 1 if it didn't.
Quick and dirty: variables are in {{ }}
, code is in {$ $}
, everything else is in
{% %}
. Parentheses around if/else/for/while expressions are optional.
Trim previous whitespace with -
, e.g. {{- }}
or {%- %}
.
Any JavaScript expression can can be interpolated
Interpolate a variable:
const tmpl = 'Hello {{ name }}';
Fmpl.render(tmpl, { name: 'yarp' }); //Hello yarp
Interpolate an expression:
const tmpl = 'Hello {{ (() => { return \'yarp\'; }()) }}';
Fmpl.render(tmpl); //Hello yarp
Sometimes you just want to set a variable or something.
{$
is the same as {{
except that it won't echo the result.
const tmpl = '{$ var name = \'yarp\'; $}Hello {{ name }}';
Fmpl.render(tmpl); //Hello yarp
if
/else
Parentheses are optional. else
is optional.
const tmpl = 'Hello {% if foo %}{{ foo }}{% else %}world{% endif %}';
Fmpl.render(tmpl, { foo: 'bar' }); //Hello bar
Fmpl.render(tmpl, { foo: '' }); //Hello world
for
Parentheses are optional.
Regular for loop:
const tmpl = '{% for var i = 0; i < 3; i++ %}{{ String.fromCharCode(i + 65) }} {% endfor %}';
Fmpl.render(tmpl); //A B C
for..in
loop:
const tmpl = 'Hello {% for var fruit in fruits %}{{ fruit }} are {{ fruits[fruit] }} {% endfor %}';
Fmpl.render(tmpl, { fruits: { apples: 'red', bananas: 'yellow' }}); //apples are red bananas are yellow
while
Parentheses are optional
const tmpl = '{$ var i = 0; $}{% while i < 3 %}{{ String.fromCharCode(i + 65) }}{$ i++ $} {% endwhile %}';
Fmpl.render(tmpl); //A B C
Blocks are blocks of content that you can declare and then override or append to. Useful for template inheritance.
They are declared with {% block <name of block> %}
, and referenced later the same way.
They can optionally have content. If they have a content, the default is to replace the content
if a block is referenced later. If you want to append content, add a "+" in front of the name,
like so {% block +<name of block> %}
.
Blocks are inserted into the content where they are initially declared.
const tmpl = '{% block yarp %}{% endblock %} Hello {% block yarp %}block content{% endblock %}world';
Fmpl.render(tmpl); //block content Hello world
Appending content:
const tmpl = '{% block yarp %}original content{% endblock %} Hello {% block +yarp %} new content{% endblock %}world';
Fmpl.render(tmpl); //original content new content Hello world
Blocks can be nested, and names from a parent block can be reused:
const tmpl = `
{% block content %}{% endblock %}
This should be last in the rendered result.
{% block content %}
blox!
{% block content %}{% endblock %}
more blox!
{% block content %}i like blox{% endblock %}
{% endblock %}
`;
Fmpl.render(tmpl);
/*
blox!
i like blox
more blox!
This should be last in the rendered result.
*/
Template inheritance can be accomplished by combining an include
and a block
.
Includes simply insert another template into the current template. You can use them as many times as you want wherever you want. Try not to create a circular template or else I'll kill your family. Not really though.
By default, included templates are resolved assuming they are file names. If this isn't ideal,
you can create your own resolver and load it into the Fmpl
instance.
The default filename resolver is very simple and kinda stupid. If the include path is not absolute, it searches relatively from the original file path (if available). So if you have doubly nested templates that include relative templates from different directories, you may run into issues. Easiest solution is to simply use your own resolver.
If an included template cannot be resolved, an error will be thrown.
const parent = `
Some stuff at the top.
{% block content %}{% endblock %}
Some stuff at the bottom.`;
const child = `
{% include myParentTemplate %}
{% block content %}
This is in the middle!
{% endblock %}
`;
const fmpl = new Fmpl();
fmpl.addIncludeResolver((name) => {
if (name === 'myParentTemplate') {
return parent;
}
return null;
});
fmpl.compile(child)();
/*
Some stuff at the top.
This is in the middle!
Some stuff at the bottom.
*/
Internally it appends a bunch of stuff to a string and then dynamically
creates a callable function using the Function
constructor. Code you write
in your template (e.g. in an if
statement) is inserted verbatim and will
throw syntax errors if it sucks.
Variables for internal use are prefixed with ____
(four underscores) so if you
do something like {$ ____render = null; $}
nothing will work. Try not do that.
FAQs
fucking template engine
The npm package fmpl receives a total of 7 weekly downloads. As such, fmpl popularity was classified as not popular.
We found that fmpl demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security Fundamentals
Attackers use obfuscation to hide malware in open source packages. Learn how to spot these techniques across npm, PyPI, Maven, and more.
Security News
Join Socket for exclusive networking events, rooftop gatherings, and one-on-one meetings during BSidesSF and RSA 2025 in San Francisco.
Security News
Biome's v2.0 beta introduces custom plugins, domain-specific linting, and type-aware rules while laying groundwork for HTML support and embedded language features in 2025.