Added constant EMPTY_OBJECT (an empty sealed object) that is used to indicate to the xml library that an empty XML element should be generated, and use it in the JSON hardcoded into the tests.

This commit is contained in:
Bruce Duncan
2019-04-10 13:47:38 -04:00
parent bb1604cd8f
commit 77edf8862b
16 changed files with 94 additions and 66 deletions

View File

@ -7,6 +7,8 @@ import { LevelForOverride } from "./level";
import { Num } from "./num";
import { Numbering } from "./numbering";
import { EMPTY_OBJECT } from "file/xml-components";
describe("Numbering", () => {
let numbering: Numbering;
@ -216,7 +218,7 @@ describe("AbstractNumbering", () => {
const level = abstractNumbering.createLevel(0, "lowerRoman", "%0.").keepLines();
const tree = new Formatter().format(level);
expect(tree["w:lvl"]).to.include({
"w:pPr": [{ "w:keepLines": {} }],
"w:pPr": [{ "w:keepLines": EMPTY_OBJECT }],
});
});
@ -225,7 +227,7 @@ describe("AbstractNumbering", () => {
const level = abstractNumbering.createLevel(0, "lowerRoman", "%0.").keepNext();
const tree = new Formatter().format(level);
expect(tree["w:lvl"]).to.include({
"w:pPr": [{ "w:keepNext": {} }],
"w:pPr": [{ "w:keepNext": EMPTY_OBJECT }],
});
});
});

View File

@ -5,6 +5,8 @@ import { Formatter } from "export/formatter";
import { ImageParagraph } from "./image";
import { EMPTY_OBJECT } from "file/xml-components";
describe("Image", () => {
let image: ImageParagraph;
@ -156,12 +158,12 @@ describe("Image", () => {
},
},
{
"a:srcRect": {},
"a:srcRect": EMPTY_OBJECT,
},
{
"a:stretch": [
{
"a:fillRect": {},
"a:fillRect": EMPTY_OBJECT,
},
],
},
@ -202,7 +204,7 @@ describe("Image", () => {
},
},
{
"a:avLst": {},
"a:avLst": EMPTY_OBJECT,
},
],
},

View File

@ -6,6 +6,8 @@ import * as file from "file";
import { Numbering } from "../numbering";
import { LeaderType } from "./formatting";
import { EMPTY_OBJECT } from "file/xml-components";
describe("Paragraph", () => {
let paragraph: file.Paragraph;
@ -471,7 +473,7 @@ describe("Paragraph", () => {
{
"w:pPr": [
{
"w:pageBreakBefore": {},
"w:pageBreakBefore": EMPTY_OBJECT,
},
],
},
@ -625,7 +627,7 @@ describe("Paragraph", () => {
paragraph.keepLines();
const tree = new Formatter().format(paragraph);
expect(tree).to.deep.equal({
"w:p": [{ "w:pPr": [{ "w:keepLines": {} }] }],
"w:p": [{ "w:pPr": [{ "w:keepLines": EMPTY_OBJECT }] }],
});
});
});
@ -635,7 +637,7 @@ describe("Paragraph", () => {
paragraph.keepNext();
const tree = new Formatter().format(paragraph);
expect(tree).to.deep.equal({
"w:p": [{ "w:pPr": [{ "w:keepNext": {} }] }],
"w:p": [{ "w:pPr": [{ "w:keepNext": EMPTY_OBJECT }] }],
});
});
});
@ -645,7 +647,7 @@ describe("Paragraph", () => {
paragraph.bidirectional();
const tree = new Formatter().format(paragraph);
expect(tree).to.deep.equal({
"w:p": [{ "w:pPr": [{ "w:bidi": {} }] }],
"w:p": [{ "w:pPr": [{ "w:bidi": EMPTY_OBJECT }] }],
});
});
});

View File

