diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000000..51d510ae68 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,51 @@ +{ + "version": "2.0.0", + "isBackground": false, + "presentation": { + "reveal": "always", + "panel": "new" + }, + "env": { + "DEBUG": "*", + "NODE_DEBUG": "1", + "NODE_ENV": "development" + }, + "tasks": [ + { + "label": "build", + "group": "build", + "type": "shell", + "command": "npm", + "args": [ + "run", + "build" + ], + "problemMatcher": [ + "$tsc", + "$eslint-stylish" + ], + "presentation": { + "reveal": "always", + "panel": "shared" + } + }, + { + "label": "lint", + "group": "build", + "type": "shell", + "command": "npm", + "args": [ + "run", + "lint" + ], + "problemMatcher": [ + "$tsc", + "$eslint-stylish" + ], + "presentation": { + "reveal": "always", + "panel": "shared" + } + } + ] +} diff --git a/package-lock.json b/package-lock.json index bda248ac4e..08aa952130 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2836,6 +2836,15 @@ } } }, + "caller-id": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/caller-id/-/caller-id-0.1.0.tgz", + "integrity": "sha1-Wb2sCJPRLDhxQIJ5Ix+XRYNk8Hs=", + "dev": true, + "requires": { + "stack-trace": "~0.0.7" + } + }, "caller-path": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", @@ -9739,6 +9748,15 @@ } } }, + "mock-require": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/mock-require/-/mock-require-2.0.2.tgz", + "integrity": "sha1-HqpxqtIwE3c9En3H6Ro/u0g31g0=", + "dev": true, + "requires": { + "caller-id": "^0.1.0" + } + }, "moment": { "version": "2.24.0", "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", @@ -15440,6 +15458,12 @@ "safe-buffer": "^5.1.1" } }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "dev": true + }, "stack-utils": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz", @@ -16723,6 +16747,15 @@ } } }, + "tslint-language-service": { + "version": "0.9.9", + "resolved": "https://registry.npmjs.org/tslint-language-service/-/tslint-language-service-0.9.9.tgz", + "integrity": "sha1-9UbcOEg5eeb7PPpZWErYUls61No=", + "dev": true, + "requires": { + "mock-require": "^2.0.2" + } + }, "tsutils": { "version": "2.29.0", "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", diff --git a/package.json b/package.json index 501d00d8a1..25622b796b 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "build": "cross-env NODE_ENV=production webpack --config webpack.config.js && ncp src/package.json dist/package.json", "build:dev:main": "webpack --config webpack.config.main.js", "start": "npm run build && cross-env DEBUG=r2:*,readium-desktop:* electron .", - "lint:ts": "tslint './src/**/*.ts' './src/**/*.tsx'", + "lint:ts": "tslint --project tsconfig.json -c tslint.json './src/**/*.ts' './src/**/*.tsx' './test/**/*.ts' './test/**/*.tsx'", "lint:editorconfig": "eclint check '**/*' '!.vscode/**/*' '!.git/**/*' '!node_modules/**/*' '!resources/**/*' '!src/renderer/assets/**/*' '!dist/**/*' '!**/.DS_Store' '!src/typings/en.translation.d.ts'", "lint": "npm run lint:editorconfig && npm run lint:ts", "start:dev:renderer-reader": "concurrently --kill-others \"npm run start:dev:renderer\" \"npm run start:dev:reader\"", @@ -270,6 +270,7 @@ "svg-sprite-loader": "^3.9.2", "ts-jest": "^23.10.5", "tslint": "^5.16.0", + "tslint-language-service": "^0.9.9", "typescript": "^3.4.3", "webpack": "^4.30.0", "webpack-cli": "^3.1.2", diff --git a/src/common/errors.ts b/src/common/errors.ts index 37294359a1..c0fb3c44ad 100644 --- a/src/common/errors.ts +++ b/src/common/errors.ts @@ -5,8 +5,17 @@ // that can be found in the LICENSE file exposed on Github (readium) in the project repository. // ==LICENSE-END== -export class CodeError extends Error { - public static fromJson(json: any): CodeError { +export interface CodeMessage { + code: number | string; + message: string; +} + +export interface CodeMessageWithClass extends CodeMessage { + class: string; +} + +export class CodeError extends Error implements CodeMessage { + public static fromJson(json: CodeMessage): CodeError { return new CodeError( json.code, json.message, @@ -22,7 +31,7 @@ export class CodeError extends Error { this.message = message; } - public toJson() { + public toJson(): CodeMessageWithClass { return { class: "CodeError", code: this.code, diff --git a/src/common/ipc/sync.ts b/src/common/ipc/sync.ts index 00af4025fa..ba41d42622 100644 --- a/src/common/ipc/sync.ts +++ b/src/common/ipc/sync.ts @@ -9,9 +9,21 @@ * Synchronization of redux actions */ +import { Action } from "../models/redux"; + +import { WindowSender } from "../models/sync"; + export enum EventType { RendererAction = "RENDERER_ACTION", MainAction = "MAIN_ACTION", } export const CHANNEL = "SYNC"; + +export interface EventPayload { + type: EventType; + payload: { + action: Action; + }; + sender: WindowSender; +} diff --git a/src/common/ipc/win.ts b/src/common/ipc/win.ts index 387c9d9423..c82c40dfce 100644 --- a/src/common/ipc/win.ts +++ b/src/common/ipc/win.ts @@ -11,3 +11,10 @@ export enum EventType { } export const CHANNEL = "WIN"; + +export interface EventPayload { + type: EventType; + payload: { + winId: string; + }; +} diff --git a/src/common/models/ipc.ts b/src/common/models/ipc.ts index 6a377cc205..7c3d9834ec 100644 --- a/src/common/models/ipc.ts +++ b/src/common/models/ipc.ts @@ -9,14 +9,6 @@ import { Catalog } from "./catalog"; import { Download } from "./download"; import { Publication } from "./publication"; -interface LibraryImportMessage { - paths: string[]; // List of files to import -} - -interface UIMessage { - message: string; -} - export interface UrlMessage { url: string; } diff --git a/src/common/models/publication.ts b/src/common/models/publication.ts index 14fb6a2cb2..b91d968975 100644 --- a/src/common/models/publication.ts +++ b/src/common/models/publication.ts @@ -7,7 +7,6 @@ import { Contributor } from "./contributor"; import { CustomCover } from "./custom-cover"; -import { Downloadable } from "./downloadable"; import { File } from "./file"; import { Identifiable } from "./identifiable"; import { Language } from "./language"; diff --git a/src/common/models/sync.ts b/src/common/models/sync.ts index 89fe935a51..199d078a9a 100644 --- a/src/common/models/sync.ts +++ b/src/common/models/sync.ts @@ -5,7 +5,18 @@ // that can be found in the LICENSE file exposed on Github (readium) in the project repository. // ==LICENSE-END== +import { Action } from "redux"; + export enum SenderType { Main, // Main process Renderer, // Renderer process } + +export interface WindowSender { + type: SenderType; + winId: string; +} + +export interface ActionWithSender extends Action { + sender: WindowSender; +} diff --git a/src/common/redux/actions/i18n.ts b/src/common/redux/actions/i18n.ts index b77d71418a..04b2372e1f 100644 --- a/src/common/redux/actions/i18n.ts +++ b/src/common/redux/actions/i18n.ts @@ -11,7 +11,15 @@ export enum ActionType { Set = "LOCALE_SET", } -export function setLocale(locale: string): Action { +export interface PayloadLocale { + locale: string; +} + +export interface ActionLocale extends Action { + payload: PayloadLocale; +} + +export function setLocale(locale: string): ActionLocale { return { type: ActionType.Set, payload: { diff --git a/src/common/redux/reducers/i18n.ts b/src/common/redux/reducers/i18n.ts index 7ff1fe585f..332e3cb2d8 100644 --- a/src/common/redux/reducers/i18n.ts +++ b/src/common/redux/reducers/i18n.ts @@ -5,8 +5,6 @@ // that can be found in the LICENSE file exposed on Github (readium) in the project repository. // ==LICENSE-END== -import { Action } from "readium-desktop/common/models/redux"; - import { i18nActions } from "readium-desktop/common/redux/actions"; import { I18NState } from "readium-desktop/common/redux/states/i18n"; @@ -17,13 +15,13 @@ const initialState: I18NState = { export function i18nReducer( state: I18NState = initialState, - action: Action, + action: i18nActions.ActionLocale, ): I18NState { switch (action.type) { case i18nActions.ActionType.Set: return Object.assign({}, state, { locale: action.payload.locale, - }); + } as I18NState); default: return state; } diff --git a/src/common/services/opds.ts b/src/common/services/opds.ts index 440f8b18d1..f25c9eb2d8 100644 --- a/src/common/services/opds.ts +++ b/src/common/services/opds.ts @@ -29,7 +29,7 @@ export class OPDSParser { /** * Parse OPDS feed and returns a catalog */ - public parse(opdsFeed: string): Promise { + public async parse(opdsFeed: string): Promise { return this.parser .parse(opdsFeed) .then((feed: AcquisitionFeed) => { diff --git a/src/common/services/serializer.ts b/src/common/services/serializer.ts index b469df6fa0..37e27fb2d8 100644 --- a/src/common/services/serializer.ts +++ b/src/common/services/serializer.ts @@ -9,23 +9,25 @@ import { injectable} from "inversify"; import { CodeError } from "readium-desktop/common/errors"; +import { Action } from "../models/redux"; + @injectable() export class ActionSerializer { - public serialize(action: any) { + public serialize(action: Action): Action { if (action.error && action.payload instanceof CodeError) { return Object.assign( {}, action, { - payload: action.payload.toJson(), - }, + payload: (action.payload as CodeError).toJson(), + } as Action, ); } else { return action; } } - public deserialize(json: any): any { + public deserialize(json: Action): Action { if (json.error && json.payload && json.payload.class && @@ -35,11 +37,11 @@ export class ActionSerializer { {}, json, { - payload: new CodeError( - json.payload.code, - json.payload.message, - ), - }, + payload: CodeError.fromJson({ + code: json.payload.code, + message: json.payload.message, + }), + } as Action, ); } else { return json; diff --git a/src/common/utils/http.ts b/src/common/utils/http.ts index ca15ee2c66..6fc362d56b 100644 --- a/src/common/utils/http.ts +++ b/src/common/utils/http.ts @@ -12,14 +12,17 @@ import { Store } from "redux"; import * as request from "request"; import { promisify } from "util"; +type TRequestCoreOptionsRequiredUriUrl = request.CoreOptions & request.RequiredUriUrl; +type TRequestCoreOptionsOptionalUriUrl = request.CoreOptions & request.OptionalUriUrl; + /** * @param url url of your GET request * @param options request options * @returns body of url response. 'String' type returned in many cases except for options.json = true */ // tslint:disable-next-line: max-line-length -export async function httpGet(url: string, options?: request.CoreOptions): Promise { - options = options || {}; +export async function httpGet(url: string, options?: TRequestCoreOptionsOptionalUriUrl): Promise { + options = options || {} as TRequestCoreOptionsOptionalUriUrl; options.headers = options.headers || {}; const headerFromOptions = {}; @@ -44,8 +47,11 @@ export async function httpGet(url: string, encoding: undefined, headers, }, - ); - const response = await promisify(request)(requestOptions); + ) as TRequestCoreOptionsRequiredUriUrl; + + const promisifiedRequest = promisify(request); + const response = await promisifiedRequest(requestOptions); + if (!response) { throw new Error(`No HTTP response?! ${url}`); } diff --git a/src/index_app.ts b/src/index_app.ts index 5cd91b9142..17e6397000 100644 --- a/src/index_app.ts +++ b/src/index_app.ts @@ -7,8 +7,6 @@ import "font-awesome/css/font-awesome.css"; -import * as path from "path"; - import { ipcRenderer } from "electron"; import * as React from "react"; import * as ReactDOM from "react-dom"; @@ -33,7 +31,7 @@ import { // import { setLcpNativePluginPath } from "@r2-lcp-js/parser/epub/lcp"; -import { SenderType } from "readium-desktop/common/models/sync"; +import { ActionWithSender } from "readium-desktop/common/models/sync"; import { ActionSerializer } from "readium-desktop/common/services/serializer"; @@ -68,7 +66,7 @@ store.subscribe(() => { } }); -ipcRenderer.on(winIpc.CHANNEL, (_0: any, data: any) => { +ipcRenderer.on(winIpc.CHANNEL, (_0: any, data: winIpc.EventPayload) => { switch (data.type) { case winIpc.EventType.IdResponse: // Initialize window @@ -78,7 +76,7 @@ ipcRenderer.on(winIpc.CHANNEL, (_0: any, data: any) => { }); // Request main process for a new id -ipcRenderer.on(syncIpc.CHANNEL, (_0: any, data: any) => { +ipcRenderer.on(syncIpc.CHANNEL, (_0: any, data: syncIpc.EventPayload) => { const actionSerializer = container.get("action-serializer") as ActionSerializer; switch (data.type) { @@ -87,7 +85,7 @@ ipcRenderer.on(syncIpc.CHANNEL, (_0: any, data: any) => { store.dispatch(Object.assign( {}, actionSerializer.deserialize(data.payload.action), - {sender: data.sender}, + {sender: data.sender} as ActionWithSender, )); break; } diff --git a/src/index_reader.ts b/src/index_reader.ts index eaae555053..f8806ef1dc 100644 --- a/src/index_reader.ts +++ b/src/index_reader.ts @@ -8,8 +8,6 @@ import "font-awesome/css/font-awesome.css"; import "react-dropdown/style.css"; -import * as path from "path"; - import { ipcRenderer } from "electron"; import * as React from "react"; import * as ReactDOM from "react-dom"; @@ -34,10 +32,12 @@ import { // import { setLcpNativePluginPath } from "@r2-lcp-js/parser/epub/lcp"; -import { SenderType } from "readium-desktop/common/models/sync"; +import { ActionWithSender } from "readium-desktop/common/models/sync"; import { ActionSerializer } from "readium-desktop/common/services/serializer"; +import { EventPayload } from "./common/ipc/sync"; + initGlobalConverters_OPDS(); initGlobalConverters_SHARED(); initGlobalConverters_GENERIC(); @@ -70,7 +70,7 @@ store.subscribe(() => { } }); -ipcRenderer.on(winIpc.CHANNEL, (_0: any, data: any) => { +ipcRenderer.on(winIpc.CHANNEL, (_0: any, data: winIpc.EventPayload) => { switch (data.type) { case winIpc.EventType.IdResponse: // Initialize window @@ -80,7 +80,7 @@ ipcRenderer.on(winIpc.CHANNEL, (_0: any, data: any) => { }); // Request main process for a new id -ipcRenderer.on(syncIpc.CHANNEL, (_0: any, data: any) => { +ipcRenderer.on(syncIpc.CHANNEL, (_0: any, data: EventPayload) => { const actionSerializer = container.get("action-serializer") as ActionSerializer; switch (data.type) { @@ -89,7 +89,7 @@ ipcRenderer.on(syncIpc.CHANNEL, (_0: any, data: any) => { store.dispatch(Object.assign( {}, actionSerializer.deserialize(data.payload.action), - {sender: data.sender}, + {sender: data.sender} as ActionWithSender, )); break; } diff --git a/src/main.ts b/src/main.ts index dbe660efa4..86cdaa7a38 100644 --- a/src/main.ts +++ b/src/main.ts @@ -25,15 +25,17 @@ import { initGlobalConverters_GENERIC, initGlobalConverters_SHARED, } from "@r2-shared-js/init-globals"; +import { ActionWithSender } from "readium-desktop/common/models/sync"; + if (_PACKAGING !== "0") { // Disable debug in packaged app delete process.env.DEBUG; debug_.disable(); - console.log = (message?: any, ...optionalParams: any[]) => { return; }; - console.warn = (message?: any, ...optionalParams: any[]) => { return; }; - console.error = (message?: any, ...optionalParams: any[]) => { return; }; - console.info = (message?: any, ...optionalParams: any[]) => { return; }; + console.log = (_message?: any, ..._optionalParams: any[]) => { return; }; + console.warn = (_message?: any, ..._optionalParams: any[]) => { return; }; + console.error = (_message?: any, ..._optionalParams: any[]) => { return; }; + console.info = (_message?: any, ..._optionalParams: any[]) => { return; }; } // Logger @@ -87,7 +89,7 @@ function main() { }); app.on("will-finish-launching", () => { - app.on("open-url", (event: any, url: any) => { + app.on("open-url", (event: any, _url: any) => { event.preventDefault(); // Process url: import or open? }); @@ -101,7 +103,7 @@ function main() { }); // Listen to renderer action - ipcMain.on(syncIpc.CHANNEL, (_0: any, data: any) => { + ipcMain.on(syncIpc.CHANNEL, (_0: any, data: syncIpc.EventPayload) => { const store = container.get("store") as Store; const actionSerializer = container.get("action-serializer") as ActionSerializer; @@ -111,7 +113,7 @@ function main() { store.dispatch(Object.assign( {}, actionSerializer.deserialize(data.payload.action), - { sender: data.sender }, + { sender: data.sender } as ActionWithSender, )); break; } diff --git a/src/main/api/catalog.ts b/src/main/api/catalog.ts index 881be005ed..a0f239fba1 100644 --- a/src/main/api/catalog.ts +++ b/src/main/api/catalog.ts @@ -26,19 +26,19 @@ export const CATALOG_CONFIG_ID = "catalog"; @injectable() export class CatalogApi { @inject("publication-repository") - private publicationRepository: PublicationRepository; + private readonly publicationRepository!: PublicationRepository; @inject("config-repository") - private configRepository: ConfigRepository; + private readonly configRepository!: ConfigRepository; @inject("locator-repository") - private locatorRepository: LocatorRepository; + private readonly locatorRepository!: LocatorRepository; @inject("publication-view-converter") - private publicationViewConverter: PublicationViewConverter; + private readonly publicationViewConverter!: PublicationViewConverter; @inject("translator") - private translator: Translator; + private readonly translator!: Translator; public async get(): Promise { const __ = this.translator.translate.bind(this.translator); diff --git a/src/main/api/lcp.ts b/src/main/api/lcp.ts index c00032b274..7c5b30f3b0 100644 --- a/src/main/api/lcp.ts +++ b/src/main/api/lcp.ts @@ -18,13 +18,13 @@ import { PublicationRepository } from "readium-desktop/main/db/repository/public @injectable() export class LcpApi { @inject("store") - private store: Store; + private readonly store!: Store; @inject("publication-repository") - private publicationRepository: PublicationRepository; + private readonly publicationRepository!: PublicationRepository; @inject("lcp-manager") - private lcpManager: LcpManager; + private readonly lcpManager!: LcpManager; public async renewPublicationLicense(data: any): Promise { const { publication } = data; diff --git a/src/main/api/opds.ts b/src/main/api/opds.ts index 8f22b7d6b9..9555647566 100644 --- a/src/main/api/opds.ts +++ b/src/main/api/opds.ts @@ -13,37 +13,28 @@ import * as xmldom from "xmldom"; import { convertOpds1ToOpds2, - convertOpds1ToOpds2_EntryToPublication, } from "@r2-opds-js/opds/converter"; import { OPDS } from "@r2-opds-js/opds/opds1/opds"; -import { Entry } from "@r2-opds-js/opds/opds1/opds-entry"; import { OPDSFeed } from "@r2-opds-js/opds/opds2/opds2"; -import { OPDSPublication } from "@r2-opds-js/opds/opds2/opds2-publication"; import { XML } from "@r2-utils-js/_utils/xml-js-mapper"; -import { OpdsFeedView } from "readium-desktop/common/views/opds"; +import { OpdsFeedView, OpdsResultView } from "readium-desktop/common/views/opds"; import { OpdsFeedViewConverter } from "readium-desktop/main/converter/opds"; import { OpdsFeedRepository } from "readium-desktop/main/db/repository/opds"; import { httpGet } from "readium-desktop/common/utils/http"; -import { OpdsParsingError } from "readium-desktop/main/exceptions/opds"; @injectable() export class OpdsApi { - private opdsFeedRepository: OpdsFeedRepository; - private opdsFeedViewConverter: OpdsFeedViewConverter; - - constructor( - @inject("opds-feed-repository") opdsFeedRepository: OpdsFeedRepository, - @inject("opds-feed-view-converter") opdsFeedViewConverter: OpdsFeedViewConverter, - ) { - this.opdsFeedRepository = opdsFeedRepository; - this.opdsFeedViewConverter = opdsFeedViewConverter; - } + @inject("opds-feed-repository") + private readonly opdsFeedRepository!: OpdsFeedRepository; + + @inject("opds-feed-view-converter") + private readonly opdsFeedViewConverter!: OpdsFeedViewConverter; public async getFeed(data: any): Promise { const { identifier } = data; @@ -73,10 +64,10 @@ export class OpdsApi { return this.opdsFeedViewConverter.convertDocumentToView(doc); } - public async browse(data: any): Promise { + public async browse(data: any): Promise { const { url } = data; const opdsFeedData = await httpGet(url); - let opds2Publication: OPDSPublication = null; + // let opds2Publication: OPDSPublication = null; let opds2Feed: OPDSFeed = null; // This is an opds feed in version 1 @@ -92,12 +83,14 @@ export class OpdsApi { const isEntry = xmlDom.documentElement.localName === "entry"; if (isEntry) { - const opds1Entry = XML.deserialize(xmlDom, Entry); - opds2Publication = convertOpds1ToOpds2_EntryToPublication(opds1Entry); + // const opds1Entry = XML.deserialize(xmlDom, Entry); + // opds2Publication = convertOpds1ToOpds2_EntryToPublication(opds1Entry); } else { const opds1Feed = XML.deserialize(xmlDom, OPDS); opds2Feed = convertOpds1ToOpds2(opds1Feed); return this.opdsFeedViewConverter.convertOpdsFeedToView(opds2Feed); } + + return Promise.reject("OPDS API browse nil"); } } diff --git a/src/main/api/publication.ts b/src/main/api/publication.ts index afd26365ed..04b3049988 100644 --- a/src/main/api/publication.ts +++ b/src/main/api/publication.ts @@ -25,19 +25,14 @@ import { open } from "readium-desktop/common/redux/actions/toast"; @injectable() export class PublicationApi { - private publicationRepository: PublicationRepository; - private publicationViewConverter: PublicationViewConverter; - private catalogService: CatalogService; - - constructor( - @inject("publication-repository") publicationRepository: PublicationRepository, - @inject("publication-view-converter") publicationViewConverter: PublicationViewConverter, - @inject("catalog-service") catalogService: CatalogService, - ) { - this.publicationRepository = publicationRepository; - this.publicationViewConverter = publicationViewConverter; - this.catalogService = catalogService; - } + @inject("publication-repository") + private readonly publicationRepository!: PublicationRepository; + + @inject("publication-view-converter") + private readonly publicationViewConverter!: PublicationViewConverter; + + @inject("catalog-service") + private readonly catalogService!: CatalogService; public async get(data: any): Promise { const { identifier } = data; diff --git a/src/main/api/reader.ts b/src/main/api/reader.ts index 31a184077a..b7ee82042b 100644 --- a/src/main/api/reader.ts +++ b/src/main/api/reader.ts @@ -18,10 +18,10 @@ import { LocatorType } from "readium-desktop/common/models/locator"; @injectable() export class ReaderApi { @inject("locator-repository") - private locatorRepository: LocatorRepository; + private readonly locatorRepository!: LocatorRepository; @inject("locator-view-converter") - private locatorViewConverter: LocatorViewConverter; + private readonly locatorViewConverter!: LocatorViewConverter; public async setLastReadingLocation(data: any): Promise { const { publication, locator } = data; diff --git a/src/main/converter/publication.ts b/src/main/converter/publication.ts index 7f92a636e6..032268dc5c 100644 --- a/src/main/converter/publication.ts +++ b/src/main/converter/publication.ts @@ -13,8 +13,6 @@ import { JSON as TAJSON } from "ta-json-x"; import { Publication as Epub } from "@r2-shared-js/models/publication"; -import { PublicationView } from "readium-desktop/common/views/publication"; - import { convertContributorArrayToStringArray, } from "readium-desktop/common/utils"; diff --git a/src/main/db/repository/base.ts b/src/main/db/repository/base.ts index dc7e6d69b3..20901b296d 100644 --- a/src/main/db/repository/base.ts +++ b/src/main/db/repository/base.ts @@ -5,9 +5,6 @@ // that can be found in the LICENSE file exposed on Github (readium) in the project repository. // ==LICENSE-END== -import { injectable} from "inversify"; - -import * as debug_ from "debug"; import * as moment from "moment"; import * as uuid from "uuid"; diff --git a/src/main/db/repository/publication.ts b/src/main/db/repository/publication.ts index d65cb7cb83..9c6d28ff2a 100644 --- a/src/main/db/repository/publication.ts +++ b/src/main/db/repository/publication.ts @@ -18,8 +18,6 @@ const TAG_INDEX = "tag_index"; const TITLE_INDEX = "title_index"; -const IDENTIFIER_INDEX = "identifier_index"; - import { convertMultiLangStringToString, } from "readium-desktop/common/utils"; diff --git a/src/main/init.ts b/src/main/init.ts index 9c54f4bcd3..15ace2e618 100644 --- a/src/main/init.ts +++ b/src/main/init.ts @@ -25,6 +25,12 @@ import { WinRegistry } from "readium-desktop/main/services/win-registry"; import { PublicationStorage } from "readium-desktop/main/storage/publication-storage"; import { Store } from "redux"; +import { ReaderStateConfig, ReaderStateMode, ReaderStateReader } from "readium-desktop/main/redux/states/reader"; + +import { UpdateState } from "readium-desktop/common/redux/states/update"; + +import { I18NState } from "readium-desktop/common/redux/states/i18n"; + // Logger const debug = debug_("readium-desktop:main"); @@ -40,7 +46,7 @@ const winOpenCallback = (appWindow: AppWindow) => { payload: { winId: appWindow.identifier, }, - }); + } as winIpc.EventPayload); // Init network on window const state = store.getState(); @@ -63,7 +69,7 @@ const winOpenCallback = (appWindow: AppWindow) => { type: netActionType, }, }, - }); + } as syncIpc.EventPayload); // Send reader information webContents.send(syncIpc.CHANNEL, { @@ -73,10 +79,10 @@ const winOpenCallback = (appWindow: AppWindow) => { type: readerActions.ActionType.OpenSuccess, payload: { reader: state.reader.readers[appWindow.identifier], - }, + } as ReaderStateReader, }, }, - }); + } as syncIpc.EventPayload); // Send reader config webContents.send(syncIpc.CHANNEL, { @@ -86,10 +92,10 @@ const winOpenCallback = (appWindow: AppWindow) => { type: readerActions.ActionType.ConfigSetSuccess, payload: { config: state.reader.config, - }, + } as ReaderStateConfig, }, }, - }); + } as syncIpc.EventPayload); // Send reader mode webContents.send(syncIpc.CHANNEL, { @@ -99,10 +105,10 @@ const winOpenCallback = (appWindow: AppWindow) => { type: readerActions.ActionType.ModeSetSuccess, payload: { mode: state.reader.mode, - }, + } as ReaderStateMode, }, }, - }); + } as syncIpc.EventPayload); // Send locale webContents.send(syncIpc.CHANNEL, { @@ -112,10 +118,10 @@ const winOpenCallback = (appWindow: AppWindow) => { type: i18nActions.ActionType.Set, payload: { locale: state.i18n.locale, - }, + } as i18nActions.PayloadLocale, }, }, - }); + } as syncIpc.EventPayload); // Send locale webContents.send(syncIpc.CHANNEL, { @@ -127,10 +133,10 @@ const winOpenCallback = (appWindow: AppWindow) => { status: state.update.status, latestVersion: state.update.latestVersion, latestVersionUrl: state.update.latestVersionUrl, - }, + } as UpdateState, }, }, - }); + } as syncIpc.EventPayload); }; // Callback called when a window is closed @@ -189,14 +195,14 @@ export function initApp() { } else { debug(`error on configRepository.get("i18n")): ${i18nLocale}`); } - }).catch(() => { + }).catch(async () => { const loc = app.getLocale().split("-")[0]; const lang = Object.keys(AvailableLanguages).find((l) => l === loc) || "en"; store.dispatch(setLocale(lang)); try { - configRepository.save({ + await configRepository.save({ identifier: "i18n", - value: { locale: lang }, + value: { locale: lang } as I18NState, }); } catch (e) { debug("error in save locale", e); diff --git a/src/main/redux/middleware/sync.ts b/src/main/redux/middleware/sync.ts index 4689d4c2a9..a47fa9ca7a 100644 --- a/src/main/redux/middleware/sync.ts +++ b/src/main/redux/middleware/sync.ts @@ -5,7 +5,7 @@ // that can be found in the LICENSE file exposed on Github (readium) in the project repository. // ==LICENSE-END== -import { Store } from "redux"; +import { AnyAction, Dispatch, Middleware, MiddlewareAPI } from "redux"; import { syncIpc } from "readium-desktop/common/ipc"; import { @@ -23,10 +23,12 @@ import { WinRegistry } from "readium-desktop/main/services/win-registry"; import { ActionSerializer } from "readium-desktop/common/services/serializer"; -import { SenderType } from "readium-desktop/common/models/sync"; +import { ActionWithSender, SenderType } from "readium-desktop/common/models/sync"; import * as debug_ from "debug"; +import { AppWindow } from "readium-desktop/common/models/win"; + const debug = debug_("readium-desktop:sync"); // Actions that can be synchronized @@ -60,8 +62,13 @@ const SYNCHRONIZABLE_ACTIONS: any = [ toastActions.ActionType.OpenRequest, ]; -export const reduxSyncMiddleware = (store: Store) => (next: any) => (action: any) => { +export const reduxSyncMiddleware: Middleware + = (_store: MiddlewareAPI>) => + (next: Dispatch) => + ((action: ActionWithSender) => { + debug("### action type", action.type); + // Test if the action must be sent to the rendeder processes if (SYNCHRONIZABLE_ACTIONS.indexOf(action.type) === -1) { // Do not send @@ -75,7 +82,9 @@ export const reduxSyncMiddleware = (store: Store) => (next: any) => (action // Get action serializer const actionSerializer = container.get("action-serializer") as ActionSerializer; - for (const appWindow of Object.values(windows)) { + for (const appWin of Object.values(windows)) { + const appWindow = appWin as AppWindow; + // Notifies renderer process const win = appWindow.win; const winId = appWindow.identifier; @@ -97,11 +106,11 @@ export const reduxSyncMiddleware = (store: Store) => (next: any) => (action sender: { type: SenderType.Main, }, - }); + } as syncIpc.EventPayload); } catch (error) { console.error("Windows does not exist", winId); } } return next(action); -}; +}) as Dispatch; diff --git a/src/main/redux/reducers/reader.ts b/src/main/redux/reducers/reader.ts index 38ea27eb7d..b5fb292c77 100644 --- a/src/main/redux/reducers/reader.ts +++ b/src/main/redux/reducers/reader.ts @@ -5,8 +5,6 @@ // that can be found in the LICENSE file exposed on Github (readium) in the project repository. // ==LICENSE-END== -import * as uuid from "uuid"; - import { Action } from "readium-desktop/common/models/redux"; import { readerActions } from "readium-desktop/common/redux/actions"; diff --git a/src/main/redux/sagas/api.ts b/src/main/redux/sagas/api.ts index 541c068221..75227397c8 100644 --- a/src/main/redux/sagas/api.ts +++ b/src/main/redux/sagas/api.ts @@ -8,11 +8,10 @@ import { container } from "readium-desktop/main/di"; import * as debug_ from "debug"; -import * as moment from "moment"; import { SagaIterator } from "redux-saga"; -import { call, fork, put, select, take } from "redux-saga/effects"; +import { call, fork, put, take } from "redux-saga/effects"; import { apiActions } from "readium-desktop/common/redux/actions"; @@ -40,7 +39,7 @@ export function* processRequest(requestAction: apiActions.ApiAction): SagaIterat export function* requestWatcher() { while (true) { - const action = yield take(apiActions.ActionType.Request); + const action: apiActions.ApiAction = yield take(apiActions.ActionType.Request); yield fork(processRequest, action); } } diff --git a/src/main/redux/sagas/i18n.ts b/src/main/redux/sagas/i18n.ts index 0ee5639a3c..97805453e7 100644 --- a/src/main/redux/sagas/i18n.ts +++ b/src/main/redux/sagas/i18n.ts @@ -11,16 +11,18 @@ import { ConfigRepository } from "readium-desktop/main/db/repository/config"; import { container } from "readium-desktop/main/di"; import { call, take } from "redux-saga/effects"; +import { I18NState } from "readium-desktop/common/redux/states/i18n"; + export function* localeWatcher() { while (true) { - const action = yield take(i18nActions.ActionType.Set); + const action: i18nActions.ActionLocale = yield take(i18nActions.ActionType.Set); const translator = container.get("translator") as Translator; translator.setLocale(action.payload.locale); const configRepository: ConfigRepository = container.get("config-repository") as ConfigRepository; yield call(() => configRepository.save({ identifier: "i18n", - value: { locale: action.payload.locale }, + value: { locale: action.payload.locale } as I18NState, })); } } diff --git a/src/main/redux/sagas/reader.ts b/src/main/redux/sagas/reader.ts index 679be42c66..e810232e44 100644 --- a/src/main/redux/sagas/reader.ts +++ b/src/main/redux/sagas/reader.ts @@ -6,7 +6,7 @@ // ==LICENSE-END== import * as debug_ from "debug"; -import { BrowserWindow, webContents } from "electron"; +import { BrowserWindow } from "electron"; import * as path from "path"; import { LocatorType } from "readium-desktop/common/models/locator"; import { Publication } from "readium-desktop/common/models/publication"; @@ -30,18 +30,11 @@ import { convertHttpUrlToCustomScheme } from "@r2-navigator-js/electron/common/s import { trackBrowserWindow } from "@r2-navigator-js/electron/main/browser-window-tracker"; import { encodeURIComponent_RFC3986 } from "@r2-utils-js/_utils/http/UrlUtils"; +import { ActionWithSender } from "readium-desktop/common/models/sync"; + // Logger const debug = debug_("readium-desktop:main:redux:sagas:reader"); -function openAllDevTools() { - for (const wc of webContents.getAllWebContents()) { - // if (wc.hostWebContents && - // wc.hostWebContents.id === electronBrowserWindow.webContents.id) { - // } - wc.openDevTools(); - } -} - async function openReader(publication: Publication, manifestUrl: string) { debug("create readerWindow"); // Create reader window @@ -369,7 +362,7 @@ export function* readerBookmarkSaveRequestWatcher(): SagaIterator { export function* readerFullscreenRequestWatcher(): SagaIterator { while (true) { // Wait for app initialization - const action = yield take([ + const action: ActionWithSender = yield take([ readerActions.ActionType.FullscreenOffRequest, readerActions.ActionType.FullscreenOnRequest, ]); diff --git a/src/main/redux/sagas/streamer.ts b/src/main/redux/sagas/streamer.ts index 063a26c10f..ec2afba76d 100644 --- a/src/main/redux/sagas/streamer.ts +++ b/src/main/redux/sagas/streamer.ts @@ -32,12 +32,12 @@ import { DialogType } from "readium-desktop/common/models/dialog"; // Logger const debug = debug_("readium-desktop:main:redux:sagas:streamer"); -function startStreamer(streamer: Server): Promise { +async function startStreamer(streamer: Server): Promise { // Find a free port on your local machine return portfinder.getPortPromise() .then(async (port) => { // HTTPS, see secureSessions() - const streamerInfo = await streamer.start(port, true); + await streamer.start(port, true); const streamerUrl = streamer.serverUrl(); debug("Streamer started on %s", streamerUrl); @@ -54,7 +54,7 @@ function stopStreamer(streamer: Server) { export function* startRequestWatcher(): SagaIterator { while (true) { - const action = yield take(streamerActions.ActionType.StartRequest); + yield take(streamerActions.ActionType.StartRequest); const streamer: Server = container.get("streamer") as Server; try { @@ -78,7 +78,7 @@ export function* startRequestWatcher(): SagaIterator { export function* stopRequestWatcher(): SagaIterator { while (true) { - const action = yield take(streamerActions.ActionType.StopRequest); + yield take(streamerActions.ActionType.StopRequest); const streamer: Server = container.get("streamer") as Server; try { diff --git a/src/main/redux/sagas/update.ts b/src/main/redux/sagas/update.ts index 24a9bd470b..2b4f55157d 100644 --- a/src/main/redux/sagas/update.ts +++ b/src/main/redux/sagas/update.ts @@ -6,7 +6,7 @@ // ==LICENSE-END== import { delay, SagaIterator } from "redux-saga"; -import { call, put, select, take } from "redux-saga/effects"; +import { call, put, take } from "redux-saga/effects"; import { httpGet } from "readium-desktop/common/utils/http"; diff --git a/src/main/redux/states/reader.ts b/src/main/redux/states/reader.ts index 700496b097..7c59830ed6 100644 --- a/src/main/redux/states/reader.ts +++ b/src/main/redux/states/reader.ts @@ -9,12 +9,21 @@ import { Reader, ReaderConfig, ReaderMode, } from "readium-desktop/common/models/reader"; -export interface ReaderState { - // Base url of started server - readers: { [identifier: string]: Reader }; +export interface ReaderStateReader { + reader: Reader; +} + +export interface ReaderStateMode { + mode: ReaderMode; +} + +export interface ReaderStateConfig { // Config for all readers config: ReaderConfig; +} - mode: ReaderMode; +export interface ReaderState extends ReaderStateMode, ReaderStateConfig { + // Base url of started server + readers: { [identifier: string]: Reader }; } diff --git a/src/main/services/catalog.ts b/src/main/services/catalog.ts index 59cc26e190..caa625b664 100644 --- a/src/main/services/catalog.ts +++ b/src/main/services/catalog.ts @@ -62,22 +62,17 @@ const debug = debug_("readium-desktop:main#services/catalog"); @injectable() export class CatalogService { - private downloader: Downloader; - private lcpManager: LcpManager; - private publicationStorage: PublicationStorage; - private publicationRepository: PublicationRepository; - - public constructor( - @inject("publication-repository") publicationRepository: PublicationRepository, - @inject("publication-storage") publicationStorage: PublicationStorage, - @inject("downloader") downloader: Downloader, - @inject("lcp-manager") lcpManager: LcpManager, - ) { - this.publicationRepository = publicationRepository; - this.publicationStorage = publicationStorage; - this.downloader = downloader; - this.lcpManager = lcpManager; - } + @inject("downloader") + private readonly downloader!: Downloader; + + @inject("lcp-manager") + private readonly lcpManager!: LcpManager; + + @inject("publication-storage") + private readonly publicationStorage!: PublicationStorage; + + @inject("publication-repository") + private readonly publicationRepository!: PublicationRepository; public async importFile(filePath: string, isLcpFile?: boolean): Promise { const ext = path.extname(filePath); @@ -201,12 +196,14 @@ export class CatalogService { const publicationApi = container.get("publication-api") as PublicationApi; const publication = await publicationApi.get({identifier: publicationIdentifier}); + // tslint:disable-next-line: await-promise await store.dispatch(closeReaderFromPublication(publication)); + // Remove from database await this.publicationRepository.delete(publicationIdentifier); // Remove from storage - await this.publicationStorage.removePublication(publicationIdentifier); + this.publicationStorage.removePublication(publicationIdentifier); } /** diff --git a/src/main/services/device.ts b/src/main/services/device.ts index 9ba35cfa2c..856decd777 100644 --- a/src/main/services/device.ts +++ b/src/main/services/device.ts @@ -7,7 +7,7 @@ import * as uuid from "uuid"; -import { inject, injectable} from "inversify"; +import { injectable } from "inversify"; import { ConfigRepository } from "readium-desktop/main/db/repository/config"; @@ -19,13 +19,13 @@ const DEVICE_ID_PREFIX = "device_id_"; @injectable() export class DeviceIdManager implements IDeviceIDManager { // Config repository - private configRepository: ConfigRepository; + private readonly configRepository: ConfigRepository; - private deviceName: string; + private readonly deviceName: string; public constructor( deviceName: string, - @inject("config-repository") configRepository: ConfigRepository, + configRepository: ConfigRepository, ) { this.deviceName = deviceName; this.configRepository = configRepository; diff --git a/src/main/services/lcp.ts b/src/main/services/lcp.ts index f37436aa7d..c70eecf369 100644 --- a/src/main/services/lcp.ts +++ b/src/main/services/lcp.ts @@ -53,19 +53,19 @@ const debug = debug_("readium-desktop:main#services/lcp"); @injectable() export class LcpManager { @inject("device-id-manager") - private deviceIdManager: DeviceIdManager; + private readonly deviceIdManager!: DeviceIdManager; @inject("publication-storage") - private publicationStorage: PublicationStorage; + private readonly publicationStorage!: PublicationStorage; @inject("publication-repository") - private publicationRepository: PublicationRepository; + private readonly publicationRepository!: PublicationRepository; @inject("lcp-secret-repository") - private lcpSecretRepository: LcpSecretRepository; + private readonly lcpSecretRepository!: LcpSecretRepository; @inject("streamer") - private streamer: Server; + private readonly streamer!: Server; /** * Inject lcpl document in publication @@ -306,7 +306,7 @@ export class LcpManager { ); // Register device - this.registerPublicationLicense(publicationDocument); + await this.registerPublicationLicense(publicationDocument); } public async unlockPublicationWithPassphrase(publication: Publication, passphrase: string): Promise { @@ -347,7 +347,7 @@ export class LcpManager { } // Register device - this.registerPublicationLicense(publicationDocument); + await this.registerPublicationLicense(publicationDocument); } public async storePassphrase(publication: Publication, passphrase: string): Promise { @@ -371,9 +371,9 @@ export class LcpManager { ); const parsedPublication: Epub = await EpubParsePromise(epubPath); - return new Promise((resolve: any, reject: any) => { + return new Promise(async (resolve: any, reject: any) => { try { - launchStatusDocumentProcessing( + await launchStatusDocumentProcessing( parsedPublication.LCP, this.deviceIdManager, async (licenseUpdateJson: string | undefined) => { diff --git a/src/main/services/win-registry.ts b/src/main/services/win-registry.ts index 59e986ed83..51e6fc7e20 100644 --- a/src/main/services/win-registry.ts +++ b/src/main/services/win-registry.ts @@ -95,7 +95,7 @@ export class WinRegistry { public getWindow(winId: number): AppWindow { if (!(winId in this.windows)) { // Window not found - return; + return undefined; } return this.windows[winId]; diff --git a/src/main/storage/publication-storage.ts b/src/main/storage/publication-storage.ts index 139eff8314..601b845c97 100644 --- a/src/main/storage/publication-storage.ts +++ b/src/main/storage/publication-storage.ts @@ -113,7 +113,7 @@ export class PublicationStorage { filename, ); - return new Promise((resolve, reject) => { + return new Promise((resolve, _reject) => { const writeStream = fs.createWriteStream(dstPath); const fileResolve = () => { resolve({ diff --git a/src/main/streamer.ts b/src/main/streamer.ts index 9a079c768d..7380f94537 100644 --- a/src/main/streamer.ts +++ b/src/main/streamer.ts @@ -62,7 +62,7 @@ debug("readium css path:", rcssPath); // TODO: centralize this code, currently duplicated // see src/renderer/components/reader/ReaderApp.jsx -function computeReadiumCssJsonMessage(publication: Publication, link: Link | undefined): +function computeReadiumCssJsonMessage(_publication: Publication, _link: Link | undefined): IEventPayload_R2_EVENT_READIUMCSS { const store = (container.get("store") as Store); let settings = store.getState().reader.config; diff --git a/src/renderer/components/App.tsx b/src/renderer/components/App.tsx index fcdceebadc..b276cd071f 100644 --- a/src/renderer/components/App.tsx +++ b/src/renderer/components/App.tsx @@ -73,10 +73,10 @@ export default class App extends React.Component { } public async componentDidMount() { - window.document.documentElement.addEventListener("keydown", (ev: KeyboardEvent) => { + window.document.documentElement.addEventListener("keydown", (_ev: KeyboardEvent) => { window.document.documentElement.classList.add("R2_CSS_CLASS__KEYBOARD_INTERACT"); }, true); - window.document.documentElement.addEventListener("mousedown", (ev: MouseEvent) => { + window.document.documentElement.addEventListener("mousedown", (_ev: MouseEvent) => { window.document.documentElement.classList.remove("R2_CSS_CLASS__KEYBOARD_INTERACT"); }, true); } diff --git a/src/renderer/components/PageManager.tsx b/src/renderer/components/PageManager.tsx index cac7a0ee32..50b35a2ae0 100644 --- a/src/renderer/components/PageManager.tsx +++ b/src/renderer/components/PageManager.tsx @@ -6,9 +6,9 @@ // ==LICENSE-END== import * as React from "react"; + import { Route, Switch } from "react-router-dom"; -import { I18nTyped, Translator } from "readium-desktop/common/services/translator"; -import { lazyInject } from "readium-desktop/renderer/di"; + import { routes } from "readium-desktop/renderer/routing"; interface States { @@ -17,9 +17,6 @@ interface States { export default class PageManager extends React.Component<{}, States> { - @lazyInject("translator") - private translator: Translator; - public constructor(props: any) { super(props); @@ -29,8 +26,6 @@ export default class PageManager extends React.Component<{}, States> { } public render(): React.ReactElement<{}> { - const __ = this.translator.translate.bind(this.translator) as I18nTyped; - const activePage = this.state.activePage; return ( {Object.keys(routes).map((path: string) => { diff --git a/src/renderer/components/catalog/GridTagButton.tsx b/src/renderer/components/catalog/GridTagButton.tsx index 85b619fa5b..2db93d3c19 100644 --- a/src/renderer/components/catalog/GridTagButton.tsx +++ b/src/renderer/components/catalog/GridTagButton.tsx @@ -7,7 +7,6 @@ import * as React from "react"; import { PublicationView } from "readium-desktop/common/views/publication"; -import * as style from "readium-desktop/renderer/assets/styles/myBooks.css"; import { withApi } from "../utils/api"; import { Link } from "react-router-dom"; diff --git a/src/renderer/components/catalog/PublicationAddButton.tsx b/src/renderer/components/catalog/PublicationAddButton.tsx index 994f663481..821921934d 100644 --- a/src/renderer/components/catalog/PublicationAddButton.tsx +++ b/src/renderer/components/catalog/PublicationAddButton.tsx @@ -50,8 +50,8 @@ export class PublicationAddButton extends React.Component { const files = event.target.files; const paths: string[] = []; - for (let i = 0 ; i < files.length ; i++) { - paths.push(files[i].path); + for (const f of files) { + paths.push(f.path); } this.props.importFiles({ paths }); } diff --git a/src/renderer/components/catalog/SearchForm.tsx b/src/renderer/components/catalog/SearchForm.tsx index 789e1a6e98..e9e4adeae2 100644 --- a/src/renderer/components/catalog/SearchForm.tsx +++ b/src/renderer/components/catalog/SearchForm.tsx @@ -14,8 +14,6 @@ import SVG from "readium-desktop/renderer/components/utils/SVG"; import { RouteComponentProps, withRouter } from "react-router-dom"; import { TranslatorProps, withTranslator } from "readium-desktop/renderer/components/utils/translator"; -import { setLatestVersion } from "readium-desktop/common/redux/actions/update"; - interface SearchProps extends RouteComponentProps, TranslatorProps {} export class Search extends React.Component { diff --git a/src/renderer/components/catalog/TagLayout.tsx b/src/renderer/components/catalog/TagLayout.tsx index dae25483cb..6cf322d270 100644 --- a/src/renderer/components/catalog/TagLayout.tsx +++ b/src/renderer/components/catalog/TagLayout.tsx @@ -15,10 +15,6 @@ import SVG from "readium-desktop/renderer/components/utils/SVG"; import Menu from "../utils/menu/Menu"; import { TranslatorProps, withTranslator } from "../utils/translator"; -import { Link } from "react-router-dom"; -import { withApi } from "../utils/api"; - -import { PublicationView } from "readium-desktop/common/views/publication"; import GridTagButton from "./GridTagButton"; interface TagProps extends TranslatorProps { diff --git a/src/renderer/components/dialog/DeletePublicationConfirm.tsx b/src/renderer/components/dialog/DeletePublicationConfirm.tsx index 13a65dfefe..11fab3bbd4 100644 --- a/src/renderer/components/dialog/DeletePublicationConfirm.tsx +++ b/src/renderer/components/dialog/DeletePublicationConfirm.tsx @@ -58,9 +58,9 @@ export class DeletePublicationConfirm extends React.Component { +const mapDispatchToProps = (dispatch: any, _ownProps: any) => { return { - closeDialog: (data: any) => { + closeDialog: (_data: any) => { dispatch( dialogActions.close(), ); diff --git a/src/renderer/components/dialog/FileImport.tsx b/src/renderer/components/dialog/FileImport.tsx index f099e108fa..89114c3093 100644 --- a/src/renderer/components/dialog/FileImport.tsx +++ b/src/renderer/components/dialog/FileImport.tsx @@ -28,11 +28,9 @@ export class FileImport extends React.Component { } public render(): React.ReactElement<{}> { - const {__} = this.props; return (
{ this.buildBasicFileImportList() } -
); } diff --git a/src/renderer/components/dialog/OpdsFeedAddForm.tsx b/src/renderer/components/dialog/OpdsFeedAddForm.tsx index 03c444f338..42d71a7c05 100644 --- a/src/renderer/components/dialog/OpdsFeedAddForm.tsx +++ b/src/renderer/components/dialog/OpdsFeedAddForm.tsx @@ -98,9 +98,9 @@ export class OpdsFeedAddForm extends React.Component { } } -const mapDispatchToProps = (dispatch: any, ownProps: any) => { +const mapDispatchToProps = (dispatch: any, _ownProps: any) => { return { - closeDialog: (data: any) => { + closeDialog: (_data: any) => { dispatch( dialogActions.close(), ); diff --git a/src/renderer/components/dialog/RenewLsdConfirm.tsx b/src/renderer/components/dialog/RenewLsdConfirm.tsx index ce5c49bbf0..3388428241 100644 --- a/src/renderer/components/dialog/RenewLsdConfirm.tsx +++ b/src/renderer/components/dialog/RenewLsdConfirm.tsx @@ -61,7 +61,7 @@ export class RenewLsdConfirm extends React.Component { +const mapDispatchToProps = (dispatch: any, _props: any) => { return { closeDialog: () => { dispatch( diff --git a/src/renderer/components/dialog/ReturnLsdConfirm.tsx b/src/renderer/components/dialog/ReturnLsdConfirm.tsx index be42598aa5..078b9f568f 100644 --- a/src/renderer/components/dialog/ReturnLsdConfirm.tsx +++ b/src/renderer/components/dialog/ReturnLsdConfirm.tsx @@ -62,7 +62,7 @@ export class LsdReturnConfirm extends React.Component { +const mapDispatchToProps = (dispatch: any, _props: any) => { return { closeDialog: () => { dispatch( diff --git a/src/renderer/components/dialog/SameFileImportConfirm.tsx b/src/renderer/components/dialog/SameFileImportConfirm.tsx index 6285224970..fcb97c3949 100644 --- a/src/renderer/components/dialog/SameFileImportConfirm.tsx +++ b/src/renderer/components/dialog/SameFileImportConfirm.tsx @@ -35,7 +35,7 @@ class SameFileImportConfirm extends React.Component { } public render(): React.ReactElement<{}> { - const { __, publication } = this.props; + const { __ } = this.props; return (

@@ -68,7 +68,7 @@ const buildRequestData = (props: Props) => { return { text: props.publication.title }; }; -const mapDispatchToProps = (dispatch: any, props: any) => { +const mapDispatchToProps = (dispatch: any, _props: any) => { return { closeDialog: () => { dispatch( diff --git a/src/renderer/components/layout/LibraryLayout.tsx b/src/renderer/components/layout/LibraryLayout.tsx index 1f73c6dfae..742b8f8bde 100644 --- a/src/renderer/components/layout/LibraryLayout.tsx +++ b/src/renderer/components/layout/LibraryLayout.tsx @@ -67,7 +67,7 @@ class LibraryLayout extends React.Component { } } -const mapStateToProps = (state: RootState, ownProps: any) => { +const mapStateToProps = (state: RootState, _ownProps: any) => { return { dialogOpen: state.dialog.open, }; diff --git a/src/renderer/components/opds/Browser.tsx b/src/renderer/components/opds/Browser.tsx index d5bbe8da71..45784d769f 100644 --- a/src/renderer/components/opds/Browser.tsx +++ b/src/renderer/components/opds/Browser.tsx @@ -26,8 +26,6 @@ import { buildOpdsBrowserRoute } from "readium-desktop/renderer/utils"; import { RootState } from "readium-desktop/renderer/redux/states"; import BrowserResult from "./BrowserResult"; -import * as styles from "readium-desktop/renderer/assets/styles/opds.css"; - interface FeedDetailsProps extends RouteComponentProps, TranslatorProps { navigation: OpdsLinkView[]; } @@ -54,7 +52,7 @@ export class Browser extends React.Component { } private buildBreadcrumb(): BreadCrumbItem[] { - const { location, match, navigation } = this.props; + const { match, navigation } = this.props; const breadcrumb: any = []; // Add root page diff --git a/src/renderer/components/opds/BrowserResult.tsx b/src/renderer/components/opds/BrowserResult.tsx index c884552a27..d03604c0f8 100644 --- a/src/renderer/components/opds/BrowserResult.tsx +++ b/src/renderer/components/opds/BrowserResult.tsx @@ -31,7 +31,7 @@ interface BrowserResultProps extends RouteComponentProps, TranslatorProps { } export class BrowserResult extends React.Component { - public componentDidUpdate?(prevProps: BrowserResultProps, prevState: any) { + public componentDidUpdate?(prevProps: BrowserResultProps, _prevState: any) { if (prevProps.url !== this.props.url) { // New url to browse this.props.cleanData(), diff --git a/src/renderer/components/opds/Entry.tsx b/src/renderer/components/opds/Entry.tsx index 2941cb9d08..e8735a1862 100644 --- a/src/renderer/components/opds/Entry.tsx +++ b/src/renderer/components/opds/Entry.tsx @@ -7,8 +7,6 @@ import * as React from "react"; -import { withApi } from "readium-desktop/renderer/components/utils/api"; - import * as styles from "readium-desktop/renderer/assets/styles/opds.css"; import { Link, RouteComponentProps, withRouter } from "react-router-dom"; @@ -17,8 +15,6 @@ import * as ArrowIcon from "readium-desktop/renderer/assets/icons/baseline-arrow import SVG from "readium-desktop/renderer/components/utils/SVG"; -import { PublicationView } from "readium-desktop/common/views/publication"; - import { buildOpdsBrowserRoute } from "readium-desktop/renderer/utils"; interface EntryProps extends RouteComponentProps { diff --git a/src/renderer/components/opds/FeedList.tsx b/src/renderer/components/opds/FeedList.tsx index 3c9d5fe762..0ec9b40982 100644 --- a/src/renderer/components/opds/FeedList.tsx +++ b/src/renderer/components/opds/FeedList.tsx @@ -64,7 +64,7 @@ export class FeedList extends React.Component { ); })} - {[...Array(6).keys()].map((__, index) => { + {[...Array(6).keys()].map((__, _index) => { return

; })} diff --git a/src/renderer/components/opds/Header.tsx b/src/renderer/components/opds/Header.tsx index 9236c6a53e..40f0c46516 100644 --- a/src/renderer/components/opds/Header.tsx +++ b/src/renderer/components/opds/Header.tsx @@ -14,8 +14,6 @@ import * as ListIcon from "readium-desktop/renderer/assets/icons/list.svg"; import { Link, RouteComponentProps, withRouter } from "react-router-dom"; -import SearchForm from "./SearchForm"; - import SVG from "readium-desktop/renderer/components/utils/SVG"; import { TranslatorProps, withTranslator } from "readium-desktop/renderer/components/utils/translator"; diff --git a/src/renderer/components/publication/Cover.tsx b/src/renderer/components/publication/Cover.tsx index 27fbd49931..7ea056afb1 100644 --- a/src/renderer/components/publication/Cover.tsx +++ b/src/renderer/components/publication/Cover.tsx @@ -9,14 +9,10 @@ import * as React from "react"; import { lazyInject } from "readium-desktop/renderer/di"; -import { Publication } from "readium-desktop/common/models/publication"; - import { Translator } from "readium-desktop/common/services/translator"; import { Styles } from "readium-desktop/renderer/components/styles"; -import { Contributor } from "readium-desktop/common/models/contributor"; - import { PublicationView } from "readium-desktop/common/views/publication"; interface ICoverProps { @@ -28,8 +24,6 @@ export default class Cover extends React.Component { private translator: Translator; public render(): React.ReactElement<{}> { - // TODO: should get language from view state? (user preferences) - const lang = "en"; if (this.props.publication.cover == null) { let authors = ""; diff --git a/src/renderer/components/publication/PublicationCard.tsx b/src/renderer/components/publication/PublicationCard.tsx index 9f53410a81..45195060c7 100644 --- a/src/renderer/components/publication/PublicationCard.tsx +++ b/src/renderer/components/publication/PublicationCard.tsx @@ -8,7 +8,7 @@ import * as React from "react"; import { DialogType } from "readium-desktop/common/models/dialog"; -import { LsdStatus, LsdStatusType } from "readium-desktop/common/models/lcp"; +import { LsdStatus } from "readium-desktop/common/models/lcp"; import { PublicationView } from "readium-desktop/common/views/publication"; diff --git a/src/renderer/components/publication/menu/PublicationExportButton.tsx b/src/renderer/components/publication/menu/PublicationExportButton.tsx index c9e3ee3383..43492b6293 100644 --- a/src/renderer/components/publication/menu/PublicationExportButton.tsx +++ b/src/renderer/components/publication/menu/PublicationExportButton.tsx @@ -6,7 +6,6 @@ // ==LICENSE-END== import * as React from "react"; -import * as ReactDom from "react-dom"; import { PublicationView } from "readium-desktop/common/views/publication"; diff --git a/src/renderer/components/reader/Reader.tsx b/src/renderer/components/reader/Reader.tsx index 432d7e1420..10f23b5fe2 100644 --- a/src/renderer/components/reader/Reader.tsx +++ b/src/renderer/components/reader/Reader.tsx @@ -54,8 +54,6 @@ import { Translator } from "readium-desktop/common/services/translator"; import { _APP_VERSION } from "readium-desktop/preprocessor-directives"; import ReaderFooter from "readium-desktop/renderer/components/reader/ReaderFooter"; import ReaderHeader from "readium-desktop/renderer/components/reader/ReaderHeader"; -import ReaderMenu from "readium-desktop/renderer/components/reader/ReaderMenu"; -import ReaderOptions from "readium-desktop/renderer/components/reader/ReaderOptions"; import { container, lazyInject } from "readium-desktop/renderer/di"; import { RootState } from "readium-desktop/renderer/redux/states"; import { Store } from "redux"; @@ -63,7 +61,6 @@ import { JSON as TAJSON } from "ta-json-x"; import { DialogType } from "readium-desktop/common/models/dialog"; import * as dialogActions from "readium-desktop/common/redux/actions/dialog"; -import { PublicationView } from "readium-desktop/common/views/publication"; import optionsValues from "./options-values"; @@ -77,8 +74,6 @@ import * as styles from "readium-desktop/renderer/assets/styles/reader-app.css"; import { Publication } from "readium-desktop/common/models/publication"; -import * as qs from "query-string"; - import { _APP_NAME } from "readium-desktop/preprocessor-directives"; // import { registerProtocol } from "@r2-navigator-js/electron/renderer/common/protocol"; @@ -163,9 +158,12 @@ setReadiumCssJsonGetter(computeReadiumCssJsonMessage); const publicationJsonUrl = queryParams.pub.startsWith(READIUM2_ELECTRON_HTTP_PROTOCOL) ? convertCustomSchemeToHttpUrl(queryParams.pub) : queryParams.pub; -const pathBase64Raw = publicationJsonUrl.replace(/.*\/pub\/(.*)\/manifest.json/, "$1"); -const pathBase64 = decodeURIComponent(pathBase64Raw); -const pathDecoded = window.atob(pathBase64); +// const pathBase64Raw = publicationJsonUrl.replace(/.*\/pub\/(.*)\/manifest.json/, "$1"); +// const pathBase64 = decodeURIComponent(pathBase64Raw); +// const pathDecoded = window.atob(pathBase64); +// const pathFileName = pathDecoded.substr( +// pathDecoded.replace(/\\/g, "/").lastIndexOf("/") + 1, +// pathDecoded.length - 1); const lcpHint = queryParams.lcpHint; @@ -319,10 +317,10 @@ export class Reader extends React.Component { } }); - window.document.documentElement.addEventListener("keydown", (ev: KeyboardEvent) => { + window.document.documentElement.addEventListener("keydown", (_ev: KeyboardEvent) => { window.document.documentElement.classList.add("R2_CSS_CLASS__KEYBOARD_INTERACT"); }, true); - window.document.documentElement.addEventListener("mousedown", (ev: MouseEvent) => { + window.document.documentElement.addEventListener("mousedown", (_ev: MouseEvent) => { window.document.documentElement.classList.remove("R2_CSS_CLASS__KEYBOARD_INTERACT"); }, true); @@ -339,7 +337,7 @@ export class Reader extends React.Component { // TODO: this is a short-term hack. // Can we instead subscribe to Redux action type == ActionType.CloseRequest, // but narrow it down specically to a reader window instance (not application-wide) - window.document.addEventListener("Thorium:DialogClose", (ev: Event) => { + window.document.addEventListener("Thorium:DialogClose", (_ev: Event) => { this.setState({ shortcutEnable: true, }); @@ -373,9 +371,9 @@ export class Reader extends React.Component { setEpubReadingSystemInfo({ name: _APP_NAME, version: _APP_VERSION }); } - public componentDidUpdate(oldProps: ReaderProps) { + public async componentDidUpdate(oldProps: ReaderProps) { if (oldProps.bookmarks !== this.props.bookmarks) { - this.checkBookmarks(); + await this.checkBookmarks(); } } @@ -455,7 +453,7 @@ export class Reader extends React.Component { // publicationJsonUrl is https://127.0.0.1:PORT response = await fetch(publicationJsonUrl); } catch (e) { - return; + return Promise.reject(e); } if (!response.ok) { console.log("BAD RESPONSE?!"); @@ -466,9 +464,10 @@ export class Reader extends React.Component { publicationJSON = await response.json(); } catch (e) { console.log(e); + return Promise.reject(e); } if (!publicationJSON) { - return; + return Promise.reject("!publicationJSON"); } const publication = TAJSON.deserialize(publicationJSON, R2Publication); @@ -717,7 +716,7 @@ const mapStateToProps = (state: RootState, __: any) => { }; }; -const mapDispatchToProps = (dispatch: any, props: ReaderProps) => { +const mapDispatchToProps = (dispatch: any, _props: ReaderProps) => { return { toggleFullscreen: (fullscreenOn: boolean) => { if (fullscreenOn) { @@ -749,7 +748,7 @@ const mapDispatchToProps = (dispatch: any, props: ReaderProps) => { }; }; -const buildRequestData = (props: ReaderProps) => { +const buildRequestData = (_props: ReaderProps) => { return { identifier: queryParams.pubId, }; diff --git a/src/renderer/components/reader/ReaderFooter.tsx b/src/renderer/components/reader/ReaderFooter.tsx index 630463d787..0a9e04a962 100644 --- a/src/renderer/components/reader/ReaderFooter.tsx +++ b/src/renderer/components/reader/ReaderFooter.tsx @@ -7,9 +7,6 @@ import * as React from "react"; -import { Translator } from "readium-desktop/common/services/translator"; -import { lazyInject } from "readium-desktop/renderer/di"; - import * as ArrowRightIcon from "readium-desktop/renderer/assets/icons/baseline-arrow_forward_ios-24px.svg"; import * as ArrowLeftIcon from "readium-desktop/renderer/assets/icons/baseline-arrow_left_ios-24px.svg"; @@ -56,9 +53,6 @@ export class ReaderFooter extends React.Component { const { __ } = this.props; const { moreInfo } = this.state; - const spineIndex = publication.Spine.findIndex( - (value) => value.Href === currentLocation.locator.href, - ); const spineTitle = currentLocation.locator.title; let afterCurrentLocation = false; diff --git a/src/renderer/components/reader/ReaderHeader.tsx b/src/renderer/components/reader/ReaderHeader.tsx index 73f179db3e..9633724ccb 100644 --- a/src/renderer/components/reader/ReaderHeader.tsx +++ b/src/renderer/components/reader/ReaderHeader.tsx @@ -9,11 +9,7 @@ import * as React from "react"; import * as styles from "readium-desktop/renderer/assets/styles/reader-app.css"; -import { Translator } from "readium-desktop/common/services/translator"; -import { lazyInject } from "readium-desktop/renderer/di"; - import * as BackIcon from "readium-desktop/renderer/assets/icons/baseline-arrow_back-24px-grey.svg"; -import * as AudioIcon from "readium-desktop/renderer/assets/icons/baseline-volume_up-24px.svg"; import * as SettingsIcon from "readium-desktop/renderer/assets/icons/font-size.svg"; import * as TOCIcon from "readium-desktop/renderer/assets/icons/open_book.svg"; import * as MarkIcon from "readium-desktop/renderer/assets/icons/outline-bookmark_border-24px.svg"; @@ -24,10 +20,6 @@ import * as QuitFullscreenIcon from "readium-desktop/renderer/assets/icons/sharp import SVG from "readium-desktop/renderer/components/utils/SVG"; -import * as readerActions from "readium-desktop/common/redux/actions/reader"; - -import { withApi } from "../utils/api"; - import { ReaderMode } from "readium-desktop/common/models/reader"; import { TranslatorProps, withTranslator } from "readium-desktop/renderer/components/utils/translator"; diff --git a/src/renderer/components/reader/ReaderMenu.tsx b/src/renderer/components/reader/ReaderMenu.tsx index 29359b9582..d4ea774e84 100644 --- a/src/renderer/components/reader/ReaderMenu.tsx +++ b/src/renderer/components/reader/ReaderMenu.tsx @@ -199,6 +199,7 @@ export class ReaderMenu extends React.Component {
, ); } + return undefined; } private closeBookarkEditForm() { diff --git a/src/renderer/components/reader/sideMenu/SideMenu.tsx b/src/renderer/components/reader/sideMenu/SideMenu.tsx index 5850f2af27..f72956268a 100644 --- a/src/renderer/components/reader/sideMenu/SideMenu.tsx +++ b/src/renderer/components/reader/sideMenu/SideMenu.tsx @@ -41,7 +41,7 @@ export class SideMenu extends React.Component { } public render(): React.ReactElement<{}> { - const { __, open, sections, className, listClassName, toggleMenu } = this.props; + const { open, sections, className, listClassName, toggleMenu } = this.props; const { openedSection } = this.state; if (!open) { diff --git a/src/renderer/components/searchResult/AllPublicationPage.tsx b/src/renderer/components/searchResult/AllPublicationPage.tsx index 52d80f83be..7b80957e76 100644 --- a/src/renderer/components/searchResult/AllPublicationPage.tsx +++ b/src/renderer/components/searchResult/AllPublicationPage.tsx @@ -5,8 +5,6 @@ // that can be found in the LICENSE file exposed on Github (readium) in the project repository. // ==LICENSE-END== -import * as qs from "query-string"; - import * as React from "react"; import { RouteComponentProps } from "react-router-dom"; diff --git a/src/renderer/components/searchResult/TextSearchResult.tsx b/src/renderer/components/searchResult/TextSearchResult.tsx index 93e155c6e3..55dfcf825d 100644 --- a/src/renderer/components/searchResult/TextSearchResult.tsx +++ b/src/renderer/components/searchResult/TextSearchResult.tsx @@ -9,7 +9,7 @@ import * as qs from "query-string"; import * as React from "react"; -import { Link, RouteComponentProps } from "react-router-dom"; +import { RouteComponentProps } from "react-router-dom"; import { withApi } from "readium-desktop/renderer/components/utils/api"; @@ -32,7 +32,7 @@ interface TextSearchResultProps extends TranslatorProps, RouteComponentProps { } export class TextSearchResult extends React.Component { - public componentDidUpdate(prevProps: any, prevState: any, snapshot?: any): boolean { + public componentDidUpdate(prevProps: any, _prevState: any, _snapshot?: any): boolean { const text = (this.props.match.params as any).value; const prevText = (prevProps.match.params as any).value; diff --git a/src/renderer/components/settings/Information.tsx b/src/renderer/components/settings/Information.tsx index 7c3c6814ba..90b300a011 100644 --- a/src/renderer/components/settings/Information.tsx +++ b/src/renderer/components/settings/Information.tsx @@ -19,6 +19,8 @@ import { promisify } from "util"; import { _PACKAGING } from "readium-desktop/preprocessor-directives"; +import { RootState } from "readium-desktop/renderer/redux/states"; + interface Props extends TranslatorProps { locale: string; setLocale: (locale: string) => void; @@ -62,7 +64,7 @@ export class LanguageSettings extends React.Component { } } -const mapStateToProps = (state: any) => { +const mapStateToProps = (state: RootState) => { return { locale: state.i18n.locale, }; diff --git a/src/renderer/components/settings/LanguageSettings.tsx b/src/renderer/components/settings/LanguageSettings.tsx index a23de3942f..109d412368 100644 --- a/src/renderer/components/settings/LanguageSettings.tsx +++ b/src/renderer/components/settings/LanguageSettings.tsx @@ -15,8 +15,6 @@ import { connect } from "react-redux"; import LibraryLayout from "readium-desktop/renderer/components/layout/LibraryLayout"; -import Header from "./Header"; - import { setLocale } from "readium-desktop/common/redux/actions/i18n"; import { TranslatorProps, withTranslator } from "readium-desktop/renderer/components/utils/translator"; @@ -24,6 +22,8 @@ import { TranslatorProps, withTranslator } from "readium-desktop/renderer/compon import * as DoneIcon from "readium-desktop/renderer/assets/icons/done.svg"; import SVG from "../utils/SVG"; +import { RootState } from "readium-desktop/renderer/redux/states"; + interface Props extends TranslatorProps { locale: string; setLocale: (locale: string) => void; @@ -43,7 +43,7 @@ export class LanguageSettings extends React.Component { } public render(): React.ReactElement<{}> { - const secondaryHeader =
; + // const secondaryHeader =
; const { __ } = this.props; return ( <> @@ -73,7 +73,7 @@ export class LanguageSettings extends React.Component { } } -const mapStateToProps = (state: any) => { +const mapStateToProps = (state: RootState) => { return { locale: state.i18n.locale, }; diff --git a/src/renderer/components/toast/Toast.tsx b/src/renderer/components/toast/Toast.tsx index 900f10163d..6abd16b915 100644 --- a/src/renderer/components/toast/Toast.tsx +++ b/src/renderer/components/toast/Toast.tsx @@ -49,7 +49,8 @@ export class Toast extends React.Component { setTimeout(this.handleClose, 5000); this.ref.addEventListener("transitionend", this.handleTransitionEnd, false); if (this.props.displaySystemNotification) { - const notif = new Notification("Thorium Reader", { + // tslint:disable-next-line: no-unused-expression + new Notification("Thorium Reader", { body: this.props.message, }); } @@ -60,7 +61,7 @@ export class Toast extends React.Component { } public render(): React.ReactElement<{}> { - const { __, icon, id } = this.props; + const { icon } = this.props; const { willLeave, toRemove } = this.state; return (
{ return (<>); } } + return undefined; })}
; } diff --git a/src/renderer/components/utils/DragAndDropList.tsx b/src/renderer/components/utils/DragAndDropList.tsx index 7a92c06d75..c39e112bb3 100644 --- a/src/renderer/components/utils/DragAndDropList.tsx +++ b/src/renderer/components/utils/DragAndDropList.tsx @@ -7,8 +7,6 @@ import * as React from "react"; -import * as styles from "readium-desktop/renderer/assets/styles/dragAndDropList.css"; - import { DragDropContext, Draggable, Droppable } from "react-beautiful-dnd"; interface DragAndDropListProps { diff --git a/src/renderer/components/utils/api.tsx b/src/renderer/components/utils/api.tsx index 74baac6ad6..412a2272bf 100644 --- a/src/renderer/components/utils/api.tsx +++ b/src/renderer/components/utils/api.tsx @@ -43,7 +43,10 @@ export interface ApiProps { cleanData?: any; } +// TS4094: private members fail the TS compiler, because: +// returned type is ConnectedComponentClass export function withApi(WrappedComponent: any, queryConfig: ApiConfig) { + // Create operationRequests const operationRequests: ApiOperationRequest[] = []; const store = container.get("store") as Store; @@ -102,7 +105,7 @@ export function withApi(WrappedComponent: any, queryConfig: ApiConfig) { {}, dispatchToPropsResult, { - requestOnLoadData: (data: any) => { + requestOnLoadData: (_data: any) => { for (const operationRequest of operationRequests) { if (operationRequest.definition.onLoad) { operationRequest.caller(ownProps)(); @@ -120,7 +123,7 @@ export function withApi(WrappedComponent: any, queryConfig: ApiConfig) { ); }; - const mapStateToProps = (state: any, ownProps: any) => { + const mapStateToProps = (state: RootState, ownProps: any) => { let stateToPropsResult = {}; if (queryConfig.mapStateToProps != null) { @@ -148,9 +151,11 @@ export function withApi(WrappedComponent: any, queryConfig: ApiConfig) { }; const BaseWrapperComponent = class extends React.Component { - private lastSuccess: ApiLastSuccess; - private store: Store; - private stateUpdateUnsubscribe: any; + + // Ideally should be private, but see TS4094 comments in this file + /* private */ public lastSuccess: ApiLastSuccess; + /* private */ public store: Store; + /* private */ public stateUpdateUnsubscribe: any; constructor(props: any) { super(props); @@ -191,7 +196,9 @@ export function withApi(WrappedComponent: any, queryConfig: ApiConfig) { if (newProps.operationResults) { for (const key in newProps.operationResults) { - newProps[key] = newProps.operationResults[key]; + if (newProps.operationResults.hasOwnProperty(key)) { + newProps[key] = newProps.operationResults[key]; + } } } @@ -203,7 +210,8 @@ export function withApi(WrappedComponent: any, queryConfig: ApiConfig) { return (); } - private handleStateUpdate() { + // Ideally should be private, but see TS4094 comments in this file + /* private */ public handleStateUpdate() { const state = this.store.getState(); const apiLastSuccess = state.api.lastSuccess; diff --git a/src/renderer/components/utils/menu/Menu.tsx b/src/renderer/components/utils/menu/Menu.tsx index 75ac153e4f..11c92b134e 100644 --- a/src/renderer/components/utils/menu/Menu.tsx +++ b/src/renderer/components/utils/menu/Menu.tsx @@ -9,7 +9,6 @@ import * as React from "react"; import * as ReactDOM from "react-dom"; import * as uuid from "uuid"; -import AccessibleMenu from "./AccessibleMenu"; import MenuButton from "./MenuButton"; import MenuContent from "./MenuContent"; diff --git a/src/renderer/components/utils/menu/MenuButton.tsx b/src/renderer/components/utils/menu/MenuButton.tsx index 204996a265..0692f0b93e 100644 --- a/src/renderer/components/utils/menu/MenuButton.tsx +++ b/src/renderer/components/utils/menu/MenuButton.tsx @@ -6,7 +6,6 @@ // ==LICENSE-END== import * as React from "react"; -import ReactDOM = require("react-dom"); interface MenuButtonProps { menuId: string; diff --git a/src/renderer/redux/middleware/sync.ts b/src/renderer/redux/middleware/sync.ts index ac4b626b3c..2128654ece 100644 --- a/src/renderer/redux/middleware/sync.ts +++ b/src/renderer/redux/middleware/sync.ts @@ -6,7 +6,7 @@ // ==LICENSE-END== import { ipcRenderer } from "electron"; -import { Store } from "redux"; +import { AnyAction, Dispatch, Middleware, MiddlewareAPI } from "redux"; import { syncIpc } from "readium-desktop/common/ipc"; import { @@ -15,7 +15,7 @@ import { readerActions, } from "readium-desktop/common/redux/actions"; -import { SenderType } from "readium-desktop/common/models/sync"; +import { ActionWithSender, SenderType } from "readium-desktop/common/models/sync"; import { container } from "readium-desktop/renderer/di"; @@ -37,7 +37,11 @@ const SYNCHRONIZABLE_ACTIONS: any = [ i18nActions.ActionType.Set, ]; -export const reduxSyncMiddleware = (store: Store) => (next: any) => (action: any) => { +export const reduxSyncMiddleware: Middleware + = (store: MiddlewareAPI>) => + (next: Dispatch) => + ((action: ActionWithSender) => { + // Does this action must be sent to the main process if (SYNCHRONIZABLE_ACTIONS.indexOf(action.type) === -1) { // Do not send @@ -62,7 +66,7 @@ export const reduxSyncMiddleware = (store: Store) => (next: any) => (action type: SenderType.Renderer, winId: store.getState().win.winId, }, - }); + } as syncIpc.EventPayload); return next(action); -}; +}) as Dispatch; diff --git a/src/renderer/redux/reducers/reader.ts b/src/renderer/redux/reducers/reader.ts index 0830ed3db5..b0c804072d 100644 --- a/src/renderer/redux/reducers/reader.ts +++ b/src/renderer/redux/reducers/reader.ts @@ -5,8 +5,6 @@ // that can be found in the LICENSE file exposed on Github (readium) in the project repository. // ==LICENSE-END== -import * as uuid from "uuid"; - import { Action } from "readium-desktop/common/models/redux"; import { readerActions } from "readium-desktop/common/redux/actions"; diff --git a/src/renderer/redux/sagas/i18n.ts b/src/renderer/redux/sagas/i18n.ts index b54e5d6c76..898ce33dd0 100644 --- a/src/renderer/redux/sagas/i18n.ts +++ b/src/renderer/redux/sagas/i18n.ts @@ -15,7 +15,7 @@ import { i18nActions } from "readium-desktop/common/redux/actions"; export function* localeWatcher() { while (true) { - const action = yield take(i18nActions.ActionType.Set); + const action: i18nActions.ActionLocale = yield take(i18nActions.ActionType.Set); const translator = container.get("translator") as Translator; translator.setLocale(action.payload.locale); } diff --git a/src/renderer/utils.ts b/src/renderer/utils.ts index affa302cbf..2366cf518d 100644 --- a/src/renderer/utils.ts +++ b/src/renderer/utils.ts @@ -39,8 +39,8 @@ export function decodeB64(data: any) { decoded = decoded.replace(/_/g, "/"); decoded = decoded.replace(/-/g, "+"); - // Add padding - const paddingLength = (3 - (decoded.length % 3)) % 3; + // // Add padding + // const paddingLength = (3 - (decoded.length % 3)) % 3; decoded = atob(decoded); return decoded; } diff --git a/src/utils/debounce.ts b/src/utils/debounce.ts index 4e3d0ec6d9..d1b578372d 100644 --- a/src/utils/debounce.ts +++ b/src/utils/debounce.ts @@ -21,15 +21,17 @@ export function debounce Promise | any>( options: Options = { isImmediate: false, }, -) { +): (...args: any[]) => void { + let timeoutId: NodeJS.Timer | undefined; - return (...args: any[]) => { + return async function fct(this: any, ...args: any[]) { + const that = this; const doLater = async () => { timeoutId = undefined; if (!options.isImmediate) { - await Promise.resolve(func.apply(this, args)); + await Promise.resolve(func.apply(that, args)); } }; @@ -44,7 +46,7 @@ export function debounce Promise | any>( timeoutId = setTimeout(doLater, waitMilliseconds) as any; if (shouldCallNow) { - Promise.resolve(func.apply(this, args)); + await Promise.resolve(func.apply(that, args)); } }; } diff --git a/src/utils/fontList.ts b/src/utils/fontList.ts index b2802bf90b..c25dae9eca 100644 --- a/src/utils/fontList.ts +++ b/src/utils/fontList.ts @@ -7,8 +7,6 @@ import { Font } from "readium-desktop/common/models/font"; -const ID_PREFIX = "fontselect_"; - const fontList: Font[] = [{ id: "DEFAULT", diff --git a/src/utils/lcp.ts b/src/utils/lcp.ts index d0aeb03584..c6bd64b4f5 100644 --- a/src/utils/lcp.ts +++ b/src/utils/lcp.ts @@ -6,16 +6,7 @@ // ==LICENSE-END== import * as crypto from "crypto"; -import * as debug_ from "debug"; import * as fs from "fs"; -import * as path from "path"; - -import { Publication as Epub } from "@r2-shared-js/models/publication"; -import { EpubParsePromise } from "@r2-shared-js/parser/epub"; - -import { IDeviceIDManager } from "@r2-lcp-js/lsd/deviceid-manager"; - -import { launchStatusDocumentProcessing } from "@r2-lcp-js/lsd/status-document-processing"; import { container } from "readium-desktop/main/di"; @@ -26,9 +17,6 @@ import { PublicationStorage } from "readium-desktop/main/storage/publication-sto import { httpGet } from "readium-desktop/common/utils/http"; import { injectDataInZip } from "readium-desktop/utils/zip"; -// Logger -const debug = debug_("readium-desktop:utils:lcp"); - export function toSha256Hex(data: string) { const checkSum = crypto.createHash("sha256"); checkSum.update(data); @@ -85,41 +73,39 @@ export async function updateLicenseStatus(publication: Publication) { // Inject lcpl in publication await injectLcpl(publication, lcplResponse); - // Get epub file from publication - // FIXME: do not use services in utils - const pubStorage = container.get("publication-storage") as PublicationStorage; - const epubPath = pubStorage.getPublicationEpubPath(publication.identifier); - - // Get lcpl information - let parsedEpub: Epub = null; - - try { - parsedEpub = await EpubParsePromise(epubPath); - } catch (error) { - debug(error); - } - - // Update status document - const deviceIdManager = container.get("device-id-manager") as IDeviceIDManager; - const deviceId = await deviceIdManager.getDeviceID(); - - try { - /* await launchStatusDocumentProcessing( - parsedEpub.LCP, deviceIdManager, - async (licenseUpdateJson: string | undefined) => { - debug("launchStatusDocumentProcessing DONE."); - debug("new license", licenseUpdateJson); - if (licenseUpdateJson) { - try { - await injectLcpl(publication, licenseUpdateJson); - } catch (err) { - console.log("1.5.error"); - debug(err); - } - } - });*/ - } catch (err) { - debug(err); - } - + // // Get epub file from publication + // // FIXME: do not use services in utils + // const pubStorage = container.get("publication-storage") as PublicationStorage; + // const epubPath = pubStorage.getPublicationEpubPath(publication.identifier); + + // // Get lcpl information + // let parsedEpub: Epub = null; + + // try { + // parsedEpub = await EpubParsePromise(epubPath); + // } catch (error) { + // debug(error); + // } + + // // Update status document + // const deviceIdManager = container.get("device-id-manager") as IDeviceIDManager; + + // try { + // /* await launchStatusDocumentProcessing( + // parsedEpub.LCP, deviceIdManager, + // async (licenseUpdateJson: string | undefined) => { + // debug("launchStatusDocumentProcessing DONE."); + // debug("new license", licenseUpdateJson); + // if (licenseUpdateJson) { + // try { + // await injectLcpl(publication, licenseUpdateJson); + // } catch (err) { + // console.log("1.5.error"); + // debug(err); + // } + // } + // });*/ + // } catch (err) { + // debug(err); + // } } diff --git a/src/utils/zip.ts b/src/utils/zip.ts index 90db471c81..db6c69cd3b 100644 --- a/src/utils/zip.ts +++ b/src/utils/zip.ts @@ -73,7 +73,7 @@ function injectObjectInZip( }); } -export function injectFileInZip( +export async function injectFileInZip( destPathTMP: string, destPathFINAL: string, filePath: string, @@ -95,7 +95,7 @@ export function injectFileInZip( }); } -export function injectDataInZip( +export async function injectDataInZip( destPathTMP: string, destPathFINAL: string, data: string, diff --git a/test/main/db/repository/config.test.ts b/test/main/db/repository/config.test.ts index b8af59a119..e02fa33e3e 100644 --- a/test/main/db/repository/config.test.ts +++ b/test/main/db/repository/config.test.ts @@ -1,15 +1,15 @@ import "reflect-metadata"; import * as moment from "moment"; -import * as PouchDB from "pouchdb-core"; import { ConfigRepository } from "readium-desktop/main/db/repository/config"; + import { NotFoundError } from "readium-desktop/main/db/exceptions"; -import { clearDatabase, createDatabase, } from "test/main/db/utils"; +import { clearDatabase, createDatabase } from "test/main/db/utils"; -let repository: ConfigRepository = null; -let db: PouchDB.Database = null; +let repository: ConfigRepository | null = null; +let db: PouchDB.Database | null = null; const now = moment.now(); const dbDocIdentifier1 = "key-1"; @@ -40,22 +40,34 @@ beforeEach(async () => { }); afterEach(async () => { + if (!db) { + return; + } repository = null; await clearDatabase(db); }); test("repository.findAll", async () => { + if (!repository) { + return; + } const result = await repository.findAll(); expect(result.length).toBe(2); }); test("repository.get - found", async () => { + if (!repository) { + return; + } const result = await repository.get("key-1"); expect(result.identifier).toBe("key-1"); expect(result.value).toBe("config-value-1"); }); test("repository.get - not found", async () => { + if (!repository) { + return; + } // Test unknown key try { await repository.get("key-3"); @@ -66,39 +78,48 @@ test("repository.get - not found", async () => { }); test("repository.save create", async () => { + if (!repository) { + return; + } const dbDoc = { identifier: "new-key", - value: "new-value" + value: "new-value", }; const result = await repository.save(dbDoc); expect(result.identifier).toBe("new-key"); expect(result.value).toBe("new-value"); - expect(result.createdAt).toBeDefined() + expect(result.createdAt).toBeDefined(); expect(result.updatedAt).toBeDefined(); expect(result.createdAt === result.updatedAt).toBeTruthy(); }); test("repository.save update", async () => { + if (!repository) { + return; + } const dbDoc = { identifier: "key-1", - value: "new-value" + value: "new-value", }; const result = await repository.save(dbDoc); expect(result.identifier).toBe("key-1"); expect(result.value).toBe("new-value"); - expect(result.createdAt).toBeDefined() + expect(result.createdAt).toBeDefined(); expect(result.updatedAt).toBeDefined(); expect(result.createdAt < result.updatedAt).toBeTruthy(); }); test("repository.delete", async () => { - let result = await db.get("config_key-1") as any; + if (!db || !repository) { + return; + } + const result = await db.get("config_key-1") as any; expect(result.identifier).toBe("key-1"); // Delete key 1 await repository.delete("key-1"); try { - await db.get("config_key-1") as any; + await db.get("config_key-1"); } catch (e) { expect(e.message).toBe("missing"); } diff --git a/test/main/db/repository/lcp-secret.test.ts b/test/main/db/repository/lcp-secret.test.ts index 787e9f25e5..4343027775 100644 --- a/test/main/db/repository/lcp-secret.test.ts +++ b/test/main/db/repository/lcp-secret.test.ts @@ -1,7 +1,6 @@ import "reflect-metadata"; import * as moment from "moment"; -import * as PouchDB from "pouchdb-core"; import { LcpSecretRepository } from "readium-desktop/main/db/repository/lcp-secret"; @@ -9,8 +8,8 @@ import { NotFoundError } from "readium-desktop/main/db/exceptions"; import { clearDatabase, createDatabase } from "test/main/db/utils"; -let repository: LcpSecretRepository = null; -let db: PouchDB.Database = null; +let repository: LcpSecretRepository | null = null; +let db: PouchDB.Database | null = null; const now = moment.now(); const dbDocIdentifier1 = "lcp-secret-1"; @@ -45,16 +44,25 @@ beforeEach(async () => { }); afterEach(async () => { + if (!db) { + return; + } repository = null; await clearDatabase(db); }); test("repository.findAll", async () => { + if (!repository) { + return; + } const result = await repository.findAll(); expect(result.length).toBe(2); }); test("repository.findByPublicationIdentifier - found", async () => { + if (!repository) { + return; + } const result = await repository.findByPublicationIdentifier("pub-1"); expect(result.length).toBe(1); const lcpSecret = result[0]; @@ -64,11 +72,17 @@ test("repository.findByPublicationIdentifier - found", async () => { }); test("repository.findByPublicationIdentifier - not found", async () => { + if (!repository) { + return; + } const result = await repository.findByPublicationIdentifier("unknown"); expect(result.length).toBe(0); }); test("repository.get - found", async () => { + if (!repository) { + return; + } const result = await repository.get("lcp-secret-1"); expect(result.identifier).toBe("lcp-secret-1"); expect(result.publicationIdentifier).toBe("pub-1"); @@ -76,6 +90,9 @@ test("repository.get - found", async () => { }); test("repository.get - not found", async () => { + if (!repository) { + return; + } // Test unknown key try { await repository.get("lcp-secret-3"); @@ -86,6 +103,9 @@ test("repository.get - not found", async () => { }); test("repository.save create", async () => { + if (!repository) { + return; + } const dbDoc = { identifier: "new-lcp-secret", _id: "lcp_secret_new-lcp-secret", @@ -102,6 +122,9 @@ test("repository.save create", async () => { }); test("repository.save update", async () => { + if (!repository) { + return; + } const dbDoc = { identifier: "lcp-secret-1", publicationIdentifier: dbPubIdentifier1, @@ -117,6 +140,9 @@ test("repository.save update", async () => { }); test("repository.delete", async () => { + if (!db || !repository) { + return; + } const result = await db.get("lcp_secret_lcp-secret-1") as any; expect(result.identifier).toBe("lcp-secret-1"); diff --git a/test/main/db/repository/locator.test.ts b/test/main/db/repository/locator.test.ts index 2420f741d2..a4efffac04 100644 --- a/test/main/db/repository/locator.test.ts +++ b/test/main/db/repository/locator.test.ts @@ -1,20 +1,17 @@ import "reflect-metadata"; import * as moment from "moment"; -import * as PouchDB from "pouchdb-core"; import { LocatorType } from "readium-desktop/common/models/locator"; import { LocatorRepository } from "readium-desktop/main/db/repository/locator"; -import { LocatorDocument } from "readium-desktop/main/db/document/locator"; - import { NotFoundError } from "readium-desktop/main/db/exceptions"; -import { clearDatabase, createDatabase, } from "test/main/db/utils"; +import { clearDatabase, createDatabase } from "test/main/db/utils"; -let repository: LocatorRepository = null; -let db: PouchDB.Database = null; +let repository: LocatorRepository | null = null; +let db: PouchDB.Database | null = null; const now = moment.now(); const dbDocIdentifier1 = "bookmark-1"; @@ -61,16 +58,25 @@ beforeEach(async () => { }); afterEach(async () => { + if (!db) { + return; + } repository = null; await clearDatabase(db); }); test("repository.findAll", async () => { + if (!repository) { + return; + } const result = await repository.findAll(); expect(result.length).toBe(2); }); test("repository.findByPublicationIdentifer - found", async () => { + if (!repository) { + return; + } const result = await repository.findByPublicationIdentifier("pub-1"); expect(result.length).toBe(1); const locator = result[0]; @@ -81,21 +87,33 @@ test("repository.findByPublicationIdentifer - found", async () => { expect(locator.locator.title).toBe("Bookmark 1"); }); test("repository.findByPublicationIdentifer - not found", async () => { + if (!repository) { + return; + } const result = await repository.findByPublicationIdentifier("pub-3"); expect(result.length).toBe(0); }); test("repository.findByLocatorType - found", async () => { + if (!repository) { + return; + } const result = await repository.findByLocatorType(LocatorType.Bookmark); expect(result.length).toBe(2); }); test("repository.findByLocatorType - not found", async () => { + if (!repository) { + return; + } const result = await repository.findByLocatorType(LocatorType.LastReadingLocation); expect(result.length).toBe(0); }); test("repository.findByPublicationIdentifer - found", async () => { + if (!repository) { + return; + } const result = await repository.findByPublicationIdentifierAndLocatorType( "pub-1", LocatorType.Bookmark, ); @@ -109,6 +127,9 @@ test("repository.findByPublicationIdentifer - found", async () => { }); test("repository.findByPublicationIdentifer - not found", async () => { + if (!repository) { + return; + } const result = await repository.findByPublicationIdentifierAndLocatorType( "pub-1", LocatorType.LastReadingLocation, ); @@ -116,6 +137,9 @@ test("repository.findByPublicationIdentifer - not found", async () => { }); test("repository.get - found", async () => { + if (!repository) { + return; + } const result = await repository.get("bookmark-1"); expect(result.identifier).toBe("bookmark-1"); expect(result.locatorType).toBe(LocatorType.Bookmark); @@ -126,6 +150,9 @@ test("repository.get - found", async () => { }); test("repository.get - not found", async () => { + if (!repository) { + return; + } // Test unknown key try { await repository.get("bookmark-3"); @@ -136,6 +163,9 @@ test("repository.get - not found", async () => { }); test("repository.save create", async () => { + if (!repository) { + return; + } const dbDoc = { identifier: "new-bookmark", locatorType: LocatorType.LastReadingLocation, @@ -153,12 +183,15 @@ test("repository.save create", async () => { expect(result.publicationIdentifier).toBe("pub-1"); expect(result.locator.href).toBe("/spines/spine-3"); expect(result.locator.locations.position).toBe(138); - expect(result.createdAt).toBeDefined() + expect(result.createdAt).toBeDefined(); expect(result.updatedAt).toBeDefined(); expect(result.createdAt === result.updatedAt).toBeTruthy(); }); test("repository.save update", async () => { + if (!repository) { + return; + } const dbDoc = { identifier: "bookmark-1", locatorType: LocatorType.Bookmark, @@ -178,19 +211,22 @@ test("repository.save update", async () => { expect(result.locator.href).toBe("/spines/spine-1"); expect(result.locator.title).toBe("New bookmark"); expect(result.locator.locations.position).toBe(12); - expect(result.createdAt).toBeDefined() + expect(result.createdAt).toBeDefined(); expect(result.updatedAt).toBeDefined(); expect(result.createdAt < result.updatedAt).toBeTruthy(); }); test("repository.delete", async () => { + if (!db || !repository) { + return; + } const result = await db.get("locator_bookmark-1") as any; expect(result.identifier).toBe("bookmark-1"); // Delete locator 1 await repository.delete("bookmark-1"); try { - await db.get("bookmark-1") as any; + await db.get("bookmark-1"); } catch (e) { expect(e.message).toBe("missing"); } diff --git a/test/main/db/repository/opds.test.ts b/test/main/db/repository/opds.test.ts index 9127291125..467a519168 100644 --- a/test/main/db/repository/opds.test.ts +++ b/test/main/db/repository/opds.test.ts @@ -1,7 +1,6 @@ import "reflect-metadata"; import * as moment from "moment"; -import * as PouchDB from "pouchdb-core"; import { NotFoundError } from "readium-desktop/main/db/exceptions"; @@ -9,8 +8,8 @@ import { OpdsFeedRepository } from "readium-desktop/main/db/repository/opds"; import { clearDatabase, createDatabase } from "test/main/db/utils"; -let repository: OpdsFeedRepository = null; -let db: PouchDB.Database = null; +let repository: OpdsFeedRepository | null = null; +let db: PouchDB.Database | null = null; const now = moment.now(); const dbDocIdentifier1 = "feed-1"; @@ -43,16 +42,25 @@ beforeEach(async () => { }); afterEach(async () => { + if (!db) { + return; + } repository = null; await clearDatabase(db); }); test("repository.findAll", async () => { + if (!repository) { + return; + } const result = await repository.findAll(); expect(result.length).toBe(2); }); test("repository.get - found", async () => { + if (!repository) { + return; + } const result = await repository.get("feed-1"); expect(result.identifier).toBe("feed-1"); expect(result.title).toBe("Feed 1"); @@ -60,6 +68,9 @@ test("repository.get - found", async () => { }); test("repository.get - not found", async () => { + if (!repository) { + return; + } // Test unknown key try { await repository.get("feed-3"); @@ -70,6 +81,9 @@ test("repository.get - not found", async () => { }); test("repository.save create", async () => { + if (!repository) { + return; + } const dbDoc = { identifier: "new-feed", title: "New feed", @@ -85,6 +99,9 @@ test("repository.save create", async () => { }); test("repository.save update", async () => { + if (!repository) { + return; + } const dbDoc = { identifier: "feed-1", title: "New feed", @@ -100,6 +117,9 @@ test("repository.save update", async () => { }); test("repository.delete", async () => { + if (!db || !repository) { + return; + } const result = await db.get("opds-feed_feed-1") as any; expect(result.identifier).toBe("feed-1"); diff --git a/test/main/db/repository/publication.test.ts b/test/main/db/repository/publication.test.ts index 7bbbc941a2..f5b34c1e92 100644 --- a/test/main/db/repository/publication.test.ts +++ b/test/main/db/repository/publication.test.ts @@ -1,16 +1,15 @@ import "reflect-metadata"; import * as moment from "moment"; -import * as PouchDB from "pouchdb-core"; import { PublicationRepository } from "readium-desktop/main/db/repository/publication"; import { NotFoundError } from "readium-desktop/main/db/exceptions"; -import { clearDatabase, createDatabase, } from "test/main/db/utils"; +import { clearDatabase, createDatabase } from "test/main/db/utils"; -let repository: PublicationRepository = null; -let db: PouchDB.Database = null; +let repository: PublicationRepository | null = null; +let db: PouchDB.Database | null = null; const now = moment.now(); const dbDocIdentifier1 = "pub-1"; @@ -53,16 +52,25 @@ beforeEach(async () => { }); afterEach(async () => { + if (!db) { + return; + } repository = null; await clearDatabase(db); }); test("repository.findAll", async () => { + if (!repository) { + return; + } const result = await repository.findAll(); expect(result.length).toBe(2); }); test("repository.find limit 1", async () => { + if (!repository) { + return; + } const result = await repository.find({ limit: 1, }); @@ -70,6 +78,9 @@ test("repository.find limit 1", async () => { }); test("repository.find sort by createdAt", async () => { + if (!repository) { + return; + } const result = await repository.find({ sort: [{ createdAt: "asc" }], }); @@ -79,6 +90,9 @@ test("repository.find sort by createdAt", async () => { }); test("repository.findByTag - found", async () => { + if (!repository) { + return; + } let result = await repository.findByTag("computer"); expect(result.length).toBe(2); @@ -88,27 +102,42 @@ test("repository.findByTag - found", async () => { const pub = result[0]; expect(pub.identifier).toBe("pub-2"); expect(pub.title).toBe("Publication 2"); - expect(pub.tags.length).toBe(2); + expect(pub.tags).toBeDefined(); + if (pub.tags) { + expect(pub.tags.length).toBe(2); + } expect(pub.tags).toContain("computer"); expect(pub.tags).toContain("node"); }); test("repository.findByTag - not found", async () => { + if (!repository) { + return; + } const result = await repository.findByTag("unknown"); expect(result.length).toBe(0); }); test("repository.findByTitle - found", async () => { + if (!repository) { + return; + } const result = await repository.findByTitle("Publication 1"); expect(result.length).toBe(1); }); test("repository.findByTitle - not found", async () => { + if (!repository) { + return; + } const result = await repository.findByTitle("unknown"); expect(result.length).toBe(0); }); test("repository.searchByTitle - found", async () => { + if (!repository) { + return; + } let result = await repository.searchByTitle("publication"); expect(result.length).toBe(2); @@ -117,6 +146,9 @@ test("repository.searchByTitle - found", async () => { }); test("repository.getAllTags", async () => { + if (!repository) { + return; + } const tags = await repository.getAllTags(); expect(tags.length).toBe(3); expect(tags).toContain("computer"); @@ -124,17 +156,25 @@ test("repository.getAllTags", async () => { expect(tags).toContain("science"); }); - test("repository.get - found", async () => { + if (!repository) { + return; + } const result = await repository.get("pub-1"); expect(result.identifier).toBe("pub-1"); expect(result.title).toBe("Publication 1"); - expect(result.tags.length).toBe(2); + expect(result.tags).toBeDefined(); + if (result.tags) { + expect(result.tags.length).toBe(2); + } expect(result.tags).toContain("computer"); expect(result.tags).toContain("science"); }); test("repository.get - not found", async () => { + if (!repository) { + return; + } // Test unknown key try { await repository.get("pub-3"); @@ -145,6 +185,9 @@ test("repository.get - not found", async () => { }); test("repository.save create", async () => { + if (!repository) { + return; + } const dbDoc = { identifier: "new-publication", publication: null as any, @@ -158,7 +201,10 @@ test("repository.save create", async () => { const result = await repository.save(dbDoc); expect(result.identifier).toBe("new-publication"); expect(result.title).toBe("New publication"); - expect(result.tags.length).toBe(1); + expect(result.tags).toBeDefined(); + if (result.tags) { + expect(result.tags.length).toBe(1); + } expect(result.tags).toContain("scifi"); expect(result.createdAt).toBeDefined(); expect(result.updatedAt).toBeDefined(); @@ -166,6 +212,9 @@ test("repository.save create", async () => { }); test("repository.save update", async () => { + if (!repository) { + return; + } const dbDoc = { identifier: "pub-1", publication: null as any, @@ -179,7 +228,10 @@ test("repository.save update", async () => { const result = await repository.save(dbDoc); expect(result.identifier).toBe("pub-1"); expect(result.title).toBe("Publication 1"); - expect(result.tags.length).toBe(1); + expect(result.tags).toBeDefined(); + if (result.tags) { + expect(result.tags.length).toBe(1); + } expect(result.tags).toContain("computer"); expect(result.createdAt).toBeDefined(); expect(result.updatedAt).toBeDefined(); @@ -187,13 +239,16 @@ test("repository.save update", async () => { }); test("repository.delete", async () => { - let result = await db.get("publication_pub-1") as any; + if (!db || !repository) { + return; + } + const result = await db.get("publication_pub-1") as any; expect(result.identifier).toBe("pub-1"); // Delete publication 1 await repository.delete("pub-1"); try { - await db.get("pub-1") as any; + await db.get("pub-1"); } catch (e) { expect(e.message).toBe("missing"); } diff --git a/test/main/db/utils.ts b/test/main/db/utils.ts index 9780fb8920..328ccef024 100644 --- a/test/main/db/utils.ts +++ b/test/main/db/utils.ts @@ -4,7 +4,7 @@ export function createDatabase() { PouchDB.plugin(require("pouchdb-adapter-memory")); PouchDB.plugin(require("pouchdb-find")); PouchDB.plugin(require("pouchdb-quick-search")); - return new PouchDB("test-db", {adapter: "memory"}) + return new PouchDB("test-db", {adapter: "memory"}); } export async function clearDatabase(db: PouchDB.Database) { diff --git a/tsconfig-fail.json b/tsconfig-fail.json new file mode 100644 index 0000000000..6e3adfb265 --- /dev/null +++ b/tsconfig-fail.json @@ -0,0 +1,4 @@ +{ + "strictNullChecks": true, + "strictPropertyInitialization": true, +} diff --git a/tsconfig.json b/tsconfig.json index fb34d6f736..2dae7e9dff 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,8 +1,59 @@ { "compilerOptions": { + "plugins": [ + { + "name": "tslint-language-service", + "alwaysShowRuleFailuresAsWarnings": false, + "ignoreDefinitionFiles": true, + "configFile": "./tslint.json", + "disableNoUnusedVariableRule": false + } + ], + "outDir": "./dist/", "sourceMap": true, "noImplicitAny": true, + "noImplicitThis": true, + "alwaysStrict": true, + "strictFunctionTypes": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitUseStrict": false, + "declaration": true, + "noEmit": false, + "noEmitHelpers": true, + "importHelpers": true, + "noEmitOnError": false, + "noLib": false, + "noResolve": false, + "forceConsistentCasingInFileNames": false, + "inlineSources": true, + "inlineSourceMap": false, + "isolatedModules": false, + "allowJs": false, + "maxNodeModuleJsDepth": 0, + "checkJs": false, + "stripInternal": false, + "suppressExcessPropertyErrors": false, + "suppressImplicitAnyIndexErrors": false, + "charset": "utf8", + "downlevelIteration": false, + "emitBOM": false, + "allowSyntheticDefaultImports": false, + "allowUnreachableCode": false, + "allowUnusedLabels": false, + "pretty": true, + "diagnostics": false, + "listFiles": false, + "listEmittedFiles": false, + "traceResolution": false, + "disableSizeLimit": false, + "preserveConstEnums": false, + "removeComments": true, + "skipLibCheck": false, + "module": "commonjs", "lib": ["es2017", "es6", "dom"], "target": "es6", diff --git a/tslint.json b/tslint.json index 759e1acbe6..b50b8925aa 100644 --- a/tslint.json +++ b/tslint.json @@ -1,20 +1,46 @@ { "extends": "tslint:recommended", "rules": { + "no-reference": false, + "no-floating-promises": true, + "promise-function-async": true, + "await-promise": true, + "no-unused-expression": true, + "variable-name": [ + true, + "ban-keywords", + "check-format", + "allow-leading-underscore", + "allow-trailing-underscore", + "allow-pascal-case" + ], + "object-literal-sort-keys": false, "ordered-imports": [ true, { "import-sources-order": "case-insensitive", - "named-imports-order": "case-insensitive" + "named-imports-order": "case-insensitive", + "__named-imports-order": "lowercase-last" } ], - "object-literal-sort-keys": false, - "interface-name": [false], - "no-unused-variable": [true], - "no-console": [false], - "forin": false, - "prefer-for-of": false + "no-console": [ + false + ], + "interface-name": [ + false + ] + }, + "jsRules": { + "ordered-imports": [ + true, + { + "import-sources-order": "case-insensitive", + "named-imports-order": "case-insensitive", + "__named-imports-order": "lowercase-last" + } + ] }, + "rulesDirectory": [], "linterOptions": { "exclude": [ "src/typings/en.translation.d.ts"