diff --git a/src/export/formatter.ts b/src/export/formatter.ts index 199c32185f..0a28070d13 100644 --- a/src/export/formatter.ts +++ b/src/export/formatter.ts @@ -2,6 +2,12 @@ import { BaseXmlComponent, IXmlableObject } from "file/xml-components"; export class Formatter { public format(input: BaseXmlComponent): IXmlableObject { - return input.prepForXml(); + const output = input.prepForXml(); + + if (output) { + return output; + } else { + throw Error("XMLComponent did not format correctly"); + } } } diff --git a/src/file/document/body/body.ts b/src/file/document/body/body.ts index e274fa359f..92664e277c 100644 --- a/src/file/document/body/body.ts +++ b/src/file/document/body/body.ts @@ -35,7 +35,7 @@ export class Body extends XmlComponent { this.sections.push(new SectionProperties(params)); } } - public prepForXml(): IXmlableObject { + public prepForXml(): IXmlableObject | undefined { if (this.sections.length === 1) { this.root.push(this.sections[0]); } else if (this.sections.length > 1) { diff --git a/src/file/document/body/section-properties/page-border/page-borders.spec.ts b/src/file/document/body/section-properties/page-border/page-borders.spec.ts index 66abb9cc66..0bf22633ee 100644 --- a/src/file/document/body/section-properties/page-border/page-borders.spec.ts +++ b/src/file/document/body/section-properties/page-border/page-borders.spec.ts @@ -8,9 +8,7 @@ describe("PageBorders", () => { describe("#constructor()", () => { it("should create empty element when no options are passed", () => { const properties = new PageBorders(); - const tree = new Formatter().format(properties); - - expect(tree).to.equal(""); + expect(() => new Formatter().format(properties)).to.throw(); }); it("should create page borders with some configuration", () => { diff --git a/src/file/document/body/section-properties/page-border/page-borders.ts b/src/file/document/body/section-properties/page-border/page-borders.ts index 0af96cfd41..4017fbb7ae 100644 --- a/src/file/document/body/section-properties/page-border/page-borders.ts +++ b/src/file/document/body/section-properties/page-border/page-borders.ts @@ -98,7 +98,9 @@ export class PageBorders extends XmlComponent { } } - public prepForXml(): IXmlableObject { - return this.root.length > 0 ? super.prepForXml() : ""; + public prepForXml(): IXmlableObject | undefined { + if (this.root.length > 0) { + return super.prepForXml(); + } } } diff --git a/src/file/footer-wrapper.ts b/src/file/footer-wrapper.ts index 403e3b7c8f..99cff08f20 100644 --- a/src/file/footer-wrapper.ts +++ b/src/file/footer-wrapper.ts @@ -41,7 +41,7 @@ export class FooterWrapper { return this.footer.createTable(rows, cols); } - public addChildElement(childElement: XmlComponent | string): void { + public addChildElement(childElement: XmlComponent): void { this.footer.addChildElement(childElement); } diff --git a/src/file/numbering/numbering.ts b/src/file/numbering/numbering.ts index a256500c45..a925f4afec 100644 --- a/src/file/numbering/numbering.ts +++ b/src/file/numbering/numbering.ts @@ -71,7 +71,7 @@ export class Numbering extends XmlComponent { return num; } - public prepForXml(): IXmlableObject { + public prepForXml(): IXmlableObject | undefined { this.abstractNumbering.forEach((x) => this.root.push(x)); this.concreteNumbering.forEach((x) => this.root.push(x)); return super.prepForXml(); diff --git a/src/file/table/table-cell-margin.ts b/src/file/table/table-cell-margin.ts index 198dc89cbd..2b8fd32049 100644 --- a/src/file/table/table-cell-margin.ts +++ b/src/file/table/table-cell-margin.ts @@ -21,8 +21,10 @@ export class TableCellMargin extends XmlComponent { super("w:tblCellMar"); } - public prepForXml(): IXmlableObject { - return this.root.length > 0 ? super.prepForXml() : ""; + public prepForXml(): IXmlableObject | undefined { + if (this.root.length > 0) { + return super.prepForXml(); + } } public addTopMargin(value: number, type: WidthType = WidthType.DXA): void { diff --git a/src/file/table/table-cell.spec.ts b/src/file/table/table-cell.spec.ts index 7a3072f186..4e761d2e07 100644 --- a/src/file/table/table-cell.spec.ts +++ b/src/file/table/table-cell.spec.ts @@ -8,8 +8,7 @@ describe("TableCellBorders", () => { describe("#prepForXml", () => { it("should not add empty borders element if there are no borders defined", () => { const tb = new TableCellBorders(); - const tree = new Formatter().format(tb); - expect(tree).to.deep.equal(""); + expect(() => new Formatter().format(tb)).to.throw(); }); }); diff --git a/src/file/table/table-cell.ts b/src/file/table/table-cell.ts index 19e3ccc428..046cc8d8aa 100644 --- a/src/file/table/table-cell.ts +++ b/src/file/table/table-cell.ts @@ -29,8 +29,10 @@ export class TableCellBorders extends XmlComponent { super("w:tcBorders"); } - public prepForXml(): IXmlableObject { - return this.root.length > 0 ? super.prepForXml() : ""; + public prepForXml(): IXmlableObject | undefined { + if (this.root.length > 0) { + return super.prepForXml(); + } } public addTopBorder(style: BorderStyle, size: number, color: string): TableCellBorders { diff --git a/src/file/table/table.ts b/src/file/table/table.ts index 0406bdf549..bc81520157 100644 --- a/src/file/table/table.ts +++ b/src/file/table/table.ts @@ -126,9 +126,13 @@ export class TableCell extends XmlComponent { return this; } - public prepForXml(): IXmlableObject { + public prepForXml(): IXmlableObject | undefined { // Cells must end with a paragraph const retval = super.prepForXml(); + if (!retval) { + return undefined; + } + const content = retval["w:tc"]; if (!content[content.length - 1]["w:p"]) { content.push(new Paragraph().prepForXml()); diff --git a/src/file/xml-components/base.ts b/src/file/xml-components/base.ts index a5f24f3824..d65e5c6f3c 100644 --- a/src/file/xml-components/base.ts +++ b/src/file/xml-components/base.ts @@ -8,7 +8,7 @@ export abstract class BaseXmlComponent { this.rootKey = rootKey; } - public abstract prepForXml(): IXmlableObject; + public abstract prepForXml(): IXmlableObject | undefined; public get IsDeleted(): boolean { return this.deleted; diff --git a/src/file/xml-components/imported-xml-component.ts b/src/file/xml-components/imported-xml-component.ts index 23c4137900..eb318a3d64 100644 --- a/src/file/xml-components/imported-xml-component.ts +++ b/src/file/xml-components/imported-xml-component.ts @@ -1,7 +1,7 @@ -/* tslint:disable */ -import { XmlComponent, IXmlableObject } from "."; +// tslint:disable:no-any import * as fastXmlParser from "fast-xml-parser"; import { flatMap } from "lodash"; +import { IXmlableObject, XmlComponent } from "."; export const parseOptions = { ignoreAttributes: false, @@ -54,8 +54,27 @@ export function convertToXmlComponent(elementName: string, element: any): Import * Represents imported xml component from xml file. */ export class ImportedXmlComponent extends XmlComponent { - private _attr: any; + /** + * Converts the xml string to a XmlComponent tree. + * + * @param importedContent xml content of the imported component + */ + public static fromXmlString(importedContent: string): ImportedXmlComponent { + const imported = fastXmlParser.parse(importedContent, parseOptions); + const elementName = Object.keys(imported)[0]; + const converted = convertToXmlComponent(elementName, imported[elementName]); + + if (Array.isArray(converted) && converted.length > 1) { + throw new Error("Invalid conversion, input must be one element."); + } + return Array.isArray(converted) ? converted[0] : converted; + } + + // tslint:disable-next-line:variable-name + private readonly _attr: any; + + // tslint:disable-next-line:variable-name constructor(rootKey: string, _attr?: any) { super(rootKey); if (_attr) { @@ -89,8 +108,12 @@ export class ImportedXmlComponent extends XmlComponent { * ] * } */ - prepForXml(): IXmlableObject { + public prepForXml(): IXmlableObject | undefined { const result = super.prepForXml(); + if (!result) { + return undefined; + } + if (!!this._attr) { if (!Array.isArray(result[this.rootKey])) { result[this.rootKey] = [result[this.rootKey]]; @@ -100,33 +123,17 @@ export class ImportedXmlComponent extends XmlComponent { return result; } - push(xmlComponent: XmlComponent) { + public push(xmlComponent: XmlComponent): void { this.root.push(xmlComponent); } - - /** - * Converts the xml string to a XmlComponent tree. - * - * @param importedContent xml content of the imported component - */ - static fromXmlString(importedContent: string): ImportedXmlComponent { - const imported = fastXmlParser.parse(importedContent, parseOptions); - const elementName = Object.keys(imported)[0]; - - const converted = convertToXmlComponent(elementName, imported[elementName]); - - if (Array.isArray(converted) && converted.length > 1) { - throw new Error("Invalid conversion, input must be one element."); - } - return Array.isArray(converted) ? converted[0] : converted; - } } /** * Used for the attributes of root element that is being imported. */ export class ImportedRootElementAttributes extends XmlComponent { - constructor(private _attr: any) { + // tslint:disable-next-line:variable-name + constructor(private readonly _attr: any) { super(""); } diff --git a/src/file/xml-components/xml-component.spec.ts b/src/file/xml-components/xml-component.spec.ts index 8b4f983388..10e2f44dc4 100644 --- a/src/file/xml-components/xml-component.spec.ts +++ b/src/file/xml-components/xml-component.spec.ts @@ -26,6 +26,11 @@ describe("XmlComponent", () => { xmlComponent.addChildElement(child); const xml = xmlComponent.prepForXml(); + + if (!xml) { + return; + } + assert.equal(xml["w:test"].length, 0); }); }); diff --git a/src/file/xml-components/xml-component.ts b/src/file/xml-components/xml-component.ts index 0ed604e9ee..acbe51cb04 100644 --- a/src/file/xml-components/xml-component.ts +++ b/src/file/xml-components/xml-component.ts @@ -7,10 +7,10 @@ export abstract class XmlComponent extends BaseXmlComponent { constructor(rootKey: string) { super(rootKey); - this.root = new Array(); + this.root = new Array(); } - public prepForXml(): IXmlableObject { + public prepForXml(): IXmlableObject | undefined { const children = this.root .filter((c) => { if (c instanceof BaseXmlComponent) { @@ -24,13 +24,12 @@ export abstract class XmlComponent extends BaseXmlComponent { } return comp; }) - .filter((comp) => comp); // Exclude null, undefined, and empty strings + .filter((comp) => comp !== undefined); // Exclude undefined return { [this.rootKey]: children, }; } - // TODO: Unused method public addChildElement(child: XmlComponent | string): XmlComponent { this.root.push(child);