From aa9c992f2ed28ab68666fc3a014921867f112b09 Mon Sep 17 00:00:00 2001 From: Joel Jeremy Marquez <joeljeremy.marquez@gmail.com> Date: Wed, 22 Nov 2023 14:28:09 -0800 Subject: [PATCH] Part 2 of eslint prefer-const (#1958) * Part 2 of eslint prefer-const * Release notes * Update --- .eslintrc.js | 9 ++ packages/loot-core/init-node.js | 8 +- .../src/client/SpreadsheetProvider.tsx | 6 +- .../loot-core/src/client/actions/account.ts | 10 +- .../loot-core/src/client/actions/budgets.ts | 14 +- .../loot-core/src/client/actions/modals.ts | 2 +- .../loot-core/src/client/actions/prefs.ts | 6 +- .../loot-core/src/client/actions/queries.ts | 14 +- packages/loot-core/src/client/actions/sync.ts | 10 +- .../src/client/data-hooks/filters.tsx | 2 +- .../src/client/data-hooks/schedules.tsx | 8 +- packages/loot-core/src/client/queries.ts | 6 +- .../src/client/query-helpers.test.ts | 78 +++++----- .../loot-core/src/client/query-helpers.ts | 34 ++--- packages/loot-core/src/client/query-hooks.tsx | 16 +- .../loot-core/src/client/reducers/account.ts | 4 +- .../loot-core/src/client/reducers/budgets.ts | 18 +-- .../loot-core/src/client/reducers/queries.ts | 6 +- .../loot-core/src/client/shared-listeners.ts | 8 +- .../src/client/update-notification.ts | 4 +- .../loot-core/src/mocks/arbitrary-schema.ts | 12 +- packages/loot-core/src/mocks/budget.ts | 142 +++++++++--------- packages/loot-core/src/mocks/redux.tsx | 2 +- packages/loot-core/src/mocks/setup.ts | 8 +- packages/loot-core/src/mocks/spreadsheet.ts | 10 +- packages/loot-core/src/mocks/util.ts | 2 +- .../client/fetch/__mocks__/index.web.ts | 6 +- .../platform/client/fetch/index.browser.ts | 14 +- .../src/platform/client/fetch/index.web.ts | 15 +- .../src/platform/client/undo/index.web.ts | 6 +- .../server/asyncStorage/index.electron.ts | 2 +- .../platform/server/asyncStorage/index.web.ts | 54 +++---- .../server/connection/index.electron.ts | 6 +- .../platform/server/connection/index.web.ts | 10 +- .../src/platform/server/fs/index.electron.ts | 2 +- .../src/platform/server/fs/index.web.test.ts | 18 +-- .../src/platform/server/fs/index.web.ts | 56 +++---- .../src/platform/server/fs/path-join.web.ts | 8 +- .../platform/server/indexeddb/index.web.ts | 18 +-- .../platform/server/sqlite/index.electron.ts | 10 +- .../platform/server/sqlite/index.web.test.ts | 10 +- .../src/platform/server/sqlite/index.web.ts | 8 +- packages/loot-core/src/shared/arithmetic.ts | 18 ++- packages/loot-core/src/shared/async.test.ts | 2 +- packages/loot-core/src/shared/async.ts | 4 +- packages/loot-core/src/shared/categories.ts | 2 +- packages/loot-core/src/shared/errors.ts | 2 +- packages/loot-core/src/shared/months.ts | 8 +- packages/loot-core/src/shared/query.ts | 12 +- packages/loot-core/src/shared/rules.ts | 8 +- packages/loot-core/src/shared/schedules.ts | 34 ++--- packages/loot-core/src/shared/test-helpers.ts | 12 +- .../loot-core/src/shared/transactions.test.ts | 30 ++-- packages/loot-core/src/shared/transactions.ts | 44 +++--- packages/loot-core/src/shared/util.ts | 56 +++---- .../loot-core/webpack/webpack.api.config.js | 4 +- .../webpack/webpack.browser.config.js | 4 +- .../webpack/webpack.desktop.config.js | 6 +- upcoming-release-notes/1958.md | 6 + 59 files changed, 476 insertions(+), 458 deletions(-) create mode 100644 upcoming-release-notes/1958.md diff --git a/.eslintrc.js b/.eslintrc.js index 78a6e37d1..19255cf7b 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -239,6 +239,7 @@ module.exports = { './packages/api/app/**/*', './packages/crdt/**/*', './packages/desktop-client/src/*', + // './packages/desktop-client/src/components/**/*', './packages/desktop-client/src/hooks/**/*', './packages/desktop-client/src/icons/**/*', './packages/desktop-client/src/style/**/*', @@ -246,6 +247,14 @@ module.exports = { './packages/desktop-client/src/util/**/*', './packages/desktop-electron/**/*', './packages/eslint-plugin-actual/**/*', + './packages/loot-core/*', + './packages/loot-core/src/client/**/*', + './packages/loot-core/src/mocks/**/*', + './packages/loot-core/src/platform/**/*', + // './packages/loot-core/src/server/**/*', + './packages/loot-core/src/shared/**/*', + './packages/loot-core/src/types/**/*', + './packages/loot-core/webpack/**/*', ], rules: { 'prefer-const': 'warn', diff --git a/packages/loot-core/init-node.js b/packages/loot-core/init-node.js index a426a73b2..3470eccd0 100644 --- a/packages/loot-core/init-node.js +++ b/packages/loot-core/init-node.js @@ -9,8 +9,8 @@ import bundle from './lib-dist/bundle.desktop.js'; global.fetch = fetch; async function init(budgetPath) { - let dir = dirname(budgetPath); - let budgetId = basename(budgetPath); + const dir = dirname(budgetPath); + const budgetId = basename(budgetPath); await bundle.initEmbedded('0.0.147', true, dir); await bundle.lib.send('load-budget', { id: budgetId }); @@ -18,8 +18,8 @@ async function init(budgetPath) { } async function run() { - let { send } = await init('/tmp/_test-budget'); - let accounts = await send('accounts-get'); + const { send } = await init('/tmp/_test-budget'); + const accounts = await send('accounts-get'); await send('transaction-add', { date: '2022-03-20', diff --git a/packages/loot-core/src/client/SpreadsheetProvider.tsx b/packages/loot-core/src/client/SpreadsheetProvider.tsx index bb30cda95..2823fe123 100644 --- a/packages/loot-core/src/client/SpreadsheetProvider.tsx +++ b/packages/loot-core/src/client/SpreadsheetProvider.tsx @@ -65,8 +65,8 @@ function makeSpreadsheet() { binding = typeof binding === 'string' ? { name: binding, value: null } : binding; - let resolvedName = `${sheetName}!${binding.name}`; - let cleanup = this.observeCell(resolvedName, cb); + const resolvedName = `${sheetName}!${binding.name}`; + const cleanup = this.observeCell(resolvedName, cb); // Always synchronously call with the existing value if it has one. // This is a display optimization to avoid flicker. The LRU cache @@ -118,7 +118,7 @@ function makeSpreadsheet() { } export function SpreadsheetProvider({ children }) { - let spreadsheet = useMemo(() => makeSpreadsheet(), []); + const spreadsheet = useMemo(() => makeSpreadsheet(), []); useEffect(() => { return spreadsheet.listen(); diff --git a/packages/loot-core/src/client/actions/account.ts b/packages/loot-core/src/client/actions/account.ts index cecc9d8f3..7d937ae65 100644 --- a/packages/loot-core/src/client/actions/account.ts +++ b/packages/loot-core/src/client/actions/account.ts @@ -83,7 +83,7 @@ export function connectAccounts( offbudgetIds, ) { return async (dispatch: Dispatch) => { - let ids = await send('accounts-connect', { + const ids = await send('accounts-connect', { institution, publicToken, accountIds, @@ -103,7 +103,7 @@ export function connectGoCardlessAccounts( offbudgetIds, ) { return async (dispatch: Dispatch) => { - let ids = await send('gocardless-accounts-connect', { + const ids = await send('gocardless-accounts-connect', { institution, publicToken, accountIds, @@ -122,7 +122,7 @@ export function syncAccounts(id: string) { } if (id) { - let account = getState().queries.accounts.find(a => a.id === id); + const account = getState().queries.accounts.find(a => a.id === id); dispatch(setAccountsSyncing(account.name)); } else { dispatch(setAccountsSyncing('__all')); @@ -133,7 +133,7 @@ export function syncAccounts(id: string) { dispatch(setAccountsSyncing(null)); if (id) { - let error = errors.find(error => error.accountId === id); + const error = errors.find(error => error.accountId === id); if (error) { // We only want to mark the account as having problem if it @@ -209,7 +209,7 @@ export function parseTransactions(filepath, options) { export function importTransactions(id, transactions) { return async (dispatch: Dispatch) => { - let { + const { errors = [], added, updated, diff --git a/packages/loot-core/src/client/actions/budgets.ts b/packages/loot-core/src/client/actions/budgets.ts index 3247472f4..c35ca100e 100644 --- a/packages/loot-core/src/client/actions/budgets.ts +++ b/packages/loot-core/src/client/actions/budgets.ts @@ -50,14 +50,14 @@ export function loadBudget(id: string, loadingText = '', options = {}) { dispatch(setAppState({ loadingText })); // Loading a budget may fail - let { error } = await send('load-budget', { id, ...options }); + const { error } = await send('load-budget', { id, ...options }); if (error) { - let message = getSyncError(error, id); + const message = getSyncError(error, id); if (error === 'out-of-sync-migrations' || error === 'out-of-sync-data') { // confirm is not available on iOS if (typeof window.confirm !== 'undefined') { - let showBackups = window.confirm( + const showBackups = window.confirm( message + ' Make sure the app is up-to-date. Do you want to load a backup?', ); @@ -103,7 +103,7 @@ export function closeBudget() { export function closeBudgetUI() { return async (dispatch: Dispatch, getState: GetState) => { - let prefs = getState().prefs.local; + const prefs = getState().prefs.local; if (prefs && prefs.id) { dispatch({ type: constants.CLOSE_BUDGET }); } @@ -164,7 +164,7 @@ export function importBudget( export function uploadBudget(id: string) { return async (dispatch: Dispatch) => { - let { error } = await send('upload-budget', { id }); + const { error } = await send('upload-budget', { id }); if (error) { return { error }; } @@ -190,14 +190,14 @@ export function downloadBudget(cloudFileId: string, { replace = false } = {}) { return async (dispatch: Dispatch) => { dispatch(setAppState({ loadingText: 'Downloading...' })); - let { id, error } = await send('download-budget', { + const { id, error } = await send('download-budget', { fileId: cloudFileId, replace, }); if (error) { if (error.reason === 'decrypt-failure') { - let opts = { + const opts = { hasExistingKey: error.meta && error.meta.isMissingKey, cloudFileId, onSuccess: () => { diff --git a/packages/loot-core/src/client/actions/modals.ts b/packages/loot-core/src/client/actions/modals.ts index 7e50ba652..7abf5e78a 100644 --- a/packages/loot-core/src/client/actions/modals.ts +++ b/packages/loot-core/src/client/actions/modals.ts @@ -37,7 +37,7 @@ export function replaceModal<M extends ModalType>( options?: FinanceModals[M], ): ReplaceModalAction { // @ts-expect-error TS is unable to determine that `name` and `options` match - let modal: M = { name, options }; + const modal: M = { name, options }; return { type: constants.REPLACE_MODAL, modal }; } diff --git a/packages/loot-core/src/client/actions/prefs.ts b/packages/loot-core/src/client/actions/prefs.ts index d309e0173..ac6cf98b9 100644 --- a/packages/loot-core/src/client/actions/prefs.ts +++ b/packages/loot-core/src/client/actions/prefs.ts @@ -7,10 +7,10 @@ import type { Dispatch, GetState } from './types'; export function loadPrefs() { return async (dispatch: Dispatch, getState: GetState) => { - let prefs = await send('load-prefs'); + const prefs = await send('load-prefs'); // Remove any modal state if switching between budgets - let currentPrefs = getState().prefs.local; + const currentPrefs = getState().prefs.local; if (prefs && prefs.id && !currentPrefs) { dispatch(closeModal()); } @@ -37,7 +37,7 @@ export function savePrefs(prefs: Partial<prefs.LocalPrefs>) { export function loadGlobalPrefs() { return async (dispatch: Dispatch, getState: GetState) => { - let globalPrefs = await send('load-global-prefs'); + const globalPrefs = await send('load-global-prefs'); dispatch({ type: constants.SET_PREFS, prefs: getState().prefs.local, diff --git a/packages/loot-core/src/client/actions/queries.ts b/packages/loot-core/src/client/actions/queries.ts index ab50be723..0482d17da 100644 --- a/packages/loot-core/src/client/actions/queries.ts +++ b/packages/loot-core/src/client/actions/queries.ts @@ -136,7 +136,7 @@ export function createCategory( isIncome: boolean, ) { return async (dispatch: Dispatch) => { - let id = await send('category-create', { + const id = await send('category-create', { name, groupId, isIncome, @@ -148,7 +148,7 @@ export function createCategory( export function deleteCategory(id: string, transferId?: string) { return async (dispatch: Dispatch) => { - let { error } = await send('category-delete', { id, transferId }); + const { error } = await send('category-delete', { id, transferId }); if (error) { switch (error) { @@ -198,7 +198,7 @@ export function moveCategoryGroup(id, targetId) { export function createGroup(name) { return async (dispatch: Dispatch) => { - let id = await send('category-group-create', { name }); + const id = await send('category-group-create', { name }); dispatch(getCategories()); return id; }; @@ -227,7 +227,7 @@ export function deleteGroup(id, transferId?) { export function getPayees() { return async (dispatch: Dispatch) => { - let payees = await send('payees-get'); + const payees = await send('payees-get'); dispatch({ type: constants.LOAD_PAYEES, payees, @@ -267,7 +267,7 @@ export function updateAccount(account) { export function createAccount(name, balance, offBudget) { return async (dispatch: Dispatch) => { - let id = await send('account-create', { name, balance, offBudget }); + const id = await send('account-create', { name, balance, offBudget }); await dispatch(getAccounts()); await dispatch(getPayees()); return id; @@ -321,8 +321,8 @@ export function forceCloseAccount(accountId) { return closeAccount(accountId, null, null, true); } -let _undo = throttle(() => send('undo'), 100); -let _redo = throttle(() => send('redo'), 100); +const _undo = throttle(() => send('undo'), 100); +const _redo = throttle(() => send('redo'), 100); let _undoEnabled = true; export function setUndoEnabled(flag: boolean) { diff --git a/packages/loot-core/src/client/actions/sync.ts b/packages/loot-core/src/client/actions/sync.ts index 4838c1e43..c2b03d22a 100644 --- a/packages/loot-core/src/client/actions/sync.ts +++ b/packages/loot-core/src/client/actions/sync.ts @@ -8,7 +8,7 @@ import type { Dispatch, GetState } from './types'; export function resetSync() { return async (dispatch: Dispatch) => { - let { error } = await send('sync-reset'); + const { error } = await send('sync-reset'); if (error) { alert(getUploadError(error)); @@ -40,7 +40,7 @@ export function sync() { return async (dispatch: Dispatch, getState: GetState) => { const prefs = getState().prefs.local; if (prefs && prefs.id) { - let result = await send('sync'); + const result = await send('sync'); if ('error' in result) { return { error: result.error }; } @@ -56,16 +56,16 @@ export function syncAndDownload(accountId) { // clients have already made, so that imported transactions can be // reconciled against them. Otherwise, two clients will each add // new transactions from the bank and create duplicate ones. - let syncState = await dispatch(sync()); + const syncState = await dispatch(sync()); if (syncState.error) { return { error: syncState.error }; } - let hasDownloaded = await dispatch(syncAccounts(accountId)); + const hasDownloaded = await dispatch(syncAccounts(accountId)); if (hasDownloaded) { // Sync again afterwards if new transactions were created - let syncState = await dispatch(sync()); + const syncState = await dispatch(sync()); if (syncState.error) { return { error: syncState.error }; } diff --git a/packages/loot-core/src/client/data-hooks/filters.tsx b/packages/loot-core/src/client/data-hooks/filters.tsx index b7b65060d..60f9999e8 100644 --- a/packages/loot-core/src/client/data-hooks/filters.tsx +++ b/packages/loot-core/src/client/data-hooks/filters.tsx @@ -4,7 +4,7 @@ import q from '../query-helpers'; import { useLiveQuery } from '../query-hooks'; function toJS(rows) { - let filters = rows.map(row => { + const filters = rows.map(row => { return { ...row.fields, id: row.id, diff --git a/packages/loot-core/src/client/data-hooks/schedules.tsx b/packages/loot-core/src/client/data-hooks/schedules.tsx index a11bb1c7f..a139658c9 100644 --- a/packages/loot-core/src/client/data-hooks/schedules.tsx +++ b/packages/loot-core/src/client/data-hooks/schedules.tsx @@ -11,7 +11,7 @@ export type ScheduleStatuses = Map<ScheduleEntity['id'], ScheduleStatusType>; function loadStatuses(schedules: ScheduleEntity[], onData) { return liveQuery(getHasTransactionsQuery(schedules), onData, { mapper: data => { - let hasTrans = new Set(data.filter(Boolean).map(row => row.schedule)); + const hasTrans = new Set(data.filter(Boolean).map(row => row.schedule)); return new Map( schedules.map(s => [ @@ -35,9 +35,9 @@ export function useSchedules({ useEffect(() => { const query = q('schedules').select('*'); - let scheduleQuery, statusQuery; + let statusQuery; - scheduleQuery = liveQuery( + const scheduleQuery = liveQuery( transform ? transform(query) : query, async (schedules: ScheduleEntity[]) => { if (scheduleQuery) { @@ -65,7 +65,7 @@ export function useSchedules({ return data; } -let SchedulesContext = createContext(null); +const SchedulesContext = createContext(null); export function SchedulesProvider({ transform, children }) { const data = useSchedules({ transform }); diff --git a/packages/loot-core/src/client/queries.ts b/packages/loot-core/src/client/queries.ts index 0da752bb3..1ed3d615b 100644 --- a/packages/loot-core/src/client/queries.ts +++ b/packages/loot-core/src/client/queries.ts @@ -49,7 +49,7 @@ export function getAccountFilter(accountId, field = 'account') { export function makeTransactionsQuery(accountId) { let query = q('transactions').options({ splits: 'grouped' }); - let filter = getAccountFilter(accountId); + const filter = getAccountFilter(accountId); if (filter) { query = query.filter(filter); } @@ -58,7 +58,7 @@ export function makeTransactionsQuery(accountId) { } export function makeTransactionSearchQuery(currentQuery, search, dateFormat) { - let amount = currencyToAmount(search); + const amount = currencyToAmount(search); // Support various date formats let parsedDate; @@ -130,7 +130,7 @@ export function offbudgetAccountBalance() { }; } -let uncategorizedQuery = q('transactions').filter({ +const uncategorizedQuery = q('transactions').filter({ 'account.offbudget': false, category: null, $or: [ diff --git a/packages/loot-core/src/client/query-helpers.test.ts b/packages/loot-core/src/client/query-helpers.test.ts index 13b42a06f..c42bbdbec 100644 --- a/packages/loot-core/src/client/query-helpers.test.ts +++ b/packages/loot-core/src/client/query-helpers.test.ts @@ -11,7 +11,7 @@ function wait(n) { function isCountQuery(query) { if (query.selectExpressions.length === 1) { - let select = query.selectExpressions[0]; + const select = query.selectExpressions[0]; return select.result && select.result.$count === '*'; } @@ -29,8 +29,8 @@ function selectData(data, selectExpressions) { } function limitOffset(data, limit, offset) { - let start = offset != null ? offset : 0; - let end = limit != null ? limit : data.length; + const start = offset != null ? offset : 0; + const end = limit != null ? limit : data.length; return data.slice(start, start + end); } @@ -40,13 +40,13 @@ function runPagedQuery(query, data) { } if (query.filterExpressions.length > 0) { - let filter = query.filterExpressions[0]; + const filter = query.filterExpressions[0]; if (filter.id != null) { return [data.find(row => row.id === filter.id)]; } if (filter.date != null) { - let op = Object.keys(filter.date)[0]; + const op = Object.keys(filter.date)[0]; return limitOffset( data @@ -95,7 +95,7 @@ function initPagingServer( dataLength, { delay, eventType = 'select' }: { delay?: number; eventType?: string } = {}, ) { - let data = []; + const data = []; for (let i = 0; i < dataLength; i++) { data.push({ id: i, date: subDays('2020-05-01', Math.floor(i / 5)) }); } @@ -123,19 +123,19 @@ describe('query helpers', () => { it('runQuery runs a query', async () => { initServer({ query: query => ({ data: query, dependencies: [] }) }); - let query = q('transactions').select('*'); - let { data } = await runQuery(query); + const query = q('transactions').select('*'); + const { data } = await runQuery(query); expect(data).toEqual(query.serialize()); }); ['liveQuery', 'pagedQuery'].forEach(queryType => { - let doQuery = queryType === 'liveQuery' ? liveQuery : pagedQuery; + const doQuery = queryType === 'liveQuery' ? liveQuery : pagedQuery; it(`${queryType} runs and subscribes to a query`, async () => { initBasicServer(); tracer.start(); - let query = q('transactions').select('*'); + const query = q('transactions').select('*'); doQuery(query, data => tracer.event('data', data)); await tracer.expect('server-query'); @@ -151,14 +151,14 @@ describe('query helpers', () => { initBasicServer(); tracer.start(); - let query = q('transactions').select('*'); + const query = q('transactions').select('*'); doQuery(query, data => tracer.event('data', data), { onlySync: true }); await tracer.expect('server-query'); await tracer.expect('data', ['*']); serverPush('sync-event', { type: 'applied', tables: ['transactions'] }); - let p = Promise.race([tracer.wait('server-query'), wait(100)]); + const p = Promise.race([tracer.wait('server-query'), wait(100)]); expect(await p).toEqual('wait(100)'); }); @@ -166,7 +166,7 @@ describe('query helpers', () => { initBasicServer(); tracer.start(); - let query = q('transactions').select('*'); + const query = q('transactions').select('*'); doQuery(query, data => tracer.event('data', data), { onlySync: true }); await tracer.expect('server-query'); @@ -189,8 +189,8 @@ describe('query helpers', () => { }); tracer.start(); - let query = q('transactions').select('*'); - let lq = doQuery(query, data => tracer.event('data', data), { + const query = q('transactions').select('*'); + const lq = doQuery(query, data => tracer.event('data', data), { onlySync: true, }); @@ -217,7 +217,7 @@ describe('query helpers', () => { initBasicServer(); tracer.start(); - let query = q('transactions').select('*'); + const query = q('transactions').select('*'); doQuery(query, data => tracer.event('data', data), { onlySync: true }); @@ -238,7 +238,7 @@ describe('query helpers', () => { initBasicServer(500); tracer.start(); - let query = q('transactions').select('*'); + const query = q('transactions').select('*'); doQuery(query, data => tracer.event('data', data), { onlySync: true }); @@ -260,9 +260,9 @@ describe('query helpers', () => { initBasicServer(); tracer.start(); - let query = q('transactions').select('*'); + const query = q('transactions').select('*'); - let lq = doQuery(query, data => tracer.event('data', data)); + const lq = doQuery(query, data => tracer.event('data', data)); await tracer.expect('server-query'); await tracer.expect('data', ['*']); @@ -271,17 +271,17 @@ describe('query helpers', () => { serverPush('sync-event', { type: 'success', tables: ['transactions'] }); // Wait a bit and make sure nothing comes through - let p = Promise.race([tracer.expect('server-query'), wait(100)]); + const p = Promise.race([tracer.expect('server-query'), wait(100)]); expect(await p).toEqual('wait(100)'); }); }); it('pagedQuery makes requests in pages', async () => { - let data = initPagingServer(1502); + const data = initPagingServer(1502); tracer.start(); - let query = q('transactions').select('id'); - let paged = pagedQuery(query, data => tracer.event('data', data), { + const query = q('transactions').select('id'); + const paged = pagedQuery(query, data => tracer.event('data', data), { onPageData: data => tracer.event('page-data', data), }); @@ -332,15 +332,15 @@ describe('query helpers', () => { await paged.fetchNext(); // Wait a bit and make sure nothing comes through - let p = Promise.race([tracer.expect('server-query'), wait(100)]); + const p = Promise.race([tracer.expect('server-query'), wait(100)]); expect(await p).toEqual('wait(100)'); }); it('pagedQuery allows customizing page count', async () => { - let data = initPagingServer(50); + const data = initPagingServer(50); tracer.start(); - let query = q('transactions').select('id'); + const query = q('transactions').select('id'); pagedQuery(query, data => tracer.event('data', data), { pageCount: 10, }); @@ -356,8 +356,8 @@ describe('query helpers', () => { initPagingServer(1000, { delay: 200 }); tracer.start(); - let query = q('transactions').select('id'); - let paged = pagedQuery(query, data => tracer.event('data', data)); + const query = q('transactions').select('id'); + const paged = pagedQuery(query, data => tracer.event('data', data)); await tracer.expect('server-query', [{ result: { $count: '*' } }]); await tracer.expect('server-query', ['id']); @@ -372,16 +372,16 @@ describe('query helpers', () => { await tracer.expect('data', data => {}); // Wait a bit and make sure nothing comes through - let p = Promise.race([tracer.expect('server-query'), wait(200)]); + const p = Promise.race([tracer.expect('server-query'), wait(200)]); expect(await p).toEqual('wait(200)'); }); it('pagedQuery refetches all paged data on update', async () => { - let data = initPagingServer(500, { delay: 200 }); + const data = initPagingServer(500, { delay: 200 }); tracer.start(); - let query = q('transactions').select('id'); - let paged = pagedQuery(query, data => tracer.event('data', data), { + const query = q('transactions').select('id'); + const paged = pagedQuery(query, data => tracer.event('data', data), { pageCount: 20, onPageData: data => tracer.event('page-data', data), }); @@ -414,9 +414,9 @@ describe('query helpers', () => { }); it('pagedQuery reruns `fetchNext` if data changed underneath it', async () => { - let data = initPagingServer(500, { delay: 10 }); - let query = q('transactions').select('id'); - let paged = pagedQuery(query, data => tracer.event('data', data), { + const data = initPagingServer(500, { delay: 10 }); + const query = q('transactions').select('id'); + const paged = pagedQuery(query, data => tracer.event('data', data), { pageCount: 20, onPageData: data => tracer.event('page-data', data), }); @@ -457,9 +457,9 @@ describe('query helpers', () => { }); it('pagedQuery fetches up to a specific row', async () => { - let data = initPagingServer(500, { delay: 10, eventType: 'all' }); - let query = q('transactions').select(['id', 'date']); - let paged = pagedQuery(query, data => tracer.event('data', data), { + const data = initPagingServer(500, { delay: 10, eventType: 'all' }); + const query = q('transactions').select(['id', 'date']); + const paged = pagedQuery(query, data => tracer.event('data', data), { pageCount: 20, onPageData: data => tracer.event('page-data', data), }); @@ -467,7 +467,7 @@ describe('query helpers', () => { tracer.start(); - let item = data.find(row => row.id === 300); + const item = data.find(row => row.id === 300); paged.refetchUpToRow(item.id, { field: 'date', order: 'desc' }); await tracer.expect( diff --git a/packages/loot-core/src/client/query-helpers.ts b/packages/loot-core/src/client/query-helpers.ts index 4ff9e457f..72a7156e3 100644 --- a/packages/loot-core/src/client/query-helpers.ts +++ b/packages/loot-core/src/client/query-helpers.ts @@ -8,13 +8,13 @@ export async function runQuery(query) { } export function liveQuery(query, onData?, opts?): LiveQuery { - let q = new LiveQuery(query, onData, opts); + const q = new LiveQuery(query, onData, opts); q.run(); return q; } export function pagedQuery(query, onData?, opts?): PagedQuery { - let q = new PagedQuery(query, onData, opts); + const q = new PagedQuery(query, onData, opts); q.run(); return q; } @@ -90,10 +90,10 @@ export class LiveQuery { // backend. could give a query an id which makes it cacheable via // an LRU cache - let reqId = Math.random(); + const reqId = Math.random(); this.inflightRequestId = reqId; - let { data, dependencies } = await makeRequest(); + const { data, dependencies } = await makeRequest(); // Regardless if this request was cancelled or not, save the // dependencies. The query can't change so all requests will @@ -105,7 +105,7 @@ export class LiveQuery { // Only fire events if this hasn't been cancelled and if we're // still subscribed (`this._subscribe` will exist) if (this.inflightRequestId === reqId && this._unsubscribe) { - let prevData = this.mappedData; + const prevData = this.mappedData; this.data = data; this.mappedData = this.mapData(data); this.onData(this.mappedData, prevData); @@ -124,7 +124,7 @@ export class LiveQuery { // always update to all changes. // // TODO: errors? - let syncTypes = this.onlySync ? ['success'] : ['applied', 'success']; + const syncTypes = this.onlySync ? ['success'] : ['applied', 'success']; if (syncTypes.indexOf(type) !== -1) { this.onUpdate(tables); @@ -169,7 +169,7 @@ export class LiveQuery { }; optimisticUpdate = (dataFunc, mappedDataFunc) => { - let prevMappedData = this.mappedData; + const prevMappedData = this.mappedData; this._optimisticUpdate(dataFunc, mappedDataFunc); this.onData(this.mappedData, prevMappedData); }; @@ -232,12 +232,12 @@ class PagedQuery extends LiveQuery { // Also fetch the total count this._fetchCount(); - let orderDesc = getPrimaryOrderBy(this.query, defaultOrderBy); + const orderDesc = getPrimaryOrderBy(this.query, defaultOrderBy); if (orderDesc == null) { throw new Error(`refetchUpToRow requires a query with orderBy`); } - let { field, order } = orderDesc; + const { field, order } = orderDesc; let result = await runQuery(this.query.filter({ id }).select(field)); if (result.data.length === 0) { @@ -246,7 +246,7 @@ class PagedQuery extends LiveQuery { // data that we don't need return; } - let fullRow = result.data[0]; + const fullRow = result.data[0]; result = await runQuery( this.query.filter({ @@ -255,7 +255,7 @@ class PagedQuery extends LiveQuery { }, }), ); - let data = result.data; + const data = result.data; // Load in an extra page to make room for the UI to show some // data after it @@ -285,10 +285,10 @@ class PagedQuery extends LiveQuery { await this.runPromise; } - let previousData = this.data; + const previousData = this.data; if (!this.done) { - let { data } = await runQuery( + const { data } = await runQuery( this.query.limit(this.pageCount).offset(previousData.length), ); @@ -305,8 +305,8 @@ class PagedQuery extends LiveQuery { this.done = data.length < this.pageCount; this.data = this.data.concat(data); - let prevData = this.mappedData; - let mapped = this.mapData(data); + const prevData = this.mappedData; + const mapped = this.mapData(data); this.mappedData = this.mappedData.concat(mapped); this.onPageData(mapped); this.onData(this.mappedData, prevData); @@ -326,8 +326,8 @@ class PagedQuery extends LiveQuery { }; optimisticUpdate = (dataFunc, mappedDataFunc) => { - let prevData = this.data; - let prevMappedData = this.mappedData; + const prevData = this.data; + const prevMappedData = this.mappedData; this._optimisticUpdate(dataFunc, mappedDataFunc); this.totalCount += this.data.length - prevData.length; diff --git a/packages/loot-core/src/client/query-hooks.tsx b/packages/loot-core/src/client/query-hooks.tsx index 671ebf6d6..329f466b7 100644 --- a/packages/loot-core/src/client/query-hooks.tsx +++ b/packages/loot-core/src/client/query-hooks.tsx @@ -12,12 +12,12 @@ import { type Query } from '../shared/query'; import { liveQuery, LiveQuery } from './query-helpers'; function makeContext(queryState, opts, QueryClass) { - let query = new QueryClass(queryState, null, opts); - let Context = createContext(null); + const query = new QueryClass(queryState, null, opts); + const Context = createContext(null); function Provider({ children }) { - let [data, setData] = useState(query.getData()); - let value = useMemo(() => ({ data, query }), [data, query]); + const [data, setData] = useState(query.getData()); + const value = useMemo(() => ({ data, query }), [data, query]); useEffect(() => { if (query.getNumListeners() !== 0) { @@ -26,7 +26,7 @@ function makeContext(queryState, opts, QueryClass) { ); } - let unlisten = query.addListener(data => setData(data)); + const unlisten = query.addListener(data => setData(data)); // Start the query if it hasn't run yet. Most likely it's not // running, however the user can freely start the query early if @@ -50,7 +50,7 @@ function makeContext(queryState, opts, QueryClass) { } function useQuery() { - let queryData = useContext(Context); + const queryData = useContext(Context); if (queryData == null) { throw new Error( '`useQuery` tried to access a query that hasn’t been run. You need to put its `Provider` in a parent component', @@ -70,8 +70,8 @@ export function liveQueryContext(query, opts?) { } export function useLiveQuery(makeQuery: () => Query, deps: DependencyList) { - let [data, setData] = useState(null); - let query = useMemo(makeQuery, deps); + const [data, setData] = useState(null); + const query = useMemo(makeQuery, deps); useEffect(() => { let live = liveQuery(query, async data => { diff --git a/packages/loot-core/src/client/reducers/account.ts b/packages/loot-core/src/client/reducers/account.ts index dc78b508f..5e713db7e 100644 --- a/packages/loot-core/src/client/reducers/account.ts +++ b/packages/loot-core/src/client/reducers/account.ts @@ -18,7 +18,7 @@ export default function update( accountsSyncing: action.name, }; case constants.ACCOUNT_SYNC_STATUS: { - let failedAccounts = new Map(state.failedAccounts); + const failedAccounts = new Map(state.failedAccounts); if (action.failed) { failedAccounts.set(action.id, { type: action.errorType, @@ -31,7 +31,7 @@ export default function update( return { ...state, failedAccounts }; } case constants.ACCOUNT_SYNC_FAILURES: { - let failures = new Map(); + const failures = new Map(); action.syncErrors.forEach(error => { failures.set(error.id, { type: error.type, diff --git a/packages/loot-core/src/client/reducers/budgets.ts b/packages/loot-core/src/client/reducers/budgets.ts index e37484b88..1d8625d9b 100644 --- a/packages/loot-core/src/client/reducers/budgets.ts +++ b/packages/loot-core/src/client/reducers/budgets.ts @@ -7,12 +7,12 @@ import type { BudgetsState } from '../state-types/budgets'; function sortFiles(arr: File[]) { arr.sort((x, y) => { - let name1 = x.name.toLowerCase(); - let name2 = y.name.toLowerCase(); + const name1 = x.name.toLowerCase(); + const name2 = y.name.toLowerCase(); let i = name1 < name2 ? -1 : name1 > name2 ? 1 : 0; if (i === 0) { - let xId = x.state === 'remote' ? x.cloudFileId : x.id; - let yId = x.state === 'remote' ? x.cloudFileId : x.id; + const xId = x.state === 'remote' ? x.cloudFileId : x.id; + const yId = x.state === 'remote' ? x.cloudFileId : x.id; i = xId < yId ? -1 : xId > yId ? 1 : 0; } return i; @@ -32,10 +32,10 @@ function reconcileFiles( remoteFiles: RemoteFile[] | null, ): File[] { console.log({ localFiles, remoteFiles }); - let reconciled = new Set(); + const reconciled = new Set(); - let files = localFiles.map((localFile): File & { deleted: boolean } => { - let { cloudFileId, groupId } = localFile; + const files = localFiles.map((localFile): File & { deleted: boolean } => { + const { cloudFileId, groupId } = localFile; if (cloudFileId && groupId) { // This is the case where for some reason getting the files from // the server failed. We don't want to scare the user, just show @@ -51,7 +51,7 @@ function reconcileFiles( }; } - let remote = remoteFiles.find(f => localFile.cloudFileId === f.fileId); + const remote = remoteFiles.find(f => localFile.cloudFileId === f.fileId); if (remote) { // Mark reconciled reconciled.add(remote.fileId); @@ -93,7 +93,7 @@ function reconcileFiles( } }); - let sorted = sortFiles( + const sorted = sortFiles( files .concat( (remoteFiles || []) diff --git a/packages/loot-core/src/client/reducers/queries.ts b/packages/loot-core/src/client/reducers/queries.ts index 8cd82fb88..f44c6ca86 100644 --- a/packages/loot-core/src/client/reducers/queries.ts +++ b/packages/loot-core/src/client/reducers/queries.ts @@ -89,7 +89,7 @@ export default function update( export const getAccountsById = memoizeOne(accounts => groupById(accounts)); export const getPayeesById = memoizeOne(payees => groupById(payees)); export const getCategoriesById = memoizeOne(categoryGroups => { - let res = {}; + const res = {}; categoryGroups.forEach(group => { group.categories.forEach(cat => { res[cat.id] = cat; @@ -99,11 +99,11 @@ export const getCategoriesById = memoizeOne(categoryGroups => { }); export const getActivePayees = memoizeOne((payees, accounts) => { - let accountsById = getAccountsById(accounts); + const accountsById = getAccountsById(accounts); return payees.filter(payee => { if (payee.transfer_acct) { - let account = accountsById[payee.transfer_acct]; + const account = accountsById[payee.transfer_acct]; return account != null && !account.closed; } return true; diff --git a/packages/loot-core/src/client/shared-listeners.ts b/packages/loot-core/src/client/shared-listeners.ts index a46f1490c..d26c8ed89 100644 --- a/packages/loot-core/src/client/shared-listeners.ts +++ b/packages/loot-core/src/client/shared-listeners.ts @@ -6,9 +6,9 @@ export function listenForSyncEvent(actions, store) { let attemptedSyncRepair = false; listen('sync-event', info => { - let { type, subtype, meta, tables } = info; + const { type, subtype, meta, tables } = info; - let prefs = store.getState().prefs.local; + const prefs = store.getState().prefs.local; if (!prefs || !prefs.id) { // Do nothing if no budget is loaded return; @@ -46,7 +46,7 @@ export function listenForSyncEvent(actions, store) { } } else if (type === 'error') { let notif: Notification | null = null; - let learnMore = + const learnMore = '[Learn more](https://actualbudget.org/docs/getting-started/sync/#debugging-sync-issues)'; const githubIssueLink = 'https://github.com/actualbudget/actual/issues/new?assignees=&labels=bug&template=bug-report.yml&title=%5BBug%5D%3A+'; @@ -174,7 +174,7 @@ export function listenForSyncEvent(actions, store) { // the server does not match the local one. This can mean a // few things depending on the state, and we try to show an // appropriate message and call to action to fix it. - let { cloudFileId } = store.getState().prefs.local; + const { cloudFileId } = store.getState().prefs.local; notif = { title: 'Syncing has been reset on this cloud file', diff --git a/packages/loot-core/src/client/update-notification.ts b/packages/loot-core/src/client/update-notification.ts index 3057a1c6f..d66b8c1c0 100644 --- a/packages/loot-core/src/client/update-notification.ts +++ b/packages/loot-core/src/client/update-notification.ts @@ -5,8 +5,8 @@ export default async function checkForUpdateNotification( loadPrefs, savePrefs, ) { - let latestVersion = await getLatestVersion(); - let isOutdated = await getIsOutdated(latestVersion); + const latestVersion = await getLatestVersion(); + const isOutdated = await getIsOutdated(latestVersion); if ( !isOutdated || (await loadPrefs())['flags.updateNotificationShownForVersion'] === diff --git a/packages/loot-core/src/mocks/arbitrary-schema.ts b/packages/loot-core/src/mocks/arbitrary-schema.ts index 97ec3113d..23aace50d 100644 --- a/packages/loot-core/src/mocks/arbitrary-schema.ts +++ b/packages/loot-core/src/mocks/arbitrary-schema.ts @@ -52,8 +52,8 @@ export function typeArbitrary(typeDesc, name?) { } export function flattenSortTransactions(arr) { - let flattened = arr.reduce((list, trans) => { - let { subtransactions, ...fields } = trans; + const flattened = arr.reduce((list, trans) => { + const { subtransactions, ...fields } = trans; if (subtransactions.length > 0) { list.push({ @@ -101,7 +101,7 @@ function tableArbitrary< extraArbs?: E, requiredKeys: Array<Extract<keyof T | keyof E, string>> = [], ) { - let arb = fc.record( + const arb = fc.record( { ...Object.fromEntries<T>( Object.entries(tableSchema).map(([name, field]) => { @@ -128,11 +128,11 @@ export function makeTransaction({ splitFreq = 1, payeeIds, }: { splitFreq?: number; payeeIds?: string[] } = {}) { - let payeeField = payeeIds + const payeeField = payeeIds ? { payee: fc.oneof(...payeeIds.map(id => fc.constant(id))) } : null; - let subtrans = tableArbitrary(schema.transactions, payeeField); + const subtrans = tableArbitrary(schema.transactions, payeeField); return tableArbitrary( schema.transactions, @@ -150,7 +150,7 @@ export function makeTransaction({ export const makeTransactionArray = ( options: { minLength?; maxLength?; splitFreq?; payeeIds? } = {}, ) => { - let { minLength, maxLength, ...transOpts } = options; + const { minLength, maxLength, ...transOpts } = options; return fc .array(makeTransaction(transOpts), { minLength, maxLength }) .map(arr => flattenSortTransactions(arr)); diff --git a/packages/loot-core/src/mocks/budget.ts b/packages/loot-core/src/mocks/budget.ts index 2993722a6..8c308b339 100644 --- a/packages/loot-core/src/mocks/budget.ts +++ b/packages/loot-core/src/mocks/budget.ts @@ -44,13 +44,13 @@ function getStartingBalanceCat(categories) { } function extractCommonThings(payees, groups) { - let incomePayee = payees.find(p => p.name === 'Deposit'); - let expensePayees = payees.filter( + const incomePayee = payees.find(p => p.name === 'Deposit'); + const expensePayees = payees.filter( p => p.name !== 'Deposit' && p.name !== 'Starting Balance', ); - let expenseGroup = groups.find(g => g.is_income === 0); - let incomeGroup = groups.find(g => g.is_income === 1); - let categories = expenseGroup.categories.filter( + const expenseGroup = groups.find(g => g.is_income === 0); + const incomeGroup = groups.find(g => g.is_income === 1); + const categories = expenseGroup.categories.filter( c => [ 'Food', @@ -74,7 +74,7 @@ function extractCommonThings(payees, groups) { } async function fillPrimaryChecking(handlers, account, payees, groups) { - let { + const { incomePayee, expensePayees, incomeGroup, @@ -82,9 +82,9 @@ async function fillPrimaryChecking(handlers, account, payees, groups) { billCategories, billPayees, } = extractCommonThings(payees, groups); - let numTransactions = integer(100, 200); + const numTransactions = integer(100, 200); - let transactions = []; + const transactions = []; for (let i = 0; i < numTransactions; i++) { let payee; if (random() < 0.09) { @@ -107,7 +107,7 @@ async function fillPrimaryChecking(handlers, account, payees, groups) { amount = integer(0, random() < 0.05 ? -8000 : -700); } - let transaction: TransactionEntity = { + const transaction: TransactionEntity = { amount, payee: payee.id, account: account.id, @@ -117,8 +117,8 @@ async function fillPrimaryChecking(handlers, account, payees, groups) { transactions.push(transaction); if (random() < 0.2) { - let a = Math.round(transaction.amount / 3); - let pick = () => + const a = Math.round(transaction.amount / 3); + const pick = () => payee === incomePayee ? incomeGroup.categories.find(c => c.name === 'Income').id : pickRandom(expenseCategories).id; @@ -133,15 +133,15 @@ async function fillPrimaryChecking(handlers, account, payees, groups) { } } - let earliestMonth = monthUtils.monthFromDate( + const earliestMonth = monthUtils.monthFromDate( transactions[transactions.length - 1].date, ); - let months = monthUtils.rangeInclusive( + const months = monthUtils.rangeInclusive( earliestMonth, monthUtils.currentMonth(), ); - let currentDay = monthUtils.currentDay(); - for (let month of months) { + const currentDay = monthUtils.currentDay(); + for (const month of months) { let date = monthUtils.addDays(month, 12); if (monthUtils.isBefore(date, currentDay)) { transactions.push({ @@ -220,11 +220,11 @@ async function fillPrimaryChecking(handlers, account, payees, groups) { } async function fillChecking(handlers, account, payees, groups) { - let { incomePayee, expensePayees, incomeGroup, expenseCategories } = + const { incomePayee, expensePayees, incomeGroup, expenseCategories } = extractCommonThings(payees, groups); - let numTransactions = integer(20, 40); + const numTransactions = integer(20, 40); - let transactions = []; + const transactions = []; for (let i = 0; i < numTransactions; i++) { let payee; if (random() < 0.04) { @@ -240,7 +240,7 @@ async function fillChecking(handlers, account, payees, groups) { category = pickRandom(expenseCategories); } - let amount = + const amount = payee.name === 'Deposit' ? integer(50000, 70000) : integer(0, -10000); transactions.push({ @@ -268,16 +268,16 @@ async function fillChecking(handlers, account, payees, groups) { } async function fillInvestment(handlers, account, payees, groups) { - let { incomePayee, incomeGroup } = extractCommonThings(payees, groups); + const { incomePayee, incomeGroup } = extractCommonThings(payees, groups); - let numTransactions = integer(10, 30); + const numTransactions = integer(10, 30); - let transactions = []; + const transactions = []; for (let i = 0; i < numTransactions; i++) { - let payee = incomePayee; - let category = incomeGroup.categories.find(c => c.name === 'Income'); + const payee = incomePayee; + const category = incomeGroup.categories.find(c => c.name === 'Income'); - let amount = integer(10000, 20000); + const amount = integer(10000, 20000); transactions.push({ amount, @@ -304,12 +304,12 @@ async function fillInvestment(handlers, account, payees, groups) { } async function fillSavings(handlers, account, payees, groups) { - let { incomePayee, expensePayees, incomeGroup, expenseCategories } = + const { incomePayee, expensePayees, incomeGroup, expenseCategories } = extractCommonThings(payees, groups); - let numTransactions = integer(15, 40); + const numTransactions = integer(15, 40); - let transactions = []; + const transactions = []; for (let i = 0; i < numTransactions; i++) { let payee; if (random() < 0.3) { @@ -317,11 +317,11 @@ async function fillSavings(handlers, account, payees, groups) { } else { payee = pickRandom(expensePayees); } - let category = + const category = payee === incomePayee ? incomeGroup.categories.find(c => c.name === 'Income') : pickRandom(expenseCategories); - let amount = + const amount = payee === incomePayee ? integer(10000, 80000) : integer(-10000, -2000); transactions.push({ @@ -349,13 +349,13 @@ async function fillSavings(handlers, account, payees, groups) { } async function fillMortgage(handlers, account, payees, groups) { - let { incomePayee, incomeGroup } = extractCommonThings(payees, groups); + const { incomePayee, incomeGroup } = extractCommonThings(payees, groups); - let numTransactions = integer(7, 10); - let amount = integer(100000, 200000); - let category = incomeGroup.categories.find(c => c.name === 'Income'); + const numTransactions = integer(7, 10); + const amount = integer(100000, 200000); + const category = incomeGroup.categories.find(c => c.name === 'Income'); - let transactions = [ + const transactions = [ { amount: integer(-3000, -3500) * 100 * 100, payee: payees.find(p => p.name === 'Starting Balance').id, @@ -367,7 +367,7 @@ async function fillMortgage(handlers, account, payees, groups) { }, ]; for (let i = 0; i < numTransactions; i++) { - let payee = incomePayee; + const payee = incomePayee; transactions.push({ amount, @@ -386,12 +386,12 @@ async function fillMortgage(handlers, account, payees, groups) { } async function fillOther(handlers, account, payees, groups) { - let { incomePayee, incomeGroup } = extractCommonThings(payees, groups); + const { incomePayee, incomeGroup } = extractCommonThings(payees, groups); - let numTransactions = integer(3, 6); - let category = incomeGroup.categories.find(c => c.name === 'Income'); + const numTransactions = integer(3, 6); + const category = incomeGroup.categories.find(c => c.name === 'Income'); - let transactions: TransactionEntity[] = [ + const transactions: TransactionEntity[] = [ { amount: integer(3250, 3700) * 100 * 100, payee: payees.find(p => p.name === 'Starting Balance').id, @@ -403,8 +403,8 @@ async function fillOther(handlers, account, payees, groups) { }, ]; for (let i = 0; i < numTransactions; i++) { - let payee = incomePayee; - let amount = integer(4, 9) * 100 * 100; + const payee = incomePayee; + const amount = integer(4, 9) * 100 * 100; transactions.push({ amount, @@ -422,14 +422,14 @@ async function fillOther(handlers, account, payees, groups) { } async function createBudget(accounts, payees, groups) { - let primaryAccount = accounts.find(a => (a.name = 'Bank of America')); - let earliestDate = ( + const primaryAccount = accounts.find(a => (a.name = 'Bank of America')); + const earliestDate = ( await db.first( `SELECT * FROM v_transactions t LEFT JOIN accounts a ON t.account = a.id WHERE a.offbudget = 0 AND t.is_child = 0 ORDER BY date ASC LIMIT 1`, ) ).date; - let earliestPrimaryDate = ( + const earliestPrimaryDate = ( await db.first( `SELECT * FROM v_transactions t LEFT JOIN accounts a ON t.account = a.id WHERE a.id = ? AND a.offbudget = 0 AND t.is_child = 0 ORDER BY date ASC LIMIT 1`, @@ -437,13 +437,13 @@ async function createBudget(accounts, payees, groups) { ) ).date; - let start = monthUtils.monthFromDate(db.fromDateRepr(earliestDate)); - let end = monthUtils.currentMonth(); - let months = monthUtils.rangeInclusive(start, end); + const start = monthUtils.monthFromDate(db.fromDateRepr(earliestDate)); + const end = monthUtils.currentMonth(); + const months = monthUtils.rangeInclusive(start, end); function category(name) { - for (let group of groups) { - let cat = group.categories.find(c => c.name === name); + for (const group of groups) { + const cat = group.categories.find(c => c.name === name); if (cat) { return cat; } @@ -455,7 +455,7 @@ async function createBudget(accounts, payees, groups) { } function setBudgetIfSpent(month, cat) { - let spent: number = sheet.getCellValue( + const spent: number = sheet.getCellValue( monthUtils.sheetForMonth(month), `sum-amount-${cat.id}`, ) as number; @@ -467,7 +467,7 @@ async function createBudget(accounts, payees, groups) { await runMutator(() => batchMessages(async () => { - for (let month of months) { + for (const month of months) { if ( month >= monthUtils.monthFromDate(db.fromDateRepr(earliestPrimaryDate)) @@ -509,18 +509,18 @@ async function createBudget(accounts, payees, groups) { await runMutator(() => batchMessages(async () => { let prevSaved = 0; - for (let month of months) { + for (const month of months) { if ( month >= monthUtils.monthFromDate(db.fromDateRepr(earliestPrimaryDate)) && month <= monthUtils.currentMonth() ) { - let sheetName = monthUtils.sheetForMonth(month); - let toBudget: number = sheet.getCellValue( + const sheetName = monthUtils.sheetForMonth(month); + const toBudget: number = sheet.getCellValue( sheetName, 'to-budget', ) as number; - let available = toBudget - prevSaved; + const available = toBudget - prevSaved; if (available - 403000 > 0) { setBudget(month, category('Savings'), available - 403000); @@ -537,8 +537,8 @@ async function createBudget(accounts, payees, groups) { await sheet.waitOnSpreadsheet(); - let sheetName = monthUtils.sheetForMonth(monthUtils.currentMonth()); - let toBudget: number = sheet.getCellValue(sheetName, 'to-budget') as number; + const sheetName = monthUtils.sheetForMonth(monthUtils.currentMonth()); + const toBudget: number = sheet.getCellValue(sheetName, 'to-budget') as number; if (toBudget < 0) { await addTransactions(primaryAccount.id, [ { @@ -567,7 +567,7 @@ export async function createTestBudget(handlers) { await db.runQuery('DELETE FROM categories;'); await db.runQuery('DELETE FROM category_groups'); - let accounts: { name: string; offBudget?: 1; id?: string }[] = [ + const accounts: { name: string; offBudget?: 1; id?: string }[] = [ { name: 'Bank of America' }, { name: 'Ally Savings' }, { name: 'Capital One Checking' }, @@ -579,13 +579,13 @@ export async function createTestBudget(handlers) { ]; await runMutator(() => batchMessages(async () => { - for (let account of accounts) { + for (const account of accounts) { account.id = await handlers['account-create'](account); } }), ); - let payees: Array<PayeeEntity & { bill?: boolean }> = [ + const payees: Array<PayeeEntity & { bill?: boolean }> = [ { name: 'Starting Balance' }, { name: 'Kroger' }, { name: 'Publix' }, @@ -602,13 +602,13 @@ export async function createTestBudget(handlers) { await runMutator(() => batchMessages(async () => { - for (let payee of payees) { + for (const payee of payees) { payee.id = await handlers['payee-create']({ name: payee.name }); } }), ); - let categoryGroups: Array<CategoryGroupEntity> = [ + const categoryGroups: Array<CategoryGroupEntity> = [ { name: 'Usual Expenses', categories: [ @@ -644,13 +644,13 @@ export async function createTestBudget(handlers) { ]; await runMutator(async () => { - for (let group of categoryGroups) { + for (const group of categoryGroups) { group.id = await handlers['category-group-create']({ name: group.name, isIncome: group.is_income ? 1 : 0, }); - for (let category of group.categories) { + for (const category of group.categories) { category.id = await handlers['category-create']({ ...category, isIncome: category.is_income ? 1 : 0, @@ -660,13 +660,13 @@ export async function createTestBudget(handlers) { } }); - let allGroups = (await runHandler(handlers['get-categories'])).grouped; + const allGroups = (await runHandler(handlers['get-categories'])).grouped; setSyncingMode('import'); await runMutator(() => batchMessages(async () => { - for (let account of accounts) { + for (const account of accounts) { if (account.name === 'Bank of America') { await fillPrimaryChecking(handlers, account, payees, allGroups); } else if ( @@ -699,22 +699,22 @@ export async function createTestBudget(handlers) { // This might happen depending on the transactions added, but we // don't want to show that as it'd be weird. We modify the latest // deposit transaction to force it to be positive - let primaryAccount = accounts.find(a => (a.name = 'Bank of America')); - let { data: primaryBalance } = await aqlQuery( + const primaryAccount = accounts.find(a => (a.name = 'Bank of America')); + const { data: primaryBalance } = await aqlQuery( q('transactions') .filter({ account: primaryAccount.id }) .calculate({ $sum: '$amount' }) .serialize(), ); if (primaryBalance < 0) { - let { data: results } = await aqlQuery( + const { data: results } = await aqlQuery( q('transactions') .filter({ account: primaryAccount.id, amount: { $gt: 0 } }) .limit(1) .select(['id', 'amount']) .serialize(), ); - let lastDeposit = results[0]; + const lastDeposit = results[0]; await runHandler(handlers['transaction-update'], { ...lastDeposit, diff --git a/packages/loot-core/src/mocks/redux.tsx b/packages/loot-core/src/mocks/redux.tsx index f47efeabb..569c6ae82 100644 --- a/packages/loot-core/src/mocks/redux.tsx +++ b/packages/loot-core/src/mocks/redux.tsx @@ -6,7 +6,7 @@ import thunk from 'redux-thunk'; import reducers from '../client/reducers'; -let appReducer = combineReducers(reducers); +const appReducer = combineReducers(reducers); let store = null; export function resetStore() { diff --git a/packages/loot-core/src/mocks/setup.ts b/packages/loot-core/src/mocks/setup.ts index 431b0a478..ec4293a7d 100644 --- a/packages/loot-core/src/mocks/setup.ts +++ b/packages/loot-core/src/mocks/setup.ts @@ -29,7 +29,7 @@ process.on('unhandledRejection', reason => { global.IS_TESTING = true; let _time = 123456789; -let _oldDateNow = global.Date.now; +const _oldDateNow = global.Date.now; global.Date.now = () => _time; global.restoreDateNow = () => (global.Date.now = _oldDateNow); @@ -99,7 +99,7 @@ global.getDatabaseDump = async function (tables) { }), ); - let grouped = {}; + const grouped = {}; data.forEach(table => (grouped[table[0]] = table[1])); return grouped; }; @@ -110,13 +110,13 @@ global.getDatabaseDump = async function (tables) { global.emptyDatabase = function (avoidUpdate) { return async () => { - let path = ':memory:'; + const path = ':memory:'; // let path = `/tmp/foo-${Math.random()}.sqlite`; // console.log('Using db ' + path); await sqlite.init(); - let memoryDB = await sqlite.openDatabase(path); + const memoryDB = await sqlite.openDatabase(path); sqlite.execQuery( memoryDB, nativeFs.readFileSync(__dirname + '/../server/sql/init.sql', 'utf8'), diff --git a/packages/loot-core/src/mocks/spreadsheet.ts b/packages/loot-core/src/mocks/spreadsheet.ts index a83cc3f5f..7a79ed62d 100644 --- a/packages/loot-core/src/mocks/spreadsheet.ts +++ b/packages/loot-core/src/mocks/spreadsheet.ts @@ -3,9 +3,9 @@ function makeSpreadsheet() { return { observers: [], _getNode(sheetName, name) { - let resolvedName = `${sheetName}!${name}`; + const resolvedName = `${sheetName}!${name}`; - let existing = cells[resolvedName]; + const existing = cells[resolvedName]; if (existing) { return existing; } @@ -23,14 +23,14 @@ function makeSpreadsheet() { }, bind(sheetName, binding, fields, cb) { - let { name } = binding; - let resolvedName = `${sheetName}!${name}`; + const { name } = binding; + const resolvedName = `${sheetName}!${name}`; if (!this.observers[resolvedName]) { this.observers[resolvedName] = []; } this.observers[resolvedName].push(cb); - let node = this._getNode(sheetName, name); + const node = this._getNode(sheetName, name); cb(node); // bind returns a function which unsubscribes itself. In this mock diff --git a/packages/loot-core/src/mocks/util.ts b/packages/loot-core/src/mocks/util.ts index 0525babc6..484c1252e 100644 --- a/packages/loot-core/src/mocks/util.ts +++ b/packages/loot-core/src/mocks/util.ts @@ -42,7 +42,7 @@ export function debugDOM(node) { str += node.textContent + '\n'; } - for (let child of node.childNodes) { + for (const child of node.childNodes) { str += debugDOM(child, indent + 2); } } diff --git a/packages/loot-core/src/platform/client/fetch/__mocks__/index.web.ts b/packages/loot-core/src/platform/client/fetch/__mocks__/index.web.ts index b486938ce..bbb71b502 100644 --- a/packages/loot-core/src/platform/client/fetch/__mocks__/index.web.ts +++ b/packages/loot-core/src/platform/client/fetch/__mocks__/index.web.ts @@ -5,10 +5,10 @@ let serverHandler = null; export const initServer: T.InitServer = handlers => { serverHandler = msg => { - let { name, args, catchErrors } = msg; + const { name, args, catchErrors } = msg; if (handlers[name]) { return Promise.resolve().then(() => { - let promise = handlers[name](args); + const promise = handlers[name](args); if (catchErrors) { return promise.then( @@ -57,7 +57,7 @@ export const listen = (name, cb) => { listeners.get(name).push(cb); return () => { - let arr = listeners.get(name); + const arr = listeners.get(name); listeners.set( name, arr.filter(cb_ => cb_ !== cb), diff --git a/packages/loot-core/src/platform/client/fetch/index.browser.ts b/packages/loot-core/src/platform/client/fetch/index.browser.ts index 8280b8493..47482e7c8 100644 --- a/packages/loot-core/src/platform/client/fetch/index.browser.ts +++ b/packages/loot-core/src/platform/client/fetch/index.browser.ts @@ -5,8 +5,8 @@ import * as undo from '../undo'; import type * as T from '.'; -let replyHandlers = new Map(); -let listeners = new Map(); +const replyHandlers = new Map(); +const listeners = new Map(); let messageQueue = []; let globalWorker = null; @@ -65,7 +65,7 @@ function handleMessage(msg) { const listens = listeners.get(name); if (listens) { for (let i = 0; i < listens.length; i++) { - let stop = listens[i](args); + const stop = listens[i](args); if (stop === true) { break; } @@ -86,7 +86,7 @@ function connectWorker(worker, onOpen, onError) { globalWorker = worker; worker.onmessage = event => { - let msg = event.data; + const msg = event.data; // The worker implementation implements its own concept of a // 'connect' event because the worker is immediately @@ -148,10 +148,10 @@ export const send: T.Send = function ( { catchErrors = false } = {}, ) { return new Promise((resolve, reject) => { - let id = uuidv4(); + const id = uuidv4(); replyHandlers.set(id, { resolve, reject }); - let message = { + const message = { id, name, args, @@ -178,7 +178,7 @@ export const listen: T.Listen = function (name, cb) { listeners.get(name).push(cb); return () => { - let arr = listeners.get(name); + const arr = listeners.get(name); listeners.set( name, arr.filter(cb_ => cb_ !== cb), diff --git a/packages/loot-core/src/platform/client/fetch/index.web.ts b/packages/loot-core/src/platform/client/fetch/index.web.ts index b993bfc4b..cdf9e2c5f 100644 --- a/packages/loot-core/src/platform/client/fetch/index.web.ts +++ b/packages/loot-core/src/platform/client/fetch/index.web.ts @@ -4,8 +4,8 @@ import * as undo from '../undo'; import type * as T from '.'; -let replyHandlers = new Map(); -let listeners = new Map(); +const replyHandlers = new Map(); +const listeners = new Map(); let messageQueue = []; let socketClient = null; let activePort = null; @@ -16,7 +16,7 @@ function connectSocket(port, onOpen) { return; } - let client = new WebSocket('ws://localhost:' + port); + const client = new WebSocket('ws://localhost:' + port); socketClient = client; activePort = port; @@ -32,7 +32,8 @@ function connectSocket(port, onOpen) { const { id } = msg; replyHandlers.delete(id); } else if (msg.type === 'reply') { - let { id, result, mutated, undoTag } = msg; + let { result } = msg; + const { id, mutated, undoTag } = msg; // Check if the result is a serialized buffer, and if so // convert it to a Uint8Array. This is only needed when working @@ -58,7 +59,7 @@ function connectSocket(port, onOpen) { const listens = listeners.get(name); if (listens) { for (let i = 0; i < listens.length; i++) { - let stop = listens[i](args); + const stop = listens[i](args); if (stop === true) { break; } @@ -96,7 +97,7 @@ export const send: T.Send = function ( { catchErrors = false } = {}, ) { return new Promise((resolve, reject) => { - let id = uuidv4(); + const id = uuidv4(); replyHandlers.set(id, { resolve, reject }); if (socketClient) { @@ -135,7 +136,7 @@ export const listen: T.Listen = function (name, cb) { listeners.get(name).push(cb); return () => { - let arr = listeners.get(name); + const arr = listeners.get(name); if (arr) { listeners.set( name, diff --git a/packages/loot-core/src/platform/client/undo/index.web.ts b/packages/loot-core/src/platform/client/undo/index.web.ts index 3718a85c3..15c3300b0 100644 --- a/packages/loot-core/src/platform/client/undo/index.web.ts +++ b/packages/loot-core/src/platform/client/undo/index.web.ts @@ -4,10 +4,10 @@ import type * as T from '.'; // List of recently used states. We don't use a true MRU structure // because our needs are simple and we also do some custom reordering. -let HISTORY_SIZE = 40; +const HISTORY_SIZE = 40; let UNDO_STATE_MRU: T.UndoState[] = []; -let currentUndoState: T.UndoState = { +const currentUndoState: T.UndoState = { url: null, openModal: null, selectedItems: null, @@ -27,7 +27,7 @@ export const getTaggedState: T.GetTaggedState = function (id) { }; export const snapshot: T.Snapshot = function () { - let tagged = { ...currentUndoState, id: uuidv4() }; + const tagged = { ...currentUndoState, id: uuidv4() }; UNDO_STATE_MRU.unshift(tagged); UNDO_STATE_MRU = UNDO_STATE_MRU.slice(0, HISTORY_SIZE); return tagged.id; diff --git a/packages/loot-core/src/platform/server/asyncStorage/index.electron.ts b/packages/loot-core/src/platform/server/asyncStorage/index.electron.ts index 7551acb07..22f3b8a02 100644 --- a/packages/loot-core/src/platform/server/asyncStorage/index.electron.ts +++ b/packages/loot-core/src/platform/server/asyncStorage/index.electron.ts @@ -5,7 +5,7 @@ import * as lootFs from '../fs'; import * as T from '.'; -let getStorePath = () => join(lootFs.getDataDir(), 'global-store.json'); +const getStorePath = () => join(lootFs.getDataDir(), 'global-store.json'); let store; let persisted = true; diff --git a/packages/loot-core/src/platform/server/asyncStorage/index.web.ts b/packages/loot-core/src/platform/server/asyncStorage/index.web.ts index b81081c71..6af2b01ae 100644 --- a/packages/loot-core/src/platform/server/asyncStorage/index.web.ts +++ b/packages/loot-core/src/platform/server/asyncStorage/index.web.ts @@ -11,13 +11,13 @@ function commit(trans) { } export const getItem: T.GetItem = async function (key) { - let db = await getDatabase(); + const db = await getDatabase(); - let transaction = db.transaction(['asyncStorage'], 'readonly'); - let objectStore = transaction.objectStore('asyncStorage'); + const transaction = db.transaction(['asyncStorage'], 'readonly'); + const objectStore = transaction.objectStore('asyncStorage'); return new Promise((resolve, reject) => { - let req = objectStore.get(key); + const req = objectStore.get(key); req.onerror = e => reject(e); req.onsuccess = e => resolve(e.target.result); commit(transaction); @@ -25,13 +25,13 @@ export const getItem: T.GetItem = async function (key) { }; export const setItem: T.SetItem = async function (key, value) { - let db = await getDatabase(); + const db = await getDatabase(); - let transaction = db.transaction(['asyncStorage'], 'readwrite'); - let objectStore = transaction.objectStore('asyncStorage'); + const transaction = db.transaction(['asyncStorage'], 'readwrite'); + const objectStore = transaction.objectStore('asyncStorage'); new Promise((resolve, reject) => { - let req = objectStore.put(value, key); + const req = objectStore.put(value, key); req.onerror = e => reject(e); req.onsuccess = e => resolve(undefined); commit(transaction); @@ -39,13 +39,13 @@ export const setItem: T.SetItem = async function (key, value) { }; export const removeItem: T.RemoveItem = async function (key) { - let db = await getDatabase(); + const db = await getDatabase(); - let transaction = db.transaction(['asyncStorage'], 'readwrite'); - let objectStore = transaction.objectStore('asyncStorage'); + const transaction = db.transaction(['asyncStorage'], 'readwrite'); + const objectStore = transaction.objectStore('asyncStorage'); return new Promise((resolve, reject) => { - let req = objectStore.delete(key); + const req = objectStore.delete(key); req.onerror = e => reject(e); req.onsuccess = e => resolve(undefined); commit(transaction); @@ -53,15 +53,15 @@ export const removeItem: T.RemoveItem = async function (key) { }; export const multiGet: T.MultiGet = async function (keys) { - let db = await getDatabase(); + const db = await getDatabase(); - let transaction = db.transaction(['asyncStorage'], 'readonly'); - let objectStore = transaction.objectStore('asyncStorage'); + const transaction = db.transaction(['asyncStorage'], 'readonly'); + const objectStore = transaction.objectStore('asyncStorage'); - let promise = Promise.all( + const promise = Promise.all( keys.map(key => { return new Promise<[string, string]>((resolve, reject) => { - let req = objectStore.get(key); + const req = objectStore.get(key); req.onerror = e => reject(e); req.onsuccess = e => resolve([key, e.target.result]); }); @@ -73,15 +73,15 @@ export const multiGet: T.MultiGet = async function (keys) { }; export const multiSet: T.MultiSet = async function (keyValues) { - let db = await getDatabase(); + const db = await getDatabase(); - let transaction = db.transaction(['asyncStorage'], 'readwrite'); - let objectStore = transaction.objectStore('asyncStorage'); + const transaction = db.transaction(['asyncStorage'], 'readwrite'); + const objectStore = transaction.objectStore('asyncStorage'); - let promise = Promise.all( + const promise = Promise.all( keyValues.map(([key, value]) => { return new Promise((resolve, reject) => { - let req = objectStore.put(value, key); + const req = objectStore.put(value, key); req.onerror = e => reject(e); req.onsuccess = e => resolve(undefined); }); @@ -93,15 +93,15 @@ export const multiSet: T.MultiSet = async function (keyValues) { }; export const multiRemove: T.MultiRemove = async function (keys) { - let db = await getDatabase(); + const db = await getDatabase(); - let transaction = db.transaction(['asyncStorage'], 'readwrite'); - let objectStore = transaction.objectStore('asyncStorage'); + const transaction = db.transaction(['asyncStorage'], 'readwrite'); + const objectStore = transaction.objectStore('asyncStorage'); - let promise = Promise.all( + const promise = Promise.all( keys.map(key => { return new Promise((resolve, reject) => { - let req = objectStore.delete(key); + const req = objectStore.delete(key); req.onerror = e => reject(e); req.onsuccess = e => resolve(undefined); }); diff --git a/packages/loot-core/src/platform/server/connection/index.electron.ts b/packages/loot-core/src/platform/server/connection/index.electron.ts index faf0ffea5..92206ff41 100644 --- a/packages/loot-core/src/platform/server/connection/index.electron.ts +++ b/packages/loot-core/src/platform/server/connection/index.electron.ts @@ -25,13 +25,13 @@ export const init: T.Init = function (socketName, handlers) { ws.on('error', console.error); ws.on('message', data => { - let msg = JSON.parse(data); + const msg = JSON.parse(data); if (ws.readyState !== 1) { return; } - let { id, name, args, undoTag, catchErrors } = msg; + const { id, name, args, undoTag, catchErrors } = msg; if (handlers[name]) { runHandler(handlers[name], args, { undoTag, name }).then( @@ -60,7 +60,7 @@ export const init: T.Init = function (socketName, handlers) { if (ws.readyState !== 1) { return; } - let error = coerceError(nativeError); + const error = coerceError(nativeError); if (name.startsWith('api/')) { // The API is newer and does automatically forward diff --git a/packages/loot-core/src/platform/server/connection/index.web.ts b/packages/loot-core/src/platform/server/connection/index.web.ts index 0cafd1e71..8b8bcd5b4 100644 --- a/packages/loot-core/src/platform/server/connection/index.web.ts +++ b/packages/loot-core/src/platform/server/connection/index.web.ts @@ -4,7 +4,7 @@ import { captureException } from '../../exceptions'; import type * as T from '.'; function getGlobalObject() { - let obj = + const obj = typeof window !== 'undefined' ? window : typeof self !== 'undefined' @@ -35,14 +35,14 @@ export const init: T.Init = function (serverChn, handlers) { serverChannel.addEventListener( 'message', e => { - let data = e.data; - let msg = typeof data === 'string' ? JSON.parse(data) : data; + const data = e.data; + const msg = typeof data === 'string' ? JSON.parse(data) : data; if (msg.type && (msg.type === 'init' || msg.type.startsWith('__'))) { return; } - let { id, name, args, undoTag, catchErrors } = msg; + const { id, name, args, undoTag, catchErrors } = msg; if (handlers[name]) { runHandler(handlers[name], args, { undoTag, name }).then( @@ -60,7 +60,7 @@ export const init: T.Init = function (serverChn, handlers) { }); }, nativeError => { - let error = coerceError(nativeError); + const error = coerceError(nativeError); if (name.startsWith('api/')) { // The API is newer and does automatically forward diff --git a/packages/loot-core/src/platform/server/fs/index.electron.ts b/packages/loot-core/src/platform/server/fs/index.electron.ts index 8e5df8d61..58313cb88 100644 --- a/packages/loot-core/src/platform/server/fs/index.electron.ts +++ b/packages/loot-core/src/platform/server/fs/index.electron.ts @@ -136,7 +136,7 @@ export const removeDir = dirpath => { export const removeDirRecursively = async dirpath => { if (await exists(dirpath)) { - for (let file of await listDir(dirpath)) { + for (const file of await listDir(dirpath)) { const fullpath = join(dirpath, file); if (fs.statSync(fullpath).isDirectory()) { await removeDirRecursively(fullpath); diff --git a/packages/loot-core/src/platform/server/fs/index.web.test.ts b/packages/loot-core/src/platform/server/fs/index.web.test.ts index a77a51889..d83f08f32 100644 --- a/packages/loot-core/src/platform/server/fs/index.web.test.ts +++ b/packages/loot-core/src/platform/server/fs/index.web.test.ts @@ -30,9 +30,9 @@ describe('web filesystem', () => { expect(await readFile('/documents/foo.txt')).toBe('hello'); // Binary file - let str = 'hello, world'; - let buf = new ArrayBuffer(str.length * 2); - let view = new Uint16Array(buf); + const str = 'hello, world'; + const buf = new ArrayBuffer(str.length * 2); + const view = new Uint16Array(buf); for (let i = 0, strLen = str.length; i < strLen; i++) { view[i] = str.charCodeAt(i); } @@ -40,8 +40,8 @@ describe('web filesystem', () => { await writeFile('/documents/foo.bin', buf); expect(await readFile('/documents/foo.bin')).toBe('hello, world'); - let db = await idb.openDatabase(); - let { store } = await idb.getStore(db, 'files'); + const db = await idb.openDatabase(); + const { store } = await idb.getStore(db, 'files'); // Make sure they are in idb expect(await idb.get(store, '/documents/foo.txt')).toEqual({ @@ -75,8 +75,8 @@ describe('web filesystem', () => { }); test('files are restored from idb', async () => { - let db = await idb.openDatabase(); - let { store } = await idb.getStore(db, 'files'); + const db = await idb.openDatabase(); + const { store } = await idb.getStore(db, 'files'); idb.set(store, { filepath: '/documents/ok.txt', contents: 'oh yeah' }); idb.set(store, { filepath: '/documents/deep/nested/file/ok.txt', @@ -94,8 +94,8 @@ describe('web filesystem', () => { expect(await exists('/documents/deep')).toBe(true); expect(await readFile('/documents/deep/nested/file/ok.txt')).toBe('deeper'); - let FS = sqlite._getModule().FS; - let { node } = FS.lookupPath('/documents/deep/nested/db.sqlite'); + const FS = sqlite._getModule().FS; + const { node } = FS.lookupPath('/documents/deep/nested/db.sqlite'); expect(node.link).toBe( '/blocked/' + pathToId('/documents/deep/nested/db.sqlite'), ); diff --git a/packages/loot-core/src/platform/server/fs/index.web.ts b/packages/loot-core/src/platform/server/fs/index.web.ts index d7685b82c..45da2f6f6 100644 --- a/packages/loot-core/src/platform/server/fs/index.web.ts +++ b/packages/loot-core/src/platform/server/fs/index.web.ts @@ -9,7 +9,7 @@ import join from './path-join'; let FS = null; let BFS = null; -let NO_PERSIST = false; +const NO_PERSIST = false; export const bundledDatabasePath = '/default-db.sqlite'; export const migrationsPath = '/migrations'; @@ -36,9 +36,9 @@ function _exists(filepath) { } function _mkdirRecursively(dir) { - let parts = dir.split('/').filter(str => str !== ''); + const parts = dir.split('/').filter(str => str !== ''); let path = ''; - for (let part of parts) { + for (const part of parts) { path += '/' + part; if (!_exists(path)) { FS.mkdir(path); @@ -80,8 +80,8 @@ async function _readFile(filepath, opts?: { encoding?: string }) { } // Grab contents from IDB - let { store } = idb.getStore(await idb.getDatabase(), 'files'); - let item = await idb.get(store, filepath); + const { store } = idb.getStore(await idb.getDatabase(), 'files'); + const item = await idb.get(store, filepath); if (item == null) { throw new Error('File does not exist: ' + filepath); @@ -102,7 +102,7 @@ async function _readFile(filepath, opts?: { encoding?: string }) { function resolveLink(path) { try { - let { node } = FS.lookupPath(path, { follow: false }); + const { node } = FS.lookupPath(path, { follow: false }); return node.link ? FS.readlink(path) : path; } catch (e) { return path; @@ -121,10 +121,10 @@ async function _writeFile(filepath, contents) { _createFile(filepath); if (!NO_PERSIST && filepath.startsWith('/documents')) { - let isDb = filepath.endsWith('.sqlite'); + const isDb = filepath.endsWith('.sqlite'); // Write to IDB - let { store } = idb.getStore(await idb.getDatabase(), 'files'); + const { store } = idb.getStore(await idb.getDatabase(), 'files'); if (isDb) { // We never write the contents of the database to idb ourselves. @@ -149,16 +149,16 @@ async function _writeFile(filepath, contents) { async function _removeFile(filepath) { if (!NO_PERSIST && filepath.startsWith('/documents')) { - let isDb = filepath.endsWith('.sqlite'); + const isDb = filepath.endsWith('.sqlite'); // Remove from IDB - let { store } = idb.getStore(await idb.getDatabase(), 'files'); + const { store } = idb.getStore(await idb.getDatabase(), 'files'); await idb.del(store, filepath); // If this is the database, is has been symlinked and we want to // remove the actual contents if (isDb) { - let linked = resolveLink(filepath); + const linked = resolveLink(filepath); // Be resilient to fs corruption: don't throw an error by trying // to remove a file that doesn't exist. For some reason the db // file is gone? It's ok, just ignore it @@ -174,14 +174,14 @@ async function _removeFile(filepath) { // Load files from the server that should exist by default async function populateDefaultFilesystem() { - let index = await ( + const index = await ( await fetch(process.env.PUBLIC_URL + 'data-file-index.txt') ).text(); - let files = index + const files = index .split('\n') .map(name => name.trim()) .filter(name => name !== ''); - let fetchFile = url => fetch(url).then(res => res.arrayBuffer()); + const fetchFile = url => fetch(url).then(res => res.arrayBuffer()); // This is hardcoded. We know we must create the migrations // directory, it's not worth complicating the index to support @@ -191,28 +191,28 @@ async function populateDefaultFilesystem() { await Promise.all( files.map(async file => { - let contents = await fetchFile(process.env.PUBLIC_URL + 'data/' + file); + const contents = await fetchFile(process.env.PUBLIC_URL + 'data/' + file); _writeFile('/' + file, contents); }), ); } export const populateFileHeirarchy = async function () { - let { store } = idb.getStore(await idb.getDatabase(), 'files'); - let req = store.getAllKeys(); - let paths: string[] = await new Promise((resolve, reject) => { + const { store } = idb.getStore(await idb.getDatabase(), 'files'); + const req = store.getAllKeys(); + const paths: string[] = await new Promise((resolve, reject) => { req.onsuccess = e => resolve(e.target.result); req.onerror = e => reject(e); }); - for (let path of paths) { + for (const path of paths) { _mkdirRecursively(basename(path)); _createFile(path); } }; export const init = async function () { - let Module = _getModule(); + const Module = _getModule(); FS = Module.FS; // When a user "uploads" a file, we just put it in memory in this @@ -234,7 +234,7 @@ export const init = async function () { // the blocked fs enough. Additionally, we don't populate the // default files in testing. if (process.env.NODE_ENV !== 'test') { - let backend = new IndexedDBBackend(() => { + const backend = new IndexedDBBackend(() => { connection.send('fallback-write-error'); }); BFS = new SQLiteFS(FS, backend); @@ -249,12 +249,12 @@ export const init = async function () { }; export const basename = function (filepath) { - let parts = filepath.split('/'); + const parts = filepath.split('/'); return parts.slice(0, -1).join('/'); }; export const listDir = async function (filepath) { - let paths = FS.readdir(filepath); + const paths = FS.readdir(filepath); return paths.filter(p => p !== '.' && p !== '..'); }; @@ -267,14 +267,14 @@ export const mkdir = async function (filepath) { }; export const size = async function (filepath) { - let attrs = FS.stat(resolveLink(filepath)); + const attrs = FS.stat(resolveLink(filepath)); return attrs.size; }; export const copyFile = async function (frompath, topath) { // TODO: This reads the whole file into memory, but that's probably // not a problem. This could be optimized - let contents = await _readFile(frompath); + const contents = await _readFile(frompath); return _writeFile(topath, contents); }; @@ -296,10 +296,10 @@ export const removeDir = async function (filepath) { export const removeDirRecursively = async function (dirpath) { if (await exists(dirpath)) { - for (let file of await listDir(dirpath)) { - let fullpath = join(dirpath, file); + for (const file of await listDir(dirpath)) { + const fullpath = join(dirpath, file); // `true` here means to not follow symlinks - let attr = FS.stat(fullpath, true); + const attr = FS.stat(fullpath, true); if (FS.isDir(attr.mode)) { await removeDirRecursively(fullpath); diff --git a/packages/loot-core/src/platform/server/fs/path-join.web.ts b/packages/loot-core/src/platform/server/fs/path-join.web.ts index cbad0db6d..7c36099fb 100644 --- a/packages/loot-core/src/platform/server/fs/path-join.web.ts +++ b/packages/loot-core/src/platform/server/fs/path-join.web.ts @@ -25,7 +25,7 @@ function normalizeStringPosix(path, allowAboveRoot) { res.charCodeAt(res.length - 2) !== 46 /*.*/ ) { if (res.length > 2) { - let lastSlashIndex = res.lastIndexOf('/'); + const lastSlashIndex = res.lastIndexOf('/'); if (lastSlashIndex !== res.length - 1) { if (lastSlashIndex === -1) { res = ''; @@ -70,8 +70,8 @@ function normalizeStringPosix(path, allowAboveRoot) { function normalizePath(path) { if (path.length === 0) return '.'; - let isAbsolute = path.charCodeAt(0) === 47; /*/*/ - let trailingSeparator = path.charCodeAt(path.length - 1) === 47; /*/*/ + const isAbsolute = path.charCodeAt(0) === 47; /*/*/ + const trailingSeparator = path.charCodeAt(path.length - 1) === 47; /*/*/ // Normalize the path path = normalizeStringPosix(path, !isAbsolute); @@ -87,7 +87,7 @@ const join: T.Join = (...args) => { if (args.length === 0) return '.'; let joined; for (let i = 0; i < args.length; ++i) { - let arg = args[i]; + const arg = args[i]; if (arg.length > 0) { if (joined === undefined) joined = arg; else joined += '/' + arg; diff --git a/packages/loot-core/src/platform/server/indexeddb/index.web.ts b/packages/loot-core/src/platform/server/indexeddb/index.web.ts index d657a53f7..58f37165a 100644 --- a/packages/loot-core/src/platform/server/indexeddb/index.web.ts +++ b/packages/loot-core/src/platform/server/indexeddb/index.web.ts @@ -5,12 +5,12 @@ let openedDb = _openDatabase(); // The web version uses IndexedDB to store data function _openDatabase() { return new Promise((resolve, reject) => { - let dbVersion = 9; - let openRequest = indexedDB.open('actual', dbVersion); + const dbVersion = 9; + const openRequest = indexedDB.open('actual', dbVersion); openRequest.onupgradeneeded = function (e) { // @ts-expect-error EventTarget needs refinement - let db: IDBDatabase = e.target.result; + const db: IDBDatabase = e.target.result; // Remove old stores if (db.objectStoreNames.contains('filesystem')) { @@ -40,7 +40,7 @@ function _openDatabase() { openRequest.onsuccess = function (e) { // @ts-expect-error EventTarget needs refinement - let db = e.target.result; + const db = e.target.result; db.onversionchange = () => { // TODO: Notify the user somehow @@ -51,7 +51,7 @@ function _openDatabase() { console.log('Database error: ' + (event.target && event.target.error)); if (event.target && event.target.error) { - let e = event.target.error; + const e = event.target.error; if (e.name === 'QuotaExceededError') { // Don't try to get the sized used -- too brittle. Is there // a better way to do it? @@ -94,13 +94,13 @@ function _openDatabase() { } export const getStore: T.GetStore = function (db, name) { - let trans = db.transaction([name], 'readwrite'); + const trans = db.transaction([name], 'readwrite'); return { trans, store: trans.objectStore(name) }; }; export const get: T.Get = async function (store, key, mapper = x => x) { return new Promise((resolve, reject) => { - let req = store.get(key); + const req = store.get(key); req.onsuccess = e => { resolve(mapper(req.result)); }; @@ -110,7 +110,7 @@ export const get: T.Get = async function (store, key, mapper = x => x) { export const set: T.Set = async function (store, item) { return new Promise((resolve, reject) => { - let req = store.put(item); + const req = store.put(item); req.onsuccess = e => resolve(undefined); req.onerror = e => reject(e); }); @@ -118,7 +118,7 @@ export const set: T.Set = async function (store, item) { export const del: T.Del = async function (store, key) { return new Promise((resolve, reject) => { - let req = store.delete(key); + const req = store.delete(key); req.onsuccess = e => resolve(undefined); req.onerror = e => reject(e); }); diff --git a/packages/loot-core/src/platform/server/sqlite/index.electron.ts b/packages/loot-core/src/platform/server/sqlite/index.electron.ts index 2e928f60f..146e8ac19 100644 --- a/packages/loot-core/src/platform/server/sqlite/index.electron.ts +++ b/packages/loot-core/src/platform/server/sqlite/index.electron.ts @@ -38,7 +38,7 @@ export function runQuery( if (fetchAll) { try { - let result = stmt.all(...params); + const result = stmt.all(...params); return result; } catch (e) { console.log('error', sql); @@ -46,7 +46,7 @@ export function runQuery( } } else { try { - let info = stmt.run(...params); + const info = stmt.run(...params); return { changes: info.changes, insertId: info.lastInsertRowid }; } catch (e) { // console.log('error', sql); @@ -95,7 +95,7 @@ export async function asyncTransaction( } export function openDatabase(pathOrBuffer: string | Buffer) { - let db = new SQL(pathOrBuffer); + const db = new SQL(pathOrBuffer); // Define Unicode-aware LOWER and UPPER implementation. // This is necessary because better-sqlite3 uses SQLite build without ICU support. db.function('UNICODE_LOWER', { deterministic: true }, (arg: string | null) => @@ -114,11 +114,11 @@ export function closeDatabase(db: SQL.Database) { export async function exportDatabase(db: SQL.Database) { // electron does not support better-sqlite serialize since v21 // save to file and read in the raw data. - let name = `backup-for-export-${uuidv4()}.db`; + const name = `backup-for-export-${uuidv4()}.db`; await db.backup(name); - let data = await readFile(name, 'binary'); + const data = await readFile(name, 'binary'); await removeFile(name); return data; diff --git a/packages/loot-core/src/platform/server/sqlite/index.web.test.ts b/packages/loot-core/src/platform/server/sqlite/index.web.test.ts index 09eaadae0..06790bdc6 100644 --- a/packages/loot-core/src/platform/server/sqlite/index.web.test.ts +++ b/packages/loot-core/src/platform/server/sqlite/index.web.test.ts @@ -13,13 +13,13 @@ beforeAll(() => { return init(); }); -let initSQL = ` +const initSQL = ` CREATE TABLE numbers (id TEXT PRIMARY KEY, number INTEGER); `; describe('Web sqlite', () => { it('should rollback transactions', async () => { - let db = await openDatabase(); + const db = await openDatabase(); execQuery(db, initSQL); runQuery(db, "INSERT INTO numbers (id, number) VALUES ('id1', 4)"); @@ -29,7 +29,7 @@ describe('Web sqlite', () => { // @ts-expect-error Property 'number' does not exist on type 'unknown' expect(rows[0].number).toBe(4); - let consoleSpy = jest.spyOn(console, 'log').mockImplementation(); + const consoleSpy = jest.spyOn(console, 'log').mockImplementation(); expect(() => { transaction(db, () => { runQuery(db, "INSERT INTO numbers (id, number) VALUES ('id2', 5)"); @@ -48,7 +48,7 @@ describe('Web sqlite', () => { }); it('should support nested transactions', async () => { - let db = await openDatabase(); + const db = await openDatabase(); execQuery(db, initSQL); runQuery(db, "INSERT INTO numbers (id, number) VALUES ('id1', 4)"); @@ -63,7 +63,7 @@ describe('Web sqlite', () => { runQuery(db, "INSERT INTO numbers (id, number) VALUES ('id3', 6)"); // Only this transaction should fail - let consoleSpy = jest.spyOn(console, 'log').mockImplementation(); + const consoleSpy = jest.spyOn(console, 'log').mockImplementation(); expect(() => { transaction(db, () => { runQuery(db, "INSERT INTO numbers (id, number) VALUES ('id4', 7)"); diff --git a/packages/loot-core/src/platform/server/sqlite/index.web.ts b/packages/loot-core/src/platform/server/sqlite/index.web.ts index b9b39f456..e804b1b41 100644 --- a/packages/loot-core/src/platform/server/sqlite/index.web.ts +++ b/packages/loot-core/src/platform/server/sqlite/index.web.ts @@ -56,12 +56,12 @@ export function runQuery(db, sql, params = [], fetchAll = false) { verifyParamTypes(sql, params); } - let stmt = typeof sql === 'string' ? db.prepare(sql) : sql; + const stmt = typeof sql === 'string' ? db.prepare(sql) : sql; if (fetchAll) { try { stmt.bind(params); - let rows = []; + const rows = []; while (stmt.step()) { rows.push(stmt.getAsObject()); @@ -156,11 +156,11 @@ export async function openDatabase(pathOrBuffer?: string | Buffer) { if (typeof pathOrBuffer !== 'string') { db = new SQL.Database(pathOrBuffer); } else { - let path = pathOrBuffer; + const path = pathOrBuffer; if (path !== ':memory:') { if (typeof SharedArrayBuffer === 'undefined') { // @ts-expect-error FS missing in sql.js types - let stream = SQL.FS.open(SQL.FS.readlink(path), 'a+'); + const stream = SQL.FS.open(SQL.FS.readlink(path), 'a+'); await stream.node.contents.readIfFallback(); // @ts-expect-error FS missing in sql.js types SQL.FS.close(stream); diff --git a/packages/loot-core/src/shared/arithmetic.ts b/packages/loot-core/src/shared/arithmetic.ts index 4dd2b8955..2bf0eaa88 100644 --- a/packages/loot-core/src/shared/arithmetic.ts +++ b/packages/loot-core/src/shared/arithmetic.ts @@ -15,7 +15,7 @@ function next(state) { return null; } - let ch = char(state); + const ch = char(state); state.index++; return ch; } @@ -31,7 +31,7 @@ function nextOperator(state, op) { function parsePrimary(state) { // We only support numbers - let isNegative = char(state) === '-'; + const isNegative = char(state) === '-'; if (isNegative) { next(state); } @@ -44,7 +44,7 @@ function parsePrimary(state) { // and we should do more strict parsing let numberStr = ''; while (char(state) && char(state).match(/[0-9,.]/)) { - let thousandsSep = getNumberFormat().separator === ',' ? '.' : ','; + const thousandsSep = getNumberFormat().separator === ',' ? '.' : ','; // Don't include the thousands separator if (char(state) === thousandsSep) { @@ -58,14 +58,16 @@ function parsePrimary(state) { fail(state, 'Unexpected character'); } - let number = parseFloat(numberStr.replace(getNumberFormat().separator, '.')); + const number = parseFloat( + numberStr.replace(getNumberFormat().separator, '.'), + ); return isNegative ? -number : number; } function parseParens(state) { if (char(state) === '(') { next(state); - let expr = parseOperator(state); + const expr = parseOperator(state); if (char(state) !== ')') { fail(state, 'Unbalanced parentheses'); @@ -91,10 +93,10 @@ function makeOperatorParser(...ops) { } // These operators go from high to low order of precedence -let parseOperator = makeOperatorParser('^', '/', '*', '-', '+'); +const parseOperator = makeOperatorParser('^', '/', '*', '-', '+'); function parse(expression) { - let state = { str: expression.replace(/\s/g, ''), index: 0 }; + const state = { str: expression.replace(/\s/g, ''), index: 0 }; return parseOperator(state); } @@ -103,7 +105,7 @@ function evaluate(ast) { return ast; } - let { left, right, op } = ast; + const { left, right, op } = ast; switch (op) { case '+': diff --git a/packages/loot-core/src/shared/async.test.ts b/packages/loot-core/src/shared/async.test.ts index 3f545b5da..31280cbc4 100644 --- a/packages/loot-core/src/shared/async.test.ts +++ b/packages/loot-core/src/shared/async.test.ts @@ -119,7 +119,7 @@ describe('async', () => { return {}; }); - let results = await Promise.all([fn(), fn(), fn()]); + const results = await Promise.all([fn(), fn(), fn()]); // It should only have been called once expect(timesCalled).toBe(1); diff --git a/packages/loot-core/src/shared/async.ts b/packages/loot-core/src/shared/async.ts index a534631cd..718204f36 100644 --- a/packages/loot-core/src/shared/async.ts +++ b/packages/loot-core/src/shared/async.ts @@ -1,7 +1,7 @@ export function sequential<T extends (...args: unknown[]) => unknown>( fn: T, ): (...args: Parameters<T>) => Promise<Awaited<ReturnType<T>>> { - let sequenceState = { + const sequenceState = { running: null, queue: [], }; @@ -47,7 +47,7 @@ export function once<T extends (...args: unknown[]) => Promise<unknown>>( fn: T, ): (...args: Parameters<T>) => Promise<Awaited<ReturnType<T>>> { let promise = null; - let onceFn = (...args: Parameters<T>): Promise<Awaited<ReturnType<T>>> => { + const onceFn = (...args: Parameters<T>): Promise<Awaited<ReturnType<T>>> => { if (!promise) { promise = fn(...args).finally(() => { promise = null; diff --git a/packages/loot-core/src/shared/categories.ts b/packages/loot-core/src/shared/categories.ts index 3cd2503ad..54784b45e 100644 --- a/packages/loot-core/src/shared/categories.ts +++ b/packages/loot-core/src/shared/categories.ts @@ -61,7 +61,7 @@ export function moveCategoryGroup(categoryGroups, id, targetId) { return categoryGroups; } - let moveGroup = categoryGroups.find(g => g.id === id); + const moveGroup = categoryGroups.find(g => g.id === id); categoryGroups = categoryGroups.reduce((groups, group) => { if (group.id === targetId) { diff --git a/packages/loot-core/src/shared/errors.ts b/packages/loot-core/src/shared/errors.ts index 1f62874da..f7fc58536 100644 --- a/packages/loot-core/src/shared/errors.ts +++ b/packages/loot-core/src/shared/errors.ts @@ -51,7 +51,7 @@ export function getDownloadError({ reason, meta, fileName }) { ); default: - let info = meta && meta.fileId ? `, fileId: ${meta.fileId}` : ''; + const info = meta && meta.fileId ? `, fileId: ${meta.fileId}` : ''; return ( 'Something went wrong trying to download that file, sorry! ' + 'Visit https://actualbudget.org/contact/ for support. ' + diff --git a/packages/loot-core/src/shared/months.ts b/packages/loot-core/src/shared/months.ts index 651333707..c87d8694d 100644 --- a/packages/loot-core/src/shared/months.ts +++ b/packages/loot-core/src/shared/months.ts @@ -61,7 +61,7 @@ export function _parse(value: DateLike): Date { // shifted backwards or forwards, doing date logic will stay // within the day we want. - let [year, month, day] = value.split('-'); + const [year, month, day] = value.split('-'); if (day != null) { return new Date(parseInt(year), parseInt(month) - 1, parseInt(day), 12); } else if (month != null) { @@ -282,7 +282,7 @@ export const getDayMonthFormat = memoizeOne((format: string) => { }); export const getDayMonthRegex = memoizeOne((format: string) => { - let regex = format + const regex = format .replace(/y+/g, '') .replace(/[^\w]$/, '') .replace(/^[^\w]/, '') @@ -302,7 +302,7 @@ export const getMonthYearFormat = memoizeOne((format: string) => { }); export const getMonthYearRegex = memoizeOne((format: string) => { - let regex = format + const regex = format .replace(/d+/g, '') .replace(/[^\w]$/, '') .replace(/^[^\w]/, '') @@ -317,7 +317,7 @@ export const getShortYearFormat = memoizeOne((format: string) => { }); export const getShortYearRegex = memoizeOne((format: string) => { - let regex = format + const regex = format .replace(/[^\w]$/, '') .replace(/^[^\w]/, '') .replace(/d+/g, '\\d{1,2}') diff --git a/packages/loot-core/src/shared/query.ts b/packages/loot-core/src/shared/query.ts index f37dee7bd..b54ab392f 100644 --- a/packages/loot-core/src/shared/query.ts +++ b/packages/loot-core/src/shared/query.ts @@ -38,7 +38,7 @@ export class Query { } unfilter(exprs) { - let exprSet = new Set(exprs); + const exprSet = new Set(exprs); return new Query({ ...this.state, filterExpressions: this.state.filterExpressions.filter( @@ -52,13 +52,13 @@ export class Query { exprs = [exprs]; } - let query = new Query({ ...this.state, selectExpressions: exprs }); + const query = new Query({ ...this.state, selectExpressions: exprs }); query.state.calculation = false; return query; } calculate(expr) { - let query = this.select({ result: expr }); + const query = this.select({ result: expr }); query.state.calculation = true; return query; } @@ -115,7 +115,7 @@ export class Query { } export function getPrimaryOrderBy(query, defaultOrderBy) { - let orderExprs = query.serialize().orderExpressions; + const orderExprs = query.serialize().orderExpressions; if (orderExprs.length === 0) { if (defaultOrderBy) { return { order: 'asc', ...defaultOrderBy }; @@ -123,12 +123,12 @@ export function getPrimaryOrderBy(query, defaultOrderBy) { return null; } - let firstOrder = orderExprs[0]; + const firstOrder = orderExprs[0]; if (typeof firstOrder === 'string') { return { field: firstOrder, order: 'asc' }; } // Handle this form: { field: 'desc' } - let [field] = Object.keys(firstOrder); + const [field] = Object.keys(firstOrder); return { field, order: firstOrder[field] }; } diff --git a/packages/loot-core/src/shared/rules.ts b/packages/loot-core/src/shared/rules.ts index 3857aff31..0bab72945 100644 --- a/packages/loot-core/src/shared/rules.ts +++ b/packages/loot-core/src/shared/rules.ts @@ -170,11 +170,11 @@ export function parse(item) { return { ...item, value: parsed }; } case 'string': { - let parsed = item.value == null ? '' : item.value; + const parsed = item.value == null ? '' : item.value; return { ...item, value: parsed }; } case 'boolean': { - let parsed = item.value; + const parsed = item.value; return { ...item, value: parsed }; } default: @@ -194,11 +194,11 @@ export function unparse({ error, inputKey, ...item }) { return { ...item, value: unparsed }; } case 'string': { - let unparsed = item.value == null ? '' : item.value; + const unparsed = item.value == null ? '' : item.value; return { ...item, value: unparsed }; } case 'boolean': { - let unparsed = item.value == null ? false : item.value; + const unparsed = item.value == null ? false : item.value; return { ...item, value: unparsed }; } default: diff --git a/packages/loot-core/src/shared/schedules.ts b/packages/loot-core/src/shared/schedules.ts index a6396b93b..8c1d816eb 100644 --- a/packages/loot-core/src/shared/schedules.ts +++ b/packages/loot-core/src/shared/schedules.ts @@ -4,7 +4,7 @@ import * as monthUtils from './months'; import q from './query'; export function getStatus(nextDate, completed, hasTrans) { - let today = monthUtils.currentDay(); + const today = monthUtils.currentDay(); if (completed) { return 'completed'; @@ -22,8 +22,8 @@ export function getStatus(nextDate, completed, hasTrans) { } export function getHasTransactionsQuery(schedules) { - let filters = schedules.map(schedule => { - let dateCond = schedule._conditions.find(c => c.field === 'date'); + const filters = schedules.map(schedule => { + const dateCond = schedule._conditions.find(c => c.field === 'date'); return { $and: { schedule: schedule.id, @@ -51,7 +51,7 @@ function makeNumberSuffix(num) { } function prettyDayName(day) { - let days = { + const days = { SU: 'Sunday', MO: 'Monday', TU: 'Tuesday', @@ -64,9 +64,9 @@ function prettyDayName(day) { } export function getRecurringDescription(config) { - let interval = config.interval || 1; + const interval = config.interval || 1; - let weekendSolveSuffix = config.skipWeekend + const weekendSolveSuffix = config.skipWeekend ? ` (${config.weekendSolveMode} weekend) ` : ''; @@ -92,9 +92,9 @@ export function getRecurringDescription(config) { // sort would put them first let patterns = [...config.patterns] .sort((p1, p2) => { - let typeOrder = + const typeOrder = (p1.type === 'day' ? 1 : 0) - (p2.type === 'day' ? 1 : 0); - let valOrder = p1.value - p2.value; + const valOrder = p1.value - p2.value; if (typeOrder === 0) { return valOrder; @@ -108,12 +108,12 @@ export function getRecurringDescription(config) { desc += ' on the '; - let strs = []; + const strs = []; - let uniqueDays = new Set(patterns.map(p => p.type)); - let isSameDay = uniqueDays.size === 1 && !uniqueDays.has('day'); + const uniqueDays = new Set(patterns.map(p => p.type)); + const isSameDay = uniqueDays.size === 1 && !uniqueDays.has('day'); - for (let pattern of patterns) { + for (const pattern of patterns) { if (pattern.type === 'day') { if (pattern.value === -1) { strs.push('last day'); @@ -122,7 +122,7 @@ export function getRecurringDescription(config) { strs.push(makeNumberSuffix(pattern.value)); } } else { - let dayName = isSameDay ? '' : ' ' + prettyDayName(pattern.type); + const dayName = isSameDay ? '' : ' ' + prettyDayName(pattern.type); if (pattern.value === -1) { // Example: last Monday @@ -163,7 +163,7 @@ export function getRecurringDescription(config) { } export function recurConfigToRSchedule(config) { - let base: IRuleOptions = { + const base: IRuleOptions = { start: monthUtils.parseDate(config.start), frequency: config.frequency.toUpperCase(), byHourOfDay: [12], @@ -173,7 +173,7 @@ export function recurConfigToRSchedule(config) { base.interval = config.interval; } - let abbrevDay = name => name.slice(0, 2).toUpperCase(); + const abbrevDay = name => name.slice(0, 2).toUpperCase(); switch (config.frequency) { case 'daily': @@ -184,8 +184,8 @@ export function recurConfigToRSchedule(config) { return [base]; case 'monthly': if (config.patterns && config.patterns.length > 0) { - let days = config.patterns.filter(p => p.type === 'day'); - let dayNames = config.patterns.filter(p => p.type !== 'day'); + const days = config.patterns.filter(p => p.type === 'day'); + const dayNames = config.patterns.filter(p => p.type !== 'day'); return [ days.length > 0 && { ...base, byDayOfMonth: days.map(p => p.value) }, diff --git a/packages/loot-core/src/shared/test-helpers.ts b/packages/loot-core/src/shared/test-helpers.ts index 574d92599..5cda80135 100644 --- a/packages/loot-core/src/shared/test-helpers.ts +++ b/packages/loot-core/src/shared/test-helpers.ts @@ -2,8 +2,8 @@ export let tracer = null; function timeout(promise, n) { let resolve; - let timeoutPromise = new Promise(_ => (resolve = _)); - let timer = setTimeout(() => resolve(`timeout(${n})`), n); + const timeoutPromise = new Promise(_ => (resolve = _)); + const timer = setTimeout(() => resolve(`timeout(${n})`), n); return Promise.race([ promise.then(res => { @@ -19,12 +19,12 @@ export function resetTracer() { } export function execTracer() { - let queue = []; + const queue = []; let hasStarted = false; let waitingFor = null; let ended = false; - let log = false; + const log = false; return { event(name: string, data?: unknown) { @@ -108,7 +108,7 @@ export function execTracer() { `Expected event “${name}†but none found - has it happened yet?`, ); } else if (queue[0].name === name) { - let entry = queue.shift(); + const entry = queue.shift(); if (typeof data === 'function') { data(entry.data); @@ -135,7 +135,7 @@ export function execTracer() { end() { if (hasStarted && queue.length !== 0) { - let str = queue.map(x => JSON.stringify(x)); + const str = queue.map(x => JSON.stringify(x)); throw new Error( 'Event tracer ended with existing events: ' + str.join('\n\n'), ); diff --git a/packages/loot-core/src/shared/transactions.test.ts b/packages/loot-core/src/shared/transactions.test.ts index 7aca05f27..2ff17433f 100644 --- a/packages/loot-core/src/shared/transactions.test.ts +++ b/packages/loot-core/src/shared/transactions.test.ts @@ -23,7 +23,7 @@ function makeTransaction(data) { } function makeSplitTransaction(data, children) { - let parent = makeTransaction({ ...data, is_parent: true }); + const parent = makeTransaction({ ...data, is_parent: true }); return [parent, ...children.map(t => makeChild(parent, t))]; } @@ -33,12 +33,12 @@ function splitError(amount) { describe('Transactions', () => { test('updating a transaction works', () => { - let transactions = [ + const transactions = [ makeTransaction({ amount: 5000 }), makeTransaction({ id: 't1', amount: 4000 }), makeTransaction({ amount: 3000 }), ]; - let { data, diff } = updateTransaction(transactions, { + const { data, diff } = updateTransaction(transactions, { id: 't1', amount: 5000, }); @@ -56,11 +56,11 @@ describe('Transactions', () => { }); test('updating does nothing if value not changed', () => { - let transactions = [ + const transactions = [ makeTransaction({ id: 't1', amount: 5000 }), makeTransaction({ amount: 3000 }), ]; - let { data, diff } = updateTransaction(transactions, { + const { data, diff } = updateTransaction(transactions, { id: 't1', amount: 5000, }); @@ -72,12 +72,12 @@ describe('Transactions', () => { }); test('deleting a transaction works', () => { - let transactions = [ + const transactions = [ makeTransaction({ amount: 5000 }), makeTransaction({ id: 't1', amount: 4000 }), makeTransaction({ amount: 3000 }), ]; - let { data, diff } = deleteTransaction(transactions, 't1'); + const { data, diff } = deleteTransaction(transactions, 't1'); expect(diff).toEqual({ added: [], @@ -91,11 +91,11 @@ describe('Transactions', () => { }); test('splitting a transaction works', () => { - let transactions = [ + const transactions = [ makeTransaction({ id: 't1', amount: 5000 }), makeTransaction({ amount: 3000 }), ]; - let { data, diff } = splitTransaction(transactions, 't1'); + const { data, diff } = splitTransaction(transactions, 't1'); expect(data.find(d => d.subtransactions)).toBeFalsy(); expect(diff).toEqual({ @@ -121,7 +121,7 @@ describe('Transactions', () => { }); test('adding a split transaction works', () => { - let transactions = [ + const transactions = [ makeTransaction({ amount: 2001 }), ...makeSplitTransaction({ id: 't1', amount: 2500 }, [ { id: 't2', amount: 2000 }, @@ -133,7 +133,7 @@ describe('Transactions', () => { expect(transactions.filter(t => t.parent_id === 't1').length).toBe(2); // Should be able to pass in any id from the split trans - let { data, diff } = addSplitTransaction(transactions, 't1'); + const { data, diff } = addSplitTransaction(transactions, 't1'); expect(data.find(d => d.subtransactions)).toBeFalsy(); expect(data.filter(t => t.parent_id === 't1').length).toBe(3); @@ -152,7 +152,7 @@ describe('Transactions', () => { }); test('updating a split transaction works', () => { - let transactions = [ + const transactions = [ makeTransaction({ amount: 2001 }), ...makeSplitTransaction({ id: 't1', amount: 2500 }, [ { id: 't2', amount: 2000 }, @@ -160,7 +160,7 @@ describe('Transactions', () => { ]), makeTransaction({ amount: 3002 }), ]; - let { data, diff } = updateTransaction(transactions, { + const { data, diff } = updateTransaction(transactions, { id: 't2', amount: 2200, }); @@ -177,7 +177,7 @@ describe('Transactions', () => { }); test('deleting a split transaction works', () => { - let transactions = [ + const transactions = [ makeTransaction({ amount: 2001 }), ...makeSplitTransaction({ id: 't1', amount: 2500 }, [ { id: 't2', amount: 2000 }, @@ -185,7 +185,7 @@ describe('Transactions', () => { ]), makeTransaction({ amount: 3002 }), ]; - let { data, diff } = deleteTransaction(transactions, 't2'); + const { data, diff } = deleteTransaction(transactions, 't2'); expect(diff).toEqual({ added: [], diff --git a/packages/loot-core/src/shared/transactions.ts b/packages/loot-core/src/shared/transactions.ts index 967532554..5e99b43d4 100644 --- a/packages/loot-core/src/shared/transactions.ts +++ b/packages/loot-core/src/shared/transactions.ts @@ -12,7 +12,7 @@ function num(n) { } function SplitTransactionError(total, parent) { - let difference = num(parent.amount) - total; + const difference = num(parent.amount) - total; return { type: 'SplitTransactionError', @@ -22,7 +22,7 @@ function SplitTransactionError(total, parent) { } export function makeChild(parent, data) { - let prefix = parent.id === 'temp' ? 'temp' : ''; + const prefix = parent.id === 'temp' ? 'temp' : ''; return { amount: 0, @@ -61,7 +61,7 @@ function findParentIndex(transactions, idx) { // are always before children, which is enforced in the db layer. // Walk backwards and find the last parent; while (idx >= 0) { - let trans = transactions[idx]; + const trans = transactions[idx]; if (trans.is_parent) { return idx; } @@ -71,7 +71,7 @@ function findParentIndex(transactions, idx) { } function getSplit(transactions, parentIndex) { - let split = [transactions[parentIndex]]; + const split = [transactions[parentIndex]]; let curr = parentIndex + 1; while (curr < transactions.length && transactions[curr].is_child) { split.push(transactions[curr]); @@ -81,14 +81,14 @@ function getSplit(transactions, parentIndex) { } export function ungroupTransactions(transactions) { - let x = transactions.reduce((list, parent) => { - let { subtransactions, ...trans } = parent; - subtransactions = subtransactions || []; + const x = transactions.reduce((list, parent) => { + const { subtransactions, ...trans } = parent; + const _subtransactions = subtransactions || []; list.push(trans); - for (let i = 0; i < subtransactions.length; i++) { - list.push(subtransactions[i]); + for (let i = 0; i < _subtransactions.length; i++) { + list.push(_subtransactions[i]); } return list; }, []); @@ -111,24 +111,24 @@ export function applyTransactionDiff(groupedTrans, diff) { } function replaceTransactions(transactions, id, func) { - let idx = transactions.findIndex(t => t.id === id); - let trans = transactions[idx]; - let transactionsCopy = [...transactions]; + const idx = transactions.findIndex(t => t.id === id); + const trans = transactions[idx]; + const transactionsCopy = [...transactions]; if (idx === -1) { throw new Error('Tried to edit unknown transaction id: ' + id); } if (trans.is_parent || trans.is_child) { - let parentIndex = findParentIndex(transactions, idx); + const parentIndex = findParentIndex(transactions, idx); if (parentIndex == null) { console.log('Cannot find parent index'); return { diff: { deleted: [], updated: [] } }; } - let split = getSplit(transactions, parentIndex); + const split = getSplit(transactions, parentIndex); let grouped = func(groupTransaction(split)); - let newSplit = ungroupTransaction(grouped); + const newSplit = ungroupTransaction(grouped); let diff; if (newSplit == null) { @@ -144,8 +144,8 @@ function replaceTransactions(transactions, id, func) { return { data: transactionsCopy, newTransaction: grouped, diff }; } else { - let grouped = func(trans); - let newTrans = ungroupTransaction(grouped) || []; + const grouped = func(trans); + const newTrans = ungroupTransaction(grouped) || []; if (grouped) { grouped.subtransactions = grouped.subtransactions || []; } @@ -164,7 +164,7 @@ export function addSplitTransaction(transactions, id) { if (!trans.is_parent) { return trans; } - let prevSub = last(trans.subtransactions); + const prevSub = last(trans.subtransactions); trans.subtransactions.push( makeChild(trans, { amount: 0, @@ -178,8 +178,8 @@ export function addSplitTransaction(transactions, id) { export function updateTransaction(transactions, transaction) { return replaceTransactions(transactions, transaction.id, trans => { if (trans.is_parent) { - let parent = trans.id === transaction.id ? transaction : trans; - let sub = trans.subtransactions.map(t => { + const parent = trans.id === transaction.id ? transaction : trans; + const sub = trans.subtransactions.map(t => { // Make sure to update the children to reflect the updated // properties (if the parent updated) @@ -216,7 +216,7 @@ export function deleteTransaction(transactions, id) { error: null, }; } else { - let sub = trans.subtransactions.filter(t => t.id !== id); + const sub = trans.subtransactions.filter(t => t.id !== id); return recalculateSplit({ ...trans, subtransactions: sub }); } } else { @@ -244,7 +244,7 @@ export function realizeTempTransactions(transactions) { let parent = transactions.find(t => !t.is_child); parent = { ...parent, id: uuidv4() }; - let children = transactions.filter(t => t.is_child); + const children = transactions.filter(t => t.is_child); return [ parent, ...children.map(child => ({ diff --git a/packages/loot-core/src/shared/util.ts b/packages/loot-core/src/shared/util.ts index 6e744c8a7..cf587db47 100644 --- a/packages/loot-core/src/shared/util.ts +++ b/packages/loot-core/src/shared/util.ts @@ -10,7 +10,7 @@ export function getChangedValues(obj1, obj2) { let hasChanged = false; for (let i = 0; i < keys.length; i++) { - let key = keys[i]; + const key = keys[i]; if (obj1[key] !== obj2[key]) { diff[key] = obj2[key]; @@ -24,7 +24,7 @@ export function getChangedValues(obj1, obj2) { export function hasFieldsChanged(obj1, obj2, fields) { let changed = false; for (let i = 0; i < fields.length; i++) { - let field = fields[i]; + const field = fields[i]; if (obj1[field] !== obj2[field]) { changed = true; break; @@ -65,12 +65,12 @@ export function applyChanges(changes, items) { } export function partitionByField(data, field) { - let res = new Map(); + const res = new Map(); for (let i = 0; i < data.length; i++) { - let item = data[i]; - let key = item[field]; + const item = data[i]; + const key = item[field]; - let items = res.get(key) || []; + const items = res.get(key) || []; items.push(item); res.set(key, items); @@ -79,11 +79,11 @@ export function partitionByField(data, field) { } export function groupBy<T, K extends keyof T>(data: T[], field: K) { - let res = new Map<T[K], T[]>(); + const res = new Map<T[K], T[]>(); for (let i = 0; i < data.length; i++) { - let item = data[i]; - let key = item[field]; - let existing = res.get(key) || []; + const item = data[i]; + const key = item[field]; + const existing = res.get(key) || []; res.set(key, existing.concat([item])); } return res; @@ -94,26 +94,26 @@ export function groupBy<T, K extends keyof T>(data: T[], field: K) { // different API and we need to go through and update everywhere that // uses it. function _groupById(data) { - let res = new Map(); + const res = new Map(); for (let i = 0; i < data.length; i++) { - let item = data[i]; + const item = data[i]; res.set(item.id, item); } return res; } export function diffItems(items, newItems) { - let grouped = _groupById(items); - let newGrouped = _groupById(newItems); - let added = []; - let updated = []; + const grouped = _groupById(items); + const newGrouped = _groupById(newItems); + const added = []; + const updated = []; - let deleted = items + const deleted = items .filter(item => !newGrouped.has(item.id)) .map(item => ({ id: item.id })); newItems.forEach(newItem => { - let item = grouped.get(newItem.id); + const item = grouped.get(newItem.id); if (!item) { added.push(newItem); } else { @@ -128,9 +128,9 @@ export function diffItems(items, newItems) { } export function groupById(data) { - let res = {}; + const res = {}; for (let i = 0; i < data.length; i++) { - let item = data[i]; + const item = data[i]; res[item.id] = item; } return res; @@ -169,8 +169,8 @@ export function getIn(map, keys) { } export function fastSetMerge(set1, set2) { - let finalSet = new Set(set1); - let iter = set2.values(); + const finalSet = new Set(set1); + const iter = set2.values(); let value = iter.next(); while (!value.done) { finalSet.add(value.value); @@ -295,7 +295,7 @@ export function amountToCurrency(n) { } export function currencyToAmount(str) { - let amount = parseFloat( + const amount = parseFloat( str .replace(getNumberFormat().regex, '') .replace(getNumberFormat().separator, '.'), @@ -304,12 +304,12 @@ export function currencyToAmount(str) { } export function currencyToInteger(str) { - let amount = currencyToAmount(str); + const amount = currencyToAmount(str); return amount == null ? null : amountToInteger(amount); } export function stringToInteger(str) { - let amount = parseInt(str.replace(/[^-0-9.,]/g, '')); + const amount = parseInt(str.replace(/[^-0-9.,]/g, '')); if (!isNaN(amount)) { return amount; } @@ -341,13 +341,13 @@ export function looselyParseAmount(amount) { amount = amount.replace('(', '-').replace(')', ''); } - let m = amount.match(/[.,][^.,]*$/); + const m = amount.match(/[.,][^.,]*$/); if (!m || m.index === 0) { return safeNumber(parseFloat(extractNumbers(amount))); } - let left = extractNumbers(amount.slice(0, m.index)); - let right = extractNumbers(amount.slice(m.index + 1)); + const left = extractNumbers(amount.slice(0, m.index)); + const right = extractNumbers(amount.slice(m.index + 1)); return safeNumber(parseFloat(left + '.' + right)); } diff --git a/packages/loot-core/webpack/webpack.api.config.js b/packages/loot-core/webpack/webpack.api.config.js index 56604239f..9db83f1e7 100644 --- a/packages/loot-core/webpack/webpack.api.config.js +++ b/packages/loot-core/webpack/webpack.api.config.js @@ -1,6 +1,6 @@ -let path = require('path'); +const path = require('path'); -let config = require('./webpack.desktop.config'); +const config = require('./webpack.desktop.config'); config.resolve.extensions = [ '.api.js', diff --git a/packages/loot-core/webpack/webpack.browser.config.js b/packages/loot-core/webpack/webpack.browser.config.js index e5024f618..6b9a70c6e 100644 --- a/packages/loot-core/webpack/webpack.browser.config.js +++ b/packages/loot-core/webpack/webpack.browser.config.js @@ -1,7 +1,7 @@ -let path = require('path'); +const path = require('path'); const TerserPlugin = require('terser-webpack-plugin'); -let webpack = require('webpack'); +const webpack = require('webpack'); const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer'); /** @type {webpack.Configuration} */ diff --git a/packages/loot-core/webpack/webpack.desktop.config.js b/packages/loot-core/webpack/webpack.desktop.config.js index 9a509a45d..a0f9b2c6d 100644 --- a/packages/loot-core/webpack/webpack.desktop.config.js +++ b/packages/loot-core/webpack/webpack.desktop.config.js @@ -1,9 +1,9 @@ -let path = require('path'); +const path = require('path'); -let webpack = require('webpack'); +const webpack = require('webpack'); const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer'); -let browser = require('./webpack.browser.config'); +const browser = require('./webpack.browser.config'); /** @type {webpack.Configuration} */ module.exports = { diff --git a/upcoming-release-notes/1958.md b/upcoming-release-notes/1958.md new file mode 100644 index 000000000..0919a55dc --- /dev/null +++ b/upcoming-release-notes/1958.md @@ -0,0 +1,6 @@ +--- +category: Maintenance +authors: [joel-jeremy] +--- + +ESLint prefer-const rule -- GitLab