dot-template
allows you to save templatized flatfiles, with added niceties
this library uses built-in javascript template literals
npm install @conjurelabs/dot-template
say you have the following file:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>${title}</title>
</head>
<body>
<div>Hello ${name}</div>
</body>
</html>
you can then use dot-template
to pull up the file and pass arguments
import dotTemplate from '@conjurelabs/dot-template'
async function main() {
const template = dotTemplate('index.html')
const result = await template({
title: 'Conjure Labs',
name: 'Tim'
})
return result
}
you can embed subtemplates as well
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>${title}</title>
</head>
<body>
@divs(<div>${content}</div>)&()
</body>
</html>
in this example divs
is expected to be an array of values, that will be passed into the subtemplate <div>${content}</div>
import dotTemplate from '@conjurelabs/dot-template'
async function main() {
const template = dotTemplate('index.html')
const result = await template({
title: 'Conjure Labs',
divs: [{
content: 'Tim'
}, {
content: 'Marshall'
}]
})
return result
}
this will end up generating <div>Tim</div><div>Marshall</div>
the &()
is telling the subtemplate to join with an empty string
you can omit &()
- by default it will join subtemplates with ,
if you attempt to fill a template, and a variable is missing, a ReferenceError
will be thrown.
this is consistent with how javascript templates work.
in addition to ${regular}
expressions, you can add in your own 'handlers'
import dotTemplate from '@conjurelabs/dot-template'
dotTemplate.addHandler({
// `expressionPrefix` is required
// this example would support `@{expression}`s
expressionPrefix: '@',
// mutates each value as it goes into the template
// templateArgs is the original {} values passed to template()
// additionalArgs is any other trailing args passed to template()
valueMutator: (value, templateArgs, ...additionalArgs) => value.toUppercase(),
// mutates each value, only when being console.log'd
// if this function is not set, the default return will
// be the value given by `valueMutator`
// templateArgs is the original {} values passed to template()
// additionalArgs is any other trailing args passed to template()
logMutator: (value, templateArgs, ...additionalArgs) => value.toLowercase(),
// mutates the entire values object,
// for both applied values and logged values
// useful if you need to Proxy `values
// type is either 'applied' or 'logged'
// additionalArgs is any other trailing args passed to template()
valuesObjectMutator: (values, type, ...additionalArgs) => new Proxy(value, {
get: (target, property) => {
const actualValue = Reflect.get(target, property)
if (type === 'logged') {
return actualValue.toLowercase()
} else {
return actualValue.toUppercase()
}
}
})
})
handlers are run in-order, after the built-in ${}
a simple use of the difference between valueMutator
and logMutator
is when you want to redact sensitive data, like PII
you can support this easily:
dotTemplate.addHandler({
expressionPrefix: '!',
logMutator: () => '<REDACTED>'
})
now, if you have a template like:
Hello !{name},
Thank you for your purchase. Your credit card ending in !{ccLastFour} will be charged in two days.
Best,
${company}
the filled in template will be as expected, while the value logged to terminal will be munged.
const template = dotTemplate('email.txt')
// content is:
/*
Hello Tim,
Thank you for your purchase. Your credit card ending in 4564 will be charged in two days.
Best,
Conjure Labs
*/
const content = await template({
name: 'Tim',
ccLastFour: 4564,
company: 'Conjure Labs'
})
// prints to terminal:
/*
Hello <REDACTED>,
Thank you for your purchase. Your credit card ending in <REDACTED> will be charged in two days.
Best,
Conjure Labs
*/
console.log(content)
see pg-dot-template for more