@ -2,13 +2,15 @@ import { expect } from "chai";
import { Formatter } from "export/formatter";
import { Compatibility } from "file/settings/compatibility";
import { EMPTY_OBJECT } from "file/xml-components";
describe("Compatibility", () => {
describe("#constructor", () => {
it("creates an initially empty property object", () => {
const compatibility = new Compatibility();
const tree = new Formatter().format(compatibility);
expect(tree).to.deep.equal({ "w:compat": {} });
expect(tree).to.deep.equal({ "w:compat": EMPTY_OBJECT });
});
});
@ -18,7 +20,7 @@ describe("Compatibility", () => {
compatibility.doNotExpandShiftReturn();
const tree = new Formatter().format(compatibility);
expect(tree).to.deep.equal({ "w:compat": [{ "w:doNotExpandShiftReturn": {} }] });
expect(tree).to.deep.equal({ "w:compat": [{ "w:doNotExpandShiftReturn": EMPTY_OBJECT }] });
});
});
});

View File

@ -4,6 +4,8 @@ import { Formatter } from "export/formatter";
import { CharacterStyle } from "./character-style";
import { EMPTY_OBJECT } from "file/xml-components";
describe("CharacterStyle", () => {
describe("#constructor", () => {
it("should set the style type to character and use the given style id", () => {
@ -20,7 +22,7 @@ describe("CharacterStyle", () => {
},
},
{
"w:unhideWhenUsed": {},
"w:unhideWhenUsed": EMPTY_OBJECT,
},
],
});
@ -41,7 +43,7 @@ describe("CharacterStyle", () => {
},
},
{
"w:unhideWhenUsed": {},
"w:unhideWhenUsed": EMPTY_OBJECT,
},
],
});
@ -63,7 +65,7 @@ describe("CharacterStyle", () => {
},
},
{
"w:unhideWhenUsed": {},
"w:unhideWhenUsed": EMPTY_OBJECT,
},
{ "w:basedOn": { _attr: { "w:val": "otherId" } } },
],
@ -89,7 +91,7 @@ describe("CharacterStyle", () => {
},
},
{
"w:unhideWhenUsed": {},
"w:unhideWhenUsed": EMPTY_OBJECT,
},
],
});
@ -113,7 +115,7 @@ describe("CharacterStyle", () => {
},
},
{
"w:unhideWhenUsed": {},
"w:unhideWhenUsed": EMPTY_OBJECT,
},
],
});
@ -136,7 +138,7 @@ describe("CharacterStyle", () => {
},
},
{
"w:unhideWhenUsed": {},
"w:unhideWhenUsed": EMPTY_OBJECT,
},
],
});
@ -159,7 +161,7 @@ describe("CharacterStyle", () => {
},
},
{
"w:unhideWhenUsed": {},
"w:unhideWhenUsed": EMPTY_OBJECT,
},
],
});
@ -191,7 +193,7 @@ describe("CharacterStyle", () => {
},
},
{
"w:unhideWhenUsed": {},
"w:unhideWhenUsed": EMPTY_OBJECT,
},
],
});
@ -214,7 +216,7 @@ describe("CharacterStyle", () => {
},
},
{
"w:unhideWhenUsed": {},
"w:unhideWhenUsed": EMPTY_OBJECT,
},
],
});
@ -237,7 +239,7 @@ describe("CharacterStyle", () => {
},
},
{
"w:unhideWhenUsed": {},
"w:unhideWhenUsed": EMPTY_OBJECT,
},
],
});
@ -260,7 +262,7 @@ describe("CharacterStyle", () => {
},
},
{
"w:unhideWhenUsed": {},
"w:unhideWhenUsed": EMPTY_OBJECT,
},
],
});
@ -280,7 +282,7 @@ describe("CharacterStyle", () => {
},
},
{
"w:unhideWhenUsed": {},
"w:unhideWhenUsed": EMPTY_OBJECT,
},
{ "w:link": { _attr: { "w:val": "MyLink" } } },
],
@ -300,8 +302,8 @@ describe("CharacterStyle", () => {
},
},
},
{ "w:unhideWhenUsed": {} },
{ "w:semiHidden": {} },
{ "w:unhideWhenUsed": EMPTY_OBJECT },
{ "w:semiHidden": EMPTY_OBJECT },
],
});
});

