A simple, expressive and safe Shopify / Github Pages compatible template engine in pure JavaScript.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
LiquidJS provides a powerful extension system for registering custom filters and tags to extend template functionality with domain-specific processing capabilities.
Register custom filters to transform template output values.
/**
* Register a custom filter
* @param name - Filter name
* @param filter - Filter implementation function
*/
registerFilter(name: string, filter: FilterImplOptions): void;
type FilterImplOptions = (this: FilterImpl, value: any, ...args: any[]) => any;
interface FilterImpl {
context: Context;
liquid: Liquid;
}Usage Examples:
import { Liquid } from "liquidjs";
const engine = new Liquid();
// Simple filter
engine.registerFilter('shout', (str) => String(str).toUpperCase() + '!');
// Filter with arguments
engine.registerFilter('repeat', (str, times) => {
return String(str).repeat(Number(times) || 1);
});
// Async filter
engine.registerFilter('fetchData', async function(url) {
const response = await fetch(String(url));
return response.json();
});
// Template usage
const result = await engine.parseAndRender(`
{{ "hello" | shout }}
{{ "world" | repeat: 3 }}
`, {});Register custom tags for template control flow and logic.
/**
* Register a custom tag
* @param name - Tag name
* @param tag - Tag class or implementation options
*/
registerTag(name: string, tag: TagClass | TagImplOptions): void;
type TagClass = new (token: TagToken, remainTokens: TopLevelToken[], liquid: Liquid) => Tag;
interface TagImplOptions {
parse?(token: TagToken, remainTokens: TopLevelToken[]): void;
render?(ctx: Context, emitter: Emitter): any;
}
interface Tag {
token: TagToken;
render(ctx: Context, emitter: Emitter): any;
}Usage Examples:
// Simple tag
engine.registerTag('hello', {
render: function(ctx, emitter) {
emitter.write('Hello from custom tag!');
}
});
// Tag with parsing
engine.registerTag('upper', {
parse: function(token, remainTokens) {
this.str = token.args;
},
render: function(ctx, emitter) {
const str = this.liquid.renderer.renderTemplates(this.str, ctx, {sync: true});
emitter.write(String(str).toUpperCase());
}
});Use the plugin system to bundle multiple extensions together.
/**
* Apply a plugin to the Liquid instance
* @param plugin - Plugin function that extends the engine
*/
plugin(plugin: (this: Liquid, L: typeof Liquid) => void): void;Usage Examples:
// Create a plugin
function myPlugin(Liquid) {
this.registerFilter('reverse', str => String(str).split('').reverse().join(''));
this.registerFilter('bold', str => `<strong>${str}</strong>`);
this.registerTag('timestamp', {
render: function(ctx, emitter) {
emitter.write(new Date().toISOString());
}
});
}
// Use the plugin
engine.plugin(myPlugin);