docx-templates
Advanced tools
Comparing version 4.11.3 to 4.11.4
@@ -0,1 +1,7 @@ | ||
## 4.11.4 (2024-01-12) | ||
- Replace weak `Object` types of `runJs` arguments. | ||
- Remove unnecessary use of `eval()` internally. | ||
- [#341](https://github.com/guigrpa/docx-templates/issues/341) Add result to `ObjectCommandResultError`. When a `ObjectCommandResultError` is thrown, this change attaches the computed result to the error in case a custom error handler wants to use it for some reason. (thanks @emilong!) | ||
- [#345](https://github.com/guigrpa/docx-templates/issues/345): Make types for template more liberal. What works with Buffer should work with ArrayBuffer, with the benefit that browsers don't need a `Buffer` polyfill. | ||
## 4.11.3 (2023-08-08) | ||
@@ -2,0 +8,0 @@ - ([PR #321](https://github.com/guigrpa/docx-templates/pull/321)) Fix `InvalidCommandError` referring to `'Unexpected END-IF outside of IF statement context:'` when the problem was actually an unexpected `END-FOR`. Thanks @davidjb |
@@ -38,13 +38,13 @@ type Buffer = ArrayBufferLike; | ||
type RunJSFunc = (o: { | ||
sandbox: Object; | ||
ctx: Object; | ||
sandbox: SandBox; | ||
ctx: Context; | ||
}) => { | ||
modifiedSandbox: Object; | ||
result: any; | ||
modifiedSandbox: SandBox; | ||
result: unknown; | ||
}; | ||
type UserOptions = { | ||
/** | ||
* Docx file template as a NodeJS Buffer or Buffer-like object in Browsers. | ||
* Docx file template as a Uint8Array (or e.g. ArrayBuffer or NodeJS Buffer). | ||
*/ | ||
template: Buffer; | ||
template: Uint8Array; | ||
/** | ||
@@ -118,2 +118,79 @@ * Object of data to be injected or a (async) function that resolves to the data. The function gets as an argument the contents of the QUERY command as a string. | ||
}; | ||
type CreateReportOptions = { | ||
cmdDelimiter: [string, string]; | ||
literalXmlDelimiter: string; | ||
processLineBreaks: boolean; | ||
noSandbox: boolean; | ||
runJs?: RunJSFunc; | ||
additionalJsContext: Object; | ||
failFast: boolean; | ||
rejectNullish: boolean; | ||
errorHandler: ErrorHandler | null; | ||
fixSmartQuotes: boolean; | ||
processLineBreaksAsNewText: boolean; | ||
}; | ||
type SandBox = { | ||
__code__: string | undefined; | ||
__result__: unknown | undefined; | ||
[k: string]: unknown; | ||
}; | ||
type Context = { | ||
gCntIf: number; | ||
gCntEndIf: number; | ||
level: number; | ||
fCmd: boolean; | ||
cmd: string; | ||
fSeekQuery: boolean; | ||
query?: string; | ||
buffers: { | ||
'w:p': BufferStatus; | ||
'w:tr': BufferStatus; | ||
}; | ||
pendingImageNode?: { | ||
image: NonTextNode; | ||
caption?: NonTextNode[]; | ||
}; | ||
imageAndShapeIdIncrement: number; | ||
images: Images; | ||
pendingLinkNode?: NonTextNode; | ||
linkId: number; | ||
links: Links; | ||
pendingHtmlNode?: TextNode | NonTextNode; | ||
htmlId: number; | ||
htmls: Htmls; | ||
vars: { | ||
[name: string]: VarValue; | ||
}; | ||
loops: Array<LoopStatus>; | ||
fJump: boolean; | ||
shorthands: { | ||
[shorthand: string]: string; | ||
}; | ||
options: CreateReportOptions; | ||
jsSandbox?: SandBox; | ||
textRunPropsNode?: NonTextNode; | ||
}; | ||
type Images = { | ||
[id: string]: Image; | ||
}; | ||
declare const ImageExtensions: readonly [".png", ".gif", ".jpg", ".jpeg", ".svg"]; | ||
type ImageExtension = (typeof ImageExtensions)[number]; | ||
type Image = { | ||
extension: ImageExtension; | ||
data: ArrayBuffer | string; | ||
}; | ||
type Links = { | ||
[id: string]: Link; | ||
}; | ||
type Link = { | ||
url: string; | ||
}; | ||
type Htmls = { | ||
[id: string]: string; | ||
}; | ||
type BufferStatus = { | ||
text: string; | ||
cmds: string; | ||
fInsertedText: boolean; | ||
}; | ||
type VarValue = unknown; | ||
@@ -186,3 +263,3 @@ type LoopStatus = { | ||
*/ | ||
declare function listCommands(template: Buffer, delimiter?: string | [string, string]): Promise<CommandSummary[]>; | ||
declare function listCommands(template: ArrayBuffer, delimiter?: string | [string, string]): Promise<CommandSummary[]>; | ||
/** | ||
@@ -192,3 +269,3 @@ * Extract metadata from a document, such as the number of pages or words. | ||
*/ | ||
declare function getMetadata(template: Buffer): Promise<{ | ||
declare function getMetadata(template: ArrayBuffer): Promise<{ | ||
pages: number | undefined; | ||
@@ -225,3 +302,4 @@ words: number | undefined; | ||
command: string; | ||
constructor(command: string); | ||
result: unknown; | ||
constructor(command: string, result: unknown); | ||
} | ||
@@ -228,0 +306,0 @@ declare class CommandSyntaxError extends Error { |
@@ -14,3 +14,4 @@ import { LoopStatus } from './types'; | ||
command: string; | ||
constructor(command: string); | ||
result: unknown; | ||
constructor(command: string, result: unknown); | ||
} | ||
@@ -17,0 +18,0 @@ export declare class CommandSyntaxError extends Error { |
@@ -38,6 +38,7 @@ "use strict"; | ||
__extends(ObjectCommandResultError, _super); | ||
function ObjectCommandResultError(command) { | ||
function ObjectCommandResultError(command, result) { | ||
var _this = _super.call(this, "Result of command '".concat(command, "' is an object")) || this; | ||
Object.setPrototypeOf(_this, ObjectCommandResultError.prototype); | ||
_this.command = command; | ||
_this.result = result; | ||
return _this; | ||
@@ -44,0 +45,0 @@ } |
@@ -64,6 +64,7 @@ "use strict"; | ||
function runUserJsAndGetRaw(data, code, ctx) { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function () { | ||
var sandbox, curLoop, context, result, temp, wrapper, script, err_1, e, nerr; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
return __generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: | ||
@@ -77,5 +78,5 @@ sandbox = __assign(__assign(__assign(__assign({}, (ctx.jsSandbox || {})), { __code__: code, __result__: undefined }), data), ctx.options.additionalJsContext); | ||
}); | ||
_a.label = 1; | ||
_b.label = 1; | ||
case 1: | ||
_a.trys.push([1, 8, , 12]); | ||
_b.trys.push([1, 8, , 12]); | ||
if (!ctx.options.runJs) return [3 /*break*/, 3]; | ||
@@ -86,3 +87,3 @@ temp = ctx.options.runJs({ sandbox: sandbox, ctx: ctx }); | ||
case 2: | ||
result = _a.sent(); | ||
result = _b.sent(); | ||
return [3 /*break*/, 7]; | ||
@@ -95,15 +96,14 @@ case 3: | ||
case 4: | ||
result = _a.sent(); | ||
result = _b.sent(); | ||
return [3 /*break*/, 7]; | ||
case 5: | ||
script = new vm_1.default.Script("\n __result__ = eval(__code__);\n ", {}); | ||
script = new vm_1.default.Script((_a = sandbox.__code__) !== null && _a !== void 0 ? _a : ''); | ||
context = vm_1.default.createContext(sandbox); | ||
script.runInContext(context); | ||
return [4 /*yield*/, context.__result__]; | ||
return [4 /*yield*/, script.runInContext(context)]; | ||
case 6: | ||
result = _a.sent(); | ||
_a.label = 7; | ||
result = _b.sent(); | ||
_b.label = 7; | ||
case 7: return [3 /*break*/, 12]; | ||
case 8: | ||
err_1 = _a.sent(); | ||
err_1 = _b.sent(); | ||
e = err_1 instanceof Error ? err_1 : new Error("".concat(err_1)); | ||
@@ -114,3 +114,3 @@ if (!(ctx.options.errorHandler != null)) return [3 /*break*/, 10]; | ||
case 9: | ||
result = _a.sent(); | ||
result = _b.sent(); | ||
return [3 /*break*/, 11]; | ||
@@ -125,3 +125,3 @@ case 10: throw new errors_1.CommandExecutionError(e, code); | ||
case 13: | ||
result = _a.sent(); | ||
result = _b.sent(); | ||
return [3 /*break*/, 15]; | ||
@@ -128,0 +128,0 @@ case 14: throw nerr; |
@@ -1,5 +0,4 @@ | ||
/// <reference types="node" /> | ||
import { UserOptions, Node, NonTextNode, CommandSummary } from './types'; | ||
import JSZip from 'jszip'; | ||
export declare function parseTemplate(template: Buffer): Promise<{ | ||
export declare function parseTemplate(template: ArrayBuffer): Promise<{ | ||
jsTemplate: Node; | ||
@@ -60,3 +59,3 @@ mainDocument: string; | ||
*/ | ||
export declare function listCommands(template: Buffer, delimiter?: string | [string, string]): Promise<CommandSummary[]>; | ||
export declare function listCommands(template: ArrayBuffer, delimiter?: string | [string, string]): Promise<CommandSummary[]>; | ||
/** | ||
@@ -66,3 +65,3 @@ * Extract metadata from a document, such as the number of pages or words. | ||
*/ | ||
export declare function getMetadata(template: Buffer): Promise<{ | ||
export declare function getMetadata(template: ArrayBuffer): Promise<{ | ||
pages: number | undefined; | ||
@@ -69,0 +68,0 @@ words: number | undefined; |
@@ -563,3 +563,3 @@ "use strict"; | ||
if (!(typeof result === 'object' && !Array.isArray(result))) return [3 /*break*/, 10]; | ||
nerr = new errors_1.ObjectCommandResultError(cmdRest); | ||
nerr = new errors_1.ObjectCommandResultError(cmdRest, result); | ||
if (!(ctx.options.errorHandler != null)) return [3 /*break*/, 9]; | ||
@@ -809,6 +809,6 @@ return [4 /*yield*/, ctx.options.errorHandler(nerr, cmdRest)]; | ||
function validateImage(img) { | ||
if (!(img.data instanceof Buffer || | ||
if (!(img.data instanceof Uint8Array || | ||
img.data instanceof ArrayBuffer || | ||
typeof img.data === 'string')) { | ||
throw new Error('image .data property needs to be provided as Buffer, ArrayBuffer, or as a base64-encoded string'); | ||
throw new Error('image .data property needs to be provided as Uint8Array (e.g. Buffer), ArrayBuffer, or as a base64-encoded string'); | ||
} | ||
@@ -815,0 +815,0 @@ if (!types_1.ImageExtensions.includes(img.extension)) { |
@@ -1,2 +0,1 @@ | ||
/// <reference types="node" /> | ||
import { QualifiedAttribute } from 'sax'; | ||
@@ -28,13 +27,13 @@ export type Node = TextNode | NonTextNode; | ||
type RunJSFunc = (o: { | ||
sandbox: Object; | ||
ctx: Object; | ||
sandbox: SandBox; | ||
ctx: Context; | ||
}) => { | ||
modifiedSandbox: Object; | ||
result: any; | ||
modifiedSandbox: SandBox; | ||
result: unknown; | ||
}; | ||
export type UserOptions = { | ||
/** | ||
* Docx file template as a NodeJS Buffer or Buffer-like object in Browsers. | ||
* Docx file template as a Uint8Array (or e.g. ArrayBuffer or NodeJS Buffer). | ||
*/ | ||
template: Buffer; | ||
template: Uint8Array; | ||
/** | ||
@@ -121,2 +120,7 @@ * Object of data to be injected or a (async) function that resolves to the data. The function gets as an argument the contents of the QUERY command as a string. | ||
}; | ||
export type SandBox = { | ||
__code__: string | undefined; | ||
__result__: unknown | undefined; | ||
[k: string]: unknown; | ||
}; | ||
export type Context = { | ||
@@ -155,3 +159,3 @@ gCntIf: number; | ||
options: CreateReportOptions; | ||
jsSandbox?: Object; | ||
jsSandbox?: SandBox; | ||
textRunPropsNode?: NonTextNode; | ||
@@ -166,3 +170,3 @@ }; | ||
extension: ImageExtension; | ||
data: Buffer | ArrayBuffer | string; | ||
data: ArrayBuffer | string; | ||
}; | ||
@@ -169,0 +173,0 @@ export type Links = { |
{ | ||
"name": "docx-templates", | ||
"version": "4.11.3", | ||
"version": "4.11.4", | ||
"description": "Template-based docx report creation", | ||
@@ -50,7 +50,7 @@ "main": "lib/index.js", | ||
"@types/jest": "^29.5.0", | ||
"@types/node": "^18.15.11", | ||
"@types/node": "^20", | ||
"@types/qrcode": "1.5.0", | ||
"@types/sax": "^1.2.4", | ||
"@typescript-eslint/eslint-plugin": "^5.57.1", | ||
"@typescript-eslint/parser": "^5.57.1", | ||
"@typescript-eslint/eslint-plugin": "^6.5.0", | ||
"@typescript-eslint/parser": "^6.5.0", | ||
"buffer": "^6.0.3", | ||
@@ -76,3 +76,3 @@ "coveralls": "^3.0.13", | ||
"ts-jest": "^29.1.0", | ||
"typescript": "^5.0.3", | ||
"typescript": "^5.2.2", | ||
"util": "^0.12.5", | ||
@@ -79,0 +79,0 @@ "vm-browserify": "^1.1.2" |
@@ -201,3 +201,3 @@ # Docx-templates [![Coverage Status](https://coveralls.io/repos/github/guigrpa/docx-templates/badge.svg?branch=master)](https://coveralls.io/github/guigrpa/docx-templates?branch=master) [![npm version](https://img.shields.io/npm/v/docx-templates.svg)](https://www.npmjs.com/package/docx-templates) | ||
## Polyfilled browser-ready bundle | ||
As this library depends on the internal NodeJS modules `vm`, `stream`, `util`, `events` and the `Buffer` global, your build tools have to polyfill these modules when using the library in the browser. We provide a browser build wich includes the required polyfills. Its file size is about 300K uncompressed or 85K / 70K with gzip / brotli compression). | ||
As this library depends on the internal NodeJS modules `vm`, `stream`, `util`, and `events`, your build tools have to polyfill these modules when using the library in the browser. We provide a browser build which includes the required polyfills. Its file size is about 300K uncompressed or 85K / 70K with gzip / brotli compression). | ||
@@ -210,3 +210,3 @@ You can import the library directly **as a module** using e.g. the unpkg.com CDN, like below, or you can host the `/lib/browser.js` bundle yourself. | ||
this is good for testing or prototyping but you should keep in mind that the `browser.js` is `es2017` code wich is supported by only 95% of users. If you have to support IE or old browser versions, you are better off compiling it to your target. Also see the support table for `es2017` [here](https://caniuse.com/sr_es8). | ||
this is good for testing or prototyping but you should keep in mind that the `browser.js` is `es2017` code which is supported by only 95% of users. If you have to support IE or old browser versions, you are better off compiling it to your target. Also see the support table for `es2017` [here](https://caniuse.com/sr_es8). | ||
@@ -448,2 +448,13 @@ ## Browser template compatibility caveat | ||
It is possible to get the current element index of the inner-most loop with the variable `$idx`, starting from `0`. For example: | ||
``` | ||
+++FOR company IN companies+++ | ||
Company (+++$idx+++): +++INS $company.name+++ | ||
Executives: | ||
+++FOR executive IN $company.executives+++ | ||
- +++$idx+++ +++$executive+++ | ||
+++END-FOR executive+++ | ||
+++END-FOR company+++ | ||
``` | ||
Since JavaScript expressions are supported, you can for example filter the loop domain: | ||
@@ -661,2 +672,2 @@ | ||
This Project is licensed under the MIT License. See [LICENSE](LICENSE) for more information. | ||
This Project is licensed under the MIT License. See [LICENSE](LICENSE) for more information. |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
1206099
3822
670