View File

@ -2,6 +2,8 @@ import { expect } from "chai";
import { Formatter } from "export/formatter";
import * as components from "./components";
import { EMPTY_OBJECT } from "file/xml-components";
describe("Style components", () => {
it("Name#constructor", () => {
const style = new components.Name("Style Name");
@ -36,18 +38,18 @@ describe("Style components", () => {
it("UnhideWhenUsed#constructor", () => {
const style = new components.UnhideWhenUsed();
const tree = new Formatter().format(style);
expect(tree).to.deep.equal({ "w:unhideWhenUsed": {} });
expect(tree).to.deep.equal({ "w:unhideWhenUsed": EMPTY_OBJECT });
});
it("QuickFormat#constructor", () => {
const style = new components.QuickFormat();
const tree = new Formatter().format(style);
expect(tree).to.deep.equal({ "w:qFormat": {} });
expect(tree).to.deep.equal({ "w:qFormat": EMPTY_OBJECT });
});
it("SemiHidden#constructor", () => {
const style = new components.SemiHidden();
const tree = new Formatter().format(style);
expect(tree).to.deep.equal({ "w:semiHidden": {} });
expect(tree).to.deep.equal({ "w:semiHidden": EMPTY_OBJECT });
});
});

View File

@ -2,6 +2,8 @@ import { expect } from "chai";
import { Formatter } from "export/formatter";
import * as defaultStyels from "./default-styles";
import { EMPTY_OBJECT } from "file/xml-components";
describe("Default Styles", () => {
it("HeadingStyle#constructor", () => {
const style = new defaultStyels.HeadingStyle("Heading1", "Heading 1");
@ -12,7 +14,7 @@ describe("Default Styles", () => {
{ "w:name": { _attr: { "w:val": "Heading 1" } } },
{ "w:basedOn": { _attr: { "w:val": "Normal" } } },
{ "w:next": { _attr: { "w:val": "Normal" } } },
{ "w:qFormat": {} },
{ "w:qFormat": EMPTY_OBJECT },
],
});
});
@ -26,7 +28,7 @@ describe("Default Styles", () => {
{ "w:name": { _attr: { "w:val": "Title" } } },
{ "w:basedOn": { _attr: { "w:val": "Normal" } } },
{ "w:next": { _attr: { "w:val": "Normal" } } },
{ "w:qFormat": {} },
{ "w:qFormat": EMPTY_OBJECT },
],
});
});
@ -40,7 +42,7 @@ describe("Default Styles", () => {
{ "w:name": { _attr: { "w:val": "Heading 1" } } },
{ "w:basedOn": { _attr: { "w:val": "Normal" } } },
{ "w:next": { _attr: { "w:val": "Normal" } } },
{ "w:qFormat": {} },
{ "w:qFormat": EMPTY_OBJECT },
],
});
});
@ -54,7 +56,7 @@ describe("Default Styles", () => {
{ "w:name": { _attr: { "w:val": "Heading 2" } } },
{ "w:basedOn": { _attr: { "w:val": "Normal" } } },
{ "w:next": { _attr: { "w:val": "Normal" } } },
{ "w:qFormat": {} },
{ "w:qFormat": EMPTY_OBJECT },
],
});
});
@ -68,7 +70,7 @@ describe("Default Styles", () => {
{ "w:name": { _attr: { "w:val": "Heading 3" } } },
{ "w:basedOn": { _attr: { "w:val": "Normal" } } },
{ "w:next": { _attr: { "w:val": "Normal" } } },
{ "w:qFormat": {} },
{ "w:qFormat": EMPTY_OBJECT },
],
});
});
@ -82,7 +84,7 @@ describe("Default Styles", () => {
{ "w:name": { _attr: { "w:val": "Heading 4" } } },
{ "w:basedOn": { _attr: { "w:val": "Normal" } } },
{ "w:next": { _attr: { "w:val": "Normal" } } },
{ "w:qFormat": {} },
{ "w:qFormat": EMPTY_OBJECT },
],
});
});
@ -96,7 +98,7 @@ describe("Default Styles", () => {
{ "w:name": { _attr: { "w:val": "Heading 5" } } },
{ "w:basedOn": { _attr: { "w:val": "Normal" } } },
{ "w:next": { _attr: { "w:val": "Normal" } } },
{ "w:qFormat": {} },
{ "w:qFormat": EMPTY_OBJECT },
],
});
});
@ -110,7 +112,7 @@ describe("Default Styles", () => {
{ "w:name": { _attr: { "w:val": "Heading 6" } } },
{ "w:basedOn": { _attr: { "w:val": "Normal" } } },
{ "w:next": { _attr: { "w:val": "Normal" } } },
{ "w:qFormat": {} },
{ "w:qFormat": EMPTY_OBJECT },
],
});
});
@ -123,7 +125,7 @@ describe("Default Styles", () => {
{ _attr: { "w:type": "paragraph", "w:styleId": "ListParagraph" } },
{ "w:name": { _attr: { "w:val": "List Paragraph" } } },
{ "w:basedOn": { _attr: { "w:val": "Normal" } } },
{ "w:qFormat": {} },
{ "w:qFormat": EMPTY_OBJECT },
],
});
});
@ -176,10 +178,10 @@ describe("Default Styles", () => {
},
},
{
"w:semiHidden": {},
"w:semiHidden": EMPTY_OBJECT,
},
{
"w:unhideWhenUsed": {},
"w:unhideWhenUsed": EMPTY_OBJECT,
},
],
});
@ -211,12 +213,12 @@ describe("Default Styles", () => {
},
},
{
"w:unhideWhenUsed": {},
"w:unhideWhenUsed": EMPTY_OBJECT,
},
{ "w:basedOn": { _attr: { "w:val": "DefaultParagraphFont" } } },
{
"w:semiHidden": {},
"w:semiHidden": EMPTY_OBJECT,
},
],
});
@ -255,12 +257,12 @@ describe("Default Styles", () => {
},
},
{
"w:unhideWhenUsed": {},
"w:unhideWhenUsed": EMPTY_OBJECT,
},
{ "w:basedOn": { _attr: { "w:val": "DefaultParagraphFont" } } },
{ "w:link": { _attr: { "w:val": "FootnoteText" } } },
{
"w:semiHidden": {},
"w:semiHidden": EMPTY_OBJECT,
},
],
});
@ -284,7 +286,7 @@ describe("Default Styles", () => {
},
},
{
"w:unhideWhenUsed": {},
"w:unhideWhenUsed": EMPTY_OBJECT,
},
{ "w:basedOn": { _attr: { "w:val": "DefaultParagraphFont" } } },
],

