From fb2e2f89935240666de66e4b2c11125cb3b2943d Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Tue, 7 Apr 2020 13:37:32 +0530 Subject: [PATCH] more lint fixes --- .eslintrc.js | 2 + .vscode/settings.json | 1 - Makefile | 2 +- package.json | 2 + src/android/index.ts | 9 +- src/crypto/primitives/kdf.ts | 4 +- src/crypto/primitives/sha256.ts | 10 +- src/crypto/talerCrypto.ts | 6 +- src/crypto/workers/cryptoApi.ts | 50 +++++---- src/crypto/workers/cryptoImplementation.ts | 31 +----- src/crypto/workers/nodeThreadWorker.ts | 20 ++-- src/crypto/workers/synchronousWorker.ts | 12 +- src/db.ts | 4 +- src/headless/bank.ts | 2 +- src/headless/clk.ts | 8 +- src/headless/helpers.ts | 4 +- src/headless/merchant.ts | 2 +- src/headless/taler-wallet-cli.ts | 13 ++- src/operations/balance.ts | 4 +- src/operations/exchanges.ts | 3 +- src/operations/pending.ts | 26 +++-- src/operations/recoup.ts | 4 +- src/operations/refresh.ts | 13 +-- src/operations/refund.ts | 2 +- src/operations/reserves.ts | 38 +++---- src/operations/state.ts | 2 +- src/operations/tip.ts | 7 +- src/operations/withdraw.ts | 20 +--- src/types/ReserveStatus.ts | 8 +- src/types/ReserveTransaction.ts | 123 +++++++++++---------- src/types/dbTypes.ts | 2 +- src/types/history.ts | 1 - src/types/notifications.ts | 9 +- src/types/pending.ts | 1 - src/types/talerTypes.ts | 30 ++--- src/types/walletTypes.ts | 20 ++-- src/util/RequestThrottler.ts | 7 +- src/util/amounts.ts | 10 +- src/util/codec.ts | 2 +- src/util/helpers.ts | 12 +- src/util/http.ts | 14 ++- src/util/query.ts | 6 +- src/util/talerconfig.ts | 2 - src/util/taleruri-test.ts | 2 +- src/util/taleruri.ts | 2 +- src/util/timer.ts | 1 - src/wallet.ts | 5 +- src/webex/compat.ts | 2 +- src/webex/i18n.tsx | 12 +- src/webex/messages.ts | 20 ---- src/webex/pageEntryPoint.ts | 2 +- src/webex/pages/add-auditor.tsx | 4 +- src/webex/pages/auditors.tsx | 21 ++-- src/webex/pages/pay.tsx | 2 +- src/webex/pages/payback.tsx | 2 +- src/webex/pages/popup.tsx | 26 ++--- src/webex/pages/refund.tsx | 6 +- src/webex/pages/reset-required.tsx | 8 +- src/webex/pages/return-coins.tsx | 5 +- src/webex/pages/tip.tsx | 19 ++-- src/webex/pages/welcome.tsx | 4 +- src/webex/pages/withdraw.tsx | 23 ++-- src/webex/renderHtml.tsx | 68 +++++++----- yarn.lock | 116 ++++++++++++++++++- 64 files changed, 486 insertions(+), 412 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 1cd05edd3..0d84f0f58 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -7,6 +7,7 @@ module.exports = { "plugin:@typescript-eslint/eslint-recommended", "plugin:@typescript-eslint/recommended", "plugin:react/recommended", + "plugin:react-hooks/recommended", ], settings: { "react": { @@ -18,6 +19,7 @@ module.exports = { "no-constant-condition": ["error", { "checkLoops": false }], "prefer-const": ["warn", { destructuring: "all" }], "@typescript-eslint/camelcase": "off", + "@typescript-eslint/ban-ts-ignore": "off", "@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/no-unused-vars": ["warn", { args: "none" }], "@typescript-eslint/explicit-function-return-type": [ diff --git a/.vscode/settings.json b/.vscode/settings.json index 6482c5da1..7f8edcba2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -34,7 +34,6 @@ }, "**/*.js.map": true }, - "tslint.enable": true, "editor.wrappingIndent": "same", "editor.tabSize": 2 } \ No newline at end of file diff --git a/Makefile b/Makefile index 46e7e0b2e..6d0bacbbc 100644 --- a/Makefile +++ b/Makefile @@ -82,4 +82,4 @@ rollup: tsc .PHONY: lint lint: - ./node_modules/.bin/eslint 'src/**/*' --ext '.js,.ts,.tsx' + ./node_modules/.bin/eslint --ext '.js,.ts,.tsx' 'src' diff --git a/package.json b/package.json index 91e263af5..eac8d69c0 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,9 @@ "@typescript-eslint/parser": "^2.26.0", "ava": "^3.6.0", "eslint": "^6.8.0", + "eslint-config-airbnb-typescript": "^7.2.0", "eslint-plugin-import": "^2.20.2", + "eslint-plugin-jsx-a11y": "^6.2.3", "eslint-plugin-react": "^7.19.0", "eslint-plugin-react-hooks": "^3.0.0", "jed": "^1.1.1", diff --git a/src/android/index.ts b/src/android/index.ts index 9c7efc0e1..019fe1fb3 100644 --- a/src/android/index.ts +++ b/src/android/index.ts @@ -32,7 +32,6 @@ import { Headers, } from "../util/http"; import { NodeHttpLib } from "../headless/NodeHttpLib"; -import { OperationFailedAndReportedError } from "../operations/errors"; import { WalletNotification } from "../types/notifications"; // @ts-ignore: special built-in module @@ -99,7 +98,7 @@ export class AndroidHttpLib implements HttpRequestLibrary { } } - handleTunnelResponse(msg: any) { + handleTunnelResponse(msg: any): void { const myId = msg.id; const p = this.requestMap[myId]; if (!p) { @@ -123,7 +122,7 @@ export class AndroidHttpLib implements HttpRequestLibrary { } } -function sendAkonoMessage(m: string) { +function sendAkonoMessage(m: string): void { // @ts-ignore globalThis.__akono_sendMessage(m); } @@ -266,7 +265,7 @@ class AndroidWalletMessageHandler { } } -export function installAndroidWalletListener() { +export function installAndroidWalletListener(): void { // @ts-ignore const sendMessage: (m: string) => void = globalThis.__akono_sendMessage; if (typeof sendMessage !== "function") { @@ -276,7 +275,7 @@ export function installAndroidWalletListener() { throw new Error(errMsg); } const handler = new AndroidWalletMessageHandler(); - const onMessage = async (msgStr: any) => { + const onMessage = async (msgStr: any): Promise => { if (typeof msgStr !== "string") { console.error("expected string as message"); return; diff --git a/src/crypto/primitives/kdf.ts b/src/crypto/primitives/kdf.ts index 03deb3727..edc681bc1 100644 --- a/src/crypto/primitives/kdf.ts +++ b/src/crypto/primitives/kdf.ts @@ -51,11 +51,11 @@ export function hmac( return digest(b2); } -export function hmacSha512(key: Uint8Array, message: Uint8Array) { +export function hmacSha512(key: Uint8Array, message: Uint8Array): Uint8Array { return hmac(sha512, 128, key, message); } -export function hmacSha256(key: Uint8Array, message: Uint8Array) { +export function hmacSha256(key: Uint8Array, message: Uint8Array): Uint8Array { return hmac(sha256, 64, key, message); } diff --git a/src/crypto/primitives/sha256.ts b/src/crypto/primitives/sha256.ts index ed88b5ffd..97723dbfc 100644 --- a/src/crypto/primitives/sha256.ts +++ b/src/crypto/primitives/sha256.ts @@ -215,7 +215,7 @@ export class HashSha256 { } // Cleans internal buffers and re-initializes hash state. - clean() { + clean(): void { for (let i = 0; i < this.buffer.length; i++) { this.buffer[i] = 0; } @@ -306,14 +306,14 @@ export class HashSha256 { } // Internal function for use in HMAC for optimization. - _saveState(out: Uint32Array) { + _saveState(out: Uint32Array): void { for (let i = 0; i < this.state.length; i++) { out[i] = this.state[i]; } } // Internal function for use in HMAC for optimization. - _restoreState(from: Uint32Array, bytesHashed: number) { + _restoreState(from: Uint32Array, bytesHashed: number): void { for (let i = 0; i < this.state.length; i++) { this.state[i] = from[i]; } @@ -376,7 +376,7 @@ export class HMAC { } // Cleans HMAC state. - clean() { + clean(): void { for (let i = 0; i < this.istate.length; i++) { this.ostate[i] = this.istate[i] = 0; } @@ -418,7 +418,7 @@ export function sha256(data: Uint8Array): Uint8Array { } // Returns HMAC-SHA256 of data under the key. -export function hmacSha256(key: Uint8Array, data: Uint8Array) { +export function hmacSha256(key: Uint8Array, data: Uint8Array): Uint8Array { const h = new HMAC(key).update(data); const digest = h.digest(); h.clean(); diff --git a/src/crypto/talerCrypto.ts b/src/crypto/talerCrypto.ts index 3da4f4a47..457009a04 100644 --- a/src/crypto/talerCrypto.ts +++ b/src/crypto/talerCrypto.ts @@ -191,12 +191,12 @@ function kdfMod( } } -export function stringToBytes(s: string) { +export function stringToBytes(s: string): Uint8Array { const te = new TextEncoder(); return te.encode(s); } -function loadBigInt(arr: Uint8Array) { +function loadBigInt(arr: Uint8Array): bigint.BigInteger { return bigint.fromArray(Array.from(arr), 256, false); } @@ -219,7 +219,7 @@ function rsaBlindingKeyDerive( * @param r KDF result * @param n RSA modulus of the public key */ -function rsaGcdValidate(r: bigint.BigInteger, n: bigint.BigInteger) { +function rsaGcdValidate(r: bigint.BigInteger, n: bigint.BigInteger): void { const t = bigint.gcd(r, n); if (!t.equals(bigint.one)) { throw Error("malicious RSA public key"); diff --git a/src/crypto/workers/cryptoApi.ts b/src/crypto/workers/cryptoApi.ts index 24a43ff47..456bf309e 100644 --- a/src/crypto/workers/cryptoApi.ts +++ b/src/crypto/workers/cryptoApi.ts @@ -34,13 +34,7 @@ import { import { CryptoWorker } from "./cryptoWorker"; -import { - RecoupRequest, - CoinDepositPermission, - RecoupConfirmation, - ExchangeSignKeyJson, - EddsaPublicKeyString, -} from "../../types/talerTypes"; +import { RecoupRequest, CoinDepositPermission } from "../../types/talerTypes"; import { BenchmarkResult, @@ -154,7 +148,7 @@ export class CryptoApi { /** * Terminate all worker threads. */ - terminateWorkers() { + terminateWorkers(): void { for (const worker of this.workers) { if (worker.w) { CryptoApi.enableTracing && console.log("terminating worker"); @@ -172,7 +166,7 @@ export class CryptoApi { } } - stop() { + stop(): void { this.terminateWorkers(); this.stopped = true; } @@ -192,11 +186,14 @@ export class CryptoApi { } ws.currentWorkItem = work; this.numBusy++; + let worker: CryptoWorker; if (!ws.w) { - const w = this.workerFactory.startWorker(); - w.onmessage = (m: MessageEvent) => this.handleWorkerMessage(ws, m); - w.onerror = (e: ErrorEvent) => this.handleWorkerError(ws, e); - ws.w = w; + worker = this.workerFactory.startWorker(); + worker.onmessage = (m: MessageEvent) => this.handleWorkerMessage(ws, m); + worker.onerror = (e: ErrorEvent) => this.handleWorkerError(ws, e); + ws.w = worker; + } else { + worker = ws.w; } const msg: any = { @@ -206,28 +203,28 @@ export class CryptoApi { }; this.resetWorkerTimeout(ws); work.startTime = timer.performanceNow(); - setTimeout(() => ws.w!.postMessage(msg), 0); + setTimeout(() => worker.postMessage(msg), 0); } - resetWorkerTimeout(ws: WorkerState) { + resetWorkerTimeout(ws: WorkerState): void { if (ws.terminationTimerHandle !== null) { ws.terminationTimerHandle.clear(); ws.terminationTimerHandle = null; } - const destroy = () => { + const destroy = (): void => { // terminate worker if it's idle if (ws.w && ws.currentWorkItem === null) { - ws.w!.terminate(); + ws.w.terminate(); ws.w = null; } }; ws.terminationTimerHandle = timer.after(15 * 1000, destroy); } - handleWorkerError(ws: WorkerState, e: ErrorEvent) { + handleWorkerError(ws: WorkerState, e: ErrorEvent): void { if (ws.currentWorkItem) { console.error( - `error in worker during ${ws.currentWorkItem!.operation}`, + `error in worker during ${ws.currentWorkItem.operation}`, e, ); } else { @@ -235,8 +232,10 @@ export class CryptoApi { } console.error(e.message); try { - ws.w!.terminate(); - ws.w = null; + if (ws.w) { + ws.w.terminate(); + ws.w = null; + } } catch (e) { console.error(e); } @@ -248,19 +247,22 @@ export class CryptoApi { this.findWork(ws); } - private findWork(ws: WorkerState) { + private findWork(ws: WorkerState): void { // try to find more work for this worker for (let i = 0; i < NUM_PRIO; i++) { const q = this.workQueues[NUM_PRIO - i - 1]; if (q.length !== 0) { - const work: WorkItem = q.shift()!; + const work: WorkItem | undefined = q.shift(); + if (!work) { + continue; + } this.wake(ws, work); return; } } } - handleWorkerMessage(ws: WorkerState, msg: MessageEvent) { + handleWorkerMessage(ws: WorkerState, msg: MessageEvent): void { const id = msg.data.id; if (typeof id !== "number") { console.error("rpc id must be number"); diff --git a/src/crypto/workers/cryptoImplementation.ts b/src/crypto/workers/cryptoImplementation.ts index 0a3c217ab..96ad29bc0 100644 --- a/src/crypto/workers/cryptoImplementation.ts +++ b/src/crypto/workers/cryptoImplementation.ts @@ -36,13 +36,7 @@ import { CoinSourceType, } from "../../types/dbTypes"; -import { - CoinDepositPermission, - RecoupRequest, - RecoupConfirmation, - ExchangeSignKeyJson, - EddsaPublicKeyString, -} from "../../types/talerTypes"; +import { CoinDepositPermission, RecoupRequest } from "../../types/talerTypes"; import { BenchmarkResult, PlanchetCreationResult, @@ -70,11 +64,7 @@ import { } from "../talerCrypto"; import { randomBytes } from "../primitives/nacl-fast"; import { kdf } from "../primitives/kdf"; -import { - Timestamp, - getTimestampNow, - timestampIsBetween, -} from "../../util/time"; +import { Timestamp, getTimestampNow } from "../../util/time"; enum SignaturePurpose { RESERVE_WITHDRAW = 1200, @@ -144,24 +134,9 @@ function buildSigPS(purposeNum: number): SignaturePurposeBuilder { return new SignaturePurposeBuilder(purposeNum); } -function checkSignKeyOkay( - key: string, - exchangeKeys: ExchangeSignKeyJson[], -): boolean { - const now = getTimestampNow(); - for (const k of exchangeKeys) { - if (k.key == key) { - return timestampIsBetween(now, k.stamp_start, k.stamp_end); - } - } - return false; -} - export class CryptoImplementation { static enableTracing = false; - constructor() {} - /** * Create a pre-coin of the given denomination to be withdrawn from then given * reserve. @@ -535,7 +510,7 @@ export class CryptoImplementation { let time_eddsa_create = 0; for (let i = 0; i < repetitions; i++) { const start = timer.performanceNow(); - const pair = createEddsaKeyPair(); + createEddsaKeyPair(); time_eddsa_create += timer.performanceNow() - start; } diff --git a/src/crypto/workers/nodeThreadWorker.ts b/src/crypto/workers/nodeThreadWorker.ts index d289c14b2..6c9dfc569 100644 --- a/src/crypto/workers/nodeThreadWorker.ts +++ b/src/crypto/workers/nodeThreadWorker.ts @@ -1,5 +1,3 @@ -import { CryptoWorkerFactory } from "./cryptoApi"; - /* This file is part of TALER (C) 2016 GNUnet e.V. @@ -16,8 +14,10 @@ import { CryptoWorkerFactory } from "./cryptoApi"; TALER; see the file COPYING. If not, see */ -// tslint:disable:no-var-requires - +/** + * Imports + */ +import { CryptoWorkerFactory } from "./cryptoApi"; import { CryptoWorker } from "./cryptoWorker"; import os from "os"; import { CryptoImplementation } from "./cryptoImplementation"; @@ -55,7 +55,7 @@ const workerCode = ` * This function is executed in the worker thread to handle * a message. */ -export function handleWorkerMessage(msg: any) { +export function handleWorkerMessage(msg: any): void { const args = msg.args; if (!Array.isArray(args)) { console.error("args must be array"); @@ -72,7 +72,7 @@ export function handleWorkerMessage(msg: any) { return; } - const handleRequest = async () => { + const handleRequest = async (): Promise => { const impl = new CryptoImplementation(); if (!(operation in impl)) { @@ -82,6 +82,7 @@ export function handleWorkerMessage(msg: any) { try { const result = (impl as any)[operation](...args); + // eslint-disable-next-line @typescript-eslint/no-var-requires const worker_threads = require("worker_threads"); const p = worker_threads.parentPort; worker_threads.parentPort?.postMessage; @@ -101,7 +102,7 @@ export function handleWorkerMessage(msg: any) { }); } -export function handleWorkerError(e: Error) { +export function handleWorkerError(e: Error): void { console.log("got error from worker", e); } @@ -135,6 +136,7 @@ class NodeThreadCryptoWorker implements CryptoWorker { private nodeWorker: import("worker_threads").Worker; constructor() { + // eslint-disable-next-line @typescript-eslint/no-var-requires const worker_threads = require("worker_threads"); this.nodeWorker = new worker_threads.Worker(workerCode, { eval: true }); this.nodeWorker.on("error", (err: Error) => { @@ -168,14 +170,14 @@ class NodeThreadCryptoWorker implements CryptoWorker { /** * Send a message to the worker thread. */ - postMessage(msg: any) { + postMessage(msg: any): void { this.nodeWorker.postMessage(msg); } /** * Forcibly terminate the worker thread. */ - terminate() { + terminate(): void { this.nodeWorker.terminate(); } } diff --git a/src/crypto/workers/synchronousWorker.ts b/src/crypto/workers/synchronousWorker.ts index f4bcf396c..2cc740975 100644 --- a/src/crypto/workers/synchronousWorker.ts +++ b/src/crypto/workers/synchronousWorker.ts @@ -70,13 +70,17 @@ export class SynchronousCryptoWorker { } } - private dispatchMessage(msg: any) { + private dispatchMessage(msg: any): void { if (this.onmessage) { this.onmessage({ data: msg }); } } - private async handleRequest(operation: string, id: number, args: string[]) { + private async handleRequest( + operation: string, + id: number, + args: string[], + ): Promise { const impl = new CryptoImplementation(); if (!(operation in impl)) { @@ -102,7 +106,7 @@ export class SynchronousCryptoWorker { /** * Send a message to the worker thread. */ - postMessage(msg: any) { + postMessage(msg: any): void { const args = msg.args; if (!Array.isArray(args)) { console.error("args must be array"); @@ -127,7 +131,7 @@ export class SynchronousCryptoWorker { /** * Forcibly terminate the worker thread. */ - terminate() { + terminate(): void { // This is a no-op. } } diff --git a/src/db.ts b/src/db.ts index da43cf827..18efbf2b0 100644 --- a/src/db.ts +++ b/src/db.ts @@ -23,7 +23,7 @@ export function openTalerDatabase( db: IDBDatabase, oldVersion: number, newVersion: number, - ) => { + ): void => { switch (oldVersion) { case 0: // DB does not exist yet for (const n in Stores) { @@ -53,6 +53,6 @@ export function openTalerDatabase( ); } -export function deleteTalerDatabase(idbFactory: IDBFactory) { +export function deleteTalerDatabase(idbFactory: IDBFactory): void { Database.deleteDatabase(idbFactory, TALER_DB_NAME); } diff --git a/src/headless/bank.ts b/src/headless/bank.ts index 81b5293bd..2177908a6 100644 --- a/src/headless/bank.ts +++ b/src/headless/bank.ts @@ -95,7 +95,7 @@ export class Bank { amount: string, reservePub: string, exchangePaytoUri: string, - ) { + ): Promise { const reqUrl = new URL("testing/withdraw", this.bankBaseUrl).href; const body = { diff --git a/src/headless/clk.ts b/src/headless/clk.ts index 09f758ad4..a905464bd 100644 --- a/src/headless/clk.ts +++ b/src/headless/clk.ts @@ -117,7 +117,7 @@ export class CommandGroup { private scArgs: SubcommandArgs, ) {} - action(f: ActionFn) { + action(f: ActionFn): void { if (this.myAction) { throw Error("only one action supported per command"); } @@ -269,7 +269,7 @@ export class CommandGroup { return cg as any; } - printHelp(progName: string, parents: CommandGroup[]) { + printHelp(progName: string, parents: CommandGroup[]): void { let usageSpec = ""; for (const p of parents) { usageSpec += (p.name ?? progName) + " "; @@ -320,7 +320,7 @@ export class CommandGroup { parents: CommandGroup[], unparsedArgs: string[], parsedArgs: any, - ) { + ): void { let posArgIndex = 0; let argsTerminated = false; let i; @@ -507,7 +507,7 @@ export class Program { }); } - run() { + run(): void { const args = process.argv; if (args.length < 2) { console.error( diff --git a/src/headless/helpers.ts b/src/headless/helpers.ts index 11e2c90de..47a0844bd 100644 --- a/src/headless/helpers.ts +++ b/src/headless/helpers.ts @@ -106,7 +106,7 @@ export async function getDefaultNodeWallet( myHttpLib = new NodeHttpLib(); } - const myVersionChange = () => { + const myVersionChange = (): Promise => { console.error("version change requested, should not happen"); throw Error(); }; @@ -141,7 +141,7 @@ export async function withdrawTestBalance( amount = "TESTKUDOS:10", bankBaseUrl = "https://bank.test.taler.net/", exchangeBaseUrl = "https://exchange.test.taler.net/", -) { +): Promise { const reserveResponse = await myWallet.createReserve({ amount: amounts.parseOrThrow(amount), exchange: exchangeBaseUrl, diff --git a/src/headless/merchant.ts b/src/headless/merchant.ts index 27e7e3f21..b479c5a8a 100644 --- a/src/headless/merchant.ts +++ b/src/headless/merchant.ts @@ -65,7 +65,7 @@ export class MerchantBackendConnection { constructor(public merchantBaseUrl: string, public apiKey: string) {} - async authorizeTip(amount: string, justification: string) { + async authorizeTip(amount: string, justification: string): Promise { const reqUrl = new URL("tip-authorize", this.merchantBaseUrl).href; const tipReq = { amount, diff --git a/src/headless/taler-wallet-cli.ts b/src/headless/taler-wallet-cli.ts index a7dcce9a3..3da01a2dd 100644 --- a/src/headless/taler-wallet-cli.ts +++ b/src/headless/taler-wallet-cli.ts @@ -22,7 +22,7 @@ import { runIntegrationTest, runIntegrationTestBasic } from "./integrationtest"; import { Wallet } from "../wallet"; import qrcodeGenerator from "qrcode-generator"; import * as clk from "./clk"; -import { BridgeIDBFactory, MemoryBackend } from "idb-bridge"; +import { BridgeIDBFactory } from "idb-bridge"; import { Logger } from "../util/logging"; import { Amounts } from "../util/amounts"; import { decodeCrock } from "../crypto/talerCrypto"; @@ -46,7 +46,7 @@ async function doPay( wallet: Wallet, payUrl: string, options: { alwaysYes: boolean } = { alwaysYes: true }, -) { +): Promise { const result = await wallet.preparePayForUri(payUrl); if (result.status === "error") { console.error("Could not pay:", result.error); @@ -89,21 +89,22 @@ async function doPay( } if (pay) { - const payRes = await wallet.confirmPay(result.proposalId, undefined); + await wallet.confirmPay(result.proposalId, undefined); console.log("paid!"); } else { console.log("not paying"); } } -function applyVerbose(verbose: boolean) { +function applyVerbose(verbose: boolean): void { if (verbose) { console.log("enabled verbose logging"); BridgeIDBFactory.enableTracing = true; } } -function printVersion() { +function printVersion(): void { + // eslint-disable-next-line @typescript-eslint/no-var-requires const info = require("../../../package.json"); console.log(`${info.version}`); process.exit(0); @@ -329,7 +330,7 @@ exchangesCli .flag("force", ["-f", "--force"]) .action(async (args) => { await withWallet(args, async (wallet) => { - const res = await wallet.updateExchangeFromUrl( + await wallet.updateExchangeFromUrl( args.exchangesUpdateCmd.url, args.exchangesUpdateCmd.force, ); diff --git a/src/operations/balance.ts b/src/operations/balance.ts index 7c2d0e3fe..c369af193 100644 --- a/src/operations/balance.ts +++ b/src/operations/balance.ts @@ -18,9 +18,9 @@ * Imports. */ import { WalletBalance, WalletBalanceEntry } from "../types/walletTypes"; -import { Database, TransactionHandle } from "../util/query"; +import { TransactionHandle } from "../util/query"; import { InternalWalletState } from "./state"; -import { Stores, TipRecord, CoinStatus } from "../types/dbTypes"; +import { Stores, CoinStatus } from "../types/dbTypes"; import * as Amounts from "../util/amounts"; import { AmountJson } from "../util/amounts"; import { Logger } from "../util/logging"; diff --git a/src/operations/exchanges.ts b/src/operations/exchanges.ts index 27fed0b6c..a9e5158e9 100644 --- a/src/operations/exchanges.ts +++ b/src/operations/exchanges.ts @@ -460,7 +460,8 @@ export async function updateExchangeFromUrl( baseUrl: string, forceNow = false, ): Promise { - const onOpErr = (e: OperationError): Promise => setExchangeError(ws, baseUrl, e); + const onOpErr = (e: OperationError): Promise => + setExchangeError(ws, baseUrl, e); return await guardOperationException( () => updateExchangeFromUrlImpl(ws, baseUrl, forceNow), onOpErr, diff --git a/src/operations/pending.ts b/src/operations/pending.ts index cee929aa2..3e548a27f 100644 --- a/src/operations/pending.ts +++ b/src/operations/pending.ts @@ -37,7 +37,7 @@ import { } from "../util/time"; import { TransactionHandle } from "../util/query"; import { InternalWalletState } from "./state"; -import { getBalances, getBalancesInsideTransaction } from "./balance"; +import { getBalancesInsideTransaction } from "./balance"; import { ReserveType } from "../types/history"; function updateRetryDelay( @@ -286,13 +286,23 @@ async function gatherProposalPending( if (onlyDue) { return; } - resp.pendingOperations.push({ - type: PendingOperationType.ProposalChoice, - givesLifeness: false, - merchantBaseUrl: proposal.download!!.contractData.merchantBaseUrl, - proposalId: proposal.proposalId, - proposalTimestamp: proposal.timestamp, - }); + const dl = proposal.download; + if (!dl) { + resp.pendingOperations.push({ + type: PendingOperationType.Bug, + message: "proposal is in invalid state", + details: {}, + givesLifeness: false, + }); + } else { + resp.pendingOperations.push({ + type: PendingOperationType.ProposalChoice, + givesLifeness: false, + merchantBaseUrl: dl.contractData.merchantBaseUrl, + proposalId: proposal.proposalId, + proposalTimestamp: proposal.timestamp, + }); + } } else if (proposal.proposalStatus == ProposalStatus.DOWNLOADING) { resp.nextRetryDelay = updateRetryDelay( resp.nextRetryDelay, diff --git a/src/operations/recoup.ts b/src/operations/recoup.ts index 97bc39564..e1c2325d7 100644 --- a/src/operations/recoup.ts +++ b/src/operations/recoup.ts @@ -279,7 +279,7 @@ async function recoupRefreshCoin( async function resetRecoupGroupRetry( ws: InternalWalletState, recoupGroupId: string, -) { +): Promise { await ws.db.mutate(Stores.recoupGroups, recoupGroupId, (x) => { if (x.retryInfo.active) { x.retryInfo = initRetryInfo(); @@ -294,7 +294,7 @@ export async function processRecoupGroup( forceNow = false, ): Promise { await ws.memoProcessRecoup.memo(recoupGroupId, async () => { - const onOpErr = (e: OperationError) => + const onOpErr = (e: OperationError): Promise => incrementRecoupRetry(ws, recoupGroupId, e); return await guardOperationException( async () => await processRecoupGroupImpl(ws, recoupGroupId, forceNow), diff --git a/src/operations/refresh.ts b/src/operations/refresh.ts index 23d192e0a..924769334 100644 --- a/src/operations/refresh.ts +++ b/src/operations/refresh.ts @@ -28,7 +28,7 @@ import { CoinSourceType, } from "../types/dbTypes"; import { amountToPretty } from "../util/helpers"; -import { Database, TransactionHandle } from "../util/query"; +import { TransactionHandle } from "../util/query"; import { InternalWalletState } from "./state"; import { Logger } from "../util/logging"; import { getWithdrawDenomList } from "./withdraw"; @@ -390,8 +390,7 @@ async function refreshReveal( console.error("denom not found"); continue; } - const pc = - refreshSession.planchetsForGammas[refreshSession.norevealIndex!][i]; + const pc = refreshSession.planchetsForGammas[norevealIndex][i]; const denomSig = await ws.cryptoApi.rsaUnblind( respJson.ev_sigs[i].ev_sig, pc.blindingKey, @@ -485,7 +484,7 @@ export async function processRefreshGroup( forceNow = false, ): Promise { await ws.memoProcessRefresh.memo(refreshGroupId, async () => { - const onOpErr = (e: OperationError) => + const onOpErr = (e: OperationError): Promise => incrementRefreshRetry(ws, refreshGroupId, e); return await guardOperationException( async () => await processRefreshGroupImpl(ws, refreshGroupId, forceNow), @@ -497,7 +496,7 @@ export async function processRefreshGroup( async function resetRefreshGroupRetry( ws: InternalWalletState, refreshSessionId: string, -) { +): Promise { await ws.db.mutate(Stores.refreshGroups, refreshSessionId, (x) => { if (x.retryInfo.active) { x.retryInfo = initRetryInfo(); @@ -510,7 +509,7 @@ async function processRefreshGroupImpl( ws: InternalWalletState, refreshGroupId: string, forceNow: boolean, -) { +): Promise { if (forceNow) { await resetRefreshGroupRetry(ws, refreshGroupId); } @@ -532,7 +531,7 @@ async function processRefreshSession( ws: InternalWalletState, refreshGroupId: string, coinIndex: number, -) { +): Promise { logger.trace( `processing refresh session for coin ${coinIndex} of group ${refreshGroupId}`, ); diff --git a/src/operations/refund.ts b/src/operations/refund.ts index af9a48895..8feb2baea 100644 --- a/src/operations/refund.ts +++ b/src/operations/refund.ts @@ -465,7 +465,7 @@ async function processPurchaseApplyRefundImpl( // Avoid duplicates const refreshCoinsMap: { [coinPub: string]: CoinPublicKey } = {}; - const modCoin = async (perm: MerchantRefundPermission) => { + const modCoin = async (perm: MerchantRefundPermission): Promise => { const c = await tx.get(Stores.coins, perm.coin_pub); if (!c) { console.warn("coin not found, can't apply refund"); diff --git a/src/operations/reserves.ts b/src/operations/reserves.ts index 2ee1b358f..153ad6b88 100644 --- a/src/operations/reserves.ts +++ b/src/operations/reserves.ts @@ -44,10 +44,7 @@ import { getExchangeTrust, getExchangePaytoUri, } from "./exchanges"; -import { - WithdrawOperationStatusResponse, - codecForWithdrawOperationStatusResponse, -} from "../types/talerTypes"; +import { codecForWithdrawOperationStatusResponse } from "../types/talerTypes"; import { assertUnreachable } from "../util/assertUnreachable"; import { encodeCrock, getRandomBytes } from "../crypto/talerCrypto"; import { randomBytes } from "../crypto/primitives/nacl-fast"; @@ -71,7 +68,10 @@ import { const logger = new Logger("reserves.ts"); -async function resetReserveRetry(ws: InternalWalletState, reservePub: string) { +async function resetReserveRetry( + ws: InternalWalletState, + reservePub: string, +): Promise { await ws.db.mutate(Stores.reserves, reservePub, (x) => { if (x.retryInfo.active) { x.retryInfo = initRetryInfo(); @@ -101,8 +101,6 @@ export async function createReserve( reserveStatus = ReserveRecordStatus.UNCONFIRMED; } - const currency = req.amount.currency; - const reserveRecord: ReserveRecord = { timestampCreated: now, exchangeBaseUrl: canonExchange, @@ -251,7 +249,7 @@ export async function processReserve( forceNow = false, ): Promise { return ws.memoProcessReserve.memo(reservePub, async () => { - const onOpError = (err: OperationError) => + const onOpError = (err: OperationError): Promise => incrementReserveRetry(ws, reservePub, err); await guardOperationException( () => processReserveImpl(ws, reservePub, forceNow), @@ -280,7 +278,8 @@ async function registerReserveWithBank( if (reserve.timestampReserveInfoPosted) { throw Error("bank claims that reserve info selection is not done"); } - const bankResp = await ws.http.postJson(bankStatusUrl, { + // FIXME: parse bank response + await ws.http.postJson(bankStatusUrl, { reserve_pub: reservePub, selected_exchange: reserve.exchangeWire, }); @@ -305,7 +304,7 @@ export async function processReserveBankStatus( ws: InternalWalletState, reservePub: string, ): Promise { - const onOpError = (err: OperationError) => + const onOpError = (err: OperationError): Promise => incrementReserveRetry(ws, reservePub, err); await guardOperationException( () => processReserveBankStatusImpl(ws, reservePub), @@ -330,20 +329,13 @@ async function processReserveBankStatusImpl( return; } - let status: WithdrawOperationStatusResponse; - try { - const statusResp = await ws.http.get(bankStatusUrl); - if (statusResp.status !== 200) { - throw Error( - `unexpected status ${statusResp.status} for bank status query`, - ); - } - status = codecForWithdrawOperationStatusResponse().decode( - await statusResp.json(), - ); - } catch (e) { - throw e; + const statusResp = await ws.http.get(bankStatusUrl); + if (statusResp.status !== 200) { + throw Error(`unexpected status ${statusResp.status} for bank status query`); } + const status = codecForWithdrawOperationStatusResponse().decode( + await statusResp.json(), + ); ws.notify({ type: NotificationType.Wildcard }); diff --git a/src/operations/state.ts b/src/operations/state.ts index 246a71266..97d591244 100644 --- a/src/operations/state.ts +++ b/src/operations/state.ts @@ -49,7 +49,7 @@ export class InternalWalletState { this.cryptoApi = new CryptoApi(cryptoWorkerFactory); } - public notify(n: WalletNotification) { + public notify(n: WalletNotification): void { logger.trace("Notification", n); for (const l of this.listeners) { const nc = JSON.parse(JSON.stringify(n)); diff --git a/src/operations/tip.ts b/src/operations/tip.ts index 1a88dbca3..6f492ea31 100644 --- a/src/operations/tip.ts +++ b/src/operations/tip.ts @@ -18,9 +18,7 @@ import { InternalWalletState } from "./state"; import { parseTipUri } from "../util/taleruri"; import { TipStatus, OperationError } from "../types/walletTypes"; import { - TipPickupGetResponse, TipPlanchetDetail, - TipResponse, codecForTipPickupGetResponse, codecForTipResponse, } from "../types/talerTypes"; @@ -149,7 +147,8 @@ export async function processTip( tipId: string, forceNow = false, ): Promise { - const onOpErr = (e: OperationError) => incrementTipRetry(ws, tipId, e); + const onOpErr = (e: OperationError): Promise => + incrementTipRetry(ws, tipId, e); await guardOperationException( () => processTipImpl(ws, tipId, forceNow), onOpErr, @@ -172,7 +171,7 @@ async function processTipImpl( ws: InternalWalletState, tipId: string, forceNow: boolean, -) { +): Promise { if (forceNow) { await resetTipRetry(ws, tipId); } diff --git a/src/operations/withdraw.ts b/src/operations/withdraw.ts index 70ecf9aed..1f5bfd0b9 100644 --- a/src/operations/withdraw.ts +++ b/src/operations/withdraw.ts @@ -21,7 +21,6 @@ import { DenominationStatus, CoinStatus, CoinRecord, - PlanchetRecord, initRetryInfo, updateRetryInfoTimeout, CoinSourceType, @@ -52,14 +51,10 @@ import { timestampCmp, timestampSubtractDuraction, } from "../util/time"; -import { - summarizeReserveHistory, - ReserveHistorySummary, -} from "../util/reserveHistoryUtil"; const logger = new Logger("withdraw.ts"); -function isWithdrawableDenom(d: DenominationRecord) { +function isWithdrawableDenom(d: DenominationRecord): boolean { const now = getTimestampNow(); const started = timestampCmp(now, d.stampStart) >= 0; const lastPossibleWithdraw = timestampSubtractDuraction( @@ -175,8 +170,6 @@ async function processPlanchet( if (withdrawalGroup.withdrawn[coinIdx]) { return; } - if (withdrawalGroup.source.type === "reserve") { - } const planchet = withdrawalGroup.planchets[coinIdx]; if (!planchet) { console.log("processPlanchet: planchet not found"); @@ -248,7 +241,6 @@ async function processPlanchet( }; let withdrawalGroupFinished = false; - let summary: ReserveHistorySummary | undefined = undefined; const success = await ws.db.runWithWriteTransaction( [Stores.coins, Stores.withdrawalGroups, Stores.reserves], @@ -276,12 +268,6 @@ async function processPlanchet( withdrawalGroupFinished = true; } await tx.put(Stores.withdrawalGroups, ws); - if (!planchet.isFromTip) { - const r = await tx.get(Stores.reserves, planchet.reservePub); - if (r) { - summary = summarizeReserveHistory(r.reserveTransactions, r.currency); - } - } await tx.add(Stores.coins, coin); return true; }, @@ -396,7 +382,7 @@ export async function processWithdrawGroup( withdrawalGroupId: string, forceNow = false, ): Promise { - const onOpErr = (e: OperationError) => + const onOpErr = (e: OperationError): Promise => incrementWithdrawalRetry(ws, withdrawalGroupId, e); await guardOperationException( () => processWithdrawGroupImpl(ws, withdrawalGroupId, forceNow), @@ -407,7 +393,7 @@ export async function processWithdrawGroup( async function resetWithdrawalGroupRetry( ws: InternalWalletState, withdrawalGroupId: string, -) { +): Promise { await ws.db.mutate(Stores.withdrawalGroups, withdrawalGroupId, (x) => { if (x.retryInfo.active) { x.retryInfo = initRetryInfo(); diff --git a/src/types/ReserveStatus.ts b/src/types/ReserveStatus.ts index 5a3011b37..18601b9a7 100644 --- a/src/types/ReserveStatus.ts +++ b/src/types/ReserveStatus.ts @@ -51,7 +51,7 @@ export interface ReserveStatus { } export const codecForReserveStatus = (): Codec => - makeCodecForObject() - .property("balance", codecForString) - .property("history", makeCodecForList(codecForReserveTransaction())) - .build("ReserveStatus"); + makeCodecForObject() + .property("balance", codecForString) + .property("history", makeCodecForList(codecForReserveTransaction())) + .build("ReserveStatus"); diff --git a/src/types/ReserveTransaction.ts b/src/types/ReserveTransaction.ts index acbd502ea..bdd9b0f93 100644 --- a/src/types/ReserveTransaction.ts +++ b/src/types/ReserveTransaction.ts @@ -179,67 +179,72 @@ export type ReserveTransaction = | ReserveClosingTransaction | ReserveRecoupTransaction; -export const codecForReserveWithdrawTransaction = (): Codec => - makeCodecForObject() - .property("amount", codecForString) - .property("h_coin_envelope", codecForString) - .property("h_denom_pub", codecForString) - .property("reserve_sig", codecForString) - .property( - "type", - makeCodecForConstString(ReserveTransactionType.Withdraw), - ) - .property("withdraw_fee", codecForString) - .build("ReserveWithdrawTransaction"); +export const codecForReserveWithdrawTransaction = (): Codec< + ReserveWithdrawTransaction +> => + makeCodecForObject() + .property("amount", codecForString) + .property("h_coin_envelope", codecForString) + .property("h_denom_pub", codecForString) + .property("reserve_sig", codecForString) + .property("type", makeCodecForConstString(ReserveTransactionType.Withdraw)) + .property("withdraw_fee", codecForString) + .build("ReserveWithdrawTransaction"); -export const codecForReserveCreditTransaction = (): Codec => - makeCodecForObject() - .property("amount", codecForString) - .property("sender_account_url", codecForString) - .property("timestamp", codecForTimestamp) - .property("wire_reference", codecForString) - .property("type", makeCodecForConstString(ReserveTransactionType.Credit)) - .build("ReserveCreditTransaction"); +export const codecForReserveCreditTransaction = (): Codec< + ReserveCreditTransaction +> => + makeCodecForObject() + .property("amount", codecForString) + .property("sender_account_url", codecForString) + .property("timestamp", codecForTimestamp) + .property("wire_reference", codecForString) + .property("type", makeCodecForConstString(ReserveTransactionType.Credit)) + .build("ReserveCreditTransaction"); -export const codecForReserveClosingTransaction = (): Codec => - makeCodecForObject() - .property("amount", codecForString) - .property("closing_fee", codecForString) - .property("exchange_pub", codecForString) - .property("exchange_sig", codecForString) - .property("h_wire", codecForString) - .property("timestamp", codecForTimestamp) - .property("type", makeCodecForConstString(ReserveTransactionType.Closing)) - .property("wtid", codecForString) - .build("ReserveClosingTransaction"); +export const codecForReserveClosingTransaction = (): Codec< + ReserveClosingTransaction +> => + makeCodecForObject() + .property("amount", codecForString) + .property("closing_fee", codecForString) + .property("exchange_pub", codecForString) + .property("exchange_sig", codecForString) + .property("h_wire", codecForString) + .property("timestamp", codecForTimestamp) + .property("type", makeCodecForConstString(ReserveTransactionType.Closing)) + .property("wtid", codecForString) + .build("ReserveClosingTransaction"); -export const codecForReserveRecoupTransaction = (): Codec => - makeCodecForObject() - .property("amount", codecForString) - .property("coin_pub", codecForString) - .property("exchange_pub", codecForString) - .property("exchange_sig", codecForString) - .property("timestamp", codecForTimestamp) - .property("type", makeCodecForConstString(ReserveTransactionType.Recoup)) - .build("ReserveRecoupTransaction"); +export const codecForReserveRecoupTransaction = (): Codec< + ReserveRecoupTransaction +> => + makeCodecForObject() + .property("amount", codecForString) + .property("coin_pub", codecForString) + .property("exchange_pub", codecForString) + .property("exchange_sig", codecForString) + .property("timestamp", codecForTimestamp) + .property("type", makeCodecForConstString(ReserveTransactionType.Recoup)) + .build("ReserveRecoupTransaction"); export const codecForReserveTransaction = (): Codec => - makeCodecForUnion() - .discriminateOn("type") - .alternative( - ReserveTransactionType.Withdraw, - codecForReserveWithdrawTransaction(), - ) - .alternative( - ReserveTransactionType.Closing, - codecForReserveClosingTransaction(), - ) - .alternative( - ReserveTransactionType.Recoup, - codecForReserveRecoupTransaction(), - ) - .alternative( - ReserveTransactionType.Credit, - codecForReserveCreditTransaction(), - ) - .build("ReserveTransaction"); + makeCodecForUnion() + .discriminateOn("type") + .alternative( + ReserveTransactionType.Withdraw, + codecForReserveWithdrawTransaction(), + ) + .alternative( + ReserveTransactionType.Closing, + codecForReserveClosingTransaction(), + ) + .alternative( + ReserveTransactionType.Recoup, + codecForReserveRecoupTransaction(), + ) + .alternative( + ReserveTransactionType.Credit, + codecForReserveCreditTransaction(), + ) + .build("ReserveTransaction"); diff --git a/src/types/dbTypes.ts b/src/types/dbTypes.ts index 434993cb5..009b05315 100644 --- a/src/types/dbTypes.ts +++ b/src/types/dbTypes.ts @@ -43,7 +43,6 @@ import { ReserveRecoupTransaction, } from "./ReserveTransaction"; import { Timestamp, Duration, getTimestampNow } from "../util/time"; -import { Wallet } from "../wallet"; export enum ReserveRecordStatus { /** @@ -1524,6 +1523,7 @@ export class WalletImportRecord { /** * The stores and indices for the wallet database. */ +// eslint-disable-next-line @typescript-eslint/no-namespace export namespace Stores { class ExchangesStore extends Store { constructor() { diff --git a/src/types/history.ts b/src/types/history.ts index 8179f6261..a5f4e9d3f 100644 --- a/src/types/history.ts +++ b/src/types/history.ts @@ -22,7 +22,6 @@ * Imports. */ import { RefreshReason } from "./walletTypes"; -import { ReserveTransaction } from "./ReserveTransaction"; import { WithdrawalSource } from "./dbTypes"; import { Timestamp } from "../util/time"; diff --git a/src/types/notifications.ts b/src/types/notifications.ts index 05d3c273a..3cd5be898 100644 --- a/src/types/notifications.ts +++ b/src/types/notifications.ts @@ -1,6 +1,3 @@ -import { OperationError } from "./walletTypes"; -import { WithdrawCoinSource, WithdrawalSource } from "./dbTypes"; - /* This file is part of GNU Taler (C) 2019 GNUnet e.V. @@ -22,6 +19,12 @@ import { WithdrawCoinSource, WithdrawalSource } from "./dbTypes"; * of the wallet. */ +/** + * Imports. + */ +import { OperationError } from "./walletTypes"; +import { WithdrawalSource } from "./dbTypes"; + export const enum NotificationType { CoinWithdrawn = "coin-withdrawn", ProposalAccepted = "proposal-accepted", diff --git a/src/types/pending.ts b/src/types/pending.ts index 5bca8c391..4ff82f55e 100644 --- a/src/types/pending.ts +++ b/src/types/pending.ts @@ -25,7 +25,6 @@ import { OperationError, WalletBalance } from "./walletTypes"; import { WithdrawalSource, RetryInfo, ReserveRecordStatus } from "./dbTypes"; import { Timestamp, Duration } from "../util/time"; import { ReserveType } from "./history"; -import { AmountString } from "./talerTypes"; export const enum PendingOperationType { Bug = "bug", diff --git a/src/types/talerTypes.ts b/src/types/talerTypes.ts index 74157b18b..799c84dc5 100644 --- a/src/types/talerTypes.ts +++ b/src/types/talerTypes.ts @@ -963,22 +963,22 @@ export const codecForWithdrawOperationStatusResponse = (): Codec< .build("WithdrawOperationStatusResponse"); export const codecForTipPickupGetResponse = (): Codec => - makeCodecForObject() - .property("extra", codecForAny) - .property("amount", codecForString) - .property("amount_left", codecForString) - .property("exchange_url", codecForString) - .property("stamp_expire", codecForTimestamp) - .property("stamp_created", codecForTimestamp) - .build("TipPickupGetResponse"); + makeCodecForObject() + .property("extra", codecForAny) + .property("amount", codecForString) + .property("amount_left", codecForString) + .property("exchange_url", codecForString) + .property("stamp_expire", codecForTimestamp) + .property("stamp_created", codecForTimestamp) + .build("TipPickupGetResponse"); export const codecForRecoupConfirmation = (): Codec => - makeCodecForObject() - .property("reserve_pub", makeCodecOptional(codecForString)) - .property("old_coin_pub", makeCodecOptional(codecForString)) - .build("RecoupConfirmation"); + makeCodecForObject() + .property("reserve_pub", makeCodecOptional(codecForString)) + .property("old_coin_pub", makeCodecOptional(codecForString)) + .build("RecoupConfirmation"); export const codecForWithdrawResponse = (): Codec => - makeCodecForObject() - .property("ev_sig", codecForString) - .build("WithdrawResponse"); + makeCodecForObject() + .property("ev_sig", codecForString) + .build("WithdrawResponse"); diff --git a/src/types/walletTypes.ts b/src/types/walletTypes.ts index 3d919c6f1..113a137ca 100644 --- a/src/types/walletTypes.ts +++ b/src/types/walletTypes.ts @@ -260,13 +260,13 @@ export interface CreateReserveRequest { } export const codecForCreateReserveRequest = (): Codec => - makeCodecForObject() - .property("amount", codecForAmountJson()) - .property("exchange", codecForString) - .property("exchangeWire", codecForString) - .property("senderWire", makeCodecOptional(codecForString)) - .property("bankWithdrawStatusUrl", makeCodecOptional(codecForString)) - .build("CreateReserveRequest"); + makeCodecForObject() + .property("amount", codecForAmountJson()) + .property("exchange", codecForString) + .property("exchangeWire", codecForString) + .property("senderWire", makeCodecOptional(codecForString)) + .property("bankWithdrawStatusUrl", makeCodecOptional(codecForString)) + .build("CreateReserveRequest"); /** * Request to mark a reserve as confirmed. @@ -280,9 +280,9 @@ export interface ConfirmReserveRequest { } export const codecForConfirmReserveRequest = (): Codec => - makeCodecForObject() - .property("reservePub", codecForString) - .build("ConfirmReserveRequest"); + makeCodecForObject() + .property("reservePub", codecForString) + .build("ConfirmReserveRequest"); /** * Wire coins to the user's own bank account. diff --git a/src/util/RequestThrottler.ts b/src/util/RequestThrottler.ts index c99c7e949..d979fbfcf 100644 --- a/src/util/RequestThrottler.ts +++ b/src/util/RequestThrottler.ts @@ -21,12 +21,7 @@ /** * Imports. */ -import { - getTimestampNow, - Timestamp, - timestampSubtractDuraction, - timestampDifference, -} from "../util/time"; +import { getTimestampNow, timestampDifference } from "../util/time"; /** * Maximum request per second, per origin. diff --git a/src/util/amounts.ts b/src/util/amounts.ts index da1c19233..5953f5130 100644 --- a/src/util/amounts.ts +++ b/src/util/amounts.ts @@ -67,11 +67,11 @@ export interface AmountJson { } export const codecForAmountJson = (): Codec => - makeCodecForObject() - .property("currency", codecForString) - .property("value", codecForNumber) - .property("fraction", codecForNumber) - .build("AmountJson"); + makeCodecForObject() + .property("currency", codecForString) + .property("value", codecForNumber) + .property("fraction", codecForNumber) + .build("AmountJson"); /** * Result of a possibly overflowing operation. diff --git a/src/util/codec.ts b/src/util/codec.ts index 480e1eec7..136c5b053 100644 --- a/src/util/codec.ts +++ b/src/util/codec.ts @@ -346,4 +346,4 @@ export function makeCodecOptional( return innerCodec.decode(x, c); }, }; -} \ No newline at end of file +} diff --git a/src/util/helpers.ts b/src/util/helpers.ts index 0e19d7aba..7cd9e4234 100644 --- a/src/util/helpers.ts +++ b/src/util/helpers.ts @@ -39,7 +39,7 @@ export function amountToPretty(amount: AmountJson): string { * * See http://api.taler.net/wallet.html#general */ -export function canonicalizeBaseUrl(url: string) { +export function canonicalizeBaseUrl(url: string): string { if (!url.startsWith("http") && !url.startsWith("https")) { url = "https://" + url; } @@ -145,13 +145,3 @@ export function strcmp(s1: string, s2: string): number { } return 0; } - -/** - * Run a function and return its result. - * - * Used as a nicer-looking way to do immediately invoked function - * expressions (IFFEs). - */ -export function runBlock(f: () => T) { - return f(); -} diff --git a/src/util/http.ts b/src/util/http.ts index 3842347dc..0ac989a17 100644 --- a/src/util/http.ts +++ b/src/util/http.ts @@ -136,9 +136,13 @@ export class BrowserHttpLib implements HttpRequestLibrary { const headerMap = new Headers(); arr.forEach(function (line) { const parts = line.split(": "); - const header = parts.shift(); + const headerName = parts.shift(); + if (!headerName) { + console.error("invalid header"); + return; + } const value = parts.join(": "); - headerMap.set(header!, value); + headerMap.set(headerName, value); }); const resp: HttpResponse = { status: myRequest.status, @@ -156,7 +160,11 @@ export class BrowserHttpLib implements HttpRequestLibrary { return this.req("get", url, undefined, opt); } - postJson(url: string, body: any, opt?: HttpRequestOptions): Promise { + postJson( + url: string, + body: any, + opt?: HttpRequestOptions, + ): Promise { return this.req("post", url, JSON.stringify(body), opt); } diff --git a/src/util/query.ts b/src/util/query.ts index 256395d42..8dd3ff1e2 100644 --- a/src/util/query.ts +++ b/src/util/query.ts @@ -292,7 +292,11 @@ export class TransactionHandle { return requestToPromise(req); } - mutate(store: Store, key: any, f: (x: T) => T | undefined): Promise { + mutate( + store: Store, + key: any, + f: (x: T) => T | undefined, + ): Promise { const req = this.tx.objectStore(store.name).openCursor(key); return applyMutation(req, f); } diff --git a/src/util/talerconfig.ts b/src/util/talerconfig.ts index 61c75574f..ec08c352f 100644 --- a/src/util/talerconfig.ts +++ b/src/util/talerconfig.ts @@ -59,8 +59,6 @@ export class ConfigValue { export class Configuration { private sectionMap: SectionMap = {}; - constructor() {} - loadFromString(s: string): void { const reComment = /^\s*#.*$/; const reSection = /^\s*\[\s*([^\]]*)\s*\]\s*$/; diff --git a/src/util/taleruri-test.ts b/src/util/taleruri-test.ts index 9efc1846d..1510880c5 100644 --- a/src/util/taleruri-test.ts +++ b/src/util/taleruri-test.ts @@ -28,7 +28,7 @@ test("taler pay url parsing: wrong scheme", (t) => { t.is(r1, undefined); const url2 = "taler://refund/a/b/c/d/e/f"; - const r2 = parsePayUri(url1); + const r2 = parsePayUri(url2); t.is(r2, undefined); }); diff --git a/src/util/taleruri.ts b/src/util/taleruri.ts index 8ad79669f..46cc199f8 100644 --- a/src/util/taleruri.ts +++ b/src/util/taleruri.ts @@ -97,7 +97,7 @@ export function classifyTalerUri(s: string): TalerUriType { return TalerUriType.Unknown; } -export function getOrderDownloadUrl(merchantBaseUrl: string, orderId: string) { +export function getOrderDownloadUrl(merchantBaseUrl: string, orderId: string): string { const u = new URL("proposal", merchantBaseUrl); u.searchParams.set("order_id", orderId); return u.href; diff --git a/src/util/timer.ts b/src/util/timer.ts index 18132a812..9d743b8e9 100644 --- a/src/util/timer.ts +++ b/src/util/timer.ts @@ -26,7 +26,6 @@ */ import { Duration } from "./time"; - /** * Cancelable timer. */ diff --git a/src/wallet.ts b/src/wallet.ts index 02450523e..273a9f875 100644 --- a/src/wallet.ts +++ b/src/wallet.ts @@ -154,7 +154,10 @@ export class Wallet { this.ws = new InternalWalletState(db, http, cryptoWorkerFactory); } - getExchangePaytoUri(exchangeBaseUrl: string, supportedTargetTypes: string[]): Promise { + getExchangePaytoUri( + exchangeBaseUrl: string, + supportedTargetTypes: string[], + ): Promise { return getExchangePaytoUri(this.ws, exchangeBaseUrl, supportedTargetTypes); } diff --git a/src/webex/compat.ts b/src/webex/compat.ts index f1a68f33e..1cbf34a2c 100644 --- a/src/webex/compat.ts +++ b/src/webex/compat.ts @@ -30,6 +30,6 @@ export function isFirefox(): boolean { /** * Check if we are running under nodejs. */ -export function isNode() { +export function isNode(): boolean { return typeof process !== "undefined" && process.release.name === "node"; } diff --git a/src/webex/i18n.tsx b/src/webex/i18n.tsx index ed6fe868f..3f23267d5 100644 --- a/src/webex/i18n.tsx +++ b/src/webex/i18n.tsx @@ -57,7 +57,7 @@ function setupJed(): any { /** * Convert template strings to a msgid */ -function toI18nString(stringSeq: ReadonlyArray) { +function toI18nString(stringSeq: ReadonlyArray): string { let s = ""; for (let i = 0; i < stringSeq.length; i++) { s += stringSeq[i]; @@ -71,7 +71,7 @@ function toI18nString(stringSeq: ReadonlyArray) { /** * Internationalize a string template with arbitrary serialized values. */ -export function str(stringSeq: TemplateStringsArray, ...values: any[]) { +export function str(stringSeq: TemplateStringsArray, ...values: any[]): string { const s = toI18nString(stringSeq); const tr = jed .translate(s) @@ -226,8 +226,8 @@ export class TranslatePlural extends React.Component< typeof childArray[i] === "string" && typeof childArray[i + 1] === "string" ) { - childArray[i + i] = - ((childArray[i] as string) + childArray[i + 1]) as string; + childArray[i + i] = ((childArray[i] as string) + + childArray[i + 1]) as string; childArray.splice(i, 1); } } @@ -267,8 +267,8 @@ export class TranslateSingular extends React.Component< typeof childArray[i] === "string" && typeof childArray[i + 1] === "string" ) { - childArray[i + i] = - ((childArray[i] as string) + childArray[i + 1]) as string; + childArray[i + i] = ((childArray[i] as string) + + childArray[i + 1]) as string; childArray.splice(i, 1); } } diff --git a/src/webex/messages.ts b/src/webex/messages.ts index b695b4ab6..19d125a89 100644 --- a/src/webex/messages.ts +++ b/src/webex/messages.ts @@ -23,7 +23,6 @@ import { AmountJson } from "../util/amounts"; import * as dbTypes from "../types/dbTypes"; -import * as talerTypes from "../types/talerTypes"; import * as walletTypes from "../types/walletTypes"; import { UpgradeResponse } from "./wxApi"; @@ -172,22 +171,3 @@ export interface MessageMap { */ export type MessageType = keyof MessageMap; -/** - * Make a request whose details match the request type. - */ -export function makeRequest( - type: T, - details: MessageMap[T]["request"], -) { - return { type, details }; -} - -/** - * Make a response that matches the request type. - */ -export function makeResponse( - type: T, - response: MessageMap[T]["response"], -) { - return response; -} diff --git a/src/webex/pageEntryPoint.ts b/src/webex/pageEntryPoint.ts index 04e3dd8d1..dd9c13031 100644 --- a/src/webex/pageEntryPoint.ts +++ b/src/webex/pageEntryPoint.ts @@ -25,7 +25,7 @@ import { createPopup } from "./pages/popup"; import { createWithdrawPage } from "./pages/withdraw"; import { createWelcomePage } from "./pages/welcome"; -function main() { +function main(): void { try { let mainElement; const m = location.pathname.match(/([^/]+)$/); diff --git a/src/webex/pages/add-auditor.tsx b/src/webex/pages/add-auditor.tsx index fc7de920f..c28d15cad 100644 --- a/src/webex/pages/add-auditor.tsx +++ b/src/webex/pages/add-auditor.tsx @@ -91,9 +91,7 @@ function ConfirmAuditor(props: ConfirmAuditorProps): JSX.Element { {addDone ? (
Auditor was added! You can also{" "} - - view and edit - {" "} + view and edit{" "} auditors.
) : ( diff --git a/src/webex/pages/auditors.tsx b/src/webex/pages/auditors.tsx index e933aeace..ac93afd31 100644 --- a/src/webex/pages/auditors.tsx +++ b/src/webex/pages/auditors.tsx @@ -29,7 +29,6 @@ import { import { getCurrencies, updateCurrency } from "../wxApi"; import * as React from "react"; -import * as ReactDOM from "react-dom"; interface CurrencyListState { currencies?: CurrencyRecord[]; @@ -49,13 +48,16 @@ class CurrencyList extends React.Component<{}, CurrencyListState> { this.state = {} as any; } - async update() { + async update(): Promise { const currencies = await getCurrencies(); console.log("currencies: ", currencies); this.setState({ currencies }); } - async confirmRemoveAuditor(c: CurrencyRecord, a: AuditorRecord) { + async confirmRemoveAuditor( + c: CurrencyRecord, + a: AuditorRecord, + ): Promise { if ( window.confirm( `Do you really want to remove auditor ${a.baseUrl} for currency ${c.name}?`, @@ -66,7 +68,10 @@ class CurrencyList extends React.Component<{}, CurrencyListState> { } } - async confirmRemoveExchange(c: CurrencyRecord, e: ExchangeForCurrencyRecord) { + async confirmRemoveExchange( + c: CurrencyRecord, + e: ExchangeForCurrencyRecord, + ): Promise { if ( window.confirm( `Do you really want to remove exchange ${e.baseUrl} for currency ${c.name}?`, @@ -86,7 +91,7 @@ class CurrencyList extends React.Component<{}, CurrencyListState> {

Trusted Auditors:

    {c.auditors.map((a) => ( -
  • +
  • {a.baseUrl}{" "} - - - + + + +
    @@ -788,4 +776,4 @@ function WalletPopup(): JSX.Element { export function createPopup(): JSX.Element { chrome.runtime.connect({ name: "popup" }); return ; -} \ No newline at end of file +} diff --git a/src/webex/pages/refund.tsx b/src/webex/pages/refund.tsx index 4a13317cd..621a286bb 100644 --- a/src/webex/pages/refund.tsx +++ b/src/webex/pages/refund.tsx @@ -47,7 +47,7 @@ function RefundStatusView(props: { talerRefundUri: string }): JSX.Element { } }; doFetch(); - }, []); + }, [props.talerRefundUri]); console.log("rendering"); @@ -63,7 +63,7 @@ function RefundStatusView(props: { talerRefundUri: string }): JSX.Element { <>

    Refund Status

    - The product {purchaseDetails.contractTerms.summary!} has + The product {purchaseDetails.contractTerms.summary} has received a total refund of{" "} .

    @@ -77,7 +77,7 @@ export function createRefundPage(): JSX.Element { const container = document.getElementById("container"); if (!container) { - throw Error("fatal: can't mount component, container missing") + throw Error("fatal: can't mount component, container missing"); } const talerRefundUri = url.searchParams.get("talerRefundUri"); diff --git a/src/webex/pages/reset-required.tsx b/src/webex/pages/reset-required.tsx index e58243b34..9e40e7981 100644 --- a/src/webex/pages/reset-required.tsx +++ b/src/webex/pages/reset-required.tsx @@ -42,17 +42,17 @@ class ResetNotification extends React.Component { this.state = { checked: false, resetRequired: true }; setInterval(() => this.update(), 500); } - async update() { + async update(): Promise { const res = await wxApi.checkUpgrade(); this.setState({ resetRequired: res.dbResetRequired }); } - render() { + render(): JSX.Element { if (this.state.resetRequired) { return (

    Manual Reset Reqired

    - The wallet's database in your browser is incompatible with the{" "} + The wallet's database in your browser is incompatible with the{" "} currently installed wallet. Please reset manually.

    @@ -88,6 +88,6 @@ class ResetNotification extends React.Component { } } -export function createResetRequiredPage() { +export function createResetRequiredPage(): JSX.Element { return ; } diff --git a/src/webex/pages/return-coins.tsx b/src/webex/pages/return-coins.tsx index 7d759705f..ccdb6db53 100644 --- a/src/webex/pages/return-coins.tsx +++ b/src/webex/pages/return-coins.tsx @@ -290,8 +290,9 @@ class ReturnCoins extends React.Component<{}, ReturnCoinsState> {

    Wire electronic cash back to own bank account

    - You can send coins back into your own bank account. Note that you're - acting as a merchant when doing this, and thus the same fees apply. + You can send coins back into your own bank account. Note that + you're acting as a merchant when doing this, and thus the same + fees apply.

    {this.state.lastConfirmedDetail ? (

    diff --git a/src/webex/pages/tip.tsx b/src/webex/pages/tip.tsx index 9c797f50d..4a1d3743a 100644 --- a/src/webex/pages/tip.tsx +++ b/src/webex/pages/tip.tsx @@ -25,10 +25,7 @@ import * as React from "react"; import { acceptTip, getTipStatus } from "../wxApi"; -import { - renderAmount, - ProgressButton, -} from "../renderHtml"; +import { renderAmount, ProgressButton } from "../renderHtml"; import { useState, useEffect } from "react"; import { TipStatus } from "../../types/walletTypes"; @@ -45,7 +42,7 @@ function TipDisplay(props: { talerTipUri: string }): JSX.Element { setTipStatus(ts); }; doFetch(); - }, []); + }, [props.talerTipUri]); if (discarded) { return You've discarded the tip.; @@ -96,11 +93,11 @@ function TipDisplay(props: { talerTipUri: string }): JSX.Element { } export function createTipPage(): JSX.Element { - const url = new URL(document.location.href); - const talerTipUri = url.searchParams.get("talerTipUri"); - if (typeof talerTipUri !== "string") { - throw Error("talerTipUri must be a string"); - } + const url = new URL(document.location.href); + const talerTipUri = url.searchParams.get("talerTipUri"); + if (typeof talerTipUri !== "string") { + throw Error("talerTipUri must be a string"); + } - return ; + return ; } diff --git a/src/webex/pages/welcome.tsx b/src/webex/pages/welcome.tsx index a99cadb05..eecbe2be5 100644 --- a/src/webex/pages/welcome.tsx +++ b/src/webex/pages/welcome.tsx @@ -69,7 +69,7 @@ function Diagnostics(): JSX.Element {

    Problems detected:

      {diagnostics.errors.map((errMsg) => ( -
    1. {errMsg}
    2. +
    3. {errMsg}
    4. ))}
    {diagnostics.firefoxIdbProblem ? ( @@ -112,4 +112,4 @@ function Welcome(): JSX.Element { export function createWelcomePage(): JSX.Element { return ; -} \ No newline at end of file +} diff --git a/src/webex/pages/withdraw.tsx b/src/webex/pages/withdraw.tsx index 9020ddb0b..efd0adc86 100644 --- a/src/webex/pages/withdraw.tsx +++ b/src/webex/pages/withdraw.tsx @@ -30,7 +30,9 @@ import { WithdrawDetailView, renderAmount } from "../renderHtml"; import React, { useState, useEffect } from "react"; import { getWithdrawDetails, acceptWithdrawal } from "../wxApi"; -function NewExchangeSelection(props: { talerWithdrawUri: string }): JSX.Element { +function NewExchangeSelection(props: { + talerWithdrawUri: string; +}): JSX.Element { const [details, setDetails] = useState(); const [selectedExchange, setSelectedExchange] = useState< string | undefined @@ -63,7 +65,7 @@ function NewExchangeSelection(props: { talerWithdrawUri: string }): JSX.Element setDetails(d); }; fetchData(); - }, [selectedExchange, errMsg, selecting]); + }, [selectedExchange, errMsg, selecting, talerWithdrawUri]); if (errMsg) { return ( @@ -145,8 +147,11 @@ function NewExchangeSelection(props: { talerWithdrawUri: string }): JSX.Element } const accept = async (): Promise => { + if (!selectedExchange) { + throw Error("can't accept, no exchange selected"); + } console.log("accepting exchange", selectedExchange); - const res = await acceptWithdrawal(talerWithdrawUri, selectedExchange!); + const res = await acceptWithdrawal(talerWithdrawUri, selectedExchange); console.log("accept withdrawal response", res); if (res.confirmTransferUrl) { document.location.href = res.confirmTransferUrl; @@ -198,9 +203,9 @@ function NewExchangeSelection(props: { talerWithdrawUri: string }): JSX.Element export function createWithdrawPage(): JSX.Element { const url = new URL(document.location.href); - const talerWithdrawUri = url.searchParams.get("talerWithdrawUri"); - if (!talerWithdrawUri) { - throw Error("withdraw URI required"); - } - return ; -} \ No newline at end of file + const talerWithdrawUri = url.searchParams.get("talerWithdrawUri"); + if (!talerWithdrawUri) { + throw Error("withdraw URI required"); + } + return ; +} diff --git a/src/webex/renderHtml.tsx b/src/webex/renderHtml.tsx index f5a6a7e4d..b1363abfb 100644 --- a/src/webex/renderHtml.tsx +++ b/src/webex/renderHtml.tsx @@ -127,6 +127,37 @@ export class Collapsible extends React.Component< } } +function WireFee(props: { + s: string; + rci: ExchangeWithdrawDetails; +}): JSX.Element { + return ( + <> + + + Wire Method {props.s} + + + Applies Until + Wire Fee + Closing Fee + + + , + + {props.rci.wireFees.feesForType[props.s].map((f) => ( + + {stringifyTimestamp(f.endStamp)} + {renderAmount(f.wireFee)} + {renderAmount(f.closingFee)} + + ))} + + , + + ); +} + function AuditorDetailsView(props: { rci: ExchangeWithdrawDetails | null; }): JSX.Element { @@ -145,7 +176,7 @@ function AuditorDetailsView(props: { return (
    {(rci.exchangeInfo.details?.auditors ?? []).map((a) => ( -
    +

    Auditor {a.auditor_url}

    Public key: @@ -202,30 +233,6 @@ function FeeDetailsView(props: { ); } - function wireFee(s: string) { - return [ - - - Wire Method {s} - - - Applies Until - Wire Fee - Closing Fee - - , - - {rci!.wireFees.feesForType[s].map((f) => ( - - {stringifyTimestamp(f.endStamp)} - {renderAmount(f.wireFee)} - {renderAmount(f.closingFee)} - - ))} - , - ]; - } - const withdrawFee = renderAmount(rci.withdrawFee); const overhead = renderAmount(rci.overhead); @@ -265,7 +272,9 @@ function FeeDetailsView(props: {

    Wire Fees

    - {Object.keys(rci.wireFees.feesForType).map(wireFee)} + {Object.keys(rci.wireFees.feesForType).map((s) => ( + + ))}
    @@ -337,7 +346,12 @@ export function PageLink( ): JSX.Element { const url = chrome.extension.getURL(`/${props.pageName}`); return ( - + {props.children} ); diff --git a/yarn.lock b/yarn.lock index 88e58bb2e..a877779b9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -175,6 +175,13 @@ core-js-pure "^3.0.0" regenerator-runtime "^0.13.4" +"@babel/runtime@^7.4.5": + version "7.9.2" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.9.2.tgz#d90df0583a3a252f09aaa619665367bae518db06" + integrity sha512-NE2DtOdufG7R5vnfQUTehdTfNycfUANEtCa9PssN9O/xmTzP4E08UI797ixaei6hBEVL9BI/PsdJS5x7mWoB9Q== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/template@^7.7.4", "@babel/template@^7.8.3", "@babel/template@^7.8.6": version "7.8.6" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.6.tgz#86b22af15f828dfb086474f964dcc3e39c43ce2b" @@ -411,6 +418,26 @@ eslint-scope "^5.0.0" eslint-utils "^2.0.0" +"@typescript-eslint/experimental-utils@2.27.0": + version "2.27.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.27.0.tgz#801a952c10b58e486c9a0b36cf21e2aab1e9e01a" + integrity sha512-vOsYzjwJlY6E0NJRXPTeCGqjv5OHgRU1kzxHKWJVPjDYGbPgLudBXjIlc+OD1hDBZ4l1DLbOc5VjofKahsu9Jw== + dependencies: + "@types/json-schema" "^7.0.3" + "@typescript-eslint/typescript-estree" "2.27.0" + eslint-scope "^5.0.0" + eslint-utils "^2.0.0" + +"@typescript-eslint/parser@^2.24.0": + version "2.27.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-2.27.0.tgz#d91664335b2c46584294e42eb4ff35838c427287" + integrity sha512-HFUXZY+EdwrJXZo31DW4IS1ujQW3krzlRjBrFRrJcMDh0zCu107/nRfhk/uBasO8m0NVDbBF5WZKcIUMRO7vPg== + dependencies: + "@types/eslint-visitor-keys" "^1.0.0" + "@typescript-eslint/experimental-utils" "2.27.0" + "@typescript-eslint/typescript-estree" "2.27.0" + eslint-visitor-keys "^1.1.0" + "@typescript-eslint/parser@^2.26.0": version "2.26.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-2.26.0.tgz#385463615818b33acb72a25b39c03579df93d76f" @@ -434,6 +461,19 @@ semver "^6.3.0" tsutils "^3.17.1" +"@typescript-eslint/typescript-estree@2.27.0": + version "2.27.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.27.0.tgz#a288e54605412da8b81f1660b56c8b2e42966ce8" + integrity sha512-t2miCCJIb/FU8yArjAvxllxbTiyNqaXJag7UOpB5DVoM3+xnjeOngtqlJkLRnMtzaRcJhe3CIR9RmL40omubhg== + dependencies: + debug "^4.1.1" + eslint-visitor-keys "^1.1.0" + glob "^7.1.6" + is-glob "^4.0.1" + lodash "^4.17.15" + semver "^6.3.0" + tsutils "^3.17.1" + acorn-jsx@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.2.0.tgz#4c66069173d6fdd68ed85239fc256226182b2ebe" @@ -546,6 +586,14 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" +aria-query@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-3.0.0.tgz#65b3fcc1ca1155a8c9ae64d6eee297f15d5133cc" + integrity sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w= + dependencies: + ast-types-flow "0.0.7" + commander "^2.11.0" + array-find-index@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" @@ -588,6 +636,11 @@ arrify@^2.0.1: resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug== +ast-types-flow@0.0.7, ast-types-flow@^0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" + integrity sha1-9wtzXGvKGlycItmCw+Oef+ujva0= + astral-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" @@ -663,6 +716,11 @@ axios@^0.19.2: dependencies: follow-redirects "1.5.10" +axobject-query@^2.0.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.1.2.tgz#2bdffc0371e643e5f03ba99065d5179b9ca79799" + integrity sha512-ICt34ZmrVt8UQnvPl6TVyDTkmhXmAyAT4Jh5ugfGUX4MOrZ+U/ZY6/sdylRw3qGNr9Ub5AJsaHeDMzNLehRdOQ== + balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" @@ -916,7 +974,7 @@ color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -commander@^2.20.0, commander@~2.20.3: +commander@^2.11.0, commander@^2.20.0, commander@~2.20.3: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== @@ -965,6 +1023,11 @@ configstore@^5.0.1: write-file-atomic "^3.0.0" xdg-basedir "^4.0.0" +confusing-browser-globals@^1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.9.tgz#72bc13b483c0276801681871d4898516f8f54fdd" + integrity sha512-KbS1Y0jMtyPgIxjO7ZzMAuUpAKMt1SzCL9fsrKsX6b0zJPTaT0SiSPmewwVZg9UAO83HVIlEhZF84LIjZ0lmAw== + contains-path@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" @@ -1024,6 +1087,11 @@ currently-unhandled@^0.4.1: dependencies: array-find-index "^1.0.1" +damerau-levenshtein@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.6.tgz#143c1641cb3d85c60c32329e26899adea8701791" + integrity sha512-JVrozIeElnj3QzfUIt8tB8YMluBJom4Vw9qTPpjGYQ9fYlB3D/rb6OordUxf3xeFB35LKWs0xqcO5U6ySvBtug== + date-time@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/date-time/-/date-time-2.1.0.tgz#0286d1b4c769633b3ca13e1e62558d2dbdc2eba2" @@ -1160,7 +1228,7 @@ emittery@^0.6.0: resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.6.0.tgz#e85312468d77c3ed9a6adf43bb57d34849e0c95a" integrity sha512-6EMRGr9KzYWp8DzHFZsKVZBsMO6QhAeHMeHND8rhyBNCHKMLpgW9tZv40bwN3rAIKRS5CxcK8oLRKUJSB9h7yQ== -emoji-regex@^7.0.1: +emoji-regex@^7.0.1, emoji-regex@^7.0.2: version "7.0.3" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== @@ -1242,6 +1310,33 @@ escape-string-regexp@^2.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== +eslint-config-airbnb-base@^14.1.0: + version "14.1.0" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.1.0.tgz#2ba4592dd6843258221d9bff2b6831bd77c874e4" + integrity sha512-+XCcfGyCnbzOnktDVhwsCAx+9DmrzEmuwxyHUJpw+kqBVT744OUBrB09khgFKlK1lshVww6qXGsYPZpavoNjJw== + dependencies: + confusing-browser-globals "^1.0.9" + object.assign "^4.1.0" + object.entries "^1.1.1" + +eslint-config-airbnb-typescript@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-7.2.0.tgz#afa7cea5657c9f70c0b96d52bf7d470e9827b66a" + integrity sha512-W7IZUIJpBZIzU3p65KoyJPl2vGSy6FS3R+K91Cp3NLK/0m1oyvCFeBHI2QlWdqxkJ4FvwnLvsoRTutwpKNIT+A== + dependencies: + "@typescript-eslint/parser" "^2.24.0" + eslint-config-airbnb "^18.1.0" + eslint-config-airbnb-base "^14.1.0" + +eslint-config-airbnb@^18.1.0: + version "18.1.0" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb/-/eslint-config-airbnb-18.1.0.tgz#724d7e93dadd2169492ff5363c5aaa779e01257d" + integrity sha512-kZFuQC/MPnH7KJp6v95xsLBf63G/w7YqdPfQ0MUanxQ7zcKUNG8j+sSY860g3NwCBOa62apw16J6pRN+AOgXzw== + dependencies: + eslint-config-airbnb-base "^14.1.0" + object.assign "^4.1.0" + object.entries "^1.1.1" + eslint-import-resolver-node@^0.3.2: version "0.3.3" resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.3.tgz#dbaa52b6b2816b50bc6711af75422de808e98404" @@ -1276,6 +1371,21 @@ eslint-plugin-import@^2.20.2: read-pkg-up "^2.0.0" resolve "^1.12.0" +eslint-plugin-jsx-a11y@^6.2.3: + version "6.2.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.2.3.tgz#b872a09d5de51af70a97db1eea7dc933043708aa" + integrity sha512-CawzfGt9w83tyuVekn0GDPU9ytYtxyxyFZ3aSWROmnRRFQFT2BiPJd7jvRdzNDi6oLWaS2asMeYSNMjWTV4eNg== + dependencies: + "@babel/runtime" "^7.4.5" + aria-query "^3.0.0" + array-includes "^3.0.3" + ast-types-flow "^0.0.7" + axobject-query "^2.0.2" + damerau-levenshtein "^1.0.4" + emoji-regex "^7.0.2" + has "^1.0.3" + jsx-ast-utils "^2.2.1" + eslint-plugin-react-hooks@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-3.0.0.tgz#9e80c71846eb68dd29c3b21d832728aa66e5bd35" @@ -2217,7 +2327,7 @@ jsonfile@^4.0.0: optionalDependencies: graceful-fs "^4.1.6" -jsx-ast-utils@^2.2.3: +jsx-ast-utils@^2.2.1, jsx-ast-utils@^2.2.3: version "2.2.3" resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.2.3.tgz#8a9364e402448a3ce7f14d357738310d9248054f" integrity sha512-EdIHFMm+1BPynpKOpdPqiOsvnIrInRGJD7bzPZdPkjitQEqpdpUuFpq4T0npZFKTiB3RhWFdGN+oqOJIdhDhQA==