Files
docx-js/src/export/packer/next-compiler.ts

410 lines
15 KiB
TypeScript
Raw Normal View History

2018-04-24 21:12:09 +01:00
import * as JSZip from "jszip";
import * as xml from "xml";
import { File } from "file";
import { Formatter } from "../formatter";
2018-12-24 16:50:53 +00:00
import { ImageReplacer } from "./image-replacer";
2019-11-08 03:11:19 +00:00
import { NumberingReplacer } from "./numbering-replacer";
2018-04-24 21:12:09 +01:00
interface IXmlifyedFile {
readonly data: string;
readonly path: string;
2018-04-24 21:12:09 +01:00
}
interface IXmlifyedFileMapping {
readonly Document: IXmlifyedFile;
readonly Styles: IXmlifyedFile;
readonly Properties: IXmlifyedFile;
readonly Numbering: IXmlifyedFile;
readonly Relationships: IXmlifyedFile;
readonly FileRelationships: IXmlifyedFile;
readonly Headers: IXmlifyedFile[];
readonly Footers: IXmlifyedFile[];
readonly HeaderRelationships: IXmlifyedFile[];
readonly FooterRelationships: IXmlifyedFile[];
readonly ContentTypes: IXmlifyedFile;
readonly CustomProperties: IXmlifyedFile;
readonly AppProperties: IXmlifyedFile;
readonly FootNotes: IXmlifyedFile;
2021-03-01 23:35:52 +00:00
readonly FootNotesRelationships: IXmlifyedFile;
readonly Settings: IXmlifyedFile;
2018-04-24 21:12:09 +01:00
}
export class Compiler {
private readonly formatter: Formatter;
2018-12-24 16:50:53 +00:00
private readonly imageReplacer: ImageReplacer;
2019-11-08 03:11:19 +00:00
private readonly numberingReplacer: NumberingReplacer;
2018-04-24 21:12:09 +01:00
2019-08-07 22:12:14 +01:00
constructor() {
2018-04-24 21:12:09 +01:00
this.formatter = new Formatter();
2018-12-24 16:50:53 +00:00
this.imageReplacer = new ImageReplacer();
2019-11-08 03:11:19 +00:00
this.numberingReplacer = new NumberingReplacer();
2018-04-24 21:12:09 +01:00
}
2019-08-07 22:12:14 +01:00
public compile(file: File, prettifyXml?: boolean): JSZip {
2018-04-24 21:12:09 +01:00
const zip = new JSZip();
2019-08-07 22:12:14 +01:00
const xmlifiedFileMapping = this.xmlifyFile(file, prettifyXml);
2018-04-24 21:12:09 +01:00
for (const key in xmlifiedFileMapping) {
if (!xmlifiedFileMapping[key]) {
continue;
}
const obj = xmlifiedFileMapping[key] as IXmlifyedFile | IXmlifyedFile[];
2018-04-24 21:12:09 +01:00
if (Array.isArray(obj)) {
for (const subFile of obj) {
zip.file(subFile.path, subFile.data);
}
} else {
zip.file(obj.path, obj.data);
}
2018-04-24 21:12:09 +01:00
}
for (const data of file.Media.Array) {
const mediaData = data.stream;
2018-04-24 22:35:31 +01:00
zip.file(`word/media/${data.fileName}`, mediaData);
}
2018-09-06 08:30:23 +01:00
2018-04-24 21:12:09 +01:00
return zip;
}
2019-08-07 22:12:14 +01:00
private xmlifyFile(file: File, prettify?: boolean): IXmlifyedFileMapping {
const documentRelationshipCount = file.Document.Relationships.RelationshipCount + 1;
2018-12-24 16:50:53 +00:00
2021-03-11 01:06:55 +00:00
const documentXmlData = xml(
this.formatter.format(file.Document.View, {
viewWrapper: file.Document,
file,
}),
{
indent: prettify,
declaration: {
standalone: "yes",
encoding: "UTF-8",
},
},
2021-03-11 01:06:55 +00:00
);
const documentMediaDatas = this.imageReplacer.getMediaData(documentXmlData, file.Media);
2018-04-24 21:12:09 +01:00
return {
2018-12-24 16:50:53 +00:00
Relationships: {
data: (() => {
documentMediaDatas.forEach((mediaData, i) => {
file.Document.Relationships.createRelationship(
2018-12-24 16:50:53 +00:00
documentRelationshipCount + i,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
`media/${mediaData.fileName}`,
);
});
2021-03-11 01:06:55 +00:00
return xml(
this.formatter.format(file.Document.Relationships, {
viewWrapper: file.Document,
file,
}),
{
indent: prettify,
declaration: {
encoding: "UTF-8",
},
},
2021-03-11 01:06:55 +00:00
);
2018-12-24 16:50:53 +00:00
})(),
path: "word/_rels/document.xml.rels",
},
2018-04-24 21:12:09 +01:00
Document: {
2018-12-24 16:50:53 +00:00
data: (() => {
const xmlData = this.imageReplacer.replace(documentXmlData, documentMediaDatas, documentRelationshipCount);
2019-11-08 03:11:19 +00:00
const referenedXmlData = this.numberingReplacer.replace(xmlData, file.Numbering.ConcreteNumbering);
2018-12-24 16:50:53 +00:00
2019-11-08 03:11:19 +00:00
return referenedXmlData;
2018-12-24 16:50:53 +00:00
})(),
2018-04-24 21:12:09 +01:00
path: "word/document.xml",
},
Styles: {
data: (() => {
const xmlStyles = xml(
this.formatter.format(file.Styles, {
viewWrapper: file.Document,
file,
}),
{
indent: prettify,
declaration: {
standalone: "yes",
encoding: "UTF-8",
},
},
);
const referencedXmlStyles = this.numberingReplacer.replace(xmlStyles, file.Numbering.ConcreteNumbering);
return referencedXmlStyles;
})(),
2018-04-24 21:12:09 +01:00
path: "word/styles.xml",
},
Properties: {
2021-03-11 01:06:55 +00:00
data: xml(
this.formatter.format(file.CoreProperties, {
viewWrapper: file.Document,
file,
}),
{
indent: prettify,
2021-03-11 01:06:55 +00:00
declaration: {
standalone: "yes",
encoding: "UTF-8",
},
2018-04-24 21:12:09 +01:00
},
2021-03-11 01:06:55 +00:00
),
2018-04-24 21:12:09 +01:00
path: "docProps/core.xml",
},
Numbering: {
2021-03-11 01:06:55 +00:00
data: xml(
this.formatter.format(file.Numbering, {
viewWrapper: file.Document,
file,
}),
{
indent: prettify,
declaration: {
standalone: "yes",
encoding: "UTF-8",
},
},
2021-03-11 01:06:55 +00:00
),
2018-04-24 21:12:09 +01:00
path: "word/numbering.xml",
},
FileRelationships: {
2021-03-11 01:06:55 +00:00
data: xml(
this.formatter.format(file.FileRelationships, {
viewWrapper: file.Document,
file,
}),
{
indent: prettify,
declaration: {
encoding: "UTF-8",
},
},
2021-03-11 01:06:55 +00:00
),
2018-04-24 21:12:09 +01:00
path: "_rels/.rels",
},
2018-12-24 16:50:53 +00:00
HeaderRelationships: file.Headers.map((headerWrapper, index) => {
2021-03-11 01:06:55 +00:00
const xmlData = xml(
this.formatter.format(headerWrapper.View, {
viewWrapper: headerWrapper,
file,
}),
{
indent: prettify,
declaration: {
encoding: "UTF-8",
},
},
2021-03-11 01:06:55 +00:00
);
2018-12-24 16:50:53 +00:00
const mediaDatas = this.imageReplacer.getMediaData(xmlData, file.Media);
mediaDatas.forEach((mediaData, i) => {
headerWrapper.Relationships.createRelationship(
i,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
`media/${mediaData.fileName}`,
);
});
return {
2021-03-11 01:06:55 +00:00
data: xml(
this.formatter.format(headerWrapper.Relationships, {
viewWrapper: headerWrapper,
file,
}),
{
indent: prettify,
declaration: {
encoding: "UTF-8",
},
},
2021-03-11 01:06:55 +00:00
),
2018-12-24 16:50:53 +00:00
path: `word/_rels/header${index + 1}.xml.rels`,
};
}),
FooterRelationships: file.Footers.map((footerWrapper, index) => {
2021-03-11 01:06:55 +00:00
const xmlData = xml(
this.formatter.format(footerWrapper.View, {
viewWrapper: footerWrapper,
file,
}),
{
indent: prettify,
declaration: {
encoding: "UTF-8",
},
},
2021-03-11 01:06:55 +00:00
);
2018-12-24 16:50:53 +00:00
const mediaDatas = this.imageReplacer.getMediaData(xmlData, file.Media);
mediaDatas.forEach((mediaData, i) => {
footerWrapper.Relationships.createRelationship(
i,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
`media/${mediaData.fileName}`,
);
});
return {
2021-03-11 01:06:55 +00:00
data: xml(
this.formatter.format(footerWrapper.Relationships, {
viewWrapper: footerWrapper,
file,
}),
{
indent: prettify,
declaration: {
encoding: "UTF-8",
},
},
2021-03-11 01:06:55 +00:00
),
2018-12-24 16:50:53 +00:00
path: `word/_rels/footer${index + 1}.xml.rels`,
};
}),
Headers: file.Headers.map((headerWrapper, index) => {
2021-03-11 01:06:55 +00:00
const tempXmlData = xml(
this.formatter.format(headerWrapper.View, {
viewWrapper: headerWrapper,
file,
}),
{
indent: prettify,
declaration: {
encoding: "UTF-8",
},
},
2021-03-11 01:06:55 +00:00
);
2018-12-24 16:50:53 +00:00
const mediaDatas = this.imageReplacer.getMediaData(tempXmlData, file.Media);
// TODO: 0 needs to be changed when headers get relationships of their own
const xmlData = this.imageReplacer.replace(tempXmlData, mediaDatas, 0);
return {
data: xmlData,
path: `word/header${index + 1}.xml`,
};
}),
Footers: file.Footers.map((footerWrapper, index) => {
2021-03-11 01:06:55 +00:00
const tempXmlData = xml(
this.formatter.format(footerWrapper.View, {
viewWrapper: footerWrapper,
file,
}),
{
indent: prettify,
declaration: {
encoding: "UTF-8",
},
},
2021-03-11 01:06:55 +00:00
);
2018-12-24 16:50:53 +00:00
const mediaDatas = this.imageReplacer.getMediaData(tempXmlData, file.Media);
// TODO: 0 needs to be changed when headers get relationships of their own
const xmlData = this.imageReplacer.replace(tempXmlData, mediaDatas, 0);
return {
data: xmlData,
path: `word/footer${index + 1}.xml`,
};
}),
2018-04-24 21:12:09 +01:00
ContentTypes: {
2021-03-11 01:06:55 +00:00
data: xml(
this.formatter.format(file.ContentTypes, {
viewWrapper: file.Document,
file,
}),
{
indent: prettify,
declaration: {
encoding: "UTF-8",
},
},
2021-03-11 01:06:55 +00:00
),
2018-04-24 21:12:09 +01:00
path: "[Content_Types].xml",
},
CustomProperties: {
2021-03-11 01:06:55 +00:00
data: xml(
this.formatter.format(file.CustomProperties, {
viewWrapper: file.Document,
file,
}),
{
indent: prettify,
declaration: {
standalone: "yes",
encoding: "UTF-8",
},
},
2021-03-11 01:06:55 +00:00
),
path: "docProps/custom.xml",
},
2018-04-24 21:12:09 +01:00
AppProperties: {
2021-03-11 01:06:55 +00:00
data: xml(
this.formatter.format(file.AppProperties, {
viewWrapper: file.Document,
file,
}),
{
indent: prettify,
declaration: {
standalone: "yes",
encoding: "UTF-8",
},
},
2021-03-11 01:06:55 +00:00
),
2018-04-24 21:12:09 +01:00
path: "docProps/app.xml",
},
FootNotes: {
2021-03-11 01:06:55 +00:00
data: xml(
this.formatter.format(file.FootNotes.View, {
viewWrapper: file.FootNotes,
file: file,
}),
{
indent: prettify,
declaration: {
encoding: "UTF-8",
},
},
2021-03-11 01:06:55 +00:00
),
path: "word/footnotes.xml",
},
2021-03-01 23:35:52 +00:00
FootNotesRelationships: {
2021-03-11 01:06:55 +00:00
data: xml(
this.formatter.format(file.FootNotes.Relationships, {
viewWrapper: file.FootNotes,
file: file,
}),
{
indent: prettify,
declaration: {
encoding: "UTF-8",
},
},
2021-03-11 01:06:55 +00:00
),
2021-03-01 23:35:52 +00:00
path: "word/_rels/footnotes.xml.rels",
},
2018-09-20 10:11:59 -03:00
Settings: {
2021-03-11 01:06:55 +00:00
data: xml(
this.formatter.format(file.Settings, {
viewWrapper: file.Document,
file,
}),
{
indent: prettify,
declaration: {
standalone: "yes",
encoding: "UTF-8",
},
},
2021-03-11 01:06:55 +00:00
),
2018-09-20 10:11:59 -03:00
path: "word/settings.xml",
},
2018-04-24 21:12:09 +01:00
};
}
}