View File

@ -4,6 +4,8 @@ import { Formatter } from "export/formatter";
import { ParagraphStyle } from "./paragraph-style";
import { EMPTY_OBJECT } from "file/xml-components";
describe("ParagraphStyle", () => {
describe("#constructor", () => {
it("should set the style type to paragraph and use the given style id", () => {
@ -42,7 +44,7 @@ describe("ParagraphStyle", () => {
const style = new ParagraphStyle("myStyleId").quickFormat();
const tree = new Formatter().format(style);
expect(tree).to.deep.equal({
"w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:qFormat": {} }],
"w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:qFormat": EMPTY_OBJECT }],
});
});
@ -216,7 +218,7 @@ describe("ParagraphStyle", () => {
const style = new ParagraphStyle("myStyleId").keepLines();
const tree = new Formatter().format(style);
expect(tree).to.deep.equal({
"w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:pPr": [{ "w:keepLines": {} }] }],
"w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:pPr": [{ "w:keepLines": EMPTY_OBJECT }] }],
});
});
@ -224,7 +226,7 @@ describe("ParagraphStyle", () => {
const style = new ParagraphStyle("myStyleId").keepNext();
const tree = new Formatter().format(style);
expect(tree).to.deep.equal({
"w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:pPr": [{ "w:keepNext": {} }] }],
"w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:pPr": [{ "w:keepNext": EMPTY_OBJECT }] }],
});
});
@ -439,7 +441,7 @@ describe("ParagraphStyle", () => {
const style = new ParagraphStyle("myStyleId").semiHidden();
const tree = new Formatter().format(style);
expect(tree).to.deep.equal({
"w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:semiHidden": {} }],
"w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:semiHidden": EMPTY_OBJECT }],
});
});
@ -464,7 +466,7 @@ describe("ParagraphStyle", () => {
const style = new ParagraphStyle("myStyleId").unhideWhenUsed();
const tree = new Formatter().format(style);
expect(tree).to.deep.equal({
"w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:unhideWhenUsed": {} }],
"w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:unhideWhenUsed": EMPTY_OBJECT }],
});
});
});

