moneyfunx 0.0.38 → 0.0.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { PaymentTooLowError } from "./lib/errors";
2
2
  export { calculateMinPayment, numPaymentsToZero, principalRemaining, interestPaid, } from "./lib/helperFunctions";
3
- export { ILoan, Loan } from "./lib/loan";
3
+ export { type ILoan, Loan } from "./lib/loan";
4
4
  export { determineExtraPayment, amortizePayments, payLoans, } from "./lib/payments";
5
- export { AmortizationRecord, LoansPaymentSummary, PaymentSummary, } from "./lib/paymentTypes";
5
+ export { type AmortizationRecord, type LoansPaymentSummary, type PaymentSummary, } from "./lib/paymentTypes";
6
6
  export { snowball, avalanche, sortLoans } from "./lib/sorting";
@@ -6,11 +6,8 @@ export interface AmortizationRecord {
6
6
  }
7
7
  export interface PaymentSummary {
8
8
  lifetimeInterest: number;
9
- amortizationSchedule: Array<AmortizationRecord>;
10
- }
11
- export interface LoansPaymentSummary {
12
- [id: string]: PaymentSummary;
13
- }
14
- export interface LoanPrincipals {
15
- [id: string]: number;
9
+ lifetimePrincipal: number;
10
+ amortizationSchedule: AmortizationRecord[];
16
11
  }
12
+ export type LoansPaymentSummary = Record<string, PaymentSummary>;
13
+ export type LoanPrincipals = Record<string, number>;
@@ -3,8 +3,8 @@
3
3
  * This file contains functions for computing detailed information on paying loans
4
4
  *
5
5
  */
6
- import { ILoan, Loan } from "./loan";
7
- import { AmortizationRecord, LoansPaymentSummary } from "./paymentTypes";
6
+ import type { ILoan, Loan } from "./loan";
7
+ import type { AmortizationRecord, LoansPaymentSummary } from "./paymentTypes";
8
8
  /**
9
9
  *
10
10
  * Calculates the extra amount in a payment after all loans' minimum payments are met
@@ -14,7 +14,7 @@ import { AmortizationRecord, LoansPaymentSummary } from "./paymentTypes";
14
14
  * @param {number} payment The amount to pay across all loans
15
15
  * @returns {number} The extra amount of payment
16
16
  */
17
- export declare function determineExtraPayment(loans: Array<ILoan>, payment: number): number;
17
+ export declare function determineExtraPayment(loans: ILoan[], payment: number): number;
18
18
  /**
19
19
  *
20
20
  * Calculates the amortization schedule for a loan paid with a payment
@@ -25,7 +25,7 @@ export declare function determineExtraPayment(loans: Array<ILoan>, payment: numb
25
25
  * @param {number} startPeriod An initial offset of periods to "fast-forward" the state of the loan to prior to calculation of each period
26
26
  * @returns {Array<AmortizationRecord>} The amortization schdule for the number of payments of payment made to the loan from the provided start period
27
27
  */
