🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

loanjs

Package Overview
Dependencies
Maintainers
1
Versions
26
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

loanjs - npm Package Compare versions

Comparing version
1.0.12
to
1.1.0
+69
-18
dist/loan.js

@@ -38,20 +38,62 @@ "use strict";

/**
* @type {import("../types").GetNextInstalmentPartFunction}
*/
function getNextDiminishingInstalment(amount, installmentsNumber, capitalSum, interestRateMonth) {
var capital = rnd(amount / installmentsNumber);
var interest = rnd((amount - capitalSum) * interestRateMonth);
var installment = capital + interest;
return {
capital: capital,
interest: interest,
installment: installment
};
}
/**
* @type {import("../types").GetNextInstalmentPartFunction}
*/
function getNextAnnuityInstalment(amount, installmentsNumber, capitalSum, interestRateMonth) {
var z = 1 / (1 + interestRateMonth);
var div = (1 - Math.pow(z, installmentsNumber)) * z;
var installment = rnd(amount * (1 - z) / div);
var interest = rnd((amount - capitalSum) * interestRateMonth);
var capital = installment - interest;
return {
capital: capital,
interest: interest,
installment: installment
};
}
/**
* @type {import("../types").GetNextInstalmentPartFunction}
*/
function getNextAnnuityDueInstalment(amount, installmentsNumber, capitalSum, interestRateMonth) {
var z = 1 / (1 + interestRateMonth);
var div = 1 - Math.pow(z, installmentsNumber);
var installment = rnd(amount * (1 - z) / div);
var interest = rnd((amount - capitalSum) * interestRateMonth);
var capital = installment - interest;
return {
capital: capital,
interest: interest,
installment: installment
};
}
var nextInstalmentFnMap = {
annuity: getNextAnnuityInstalment,
diminishing: getNextDiminishingInstalment,
annuityDue: getNextAnnuityDueInstalment
};
/**
* @type {import("../types").GetNextInstalmentFunction}
*/
var getNextInstalment = function getNextInstalment(amount, installmentsNumber, interestRate, diminishing, capitalSum, interestSum) {
var capital;
var interest;
var installment;
var irmPow;
function getNextInstalment(amount, installmentsNumber, interestRate, loanType, capitalSum, interestSum) {
var interestRateMonth = interestRate / 1200;
if (diminishing) {
capital = rnd(amount / installmentsNumber);
interest = rnd((amount - capitalSum) * interestRateMonth);
installment = capital + interest;
} else {
irmPow = Math.pow(1 + interestRateMonth, installmentsNumber);
installment = rnd(amount * (interestRateMonth * irmPow / (irmPow - 1)));
interest = rnd((amount - capitalSum) * interestRateMonth);
capital = installment - interest;
}
var nextInstalmentFn = typeof loanType === 'function' ? loanType : nextInstalmentFnMap[loanType] || getNextAnnuityInstalment;
var _nextInstalmentFn = nextInstalmentFn(amount, installmentsNumber, capitalSum, interestRateMonth),
capital = _nextInstalmentFn.capital,
interest = _nextInstalmentFn.interest,
installment = _nextInstalmentFn.installment;
return {

@@ -64,3 +106,3 @@ capital: capital,

};
};
}

@@ -71,3 +113,3 @@ /**

function Loan(amount, installmentsNumber, interestRate) {
var diminishing = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
var loanTypeWithBool = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'annuity';
if (!amount || amount <= 0 || !installmentsNumber || installmentsNumber <= 0 || !interestRate || interestRate <= 0) {

@@ -77,2 +119,3 @@ throw new Error("wrong parameters: ".concat(amount, " ").concat(installmentsNumber, " ").concat(interestRate));

var installments = [];
var loanType = typeof loanTypeWithBool === 'boolean' ? loanTypeFromBool(loanTypeWithBool) : loanTypeWithBool;
var interestSum = 0;

@@ -82,3 +125,3 @@ var capitalSum = 0;

for (var i = 0; i < installmentsNumber; i++) {
var inst = getNextInstalment(amount, installmentsNumber, interestRate, diminishing, capitalSum, interestSum);
var inst = getNextInstalment(amount, installmentsNumber, interestRate, loanType, capitalSum, interestSum);
sum += inst.installment;

@@ -104,2 +147,10 @@ capitalSum += inst.capital;

/**
* @param {boolean} boolType
* @returns {import("../types").LoanType}
*/
function loanTypeFromBool(boolType) {
return boolType ? 'diminishing' : 'annuity';
}
/* istanbul ignore next */

