Skip to content

Commit

Permalink
fix: Missing text property for patchDocument (#2760)
Browse files Browse the repository at this point in the history
* fix: Missing text property

Ignore <br /> for patched files

* Fix spelling issues
  • Loading branch information
dolanmiu authored Oct 13, 2024
1 parent 0cadec7 commit 2d2e4cd
Show file tree
Hide file tree
Showing 7 changed files with 751 additions and 2 deletions.
72 changes: 72 additions & 0 deletions demo/93-template-document.ts
Original file line number Diff line number Diff line change
@@ -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);
});
Binary file added demo/assets/field-trip.docx
Binary file not shown.
60 changes: 60 additions & 0 deletions src/patcher/paragraph-split-inject.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,5 +273,65 @@ describe("paragraph-split-inject", () => {
},
});
});

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" } }],
},
});
});
});
});
2 changes: 1 addition & 1 deletion src/patcher/paragraph-split-inject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
168 changes: 168 additions & 0 deletions src/patcher/patch-detector.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,147 @@ const MOCK_XML = `
</w:document>
`;

// cspell:disable
const MOCK_XML_2 = `
<w:body>
<w:tbl>
<w:tblPr>
<w:tblStyle w:val="TableGrid" />
<w:tblW w:w="9350" w:type="dxa" />
<w:jc w:val="left" />
<w:tblInd w:w="0" w:type="dxa" />
<w:tblLayout w:type="fixed" />
<w:tblCellMar>
<w:top w:w="0" w:type="dxa" />
<w:left w:w="108" w:type="dxa" />
<w:bottom w:w="0" w:type="dxa" />
<w:right w:w="108" w:type="dxa" />
</w:tblCellMar>
<w:tblLook w:firstRow="1" w:noVBand="1" w:lastRow="0" w:firstColumn="1"
w:lastColumn="0" w:noHBand="0" w:val="04a0" />
</w:tblPr>
<w:tblGrid>
<w:gridCol w:w="3119" />
<w:gridCol w:w="3141" />
<w:gridCol w:w="3090" />
</w:tblGrid>
<w:tr>
<w:trPr></w:trPr>
<w:tc>
<w:tcPr>
<w:tcW w:w="3119" w:type="dxa" />
<w:tcBorders>
<w:right w:val="nil" />
</w:tcBorders>
<w:shd w:color="auto" w:fill="D9D9D9" w:themeFill="background1"
w:themeFillShade="d9" w:val="clear" />
</w:tcPr>
<w:p>
<w:pPr>
<w:pStyle w:val="NormalSpaceAboveandBelow" />
<w:widowControl />
<w:spacing w:before="120" w:after="120" />
<w:jc w:val="left" />
<w:rPr>
<w:rFonts w:eastAsia="Times New Roman" />
<w:kern w:val="0" />
<w:sz w:val="20" />
<w:lang w:val="en-US" w:eastAsia="en-US" w:bidi="ar-SA" />
</w:rPr>
</w:pPr>
<w:r>
<w:rPr>
<w:rFonts w:eastAsia="Times New Roman" />
<w:kern w:val="0" />
<w:sz w:val="20" />
<w:lang w:val="en-US" w:eastAsia="en-US" w:bidi="ar-SA" />
</w:rPr>
<w:t>{{</w:t>
</w:r>
<w:r>
<w:rPr>
<w:rFonts w:eastAsia="Times New Roman" />
<w:kern w:val="0" />
<w:sz w:val="20" />
<w:lang w:val="en-US" w:eastAsia="en-US" w:bidi="ar-SA" />
</w:rPr>
<w:t>s</w:t>
</w:r>
<w:r>
<w:rPr>
<w:rFonts w:eastAsia="Times New Roman" />
<w:kern w:val="0" />
<w:sz w:val="20" />
<w:lang w:val="en-US" w:eastAsia="en-US" w:bidi="ar-SA" />
</w:rPr>
<w:t>chool_</w:t>
</w:r>
<w:r>
<w:rPr>
<w:rFonts w:eastAsia="Times New Roman" />
<w:kern w:val="0" />
<w:sz w:val="20" />
<w:lang w:val="en-US" w:eastAsia="en-US" w:bidi="ar-SA" />
</w:rPr>
<w:t>n</w:t>
</w:r>
<w:r>
<w:rPr>
<w:rFonts w:eastAsia="Times New Roman" />
<w:kern w:val="0" />
<w:sz w:val="20" />
<w:lang w:val="en-US" w:eastAsia="en-US" w:bidi="ar-SA" />
</w:rPr>
<w:t>ame}}</w:t>
<w:br />
<w:t>{{</w:t>
</w:r>
<w:r>
<w:rPr>
<w:rFonts w:eastAsia="Times New Roman" />
<w:kern w:val="0" />
<w:sz w:val="20" />
<w:lang w:val="en-US" w:eastAsia="en-US" w:bidi="ar-SA" />
</w:rPr>
<w:t>a</w:t>
</w:r>
<w:r>
<w:rPr>
<w:rFonts w:eastAsia="Times New Roman" />
<w:kern w:val="0" />
<w:sz w:val="20" />
<w:lang w:val="en-US" w:eastAsia="en-US" w:bidi="ar-SA" />
</w:rPr>
<w:t>ddr</w:t>
</w:r>
<w:r>
<w:rPr>
<w:rFonts w:eastAsia="Times New Roman" />
<w:kern w:val="0" />
<w:sz w:val="20" />
<w:lang w:val="en-US" w:eastAsia="en-US" w:bidi="ar-SA" />
</w:rPr>
<w:t>ess</w:t>
</w:r>
<w:r>
<w:rPr>
<w:rFonts w:eastAsia="Times New Roman" />
<w:kern w:val="0" />
<w:sz w:val="20" />
<w:lang w:val="en-US" w:eastAsia="en-US" w:bidi="ar-SA" />
</w:rPr>
<w:t>}}</w:t>
<w:br />
<w:t>{{</w:t>
</w:r>
</w:p>
</w:tc>
</w:tr>
</w:tbl>
</w:body>
`;
// cspell:enable

describe("patch-detector", () => {
describe("patchDetector", () => {
describe("document.xml and [Content_Types].xml", () => {
Expand Down Expand Up @@ -222,4 +363,31 @@ describe("patch-detector", () => {
});
});
});

describe("patchDetector", () => {
describe("document.xml and [Content_Types].xml", () => {
beforeEach(() => {
vi.spyOn(JSZip, "loadAsync").mockReturnValue(
new Promise<JSZip>((resolve) => {
const zip = new JSZip();

zip.file("word/document.xml", MOCK_XML_2);
zip.file("[Content_Types].xml", `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>`);
resolve(zip);
}),
);
});

afterEach(() => {
vi.restoreAllMocks();
});

it("should patch the document", async () => {
const output = await patchDetector({
data: Buffer.from(""),
});
expect(output).toMatchObject(["school_name", "address"]);
});
});
});
});
Loading

0 comments on commit 2d2e4cd

Please sign in to comment.