From ffd998cbf5fb67e6c4b1b7ce407afe3ccc86b2cb Mon Sep 17 00:00:00 2001 From: Dolan Date: Wed, 8 Feb 2023 03:18:11 +0000 Subject: [PATCH] Simple import and export of document --- demo/85-template-document.ts | 8 +++++++ demo/template.docx | Bin 0 -> 14233 bytes src/index.ts | 1 + src/templater/from-docx.ts | 42 +++++++++++++++++++++++++++++++++++ src/templater/index.ts | 1 + 5 files changed, 52 insertions(+) create mode 100644 demo/85-template-document.ts create mode 100644 demo/template.docx create mode 100644 src/templater/from-docx.ts create mode 100644 src/templater/index.ts diff --git a/demo/85-template-document.ts b/demo/85-template-document.ts new file mode 100644 index 0000000000..d219170491 --- /dev/null +++ b/demo/85-template-document.ts @@ -0,0 +1,8 @@ +// Simple template example +// Import from 'docx' rather than '../build' if you install from npm +import * as fs from "fs"; +import { fromDocx } from "../build"; + +fromDocx(fs.readFileSync("demo/template.docx")).then((doc) => { + fs.writeFileSync("My Document.docx", doc); +}); diff --git a/demo/template.docx b/demo/template.docx new file mode 100644 index 0000000000000000000000000000000000000000..fd05df5947551e4ec2f75838e257d2b49f7512c1 GIT binary patch literal 14233 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 literal 0 HcmV?d00001 diff --git a/src/index.ts b/src/index.ts index 3d76a0f70f..7162ae5a1f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,3 +5,4 @@ export * from "./file"; export * from "./export"; export * from "./import-dotx"; export * from "./util"; +export * from "./templater"; diff --git a/src/templater/from-docx.ts b/src/templater/from-docx.ts new file mode 100644 index 0000000000..cec1a84877 --- /dev/null +++ b/src/templater/from-docx.ts @@ -0,0 +1,42 @@ +import * as JSZip from "jszip"; +import { xml2js, ElementCompact, js2xml } from "xml-js"; + +// eslint-disable-next-line functional/prefer-readonly-type +type InputDataType = Buffer | string | number[] | Uint8Array | ArrayBuffer | Blob | NodeJS.ReadableStream; + +export const fromDocx = async (data: InputDataType): Promise => { + const zipContent = await JSZip.loadAsync(data); + + const map = new Map(); + + for (const [key, value] of Object.entries(zipContent.files)) { + const json = toJson(await value.async("text")); + map.set(key, json); + } + + const zip = new JSZip(); + + for (const [key, value] of map) { + const output = toXml(value); + + zip.file(key, output); + } + + const zipData = await zip.generateAsync({ + type: "nodebuffer", + mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + compression: "DEFLATE", + }); + + return zipData; +}; + +const toJson = (xmlData: string): ElementCompact => { + const xmlObj = xml2js(xmlData, { compact: false }) as ElementCompact; + return xmlObj; +}; + +const toXml = (jsonObj: ElementCompact): string => { + const output = js2xml(jsonObj); + return output; +}; diff --git a/src/templater/index.ts b/src/templater/index.ts new file mode 100644 index 0000000000..466cb3eda7 --- /dev/null +++ b/src/templater/index.ts @@ -0,0 +1 @@ +export * from "./from-docx";