Skip to content

Commit

Permalink
#2028 Fix patcher offset indexes
Browse files Browse the repository at this point in the history
  • Loading branch information
dolanmiu committed Mar 23, 2023
1 parent 5280084 commit 16bfc78
Show file tree
Hide file tree
Showing 5 changed files with 173 additions and 2 deletions.
15 changes: 15 additions & 0 deletions demo/87-template-document.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Patch a document with patches
// Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs";
import { patchDocument, PatchType, TextRun } from "../build";

patchDocument(fs.readFileSync("demo/assets/simple-template-2.docx"), {
patches: {
name: {
type: PatchType.PARAGRAPH,
children: [new TextRun("Max")],
},
},
}).then((doc) => {
fs.writeFileSync("My Document.docx", doc);
});
Binary file added demo/assets/simple-template-2.docx
Binary file not shown.
150 changes: 150 additions & 0 deletions src/patcher/paragraph-token-replacer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,156 @@ describe("paragraph-token-replacer", () => {
});
});

it("should handle case where it cannot find any text to replace", () => {
const output = replaceTokenInParagraphElement({
paragraphElement: {
name: "w:p",
attributes: {
"w14:paraId": "2499FE9F",
"w14:textId": "27B4FBC2",
"w:rsidR": "00B51233",
"w:rsidRDefault": "007B52ED",
"w:rsidP": "007B52ED",
},
elements: [
{
type: "element",
name: "w:pPr",
elements: [{ type: "element", name: "w:pStyle", attributes: { "w:val": "Title" } }],
},
{
type: "element",
name: "w:r",
elements: [
{
type: "element",
name: "w:t",
attributes: { "xml:space": "preserve" },
elements: [{ type: "text", text: "Hello " }],
},
],
},
{
type: "element",
name: "w:r",
attributes: { "w:rsidR": "007F116B" },
elements: [
{
type: "element",
name: "w:t",
attributes: { "xml:space": "preserve" },
elements: [{ type: "text", text: "{{name}} " }],
},
],
},
{
type: "element",
name: "w:r",
elements: [{ type: "element", name: "w:t", elements: [{ type: "text", text: "World" }] }],
},
],
},
renderedParagraph: {
text: "Hello {{name}} World",
runs: [
{ text: "Hello ", parts: [{ text: "Hello ", index: 0, start: 0, end: 5 }], index: 1, start: 0, end: 5 },
{ text: "{{name}} ", parts: [{ text: "{{name}} ", index: 0, start: 6, end: 14 }], index: 2, start: 6, end: 14 },
{ text: "World", parts: [{ text: "World", index: 0, start: 15, end: 19 }], index: 3, start: 15, end: 19 },
],
index: 0,
path: [0, 1, 0, 0],
},
originalText: "{{name}}",
replacementText: "John",
});

expect(output).to.deep.equal({
attributes: {
"w14:paraId": "2499FE9F",
"w14:textId": "27B4FBC2",
"w:rsidP": "007B52ED",
"w:rsidR": "00B51233",
"w:rsidRDefault": "007B52ED",
},
elements: [
{
elements: [
{
attributes: {
"w:val": "Title",
},
name: "w:pStyle",
type: "element",
},
],
name: "w:pPr",
type: "element",
},
{
elements: [
{
attributes: {
"xml:space": "preserve",
},
elements: [
{
text: "Hello ",
type: "text",
},
],
name: "w:t",
type: "element",
},
],
name: "w:r",
type: "element",
},
{
attributes: {
"w:rsidR": "007F116B",
},
elements: [
{
attributes: {
"xml:space": "preserve",
},
elements: [
{
text: "John ",
type: "text",
},
],
name: "w:t",
type: "element",
},
],
name: "w:r",
type: "element",
},
{
elements: [
{
attributes: {
"xml:space": "preserve",
},
elements: [
{
text: "World",
type: "text",
},
],
name: "w:t",
type: "element",
},
],
name: "w:r",
type: "element",
},
],
name: "w:p",
});
});

// Try to fill rest of test coverage
// it("should replace token in paragraph", () => {
// const output = replaceTokenInParagraphElement({
Expand Down
8 changes: 7 additions & 1 deletion src/patcher/paragraph-token-replacer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,15 @@ export const replaceTokenInParagraphElement = ({
switch (replaceMode) {
case ReplaceMode.START:
if (startIndex >= start) {
const partToReplace = run.text.substring(Math.max(startIndex, start), Math.min(endIndex, end) + 1);
const offsetStartIndex = startIndex - start;
const offsetEndIndex = Math.min(endIndex, end) - start;
const partToReplace = run.text.substring(offsetStartIndex, offsetEndIndex + 1);
// We use a token to split the text if the replacement is within the same run
// If not, we just add text to the middle of the run later
if (partToReplace === "") {
continue;
}

const firstPart = text.replace(partToReplace, replacementText);
patchTextElement(paragraphElement.elements![run.index].elements![index], firstPart);
replaceMode = ReplaceMode.MIDDLE;
Expand Down
2 changes: 1 addition & 1 deletion src/patcher/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Text } from "@file/paragraph/run/run-components/text";
const formatter = new Formatter();

export const toJson = (xmlData: string): Element => {
const xmlObj = xml2js(xmlData, { compact: false }) as Element;
const xmlObj = xml2js(xmlData, { compact: false, captureSpacesBetweenElements: true }) as Element;
return xmlObj;
};

Expand Down

0 comments on commit 16bfc78

Please sign in to comment.