@paroicms/server
Version:
The ParoiCMS server
102 lines • 4.45 kB
JavaScript
import { Context, Hash, Tag, TypeGuards, assert, evalQuotedToken, evalToken } from 'liquidjs';
import { toEnumerable } from './collection.js';
import { ForloopDrop } from './forloop-drop.js';
export default class RenderTag extends Tag {
static passThroughSymbol = Symbol("passThrough");
file;
currentFile;
hash;
constructor(token, remainTokens, liquid) {
super(token, remainTokens, liquid);
const tokenizer = this.tokenizer;
this.file = parseFilePath(tokenizer, this.liquid);
this.currentFile = token.file;
while (!tokenizer.end()) {
tokenizer.skipBlank();
const begin = tokenizer.p;
const keyword = tokenizer.readIdentifier();
if (keyword.content === 'with' || keyword.content === 'for') {
tokenizer.skipBlank();
if (tokenizer.peek() !== ':') {
const value = tokenizer.readValue();
if (value) {
const beforeAs = tokenizer.p;
const asStr = tokenizer.readIdentifier();
let alias;
if (asStr.content === 'as')
alias = tokenizer.readIdentifier();
else
tokenizer.p = beforeAs(this)[keyword.content] = { value, alias: alias && alias.content };
tokenizer.skipBlank();
if (tokenizer.peek() === ',')
tokenizer.advance();
continue;
}
}
}
tokenizer.p = begin;
break;
}
this.hash = new Hash(tokenizer.remaining());
}
*render(ctx, emitter) {
const { liquid, hash } = this;
let filepath = (yield renderFilePath(this['file'], ctx, liquid));
assert(filepath, () => `illegal file path "${filepath}"`);
if (!filepath.endsWith(".liquid")) {
filepath += ".liquid";
}
const env = { [RenderTag.passThroughSymbol]: (ctx.environments ?? {})[RenderTag.passThroughSymbol] };
const childCtx = new Context(env, ctx.opts, { sync: ctx.sync, globals: ctx.globals, strictVariables: ctx.strictVariables });
const scope = childCtx.bottom();
Object.assign(scope, yield hash.render(ctx));
if (this['with']) {
const { value, alias } = this['with'];
scope[alias || filepath] = yield evalToken(value, ctx);
}
if (this['for']) {
const { value, alias } = this['for'];
const collection = toEnumerable(yield evalToken(value, ctx));
scope['forloop'] = new ForloopDrop(collection.length, value.getText(), alias);
for (const item of collection) {
scope[alias] = item;
const templates = (yield liquid._parsePartialFile(filepath, childCtx.sync, this['currentFile']));
yield liquid.renderer.renderTemplates(templates, childCtx, emitter);
scope['forloop'].next();
}
}
else {
const templates = (yield liquid._parsePartialFile(filepath, childCtx.sync, this['currentFile']));
yield liquid.renderer.renderTemplates(templates, childCtx, emitter);
}
}
}
export function parseFilePath(tokenizer, liquid) {
if (liquid.options.dynamicPartials) {
const file = tokenizer.readValue();
tokenizer.assert(file, 'illegal file path');
if (file.getText() === 'none')
return;
if (TypeGuards.isQuotedToken(file)) {
const templates = liquid.parse(evalQuotedToken(file));
return optimize(templates);
}
return file;
}
const tokens = [...tokenizer.readFileNameTemplate(liquid.options)];
const templates = optimize(liquid.parser.parseTokens(tokens));
return templates === 'none' ? undefined : templates;
}
function optimize(templates) {
if (templates.length === 1 && TypeGuards.isHTMLToken(templates[0].token))
return templates[0].token.getContent();
return templates;
}
export function* renderFilePath(file, ctx, liquid) {
if (typeof file === 'string')
return file;
if (Array.isArray(file))
return liquid.renderer.renderTemplates(file, ctx);
return yield evalToken(file, ctx);
}
//# sourceMappingURL=render.js.map