docxtemplater
Version:
Generate docx, pptx, and xlsx from templates (Word, Powerpoint and Excel documents), from Node.js, the Browser and the command line
1,720 lines (1,719 loc) • 72.4 kB
JavaScript
"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("lodash"),
assign = _require.assign;
var expressionParser = require("../../expressions.js");
var angularParserIE11 = require("../../expressions-ie11.js");
var Errors = require("../../errors.js");
var _require2 = require("../utils.js"),
wrapMultiError = _require2.wrapMultiError;
var nbsp = String.fromCharCode(160);
var _require3 = require("../utils.js"),
expect = _require3.expect;
expressionParser.filters.upper = function (str) {
if (!str) {
return str;
}
return str.toUpperCase();
};
expressionParser.filters.sum = function (num1, num2) {
return num1 + num2;
};
var noInternals = {
lexed: null,
parsed: null,
postparsed: null
};
var xmlSpacePreserveTag = {
type: "tag",
position: "start",
value: '<w:t xml:space="preserve">',
text: true,
tag: "w:t"
};
var startText = {
type: "tag",
position: "start",
value: "<w:t>",
text: true,
tag: "w:t"
};
var endText = {
type: "tag",
value: "</w:t>",
text: true,
position: "end",
tag: "w:t"
};
var startParagraph = {
type: "tag",
value: "<w:p>",
text: false,
position: "start",
tag: "w:p"
};
var endParagraph = {
type: "tag",
value: "</w:p>",
text: false,
position: "end",
tag: "w:p"
};
var tableRowStart = {
type: "tag",
position: "start",
text: false,
value: "<w:tr>",
tag: "w:tr"
};
var tableRowEnd = {
type: "tag",
value: "</w:tr>",
text: false,
position: "end",
tag: "w:tr"
};
var tableColStart = {
type: "tag",
position: "start",
text: false,
value: "<w:tc>",
tag: "w:tc"
};
var tableColEnd = {
type: "tag",
value: "</w:tc>",
text: false,
position: "end",
tag: "w:tc"
};
var delimiters = {
start: {
type: "delimiter",
position: "start"
},
end: {
type: "delimiter",
position: "end"
}
};
function content(value) {
return {
type: "content",
value: value,
position: "insidetag"
};
}
function externalContent(value) {
return {
type: "content",
value: value,
position: "outsidetag"
};
}
var fixtures = [{
it: "should handle {user} with tag",
content: "<w:t>Hi {user}</w:t>",
scope: {
user: "Foo"
},
result: '<w:t xml:space="preserve">Hi Foo</w:t>',
xmllexed: [{
position: "start",
tag: "w:t",
text: true,
type: "tag",
value: "<w:t>"
}, {
type: "content",
value: "Hi {user}"
}, {
position: "end",
tag: "w:t",
text: true,
type: "tag",
value: "</w:t>"
}],
lexed: [startText, content("Hi "), delimiters.start, content("user"), delimiters.end, endText],
parsed: [startText, content("Hi "), {
type: "placeholder",
value: "user"
}, endText],
postparsed: [xmlSpacePreserveTag, content("Hi "), {
type: "placeholder",
value: "user"
}, endText]
}, {
it: "should handle {.} with tag",
content: "<w:t>Hi {.}</w:t>",
scope: "Foo",
result: '<w:t xml:space="preserve">Hi Foo</w:t>',
lexed: [startText, content("Hi "), delimiters.start, content("."), delimiters.end, endText],
parsed: [startText, content("Hi "), {
type: "placeholder",
value: "."
}, endText],
postparsed: [xmlSpacePreserveTag, content("Hi "), {
type: "placeholder",
value: "."
}, endText]
}, _objectSpread(_objectSpread({
it: "should handle {userGreeting} with lambda function",
content: "<w:t>{#users}{userGreeting}{/}</w:t>"
}, noInternals), {}, {
scope: {
userGreeting: function userGreeting(scope, sm) {
return "How is it going, " + scope.name + " ? " + sm.scopeLindex.length;
},
users: [{
name: "John"
}, {
name: "Mary"
}]
},
result: '<w:t xml:space="preserve">How is it going, John ? 1How is it going, Mary ? 1</w:t>'
}), _objectSpread(_objectSpread({
it: "should handle non breaking space in tag",
result: '<w:t xml:space="preserve">Hey Ho</w:t>'
}, noInternals), {}, {
content: "<w:t>{:foo".concat(nbsp).concat(nbsp, "bar").concat(nbsp, "bar} {:zing").concat(nbsp).concat(nbsp).concat(nbsp, "bang}</w:t>"),
options: {
modules: function modules() {
return [{
name: "FooModule",
parse: function parse(placeHolderContent, options) {
if (options.match(":foo ", placeHolderContent)) {
return {
type: "placeholder",
value: options.getValue(":foo ", placeHolderContent)
};
}
if (options.match(/^:zing +(.*)/, placeHolderContent)) {
return {
type: "placeholder",
value: options.getValue(/^:zing +(.*)/, placeHolderContent)
};
}
}
}];
},
parser: function parser(tag) {
return {
get: function get() {
if (tag === "bar bar") {
return "Hey";
}
if (tag === "bang") {
return "Ho";
}
return "Bad";
}
};
}
}
}), _objectSpread(_objectSpread({
it: "should be possible to implement a parser that loads nested data using {user.name}",
result: '<w:t xml:space="preserve">Hello John, your age is 33. Date : 17/01/2000</w:t>'
}, noInternals), {}, {
content: "<w:t>Hello {user.name}, your age is {user.age}. Date : {date}</w:t>",
options: {
parser: function parser(tag) {
var splitted = tag.split(".");
return {
get: function get(scope) {
if (tag === ".") {
return scope;
}
var s = scope;
for (var i = 0, len = splitted.length; i < len; i++) {
var key = splitted[i];
s = s[key];
}
return s;
}
};
}
},
scope: {
user: {
name: "John",
age: 33
},
date: "17/01/2000"
}
}), _objectSpread(_objectSpread({
it: "should be possible to add nullGetter to module",
result: '<w:t xml:space="preserve">foo</w:t>'
}, noInternals), {}, {
content: "<w:t>{foo}</w:t>",
options: {
modules: function modules() {
return [{
name: "MyModule",
nullGetter: function nullGetter() {
return "foo";
}
}, {
name: "MyModule2",
nullGetter: function nullGetter() {
return "bar";
}
}];
}
}
}), _objectSpread(_objectSpread({
it: "should handle {#userGet} with lambda function",
content: "<w:t>{#userGet}- {name}{/}</w:t>"
}, noInternals), {}, {
scope: {
userGet: function userGet() {
return [{
name: "John"
}, {
name: "Mary"
}];
}
},
result: '<w:t xml:space="preserve">- John- Mary</w:t>'
}), _objectSpread(_objectSpread({
it: "should allow to call a function up one scope with angular expressions",
content: "<w:t>{#users}{hi(.)}{/}</w:t>"
}, noInternals), {}, {
options: {
parser: expressionParser
},
scope: {
hi: function hi(user) {
return "What's up, ".concat(user, " ?");
},
users: ["John", "Jackie"]
},
result: '<w:t xml:space="preserve">What's up, John ?What's up, Jackie ?</w:t>'
}), {
it: "should xmlparse strange tags",
content: "<w:t>{name} {</w:t>FOO<w:t>age</w:t>BAR<w:t>}</w:t>",
scope: {
name: "Foo",
age: 12
},
result: '<w:t xml:space="preserve">Foo 12</w:t>FOO<w:t></w:t>BAR<w:t></w:t>',
xmllexed: [startText, {
type: "content",
value: "{name} {"
}, endText, {
type: "content",
value: "FOO"
}, startText, {
type: "content",
value: "age"
}, endText, {
type: "content",
value: "BAR"
}, startText, {
type: "content",
value: "}"
}, endText],
lexed: [startText, delimiters.start, content("name"), delimiters.end, content(" "), delimiters.start, endText, externalContent("FOO"), startText, content("age"), endText, externalContent("BAR"), startText, delimiters.end, endText],
parsed: [startText, {
type: "placeholder",
value: "name"
}, content(" "), {
type: "placeholder",
value: "age"
}, endText, externalContent("FOO"), startText, endText, externalContent("BAR"), startText, endText],
postparsed: null
}, {
it: "should work with custom delimiters",
content: "<w:t>Hello [[[name]]</w:t>",
scope: {
name: "John Doe"
},
result: '<w:t xml:space="preserve">Hello John Doe</w:t>',
delimiters: {
start: "[[[",
end: "]]"
},
lexed: [startText, content("Hello "), delimiters.start, content("name"), delimiters.end, endText],
parsed: [startText, content("Hello "), {
type: "placeholder",
value: "name"
}, endText],
postparsed: null
}, {
it: "should work with custom delimiters splitted",
content: '<w:t>Hello {name}</w:t><w:t foo="bar">}, how is it ?</w:t>',
scope: {
name: "John Doe"
},
result: '<w:t xml:space="preserve">Hello John Doe</w:t><w:t foo="bar">, how is it ?</w:t>',
delimiters: {
start: "{",
end: "}}"
},
lexed: [startText, content("Hello "), delimiters.start, content("name"), delimiters.end, endText, {
type: "tag",
value: '<w:t foo="bar">',
text: true,
position: "start",
tag: "w:t"
}, content(", how is it ?"), endText],
parsed: [startText, content("Hello "), {
type: "placeholder",
value: "name"
}, endText, {
type: "tag",
value: '<w:t foo="bar">',
text: true,
position: "start",
tag: "w:t"
}, content(", how is it ?"), endText],
postparsed: null
}, {
it: "should work with custom delimiters splitted over > 2 tags",
content: "<w:t>Hello {name}</w:t><w:t>}</w:t>TAG<w:t>}</w:t><w:t>}}foobar</w:t>",
scope: {
name: "John Doe"
},
result: '<w:t xml:space="preserve">Hello John Doe</w:t><w:t></w:t>TAG<w:t></w:t><w:t>foobar</w:t>',
delimiters: {
start: "{",
end: "}}}}}"
},
lexed: [startText, content("Hello "), delimiters.start, content("name"), delimiters.end, endText, startText, endText, externalContent("TAG"), startText, endText, startText, content("foobar"), endText],
parsed: [startText, content("Hello "), {
type: "placeholder",
value: "name"
}, endText, startText, endText, externalContent("TAG"), startText, endText, startText, content("foobar"), endText],
postparsed: null
}, _objectSpread(_objectSpread({
it: "should work when having equal sign after closing tag",
content: "<w:r><w:t>{foo}====</w:t></w:r>",
scope: {
foo: "FOO"
}
}, noInternals), {}, {
result: '<w:r><w:t xml:space="preserve">FOO====</w:t></w:r>'
}), _objectSpread(_objectSpread({
it: "should fail when having two open text tags",
content: "<w:t><w:t>xxx"
}, noInternals), {}, {
error: {
message: "Malformed xml",
name: "InternalError",
properties: {
id: "malformed_xml",
explanation: "The template contains malformed xml"
}
},
errorType: Errors.XTInternalError
}), _objectSpread(_objectSpread({
it: "should fail when having two close text tags",
content: "<w:t></w:t></w:t>xxx"
}, noInternals), {}, {
error: {
message: "Malformed xml",
name: "InternalError",
properties: {
id: "malformed_xml",
explanation: "The template contains malformed xml"
}
},
errorType: Errors.XTInternalError
}), _objectSpread(_objectSpread({
it: "should show multierror with loops",
content: "<w:t>{#a}{b}{/a}</w:t>"
}, noInternals), {}, {
options: {
parser: function parser() {
return {
get: function get() {
throw new Error("Foobar");
}
};
}
},
error: wrapMultiError({
name: "ScopeParserError",
message: "Scope parser execution failed",
properties: {
explanation: "The scope parser for the tag a failed to execute",
rootError: {
message: "Foobar"
},
file: "word/document.xml",
id: "scopeparser_execution_failed",
xtag: "a",
offset: 0
}
}),
errorType: Errors.XTTemplateError
}), _objectSpread(_objectSpread({
it: "should show multierror with loops",
content: "<w:t>{#a}{b}{/a}</w:t>"
}, noInternals), {}, {
options: {
parser: function parser(tag) {
return {
get: function get(scope) {
if (tag === "a") {
return scope[tag];
}
throw new Error("Foobar");
}
};
}
},
scope: {
a: [1]
},
error: wrapMultiError({
name: "ScopeParserError",
message: "Scope parser execution failed",
properties: {
explanation: "The scope parser for the tag b failed to execute",
rootError: {
message: "Foobar"
},
file: "word/document.xml",
id: "scopeparser_execution_failed",
scope: 1,
xtag: "b",
offset: 4
}
}),
errorType: Errors.XTTemplateError
}), {
it: "should work with loops",
content: "<w:t>Hello {#users}{name}, {/users}</w:t>",
scope: {
users: [{
name: "John Doe"
}, {
name: "Jane Doe"
}, {
name: "Wane Doe"
}]
},
result: '<w:t xml:space="preserve">Hello John Doe, Jane Doe, Wane Doe, </w:t>',
lexed: [startText, content("Hello "), delimiters.start, content("#users"), delimiters.end, delimiters.start, content("name"), delimiters.end, content(", "), delimiters.start, content("/users"), delimiters.end, endText],
parsed: [startText, content("Hello "), {
type: "placeholder",
value: "users",
location: "start",
module: "loop",
inverted: false,
expandTo: "auto"
}, {
type: "placeholder",
value: "name"
}, content(", "), {
type: "placeholder",
value: "users",
location: "end",
module: "loop"
}, endText],
postparsed: [xmlSpacePreserveTag, content("Hello "), {
type: "placeholder",
value: "users",
module: "loop",
inverted: false,
sectPrCount: 0,
subparsed: [{
type: "placeholder",
value: "name"
}, content(", ")]
}, endText]
}, {
it: "should work with paragraph loops",
content: "<w:p><w:t>Hello </w:t></w:p><w:p><w:t>{#users}</w:t></w:p><w:p><w:t>User {.}</w:t></w:p><w:p><w:t>{/users}</w:t></w:p>",
options: {
paragraphLoop: true
},
scope: {
users: ["John Doe", "Jane Doe", "Wane Doe"]
},
result: '<w:p><w:t>Hello </w:t></w:p><w:p><w:t xml:space="preserve">User John Doe</w:t></w:p><w:p><w:t xml:space="preserve">User Jane Doe</w:t></w:p><w:p><w:t xml:space="preserve">User Wane Doe</w:t></w:p>',
lexed: [startParagraph, startText, content("Hello "), endText, endParagraph, startParagraph, startText, delimiters.start, content("#users"), delimiters.end, endText, endParagraph, startParagraph, startText, content("User "), delimiters.start, content("."), delimiters.end, endText, endParagraph, startParagraph, startText, delimiters.start, content("/users"), delimiters.end, endText, endParagraph],
parsed: [startParagraph, startText, content("Hello "), endText, endParagraph, startParagraph, startText, {
type: "placeholder",
value: "users",
location: "start",
module: "loop",
inverted: false,
expandTo: "auto"
}, endText, endParagraph, startParagraph, startText, content("User "), {
type: "placeholder",
value: "."
}, endText, endParagraph, startParagraph, startText, {
type: "placeholder",
value: "users",
location: "end",
module: "loop"
}, endText, endParagraph],
postparsed: [startParagraph, startText, content("Hello "), endText, endParagraph, {
type: "placeholder",
value: "users",
module: "loop",
paragraphLoop: true,
sectPrCount: 0,
hasPageBreak: false,
hasPageBreakBeginning: false,
inverted: false,
subparsed: [startParagraph, xmlSpacePreserveTag, content("User "), {
type: "placeholder",
value: "."
}, endText, endParagraph]
}]
}, _objectSpread(_objectSpread({
it: "should work with paragraph loops and selfclosing paragraphs"
}, noInternals), {}, {
content: "<w:p><w:t>{#foo}</w:t></w:p><w:p/><w:xxx></w:xxx><w:p><w:t>{/}</w:t></w:p>",
options: {
paragraphLoop: true
},
scope: {
foo: true
},
result: "<w:p/><w:xxx></w:xxx>"
}), _objectSpread(_objectSpread({
it: "should not fail with nested loops if using paragraphLoop",
content: "<w:p><w:t>{#users} {#pets}</w:t></w:p><w:p><w:t>Pet {.}</w:t></w:p><w:p><w:t>{/pets}{/users}</w:t></w:p>"
}, noInternals), {}, {
options: {
paragraphLoop: true
},
scope: {
users: [{
pets: ["Cat", "Dog"]
}, {
pets: ["Cat", "Dog"]
}]
},
result: '<w:p><w:t xml:space="preserve"> </w:t></w:p><w:p><w:t xml:space="preserve">Pet Cat</w:t></w:p><w:p><w:t/></w:p><w:p><w:t xml:space="preserve">Pet Dog</w:t></w:p><w:p><w:t xml:space="preserve"> </w:t></w:p><w:p><w:t xml:space="preserve">Pet Cat</w:t></w:p><w:p><w:t/></w:p><w:p><w:t xml:space="preserve">Pet Dog</w:t></w:p><w:p><w:t/></w:p>'
}), {
it: "should work with spacing loops",
content: "<w:t>{#condition</w:t><w:t>} hello{/</w:t><w:t>condition}</w:t>",
scope: {
condition: true
},
result: '<w:t/><w:t xml:space="preserve"> hello</w:t><w:t></w:t>',
lexed: [startText, delimiters.start, content("#condition"), endText, startText, delimiters.end, content(" hello"), delimiters.start, content("/"), endText, startText, content("condition"), delimiters.end, endText],
parsed: [startText, {
type: "placeholder",
value: "condition",
location: "start",
module: "loop",
inverted: false,
expandTo: "auto"
}, endText, startText, content(" hello"), {
type: "placeholder",
value: "condition",
location: "end",
module: "loop"
}, endText, startText, endText],
postparsed: null
}, _objectSpread(_objectSpread({
it: "should work with spacing loops 2"
}, noInternals), {}, {
content: "<w:t>{#condition}{text}{/condition}</w:t>",
scope: {
condition: [{
text: " hello "
}]
},
result: '<w:t xml:space="preserve"> hello </w:t>'
}), _objectSpread(_objectSpread({
it: "should work with empty condition"
}, noInternals), {}, {
content: "<w:t>{#a}A{/a}{^b}{/b}</w:t>",
scope: {
a: true
},
result: '<w:t xml:space="preserve">A</w:t>'
}), _objectSpread(_objectSpread({
it: "should work with spacing loops 3"
}, noInternals), {}, {
content: "<w:t>{#condition}</w:t><w:t>{/condition} foo</w:t>",
scope: {
condition: false
},
result: '<w:t xml:space="preserve"> foo</w:t>'
}), _objectSpread(_objectSpread({
it: "should work with spacing loops 4"
}, noInternals), {}, {
content: "<w:t>{#condition}foo{/condition}</w:t>",
scope: {
condition: false
},
result: "<w:t/>"
}), {
it: "should work with dashloops",
content: "<w:p><w:t>Hello {-w:p users}{name}, {/users}</w:t></w:p>",
scope: {
users: [{
name: "John Doe"
}, {
name: "Jane Doe"
}, {
name: "Wane Doe"
}]
},
result: '<w:p><w:t xml:space="preserve">Hello John Doe, </w:t></w:p><w:p><w:t xml:space="preserve">Hello Jane Doe, </w:t></w:p><w:p><w:t xml:space="preserve">Hello Wane Doe, </w:t></w:p>',
lexed: [startParagraph, startText, content("Hello "), delimiters.start, content("-w:p users"), delimiters.end, delimiters.start, content("name"), delimiters.end, content(", "), delimiters.start, content("/users"), delimiters.end, endText, endParagraph],
parsed: [startParagraph, startText, content("Hello "), {
type: "placeholder",
value: "users",
location: "start",
module: "loop",
inverted: false,
expandTo: "w:p"
}, {
type: "placeholder",
value: "name"
}, content(", "), {
type: "placeholder",
value: "users",
location: "end",
module: "loop"
}, endText, endParagraph],
postparsed: [{
type: "placeholder",
value: "users",
module: "loop",
inverted: false,
sectPrCount: 0,
subparsed: [startParagraph, xmlSpacePreserveTag, content("Hello "), {
type: "placeholder",
value: "name"
}, content(", "), endText, endParagraph]
}]
}, _objectSpread(_objectSpread({
it: "should drop table if it has no tc"
}, noInternals), {}, {
content: "<w:tbl><w:tr><w:tc><w:p><w:t>{-w:tr columns} Hello {-w:p users}{name}, {/users}</w:t><w:t>{/columns}</w:t></w:p></w:tc></w:tr></w:tbl>Other",
scope: {},
result: "<w:p/>Other"
}), {
it: "should work with dashloops nested",
content: "<w:tr><w:tc><w:p><w:t>{-w:tr columns} Hello {-w:p users}{name}, {/users}</w:t><w:t>{/columns}</w:t></w:p></w:tc></w:tr>",
scope: {
columns: [{
users: [{
name: "John Doe"
}, {
name: "Jane Doe"
}, {
name: "Wane Doe"
}]
}]
},
result: '<w:tr><w:tc><w:p><w:t xml:space="preserve"> Hello John Doe, </w:t><w:t/></w:p><w:p><w:t xml:space="preserve"> Hello Jane Doe, </w:t><w:t/></w:p><w:p><w:t xml:space="preserve"> Hello Wane Doe, </w:t><w:t/></w:p></w:tc></w:tr>',
lexed: [tableRowStart, tableColStart, startParagraph, startText, delimiters.start, content("-w:tr columns"), delimiters.end, content(" Hello "), delimiters.start, content("-w:p users"), delimiters.end, delimiters.start, content("name"), delimiters.end, content(", "), delimiters.start, content("/users"), delimiters.end, endText, startText, delimiters.start, content("/columns"), delimiters.end, endText, endParagraph, tableColEnd, tableRowEnd],
parsed: [tableRowStart, tableColStart, startParagraph, startText, {
type: "placeholder",
value: "columns",
location: "start",
module: "loop",
inverted: false,
expandTo: "w:tr"
}, content(" Hello "), {
type: "placeholder",
value: "users",
location: "start",
module: "loop",
inverted: false,
expandTo: "w:p"
}, {
type: "placeholder",
value: "name"
}, content(", "), {
type: "placeholder",
value: "users",
location: "end",
module: "loop"
}, endText, startText, {
type: "placeholder",
value: "columns",
location: "end",
module: "loop"
}, endText, endParagraph, tableColEnd, tableRowEnd],
postparsed: null
}, {
it: "should handle selfclose tag",
content: "<w:t />",
scope: {
user: "Foo"
},
result: "<w:t />",
lexed: [{
type: "tag",
value: "<w:t />",
text: true,
position: "selfclosing",
tag: "w:t"
}],
parsed: [{
type: "tag",
position: "selfclosing",
value: "<w:t />",
text: true,
tag: "w:t"
}],
postparsed: [{
type: "tag",
position: "selfclosing",
value: "<w:t />",
text: true,
tag: "w:t"
}]
}, {
it: "should handle {user} with tag with selfclosing",
content: "<w:t /><w:t>Hi {user}</w:t>",
scope: {
user: "Foo"
},
result: '<w:t /><w:t xml:space="preserve">Hi Foo</w:t>',
lexed: [{
type: "tag",
value: "<w:t />",
text: true,
position: "selfclosing",
tag: "w:t"
}, startText, content("Hi "), delimiters.start, content("user"), delimiters.end, endText],
parsed: [{
type: "tag",
position: "selfclosing",
value: "<w:t />",
text: true,
tag: "w:t"
}, startText, content("Hi "), {
type: "placeholder",
value: "user"
}, endText],
postparsed: [{
type: "tag",
position: "selfclosing",
value: "<w:t />",
text: true,
tag: "w:t"
}, xmlSpacePreserveTag, content("Hi "), {
type: "placeholder",
value: "user"
}, endText]
}, {
it: "should be possible to change the delimiters",
content: "<w:t>Hi {=[[ ]]=}[[user]][[={ }=]] and {user2}</w:t>",
scope: {
user: "John",
user2: "Jane"
},
result: '<w:t xml:space="preserve">Hi John and Jane</w:t>',
lexed: [startText, content("Hi "), delimiters.start, content("user"), delimiters.end, content(" and "), delimiters.start, content("user2"), delimiters.end, endText],
parsed: [startText, content("Hi "), {
type: "placeholder",
value: "user"
}, content(" and "), {
type: "placeholder",
value: "user2"
}, endText],
postparsed: [xmlSpacePreserveTag, content("Hi "), {
type: "placeholder",
value: "user"
}, content(" and "), {
type: "placeholder",
value: "user2"
}, endText]
}, {
it: "should be possible to change the delimiters",
content: "<w:t>Hi {=a b c=}</w:t>",
error: {
name: "TemplateError",
message: "New Delimiters cannot be parsed",
properties: {
id: "change_delimiters_invalid"
}
},
errorType: Errors.XTTemplateError
}, {
it: "should throw error if delimiters invalid",
content: "<w:t>Hi {= =}</w:t>",
error: {
name: "TemplateError",
message: "New Delimiters cannot be parsed",
properties: {
id: "change_delimiters_invalid"
}
},
errorType: Errors.XTTemplateError
}, {
it: "should throw error if delimiters invalid (2)",
content: "<w:t>Hi {=[ =}</w:t>",
error: {
name: "TemplateError",
message: "New Delimiters cannot be parsed",
properties: {
id: "change_delimiters_invalid"
}
},
errorType: Errors.XTTemplateError
}, {
it: "should throw error if delimiters invalid (3)",
content: "<w:t>Hi {= ]=}</w:t>",
error: {
name: "TemplateError",
message: "New Delimiters cannot be parsed",
properties: {
id: "change_delimiters_invalid"
}
},
errorType: Errors.XTTemplateError
}, {
it: "should be possible to change the delimiters with complex example",
content: "<w:t>Hi {={{[ ]}}=}{{[user]}}{{[={{ ]=]}} and {{user2]</w:t>",
scope: {
user: "John",
user2: "Jane"
},
result: '<w:t xml:space="preserve">Hi John and Jane</w:t>',
lexed: [startText, content("Hi "), delimiters.start, content("user"), delimiters.end, content(" and "), delimiters.start, content("user2"), delimiters.end, endText],
parsed: [startText, content("Hi "), {
type: "placeholder",
value: "user"
}, content(" and "), {
type: "placeholder",
value: "user2"
}, endText],
postparsed: [xmlSpacePreserveTag, content("Hi "), {
type: "placeholder",
value: "user"
}, content(" and "), {
type: "placeholder",
value: "user2"
}, endText]
}, _objectSpread(_objectSpread({
it: "should resolve the data correctly"
}, noInternals), {}, {
content: "<w:t>{test}{#test}{label}{/test}{test}</w:t>",
scope: {
label: "T1",
test: true
},
resolved: [{
tag: "test",
lIndex: 3,
value: true
}, {
tag: "test",
lIndex: 15,
value: true
}, {
tag: "test",
lIndex: 6,
value: [[{
tag: "label",
lIndex: 9,
value: "T1"
}]]
}],
result: '<w:t xml:space="preserve">trueT1true</w:t>'
}), _objectSpread(_objectSpread({
it: "should resolve 2 the data correctly"
}, noInternals), {}, {
content: "<w:t>{^a}{label}{/a}</w:t>",
scope: {
a: true
},
resolved: [{
tag: "a",
lIndex: 3,
value: []
}],
result: "<w:t/>"
}), _objectSpread(_objectSpread({
it: "should resolve 3 the data correctly"
}, noInternals), {}, {
content: "<w:t>{#frames}{#true}{label}{#false}{label}{/false}{/true}{#false}{label}{/false}{/frames}</w:t>",
scope: {
frames: [{
label: "T1",
"true": true
}]
},
resolved: [{
tag: "frames",
lIndex: 3,
value: [[{
tag: "false",
lIndex: 24,
value: []
}, {
tag: "true",
lIndex: 6,
value: [[{
tag: "label",
lIndex: 9,
value: "T1"
}, {
tag: "false",
lIndex: 12,
value: []
}]]
}]]
}],
result: '<w:t xml:space="preserve">T1</w:t>'
}), _objectSpread(_objectSpread({
it: "should resolve truthy data correctly",
content: "<w:t>{#loop}L{#cond2}{label}{/cond2}{#cond3}{label}{/cond3}{/loop}</w:t>"
}, noInternals), {}, {
scope: {
label: "outer",
loop: [{
cond2: true,
label: "inner"
}]
},
result: '<w:t xml:space="preserve">Linner</w:t>'
}), _objectSpread(_objectSpread({
it: "should resolve truthy multi data correctly",
content: "<w:t>{#loop}L{#cond2}{label}{/cond2}{#cond3}{label}{/cond3}{/loop}</w:t>"
}, noInternals), {}, {
scope: {
label: "outer",
loop: [{
cond2: true,
label: "inner"
}, {
cond2: true,
label: "inner"
}, {
cond3: true,
label: "inner"
}, {
cond2: true,
cond3: true
}]
},
result: '<w:t xml:space="preserve">LinnerLinnerLinnerLouterouter</w:t>'
}), _objectSpread(_objectSpread({
it: "should resolve async loop",
content: "<w:t>{#loop}{#cond1}{label}{/}{#cond2}{label}{/}{/loop}</w:t>"
}, noInternals), {}, {
scope: {
label: "outer",
loop: [{
cond1: true,
label: "inner"
}, {
cond1: true,
cond2: true
}]
},
result: '<w:t xml:space="preserve">innerouterouter</w:t>'
}), _objectSpread(_objectSpread({
it: "should work well with inversed loop simple",
content: "<w:t>{^b}{label}{/}</w:t>"
}, noInternals), {}, {
scope: {
b: false,
label: "hi"
},
result: '<w:t xml:space="preserve">hi</w:t>'
}), _objectSpread(_objectSpread({
it: "should work well with nested inversed loop",
content: "<w:t>{#a}{^b}{label}{/}{/}</w:t>"
}, noInternals), {}, {
scope: {
a: [{
b: false,
label: "hi"
}]
},
result: '<w:t xml:space="preserve">hi</w:t>'
}), _objectSpread(_objectSpread({
it: "should work well with deeply nested inversed loop nested",
content: "<w:t>{#a}{^b}{^c}{label}{/}{/}{/}</w:t>"
}, noInternals), {}, {
scope: {
a: [{
b: false,
label: "hi"
}]
},
result: '<w:t xml:space="preserve">hi</w:t>'
}), _objectSpread(_objectSpread({
it: "should work well with true value for condition",
content: "<w:t>{#cond}{#product.price > 10}high{/}{#product.price <= 10}low{/}{/cond}</w:t>"
}, noInternals), {}, {
options: {
parser: expressionParser
},
scope: {
cond: true,
product: {
price: 2
}
},
result: '<w:t xml:space="preserve">low</w:t>'
}), _objectSpread(_objectSpread({
it: "should handle {this+this+this} tag",
scope: "Foo"
}, noInternals), {}, {
content: "<w:t>Hi {this+this+this}</w:t>",
options: {
parser: expressionParser
},
result: '<w:t xml:space="preserve">Hi FooFooFoo</w:t>'
}), _objectSpread(_objectSpread({
it: "should handle {((.+.+.)*.*0.5)|sum:.} tag",
scope: 2
}, noInternals), {}, {
content: "<w:t>Hi {((((.+.+.)*.*0.5)|sum:.)-.)/.}</w:t>",
// = (((2 + 2 + 2)*2 * 0.5 | sum:2)-2)/2
// = (((6)*2 * 0.5 | sum:2)-2)/2
// = ((6 | sum:2)-2)/2
// = ((8)-2)/2
// = (6)/2
// = 3
options: {
parser: expressionParser
},
result: '<w:t xml:space="preserve">Hi 3</w:t>'
}), _objectSpread(_objectSpread({
it: "should handle {.['user-name']} tag",
scope: {
"user-name": "John"
}
}, noInternals), {}, {
content: "<w:t>Hi {.['user-name']}</w:t>",
options: {
parser: expressionParser
},
result: '<w:t xml:space="preserve">Hi John</w:t>'
}), _objectSpread(_objectSpread({
it: "should handle {#loop}{. | myFilter}{/loop} tag",
scope: {
loop: [3]
}
}, noInternals), {}, {
content: "<w:t>Hi {#loop}{. | myFilter}{/loop}</w:t>",
options: {
parser: expressionParser.configure({
filters: {
myFilter: function myFilter(input) {
expect(_typeof(input)).to.equal("number");
expect(input).to.equal(3);
return input + input;
}
}
})
},
result: '<w:t xml:space="preserve">Hi 6</w:t>'
}), _objectSpread(_objectSpread({
it: 'should handle {this["a b"]} tag',
scope: {
"a b": "John"
}
}, noInternals), {}, {
content: '<w:t>Hi {this["a b"]}</w:t>',
options: {
parser: expressionParser
},
result: '<w:t xml:space="preserve">Hi John</w:t>'
}), _objectSpread(_objectSpread({
it: 'should handle {this["length"]} tag',
scope: "John"
}, noInternals), {}, {
content: '<w:t>Hi { this["length"]}</w:t>',
options: {
parser: expressionParser
},
result: '<w:t xml:space="preserve">Hi 4</w:t>'
}), _objectSpread(_objectSpread({
it: 'should handle {this["split"]} tag',
scope: "John"
}, noInternals), {}, {
content: '<w:t>Hi {this["split"]}</w:t>',
options: {
parser: expressionParser
},
result: '<w:t xml:space="preserve">Hi undefined</w:t>'
}), _objectSpread(_objectSpread({
it: "should handle {this.split} tag",
scope: "John"
}, noInternals), {}, {
content: "<w:t>Hi {this.split}</w:t>",
options: {
parser: expressionParser
},
result: '<w:t xml:space="preserve">Hi undefined</w:t>'
}), _objectSpread(_objectSpread({
it: "should handle {(this+this+this)*this} tag",
scope: 1
}, noInternals), {}, {
content: "<w:t>Hi {(this+this+this)*(this+this)}</w:t>",
options: {
parser: expressionParser
},
result: '<w:t xml:space="preserve">Hi 6</w:t>'
}), _objectSpread(_objectSpread({
it: "should handle {(this+this+this)*(this+this)}, this=0 tag",
scope: 0
}, noInternals), {}, {
content: "<w:t>Hi {( this + this + this)*(this+this)}</w:t>",
options: {
parser: expressionParser
},
result: '<w:t xml:space="preserve">Hi 0</w:t>'
}), _objectSpread(_objectSpread({
it: "should handle {#products}{# . }-{ . }-{/}{/}",
scope: {
products: [[1, 2, 3, 4], [4, 5, 6, 7]]
}
}, noInternals), {}, {
// The space inside {# . } is important.
// It tests a regression that was fixed in version 3.37.12
content: "<w:t>Hi {#products}{# . }-{ . }-{/}{/}</w:t>",
options: {
parser: expressionParser
},
result: '<w:t xml:space="preserve">Hi -1--2--3--4--4--5--6--7-</w:t>'
}), _objectSpread(_objectSpread({
it: "should work well with int value for condition",
content: "<w:t>{#cond}{#product.price > 10}high{/}{#product.price <= 10}low{/}{/cond}</w:t>"
}, noInternals), {}, {
options: {
parser: expressionParser
},
scope: {
cond: 10,
product: {
price: 2
}
},
result: '<w:t xml:space="preserve">low</w:t>'
}), _objectSpread(_objectSpread({
it: "should work well with empty string as result",
content: "<w:t>{foo}</w:t>"
}, noInternals), {}, {
options: {
parser: expressionParser
},
scope: {
foo: ""
},
result: "<w:t/>"
}), _objectSpread(_objectSpread({
it: "should work well with str value for condition",
content: "<w:t>{#cond}{#product.price > 10}high{/}{#product.price <= 10}low{/}{/cond}</w:t>"
}, noInternals), {}, {
options: {
parser: expressionParser
},
scope: {
cond: "cond",
product: {
price: 2
}
},
result: '<w:t xml:space="preserve">low</w:t>'
}), _objectSpread(_objectSpread({
it: "should work well with false value for condition",
content: "<w:t>{^cond}{#product.price > 10}high{/}{#product.price <= 10}low{/}{/cond}</w:t>"
}, noInternals), {}, {
options: {
parser: expressionParser
},
scope: {
cond: false,
product: {
price: 2
}
},
result: '<w:t xml:space="preserve">low</w:t>'
}), _objectSpread(_objectSpread({
it: "should work well with multi level angular parser",
// This tag was designed to match /-([^\s]+)\s(.+)$/ which is the prefix of the dash loop
content: "<w:t>{#users}{name} {date-age+ offset} {/}</w:t>"
}, noInternals), {}, {
options: {
parser: expressionParser
},
scope: {
date: 2019,
offset: 1,
users: [{
name: "John",
age: 44
}, {
name: "Mary",
age: 22
}, {
date: 2100,
age: 22,
name: "Walt"
}]
},
result: '<w:t xml:space="preserve">John 1976 Mary 1998 Walt 2079 </w:t>'
}), _objectSpread(_objectSpread({
it: "should work well with $index angular parser",
content: "<w:t>{#list}{#$index==0}FIRST {/}{text} {/list}</w:t>"
}, noInternals), {}, {
options: {
parser: expressionParser
},
scope: {
list: [{
text: "Hello"
}, {
text: "Other item"
}]
},
result: '<w:t xml:space="preserve">FIRST Hello Other item </w:t>'
}), _objectSpread(_objectSpread({
it: "should work well with $index inside condition angular parser",
content: "<w:t>{#list}{#important}!!{$index+1}{text}{/}{^important}?{$index+1}{text}{/}{/}</w:t>"
}, noInternals), {}, {
options: {
parser: expressionParser
},
scope: {
list: [{
important: true,
text: "Hello"
}, {
text: "Other item"
}, {
important: true,
text: "Bye"
}]
},
result: '<w:t xml:space="preserve">!!1Hello?2Other item!!3Bye</w:t>'
}), _objectSpread(_objectSpread({
it: "should work well with $index inside condition angular parser",
content: "<w:t>{#list}{#important}!!{$index+1}{text}{/}{^important}?{$index+1}{text}{/}{/}</w:t>"
}, noInternals), {}, {
options: {
parser: angularParserIE11
},
scope: {
list: [{
important: true,
text: "Hello"
}, {
text: "Other item"
}, {
important: true,
text: "Bye"
}]
},
result: '<w:t xml:space="preserve">!!1Hello?2Other item!!3Bye</w:t>'
}), _objectSpread(_objectSpread({
it: "should work well with nested conditions inside table"
}, noInternals), {}, {
content: "<w:tbl><w:tr><w:tc><w:p><w:r><w:t>{#cond}{#cond2}{name}</w:t></w:r></w:p></w:tc><w:tc><w:p><w:r><w:t>{/}{/}</w:t></w:r></w:p></w:tc></w:tr></w:tbl>",
options: {
paragraphLoop: true
},
scope: {
cond: true,
cond2: false
},
result: ""
}), _objectSpread(_objectSpread({
it: "should work well with -w:tr conditions inside table inside paragraphLoop condition"
}, noInternals), {}, {
content: "<w:p><w:r><w:t>{#cond}</w:t></w:r></w:p><w:tbl><w:tr><w:tc><w:p><w:r><w:t>{-w:tc cond}{val}{/}</w:t></w:r></w:p></w:tc></w:tr></w:tbl><w:p><w:r><w:t>{/}</w:t></w:r></w:p>",
options: {
paragraphLoop: true
},
scope: {
cond: true,
val: "yep"
},
result: '<w:tbl><w:tr><w:tc><w:p><w:r><w:t xml:space="preserve">yep</w:t></w:r></w:p></w:tc></w:tr></w:tbl>'
}), _objectSpread(_objectSpread({
it: "should work well with nested angular expressions",
content: "<w:t>{v}{#c1}{v}{#c2}{v}{#c3}{v}{/}{/}{/}</w:t>"
}, noInternals), {}, {
options: {
parser: expressionParser
},
scope: {
v: "0",
c1: {
v: "1",
c2: {
v: "2",
c3: {
v: "3"
}
}
}
},
result: '<w:t xml:space="preserve">0123</w:t>'
}), _objectSpread(_objectSpread({
it: "should work with this with angular expressions",
content: "<w:t>{#hello}{this}{/hello}</w:t>"
}, noInternals), {}, {
options: {
parser: expressionParser
},
scope: {
hello: ["world"]
},
result: '<w:t xml:space="preserve">world</w:t>'
}), _objectSpread(_objectSpread({
it: "should be possible to close loops with {/}",
content: "<w:t>{#products}Product {name}{/}</w:t>"
}, noInternals), {}, {
scope: {
products: [{
name: "Bread"
}]
},
result: '<w:t xml:space="preserve">Product Bread</w:t>'
}), _objectSpread(_objectSpread({
it: "should get parent prop if child is null",
content: "<w:t>{#c}{label}{/c}</w:t>"
}, noInternals), {}, {
options: {
parser: expressionParser
},
scope: {
c: {
label: null
},
label: "hello"
},
result: '<w:t xml:space="preserve">hello</w:t>'
}), _objectSpread(_objectSpread({
it: "should work when using double nested arrays",
content: "<w:t>{#a}</w:t><w:t>{this}</w:t><w:t>{/}</w:t>"
}, noInternals), {}, {
options: {
parser: expressionParser
},
scope: {
a: [["first-part", "other-part"]]
},
result: '<w:t/><w:t xml:space="preserve">first-part,other-part</w:t><w:t/>'
}), _objectSpread(_objectSpread({
it: "should work when using accents or numbers in variable names, ...",
content: "<w:t>{êtreîöò12áeêëẽ}</w:t>"
}, noInternals), {}, {
options: {
parser: expressionParser
},
result: '<w:t xml:space="preserve">undefined</w:t>'
}), _objectSpread(_objectSpread({
it: "should fail when using € sign",
content: "<w:t>{hello€}</w:t>"
}, noInternals), {}, {
options: {
parser: expressionParser
},
error: wrapMultiError({
name: "ScopeParserError",
message: "Scope parser compilation failed",
properties: {
explanation: 'The scope parser for the tag "hello€" failed to compile',
rootError: {
message: "[$parse:lexerr] Lexer Error: Unexpected next character at columns 5-5 [\u20AC] in expression [hello\u20AC].\nhttp://errors.angularjs.org/\"NG_VERSION_FULL\"/$parse/lexerr?p0=Unexpected%20next%20character%20&p1=s%205-5%20%5B%E2%82%AC%5D&p2=hello%E2%82%AC"
},
file: "word/document.xml",
id: "scopeparser_compilation_failed",
xtag: "hello€",
offset: 0
}
}),
errorType: Errors.XTTemplateError,
result: '<w:t xml:space="preserve">undefined</w:t>'
}), _objectSpread(_objectSpread({
it: "should disallow access to internal property",
content: '<w:t>{"".split.toString()}</w:t>'
}, noInternals), {}, {
options: {
parser: expressionParser
},
result: '<w:t xml:space="preserve">undefined</w:t>'
}), _objectSpread(_objectSpread({
it: "should allow filters like | upper",
content: "<w:t>{name | upper}</w:t>"
}, noInternals), {}, {
options: {
parser: expressionParser
},
scope: {
name: "john"
},
result: '<w:t xml:space="preserve">JOHN</w:t>'
}), _objectSpread(_objectSpread({
it: "should work when using angular assignment that is already in the scope",
content: "<w:t>{b=a}{b}</w:t>"
}, noInternals), {}, {
options: {
parser: expressionParser
},
scope: {
a: 10,
b: 5
},
result: '<w:t xml:space="preserve">10</w:t>'
}), _objectSpread(_objectSpread({
it: "should work with linebreaks",
content: "<w:t>{b}</w:t>"
}, noInternals), {}, {
options: {
linebreaks: true,
parser: expressionParser
},
scope: {
b: "Hello\n\nFoo\n\nBar\n\n"
},
result: '<w:t xml:space="preserve">Hello</w:t></w:r><w:r><w:br/></w:r><w:r><w:t/></w:r><w:r><w:br/></w:r><w:r><w:t xml:space="preserve">Foo</w:t></w:r><w:r><w:br/></w:r><w:r><w:t/></w:r><w:r><w:br/></w:r><w:r><w:t xml:space="preserve">Bar</w:t></w:r><w:r><w:br/></w:r><w:r><w:t/></w:r><w:r><w:br/></w:r><w:r><w:t/>'
}), _objectSpread(_objectSpread({
it: "should not fail with no scope on expressionParser",
content: "<w:t>{b}</w:t>"
}, noInternals), {}, {
options: {
linebreaks: true,
parser: expressionParser
},
result: '<w:t xml:space="preserve">undefined</w:t>'
}), _objectSpread(_objectSpread({
it: "should be possible to add filter for one instance of the expressionParser",
content: "<w:t>{b|foo}</w:t>"
}, noInternals), {}, {
options: {
linebreaks: true,
parser: expressionParser.configure({
filters: {
foo: function foo() {
return "FOO";
}
}
})
},
result: '<w:t xml:space="preserve">FOO</w:t>'
}), function () {
var globalData = {
val: 0
};
return _objectSpread(_objectSpread({
it: "should be possible to configure expressionParser with set command",
content: "<w:t>{#loop}{$$val = (cond ? 0 : $$val + 1); $$val}{/loop}</w:t>"
}, noInternals), {}, {
options: {
linebreaks: true,
parser: expressionParser.configure({
setIdentifier: function setIdentifier(tag, value) {
var matchGlobal = /^\$\$/g;
if (matchGlobal.test(tag)) {
globalData[tag] = value;
return true;
}
},
evaluateIdentifier: function evaluateIdentifier(tag) {
var matchGlobal = /^\$\$/g;
if (matchGlobal.test(tag)) {
return globalData[tag];
}
}
})
},
scope: {
loop: [{
cond: true,
x: "foo"
}, {
cond: false,
x: "foo"
}, {
cond: false,
x: "foo"
}, {
cond: true,
x: "foo"
}, {
cond: false,
x: "foo"
}]
},
result: '<w:t xml:space="preserve">01201</w:t>'
});
}(), _objectSpread(_objectSpread({
it: "should be possible to use parent scope together with expressionParser",
content: "<w:t>{#loop}{__b|twice}{b|twice}{/loop}</w:t>",
// $b means in this context "b" but from the rootscope
scope: {
loop: [{
b: 2
}, {
b: 3
}],
b: 1
}
}, noInternals), {}, {
options: {
linebreaks: true,
parser: expressionParser.configure({
evaluateIdentifier: function evaluateIdentifier(tag, scope, scopeList, context) {
var matchesParent = /^(_{2,})(.*)/g;
expect(context.num).to.be.a("number");
if (matchesParent.test(tag)) {
var parentCount = tag.replace(matchesParent, "$1").length - 1;
tag = tag.replace(matchesParent, "$2");
if (parentCount >= 1) {
for (var i = scopeList.length - 1 - parentCount; i >= 0; i--) {
var s = scopeList[i];
if (s[tag] != null) {
var property = s[tag];
return typeof property === "function" ? property.bind(s) : property;
}
}
}
}
},
filters: {
twice: function twice(input) {
return 2 * input;
}
}
})
},
result: '<w:t xml:space="preserve">2426</w:t>'
}), _objectSpread(_objectSpread({
it: "should be possible to add filter for one instance of the ie11 parser",
content: "<w:t>{b|foo}</w:t>"
}, noInternals), {}, {
options: {
linebreaks: true,
parser: angularParserIE11.configure({
csp: true,
filters: {
foo: function foo() {
return "FOO";
}
}
})
},
result: '<w:t xml:space="preserve">FOO</w:t>'
}), _objectSpread(_objectSpread({
it: "should not fail with no scope on ie11 parser",
content: "<w:t>{b}</w:t>"
}, noInternals), {}, {
options: {
linebreaks: true,
parser: angularParserIE11
},
result: '<w:t xml:space="preserve">undefined</w:t>'
}), {
it: "should show error when having table with nested loops",
content: "<w:tbl>\n\t\t<w:tr><w:tc><w:p><w:r><w:t>{#c1}A</w:t></w:r></w:p></w:tc></w:tr>\n\t\t<w:tr><w:tc><w:p><w:r><w:t>{/}{#c2}B</w:t></w:r><w:r><w:t>{/}</w:t></w:r></w:p></w:tc></w:tr>\n</w:tbl>",
error: wrapMultiError({
name: "TemplateError",
message: "Unbalanced loop tag",
properties: {
explanation: "Unbalanced loop tags {#c1}{/}{#c2}{/}",
file: "word/document.xml",
id: "unbalanced_loop_tags",
lastPair: {
left: "c1",
right: ""
},
offset: [0, 15],
pair: {
left: "c2",
right: ""
}
}
}),
errorType: Errors.XTTemplateError
}, {
it: "should not escape explanation for unclosed tag with &&",
content: "<w:t>Unclosed tag : {Hi&&Ho</w:t>",
error: wrapMultiError({
name: "TemplateError",
message: "Unclosed tag",
properties: {
explanation: 'The tag beginning with "{Hi&&Ho" is unclosed',
context: "{Hi&&Ho",
xtag: "Hi&&Ho",
file: "word/document.xml",
id: "unclosed_tag",
offset: 15
}
}),
errorType: Errors.XTTemplateError
}, {
it: "should not escape explanation for unopened tag with &&",
content: "<w:t>&&foo}</w:t>",
error: wrapMultiError({
name: "TemplateError",
message: "Unopened tag",
properties: {
explanation: 'The tag beginning with "&&foo" is unopened',
context: "&&foo",
xtag: "&&foo",
file: "word/document.xml",
id: "unopened_tag",
offset: null
}
}),
errorType: Errors.XTTemplateError
}, {
it: "should not escape explanation for unclosed loop with &&",
content: "<w:t>Unclosed tag : {#Hi&&Ho}{/%%><&&bar}</w:t>",
error: wrapMultiError({
name: "TemplateError",
message: "Closing tag does not match opening tag",
properties: {
explanation: 'The tag "Hi&&Ho" is closed by the tag "%%><&&bar"',
file: "word/document.xml",
openingtag: "Hi&&Ho",
closingtag: "%%><&&bar",
id: "closing_tag_does_not_match_opening_tag",
offset: [15, 32]
}
}),
errorType: Errors.XTTemplateError
}, {
it: "should not escape explanation for duplicate opening with &&",
content: "<w:t>Unclosed tag : {Hi&&{foo</w:t>",
error: {
message: "Multi error",
name: "TemplateError",
properties: {
id: "multi_error",
errors: [{
name: "TemplateError",
message: "Unclosed tag",
properties: {
context: "{Hi&&",
xtag: "Hi&&",
explanation: 'The tag beginning with "{Hi&&" is unclosed',
file: "word/document.xml",
id: "unclosed_tag",
offset: null
}
}, {
name: "TemplateError",
message: "Unclosed tag",
properties: {
context: "{foo",
xtag: "foo",
explanation: 'The tag beginning with "{foo" is unclosed',
file: "word/document.xml",
id: "unclosed_tag",
offset: null
}
}]
}
},
errorType: Errors.XTTemplateError
}, _objectSpread(_objectSpr