UNPKG

docxtemplater

Version:

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

451 lines (445 loc) 19.5 kB
const _ = require("lodash"); const xmlSpacePreserveTag = {type: "tag", position: "start", value: '<w:t xml:space="preserve">', text: true}; const 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: [ {type: "tag", position: "start", value: "<w:t>", text: true}, {type: "content", value: "Hi ", position: "insidetag"}, {type: "delimiter", position: "start"}, {type: "content", value: "user", position: "insidetag"}, {type: "delimiter", position: "end"}, {type: "tag", value: "</w:t>", text: true, position: "end"}, ], parsed: [ {type: "tag", position: "start", value: "<w:t>", text: true}, {type: "content", value: "Hi ", position: "insidetag"}, {type: "placeholder", value: "user"}, {type: "tag", value: "</w:t>", text: true, position: "end"}, ], postparsed: [ {type: "tag", position: "start", value: '<w:t xml:space="preserve">', text: true}, {type: "content", value: "Hi ", position: "insidetag"}, {type: "placeholder", value: "user"}, {type: "tag", value: "</w:t>", text: true, position: "end"}, ], }, 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: [ {type: "tag", position: "start", value: "<w:t>", text: true}, {type: "content", value: "Hi ", position: "insidetag"}, {type: "delimiter", position: "start"}, {type: "content", value: ".", position: "insidetag"}, {type: "delimiter", position: "end"}, {type: "tag", value: "</w:t>", text: true, position: "end"}, ], parsed: [ {type: "tag", position: "start", value: "<w:t>", text: true}, {type: "content", value: "Hi ", position: "insidetag"}, {type: "placeholder", value: "."}, {type: "tag", value: "</w:t>", text: true, position: "end"}, ], postparsed: [ {type: "tag", position: "start", value: '<w:t xml:space="preserve">', text: true}, {type: "content", value: "Hi ", position: "insidetag"}, {type: "placeholder", value: "."}, {type: "tag", value: "</w:t>", text: true, position: "end"}, ], }, 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: [ {type: "tag", value: "<w:t>", text: true, position: "start"}, {type: "placeholder", value: "name"}, {type: "content", value: " ", position: "insidetag"}, {type: "placeholder", value: "age"}, {type: "tag", value: "</w:t>", text: true, position: "end"}, {type: "content", value: "FOO", position: "outsidetag"}, {type: "tag", value: "<w:t>", text: true, position: "start"}, {type: "tag", value: "</w:t>", text: true, position: "end"}, {type: "content", value: "BAR", position: "outsidetag"}, {type: "tag", value: "<w:t>", text: true, position: "start"}, {type: "tag", value: "</w:t>", text: true, position: "end"}, ], xmllexed: [ {type: "tag", position: "start", value: "<w:t>", text: true}, {type: "content", value: "{name} {"}, {type: "tag", position: "end", value: "</w:t>", text: true}, {type: "content", value: "FOO"}, {type: "tag", position: "start", value: "<w:t>", text: true}, {type: "content", value: "age"}, {type: "tag", position: "end", value: "</w:t>", text: true}, {type: "content", value: "BAR"}, {type: "tag", position: "start", value: "<w:t>", text: true}, {type: "content", value: "}"}, {type: "tag", position: "end", value: "</w:t>", text: true}, ], lexed: [ {type: "tag", value: "<w:t>", text: true, position: "start"}, {type: "delimiter", position: "start"}, {type: "content", value: "name", position: "insidetag"}, {type: "delimiter", position: "end"}, {type: "content", value: " ", position: "insidetag"}, {type: "delimiter", position: "start"}, {type: "tag", value: "</w:t>", text: true, position: "end"}, {type: "content", value: "FOO", position: "outsidetag"}, {type: "tag", value: "<w:t>", text: true, position: "start"}, {type: "content", value: "age", position: "insidetag"}, {type: "tag", value: "</w:t>", text: true, position: "end"}, {type: "content", value: "BAR", position: "outsidetag"}, {type: "tag", value: "<w:t>", text: true, position: "start"}, {type: "delimiter", position: "end"}, {type: "tag", value: "</w:t>", text: true, position: "end"}, ], }, 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: [ {type: "tag", value: "<w:t>", text: true, position: "start"}, {type: "content", value: "Hello ", position: "insidetag"}, {type: "delimiter", position: "start"}, {type: "content", value: "name", position: "insidetag"}, {type: "delimiter", position: "end"}, {type: "tag", value: "</w:t>", text: true, position: "end"}, ], parsed: [ {type: "tag", value: "<w:t>", text: true, position: "start"}, {type: "content", value: "Hello ", position: "insidetag"}, {type: "placeholder", value: "name"}, {type: "tag", value: "</w:t>", text: true, position: "end"}, ], }, 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: [ {type: "tag", value: "<w:t>", text: true, position: "start"}, {type: "content", value: "Hello ", position: "insidetag"}, {type: "delimiter", position: "start"}, {type: "content", value: "name", position: "insidetag"}, {type: "delimiter", position: "end"}, {type: "tag", value: "</w:t>", text: true, position: "end"}, {type: "tag", value: '<w:t foo="bar">', text: true, position: "start"}, {type: "content", value: ", how is it ?", position: "insidetag"}, {type: "tag", value: "</w:t>", text: true, position: "end"}, ], parsed: [ {type: "tag", value: "<w:t>", text: true, position: "start"}, {type: "content", value: "Hello ", position: "insidetag"}, {type: "placeholder", value: "name"}, {type: "tag", value: "</w:t>", text: true, position: "end"}, {type: "tag", value: '<w:t foo="bar">', text: true, position: "start"}, {type: "content", value: ", how is it ?", position: "insidetag"}, {type: "tag", value: "</w:t>", text: true, position: "end"}, ], }, 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: [ {type: "tag", value: "<w:t>", text: true, position: "start"}, {type: "content", value: "Hello ", position: "insidetag"}, {type: "delimiter", position: "start"}, {type: "content", value: "name", position: "insidetag"}, {type: "delimiter", position: "end"}, {type: "tag", value: "</w:t>", text: true, position: "end"}, {type: "tag", value: "<w:t>", text: true, position: "start"}, {type: "tag", value: "</w:t>", text: true, position: "end"}, {type: "content", value: "TAG", position: "outsidetag"}, {type: "tag", value: "<w:t>", text: true, position: "start"}, {type: "tag", value: "</w:t>", text: true, position: "end"}, {type: "tag", value: "<w:t>", text: true, position: "start"}, {type: "content", value: "foobar", position: "insidetag"}, {type: "tag", value: "</w:t>", text: true, position: "end"}, ], parsed: [ {type: "tag", value: "<w:t>", text: true, position: "start"}, {type: "content", value: "Hello ", position: "insidetag"}, {type: "placeholder", value: "name"}, {type: "tag", value: "</w:t>", text: true, position: "end"}, {type: "tag", value: "<w:t>", text: true, position: "start"}, {type: "tag", value: "</w:t>", text: true, position: "end"}, {type: "content", value: "TAG", position: "outsidetag"}, {type: "tag", value: "<w:t>", text: true, position: "start"}, {type: "tag", value: "</w:t>", text: true, position: "end"}, {type: "tag", value: "<w:t>", text: true, position: "start"}, {type: "content", value: "foobar", position: "insidetag"}, {type: "tag", value: "</w:t>", text: true, position: "end"}, ], }, 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: [ {type: "tag", value: "<w:t>", text: true, position: "start"}, {type: "content", value: "Hello ", position: "insidetag"}, {type: "delimiter", position: "start"}, {type: "content", value: "#users", position: "insidetag"}, {type: "delimiter", position: "end"}, {type: "delimiter", position: "start"}, {type: "content", value: "name", position: "insidetag"}, {type: "delimiter", position: "end"}, {type: "content", value: ", ", position: "insidetag"}, {type: "delimiter", position: "start"}, {type: "content", value: "/users", position: "insidetag"}, {type: "delimiter", position: "end"}, {type: "tag", value: "</w:t>", text: true, position: "end"}, ], parsed: [ {type: "tag", value: "<w:t>", text: true, position: "start"}, {type: "content", value: "Hello ", position: "insidetag"}, {type: "placeholder", value: "users", location: "start", module: "loop", inverted: false, expandTo: "auto"}, {type: "placeholder", value: "name"}, {type: "content", value: ", ", position: "insidetag"}, {type: "placeholder", value: "users", location: "end", module: "loop"}, {type: "tag", value: "</w:t>", text: true, position: "end"}, ], postparsed: [ xmlSpacePreserveTag, {type: "content", value: "Hello ", position: "insidetag"}, { type: "placeholder", value: "users", module: "loop", inverted: false, subparsed: [ {type: "placeholder", value: "name"}, {type: "content", value: ", ", position: "insidetag"}, ], }, {type: "tag", value: "</w:t>", text: true, position: "end"}, ], }, 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: [ {type: "tag", value: "<w:p>", text: false, position: "start"}, {type: "tag", value: "<w:t>", text: true, position: "start"}, {type: "content", value: "Hello ", position: "insidetag"}, {type: "delimiter", position: "start"}, {type: "content", value: "-w:p users", position: "insidetag"}, {type: "delimiter", position: "end"}, {type: "delimiter", position: "start"}, {type: "content", value: "name", position: "insidetag"}, {type: "delimiter", position: "end"}, {type: "content", value: ", ", position: "insidetag"}, {type: "delimiter", position: "start"}, {type: "content", value: "/users", position: "insidetag"}, {type: "delimiter", position: "end"}, {type: "tag", value: "</w:t>", text: true, position: "end"}, {type: "tag", value: "</w:p>", text: false, position: "end"}, ], parsed: [ {type: "tag", value: "<w:p>", text: false, position: "start"}, {type: "tag", value: "<w:t>", text: true, position: "start"}, {type: "content", value: "Hello ", position: "insidetag"}, {type: "placeholder", value: "users", location: "start", module: "loop", inverted: false, expandTo: "w:p"}, {type: "placeholder", value: "name"}, {type: "content", value: ", ", position: "insidetag"}, {type: "placeholder", value: "users", location: "end", module: "loop"}, {type: "tag", value: "</w:t>", text: true, position: "end"}, {type: "tag", value: "</w:p>", text: false, position: "end"}, ], postparsed: [ { type: "placeholder", value: "users", module: "loop", inverted: false, subparsed: [ {type: "tag", value: "<w:p>", text: false, position: "start"}, xmlSpacePreserveTag, {type: "content", value: "Hello ", position: "insidetag"}, {type: "placeholder", value: "name"}, {type: "content", value: ", ", position: "insidetag"}, {type: "tag", value: "</w:t>", text: true, position: "end"}, {type: "tag", value: "</w:p>", text: false, position: "end"}, ], }, ], }, 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:t></w:p><w:p><w:t xml:space="preserve"> Hello Jane Doe, </w:t><w:t></w:t></w:p><w:p><w:t xml:space="preserve"> Hello Wane Doe, </w:t><w:t></w:t></w:p></w:tr>', lexed: [ {type: "tag", position: "start", text: false, value: "<w:tr>"}, {type: "tag", position: "start", text: false, value: "<w:p>"}, {type: "tag", position: "start", text: true, value: "<w:t>"}, {type: "delimiter", position: "start"}, {type: "content", value: "-w:tr columns", position: "insidetag"}, {type: "delimiter", position: "end"}, {type: "content", value: " Hello ", position: "insidetag"}, {type: "delimiter", position: "start"}, {type: "content", value: "-w:p users", position: "insidetag"}, {type: "delimiter", position: "end"}, {type: "delimiter", position: "start"}, {type: "content", value: "name", position: "insidetag"}, {type: "delimiter", position: "end"}, {type: "content", value: ", ", position: "insidetag"}, {type: "delimiter", position: "start"}, {type: "content", value: "/users", position: "insidetag"}, {type: "delimiter", position: "end"}, {type: "tag", position: "end", text: true, value: "</w:t>"}, {type: "tag", position: "start", text: true, value: "<w:t>"}, {type: "delimiter", position: "start"}, {type: "content", value: "/columns", position: "insidetag"}, {type: "delimiter", position: "end"}, {type: "tag", position: "end", text: true, value: "</w:t>"}, {type: "tag", position: "end", text: false, value: "</w:p>"}, {type: "tag", position: "end", text: false, value: "</w:tr>"}, ], parsed: [ {type: "tag", position: "start", text: false, value: "<w:tr>"}, {type: "tag", position: "start", text: false, value: "<w:p>"}, {type: "tag", position: "start", text: true, value: "<w:t>"}, {type: "placeholder", value: "columns", location: "start", module: "loop", inverted: false, expandTo: "w:tr"}, {type: "content", value: " Hello ", position: "insidetag"}, {type: "placeholder", value: "users", location: "start", module: "loop", inverted: false, expandTo: "w:p"}, {type: "placeholder", value: "name"}, {type: "content", value: ", ", position: "insidetag"}, {type: "placeholder", value: "users", location: "end", module: "loop"}, {type: "tag", position: "end", text: true, value: "</w:t>"}, {type: "tag", position: "start", text: true, value: "<w:t>"}, {type: "placeholder", value: "columns", location: "end", module: "loop"}, {type: "tag", position: "end", text: true, value: "</w:t>"}, {type: "tag", position: "end", text: false, value: "</w:p>"}, {type: "tag", position: "end", text: false, value: "</w:tr>"}, ], postparsed: [ { type: "placeholder", value: "columns", module: "loop", inverted: false, subparsed: [ {type: "tag", value: "<w:tr>", text: false, position: "start"}, { type: "placeholder", value: "users", module: "loop", inverted: false, subparsed: [ {type: "tag", value: "<w:p>", text: false, position: "start"}, xmlSpacePreserveTag, {type: "content", value: " Hello ", position: "insidetag"}, {type: "placeholder", value: "name"}, {type: "content", value: ", ", position: "insidetag"}, {type: "tag", value: "</w:t>", text: true, position: "end"}, {type: "tag", value: "<w:t>", text: true, position: "start"}, {type: "tag", value: "</w:t>", text: true, position: "end"}, {type: "tag", value: "</w:p>", text: false, position: "end"}, ], }, {type: "tag", value: "</w:tr>", text: false, position: "end"}, ], }, ], }, 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: [ {type: "content", value: "BEFORE", position: "outsidetag"}, {type: "tag", value: "<w:p>", text: false, position: "start"}, {type: "tag", value: "<w:t>", text: true, position: "start"}, {type: "delimiter", position: "start"}, {type: "content", value: "@rawxml", position: "insidetag"}, {type: "delimiter", position: "end"}, {type: "tag", value: "</w:t>", text: true, position: "end"}, {type: "tag", value: "</w:p>", text: false, position: "end"}, {type: "content", value: "AFTER", position: "outsidetag"}, ], parsed: [ {type: "content", value: "BEFORE", position: "outsidetag"}, {type: "tag", value: "<w:p>", text: false, position: "start"}, {type: "tag", value: "<w:t>", text: true, position: "start"}, {type: "placeholder", value: "rawxml", module: "rawxml"}, {type: "tag", value: "</w:t>", text: true, position: "end"}, {type: "tag", value: "</w:p>", text: false, position: "end"}, {type: "content", value: "AFTER", position: "outsidetag"}, ], postparsed: [ {type: "content", value: "BEFORE", position: "outsidetag"}, {type: "placeholder", value: "rawxml", module: "rawxml", expanded: [ [ {type: "tag", value: "<w:p>", text: false, position: "start"}, {type: "tag", value: "<w:t>", text: true, position: "start"}, ], [ {type: "tag", value: "</w:t>", text: true, position: "end"}, {type: "tag", value: "</w:p>", text: false, position: "end"}, ], ]}, {type: "content", value: "AFTER", position: "outsidetag"}, ], }, }; 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) { const fixture = fixtures[key]; fixture.delimiters = fixture.delimiters || { start: "{", end: "}", }; }); module.exports = fixtures;