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: