
Research
Security News
Lazarus Strikes npm Again with New Wave of Malicious Packages
The Socket Research Team has discovered six new malicious npm packages linked to North Korea’s Lazarus Group, designed to steal credentials and deploy backdoors.
easy-template-x
Advanced tools
Generate docx documents from templates, in Node or in the browser.
import * as fs from 'fs';
import { TemplateHandler } from 'easy-template-x';
// 1. read template file
const templateFile = fs.readFileSync('myTemplate.docx');
// 2. process the template
const data = {
posts: [
{ author: 'Alon Bar', text: 'Very important\ntext here!' },
{ author: 'Alon Bar', text: 'Forgot to mention that...' }
]
};
const handler = new TemplateHandler();
const doc = await handler.process(templateFile, data);
// 3. save output
fs.writeFileSync('myTemplate - output.docx', doc);
Input:
Output:
The following example produces the same output while running in the browser. Notice that the actual template processing (step 2) is exactly the same as in the previous Node example.
import { TemplateHandler } from 'easy-template-x';
// 1. read template file
// (in this example we're loading the template by performing
// an AJAX call using the fetch API, another common way to
// get your hand on a Blob is to use an HTML File Input)
const response = await fetch('http://somewhere.com/myTemplate.docx');
const templateFile = await response.blob();
// 2. process the template
const data = {
posts: [
{ author: 'Alon Bar', text: 'Very important\ntext here!' },
{ author: 'Alon Bar', text: 'Forgot to mention that...' }
]
};
const handler = new TemplateHandler();
const doc = await handler.process(templateFile, data);
// 3. save output
saveFile('myTemplate - output.docx', doc);
function saveFile(filename, blob) {
// see: https://stackoverflow.com/questions/19327749/javascript-blob-filename-without-link
// get downloadable url from the blob
const blobUrl = URL.createObjectURL(blob);
// create temp link element
let link = document.createElement("a");
link.download = filename;
link.href = blobUrl;
// use the link to invoke a download
document.body.appendChild(link);
link.click();
// remove the link
setTimeout(() => {
link.remove();
window.URL.revokeObjectURL(blobUrl);
link = null;
}, 0);
}
easy-template-x
comes bundled with several plugins:
The most basic plugin. Replaces a single tag with custom text. Preserves the original text style.
Input template:
Input data:
{
"First Tag": "Quis et ducimus voluptatum\nipsam id.",
"Second Tag": "Dolorem sit voluptas magni dolorem molestias."
}
Output document:
Iterates text, table rows and lists.
Requires an opening tag that starts with #
and a closing tag that has the same
name and starts with /
.
Input template:
Input data:
{
"Beers": [
{ "Brand": "Carlsberg", "Price": 1 },
{ "Brand": "Leaf Blonde", "Price": 2 },
{ "Brand": "Weihenstephan", "Price": 1.5 }
]
}
Output document:
Embed images into the document.
Input template:
Input data:
{
"Kung Fu Hero": {
_type: "image",
source: fs.readFileSync("hero.png"),
format: MimeType.Png,
width: 200,
height: 200
}
}
Output document:
Inserts hyperlinks into the document.
Like text tags link tags also preserve their original style.
Input template:
Input data:
{
"easy": {
_type: 'link',
text: 'super easy', // optional - if not specified the `target` property will be used
target: 'https://github.com/alonrbar/easy-template-x'
}
}
Output document:
Add custom xml into the document to be interpreted by Word.
Tip:
You can add page breaks using this plugin and the following xml markup:
<w:br w:type="page"/>
Input template:
Input data:
{
"Dont worry be happy": {
_type: 'rawXml',
xml: '<w:sym w:font="Wingdings" w:char="F04A"/>'
}
}
Output document:
easy-template-x
supports tag data scoping. That is, you can reference
"shallow" data from within deeper in the hierarchy similarly to how you can
reference an outer scope variables from within a function in JavaScript. You can
leverage this property to declare "top level" data (your logo and company name
or some useful xml snippets like page breaks, etc.) to be used anywhere in the
document.
Input template:
(notice that we are using the "Company" tag inside the "Employees" loop)
Input data:
(notice that the "Company" data is declared outside the "Employees" loop, in it's so called "outer scope")
{
"Company": "Contoso Ltd.",
"Employees": [
{ "Surname": "Gates", "Given name": "William" },
{ "Surname": "Nadella", "Given name": "Satya" },
]
}
Output document:
To write a plugin inherit from the TemplatePlugin class.
The base class provides two methods you can implement and a set of utilities to
make it easier to do the actual xml modification.
To better understand the internal structure of Word documents check out this excellent source.
Example plugin implementation (source):
/**
* A plugin that inserts raw xml to the document.
*/
export class RawXmlPlugin extends TemplatePlugin {
// Declare the unique "content type" this plugin handles
public readonly contentType = 'rawXml';
// Plugin logic goes here:
public simpleTagReplacements(tag: Tag, data: ScopeData): void {
// Tag.xmlTextNode always reference the actual xml text node.
// In MS Word each text node is wrapped by a <w:t> node so we retrieve that.
const wordTextNode = this.utilities.docxParser.containingTextNode(tag.xmlTextNode);
// Get the value to use from the input data.
const value = data.getScopeData() as RawXmlContent;
if (value && typeof value.xml === 'string') {
// If it contains a "xml" string property parse it and insert.
const newNode = this.utilities.xmlParser.parse(value.xml);
XmlNode.insertBefore(newNode, wordTextNode);
}
// Remove the placeholder node.
// We can be sure that only the placeholder is removed since easy-template-x
// makes sure that each tag is isolated into it's own separate <w:t> node.
XmlNode.remove(wordTextNode);
}
}
The content type that this plugin expects to see is:
export interface RawXmlContent extends PluginContent {
_type: 'rawXml';
xml: string;
}
You'll usually just use the TemplateHandler
as seen in the examples but if you
want to implement a custom plugin or otherwise do some advanced work yourself
checkout the typings file. Do note however that while the
advanced API is mostly documented in the typings file it's still considered an
internal implementation detail and may break between minor versions, use at your
own risk.
The library supports the following binary formats:
The main principal the package aspire to adhere to is being simple and easy.
It tries to keep it simple and has the following priorities in mind:
easy-template-x
package itself.There are already some very good templating libraries out there, most notably these two:
easy-template-x
takes great inspiration from both. It aspires to take the best
out of both and to add some good of it's own.
While these packages has some great features such as GraphQL and inline
JavaScript support in docx-templates
and a breadth of additional (payed)
modules in docxtemplater
. This package, in accordance with it's declared above
philosophy, offers some unique benefits including a most simple, non-programmer
oriented template syntax, an even better (at least in my opinion 😄) API, a
free image insertion plugin and a TypeScript code base. Hopefully it will
serve you well :)
The change log can be found here.
FAQs
Generate docx documents from templates, in Node or in the browser.
The npm package easy-template-x receives a total of 6,500 weekly downloads. As such, easy-template-x popularity was classified as popular.
We found that easy-template-x demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
The Socket Research Team has discovered six new malicious npm packages linked to North Korea’s Lazarus Group, designed to steal credentials and deploy backdoors.
Security News
Socket CEO Feross Aboukhadijeh discusses the open web, open source security, and how Socket tackles software supply chain attacks on The Pair Program podcast.
Security News
Opengrep continues building momentum with the alpha release of its Playground tool, demonstrating the project's rapid evolution just two months after its initial launch.