UNPKG

docxtemplater

Version:

.docx generator working with templates and data (like Mustache)

128 lines (116 loc) 3.36 kB
const DocUtils = require("./doc-utils"); const Errors = require("./errors"); function throwRawTagNotInParagraph(options) { const err = new Errors.XTTemplateError("Raw tag not in paragraph"); const tag = options.part.value; err.properties = { id: "raw_tag_outerxml_invalid", explanation: `The tag "${tag}"`, rootError: options.rootError, xtag: tag, postparsed: options.postparsed, expandTo: options.expandTo, index: options.index, }; throw err; } function lastTagIsOpenTag(array, tag) { if (array.length === 0) { return false; } const lastTag = array[array.length - 1]; const innerLastTag = lastTag.tag.substr(1); const innerCurrentTag = tag.substr(2, tag.length - 3); return innerLastTag.indexOf(innerCurrentTag) === 0; } function addTag(array, tag) { array.push({tag}); return array; } function getListXmlElements(parts) { /* get the different closing and opening tags between two texts (doesn't take into account tags that are opened then closed (those that are closed then opened are returned)): returns:[{"tag":"</w:r>","offset":13},{"tag":"</w:p>","offset":265},{"tag":"</w:tc>","offset":271},{"tag":"<w:tc>","offset":828},{"tag":"<w:p>","offset":883},{"tag":"<w:r>","offset":1483}] */ const tags = parts.filter(function (part) { return part.type === "tag"; }).map(function (part) { return part.value; }); let result = []; for (let i = 0, tag; i < tags.length; i++) { tag = tags[i]; // closing tag if (tag[1] === "/") { if (lastTagIsOpenTag(result, tag)) { result.pop(); } else { result = addTag(result, tag); } } else if (tag[tag.length - 1] !== "/") { result = addTag(result, tag); } } return result; } function getExpandToDefault(parts) { const xmlElements = getListXmlElements(parts); for (let i = 0; i < xmlElements.length; i++) { const xmlElement = xmlElements[i]; if(xmlElement.tag.indexOf("<w:tc") === 0) { return "w:tr"; } if(xmlElement.tag.indexOf("<a:tc") === 0) { return "a:tr"; } } return false; } function expandOne(part, postparsed, options) { const expandTo = part.expandTo || options.expandTo; const index = postparsed.indexOf(part); if (!expandTo) { return postparsed; } let right, left; try { right = DocUtils.getRight(postparsed, expandTo, index); left = DocUtils.getLeft(postparsed, expandTo, index); } catch (rootError) { if (rootError instanceof Errors.XTTemplateError) { throwRawTagNotInParagraph({part, rootError, postparsed, expandTo, index}); } throw rootError; } const leftParts = postparsed.slice(left, index); const rightParts = postparsed.slice(index + 1, right + 1); let inner = options.getInner({index, part, leftParts, rightParts, left, right, postparsed}); if (!inner.length) { inner.expanded = [leftParts, rightParts]; inner = [inner]; } return DocUtils.concatArrays([ postparsed.slice(0, left), inner, postparsed.slice(right + 1), ]); } function expandToOne(postparsed, options) { const expandToElements = postparsed.reduce(function (elements, part) { if (part.type === "placeholder" && part.module === options.moduleName) { elements.push(part); } return elements; }, []); expandToElements.forEach(function (part) { postparsed = expandOne(part, postparsed, options); }); return postparsed; } module.exports = { expandToOne, getExpandToDefault, };