docxtemplater/es6/modules/expand-pair-trait.js
2021-09-04 10:15:02 +05:00

140 lines
3.6 KiB
JavaScript

const traitName = "expandPair";
const mergeSort = require("../mergesort");
const { getLeft, getRight } = require("../doc-utils");
const wrapper = require("../module-wrapper");
const { getExpandToDefault } = require("../traits");
const {
getUnmatchedLoopException,
getClosingTagNotMatchOpeningTag,
throwLocationInvalid,
} = require("../errors");
function getOpenCountChange(part) {
switch (part.location) {
case "start":
return 1;
case "end":
return -1;
default:
throwLocationInvalid(part);
}
}
function getPairs(traits) {
const errors = [];
let pairs = [];
if (traits.length === 0) {
return { pairs, errors };
}
let countOpen = 1;
const [firstTrait] = traits;
if (firstTrait.part.location === "start") {
for (let i = 1; i < traits.length; i++) {
const currentTrait = traits[i];
countOpen += getOpenCountChange(currentTrait.part);
if (countOpen === 0) {
const outer = getPairs(traits.slice(i + 1));
if (
currentTrait.part.value !== firstTrait.part.value &&
currentTrait.part.value !== ""
) {
errors.push(
getClosingTagNotMatchOpeningTag({
tags: [firstTrait.part, currentTrait.part],
})
);
} else {
pairs = [[firstTrait, currentTrait]];
}
return {
pairs: pairs.concat(outer.pairs),
errors: errors.concat(outer.errors),
};
}
}
}
const { part } = firstTrait;
errors.push(getUnmatchedLoopException({ part, location: part.location }));
const outer = getPairs(traits.slice(1));
return { pairs: outer.pairs, errors: errors.concat(outer.errors) };
}
const expandPairTrait = {
name: "ExpandPairTrait",
optionsTransformer(options, docxtemplater) {
this.expandTags = docxtemplater.fileTypeConfig.expandTags.concat(
docxtemplater.options.paragraphLoop
? docxtemplater.fileTypeConfig.onParagraphLoop
: []
);
return options;
},
postparse(postparsed, { getTraits, postparse }) {
let traits = getTraits(traitName, postparsed);
traits = traits.map(function (trait) {
return trait || [];
});
traits = mergeSort(traits);
const { pairs, errors } = getPairs(traits);
const expandedPairs = pairs.map((pair) => {
let { expandTo } = pair[0].part;
if (expandTo === "auto") {
const result = getExpandToDefault(postparsed, pair, this.expandTags);
if (result.error) {
errors.push(result.error);
}
expandTo = result.value;
}
if (!expandTo) {
return [pair[0].offset, pair[1].offset];
}
let left, right;
try {
left = getLeft(postparsed, expandTo, pair[0].offset);
} catch (e) {
errors.push(e);
}
try {
right = getRight(postparsed, expandTo, pair[1].offset);
} catch (e) {
errors.push(e);
}
return [left, right];
});
let currentPairIndex = 0;
let innerParts;
const newParsed = postparsed.reduce(function (newParsed, part, i) {
const inPair =
currentPairIndex < pairs.length &&
expandedPairs[currentPairIndex][0] <= i;
const pair = pairs[currentPairIndex];
const expandedPair = expandedPairs[currentPairIndex];
if (!inPair) {
newParsed.push(part);
return newParsed;
}
if (expandedPair[0] === i) {
innerParts = [];
}
if (pair[0].offset !== i && pair[1].offset !== i) {
innerParts.push(part);
}
if (expandedPair[1] === i) {
const basePart = postparsed[pair[0].offset];
basePart.subparsed = postparse(innerParts, { basePart });
delete basePart.location;
delete basePart.expandTo;
newParsed.push(basePart);
currentPairIndex++;
}
return newParsed;
}, []);
return { postparsed: newParsed, errors };
},
};
module.exports = () => wrapper(expandPairTrait);