docx-templates
Advanced tools
Comparing version 4.2.0 to 4.3.0
@@ -0,1 +1,6 @@ | ||
## 4.3.0 (2020-06-23) | ||
* Feature: added `listCommands` function to find and list all commands in a document (see [issue #90](https://github.com/guigrpa/docx-templates/issues/90)). | ||
* Minor refactoring. | ||
* Updated jszip dependency. | ||
## 4.2.0 (2020-06-15) | ||
@@ -2,0 +7,0 @@ * Feature: added 'rejectNullish' setting. When set to `true`, this setting ensures `createReport` throws a `NullishCommandResultError` when the result of an INS, HTML, IMAGE, or LINK command is `null` or `undefined`. This is useful as nullish return values usually indicate a mistake in the template or the invoking code. Defaults to `false`. |
@@ -1,11 +0,6 @@ | ||
declare const _default: { | ||
info: { | ||
(...data: any[]): void; | ||
(message?: any, ...optionalParams: any[]): void; | ||
}; | ||
debug: { | ||
(...data: any[]): void; | ||
(message?: any, ...optionalParams: any[]): void; | ||
}; | ||
declare type LogSink = (message?: any, ...optionalParams: any[]) => void; | ||
export declare const logger: { | ||
debug: LogSink; | ||
}; | ||
export default _default; | ||
export declare function setDebugLogSink(f: LogSink): void; | ||
export {}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.default = { info: console.log, debug: console.log }; | ||
exports.setDebugLogSink = exports.logger = void 0; | ||
exports.logger = { debug: function () { } }; | ||
function setDebugLogSink(f) { | ||
exports.logger.debug = f; | ||
} | ||
exports.setDebugLogSink = setDebugLogSink; |
@@ -1,3 +0,3 @@ | ||
import createReport from './main'; | ||
export { createReport }; | ||
import createReport, { listCommands } from './main'; | ||
export { createReport, listCommands }; | ||
export default createReport; |
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); | ||
}) : (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
o[k2] = m[k]; | ||
})); | ||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { | ||
Object.defineProperty(o, "default", { enumerable: true, value: v }); | ||
}) : function(o, v) { | ||
o["default"] = v; | ||
}); | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
if (mod && mod.__esModule) return mod; | ||
var result = {}; | ||
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); | ||
__setModuleDefault(result, mod); | ||
return result; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.createReport = void 0; | ||
var main_1 = __importDefault(require("./main")); | ||
exports.listCommands = exports.createReport = void 0; | ||
var main_1 = __importStar(require("./main")); | ||
exports.createReport = main_1.default; | ||
Object.defineProperty(exports, "listCommands", { enumerable: true, get: function () { return main_1.listCommands; } }); | ||
exports.default = main_1.default; |
@@ -47,4 +47,3 @@ "use strict"; | ||
var errors_1 = require("./errors"); | ||
var DEBUG = process.env.DEBUG_DOCX_TEMPLATES; | ||
var log = DEBUG ? require('./debug').mainStory : null; | ||
var debug_1 = require("./debug"); | ||
// Runs a user snippet in a sandbox, and returns the result. | ||
@@ -100,3 +99,3 @@ // The snippet can return a Promise, which is then awaited. | ||
ctx.jsSandbox = timm_1.omit(context, ['__code__', '__result__']); | ||
DEBUG && log.debug('JS result', { attach: result }); | ||
debug_1.logger.debug('JS result', { attach: result }); | ||
return [2 /*return*/, result]; | ||
@@ -103,0 +102,0 @@ } |
@@ -1,2 +0,3 @@ | ||
import { UserOptions, Node, NonTextNode } from './types'; | ||
/// <reference types="node" /> | ||
import { UserOptions, Node, NonTextNode, CommandSummary } from './types'; | ||
import JSZip from 'jszip'; | ||
@@ -36,4 +37,22 @@ /** | ||
declare function createReport(options: UserOptions, _probe: 'XML'): Promise<string>; | ||
/** | ||
* Lists all the commands in a docx template. | ||
* | ||
* example: | ||
* ```js | ||
* const template_buffer = fs.readFileSync('template.docx'); | ||
* const commands = await listCommands(template_buffer, ['{', '}']); | ||
* // `commands` will contain something like: | ||
* [ | ||
* { raw: 'INS some_variable', code: 'some_variable', type: 'INS' }, | ||
* { raw: 'IMAGE svgImgFile()', code: 'svgImgFile()', type: 'IMAGE' }, | ||
* ] | ||
* ``` | ||
* | ||
* @param template the docx template as a Buffer-like object | ||
* @param delimiter the command delimiter (defaults to ['+++', '+++']) | ||
*/ | ||
export declare function listCommands(template: Buffer, delimiter?: string | [string, string]): Promise<CommandSummary[]>; | ||
export declare function readContentTypes(zip: JSZip): Promise<NonTextNode>; | ||
export declare function getMainDoc(contentTypes: NonTextNode): string; | ||
export default createReport; |
302
lib/main.js
@@ -42,3 +42,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.getMainDoc = exports.readContentTypes = void 0; | ||
exports.getMainDoc = exports.readContentTypes = exports.listCommands = void 0; | ||
var timm_1 = require("timm"); | ||
@@ -50,42 +50,20 @@ var zip_1 = require("./zip"); | ||
var reportUtils_1 = require("./reportUtils"); | ||
var debug_1 = __importDefault(require("./debug")); | ||
var errors_1 = require("./errors"); | ||
var debug_1 = require("./debug"); | ||
var DEFAULT_CMD_DELIMITER = '+++'; | ||
var DEFAULT_LITERAL_XML_DELIMITER = '||'; | ||
var CONTENT_TYPES_PATH = '[Content_Types].xml'; | ||
// TODO: remove | ||
var DEBUG = process.env.DEBUG_DOCX_TEMPLATES; | ||
function createReport(options, _probe) { | ||
var TEMPLATE_PATH = 'word'; | ||
function parseTemplate(template) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var template, data, queryVars, templatePath, literalXmlDelimiter, createOptions, xmlOptions, zip, contentTypes, mainDocument, templateXml, tic, parseResult, jsTemplate, tac, finalTemplate, queryResult, query, result, report1, images1, links1, htmls1, reportXml, numImages, numHtmls, files, images, links, htmls, i, filePath, raw, js0, js, result_1, report2, images2, links2, htmls2, xml, segments, documentComponent, ensureContentType, finalContentTypesXml, output; | ||
var _this = this; | ||
var zip, contentTypes, mainDocument, templateXml, tic, parseResult, jsTemplate, tac; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
DEBUG && debug_1.default.debug('Report options:', { attach: options }); | ||
template = options.template, data = options.data, queryVars = options.queryVars; | ||
templatePath = 'word'; | ||
literalXmlDelimiter = options.literalXmlDelimiter || DEFAULT_LITERAL_XML_DELIMITER; | ||
createOptions = { | ||
cmdDelimiter: getCmdDelimiter(options.cmdDelimiter), | ||
literalXmlDelimiter: literalXmlDelimiter, | ||
processLineBreaks: options.processLineBreaks != null ? options.processLineBreaks : true, | ||
noSandbox: options.noSandbox || false, | ||
runJs: options.runJs, | ||
additionalJsContext: options.additionalJsContext || {}, | ||
failFast: options.failFast == null ? true : options.failFast, | ||
rejectNullish: options.rejectNullish == null ? false : options.rejectNullish, | ||
}; | ||
xmlOptions = { literalXmlDelimiter: literalXmlDelimiter }; | ||
// --------------------------------------------------------- | ||
// Unzip | ||
// --------------------------------------------------------- | ||
DEBUG && debug_1.default.debug('Unzipping...'); | ||
debug_1.logger.debug('Unzipping...'); | ||
return [4 /*yield*/, zip_1.zipLoad(template)]; | ||
case 1: | ||
zip = _a.sent(); | ||
// --------------------------------------------------------- | ||
// Read the 'document.xml' file (the template) and parse it | ||
// --------------------------------------------------------- | ||
DEBUG && debug_1.default.debug('finding main template file (e.g. document.xml)'); | ||
debug_1.logger.debug('finding main template file (e.g. document.xml)'); | ||
return [4 /*yield*/, readContentTypes(zip)]; | ||
@@ -95,4 +73,4 @@ case 2: | ||
mainDocument = getMainDoc(contentTypes); | ||
DEBUG && debug_1.default.debug('Reading template...'); | ||
return [4 /*yield*/, zip_1.zipGetText(zip, templatePath + "/" + mainDocument)]; | ||
debug_1.logger.debug('Reading template...'); | ||
return [4 /*yield*/, zip_1.zipGetText(zip, TEMPLATE_PATH + "/" + mainDocument)]; | ||
case 3: | ||
@@ -102,4 +80,4 @@ templateXml = _a.sent(); | ||
throw new errors_1.TemplateParseError(mainDocument + " could not be found"); | ||
DEBUG && debug_1.default.debug("Template file length: " + templateXml.length); | ||
DEBUG && debug_1.default.debug('Parsing XML...'); | ||
debug_1.logger.debug("Template file length: " + templateXml.length); | ||
debug_1.logger.debug('Parsing XML...'); | ||
tic = new Date().getTime(); | ||
@@ -111,28 +89,52 @@ return [4 /*yield*/, xml_1.parseXml(templateXml)]; | ||
tac = new Date().getTime(); | ||
DEBUG && | ||
debug_1.default.debug("File parsed in " + (tac - tic) + " ms", { | ||
attach: jsTemplate, | ||
attachLevel: 'trace', | ||
}); | ||
// --------------------------------------------------------- | ||
// Preprocess template | ||
// --------------------------------------------------------- | ||
DEBUG && debug_1.default.debug('Preprocessing template...'); | ||
finalTemplate = preprocessTemplate_1.default(jsTemplate, createOptions); | ||
debug_1.logger.debug("File parsed in " + (tac - tic) + " ms", { | ||
attach: jsTemplate, | ||
attachLevel: 'trace', | ||
}); | ||
return [2 /*return*/, { jsTemplate: jsTemplate, mainDocument: mainDocument, zip: zip, contentTypes: contentTypes }]; | ||
} | ||
}); | ||
}); | ||
} | ||
function createReport(options, _probe) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var template, data, queryVars, literalXmlDelimiter, createOptions, xmlOptions, _a, jsTemplate, mainDocument, zip, contentTypes, finalTemplate, queryResult, query, result, report1, images1, links1, htmls1, reportXml, numImages, numHtmls, files, images, links, htmls, i, filePath, raw, js0, js, result_1, report2, images2, links2, htmls2, xml, segments, documentComponent, ensureContentType, finalContentTypesXml, output; | ||
var _this = this; | ||
return __generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: | ||
debug_1.logger.debug('Report options:', { attach: options }); | ||
template = options.template, data = options.data, queryVars = options.queryVars; | ||
literalXmlDelimiter = options.literalXmlDelimiter || DEFAULT_LITERAL_XML_DELIMITER; | ||
createOptions = { | ||
cmdDelimiter: getCmdDelimiter(options.cmdDelimiter), | ||
literalXmlDelimiter: literalXmlDelimiter, | ||
processLineBreaks: options.processLineBreaks != null ? options.processLineBreaks : true, | ||
noSandbox: options.noSandbox || false, | ||
runJs: options.runJs, | ||
additionalJsContext: options.additionalJsContext || {}, | ||
failFast: options.failFast == null ? true : options.failFast, | ||
rejectNullish: options.rejectNullish == null ? false : options.rejectNullish, | ||
}; | ||
xmlOptions = { literalXmlDelimiter: literalXmlDelimiter }; | ||
return [4 /*yield*/, parseTemplate(template)]; | ||
case 1: | ||
_a = _b.sent(), jsTemplate = _a.jsTemplate, mainDocument = _a.mainDocument, zip = _a.zip, contentTypes = _a.contentTypes; | ||
debug_1.logger.debug('Preprocessing template...'); | ||
finalTemplate = preprocessTemplate_1.default(jsTemplate, createOptions.cmdDelimiter); | ||
queryResult = null; | ||
if (!(typeof data === 'function')) return [3 /*break*/, 7]; | ||
DEBUG && debug_1.default.debug('Looking for the query in the template...'); | ||
if (!(typeof data === 'function')) return [3 /*break*/, 4]; | ||
debug_1.logger.debug('Looking for the query in the template...'); | ||
return [4 /*yield*/, processTemplate_1.extractQuery(finalTemplate, createOptions)]; | ||
case 5: | ||
query = _a.sent(); | ||
DEBUG && debug_1.default.debug("Query: " + (query || 'no query found')); | ||
case 2: | ||
query = _b.sent(); | ||
debug_1.logger.debug("Query: " + (query || 'no query found')); | ||
return [4 /*yield*/, data(query, queryVars)]; | ||
case 6: | ||
queryResult = _a.sent(); | ||
return [3 /*break*/, 8]; | ||
case 7: | ||
case 3: | ||
queryResult = _b.sent(); | ||
return [3 /*break*/, 5]; | ||
case 4: | ||
queryResult = data; | ||
_a.label = 8; | ||
case 8: | ||
// --------------------------------------------------------- | ||
_b.label = 5; | ||
case 5: | ||
// Process document.xml: | ||
@@ -142,7 +144,6 @@ // - Generate the report | ||
// - Images | ||
// --------------------------------------------------------- | ||
DEBUG && debug_1.default.debug('Generating report...'); | ||
debug_1.logger.debug('Generating report...'); | ||
return [4 /*yield*/, processTemplate_1.produceJsReport(queryResult, finalTemplate, createOptions)]; | ||
case 9: | ||
result = _a.sent(); | ||
case 6: | ||
result = _b.sent(); | ||
if (result.status === 'errors') { | ||
@@ -154,25 +155,19 @@ throw result.errors; | ||
return [2 /*return*/, report1]; | ||
// DEBUG && | ||
// log.debug('Report', { | ||
// attach: report, | ||
// attachLevel: 'debug', | ||
// ignoreKeys: ['_parent', '_fTextNode', '_attrs'], | ||
// }); | ||
DEBUG && debug_1.default.debug('Converting report to XML...'); | ||
debug_1.logger.debug('Converting report to XML...'); | ||
reportXml = xml_1.buildXml(report1, xmlOptions); | ||
if (_probe === 'XML') | ||
return [2 /*return*/, reportXml]; | ||
DEBUG && debug_1.default.debug('Writing report...'); | ||
zip_1.zipSetText(zip, templatePath + "/" + mainDocument, reportXml); | ||
debug_1.logger.debug('Writing report...'); | ||
zip_1.zipSetText(zip, TEMPLATE_PATH + "/" + mainDocument, reportXml); | ||
numImages = Object.keys(images1).length; | ||
numHtmls = Object.keys(htmls1).length; | ||
return [4 /*yield*/, processImages(images1, mainDocument, zip, templatePath)]; | ||
case 10: | ||
_a.sent(); | ||
return [4 /*yield*/, processLinks(links1, mainDocument, zip, templatePath)]; | ||
case 11: | ||
_a.sent(); | ||
return [4 /*yield*/, processHtmls(htmls1, mainDocument, zip, templatePath)]; | ||
case 12: | ||
_a.sent(); | ||
return [4 /*yield*/, processImages(images1, mainDocument, zip, TEMPLATE_PATH)]; | ||
case 7: | ||
_b.sent(); | ||
return [4 /*yield*/, processLinks(links1, mainDocument, zip, TEMPLATE_PATH)]; | ||
case 8: | ||
_b.sent(); | ||
return [4 /*yield*/, processHtmls(htmls1, mainDocument, zip, TEMPLATE_PATH)]; | ||
case 9: | ||
_b.sent(); | ||
files = []; | ||
@@ -182,6 +177,6 @@ zip.forEach(function (filePath) { return __awaiter(_this, void 0, void 0, function () { | ||
return __generator(this, function (_a) { | ||
regex = new RegExp(templatePath + "\\/[^\\/]+\\.xml"); | ||
regex = new RegExp(TEMPLATE_PATH + "\\/[^\\/]+\\.xml"); | ||
if (regex.test(filePath) && | ||
filePath !== templatePath + "/" + mainDocument && | ||
filePath.indexOf(templatePath + "/template") !== 0) { | ||
filePath !== TEMPLATE_PATH + "/" + mainDocument && | ||
filePath.indexOf(TEMPLATE_PATH + "/template") !== 0) { | ||
files.push(filePath); | ||
@@ -196,19 +191,19 @@ } | ||
i = 0; | ||
_a.label = 13; | ||
case 13: | ||
if (!(i < files.length)) return [3 /*break*/, 21]; | ||
_b.label = 10; | ||
case 10: | ||
if (!(i < files.length)) return [3 /*break*/, 18]; | ||
filePath = files[i]; | ||
DEBUG && debug_1.default.info("Processing " + filePath + "..."); | ||
debug_1.logger.debug("Processing " + filePath + "..."); | ||
return [4 /*yield*/, zip_1.zipGetText(zip, filePath)]; | ||
case 14: | ||
raw = _a.sent(); | ||
case 11: | ||
raw = _b.sent(); | ||
if (raw == null) | ||
throw new errors_1.TemplateParseError(filePath + " could not be read"); | ||
return [4 /*yield*/, xml_1.parseXml(raw)]; | ||
case 15: | ||
js0 = _a.sent(); | ||
js = preprocessTemplate_1.default(js0, createOptions); | ||
case 12: | ||
js0 = _b.sent(); | ||
js = preprocessTemplate_1.default(js0, createOptions.cmdDelimiter); | ||
return [4 /*yield*/, processTemplate_1.produceJsReport(queryResult, js, createOptions)]; | ||
case 16: | ||
result_1 = _a.sent(); | ||
case 13: | ||
result_1 = _b.sent(); | ||
if (result_1.status === 'errors') { | ||
@@ -227,21 +222,19 @@ throw result_1.errors; | ||
documentComponent = segments[segments.length - 1]; | ||
return [4 /*yield*/, processImages(images2, documentComponent, zip, templatePath)]; | ||
return [4 /*yield*/, processImages(images2, documentComponent, zip, TEMPLATE_PATH)]; | ||
case 14: | ||
_b.sent(); | ||
return [4 /*yield*/, processLinks(links2, mainDocument, zip, TEMPLATE_PATH)]; | ||
case 15: | ||
_b.sent(); | ||
return [4 /*yield*/, processHtmls(htmls2, mainDocument, zip, TEMPLATE_PATH)]; | ||
case 16: | ||
_b.sent(); | ||
_b.label = 17; | ||
case 17: | ||
_a.sent(); | ||
return [4 /*yield*/, processLinks(links2, mainDocument, zip, templatePath)]; | ||
i++; | ||
return [3 /*break*/, 10]; | ||
case 18: | ||
_a.sent(); | ||
return [4 /*yield*/, processHtmls(htmls2, mainDocument, zip, templatePath)]; | ||
case 19: | ||
_a.sent(); | ||
_a.label = 20; | ||
case 20: | ||
i++; | ||
return [3 /*break*/, 13]; | ||
case 21: | ||
// --------------------------------------------------------- | ||
// Process [Content_Types].xml | ||
// --------------------------------------------------------- | ||
if (numImages || numHtmls) { | ||
DEBUG && debug_1.default.debug('Completing [Content_Types].xml...'); | ||
debug_1.logger.debug('Completing [Content_Types].xml...'); | ||
ensureContentType = function (extension, contentType) { | ||
@@ -259,3 +252,3 @@ var children = contentTypes._children; | ||
if (numImages) { | ||
DEBUG && debug_1.default.debug('Completing [Content_Types].xml for IMAGES...'); | ||
debug_1.logger.debug('Completing [Content_Types].xml for IMAGES...'); | ||
ensureContentType('png', 'image/png'); | ||
@@ -269,3 +262,3 @@ ensureContentType('jpg', 'image/jpeg'); | ||
if (numHtmls) { | ||
DEBUG && debug_1.default.debug('Completing [Content_Types].xml for HTML...'); | ||
debug_1.logger.debug('Completing [Content_Types].xml for HTML...'); | ||
ensureContentType('html', 'text/html'); | ||
@@ -276,9 +269,6 @@ } | ||
} | ||
// --------------------------------------------------------- | ||
// Zip the results | ||
// --------------------------------------------------------- | ||
DEBUG && debug_1.default.debug('Zipping...'); | ||
debug_1.logger.debug('Zipping...'); | ||
return [4 /*yield*/, zip_1.zipSave(zip)]; | ||
case 22: | ||
output = _a.sent(); | ||
case 19: | ||
output = _b.sent(); | ||
return [2 /*return*/, output]; | ||
@@ -289,2 +279,67 @@ } | ||
} | ||
/** | ||
* Lists all the commands in a docx template. | ||
* | ||
* example: | ||
* ```js | ||
* const template_buffer = fs.readFileSync('template.docx'); | ||
* const commands = await listCommands(template_buffer, ['{', '}']); | ||
* // `commands` will contain something like: | ||
* [ | ||
* { raw: 'INS some_variable', code: 'some_variable', type: 'INS' }, | ||
* { raw: 'IMAGE svgImgFile()', code: 'svgImgFile()', type: 'IMAGE' }, | ||
* ] | ||
* ``` | ||
* | ||
* @param template the docx template as a Buffer-like object | ||
* @param delimiter the command delimiter (defaults to ['+++', '+++']) | ||
*/ | ||
function listCommands(template, delimiter) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var opts, jsTemplate, prepped, commands; | ||
var _this = this; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
opts = { | ||
cmdDelimiter: getCmdDelimiter(delimiter), | ||
// Otherwise unused but mandatory options | ||
literalXmlDelimiter: DEFAULT_LITERAL_XML_DELIMITER, | ||
processLineBreaks: true, | ||
noSandbox: false, | ||
additionalJsContext: {}, | ||
failFast: false, | ||
rejectNullish: false, | ||
}; | ||
return [4 /*yield*/, parseTemplate(template)]; | ||
case 1: | ||
jsTemplate = (_a.sent()).jsTemplate; | ||
debug_1.logger.debug('Preprocessing template...'); | ||
prepped = preprocessTemplate_1.default(jsTemplate, opts.cmdDelimiter); | ||
commands = []; | ||
return [4 /*yield*/, processTemplate_1.walkTemplate(undefined, prepped, opts, function (data, node, ctx) { return __awaiter(_this, void 0, void 0, function () { | ||
var raw, _a, cmdName, code, type; | ||
return __generator(this, function (_b) { | ||
raw = processTemplate_1.getCommand(ctx.cmd, ctx.shorthands); | ||
ctx.cmd = ''; // flush the context | ||
_a = processTemplate_1.splitCommand(raw), cmdName = _a.cmdName, code = _a.cmdRest; | ||
type = cmdName; | ||
if (type != null && type !== 'CMD_NODE') { | ||
commands.push({ | ||
raw: raw, | ||
type: type, | ||
code: code, | ||
}); | ||
} | ||
return [2 /*return*/, undefined]; | ||
}); | ||
}); })]; | ||
case 2: | ||
_a.sent(); | ||
return [2 /*return*/, commands]; | ||
} | ||
}); | ||
}); | ||
} | ||
exports.listCommands = listCommands; | ||
function readContentTypes(zip) { | ||
@@ -335,6 +390,6 @@ return __awaiter(this, void 0, void 0, function () { | ||
case 0: | ||
DEBUG && debug_1.default.debug("Processing images for " + documentComponent + "..."); | ||
debug_1.logger.debug("Processing images for " + documentComponent + "..."); | ||
imageIds = Object.keys(images); | ||
if (!imageIds.length) return [3 /*break*/, 2]; | ||
DEBUG && debug_1.default.debug('Completing document.xml.rels...'); | ||
debug_1.logger.debug('Completing document.xml.rels...'); | ||
relsPath = templatePath + "/_rels/" + documentComponent + ".rels"; | ||
@@ -348,3 +403,3 @@ return [4 /*yield*/, getRelsFromZip(zip, relsPath)]; | ||
imgName = "template_" + documentComponent + "_image" + (i + 1) + extension; | ||
DEBUG && debug_1.default.debug("Writing image " + imageId + " (" + imgName + ")..."); | ||
debug_1.logger.debug("Writing image " + imageId + " (" + imgName + ")..."); | ||
imgPath = templatePath + "/media/" + imgName; | ||
@@ -380,6 +435,6 @@ if (typeof imgData === 'string') { | ||
case 0: | ||
DEBUG && debug_1.default.debug("Processing links for " + documentComponent + "..."); | ||
debug_1.logger.debug("Processing links for " + documentComponent + "..."); | ||
linkIds = Object.keys(links); | ||
if (!linkIds.length) return [3 /*break*/, 2]; | ||
DEBUG && debug_1.default.debug('Completing document.xml.rels...'); | ||
debug_1.logger.debug('Completing document.xml.rels...'); | ||
relsPath = templatePath + "/_rels/" + documentComponent + ".rels"; | ||
@@ -413,7 +468,7 @@ return [4 /*yield*/, getRelsFromZip(zip, relsPath)]; | ||
case 0: | ||
DEBUG && debug_1.default.debug("Processing htmls for " + documentComponent + "..."); | ||
debug_1.logger.debug("Processing htmls for " + documentComponent + "..."); | ||
htmlIds = Object.keys(htmls); | ||
if (!htmlIds.length) return [3 /*break*/, 2]; | ||
// Process rels | ||
DEBUG && debug_1.default.debug("Completing document.xml.rels..."); | ||
debug_1.logger.debug("Completing document.xml.rels..."); | ||
htmlFiles = []; | ||
@@ -428,3 +483,3 @@ relsPath = templatePath + "/_rels/" + documentComponent + ".rels"; | ||
htmlName = "template_" + documentComponent + "_" + htmlId + ".html"; | ||
DEBUG && debug_1.default.debug("Writing html " + htmlId + " (" + htmlName + ")..."); | ||
debug_1.logger.debug("Writing html " + htmlId + " (" + htmlName + ")..."); | ||
htmlPath = templatePath + "/" + htmlName; | ||
@@ -472,5 +527,2 @@ htmlFiles.push("/" + htmlPath); | ||
}; | ||
// ========================================== | ||
// Public API | ||
// ========================================== | ||
exports.default = createReport; |
@@ -1,3 +0,3 @@ | ||
import { Node, CreateReportOptions } from './types'; | ||
declare const preprocessTemplate: (template: Node, options: CreateReportOptions) => Node; | ||
import { Node } from './types'; | ||
declare const preprocessTemplate: (template: Node, delimiter: [string, string]) => Node; | ||
export default preprocessTemplate; |
@@ -7,4 +7,3 @@ "use strict"; | ||
// at the starting node | ||
var preprocessTemplate = function (template, options) { | ||
var delimiter = options.cmdDelimiter; | ||
var preprocessTemplate = function (template, delimiter) { | ||
var node = template; | ||
@@ -11,0 +10,0 @@ var fCmd = false; |
@@ -1,3 +0,3 @@ | ||
import { Node, ReportData, CreateReportOptions, Images, Links, Htmls } from './types'; | ||
declare const extractQuery: (template: Node, options: CreateReportOptions) => Promise<string | undefined>; | ||
import { Node, ReportData, Context, CreateReportOptions, Images, Links, Htmls } from './types'; | ||
export declare function extractQuery(template: Node, options: CreateReportOptions): Promise<string | undefined>; | ||
declare type ReportOutput = { | ||
@@ -13,3 +13,10 @@ status: 'success'; | ||
}; | ||
declare const produceJsReport: (data: ReportData | undefined, template: Node, options: CreateReportOptions) => Promise<ReportOutput>; | ||
export { extractQuery, produceJsReport }; | ||
export declare function produceJsReport(data: ReportData | undefined, template: Node, options: CreateReportOptions): Promise<ReportOutput>; | ||
export declare function walkTemplate(data: ReportData | undefined, template: Node, options: CreateReportOptions, processor: CommandProcessor): Promise<ReportOutput>; | ||
declare type CommandProcessor = (data: ReportData | undefined, node: Node, ctx: Context) => Promise<undefined | string | Error>; | ||
export declare function getCommand(command: string, shorthands: Context['shorthands']): string; | ||
export declare function splitCommand(cmd: string): { | ||
cmdName: string | undefined; | ||
cmdRest: string; | ||
}; | ||
export {}; |
@@ -39,324 +39,334 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.produceJsReport = exports.extractQuery = void 0; | ||
exports.splitCommand = exports.getCommand = exports.walkTemplate = exports.produceJsReport = exports.extractQuery = void 0; | ||
var reportUtils_1 = require("./reportUtils"); | ||
var jsSandbox_1 = require("./jsSandbox"); | ||
var types_1 = require("./types"); | ||
var errors_1 = require("./errors"); | ||
var DEBUG = process.env.DEBUG_DOCX_TEMPLATES; | ||
var log = DEBUG ? require('./debug').mainStory : null; | ||
var gCntIf = 0; | ||
var debug_1 = require("./debug"); | ||
function newContext(options) { | ||
return { | ||
gCntIf: 0, | ||
level: 1, | ||
fCmd: false, | ||
cmd: '', | ||
fSeekQuery: false, | ||
buffers: { | ||
'w:p': { text: '', cmds: '', fInsertedText: false }, | ||
'w:tr': { text: '', cmds: '', fInsertedText: false }, | ||
}, | ||
imageId: 0, | ||
images: {}, | ||
linkId: 0, | ||
links: {}, | ||
htmlId: 0, | ||
htmls: {}, | ||
vars: {}, | ||
loops: [], | ||
fJump: false, | ||
shorthands: {}, | ||
options: options, | ||
}; | ||
} | ||
// Go through the document until the query string is found (normally at the beginning) | ||
var extractQuery = function (template, options) { return __awaiter(void 0, void 0, void 0, function () { | ||
var ctx, nodeIn, fFound, parent_1, nextSibling, parent_2; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
ctx = { | ||
fCmd: false, | ||
cmd: '', | ||
fSeekQuery: true, | ||
query: null, | ||
loops: [], | ||
options: options, | ||
}; | ||
nodeIn = template; | ||
_a.label = 1; | ||
case 1: | ||
if (!true) return [3 /*break*/, 4]; | ||
// Move down | ||
if (nodeIn._children.length) | ||
nodeIn = nodeIn._children[0]; | ||
else { | ||
fFound = false; | ||
while (nodeIn._parent != null) { | ||
parent_1 = nodeIn._parent; | ||
nextSibling = reportUtils_1.getNextSibling(nodeIn); | ||
if (nextSibling) { | ||
nodeIn = nextSibling; | ||
fFound = true; | ||
break; | ||
function extractQuery(template, options) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var ctx, nodeIn, fFound, parent_1, nextSibling, parent_2; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
ctx = newContext(options); | ||
// ensure no command will be processed, except QUERY | ||
ctx.fSeekQuery = true; | ||
nodeIn = template; | ||
_a.label = 1; | ||
case 1: | ||
if (!true) return [3 /*break*/, 4]; | ||
// Move down | ||
if (nodeIn._children.length) | ||
nodeIn = nodeIn._children[0]; | ||
else { | ||
fFound = false; | ||
while (nodeIn._parent != null) { | ||
parent_1 = nodeIn._parent; | ||
nextSibling = reportUtils_1.getNextSibling(nodeIn); | ||
if (nextSibling) { | ||
nodeIn = nextSibling; | ||
fFound = true; | ||
break; | ||
} | ||
nodeIn = parent_1; | ||
} | ||
nodeIn = parent_1; | ||
if (!fFound) | ||
return [3 /*break*/, 4]; | ||
} | ||
if (!fFound) | ||
if (!nodeIn) | ||
return [3 /*break*/, 4]; | ||
} | ||
if (!nodeIn) | ||
return [3 /*break*/, 4]; | ||
parent_2 = nodeIn._parent; | ||
if (!(nodeIn._fTextNode && | ||
parent_2 && | ||
!parent_2._fTextNode && // Flow, don't complain | ||
parent_2._tag === 'w:t')) return [3 /*break*/, 3]; | ||
return [4 /*yield*/, processText(null, nodeIn, ctx)]; | ||
case 2: | ||
_a.sent(); | ||
_a.label = 3; | ||
case 3: | ||
if (ctx.query != null) | ||
return [3 /*break*/, 4]; | ||
return [3 /*break*/, 1]; | ||
case 4: return [2 /*return*/, ctx.query]; | ||
} | ||
parent_2 = nodeIn._parent; | ||
if (!(nodeIn._fTextNode && | ||
parent_2 && | ||
!parent_2._fTextNode && // Flow, don't complain | ||
parent_2._tag === 'w:t')) return [3 /*break*/, 3]; | ||
return [4 /*yield*/, processText(null, nodeIn, ctx, processCmd)]; | ||
case 2: | ||
_a.sent(); | ||
_a.label = 3; | ||
case 3: | ||
if (ctx.query != null) | ||
return [3 /*break*/, 4]; | ||
return [3 /*break*/, 1]; | ||
case 4: return [2 /*return*/, ctx.query]; | ||
} | ||
}); | ||
}); | ||
}); }; | ||
} | ||
exports.extractQuery = extractQuery; | ||
var produceJsReport = function (data, template, options) { return __awaiter(void 0, void 0, void 0, function () { | ||
var out, ctx, nodeIn, nodeOut, move, deltaJump, errors, curLoop, nextSibling, refNode, refNodeLevel, parent_3, tag, fRemoveNode, buffers, nodeOutParent, imgNode, parent_4, linkNode, parent_5, htmlNode, parent_6, tag, newNode, parent_7, result, newNodeAsTextNode; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
out = reportUtils_1.cloneNodeWithoutChildren(template); | ||
ctx = { | ||
level: 1, | ||
fCmd: false, | ||
cmd: '', | ||
fSeekQuery: false, | ||
buffers: { | ||
'w:p': { text: '', cmds: '', fInsertedText: false }, | ||
'w:tr': { text: '', cmds: '', fInsertedText: false }, | ||
}, | ||
imageId: 0, | ||
images: {}, | ||
linkId: 0, | ||
links: {}, | ||
htmlId: 0, | ||
htmls: {}, | ||
vars: {}, | ||
loops: [], | ||
fJump: false, | ||
shorthands: {}, | ||
options: options, | ||
}; | ||
nodeIn = template; | ||
nodeOut = out; | ||
deltaJump = 0; | ||
errors = []; | ||
_a.label = 1; | ||
case 1: | ||
if (!true) return [3 /*break*/, 5]; | ||
curLoop = reportUtils_1.getCurLoop(ctx); | ||
nextSibling = void 0; | ||
// ============================================= | ||
// Move input node pointer | ||
// ============================================= | ||
if (ctx.fJump) { | ||
if (!curLoop) | ||
throw new errors_1.InternalError(); | ||
refNode = curLoop.refNode, refNodeLevel = curLoop.refNodeLevel; | ||
// DEBUG && | ||
// log.debug(`Jumping to level ${refNodeLevel}...`, { | ||
// attach: cloneNodeForLogging(refNode), | ||
// }); | ||
deltaJump = ctx.level - refNodeLevel; | ||
nodeIn = refNode; | ||
ctx.level = refNodeLevel; | ||
ctx.fJump = false; | ||
move = 'JUMP'; | ||
// Down (only if he haven't just moved up) | ||
} | ||
else if (nodeIn._children.length && move !== 'UP') { | ||
nodeIn = nodeIn._children[0]; | ||
ctx.level += 1; | ||
move = 'DOWN'; | ||
// Sideways | ||
} | ||
else if ((nextSibling = reportUtils_1.getNextSibling(nodeIn))) { | ||
nodeIn = nextSibling; | ||
move = 'SIDE'; | ||
// Up | ||
} | ||
else { | ||
parent_3 = nodeIn._parent; | ||
if (parent_3 == null) | ||
return [3 /*break*/, 5]; | ||
nodeIn = parent_3; | ||
ctx.level -= 1; | ||
move = 'UP'; | ||
} | ||
// DEBUG && | ||
// log.debug( | ||
// `Next node [${chalk.green.bold(move)}, level ${chalk.dim(ctx.level)}]`, | ||
// { attach: cloneNodeForLogging(nodeIn) } | ||
// ); | ||
// ============================================= | ||
// Process input node | ||
// ============================================= | ||
// Delete the last generated output node in several special cases | ||
// -------------------------------------------------------------- | ||
if (move !== 'DOWN') { | ||
tag = nodeOut._fTextNode ? null : nodeOut._tag; | ||
fRemoveNode = false; | ||
// Delete last generated output node if we're skipping nodes due to an empty FOR loop | ||
if ((tag === 'w:p' || tag === 'w:tbl' || tag === 'w:tr') && | ||
reportUtils_1.isLoopExploring(ctx)) { | ||
fRemoveNode = true; | ||
// Delete last generated output node if the user inserted a paragraph | ||
// (or table row) with just a command | ||
function produceJsReport(data, template, options) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
return __generator(this, function (_a) { | ||
return [2 /*return*/, walkTemplate(data, template, options, processCmd)]; | ||
}); | ||
}); | ||
} | ||
exports.produceJsReport = produceJsReport; | ||
function walkTemplate(data, template, options, processor) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var out, ctx, nodeIn, nodeOut, move, deltaJump, errors, curLoop, nextSibling, refNode, refNodeLevel, parent_3, tag, fRemoveNode, buffers, nodeOutParent, imgNode, parent_4, linkNode, parent_5, htmlNode, parent_6, tag, newNode, parent_7, result, newNodeAsTextNode; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
out = reportUtils_1.cloneNodeWithoutChildren(template); | ||
ctx = newContext(options); | ||
nodeIn = template; | ||
nodeOut = out; | ||
deltaJump = 0; | ||
errors = []; | ||
_a.label = 1; | ||
case 1: | ||
if (!true) return [3 /*break*/, 5]; | ||
curLoop = reportUtils_1.getCurLoop(ctx); | ||
nextSibling = void 0; | ||
// ============================================= | ||
// Move input node pointer | ||
// ============================================= | ||
if (ctx.fJump) { | ||
if (!curLoop) | ||
throw new errors_1.InternalError(); | ||
refNode = curLoop.refNode, refNodeLevel = curLoop.refNodeLevel; | ||
// | ||
// logger.debug(`Jumping to level ${refNodeLevel}...`, { | ||
// attach: cloneNodeForLogging(refNode), | ||
// }); | ||
deltaJump = ctx.level - refNodeLevel; | ||
nodeIn = refNode; | ||
ctx.level = refNodeLevel; | ||
ctx.fJump = false; | ||
move = 'JUMP'; | ||
// Down (only if he haven't just moved up) | ||
} | ||
else if (tag === 'w:p' || tag === 'w:tr') { | ||
buffers = ctx.buffers[tag]; | ||
fRemoveNode = | ||
buffers.text === '' && buffers.cmds !== '' && !buffers.fInsertedText; | ||
else if (nodeIn._children.length && move !== 'UP') { | ||
nodeIn = nodeIn._children[0]; | ||
ctx.level += 1; | ||
move = 'DOWN'; | ||
// Sideways | ||
} | ||
// Execute removal, if needed. The node will no longer be part of the output, but | ||
// the parent will be accessible from the child (so that we can still move up the tree) | ||
if (fRemoveNode && nodeOut._parent != null) { | ||
nodeOut._parent._children.pop(); | ||
else if ((nextSibling = reportUtils_1.getNextSibling(nodeIn))) { | ||
nodeIn = nextSibling; | ||
move = 'SIDE'; | ||
// Up | ||
} | ||
} | ||
// Handle an UP movement | ||
// --------------------- | ||
if (move === 'UP') { | ||
// Loop exploring? Update the reference node for the current loop | ||
if (reportUtils_1.isLoopExploring(ctx) && | ||
curLoop && // Flow, don't complain | ||
nodeIn === curLoop.refNode._parent) { | ||
curLoop.refNode = nodeIn; | ||
curLoop.refNodeLevel -= 1; | ||
// DEBUG && | ||
// log.debug(`Updated loop '${curLoop.varName}' refNode:`, { | ||
// attach: cloneNodeForLogging(nodeIn), | ||
// }); | ||
else { | ||
parent_3 = nodeIn._parent; | ||
if (parent_3 == null) | ||
return [3 /*break*/, 5]; | ||
nodeIn = parent_3; | ||
ctx.level -= 1; | ||
move = 'UP'; | ||
} | ||
nodeOutParent = nodeOut._parent; | ||
if (nodeOutParent == null) | ||
throw new errors_1.InternalError(); | ||
// Execute the move in the output tree | ||
nodeOut = nodeOutParent; | ||
// If an image was generated, replace the parent `w:t` node with | ||
// the image node | ||
if (ctx.pendingImageNode && | ||
!nodeOut._fTextNode && // Flow-prevention | ||
nodeOut._tag === 'w:t') { | ||
imgNode = ctx.pendingImageNode; | ||
parent_4 = nodeOut._parent; | ||
if (parent_4) { | ||
imgNode._parent = parent_4; | ||
parent_4._children.pop(); | ||
parent_4._children.push(imgNode); | ||
// Prevent containing paragraph or table row from being removed | ||
ctx.buffers['w:p'].fInsertedText = true; | ||
ctx.buffers['w:tr'].fInsertedText = true; | ||
// | ||
// logger.debug( | ||
// `Next node [${chalk.green.bold(move)}, level ${chalk.dim(ctx.level)}]`, | ||
// { attach: cloneNodeForLogging(nodeIn) } | ||
// ); | ||
// ============================================= | ||
// Process input node | ||
// ============================================= | ||
// Delete the last generated output node in several special cases | ||
// -------------------------------------------------------------- | ||
if (move !== 'DOWN') { | ||
tag = nodeOut._fTextNode ? null : nodeOut._tag; | ||
fRemoveNode = false; | ||
// Delete last generated output node if we're skipping nodes due to an empty FOR loop | ||
if ((tag === 'w:p' || tag === 'w:tbl' || tag === 'w:tr') && | ||
reportUtils_1.isLoopExploring(ctx)) { | ||
fRemoveNode = true; | ||
// Delete last generated output node if the user inserted a paragraph | ||
// (or table row) with just a command | ||
} | ||
delete ctx.pendingImageNode; | ||
} | ||
// If a link was generated, replace the parent `w:r` node with | ||
// the link node | ||
if (ctx.pendingLinkNode && | ||
!nodeOut._fTextNode && // Flow-prevention | ||
nodeOut._tag === 'w:r') { | ||
linkNode = ctx.pendingLinkNode; | ||
parent_5 = nodeOut._parent; | ||
if (parent_5) { | ||
linkNode._parent = parent_5; | ||
parent_5._children.pop(); | ||
parent_5._children.push(linkNode); | ||
// Prevent containing paragraph or table row from being removed | ||
ctx.buffers['w:p'].fInsertedText = true; | ||
ctx.buffers['w:tr'].fInsertedText = true; | ||
else if (tag === 'w:p' || tag === 'w:tr') { | ||
buffers = ctx.buffers[tag]; | ||
fRemoveNode = | ||
buffers.text === '' && buffers.cmds !== '' && !buffers.fInsertedText; | ||
} | ||
delete ctx.pendingLinkNode; | ||
// Execute removal, if needed. The node will no longer be part of the output, but | ||
// the parent will be accessible from the child (so that we can still move up the tree) | ||
if (fRemoveNode && nodeOut._parent != null) { | ||
nodeOut._parent._children.pop(); | ||
} | ||
} | ||
// If a html page was generated, replace the parent `w:p` node with | ||
// the html node | ||
if (ctx.pendingHtmlNode && | ||
!nodeOut._fTextNode && // Flow-prevention | ||
nodeOut._tag === 'w:p') { | ||
htmlNode = ctx.pendingHtmlNode; | ||
parent_6 = nodeOut._parent; | ||
if (parent_6) { | ||
htmlNode._parent = parent_6; | ||
parent_6._children.pop(); | ||
parent_6._children.push(htmlNode); | ||
// Prevent containing paragraph or table row from being removed | ||
ctx.buffers['w:p'].fInsertedText = true; | ||
ctx.buffers['w:tr'].fInsertedText = true; | ||
// Handle an UP movement | ||
// --------------------- | ||
if (move === 'UP') { | ||
// Loop exploring? Update the reference node for the current loop | ||
if (reportUtils_1.isLoopExploring(ctx) && | ||
curLoop && // Flow, don't complain | ||
nodeIn === curLoop.refNode._parent) { | ||
curLoop.refNode = nodeIn; | ||
curLoop.refNodeLevel -= 1; | ||
// | ||
// logger.debug(`Updated loop '${curLoop.varName}' refNode:`, { | ||
// attach: cloneNodeForLogging(nodeIn), | ||
// }); | ||
} | ||
delete ctx.pendingHtmlNode; | ||
nodeOutParent = nodeOut._parent; | ||
if (nodeOutParent == null) | ||
throw new errors_1.InternalError(); | ||
// Execute the move in the output tree | ||
nodeOut = nodeOutParent; | ||
// If an image was generated, replace the parent `w:t` node with | ||
// the image node | ||
if (ctx.pendingImageNode && | ||
!nodeOut._fTextNode && // Flow-prevention | ||
nodeOut._tag === 'w:t') { | ||
imgNode = ctx.pendingImageNode; | ||
parent_4 = nodeOut._parent; | ||
if (parent_4) { | ||
imgNode._parent = parent_4; | ||
parent_4._children.pop(); | ||
parent_4._children.push(imgNode); | ||
// Prevent containing paragraph or table row from being removed | ||
ctx.buffers['w:p'].fInsertedText = true; | ||
ctx.buffers['w:tr'].fInsertedText = true; | ||
} | ||
delete ctx.pendingImageNode; | ||
} | ||
// If a link was generated, replace the parent `w:r` node with | ||
// the link node | ||
if (ctx.pendingLinkNode && | ||
!nodeOut._fTextNode && // Flow-prevention | ||
nodeOut._tag === 'w:r') { | ||
linkNode = ctx.pendingLinkNode; | ||
parent_5 = nodeOut._parent; | ||
if (parent_5) { | ||
linkNode._parent = parent_5; | ||
parent_5._children.pop(); | ||
parent_5._children.push(linkNode); | ||
// Prevent containing paragraph or table row from being removed | ||
ctx.buffers['w:p'].fInsertedText = true; | ||
ctx.buffers['w:tr'].fInsertedText = true; | ||
} | ||
delete ctx.pendingLinkNode; | ||
} | ||
// If a html page was generated, replace the parent `w:p` node with | ||
// the html node | ||
if (ctx.pendingHtmlNode && | ||
!nodeOut._fTextNode && // Flow-prevention | ||
nodeOut._tag === 'w:p') { | ||
htmlNode = ctx.pendingHtmlNode; | ||
parent_6 = nodeOut._parent; | ||
if (parent_6) { | ||
htmlNode._parent = parent_6; | ||
parent_6._children.pop(); | ||
parent_6._children.push(htmlNode); | ||
// Prevent containing paragraph or table row from being removed | ||
ctx.buffers['w:p'].fInsertedText = true; | ||
ctx.buffers['w:tr'].fInsertedText = true; | ||
} | ||
delete ctx.pendingHtmlNode; | ||
} | ||
// `w:tc` nodes shouldn't be left with no `w:p` children; if that's the | ||
// case, add an empty `w:p` inside | ||
if (!nodeOut._fTextNode && // Flow-prevention | ||
nodeOut._tag === 'w:tc' && | ||
!nodeOut._children.filter(function (o) { return !o._fTextNode && o._tag === 'w:p'; }).length) { | ||
nodeOut._children.push({ | ||
_parent: nodeOut, | ||
_children: [], | ||
_fTextNode: false, | ||
_tag: 'w:p', | ||
_attrs: {}, | ||
}); | ||
} | ||
// Save latest `w:rPr` node that was visited (for LINK properties) | ||
if (!nodeIn._fTextNode && nodeIn._tag === 'w:rPr') { | ||
ctx.textRunPropsNode = nodeIn; | ||
} | ||
if (!nodeIn._fTextNode && nodeIn._tag === 'w:r') { | ||
delete ctx.textRunPropsNode; | ||
} | ||
} | ||
// `w:tc` nodes shouldn't be left with no `w:p` children; if that's the | ||
// case, add an empty `w:p` inside | ||
if (!nodeOut._fTextNode && // Flow-prevention | ||
nodeOut._tag === 'w:tc' && | ||
!nodeOut._children.filter(function (o) { return !o._fTextNode && o._tag === 'w:p'; }).length) { | ||
nodeOut._children.push({ | ||
_parent: nodeOut, | ||
_children: [], | ||
_fTextNode: false, | ||
_tag: 'w:p', | ||
_attrs: {}, | ||
}); | ||
} | ||
// Save latest `w:rPr` node that was visited (for LINK properties) | ||
if (!nodeIn._fTextNode && nodeIn._tag === 'w:rPr') { | ||
ctx.textRunPropsNode = nodeIn; | ||
} | ||
if (!nodeIn._fTextNode && nodeIn._tag === 'w:r') { | ||
delete ctx.textRunPropsNode; | ||
} | ||
} | ||
if (!(move === 'DOWN' || move === 'SIDE')) return [3 /*break*/, 4]; | ||
// Move nodeOut to point to the new node's parent | ||
if (move === 'SIDE') { | ||
if (nodeOut._parent == null) | ||
throw new errors_1.InternalError(); | ||
nodeOut = nodeOut._parent; | ||
} | ||
tag = nodeIn._fTextNode ? null : nodeIn._tag; | ||
if (tag === 'w:p' || tag === 'w:tr') { | ||
ctx.buffers[tag] = { text: '', cmds: '', fInsertedText: false }; | ||
} | ||
newNode = reportUtils_1.cloneNodeWithoutChildren(nodeIn); | ||
newNode._parent = nodeOut; | ||
nodeOut._children.push(newNode); | ||
parent_7 = nodeIn._parent; | ||
if (!(nodeIn._fTextNode && | ||
parent_7 && | ||
!parent_7._fTextNode && | ||
parent_7._tag === 'w:t')) return [3 /*break*/, 3]; | ||
return [4 /*yield*/, processText(data, nodeIn, ctx)]; | ||
case 2: | ||
result = _a.sent(); | ||
if (typeof result === 'string') { | ||
newNodeAsTextNode = newNode; | ||
newNodeAsTextNode._text = result; | ||
} | ||
else { | ||
errors.push.apply(errors, result); | ||
} | ||
_a.label = 3; | ||
case 3: | ||
// Execute the move in the output tree | ||
nodeOut = newNode; | ||
_a.label = 4; | ||
case 4: | ||
// Correct output tree level in case of a JUMP | ||
// ------------------------------------------- | ||
if (move === 'JUMP') { | ||
while (deltaJump > 0) { | ||
if (!(move === 'DOWN' || move === 'SIDE')) return [3 /*break*/, 4]; | ||
// Move nodeOut to point to the new node's parent | ||
if (move === 'SIDE') { | ||
if (nodeOut._parent == null) | ||
throw new errors_1.InternalError(); | ||
nodeOut = nodeOut._parent; | ||
deltaJump -= 1; | ||
} | ||
} | ||
return [3 /*break*/, 1]; | ||
case 5: | ||
if (errors.length > 0) | ||
tag = nodeIn._fTextNode ? null : nodeIn._tag; | ||
if (tag === 'w:p' || tag === 'w:tr') { | ||
ctx.buffers[tag] = { text: '', cmds: '', fInsertedText: false }; | ||
} | ||
newNode = reportUtils_1.cloneNodeWithoutChildren(nodeIn); | ||
newNode._parent = nodeOut; | ||
nodeOut._children.push(newNode); | ||
parent_7 = nodeIn._parent; | ||
if (!(nodeIn._fTextNode && | ||
parent_7 && | ||
!parent_7._fTextNode && | ||
parent_7._tag === 'w:t')) return [3 /*break*/, 3]; | ||
return [4 /*yield*/, processText(data, nodeIn, ctx, processor)]; | ||
case 2: | ||
result = _a.sent(); | ||
if (typeof result === 'string') { | ||
newNodeAsTextNode = newNode; | ||
newNodeAsTextNode._text = result; | ||
} | ||
else { | ||
errors.push.apply(errors, result); | ||
} | ||
_a.label = 3; | ||
case 3: | ||
// Execute the move in the output tree | ||
nodeOut = newNode; | ||
_a.label = 4; | ||
case 4: | ||
// Correct output tree level in case of a JUMP | ||
// ------------------------------------------- | ||
if (move === 'JUMP') { | ||
while (deltaJump > 0) { | ||
if (nodeOut._parent == null) | ||
throw new errors_1.InternalError(); | ||
nodeOut = nodeOut._parent; | ||
deltaJump -= 1; | ||
} | ||
} | ||
return [3 /*break*/, 1]; | ||
case 5: | ||
if (errors.length > 0) | ||
return [2 /*return*/, { | ||
status: 'errors', | ||
errors: errors, | ||
}]; | ||
return [2 /*return*/, { | ||
status: 'errors', | ||
errors: errors, | ||
status: 'success', | ||
report: out, | ||
images: ctx.images, | ||
links: ctx.links, | ||
htmls: ctx.htmls, | ||
}]; | ||
return [2 /*return*/, { | ||
status: 'success', | ||
report: out, | ||
images: ctx.images, | ||
links: ctx.links, | ||
htmls: ctx.htmls, | ||
}]; | ||
} | ||
} | ||
}); | ||
}); | ||
}); }; | ||
exports.produceJsReport = produceJsReport; | ||
var processText = function (data, node, ctx) { return __awaiter(void 0, void 0, void 0, function () { | ||
} | ||
exports.walkTemplate = walkTemplate; | ||
var processText = function (data, node, ctx, onCommand) { return __awaiter(void 0, void 0, void 0, function () { | ||
var _a, cmdDelimiter, failFast, text, segments, outText, errors, idx, segment, cmdResultText; | ||
@@ -384,3 +394,3 @@ return __generator(this, function (_b) { | ||
segment = segments[idx]; | ||
// DEBUG && log.debug(`Token: '${segment}' (${ctx.fCmd})`); | ||
// logger.debug(`Token: '${segment}' (${ctx.fCmd})`); | ||
if (ctx.fCmd) | ||
@@ -393,3 +403,3 @@ ctx.cmd += segment; | ||
if (!ctx.fCmd) return [3 /*break*/, 3]; | ||
return [4 /*yield*/, processCmd(data, node, ctx)]; | ||
return [4 /*yield*/, onCommand(data, node, ctx)]; | ||
case 2: | ||
@@ -429,18 +439,13 @@ cmdResultText = _b.sent(); | ||
var processCmd = function (data, node, ctx) { return __awaiter(void 0, void 0, void 0, function () { | ||
var cmd, cmdNameMatch, cmdName, cmdRest, aliasMatch, aliasName, fullCmd, result, str, literalXmlDelimiter, img, e_1, pars, html, err_1; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
var cmd, _a, cmdName, cmdRest, aliasMatch, aliasName, fullCmd, result, str, literalXmlDelimiter, img, e_1, pars, html, err_1; | ||
return __generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: | ||
cmd = getCommand(ctx); | ||
DEBUG && log.debug("Processing cmd: " + cmd); | ||
_a.label = 1; | ||
cmd = getCommand(ctx.cmd, ctx.shorthands); | ||
ctx.cmd = ''; // flush the context | ||
debug_1.logger.debug("Processing cmd: " + cmd); | ||
_b.label = 1; | ||
case 1: | ||
_a.trys.push([1, 28, , 29]); | ||
cmdNameMatch = /^(\S+)\s*/.exec(cmd); | ||
cmdName = void 0; | ||
cmdRest = ''; | ||
if (cmdNameMatch != null) { | ||
cmdName = cmdNameMatch[1].toUpperCase(); | ||
cmdRest = cmd.slice(cmdName.length).trim(); | ||
} | ||
_b.trys.push([1, 28, , 29]); | ||
_a = splitCommand(cmd), cmdName = _a.cmdName, cmdRest = _a.cmdRest; | ||
// Seeking query? | ||
@@ -462,3 +467,3 @@ if (ctx.fSeekQuery) { | ||
ctx.shorthands[aliasName] = fullCmd; | ||
DEBUG && log.debug("Defined alias '" + aliasName + "' for: " + fullCmd); | ||
debug_1.logger.debug("Defined alias '" + aliasName + "' for: " + fullCmd); | ||
return [3 /*break*/, 27]; | ||
@@ -469,3 +474,3 @@ case 3: | ||
case 4: | ||
_a.sent(); | ||
_b.sent(); | ||
return [3 /*break*/, 27]; | ||
@@ -481,3 +486,3 @@ case 5: | ||
case 7: | ||
result = _a.sent(); | ||
result = _b.sent(); | ||
if (result == null) { | ||
@@ -501,4 +506,4 @@ if (ctx.options.rejectNullish) { | ||
case 10: | ||
_a.sent(); | ||
_a.label = 11; | ||
_b.sent(); | ||
_b.label = 11; | ||
case 11: return [3 /*break*/, 27]; | ||
@@ -510,3 +515,3 @@ case 12: | ||
case 13: | ||
img = _a.sent(); | ||
img = _b.sent(); | ||
if (ctx.options.rejectNullish && img == null) { | ||
@@ -516,11 +521,11 @@ throw new errors_1.NullishCommandResultError(cmdRest); | ||
if (!(img != null)) return [3 /*break*/, 17]; | ||
_a.label = 14; | ||
_b.label = 14; | ||
case 14: | ||
_a.trys.push([14, 16, , 17]); | ||
_b.trys.push([14, 16, , 17]); | ||
return [4 /*yield*/, processImage(ctx, img)]; | ||
case 15: | ||
_a.sent(); | ||
_b.sent(); | ||
return [3 /*break*/, 17]; | ||
case 16: | ||
e_1 = _a.sent(); | ||
e_1 = _b.sent(); | ||
throw new errors_1.ImageError(e_1.message, cmd); | ||
@@ -533,3 +538,3 @@ case 17: return [3 /*break*/, 27]; | ||
case 19: | ||
pars = _a.sent(); | ||
pars = _b.sent(); | ||
if (ctx.options.rejectNullish && pars == null) { | ||
@@ -541,4 +546,4 @@ throw new errors_1.NullishCommandResultError(cmdRest); | ||
case 20: | ||
_a.sent(); | ||
_a.label = 21; | ||
_b.sent(); | ||
_b.label = 21; | ||
case 21: return [3 /*break*/, 27]; | ||
@@ -550,3 +555,3 @@ case 22: | ||
case 23: | ||
html = _a.sent(); | ||
html = _b.sent(); | ||
if (ctx.options.rejectNullish && html == null) { | ||
@@ -558,4 +563,4 @@ throw new errors_1.NullishCommandResultError(cmdRest); | ||
case 24: | ||
_a.sent(); | ||
_a.label = 25; | ||
_b.sent(); | ||
_b.label = 25; | ||
case 25: return [3 /*break*/, 27]; | ||
@@ -565,3 +570,3 @@ case 26: throw new errors_1.CommandSyntaxError(cmd); | ||
case 28: | ||
err_1 = _a.sent(); | ||
err_1 = _b.sent(); | ||
return [2 /*return*/, err_1]; | ||
@@ -572,28 +577,14 @@ case 29: return [2 /*return*/]; | ||
}); }; | ||
var builtInCommands = [ | ||
'QUERY', | ||
'CMD_NODE', | ||
'ALIAS', | ||
'FOR', | ||
'END-FOR', | ||
'IF', | ||
'END-IF', | ||
'INS', | ||
'EXEC', | ||
'IMAGE', | ||
'LINK', | ||
'HTML', | ||
]; | ||
var builtInRegexes = builtInCommands.map(function (word) { return new RegExp("^" + word + "\\b"); }); | ||
var builtInRegexes = types_1.BUILT_IN_COMMANDS.map(function (word) { return new RegExp("^" + word + "\\b"); }); | ||
var notBuiltIns = function (cmd) { | ||
return !builtInRegexes.some(function (r) { return r.test(cmd.toUpperCase()); }); | ||
}; | ||
var getCommand = function (ctx) { | ||
var cmd = ctx.cmd.trim(); | ||
function getCommand(command, shorthands) { | ||
var cmd = command.trim(); | ||
if (cmd[0] === '*') { | ||
var aliasName = cmd.slice(1).trim(); | ||
if (!ctx.shorthands[aliasName]) | ||
if (!shorthands[aliasName]) | ||
throw new errors_1.InvalidCommandError('Unknown alias', cmd); | ||
cmd = ctx.shorthands[aliasName]; | ||
DEBUG && log.debug("Alias for: " + cmd); | ||
cmd = shorthands[aliasName]; | ||
debug_1.logger.debug("Alias for: " + cmd); | ||
} | ||
@@ -609,5 +600,17 @@ else if (cmd[0] === '=') { | ||
} | ||
ctx.cmd = ''; | ||
return cmd.trim(); | ||
}; | ||
} | ||
exports.getCommand = getCommand; | ||
function splitCommand(cmd) { | ||
// Extract command name | ||
var cmdNameMatch = /^(\S+)\s*/.exec(cmd); | ||
var cmdName; | ||
var cmdRest = ''; | ||
if (cmdNameMatch != null) { | ||
cmdName = cmdNameMatch[1].toUpperCase(); | ||
cmdRest = cmd.slice(cmdName.length).trim(); | ||
} | ||
return { cmdName: cmdName, cmdRest: cmdRest }; | ||
} | ||
exports.splitCommand = splitCommand; | ||
// ========================================== | ||
@@ -624,4 +627,4 @@ // Individual commands | ||
if (!node._ifName) { | ||
node._ifName = "__if_" + gCntIf; | ||
gCntIf += 1; | ||
node._ifName = "__if_" + ctx.gCntIf; | ||
ctx.gCntIf += 1; | ||
} | ||
@@ -693,4 +696,3 @@ varName = node._ifName; | ||
if (ctx.loops.find(function (o) { return o.varName === varName; }) == null) { | ||
DEBUG && | ||
log.debug("Ignoring " + cmd + " (" + varName + ", but we're expecting " + curLoop.varName + ")"); | ||
debug_1.logger.debug("Ignoring " + cmd + " (" + varName + ", but we're expecting " + curLoop.varName + ")"); | ||
return; | ||
@@ -697,0 +699,0 @@ } |
@@ -6,4 +6,3 @@ "use strict"; | ||
var errors_1 = require("./errors"); | ||
var DEBUG = process.env.DEBUG_DOCX_TEMPLATES; | ||
var log = DEBUG ? require('./debug').mainStory : null; | ||
var debug_1 = require("./debug"); | ||
// ========================================== | ||
@@ -108,4 +107,2 @@ // Nodes and trees | ||
var logLoop = function (loops) { | ||
if (!DEBUG) | ||
return; | ||
if (!loops.length) | ||
@@ -116,3 +113,3 @@ return; | ||
var idxStr = idx >= 0 ? idx + 1 : 'EXPLORATION'; | ||
log.debug((isIf ? 'IF' : 'FOR') + " loop " + | ||
debug_1.logger.debug((isIf ? 'IF' : 'FOR') + " loop " + | ||
("on " + level + ":" + varName) + | ||
@@ -119,0 +116,0 @@ (idxStr + "/" + loopOver.length)); |
@@ -101,2 +101,3 @@ /// <reference types="node" /> | ||
export declare type Context = { | ||
gCntIf: number; | ||
level: number; | ||
@@ -174,2 +175,9 @@ fCmd: boolean; | ||
}; | ||
export declare type CommandSummary = { | ||
raw: string; | ||
type: BuiltInCommand; | ||
code: string; | ||
}; | ||
export declare type BuiltInCommand = typeof BUILT_IN_COMMANDS[number]; | ||
export declare const BUILT_IN_COMMANDS: readonly ["QUERY", "CMD_NODE", "ALIAS", "FOR", "END-FOR", "IF", "END-IF", "INS", "EXEC", "IMAGE", "LINK", "HTML"]; | ||
export {}; |
@@ -5,1 +5,16 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.BUILT_IN_COMMANDS = void 0; | ||
exports.BUILT_IN_COMMANDS = [ | ||
'QUERY', | ||
'CMD_NODE', | ||
'ALIAS', | ||
'FOR', | ||
'END-FOR', | ||
'IF', | ||
'END-IF', | ||
'INS', | ||
'EXEC', | ||
'IMAGE', | ||
'LINK', | ||
'HTML', | ||
]; |
@@ -8,4 +8,3 @@ "use strict"; | ||
var sax_1 = __importDefault(require("sax")); | ||
var DEBUG = process.env.DEBUG_DOCX_TEMPLATES; | ||
var log = DEBUG ? require('./debug').mainStory : null; | ||
var debug_1 = require("./debug"); | ||
var parseXml = function (templateXml) { | ||
@@ -50,3 +49,3 @@ var parser = sax_1.default.parser(true, { | ||
parser.onend = function () { | ||
DEBUG && log.debug("Number of XML elements: " + numXmlElements); | ||
debug_1.logger.debug("Number of XML elements: " + numXmlElements); | ||
resolve(template); | ||
@@ -53,0 +52,0 @@ }; |
{ | ||
"name": "docx-templates", | ||
"version": "4.2.0", | ||
"version": "4.3.0", | ||
"description": "Template-based docx report creation", | ||
@@ -42,3 +42,3 @@ "main": "lib/index.js", | ||
"dependencies": { | ||
"jszip": "^3.4.0", | ||
"jszip": "^3.5.0", | ||
"sax": "1.2.4", | ||
@@ -48,4 +48,4 @@ "timm": "^1.6.2" | ||
"devDependencies": { | ||
"@types/jest": "^25.2.3", | ||
"@types/node": "^13.13.2", | ||
"@types/jest": "^26.0.0", | ||
"@types/node": "^14.0.13", | ||
"@types/qrcode": "^1.3.4", | ||
@@ -56,3 +56,3 @@ "@types/sax": "^1.2.1", | ||
"coveralls": "^3.0.13", | ||
"eslint": "^6.8.0", | ||
"eslint": "^7.3.1", | ||
"eslint-config-prettier": "^6.11.0", | ||
@@ -63,3 +63,3 @@ "eslint-plugin-import": "^2.20.2", | ||
"jest": "^26.0.1", | ||
"mockdate": "^2.0.5", | ||
"mockdate": "^3.0.2", | ||
"nyc": "^15.0.1", | ||
@@ -66,0 +66,0 @@ "oao": "^1.8.0", |
@@ -345,2 +345,3 @@ # Docx-templates [![Build Status](https://travis-ci.org/guigrpa/docx-templates.svg)](https://travis-ci.org/guigrpa/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) | ||
+++HTML ` | ||
<meta charset="UTF-8"> | ||
<body> | ||
@@ -474,2 +475,16 @@ <h1>${$film.title}</h1> | ||
# Inspecting templates | ||
The `listCommands` function lets you list all the commands in a docx template using the same parser as `createReport`. | ||
```typescript | ||
const template_buffer = fs.readFileSync('template.docx'); | ||
const commands = await listCommands(template_buffer, ['{', '}']); | ||
// `commands` will contain something like: | ||
[ | ||
{ raw: 'INS some_variable', code: 'some_variable', type: 'INS' }, | ||
{ raw: 'IMAGE svgImgFile()', code: 'svgImgFile()', type: 'IMAGE' }, | ||
] | ||
``` | ||
# Performance & security | ||
@@ -476,0 +491,0 @@ |
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
135462
2311
519
1
Updatedjszip@^3.5.0