Work on replacer logic

This commit is contained in:
Dolan
2023-02-24 01:05:43 +00:00
parent a4d96bbf6e
commit f3dc1f0712
6 changed files with 91 additions and 15 deletions

View File

@ -9,6 +9,18 @@ patchDocument(fs.readFileSync("demo/assets/simple-template.docx"), {
children: [new TextRun("John Doe")], children: [new TextRun("John Doe")],
text: "{{ name }}", text: "{{ name }}",
}, },
{
children: [new TextRun("Heading wow!")],
text: "{{ table_heading_1 }}",
},
{
children: [new TextRun("#657")],
text: "{{ item_1 }}",
},
{
children: [new TextRun("Lorem ipsum paragraph")],
text: "{{ paragraph_replace }}",
},
], ],
}).then((doc) => { }).then((doc) => {
fs.writeFileSync("My Document.docx", doc); fs.writeFileSync("My Document.docx", doc);

View File

@ -0,0 +1,56 @@
import { Element } from "xml-js";
import { createTextElementContents } from "./util";
export const findRunElementIndexWithToken = (paragraphElement: Element, token: string): number => {
for (let i = 0; i < (paragraphElement.elements ?? []).length; i++) {
const element = paragraphElement.elements![i];
if (element.type === "element" && element.name === "w:r") {
const textElement = (element.elements ?? []).filter((e) => e.type === "element" && e.name === "w:t");
for (const text of textElement) {
if ((text.elements?.[0].text as string)?.includes(token)) {
return i;
}
}
}
}
// return -1;
throw new Error("Token not found");
};
export const splitRunElement = (runElement: Element, token: string): { readonly left: Element; readonly right: Element } => {
let splitIndex = 0;
const splitElements =
runElement.elements
?.map((e, i) => {
if (e.type === "element" && e.name === "w:t") {
const text = e.elements?.[0].text as string;
const splitText = text.split(token);
const newElements = splitText.map((t) => ({
...e,
attributes: {
"xml:space": "preserve",
},
elements: createTextElementContents(t),
}));
splitIndex = i;
return newElements;
} else {
return e;
}
})
.flat() ?? [];
const leftRunElement: Element = {
...JSON.parse(JSON.stringify(runElement)),
elements: splitElements.slice(0, splitIndex + 1),
};
const rightRunElement: Element = {
...JSON.parse(JSON.stringify(runElement)),
elements: splitElements.slice(splitIndex + 1),
};
return { left: leftRunElement, right: rightRunElement };
};

View File

@ -1,10 +1,6 @@
import { Element } from "xml-js"; import { Element } from "xml-js";
import * as xml from "xml";
import { Formatter } from "@export/formatter"; import { createTextElementContents } from "./util";
import { Text } from "@file/paragraph/run/run-components/text";
import { toJson } from "./util";
import { IRenderedParagraphNode } from "./run-renderer"; import { IRenderedParagraphNode } from "./run-renderer";
enum ReplaceMode { enum ReplaceMode {
@ -13,8 +9,6 @@ enum ReplaceMode {
END, END,
} }
const formatter = new Formatter();
export const replaceTokenInParagraphElement = ({ export const replaceTokenInParagraphElement = ({
paragraphElement, paragraphElement,
renderedParagraph, renderedParagraph,
@ -63,10 +57,8 @@ export const replaceTokenInParagraphElement = ({
}; };
const patchTextElement = (element: Element, text: string): Element => { const patchTextElement = (element: Element, text: string): Element => {
const textJson = toJson(xml(formatter.format(new Text({ text }))));
// eslint-disable-next-line functional/immutable-data // eslint-disable-next-line functional/immutable-data
element.elements = textJson.elements; element.elements = createTextElementContents(text);
return element; return element;
}; };

View File

@ -8,6 +8,7 @@ import { IPatch } from "./from-docx";
import { toJson } from "./util"; import { toJson } from "./util";
import { IRenderedParagraphNode } from "./run-renderer"; import { IRenderedParagraphNode } from "./run-renderer";
import { replaceTokenInParagraphElement } from "./paragraph-token-replacer"; import { replaceTokenInParagraphElement } from "./paragraph-token-replacer";
import { findRunElementIndexWithToken, splitRunElement } from "./paragraph-split-inject";
const formatter = new Formatter(); const formatter = new Formatter();
@ -18,7 +19,6 @@ export const replacer = (json: Element, options: IPatch, renderedParagraphs: rea
if (child instanceof Paragraph) { if (child instanceof Paragraph) {
console.log("is para"); console.log("is para");
} else if (child instanceof TextRun) { } else if (child instanceof TextRun) {
console.log("paragrapghs", JSON.stringify(renderedParagraphs, null, 2));
for (const renderedParagraph of renderedParagraphs) { for (const renderedParagraph of renderedParagraphs) {
const textJson = toJson(xml(formatter.format(child))); const textJson = toJson(xml(formatter.format(child)));
const paragraphElement = goToElementFromPath(json, renderedParagraph.path); const paragraphElement = goToElementFromPath(json, renderedParagraph.path);
@ -33,9 +33,6 @@ export const replacer = (json: Element, options: IPatch, renderedParagraphs: rea
} else { } else {
// Hard case where the text is only part of the paragraph // Hard case where the text is only part of the paragraph
console.log("hard case");
console.log("paragraphElement", JSON.stringify(paragraphElement, null, 2));
replaceTokenInParagraphElement({ replaceTokenInParagraphElement({
paragraphElement, paragraphElement,
renderedParagraph, renderedParagraph,
@ -43,6 +40,12 @@ export const replacer = (json: Element, options: IPatch, renderedParagraphs: rea
replacementText: SPLIT_TOKEN, replacementText: SPLIT_TOKEN,
}); });
const index = findRunElementIndexWithToken(paragraphElement, SPLIT_TOKEN);
const { left, right } = splitRunElement(paragraphElement.elements![index], SPLIT_TOKEN);
// eslint-disable-next-line functional/immutable-data
paragraphElement.elements!.splice(index, 1, left, ...textJson.elements!, right);
console.log(index, JSON.stringify(paragraphElement.elements![index], null, 2));
console.log("paragraphElement after", JSON.stringify(paragraphElement, null, 2)); console.log("paragraphElement after", JSON.stringify(paragraphElement, null, 2));
} }
} }

View File

@ -82,7 +82,7 @@ const renderRunNode = (node: Element, index: number, currentRunStringIndex: numb
const parts = node.elements const parts = node.elements
.map((element, i: number) => .map((element, i: number) =>
element.name === "w:t" && element.elements element.name === "w:t" && element.elements && element.elements.length > 0
? { ? {
text: element.elements[0].text?.toString() ?? "", text: element.elements[0].text?.toString() ?? "",
index: i, index: i,

View File

@ -1,6 +1,19 @@
import { xml2js, Element } from "xml-js"; import { xml2js, Element } from "xml-js";
import * as xml from "xml";
import { Formatter } from "@export/formatter";
import { Text } from "@file/paragraph/run/run-components/text";
const formatter = new Formatter();
export const toJson = (xmlData: string): Element => { export const toJson = (xmlData: string): Element => {
const xmlObj = xml2js(xmlData, { compact: false }) as Element; const xmlObj = xml2js(xmlData, { compact: false }) as Element;
return xmlObj; return xmlObj;
}; };
// eslint-disable-next-line functional/prefer-readonly-type
export const createTextElementContents = (text: string): Element[] => {
const textJson = toJson(xml(formatter.format(new Text({ text }))));
return textJson.elements![0].elements ?? [];
};