diff --git a/.oxlintrc.json b/.oxlintrc.json index c51a563682..f1c3d9b482 100644 --- a/.oxlintrc.json +++ b/.oxlintrc.json @@ -102,8 +102,8 @@ // we want to allow unions such as "{ name: DbAccount['name'] | DbPayee['name'] }" "typescript/no-duplicate-type-constituents": "off", "typescript/await-thenable": "error", - "typescript/no-floating-promises": "warn", // TODO: covert to error - "typescript/require-array-sort-compare": "warn", // TODO: covert to error + "typescript/no-floating-promises": "error", + "typescript/require-array-sort-compare": "error", "typescript/unbound-method": "error", "typescript/no-for-in-array": "warn", // TODO: covert to error "typescript/restrict-template-expressions": "warn", // TODO: covert to error diff --git a/packages/crdt/src/crdt/merkle.ts b/packages/crdt/src/crdt/merkle.ts index 715f4efdc1..6474057cea 100644 --- a/packages/crdt/src/crdt/merkle.ts +++ b/packages/crdt/src/crdt/merkle.ts @@ -91,7 +91,7 @@ export function diff(trie1: TrieNode, trie2: TrieNode): number | null { while (true) { const keyset = new Set([...getKeys(node1), ...getKeys(node2)]); const keys = [...keyset.values()]; - keys.sort(); + keys.sort((a, b) => a.localeCompare(b)); let diffkey: null | '0' | '1' | '2' = null; @@ -145,7 +145,7 @@ export function prune(trie: TrieNode, n = 2): TrieNode { } const keys = getKeys(trie); - keys.sort(); + keys.sort((a, b) => a.localeCompare(b)); const next: TrieNode = { hash: trie.hash }; diff --git a/packages/desktop-client/src/components/budget/BudgetSummaries.tsx b/packages/desktop-client/src/components/budget/BudgetSummaries.tsx index 970c786edb..c9778f6088 100644 --- a/packages/desktop-client/src/components/budget/BudgetSummaries.tsx +++ b/packages/desktop-client/src/components/budget/BudgetSummaries.tsx @@ -55,7 +55,7 @@ export function BudgetSummaries() { } const to = -offsetX; - spring.start({ from: { x: from }, x: to }); + void spring.start({ from: { x: from }, x: to }); }, [spring, firstMonth, monthWidth, allMonths]); useLayoutEffect(() => { @@ -63,7 +63,7 @@ export function BudgetSummaries() { }, [firstMonth]); useLayoutEffect(() => { - spring.start({ from: { x: -monthWidth }, to: { x: -monthWidth } }); + void spring.start({ from: { x: -monthWidth }, to: { x: -monthWidth } }); }, [spring, monthWidth]); const { SummaryComponent } = useBudgetComponents(); diff --git a/packages/desktop-client/src/components/filters/FiltersMenu.tsx b/packages/desktop-client/src/components/filters/FiltersMenu.tsx index 05a8337fba..d3afeec7ce 100644 --- a/packages/desktop-client/src/components/filters/FiltersMenu.tsx +++ b/packages/desktop-client/src/components/filters/FiltersMenu.tsx @@ -518,7 +518,7 @@ export function FilterButton({ items={[ ...translatedFilterFields .filter(f => (exclude ? !exclude.includes(f[0]) : true)) - .sort() + .sort((a, b) => a[0].localeCompare(b[0])) .map(([name, text]) => ({ name, text: titleFirst(text), diff --git a/packages/desktop-client/src/components/mobile/ActionableGridListItem.tsx b/packages/desktop-client/src/components/mobile/ActionableGridListItem.tsx index 56ca9490e0..13a68054be 100644 --- a/packages/desktop-client/src/components/mobile/ActionableGridListItem.tsx +++ b/packages/desktop-client/src/components/mobile/ActionableGridListItem.tsx @@ -47,7 +47,7 @@ export function ActionableGridListItem({ if (active) { dragStartedRef.current = true; - api.start({ + void api.start({ x: Math.max(-actionsWidth, Math.min(0, currentX)), onRest: () => { dragStartedRef.current = false; @@ -61,7 +61,7 @@ export function ActionableGridListItem({ currentX < -actionsWidth / 2 || (vx < -0.5 && currentX < -actionsWidth / 5); - api.start({ + void api.start({ x: shouldReveal ? -actionsWidth : 0, onRest: () => { dragStartedRef.current = false; @@ -140,7 +140,7 @@ export function ActionableGridListItem({ {typeof actions === 'function' ? actions({ close: () => { - api.start({ + void api.start({ x: 0, onRest: () => { setIsRevealed(false); diff --git a/packages/desktop-client/src/components/mobile/MobileNavTabs.tsx b/packages/desktop-client/src/components/mobile/MobileNavTabs.tsx index aed83c8486..9af026bf15 100644 --- a/packages/desktop-client/src/components/mobile/MobileNavTabs.tsx +++ b/packages/desktop-client/src/components/mobile/MobileNavTabs.tsx @@ -59,7 +59,7 @@ export function MobileNavTabs() { // when cancel is true, it means that the user passed the upwards threshold // so we change the spring config to create a nice wobbly effect setNavbarState('open'); - api.start({ + void api.start({ y: OPEN_FULL_Y, immediate: isTestEnv, config: canceled ? config.wobbly : config.stiff, @@ -71,7 +71,7 @@ export function MobileNavTabs() { const openDefault = useCallback( (velocity = 0) => { setNavbarState('default'); - api.start({ + void api.start({ y: OPEN_DEFAULT_Y, immediate: isTestEnv, config: { ...config.stiff, velocity }, @@ -83,7 +83,7 @@ export function MobileNavTabs() { const hide = useCallback( (velocity = 0) => { setNavbarState('hidden'); - api.start({ + void api.start({ y: HIDDEN_Y, immediate: isTestEnv, config: { ...config.stiff, velocity }, @@ -199,7 +199,7 @@ export function MobileNavTabs() { } else { // when the user keeps dragging, we just move the sheet according to // the cursor position - api.start({ y: oy, immediate: true }); + void api.start({ y: oy, immediate: true }); } }, { diff --git a/packages/desktop-client/src/components/mobile/transactions/TransactionEdit.tsx b/packages/desktop-client/src/components/mobile/transactions/TransactionEdit.tsx index 3833ab3c7c..52c72e9e1d 100644 --- a/packages/desktop-client/src/components/mobile/transactions/TransactionEdit.tsx +++ b/packages/desktop-client/src/components/mobile/transactions/TransactionEdit.tsx @@ -1680,7 +1680,7 @@ function TransactionEditUnconnected({ ...serializeTransaction(transaction, dateFormat), payee: nearestPayee.id, }; - onUpdate(updated, 'payee'); + void onUpdate(updated, 'payee'); }, [transactions, nearestPayee, onUpdate, dateFormat]); if (accounts.length === 0) { diff --git a/packages/desktop-client/src/hooks/useScheduleEdit.ts b/packages/desktop-client/src/hooks/useScheduleEdit.ts index 7150f294e1..436775e39b 100644 --- a/packages/desktop-client/src/hooks/useScheduleEdit.ts +++ b/packages/desktop-client/src/hooks/useScheduleEdit.ts @@ -164,9 +164,11 @@ function createScheduleEditReducer(useGetScheduledAmount: boolean = false) { const transactions = action.transactions; // Sort transactions if we have a transactionId to prioritize if (action.transactionId && transactions) { - transactions.sort(a => { - return action.transactionId === a.id ? -1 : 1; - }); + transactions.sort( + (a, b) => + (action.transactionId === b.id ? 1 : 0) - + (action.transactionId === a.id ? 1 : 0), + ); } return { ...state, transactions }; } diff --git a/packages/desktop-electron/index.ts b/packages/desktop-electron/index.ts index f8be545225..1095192838 100644 --- a/packages/desktop-electron/index.ts +++ b/packages/desktop-electron/index.ts @@ -420,8 +420,10 @@ async function createWindow() { clientWin = win; // Execute queued logs - displaying them in the client window - queuedClientWinLogs.map((log: string) => - win.webContents.executeJavaScript(log), + void Promise.all( + queuedClientWinLogs.map((log: string) => + win.webContents.executeJavaScript(log), + ), ); queuedClientWinLogs = []; diff --git a/packages/loot-core/src/server/aql/exec.test.ts b/packages/loot-core/src/server/aql/exec.test.ts index fd1a285cc7..5495c8e372 100644 --- a/packages/loot-core/src/server/aql/exec.test.ts +++ b/packages/loot-core/src/server/aql/exec.test.ts @@ -271,7 +271,7 @@ describe('compileAndRunQuery', () => { 'SELECT id FROM transactions WHERE amount < -50', ); const ids = rows.slice(0, 3).map(row => row.id); - ids.sort(); + ids.sort((a, b) => String(a).localeCompare(String(b))); const { data } = await compileAndRunAqlQuery( q('transactions') @@ -280,6 +280,10 @@ describe('compileAndRunQuery', () => { .raw() .serialize(), ); - expect(data.map(row => row.id).sort()).toEqual(ids); + expect( + data + .map(row => row.id) + .sort((a, b) => String(a).localeCompare(String(b))), + ).toEqual(ids); }); }); diff --git a/packages/loot-core/src/server/budget/category-template-context.ts b/packages/loot-core/src/server/budget/category-template-context.ts index 7b500073d2..6000b23ba9 100644 --- a/packages/loot-core/src/server/budget/category-template-context.ts +++ b/packages/loot-core/src/server/budget/category-template-context.ts @@ -124,7 +124,9 @@ export class CategoryTemplateContext { // what is the full requested amount this month async runAll(available: number) { let toBudget: number = 0; - const prioritiesSorted = new Int32Array([...this.getPriorities()].sort()); + const prioritiesSorted = new Int32Array( + [...this.getPriorities()].sort((a, b) => a - b), + ); for (let i = 0; i < prioritiesSorted.length; i++) { const p = prioritiesSorted[i]; toBudget += await this.runTemplatesForPriority(p, available, available); diff --git a/packages/loot-core/src/server/budget/goal-template.ts b/packages/loot-core/src/server/budget/goal-template.ts index 2b78e1b0a9..15a6087835 100644 --- a/packages/loot-core/src/server/budget/goal-template.ts +++ b/packages/loot-core/src/server/budget/goal-template.ts @@ -258,7 +258,7 @@ async function processTemplate( }; } - const priorities = new Int32Array([...prioritiesSet]).sort(); + const priorities = new Int32Array([...prioritiesSet]).sort((a, b) => a - b); // run each priority level for (const priority of priorities) { const availStart = availBudget; diff --git a/packages/loot-core/src/server/main.test.ts b/packages/loot-core/src/server/main.test.ts index e2497788c1..50015bea46 100644 --- a/packages/loot-core/src/server/main.test.ts +++ b/packages/loot-core/src/server/main.test.ts @@ -261,7 +261,9 @@ describe('Budget', () => { let changed = await captureChangedCells(() => runHandler(handlers['transaction-add'], trans), ); - expect(changed.sort()).toMatchSnapshot(); + expect( + changed.sort((a, b) => (a > b ? 1 : a < b ? -1 : 0)), + ).toMatchSnapshot(); // Test updates changed = await captureChangedCells(async () => { await runHandler(handlers['transaction-update'], { @@ -269,12 +271,16 @@ describe('Budget', () => { amount: 7000, }); }); - expect(changed.sort()).toMatchSnapshot(); + expect( + changed.sort((a, b) => (a > b ? 1 : a < b ? -1 : 0)), + ).toMatchSnapshot(); // Test deletions changed = await captureChangedCells(async () => { await runHandler(handlers['transaction-delete'], { id: trans.id }); }); - expect(changed.sort()).toMatchSnapshot(); + expect( + changed.sort((a, b) => (a > b ? 1 : a < b ? -1 : 0)), + ).toMatchSnapshot(); }); }); diff --git a/packages/loot-core/src/shared/transactions.test.ts b/packages/loot-core/src/shared/transactions.test.ts index ac55755d2d..bedd5a6ec0 100644 --- a/packages/loot-core/src/shared/transactions.test.ts +++ b/packages/loot-core/src/shared/transactions.test.ts @@ -51,7 +51,14 @@ describe('Transactions', () => { deleted: [], updated: [expect.objectContaining({ id: 't1', amount: 5000 })], }); - expect(data.map(t => ({ id: t.id, amount: t.amount })).sort()).toEqual([ + expect( + data + .map(t => ({ id: t.id, amount: t.amount })) + .sort( + (a, b) => + b.amount - a.amount || String(a.id).localeCompare(String(b.id)), + ), + ).toEqual([ { id: expect.any(String), amount: 5000 }, { id: 't1', amount: 5000 }, { id: expect.any(String), amount: 3000 }, @@ -66,7 +73,14 @@ describe('Transactions', () => { ]; const { data, diff } = updateTransaction(transactions, updatedTransaction); expect(diff).toEqual({ added: [], deleted: [], updated: [] }); - expect(data.map(t => ({ id: t.id, amount: t.amount })).sort()).toEqual([ + expect( + data + .map(t => ({ id: t.id, amount: t.amount })) + .sort( + (a, b) => + b.amount - a.amount || String(a.id).localeCompare(String(b.id)), + ), + ).toEqual([ { id: expect.any(String), amount: 5000 }, { id: expect.any(String), amount: 3000 }, ]); @@ -85,7 +99,14 @@ describe('Transactions', () => { deleted: [{ id: 't1' }], updated: [], }); - expect(data.map(t => ({ id: t.id, amount: t.amount })).sort()).toEqual([ + expect( + data + .map(t => ({ id: t.id, amount: t.amount })) + .sort( + (a, b) => + b.amount - a.amount || String(a.id).localeCompare(String(b.id)), + ), + ).toEqual([ { id: expect.any(String), amount: 5000 }, { id: expect.any(String), amount: 3000 }, ]); diff --git a/packages/sync-server/src/migrations.ts b/packages/sync-server/src/migrations.ts index d57ecc40c4..0ded782bc9 100644 --- a/packages/sync-server/src/migrations.ts +++ b/packages/sync-server/src/migrations.ts @@ -31,7 +31,7 @@ export async function run(direction: 'up' | 'down' = 'up'): Promise { .filter( f => (f.endsWith('.js') || f.endsWith('.ts')) && !f.endsWith('.d.ts'), ) - .sort()) { + .sort((a, b) => (a > b ? 1 : a < b ? -1 : 0))) { migrationsModules[f] = await import( pathToFileURL(path.join(migrationsDir, f)).href ); diff --git a/upcoming-release-notes/7168.md b/upcoming-release-notes/7168.md new file mode 100644 index 0000000000..ade49321a4 --- /dev/null +++ b/upcoming-release-notes/7168.md @@ -0,0 +1,6 @@ +--- +category: Maintenance +authors: [MatissJanis] +--- + +Lint: fix 'typescript/no-floating-promises' and 'typescript/require-array-sort-compare' issues