UNPKG

docxtemplater

Version:

docx and pptx generator working with templates and data (like Mustache, for Word and Powerpoint documents)

1,029 lines (1,021 loc) 30.4 kB
"use strict"; var _require = require("lodash"), clone = _require.clone, assign = _require.assign; var angularParser = require("./angular-parser.js"); var Errors = require("../errors.js"); var _require2 = require("./utils.js"), wrapMultiError = _require2.wrapMultiError; 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 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 = { simple: { 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>', 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] }, dot: { 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] }, strangetags: { 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>', parsed: [startText, { type: "placeholder", value: "name" }, content(" "), { type: "placeholder", value: "age" }, endText, externalContent("FOO"), startText, endText, externalContent("BAR"), startText, endText], 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], postparsed: null }, otherdelimiters: { 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 }, otherdelimiterssplitted: { 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 }, otherdelimiterssplittedover2tags: { 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 }, looptag: { 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, sectPrIndex: 0, subparsed: [{ type: "placeholder", value: "name" }, content(", ")] }, endText] }, paragraphlooptag: { 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>", 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", sectPrCount: 0, sectPrIndex: 0, hasPageBreak: false, hasPageBreakBeginning: false, inverted: false, subparsed: [startParagraph, xmlSpacePreserveTag, content("User "), { type: "placeholder", value: "." }, endText, endParagraph] }], options: { paragraphLoop: true } }, nestedparagraphlooptag: { 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>", 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>', lexed: null, parsed: null, postparsed: null, options: { paragraphLoop: true } }, spacingloops: { it: "should work with spacing loops", content: "<w:t>{#condition</w:t><w:t>} hello{/</w:t><w:t>condition}</w:t>", result: '<w:t/><w:t xml:space="preserve"> hello</w:t><w:t></w:t>', scope: { condition: true }, 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 }, spacingloops2: { it: "should work with spacing loops 2", content: "<w:t>{#condition}{text}{/condition}</w:t>", result: '<w:t xml:space="preserve"> hello </w:t>', lexed: null, parsed: null, postparsed: null, scope: { condition: [{ text: " hello " }] } }, spacingloops3: { it: "should work with spacing loops 3", content: "<w:t>{#condition}</w:t><w:t>{/condition} foo</w:t>", result: '<w:t xml:space="preserve"> foo</w:t>', lexed: null, parsed: null, postparsed: null, scope: { condition: false } }, spacingloops4: { it: "should work with spacing loops 4", content: "<w:t>{#condition}foo{/condition}</w:t>", result: "<w:t/>", lexed: null, parsed: null, postparsed: null, scope: { condition: false } }, dashlooptag: { 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, sectPrIndex: 0, subparsed: [startParagraph, xmlSpacePreserveTag, content("Hello "), { type: "placeholder", value: "name" }, content(", "), endText, endParagraph] }] }, dashloopnested: { it: "should work with dashloops nested", content: "<w:tr><w:p><w:t>{-w:tr columns} Hello {-w:p users}{name}, {/users}</w:t><w:t>{/columns}</w:t></w:p></w:tr>", scope: { columns: [{ users: [{ name: "John Doe" }, { name: "Jane Doe" }, { name: "Wane Doe" }] }] }, result: '<w:tr><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:tr>', lexed: [tableRowStart, 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, tableRowEnd], parsed: [tableRowStart, 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, tableRowEnd], postparsed: null }, rawxml: { it: "should work with rawxml", content: "BEFORE<w:p><w:t>{@rawxml}</w:t></w:p>AFTER", scope: { rawxml: '<w:p><w:pPr><w:rPr><w:color w:val="FF0000"/></w:rPr></w:pPr><w:r><w:rPr><w:color w:val="FF0000"/></w:rPr><w:t>My custom</w:t></w:r><w:r><w:rPr><w:color w:val="00FF00"/></w:rPr><w:t>XML</w:t></w:r></w:p>' }, result: 'BEFORE<w:p><w:pPr><w:rPr><w:color w:val="FF0000"/></w:rPr></w:pPr><w:r><w:rPr><w:color w:val="FF0000"/></w:rPr><w:t>My custom</w:t></w:r><w:r><w:rPr><w:color w:val="00FF00"/></w:rPr><w:t>XML</w:t></w:r></w:p>AFTER', lexed: [externalContent("BEFORE"), startParagraph, startText, delimiters.start, content("@rawxml"), delimiters.end, endText, endParagraph, externalContent("AFTER")], parsed: [externalContent("BEFORE"), startParagraph, startText, { type: "placeholder", value: "rawxml", module: "rawxml" }, endText, endParagraph, externalContent("AFTER")], postparsed: [externalContent("BEFORE"), { type: "placeholder", value: "rawxml", module: "rawxml", expanded: [[startParagraph, startText], [endText, endParagraph]] }, externalContent("AFTER")] }, selfclosing: { 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" }] }, selfclosing_with_placeholderr: { 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] }, delimiters_change: { 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] }, delimiters_change_complex: { 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] }, error_resolve: { it: "should resolve the data correctly", content: "<w:t>{test}{#test}{label}{/test}{test}</w:t>", result: '<w:t xml:space="preserve">trueT1true</w:t>', scope: { label: "T1", test: true }, resolved: [{ tag: "test", value: true, lIndex: 3 }, { tag: "test", value: true, lIndex: 15 }, { tag: "test", value: [[{ tag: "label", value: "T1", lIndex: 9 }]], lIndex: 6 }], lexed: null, parsed: null, postparsed: null }, error_resolve_2: { it: "should resolve 2 the data correctly", content: "<w:t>{^a}{label}{/a}</w:t>", result: "<w:t/>", scope: { a: true }, resolved: [{ tag: "a", value: [], lIndex: 3 }], lexed: null, parsed: null, postparsed: null }, error_resolve_3: { it: "should resolve 3 the data correctly", content: "<w:t>{#frames}{#true}{label}{#false}{label}{/false}{/true}{#false}{label}{/false}{/frames}</w:t>", result: '<w:t xml:space="preserve">T1</w:t>', scope: { frames: [{ label: "T1", "true": true }] }, resolved: [{ tag: "frames", value: [[{ tag: "false", value: [], lIndex: 24 }, { tag: "true", value: [[{ tag: "label", value: "T1", lIndex: 9 }, { tag: "false", value: [], lIndex: 12 }]], lIndex: 6 }]], lIndex: 3 }], lexed: null, parsed: null, postparsed: null }, error_resolve_truthy: { it: "should resolve truthy data correctly", content: "<w:t>{#loop}L{#cond2}{label}{/cond2}{#cond3}{label}{/cond3}{/loop}</w:t>", result: '<w:t xml:space="preserve">Linner</w:t>', scope: { label: "outer", loop: [{ cond2: true, label: "inner" }] }, lexed: null, parsed: null, postparsed: null, resolved: null }, error_resolve_truthy_multi: { it: "should resolve truthy multi data correctly", content: "<w:t>{#loop}L{#cond2}{label}{/cond2}{#cond3}{label}{/cond3}{/loop}</w:t>", result: '<w:t xml:space="preserve">LinnerLinnerLinnerLouterouter</w:t>', scope: { label: "outer", loop: [{ cond2: true, label: "inner" }, { cond2: true, label: "inner" }, { cond3: true, label: "inner" }, { cond2: true, cond3: true }] }, lexed: null, parsed: null, postparsed: null, resolved: null }, async_loop_issue: { it: "should resolve async loop", content: "<w:t>{#loop}{#cond1}{label}{/}{#cond2}{label}{/}{/loop}</w:t>", result: '<w:t xml:space="preserve">innerouterouter</w:t>', scope: { label: "outer", loop: [{ cond1: true, label: "inner" }, { cond1: true, cond2: true }] }, lexed: null, parsed: null, postparsed: null, resolved: null }, inversed_loop_simple: { it: "should work well with inversed loop simple", content: "<w:t>{^b}{label}{/}</w:t>", result: '<w:t xml:space="preserve">hi</w:t>', scope: { b: false, label: "hi" }, lexed: null, parsed: null, postparsed: null, resolved: null }, inversed_loop: { it: "should work well with nested inversed loop", content: "<w:t>{#a}{^b}{label}{/}{/}</w:t>", result: '<w:t xml:space="preserve">hi</w:t>', scope: { a: [{ b: false, label: "hi" }] }, lexed: null, parsed: null, postparsed: null, resolved: null }, inversed_loop_nested: { it: "should work well with deeply nested inversed loop nested", content: "<w:t>{#a}{^b}{^c}{label}{/}{/}{/}</w:t>", result: '<w:t xml:space="preserve">hi</w:t>', scope: { a: [{ b: false, label: "hi" }] }, lexed: null, parsed: null, postparsed: null, resolved: null }, condition_true_value: { it: "should work well with true value for condition", content: "<w:t>{#cond}{#product.price &gt; 10}high{/}{#product.price &lt;= 10}low{/}{/cond}</w:t>", result: '<w:t xml:space="preserve">low</w:t>', scope: { cond: true, product: { price: 2 } }, options: { parser: angularParser }, lexed: null, parsed: null, postparsed: null, resolved: null }, condition_int_value: { it: "should work well with int value for condition", content: "<w:t>{#cond}{#product.price &gt; 10}high{/}{#product.price &lt;= 10}low{/}{/cond}</w:t>", result: '<w:t xml:space="preserve">low</w:t>', scope: { cond: 10, product: { price: 2 } }, options: { parser: angularParser }, lexed: null, parsed: null, postparsed: null, resolved: null }, condition_string_value: { it: "should work well with str value for condition", content: "<w:t>{#cond}{#product.price &gt; 10}high{/}{#product.price &lt;= 10}low{/}{/cond}</w:t>", result: '<w:t xml:space="preserve">low</w:t>', scope: { cond: "cond", product: { price: 2 } }, options: { parser: angularParser }, lexed: null, parsed: null, postparsed: null, resolved: null }, condition_false_value: { it: "should work well with false value for condition", content: "<w:t>{^cond}{#product.price &gt; 10}high{/}{#product.price &lt;= 10}low{/}{/cond}</w:t>", result: '<w:t xml:space="preserve">low</w:t>', scope: { cond: false, product: { price: 2 } }, options: { parser: angularParser }, lexed: null, parsed: null, postparsed: null, resolved: null }, condition_multi_level: { it: "should work well with multi level angular parser", content: "<w:t>{#users}{name} {date-age} {/}</w:t>", result: '<w:t xml:space="preserve">John 1975 Mary 1997 Walt 2078 </w:t>', scope: { date: 2019, users: [{ name: "John", age: 44 }, { name: "Mary", age: 22 }, { date: 2100, age: 22, name: "Walt" }] }, options: { parser: angularParser }, lexed: null, parsed: null, postparsed: null, resolved: null }, condition_w_tr: { it: "should work well with -w:tr conditions inside table inside paragraphLoop condition", 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>", 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>', scope: { cond: true, val: "yep" }, options: { paragraphLoop: true }, lexed: null, parsed: null, postparsed: null, resolved: null }, angular_expressions: { it: "should work well with nested angular expressions", content: "<w:t>{v}{#c1}{v}{#c2}{v}{#c3}{v}{/}{/}{/}</w:t>", result: '<w:t xml:space="preserve">0123</w:t>', scope: { v: "0", c1: { v: "1", c2: { v: "2", c3: { v: "3" } } } }, options: { parser: angularParser }, lexed: null, parsed: null, postparsed: null, resolved: null }, angular_this: { it: "should work with this with angular expressions", content: "<w:t>{#hello}{this}{/hello}</w:t>", result: '<w:t xml:space="preserve">world</w:t>', scope: { hello: ["world"] }, options: { parser: angularParser }, lexed: null, parsed: null, postparsed: null, resolved: null }, angular_get_parent_prop_if_null_child: { it: "should get parent prop if child is null", content: "<w:t>{#c}{label}{/c}</w:t>", result: '<w:t xml:space="preserve">hello</w:t>', scope: { c: { label: null }, label: "hello" }, options: { parser: angularParser }, lexed: null, parsed: null, postparsed: null, resolved: null }, double_nested_array: { it: "should work when using double nested arrays", content: "<w:t>{#a}</w:t><w:t>{this}</w:t><w:t>{/}</w:t>", result: '<w:t/><w:t xml:space="preserve">first-part,other-part</w:t><w:t/>', scope: { a: [["first-part", "other-part"]] }, options: { parser: angularParser }, lexed: null, parsed: null, postparsed: null, resolved: null }, table_with_nested_loops: { it: "should work for table with nested loops", lexed: null, 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>", errorType: Errors.XTTemplateError, 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: "" } } }) }, spacepreserve: { it: "should add space=preserve to last tag", lexed: null, parsed: null, postparsed: null, content: "<w:p>\n <w:r>\n <w:t>Hello {firstName} {</w:t>\n </w:r>\n <w:r>\n <w:t>lastName</w:t>\n </w:r>\n <w:r>\n <w:t>} world</w:t>\n </w:r>\n </w:p>", result: "<w:p>\n <w:r>\n <w:t xml:space=\"preserve\">Hello undefined undefined</w:t>\n </w:r>\n <w:r>\n <w:t></w:t>\n </w:r>\n <w:r>\n <w:t xml:space=\"preserve\"> world</w:t>\n </w:r>\n </w:p>" }, spacepreserve2: { it: "should add space=preserve to last tag when having middle tag", lexed: null, parsed: null, postparsed: null, content: "<w:p>\n\t\t<w:r>\n\t\t\t<w:t>Hello {</w:t>\n\t\t</w:r>\n\t\t<w:r>\n\t\t\t<w:t>last_name</w:t>\n\t\t</w:r>\n\t\t<w:r>\n\t\t\t<w:t>} {</w:t>\n\t\t</w:r>\n\t\t<w:r>\n\t\t\t<w:t>first_name</w:t>\n\t\t</w:r>\n\t\t<w:r>\n\t\t\t<w:t>} what's up ?</w:t>\n\t\t</w:r>\n </w:p>", result: "<w:p>\n\t\t<w:r>\n\t\t\t<w:t xml:space=\"preserve\">Hello undefined</w:t>\n\t\t</w:r>\n\t\t<w:r>\n\t\t\t<w:t></w:t>\n\t\t</w:r>\n\t\t<w:r>\n\t\t\t<w:t xml:space=\"preserve\"> undefined</w:t>\n\t\t</w:r>\n\t\t<w:r>\n\t\t\t<w:t></w:t>\n\t\t</w:r>\n\t\t<w:r>\n\t\t\t<w:t xml:space=\"preserve\"> what&apos;s up ?</w:t>\n\t\t</w:r>\n </w:p>" } }; fixtures.rawxmlemptycontent = clone(fixtures.rawxml); fixtures.rawxmlemptycontent.it = "should work with rawxml with undefined tags"; fixtures.rawxmlemptycontent.scope = {}; fixtures.rawxmlemptycontent.result = "BEFOREAFTER"; Object.keys(fixtures).forEach(function (key) { var fixture = fixtures[key]; var delimiters = { delimiters: fixture.delimiters || { start: "{", end: "}" } }; fixture.options = assign({}, fixture.options, delimiters); }); module.exports = fixtures;