Add next gen compiler using JSZip

This commit is contained in:
Dolan
2018-04-24 21:12:09 +01:00
parent 8108eca2fa
commit c99b2940c6
4 changed files with 154 additions and 12 deletions

16
demo/demo13.js Normal file
View File

@ -0,0 +1,16 @@
const docx = require('../build');
var doc = new docx.Document();
var paragraph = new docx.Paragraph("Hello World");
var institutionText = new docx.TextRun("University College London").bold();
var dateText = new docx.TextRun("5th Dec 2015").tab().bold();
paragraph.addRun(institutionText);
paragraph.addRun(dateText);
doc.addParagraph(paragraph);
var exporter = new docx.LocalPacker(doc);
exporter.packPdf('My Document');
console.log('Document created successfully at project root!');

View File

@ -43,9 +43,11 @@
"@types/archiver": "^2.1.0", "@types/archiver": "^2.1.0",
"@types/express": "^4.0.35", "@types/express": "^4.0.35",
"@types/image-size": "0.0.29", "@types/image-size": "0.0.29",
"@types/jszip": "^3.1.3",
"@types/request-promise": "^4.1.41", "@types/request-promise": "^4.1.41",
"archiver": "^2.1.1", "archiver": "^2.1.1",
"image-size": "^0.6.2", "image-size": "^0.6.2",
"jszip": "^3.1.5",
"request": "^2.83.0", "request": "^2.83.0",
"request-promise": "^4.2.2", "request-promise": "^4.2.2",
"xml": "^1.0.1" "xml": "^1.0.1"

View File

@ -3,12 +3,11 @@ import * as os from "os";
import * as path from "path"; import * as path from "path";
import { File } from "../../file"; import { File } from "../../file";
import { Compiler } from "./compiler"; import { Compiler } from "./next-compiler";
import { IPacker } from "./packer"; import { IPacker } from "./packer";
import { PdfConvertWrapper } from "./pdf-convert-wrapper"; import { PdfConvertWrapper } from "./pdf-convert-wrapper";
export class LocalPacker implements IPacker { export class LocalPacker implements IPacker {
private stream: fs.WriteStream;
private readonly pdfConverter: PdfConvertWrapper; private readonly pdfConverter: PdfConvertWrapper;
private readonly packer: Compiler; private readonly packer: Compiler;
@ -20,8 +19,8 @@ export class LocalPacker implements IPacker {
public async pack(filePath: string): Promise<void> { public async pack(filePath: string): Promise<void> {
filePath = filePath.replace(/.docx$/, ""); filePath = filePath.replace(/.docx$/, "");
this.stream = fs.createWriteStream(`${filePath}.docx`); const zipData = await this.packer.compile().generateAsync({ type: "base64" }) as string;
await this.packer.compile(this.stream); await this.writeToFile(`${filePath}.docx`, zipData);
} }
public async packPdf(filePath: string): Promise<void> { public async packPdf(filePath: string): Promise<void> {
@ -29,19 +28,27 @@ export class LocalPacker implements IPacker {
const fileName = path.basename(filePath, path.extname(filePath)); const fileName = path.basename(filePath, path.extname(filePath));
const tempPath = path.join(os.tmpdir(), `${fileName}.docx`); const tempPath = path.join(os.tmpdir(), `${fileName}.docx`);
this.stream = fs.createWriteStream(tempPath);
await this.packer.compile(this.stream); const zipData = await this.packer.compile().generateAsync({ type: "base64" }) as string;
await this.writeToFile(tempPath, zipData);
const text = await this.pdfConverter.convert(tempPath); const text = await this.pdfConverter.convert(tempPath);
// const writeFile = util.promisify(fs.writeFile); --use this in future, in 3 years time. Only in node 8 // const writeFile = util.promisify(fs.writeFile); --use this in future, in 3 years time. Only in node 8
// return writeFile(`${filePath}.pdf`, text); // return writeFile(`${filePath}.pdf`, text);
return new Promise<void>((resolve, reject) => {
fs.writeFile(`${filePath}.pdf`, text, (err) => { await this.writeToFile(`${filePath}.pdf`, text);
if (err) { }
reject(err);
return; private writeToFile(filePath: string, data: string): Promise<void> {
} const file = fs.createWriteStream(filePath);
return new Promise((resolve, reject) => {
file.write(data, "base64");
file.end();
file.on("finish", () => {
resolve(); resolve();
}); });
file.on("error", reject);
}); });
} }
} }

View File

@ -0,0 +1,117 @@
import * as JSZip from "jszip";
import * as xml from "xml";
import { File } from "file";
import { Formatter } from "../formatter";
interface IXmlifyedFile {
data: string;
path: string;
}
interface IXmlifyedFileMapping {
Document: IXmlifyedFile;
Styles: IXmlifyedFile;
Properties: IXmlifyedFile;
Numbering: IXmlifyedFile;
Relationships: IXmlifyedFile;
FileRelationships: IXmlifyedFile;
Header: IXmlifyedFile;
Footer: IXmlifyedFile;
HeaderRelationships: IXmlifyedFile;
FooterRelationships: IXmlifyedFile;
ContentTypes: IXmlifyedFile;
AppProperties: IXmlifyedFile;
}
export class Compiler {
private formatter: Formatter;
constructor(private file: File) {
this.formatter = new Formatter();
}
public compile(): JSZip {
const zip = new JSZip();
const xmlifiedFileMapping = this.xmlifyFile(this.file);
for (const key in xmlifiedFileMapping) {
if (!xmlifiedFileMapping[key]) {
continue;
}
const xmlifiedFile = xmlifiedFileMapping[key];
zip.file(xmlifiedFile.path, xmlifiedFile.data);
}
// for (const data of file.Media.array) {
// this.archive.append(data.stream, {
// name: `word/media/${data.fileName}`,
// });
// zip.file(`word/media/${data.fileName}`, )
// }
return zip;
}
private xmlifyFile(file: File): IXmlifyedFileMapping {
return {
Document: {
data: xml(this.formatter.format(file.Document), true),
path: "word/document.xml",
},
Styles: {
data: xml(this.formatter.format(file.Styles)),
path: "word/styles.xml",
},
Properties: {
data: xml(this.formatter.format(file.CoreProperties), {
declaration: {
standalone: "yes",
encoding: "UTF-8",
},
}),
path: "docProps/core.xml",
},
Numbering: {
data: xml(this.formatter.format(file.Numbering)),
path: "word/numbering.xml",
},
Relationships: {
data: xml(this.formatter.format(file.DocumentRelationships)),
path: "word/_rels/document.xml.rels",
},
FileRelationships: {
data: xml(this.formatter.format(file.FileRelationships)),
path: "_rels/.rels",
},
Header: {
data: xml(this.formatter.format(file.Header.Header)),
path: "word/header1.xml",
},
Footer: {
data: xml(this.formatter.format(file.Footer.Footer)),
path: "word/footer1.xml",
},
HeaderRelationships: {
data: xml(this.formatter.format(file.Header.Relationships)),
path: "word/_rels/header1.xml.rels",
},
FooterRelationships: {
data: xml(this.formatter.format(file.Footer.Relationships)),
path: "word/_rels/footer1.xml.rels",
},
ContentTypes: {
data: xml(this.formatter.format(file.ContentTypes)),
path: "[Content_Types].xml",
},
AppProperties: {
data: xml(this.formatter.format(file.AppProperties)),
path: "docProps/app.xml",
},
};
}
}