From 2d2e4cdab241594b3e1500d976968dadacb847c1 Mon Sep 17 00:00:00 2001 From: Dolan Date: Sun, 13 Oct 2024 01:29:32 +0100 Subject: [PATCH] fix: Missing text property for patchDocument (#2760) * fix: Missing text property Ignore
for patched files * Fix spelling issues --- demo/93-template-document.ts | 72 ++++ demo/assets/field-trip.docx | Bin 0 -> 25543 bytes src/patcher/paragraph-split-inject.spec.ts | 60 +++ src/patcher/paragraph-split-inject.ts | 2 +- src/patcher/patch-detector.spec.ts | 168 ++++++++ src/patcher/replacer.spec.ts | 449 +++++++++++++++++++++ src/patcher/replacer.ts | 2 +- 7 files changed, 751 insertions(+), 2 deletions(-) create mode 100644 demo/93-template-document.ts create mode 100644 demo/assets/field-trip.docx diff --git a/demo/93-template-document.ts b/demo/93-template-document.ts new file mode 100644 index 0000000000..7f5263004d --- /dev/null +++ b/demo/93-template-document.ts @@ -0,0 +1,72 @@ +// Patch a document with patches + +import * as fs from "fs"; +import { patchDocument, PatchType, TextRun } from "docx"; + +patchDocument({ + outputType: "nodebuffer", + data: fs.readFileSync("demo/assets/field-trip.docx"), + patches: { + todays_date: { + type: PatchType.PARAGRAPH, + children: [new TextRun({ text: new Date().toLocaleDateString() })], + }, + + school_name: { + type: PatchType.PARAGRAPH, + children: [new TextRun({ text: "test" })], + }, + + address: { + type: PatchType.PARAGRAPH, + children: [new TextRun({ text: "blah blah" })], + }, + + city: { + type: PatchType.PARAGRAPH, + children: [new TextRun({ text: "test" })], + }, + + state: { + type: PatchType.PARAGRAPH, + children: [new TextRun({ text: "test" })], + }, + + zip: { + type: PatchType.PARAGRAPH, + children: [new TextRun({ text: "test" })], + }, + + phone: { + type: PatchType.PARAGRAPH, + children: [new TextRun({ text: "test" })], + }, + + first_name: { + type: PatchType.PARAGRAPH, + children: [new TextRun({ text: "test" })], + }, + + last_name: { + type: PatchType.PARAGRAPH, + children: [new TextRun({ text: "test" })], + }, + + email_address: { + type: PatchType.PARAGRAPH, + children: [new TextRun({ text: "test" })], + }, + + ft_dates: { + type: PatchType.PARAGRAPH, + children: [new TextRun({ text: "test" })], + }, + + grade: { + type: PatchType.PARAGRAPH, + children: [new TextRun({ text: "test" })], + }, + }, +}).then((doc) => { + fs.writeFileSync("My Document.docx", doc); +}); diff --git a/demo/assets/field-trip.docx b/demo/assets/field-trip.docx new file mode 100644 index 0000000000000000000000000000000000000000..a7415962bbde5dbd3b5244ba1747a99c0bd611f9 GIT binary patch literal 25543 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 { }, }); }); + + it("should create an empty end element if it is at the end", () => { + const output = splitRunElement( + { + type: "element", + name: "w:r", + elements: [ + { + type: "element", + name: "w:rPr", + elements: [ + { type: "element", name: "w:rFonts", attributes: { "w:eastAsia": "Times New Roman" } }, + { type: "element", name: "w:kern", attributes: { "w:val": "0" } }, + { type: "element", name: "w:sz", attributes: { "w:val": "20" } }, + { + type: "element", + name: "w:lang", + attributes: { "w:val": "en-US", "w:eastAsia": "en-US", "w:bidi": "ar-SA" }, + }, + ], + }, + { type: "element", name: "w:t", elements: [], attributes: { "xml:space": "preserve" } }, + { type: "element", name: "w:br" }, + { type: "element", name: "w:t", elements: [{ type: "text", text: "ɵ" }] }, + ], + }, + "ɵ", + ); + + expect(output).to.deep.equal({ + left: { + type: "element", + name: "w:r", + elements: [ + { + type: "element", + name: "w:rPr", + elements: [ + { type: "element", name: "w:rFonts", attributes: { "w:eastAsia": "Times New Roman" } }, + { type: "element", name: "w:kern", attributes: { "w:val": "0" } }, + { type: "element", name: "w:sz", attributes: { "w:val": "20" } }, + { + type: "element", + name: "w:lang", + attributes: { "w:val": "en-US", "w:eastAsia": "en-US", "w:bidi": "ar-SA" }, + }, + ], + }, + { type: "element", name: "w:t", elements: [], attributes: { "xml:space": "preserve" } }, + { type: "element", name: "w:br" }, + { type: "element", name: "w:t", elements: [], attributes: { "xml:space": "preserve" } }, + ], + }, + right: { + type: "element", + name: "w:r", + elements: [{ type: "element", name: "w:t", elements: [], attributes: { "xml:space": "preserve" } }], + }, + }); + }); }); }); diff --git a/src/patcher/paragraph-split-inject.ts b/src/patcher/paragraph-split-inject.ts index d7485e4991..008d47c7fc 100644 --- a/src/patcher/paragraph-split-inject.ts +++ b/src/patcher/paragraph-split-inject.ts @@ -29,7 +29,7 @@ export const splitRunElement = (runElement: Element, token: string): { readonly runElement.elements ?.map((e, i) => { if (e.type === "element" && e.name === "w:t") { - const text = (e.elements?.[0].text as string) ?? ""; + const text = (e.elements?.[0]?.text as string) ?? ""; const splitText = text.split(token); const newElements = splitText.map((t) => ({ ...e, diff --git a/src/patcher/patch-detector.spec.ts b/src/patcher/patch-detector.spec.ts index 961502c11a..dee2bb7ecc 100644 --- a/src/patcher/patch-detector.spec.ts +++ b/src/patcher/patch-detector.spec.ts @@ -195,6 +195,147 @@ const MOCK_XML = ` `; +// cspell:disable +const MOCK_XML_2 = ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{ + + + + + + + + + s + + + + + + + + + chool_ + + + + + + + + + n + + + + + + + + + ame}} + + {{ + + + + + + + + + a + + + + + + + + + ddr + + + + + + + + + ess + + + + + + + + + }} + + {{ + + + + + + +`; +// cspell:enable + describe("patch-detector", () => { describe("patchDetector", () => { describe("document.xml and [Content_Types].xml", () => { @@ -222,4 +363,31 @@ describe("patch-detector", () => { }); }); }); + + describe("patchDetector", () => { + describe("document.xml and [Content_Types].xml", () => { + beforeEach(() => { + vi.spyOn(JSZip, "loadAsync").mockReturnValue( + new Promise((resolve) => { + const zip = new JSZip(); + + zip.file("word/document.xml", MOCK_XML_2); + zip.file("[Content_Types].xml", ``); + resolve(zip); + }), + ); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + it("should patch the document", async () => { + const output = await patchDetector({ + data: Buffer.from(""), + }); + expect(output).toMatchObject(["school_name", "address"]); + }); + }); + }); }); diff --git a/src/patcher/replacer.spec.ts b/src/patcher/replacer.spec.ts index 903ef0bd2b..12fdb27dc7 100644 --- a/src/patcher/replacer.spec.ts +++ b/src/patcher/replacer.spec.ts @@ -200,5 +200,454 @@ describe("replacer", () => { expect(JSON.stringify(output)).to.contain("Lorem ipsum paragraph"); }); + + it("should replace", () => { + // cspell:disable + const output = replacer({ + json: { + elements: [ + { + type: "element", + name: "w:hdr", + elements: [ + { + type: "element", + name: "w:p", + elements: [ + { + type: "element", + name: "w:r", + elements: [ + { type: "text", text: "\n " }, + { + type: "element", + name: "w:rPr", + elements: [ + { type: "text", text: "\n " }, + { + type: "element", + name: "w:rFonts", + attributes: { "w:eastAsia": "Times New Roman" }, + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:kern", + attributes: { "w:val": "0" }, + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:sz", + attributes: { "w:val": "20" }, + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:lang", + attributes: { + "w:val": "en-US", + "w:eastAsia": "en-US", + "w:bidi": "ar-SA", + }, + }, + { type: "text", text: "\n " }, + ], + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:t", + elements: [{ type: "text", text: "{{" }], + }, + { type: "text", text: "\n " }, + ], + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:r", + elements: [ + { type: "text", text: "\n " }, + { + type: "element", + name: "w:rPr", + elements: [ + { type: "text", text: "\n " }, + { + type: "element", + name: "w:rFonts", + attributes: { "w:eastAsia": "Times New Roman" }, + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:kern", + attributes: { "w:val": "0" }, + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:sz", + attributes: { "w:val": "20" }, + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:lang", + attributes: { + "w:val": "en-US", + "w:eastAsia": "en-US", + "w:bidi": "ar-SA", + }, + }, + { type: "text", text: "\n " }, + ], + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:t", + elements: [{ type: "text", text: "s" }], + }, + { type: "text", text: "\n " }, + ], + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:r", + elements: [ + { type: "text", text: "\n " }, + { + type: "element", + name: "w:rPr", + elements: [ + { type: "text", text: "\n " }, + { + type: "element", + name: "w:rFonts", + attributes: { "w:eastAsia": "Times New Roman" }, + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:kern", + attributes: { "w:val": "0" }, + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:sz", + attributes: { "w:val": "20" }, + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:lang", + attributes: { + "w:val": "en-US", + "w:eastAsia": "en-US", + "w:bidi": "ar-SA", + }, + }, + { type: "text", text: "\n " }, + ], + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:t", + elements: [{ type: "text", text: "chool_" }], + }, + { type: "text", text: "\n " }, + ], + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:r", + elements: [ + { type: "text", text: "\n " }, + { + type: "element", + name: "w:rPr", + elements: [ + { type: "text", text: "\n " }, + { + type: "element", + name: "w:rFonts", + attributes: { "w:eastAsia": "Times New Roman" }, + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:kern", + attributes: { "w:val": "0" }, + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:sz", + attributes: { "w:val": "20" }, + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:lang", + attributes: { + "w:val": "en-US", + "w:eastAsia": "en-US", + "w:bidi": "ar-SA", + }, + }, + { type: "text", text: "\n " }, + ], + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:t", + elements: [{ type: "text", text: "n" }], + }, + { type: "text", text: "\n " }, + ], + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:r", + elements: [ + { type: "text", text: "\n " }, + { + type: "element", + name: "w:t", + elements: [{ type: "text", text: "{{" }], + }, + { type: "text", text: "\n " }, + ], + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:r", + elements: [ + { type: "text", text: "\n " }, + { + type: "element", + name: "w:rPr", + elements: [ + { type: "text", text: "\n " }, + { + type: "element", + name: "w:rFonts", + attributes: { "w:eastAsia": "Times New Roman" }, + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:kern", + attributes: { "w:val": "0" }, + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:sz", + attributes: { "w:val": "20" }, + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:lang", + attributes: { + "w:val": "en-US", + "w:eastAsia": "en-US", + "w:bidi": "ar-SA", + }, + }, + { type: "text", text: "\n " }, + ], + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:t", + elements: [{ type: "text", text: "a" }], + }, + { type: "text", text: "\n " }, + ], + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:r", + elements: [ + { type: "text", text: "\n " }, + { + type: "element", + name: "w:rPr", + elements: [ + { type: "text", text: "\n " }, + { + type: "element", + name: "w:rFonts", + attributes: { "w:eastAsia": "Times New Roman" }, + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:kern", + attributes: { "w:val": "0" }, + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:sz", + attributes: { "w:val": "20" }, + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:lang", + attributes: { + "w:val": "en-US", + "w:eastAsia": "en-US", + "w:bidi": "ar-SA", + }, + }, + { type: "text", text: "\n " }, + ], + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:t", + elements: [{ type: "text", text: "ddr" }], + }, + { type: "text", text: "\n " }, + ], + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:r", + elements: [ + { type: "text", text: "\n " }, + { + type: "element", + name: "w:rPr", + elements: [ + { type: "text", text: "\n " }, + { + type: "element", + name: "w:rFonts", + attributes: { "w:eastAsia": "Times New Roman" }, + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:kern", + attributes: { "w:val": "0" }, + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:sz", + attributes: { "w:val": "20" }, + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:lang", + attributes: { + "w:val": "en-US", + "w:eastAsia": "en-US", + "w:bidi": "ar-SA", + }, + }, + { type: "text", text: "\n " }, + ], + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:t", + elements: [{ type: "text", text: "ess" }], + }, + { type: "text", text: "\n " }, + ], + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:r", + elements: [ + { type: "text", text: "\n " }, + { + type: "element", + name: "w:rPr", + elements: [ + { type: "text", text: "\n " }, + { + type: "element", + name: "w:rFonts", + attributes: { "w:eastAsia": "Times New Roman" }, + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:kern", + attributes: { "w:val": "0" }, + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:sz", + attributes: { "w:val": "20" }, + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:lang", + attributes: { + "w:val": "en-US", + "w:eastAsia": "en-US", + "w:bidi": "ar-SA", + }, + }, + { type: "text", text: "\n " }, + ], + }, + { type: "text", text: "\n " }, + { + type: "element", + name: "w:t", + elements: [{ type: "text", text: "}}" }], + }, + ], + }, + ], + }, + ], + }, + ], + }, + // cspell:enable + patch: { + type: PatchType.PARAGRAPH, + children: [new Paragraph("Lorem ipsum paragraph")], + }, + patchText: "{{address}}", + context: { + file: {} as unknown as File, + viewWrapper: { + Relationships: {}, + } as unknown as IViewWrapper, + stack: [], + }, + }); + + expect(JSON.stringify(output)).to.contain("Lorem ipsum paragraph"); + }); }); }); diff --git a/src/patcher/replacer.ts b/src/patcher/replacer.ts index ab06945758..f9670c1fb0 100644 --- a/src/patcher/replacer.ts +++ b/src/patcher/replacer.ts @@ -67,7 +67,7 @@ export const replacer = ({ if (keepOriginalStyles) { const runElementNonTextualElements = runElementToBeReplaced.elements!.filter( - (e) => e.type === "element" && e.name !== "w:t", + (e) => e.type === "element" && e.name !== "w:t" && e.name !== "w:br", ); newRunElements = textJson.map((e) => ({