easy-template-x
Advanced tools
Comparing version 0.8.3 to 0.9.0
# Change Log | ||
## [0.9.0 - 2020-02-10](https://github.com/alonrbar/easy-template-x/tree/v0.9.0) | ||
### Added | ||
- Extensions API (#24). | ||
## [0.8.3 - 2019-12-27](https://github.com/alonrbar/easy-template-x/tree/v0.8.3) | ||
@@ -4,0 +10,0 @@ |
@@ -11,3 +11,3 @@ import { Constructor } from '../types'; | ||
private readonly xmlParser; | ||
readonly documentPath: string; | ||
get documentPath(): string; | ||
readonly rels: Rels; | ||
@@ -14,0 +14,0 @@ readonly mediaFiles: MediaFiles; |
@@ -17,3 +17,4 @@ import { Tag } from './compilation'; | ||
getXml(docxFile: Binary): Promise<XmlNode>; | ||
private callExtensions; | ||
private loadDocx; | ||
} |
import { Delimiters } from './delimiters'; | ||
import { TemplatePlugin } from './plugins'; | ||
import { ExtensionOptions } from './extensions'; | ||
export declare class TemplateHandlerOptions { | ||
@@ -9,3 +10,4 @@ plugins?: TemplatePlugin[]; | ||
maxXmlDepth?: number; | ||
extensions?: ExtensionOptions; | ||
constructor(initial?: Partial<TemplateHandlerOptions>); | ||
} |
@@ -6,4 +6,5 @@ import * as JSZip from 'jszip'; | ||
private readonly zipObject; | ||
name: string; | ||
readonly isDirectory: boolean; | ||
get name(): string; | ||
set name(value: string); | ||
get isDirectory(): boolean; | ||
constructor(zipObject: JSZip.JSZipObject); | ||
@@ -10,0 +11,0 @@ getContentText(): Promise<string>; |
{ | ||
"name": "easy-template-x", | ||
"version": "0.8.3", | ||
"version": "0.9.0", | ||
"description": "Generate docx documents from templates, in Node or in the browser.", | ||
@@ -44,32 +44,33 @@ "keywords": [ | ||
"lodash.get": "4.4.2", | ||
"xmldom": "0.1.27" | ||
"xmldom": "0.2.1" | ||
}, | ||
"devDependencies": { | ||
"@babel/core": "7.5.0", | ||
"@babel/plugin-proposal-class-properties": "7.5.0", | ||
"@babel/plugin-proposal-object-rest-spread": "7.5.3", | ||
"@babel/plugin-proposal-optional-catch-binding": "7.2.0", | ||
"@babel/plugin-transform-modules-commonjs": "7.5.0", | ||
"@babel/preset-typescript": "7.3.3", | ||
"@rollup/plugin-replace": "2.2.1", | ||
"@types/jest": "24.0.15", | ||
"@types/jszip": "3.1.6", | ||
"@types/node": "10.1.4", | ||
"@babel/core": "7.8.4", | ||
"@babel/plugin-proposal-class-properties": "7.8.3", | ||
"@babel/plugin-proposal-object-rest-spread": "7.8.3", | ||
"@babel/plugin-proposal-optional-catch-binding": "7.8.3", | ||
"@babel/plugin-proposal-optional-chaining": "7.8.3", | ||
"@babel/plugin-transform-modules-commonjs": "7.8.3", | ||
"@babel/preset-typescript": "7.8.3", | ||
"@rollup/plugin-replace": "2.3.1", | ||
"@types/jest": "25.1.2", | ||
"@types/jszip": "3.1.7", | ||
"@types/node": "13.7.0", | ||
"@types/xmldom": "0.1.29", | ||
"@typescript-eslint/eslint-plugin": "1.11.0", | ||
"@typescript-eslint/parser": "1.11.0", | ||
"babel-jest": "24.9.0", | ||
"@typescript-eslint/eslint-plugin": "2.19.0", | ||
"@typescript-eslint/parser": "2.19.0", | ||
"babel-jest": "25.1.0", | ||
"babel-loader": "8.0.6", | ||
"babel-plugin-ts-nameof": "0.3.0", | ||
"eslint": "5.16.0", | ||
"jest": "24.9.0", | ||
"jest-junit": "6.4.0", | ||
"lorem-ipsum": "1.0.4", | ||
"rimraf": "3.0.0", | ||
"rollup": "1.27.5", | ||
"babel-plugin-ts-nameof": "4.2.0", | ||
"eslint": "6.8.0", | ||
"jest": "25.1.0", | ||
"jest-junit": "10.0.0", | ||
"lorem-ipsum": "2.0.3", | ||
"rimraf": "3.0.2", | ||
"rollup": "1.31.0", | ||
"rollup-plugin-auto-external": "2.0.0", | ||
"rollup-plugin-babel": "4.3.3", | ||
"rollup-plugin-node-resolve": "5.2.0", | ||
"typescript": "3.5.3" | ||
"typescript": "3.7.5" | ||
} | ||
} |
142
README.md
@@ -13,11 +13,13 @@ # easy-template-x | ||
- [Live Demo](#live-demo) | ||
- [Standard plugins](#standard-plugins) | ||
- [Text plugin](#text-plugin) | ||
- [Loop plugin](#loop-plugin) | ||
- [Image plugin](#image-plugin) | ||
- [Link plugin](#link-plugin) | ||
- [Raw xml plugin](#raw-xml-plugin) | ||
- [Plugins](#plugins) | ||
- [Default plugins](#standard-plugins) | ||
- [Text plugin](#text-plugin) | ||
- [Loop plugin](#loop-plugin) | ||
- [Image plugin](#image-plugin) | ||
- [Link plugin](#link-plugin) | ||
- [Raw xml plugin](#raw-xml-plugin) | ||
- [Writing custom plugins](#writing-your-own-plugins) | ||
- [Extensions](#extensions) | ||
- [Scope resolution](#scope-resolution) | ||
- [Writing your own plugins](#writing-your-own-plugins) | ||
- [Advanced API](#advanced-api) | ||
- [Advanced API](#note---advanced-api) | ||
- [Supported Binary Formats](#supported-binary-formats) | ||
@@ -119,6 +121,10 @@ - [Philosophy](#philosophy) | ||
## Standard plugins | ||
## Plugins | ||
`easy-template-x` comes bundled with several plugins: | ||
`easy-template-x` uses a plugin model to support it's various template manipulation capabilities. There are some built-in plugins and you can also write your own custom plugins if required. | ||
### Default plugins | ||
These are the plugins that comes bundled with `easy-template-x`: | ||
- [Simple text replacement plugin.](#text-plugin) | ||
@@ -130,3 +136,3 @@ - [Loop plugin for iterating text, table rows and list rows.](#loop-plugin) | ||
### Text plugin | ||
#### Text plugin | ||
@@ -152,3 +158,3 @@ The most basic plugin. Replaces a single tag with custom text. Preserves the original text style. | ||
### Loop plugin | ||
#### Loop plugin | ||
@@ -179,3 +185,3 @@ Iterates text, table rows and lists. | ||
### Image plugin | ||
#### Image plugin | ||
@@ -206,3 +212,3 @@ Embed images into the document. | ||
### Link plugin | ||
#### Link plugin | ||
@@ -232,3 +238,3 @@ Inserts hyperlinks into the document. | ||
### Raw xml plugin | ||
#### Raw xml plugin | ||
@@ -260,38 +266,4 @@ Add custom xml into the document to be interpreted by Word. | ||
## Scope resolution | ||
### Writing your own plugins | ||
`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 template](./docs/assets/scope-in.png?raw=true) | ||
Input data: | ||
(notice that the "Company" data is declared outside the "Employees" loop, in it's so | ||
called "outer scope") | ||
```javascript | ||
{ | ||
"Company": "Contoso Ltd.", | ||
"Employees": [ | ||
{ "Surname": "Gates", "Given name": "William" }, | ||
{ "Surname": "Nadella", "Given name": "Satya" }, | ||
] | ||
} | ||
``` | ||
Output document: | ||
![output document](./docs/assets/scope-out.png?raw=true) | ||
## Writing your own plugins | ||
To write a plugin inherit from the [TemplatePlugin](./src/plugins/templatePlugin.ts) class. | ||
@@ -347,7 +319,68 @@ The base class provides two methods you can implement and a set of [utilities](./src/plugins/templatePlugin.ts) to | ||
## Advanced API | ||
## Extensions | ||
Although most document manipulation can be achieved by using plugins, there are some cases where a more powerful tool is required. In order to extend the document manipulation process you can specify extensions that will be run before and/or after the standard template processing. | ||
Some cases where an extension may be a good fit: | ||
- Manipulating the document metadata (author, keywords, description, etc.). | ||
- Adding and manipulating [Content Controls](http://www.datypic.com/sc/ooxml/e-w_sdtContent-2.html). | ||
- Leveraging [Data Binding](https://blogs.msdn.microsoft.com/modonovan/2006/05/22/word-2007-content-controls-and-xml-part-1-the-basics/) (where the data is stored in files other than the base Word files). | ||
By default no extensions will be loaded. | ||
Extensions and the order they run in are specified via the `TemplateHandlerOptions`. | ||
```typescript | ||
const handler = new TemplateHandler( | ||
new TemplateHandlerOptions({ | ||
extensions: { | ||
afterCompilation: [ | ||
new ContentControlExtension(), | ||
new DataBindingExtension() | ||
] | ||
} | ||
}); | ||
); | ||
``` | ||
## Scope resolution | ||
`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 template](./docs/assets/scope-in.png?raw=true) | ||
Input data: | ||
(notice that the "Company" data is declared outside the "Employees" loop, in it's so | ||
called "outer scope") | ||
```javascript | ||
{ | ||
"Company": "Contoso Ltd.", | ||
"Employees": [ | ||
{ "Surname": "Gates", "Given name": "William" }, | ||
{ "Surname": "Nadella", "Given name": "Satya" }, | ||
] | ||
} | ||
``` | ||
Output document: | ||
![output document](./docs/assets/scope-out.png?raw=true) | ||
## Note - Advanced API | ||
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](./dist/index.d.ts) file. Do note however that while the | ||
checkout the [typings](./dist/types/index.d.ts) file. Do note however that while the | ||
advanced API is mostly documented in the typings file it's still considered an | ||
@@ -388,5 +421,4 @@ internal implementation detail and may break between minor versions, use at your | ||
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 :) | ||
oriented template syntax, an even neater API (IMHO 😄), a _free_ image insertion | ||
plugin and a TypeScript code base. Hopefully it will serve you well :) | ||
@@ -393,0 +425,0 @@ ## Changelog |
import { DelimiterSearcher, ScopeData, Tag, TagParser, TemplateCompiler, TemplateContext } from './compilation'; | ||
import { Delimiters } from './delimiters'; | ||
import { MalformedFileError } from './errors'; | ||
import { TemplateExtension } from './extensions'; | ||
import { Docx, DocxParser } from './office'; | ||
@@ -56,2 +57,17 @@ import { TemplateData } from './templateData'; | ||
}); | ||
const extensionUtilities = { | ||
xmlParser: this.xmlParser, | ||
docxParser: this.docxParser, | ||
tagParser, | ||
compiler: this.compiler | ||
}; | ||
this.options.extensions?.beforeCompilation?.forEach(extension => { | ||
extension.setUtilities(extensionUtilities); | ||
}); | ||
this.options.extensions?.afterCompilation?.forEach(extension => { | ||
extension.setUtilities(extensionUtilities); | ||
}); | ||
} | ||
@@ -65,3 +81,3 @@ | ||
// process content (do replacements) | ||
// prepare context | ||
const scopeData = new ScopeData(data); | ||
@@ -71,4 +87,12 @@ const context: TemplateContext = { | ||
}; | ||
// extensions - before compilation | ||
await this.callExtensions(this.options.extensions?.beforeCompilation, scopeData, context); | ||
// compilation (do replacements) | ||
await this.compiler.compile(document, scopeData, context); | ||
// extensions - after compilation | ||
await this.callExtensions(this.options.extensions?.afterCompilation, scopeData, context); | ||
// export the result | ||
@@ -106,2 +130,11 @@ return docx.export(templateFile.constructor as Constructor<T>); | ||
private async callExtensions(extensions: TemplateExtension[], scopeData: ScopeData, context: TemplateContext): Promise<void> { | ||
if (!extensions) | ||
return; | ||
for (const extension of extensions) { | ||
await extension.execute(scopeData, context); | ||
} | ||
} | ||
private async loadDocx(file: Binary): Promise<Docx> { | ||
@@ -108,0 +141,0 @@ |
import { Delimiters } from './delimiters'; | ||
import { createDefaultPlugins, LOOP_CONTENT_TYPE, TemplatePlugin, TEXT_CONTENT_TYPE } from './plugins'; | ||
import { ExtensionOptions } from './extensions'; | ||
@@ -16,2 +17,4 @@ export class TemplateHandlerOptions { | ||
public extensions?: ExtensionOptions = {}; | ||
constructor(initial?: Partial<TemplateHandlerOptions>) { | ||
@@ -28,2 +31,2 @@ Object.assign(this, initial); | ||
} | ||
} | ||
} |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
341599
142
8042
418
27
+ Addedxmldom@0.2.1(transitive)
- Removedxmldom@0.1.27(transitive)
Updatedxmldom@0.2.1