@@ -106,0 +157,0 @@ if (typeof window !== 'undefined') {

@@ -1,1 +0,1 @@

"use strict";function _typeof(n){return(_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(n){return typeof n}:function(n){return n&&"function"==typeof Symbol&&n.constructor===Symbol&&n!==Symbol.prototype?"symbol":typeof n})(n)}!function(n){"object"===("undefined"==typeof exports?"undefined":_typeof(exports))&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):("undefined"!=typeof globalThis?globalThis:self).loan=n()}(function(){function w(n){return Math.round(100*n)/100}var n;function t(n,t,e){var o=3<arguments.length&&void 0!==arguments[3]&&arguments[3];if(!n||n<=0||!t||t<=0||!e||e<=0)throw new Error("wrong parameters: ".concat(n," ").concat(t," ").concat(e));for(var r,i,a,f,u,l,p,c,m=[],s=0,d=0,y=0,S=0;S<t;S++){r=n,b=t,i=e,f=d,u=s,c=p=l=void 0,i/=1200,(a=o)?c=(l=w(r/b))+(p=w((r-f)*i)):l=(c=w(r*(i*(a=Math.pow(1+i,b))/(a-1))))-(p=w((r-f)*i));var b={capital:l,interest:p,installment:c,remain:r-f-l,interestSum:u+p};y+=b.installment,d+=b.capital,s+=b.interest,S===t-1&&(d+=b.remain,y+=b.remain,b.remain=0),m.push(b)}return{installments:m,amount:w(n),interestSum:w(s),capitalSum:w(d),sum:w(y)}}return"undefined"!=typeof window&&((n=window).LoanJS||(n.LoanJS={}),n.LoanJS.Loan=t),t});
"use strict";function _typeof(n){return(_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(n){return typeof n}:function(n){return n&&"function"==typeof Symbol&&n.constructor===Symbol&&n!==Symbol.prototype?"symbol":typeof n})(n)}!function(n){"object"===("undefined"==typeof exports?"undefined":_typeof(exports))&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):("undefined"!=typeof globalThis?globalThis:self).loan=n()}(function(){function b(n){return Math.round(100*n)/100}function S(n,t,e,o){var i=1/(1+o),t=b(n*(1-i)/((1-Math.pow(i,t))*i)),i=b((n-e)*o);return{capital:t-i,interest:i,installment:t}}var n,h={annuity:S,diminishing:function(n,t,e,o){return t=b(n/t),n=b((n-e)*o),{capital:t,interest:n,installment:t+n}},annuityDue:function(n,t,e,o){var i=b(n*(1-(i=1/(1+o)))/(1-Math.pow(i,t))),t=b((n-e)*o);return{capital:i-t,interest:t,installment:i}}};function t(n,t,e){var o=3<arguments.length&&void 0!==arguments[3]?arguments[3]:"annuity";if(!n||n<=0||!t||t<=0||!e||e<=0)throw new Error("wrong parameters: ".concat(n," ").concat(t," ").concat(e));for(var i,a,r,u,f,l=[],s="boolean"==typeof o?o?"diminishing":"annuity":o,c=0,p=0,m=0,y=0;y<t;y++){i=n,a=t,r=e,u=p,f=c,d=("function"==typeof(d=s)?d:h[d]||S)(i,a,u,r/1200),a=d.capital,r=d.interest;var d={capital:a,interest:r,installment:d.installment,remain:i-u-a,interestSum:f+r};m+=d.installment,p+=d.capital,c+=d.interest,y===t-1&&(p+=d.remain,m+=d.remain,d.remain=0),l.push(d)}return{installments:l,amount:b(n),interestSum:b(c),capitalSum:b(p),sum:b(m)}}return"undefined"!=typeof window&&((n=window).LoanJS||(n.LoanJS={}),n.LoanJS.Loan=t),t});

@@ -13,29 +13,59 @@ /*

/**
* @type {import("../types").GetNextInstalmentPartFunction}
*/
function getNextDiminishingInstalment (amount, installmentsNumber, capitalSum, interestRateMonth) {
const capital = rnd(amount / installmentsNumber)
const interest = rnd((amount - capitalSum) * interestRateMonth)
const installment = capital + interest
return { capital, interest, installment }
}
/**
* @type {import("../types").GetNextInstalmentPartFunction}
*/
function getNextAnnuityInstalment (amount, installmentsNumber, capitalSum, interestRateMonth) {
const z = 1 / (1 + interestRateMonth)
const div = (1 - Math.pow(z, installmentsNumber)) * z
const installment = rnd(amount * (1 - z) / div)
const interest = rnd((amount - capitalSum) * interestRateMonth)
const capital = installment - interest
return { capital, interest, installment }
}
/**
* @type {import("../types").GetNextInstalmentPartFunction}
*/
function getNextAnnuityDueInstalment (amount, installmentsNumber, capitalSum, interestRateMonth) {
const z = 1 / (1 + interestRateMonth)
const div = (1 - Math.pow(z, installmentsNumber))
const installment = rnd(amount * (1 - z) / div)
const interest = rnd((amount - capitalSum) * interestRateMonth)
const capital = installment - interest
return { capital, interest, installment }
}
const nextInstalmentFnMap = {
annuity: getNextAnnuityInstalment,
diminishing: getNextDiminishingInstalment,
annuityDue: getNextAnnuityDueInstalment
}
/**
* @type {import("../types").GetNextInstalmentFunction}
*/
const getNextInstalment = (
function getNextInstalment (
amount,
installmentsNumber,
interestRate,
diminishing,
loanType,
capitalSum,
interestSum
) => {
let capital
let interest
let installment
let irmPow
) {
const interestRateMonth = interestRate / 1200
const nextInstalmentFn = typeof loanType === 'function' ? loanType : nextInstalmentFnMap[loanType] || getNextAnnuityInstalment
const { capital, interest, installment } = nextInstalmentFn(amount, installmentsNumber, capitalSum, interestRateMonth)
if (diminishing) {
capital = rnd(amount / installmentsNumber)
interest = rnd((amount - capitalSum) * interestRateMonth)
installment = capital + interest
} else {
irmPow = Math.pow(1 + interestRateMonth, installmentsNumber)
installment = rnd(amount * ((interestRateMonth * irmPow) / (irmPow - 1)))
interest = rnd((amount - capitalSum) * interestRateMonth)
capital = installment - interest
}
return {

@@ -53,3 +83,3 @@ capital,

*/
function Loan (amount, installmentsNumber, interestRate, diminishing = false) {
function Loan (amount, installmentsNumber, interestRate, loanTypeWithBool = 'annuity') {
if (

@@ -69,2 +99,3 @@ !amount ||

const installments = []
const loanType = typeof loanTypeWithBool === 'boolean' ? loanTypeFromBool(loanTypeWithBool) : loanTypeWithBool
let interestSum = 0

@@ -79,3 +110,3 @@ let capitalSum = 0

interestRate,
diminishing,
loanType,
capitalSum,

@@ -107,2 +138,10 @@ interestSum

/**
* @param {boolean} boolType
* @returns {import("../types").LoanType}
*/
function loanTypeFromBool (boolType) {
return boolType ? 'diminishing' : 'annuity'
}
/* istanbul ignore next */

@@ -109,0 +148,0 @@ if (typeof window !== 'undefined') {

@@ -9,3 +9,3 @@ /* eslint-env jest */

test('loan js should count loan with equal instalment', () => {
test('loan js should count loan with equal instalment (annuity)', () => {
const loan = Loan(20000, 30 * 12, 5, false)

@@ -25,2 +25,19 @@

test('loan js should count loan with equal instalment (annuity) as default', () => {
/** @type any */
const LoanToTest = Loan
const loan = LoanToTest(20000, 30 * 12, 5, 'wrong-type-as-annuity')
expect(loan).toBeDefined()
expect(loan.installments.length).toBe(30 * 12)
expect(loan.installments[0].installment).toBe(107.36)
expect(loan.installments[30 * 12 - 1].installment).toBe(107.36)
expect(loan.amount).toBe(20000)
expect(loan.capitalSum).toBe(20000)
expect(loan.interestSum).toBe(18653.27)
expect(loan.sum).toBe(38653.27)
expect(rnd(loan.capitalSum + loan.interestSum)).toBe(loan.sum)
})
test('loan js should count loan with dismissing instalment', () => {

@@ -42,2 +59,44 @@ const loan = Loan(20000, 30 * 12, 5, true)

test('loan js should count loan with any loanType function', () => {
/**
* @type {import("../types").GetNextInstalmentPartFunction}
*/
function getNext10Instalment (amount, installmentsNumber, capitalSum, interestRateMonth) {
const capital = rnd(amount / installmentsNumber)
const interest = 10
const installment = capital + interest
return { capital, interest, installment }
}
const loan = Loan(20000, 30 * 12, 5, getNext10Instalment)
expect(loan).toBeDefined()
expect(loan.installments.length).toBe(30 * 12)
expect(loan.installments[0].installment).toBe(65.56)
expect(loan.installments[30 * 12 - 1].installment).toBe(65.56)
expect(loan.amount).toBe(20000)
expect(loan.capitalSum).toBe(20000)
expect(loan.interestSum).toBe(3600)
expect(loan.sum).toBe(23600)
expect(rnd(loan.capitalSum + loan.interestSum)).toBe(loan.sum)
})
test('loan js should count loan with annuity due function', () => {
const loan = Loan(30000, 30 * 12, 5, 'annuityDue')
expect(loan).toBeDefined()
expect(loan.installments.length).toBe(360)
expect(loan.installments[0].installment).toBe(160.38)
expect(loan.installments[23].installment).toBe(160.38)
expect(loan.amount).toBe(30000)
expect(loan.capitalSum).toBe(30000)
expect(loan.interestSum).toBe(28291.49)
expect(loan.sum).toBe(58291.49)
expect(rnd(loan.capitalSum + loan.interestSum)).toBe(loan.sum)
})
test('loan js should throw on wrong params', () => {

@@ -44,0 +103,0 @@ /** @type any */

{
"name": "loanjs",
"version": "1.0.12",
"version": "1.1.0",
"main": "LoanJS.js",

@@ -5,0 +5,0 @@ "description": "Calculate loan in js (browser/node.js) for equal installments, installments decreasing, the sum of interest, etc.",

+63
-25

@@ -7,9 +7,8 @@ # LoanJS

Super **small** (**~500B**) and **fast** module to calculate loan in js (browser/node.js) for **equal**/**decreasing** installments, the **sum of interest**, etc.
Super **small** (**~500B**) and **fast** module to calculate loan in js (browser/node.js) for **equal**/**decreasing**/**annuity**/**annuityDue** installments, the **sum of interest**, etc, with TypeScript support
Now with TypeScript support
## Getting Started
Install the module with:
Install with:
```

@@ -19,7 +18,2 @@ npm install loanjs

or Bower:
```
bower install loan-js --save
```
#### Calculating Loan:

@@ -35,3 +29,3 @@ ```js

5, // interest rate
true // diminishing
'annuity' // loanType: 'annuity' | 'annuityDue' | 'diminishing' | GetNextInstalmentPartFunction
);

@@ -59,12 +53,27 @@ /** returns

### Loan
LoanJS.Loan(amount, installmentsNumber, interestRate, diminishing)
LoanJS.Loan(amount, installmentsNumber, interestRate, loanType)
### Arguments
| Argument | type | default | Description
| ------------------ | ------ | --------- | ------------------
| amount | number | *required | full amount of Loan
| installmentsNumber | number | *required | how many installments will be (in months)
| interestRate | number | *required | interest rate in percent (ex. 3.5)
| diminishing | bool | false | if installments will be - true: diminishing; false: equal/annuity
| Argument | type | default | Description
| ------------------ | -------------- | --------- | ------------------
| amount | number | *required | full amount of Loan
| installmentsNumber | number | *required | how many installments will be (in months)
| interestRate | number | *required | interest rate in percent (ex. 3.5)
| loanType | string or fn | 'annuity' | 'annuity' | 'annuityDue' | 'diminishing' | GetNextInstalmentPartFunction
```ts
interface InstallmentPart {
capital: number;
interest: number;
installment: number;
}
type GetNextInstalmentPartFunction = (
amount: number,
installmentsNumber: number,
interestRateMonth: number,
capitalSum: number
) => InstallmentPart;
```
### Returns

@@ -90,15 +99,38 @@ ```js

nodejs / browserify example
### typescript example
```ts
import { Loan } from 'loanjs';
const annuityLoan = new Loan(1000, 12, 5, 'annuity');
const annuityDueLoan = new Loan(1000, 12, 5, 'annuityDue');
const diminishingLoan = new Loan(1000, 12, 5, 'diminishing');
const customInstalmentLoan = new Loan(1000, 12, 5, getNext10Instalment);
function getNext10Instalment (amount: number, installmentsNumber: number, capitalSum: number, interestRateMonth: number) {
const capital = rnd(amount / installmentsNumber);
const interest = 10;
const installment = capital + interest;
return { capital, interest, installment };
}
```
### nodejs example
```js
import { Loan } from 'loanjs';
// or
const { Loan } = require('loanjs');
const loan_1 = new Loan(1000, 12, 5, true);
// loan on 1 000($) in 12 diminishing installments (ex. months) with 5% interest rate
const loan_1 = new Loan(1000, 12, 5, 'diminishing');
// loan on 1 000($) in 12 loanType installments (ex. months) with 5% interest rate
const loan_2 = new Loan(500000, 360, 3.5);
const loan_2 = new Loan(500000, 360, 3.5, 'annuity');
// loan on 500 000($) in 360 equal installments (30 years) with 3.5% interest rate
```
Browser example:
### Browser example:
> You can also render loan as html table

@@ -110,5 +142,5 @@

<script>
var loan = new LoanJS.Loan(1000, 12, 5, true);
const loan = new LoanJS.Loan(1000, 12, 5, 'annuity');
var div = document.createElement("div");
const div = document.createElement("div");
div.innerHTML = LoanJS.loanToHtmlTable(loan); // loan rendering as html table string

@@ -131,2 +163,8 @@ document.body.appendChild(div);

#### 2023-06-23 v1.1.0
* add `annuityDue` interest rate loan type
* changing the fourth argument `diminishing` to `loanType` (`annuity` | `diminishing` | `annuityDue`), with backward compatibility (false == 'annuity', true == 'diminishing')
* refactor getNextInstalment to be open for extensions
* add option to provide function to loanType to customize instalments counting
#### 2023-06-23 v1.0.11

@@ -133,0 +171,0 @@ * add TypeScript types

@@ -21,3 +21,3 @@ export interface Installment {

interestRate: number,
diminishing: boolean,
loanType: LoanType,
capitalSum: number,

@@ -27,2 +27,17 @@ interestSum: number

export interface InstallmentPart {
capital: number;
interest: number;
installment: number;
}
export type GetNextInstalmentPartFunction = (
amount: number,
installmentsNumber: number,
interestRateMonth: number,
capitalSum: number
) => InstallmentPart;
export type LoanType = 'annuity' | 'annuityDue' | 'diminishing' | GetNextInstalmentPartFunction
export type LoanFunction = (

@@ -32,3 +47,3 @@ amount: number,

interestRate: number,
diminishing = false
loanType: LoanType | false | true = 'annuity'
) => LoanInstance;

@@ -35,0 +50,0 @@