From 62911d6e44c73ee612d377bc87da89dc2b63e5bb Mon Sep 17 00:00:00 2001 From: felipe Date: Fri, 10 Mar 2017 10:42:24 +0100 Subject: [PATCH] make XmlAttributeComponent into a generic class This change brings increased type safety to uses of XmlAttributeComponent. Now the compiler is checkign for us that the properties that get passed in to every subclass match the intended interface, and also that the xmlKeys property -> xml attribute mapping has all the right keys --- ts/docx/document/document-attributes.ts | 61 ++++++++----------- ts/docx/paragraph/indent.ts | 15 ++--- ts/docx/paragraph/spacing.ts | 14 ++--- ts/docx/run/run-fonts.ts | 15 ++--- ts/docx/xml-components/attributes.ts | 47 +++++++------- ts/docx/xml-components/default-attributes.ts | 32 ++++------ ts/numbering/abstract-numbering.ts | 13 ++-- ts/numbering/level.ts | 13 ++-- ts/numbering/num.ts | 9 +-- ts/styles/style/components.ts | 6 +- ts/styles/style/index.ts | 16 +++-- ts/tests/docx/xml-components/attributeTest.ts | 13 ---- 12 files changed, 100 insertions(+), 154 deletions(-) diff --git a/ts/docx/document/document-attributes.ts b/ts/docx/document/document-attributes.ts index 8c1572f632..bdd3dff089 100644 --- a/ts/docx/document/document-attributes.ts +++ b/ts/docx/document/document-attributes.ts @@ -26,39 +26,30 @@ interface IDocumentAttributesProperties { type?: string; } -export class DocumentAttributes extends XmlAttributeComponent { - - constructor(properties?: IDocumentAttributesProperties) { - super({ - wpc: "xmlns:wpc", - mc: "xmlns:mc", - o: "xmlns:o", - r: "xmlns:r", - m: "xmlns:m", - v: "xmlns:v", - wp14: "xmlns:wp14", - wp: "xmlns:wp", - w10: "xmlns:w10", - w: "xmlns:w", - w14: "xmlns:w14", - w15: "xmlns:w15", - wpg: "xmlns:wpg", - wpi: "xmlns:wpi", - wne: "xmlns:wne", - wps: "xmlns:wps", - Ignorable: "mc:Ignorable", - cp: "xmlns:cp", - dc: "xmlns:dc", - dcterms: "xmlns:dcterms", - dcmitype: "xmlns:dcmitype", - xsi: "xmlns:xsi", - type: "xsi:type", - }, properties); - - this.root = properties; - - if (!properties) { - this.root = {}; - } - } +export class DocumentAttributes extends XmlAttributeComponent { + protected xmlKeys = { + wpc: "xmlns:wpc", + mc: "xmlns:mc", + o: "xmlns:o", + r: "xmlns:r", + m: "xmlns:m", + v: "xmlns:v", + wp14: "xmlns:wp14", + wp: "xmlns:wp", + w10: "xmlns:w10", + w: "xmlns:w", + w14: "xmlns:w14", + w15: "xmlns:w15", + wpg: "xmlns:wpg", + wpi: "xmlns:wpi", + wne: "xmlns:wne", + wps: "xmlns:wps", + Ignorable: "mc:Ignorable", + cp: "xmlns:cp", + dc: "xmlns:dc", + dcterms: "xmlns:dcterms", + dcmitype: "xmlns:dcmitype", + xsi: "xmlns:xsi", + type: "xsi:type", + }; } diff --git a/ts/docx/paragraph/indent.ts b/ts/docx/paragraph/indent.ts index c98b3570a1..5b4195deaf 100644 --- a/ts/docx/paragraph/indent.ts +++ b/ts/docx/paragraph/indent.ts @@ -1,18 +1,15 @@ import { XmlAttributeComponent, XmlComponent } from "../xml-components"; -interface IndentAttributesProperties { +interface IIndentAttributesProperties { left: number; hanging: number; } -class IndentAttributes extends XmlAttributeComponent { - - constructor(properties: IndentAttributesProperties) { - super({ - left: "w:left", - hanging: "w:hanging", - }, properties); - } +class IndentAttributes extends XmlAttributeComponent { + protected xmlKeys = { + left: "w:left", + hanging: "w:hanging", + }; } export class Indent extends XmlComponent { diff --git a/ts/docx/paragraph/spacing.ts b/ts/docx/paragraph/spacing.ts index 527d62c6d3..af4c4e8f79 100644 --- a/ts/docx/paragraph/spacing.ts +++ b/ts/docx/paragraph/spacing.ts @@ -6,14 +6,12 @@ export interface ISpacingProperties { line?: number; } -class SpacingAttributes extends XmlAttributeComponent { - constructor(properties: ISpacingProperties) { - super({ - after: "w:after", - before: "w:before", - line: "w:line", - }, properties); - } +class SpacingAttributes extends XmlAttributeComponent { + protected xmlKeys = { + after: "w:after", + before: "w:before", + line: "w:line", + }; } export class Spacing extends XmlComponent { diff --git a/ts/docx/run/run-fonts.ts b/ts/docx/run/run-fonts.ts index cc542934ae..674f1395b9 100644 --- a/ts/docx/run/run-fonts.ts +++ b/ts/docx/run/run-fonts.ts @@ -6,15 +6,12 @@ interface IRunFontAttributesProperties { hint?: string; } -class RunFontAttributes extends XmlAttributeComponent { - - constructor(properties: IRunFontAttributesProperties) { - super({ - ascii: "w:ascii", - hAnsi: "w:hAnsi", - hint: "w:hint", - }, properties); - } +class RunFontAttributes extends XmlAttributeComponent { + protected xmlKeys = { + ascii: "w:ascii", + hAnsi: "w:hAnsi", + hint: "w:hint", + }; } export class RunFonts extends XmlComponent { diff --git a/ts/docx/xml-components/attributes.ts b/ts/docx/xml-components/attributes.ts index 126a040699..33cbbc1f7b 100644 --- a/ts/docx/xml-components/attributes.ts +++ b/ts/docx/xml-components/attributes.ts @@ -22,29 +22,26 @@ interface IAttributesProperties { pos?: string | number; // Little strange. Perhaps it is normal. Need to clarify in the spec. } -export class Attributes extends XmlAttributeComponent { - - constructor(properties?: IAttributesProperties) { - super({ - val: "w:val", - color: "w:color", - space: "w:space", - sz: "w:sz", - type: "w:type", - rsidR: "w:rsidR", - rsidRPr: "w:rsidRPr", - rsidSect: "w:rsidSect", - w: "w:w", - h: "w:h", - top: "w:top", - right: "w:right", - bottom: "w:bottom", - left: "w:left", - header: "w:header", - footer: "w:footer", - gutter: "w:gutter", - linePitch: "w:linePitch", - pos: "w:pos", - }, properties); - } +export class Attributes extends XmlAttributeComponent { + protected xmlKeys = { + val: "w:val", + color: "w:color", + space: "w:space", + sz: "w:sz", + type: "w:type", + rsidR: "w:rsidR", + rsidRPr: "w:rsidRPr", + rsidSect: "w:rsidSect", + w: "w:w", + h: "w:h", + top: "w:top", + right: "w:right", + bottom: "w:bottom", + left: "w:left", + header: "w:header", + footer: "w:footer", + gutter: "w:gutter", + linePitch: "w:linePitch", + pos: "w:pos", + }; } diff --git a/ts/docx/xml-components/default-attributes.ts b/ts/docx/xml-components/default-attributes.ts index 7559f9fead..7c56a96e63 100644 --- a/ts/docx/xml-components/default-attributes.ts +++ b/ts/docx/xml-components/default-attributes.ts @@ -1,31 +1,25 @@ -import * as _ from "lodash"; import { BaseXmlComponent } from "./base"; -export abstract class XmlAttributeComponent extends BaseXmlComponent { - protected root: object; - private xmlKeys: object; +type AttributeMap = {[P in keyof T]: string}; - constructor(xmlKeys: object, properties: object) { +export abstract class XmlAttributeComponent extends BaseXmlComponent { + protected root: T; + protected xmlKeys: AttributeMap; + + constructor(properties: T) { super("_attr"); - this.xmlKeys = xmlKeys; - this.root = properties; - - if (!properties) { - this.root = {}; - } } public prepForXml(): {_attr: {[key: string]: (string | number | boolean)}} { const attrs = {}; - if (this.root !== undefined) { - _.forOwn(this.root, (value, key) => { - if (value !== undefined) { - const newKey = this.xmlKeys[key]; - attrs[newKey] = value; - } - }); - } + Object.keys(this.root).forEach((key) => { + const value = this.root[key]; + if (value !== undefined) { + const newKey = this.xmlKeys[key]; + attrs[newKey] = value; + } + }); return {_attr: attrs}; } } diff --git a/ts/numbering/abstract-numbering.ts b/ts/numbering/abstract-numbering.ts index 5aaaf7a20d..3491ec6426 100644 --- a/ts/numbering/abstract-numbering.ts +++ b/ts/numbering/abstract-numbering.ts @@ -7,14 +7,11 @@ interface IAbstractNumberingAttributesProperties { restartNumberingAfterBreak?: number; } -class AbstractNumberingAttributes extends XmlAttributeComponent { - - constructor(properties: IAbstractNumberingAttributesProperties) { - super({ - abstractNumId: "w:abstractNumId", - restartNumberingAfterBreak: "w15:restartNumberingAfterBreak", - }, properties); - } +class AbstractNumberingAttributes extends XmlAttributeComponent { + protected xmlKeys = { + abstractNumId: "w:abstractNumId", + restartNumberingAfterBreak: "w15:restartNumberingAfterBreak", + }; } export class AbstractNumbering extends XmlComponent { diff --git a/ts/numbering/level.ts b/ts/numbering/level.ts index 2882c20589..02f0896f21 100644 --- a/ts/numbering/level.ts +++ b/ts/numbering/level.ts @@ -7,14 +7,11 @@ interface ILevelAttributesProperties { tentative?: number; } -class LevelAttributes extends XmlAttributeComponent { - - constructor(properties: ILevelAttributesProperties) { - super({ - ilvl: "w:ilvl", - tentative: "w15:tentative", - }, properties); - } +class LevelAttributes extends XmlAttributeComponent { + protected xmlKeys = { + ilvl: "w:ilvl", + tentative: "w15:tentative", + }; } class Start extends XmlComponent { diff --git a/ts/numbering/num.ts b/ts/numbering/num.ts index 1958b989ac..ef7281dc78 100644 --- a/ts/numbering/num.ts +++ b/ts/numbering/num.ts @@ -14,13 +14,8 @@ interface INumAttributesProperties { numId: number; } -class NumAttributes extends XmlAttributeComponent { - - constructor(properties: INumAttributesProperties) { - super({ - numId: "w:numId", - }, properties); - } +class NumAttributes extends XmlAttributeComponent { + protected xmlKeys = {numId: "w:numId"}; } export class Num extends XmlComponent { diff --git a/ts/styles/style/components.ts b/ts/styles/style/components.ts index 080ce00162..8980ee8a58 100644 --- a/ts/styles/style/components.ts +++ b/ts/styles/style/components.ts @@ -4,10 +4,8 @@ interface IComponentAttributes { val: string; } -class ComponentAttributes extends XmlAttributeComponent { - constructor(properties: IComponentAttributes) { - super({val: "w:val"}, properties); - } +class ComponentAttributes extends XmlAttributeComponent { + protected xmlKeys = {val: "w:val"}; } export class Name extends XmlComponent { diff --git a/ts/styles/style/index.ts b/ts/styles/style/index.ts index 9a486abbdc..e5e3561eef 100644 --- a/ts/styles/style/index.ts +++ b/ts/styles/style/index.ts @@ -14,15 +14,13 @@ export interface IStyleAttributes { customStyle?: string; } -class StyleAttributes extends XmlAttributeComponent { - constructor(properties: IStyleAttributes) { - super({ - type: "w:type", - styleId: "w:styleId", - default: "w:default", - customStyle: "w:customStyle", - }, properties); - } +class StyleAttributes extends XmlAttributeComponent { + protected xmlKeys = { + type: "w:type", + styleId: "w:styleId", + default: "w:default", + customStyle: "w:customStyle", + }; } export class Style extends XmlComponent { diff --git a/ts/tests/docx/xml-components/attributeTest.ts b/ts/tests/docx/xml-components/attributeTest.ts index 002a6bb82c..928164e051 100644 --- a/ts/tests/docx/xml-components/attributeTest.ts +++ b/ts/tests/docx/xml-components/attributeTest.ts @@ -2,21 +2,8 @@ import { assert } from "chai"; import { Attributes } from "../../../docx/xml-components"; describe("Attribute", () => { - let attributes: Attributes; - - beforeEach(() => { - attributes = new Attributes(); - }); - describe("#constructor()", () => { - it("should not add val with empty constructor", () => { - const newAttrs = new Attributes(); - const stringifiedJson = JSON.stringify(newAttrs); - const newJson = JSON.parse(stringifiedJson); - assert.isUndefined(newJson.root.val); - }); - it("should have val as defined with populated constructor", () => { const newAttrs = new Attributes({ val: "test",