Skip to content

Instantly share code, notes, and snippets.

@jonschlinkert
Last active February 8, 2024 08:26
Show Gist options
  • Save jonschlinkert/58286a4fb931da6205c0166ec7e46522 to your computer and use it in GitHub Desktop.
Save jonschlinkert/58286a4fb931da6205c0166ec7e46522 to your computer and use it in GitHub Desktop.
PoC of an async template engine using native template literals and async-await. Response to https://twitter.com/doowb/status/1072688034485805058
const compile = (input, helpers, thisArg) => {
return async data => {
let ctx = { ...thisArg, ...data };
let keys = [];
let vals = [];
if (helpers) {
for (let key of Object.keys(helpers)) {
if (ctx[key] === void 0) {
ctx[key] = (...args) => helpers[key].call(ctx, ...args);
}
}
}
for (let key in ctx) {
if (ctx.hasOwnProperty(key)) {
keys.push(key);
vals.push(ctx[key]);
}
}
let isPromise = val => typeof val === 'function' || val instanceof Promise;
let resolve = (input, ctx) => {
return typeof input === 'function' ? input.call(ctx, ctx) : input;
};
ctx.compile = compile;
ctx.render = (str, locals) => compile(str)({ ...ctx, ...locals });
while (isPromise(input)) input = await resolve(input, ctx);
let source = `return ((async () => \`${input.replace(/\${/g, '${await ')}\`))()`;
return await Function(keys, source).apply(ctx, vals);
};
};
'use strict';
const fs = require('fs');
const path = require('path');
const util = require('util');
const compile = require('./es6-engine');
const readfile = util.promisify(fs.readFile);
const { prompt } = require('enquirer');
let partials = {};
let helpers = {
read(name) {
return readfile(path.resolve(process.cwd(), name), 'utf8');
},
log(...args) {
console.log(...args);
return '';
},
prompt(question) {
return prompt(question).then(answers => {
this[question.name] = answers[question.name];
return '';
});
},
async partial(name, locals) {
return this.render(await partials[name], locals);
},
include(name, locals) {
return this.render(helpers.read(name), locals);
}
};
let registerPartial = (name, str) => {
partials[name] = compile(str, helpers);
};
registerPartial('fixture3', helpers.read('fixture3.txt'));
// "compile()" takes a string, or a promise that returns a string
let value = helpers.read('fixture1.txt');
let render = compile(value, helpers);
render({ name: 'Brian' })
.then(console.log)
.catch(console.log);
Hi, my name is: ${include("fixture2.txt")}
Hi, my name is: ${include("fixture2.txt", { name: 'Bob' })}
Hi, my name is: ${partial("fixture3", { name: 'Alice' })}
${prompt({ type: 'input', name: 'name', message: 'Name?' })}
Hi, my name is: ${include("fixture2.txt")}
${log(this)}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment