From 2d7e0c3f7a4bebaa639dd0b55259c075f29041c8 Mon Sep 17 00:00:00 2001 From: Alberto Gasparin <albertogasparin@gmail.com> Date: Sun, 30 Apr 2023 09:25:45 +1000 Subject: [PATCH] Migrate core to TS p4 (#957) This is the last PR with lots of renaming for `loot-core`! --- packages/loot-core/jest.config.js | 2 +- ...eetProvider.js => SpreadsheetProvider.tsx} | 2 +- .../loot-core/src/client/actions/budgets.ts | 1 - .../src/client/{constants.js => constants.ts} | 0 .../src/client/{platform.js => platform.ts} | 2 +- .../src/client/{queries.js => queries.ts} | 0 ...-helpers.test.js => query-helpers.test.ts} | 7 ++- .../{query-helpers.js => query-helpers.ts} | 33 ++++++++++-- .../{query-hooks.js => query-hooks.tsx} | 30 +---------- ...hared-listeners.js => shared-listeners.ts} | 0 .../src/client/{tutorial.js => tutorial.ts} | 0 ...notification.js => update-notification.ts} | 0 ...ifications.js => upgrade-notifications.ts} | 0 ...rbitrary-schema.js => arbitrary-schema.ts} | 26 +++++++--- .../src/mocks/{budget.js => budget.ts} | 19 ++++--- .../src/mocks/{index.js => index.ts} | 5 +- .../src/mocks/{plaid.js => plaid.ts} | 0 .../src/mocks/{redux.js => redux.tsx} | 0 .../src/mocks/{setup.js => setup.ts} | 8 +-- .../mocks/{spreadsheet.js => spreadsheet.ts} | 0 .../loot-core/src/mocks/{util.js => util.ts} | 5 +- .../client/fetch/__mocks__/index.web.ts | 8 +-- .../src/platform/client/fetch/index.d.ts | 16 +++++- .../platform/server/asyncStorage/index.d.ts | 4 +- .../platform/server/asyncStorage/index.web.ts | 2 +- .../src/platform/server/connection/index.d.ts | 9 +++- .../src/platform/server/fs/index.d.ts | 5 +- .../src/platform/server/fs/index.electron.ts | 9 +++- ...kups.test.js.snap => backups.test.ts.snap} | 0 .../{main.test.js.snap => main.test.ts.snap} | 0 ...{sheet.test.js.snap => sheet.test.ts.snap} | 0 .../server/{api-models.js => api-models.ts} | 2 +- .../loot-core/src/server/{api.js => api.ts} | 8 +-- .../loot-core/src/server/{app.js => app.ts} | 5 ++ .../{backups.test.js => backups.test.ts} | 0 .../src/server/{backups.js => backups.ts} | 4 +- .../src/server/{bench.js => bench.ts} | 4 +- .../{cloud-storage.js => cloud-storage.ts} | 8 +-- packages/loot-core/src/server/db/index.ts | 6 +-- ...n-internals.js => encryption-internals.ts} | 15 ++++-- ...als.web.js => encryption-internals.web.ts} | 2 + ...{encryption.test.js => encryption.test.ts} | 0 .../server/{encryption.js => encryption.ts} | 3 ++ .../src/server/{errors.js => errors.ts} | 33 +++++++----- .../src/server/{main-app.js => main-app.ts} | 0 .../src/server/{main.test.js => main.test.ts} | 5 +- .../loot-core/src/server/{main.js => main.ts} | 52 +++++++------------ .../src/server/{models.js => models.ts} | 12 ++--- .../src/server/{mutators.js => mutators.ts} | 17 ++++-- .../loot-core/src/server/{perf.js => perf.ts} | 0 .../src/server/{platform.js => platform.ts} | 0 .../{platform.web.js => platform.web.ts} | 0 .../src/server/{polyfills.js => polyfills.ts} | 0 packages/loot-core/src/server/post.ts | 2 +- .../src/server/{prefs.js => prefs.ts} | 2 +- .../{server-config.js => server-config.ts} | 2 +- .../server/{sheet.test.js => sheet.test.ts} | 8 +-- .../src/server/{sheet.js => sheet.ts} | 10 ++-- packages/loot-core/src/server/sync/index.ts | 5 +- packages/loot-core/src/server/sync/reset.ts | 2 +- .../loot-core/src/server/{undo.js => undo.ts} | 22 +++++--- .../src/server/{update.js => update.ts} | 0 packages/loot-core/src/shared/months.ts | 2 +- packages/loot-core/src/shared/test-helpers.ts | 2 +- ...nsactions.test.js => transactions.test.ts} | 0 packages/loot-core/src/types/handlers.d.ts | 11 ++-- .../loot-core/src/types/main.handlers.d.ts | 11 +--- .../loot-core/src/types/models/account.d.ts | 11 ++++ .../src/types/models/category-group.d.ts | 9 ++++ .../loot-core/src/types/models/category.d.ts | 10 ++++ .../loot-core/src/types/models/index.d.ts | 6 +++ .../loot-core/src/types/models/payee.d.ts | 10 ++++ packages/loot-core/src/types/models/rule.d.ts | 8 +++ .../loot-core/src/types/models/schedule.d.ts | 23 ++++++++ .../src/types/models/transaction.d.ts | 29 +++++++++++ .../loot-core/src/types/server-events.d.ts | 16 ++++++ .../{typings.d.ts => typings/pegjs.d.ts} | 0 packages/loot-core/typings/window.d.ts | 16 ++++++ .../webpack/webpack.browser.config.js | 2 +- upcoming-release-notes/957.md | 6 +++ 80 files changed, 405 insertions(+), 189 deletions(-) rename packages/loot-core/src/client/{SpreadsheetProvider.js => SpreadsheetProvider.tsx} (98%) rename packages/loot-core/src/client/{constants.js => constants.ts} (100%) rename packages/loot-core/src/client/{platform.js => platform.ts} (90%) rename packages/loot-core/src/client/{queries.js => queries.ts} (100%) rename packages/loot-core/src/client/{query-helpers.test.js => query-helpers.test.ts} (98%) rename packages/loot-core/src/client/{query-helpers.js => query-helpers.ts} (93%) rename packages/loot-core/src/client/{query-hooks.js => query-hooks.tsx} (76%) rename packages/loot-core/src/client/{shared-listeners.js => shared-listeners.ts} (100%) rename packages/loot-core/src/client/{tutorial.js => tutorial.ts} (100%) rename packages/loot-core/src/client/{update-notification.js => update-notification.ts} (100%) rename packages/loot-core/src/client/{upgrade-notifications.js => upgrade-notifications.ts} (100%) rename packages/loot-core/src/mocks/{arbitrary-schema.js => arbitrary-schema.ts} (83%) rename packages/loot-core/src/mocks/{budget.js => budget.ts} (98%) rename packages/loot-core/src/mocks/{index.js => index.ts} (94%) rename packages/loot-core/src/mocks/{plaid.js => plaid.ts} (100%) rename packages/loot-core/src/mocks/{redux.js => redux.tsx} (100%) rename packages/loot-core/src/mocks/{setup.js => setup.ts} (95%) rename packages/loot-core/src/mocks/{spreadsheet.js => spreadsheet.ts} (100%) rename packages/loot-core/src/mocks/{util.js => util.ts} (91%) rename packages/loot-core/src/server/__snapshots__/{backups.test.js.snap => backups.test.ts.snap} (100%) rename packages/loot-core/src/server/__snapshots__/{main.test.js.snap => main.test.ts.snap} (100%) rename packages/loot-core/src/server/__snapshots__/{sheet.test.js.snap => sheet.test.ts.snap} (100%) rename packages/loot-core/src/server/{api-models.js => api-models.ts} (98%) rename packages/loot-core/src/server/{api.js => api.ts} (98%) rename packages/loot-core/src/server/{app.js => app.ts} (96%) rename packages/loot-core/src/server/{backups.test.js => backups.test.ts} (100%) rename packages/loot-core/src/server/{backups.js => backups.ts} (99%) rename packages/loot-core/src/server/{bench.js => bench.ts} (86%) rename packages/loot-core/src/server/{cloud-storage.js => cloud-storage.ts} (98%) rename packages/loot-core/src/server/{encryption-internals.js => encryption-internals.ts} (85%) rename packages/loot-core/src/server/{encryption-internals.web.js => encryption-internals.web.ts} (95%) rename packages/loot-core/src/server/{encryption.test.js => encryption.test.ts} (100%) rename packages/loot-core/src/server/{encryption.js => encryption.ts} (99%) rename packages/loot-core/src/server/{errors.js => errors.ts} (68%) rename packages/loot-core/src/server/{main-app.js => main-app.ts} (100%) rename packages/loot-core/src/server/{main.test.js => main.test.ts} (99%) rename packages/loot-core/src/server/{main.js => main.ts} (98%) rename packages/loot-core/src/server/{models.js => models.ts} (92%) rename packages/loot-core/src/server/{mutators.js => mutators.ts} (90%) rename packages/loot-core/src/server/{perf.js => perf.ts} (100%) rename packages/loot-core/src/server/{platform.js => platform.ts} (100%) rename packages/loot-core/src/server/{platform.web.js => platform.web.ts} (100%) rename packages/loot-core/src/server/{polyfills.js => polyfills.ts} (100%) rename packages/loot-core/src/server/{prefs.js => prefs.ts} (98%) rename packages/loot-core/src/server/{server-config.js => server-config.ts} (94%) rename packages/loot-core/src/server/{sheet.test.js => sheet.test.ts} (95%) rename packages/loot-core/src/server/{sheet.js => sheet.ts} (95%) rename packages/loot-core/src/server/{undo.js => undo.ts} (92%) rename packages/loot-core/src/server/{update.js => update.ts} (100%) rename packages/loot-core/src/shared/{transactions.test.js => transactions.test.ts} (100%) create mode 100644 packages/loot-core/src/types/models/account.d.ts create mode 100644 packages/loot-core/src/types/models/category-group.d.ts create mode 100644 packages/loot-core/src/types/models/category.d.ts create mode 100644 packages/loot-core/src/types/models/index.d.ts create mode 100644 packages/loot-core/src/types/models/payee.d.ts create mode 100644 packages/loot-core/src/types/models/rule.d.ts create mode 100644 packages/loot-core/src/types/models/schedule.d.ts create mode 100644 packages/loot-core/src/types/models/transaction.d.ts create mode 100644 packages/loot-core/src/types/server-events.d.ts rename packages/loot-core/{typings.d.ts => typings/pegjs.d.ts} (100%) create mode 100644 packages/loot-core/typings/window.d.ts create mode 100644 upcoming-release-notes/957.md diff --git a/packages/loot-core/jest.config.js b/packages/loot-core/jest.config.js index 1a8248b70..f62c2c4dc 100644 --- a/packages/loot-core/jest.config.js +++ b/packages/loot-core/jest.config.js @@ -11,7 +11,7 @@ module.exports = { 'tsx', 'json', ], - setupFilesAfterEnv: ['<rootDir>/src/mocks/setup.js'], + setupFilesAfterEnv: ['<rootDir>/src/mocks/setup.ts'], testEnvironment: 'node', testPathIgnorePatterns: [ '/node_modules/', diff --git a/packages/loot-core/src/client/SpreadsheetProvider.js b/packages/loot-core/src/client/SpreadsheetProvider.tsx similarity index 98% rename from packages/loot-core/src/client/SpreadsheetProvider.js rename to packages/loot-core/src/client/SpreadsheetProvider.tsx index 36d3cb9a2..1494c663d 100644 --- a/packages/loot-core/src/client/SpreadsheetProvider.js +++ b/packages/loot-core/src/client/SpreadsheetProvider.tsx @@ -77,7 +77,7 @@ function makeSpreadsheet() { if (cellCache[resolvedName] != null) { cellCache[resolvedName].then(cb); } else { - const req = this.get(sheetName, binding.name, fields); + const req = this.get(sheetName, binding.name); cellCache[resolvedName] = req; req.then(result => { diff --git a/packages/loot-core/src/client/actions/budgets.ts b/packages/loot-core/src/client/actions/budgets.ts index aea8292df..5eff493d1 100644 --- a/packages/loot-core/src/client/actions/budgets.ts +++ b/packages/loot-core/src/client/actions/budgets.ts @@ -165,7 +165,6 @@ export function importBudget(filepath, type) { dispatch(closeModal()); await dispatch(loadPrefs()); - // @ts-expect-error __history needs refinement window.__history.push('/budget'); }; } diff --git a/packages/loot-core/src/client/constants.js b/packages/loot-core/src/client/constants.ts similarity index 100% rename from packages/loot-core/src/client/constants.js rename to packages/loot-core/src/client/constants.ts diff --git a/packages/loot-core/src/client/platform.js b/packages/loot-core/src/client/platform.ts similarity index 90% rename from packages/loot-core/src/client/platform.js rename to packages/loot-core/src/client/platform.ts index 20e2fd00b..ba0a61a7c 100644 --- a/packages/loot-core/src/client/platform.js +++ b/packages/loot-core/src/client/platform.ts @@ -9,5 +9,5 @@ export const isProbablySafari = /^((?!chrome|android).)*safari/i.test( ); export const OS = isWindows ? 'windows' : isMac ? 'mac' : 'linux'; -export const env = 'web'; +export const env: 'web' | 'mobile' = 'web'; export const isBrowser = !!window.Actual?.IS_FAKE_WEB; diff --git a/packages/loot-core/src/client/queries.js b/packages/loot-core/src/client/queries.ts similarity index 100% rename from packages/loot-core/src/client/queries.js rename to packages/loot-core/src/client/queries.ts diff --git a/packages/loot-core/src/client/query-helpers.test.js b/packages/loot-core/src/client/query-helpers.test.ts similarity index 98% rename from packages/loot-core/src/client/query-helpers.test.js rename to packages/loot-core/src/client/query-helpers.test.ts index 9b72a3fb0..13b42a06f 100644 --- a/packages/loot-core/src/client/query-helpers.test.js +++ b/packages/loot-core/src/client/query-helpers.test.ts @@ -77,7 +77,7 @@ function runPagedQuery(query, data) { throw new Error('Unable to execute query: ' + JSON.stringify(query, null, 2)); } -function initBasicServer(delay) { +function initBasicServer(delay?) { initServer({ query: async query => { if (!isCountQuery(query)) { @@ -91,7 +91,10 @@ function initBasicServer(delay) { }); } -function initPagingServer(dataLength, { delay, eventType = 'select' } = {}) { +function initPagingServer( + dataLength, + { delay, eventType = 'select' }: { delay?: number; eventType?: string } = {}, +) { let data = []; for (let i = 0; i < dataLength; i++) { data.push({ id: i, date: subDays('2020-05-01', Math.floor(i / 5)) }); diff --git a/packages/loot-core/src/client/query-helpers.js b/packages/loot-core/src/client/query-helpers.ts similarity index 93% rename from packages/loot-core/src/client/query-helpers.js rename to packages/loot-core/src/client/query-helpers.ts index 635d9c75e..4416d3851 100644 --- a/packages/loot-core/src/client/query-helpers.js +++ b/packages/loot-core/src/client/query-helpers.ts @@ -7,13 +7,13 @@ export async function runQuery(query) { return send('query', query.serialize()); } -export function liveQuery(query, onData, opts) { +export function liveQuery(query, onData?, opts?) { let q = new LiveQuery(query, onData, opts); q.run(); return q; } -export function pagedQuery(query, onData, opts) { +export function pagedQuery(query, onData?, opts?) { let q = new PagedQuery(query, onData, opts); q.run(); return q; @@ -21,7 +21,22 @@ export function pagedQuery(query, onData, opts) { // Subscribe and refetch export class LiveQuery { - constructor(query, onData, opts = {}) { + _unsubscribe; + data; + dependencies; + error; + listeners; + mappedData; + mapper; + onlySync; + query; + + // Async coordination + inflight; + inflightRequestId; + restart; + + constructor(query, onData?, opts: { mapper?; onlySync?: boolean } = {}) { this.error = new Error(); this.query = query; this.data = null; @@ -162,7 +177,17 @@ export class LiveQuery { // Paging export class PagedQuery extends LiveQuery { - constructor(query, onData, opts = {}) { + done; + onPageData; + pageCount; + runPromise; + totalCount; + + constructor( + query, + onData, + opts: { pageCount?: number; onPageData?; mapper?; onlySync? } = {}, + ) { super(query, onData, opts); this.totalCount = null; this.pageCount = opts.pageCount || 500; diff --git a/packages/loot-core/src/client/query-hooks.js b/packages/loot-core/src/client/query-hooks.tsx similarity index 76% rename from packages/loot-core/src/client/query-hooks.js rename to packages/loot-core/src/client/query-hooks.tsx index c141b2abf..f5f3e72b0 100644 --- a/packages/loot-core/src/client/query-hooks.js +++ b/packages/loot-core/src/client/query-hooks.tsx @@ -1,6 +1,6 @@ import React, { useState, useContext, useMemo, useEffect } from 'react'; -import { runQuery, liveQuery, LiveQuery, PagedQuery } from './query-helpers'; +import { liveQuery, LiveQuery, PagedQuery } from './query-helpers'; function makeContext(queryState, opts, QueryClass) { let query = new QueryClass(queryState, null, opts); @@ -56,34 +56,6 @@ function makeContext(queryState, opts, QueryClass) { }; } -export function queryContext(queryState, opts) { - let Context = React.createContext(null); - - function Provider({ children }) { - let [data, setData] = useState(null); - let value = useMemo(() => ({ data }), [data]); - - useEffect(() => { - async function run() { - let { data } = await runQuery(queryState, opts); - setData(data); - } - run(); - }, []); - - return <Context.Provider value={value} children={children} />; - } - - function useQuery() { - return useContext(Context); - } - - return { - Provider, - useQuery, - }; -} - export function liveQueryContext(query, opts) { return makeContext(query, opts, LiveQuery); } diff --git a/packages/loot-core/src/client/shared-listeners.js b/packages/loot-core/src/client/shared-listeners.ts similarity index 100% rename from packages/loot-core/src/client/shared-listeners.js rename to packages/loot-core/src/client/shared-listeners.ts diff --git a/packages/loot-core/src/client/tutorial.js b/packages/loot-core/src/client/tutorial.ts similarity index 100% rename from packages/loot-core/src/client/tutorial.js rename to packages/loot-core/src/client/tutorial.ts diff --git a/packages/loot-core/src/client/update-notification.js b/packages/loot-core/src/client/update-notification.ts similarity index 100% rename from packages/loot-core/src/client/update-notification.js rename to packages/loot-core/src/client/update-notification.ts diff --git a/packages/loot-core/src/client/upgrade-notifications.js b/packages/loot-core/src/client/upgrade-notifications.ts similarity index 100% rename from packages/loot-core/src/client/upgrade-notifications.js rename to packages/loot-core/src/client/upgrade-notifications.ts diff --git a/packages/loot-core/src/mocks/arbitrary-schema.js b/packages/loot-core/src/mocks/arbitrary-schema.ts similarity index 83% rename from packages/loot-core/src/mocks/arbitrary-schema.js rename to packages/loot-core/src/mocks/arbitrary-schema.ts index 282f65384..97ec3113d 100644 --- a/packages/loot-core/src/mocks/arbitrary-schema.js +++ b/packages/loot-core/src/mocks/arbitrary-schema.ts @@ -1,9 +1,9 @@ -import fc from 'fast-check'; +import fc, { type Arbitrary } from 'fast-check'; import { schema } from '../server/aql'; import { addDays } from '../shared/months'; -export function typeArbitrary(typeDesc, name) { +export function typeArbitrary(typeDesc, name?) { let arb; switch (typeDesc.type) { case 'id': @@ -93,12 +93,19 @@ export function flattenSortTransactions(arr) { }); } -function tableArbitrary(tableSchema, extraArbs, requiredKeys = []) { +function tableArbitrary< + T extends Record<string, { type: string; required?: boolean }>, + E extends Record<string, Arbitrary<unknown>>, +>( + tableSchema: T, + extraArbs?: E, + requiredKeys: Array<Extract<keyof T | keyof E, string>> = [], +) { let arb = fc.record( { - ...Object.fromEntries( + ...Object.fromEntries<T>( Object.entries(tableSchema).map(([name, field]) => { - return [name, typeArbitrary(field, name)]; + return [name, typeArbitrary(field, name)] as const; }), ), // Override the amount to make it a smaller integer @@ -117,7 +124,10 @@ function tableArbitrary(tableSchema, extraArbs, requiredKeys = []) { return arb; } -export function makeTransaction({ splitFreq = 1, payeeIds } = {}) { +export function makeTransaction({ + splitFreq = 1, + payeeIds, +}: { splitFreq?: number; payeeIds?: string[] } = {}) { let payeeField = payeeIds ? { payee: fc.oneof(...payeeIds.map(id => fc.constant(id))) } : null; @@ -137,7 +147,9 @@ export function makeTransaction({ splitFreq = 1, payeeIds } = {}) { ); } -export const makeTransactionArray = (options = {}) => { +export const makeTransactionArray = ( + options: { minLength?; maxLength?; splitFreq?; payeeIds? } = {}, +) => { let { minLength, maxLength, ...transOpts } = options; return fc .array(makeTransaction(transOpts), { minLength, maxLength }) diff --git a/packages/loot-core/src/mocks/budget.js b/packages/loot-core/src/mocks/budget.ts similarity index 98% rename from packages/loot-core/src/mocks/budget.js rename to packages/loot-core/src/mocks/budget.ts index bc387d940..b90ca9958 100644 --- a/packages/loot-core/src/mocks/budget.js +++ b/packages/loot-core/src/mocks/budget.ts @@ -9,6 +9,12 @@ import * as sheet from '../server/sheet'; import { batchMessages, setSyncingMode } from '../server/sync'; import * as monthUtils from '../shared/months'; import q from '../shared/query'; +import type { + AccountEntity, + CategoryGroupEntity, + PayeeEntity, + TransactionEntity, +} from '../types/models'; function pickRandom(list) { return list[Math.floor(Math.random() * list.length) % list.length]; @@ -100,7 +106,7 @@ async function fillPrimaryChecking(handlers, account, payees, groups) { amount = integer(0, Math.random() < 0.05 ? -8000 : -700); } - let transaction = { + let transaction: TransactionEntity = { amount, payee: payee.id, account: account.id, @@ -122,7 +128,7 @@ async function fillPrimaryChecking(handlers, account, payees, groups) { amount: transaction.amount - a * 2, category: pick(), }, - ]; + ] as TransactionEntity[]; } } @@ -384,7 +390,7 @@ async function fillOther(handlers, account, payees, groups) { let numTransactions = integer(3, 6); let category = incomeGroup.categories.find(c => c.name === 'Income'); - let transactions = [ + let transactions: TransactionEntity[] = [ { amount: integer(3250, 3700) * 100 * 100, payee: payees.find(p => p.name === 'Starting Balance').id, @@ -557,7 +563,7 @@ export async function createTestBudget(handlers) { await db.runQuery('DELETE FROM categories;'); await db.runQuery('DELETE FROM category_groups'); - let accounts = [ + let accounts: AccountEntity[] = [ { name: 'Bank of America', type: 'checking' }, { name: 'Ally Savings', type: 'savings' }, { name: 'Capital One Checking', type: 'checking' }, @@ -575,7 +581,7 @@ export async function createTestBudget(handlers) { }), ); - let payees = [ + let payees: PayeeEntity[] = [ { name: 'Starting Balance' }, { name: 'Kroger' }, { name: 'Publix' }, @@ -598,7 +604,7 @@ export async function createTestBudget(handlers) { }), ); - let categoryGroups = [ + let categoryGroups: CategoryGroupEntity[] = [ { name: 'Usual Expenses', categories: [ @@ -640,6 +646,7 @@ export async function createTestBudget(handlers) { isIncome: group.is_income ? 1 : 0, }); + // @ts-expect-error Missing proper type refinement for (let category of group.categories) { category.id = await handlers['category-create']({ ...category, diff --git a/packages/loot-core/src/mocks/index.js b/packages/loot-core/src/mocks/index.ts similarity index 94% rename from packages/loot-core/src/mocks/index.js rename to packages/loot-core/src/mocks/index.ts index b61a8a3b4..f0e055c35 100644 --- a/packages/loot-core/src/mocks/index.js +++ b/packages/loot-core/src/mocks/index.ts @@ -1,5 +1,6 @@ import * as uuid from '../platform/uuid'; import * as monthUtils from '../shared/months'; +import type { TransactionEntity } from '../types/models'; export function generateAccount(name, isConnected, type, offbudget) { return { @@ -49,7 +50,7 @@ export function generateCategoryGroups(definition) { }); } -function _generateTransaction(data) { +function _generateTransaction(data): TransactionEntity { const id = data.id || uuid.v4Sync(); return { id: id, @@ -65,7 +66,7 @@ function _generateTransaction(data) { }; } -export function generateTransaction(data, splitAmount, showError = false) { +export function generateTransaction(data, splitAmount?, showError = false) { const result = []; const trans = _generateTransaction(data); diff --git a/packages/loot-core/src/mocks/plaid.js b/packages/loot-core/src/mocks/plaid.ts similarity index 100% rename from packages/loot-core/src/mocks/plaid.js rename to packages/loot-core/src/mocks/plaid.ts diff --git a/packages/loot-core/src/mocks/redux.js b/packages/loot-core/src/mocks/redux.tsx similarity index 100% rename from packages/loot-core/src/mocks/redux.js rename to packages/loot-core/src/mocks/redux.tsx diff --git a/packages/loot-core/src/mocks/setup.js b/packages/loot-core/src/mocks/setup.ts similarity index 95% rename from packages/loot-core/src/mocks/setup.js rename to packages/loot-core/src/mocks/setup.ts index 1a415914c..7da62ee46 100644 --- a/packages/loot-core/src/mocks/setup.js +++ b/packages/loot-core/src/mocks/setup.ts @@ -58,7 +58,7 @@ global.randomId = () => { global.getDatabaseDump = async function (tables) { if (!tables) { - const rows = await sqlite.runQuery( + const rows = await sqlite.runQuery<{ name }>( db.getDatabase(), "SELECT name FROM sqlite_master WHERE type='table'", [], @@ -114,7 +114,7 @@ global.emptyDatabase = function (avoidUpdate) { await sqlite.init(); - let memoryDB = new sqlite.openDatabase(path); + let memoryDB = await sqlite.openDatabase(path); sqlite.execQuery( memoryDB, nativeFs.readFileSync(__dirname + '/../server/sql/init.sql', 'utf8'), @@ -145,10 +145,10 @@ afterEach(() => { if (sheet.get()) { sheet.get().onFinish(() => { sheet.unloadSpreadsheet(); - resolve(); + resolve(undefined); }); } else { - resolve(); + resolve(undefined); } }); }); diff --git a/packages/loot-core/src/mocks/spreadsheet.js b/packages/loot-core/src/mocks/spreadsheet.ts similarity index 100% rename from packages/loot-core/src/mocks/spreadsheet.js rename to packages/loot-core/src/mocks/spreadsheet.ts diff --git a/packages/loot-core/src/mocks/util.js b/packages/loot-core/src/mocks/util.ts similarity index 91% rename from packages/loot-core/src/mocks/util.js rename to packages/loot-core/src/mocks/util.ts index 6128df60a..0525babc6 100644 --- a/packages/loot-core/src/mocks/util.js +++ b/packages/loot-core/src/mocks/util.ts @@ -2,7 +2,10 @@ import { join, dirname, basename } from 'path'; import snapshotDiff from 'snapshot-diff'; -export function expectSnapshotWithDiffer(initialValue, { onlyUpdates } = {}) { +export function expectSnapshotWithDiffer( + initialValue, + { onlyUpdates }: { onlyUpdates? } = {}, +) { let currentValue = initialValue; if (!onlyUpdates) { expect(initialValue).toMatchSnapshot(); 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 5761ed568..40cc73c0d 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 @@ -1,7 +1,9 @@ +import type * as T from '..'; + let listeners = new Map(); let serverHandler = null; -export const initServer = handlers => { +export const initServer: T.InitServer = handlers => { serverHandler = msg => { let { name, args, catchErrors } = msg; if (handlers[name]) { @@ -20,12 +22,12 @@ export const initServer = handlers => { }; }; -export const clearServer = () => { +export const clearServer: T.ClearServer = () => { serverHandler = null; listeners = new Map(); }; -export const serverPush = (name, args) => { +export const serverPush: T.ServerPush = (name, args) => { Promise.resolve().then(() => { const listens = listeners.get(name); if (listens) { diff --git a/packages/loot-core/src/platform/client/fetch/index.d.ts b/packages/loot-core/src/platform/client/fetch/index.d.ts index 646890e9b..ae2b1aeb9 100644 --- a/packages/loot-core/src/platform/client/fetch/index.d.ts +++ b/packages/loot-core/src/platform/client/fetch/index.d.ts @@ -1,4 +1,5 @@ import type { Handlers } from '../../../types/handlers'; +import type { ServerEvents } from '../../../types/server-events'; export function init(socketName: string): Promise<unknown>; export type Init = typeof init; @@ -16,8 +17,21 @@ export function sendCatch<K extends keyof Handlers>( ): ReturnType<Handlers[K]>; export type SendCatch = typeof sendCatch; -export function listen(name: string, cb: () => void): () => void; +export function listen<K extends keyof ServerEvents>( + name: K, + cb: (arg: ServerEvents[K]) => void, +): () => void; export type Listen = typeof listen; export function unlisten(name: string): void; export type Unlisten = typeof unlisten; + +/** Mock functions */ +export function initServer(handlers: unknown): void; +export type InitServer = typeof initServer; + +export function serverPush(name: string, args: unknown): void; +export type ServerPush = typeof serverPush; + +export function clearServer(): void; +export type ClearServer = typeof clearServer; diff --git a/packages/loot-core/src/platform/server/asyncStorage/index.d.ts b/packages/loot-core/src/platform/server/asyncStorage/index.d.ts index 6995ad9f9..4a189f3a8 100644 --- a/packages/loot-core/src/platform/server/asyncStorage/index.d.ts +++ b/packages/loot-core/src/platform/server/asyncStorage/index.d.ts @@ -1,4 +1,4 @@ -export function init(): void; +export function init(opts?: { persist?: boolean }): void; export type Init = typeof init; export function getItem(key: string): Promise<string>; @@ -10,7 +10,7 @@ export type SetItem = typeof setItem; export function removeItem(key: string): void; export type RemoveItem = typeof removeItem; -export function multiGet(keys: string[]): Promise<[string, unknown][]>; +export function multiGet(keys: string[]): Promise<[string, string][]>; export type MultiGet = typeof multiGet; export function multiSet(keyValues: [string, unknown][]): void; 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 e0bde3120..b81081c71 100644 --- a/packages/loot-core/src/platform/server/asyncStorage/index.web.ts +++ b/packages/loot-core/src/platform/server/asyncStorage/index.web.ts @@ -60,7 +60,7 @@ export const multiGet: T.MultiGet = async function (keys) { let promise = Promise.all( keys.map(key => { - return new Promise<[string, unknown]>((resolve, reject) => { + return new Promise<[string, string]>((resolve, reject) => { let req = objectStore.get(key); req.onerror = e => reject(e); req.onsuccess = e => resolve([key, e.target.result]); diff --git a/packages/loot-core/src/platform/server/connection/index.d.ts b/packages/loot-core/src/platform/server/connection/index.d.ts index 8bcebcd84..48eec7ff0 100644 --- a/packages/loot-core/src/platform/server/connection/index.d.ts +++ b/packages/loot-core/src/platform/server/connection/index.d.ts @@ -1,16 +1,21 @@ +import type { ServerEvents } from '../../../types/server-events'; + export function init( channel: Window | string, handlers: Record<string, () => void>, ): void; export type Init = typeof init; -export function send(type: string, args?: unknown): void; +export function send<K extends keyof ServerEvents>( + type: K, + args?: ServerEvents[k], +): void; export type Send = typeof send; export function getEvents(): unknown[]; export type GetEvents = typeof getEvents; -export function getNumClients(): void; +export function getNumClients(): number; export type GetNumClients = typeof getNumClients; export function resetEvents(): void; diff --git a/packages/loot-core/src/platform/server/fs/index.d.ts b/packages/loot-core/src/platform/server/fs/index.d.ts index aa7a9ce05..d9c1d8a60 100644 --- a/packages/loot-core/src/platform/server/fs/index.d.ts +++ b/packages/loot-core/src/platform/server/fs/index.d.ts @@ -47,8 +47,9 @@ export type CopyFile = typeof copyFile; export function readFile( filepath: string, - encoding?: 'utf8' | 'binary' | null, -): Promise<string | Buffer>; + encoding: 'binary' | null, +): Promise<Buffer>; +export function readFile(filepath: string, encoding?: 'utf8'): Promise<string>; export type ReadFile = typeof readFile; export function writeFile( 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 46ad57118..89d042397 100644 --- a/packages/loot-core/src/platform/server/fs/index.electron.ts +++ b/packages/loot-core/src/platform/server/fs/index.electron.ts @@ -117,13 +117,18 @@ export const copyFile = (frompath, topath) => { }); }; -export const readFile: T.ReadFile = (filepath, encoding = 'utf8') => { +export const readFile: T.ReadFile = ( + filepath: string, + encoding: 'utf8' | 'binary' | null = 'utf8', +) => { if (encoding === 'binary') { // `binary` is not actually a valid encoding, you pass `null` into node if // you want a buffer encoding = null; } - return new Promise((resolve, reject) => { + // `any` as cannot refine return with two function overrides + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return new Promise<any>((resolve, reject) => { fs.readFile(filepath, encoding, (err, data) => { if (err) { reject(err); diff --git a/packages/loot-core/src/server/__snapshots__/backups.test.js.snap b/packages/loot-core/src/server/__snapshots__/backups.test.ts.snap similarity index 100% rename from packages/loot-core/src/server/__snapshots__/backups.test.js.snap rename to packages/loot-core/src/server/__snapshots__/backups.test.ts.snap diff --git a/packages/loot-core/src/server/__snapshots__/main.test.js.snap b/packages/loot-core/src/server/__snapshots__/main.test.ts.snap similarity index 100% rename from packages/loot-core/src/server/__snapshots__/main.test.js.snap rename to packages/loot-core/src/server/__snapshots__/main.test.ts.snap diff --git a/packages/loot-core/src/server/__snapshots__/sheet.test.js.snap b/packages/loot-core/src/server/__snapshots__/sheet.test.ts.snap similarity index 100% rename from packages/loot-core/src/server/__snapshots__/sheet.test.js.snap rename to packages/loot-core/src/server/__snapshots__/sheet.test.ts.snap diff --git a/packages/loot-core/src/server/api-models.js b/packages/loot-core/src/server/api-models.ts similarity index 98% rename from packages/loot-core/src/server/api-models.js rename to packages/loot-core/src/server/api-models.ts index c42701eff..ea1da3d13 100644 --- a/packages/loot-core/src/server/api-models.js +++ b/packages/loot-core/src/server/api-models.ts @@ -39,7 +39,7 @@ export const transactionModel = { }, fromExternal(transaction) { - let result = {}; + let result: Record<string, unknown> = {}; if ('id' in transaction) { result.id = transaction.id; } diff --git a/packages/loot-core/src/server/api.js b/packages/loot-core/src/server/api.ts similarity index 98% rename from packages/loot-core/src/server/api.js rename to packages/loot-core/src/server/api.ts index 3509ffd2e..4c73f5419 100644 --- a/packages/loot-core/src/server/api.js +++ b/packages/loot-core/src/server/api.ts @@ -33,7 +33,7 @@ import { setSyncingMode, batchMessages } from './sync'; let IMPORT_MODE = false; // This is duplicate from main.js... -function APIError(msg, meta) { +function APIError(msg, meta?) { return { type: 'APIError', message: msg, meta }; } @@ -193,7 +193,7 @@ handlers['api/download-budget'] = async function ({ syncId, password }) { let result = await handlers['download-budget']({ fileId: file.fileId }); if (result.error) { - throw new Error(getDownloadError(result.error, result.id)); + throw new Error(getDownloadError(result.error)); } await handlers['load-budget']({ id: result.id }); } @@ -466,7 +466,9 @@ handlers['api/account-delete'] = withMutation(async function ({ id }) { return handlers['account-close']({ id, forced: true }); }); -handlers['api/categories-get'] = async function ({ grouped } = {}) { +handlers['api/categories-get'] = async function ({ + grouped, +}: { grouped? } = {}) { let result = await handlers['get-categories'](); return grouped ? result.grouped.map(categoryGroupModel.toExternal) diff --git a/packages/loot-core/src/server/app.js b/packages/loot-core/src/server/app.ts similarity index 96% rename from packages/loot-core/src/server/app.js rename to packages/loot-core/src/server/app.ts index d34b9b09a..c2bca043a 100644 --- a/packages/loot-core/src/server/app.js +++ b/packages/loot-core/src/server/app.ts @@ -8,6 +8,11 @@ import { captureException } from '../platform/exceptions'; // methods an "app". class App { + events; + handlers; + services; + unlistenServices; + constructor() { this.handlers = {}; this.services = []; diff --git a/packages/loot-core/src/server/backups.test.js b/packages/loot-core/src/server/backups.test.ts similarity index 100% rename from packages/loot-core/src/server/backups.test.js rename to packages/loot-core/src/server/backups.test.ts diff --git a/packages/loot-core/src/server/backups.js b/packages/loot-core/src/server/backups.ts similarity index 99% rename from packages/loot-core/src/server/backups.js rename to packages/loot-core/src/server/backups.ts index ca72eaf5c..0766ee670 100644 --- a/packages/loot-core/src/server/backups.js +++ b/packages/loot-core/src/server/backups.ts @@ -66,12 +66,10 @@ export async function getAvailableBackups(id) { backups.unshift(latestBackup); } - backups = backups.map(backup => ({ + return backups.map(backup => ({ ...backup, date: backup.date ? dateFns.format(backup.date, 'yyyy-MM-dd h:mm') : null, })); - - return backups; } export async function updateBackups(backups) { diff --git a/packages/loot-core/src/server/bench.js b/packages/loot-core/src/server/bench.ts similarity index 86% rename from packages/loot-core/src/server/bench.js rename to packages/loot-core/src/server/bench.ts index c0be1eb6e..cb50c267e 100644 --- a/packages/loot-core/src/server/bench.js +++ b/packages/loot-core/src/server/bench.ts @@ -8,8 +8,8 @@ const queries = fs .split('___BOUNDARY') .map(q => q.trim()); -function runQueries(n) { - for (var i = 0; i < queries.length; i++) { +function runQueries(n?) { + for (let i = 0; i < queries.length; i++) { if (queries[i] !== '') { db.runQuery(queries[i], [], true); } diff --git a/packages/loot-core/src/server/cloud-storage.js b/packages/loot-core/src/server/cloud-storage.ts similarity index 98% rename from packages/loot-core/src/server/cloud-storage.js rename to packages/loot-core/src/server/cloud-storage.ts index 1963eeab2..12dafc4bd 100644 --- a/packages/loot-core/src/server/cloud-storage.js +++ b/packages/loot-core/src/server/cloud-storage.ts @@ -31,7 +31,7 @@ async function checkHTTPStatus(res) { } } -async function fetchJSON(...args) { +async function fetchJSON(...args: Parameters<typeof fetch>) { let res = await fetch(...args); res = await checkHTTPStatus(res); return res.json(); @@ -279,7 +279,7 @@ export async function upload() { console.log('Upload failure', err); if (err instanceof PostError) { - throw new FileUploadError( + throw FileUploadError( err.reason === 'unauthorized' ? 'unauthorized' : err.reason || 'network', @@ -362,7 +362,7 @@ export async function listRemoteFiles() { })); } -export async function download(fileId, replace) { +export async function download(fileId) { let userToken = await asyncStorage.getItem('user-token'); let buffer; @@ -415,5 +415,5 @@ export async function download(fileId, replace) { } } - return importBuffer(fileData, buffer, replace); + return importBuffer(fileData, buffer); } diff --git a/packages/loot-core/src/server/db/index.ts b/packages/loot-core/src/server/db/index.ts index 46eef2310..1d08c3d16 100644 --- a/packages/loot-core/src/server/db/index.ts +++ b/packages/loot-core/src/server/db/index.ts @@ -41,7 +41,7 @@ export function getDatabasePath() { return dbPath; } -export async function openDatabase(id) { +export async function openDatabase(id?) { if (db) { await sqlite.closeDatabase(db); } @@ -634,8 +634,8 @@ export async function getTransactionsByDate( throw new Error('`getTransactionsByDate` is deprecated'); } -export async function getTransactions(accountId, arg2?: unknown) { - if (arg2 !== undefined) { +export async function getTransactions(accountId) { + if (arguments.length > 1) { throw new Error( '`getTransactions` was given a second argument, it now only takes a single argument `accountId`', ); diff --git a/packages/loot-core/src/server/encryption-internals.js b/packages/loot-core/src/server/encryption-internals.ts similarity index 85% rename from packages/loot-core/src/server/encryption-internals.js rename to packages/loot-core/src/server/encryption-internals.ts index 79ff20538..02695f529 100644 --- a/packages/loot-core/src/server/encryption-internals.js +++ b/packages/loot-core/src/server/encryption-internals.ts @@ -1,6 +1,6 @@ import crypto from 'crypto'; -let ENCRYPTION_ALGORITHM = 'aes-256-gcm'; +let ENCRYPTION_ALGORITHM = 'aes-256-gcm' as const; export async function sha256String(str) { return crypto.createHash('sha256').update(str).digest('base64'); @@ -65,11 +65,16 @@ export function importKey(str) { * Generates a Buffer of a desired byte length to be used as either an encryption key or an initialization vector. * * @private - * @param {Integer} [numBytes = 32] - Optional, number of bytes to fill the Buffer with. - * @param {String} [secret = <random bytes>] - Optional, a secret to use as a basis for the key generation algorithm. - * @returns {Buffer} */ -function createKeyBuffer({ numBytes, secret, salt }) { +function createKeyBuffer({ + numBytes, + secret, + salt, +}: { + numBytes?: number; + secret?: string; + salt?: string; +}) { return crypto.pbkdf2Sync( secret || crypto.randomBytes(128).toString('base64'), salt || crypto.randomBytes(32).toString('base64'), diff --git a/packages/loot-core/src/server/encryption-internals.web.js b/packages/loot-core/src/server/encryption-internals.web.ts similarity index 95% rename from packages/loot-core/src/server/encryption-internals.web.js rename to packages/loot-core/src/server/encryption-internals.web.ts index d808d13a2..9a4161ef9 100644 --- a/packages/loot-core/src/server/encryption-internals.web.js +++ b/packages/loot-core/src/server/encryption-internals.web.ts @@ -10,6 +10,7 @@ function browserAlgorithmName(name) { } export async function sha256String(str) { + // @ts-expect-error TextEncoder might not accept an argument let inputBuffer = new TextEncoder('utf-8').encode(str).buffer; let buffer = await crypto.subtle.digest('sha-256', inputBuffer); let outputStr = Array.from(new Uint8Array(buffer)) @@ -47,6 +48,7 @@ export async function encrypt(masterKey, value) { keyId: masterKey.getId(), algorithm: ENCRYPTION_ALGORITHM, iv: Buffer.from(iv).toString('base64'), + // @ts-expect-error base64 argument is valid only on NodeJS authTag: authTag.toString('base64'), }, }; diff --git a/packages/loot-core/src/server/encryption.test.js b/packages/loot-core/src/server/encryption.test.ts similarity index 100% rename from packages/loot-core/src/server/encryption.test.js rename to packages/loot-core/src/server/encryption.test.ts diff --git a/packages/loot-core/src/server/encryption.js b/packages/loot-core/src/server/encryption.ts similarity index 99% rename from packages/loot-core/src/server/encryption.js rename to packages/loot-core/src/server/encryption.ts index c42f5c20e..159421aa4 100644 --- a/packages/loot-core/src/server/encryption.js +++ b/packages/loot-core/src/server/encryption.ts @@ -7,6 +7,9 @@ import * as internals from './encryption-internals'; let keys = {}; class Key { + id; + value; + constructor({ id }) { this.id = id || uuid.v4Sync(); } diff --git a/packages/loot-core/src/server/errors.js b/packages/loot-core/src/server/errors.ts similarity index 68% rename from packages/loot-core/src/server/errors.js rename to packages/loot-core/src/server/errors.ts index 418c2df77..3d1ddccc5 100644 --- a/packages/loot-core/src/server/errors.js +++ b/packages/loot-core/src/server/errors.ts @@ -1,6 +1,10 @@ // TODO: normalize error types export class PostError extends Error { - constructor(reason, meta) { + meta; + reason; + type; + + constructor(reason, meta?) { super('PostError: ' + reason); this.type = 'PostError'; this.reason = reason; @@ -9,6 +13,9 @@ export class PostError extends Error { } export class HTTPError extends Error { + statusCode; + responseBody; + constructor(code, body) { super(`HTTPError: unsuccessful status code (${code}): ${body}`); this.statusCode = code; @@ -17,36 +24,36 @@ export class HTTPError extends Error { } export class SyncError extends Error { - constructor(reason, meta) { + meta; + reason; + + constructor(reason, meta?) { super('SyncError: ' + reason); this.reason = reason; this.meta = meta; } } -export class TransactionError extends Error { - // eslint-disable-next-line no-useless-constructor - constructor(message) { - super(message); - } -} +export class TransactionError extends Error {} export class RuleError extends Error { - constructor(type, message) { + type; + + constructor(name, message) { super('RuleError: ' + message); - this.type = type; + this.type = name; } } -export function APIError(msg, meta) { +export function APIError(msg, meta?) { return { type: 'APIError', message: msg, meta }; } -export function FileDownloadError(reason, meta) { +export function FileDownloadError(reason, meta?) { return { type: 'FileDownloadError', reason, meta }; } -export function FileUploadError(reason, meta) { +export function FileUploadError(reason, meta?) { return { type: 'FileUploadError', reason, meta }; } diff --git a/packages/loot-core/src/server/main-app.js b/packages/loot-core/src/server/main-app.ts similarity index 100% rename from packages/loot-core/src/server/main-app.js rename to packages/loot-core/src/server/main-app.ts diff --git a/packages/loot-core/src/server/main.test.js b/packages/loot-core/src/server/main.test.ts similarity index 99% rename from packages/loot-core/src/server/main.test.js rename to packages/loot-core/src/server/main.test.ts index 5fd901dd7..7aa48c5d8 100644 --- a/packages/loot-core/src/server/main.test.js +++ b/packages/loot-core/src/server/main.test.ts @@ -29,6 +29,7 @@ afterEach(async () => { await runHandler(handlers['close-budget']); connection.resetEvents(); enableGlobalMutations(); + global.currentMonth = null; }); async function createTestBudget(name) { @@ -234,7 +235,7 @@ describe('Budget', () => { // Fast-forward in time to a future month and make sure it creates // budgets for the months in the future - monthUtils.currentMonth = () => '2017-02'; + global.currentMonth = '2017-02'; bounds = await runHandler(handlers['get-budget-bounds']); expect(bounds.start).toBe('2016-02'); @@ -247,7 +248,7 @@ describe('Budget', () => { test('budget updates when changing a category', async () => { const spreadsheet = await sheet.loadSpreadsheet(db); function captureChangedCells(func) { - return new Promise(async resolve => { + return new Promise<unknown[]>(async resolve => { let changed = []; let remove = spreadsheet.addEventListener('change', ({ names }) => { changed = changed.concat(names); diff --git a/packages/loot-core/src/server/main.js b/packages/loot-core/src/server/main.ts similarity index 98% rename from packages/loot-core/src/server/main.js rename to packages/loot-core/src/server/main.ts index e22068a5f..17a0f752c 100644 --- a/packages/loot-core/src/server/main.js +++ b/packages/loot-core/src/server/main.ts @@ -140,23 +140,6 @@ handlers['transaction-delete'] = mutator(async function (transaction) { return {}; }); -handlers['transactions-filter'] = async function ({ - term, - accountId, - latestDate, - count, - notPaged, - options = {}, -}) { - return db.getTransactions( - term, - accountId, - latestDate, - notPaged ? null : count == null ? undefined : count, - options, - ); -}; - handlers['transactions-parse-file'] = async function ({ filepath, options }) { return parseFile(filepath, options); }; @@ -1120,7 +1103,7 @@ handlers['accounts-sync'] = async function ({ id }) { let matchedTransactions = []; let updatedAccounts = []; - for (var i = 0; i < accounts.length; i++) { + for (let i = 0; i < accounts.length; i++) { const acct = accounts[i]; if (acct.bankId) { try { @@ -1322,7 +1305,7 @@ handlers['nordigen-accounts-sync'] = async function ({ id }) { let matchedTransactions = []; let updatedAccounts = []; - for (var i = 0; i < accounts.length; i++) { + for (let i = 0; i < accounts.length; i++) { const acct = accounts[i]; if (acct.bankId) { try { @@ -1635,7 +1618,9 @@ handlers['key-test'] = async function ({ fileId, password }) { return {}; }; -handlers['subscribe-needs-bootstrap'] = async function ({ url } = {}) { +handlers['subscribe-needs-bootstrap'] = async function ({ + url, +}: { url? } = {}) { if (getServer(url).BASE_SERVER === UNCONFIGURED_SERVER) { return { bootstrapped: true, hasServer: false }; } @@ -1688,15 +1673,15 @@ handlers['subscribe-get-user'] = async function () { if (userToken) { try { - let res = await get(getServer().SIGNUP_SERVER + '/validate', { + const res = await get(getServer().SIGNUP_SERVER + '/validate', { headers: { 'X-ACTUAL-TOKEN': userToken, }, }); - res = JSON.parse(res); + const { status, reason } = JSON.parse(res); - if (res.status === 'error') { - if (res.reason === 'unauthorized') { + if (status === 'error') { + if (reason === 'unauthorized') { return null; } return { offline: true }; @@ -1845,7 +1830,7 @@ handlers['reset-budget-cache'] = mutator(async function () { await sheet.waitOnSpreadsheet(); }); -handlers['upload-budget'] = async function ({ id } = {}) { +handlers['upload-budget'] = async function ({ id }: { id? } = {}) { if (id) { if (prefs.getPrefs()) { throw new Error('upload-budget: id given but prefs already loaded'); @@ -1872,10 +1857,10 @@ handlers['upload-budget'] = async function ({ id } = {}) { return {}; }; -handlers['download-budget'] = async function ({ fileId, replace }) { +handlers['download-budget'] = async function ({ fileId }) { let result; try { - result = await cloudStorage.download(fileId, replace); + result = await cloudStorage.download(fileId); } catch (e) { if (e.type === 'FileDownloadError') { if (e.reason === 'file-exists' && e.meta.id) { @@ -1924,7 +1909,7 @@ handlers['load-budget'] = async function ({ id }) { } } - let res = await loadBudget(id, { showUpdate: true }); + let res = await loadBudget(id); return res; }; @@ -1988,6 +1973,11 @@ handlers['create-budget'] = async function ({ avoidUpload, testMode, testBudgetId, +}: { + budgetName?; + avoidUpload?; + testMode?; + testBudgetId?; } = {}) { let id; if (testMode) { @@ -2143,7 +2133,7 @@ handlers['export-budget'] = async function () { return await cloudStorage.exportBuffer(); }; -async function loadBudget(id, { showUpdate } = {}) { +async function loadBudget(id) { let dir; try { dir = fs.getBudgetDir(id); @@ -2178,10 +2168,8 @@ async function loadBudget(id, { showUpdate } = {}) { prefs.savePrefs({ userId }); } - let { budgetVersion } = prefs.getPrefs(); - try { - await updateVersion(budgetVersion, showUpdate); + await updateVersion(); } catch (e) { console.warn('Error updating', e); let result; diff --git a/packages/loot-core/src/server/models.js b/packages/loot-core/src/server/models.ts similarity index 92% rename from packages/loot-core/src/server/models.js rename to packages/loot-core/src/server/models.ts index 1f504569b..86bcd3ed5 100644 --- a/packages/loot-core/src/server/models.js +++ b/packages/loot-core/src/server/models.ts @@ -51,7 +51,7 @@ export const accountModel = { } }, - validate(account, { update } = {}) { + validate(account, { update }: { update?: boolean } = {}) { if (!update || account.type != null) { accountModel.validateAccountType(account); } @@ -68,7 +68,7 @@ export const accountModel = { }; export const categoryModel = { - validate(category, { update } = {}) { + validate(category, { update }: { update?: boolean } = {}) { requiredFields( 'category', category, @@ -82,7 +82,7 @@ export const categoryModel = { }; export const categoryGroupModel = { - validate(categoryGroup, { update } = {}) { + validate(categoryGroup, { update }: { update?: boolean } = {}) { requiredFields( 'categoryGroup', categoryGroup, @@ -96,7 +96,7 @@ export const categoryGroupModel = { }; export const payeeModel = { - validate(payee, { update } = {}) { + validate(payee, { update }: { update?: boolean } = {}) { requiredFields('payee', payee, ['name'], update); return payee; }, @@ -110,7 +110,7 @@ export const payeeRuleModel = { } }, - validate(rule, { update } = {}) { + validate(rule, { update }: { update?: boolean } = {}) { if (!update || 'type' in rule) { payeeRuleModel.validateType(rule); } @@ -121,7 +121,7 @@ export const payeeRuleModel = { }; export const transactionModel = { - validate(trans, { update } = {}) { + validate(trans, { update }: { update?: boolean } = {}) { requiredFields('transaction', trans, ['date', 'acct'], update); if ('date' in trans) { diff --git a/packages/loot-core/src/server/mutators.js b/packages/loot-core/src/server/mutators.ts similarity index 90% rename from packages/loot-core/src/server/mutators.js rename to packages/loot-core/src/server/mutators.ts index 0cb518cfd..a50472c63 100644 --- a/packages/loot-core/src/server/mutators.js +++ b/packages/loot-core/src/server/mutators.ts @@ -36,7 +36,11 @@ function wait(time) { return new Promise(resolve => setTimeout(resolve, time)); } -export async function runHandler(handler, args, { undoTag, name } = {}) { +export async function runHandler( + handler, + args?, + { undoTag, name }: { undoTag?; name? } = {}, +) { // For debug reasons, track the latest handlers that have been // called _latestHandlerNames.push(name); @@ -77,12 +81,17 @@ export function disableGlobalMutations() { } } -export const runMutator = sequential(async (func, initialContext = {}) => { +function _runMutator<T extends () => Promise<unknown>>( + func: T, + initialContext = {}, +) { currentContext = initialContext; return func().finally(() => { currentContext = null; - }); -}); + }) as ReturnType<T>; +} +// Type cast needed as TS looses types over nested generic returns +export const runMutator = sequential(_runMutator) as typeof _runMutator; export function withMutatorContext(context, func) { if (currentContext == null && !globalMutationsEnabled) { diff --git a/packages/loot-core/src/server/perf.js b/packages/loot-core/src/server/perf.ts similarity index 100% rename from packages/loot-core/src/server/perf.js rename to packages/loot-core/src/server/perf.ts diff --git a/packages/loot-core/src/server/platform.js b/packages/loot-core/src/server/platform.ts similarity index 100% rename from packages/loot-core/src/server/platform.js rename to packages/loot-core/src/server/platform.ts diff --git a/packages/loot-core/src/server/platform.web.js b/packages/loot-core/src/server/platform.web.ts similarity index 100% rename from packages/loot-core/src/server/platform.web.js rename to packages/loot-core/src/server/platform.web.ts diff --git a/packages/loot-core/src/server/polyfills.js b/packages/loot-core/src/server/polyfills.ts similarity index 100% rename from packages/loot-core/src/server/polyfills.js rename to packages/loot-core/src/server/polyfills.ts diff --git a/packages/loot-core/src/server/post.ts b/packages/loot-core/src/server/post.ts index 1f0bbc82d..891965063 100644 --- a/packages/loot-core/src/server/post.ts +++ b/packages/loot-core/src/server/post.ts @@ -89,6 +89,6 @@ export async function postBinary(url, data, headers) { return buffer; } -export function get(url, opts) { +export function get(url, opts?) { return fetch(url, opts).then(res => res.text()); } diff --git a/packages/loot-core/src/server/prefs.js b/packages/loot-core/src/server/prefs.ts similarity index 98% rename from packages/loot-core/src/server/prefs.js rename to packages/loot-core/src/server/prefs.ts index 9cbf7c6b9..43d89db2e 100644 --- a/packages/loot-core/src/server/prefs.js +++ b/packages/loot-core/src/server/prefs.ts @@ -5,7 +5,7 @@ import { sendMessages } from './sync'; let prefs = null; -export async function loadPrefs(id) { +export async function loadPrefs(id?) { if (process.env.NODE_ENV === 'test' && !id) { prefs = { dummyTestPrefs: true }; return prefs; diff --git a/packages/loot-core/src/server/server-config.js b/packages/loot-core/src/server/server-config.ts similarity index 94% rename from packages/loot-core/src/server/server-config.js rename to packages/loot-core/src/server/server-config.ts index c509cdc12..56f62cd10 100644 --- a/packages/loot-core/src/server/server-config.js +++ b/packages/loot-core/src/server/server-config.ts @@ -17,7 +17,7 @@ export function setServer(url) { } // `url` is optional; if not given it will provide the global config -export function getServer(url) { +export function getServer(url?) { if (url) { return { BASE_SERVER: url, diff --git a/packages/loot-core/src/server/sheet.test.js b/packages/loot-core/src/server/sheet.test.ts similarity index 95% rename from packages/loot-core/src/server/sheet.test.js rename to packages/loot-core/src/server/sheet.test.ts index f48a9e741..82c8861d1 100644 --- a/packages/loot-core/src/server/sheet.test.js +++ b/packages/loot-core/src/server/sheet.test.ts @@ -54,7 +54,7 @@ describe('Spreadsheet', () => { await new Promise(resolve => { spreadsheet.onFinish(() => { expect(spreadsheet.getValue('g!foo')).toMatchSnapshot(); - resolve(); + resolve(undefined); }); }); @@ -63,7 +63,7 @@ describe('Spreadsheet', () => { return new Promise(resolve => { spreadsheet.onFinish(() => { expect(spreadsheet.getValue('g!foo')).toMatchSnapshot(); - resolve(); + resolve(undefined); }); }); }); @@ -84,7 +84,7 @@ describe('Spreadsheet', () => { await new Promise(resolve => { spreadsheet.onFinish(() => { expect(spreadsheet.getValue('g!foo')).toMatchSnapshot(); - resolve(); + resolve(undefined); }); }); @@ -93,7 +93,7 @@ describe('Spreadsheet', () => { await new Promise(resolve => { spreadsheet.onFinish(() => { expect(spreadsheet.getValue('g!foo')).toMatchSnapshot(); - resolve(); + resolve(undefined); }); }); }); diff --git a/packages/loot-core/src/server/sheet.js b/packages/loot-core/src/server/sheet.ts similarity index 95% rename from packages/loot-core/src/server/sheet.js rename to packages/loot-core/src/server/sheet.ts index 199fd8277..8eb5341c0 100644 --- a/packages/loot-core/src/server/sheet.js +++ b/packages/loot-core/src/server/sheet.ts @@ -54,7 +54,7 @@ function setCacheStatus(mainDb, cacheDb, { clean }) { } function isCacheDirty(mainDb, cacheDb) { - let rows = sqlite.runQuery( + let rows = sqlite.runQuery<{ key?: number }>( cacheDb, 'SELECT key FROM kvcache_key WHERE id = 1', [], @@ -67,7 +67,7 @@ function isCacheDirty(mainDb, cacheDb) { } if (mainDb) { - let rows = sqlite.runQuery( + let rows = sqlite.runQuery<{ key?: number }>( mainDb, 'SELECT key FROM kvcache_key WHERE id = 1', [], @@ -84,7 +84,7 @@ function isCacheDirty(mainDb, cacheDb) { return rows.length === 0; } -export async function loadSpreadsheet(db, onSheetChange) { +export async function loadSpreadsheet(db, onSheetChange?) { let cacheEnabled = process.env.NODE_ENV !== 'test'; let mainDb = db.getDatabase(); let cacheDb; @@ -132,7 +132,7 @@ export async function loadSpreadsheet(db, onSheetChange) { } if (cacheEnabled && !isCacheDirty(mainDb, cacheDb)) { - let cachedRows = await sqlite.runQuery( + let cachedRows = await sqlite.runQuery<{ key?: number; value: string }>( cacheDb, 'SELECT * FROM kvcache', [], @@ -243,7 +243,7 @@ export function waitOnSpreadsheet() { if (globalSheet) { globalSheet.onFinish(resolve); } else { - resolve(); + resolve(undefined); } }); } diff --git a/packages/loot-core/src/server/sync/index.ts b/packages/loot-core/src/server/sync/index.ts index 104a6b97e..6aab81a77 100644 --- a/packages/loot-core/src/server/sync/index.ts +++ b/packages/loot-core/src/server/sync/index.ts @@ -249,7 +249,8 @@ type Message = { export const applyMessages = sequential(async (messages: Message[]) => { if (checkSyncingMode('import')) { - return applyMessagesForImport(messages); + applyMessagesForImport(messages); + return undefined; } else if (checkSyncingMode('enabled')) { // Compare the messages with the existing crdt. This filters out // already applied messages and determines if a message is old or @@ -671,7 +672,7 @@ async function _fullSync(sinceTimestamp, count, prevDiffTime) { let localTimeChanged = getClock().timestamp.toString() !== currentTime; // Apply the new messages - let receivedMessages: unknown[] = []; + let receivedMessages: Message[] = []; if (res.messages.length > 0) { receivedMessages = await receiveMessages( res.messages.map(msg => ({ diff --git a/packages/loot-core/src/server/sync/reset.ts b/packages/loot-core/src/server/sync/reset.ts index 4f21dc0cd..27e18feb9 100644 --- a/packages/loot-core/src/server/sync/reset.ts +++ b/packages/loot-core/src/server/sync/reset.ts @@ -6,7 +6,7 @@ import * as db from '../db'; import { runMutator } from '../mutators'; import * as prefs from '../prefs'; -export default async function resetSync(keyState) { +export default async function resetSync(keyState?) { if (!keyState) { // If we aren't resetting the key, make sure our key is up-to-date // so we don't accidentally upload a file encrypted with the wrong diff --git a/packages/loot-core/src/server/undo.js b/packages/loot-core/src/server/undo.ts similarity index 92% rename from packages/loot-core/src/server/undo.js rename to packages/loot-core/src/server/undo.ts index f6ecdf7e1..6217ea6be 100644 --- a/packages/loot-core/src/server/undo.js +++ b/packages/loot-core/src/server/undo.ts @@ -6,7 +6,17 @@ import { withMutatorContext, getMutatorContext } from './mutators'; import { sendMessages } from './sync'; // A marker always sits as the first entry to simplify logic -let MESSAGE_HISTORY = [{ type: 'marker' }]; +type MarkerMessage = { type: 'marker'; meta? }; +type MessagesMessage = { + type: 'messages'; + messages: unknown[]; + meta?; + oldData; + undoTag; +}; +let MESSAGE_HISTORY: Array<MarkerMessage | MessagesMessage> = [ + { type: 'marker' }, +]; let CURSOR = 0; let HISTORY_SIZE = 20; @@ -45,7 +55,7 @@ export function clearUndo() { CURSOR = 0; } -export function withUndo(func, meta) { +export function withUndo(func, meta?) { let context = getMutatorContext(); if (context.undoDisabled || context.undoListening) { return func(); @@ -53,7 +63,7 @@ export function withUndo(func, meta) { MESSAGE_HISTORY = MESSAGE_HISTORY.slice(0, CURSOR + 1); - let marker = { type: 'marker', meta }; + let marker = { type: 'marker' as const, meta }; if (MESSAGE_HISTORY[MESSAGE_HISTORY.length - 1].type === 'marker') { MESSAGE_HISTORY[MESSAGE_HISTORY.length - 1] = marker; @@ -110,7 +120,7 @@ export async function undo() { let meta = MESSAGE_HISTORY[CURSOR].meta; let start = Math.max(CURSOR, 0); let entries = MESSAGE_HISTORY.slice(start, end + 1).filter( - entry => entry.type === 'messages', + (entry): entry is MessagesMessage => entry.type === 'messages', ); if (entries.length > 0) { @@ -192,7 +202,7 @@ export async function redo() { let end = CURSOR; let entries = MESSAGE_HISTORY.slice(start + 1, end + 1).filter( - entry => entry.type === 'messages', + (entry): entry is MessagesMessage => entry.type === 'messages', ); if (entries.length > 0) { @@ -207,7 +217,7 @@ export async function redo() { } function redoResurrections(messages, oldData) { - let resurrect = new Set(); + let resurrect = new Set<string>(); messages.forEach(message => { // If any of the ids didn't exist before, we need to "resurrect" diff --git a/packages/loot-core/src/server/update.js b/packages/loot-core/src/server/update.ts similarity index 100% rename from packages/loot-core/src/server/update.js rename to packages/loot-core/src/server/update.ts diff --git a/packages/loot-core/src/shared/months.ts b/packages/loot-core/src/shared/months.ts index 5132c0dcc..7a48d7be4 100644 --- a/packages/loot-core/src/shared/months.ts +++ b/packages/loot-core/src/shared/months.ts @@ -85,7 +85,7 @@ export function dayFromDate(date) { export function currentMonth() { if (global.IS_TESTING) { - return '2017-01'; + return global.currentMonth || '2017-01'; } else { return d.format(new Date(), 'yyyy-MM'); } diff --git a/packages/loot-core/src/shared/test-helpers.ts b/packages/loot-core/src/shared/test-helpers.ts index 6c3d499f7..574d92599 100644 --- a/packages/loot-core/src/shared/test-helpers.ts +++ b/packages/loot-core/src/shared/test-helpers.ts @@ -14,7 +14,7 @@ function timeout(promise, n) { ]); } -export function resetTracer(x) { +export function resetTracer() { tracer = execTracer(); } diff --git a/packages/loot-core/src/shared/transactions.test.js b/packages/loot-core/src/shared/transactions.test.ts similarity index 100% rename from packages/loot-core/src/shared/transactions.test.js rename to packages/loot-core/src/shared/transactions.test.ts diff --git a/packages/loot-core/src/types/handlers.d.ts b/packages/loot-core/src/types/handlers.d.ts index e4eb27a09..8ed197b7a 100644 --- a/packages/loot-core/src/types/handlers.d.ts +++ b/packages/loot-core/src/types/handlers.d.ts @@ -5,8 +5,9 @@ import type { SchedulesHandlers } from '../server/schedules/types/handlers'; import type { ApiHandlers } from './api.handlers'; import type { MainHandlers } from './main.handlers'; -export type Handlers = MainHandlers & - ApiHandlers & - BudgetHandlers & - NotesHandlers & - SchedulesHandlers; +export interface Handlers + extends MainHandlers, + ApiHandlers, + BudgetHandlers, + NotesHandlers, + SchedulesHandlers {} diff --git a/packages/loot-core/src/types/main.handlers.d.ts b/packages/loot-core/src/types/main.handlers.d.ts index 51d1065fa..0145d703a 100644 --- a/packages/loot-core/src/types/main.handlers.d.ts +++ b/packages/loot-core/src/types/main.handlers.d.ts @@ -20,15 +20,6 @@ export interface MainHandlers { 'transaction-delete': (transaction) => Promise<Record<string, never>>; - 'transactions-filter': (arg: { - term; - accountId; - latestDate; - count; - notPaged; - options; - }) => Promise<unknown>; - 'transactions-parse-file': (arg: { filepath; options }) => Promise<unknown>; 'transactions-export': (arg: { @@ -130,7 +121,7 @@ export interface MainHandlers { 'create-query': (arg: { sheetName; name; query }) => Promise<unknown>; - query: (query) => Promise<unknown>; + query: (query) => Promise<{ data; dependencies }>; 'bank-delete': (arg: { id }) => Promise<unknown>; diff --git a/packages/loot-core/src/types/models/account.d.ts b/packages/loot-core/src/types/models/account.d.ts new file mode 100644 index 000000000..b00123056 --- /dev/null +++ b/packages/loot-core/src/types/models/account.d.ts @@ -0,0 +1,11 @@ +export interface AccountEntity { + id?: string; + name: string; + type?: string; + offbudget?: boolean; + closed?: boolean; + sort_order?: number; + tombstone?: boolean; + // TODO: remove once properly typed + [k: string]: unknown; +} diff --git a/packages/loot-core/src/types/models/category-group.d.ts b/packages/loot-core/src/types/models/category-group.d.ts new file mode 100644 index 000000000..227dba003 --- /dev/null +++ b/packages/loot-core/src/types/models/category-group.d.ts @@ -0,0 +1,9 @@ +export interface CategoryGroupEntity { + id?: string; + name: string; + is_income?: boolean; + sort_order?: number; + tombstone?: boolean; + // TODO: remove once properly typed + [k: string]: unknown; +} diff --git a/packages/loot-core/src/types/models/category.d.ts b/packages/loot-core/src/types/models/category.d.ts new file mode 100644 index 000000000..b495fe0d0 --- /dev/null +++ b/packages/loot-core/src/types/models/category.d.ts @@ -0,0 +1,10 @@ +import type { CategoryGroupEntity } from './category-group'; + +export interface CategoryEntity { + id?: string; + name: string; + is_income?: boolean; + group: CategoryGroupEntity; + sort_order?: number; + tombstone?: boolean; +} diff --git a/packages/loot-core/src/types/models/index.d.ts b/packages/loot-core/src/types/models/index.d.ts new file mode 100644 index 000000000..4c2ba4496 --- /dev/null +++ b/packages/loot-core/src/types/models/index.d.ts @@ -0,0 +1,6 @@ +export type * from './account'; +export type * from './category'; +export type * from './category-group'; +export type * from './payee'; +export type * from './schedule'; +export type * from './transaction'; diff --git a/packages/loot-core/src/types/models/payee.d.ts b/packages/loot-core/src/types/models/payee.d.ts new file mode 100644 index 000000000..67f14cd30 --- /dev/null +++ b/packages/loot-core/src/types/models/payee.d.ts @@ -0,0 +1,10 @@ +import type { AccountEntity } from './account'; + +export interface PayeeEntity { + id?: string; + name: string; + transfer_acct?: AccountEntity; + tombstone?: boolean; + // TODO: remove once properly typed + [k: string]: unknown; +} diff --git a/packages/loot-core/src/types/models/rule.d.ts b/packages/loot-core/src/types/models/rule.d.ts new file mode 100644 index 000000000..e2991e0cc --- /dev/null +++ b/packages/loot-core/src/types/models/rule.d.ts @@ -0,0 +1,8 @@ +export interface RuleEntity { + id: string; + stage: string; + conditions_op: string; + conditions: unknown; + actions: unknown; + tombstone: boolean; +} diff --git a/packages/loot-core/src/types/models/schedule.d.ts b/packages/loot-core/src/types/models/schedule.d.ts new file mode 100644 index 000000000..f170b736a --- /dev/null +++ b/packages/loot-core/src/types/models/schedule.d.ts @@ -0,0 +1,23 @@ +import type { AccountEntity } from './account'; +import type { PayeeEntity } from './payee'; +import type { RuleEntity } from './rule'; + +export interface ScheduleEntity { + id?: string; + name?: string; + rule: RuleEntity; + next_date: string; + completed: boolean; + posts_transaction: boolean; + tombstone: boolean; + + // These are special fields that are actually pulled from the + // underlying rule + _payee: PayeeEntity; + _account: AccountEntity; + _amount: unknown; + _amountOp: string; + _date: unknown; + _conditions: unknown; + _actions: unknown; +} diff --git a/packages/loot-core/src/types/models/transaction.d.ts b/packages/loot-core/src/types/models/transaction.d.ts new file mode 100644 index 000000000..b5366b8d6 --- /dev/null +++ b/packages/loot-core/src/types/models/transaction.d.ts @@ -0,0 +1,29 @@ +import type { AccountEntity } from './account'; +import type { CategoryEntity } from './category'; +import type { PayeeEntity } from './payee'; +import type { ScheduleEntity } from './schedule'; + +export interface TransactionEntity { + id?: string; + is_parent?: boolean; + is_child?: boolean; + parent_id?: string; + account: AccountEntity; + category?: CategoryEntity; + amount: number; + payee?: PayeeEntity; + notes?: string; + date: string; + imported_id?: string; + error?: unknown; + imported_payee?: string; + starting_balance_flag?: boolean; + transfer_id?: string; + sort_order?: number; + cleared?: boolean; + tombstone?: boolean; + schedule?: ScheduleEntity; + subtransactions?: TransactionEntity[]; + // TODO: remove once properly typed + [k: string]: unknown; +} diff --git a/packages/loot-core/src/types/server-events.d.ts b/packages/loot-core/src/types/server-events.d.ts new file mode 100644 index 000000000..75f5c8db7 --- /dev/null +++ b/packages/loot-core/src/types/server-events.d.ts @@ -0,0 +1,16 @@ +export interface ServerEvents { + 'backups-updated': unknown; + 'cells-changed': Array<{ name }>; + 'fallback-write-error': unknown; + 'finish-import': unknown; + 'finish-load': unknown; + 'orphaned-payees': unknown; + 'prefs-updated': unknown; + 'schedules-offline': { payees: unknown[] }; + 'server-error': unknown; + 'show-budgets': unknown; + 'start-import': unknown; + 'start-load': unknown; + 'sync-event': { type; subtype; meta; tables }; + 'undo-event': unknown; +} diff --git a/packages/loot-core/typings.d.ts b/packages/loot-core/typings/pegjs.d.ts similarity index 100% rename from packages/loot-core/typings.d.ts rename to packages/loot-core/typings/pegjs.d.ts diff --git a/packages/loot-core/typings/window.d.ts b/packages/loot-core/typings/window.d.ts new file mode 100644 index 000000000..fc21a3e45 --- /dev/null +++ b/packages/loot-core/typings/window.d.ts @@ -0,0 +1,16 @@ +export {}; + +declare global { + // eslint-disable-next-line no-unused-vars + interface Window { + Actual?: { + IS_FAKE_WEB: boolean; + ACTUAL_VERSION: string; + }; + + __history?: { + location; + push(url: string, opts?: unknown): void; + }; + } +} diff --git a/packages/loot-core/webpack/webpack.browser.config.js b/packages/loot-core/webpack/webpack.browser.config.js index c30427f3b..e8bc0bdae 100644 --- a/packages/loot-core/webpack/webpack.browser.config.js +++ b/packages/loot-core/webpack/webpack.browser.config.js @@ -5,7 +5,7 @@ let webpack = require('webpack'); /** @type {webpack.Configuration} */ module.exports = { mode: process.env.NODE_ENV === 'development' ? 'development' : 'production', - entry: path.join(__dirname, '../src/server/main.js'), + entry: path.join(__dirname, '../src/server/main.ts'), context: path.resolve(__dirname, '../../..'), devtool: false, output: { diff --git a/upcoming-release-notes/957.md b/upcoming-release-notes/957.md new file mode 100644 index 000000000..8c18f3ef8 --- /dev/null +++ b/upcoming-release-notes/957.md @@ -0,0 +1,6 @@ +--- +category: Maintenance +authors: [albertogasparin] +--- + +Finish converting `loot-core` to Typescript -- GitLab