
Research
Security News
Malicious PyPI Package Exploits Deezer API for Coordinated Music Piracy
Socket researchers uncovered a malicious PyPI package exploiting Deezer’s API to enable coordinated music piracy through API abuse and C2 server control.
A lightweight Node.js theme engine.
Themeleon is two things:
A theme is a simple JavaScript function. The purpose of this function is to render a context in a destination.
The context is a JavaScript object. It typically contains the variables and configuration you will use to render the theme in the destination directory.
A theme is also asynchronous, and relies on Promises/A+ for this.
The following JSDoc comment describes the theme interface:
/**
* @param {String} destination
* Destination directory to render the theme in. The directory must
* already exist, be empty, and be writable.
*
* @param {Object} context
* An object passed to the template engine to render the theme. Usually,
* each key of the context object will be a variable in the template.
*
* @return {Promise}
* Any compatible implementation of the Promises/A+ specification.
*/
function render(destination, context) {}
So, if you want to create a Themeleon compatible theme, you can
implement this interface by hand without relying on the themeleon
Node.js package.
The behavior is undefined if the destination directory doesn't exists or is not empty.
Note: Themeleon does not document anything about the context object structure. This is left to the project that will be themed. It means that a Themeleon theme is strongly tied with the context it is designed for.
You will probably be publishing themes for a context, since you need a predictable idea of what will contain the context data.
The convention is to name the Node.js package like this:
{{context}}-theme-{{theme}}
The {{context}}
variable is the context name, an identifier that
qualifies the kind of data the context object will contain, and
{{theme}}
is the name of your theme.
See a practical example in the Examples section below.
You're not required to publish the theme on npm, anything that can be
require
d will do the job, so downloading a theme archive, extracting
it in a folder, and including its index.js
is also an acceptable
solution. I believe it's more practical to use a package manager for
this though.
If you want to make your project themable, all you'll need to do is to
dynamically require
a theme module, an call it with a destination and
context object.
Themeleon doesn't enforces anything about this, but the recommended way is the following:
[a-z-]+
, but you can be less strict), require
the prefixed name ({{context}}-theme-{{theme}}
).require
the whole name (it might be a path), resolved to
process.cwd()
(it might be relative too).Themeleon also acts as a theme creation framework, to ease the interface implementation by hiding relatively low-level considerations, like reading and writing files, handling promises, and using a raw template engine.
When using the framework, you only have to define a render function, that will describe the high-level tasks needed to render the theme.
These tasks are in fact mixins that you include in your Themeleon instance. It's easy to define and share custom mixins, and that's how template engines are brought to Themeleon.
The mixins makes it easy to abstract the theme directory, destination directory and the context data. For example, a mixin can decide to make a given path relative to the theme or destination directory when it makes sense, instead of the CWD, and a template engine mixin can implicitely pass the context object to the templates.
First, install Themeleon in your package.json
:
npm install themeleon --save
{
"dependencies": {
"themeleon": "1.*"
}
}
You will be using Themeleon in the index.js
of your theme package.
First, create a Themeleon instance:
var themeleon = require('themeleon')();
You can then use some mixins, for example see the supported template engines.
// Use Swig mixin
themeleon.use('swig');
// You can also use Jade
// themeleon.use('jade');
// Or Mustache
// themeleon.use('mustache');
You may also add your own mixin:
themeleon.use({
/**
* Log current source directory, destination directory, and context
* variables.
*/
log: function () {
console.log(this.src, this.dest, this.ctx);
},
});
Now everything is initialized, you can begin to describe your theme.
For this, you define a function taking a Themeleon instance t
as
parameter, and you give this function to the themeleon
function,
together with the theme directory (certainly __dirname
if you're in
the index.js
):
module.exports = themeleon(__dirname, function (t) {
// Theme render logic here
});
The themeleon
function will take care of the
interface implementation, and will call your render
function on demand. That's where the magic resides:
module.exports = themeleon(__dirname, function (t) {
t.copy('assets'); // Will copy `assets` in destination directory
// t.copy('assets', 'foo'); // Other name in destination directory
// Compile a Swig view as `index.html` in destination directory
t.swig('views/index.html.swig', 'index.html');
// Call the custom mixin defined above
t.log();
});
And that's all! Themeleon will run all the tasks and return a promise waiting for them all to complete.
Use the above theme (assuming it's named project-theme-foo
) in a
project:
var theme = require('project-theme-foo');
// Render the theme in `dest` directory with given variables
theme('dest', {
some: 'variables',
that: 'will be',
passed: 2,
the: 'theme',
});
// Use the Swig mixin
themeleon.use('swig');
// Or inject your own instance
themeleon.use('swig', require('swig'));
module.exports = themeleon(__dirname, function (t) {
// Compile a Swig view as `index.html` in destination directory
t.swig('views/index.html.swig', 'index.html');
});
// Use the Nunjucks mixin
themeleon.use('nunjucks');
// Or inject your own instance
themeleon.use('nunjucks', require('nunjucks'));
module.exports = themeleon(__dirname, function (t) {
// Configure Nunjucks views base path and options
t.nunjucks.configure('views', options);
// Compile a Nunjucks view as `index.html` in destination directory
t.nunjucks('index.html', 'dist/index.html');
});
// Use the Jade mixin
themeleon.use('jade');
// Or inject your own instance
themeleon.use('jade', require('jade'));
module.exports = themeleon(__dirname, function (t) {
var options = {
pretty: true,
};
// Compile a Jade view as `index.html` in destination directory
t.jade('views/index.jade', 'index.html', options);
});
// Use the Mustache mixin
themeleon.use('mustache');
// Or inject your own instance
themeleon.use('mustache', require('mustache'));
module.exports = themeleon(__dirname, function (t) {
// Render index alone
t.mustache('views/index.mustache', 'index.html');
// Or include a partials object
t.mustache('views/index.mustache', 'index.html', {
foo: 'views/foo.mustache',
'foo/bar': 'views/foo/bar.mustache',
});
// Or let the mixin resolve all `.mustache` files in `views`
t.mustache('views/index.mustache', 'index.html', 'views');
});
// Use the Handlebars mixin
themeleon.use('handlebars');
// Or inject your own instance
themeleon.use('handlebars', require('handlebars'));
module.exports = themeleon(__dirname, function (t) {
// Render index alone
t.handlebars('views/index.handlebars', 'index.html');
// Or include a partials object
t.handlebars('views/index.handlebars', 'index.html', {
foo: 'views/foo.handlebars',
'foo/bar': 'views/foo/bar.handlebars',
});
// Or let the mixin resolve all `.handlebars` files in `views`
t.handlebars('views/index.handlebars', 'index.html', 'views');
});
Note: .handlebars
and .hbs
extensions are supported.
The best production example for Themeleon is SassDoc. In fact, Themeleon was created for SassDoc because we wanted to support custom themes, without having any theming logic inside SassDoc.
SassDoc describes a theme context interface. This documents the context object passed to SassDoc themes. So, if you want to write a theme for SassDoc, all you have to do is to provide a function implementing the Themeleon interface, and making sense of the context data passed by SassDoc.
Since the context is specific to SassDoc, all themes are prefixed with
sassdoc-theme-
. Thus, the default theme is
published as sassdoc-theme-default
. This theme uses Swig to render a
single HTML page from multiple Swig partials, built around the
documented SassDoc context.
FAQs
A lightweight Node.js theme engine.
The npm package themeleon receives a total of 251 weekly downloads. As such, themeleon popularity was classified as not popular.
We found that themeleon demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 2 open source maintainers 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.
Research
Security News
Socket researchers uncovered a malicious PyPI package exploiting Deezer’s API to enable coordinated music piracy through API abuse and C2 server control.
Research
The Socket Research Team discovered a malicious npm package, '@ton-wallet/create', stealing cryptocurrency wallet keys from developers and users in the TON ecosystem.
Security News
Newly introduced telemetry in devenv 1.4 sparked a backlash over privacy concerns, leading to the removal of its AI-powered feature after strong community pushback.