Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
xxczaki committed Aug 7, 2019
1 parent 6f7c72e commit a9fe8b8
Show file tree
Hide file tree
Showing 9 changed files with 366 additions and 0 deletions.
12 changes: 12 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
root = true

[*]
indent_style = tab
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.yml]
indent_style = space
indent_size = 2
4 changes: 4 additions & 0 deletions .github/funding.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# These are supported funding model platforms

github: xxczaki
patreon: akepinski
64 changes: 64 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# TypeScript v1 declaration files
typings/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env

# next.js build output
.next

# Transpilation output
dist
5 changes: 5 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
language: node_js
node_js:
- "12"
- "10"
- "8"
64 changes: 64 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
{
"name": "cashify",
"version": "1.0.0",
"description": "Lightweight currency conversion library, successor of money.js",
"main": "dist/index.js",
"module": "dist/index.esm.js",
"types": "dist/index.d.ts",
"files": [
"dist/index.js",
"dist/index.esm.js",
"dist/index.d.ts"
],
"author": "Antoni Kepinski <[email protected]> (https://kepinski.me)",
"bugs": {
"url": "https://github.com/xxczaki/cashify/issues"
},
"scripts": {
"prebuild": "del-cli dist",
"esm": "tsc --module esnext && cpy dist/index.js dist --rename index.esm.js",
"cjs": "tsc --module commonjs",
"build": "npm run esm && npm run cjs",
"test": "npm run build && xo && ava",
"prepublishOnly": "npm run build"
},
"engines": {
"node": ">=8"
},
"license": "MIT",
"repository": "xxczaki/cashify",
"homepage": "https://github.com/xxczaki/cashify",
"devDependencies": {
"@akepinski/tsconfig": "0.0.2",
"@typescript-eslint/eslint-plugin": "^1.13.0",
"@typescript-eslint/parser": "^1.13.0",
"ava": "^2.2.0",
"browser-env": "^3.2.6",
"cpy-cli": "^2.0.0",
"del-cli": "^2.0.0",
"eslint-config-xo-typescript": "^0.15.0",
"ts-node": "^8.3.0",
"typescript": "^3.5.3",
"xo": "*"
},
"sideEffects": false,
"ava": {
"babel": false,
"compileEnhancements": false,
"extensions": [
"ts"
],
"require": [
"ts-node/register"
]
},
"xo": {
"extends": "xo-typescript",
"extensions": [
"ts"
],
"rules": {
"ava/no-ignored-test-files": "off"
}
}
}
107 changes: 107 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# Cashify 💸

> Lightweight currency conversion library, successor of money.js
[![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)

## Highlights

- Simple API
- 0 dependencies
- Actively maintained
- Well tested
- [Easy migration from money.js](#migrating-from-money.js)
- Written in TypeScript

## Install

```
$ npm install cashify
```

## Usage

```js
const Cashify = require('cashify');

const rates = {
GBP: 0.92,
EUR: 1.00,
USD: 1.12
};

const cashify = new Cashify({base: 'EUR', rates});

const result = cashify.convert(10, {from: 'EUR', to: 'GBP'});

console.log(result); //=> 9.200000000000001
```

## API

### Cashify({base, rates})

Constructor

##### base

Type: `string`

Base currency

##### rates

Type: `object`

Object containing currency rates (for example from an API, such as Open Exchange Rates)

### convert(amount, {from, to})

Returns conversion result (`number`)

##### amount

Type: `number`

Amount of money you want to convert

##### from

Type: `string`

Currency from which you want to convert

##### to

Type: `string`

Currency to which you want to convert

## Migrating from [money.js](http://openexchangerates.github.io/money.js/)

```diff
- const fx = require('money');
+ const Cashify = require('cashify');

- fx.base = 'EUR';
- fx.rates = {
- GBP: 0.92,
- EUR: 1.00,
- USD: 1.12
- }

+ const rates = {
+ GBP: 0.92,
+ EUR: 1.00,
+ USD: 1.12
+ };

+ const cashify = new Cashify({base: 'EUR', rates});

- fx.convert(10, {from: 'GBP', to: 'EUR'});
+ cashify.convert(10, {from: 'GBP', to: 'EUR'});
```

## License

MIT © [Antoni Kepinski](https://kepinski.me)
65 changes: 65 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
'use strict';

interface Options {
from: string;
to: string;
base: string;
rates: object;
}

function hasKey<T>(obj: T, key: keyof any): key is keyof T {
return key in obj;
}

const getRate = ({base, rates, from, to}: Options): number => {
if (hasKey(rates, from) && hasKey(rates, to)) {
// If `from` equals `base`, return the basic exchange rate for the `to` currency
if (from === base) {
return rates[to];
}

// If `to` equals `base`, return the basic inverse rate of the `from` currency
if (to === base) {
return 1 / rates[from];
}

/**
Otherwise, return the `to` rate multipled by the inverse of the `from` rate to get the
relative exchange rate between the two currencies
*/
return rates[to] * (1 / rates[from]);
}

throw new Error('Rates do not contain either `from` or `to` currency!');
};

class Cashify {
/**
* @param {string} base Base currency
* @param {object} rates Object containing currency rates (for example from an API, such as Open Exchange Rates)
*/

public readonly options: Omit<Options, 'from' | 'to'>;

constructor({base, rates}: Omit<Options, 'from' | 'to'>) {
this.options = {
base,
rates
};
}

/**
* @param {number} amount Amount of money you want to convert
* @param {object} options Conversion options
* @param {string} options.from Currency from which you want to convert
* @param {string} options.to Currency to which you want to convert
* @return {number} Conversion result
*/
convert(amount: number, {from, to}: Omit<Options, 'base' | 'rates'>): number {
const {base, rates} = this.options;

return amount * getRate({base, rates, from, to});
}
}

export default Cashify;
30 changes: 30 additions & 0 deletions test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import test from 'ava';
import Cashify from './dist';

const rates = {
GBP: 0.92,
EUR: 1.00,
USD: 1.12
};

const cashify = new Cashify({base: 'EUR', rates});

test('basic conversion', t => {
t.is(cashify.convert(12, {from: 'USD', to: 'GBP'}), 9.857142857142858);
});

test('`from` equals `base`', t => {
t.is(cashify.convert(10, {from: 'EUR', to: 'GBP'}), 9.200000000000001);
});

test('`to` equals `base`', t => {
t.is(cashify.convert(10, {from: 'GBP', to: 'EUR'}), 10.869565217391305);
});

test('rates do not contain `from`', t => {
const error = t.throws(() => {
cashify.convert(10, {from: 'PLN', to: 'EUR'});
}, Error);

t.is(error.message, 'Rates do not contain either `from` or `to` currency!');
});
15 changes: 15 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"extends": "@akepinski/tsconfig",
"compilerOptions": {
"outDir": "dist",
"target": "es5",
"sourceMap": false,
"incremental": false,
"lib": [
"dom"
],
},
"include": [
"src/**/*"
]
}

0 comments on commit a9fe8b8

Please sign in to comment.