UNPKG

docxtemplater

Version:

Generate docx, pptx, and xlsx from templates (Word, Powerpoint and Excel documents), from Node.js, the Browser and the command line

694 lines (693 loc) 23.9 kB
"use strict"; function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } var _require = require("./utils.js"), last = _require.last, first = _require.first; function XTError(message) { this.name = "GenericError"; this.message = message; this.stack = new Error(message).stack; } XTError.prototype = Error.prototype; function XTTemplateError(message) { this.name = "TemplateError"; this.message = message; this.stack = new Error(message).stack; } XTTemplateError.prototype = new XTError(); function XTRenderingError(message) { this.name = "RenderingError"; this.message = message; this.stack = new Error(message).stack; } XTRenderingError.prototype = new XTError(); function XTScopeParserError(message) { this.name = "ScopeParserError"; this.message = message; this.stack = new Error(message).stack; } XTScopeParserError.prototype = new XTError(); function XTInternalError(message) { this.name = "InternalError"; this.properties = { explanation: "InternalError" }; this.message = message; this.stack = new Error(message).stack; } XTInternalError.prototype = new XTError(); function XTAPIVersionError(message) { this.name = "APIVersionError"; this.properties = { explanation: "APIVersionError" }; this.message = message; this.stack = new Error(message).stack; } XTAPIVersionError.prototype = new XTError(); function throwApiVersionError(msg, properties) { var err = new XTAPIVersionError(msg); /* * This error arises when a recent module version necessitates a more * current version of the docxtemplater core. Docxtemplater specifies an * "APIVersion," and if a module requires API Version 3.55 or higher, * but the docxtemplater instance provides API 3.52, this error will * occur. To resolve this issue, please update to the latest version of * docxtemplater. */ err.properties = _objectSpread({ id: "api_version_error" }, properties); throw err; } function throwMultiError(errors) { var err = new XTTemplateError("Multi error"); /* * This error is an Error that contains all template errors. * It is a multi error because it contains all errors of the template in : * err.properties.errors. * * You can then map on each sub error like this : * * ```js * for (const err of error.properties.errors) { * console.log(err.properties.explanation); * } * ``` */ err.properties = { errors: errors, id: "multi_error", explanation: "The template has multiple errors" }; throw err; } function getUnopenedTagException(options) { var err = new XTTemplateError("Unopened tag"); /* * This error happens if a tag is closed but not opened. For example with * the following template: * * ```docx * Hello name} ! * ``` */ err.properties = { xtag: last(options.xtag.split(" ")), id: "unopened_tag", context: options.xtag, offset: options.offset, lIndex: options.lIndex, explanation: "The tag beginning with \"".concat(options.xtag.substr(0, 30), "\" is unopened") }; return err; } function getDuplicateOpenTagException(options) { var err = new XTTemplateError("Duplicate open tag, expected one open tag"); /* * This error happens with following template : * * ```docx * Hello {{name * ``` */ err.properties = { xtag: first(options.xtag.split(" ")), id: "duplicate_open_tag", context: options.xtag, offset: options.offset, lIndex: options.lIndex, explanation: "The tag beginning with \"".concat(options.xtag.substr(0, 30), "\" has duplicate open tags") }; return err; } function getDuplicateCloseTagException(options) { var err = new XTTemplateError("Duplicate close tag, expected one close tag"); /* * This error happens with following template : * * ```docx * Hello {name}} * ``` */ err.properties = { xtag: first(options.xtag.split(" ")), id: "duplicate_close_tag", context: options.xtag, offset: options.offset, lIndex: options.lIndex, explanation: "The tag ending with \"".concat(options.xtag.substr(0, 30), "\" has duplicate close tags") }; return err; } function getUnclosedTagException(options) { var err = new XTTemplateError("Unclosed tag"); /* * This error happens if a tag is opened but not closed. * For example with the following template: * * ```docx * Hello {name ! * ``` */ err.properties = { xtag: first(options.xtag.split(" ")).substr(1), // name id: "unclosed_tag", context: options.xtag, offset: options.offset, lIndex: options.lIndex, explanation: "The tag beginning with \"".concat(options.xtag.substr(0, 30), "\" is unclosed") }; return err; } function throwXmlTagNotFound(options) { if (options.position === "left") { throwXmlTagNotFoundLeft(options); } else { throwXmlTagNotFoundRight(options); } } function throwXmlTagNotFoundLeft(options) { var err = new XTTemplateError("No tag \"".concat(options.element, "\" was found at the ").concat(options.position)); var part = options.parsed[options.index]; /* * This error is not directly linked to the template, it means that some * tag tried to expand to adjacent XML tags, but those elements cannot be * accessed from the current node. * * This error happens if a rawXMLTag doesn't find a `<w:p>` element * * ```docx * <w:p><w:t>{@raw}</w:t> * // Note that the `</w:p>` tag is missing. * ``` */ err.properties = { id: "no_xml_tag_found_at_left", explanation: "No tag \"".concat(options.element, "\" was found at the left"), offset: part.offset, part: part, parsed: options.parsed, index: options.index, element: options.element }; throw err; } function throwXmlTagNotFoundRight(options) { var err = new XTTemplateError("No tag \"".concat(options.element, "\" was found at the ").concat(options.position)); var part = options.parsed[options.index]; /* * This error is not directly linked to the template, it means that some * tag tried to expand to adjacent XML tags, but those elements cannot be * accessed from the current node. */ err.properties = { id: "no_xml_tag_found_at_right", explanation: "No tag \"".concat(options.element, "\" was found at the right"), offset: part.offset, part: part, parsed: options.parsed, index: options.index, element: options.element }; throw err; } function getCorruptCharactersException(_ref) { var tag = _ref.tag, value = _ref.value, offset = _ref.offset; var err = new XTRenderingError("There are some XML corrupt characters"); /* * This error prevents the docx document to become corrupt. * It happens if you're trying to render text that would produce invalid XML output. * * See #corrupt-character-error on how this can be fixed by changing your parser. */ err.properties = { id: "invalid_xml_characters", xtag: tag, value: value, offset: offset, explanation: "There are some corrupt characters for the field \"".concat(tag, "\"") }; return err; } function getInvalidRawXMLValueException(_ref2) { var tag = _ref2.tag, value = _ref2.value, offset = _ref2.offset, partDelims = _ref2.partDelims; var err = new XTRenderingError("Non string values are not allowed for rawXML tags"); /* * This error happens if you try to render a rawXml tag, such as : {@raw} * And the value of the data for "raw" is truthy but not a string. * * (If the value of the data is falsy, than the tag is simply dropped and * no error is thrown) */ err.properties = { id: "invalid_raw_xml_value", xtag: tag, value: value, offset: offset, explanation: "The value of the raw tag : \"".concat(partDelims, "\" is not a string") }; return err; } function throwExpandNotFound(options) { var _options$part = options.part, value = _options$part.value, offset = _options$part.offset, _options$id = options.id, id = _options$id === void 0 ? "raw_tag_outerxml_invalid" : _options$id, _options$message = options.message, message = _options$message === void 0 ? "Raw tag not in paragraph" : _options$message; var part = options.part; var _options$explanation = options.explanation, explanation = _options$explanation === void 0 ? "The tag \"".concat(value, "\" is not inside a paragraph") : _options$explanation; if (typeof explanation === "function") { explanation = explanation(part); } /* * This error happens if you try to render a rawXml tag, such as : {@raw}, * but that tag is not placed inside a paragraph. */ var err = new XTTemplateError(message); err.properties = { id: id, explanation: explanation, rootError: options.rootError, xtag: value, offset: offset, postparsed: options.postparsed, expandTo: options.expandTo, index: options.index }; throw err; } function throwRawTagShouldBeOnlyTextInParagraph(options) { var err = new XTTemplateError("Raw tag should be the only text in paragraph"); var tag = options.part.value; /* * This happens when a rawXMLTag {@raw} is not the only text in the * paragraph. For example, writing ` {@raw}` (Note the spaces) * is not acceptable because the {@raw} tag replaces the full paragraph. We * prefer to throw an Error now rather than have "strange behavior" * because the spaces "disappeared". * * To correct this error, you have to add manually the text that you want * in your raw tag. (Or you can use the [docxtemplater word-run * module](/modules/word-run/) which adds a tag * that can replace rawXML inside a tag). * * Writing * * ```docx * {@my_first_tag}{my_second_tag} * ``` * * Or even * * ```docx * Hello {@my_first_tag} * ``` * * Is misusing docxtemplater. * * The `@` at the beginning means "replace the xml of **the * current paragraph** with scope.my_first_tag" so that means that * everything else in that Paragraph will be removed. */ err.properties = { id: "raw_xml_tag_should_be_only_text_in_paragraph", explanation: "The raw tag \"".concat(tag, "\" should be the only text in this paragraph. This means that this tag should not be surrounded by any text or spaces."), xtag: tag, offset: options.part.offset, paragraphParts: options.paragraphParts }; throw err; } function getUnmatchedLoopException(part) { var location = part.location, offset = part.offset, square = part.square; var t = location === "start" ? "unclosed" : "unopened"; var T = location === "start" ? "Unclosed" : "Unopened"; var err = new XTTemplateError("".concat(T, " loop")); var tag = part.value; /* * This error happens with following template : * * ```docx * {#users} * {/companies} * ``` */ err.properties = { id: "".concat(t, "_loop"), explanation: "The loop with tag \"".concat(tag, "\" is ").concat(t), xtag: tag, offset: offset }; if (square) { err.properties.square = square; } return err; } function getUnbalancedLoopException(pair, lastPair) { var err = new XTTemplateError("Unbalanced loop tag"); var lastL = lastPair[0].part.value; var lastR = lastPair[1].part.value; var l = pair[0].part.value; var r = pair[1].part.value; /* * This error happens if you create a table and misplace tags inside the table : * * ```docx-md * | Head1 | Head2 | * | -------- | ------------ | * | {#a}X | {/a}{#b}Y{/b} | * ``` * * In the case above, the {#a} and {/a} will expand to the whole loop, but this is not possible because of the other loop in {#b}Y{/b} * * Instead, you should usually write : * * ```docx-md * | Head1 | Head2 | * | -------- | ------------ | * | {#a}X | {#b}Y{/b}{/a} | * ``` */ err.properties = { id: "unbalanced_loop_tags", explanation: "Unbalanced loop tags {#".concat(lastL, "}{/").concat(lastR, "}{#").concat(l, "}{/").concat(r, "}"), offset: [lastPair[0].part.offset, pair[1].part.offset], lastPair: { left: lastPair[0].part.value, right: lastPair[1].part.value }, pair: { left: pair[0].part.value, right: pair[1].part.value } }; return err; } function getClosingTagNotMatchOpeningTag(_ref3) { var tags = _ref3.tags; var err = new XTTemplateError("Closing tag does not match opening tag"); /* * This error happens if your loop tags are incorrectly closed * * ```docx * {#condition1} * Some text * {/otherCondition} * ``` * * Since the start tag does not match the open tag, the template is invalid. */ err.properties = { id: "closing_tag_does_not_match_opening_tag", explanation: "The tag \"".concat(tags[0].value, "\" is closed by the tag \"").concat(tags[1].value, "\""), openingtag: first(tags).value, offset: [first(tags).offset, last(tags).offset], closingtag: last(tags).value }; if (first(tags).square) { err.properties.square = [first(tags).square, last(tags).square]; } return err; } function getScopeCompilationError(_ref4) { var tag = _ref4.tag, rootError = _ref4.rootError, offset = _ref4.offset; var err = new XTScopeParserError("Scope parser compilation failed"); /* * This happens when your parser throws an error during compilation. The * parser is the second argument of the constructor * `new Docxtemplater(zip, {parser: function parser(tag) {}});` * * For example, if your template is: * * ```docx * {name++} * ``` * * and you use the angular expression parser, you will have this error. The error * happens when you call parser('name++'); The underlying error can be * read in `e.properties.rootError` */ err.properties = { id: "scopeparser_compilation_failed", offset: offset, xtag: tag, explanation: "The scope parser for the tag \"".concat(tag, "\" failed to compile"), rootError: rootError }; return err; } function getScopeParserExecutionError(_ref5) { var tag = _ref5.tag, scope = _ref5.scope, error = _ref5.error, offset = _ref5.offset; var err = new XTScopeParserError("Scope parser execution failed"); /* * This happens when your parser throws an error during execution. The * parser is the second argument of the constructor * `new Docxtemplater(zip, {parser: function parser(tag) {}});` * * For example, if your template is: * * ```docx * {test | toFixed} * ``` * * and your code is : * * ```js * const expressionParser = require("docxtemplater/expressions.js"); * const doc = new Docxtemplater(zip, { * paragraphLoop: true, * linebreaks: true, * parser: expressionParser.configure({ * filters: { * toFixed(input) { * return input.toFixed(); * } * } * }), * }); * doc.render({ * test: false * }); * ``` * * Since false.toFixed() triggers an error in Javascript, this will then throw an error "Scope parser execution failed". * * You can either fix your data or make your toFixed function more robust * by returning "input" if the input is not a number. */ err.properties = { id: "scopeparser_execution_failed", explanation: "The scope parser for the tag ".concat(tag, " failed to execute"), scope: scope, offset: offset, xtag: tag, rootError: error }; return err; } function getLoopPositionProducesInvalidXMLError(_ref6) { var tag = _ref6.tag, offset = _ref6.offset; var err = new XTTemplateError("The position of the loop tags \"".concat(tag, "\" would produce invalid XML")); /* * This happens when a loop would produce invalid XML. * * For example, if you write: * * ```docx-md * | Head1 | Head2 | * | -------- | ------------ | * | {#users} | content | * * {/users} * ``` * * this is not allowed since a loop that starts in a table must also end * in that table. */ err.properties = { xtag: tag, id: "loop_position_invalid", explanation: "The tags \"".concat(tag, "\" are misplaced in the document, for example one of them is in a table and the other one outside the table"), offset: offset }; return err; } function throwUnimplementedTagType(part, index) { var errorMsg = "Unimplemented tag type \"".concat(part.type, "\""); if (part.module) { errorMsg += " \"".concat(part.module, "\""); } var err = new XTTemplateError(errorMsg); /* * This happens when a tag type is not implemented. It should normally not happen, * unless you changed docxtemplater code or created your own module and didn't * implement the `render` function of your module correctly. */ err.properties = { part: part, index: index, id: "unimplemented_tag_type" }; throw err; } function throwMalformedXml() { var err = new XTInternalError("Malformed xml"); /* * This happens when an xml file of the document cannot be parsed * correctly. */ err.properties = { explanation: "The template contains malformed xml", id: "malformed_xml" }; throw err; } function throwResolveBeforeCompile() { var err = new XTInternalError("You must run `.compile()` before running `.resolveData()`"); /* * This happens if you're calling `resolveData()` before you run `.compile()`. * * You should always call `compile` first and then only `resolveData` * * Or you can migrate to [the constructor with two arguments](/docs/get-started-node/#usage) */ err.properties = { id: "resolve_before_compile", explanation: "You must run `.compile()` before running `.resolveData()`" }; throw err; } function throwRenderInvalidTemplate() { var err = new XTInternalError("You should not call .render on a document that had compilation errors"); /* * This happens if you're calling `render()` on a document that had template errors */ err.properties = { id: "render_on_invalid_template", explanation: "You should not call .render on a document that had compilation errors" }; throw err; } function throwRenderTwice() { var err = new XTInternalError("You should not call .render twice on the same docxtemplater instance"); /* * This happens if you're calling `render()` on a document twice. * * You should always create a new docxtemplater instance if you need to create two output documents. */ err.properties = { id: "render_twice", explanation: "You should not call .render twice on the same docxtemplater instance" }; throw err; } function throwFileTypeNotIdentified(zip) { var files = Object.keys(zip.files).slice(0, 10); var msg = ""; if (files.length === 0) { msg = "Empty zip file"; } else { msg = "Zip file contains : ".concat(files.join(",")); } var err = new XTInternalError("The filetype for this file could not be identified, is this file corrupted ? ".concat(msg)); /* * This error happens if you're creating docxtemplater with a zip file, but that file is not recognized as a docx/pptx/xlsx or odt file. * * Note that xlsx files and odt files need a paid module to be templated. * * Other zip files (zip, odp, ods) will trigger the same error. */ err.properties = { id: "filetype_not_identified", explanation: "The filetype for this file could not be identified, is this file corrupted ? ".concat(msg) }; throw err; } function throwXmlInvalid(content, offset) { var err = new XTTemplateError("An XML file has invalid xml"); /* * This error happens if the XML is invalid in your template file. * * This should be very rare except if you were using a tool to preprocess * the template (an XML error in a docx file means that the template file * is already corrupt). */ err.properties = { id: "file_has_invalid_xml", content: content, offset: offset, explanation: "The docx contains invalid XML, it is most likely corrupt" }; throw err; } function throwFileTypeNotHandled(fileType) { var err = new XTInternalError("The filetype \"".concat(fileType, "\" is not handled by docxtemplater")); /* * This error happens if the filetype was recognized (xlsx, odt), but * without the correct module, this file cannot be templated */ err.properties = { id: "filetype_not_handled", explanation: "The file you are trying to generate is of type \"".concat(fileType, "\", but only docx and pptx formats are handled"), fileType: fileType }; throw err; } module.exports = { XTError: XTError, XTTemplateError: XTTemplateError, XTInternalError: XTInternalError, XTScopeParserError: XTScopeParserError, XTAPIVersionError: XTAPIVersionError, // Remove this alias in v4 RenderingError: XTRenderingError, XTRenderingError: XTRenderingError, getClosingTagNotMatchOpeningTag: getClosingTagNotMatchOpeningTag, getLoopPositionProducesInvalidXMLError: getLoopPositionProducesInvalidXMLError, getScopeCompilationError: getScopeCompilationError, getScopeParserExecutionError: getScopeParserExecutionError, getUnclosedTagException: getUnclosedTagException, getUnopenedTagException: getUnopenedTagException, getUnmatchedLoopException: getUnmatchedLoopException, getDuplicateCloseTagException: getDuplicateCloseTagException, getDuplicateOpenTagException: getDuplicateOpenTagException, getCorruptCharactersException: getCorruptCharactersException, getInvalidRawXMLValueException: getInvalidRawXMLValueException, getUnbalancedLoopException: getUnbalancedLoopException, throwApiVersionError: throwApiVersionError, throwFileTypeNotHandled: throwFileTypeNotHandled, throwFileTypeNotIdentified: throwFileTypeNotIdentified, throwMalformedXml: throwMalformedXml, throwMultiError: throwMultiError, throwExpandNotFound: throwExpandNotFound, throwRawTagShouldBeOnlyTextInParagraph: throwRawTagShouldBeOnlyTextInParagraph, throwUnimplementedTagType: throwUnimplementedTagType, throwXmlTagNotFound: throwXmlTagNotFound, throwXmlInvalid: throwXmlInvalid, throwResolveBeforeCompile: throwResolveBeforeCompile, throwRenderInvalidTemplate: throwRenderInvalidTemplate, throwRenderTwice: throwRenderTwice };