View File

@ -6,6 +6,8 @@ import { CharacterStyle, ParagraphStyle } from "./style";
import { Styles } from "./styles";
import { EMPTY_OBJECT } from "file/xml-components";
describe("Styles", () => {
let styles: Styles;
@ -64,7 +66,7 @@ describe("Styles", () => {
},
},
{
"w:unhideWhenUsed": {},
"w:unhideWhenUsed": EMPTY_OBJECT,
},
],
},
@ -88,7 +90,7 @@ describe("Styles", () => {
},
},
{
"w:unhideWhenUsed": {},
"w:unhideWhenUsed": EMPTY_OBJECT,
},
],
},

View File

@ -4,6 +4,8 @@ import { Formatter } from "export/formatter";
import { GridCol, TableGrid } from "./grid";
import { EMPTY_OBJECT } from "file/xml-components";
describe("GridCol", () => {
describe("#constructor", () => {
it("sets the width attribute to the value given", () => {
@ -17,7 +19,7 @@ describe("GridCol", () => {
it("does not set a width attribute if not given", () => {
const grid = new GridCol();
const tree = new Formatter().format(grid);
expect(tree).to.deep.equal({ "w:gridCol": {} });
expect(tree).to.deep.equal({ "w:gridCol": EMPTY_OBJECT });
});
});
});

View File

@ -5,6 +5,8 @@ import { Formatter } from "export/formatter";
import { TableCell } from "./table-cell";
import { TableColumn } from "./table-column";
import { EMPTY_OBJECT } from "file/xml-components";
describe("TableColumn", () => {
let cells: TableCell[];
beforeEach(() => {
@ -37,15 +39,15 @@ describe("TableColumn", () => {
const tree = new Formatter().format(cells[0]);
expect(tree).to.deep.equal({
"w:tc": [{ "w:tcPr": [{ "w:vMerge": { _attr: { "w:val": "restart" } } }] }, { "w:p": {} }],
"w:tc": [{ "w:tcPr": [{ "w:vMerge": { _attr: { "w:val": "restart" } } }] }, { "w:p": EMPTY_OBJECT }],
});
const tree2 = new Formatter().format(cells[1]);
expect(tree2).to.deep.equal({ "w:tc": [{ "w:p": {} }] });
expect(tree2).to.deep.equal({ "w:tc": [{ "w:p": EMPTY_OBJECT }] });
const tree3 = new Formatter().format(cells[2]);
expect(tree3).to.deep.equal({
"w:tc": [{ "w:tcPr": [{ "w:vMerge": { _attr: { "w:val": "continue" } } }] }, { "w:p": {} }],
"w:tc": [{ "w:tcPr": [{ "w:vMerge": { _attr: { "w:val": "continue" } } }] }, { "w:p": EMPTY_OBJECT }],
});
});
});

View File

@ -5,13 +5,15 @@ import { Formatter } from "export/formatter";
import { TableCell } from "../table-cell";
import { TableRow } from "./table-row";
import { EMPTY_OBJECT } from "file/xml-components";
describe("TableRow", () => {
describe("#constructor", () => {
it("should create with no cells", () => {
const tableRow = new TableRow([]);
const tree = new Formatter().format(tableRow);
expect(tree).to.deep.equal({
"w:tr": {},
"w:tr": EMPTY_OBJECT,
});
});
@ -23,7 +25,7 @@ describe("TableRow", () => {
{
"w:tc": [
{
"w:p": {},
"w:p": EMPTY_OBJECT,
},
],
},

View File

@ -8,6 +8,8 @@ import { Table } from "./table";
// import { WidthType } from "./table-cell";
import { RelativeHorizontalPosition, RelativeVerticalPosition, TableAnchorType } from "./table-properties";
import { EMPTY_OBJECT } from "file/xml-components";
const DEFAULT_TABLE_PROPERTIES = {
"w:tblCellMar": [
{
@ -107,7 +109,7 @@ const WIDTHS = {
// ],
// },
// { "w:tblGrid": [{ "w:gridCol": { _attr: { "w:w": 100 } } }] },
// { "w:tr": [{ "w:tc": [{ "w:p": {} }] }] },
// { "w:tr": [{ "w:tc": [{ "w:p": EMPTY_OBJECT }] }] },
// ],
// };
@ -119,7 +121,7 @@ describe("Table", () => {
columns: 2,
});
const tree = new Formatter().format(table);
const cell = { "w:tc": [{ "w:p": {} }] };
const cell = { "w:tc": [{ "w:p": EMPTY_OBJECT }] };
expect(tree).to.deep.equal({
"w:tbl": [
{ "w:tblPr": [DEFAULT_TABLE_PROPERTIES, BORDERS, WIDTHS] },
@ -284,7 +286,7 @@ describe("Table", () => {
.to.be.an("array")
.which.has.length.at.least(1);
expect(row["w:tr"].find((x) => x["w:tc"])).to.deep.equal({
"w:tc": [{ "w:p": {} }],
"w:tc": [{ "w:p": EMPTY_OBJECT }],
});
});
@ -311,7 +313,7 @@ describe("Table", () => {
const cell = row["w:tr"].find((x) => x["w:tc"]);
expect(cell).not.to.be.undefined;
expect(cell["w:tc"][cell["w:tc"].length - 1]).to.deep.equal({
"w:p": {},
"w:p": EMPTY_OBJECT,
});
});

View File

@ -1,7 +1,7 @@
import { expect } from "chai";
import { Element, xml2js } from "xml-js";
import { ImportedXmlComponent } from "./";
import { EMPTY_OBJECT, ImportedXmlComponent } from "./";
import { convertToXmlComponent } from "./imported-xml-component";
const xmlString = `
@ -73,7 +73,7 @@ describe("ImportedXmlComponent", () => {
},
},
{
"w:child": {},
"w:child": EMPTY_OBJECT,
},
],
});

View File

@ -1,7 +1,7 @@
import { expect } from "chai";
import { Utility } from "tests/utility";
import { XmlComponent } from "./";
import { EMPTY_OBJECT, XmlComponent } from "./";
class TestComponent extends XmlComponent {}
@ -31,7 +31,7 @@ describe("XmlComponent", () => {
return;
}
expect(xml["w:test"]).to.deep.equal({});
expect(xml["w:test"]).to.deep.equal(EMPTY_OBJECT);
});
});
});

View File

@ -2,6 +2,8 @@ import { BaseXmlComponent } from "./base";
import { IXmlableObject } from "./xmlable-object";
export { BaseXmlComponent };
export const EMPTY_OBJECT = Object.seal({});
export abstract class XmlComponent extends BaseXmlComponent {
// tslint:disable-next-line:readonly-keyword
protected root: Array<BaseXmlComponent | string>;
@ -34,7 +36,7 @@ export abstract class XmlComponent extends BaseXmlComponent {
// children in order to get an empty XML element generated.
const onlyAttrs = (c) => typeof c === "object" && c._attr;
return {
[this.rootKey]: children.length ? (children.length === 1 && onlyAttrs(children[0]) ? children[0] : children) : {},
[this.rootKey]: children.length ? (children.length === 1 && onlyAttrs(children[0]) ? children[0] : children) : EMPTY_OBJECT,
};
}