fix(replacer): errors suppressed by catch statement (#2856)
This commit is contained in:
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
@ -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,
|
||||
@ -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",
|
||||
@ -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,
|
||||
@ -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: [
|
||||
{
|
||||
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -14,6 +14,11 @@ const formatter = new Formatter();
|
||||
|
||||
const SPLIT_TOKEN = "ɵ";
|
||||
|
||||
type IReplacerResult = {
|
||||
readonly element: Element;
|
||||
readonly didFindOccurrence: boolean;
|
||||
};
|
||||
|
||||
export const replacer = ({
|
||||
json,
|
||||
patch,
|
||||
@ -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) {
|
||||
@ -85,7 +90,7 @@ export const replacer = ({
|
||||
}
|
||||
}
|
||||
|
||||
return json;
|
||||
return { element: json, didFindOccurrence: true };
|
||||
};
|
||||
|
||||
const goToElementFromPath = (json: Element, path: readonly number[]): Element => {
|
||||
|
Reference in New Issue
Block a user