diff --git a/.eslintrc.js b/.eslintrc.js index a4cea40931..d25922b741 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -12,6 +12,7 @@ https://github.com/typescript-eslint/tslint-to-eslint-config/blob/master/docs/FA Happy linting! 💖 */ module.exports = { + extends: "eslint:recommended", env: { browser: true, es6: true, @@ -33,6 +34,31 @@ module.exports = { ], root: true, rules: { + "no-undef": "off", + "no-extra-boolean-cast": "off", + "no-alert": "error", + "no-self-compare": "error", + "no-unreachable-loop": "error", + "no-template-curly-in-string": "error", + "no-unused-private-class-members": "error", + "no-extend-native": "error", + "no-floating-decimal": "error", + "no-implied-eval": "error", + "no-iterator": "error", + "no-lone-blocks": "error", + "no-loop-func": "error", + "no-new-object": "error", + "no-proto": "error", + "no-useless-catch": "error", + "one-var-declaration-per-line": "error", + "prefer-arrow-callback": "error", + "prefer-destructuring": "error", + "prefer-exponentiation-operator": "error", + "prefer-promise-reject-errors": "error", + "prefer-regex-literals": "error", + "prefer-spread": "error", + "prefer-template": "error", + "require-await": "error", "@typescript-eslint/adjacent-overload-signatures": "error", "@typescript-eslint/array-type": [ "error", @@ -95,22 +121,6 @@ module.exports = { allowTypedFunctionExpressions: false, }, ], - "@typescript-eslint/indent": [ - "error", - 4, - { - ObjectExpression: "first", - FunctionDeclaration: { - parameters: "first", - }, - FunctionExpression: { - parameters: "first", - }, - SwitchCase: 1, - flatTernaryExpressions: false, - ignoredNodes: [], - }, - ], "@typescript-eslint/naming-convention": [ "error", { @@ -176,7 +186,7 @@ module.exports = { "import/order": "error", indent: "off", "jsdoc/check-alignment": "error", - "jsdoc/check-indentation": "error", + "jsdoc/check-indentation": "off", "jsdoc/newline-after-description": "error", "max-classes-per-file": "off", "max-len": "off", @@ -245,6 +255,7 @@ module.exports = { "functional/no-method-signature": "error", "functional/no-mixed-type": "error", "functional/prefer-readonly-type": "error", + "no-unused-vars": ["error", { argsIgnorePattern: "^[_]+$" }], }, overrides: [ { @@ -252,6 +263,7 @@ module.exports = { rules: { "@typescript-eslint/no-unused-expressions": "off", "@typescript-eslint/dot-notation": "off", + "prefer-destructuring": "off", }, }, ], diff --git a/demo/74-nodejs-stream.ts b/demo/74-nodejs-stream.ts index 4dea1f7524..0a73bd0508 100644 --- a/demo/74-nodejs-stream.ts +++ b/demo/74-nodejs-stream.ts @@ -1,4 +1,4 @@ -// Simple example to add text to a document +// Exporting the document as a stream // Import from 'docx' rather than '../build' if you install from npm import * as fs from "fs"; import { Document, Packer, Paragraph, TextRun } from "../build"; @@ -26,6 +26,5 @@ const doc = new Document({ ], }); -Packer.toStream(doc).then((stream) => { - stream.pipe(fs.createWriteStream("My Document.docx")); -}); +const stream = Packer.toStream(doc); +stream.pipe(fs.createWriteStream("My Document.docx")); diff --git a/src/export/packer/next-compiler.spec.ts b/src/export/packer/next-compiler.spec.ts index 3cd56c211f..2daac3460a 100644 --- a/src/export/packer/next-compiler.spec.ts +++ b/src/export/packer/next-compiler.spec.ts @@ -25,7 +25,7 @@ describe("Compiler", () => { }); describe("#compile()", () => { - it("should pack all the content", async function () { + it("should pack all the content", function () { this.timeout(99999999); const file = new File({ sections: [], @@ -53,7 +53,7 @@ describe("Compiler", () => { expect(fileNames).to.include("_rels/.rels"); }); - it("should pack all additional headers and footers", async function () { + it("should pack all additional headers and footers", function () { const file = new File({ sections: [ { diff --git a/src/export/packer/packer.spec.ts b/src/export/packer/packer.spec.ts index 9dd5d55021..7055db1e06 100644 --- a/src/export/packer/packer.spec.ts +++ b/src/export/packer/packer.spec.ts @@ -54,7 +54,7 @@ describe("Packer", () => { assert.isTrue(buffer.byteLength > 0); }); - it("should handle exception if it throws any", async () => { + it("should handle exception if it throws any", () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any const compiler = stub((Packer as any).compiler, "compile"); @@ -139,7 +139,7 @@ describe("Packer", () => { const stream = await Packer.toStream(file); return new Promise((resolve, reject) => { stream.on("error", () => { - reject(); + reject(new Error()); }); stream.on("end", () => { @@ -148,7 +148,7 @@ describe("Packer", () => { }); }); - it("should handle exception if it throws any", async () => { + it("should handle exception if it throws any", () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any const compiler = stub((Packer as any).compiler, "compile").callsFake(() => ({ // tslint:disable-next-line: no-empty @@ -160,9 +160,11 @@ describe("Packer", () => { })); compiler.throwsException(); - return Packer.toStream(file).catch((error) => { + try { + Packer.toStream(file); + } catch (error) { assert.isDefined(error); - }); + } }); afterEach(() => { diff --git a/src/export/packer/packer.ts b/src/export/packer/packer.ts index 9e230fda86..523d0226aa 100644 --- a/src/export/packer/packer.ts +++ b/src/export/packer/packer.ts @@ -58,7 +58,7 @@ export class Packer { return zipData; } - public static async toStream(file: File, prettify?: boolean | PrettifyType): Promise { + public static toStream(file: File, prettify?: boolean | PrettifyType): Stream { const zip = this.compiler.compile(file, prettify); const zipData = zip.generateNodeStream({ type: "nodebuffer", diff --git a/src/file/custom-properties/custom-properties.ts b/src/file/custom-properties/custom-properties.ts index 8c15db148f..c85a02ef74 100644 --- a/src/file/custom-properties/custom-properties.ts +++ b/src/file/custom-properties/custom-properties.ts @@ -33,6 +33,7 @@ export class CustomProperties extends XmlComponent { } public addCustomProperty(property: ICustomPropertyOptions): void { + // eslint-disable-next-line functional/immutable-data this.properties.push(new CustomProperty(this.nextId++, property)); } } diff --git a/src/file/file.ts b/src/file/file.ts index aa1b1c64e1..0f170d7d7f 100644 --- a/src/file/file.ts +++ b/src/file/file.ts @@ -37,13 +37,13 @@ export interface ISectionOptions { } export class File { - // eslint-disable-next-line functional/immutable-data + // eslint-disable-next-line functional/prefer-readonly-type private currentRelationshipId: number = 1; private readonly documentWrapper: DocumentWrapper; - // eslint-disable-next-line functional/immutable-data + // eslint-disable-next-line functional/prefer-readonly-type private readonly headers: IDocumentHeader[] = []; - // eslint-disable-next-line functional/immutable-data + // eslint-disable-next-line functional/prefer-readonly-type private readonly footers: IDocumentFooter[] = []; private readonly coreProperties: CoreProperties; private readonly numbering: Numbering; @@ -128,7 +128,7 @@ export class File { } if (options.footnotes) { - // tslint:disable-next-line: forin + // eslint-disable-next-line guard-for-in for (const key in options.footnotes) { this.footnotesWrapper.View.createFootNote(parseFloat(key), options.footnotes[key].children); } @@ -156,6 +156,7 @@ export class File { } private createHeader(header: Header): HeaderWrapper { + // eslint-disable-next-line functional/immutable-data const wrapper = new HeaderWrapper(this.media, this.currentRelationshipId++); for (const child of header.options.children) { @@ -167,6 +168,7 @@ export class File { } private createFooter(footer: Footer): FooterWrapper { + // eslint-disable-next-line functional/immutable-data const wrapper = new FooterWrapper(this.media, this.currentRelationshipId++); for (const child of footer.options.children) { @@ -178,6 +180,7 @@ export class File { } private addHeaderToDocument(header: HeaderWrapper, type: HeaderFooterReferenceType = HeaderFooterReferenceType.DEFAULT): void { + // eslint-disable-next-line functional/immutable-data this.headers.push({ header, type }); this.documentWrapper.Relationships.createRelationship( header.View.ReferenceId, @@ -188,6 +191,7 @@ export class File { } private addFooterToDocument(footer: FooterWrapper, type: HeaderFooterReferenceType = HeaderFooterReferenceType.DEFAULT): void { + // eslint-disable-next-line functional/immutable-data this.footers.push({ footer, type }); this.documentWrapper.Relationships.createRelationship( footer.View.ReferenceId, @@ -220,26 +224,31 @@ export class File { ); this.documentWrapper.Relationships.createRelationship( + // eslint-disable-next-line functional/immutable-data this.currentRelationshipId++, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles", "styles.xml", ); this.documentWrapper.Relationships.createRelationship( + // eslint-disable-next-line functional/immutable-data this.currentRelationshipId++, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering", "numbering.xml", ); this.documentWrapper.Relationships.createRelationship( + // eslint-disable-next-line functional/immutable-data this.currentRelationshipId++, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes", "footnotes.xml", ); this.documentWrapper.Relationships.createRelationship( + // eslint-disable-next-line functional/immutable-data this.currentRelationshipId++, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings", "settings.xml", ); this.documentWrapper.Relationships.createRelationship( + // eslint-disable-next-line functional/immutable-data this.currentRelationshipId++, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments", "comments.xml", diff --git a/src/file/header.ts b/src/file/header.ts index d9dd2166f5..76f008ed76 100644 --- a/src/file/header.ts +++ b/src/file/header.ts @@ -6,13 +6,17 @@ export interface IHeaderOptions { } export class Header { - public constructor(public readonly options: IHeaderOptions = { children: [] }) { - // noop + public readonly options: IHeaderOptions; + + public constructor(options: IHeaderOptions = { children: [] }) { + this.options = options; } } export class Footer { - public constructor(public readonly options: IHeaderOptions = { children: [] }) { - // noop + public readonly options: IHeaderOptions; + + public constructor(options: IHeaderOptions = { children: [] }) { + this.options = options; } } diff --git a/src/file/media/media.spec.ts b/src/file/media/media.spec.ts index 79f6591888..9886fa811f 100644 --- a/src/file/media/media.spec.ts +++ b/src/file/media/media.spec.ts @@ -37,6 +37,7 @@ describe("Media", () => { }); it("should return UInt8Array if atob is present", () => { + // eslint-disable-next-line functional/immutable-data global.atob = () => "atob result"; const image = new Media().addMedia("", { @@ -45,11 +46,12 @@ describe("Media", () => { }); expect(image.stream).to.be.an.instanceof(Uint8Array); - // tslint:disable-next-line: no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, functional/immutable-data (global as any).atob = undefined; }); it("should use data as is if its not a string", () => { + // eslint-disable-next-line functional/immutable-data global.atob = () => "atob result"; const image = new Media().addMedia(Buffer.from(""), { @@ -58,7 +60,7 @@ describe("Media", () => { }); expect(image.stream).to.be.an.instanceof(Uint8Array); - // tslint:disable-next-line: no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, functional/immutable-data (global as any).atob = undefined; }); }); diff --git a/src/file/numbering/numbering.spec.ts b/src/file/numbering/numbering.spec.ts index fb81a17e2b..71540f8691 100644 --- a/src/file/numbering/numbering.spec.ts +++ b/src/file/numbering/numbering.spec.ts @@ -34,13 +34,14 @@ describe("Numbering", () => { .filter((el) => el["w:lvl"]) .forEach((el, ix) => { expect(Object.keys(el)).to.have.lengthOf(1); - expect(Object.keys(el["w:lvl"]).sort()).to.deep.equal(["_attr", "w:start", "w:lvlJc", "w:numFmt", "w:pPr", "w:rPr"]); + expect(Object.keys(el["w:lvl"])).to.deep.equal(["_attr", "w:start", "w:lvlJc", "w:numFmt", "w:pPr", "w:rPr"]); expect(el["w:lvl"]).to.have.deep.members([ { _attr: { "w:ilvl": ix, "w15:tentative": 1 } }, { "w:start": [{ _attr: { "w:val": 1 } }] }, { "w:lvlJc": [{ _attr: { "w:val": "left" } }] }, { "w:numFmt": [{ _attr: { "w:val": "bullet" } }] }, ]); + // TODO // Once chai 4.0.0 lands and #644 is resolved, we can add the following to the test: // {"w:lvlText": {"_attr": {"w:val": "•"}}}, // {"w:rPr": [{"w:rFonts": {"_attr": {"w:ascii": "Symbol", "w:cs": "Symbol", "w:eastAsia": "Symbol", "w:hAnsi": "Symbol", "w:hint": "default"}}}]}, diff --git a/src/file/paragraph/run/image-run.spec.ts b/src/file/paragraph/run/image-run.spec.ts index 7887d4b0cd..c59ddd1ff4 100644 --- a/src/file/paragraph/run/image-run.spec.ts +++ b/src/file/paragraph/run/image-run.spec.ts @@ -771,7 +771,7 @@ describe("ImageRun", () => { ], }); - // tslint:disable-next-line: no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, functional/immutable-data (global as any).atob = undefined; }); @@ -1028,7 +1028,7 @@ describe("ImageRun", () => { ], }); - // tslint:disable-next-line: no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, functional/immutable-data (global as any).atob = undefined; }); }); diff --git a/src/file/xml-components/imported-xml-component.ts b/src/file/xml-components/imported-xml-component.ts index 5385e8a9b6..aad5719f52 100644 --- a/src/file/xml-components/imported-xml-component.ts +++ b/src/file/xml-components/imported-xml-component.ts @@ -1,4 +1,3 @@ -// eslint-disable @typescript-eslint/no-explicit-any import { Element as XmlElement, xml2js } from "xml-js"; import { IXmlableObject, XmlAttributeComponent, XmlComponent } from "@file/xml-components"; @@ -15,7 +14,9 @@ export const convertToXmlComponent = (element: XmlElement): ImportedXmlComponent switch (element.type) { case undefined: case "element": + // eslint-disable-next-line no-case-declarations const xmlComponent = new ImportedXmlComponent(element.name as string, element.attributes); + // eslint-disable-next-line no-case-declarations const childElements = element.elements || []; for (const childElm of childElements) { const child = convertToXmlComponent(childElm); @@ -31,6 +32,7 @@ export const convertToXmlComponent = (element: XmlElement): ImportedXmlComponent } }; +// eslint-disable-next-line @typescript-eslint/no-explicit-any class ImportedXmlComponentAttributes extends XmlAttributeComponent { // noop } @@ -54,7 +56,7 @@ export class ImportedXmlComponent extends XmlComponent { * @param importedContent xml content of the imported component */ - // tslint:disable-next-line:variable-name + // eslint-disable-next-line @typescript-eslint/no-explicit-any public constructor(rootKey: string, _attr?: any) { super(rootKey); if (_attr) { @@ -71,7 +73,7 @@ export class ImportedXmlComponent extends XmlComponent { * Used for the attributes of root element that is being imported. */ export class ImportedRootElementAttributes extends XmlComponent { - // tslint:disable-next-line:variable-name + // eslint-disable-next-line @typescript-eslint/no-explicit-any public constructor(private readonly _attr: any) { super(""); } diff --git a/src/util/values.ts b/src/util/values.ts index fa666bd084..f44e2eb1d9 100644 --- a/src/util/values.ts +++ b/src/util/values.ts @@ -32,7 +32,7 @@ export const unsignedDecimalNumber = (val: number): number => { // http://www.datypic.com/sc/xsd/t-xsd_hexBinary.html const hexBinary = (val: string, length: number): string => { const expectedLength = length * 2; - if (val.length !== expectedLength || isNaN(Number("0x" + val))) { + if (val.length !== expectedLength || isNaN(Number(`0x${val}`))) { throw new Error(`Invalid hex value '${val}'. Expected ${expectedLength} digit hex value`); } return val;