Skip to content

Commit a9fe8b8

Browse files
committed
Initial commit
1 parent 6f7c72e commit a9fe8b8

9 files changed

+366
-0
lines changed

.editorconfig

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
root = true
2+
3+
[*]
4+
indent_style = tab
5+
end_of_line = lf
6+
charset = utf-8
7+
trim_trailing_whitespace = true
8+
insert_final_newline = true
9+
10+
[*.yml]
11+
indent_style = space
12+
indent_size = 2

.github/funding.yml

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# These are supported funding model platforms
2+
3+
github: xxczaki
4+
patreon: akepinski

.gitignore

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
8+
# Runtime data
9+
pids
10+
*.pid
11+
*.seed
12+
*.pid.lock
13+
14+
# Directory for instrumented libs generated by jscoverage/JSCover
15+
lib-cov
16+
17+
# Coverage directory used by tools like istanbul
18+
coverage
19+
20+
# nyc test coverage
21+
.nyc_output
22+
23+
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24+
.grunt
25+
26+
# Bower dependency directory (https://bower.io/)
27+
bower_components
28+
29+
# node-waf configuration
30+
.lock-wscript
31+
32+
# Compiled binary addons (https://nodejs.org/api/addons.html)
33+
build/Release
34+
35+
# Dependency directories
36+
node_modules/
37+
jspm_packages/
38+
39+
# TypeScript v1 declaration files
40+
typings/
41+
42+
# Optional npm cache directory
43+
.npm
44+
45+
# Optional eslint cache
46+
.eslintcache
47+
48+
# Optional REPL history
49+
.node_repl_history
50+
51+
# Output of 'npm pack'
52+
*.tgz
53+
54+
# Yarn Integrity file
55+
.yarn-integrity
56+
57+
# dotenv environment variables file
58+
.env
59+
60+
# next.js build output
61+
.next
62+
63+
# Transpilation output
64+
dist

.travis.yml

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
language: node_js
2+
node_js:
3+
- "12"
4+
- "10"
5+
- "8"

package.json

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
{
2+
"name": "cashify",
3+
"version": "1.0.0",
4+
"description": "Lightweight currency conversion library, successor of money.js",
5+
"main": "dist/index.js",
6+
"module": "dist/index.esm.js",
7+
"types": "dist/index.d.ts",
8+
"files": [
9+
"dist/index.js",
10+
"dist/index.esm.js",
11+
"dist/index.d.ts"
12+
],
13+
"author": "Antoni Kepinski <a@kepinski.me> (https://kepinski.me)",
14+
"bugs": {
15+
"url": "https://github.com/xxczaki/cashify/issues"
16+
},
17+
"scripts": {
18+
"prebuild": "del-cli dist",
19+
"esm": "tsc --module esnext && cpy dist/index.js dist --rename index.esm.js",
20+
"cjs": "tsc --module commonjs",
21+
"build": "npm run esm && npm run cjs",
22+
"test": "npm run build && xo && ava",
23+
"prepublishOnly": "npm run build"
24+
},
25+
"engines": {
26+
"node": ">=8"
27+
},
28+
"license": "MIT",
29+
"repository": "xxczaki/cashify",
30+
"homepage": "https://github.com/xxczaki/cashify",
31+
"devDependencies": {
32+
"@akepinski/tsconfig": "0.0.2",
33+
"@typescript-eslint/eslint-plugin": "^1.13.0",
34+
"@typescript-eslint/parser": "^1.13.0",
35+
"ava": "^2.2.0",
36+
"browser-env": "^3.2.6",
37+
"cpy-cli": "^2.0.0",
38+
"del-cli": "^2.0.0",
39+
"eslint-config-xo-typescript": "^0.15.0",
40+
"ts-node": "^8.3.0",
41+
"typescript": "^3.5.3",
42+
"xo": "*"
43+
},
44+
"sideEffects": false,
45+
"ava": {
46+
"babel": false,
47+
"compileEnhancements": false,
48+
"extensions": [
49+
"ts"
50+
],
51+
"require": [
52+
"ts-node/register"
53+
]
54+
},
55+
"xo": {
56+
"extends": "xo-typescript",
57+
"extensions": [
58+
"ts"
59+
],
60+
"rules": {
61+
"ava/no-ignored-test-files": "off"
62+
}
63+
}
64+
}

readme.md

