docxtemplater
Version:
docx and pptx generator working with templates and data (like Mustache, for Word and Powerpoint documents)
454 lines (368 loc) • 14.6 kB
JavaScript
;
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
var _require = require("../doc-utils.js"),
mergeObjects = _require.mergeObjects,
chunkBy = _require.chunkBy,
last = _require.last,
isParagraphStart = _require.isParagraphStart,
isParagraphEnd = _require.isParagraphEnd,
isContent = _require.isContent,
startsWith = _require.startsWith;
var wrapper = require("../module-wrapper.js");
var moduleName = "loop";
function hasContent(parts) {
return parts.some(function (part) {
return isContent(part);
});
}
function getFirstMeaningFulPart(parsed) {
for (var i = 0, len = parsed.length; i < len; i++) {
if (parsed[i].type !== "content") {
return parsed[i];
}
}
return null;
}
function isInsideParagraphLoop(part) {
var firstMeaningfulPart = getFirstMeaningFulPart(part.subparsed);
return firstMeaningfulPart != null && firstMeaningfulPart.tag !== "w:t";
}
function getPageBreakIfApplies(part) {
if (part.hasPageBreak) {
if (isInsideParagraphLoop(part)) {
return '<w:p><w:r><w:br w:type="page"/></w:r></w:p>';
}
}
return "";
}
function isEnclosedByParagraphs(parsed) {
if (parsed.length === 0) {
return false;
}
return isParagraphStart(parsed[0]) && isParagraphEnd(last(parsed));
}
function getOffset(chunk) {
return hasContent(chunk) ? 0 : chunk.length;
}
function addPageBreakAtEnd(subRendered) {
var found = false;
var i = subRendered.parts.length - 1;
for (var j = subRendered.parts.length - 1; i >= 0; i--) {
var p = subRendered.parts[j];
if (p === "</w:p>" && !found) {
found = true;
subRendered.parts.splice(j, 0, '<w:r><w:br w:type="page"/></w:r>');
break;
}
}
if (!found) {
subRendered.parts.push('<w:p><w:r><w:br w:type="page"/></w:r></w:p>');
}
}
function addPageBreakAtBeginning(subRendered) {
subRendered.parts.unshift('<w:p><w:r><w:br w:type="page"/></w:r></w:p>');
}
function addContinuousType(parts) {
var stop = false;
var inSectPr = false;
return parts.reduce(function (result, part) {
if (stop === false && startsWith(part, "<w:sectPr")) {
inSectPr = true;
}
if (inSectPr) {
if (startsWith(part, "<w:type")) {
stop = true;
}
if (stop === false && startsWith(part, "</w:sectPr")) {
result.push('<w:type w:val="continuous"/>');
}
}
result.push(part);
return result;
}, []);
}
function dropHeaderFooterRefs(parts) {
return parts.filter(function (text) {
if (startsWith(text, "<w:headerReference") || startsWith(text, "<w:footerReference")) {
return false;
}
return true;
});
}
function hasPageBreak(chunk) {
return chunk.some(function (part) {
if (part.tag === "w:br" && part.value.indexOf('w:type="page"') !== -1) {
return true;
}
});
}
function getSectPrHeaderFooterChangeCount(chunks) {
var collectSectPr = false;
var sectPrCount = 0;
chunks.forEach(function (part) {
if (part.tag === "w:sectPr" && part.position === "start") {
collectSectPr = true;
}
if (collectSectPr) {
if (part.tag === "w:headerReference" || part.tag === "w:footerReference") {
sectPrCount++;
collectSectPr = false;
}
}
if (part.tag === "w:sectPr" && part.position === "end") {
collectSectPr = false;
}
});
return sectPrCount;
}
var LoopModule = /*#__PURE__*/function () {
function LoopModule() {
_classCallCheck(this, LoopModule);
this.name = "LoopModule";
this.totalSectPr = 0;
this.prefix = {
start: "#",
end: "/",
dash: /^-([^\s]+)\s(.+)$/,
inverted: "^"
};
}
_createClass(LoopModule, [{
key: "parse",
value: function parse(placeHolderContent, _ref) {
var match = _ref.match,
getValue = _ref.getValue,
getValues = _ref.getValues;
var module = moduleName;
var type = "placeholder";
var _this$prefix = this.prefix,
start = _this$prefix.start,
inverted = _this$prefix.inverted,
dash = _this$prefix.dash,
end = _this$prefix.end;
if (match(start, placeHolderContent)) {
return {
type: type,
value: getValue(start, placeHolderContent),
expandTo: "auto",
module: module,
location: "start",
inverted: false
};
}
if (match(inverted, placeHolderContent)) {
return {
type: type,
value: getValue(inverted, placeHolderContent),
expandTo: "auto",
module: module,
location: "start",
inverted: true
};
}
if (match(end, placeHolderContent)) {
return {
type: type,
value: getValue(end, placeHolderContent),
module: module,
location: "end"
};
}
if (match(dash, placeHolderContent)) {
var _getValues = getValues(dash, placeHolderContent),
_getValues2 = _slicedToArray(_getValues, 3),
expandTo = _getValues2[1],
value = _getValues2[2];
return {
type: type,
value: value,
expandTo: expandTo,
module: module,
location: "start",
inverted: false
};
}
return null;
}
}, {
key: "getTraits",
value: function getTraits(traitName, parsed) {
if (traitName !== "expandPair") {
return;
}
return parsed.reduce(function (tags, part, offset) {
if (part.type === "placeholder" && part.module === moduleName && part.subparsed == null) {
tags.push({
part: part,
offset: offset
});
}
return tags;
}, []);
}
}, {
key: "postparse",
value: function postparse(parsed, _ref2) {
var basePart = _ref2.basePart;
if (basePart) {
basePart.sectPrCount = getSectPrHeaderFooterChangeCount(parsed);
basePart.sectPrIndex = this.totalSectPr;
this.totalSectPr += basePart.sectPrCount;
}
if (!basePart || basePart.expandTo !== "auto" || basePart.module !== moduleName || !isEnclosedByParagraphs(parsed)) {
return parsed;
}
var level = 0;
var chunks = chunkBy(parsed, function (p) {
if (isParagraphStart(p)) {
level++;
if (level === 1) {
return "start";
}
}
if (isParagraphEnd(p)) {
level--;
if (level === 0) {
return "end";
}
}
return null;
});
if (chunks.length <= 2) {
return parsed;
}
var firstChunk = chunks[0];
var lastChunk = last(chunks);
var firstOffset = getOffset(firstChunk);
var lastOffset = getOffset(lastChunk);
basePart.hasPageBreak = hasPageBreak(lastChunk);
basePart.hasPageBreakBeginning = hasPageBreak(firstChunk);
if (firstOffset === 0 || lastOffset === 0) {
return parsed;
}
return parsed.slice(firstOffset, parsed.length - lastOffset);
}
}, {
key: "render",
value: function render(part, options) {
if (part.type !== "placeholder" || part.module !== moduleName) {
return null;
}
var totalValue = [];
var errors = [];
function loopOver(scope, i, length) {
var scopeManager = options.scopeManager.createSubScopeManager(scope, part.value, i, part, length);
var subRendered = options.render(mergeObjects({}, options, {
compiled: part.subparsed,
tags: {},
scopeManager: scopeManager
}));
if (part.hasPageBreak && i === length - 1 && isInsideParagraphLoop(part)) {
addPageBreakAtEnd(subRendered);
}
var isNotFirst = scopeManager.scopePathItem.some(function (i) {
return i !== 0;
});
if (isNotFirst) {
if (part.sectPrCount === 1) {
subRendered.parts = dropHeaderFooterRefs(subRendered.parts);
}
if (part.sectPrIndex === 0) {
// For the first sectPr in the document, add the continuous attribute (except for the first iteration)
subRendered.parts = addContinuousType(subRendered.parts);
}
}
if (part.hasPageBreakBeginning && isInsideParagraphLoop(part)) {
addPageBreakAtBeginning(subRendered);
}
totalValue = totalValue.concat(subRendered.parts);
errors = errors.concat(subRendered.errors || []);
}
var result;
try {
result = options.scopeManager.loopOver(part.value, loopOver, part.inverted, {
part: part
});
} catch (e) {
errors.push(e);
return {
errors: errors
};
} // if the loop is showing empty content
if (result === false) {
return {
value: getPageBreakIfApplies(part) || "",
errors: errors
};
}
return {
value: options.joinUncorrupt(totalValue, _objectSpread(_objectSpread({}, options), {}, {
basePart: part
})),
errors: errors
};
}
}, {
key: "resolve",
value: function resolve(part, options) {
if (part.type !== "placeholder" || part.module !== moduleName) {
return null;
}
var sm = options.scopeManager;
var promisedValue = sm.getValueAsync(part.value, {
part: part
});
var promises = [];
function loopOver(scope, i, length) {
var scopeManager = sm.createSubScopeManager(scope, part.value, i, part, length);
promises.push(options.resolve({
filePath: options.filePath,
modules: options.modules,
baseNullGetter: options.baseNullGetter,
resolve: options.resolve,
compiled: part.subparsed,
tags: {},
scopeManager: scopeManager
}));
}
var errorList = [];
return promisedValue.then(function (value) {
sm.loopOverValue(value, loopOver, part.inverted);
return Promise.all(promises).then(function (r) {
return r.map(function (_ref3) {
var resolved = _ref3.resolved,
errors = _ref3.errors;
if (errors.length > 0) {
errorList.push.apply(errorList, _toConsumableArray(errors));
}
return resolved;
});
}).then(function (value) {
if (errorList.length > 0) {
throw errorList;
}
return value;
});
});
}
}]);
return LoopModule;
}();
module.exports = function () {
return wrapper(new LoopModule());
};