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
|
// 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
|
// It is possible that the patch text is in the same run
|
||||||
// This algorithm is limited to one patch per text 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
|
// https://github.com/dolanmiu/docx/issues/2267
|
||||||
while (true) {
|
while (true) {
|
||||||
try {
|
const { didFindOccurrence } = replacer({
|
||||||
replacer({
|
json,
|
||||||
json,
|
patch: {
|
||||||
patch: {
|
...patchValue,
|
||||||
...patchValue,
|
children: patchValue.children.map((element) => {
|
||||||
children: patchValue.children.map((element) => {
|
// We need to replace external hyperlinks with concrete hyperlinks
|
||||||
// We need to replace external hyperlinks with concrete hyperlinks
|
if (element instanceof ExternalHyperlink) {
|
||||||
if (element instanceof ExternalHyperlink) {
|
const concreteHyperlink = new ConcreteHyperlink(element.options.children, uniqueId());
|
||||||
const concreteHyperlink = new ConcreteHyperlink(element.options.children, uniqueId());
|
// eslint-disable-next-line functional/immutable-data
|
||||||
// eslint-disable-next-line functional/immutable-data
|
hyperlinkRelationshipAdditions.push({
|
||||||
hyperlinkRelationshipAdditions.push({
|
key,
|
||||||
key,
|
hyperlink: {
|
||||||
hyperlink: {
|
id: concreteHyperlink.linkId,
|
||||||
id: concreteHyperlink.linkId,
|
link: element.options.link,
|
||||||
link: element.options.link,
|
},
|
||||||
},
|
});
|
||||||
});
|
return concreteHyperlink;
|
||||||
return concreteHyperlink;
|
} else {
|
||||||
} else {
|
return element;
|
||||||
return element;
|
}
|
||||||
}
|
}),
|
||||||
}),
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
} as any,
|
||||||
} as any,
|
patchText,
|
||||||
patchText,
|
context,
|
||||||
context,
|
keepOriginalStyles,
|
||||||
keepOriginalStyles,
|
});
|
||||||
});
|
if (!didFindOccurrence) {
|
||||||
} catch {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,24 +78,23 @@ export const MOCK_JSON = {
|
|||||||
describe("replacer", () => {
|
describe("replacer", () => {
|
||||||
describe("replacer", () => {
|
describe("replacer", () => {
|
||||||
it("should throw an error if nothing is added", () => {
|
it("should throw an error if nothing is added", () => {
|
||||||
expect(() =>
|
const { didFindOccurrence } = replacer({
|
||||||
replacer({
|
json: {
|
||||||
json: {
|
elements: [],
|
||||||
elements: [],
|
},
|
||||||
},
|
patch: {
|
||||||
patch: {
|
type: PatchType.PARAGRAPH,
|
||||||
type: PatchType.PARAGRAPH,
|
children: [],
|
||||||
children: [],
|
},
|
||||||
},
|
patchText: "hello",
|
||||||
patchText: "hello",
|
// eslint-disable-next-line functional/prefer-readonly-type
|
||||||
// eslint-disable-next-line functional/prefer-readonly-type
|
context: vi.fn<[], IContext>()(),
|
||||||
context: vi.fn<[], IContext>()(),
|
});
|
||||||
}),
|
expect(didFindOccurrence).toBe(false);
|
||||||
).toThrow();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should replace paragraph type", () => {
|
it("should replace paragraph type", () => {
|
||||||
const output = replacer({
|
const { element, didFindOccurrence } = replacer({
|
||||||
json: JSON.parse(JSON.stringify(MOCK_JSON)),
|
json: JSON.parse(JSON.stringify(MOCK_JSON)),
|
||||||
patch: {
|
patch: {
|
||||||
type: PatchType.PARAGRAPH,
|
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", () => {
|
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)),
|
json: JSON.parse(JSON.stringify(MOCK_JSON)),
|
||||||
patch: {
|
patch: {
|
||||||
type: PatchType.PARAGRAPH,
|
type: PatchType.PARAGRAPH,
|
||||||
@ -132,8 +132,8 @@ describe("replacer", () => {
|
|||||||
keepOriginalStyles: true,
|
keepOriginalStyles: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(JSON.stringify(output)).to.contain("sweet");
|
expect(JSON.stringify(element)).to.contain("sweet");
|
||||||
expect(output.elements![0].elements![1].elements).toMatchObject([
|
expect(element.elements![0].elements![1].elements).toMatchObject([
|
||||||
{
|
{
|
||||||
type: "element",
|
type: "element",
|
||||||
name: "w:r",
|
name: "w:r",
|
||||||
@ -187,10 +187,11 @@ describe("replacer", () => {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
expect(didFindOccurrence).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should replace document type", () => {
|
it("should replace document type", () => {
|
||||||
const output = replacer({
|
const { element, didFindOccurrence } = replacer({
|
||||||
json: JSON.parse(JSON.stringify(MOCK_JSON)),
|
json: JSON.parse(JSON.stringify(MOCK_JSON)),
|
||||||
patch: {
|
patch: {
|
||||||
type: PatchType.DOCUMENT,
|
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", () => {
|
it("should replace", () => {
|
||||||
// cspell:disable
|
// cspell:disable
|
||||||
const output = replacer({
|
const { element, didFindOccurrence } = replacer({
|
||||||
json: {
|
json: {
|
||||||
elements: [
|
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 = "ɵ";
|
const SPLIT_TOKEN = "ɵ";
|
||||||
|
|
||||||
|
type IReplacerResult = {
|
||||||
|
readonly element: Element;
|
||||||
|
readonly didFindOccurrence: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export const replacer = ({
|
export const replacer = ({
|
||||||
json,
|
json,
|
||||||
patch,
|
patch,
|
||||||
@ -26,11 +31,11 @@ export const replacer = ({
|
|||||||
readonly patchText: string;
|
readonly patchText: string;
|
||||||
readonly context: IContext;
|
readonly context: IContext;
|
||||||
readonly keepOriginalStyles?: boolean;
|
readonly keepOriginalStyles?: boolean;
|
||||||
}): Element => {
|
}): IReplacerResult => {
|
||||||
const renderedParagraphs = findLocationOfText(json, patchText);
|
const renderedParagraphs = findLocationOfText(json, patchText);
|
||||||
|
|
||||||
if (renderedParagraphs.length === 0) {
|
if (renderedParagraphs.length === 0) {
|
||||||
throw new Error(`Could not find text ${patchText}`);
|
return { element: json, didFindOccurrence: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const renderedParagraph of renderedParagraphs) {
|
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 => {
|
const goToElementFromPath = (json: Element, path: readonly number[]): Element => {
|
||||||
|
Reference in New Issue
Block a user