28
- export declare function amortizePayments(loan: Loan, principal: number, payment: number, numPayments: number, startPeriod?: number, carryover?: number): Array<AmortizationRecord>;
28
+ export declare function amortizePayments(loan: Loan, principal: number, payment: number, numPayments: number, startPeriod?: number, carryover?: number): AmortizationRecord[];
29
29
  /**
30
30
  *
31
31
  * Calculates a wealth of information about paying of a set of loans with a total payment amount
@@ -40,16 +40,18 @@ export function amortizePayments(loan, principal, payment, numPayments, startPer
40
40
  numPayments = loan.numPaymentsToZero(payment);
41
41
  }
42
42
  let principalRemaining = principal;
43
- let amortizationSchedule = [];
43
+ const amortizationSchedule = [];
44
44
  for (let period = 0; period < numPayments; period++) {
45
- let interestThisPeriod = loan.accrueInterest(principalRemaining);
46
- let principalThisPeriod = Math.min((period === numPayments - 1 ? payment + carryover : payment) - interestThisPeriod, principalRemaining);
45
+ const interestThisPeriod = loan.accrueInterest(principalRemaining);
46
+ const principalThisPeriod = Math.min((period === numPayments - 1
47
+ ? payment + carryover
48
+ : payment) - interestThisPeriod, principalRemaining);
47
49
  principalRemaining -= principalThisPeriod;
48
50
  amortizationSchedule.push({
49
51
  period: startPeriod + period + 1,
50
52
  principal: principalThisPeriod,
51
53
  interest: interestThisPeriod,
52
- principalRemaining: principalRemaining,
54
+ principalRemaining,
53
55
  });
54
56
  }
55
57
  return amortizationSchedule;
@@ -68,13 +70,18 @@ export function payLoans(loans, payment, reduceMinimum = false) {
68
70
  let monthlyPayment = payment;
69
71
  const paymentData = {};
70
72
  const loanPrincipalsRemaining = {};
71
- loans.map((loan) => {
72
- paymentData[loan.id] = { lifetimeInterest: 0, amortizationSchedule: [] };
73
+ loans.forEach((loan) => {
74
+ paymentData[loan.id] = {
75
+ lifetimeInterest: 0,
76
+ lifetimePrincipal: loan.principal,
77
+ amortizationSchedule: []
78
+ };
73
79
  loanPrincipalsRemaining[loan.id] = loan.principal;
74
80
  });
75
81
  let periodsElapsed = 0;
76
82
  let paidLoans = 0;
77
83
  let totalLifetimeInterest = 0;
84
+ let totalLifetimePrincipal = 0;
78
85
  let totalAmortizationSchedule = [];
79
86
  while (paidLoans < loans.length) {
80
87
  const firstLoan = loans.slice(paidLoans)[0];
@@ -83,7 +90,7 @@ export function payLoans(loans, payment, reduceMinimum = false) {
83
90
  const firstLoanPrincipalRemaining = loanPrincipalsRemaining[firstLoan.id];
84
91
  const periodsToPay = helpers.numPaymentsToZero(firstLoanPrincipalRemaining, firstLoanPayment, firstLoan.periodicRate);
85
92
  const firstLoanPaidPeriods = amortizePayments(firstLoan, firstLoanPrincipalRemaining, firstLoanPayment, periodsToPay, periodsElapsed);
86
- const firstLoanCarryover = firstLoanPayment - firstLoan.principalRemaining(periodsToPay - 1, firstLoanPayment, firstLoanPrincipalRemaining);
93
+ const firstLoanCarryover = firstLoanPayment - (firstLoan.principalRemaining(periodsToPay - 1, firstLoanPayment, firstLoanPrincipalRemaining) + firstLoan.accrueInterest(firstLoan.principalRemaining(periodsToPay - 1, firstLoanPayment, firstLoanPrincipalRemaining)));
87
94
  paymentData[firstLoan.id].amortizationSchedule = [
88
95
  ...paymentData[firstLoan.id].amortizationSchedule,
89
96
  ...firstLoanPaidPeriods
@@ -104,7 +111,7 @@ export function payLoans(loans, payment, reduceMinimum = false) {
104
111
  loanPrincipalsRemaining[loan.id] = paymentData[loan.id].amortizationSchedule[paymentData[loan.id].amortizationSchedule.length - 1].principalRemaining;
105
112
  totalAmortizationSchedule = totalAmortizationSchedule.map((element) => {
106
113
  const matchedInnerElement = paidPeriods.find((innerElement) => innerElement.period === element.period);
107
- return matchedInnerElement
114
+ return (matchedInnerElement != null)
108
115
  ? {
109
116
  period: element.period,
110
117
  principal: element.principal + matchedInnerElement.principal,
@@ -121,12 +128,15 @@ export function payLoans(loans, payment, reduceMinimum = false) {
121
128
  periodsElapsed += periodsToPay;
122
129
  }
123
130
  for (const loan of loans) {
124
- const loanLifetimeInterest = paymentData[loan.id].amortizationSchedule.reduce((acc, curval) => acc + curval.interest, 0);
131
+ const loanLifetimeInterest = (paymentData[loan.id].amortizationSchedule.reduce((acc, curval) => acc + curval.interest, 0));
125
132
  paymentData[loan.id].lifetimeInterest = loanLifetimeInterest;
133
+ paymentData[loan.id].lifetimePrincipal = loan.principal;
126
134
  totalLifetimeInterest += loanLifetimeInterest;
135
+ totalLifetimePrincipal += loan.principal;
127
136
  }
128
- paymentData["totals"] = {
137
+ paymentData.totals = {
129
138
  lifetimeInterest: totalLifetimeInterest,
139
+ lifetimePrincipal: totalLifetimePrincipal,
130
140
  amortizationSchedule: totalAmortizationSchedule
131
141
  };
132
142
  return paymentData;
@@ -3,7 +3,7 @@
3
3
  * This file contains functions for sorting Arrays of Loans on certain attributes
4
4
  *
5
5
  */
6
- import { ILoan } from "./loan";
6
+ import { type ILoan } from "./loan";
7
7
  type avalanche = (loan1: ILoan, loan2: ILoan) => number;
8
8
  type snowball = (loan1: ILoan, loan2: ILoan) => number;
9
9
  type sortFunction = avalanche | snowball;
@@ -27,5 +27,5 @@ export declare function snowball(loan1: ILoan, loan2: ILoan): number;
27
27
  * @param {function} sortFunc The algorithm to sort the loans with
28
28
  * @returns The sorted array loans
29
29
  */
30
- export declare function sortLoans(loans: Array<ILoan>, sortFunction: sortFunction): ILoan[];
30
+ export declare function sortLoans(loans: ILoan[], sortFunction: sortFunction): ILoan[];
31
31
  export {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "moneyfunx",
3
3
  "type": "module",
4
- "version": "0.0.38",
4
+ "version": "0.0.40",
5
5
  "description": "MoneyFunx is a small library of functions for financial computations, with a focus on personal finance",
6
6
  "main": "build/index.js",
7
7
  "types": "build/index.d.ts",
package/src/index.ts CHANGED
@@ -5,15 +5,15 @@ export {
5
5
  principalRemaining,
6
6
  interestPaid,
7
7
  } from "./lib/helperFunctions";
8
- export { ILoan, Loan } from "./lib/loan";
8
+ export { type ILoan, Loan } from "./lib/loan";
9
9
  export {
10
10
  determineExtraPayment,
11
11
  amortizePayments,
12
12
  payLoans,
13
13
  } from "./lib/payments";
14
14
  export {
15
- AmortizationRecord,
16
- LoansPaymentSummary,
17
- PaymentSummary,
15
+ type AmortizationRecord,
16
+ type LoansPaymentSummary,
17
+ type PaymentSummary,
18
18
  } from "./lib/paymentTypes";
19
19
  export { snowball, avalanche, sortLoans } from "./lib/sorting";
@@ -7,13 +7,10 @@ export interface AmortizationRecord {
7
7
 
8
8
  export interface PaymentSummary {
9
9
  lifetimeInterest: number;
10
- amortizationSchedule: Array<AmortizationRecord>;
10
+ lifetimePrincipal: number;
11
+ amortizationSchedule: AmortizationRecord[];
11
12
  }
12
13
 
13
- export interface LoansPaymentSummary {
14
- [id: string]: PaymentSummary;
15
- }
14
+ export type LoansPaymentSummary = Record<string, PaymentSummary>;
16
15
 
17
- export interface LoanPrincipals {
18
- [id: string]: number;
19
- }
16
+ export type LoanPrincipals = Record<string, number>;
@@ -6,12 +6,11 @@
6
6
 
7
7
  import * as errors from "./errors";
8
8
  import * as helpers from "./helperFunctions";
9
- import { ILoan, Loan } from "./loan";
10
- import {
9
+ import type { ILoan, Loan } from "./loan";
10
+ import type {
11
11
  AmortizationRecord,
12
12
  LoanPrincipals,
13
13
  LoansPaymentSummary,
14
- PaymentSummary,
15
14
  } from "./paymentTypes";
16
15
 
17
16
  /**
@@ -24,7 +23,7 @@ import {
24
23
  * @returns {number} The extra amount of payment
25
24
  */
26
25
  export function determineExtraPayment(
27
- loans: Array<ILoan>,
26
+ loans: ILoan[],
28
27
  payment: number
29
28
  ): number {
30
29
  const totalMinPayment = loans.reduce(
@@ -56,7 +55,7 @@ export function amortizePayments(
56
55
  numPayments: number,
57
56
  startPeriod: number = 0,
58
57
  carryover: number = 0
59
- ): Array<AmortizationRecord> {
58
+ ): AmortizationRecord[] {
60
59
  if (payment === null) {
61
60
  payment = loan.minPayment;
62
61
  }
@@ -68,11 +67,13 @@ export function amortizePayments(
68
67
 
69
68
  let principalRemaining = principal;
70
69
 
71
- let amortizationSchedule: AmortizationRecord[] = [];
70
+ const amortizationSchedule: AmortizationRecord[] = [];
72
71
  for (let period = 0; period < numPayments; period++) {
73
- let interestThisPeriod = loan.accrueInterest(principalRemaining);
74
- let principalThisPeriod = Math.min(
75
- (period === numPayments - 1 ? payment + carryover : payment) - interestThisPeriod,
72
+ const interestThisPeriod = loan.accrueInterest(principalRemaining);
73
+ const principalThisPeriod = Math.min(
74
+ (period === numPayments - 1
75
+ ? payment + carryover
76
+ : payment) - interestThisPeriod,
76
77
  principalRemaining
77
78
  );
78
79
  principalRemaining -= principalThisPeriod;
@@ -80,7 +81,7 @@ export function amortizePayments(
80
81
  period: startPeriod + period + 1,
81
82
  principal: principalThisPeriod,
82
83
  interest: interestThisPeriod,
83
- principalRemaining: principalRemaining,
84
+ principalRemaining,
84
85
  });
85
86
  }
86
87
  return amortizationSchedule;
@@ -104,14 +105,19 @@ export function payLoans(
104
105
  let monthlyPayment = payment;
105
106
  const paymentData: LoansPaymentSummary = {};
106
107
  const loanPrincipalsRemaining: LoanPrincipals = {};
107
- loans.map((loan) => {
108
- paymentData[loan.id] = { lifetimeInterest: 0, amortizationSchedule: [] };
108
+ loans.forEach((loan) => {
109
+ paymentData[loan.id] = {
110
+ lifetimeInterest: 0,
111
+ lifetimePrincipal: loan.principal,
112
+ amortizationSchedule: []
113
+ };
109
114
  loanPrincipalsRemaining[loan.id] = loan.principal;
110
115
  });
111
116
 
112
117
  let periodsElapsed = 0;
113
118
  let paidLoans = 0;
114
119
  let totalLifetimeInterest = 0;
120
+ let totalLifetimePrincipal = 0;
115
121
  let totalAmortizationSchedule: AmortizationRecord[] = [];
116
122
 
117
123
  while (paidLoans < loans.length) {
@@ -132,10 +138,18 @@ export function payLoans(
132
138
  periodsToPay,
133
139
  periodsElapsed
134
140
  );
135
- const firstLoanCarryover = firstLoanPayment - firstLoan.principalRemaining(
136
- periodsToPay - 1,
137
- firstLoanPayment,
138
- firstLoanPrincipalRemaining
141
+ const firstLoanCarryover = firstLoanPayment - (
142
+ firstLoan.principalRemaining(
143
+ periodsToPay - 1,
144
+ firstLoanPayment,
145
+ firstLoanPrincipalRemaining
146
+ ) + firstLoan.accrueInterest(
147
+ firstLoan.principalRemaining(
148
+ periodsToPay - 1,
149
+ firstLoanPayment,
150
+ firstLoanPrincipalRemaining
151
+ )
152
+ )
139
153
  );
140
154
  paymentData[firstLoan.id].amortizationSchedule = [
141
155
  ...paymentData[firstLoan.id].amortizationSchedule,
@@ -172,15 +186,15 @@ export function payLoans(
172
186
  const matchedInnerElement = paidPeriods.find(
173
187
  (innerElement) => innerElement.period === element.period
174
188
  );
175
- return matchedInnerElement
189
+ return (matchedInnerElement != null)
176
190
  ? {
177
- period: element.period,
178
- principal: element.principal + matchedInnerElement.principal,
179
- interest: element.interest + matchedInnerElement.interest,
180
- principalRemaining:
181
- element.principalRemaining +
182
- matchedInnerElement.principalRemaining
183
- }
191
+ period: element.period,
192
+ principal: element.principal + matchedInnerElement.principal,
193
+ interest: element.interest + matchedInnerElement.interest,
194
+ principalRemaining:
195
+ element.principalRemaining +
196
+ matchedInnerElement.principalRemaining
197
+ }
184
198
  : element;
185
199
  });
186
200
  });
@@ -192,13 +206,21 @@ export function payLoans(
192
206
  }
193
207
 
194
208
  for (const loan of loans) {
195
- const loanLifetimeInterest = paymentData[loan.id].amortizationSchedule.reduce((acc, curval) => acc + curval.interest, 0);
209
+ const loanLifetimeInterest = (
210
+ paymentData[loan.id].amortizationSchedule.reduce(
211
+ (acc, curval) => acc + curval.interest,
212
+ 0
213
+ )
214
+ );
196
215
  paymentData[loan.id].lifetimeInterest = loanLifetimeInterest;
216
+ paymentData[loan.id].lifetimePrincipal = loan.principal;
197
217
  totalLifetimeInterest += loanLifetimeInterest;
218
+ totalLifetimePrincipal += loan.principal;
198
219
  }
199
220
 
200
- paymentData["totals"] = {
221
+ paymentData.totals = {
201
222
  lifetimeInterest: totalLifetimeInterest,
223
+ lifetimePrincipal: totalLifetimePrincipal,
202
224
  amortizationSchedule: totalAmortizationSchedule
203
225
  };
204
226
 
@@ -4,7 +4,7 @@
4
4
  *
5
5
  */
6
6
 
7
- import { ILoan } from "./loan";
7
+ import { type ILoan } from "./loan";
8
8
 
9
9
  type avalanche = (loan1: ILoan, loan2: ILoan) => number;
10
10
  type snowball = (loan1: ILoan, loan2: ILoan) => number;
@@ -36,6 +36,6 @@ export function snowball(loan1: ILoan, loan2: ILoan) {
36
36
  * @param {function} sortFunc The algorithm to sort the loans with
37
37
  * @returns The sorted array loans
38
38
  */
39
- export function sortLoans(loans: Array<ILoan>, sortFunction: sortFunction) {
39
+ export function sortLoans(loans: ILoan[], sortFunction: sortFunction) {
40
40
  return loans.sort(sortFunction);
41
41
  }