+107
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# Cashify 💸
2+
3+
> Lightweight currency conversion library, successor of money.js
4+
5+
[![Build Status](https://travis-ci.org/xxczaki/cashify.svg?branch=master)](https://travis-ci.org/xxczaki/cashify) [![XO code style](https://img.shields.io/badge/code_style-XO-5ed9c7.svg)](https://github.com/xojs/xo)
6+
7+
## Highlights
8+
9+
- Simple API
10+
- 0 dependencies
11+
- Actively maintained
12+
- Well tested
13+
- [Easy migration from money.js](#migrating-from-money.js)
14+
- Written in TypeScript
15+
16+
## Install
17+
18+
```
19+
$ npm install cashify
20+
```
21+
22+
## Usage
23+
24+
```js
25+
const Cashify = require('cashify');
26+
27+
const rates = {
28+
GBP: 0.92,
29+
EUR: 1.00,
30+
USD: 1.12
31+
};
32+
33+
const cashify = new Cashify({base: 'EUR', rates});
34+
35+
const result = cashify.convert(10, {from: 'EUR', to: 'GBP'});
36+
37+
console.log(result); //=> 9.200000000000001
38+
```
39+
40+
## API
41+
42+
### Cashify({base, rates})
43+
44+
Constructor
45+
46+
##### base
47+
48+
Type: `string`
49+
50+
Base currency
51+
52+
##### rates
53+
54+
Type: `object`
55+
56+
Object containing currency rates (for example from an API, such as Open Exchange Rates)
57+
58+
### convert(amount, {from, to})
59+
60+
Returns conversion result (`number`)
61+
62+
##### amount
63+
64+
Type: `number`
65+
66+
Amount of money you want to convert
67+
68+
##### from
69+
70+
Type: `string`
71+
72+
Currency from which you want to convert
73+
74+
##### to
75+
76+
Type: `string`
77+
78+
Currency to which you want to convert
79+
80+
## Migrating from [money.js](http://openexchangerates.github.io/money.js/)
81+
82+
```diff
83+
- const fx = require('money');
84+
+ const Cashify = require('cashify');
85+
86+
- fx.base = 'EUR';
87+
- fx.rates = {
88+
- GBP: 0.92,
89+
- EUR: 1.00,
90+
- USD: 1.12
91+
- }
92+
93+
+ const rates = {
94+
+ GBP: 0.92,
95+
+ EUR: 1.00,
96+
+ USD: 1.12
97+
+ };
98+
99+
+ const cashify = new Cashify({base: 'EUR', rates});
100+
101+
- fx.convert(10, {from: 'GBP', to: 'EUR'});
102+
+ cashify.convert(10, {from: 'GBP', to: 'EUR'});
103+
```
104+
105+
## License
106+
107+
MIT © [Antoni Kepinski](https://kepinski.me)

src/index.ts

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
'use strict';
2+
3+
interface Options {
4+
from: string;
5+
to: string;
6+
base: string;
7+
rates: object;
8+
}
9+
10+
function hasKey<T>(obj: T, key: keyof any): key is keyof T {
11+
return key in obj;
12+
}
13+
14+
const getRate = ({base, rates, from, to}: Options): number => {
15+
if (hasKey(rates, from) && hasKey(rates, to)) {
16+
// If `from` equals `base`, return the basic exchange rate for the `to` currency
17+
if (from === base) {
18+
return rates[to];
19+
}
20+
21+
// If `to` equals `base`, return the basic inverse rate of the `from` currency
22+
if (to === base) {
23+
return 1 / rates[from];
24+
}
25+
26+
/**
27+
Otherwise, return the `to` rate multipled by the inverse of the `from` rate to get the
28+
relative exchange rate between the two currencies
29+
*/
30+
return rates[to] * (1 / rates[from]);
31+
}
32+
33+
throw new Error('Rates do not contain either `from` or `to` currency!');
34+
};
35+
36+
class Cashify {
37+
/**
38+
* @param {string} base Base currency
39+
* @param {object} rates Object containing currency rates (for example from an API, such as Open Exchange Rates)
40+
*/
41+
42+
public readonly options: Omit<Options, 'from' | 'to'>;
43+
44+
constructor({base, rates}: Omit<Options, 'from' | 'to'>) {
45+
this.options = {
46+
base,
47+
rates
48+
};
49+
}
50+
51+
/**
52+
* @param {number} amount Amount of money you want to convert
53+
* @param {object} options Conversion options
54+
* @param {string} options.from Currency from which you want to convert
55+
* @param {string} options.to Currency to which you want to convert
56+
* @return {number} Conversion result
57+
*/
58+
convert(amount: number, {from, to}: Omit<Options, 'base' | 'rates'>): number {
59+
const {base, rates} = this.options;
60+
61+
return amount * getRate({base, rates, from, to});
62+
}
63+
}
64+
65+
export default Cashify;

test.ts

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import test from 'ava';
2+
import Cashify from './dist';
3+
4+
const rates = {
5+
GBP: 0.92,
6+
EUR: 1.00,
7+
USD: 1.12
8+
};
9+
10+
const cashify = new Cashify({base: 'EUR', rates});
11+
12+
test('basic conversion', t => {
13+
t.is(cashify.convert(12, {from: 'USD', to: 'GBP'}), 9.857142857142858);
14+
});
15+
16+
test('`from` equals `base`', t => {
17+
t.is(cashify.convert(10, {from: 'EUR', to: 'GBP'}), 9.200000000000001);
18+
});
19+
20+
test('`to` equals `base`', t => {
21+
t.is(cashify.convert(10, {from: 'GBP', to: 'EUR'}), 10.869565217391305);
22+
});
23+
24+
test('rates do not contain `from`', t => {
25+
const error = t.throws(() => {
26+
cashify.convert(10, {from: 'PLN', to: 'EUR'});
27+
}, Error);
28+
29+
t.is(error.message, 'Rates do not contain either `from` or `to` currency!');
30+
});

tsconfig.json

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"extends": "@akepinski/tsconfig",
3+
"compilerOptions": {
4+
"outDir": "dist",
5+
"target": "es5",
6+
"sourceMap": false,
7+
"incremental": false,
8+
"lib": [
9+
"dom"
10+
],
11+
},
12+
"include": [
13+
"src/**/*"
14+
]
15+
}

0 commit comments

Comments
 (0)