From cd00da76ef80255d8e4d94c81e71cdbfbff6ffb9 Mon Sep 17 00:00:00 2001 From: Alberto Gasparin Date: Tue, 11 Apr 2023 05:40:40 +1000 Subject: [PATCH] Convert commonjs to esm (#877) This PR converts everything (aside from electron) from CommonJS to ESM. It is needed to reduce the changes that will happen during the migration to Typescript (as TS does not play nice with CJS). Basically: - rewrite `require()` to `import` - rewrite `module.exports` to `exports` - introduce `ts-node` to run importers so we can convert them to TS too Lastly, sorry for this larg-ish PR, not my preference but when I tried to reduce its scope, I would end up with mixed commons/esm that was even more tricky to handle. --- .gitignore | 1 + packages/api/app/query.js | 4 +- packages/api/index.js | 31 +- packages/api/injected.js | 6 +- packages/api/methods.js | 123 +++---- packages/api/package.json | 18 +- packages/api/test.js | 2 +- packages/api/tsconfig.dist.json | 11 + packages/api/utils.js | 6 +- .../accounts/TransactionsTable.test.js | 3 +- packages/desktop-client/src/index.js | 2 +- packages/import-ynab4/importer.js | 16 +- packages/import-ynab4/index.js | 8 +- packages/import-ynab4/package.json | 1 + packages/import-ynab5/importer.js | 8 +- packages/import-ynab5/index.js | 8 +- packages/import-ynab5/package.json | 1 + packages/loot-core/bin/profile-sql.js | 2 +- packages/loot-core/init-node.js | 11 +- packages/loot-core/jest.config.js | 2 +- packages/loot-core/jest.web.config.js | 2 +- .../loot-core/src/client/actions/budgets.js | 11 - .../src/client/actions/notifications.js | 3 +- packages/loot-core/src/mocks/index.js | 3 +- packages/loot-core/src/mocks/plaid.js | 2 +- packages/loot-core/src/mocks/setup.js | 4 +- packages/loot-core/src/mocks/util.js | 4 +- .../client/fetch/__mocks__/index.web.js | 18 +- .../platform/client/fetch/index.browser.js | 19 +- .../src/platform/client/fetch/index.web.js | 17 +- .../src/platform/client/undo/index.web.js | 24 +- .../src/platform/exceptions/index.browser.ts | 10 +- .../src/platform/exceptions/index.d.ts | 3 + .../src/platform/exceptions/index.electron.ts | 10 +- .../src/platform/exceptions/index.testing.ts | 6 +- .../src/platform/exceptions/index.web.ts | 10 +- .../server/asyncStorage/index.electron.js | 42 +-- .../server/asyncStorage/index.testing.js | 34 +- .../platform/server/asyncStorage/index.web.js | 36 +- .../platform/server/connection/index.api.js | 12 +- .../server/connection/index.electron.js | 20 +- .../server/connection/index.testing.js | 18 +- .../platform/server/connection/index.web.js | 18 +- .../platform/server/fetch/index.electron.ts | 14 +- .../platform/server/fetch/index.testing.ts | 10 +- .../src/platform/server/fetch/index.web.ts | 9 +- .../src/platform/server/fs/index.electron.js | 327 +++++++++--------- .../src/platform/server/fs/index.web.js | 108 +++--- .../src/platform/server/fs/index.web.test.js | 11 +- .../src/platform/server/fs/path-join.web.js | 4 +- .../src/platform/server/indexeddb/index.d.ts | 19 +- .../platform/server/indexeddb/index.web.ts | 38 +- .../loot-core/src/platform/uuid/index.d.ts | 3 + .../src/platform/uuid/index.electron.ts | 16 +- .../src/platform/uuid/index.testing.ts | 14 +- .../loot-core/src/platform/uuid/index.web.ts | 16 +- .../loot-core/src/server/__mocks__/post.js | 13 +- .../loot-core/src/server/accounts/link.js | 5 +- .../src/server/accounts/parse-file.js | 2 +- .../loot-core/src/server/accounts/sync.js | 11 +- .../src/server/accounts/sync.test.js | 9 +- .../src/server/accounts/title/index.js | 8 +- .../src/server/accounts/title/lower-case.js | 3 +- .../src/server/accounts/title/specials.js | 2 +- .../src/server/accounts/transactions.js | 3 +- packages/loot-core/src/server/api.js | 3 +- .../loot-core/src/server/aql/exec.test.js | 3 +- packages/loot-core/src/server/backups.js | 11 +- packages/loot-core/src/server/backups.test.js | 4 +- packages/loot-core/src/server/bench.js | 3 +- .../loot-core/src/server/budget/report.js | 3 +- .../loot-core/src/server/budget/rollover.js | 3 +- .../loot-core/src/server/cloud-storage.js | 11 +- .../loot-core/src/server/crdt/timestamp.js | 2 +- packages/loot-core/src/server/db/index.js | 5 +- .../src/server/encryption-internals.js | 2 +- packages/loot-core/src/server/encryption.js | 4 +- packages/loot-core/src/server/main-app.js | 4 +- packages/loot-core/src/server/main.js | 29 +- packages/loot-core/src/server/main.test.js | 12 +- packages/loot-core/src/server/migrate/cli.js | 6 +- .../src/server/migrate/migrations.js | 5 +- packages/loot-core/src/server/post.js | 7 +- packages/loot-core/src/server/prefs.js | 4 +- .../loot-core/src/server/schedules/app.js | 5 +- .../src/server/schedules/find-schedules.js | 3 +- .../loot-core/src/server/server-config.js | 2 +- packages/loot-core/src/server/sheet.js | 3 +- .../src/server/spreadsheet/globals.js | 18 +- .../spreadsheet/graph-data-structure.js | 2 +- .../src/server/spreadsheet/new/vm.test.js | 4 +- .../src/server/spreadsheet/spreadsheet.js | 4 +- .../src/server/spreadsheet/sqlinterp.js | 4 +- .../src/server/spreadsheet/sqlinterp.test.js | 3 +- .../src/server/spreadsheet/tests/graph.js | 6 +- .../loot-core/src/server/spreadsheet/util.js | 15 +- packages/loot-core/src/server/sync/encoder.js | 5 +- packages/loot-core/src/server/sync/index.js | 7 +- .../src/server/sync/make-test-message.js | 2 +- packages/loot-core/src/server/sync/reset.js | 5 +- .../src/server/sync/sync.property.test.js | 6 +- .../loot-core/src/server/sync/sync.test.js | 3 +- .../src/server/tests/mockSyncServer.js | 22 +- packages/loot-core/src/server/undo.js | 3 +- .../loot-core/src/server/util/budget-name.js | 5 +- .../loot-core/src/shared/transactions.test.js | 4 +- packages/loot-core/src/shared/transactions.ts | 4 +- packages/node-libofx/ffi.js | 2 +- packages/node-libofx/index.js | 10 +- tsconfig.json | 7 +- upcoming-release-notes/877.md | 6 + yarn.lock | 5 +- 112 files changed, 708 insertions(+), 813 deletions(-) create mode 100644 packages/api/tsconfig.dist.json create mode 100644 upcoming-release-notes/877.md diff --git a/.gitignore b/.gitignore index bade354f18..66fb303b2f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ /data/* !data/.gitkeep /data2 +packages/api/dist packages/desktop-electron/client-build packages/desktop-electron/.electron-symbols packages/desktop-electron/dist diff --git a/packages/api/app/query.js b/packages/api/app/query.js index 0c0d5f5b08..1ee3b16eca 100644 --- a/packages/api/app/query.js +++ b/packages/api/app/query.js @@ -99,6 +99,6 @@ class Query { } } -module.exports = function q(table) { +export default function q(table) { return new Query({ table }); -}; +} diff --git a/packages/api/index.js b/packages/api/index.js index 140f150600..71f97f69b6 100644 --- a/packages/api/index.js +++ b/packages/api/index.js @@ -1,34 +1,31 @@ -let bundle = require('./app/bundle.api.js'); -let injected = require('./injected'); -let methods = require('./methods'); -let utils = require('./utils'); -let actualApp; +import fetch from 'node-fetch'; -async function init(config = {}) { +import * as bundle from './app/bundle.api'; +import * as injected from './injected'; + +let actualApp; +export const internal = bundle.lib; + +export * as methods from './methods'; +export * as utils from './utils'; + +export async function init(config = {}) { if (actualApp) { return; } - global.fetch = require('node-fetch'); + global.fetch = fetch; await bundle.init(config); actualApp = bundle.lib; - injected.send = bundle.lib.send; + injected.override(bundle.lib.send); return bundle.lib; } -async function shutdown() { +export async function shutdown() { if (actualApp) { await actualApp.send('close-budget'); actualApp = null; } } - -module.exports = { - init, - shutdown, - utils, - internal: bundle.lib, - ...methods, -}; diff --git a/packages/api/injected.js b/packages/api/injected.js index 28bb952351..682ccfd4f0 100644 --- a/packages/api/injected.js +++ b/packages/api/injected.js @@ -1,5 +1,7 @@ // TODO: comment on why it works this way -let send; +export let send; -module.exports = { send }; +export function override(sendImplementation) { + send = sendImplementation; +} diff --git a/packages/api/methods.js b/packages/api/methods.js index 1a01cfce46..ccad98af6c 100644 --- a/packages/api/methods.js +++ b/packages/api/methods.js @@ -1,11 +1,12 @@ -const q = require('./app/query'); -const injected = require('./injected'); +import * as injected from './injected'; + +export { default as q } from './app/query'; function send(name, args) { return injected.send(name, args); } -async function runImport(name, func) { +export async function runImport(name, func) { await send('api/start-import', { budgetName: name }); try { await func(); @@ -16,15 +17,15 @@ async function runImport(name, func) { await send('api/finish-import'); } -async function loadBudget(budgetId) { +export async function loadBudget(budgetId) { return send('api/load-budget', { id: budgetId }); } -async function downloadBudget(syncId, { password } = {}) { +export async function downloadBudget(syncId, { password } = {}) { return send('api/download-budget', { syncId, password }); } -async function batchBudgetUpdates(func) { +export async function batchBudgetUpdates(func) { await send('api/batch-budget-start'); try { await func(); @@ -33,63 +34,63 @@ async function batchBudgetUpdates(func) { } } -function runQuery(query) { +export function runQuery(query) { return send('api/query', { query: query.serialize() }); } -function getBudgetMonths() { +export function getBudgetMonths() { return send('api/budget-months'); } -function getBudgetMonth(month) { +export function getBudgetMonth(month) { return send('api/budget-month', { month }); } -function setBudgetAmount(month, categoryId, value) { +export function setBudgetAmount(month, categoryId, value) { return send('api/budget-set-amount', { month, categoryId, amount: value }); } -function setBudgetCarryover(month, categoryId, flag) { +export function setBudgetCarryover(month, categoryId, flag) { return send('api/budget-set-carryover', { month, categoryId, flag }); } -function addTransactions(accountId, transactions) { +export function addTransactions(accountId, transactions) { return send('api/transactions-add', { accountId, transactions }); } -function importTransactions(accountId, transactions) { +export function importTransactions(accountId, transactions) { return send('api/transactions-import', { accountId, transactions }); } -function getTransactions(accountId, startDate, endDate) { +export function getTransactions(accountId, startDate, endDate) { return send('api/transactions-get', { accountId, startDate, endDate }); } -function filterTransactions(accountId, text) { +export function filterTransactions(accountId, text) { return send('api/transactions-filter', { accountId, text }); } -function updateTransaction(id, fields) { +export function updateTransaction(id, fields) { return send('api/transaction-update', { id, fields }); } -function deleteTransaction(id) { +export function deleteTransaction(id) { return send('api/transaction-delete', { id }); } -function getAccounts() { +export function getAccounts() { return send('api/accounts-get'); } -function createAccount(account, initialBalance) { +export function createAccount(account, initialBalance) { return send('api/account-create', { account, initialBalance }); } -function updateAccount(id, fields) { +export function updateAccount(id, fields) { return send('api/account-update', { id, fields }); } -function closeAccount(id, transferAccountId, transferCategoryId) { +export function closeAccount(id, transferAccountId, transferCategoryId) { return send('api/account-close', { id, transferAccountId, @@ -97,116 +98,70 @@ function closeAccount(id, transferAccountId, transferCategoryId) { }); } -function reopenAccount(id) { +export function reopenAccount(id) { return send('api/account-reopen', { id }); } -function deleteAccount(id) { +export function deleteAccount(id) { return send('api/account-delete', { id }); } -function createCategoryGroup(group) { +export function createCategoryGroup(group) { return send('api/category-group-create', { group }); } -function updateCategoryGroup(id, fields) { +export function updateCategoryGroup(id, fields) { return send('api/category-group-update', { id, fields }); } -function deleteCategoryGroup(id, transferCategoryId) { +export function deleteCategoryGroup(id, transferCategoryId) { return send('api/category-group-delete', { id, transferCategoryId }); } -function getCategories() { +export function getCategories() { return send('api/categories-get', { grouped: false }); } -function createCategory(category) { +export function createCategory(category) { return send('api/category-create', { category }); } -function updateCategory(id, fields) { +export function updateCategory(id, fields) { return send('api/category-update', { id, fields }); } -function deleteCategory(id, transferCategoryId) { +export function deleteCategory(id, transferCategoryId) { return send('api/category-delete', { id, transferCategoryId }); } -function getPayees() { +export function getPayees() { return send('api/payees-get'); } -function createPayee(payee) { +export function createPayee(payee) { return send('api/payee-create', { payee }); } -function updatePayee(id, fields) { +export function updatePayee(id, fields) { return send('api/payee-update', { id, fields }); } -function deletePayee(id) { +export function deletePayee(id) { return send('api/payee-delete', { id }); } -function getPayeeRules(payeeId) { +export function getPayeeRules(payeeId) { return send('api/payee-rules-get', { payeeId }); } -function createPayeeRule(payeeId, rule) { +export function createPayeeRule(payeeId, rule) { return send('api/payee-rule-create', { payee_id: payeeId, rule }); } -function updatePayeeRule(id, fields) { +export function updatePayeeRule(id, fields) { return send('api/payee-rule-update', { id, fields }); } -function deletePayeeRule(id) { +export function deletePayeeRule(id) { return send('api/payee-rule-delete', { id }); } - -module.exports = { - runImport, - - runQuery, - q, - - loadBudget, - downloadBudget, - batchBudgetUpdates, - getBudgetMonths, - getBudgetMonth, - setBudgetAmount, - setBudgetCarryover, - - addTransactions, - importTransactions, - filterTransactions, - getTransactions, - updateTransaction, - deleteTransaction, - - getAccounts, - createAccount, - updateAccount, - closeAccount, - reopenAccount, - deleteAccount, - - getCategories, - createCategoryGroup, - updateCategoryGroup, - deleteCategoryGroup, - createCategory, - updateCategory, - deleteCategory, - - getPayees, - createPayee, - updatePayee, - deletePayee, - getPayeeRules, - createPayeeRule, - deletePayeeRule, - updatePayeeRule, -}; diff --git a/packages/api/package.json b/packages/api/package.json index 5ec80c3378..a9d8dc818b 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -3,23 +3,25 @@ "version": "5.1.2", "license": "MIT", "description": "An API for Actual", - "main": "index.js", + "main": "dist/index.js", + "types": "dist/index.d.ts", "files": [ - "app", + "dist", "default-db.sqlite", - "index.js", - "injected.js", - "methods.js", - "migrations", - "utils.js" + "migrations" ], "scripts": { "lint": "eslint .", - "build": "yarn workspace loot-core build:api" + "build:app": "yarn workspace loot-core build:api", + "build:node": "tsc --p tsconfig.dist.json", + "build": "yarn run build:app && yarn run build:node" }, "dependencies": { "better-sqlite3": "^8.2.0", "node-fetch": "^2.6.9", "uuid": "3.3.2" + }, + "devDependencies": { + "typescript": "^5.0.2" } } diff --git a/packages/api/test.js b/packages/api/test.js index 67963871ea..0a0ee9dd0c 100644 --- a/packages/api/test.js +++ b/packages/api/test.js @@ -1,4 +1,4 @@ -let api = require('./index'); +import * as api from './index'; async function run() { let app = await api.init({ config: { dataDir: '/tmp' } }); diff --git a/packages/api/tsconfig.dist.json b/packages/api/tsconfig.dist.json new file mode 100644 index 0000000000..b8ca13a9ae --- /dev/null +++ b/packages/api/tsconfig.dist.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "target": "es5", + "module": "CommonJS", + "noEmit": false, + "declaration": true, + "outDir": "dist" + }, + "include": ["."] +} diff --git a/packages/api/utils.js b/packages/api/utils.js index b59d259d6c..83ab8db67e 100644 --- a/packages/api/utils.js +++ b/packages/api/utils.js @@ -1,9 +1,7 @@ -function amountToInteger(n) { +export function amountToInteger(n) { return Math.round(n * 100); } -function integerToAmount(n) { +export function integerToAmount(n) { return parseFloat((n / 100).toFixed(2)); } - -module.exports = { amountToInteger, integerToAmount }; diff --git a/packages/desktop-client/src/components/accounts/TransactionsTable.test.js b/packages/desktop-client/src/components/accounts/TransactionsTable.test.js index 9f64b80931..a7e0395061 100644 --- a/packages/desktop-client/src/components/accounts/TransactionsTable.test.js +++ b/packages/desktop-client/src/components/accounts/TransactionsTable.test.js @@ -11,6 +11,7 @@ import { } from 'loot-core/src/mocks'; import { TestProvider } from 'loot-core/src/mocks/redux'; import { initServer } from 'loot-core/src/platform/client/fetch'; +import * as uuid from 'loot-core/src/platform/uuid'; import { addSplitTransaction, realizeTempTransactions, @@ -23,8 +24,6 @@ import { SelectedProviderWithItems } from '../../hooks/useSelected'; import { SplitsExpandedProvider, TransactionTable } from './TransactionsTable'; -const uuid = require('loot-core/src/platform/uuid'); - jest.mock('loot-core/src/platform/client/fetch'); jest.mock('../../hooks/useFeatureFlag', () => jest.fn().mockReturnValue(false)); diff --git a/packages/desktop-client/src/index.js b/packages/desktop-client/src/index.js index d64a511d7d..8c9e9d9369 100644 --- a/packages/desktop-client/src/index.js +++ b/packages/desktop-client/src/index.js @@ -32,7 +32,7 @@ import { handleGlobalEvents } from './global-events'; // See https://github.com/WICG/focus-visible. Only makes the blue // focus outline appear from keyboard events. -require('focus-visible'); +import 'focus-visible'; const appReducer = combineReducers(reducers); function rootReducer(state, action) { diff --git a/packages/import-ynab4/importer.js b/packages/import-ynab4/importer.js index bdb59bfe25..6c53124b15 100644 --- a/packages/import-ynab4/importer.js +++ b/packages/import-ynab4/importer.js @@ -2,12 +2,12 @@ // into Actual itself. We only want to pull in the methods in that // case and ignore everything else; otherwise we'd be pulling in the // entire backend bundle from the API -const actual = require('@actual-app/api/methods'); -const { amountToInteger } = require('@actual-app/api/utils'); -const AdmZip = require('adm-zip'); -const d = require('date-fns'); -const normalizePathSep = require('slash'); -const uuid = require('uuid'); +import * as actual from '@actual-app/api/methods'; +import { amountToInteger } from '@actual-app/api/utils'; +import AdmZip from 'adm-zip'; +import * as d from 'date-fns'; +import normalizePathSep from 'slash'; +import uuid from 'uuid'; // Utils @@ -408,7 +408,7 @@ function join(...paths) { }, paths[0].replace(/\/$/, '')); } -async function importBuffer(filepath, buffer) { +export async function importBuffer(filepath, buffer) { let budgetName = getBudgetName(filepath); if (!budgetName) { @@ -451,5 +451,3 @@ async function importBuffer(filepath, buffer) { return actual.runImport(budgetName, () => doImport(data)); } - -module.exports = { importBuffer }; diff --git a/packages/import-ynab4/index.js b/packages/import-ynab4/index.js index 214f3affb7..9af8154bdf 100755 --- a/packages/import-ynab4/index.js +++ b/packages/import-ynab4/index.js @@ -1,9 +1,9 @@ -#!/usr/bin/env node -const fs = require('fs'); +#!/usr/bin/env ts-node +import * as fs from 'fs'; -const { init, shutdown } = require('@actual-app/api'); +import { init, shutdown } from '@actual-app/api'; -const { importBuffer } = require('./importer'); +import { importBuffer } from './importer'; async function run() { let filepath = process.argv[2]; diff --git a/packages/import-ynab4/package.json b/packages/import-ynab4/package.json index a154569825..1cdea063ff 100644 --- a/packages/import-ynab4/package.json +++ b/packages/import-ynab4/package.json @@ -23,6 +23,7 @@ "adm-zip": "^0.5.9", "date-fns": "^2.29.3", "slash": "3.0.0", + "ts-node": "^10.9.1", "uuid": "3.3.2" } } diff --git a/packages/import-ynab5/importer.js b/packages/import-ynab5/importer.js index 6562d19d66..554bcd51c7 100644 --- a/packages/import-ynab5/importer.js +++ b/packages/import-ynab5/importer.js @@ -2,8 +2,8 @@ // into Actual itself. We only want to pull in the methods in that // case and ignore everything else; otherwise we'd be pulling in the // entire backend bundle from the API -const actual = require('@actual-app/api/methods'); -const uuid = require('uuid'); +import * as actual from '@actual-app/api/methods'; +import uuid from 'uuid'; function amountFromYnab(amount) { // ynabs multiplies amount by 1000 and actual by 100 @@ -318,12 +318,10 @@ async function doImport(data) { console.log('Setting up...'); } -async function importYNAB5(data) { +export async function importYNAB5(data) { if (data.data) { data = data.data; } return actual.runImport(data.budget.name, () => doImport(data.budget)); } - -module.exports = { importYNAB5 }; diff --git a/packages/import-ynab5/index.js b/packages/import-ynab5/index.js index 1b2e9f7204..0cb184ab47 100755 --- a/packages/import-ynab5/index.js +++ b/packages/import-ynab5/index.js @@ -1,9 +1,9 @@ -#!/usr/bin/env node -const fs = require('fs'); +#!/usr/bin/env ts-node +import * as fs from 'fs'; -const { init, shutdown } = require('@actual-app/api'); +import { init, shutdown } from '@actual-app/api'; -const { importYNAB5 } = require('./importer'); +import { importYNAB5 } from './importer'; async function run() { let filepath = process.argv[2]; diff --git a/packages/import-ynab5/package.json b/packages/import-ynab5/package.json index 44b3029955..7896e56fcf 100644 --- a/packages/import-ynab5/package.json +++ b/packages/import-ynab5/package.json @@ -21,6 +21,7 @@ "dependencies": { "@actual-app/api": "*", "date-fns": "^2.29.3", + "ts-node": "^10.9.1", "uuid": "3.3.2" } } diff --git a/packages/loot-core/bin/profile-sql.js b/packages/loot-core/bin/profile-sql.js index 3f3c938ccd..053f354a4c 100755 --- a/packages/loot-core/bin/profile-sql.js +++ b/packages/loot-core/bin/profile-sql.js @@ -2,7 +2,7 @@ import fs from 'fs'; import os from 'os'; -import asyncStorage from '../src/platform/server/asyncStorage'; +import * as asyncStorage from '../src/platform/server/asyncStorage'; import * as sqlite from '../src/platform/server/sqlite'; import { runQuery } from '../src/server/aql'; import * as db from '../src/server/db'; diff --git a/packages/loot-core/init-node.js b/packages/loot-core/init-node.js index d45c597450..36b75e2126 100644 --- a/packages/loot-core/init-node.js +++ b/packages/loot-core/init-node.js @@ -1,8 +1,11 @@ -let { dirname, basename } = require('path'); +import { dirname, basename } from 'path'; -require('source-map-support').install(); -global.fetch = require('node-fetch'); -let bundle = require('./lib-dist/bundle.desktop.js'); +import fetch from 'node-fetch'; +import 'source-map-support/register'; + +import bundle from './lib-dist/bundle.desktop'; + +global.fetch = fetch; async function init(budgetPath) { let dir = dirname(budgetPath); diff --git a/packages/loot-core/jest.config.js b/packages/loot-core/jest.config.js index f28baba230..9078246af7 100644 --- a/packages/loot-core/jest.config.js +++ b/packages/loot-core/jest.config.js @@ -18,7 +18,7 @@ module.exports = { '/lib/', '.+/index\\.web\\.test\\.(js|ts|tsx)', ], - transformIgnorePatterns: ['/node_modules/', '__mocks__'], + transformIgnorePatterns: ['/node_modules/'], transform: { '\\.pegjs$': 'pegjs-jest-transformer', }, diff --git a/packages/loot-core/jest.web.config.js b/packages/loot-core/jest.web.config.js index 658a61021e..c974dab2b2 100644 --- a/packages/loot-core/jest.web.config.js +++ b/packages/loot-core/jest.web.config.js @@ -15,7 +15,7 @@ module.exports = { testEnvironment: 'jsdom', testPathIgnorePatterns: ['/node_modules/', '/lib/'].filter(Boolean), testMatch: ['**/*.web.test.(js|ts|tsx)'], - transformIgnorePatterns: ['__mocks__', '/node_modules/(?!absurd-sql)'], + transformIgnorePatterns: ['/node_modules/(?!absurd-sql)'], transform: { '\\.pegjs$': 'pegjs-jest-transformer', }, diff --git a/packages/loot-core/src/client/actions/budgets.js b/packages/loot-core/src/client/actions/budgets.js index 24a7671d21..8684e3cf42 100644 --- a/packages/loot-core/src/client/actions/budgets.js +++ b/packages/loot-core/src/client/actions/budgets.js @@ -239,14 +239,3 @@ export function downloadBudget(cloudFileId, { replace } = {}) { return id; }; } - -export function getYNAB4Imports() { - return async dispatch => { - let imports = await send('get-ynab4-files'); - dispatch({ - type: 'SET_AVAILABLE_IMPORTS', - imports, - }); - return imports; - }; -} diff --git a/packages/loot-core/src/client/actions/notifications.js b/packages/loot-core/src/client/actions/notifications.js index 9bd8be621f..7cc0ca1eb6 100644 --- a/packages/loot-core/src/client/actions/notifications.js +++ b/packages/loot-core/src/client/actions/notifications.js @@ -1,7 +1,6 @@ +import * as uuid from '../../platform/uuid'; import * as constants from '../constants'; -const uuid = require('../../platform/uuid'); - export function addNotification(notification) { return { type: constants.ADD_NOTIFICATION, diff --git a/packages/loot-core/src/mocks/index.js b/packages/loot-core/src/mocks/index.js index fc3b126626..b61a8a3b4f 100644 --- a/packages/loot-core/src/mocks/index.js +++ b/packages/loot-core/src/mocks/index.js @@ -1,7 +1,6 @@ +import * as uuid from '../platform/uuid'; import * as monthUtils from '../shared/months'; -const uuid = require('../platform/uuid'); - export function generateAccount(name, isConnected, type, offbudget) { return { id: uuid.v4Sync(), diff --git a/packages/loot-core/src/mocks/plaid.js b/packages/loot-core/src/mocks/plaid.js index d582060bc1..2e783d1852 100644 --- a/packages/loot-core/src/mocks/plaid.js +++ b/packages/loot-core/src/mocks/plaid.js @@ -1,4 +1,4 @@ -const uuid = require('../platform/uuid'); +import * as uuid from '../platform/uuid'; export function generateAccount(balance) { return { diff --git a/packages/loot-core/src/mocks/setup.js b/packages/loot-core/src/mocks/setup.js index 898ff7e0a6..1a415914c0 100644 --- a/packages/loot-core/src/mocks/setup.js +++ b/packages/loot-core/src/mocks/setup.js @@ -1,3 +1,5 @@ +import * as nativeFs from 'fs'; + import * as fetchClient from '../platform/client/fetch'; import * as sqlite from '../platform/server/sqlite'; import * as rules from '../server/accounts/transaction-rules'; @@ -14,8 +16,6 @@ import { resetTracer, tracer } from '../shared/test-helpers'; jest.mock('../server/post'); -const nativeFs = require('fs'); - // By default, syncing is disabled setSyncingMode('disabled'); diff --git a/packages/loot-core/src/mocks/util.js b/packages/loot-core/src/mocks/util.js index 32c2952b7f..6128df60af 100644 --- a/packages/loot-core/src/mocks/util.js +++ b/packages/loot-core/src/mocks/util.js @@ -1,6 +1,6 @@ -const { join, dirname, basename } = require('path'); +import { join, dirname, basename } from 'path'; -const snapshotDiff = require('snapshot-diff'); +import snapshotDiff from 'snapshot-diff'; export function expectSnapshotWithDiffer(initialValue, { onlyUpdates } = {}) { let currentValue = initialValue; diff --git a/packages/loot-core/src/platform/client/fetch/__mocks__/index.web.js b/packages/loot-core/src/platform/client/fetch/__mocks__/index.web.js index 42b287a8c1..abc33cf50c 100644 --- a/packages/loot-core/src/platform/client/fetch/__mocks__/index.web.js +++ b/packages/loot-core/src/platform/client/fetch/__mocks__/index.web.js @@ -1,7 +1,7 @@ let listeners = new Map(); let serverHandler = null; -module.exports.initServer = handlers => { +export const initServer = handlers => { serverHandler = msg => { let { name, args, catchErrors } = msg; if (handlers[name]) { @@ -20,12 +20,12 @@ module.exports.initServer = handlers => { }; }; -module.exports.clearServer = () => { +export const clearServer = () => { serverHandler = null; listeners = new Map(); }; -module.exports.serverPush = (name, args) => { +export const serverPush = (name, args) => { Promise.resolve().then(() => { const listens = listeners.get(name); if (listens) { @@ -36,11 +36,7 @@ module.exports.serverPush = (name, args) => { }); }; -module.exports.send = async function ( - name, - args, - { catchErrors = false } = {}, -) { +export const send = async function (name, args, { catchErrors = false } = {}) { if (serverHandler) { return serverHandler({ name, args, catchErrors }); } else { @@ -48,11 +44,11 @@ module.exports.send = async function ( } }; -module.exports.sendCatch = function send(name, args) { - return module.exports.send(name, args, { catchErrors: true }); +export const sendCatch = function send(name, args) { + return send(name, args, { catchErrors: true }); }; -module.exports.listen = function listen(name, cb) { +export const listen = function listen(name, cb) { if (!listeners.get(name)) { listeners.set(name, []); } diff --git a/packages/loot-core/src/platform/client/fetch/index.browser.js b/packages/loot-core/src/platform/client/fetch/index.browser.js index 751ebede25..8db30f08c6 100644 --- a/packages/loot-core/src/platform/client/fetch/index.browser.js +++ b/packages/loot-core/src/platform/client/fetch/index.browser.js @@ -1,6 +1,7 @@ -const { captureException, captureBreadcrumb } = require('../../exceptions'); -const uuid = require('../../uuid'); -const undo = require('../undo'); +import { captureException, captureBreadcrumb } from '../../exceptions'; +import * as uuid from '../../uuid'; +import * as undo from '../undo'; + let replyHandlers = new Map(); let listeners = new Map(); let messageQueue = []; @@ -128,13 +129,13 @@ function connectWorker(worker, onOpen, onError) { } } -module.exports.init = async function init(worker) { +export const init = async function (worker) { return new Promise((resolve, reject) => connectWorker(worker, resolve, reject), ); }; -module.exports.send = function send(name, args, { catchErrors = false } = {}) { +export const send = function (name, args, { catchErrors = false } = {}) { return new Promise((resolve, reject) => { uuid.v4().then(id => { replyHandlers.set(id, { resolve, reject }); @@ -154,11 +155,11 @@ module.exports.send = function send(name, args, { catchErrors = false } = {}) { }); }; -module.exports.sendCatch = function send(name, args) { - return module.exports.send(name, args, { catchErrors: true }); +export const sendCatch = function (name, args) { + return send(name, args, { catchErrors: true }); }; -module.exports.listen = function listen(name, cb) { +export const listen = function (name, cb) { if (!listeners.get(name)) { listeners.set(name, []); } @@ -173,6 +174,6 @@ module.exports.listen = function listen(name, cb) { }; }; -module.exports.unlisten = function unlisten(name) { +export const unlisten = function (name) { listeners.set(name, []); }; diff --git a/packages/loot-core/src/platform/client/fetch/index.web.js b/packages/loot-core/src/platform/client/fetch/index.web.js index 4790ae4715..50b02f12e1 100644 --- a/packages/loot-core/src/platform/client/fetch/index.web.js +++ b/packages/loot-core/src/platform/client/fetch/index.web.js @@ -1,5 +1,6 @@ -const uuid = require('../../uuid'); -const undo = require('../undo'); +import * as uuid from '../../uuid'; +import * as undo from '../undo'; + let replyHandlers = new Map(); let listeners = new Map(); let messageQueue = []; @@ -74,11 +75,11 @@ function connectSocket(name, onOpen) { }); } -module.exports.init = async function init(socketName) { +export const init = async function (socketName) { return new Promise(resolve => connectSocket(socketName, resolve)); }; -module.exports.send = function send(name, args, { catchErrors = false } = {}) { +export const send = function (name, args, { catchErrors = false } = {}) { return new Promise((resolve, reject) => { uuid.v4().then(id => { replyHandlers.set(id, { resolve, reject }); @@ -104,11 +105,11 @@ module.exports.send = function send(name, args, { catchErrors = false } = {}) { }); }; -module.exports.sendCatch = function sendCatch(name, args) { - return module.exports.send(name, args, { catchErrors: true }); +export const sendCatch = function (name, args) { + return send(name, args, { catchErrors: true }); }; -module.exports.listen = function listen(name, cb) { +export const listen = function (name, cb) { if (!listeners.get(name)) { listeners.set(name, []); } @@ -125,6 +126,6 @@ module.exports.listen = function listen(name, cb) { }; }; -module.exports.unlisten = function unlisten(name) { +export const unlisten = function (name) { listeners.set(name, []); }; diff --git a/packages/loot-core/src/platform/client/undo/index.web.js b/packages/loot-core/src/platform/client/undo/index.web.js index 580c1cecb8..fcfa0a2fc0 100644 --- a/packages/loot-core/src/platform/client/undo/index.web.js +++ b/packages/loot-core/src/platform/client/undo/index.web.js @@ -1,4 +1,4 @@ -const uuid = require('../../uuid'); +import * as uuid from '../../uuid'; // 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. @@ -11,28 +11,26 @@ let currentUndoState = { selectedItems: null, }; -function setUndoState(name, value) { +export const setUndoState = function (name, value) { currentUndoState[name] = value; currentUndoState.id = uuid.v4Sync(); -} +}; -function getUndoState(name) { +export const getUndoState = function (name) { return currentUndoState[name]; -} +}; -function getTaggedState(id) { +export const getTaggedState = function (id) { return UNDO_STATE_MRU.find(state => state.id === id); -} +}; -function snapshot() { +export const snapshot = function () { let tagged = { ...currentUndoState, id: uuid.v4Sync() }; UNDO_STATE_MRU.unshift(tagged); UNDO_STATE_MRU = UNDO_STATE_MRU.slice(0, HISTORY_SIZE); return tagged.id; -} +}; -function gc(id) { +export const gc = function (id) { UNDO_STATE_MRU = UNDO_STATE_MRU.filter(state => state.id !== id); -} - -module.exports = { setUndoState, getUndoState, getTaggedState, snapshot, gc }; +}; diff --git a/packages/loot-core/src/platform/exceptions/index.browser.ts b/packages/loot-core/src/platform/exceptions/index.browser.ts index 3be4481c99..56ccc5c37b 100644 --- a/packages/loot-core/src/platform/exceptions/index.browser.ts +++ b/packages/loot-core/src/platform/exceptions/index.browser.ts @@ -1,5 +1,7 @@ -export function captureException(exc) { - console.log('[Exception]', exc); -} +import type * as T from '.'; -export function captureBreadcrumb(breadcrumb) {} +export const captureException: T.CaptureException = function (exc) { + console.log('[Exception]', exc); +}; + +export const captureBreadcrumb: T.CaptureBreadcrumb = function (breadcrumb) {}; diff --git a/packages/loot-core/src/platform/exceptions/index.d.ts b/packages/loot-core/src/platform/exceptions/index.d.ts index 56aad41fa9..11568b754b 100644 --- a/packages/loot-core/src/platform/exceptions/index.d.ts +++ b/packages/loot-core/src/platform/exceptions/index.d.ts @@ -1,2 +1,5 @@ export function captureException(exc: Error): void; +export type CaptureException = typeof captureException; + export function captureBreadcrumb(breadcrumb: unknown): void; +export type CaptureBreadcrumb = typeof captureBreadcrumb; diff --git a/packages/loot-core/src/platform/exceptions/index.electron.ts b/packages/loot-core/src/platform/exceptions/index.electron.ts index 3be4481c99..56ccc5c37b 100644 --- a/packages/loot-core/src/platform/exceptions/index.electron.ts +++ b/packages/loot-core/src/platform/exceptions/index.electron.ts @@ -1,5 +1,7 @@ -export function captureException(exc) { - console.log('[Exception]', exc); -} +import type * as T from '.'; -export function captureBreadcrumb(breadcrumb) {} +export const captureException: T.CaptureException = function (exc) { + console.log('[Exception]', exc); +}; + +export const captureBreadcrumb: T.CaptureBreadcrumb = function (breadcrumb) {}; diff --git a/packages/loot-core/src/platform/exceptions/index.testing.ts b/packages/loot-core/src/platform/exceptions/index.testing.ts index cc1a66bfac..988d67f826 100644 --- a/packages/loot-core/src/platform/exceptions/index.testing.ts +++ b/packages/loot-core/src/platform/exceptions/index.testing.ts @@ -1,3 +1,5 @@ -export function captureException(exc) {} +import type * as T from '.'; -export function captureBreadcrumb(info) {} +export const captureException: T.CaptureException = function (exc) {}; + +export const captureBreadcrumb: T.CaptureBreadcrumb = function (info) {}; diff --git a/packages/loot-core/src/platform/exceptions/index.web.ts b/packages/loot-core/src/platform/exceptions/index.web.ts index 3be4481c99..56ccc5c37b 100644 --- a/packages/loot-core/src/platform/exceptions/index.web.ts +++ b/packages/loot-core/src/platform/exceptions/index.web.ts @@ -1,5 +1,7 @@ -export function captureException(exc) { - console.log('[Exception]', exc); -} +import type * as T from '.'; -export function captureBreadcrumb(breadcrumb) {} +export const captureException: T.CaptureException = function (exc) { + console.log('[Exception]', exc); +}; + +export const captureBreadcrumb: T.CaptureBreadcrumb = function (breadcrumb) {}; diff --git a/packages/loot-core/src/platform/server/asyncStorage/index.electron.js b/packages/loot-core/src/platform/server/asyncStorage/index.electron.js index 4062fc654d..1bad6db607 100644 --- a/packages/loot-core/src/platform/server/asyncStorage/index.electron.js +++ b/packages/loot-core/src/platform/server/asyncStorage/index.electron.js @@ -1,13 +1,13 @@ -const fs = require('fs'); -const { join } = require('path'); +import * as fs from 'fs'; +import { join } from 'path'; -const lootFs = require('../fs'); +import * as lootFs from '../fs'; let getStorePath = () => join(lootFs.getDataDir(), 'global-store.json'); let store; let persisted = true; -function init({ persist = true } = {}) { +export const init = function ({ persist = true } = {}) { if (persist) { try { store = JSON.parse(fs.readFileSync(getStorePath(), 'utf8')); @@ -19,7 +19,7 @@ function init({ persist = true } = {}) { } persisted = persist; -} +}; function _saveStore() { if (persisted) { @@ -36,23 +36,23 @@ function _saveStore() { } } -function getItem(key) { +export const getItem = function (key) { return new Promise(function (resolve) { return resolve(store[key]); }); -} +}; -function setItem(key, value) { +export const setItem = function (key, value) { store[key] = value; return _saveStore(); -} +}; -function removeItem(key) { +export const removeItem = function (key) { delete store[key]; return _saveStore(); -} +}; -function multiGet(keys) { +export const multiGet = function (keys) { return new Promise(function (resolve) { return resolve( keys.map(function (key) { @@ -60,28 +60,18 @@ function multiGet(keys) { }), ); }); -} +}; -function multiSet(keyValues) { +export const multiSet = function (keyValues) { keyValues.forEach(function ([key, value]) { store[key] = value; }); return _saveStore(); -} +}; -function multiRemove(keys) { +export const multiRemove = function (keys) { keys.forEach(function (key) { delete store[key]; }); return _saveStore(); -} - -module.exports = { - init, - getItem, - setItem, - removeItem, - multiGet, - multiSet, - multiRemove, }; diff --git a/packages/loot-core/src/platform/server/asyncStorage/index.testing.js b/packages/loot-core/src/platform/server/asyncStorage/index.testing.js index ec1a75924c..34f5182fa0 100644 --- a/packages/loot-core/src/platform/server/asyncStorage/index.testing.js +++ b/packages/loot-core/src/platform/server/asyncStorage/index.testing.js @@ -1,22 +1,22 @@ const store = {}; -function init() {} +export const init = function () {}; -function getItem(key) { +export const getItem = function (key) { return new Promise(function (resolve) { return resolve(store[key]); }); -} +}; -function setItem(key, value) { +export const setItem = function (key, value) { store[key] = value; -} +}; -function removeItem(key) { +export const removeItem = function (key) { delete store[key]; -} +}; -function multiGet(keys) { +export const multiGet = function (keys) { return new Promise(function (resolve) { return resolve( keys.map(function (key) { @@ -24,26 +24,16 @@ function multiGet(keys) { }), ); }); -} +}; -function multiSet(keyValues) { +export const multiSet = function (keyValues) { keyValues.forEach(function ([key, value]) { store[key] = value; }); -} +}; -function multiRemove(keys) { +export const multiRemove = function (keys) { keys.forEach(function (key) { delete store[key]; }); -} - -module.exports = { - init, - getItem, - setItem, - removeItem, - multiGet, - multiSet, - multiRemove, }; diff --git a/packages/loot-core/src/platform/server/asyncStorage/index.web.js b/packages/loot-core/src/platform/server/asyncStorage/index.web.js index 09835319bb..c24bf20341 100644 --- a/packages/loot-core/src/platform/server/asyncStorage/index.web.js +++ b/packages/loot-core/src/platform/server/asyncStorage/index.web.js @@ -1,6 +1,6 @@ -let { getDatabase } = require('../indexeddb'); +import { getDatabase } from '../indexeddb'; -function init() {} +export const init = function () {}; function commit(trans) { if (trans.commit) { @@ -8,7 +8,7 @@ function commit(trans) { } } -async function getItem(key) { +export const getItem = async function (key) { let db = await getDatabase(); let transaction = db.transaction(['asyncStorage'], 'readonly'); @@ -20,9 +20,9 @@ async function getItem(key) { req.onsuccess = e => resolve(e.target.result); commit(transaction); }); -} +}; -async function setItem(key, value) { +export const setItem = async function (key, value) { let db = await getDatabase(); let transaction = db.transaction(['asyncStorage'], 'readwrite'); @@ -34,9 +34,9 @@ async function setItem(key, value) { req.onsuccess = e => resolve(); commit(transaction); }); -} +}; -async function removeItem(key) { +export const removeItem = async function (key) { let db = await getDatabase(); let transaction = db.transaction(['asyncStorage'], 'readwrite'); @@ -48,9 +48,9 @@ async function removeItem(key) { req.onsuccess = e => resolve(); commit(transaction); }); -} +}; -async function multiGet(keys) { +export const multiGet = async function (keys) { let db = await getDatabase(); let transaction = db.transaction(['asyncStorage'], 'readonly'); @@ -68,9 +68,9 @@ async function multiGet(keys) { commit(transaction); return promise; -} +}; -async function multiSet(keyValues) { +export const multiSet = async function (keyValues) { let db = await getDatabase(); let transaction = db.transaction(['asyncStorage'], 'readwrite'); @@ -88,9 +88,9 @@ async function multiSet(keyValues) { commit(transaction); return promise; -} +}; -async function multiRemove(keys) { +export const multiRemove = async function (keys) { let db = await getDatabase(); let transaction = db.transaction(['asyncStorage'], 'readwrite'); @@ -108,14 +108,4 @@ async function multiRemove(keys) { commit(transaction); return promise; -} - -module.exports = { - init, - getItem, - setItem, - removeItem, - multiGet, - multiSet, - multiRemove, }; diff --git a/packages/loot-core/src/platform/server/connection/index.api.js b/packages/loot-core/src/platform/server/connection/index.api.js index e457e8fc6f..c54e64c608 100644 --- a/packages/loot-core/src/platform/server/connection/index.api.js +++ b/packages/loot-core/src/platform/server/connection/index.api.js @@ -1,11 +1,9 @@ -function init() {} +export const init = function () {}; -function send(type, args) { +export const send = function (type, args) { // Nothing -} +}; -function getNumClients() { +export const getNumClients = function () { return 1; -} - -module.exports = { init, send, getNumClients }; +}; diff --git a/packages/loot-core/src/platform/server/connection/index.electron.js b/packages/loot-core/src/platform/server/connection/index.electron.js index 4683888fcc..87c62d7fac 100644 --- a/packages/loot-core/src/platform/server/connection/index.electron.js +++ b/packages/loot-core/src/platform/server/connection/index.electron.js @@ -1,7 +1,7 @@ -const ipc = require('node-ipc'); +import ipc from 'node-ipc'; -const { runHandler, isMutating } = require('../../../server/mutators'); -const { captureException } = require('../../exceptions'); +import { runHandler, isMutating } from '../../../server/mutators'; +import { captureException } from '../../exceptions'; function coerceError(error) { if (error.type && error.type === 'APIError') { @@ -11,7 +11,7 @@ function coerceError(error) { return { type: 'InternalError', message: error.message }; } -function init(socketName, handlers) { +export const init = function (socketName, handlers) { ipc.config.id = socketName; ipc.config.silent = true; @@ -79,16 +79,14 @@ function init(socketName, handlers) { }); ipc.server.start(); -} +}; -function getNumClients() { +export const getNumClients = function () { return ipc.server.sockets.length; -} +}; -function send(name, args) { +export const send = function (name, args) { if (ipc.server) { ipc.server.broadcast('message', { type: 'push', name, args }); } -} - -module.exports = { init, send, getNumClients }; +}; diff --git a/packages/loot-core/src/platform/server/connection/index.testing.js b/packages/loot-core/src/platform/server/connection/index.testing.js index 8bd8ac31c0..4582be3649 100644 --- a/packages/loot-core/src/platform/server/connection/index.testing.js +++ b/packages/loot-core/src/platform/server/connection/index.testing.js @@ -1,13 +1,15 @@ -function init() {} - let events = []; -function send(type, args) { +export const init = function () {}; + +export const send = function (type, args) { events.push([type, args]); -} +}; -function resetEvents() { +export const getEvents = function () { + return events; +}; + +export const resetEvents = function () { events = []; -} - -module.exports = { init, send, resetEvents, getEvents: () => events }; +}; diff --git a/packages/loot-core/src/platform/server/connection/index.web.js b/packages/loot-core/src/platform/server/connection/index.web.js index 8c9b4f658d..7b084970cb 100644 --- a/packages/loot-core/src/platform/server/connection/index.web.js +++ b/packages/loot-core/src/platform/server/connection/index.web.js @@ -1,5 +1,5 @@ -const { runHandler, isMutating } = require('../../../server/mutators'); -const { captureException } = require('../../exceptions'); +import { runHandler, isMutating } from '../../../server/mutators'; +import { captureException } from '../../exceptions'; function getGlobalObject() { let obj = @@ -24,7 +24,7 @@ function coerceError(error) { return { type: 'InternalError', message: error.message }; } -function init(serverChannel, handlers) { +export const init = function (serverChannel, handlers) { getGlobalObject().__globalServerChannel = serverChannel; serverChannel.addEventListener( @@ -96,9 +96,9 @@ function init(serverChannel, handlers) { ); serverChannel.postMessage({ type: 'connect' }); -} +}; -function send(name, args) { +export const send = function (name, args) { if (getGlobalObject().__globalServerChannel) { getGlobalObject().__globalServerChannel.postMessage({ type: 'push', @@ -106,10 +106,8 @@ function send(name, args) { args, }); } -} +}; -function getNumClients() { +export const getNumClients = function () { return 1; -} - -module.exports = { init, send, getNumClients }; +}; diff --git a/packages/loot-core/src/platform/server/fetch/index.electron.ts b/packages/loot-core/src/platform/server/fetch/index.electron.ts index 4374bab0af..18960a84dd 100644 --- a/packages/loot-core/src/platform/server/fetch/index.electron.ts +++ b/packages/loot-core/src/platform/server/fetch/index.electron.ts @@ -1,9 +1,11 @@ -let fs = require('fs'); +import * as fs from 'fs'; -const _fetch = require('node-fetch'); +import fetch from 'node-fetch'; -async function _fetchBinary(url, filepath) { - const res = await _fetch(url); +export { fetch }; + +export const fetchBinary = async function (url, filepath) { + const res = await fetch(url); return new Promise((resolve, reject) => { const fileStream = fs.createWriteStream(filepath); res.body.pipe(fileStream); @@ -14,6 +16,4 @@ async function _fetchBinary(url, filepath) { resolve(undefined); }); }); -} - -module.exports = { fetch: _fetch, fetchBinary: _fetchBinary }; +}; diff --git a/packages/loot-core/src/platform/server/fetch/index.testing.ts b/packages/loot-core/src/platform/server/fetch/index.testing.ts index e8fdd8d2c4..8b20f1c781 100644 --- a/packages/loot-core/src/platform/server/fetch/index.testing.ts +++ b/packages/loot-core/src/platform/server/fetch/index.testing.ts @@ -1,9 +1,7 @@ -function fetch() { +export const fetch = function () { throw new Error('fetch not implemented'); -} +}; -function fetchBinary() { +export const fetchBinary = function () { throw new Error('fetchBinary not implemented'); -} - -module.exports = { fetch, fetchBinary }; +}; diff --git a/packages/loot-core/src/platform/server/fetch/index.web.ts b/packages/loot-core/src/platform/server/fetch/index.web.ts index f5061330ec..82442d8469 100644 --- a/packages/loot-core/src/platform/server/fetch/index.web.ts +++ b/packages/loot-core/src/platform/server/fetch/index.web.ts @@ -1,6 +1,5 @@ -module.exports = { - fetch: self.fetch, - fetchBinary: () => { - throw new Error('fetchBinary not implemented'); - }, +export const fetch = self.fetch; + +export const fetchBinary = function () { + throw new Error('fetchBinary not implemented'); }; diff --git a/packages/loot-core/src/platform/server/fs/index.electron.js b/packages/loot-core/src/platform/server/fs/index.electron.js index d78e0dd82e..7a9340579e 100644 --- a/packages/loot-core/src/platform/server/fs/index.electron.js +++ b/packages/loot-core/src/platform/server/fs/index.electron.js @@ -1,5 +1,5 @@ -const fs = require('fs'); -const path = require('path'); +import * as fs from 'fs'; +import * as path from 'path'; let documentDir; @@ -11,157 +11,174 @@ if (__filename.match('bundle')) { rootPath = path.join(__dirname, '..'); } -module.exports = { - init: () => { - // Nothing to do - }, - getDataDir: () => { - if (!process.env.ACTUAL_DATA_DIR) { - throw new Error('ACTUAL_DATA_DIR env variable is required'); - } - return process.env.ACTUAL_DATA_DIR; - }, - _setDocumentDir: dir => (documentDir = dir), - getDocumentDir: () => { - if (!documentDir) { - throw new Error('Document directory is not set'); - } - return documentDir; - }, - getBudgetDir: id => { - if (!id) { - throw new Error('getDocumentDir: id is falsy: ' + id); - } - - // TODO: This should be better - // - // A cheesy safe guard. The id is generated from the budget name, - // so it provides an entry point for the user to accidentally (or - // intentionally) access other parts of the system. Always - // restrict it to only access files within the budget directory by - // never allowing slashes. - if (id.match(/[^A-Za-z0-9\-_]/)) { - throw new Error( - `Invalid budget id “${id}”. Check the id of your budget in the Advanced section of the settings page.`, - ); - } - - return path.join(module.exports.getDocumentDir(), id); - }, - bundledDatabasePath: path.join(rootPath, 'default-db.sqlite'), - migrationsPath: path.join(rootPath, 'migrations'), - demoBudgetPath: path.join(rootPath, 'demo-budget'), - join: path.join, - basename: filepath => path.basename(filepath), - listDir: filepath => - new Promise((resolve, reject) => { - fs.readdir(filepath, (err, files) => { - if (err) { - reject(err); - } else { - resolve(files); - } - }); - }), - exists: filepath => - new Promise(resolve => { - fs.access(filepath, fs.constants.F_OK, err => { - return resolve(!err); - }); - }), - mkdir: filepath => - new Promise((resolve, reject) => { - fs.mkdir(filepath, err => { - if (err) { - reject(err); - } else { - resolve(); - } - }); - }), - size: filepath => - new Promise((resolve, reject) => { - fs.stat(filepath, (err, stats) => { - if (err) { - reject(err); - } else { - resolve(stats.size); - } - }); - }), - copyFile: (frompath, topath) => { - return new Promise((resolve, reject) => { - const readStream = fs.createReadStream(frompath); - const writeStream = fs.createWriteStream(topath); - - readStream.on('error', reject); - writeStream.on('error', reject); - - writeStream.on('open', () => readStream.pipe(writeStream)); - writeStream.once('close', resolve); - }); - }, - readFile: (filepath, encoding = '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) => { - fs.readFile(filepath, encoding, (err, data) => { - if (err) { - reject(err); - } else { - resolve(data); - } - }); - }); - }, - writeFile: (filepath, contents) => { - return new Promise(function (resolve, reject) { - fs.writeFile(filepath, contents, 'utf8', function (err, _) { - return err ? reject(err) : resolve(); - }); - }); - }, - removeFile: filepath => { - return new Promise(function (resolve, reject) { - fs.unlink(filepath, err => { - return err ? reject(err) : resolve(); - }); - }); - }, - removeDir: dirpath => { - return new Promise(function (resolve, reject) { - fs.rmdir(dirpath, err => { - return err ? reject(err) : resolve(); - }); - }); - }, - removeDirRecursively: async dirpath => { - const f = module.exports; - if (await f.exists(dirpath)) { - for (let file of await f.listDir(dirpath)) { - const fullpath = f.join(dirpath, file); - if (fs.statSync(fullpath).isDirectory()) { - await f.removeDirRecursively(fullpath); - } else { - await f.removeFile(fullpath); - } - } - - await f.removeDir(dirpath); - } - }, - getModifiedTime: filepath => { - return new Promise(function (resolve, reject) { - fs.stat(filepath, (err, stats) => { - if (err) { - reject(err); - } else { - resolve(new Date(stats.mtime)); - } - }); - }); - }, +export const init = () => { + // Nothing to do +}; + +export const getDataDir = () => { + if (!process.env.ACTUAL_DATA_DIR) { + throw new Error('ACTUAL_DATA_DIR env variable is required'); + } + return process.env.ACTUAL_DATA_DIR; +}; + +export const _setDocumentDir = dir => (documentDir = dir); + +export const getDocumentDir = () => { + if (!documentDir) { + throw new Error('Document directory is not set'); + } + return documentDir; +}; + +export const getBudgetDir = id => { + if (!id) { + throw new Error('getDocumentDir: id is falsy: ' + id); + } + + // TODO: This should be better + // + // A cheesy safe guard. The id is generated from the budget name, + // so it provides an entry point for the user to accidentally (or + // intentionally) access other parts of the system. Always + // restrict it to only access files within the budget directory by + // never allowing slashes. + if (id.match(/[^A-Za-z0-9\-_]/)) { + throw new Error( + `Invalid budget id “${id}”. Check the id of your budget in the Advanced section of the settings page.`, + ); + } + + return path.join(getDocumentDir(), id); +}; + +export const bundledDatabasePath = path.join(rootPath, 'default-db.sqlite'); + +export const migrationsPath = path.join(rootPath, 'migrations'); + +export const demoBudgetPath = path.join(rootPath, 'demo-budget'); + +export const join = path.join; + +export const basename = filepath => path.basename(filepath); + +export const listDir = filepath => + new Promise((resolve, reject) => { + fs.readdir(filepath, (err, files) => { + if (err) { + reject(err); + } else { + resolve(files); + } + }); + }); + +export const exists = filepath => + new Promise(resolve => { + fs.access(filepath, fs.constants.F_OK, err => { + return resolve(!err); + }); + }); + +export const mkdir = filepath => + new Promise((resolve, reject) => { + fs.mkdir(filepath, err => { + if (err) { + reject(err); + } else { + resolve(); + } + }); + }); + +export const size = filepath => + new Promise((resolve, reject) => { + fs.stat(filepath, (err, stats) => { + if (err) { + reject(err); + } else { + resolve(stats.size); + } + }); + }); + +export const copyFile = (frompath, topath) => { + return new Promise((resolve, reject) => { + const readStream = fs.createReadStream(frompath); + const writeStream = fs.createWriteStream(topath); + + readStream.on('error', reject); + writeStream.on('error', reject); + + writeStream.on('open', () => readStream.pipe(writeStream)); + writeStream.once('close', resolve); + }); +}; + +export const readFile = (filepath, encoding = '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) => { + fs.readFile(filepath, encoding, (err, data) => { + if (err) { + reject(err); + } else { + resolve(data); + } + }); + }); +}; + +export const writeFile = (filepath, contents) => { + return new Promise(function (resolve, reject) { + fs.writeFile(filepath, contents, 'utf8', function (err, _) { + return err ? reject(err) : resolve(); + }); + }); +}; + +export const removeFile = filepath => { + return new Promise(function (resolve, reject) { + fs.unlink(filepath, err => { + return err ? reject(err) : resolve(); + }); + }); +}; + +export const removeDir = dirpath => { + return new Promise(function (resolve, reject) { + fs.rmdir(dirpath, err => { + return err ? reject(err) : resolve(); + }); + }); +}; + +export const removeDirRecursively = async dirpath => { + if (await exists(dirpath)) { + for (let file of await listDir(dirpath)) { + const fullpath = join(dirpath, file); + if (fs.statSync(fullpath).isDirectory()) { + await removeDirRecursively(fullpath); + } else { + await removeFile(fullpath); + } + } + + await removeDir(dirpath); + } +}; + +export const getModifiedTime = filepath => { + return new Promise(function (resolve, reject) { + fs.stat(filepath, (err, stats) => { + if (err) { + reject(err); + } else { + resolve(new Date(stats.mtime)); + } + }); + }); }; diff --git a/packages/loot-core/src/platform/server/fs/index.web.js b/packages/loot-core/src/platform/server/fs/index.web.js index 3b0bbc3590..52a2b3c26a 100644 --- a/packages/loot-core/src/platform/server/fs/index.web.js +++ b/packages/loot-core/src/platform/server/fs/index.web.js @@ -1,21 +1,31 @@ -let { SQLiteFS } = require('absurd-sql'); -let IndexedDBBackend = require('absurd-sql/dist/indexeddb-backend').default; +import { SQLiteFS } from 'absurd-sql'; +import IndexedDBBackend from 'absurd-sql/dist/indexeddb-backend'; -let connection = require('../connection'); -let idb = require('../indexeddb'); -let { _getModule } = require('../sqlite'); +import * as connection from '../connection'; +import * as idb from '../indexeddb'; +import { _getModule } from '../sqlite'; -let baseAPI = require('./index.electron'); -let join = require('./path-join'); +import join from './path-join'; let FS = null; let BFS = null; // let NO_PERSIST = process.env.IS_BETA === true; let NO_PERSIST = false; -function pathToId(filepath) { +export const bundledDatabasePath = '/default-db.sqlite'; +export const migrationsPath = '/migrations'; +export const demoBudgetPath = '/demo-budget'; +export { join }; +export { + getDataDir, + getDocumentDir, + getBudgetDir, + _setDocumentDir, +} from './index.electron'; + +export const pathToId = function (filepath) { return filepath.replace(/^\//, '').replace(/\//g, '-'); -} +}; function _exists(filepath) { try { @@ -192,7 +202,7 @@ async function populateDefaultFilesystem() { ); } -async function populateFileHeirarchy() { +export const populateFileHeirarchy = async function () { let { store } = idb.getStore(await idb.getDatabase(), 'files'); let req = store.getAllKeys(); let paths = await new Promise((resolve, reject) => { @@ -204,9 +214,9 @@ async function populateFileHeirarchy() { _mkdirRecursively(basename(path)); _createFile(path); } -} +}; -async function init() { +export const init = async function () { let Module = _getModule(); FS = Module.FS; @@ -241,55 +251,55 @@ async function init() { } await populateFileHeirarchy(); -} +}; -function basename(filepath) { +export const basename = function (filepath) { let parts = filepath.split('/'); return parts.slice(0, -1).join('/'); -} +}; -async function listDir(filepath) { +export const listDir = async function (filepath) { let paths = FS.readdir(filepath); return paths.filter(p => p !== '.' && p !== '..'); -} +}; -async function exists(filepath) { +export const exists = async function (filepath) { return _exists(filepath); -} +}; -async function mkdir(filepath) { +export const mkdir = async function (filepath) { FS.mkdir(filepath); -} +}; -async function size(filepath) { +export const size = async function (filepath) { let attrs = FS.stat(resolveLink(filepath)); return attrs.size; -} +}; -async function copyFile(frompath, topath) { +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); return _writeFile(topath, contents); -} +}; -async function readFile(filepath, encoding = 'utf8') { +export const readFile = async function (filepath, encoding = 'utf8') { return _readFile(filepath, { encoding }); -} +}; -async function writeFile(filepath, contents) { +export const writeFile = async function (filepath, contents) { return _writeFile(filepath, contents); -} +}; -async function removeFile(filepath) { +export const removeFile = async function (filepath) { return _removeFile(filepath); -} +}; -async function removeDir(filepath) { +export const removeDir = async function (filepath) { FS.rmdir(filepath); -} +}; -async function removeDirRecursively(dirpath) { +export const removeDirRecursively = async function (dirpath) { if (await exists(dirpath)) { for (let file of await listDir(dirpath)) { let fullpath = join(dirpath, file); @@ -305,36 +315,10 @@ async function removeDirRecursively(dirpath) { await removeDir(dirpath); } -} +}; -async function getModifiedTime(filepath) { +export const getModifiedTime = async function (filepath) { throw new Error( 'getModifiedTime not supported on the web (only used for backups)', ); -} - -module.exports = { - pathToId, - populateFileHeirarchy, - init, - bundledDatabasePath: '/default-db.sqlite', - migrationsPath: '/migrations', - demoBudgetPath: '/demo-budget', - getDataDir: baseAPI.getDataDir, - getDocumentDir: baseAPI.getDocumentDir, - getBudgetDir: baseAPI.getBudgetDir, - _setDocumentDir: baseAPI._setDocumentDir, - join, - basename, - listDir, - exists, - mkdir, - size, - copyFile, - readFile, - writeFile, - removeFile, - removeDir, - removeDirRecursively, - getModifiedTime, }; diff --git a/packages/loot-core/src/platform/server/fs/index.web.test.js b/packages/loot-core/src/platform/server/fs/index.web.test.js index 14f67e6fd4..9395bb717e 100644 --- a/packages/loot-core/src/platform/server/fs/index.web.test.js +++ b/packages/loot-core/src/platform/server/fs/index.web.test.js @@ -1,11 +1,10 @@ +import 'fake-indexeddb/auto'; +import FDBFactory from 'fake-indexeddb/lib/FDBFactory'; + +import * as idb from '../indexeddb'; import * as sqlite from '../sqlite'; -require('fake-indexeddb/auto'); -let FDBFactory = require('fake-indexeddb/lib/FDBFactory'); - -let idb = require('../indexeddb'); - -let { init, readFile, writeFile, exists, pathToId, join } = require('./index'); +import { init, readFile, writeFile, exists, pathToId, join } from './index'; beforeAll(() => { process.env.PUBLIC_URL = diff --git a/packages/loot-core/src/platform/server/fs/path-join.web.js b/packages/loot-core/src/platform/server/fs/path-join.web.js index aaede10d0c..5ba0dc0225 100644 --- a/packages/loot-core/src/platform/server/fs/path-join.web.js +++ b/packages/loot-core/src/platform/server/fs/path-join.web.js @@ -81,7 +81,7 @@ function normalizePath(path) { return path; } -module.exports = function join(...args) { +export default function join(...args) { if (args.length === 0) return '.'; let joined; for (var i = 0; i < args.length; ++i) { @@ -93,4 +93,4 @@ module.exports = function join(...args) { } if (joined === undefined) return '.'; return normalizePath(joined); -}; +} diff --git a/packages/loot-core/src/platform/server/indexeddb/index.d.ts b/packages/loot-core/src/platform/server/indexeddb/index.d.ts index 97b1d26b13..8945c9a0db 100644 --- a/packages/loot-core/src/platform/server/indexeddb/index.d.ts +++ b/packages/loot-core/src/platform/server/indexeddb/index.d.ts @@ -1,7 +1,24 @@ export function getDatabase(); +export type GetDatabase = typeof getDatabase; + export function openDatabase(); +export type OpenDatabase = typeof openDatabase; + export function closeDatabase(); +export type CloseDatabase = typeof closeDatabase; + export function getStore(db: IDBDatabase, name: string); -export function get(store: IDBObjectStore, key: IDBValidKey | IDBKeyRange); +export type GetStore = typeof getStore; + +export function get( + store: IDBObjectStore, + key: IDBValidKey | IDBKeyRange, + mapper: (v: unknown) => unknown, +); +export type Get = typeof get; + export function set(store: IDBObjectStore, value: unknown); +export type Set = typeof set; + export function del(store: IDBObjectStore, key: IDBValidKey); +export type Del = typeof del; 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 a88bf609c9..d657a53f79 100644 --- a/packages/loot-core/src/platform/server/indexeddb/index.web.ts +++ b/packages/loot-core/src/platform/server/indexeddb/index.web.ts @@ -1,3 +1,5 @@ +import type * as T from '.'; + let openedDb = _openDatabase(); // The web version uses IndexedDB to store data @@ -91,12 +93,12 @@ function _openDatabase() { }); } -function getStore(db: IDBDatabase, name: string) { +export const getStore: T.GetStore = function (db, name) { let trans = db.transaction([name], 'readwrite'); return { trans, store: trans.objectStore(name) }; -} +}; -async function get(store: IDBObjectStore, key, mapper = x => x) { +export const get: T.Get = async function (store, key, mapper = x => x) { return new Promise((resolve, reject) => { let req = store.get(key); req.onsuccess = e => { @@ -104,36 +106,36 @@ async function get(store: IDBObjectStore, key, mapper = x => x) { }; req.onerror = e => reject(e); }); -} +}; -async function set(store: IDBObjectStore, item) { +export const set: T.Set = async function (store, item) { return new Promise((resolve, reject) => { let req = store.put(item); req.onsuccess = e => resolve(undefined); req.onerror = e => reject(e); }); -} +}; -async function del(store, key) { +export const del: T.Del = async function (store, key) { return new Promise((resolve, reject) => { let req = store.delete(key); req.onsuccess = e => resolve(undefined); req.onerror = e => reject(e); }); -} +}; -function getDatabase() { +export const getDatabase: T.GetDatabase = function () { return openedDb; -} +}; -function openDatabase() { +export const openDatabase: T.OpenDatabase = function () { if (openedDb == null) { openedDb = _openDatabase(); } return openedDb; -} +}; -function closeDatabase() { +export const closeDatabase: T.CloseDatabase = function () { if (openedDb) { openedDb.then(db => { // @ts-expect-error db type needs refinement @@ -141,14 +143,4 @@ function closeDatabase() { }); openedDb = null; } -} - -module.exports = { - getDatabase, - openDatabase, - closeDatabase, - getStore, - get, - set, - del, }; diff --git a/packages/loot-core/src/platform/uuid/index.d.ts b/packages/loot-core/src/platform/uuid/index.d.ts index f990539567..13fb979028 100644 --- a/packages/loot-core/src/platform/uuid/index.d.ts +++ b/packages/loot-core/src/platform/uuid/index.d.ts @@ -1,2 +1,5 @@ export function v4(): Promise; +export type V4 = typeof v4; + export function v4Sync(): string; +export type V4Sync = typeof v4Sync; diff --git a/packages/loot-core/src/platform/uuid/index.electron.ts b/packages/loot-core/src/platform/uuid/index.electron.ts index beb846a813..84708652b3 100644 --- a/packages/loot-core/src/platform/uuid/index.electron.ts +++ b/packages/loot-core/src/platform/uuid/index.electron.ts @@ -1,11 +1,11 @@ -const _uuid = require('uuid'); +import uuid from 'uuid'; -module.exports = { - v4: function () { - return Promise.resolve(_uuid.v4()); - }, +import type * as T from '.'; - v4Sync: function () { - return _uuid.v4(); - }, +export const v4: T.V4 = function () { + return Promise.resolve(uuid.v4()); +}; + +export const v4Sync: T.V4Sync = function () { + return uuid.v4(); }; diff --git a/packages/loot-core/src/platform/uuid/index.testing.ts b/packages/loot-core/src/platform/uuid/index.testing.ts index fdae42aec9..0905063888 100644 --- a/packages/loot-core/src/platform/uuid/index.testing.ts +++ b/packages/loot-core/src/platform/uuid/index.testing.ts @@ -1,9 +1,9 @@ -module.exports = { - v4: function () { - return Promise.resolve(global.randomId()); - }, +import type * as T from '.'; - v4Sync: function () { - return global.randomId(); - }, +export const v4: T.V4 = function () { + return Promise.resolve(global.randomId()); +}; + +export const v4Sync: T.V4Sync = function () { + return global.randomId(); }; diff --git a/packages/loot-core/src/platform/uuid/index.web.ts b/packages/loot-core/src/platform/uuid/index.web.ts index 633da75631..84708652b3 100644 --- a/packages/loot-core/src/platform/uuid/index.web.ts +++ b/packages/loot-core/src/platform/uuid/index.web.ts @@ -1,11 +1,11 @@ -const uuid = require('uuid'); +import uuid from 'uuid'; -module.exports = { - v4: function () { - return Promise.resolve(uuid.v4()); - }, +import type * as T from '.'; - v4Sync: function () { - return uuid.v4(); - }, +export const v4: T.V4 = function () { + return Promise.resolve(uuid.v4()); +}; + +export const v4Sync: T.V4Sync = function () { + return uuid.v4(); }; diff --git a/packages/loot-core/src/server/__mocks__/post.js b/packages/loot-core/src/server/__mocks__/post.js index 8524d220e0..89a961b872 100644 --- a/packages/loot-core/src/server/__mocks__/post.js +++ b/packages/loot-core/src/server/__mocks__/post.js @@ -1,9 +1,8 @@ -const mockServer = require('../tests/mockSyncServer'); +export { + handleRequest as post, + handleRequestBinary as postBinary, +} from '../tests/mockSyncServer'; -module.exports = { - post: mockServer.handleRequest, - postBinary: mockServer.handleRequestBinary, - get(url) { - throw new Error('get unimplemented'); - }, +export const get = function (url) { + throw new Error('get unimplemented'); }; diff --git a/packages/loot-core/src/server/accounts/link.js b/packages/loot-core/src/server/accounts/link.js index e22a09c0c8..eb12b9fc89 100644 --- a/packages/loot-core/src/server/accounts/link.js +++ b/packages/loot-core/src/server/accounts/link.js @@ -1,4 +1,5 @@ -import asyncStorage from '../../platform/server/asyncStorage'; +import * as asyncStorage from '../../platform/server/asyncStorage'; +import * as uuid from '../../platform/uuid'; import { fromPlaidAccountType } from '../../shared/accounts'; import { amountToInteger } from '../../shared/util'; import * as db from '../db'; @@ -8,8 +9,6 @@ import { getServer } from '../server-config'; import * as bankSync from './sync'; -const uuid = require('../../platform/uuid'); - export async function handoffPublicToken(institution, publicToken) { let [[, userId], [, key]] = await asyncStorage.multiGet([ 'user-id', diff --git a/packages/loot-core/src/server/accounts/parse-file.js b/packages/loot-core/src/server/accounts/parse-file.js index 71594b6f68..750cecedef 100644 --- a/packages/loot-core/src/server/accounts/parse-file.js +++ b/packages/loot-core/src/server/accounts/parse-file.js @@ -1,6 +1,6 @@ import csv2json from 'csv-parse/lib/sync'; -import fs from '../../platform/server/fs'; +import * as fs from '../../platform/server/fs'; import { dayFromDate } from '../../shared/months'; import { looselyParseAmount } from '../../shared/util'; diff --git a/packages/loot-core/src/server/accounts/sync.js b/packages/loot-core/src/server/accounts/sync.js index c01f2f65de..1f3b872234 100644 --- a/packages/loot-core/src/server/accounts/sync.js +++ b/packages/loot-core/src/server/accounts/sync.js @@ -1,4 +1,7 @@ -import asyncStorage from '../../platform/server/asyncStorage'; +import * as dateFns from 'date-fns'; + +import * as asyncStorage from '../../platform/server/asyncStorage'; +import * as uuid from '../../platform/uuid'; import * as monthUtils from '../../shared/months'; import { makeChild as makeChildTransaction, @@ -7,6 +10,7 @@ import { import { hasFieldsChanged, amountToInteger } from '../../shared/util'; import * as db from '../db'; import { runMutator } from '../mutators'; +import { post } from '../post'; import { getServer } from '../server-config'; import { batchMessages } from '../sync'; @@ -15,11 +19,6 @@ import title from './title'; import { runRules } from './transaction-rules'; import { batchUpdateTransactions } from './transactions'; -const dateFns = require('date-fns'); - -const uuid = require('../../platform/uuid'); -const { post } = require('../post'); - // Plaid article about API options: // https://support.plaid.com/customer/en/portal/articles/2612155-transactions-returned-per-request diff --git a/packages/loot-core/src/server/accounts/sync.test.js b/packages/loot-core/src/server/accounts/sync.test.js index 63288426c2..56e22d3dfa 100644 --- a/packages/loot-core/src/server/accounts/sync.test.js +++ b/packages/loot-core/src/server/accounts/sync.test.js @@ -1,7 +1,11 @@ +import snapshotDiff from 'snapshot-diff'; + import * as monthUtils from '../../shared/months'; import * as db from '../db'; import { loadMappings } from '../db/mappings'; +import { post } from '../post'; import { getServer } from '../server-config'; +import * as mockSyncServer from '../tests/mockSyncServer'; import { syncAccount, @@ -12,11 +16,6 @@ import { import { loadRules, insertRule } from './transaction-rules'; import * as transfer from './transfer'; -const snapshotDiff = require('snapshot-diff'); - -const { post } = require('../post'); -const mockSyncServer = require('../tests/mockSyncServer'); - const papaJohns = 'Papa Johns east side'; const lowes = 'Lowe’s Store'; diff --git a/packages/loot-core/src/server/accounts/title/index.js b/packages/loot-core/src/server/accounts/title/index.js index af08c964d7..443e1b03c3 100644 --- a/packages/loot-core/src/server/accounts/title/index.js +++ b/packages/loot-core/src/server/accounts/title/index.js @@ -1,6 +1,6 @@ // Utilities -const lowerCase = require('./lower-case'); -const specials = require('./specials'); +import lowerCase from './lower-case'; +import specials from './specials'; let character = '[0-9\u0041-\u005A\u0061-\u007A\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376-\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u0523\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0621-\u064A\u066E-\u066F\u0671-\u06D3\u06D5\u06E5-\u06E6\u06EE-\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4-\u07F5\u07FA\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0972\u097B-\u097F\u0985-\u098C\u098F-\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC-\u09DD\u09DF-\u09E1\u09F0-\u09F1\u0A05-\u0A0A\u0A0F-\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32-\u0A33\u0A35-\u0A36\u0A38-\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2-\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0-\u0AE1\u0B05-\u0B0C\u0B0F-\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32-\u0B33\u0B35-\u0B39\u0B3D\u0B5C-\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99-\u0B9A\u0B9C\u0B9E-\u0B9F\u0BA3-\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D\u0C58-\u0C59\u0C60-\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0-\u0CE1\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D28\u0D2A-\u0D39\u0D3D\u0D60-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32-\u0E33\u0E40-\u0E46\u0E81-\u0E82\u0E84\u0E87-\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA-\u0EAB\u0EAD-\u0EB0\u0EB2-\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDD\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8B\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065-\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10D0-\u10FA\u10FC\u1100-\u1159\u115F-\u11A2\u11A8-\u11F9\u1200-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u1676\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F0\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u1900-\u191C\u1950-\u196D\u1970-\u1974\u1980-\u19A9\u19C1-\u19C7\u1A00-\u1A16\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE-\u1BAF\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u2094\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2C6F\u2C71-\u2C7D\u2C80-\u2CE4\u2D00-\u2D25\u2D30-\u2D65\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31B7\u31F0-\u31FF\u3400\u4DB5\u4E00\u9FC3\uA000-\uA48C\uA500-\uA60C\uA610-\uA61F\uA62A-\uA62B\uA640-\uA65F\uA662-\uA66E\uA67F-\uA697\uA717-\uA71F\uA722-\uA788\uA78B-\uA78C\uA7FB-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA90A-\uA925\uA930-\uA946\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAC00\uD7A3\uF900-\uFA2D\uFA30-\uFA6A\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40-\uFB41\uFB43-\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]'; @@ -28,7 +28,7 @@ function parseMatch(match) { return match; } -module.exports = (str, options = {}) => { +export default function title(str, options = {}) { str = str .toLowerCase() .replace(regex, (m, lead = '', forced, lower, rest) => { @@ -56,4 +56,4 @@ module.exports = (str, options = {}) => { }); return str; -}; +} diff --git a/packages/loot-core/src/server/accounts/title/lower-case.js b/packages/loot-core/src/server/accounts/title/lower-case.js index 78bcc639b0..8f669a4e49 100644 --- a/packages/loot-core/src/server/accounts/title/lower-case.js +++ b/packages/loot-core/src/server/accounts/title/lower-case.js @@ -86,4 +86,5 @@ const prepositions = [ 'without', ]; -module.exports = new Set([...conjunctions, ...articles, ...prepositions]); +const dictionary = new Set([...conjunctions, ...articles, ...prepositions]); +export default dictionary; diff --git a/packages/loot-core/src/server/accounts/title/specials.js b/packages/loot-core/src/server/accounts/title/specials.js index e2493792cc..1beb793640 100644 --- a/packages/loot-core/src/server/accounts/title/specials.js +++ b/packages/loot-core/src/server/accounts/title/specials.js @@ -20,4 +20,4 @@ const intended = [ 'Node.js', ]; -module.exports = intended; +export default intended; diff --git a/packages/loot-core/src/server/accounts/transactions.js b/packages/loot-core/src/server/accounts/transactions.js index 3562f74788..348c7342f1 100644 --- a/packages/loot-core/src/server/accounts/transactions.js +++ b/packages/loot-core/src/server/accounts/transactions.js @@ -1,3 +1,4 @@ +import * as connection from '../../platform/server/connection'; import * as db from '../db'; import { incrFetch, whereIn } from '../db/util'; import { batchMessages } from '../sync'; @@ -5,8 +6,6 @@ import { batchMessages } from '../sync'; import * as rules from './transaction-rules'; import * as transfer from './transfer'; -const connection = require('../../platform/server/connection'); - async function idsWithChildren(ids) { let whereIds = whereIn(ids, 'parent_id'); let rows = await db.all( diff --git a/packages/loot-core/src/server/api.js b/packages/loot-core/src/server/api.js index b6c09603a8..3509ffd2e1 100644 --- a/packages/loot-core/src/server/api.js +++ b/packages/loot-core/src/server/api.js @@ -1,3 +1,4 @@ +import * as connection from '../platform/server/connection'; import { getDownloadError, getSyncError, @@ -29,8 +30,6 @@ import * as prefs from './prefs'; import * as sheet from './sheet'; import { setSyncingMode, batchMessages } from './sync'; -const connection = require('../platform/server/connection'); - let IMPORT_MODE = false; // This is duplicate from main.js... diff --git a/packages/loot-core/src/server/aql/exec.test.js b/packages/loot-core/src/server/aql/exec.test.js index f5c5294fdc..78cb4730c3 100644 --- a/packages/loot-core/src/server/aql/exec.test.js +++ b/packages/loot-core/src/server/aql/exec.test.js @@ -1,3 +1,4 @@ +import * as uuid from '../../platform/uuid'; import query from '../../shared/query'; import { makeChild } from '../../shared/transactions'; import * as db from '../db'; @@ -5,8 +6,6 @@ import * as db from '../db'; import * as aql from './exec'; import { schema, schemaConfig } from './schema'; -const uuid = require('../../platform/uuid'); - beforeEach(global.emptyDatabase()); function repeat(arr, times) { diff --git a/packages/loot-core/src/server/backups.js b/packages/loot-core/src/server/backups.js index 25a051510c..ca72eaf5ca 100644 --- a/packages/loot-core/src/server/backups.js +++ b/packages/loot-core/src/server/backups.js @@ -1,15 +1,14 @@ -import fs from '../platform/server/fs'; +import * as dateFns from 'date-fns'; + +import * as connection from '../platform/server/connection'; +import * as fs from '../platform/server/fs'; import * as sqlite from '../platform/server/sqlite'; +import * as uuid from '../platform/uuid'; import * as monthUtils from '../shared/months'; import * as cloudStorage from './cloud-storage'; import * as prefs from './prefs'; -const dateFns = require('date-fns'); - -const connection = require('../platform/server/connection'); -const uuid = require('../platform/uuid'); - // A special backup that represents the latest version of the db that // can be reverted to after loading a backup const LATEST_BACKUP_FILENAME = 'db.latest.sqlite'; diff --git a/packages/loot-core/src/server/backups.test.js b/packages/loot-core/src/server/backups.test.js index 491f6633f5..e87ad62a9e 100644 --- a/packages/loot-core/src/server/backups.test.js +++ b/packages/loot-core/src/server/backups.test.js @@ -1,6 +1,6 @@ -import { updateBackups } from './backups'; +import * as dateFns from 'date-fns'; -const dateFns = require('date-fns'); +import { updateBackups } from './backups'; describe('Backups', () => { test('backups work', async () => { diff --git a/packages/loot-core/src/server/bench.js b/packages/loot-core/src/server/bench.js index 25109ec22c..c0be1eb6e9 100644 --- a/packages/loot-core/src/server/bench.js +++ b/packages/loot-core/src/server/bench.js @@ -1,7 +1,8 @@ #!/usr/bin/env node +import * as fs from 'fs'; + import * as db from './db'; -const fs = require('fs'); const queries = fs .readFileSync(__dirname + '/../../src/server/slow-queries.txt', 'utf8') .split('___BOUNDARY') diff --git a/packages/loot-core/src/server/budget/report.js b/packages/loot-core/src/server/budget/report.js index 6e6098e7e7..66ccf19e8d 100644 --- a/packages/loot-core/src/server/budget/report.js +++ b/packages/loot-core/src/server/budget/report.js @@ -1,10 +1,9 @@ import { safeNumber } from '../../shared/util'; import * as sheet from '../sheet'; +import { resolveName } from '../spreadsheet/util'; import { number, sumAmounts } from './util'; -const { resolveName } = require('../spreadsheet/util'); - export async function createCategory(cat, sheetName, prevSheetName) { sheet.get().createStatic(sheetName, `budget-${cat.id}`, 0); diff --git a/packages/loot-core/src/server/budget/rollover.js b/packages/loot-core/src/server/budget/rollover.js index 1fcbec4cd6..1c8080a0a9 100644 --- a/packages/loot-core/src/server/budget/rollover.js +++ b/packages/loot-core/src/server/budget/rollover.js @@ -1,11 +1,10 @@ import * as monthUtils from '../../shared/months'; import { safeNumber } from '../../shared/util'; import * as sheet from '../sheet'; +import { resolveName } from '../spreadsheet/util'; import { number, sumAmounts, flatten2, unflatten2 } from './util'; -const { resolveName } = require('../spreadsheet/util'); - function getBlankSheet(months) { let blankMonth = monthUtils.prevMonth(months[0]); return monthUtils.sheetForMonth(blankMonth, 'rollover'); diff --git a/packages/loot-core/src/server/cloud-storage.js b/packages/loot-core/src/server/cloud-storage.js index d37d975302..1963eeab2e 100644 --- a/packages/loot-core/src/server/cloud-storage.js +++ b/packages/loot-core/src/server/cloud-storage.js @@ -1,7 +1,10 @@ -import asyncStorage from '../platform/server/asyncStorage'; +import AdmZip from 'adm-zip'; + +import * as asyncStorage from '../platform/server/asyncStorage'; import { fetch } from '../platform/server/fetch'; -import fs from '../platform/server/fs'; +import * as fs from '../platform/server/fs'; import * as sqlite from '../platform/server/sqlite'; +import * as uuid from '../platform/uuid'; import * as monthUtils from '../shared/months'; import * as encryption from './encryption'; @@ -16,10 +19,6 @@ import { post } from './post'; import * as prefs from './prefs'; import { getServer } from './server-config'; -let AdmZip = require('adm-zip'); - -let uuid = require('../platform/uuid'); - let UPLOAD_FREQUENCY_IN_DAYS = 7; async function checkHTTPStatus(res) { diff --git a/packages/loot-core/src/server/crdt/timestamp.js b/packages/loot-core/src/server/crdt/timestamp.js index e91b5c3385..ddcbaaf5fc 100644 --- a/packages/loot-core/src/server/crdt/timestamp.js +++ b/packages/loot-core/src/server/crdt/timestamp.js @@ -1,6 +1,6 @@ import murmurhash from 'murmurhash'; -const uuid = require('../../platform/uuid'); +import * as uuid from '../../platform/uuid'; /** * Hybrid Unique Logical Clock (HULC) timestamp generator diff --git a/packages/loot-core/src/server/db/index.js b/packages/loot-core/src/server/db/index.js index c3901d39b7..379ad59a13 100644 --- a/packages/loot-core/src/server/db/index.js +++ b/packages/loot-core/src/server/db/index.js @@ -1,7 +1,8 @@ import LRU from 'lru-cache'; -import fs from '../../platform/server/fs'; +import * as fs from '../../platform/server/fs'; import * as sqlite from '../../platform/server/sqlite'; +import * as uuid from '../../platform/uuid'; import { groupById } from '../../shared/util'; import { schema, @@ -31,8 +32,6 @@ import { shoveSortOrders, SORT_INCREMENT } from './sort'; export { toDateRepr, fromDateRepr } from '../models'; -const uuid = require('../../platform/uuid'); - let dbPath; let db; diff --git a/packages/loot-core/src/server/encryption-internals.js b/packages/loot-core/src/server/encryption-internals.js index bdae080351..79ff20538f 100644 --- a/packages/loot-core/src/server/encryption-internals.js +++ b/packages/loot-core/src/server/encryption-internals.js @@ -1,4 +1,4 @@ -let crypto = require('crypto'); +import crypto from 'crypto'; let ENCRYPTION_ALGORITHM = 'aes-256-gcm'; diff --git a/packages/loot-core/src/server/encryption.js b/packages/loot-core/src/server/encryption.js index 1e1926d517..c42f5c20e0 100644 --- a/packages/loot-core/src/server/encryption.js +++ b/packages/loot-core/src/server/encryption.js @@ -1,6 +1,6 @@ -import * as internals from './encryption-internals'; +import * as uuid from '../platform/uuid'; -let uuid = require('../platform/uuid'); +import * as internals from './encryption-internals'; // A map of all possible master encryption keys to use, keyed by // unique id diff --git a/packages/loot-core/src/server/main-app.js b/packages/loot-core/src/server/main-app.js index e3597cb4ef..6e89fc1ef9 100644 --- a/packages/loot-core/src/server/main-app.js +++ b/packages/loot-core/src/server/main-app.js @@ -1,6 +1,6 @@ -import { createApp } from './app'; +import * as connection from '../platform/server/connection'; -const connection = require('../platform/server/connection'); +import { createApp } from './app'; // Main app const app = createApp(); diff --git a/packages/loot-core/src/server/main.js b/packages/loot-core/src/server/main.js index 86bbe82aaa..e22068a5f9 100644 --- a/packages/loot-core/src/server/main.js +++ b/packages/loot-core/src/server/main.js @@ -1,12 +1,16 @@ import './polyfills'; -import injectAPI from '@actual-app/api/injected'; +import * as injectAPI from '@actual-app/api/injected'; +import * as YNAB4 from '@actual-app/import-ynab4/importer'; +import * as YNAB5 from '@actual-app/import-ynab5/importer'; import { createTestBudget } from '../mocks/budget'; import { captureException, captureBreadcrumb } from '../platform/exceptions'; -import asyncStorage from '../platform/server/asyncStorage'; -import fs from '../platform/server/fs'; +import * as asyncStorage from '../platform/server/asyncStorage'; +import * as connection from '../platform/server/connection'; +import * as fs from '../platform/server/fs'; import logger from '../platform/server/log'; import * as sqlite from '../platform/server/sqlite'; +import * as uuid from '../platform/uuid'; import { fromPlaidAccountType } from '../shared/accounts'; import { isNonProductionEnvironment } from '../shared/environment'; import * as monthUtils from '../shared/months'; @@ -57,6 +61,7 @@ import * as prefs from './prefs'; import schedulesApp from './schedules/app'; import { getServer, setServer } from './server-config'; import * as sheet from './sheet'; +import { resolveName, unresolveName } from './spreadsheet/util'; import { initialFullSync, fullSync, @@ -69,22 +74,12 @@ import { repairSync, } from './sync'; import * as syncMigrations from './sync/migrate'; +import * as SyncPb from './sync/proto/sync_pb'; import toolsApp from './tools/app'; import { withUndo, clearUndo, undo, redo } from './undo'; import { updateVersion } from './update'; import { uniqueFileName, idFromFileName } from './util/budget-name'; -const YNAB4 = require('@actual-app/import-ynab4/importer'); -const YNAB5 = require('@actual-app/import-ynab5/importer'); - -const connection = require('../platform/server/connection'); -const uuid = require('../platform/uuid'); - -const { resolveName, unresolveName } = require('./spreadsheet/util'); -const SyncPb = require('./sync/proto/sync_pb'); - -// let indexeddb = require('../platform/server/indexeddb'); - let DEMO_BUDGET_ID = '_demo-budget'; let TEST_BUDGET_ID = '_test-budget'; let UNCONFIGURED_SERVER = 'https://not-configured/'; @@ -1839,10 +1834,6 @@ handlers['get-budgets'] = async function () { return budgets; }; -handlers['get-ynab4-files'] = async function () { - return YNAB4.findBudgets(); -}; - handlers['get-remote-files'] = async function () { return cloudStorage.listRemoteFiles(); }; @@ -2346,7 +2337,7 @@ handlers['app-focused'] = async function () { handlers = installAPI(handlers); -injectAPI.send = (name, args) => runHandler(app.handlers[name], args); +injectAPI.override((name, args) => runHandler(app.handlers[name], args)); // A hack for now until we clean up everything app.handlers = handlers; diff --git a/packages/loot-core/src/server/main.test.js b/packages/loot-core/src/server/main.test.js index b79d609bcb..5fd901dd7c 100644 --- a/packages/loot-core/src/server/main.test.js +++ b/packages/loot-core/src/server/main.test.js @@ -1,26 +1,24 @@ import { expectSnapshotWithDiffer } from '../mocks/util'; +import * as connection from '../platform/server/connection'; +import * as fs from '../platform/server/fs'; import * as monthUtils from '../shared/months'; import * as budgetActions from './budget/actions'; import * as budget from './budget/base'; import { getClock, deserializeClock } from './crdt'; import * as db from './db'; +import { handlers } from './main'; import { runHandler, runMutator, disableGlobalMutations, enableGlobalMutations, } from './mutators'; +import { post } from './post'; import * as prefs from './prefs'; +import * as sheet from './sheet'; jest.mock('./post'); -const connection = require('../platform/server/connection'); -const fs = require('../platform/server/fs'); - -const backend = require('./main'); -const { post } = require('./post'); -const handlers = backend.handlers; -const sheet = require('./sheet'); beforeEach(async () => { await global.emptyDatabase()(); diff --git a/packages/loot-core/src/server/migrate/cli.js b/packages/loot-core/src/server/migrate/cli.js index 693cdc8e73..5f67f773c9 100755 --- a/packages/loot-core/src/server/migrate/cli.js +++ b/packages/loot-core/src/server/migrate/cli.js @@ -1,4 +1,7 @@ #!/usr/bin/env node --trace-warnings +import * as fs from 'fs'; +import * as path from 'path'; + import * as sqlite from '../../platform/server/sqlite'; import { @@ -11,9 +14,6 @@ import { migrate, } from './migrations'; -const fs = require('fs'); -const path = require('path'); - const argv = require('yargs').options({ m: { alias: 'migrationsDir', diff --git a/packages/loot-core/src/server/migrate/migrations.js b/packages/loot-core/src/server/migrate/migrations.js index d4b7ae2dbc..231b8be28b 100644 --- a/packages/loot-core/src/server/migrate/migrations.js +++ b/packages/loot-core/src/server/migrate/migrations.js @@ -2,10 +2,9 @@ // them which doesn't play well with CSP. There isn't great, and eventually // we can remove this migration. import m1632571489012 from '../../../migrations/1632571489012_remove_cache.js'; -import fs from '../../platform/server/fs'; +import * as fs from '../../platform/server/fs'; import * as sqlite from '../../platform/server/sqlite'; - -const uuid = require('../../platform/uuid'); +import * as uuid from '../../platform/uuid'; let MIGRATIONS_DIR = fs.migrationsPath; diff --git a/packages/loot-core/src/server/post.js b/packages/loot-core/src/server/post.js index 42e2f02d00..1f0bbc82d6 100644 --- a/packages/loot-core/src/server/post.js +++ b/packages/loot-core/src/server/post.js @@ -1,9 +1,8 @@ +import { fetch } from '../platform/server/fetch'; + +import { PostError } from './errors'; import * as Platform from './platform'; -const { fetch } = require('../platform/server/fetch'); - -const { PostError } = require('./errors'); - function throwIfNot200(res, text) { if (res.status !== 200) { if (res.status === 500) { diff --git a/packages/loot-core/src/server/prefs.js b/packages/loot-core/src/server/prefs.js index 2085acc759..9cbf7c6b95 100644 --- a/packages/loot-core/src/server/prefs.js +++ b/packages/loot-core/src/server/prefs.js @@ -1,8 +1,8 @@ +import * as fs from '../platform/server/fs'; + import { Timestamp } from './crdt'; import { sendMessages } from './sync'; -const fs = require('../platform/server/fs'); - let prefs = null; export async function loadPrefs(id) { diff --git a/packages/loot-core/src/server/schedules/app.js b/packages/loot-core/src/server/schedules/app.js index f8fb0fd45b..663bb9a9d9 100644 --- a/packages/loot-core/src/server/schedules/app.js +++ b/packages/loot-core/src/server/schedules/app.js @@ -2,6 +2,8 @@ import * as d from 'date-fns'; import deepEqual from 'deep-equal'; import { captureBreadcrumb } from '../../platform/exceptions'; +import * as connection from '../../platform/server/connection'; +import * as uuid from '../../platform/uuid'; import { dayFromDate, currentDay, parseDate } from '../../shared/months'; import q from '../../shared/query'; import { @@ -31,9 +33,6 @@ import { Schedule as RSchedule } from '../util/rschedule'; import { findSchedules } from './find-schedules'; -const connection = require('../../platform/server/connection'); -const uuid = require('../../platform/uuid'); - // Utilities function zip(arr1, arr2) { diff --git a/packages/loot-core/src/server/schedules/find-schedules.js b/packages/loot-core/src/server/schedules/find-schedules.js index 893639db40..656579e974 100644 --- a/packages/loot-core/src/server/schedules/find-schedules.js +++ b/packages/loot-core/src/server/schedules/find-schedules.js @@ -1,5 +1,6 @@ import * as d from 'date-fns'; +import * as uuid from '../../platform/uuid'; import { dayFromDate, parseDate } from '../../shared/months'; import q from '../../shared/query'; import { getApproxNumberThreshold } from '../../shared/rules'; @@ -11,8 +12,6 @@ import * as db from '../db'; import { fromDateRepr } from '../models'; import { Schedule as RSchedule } from '../util/rschedule'; -const uuid = require('../../platform/uuid'); - function takeDates(config) { let schedule = new RSchedule({ rrules: recurConfigToRSchedule(config) }); return schedule diff --git a/packages/loot-core/src/server/server-config.js b/packages/loot-core/src/server/server-config.js index 8346db6a66..c509cdc120 100644 --- a/packages/loot-core/src/server/server-config.js +++ b/packages/loot-core/src/server/server-config.js @@ -1,4 +1,4 @@ -import fs from '../platform/server/fs'; +import * as fs from '../platform/server/fs'; let config = null; diff --git a/packages/loot-core/src/server/sheet.js b/packages/loot-core/src/server/sheet.js index dc23c4b5b0..199fd82779 100644 --- a/packages/loot-core/src/server/sheet.js +++ b/packages/loot-core/src/server/sheet.js @@ -5,8 +5,7 @@ import { sheetForMonth } from '../shared/months'; import * as Platform from './platform'; import * as prefs from './prefs'; import Spreadsheet from './spreadsheet/spreadsheet'; - -const { resolveName } = require('./spreadsheet/util'); +import { resolveName } from './spreadsheet/util'; let globalSheet, globalOnChange; let globalCacheDb; diff --git a/packages/loot-core/src/server/spreadsheet/globals.js b/packages/loot-core/src/server/spreadsheet/globals.js index 1faf592f65..fcbfbc6625 100644 --- a/packages/loot-core/src/server/spreadsheet/globals.js +++ b/packages/loot-core/src/server/spreadsheet/globals.js @@ -1,13 +1,13 @@ -function first(arr) { +export function first(arr) { return arr[0]; } -function firstValue(arr) { +export function firstValue(arr) { const keys = Object.keys(arr[0]); return arr[0][keys[0]]; } -function number(v) { +export function number(v) { if (typeof v === 'number') { return v; } else if (typeof v === 'string') { @@ -21,18 +21,10 @@ function number(v) { return 0; } -function min(x, y) { +export function min(x, y) { return Math.min(x, y); } -function max(x, y) { +export function max(x, y) { return Math.max(x, y); } - -module.exports = { - first, - firstValue, - number, - min, - max, -}; diff --git a/packages/loot-core/src/server/spreadsheet/graph-data-structure.js b/packages/loot-core/src/server/spreadsheet/graph-data-structure.js index 8cd8399dcc..9784e8b766 100644 --- a/packages/loot-core/src/server/spreadsheet/graph-data-structure.js +++ b/packages/loot-core/src/server/spreadsheet/graph-data-structure.js @@ -120,4 +120,4 @@ function Graph(serialized) { return graph; } -module.exports = Graph; +export default Graph; diff --git a/packages/loot-core/src/server/spreadsheet/new/vm.test.js b/packages/loot-core/src/server/spreadsheet/new/vm.test.js index 354ec1c1a8..5f44b36e8c 100644 --- a/packages/loot-core/src/server/spreadsheet/new/vm.test.js +++ b/packages/loot-core/src/server/spreadsheet/new/vm.test.js @@ -1,6 +1,6 @@ -import VM from './vm'; +import { unresolveName } from '../util'; -const { unresolveName } = require('../util'); +import VM from './vm'; const db = { runQuery: sql => { diff --git a/packages/loot-core/src/server/spreadsheet/spreadsheet.js b/packages/loot-core/src/server/spreadsheet/spreadsheet.js index 6873d1b9a2..9538f4a5e8 100644 --- a/packages/loot-core/src/server/spreadsheet/spreadsheet.js +++ b/packages/loot-core/src/server/spreadsheet/spreadsheet.js @@ -2,8 +2,8 @@ import mitt from 'mitt'; import { compileQuery, runCompiledQuery, schema, schemaConfig } from '../aql'; -const Graph = require('./graph-data-structure'); -const { unresolveName, resolveName } = require('./util'); +import Graph from './graph-data-structure'; +import { unresolveName, resolveName } from './util'; export default class Spreadsheet { constructor(saveCache, setCacheStatus) { diff --git a/packages/loot-core/src/server/spreadsheet/sqlinterp.js b/packages/loot-core/src/server/spreadsheet/sqlinterp.js index d3581df87c..d1ac4d5ca2 100644 --- a/packages/loot-core/src/server/spreadsheet/sqlinterp.js +++ b/packages/loot-core/src/server/spreadsheet/sqlinterp.js @@ -1,4 +1,4 @@ -const dateFns = require('date-fns'); +import * as dateFns from 'date-fns'; const AlwaysTrue = Symbol('AlwaysTrue'); let shouldLog = false; @@ -184,4 +184,4 @@ function interpret(where, row, table) { return ret; } -module.exports = interpret; +export default interpret; diff --git a/packages/loot-core/src/server/spreadsheet/sqlinterp.test.js b/packages/loot-core/src/server/spreadsheet/sqlinterp.test.js index 02cbc8fcff..7f9eb2b7cc 100644 --- a/packages/loot-core/src/server/spreadsheet/sqlinterp.test.js +++ b/packages/loot-core/src/server/spreadsheet/sqlinterp.test.js @@ -1,6 +1,5 @@ import { compile } from './new/compiler'; - -const sqlinterp = require('./sqlinterp'); +import sqlinterp from './sqlinterp'; test('sql interpretation works', async () => { const transJan = { diff --git a/packages/loot-core/src/server/spreadsheet/tests/graph.js b/packages/loot-core/src/server/spreadsheet/tests/graph.js index d097d9fbb8..c8a2431a1e 100644 --- a/packages/loot-core/src/server/spreadsheet/tests/graph.js +++ b/packages/loot-core/src/server/spreadsheet/tests/graph.js @@ -1,9 +1,9 @@ // Unit tests for reactive-property. -var assert = require('assert'); +import assert from 'assert'; // If using from the NPM package, this line would be -// var Graph = require("graph-data-structure"); -var Graph = require('../data-compute/graph-data-structure'); +// import Graph from "graph-data-structure"; +import Graph from '../data-compute/graph-data-structure'; describe('Graph', function () { describe('Data structure', function () { diff --git a/packages/loot-core/src/server/spreadsheet/util.js b/packages/loot-core/src/server/spreadsheet/util.js index 21628179c9..cc69f85894 100644 --- a/packages/loot-core/src/server/spreadsheet/util.js +++ b/packages/loot-core/src/server/spreadsheet/util.js @@ -1,4 +1,4 @@ -function unresolveName(name) { +export function unresolveName(name) { let idx = name.indexOf('!'); if (idx !== -1) { return { @@ -9,11 +9,11 @@ function unresolveName(name) { return { sheet: null, name }; } -function resolveName(sheet, name) { +export function resolveName(sheet, name) { return sheet + '!' + name; } -function resolveNamesAsObjects(sheets) { +export function resolveNamesAsObjects(sheets) { const cells = {}; Object.keys(sheets).forEach(sheetName => { const sheet = sheets[sheetName]; @@ -26,7 +26,7 @@ function resolveNamesAsObjects(sheets) { return cells; } -function resolveNamesAsArrays(sheets) { +export function resolveNamesAsArrays(sheets) { const cells = []; Object.keys(sheets).forEach(sheetName => { const sheet = sheets[sheetName]; @@ -37,10 +37,3 @@ function resolveNamesAsArrays(sheets) { }); return cells; } - -module.exports = { - unresolveName, - resolveName, - resolveNamesAsObjects, - resolveNamesAsArrays, -}; diff --git a/packages/loot-core/src/server/sync/encoder.js b/packages/loot-core/src/server/sync/encoder.js index baa976edd0..b64aa4d800 100644 --- a/packages/loot-core/src/server/sync/encoder.js +++ b/packages/loot-core/src/server/sync/encoder.js @@ -1,9 +1,8 @@ import * as encryption from '../encryption'; +import { SyncError } from '../errors'; import * as prefs from '../prefs'; -let { SyncError } = require('../errors'); - -let SyncPb = require('./proto/sync_pb'); +import * as SyncPb from './proto/sync_pb'; function coerceBuffer(value) { // The web encryption APIs give us back raw Uint8Array... but our diff --git a/packages/loot-core/src/server/sync/index.js b/packages/loot-core/src/server/sync/index.js index 1adf620c2a..70023e05f9 100644 --- a/packages/loot-core/src/server/sync/index.js +++ b/packages/loot-core/src/server/sync/index.js @@ -1,5 +1,6 @@ import { captureException } from '../../platform/exceptions'; -import asyncStorage from '../../platform/server/asyncStorage'; +import * as asyncStorage from '../../platform/server/asyncStorage'; +import * as connection from '../../platform/server/connection'; import logger from '../../platform/server/log'; import { sequential, once } from '../../shared/async'; import { setIn, getIn } from '../../shared/util'; @@ -12,6 +13,7 @@ import { merkle, } from '../crdt'; import * as db from '../db'; +import { PostError, SyncError } from '../errors'; import app from '../main-app'; import { runMutator } from '../mutators'; import { postBinary } from '../post'; @@ -23,9 +25,6 @@ import * as undo from '../undo'; import * as encoder from './encoder'; import { rebuildMerkleHash } from './repair'; -const connection = require('../../platform/server/connection'); -const { PostError, SyncError } = require('../errors'); - export { default as makeTestMessage } from './make-test-message'; export { default as resetSync } from './reset'; export { default as repairSync } from './repair'; diff --git a/packages/loot-core/src/server/sync/make-test-message.js b/packages/loot-core/src/server/sync/make-test-message.js index 01af04b3f8..e4173925b0 100644 --- a/packages/loot-core/src/server/sync/make-test-message.js +++ b/packages/loot-core/src/server/sync/make-test-message.js @@ -1,6 +1,6 @@ import * as encryption from '../encryption'; -let SyncPb = require('./proto/sync_pb'); +import * as SyncPb from './proto/sync_pb'; async function randomString() { return (await encryption.randomBytes(12)).toString(); diff --git a/packages/loot-core/src/server/sync/reset.js b/packages/loot-core/src/server/sync/reset.js index e9d6477b91..4f21dc0cd4 100644 --- a/packages/loot-core/src/server/sync/reset.js +++ b/packages/loot-core/src/server/sync/reset.js @@ -1,12 +1,11 @@ import { captureException } from '../../platform/exceptions'; -import asyncStorage from '../../platform/server/asyncStorage'; +import * as asyncStorage from '../../platform/server/asyncStorage'; +import * as connection from '../../platform/server/connection'; import * as cloudStorage from '../cloud-storage'; import * as db from '../db'; import { runMutator } from '../mutators'; import * as prefs from '../prefs'; -const connection = require('../../platform/server/connection'); - export default async function resetSync(keyState) { if (!keyState) { // If we aren't resetting the key, make sure our key is up-to-date diff --git a/packages/loot-core/src/server/sync/sync.property.test.js b/packages/loot-core/src/server/sync/sync.property.test.js index 01f9cbd34b..454a1f3d26 100644 --- a/packages/loot-core/src/server/sync/sync.property.test.js +++ b/packages/loot-core/src/server/sync/sync.property.test.js @@ -1,20 +1,20 @@ +import jsc from 'jsverify'; + import { merkle, getClock, Timestamp } from '../crdt'; import * as db from '../db'; import * as prefs from '../prefs'; import * as sheet from '../sheet'; +import * as mockSyncServer from '../tests/mockSyncServer'; import * as encoder from './encoder'; import * as sync from './index'; -const jsc = require('jsverify'); const uuidGenerator = jsc.integer({ min: 97, max: 122 }).smap( x => String.fromCharCode(x), x => x.charCodeAt(x), ); -const mockSyncServer = require('../tests/mockSyncServer'); - beforeEach(() => { sync.setSyncingMode('enabled'); mockSyncServer.reset(); diff --git a/packages/loot-core/src/server/sync/sync.test.js b/packages/loot-core/src/server/sync/sync.test.js index b6f98b0030..a1fa6e0601 100644 --- a/packages/loot-core/src/server/sync/sync.test.js +++ b/packages/loot-core/src/server/sync/sync.test.js @@ -2,13 +2,12 @@ import { getClock, Timestamp } from '../crdt'; import * as db from '../db'; import * as prefs from '../prefs'; import * as sheet from '../sheet'; +import * as mockSyncServer from '../tests/mockSyncServer'; import * as encoder from './encoder'; import { setSyncingMode, sendMessages, applyMessages, fullSync } from './index'; -const mockSyncServer = require('../tests/mockSyncServer'); - beforeEach(() => { mockSyncServer.reset(); setSyncingMode('enabled'); diff --git a/packages/loot-core/src/server/tests/mockSyncServer.js b/packages/loot-core/src/server/tests/mockSyncServer.js index 18e4995308..f279b068a7 100644 --- a/packages/loot-core/src/server/tests/mockSyncServer.js +++ b/packages/loot-core/src/server/tests/mockSyncServer.js @@ -1,8 +1,7 @@ import { makeClock, Timestamp, merkle } from '../crdt'; +import * as SyncPb from '../sync/proto/sync_pb'; -const SyncPb = require('../sync/proto/sync_pb'); - -const defaultMockData = require('./mockData').basic; +import { basic as defaultMockData } from './mockData'; const handlers = {}; let currentMockData = defaultMockData; @@ -95,22 +94,22 @@ handlers['/plaid/transactions'] = ({ }; }; -module.exports.filterMockData = func => { +export const filterMockData = func => { let copied = JSON.parse(JSON.stringify(defaultMockData)); currentMockData = func(copied); }; -module.exports.reset = () => { +export const reset = () => { currentMockData = defaultMockData; currentClock = makeClock(new Timestamp(0, 0, '0000000000000000')); currentMessages = []; }; -module.exports.getClock = () => { +export const getClock = () => { return currentClock; }; -module.exports.getMessages = () => { +export const getMessages = () => { return currentMessages.map(msg => { let { timestamp, content } = msg; let fields = SyncPb.Message.deserializeBinary(content); @@ -125,15 +124,12 @@ module.exports.getMessages = () => { }); }; -module.exports.handlers = handlers; - -function handleRequest(url, data) { +export const handleRequest = (url, data) => { url = url.replace(/http(s)?:\/\/[^/]*/, ''); if (!handlers[url]) { throw new Error('No url handler for ' + url); } return Promise.resolve(handlers[url](data)); -} +}; -module.exports.handleRequest = handleRequest; -module.exports.handleRequestBinary = handleRequest; +export { handlers, handleRequest as handleRequestBinary }; diff --git a/packages/loot-core/src/server/undo.js b/packages/loot-core/src/server/undo.js index efdcb00d96..f6ecdf7e17 100644 --- a/packages/loot-core/src/server/undo.js +++ b/packages/loot-core/src/server/undo.js @@ -1,11 +1,10 @@ +import * as connection from '../platform/server/connection'; import { getIn } from '../shared/util'; import { Timestamp } from './crdt'; import { withMutatorContext, getMutatorContext } from './mutators'; import { sendMessages } from './sync'; -const connection = require('../platform/server/connection'); - // A marker always sits as the first entry to simplify logic let MESSAGE_HISTORY = [{ type: 'marker' }]; let CURSOR = 0; diff --git a/packages/loot-core/src/server/util/budget-name.js b/packages/loot-core/src/server/util/budget-name.js index 811904be44..a6c428cb72 100644 --- a/packages/loot-core/src/server/util/budget-name.js +++ b/packages/loot-core/src/server/util/budget-name.js @@ -1,6 +1,5 @@ -import fs from '../../platform/server/fs'; - -const uuid = require('../../platform/uuid'); +import * as fs from '../../platform/server/fs'; +import * as uuid from '../../platform/uuid'; export async function uniqueFileName(existingFiles) { let initialName = 'My Finances'; diff --git a/packages/loot-core/src/shared/transactions.test.js b/packages/loot-core/src/shared/transactions.test.js index df37c6ba0c..b448ba28ce 100644 --- a/packages/loot-core/src/shared/transactions.test.js +++ b/packages/loot-core/src/shared/transactions.test.js @@ -1,3 +1,5 @@ +import * as uuid from '../platform/uuid'; + import { splitTransaction, updateTransaction, @@ -6,8 +8,6 @@ import { makeChild, } from './transactions'; -const uuid = require('../platform/uuid'); - // const data = { // splitTransactions: generateTransaction({ amount: -5000, acct: 2 }, -2000) // }; diff --git a/packages/loot-core/src/shared/transactions.ts b/packages/loot-core/src/shared/transactions.ts index d2ed3a083f..2653b48263 100644 --- a/packages/loot-core/src/shared/transactions.ts +++ b/packages/loot-core/src/shared/transactions.ts @@ -1,6 +1,6 @@ -import { last, diffItems, applyChanges } from './util'; +import * as uuid from '../platform/uuid'; -const uuid = require('../platform/uuid'); +import { last, diffItems, applyChanges } from './util'; export function isPreviewId(id) { return id.indexOf('preview/') !== -1; diff --git a/packages/node-libofx/ffi.js b/packages/node-libofx/ffi.js index 422ec69477..d2d38a01ba 100644 --- a/packages/node-libofx/ffi.js +++ b/packages/node-libofx/ffi.js @@ -35,4 +35,4 @@ function create(libofx) { }; } -module.exports = create; +export default create; diff --git a/packages/node-libofx/index.js b/packages/node-libofx/index.js index 54b52a8acd..d6beb54667 100644 --- a/packages/node-libofx/index.js +++ b/packages/node-libofx/index.js @@ -1,5 +1,5 @@ -const createFFI = require('./ffi'); -const libofxWrapper = require('./libofx'); +import createFFI from './ffi'; +import libofxWrapper from './libofx'; let _libofxPromise; let _libofx; @@ -26,7 +26,7 @@ var parser = { }, }; -async function initModule() { +export async function initModule() { if (!_libofxPromise) { _libofxPromise = new Promise(resolve => { libofxWrapper({ @@ -59,11 +59,9 @@ async function initModule() { await _libofxPromise; } -function getOFXTransactions(data) { +export function getOFXTransactions(data) { ffi.parse_data(parser.ctx, data); let transactions = parser.transactions; parser.reset(); return transactions; } - -module.exports = { initModule, getOFXTransactions }; diff --git a/tsconfig.json b/tsconfig.json index 11deb17d73..8936baed89 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -29,5 +29,10 @@ "noEmit": true }, "include": ["packages/**/*"], - "exclude": ["**/node_modules/*", "**/build/*", "**/lib-dist/*"] + "exclude": ["**/node_modules/*", "**/build/*", "**/lib-dist/*"], + "ts-node": { + "compilerOptions": { + "module": "commonjs" + } + } } diff --git a/upcoming-release-notes/877.md b/upcoming-release-notes/877.md new file mode 100644 index 0000000000..6d362b08b2 --- /dev/null +++ b/upcoming-release-notes/877.md @@ -0,0 +1,6 @@ +--- +category: Maintenance +authors: [albertogasparin] +--- + +Convert most CommonJS imports/exports to ESM diff --git a/yarn.lock b/yarn.lock index e83512095a..f91a1defb6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -18,6 +18,7 @@ __metadata: dependencies: better-sqlite3: ^8.2.0 node-fetch: ^2.6.9 + typescript: ^5.0.2 uuid: 3.3.2 languageName: unknown linkType: soft @@ -30,6 +31,7 @@ __metadata: adm-zip: ^0.5.9 date-fns: ^2.29.3 slash: 3.0.0 + ts-node: ^10.9.1 uuid: 3.3.2 bin: import-ynab4: ./index.js @@ -42,6 +44,7 @@ __metadata: dependencies: "@actual-app/api": "*" date-fns: ^2.29.3 + ts-node: ^10.9.1 uuid: 3.3.2 bin: import-ynab5: ./index.js @@ -19771,7 +19774,7 @@ __metadata: languageName: node linkType: hard -"ts-node@npm:^10.7.0": +"ts-node@npm:^10.7.0, ts-node@npm:^10.9.1": version: 10.9.1 resolution: "ts-node@npm:10.9.1" dependencies: