Skip to content

Commit

Permalink
fix(replacer): errors suppressed by catch statement (#2856)
Browse files Browse the repository at this point in the history
  • Loading branch information
SebKranz authored Nov 28, 2024
1 parent 3654eb0 commit 3997ce5
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 56 deletions.
59 changes: 29 additions & 30 deletions src/patcher/from-docx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,38 +132,37 @@ export const patchDocument = async <T extends PatchDocumentOutputType = PatchDoc
// We need to loop through to catch every occurrence of the patch text
// It is possible that the patch text is in the same run
// This algorithm is limited to one patch per text run
// Once it cannot find any more occurrences, it will throw an error, and then we break out of the loop
// We break out of the loop once it cannot find any more occurrences
// https://github.com/dolanmiu/docx/issues/2267
while (true) {
try {
replacer({
json,
patch: {
...patchValue,
children: patchValue.children.map((element) => {
// We need to replace external hyperlinks with concrete hyperlinks
if (element instanceof ExternalHyperlink) {
const concreteHyperlink = new ConcreteHyperlink(element.options.children, uniqueId());
// eslint-disable-next-line functional/immutable-data
hyperlinkRelationshipAdditions.push({
key,
hyperlink: {
id: concreteHyperlink.linkId,
link: element.options.link,
},
});
return concreteHyperlink;
} else {
return element;
}
}),
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} as any,
patchText,
context,
keepOriginalStyles,
});
} catch {
const { didFindOccurrence } = replacer({
json,
patch: {
...patchValue,
children: patchValue.children.map((element) => {
// We need to replace external hyperlinks with concrete hyperlinks
if (element instanceof ExternalHyperlink) {
const concreteHyperlink = new ConcreteHyperlink(element.options.children, uniqueId());
// eslint-disable-next-line functional/immutable-data
hyperlinkRelationshipAdditions.push({
key,
hyperlink: {
id: concreteHyperlink.linkId,
link: element.options.link,
},
});
return concreteHyperlink;
} else {
return element;
}
}),
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} as any,
patchText,
context,
keepOriginalStyles,
});
if (!didFindOccurrence) {
break;
}
}
Expand Down
49 changes: 26 additions & 23 deletions src/patcher/replacer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,24 +78,23 @@ export const MOCK_JSON = {
describe("replacer", () => {
describe("replacer", () => {
it("should throw an error if nothing is added", () => {
expect(() =>
replacer({
json: {
elements: [],
},
patch: {
type: PatchType.PARAGRAPH,
children: [],
},
patchText: "hello",
// eslint-disable-next-line functional/prefer-readonly-type
context: vi.fn<[], IContext>()(),
}),
).toThrow();
const { didFindOccurrence } = replacer({
json: {
elements: [],
},
patch: {
type: PatchType.PARAGRAPH,
children: [],
},
patchText: "hello",
// eslint-disable-next-line functional/prefer-readonly-type
context: vi.fn<[], IContext>()(),
});
expect(didFindOccurrence).toBe(false);
});

it("should replace paragraph type", () => {
const output = replacer({
const { element, didFindOccurrence } = replacer({
json: JSON.parse(JSON.stringify(MOCK_JSON)),
patch: {
type: PatchType.PARAGRAPH,
Expand All @@ -111,11 +110,12 @@ describe("replacer", () => {
},
});

expect(JSON.stringify(output)).to.contain("Delightful Header");
expect(JSON.stringify(element)).to.contain("Delightful Header");
expect(didFindOccurrence).toBe(true);
});

it("should replace paragraph type keeping original styling if keepOriginalStyles is true", () => {
const output = replacer({
const { element, didFindOccurrence } = replacer({
json: JSON.parse(JSON.stringify(MOCK_JSON)),
patch: {
type: PatchType.PARAGRAPH,
Expand All @@ -132,8 +132,8 @@ describe("replacer", () => {
keepOriginalStyles: true,
});

expect(JSON.stringify(output)).to.contain("sweet");
expect(output.elements![0].elements![1].elements).toMatchObject([
expect(JSON.stringify(element)).to.contain("sweet");
expect(element.elements![0].elements![1].elements).toMatchObject([
{
type: "element",
name: "w:r",
Expand Down Expand Up @@ -187,10 +187,11 @@ describe("replacer", () => {
],
},
]);
expect(didFindOccurrence).toBe(true);
});

it("should replace document type", () => {
const output = replacer({
const { element, didFindOccurrence } = replacer({
json: JSON.parse(JSON.stringify(MOCK_JSON)),
patch: {
type: PatchType.DOCUMENT,
Expand All @@ -206,12 +207,13 @@ describe("replacer", () => {
},
});

expect(JSON.stringify(output)).to.contain("Lorem ipsum paragraph");
expect(JSON.stringify(element)).to.contain("Lorem ipsum paragraph");
expect(didFindOccurrence).toBe(true);
});

it("should replace", () => {
// cspell:disable
const output = replacer({
const { element, didFindOccurrence } = replacer({
json: {
elements: [
{
Expand Down Expand Up @@ -655,7 +657,8 @@ describe("replacer", () => {
},
});

expect(JSON.stringify(output)).to.contain("Lorem ipsum paragraph");
expect(JSON.stringify(element)).to.contain("Lorem ipsum paragraph");
expect(didFindOccurrence).toBe(true);
});
});
});
11 changes: 8 additions & 3 deletions src/patcher/replacer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ const formatter = new Formatter();

const SPLIT_TOKEN = "ɵ";

type IReplacerResult = {
readonly element: Element;
readonly didFindOccurrence: boolean;
};

export const replacer = ({
json,
patch,
Expand All @@ -26,11 +31,11 @@ export const replacer = ({
readonly patchText: string;
readonly context: IContext;
readonly keepOriginalStyles?: boolean;
}): Element => {
}): IReplacerResult => {
const renderedParagraphs = findLocationOfText(json, patchText);

if (renderedParagraphs.length === 0) {
throw new Error(`Could not find text ${patchText}`);
return { element: json, didFindOccurrence: false };
}

for (const renderedParagraph of renderedParagraphs) {
Expand Down Expand Up @@ -85,7 +90,7 @@ export const replacer = ({
}
}

return json;
return { element: json, didFindOccurrence: true };
};

const goToElementFromPath = (json: Element, path: readonly number[]): Element => {
Expand Down

0 comments on commit 3997ce5

Please sign in to comment.