-
Hello world,
For |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments
-
Abstract File System can be used anywhere when the template for rendering is not stored in a file. So yes, you can use it for your case. But if you treat There's another approach though, create a tag: engine.registerTag('json-template', {
parse: function(tagToken: TagToken, remainTokens: TopLevelToken[]) {
this.value = new Value(token.args, liquid)
},
render: function*(ctx: Context) {
const str = yield this.value.value(ctx); // 'jsonFile.json'
const json = JSON.parse(fs.readFileSync(str, 'utf8'))
let result = ''
for (const part of json.sequence) {
result += yield engine.parseAndRender(`${part}.liquid`, json.settings[part])
}
return result
}
}); Call the tag with the json file path: {% json-template 'jsonFile.json' %} For better performance/caching, you'll need liquid Line 1 in fe978c8 |
Beta Was this translation helpful? Give feedback.
-
This example uses the default The plan was to use an instance of import { Liquid, RenderTag, Context } from "liquidjs";
// NOTE: I wanted to use `Loader` from `fs/loader.js`, but it is not exported by LiquidJS.
// This mock loader is incomplete and is just for demonstration purposes.
class MockLoader {
options;
constructor(options) {
this.options = options;
}
*lookup(file, sync) {
const { fs, extname, partials } = this.options;
// Looking for .json files in liquid.options.partials[0].
const filepath = yield fs.resolve(partials[0], file, extname);
if (sync ? fs.existsSync(filepath) : yield fs.exists(filepath))
return filepath;
throw new Error(`Can't find "${file}${extname}"`);
}
}
// A custom implementation of the `{% render %}` tag.
class MyRenderTag extends RenderTag {
jsonLoader;
constructor(token, remainTokens, liquid) {
super(token, remainTokens, liquid);
// A loader for looking up JSON template files. Uses the same FS as liquid.options.
this.jsonLoader = new MockLoader({ ...liquid.options, extname: ".json" });
// Or, if Loader were exported.
// this.jsonLoader = new Loader({ ...liquid.options, extname: ".json" });
}
*render(ctx, emitter) {
if (typeof this.file === "string") {
try {
const filepath = yield this.jsonLoader.lookup(this.file);
} catch (error) {
// Fall back to the standard render tag if the ".json" file does not exist.
yield* super.render(ctx, emitter);
}
yield* this.renderJsonFile(filepath, ctx, emitter);
} else {
// Fall back to the standard render tag if the file name is not a string.
yield* super.render(ctx, emitter);
}
}
*renderJsonFile(filepath, ctx, emitter) {
// Setup a render context. We'll add settings from the JSON template to this scope.
const renderCtx = new Context({}, ctx.opts, {
sync: ctx.sync,
globals: ctx.globals,
strictVariables: ctx.strictVariables,
});
// Read the JSON template.
// TODO: handle JSON parsing errors.
const jsonTemplate = JSON.parse(
ctx.sync
? this.liquid.options.fs.readFileSync(filepath)
: yield this.liquid.options.fs.readFile(filepath)
);
// TODO: Validate the the JSON schema.
// Render each partial template in _sequence_.
for (const templateName of jsonTemplate.sequence) {
// Push settings for this partial template on to the scope stack.
renderCtx.push(jsonTemplate.settings[templateName] || {});
// Parse the partial template.
const templates = yield this.liquid._parsePartialFile(
templateName,
renderCtx.sync,
this["currentFile"]
);
// Render the partial template.
yield this.liquid.renderer.renderTemplates(templates, renderCtx, emitter);
// Remove settings for the partial template.
renderCtx.pop();
}
}
}
const engine = new Liquid({ extname: ".liquid" });
engine.registerTag("render", MyRenderTag); |
Beta Was this translation helpful? Give feedback.
This example uses the default
FS
implementation to find.json
templates, and handles JSON parsing and partial settings in a custom{% render %}
tag, which extends and falls back to the defaultrender
tag.The plan was to use an instance of
Loader
fromfs/loader.ts
for.json
template lookup, but LiquidJS does not export it. If this kind of thing works for you, you'll need to either ask @harttle to exportLoader
(and maybeLookupType
) or implement a loader-like class yourself.