"use strict"; const { last, first } = require("./utils"); 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) { const err = new XTAPIVersionError(msg); err.properties = { id: "api_version_error", ...properties, }; throw err; } function throwMultiError(errors) { const err = new XTTemplateError("Multi error"); err.properties = { errors, id: "multi_error", explanation: "The template has multiple errors", }; throw err; } function getUnopenedTagException(options) { const err = new XTTemplateError("Unopened tag"); err.properties = { xtag: last(options.xtag.split(" ")), id: "unopened_tag", context: options.xtag, offset: options.offset, lIndex: options.lIndex, explanation: `The tag beginning with "${options.xtag.substr( 0, 10 )}" is unopened`, }; return err; } function getDuplicateOpenTagException(options) { const err = new XTTemplateError("Duplicate open tag, expected one open tag"); 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 "${options.xtag.substr( 0, 10 )}" has duplicate open tags`, }; return err; } function getDuplicateCloseTagException(options) { const err = new XTTemplateError( "Duplicate close tag, expected one close tag" ); 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 "${options.xtag.substr( 0, 10 )}" has duplicate close tags`, }; return err; } function getUnclosedTagException(options) { const err = new XTTemplateError("Unclosed tag"); err.properties = { xtag: first(options.xtag.split(" ")).substr(1), id: "unclosed_tag", context: options.xtag, offset: options.offset, lIndex: options.lIndex, explanation: `The tag beginning with "${options.xtag.substr( 0, 10 )}" is unclosed`, }; return err; } function throwXmlTagNotFound(options) { const err = new XTTemplateError( `No tag "${options.element}" was found at the ${options.position}` ); const part = options.parsed[options.index]; err.properties = { id: `no_xml_tag_found_at_${options.position}`, explanation: `No tag "${options.element}" was found at the ${options.position}`, offset: part.offset, part, parsed: options.parsed, index: options.index, element: options.element, }; throw err; } function getCorruptCharactersException({ tag, value, offset }) { const err = new XTRenderingError("There are some XML corrupt characters"); err.properties = { id: "invalid_xml_characters", xtag: tag, value, offset, explanation: "There are some corrupt characters for the field ${tag}", }; return err; } function throwContentMustBeString(type) { const err = new XTInternalError("Content must be a string"); err.properties.id = "xmltemplater_content_must_be_string"; err.properties.type = type; throw err; } function throwExpandNotFound(options) { const { part: { value, offset }, id = "raw_tag_outerxml_invalid", message = "Raw tag not in paragraph", } = options; const { part } = options; let { explanation = `The tag "${value}" is not inside a paragraph`, } = options; if (typeof explanation === "function") { explanation = explanation(part); } const err = new XTTemplateError(message); err.properties = { id, explanation, rootError: options.rootError, xtag: value, offset, postparsed: options.postparsed, expandTo: options.expandTo, index: options.index, }; throw err; } function throwRawTagShouldBeOnlyTextInParagraph(options) { const err = new XTTemplateError( "Raw tag should be the only text in paragraph" ); const tag = options.part.value; err.properties = { id: "raw_xml_tag_should_be_only_text_in_paragraph", explanation: `The raw tag "${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(options) { const { location } = options; const t = location === "start" ? "unclosed" : "unopened"; const T = location === "start" ? "Unclosed" : "Unopened"; const err = new XTTemplateError(`${T} loop`); const tag = options.part.value; err.properties = { id: `${t}_loop`, explanation: `The loop with tag "${tag}" is ${t}`, xtag: tag, offset: options.part.offset, }; return err; } function getClosingTagNotMatchOpeningTag({ tags }) { const err = new XTTemplateError("Closing tag does not match opening tag"); err.properties = { id: "closing_tag_does_not_match_opening_tag", explanation: `The tag "${tags[0].value}" is closed by the tag "${tags[1].value}"`, openingtag: first(tags).value, offset: [first(tags).offset, last(tags).offset], closingtag: last(tags).value, }; return err; } function getScopeCompilationError({ tag, rootError, offset }) { const err = new XTScopeParserError("Scope parser compilation failed"); err.properties = { id: "scopeparser_compilation_failed", offset, tag, explanation: `The scope parser for the tag "${tag}" failed to compile`, rootError, }; return err; } function getScopeParserExecutionError({ tag, scope, error, offset }) { const err = new XTScopeParserError("Scope parser execution failed"); err.properties = { id: "scopeparser_execution_failed", explanation: `The scope parser for the tag ${tag} failed to execute`, scope, offset, tag, rootError: error, }; return err; } function getLoopPositionProducesInvalidXMLError({ tag, offset }) { const err = new XTTemplateError( `The position of the loop tags "${tag}" would produce invalid XML` ); err.properties = { tag, id: "loop_position_invalid", explanation: `The tags "${tag}" are misplaced in the document, for example one of them is in a table and the other one outside the table`, offset, }; return err; } function throwUnimplementedTagType(part, index) { let errorMsg = `Unimplemented tag type "${part.type}"`; if (part.module) { errorMsg += ` "${part.module}"`; } const err = new XTTemplateError(errorMsg); err.properties = { part, index, id: "unimplemented_tag_type", }; throw err; } function throwMalformedXml(part) { const err = new XTInternalError("Malformed xml"); err.properties = { part, id: "malformed_xml", }; throw err; } function throwLocationInvalid(part) { throw new XTInternalError( `Location should be one of "start" or "end" (given : ${part.location})` ); } function throwResolveBeforeCompile() { const err = new XTInternalError( "You must run `.compile()` before running `.resolveData()`" ); err.properties = { id: "resolve_before_compile", }; throw err; } function throwRenderInvalidTemplate() { const err = new XTInternalError( "You should not call .render on a document that had compilation errors" ); err.properties = { id: "render_on_invalid_template", }; throw err; } function throwFileTypeNotIdentified() { const err = new XTInternalError( "The filetype for this file could not be identified, is this file corrupted ?" ); err.properties = { id: "filetype_not_identified", }; throw err; } function throwXmlInvalid(content, offset) { const err = new XTTemplateError("An XML file has invalid xml"); err.properties = { id: "file_has_invalid_xml", content, offset, explanation: "The docx contains invalid XML, it is most likely corrupt", }; throw err; } function throwFileTypeNotHandled(fileType) { const err = new XTInternalError( `The filetype "${fileType}" is not handled by docxtemplater` ); err.properties = { id: "filetype_not_handled", explanation: `The file you are trying to generate is of type "${fileType}", but only docx and pptx formats are handled`, fileType, }; throw err; } module.exports = { XTError, XTTemplateError, XTInternalError, XTScopeParserError, XTAPIVersionError, // Remove this alias in v4 RenderingError: XTRenderingError, XTRenderingError, getClosingTagNotMatchOpeningTag, getLoopPositionProducesInvalidXMLError, getScopeCompilationError, getScopeParserExecutionError, getUnclosedTagException, getUnopenedTagException, getUnmatchedLoopException, getDuplicateCloseTagException, getDuplicateOpenTagException, getCorruptCharactersException, throwApiVersionError, throwContentMustBeString, throwFileTypeNotHandled, throwFileTypeNotIdentified, throwLocationInvalid, throwMalformedXml, throwMultiError, throwExpandNotFound, throwRawTagShouldBeOnlyTextInParagraph, throwUnimplementedTagType, throwXmlTagNotFound, throwXmlInvalid, throwResolveBeforeCompile, throwRenderInvalidTemplate, };