Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: simplify CLI usage #63

Merged
merged 2 commits into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
87 changes: 17 additions & 70 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,96 +21,43 @@ You can install the crypto-cli tool via npm and yarn:
npm install -g coffee-crypto-cli
```

```sh
yarn add global coffee-crypto-cli
```

## Usage

```sh
$ crypto --price bitcoin --volume --ath
>> Bitcoin: $20,000 - volume: $13,337 - ATH: $68,000
$ crypto bitcoin
>> Bitcoin: $20,000
```

## Flags

Note: `--price, --p` is required for any of the subsequent flags.

```sh
--price, --p - coin name
```

Coin price change (%) in the past 24 hours.

```sh
--price-change, --pc
```

Coin volume in the past 24 hours.

```sh
--volume, --v
```

Highest price sold in the past 24 hours.

```sh
--high
```

Lowest price sold in the past 24 hours.

```sh
--low
```

Coin all time high price.

```sh
--ath
```

Percent price change from the all time high.

```sh
--ath-change, --athc
```

Save coin data via JSON and/or CSV

```sh
--save json
--save json,csv
```

CLI help message.

```sh
--help
```

Current version.

```sh
--version
```
| Name | Description |
| ------------------------ | ------------------------------------------- |
| `--price-change`, `--pc` | Coin price change (%) in the past 24 hours |
| `--volume`, `--v` | Coin volume in the past 24 hours |
| `--ath-change`, `--athc` | Percent price change from the all time high |
| `--high`, `--h` | Highest price sold in the past 24 hours |
| `--low`, `--l` | Lowest price sold in the past 24 hours |
| `--ath` | Coin all time high price |
| `--save json,csv` | Save coin data via JSON and/or CSV |
| `--help` | Flag description and usage examples |
| `--version` | Current version |

## Local Development

First things first, we'll need to clone the repo, install the dependencies, and, build the project.
Clone the repo, install the dependencies, and, build the project.

```sh
git clone https://github.com/Zidious/crypto-cli.git
```

```sh
yarn install && yarn build
yarn install --frozen-lockfile && yarn build
```

To run the CLI locally, use the below command followed by the flag you want to run.
To run the CLI locally:

```sh
node dist/index.js --price bitcoin
node dist/index.js bitcoin
```

## Contributing
Expand Down
10 changes: 6 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"prebuild": "rimraf dist",
"build": "tsc",
"test": "mocha 'src/*.test.ts'",
"lint": "eslint --fix",
"prepare": "husky install",
"precommit": "lint-staged"
},
Expand All @@ -37,8 +38,8 @@
"@types/json2csv": "^5.0.3",
"@types/mocha": "^10.0.1",
"@types/node": "^20.6.0",
"@typescript-eslint/eslint-plugin": "^6.6.0",
"@typescript-eslint/parser": "^5.54.0",
"@typescript-eslint/eslint-plugin": "^6.13.1",
"@typescript-eslint/parser": "^6.13.1",
"chai": "^4.3.8",
"eslint": "^8.49.0",
"execa": "^8.0.1",
Expand All @@ -51,10 +52,11 @@
"typescript": "^5.2.2"
},
"lint-staged": {
"*.{md,ts}": [
"*.ts": [
"eslint --fix",
"prettier --write"
]
],
"*.md": "prettier --write"
},
"keywords": [
"bitcoin",
Expand Down
113 changes: 49 additions & 64 deletions src/actions/priceStats.ts
Original file line number Diff line number Diff line change
@@ -1,67 +1,52 @@
import { format, logSuccess } from '../utils.js'
import type { Flags } from '../constants.js'

interface PriceStatsParams {
name: string
current_price: number
total_volume: number
high_24h: number
low_24h: number
percent24h: number
athPrice: number
athPercent: number
}

type PriceStatFlags = Omit<Flags, 'save'>

export const priceStats = (
{
name,
current_price,
total_volume,
high_24h,
low_24h,
percent24h,
athPrice,
athPercent
}: PriceStatsParams,
{ price, priceChange, high, low, volume, ath, athChange }: PriceStatFlags
): void => {
const priceRes = `${name}: ${format(current_price)}`
let priceChangeRes
let volumeRes
let highRes
let lowRes
let athRes
let athChangeRes

if (priceChange) {
priceChangeRes = `change (24H): ${percent24h.toFixed(2)}%`
}

if (high) {
highRes = `high (24H): ${format(high_24h)}`
}

if (low) {
lowRes = `low (24H): ${format(low_24h)}`
}

if (volume) {
volumeRes = `volume (24H): ${format(total_volume)}`
}

if (ath) {
athRes = `ATH: ${format(athPrice)}`
}

if (athChange) {
athChangeRes = `ATH (%): ${athPercent.toFixed(2)}%`
import type { PriceStatsParams } from '../types.js'

export const priceStats = ({ results, flags }: PriceStatsParams): void => {
for (const result of results) {
const priceRes = `${result.name}: ${format(result.current_price)}`
let priceChangeRes
let volumeRes
let highRes
let lowRes
let athRes
let athChangeRes

if (flags.priceChange) {
priceChangeRes = `change (24H): ${result.price_change_24h.toFixed(2)}%`
}

if (flags.high) {
highRes = `high (24H): ${format(result.high_24h)}`
}

if (flags.low) {
lowRes = `low (24H): ${format(result.low_24h)}`
}

if (flags.volume) {
volumeRes = `volume (24H): ${format(result.total_volume)}`
}

if (flags.ath) {
athRes = `ATH: ${format(result.ath)}`
}

if (flags.athChange) {
athChangeRes = `ATH (%): ${result.atl_change_percentage.toFixed(2)}%`
}

logSuccess(
[
priceRes,
priceChangeRes,
volumeRes,
highRes,
lowRes,
athRes,
athChangeRes
]
.filter(Boolean)
.join(' - ')
)
}

logSuccess(
[priceRes, priceChangeRes, volumeRes, highRes, lowRes, athRes, athChangeRes]
.filter(Boolean)
.join(' - ')
)
}
42 changes: 25 additions & 17 deletions src/actions/saveCoinData.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import fs from 'fs'
import { parseAsync } from 'json2csv'
import { logError, logSuccess } from '../utils.js'
import { formatFileName, logError, logSuccess } from '../utils.js'
import { CSVEXT, JSONEXT } from '../constants.js'
import type { ExportData } from '../constants.js'
import { CoinMarkets } from '@crypto-coffee/coingecko-api/dist/types.js'
import type { SaveCoinDataParams } from '../types.js'

export const saveCoinData = async ({
options,
results
}: SaveCoinDataParams) => {
if (!options) {
return
}

export const saveCoinData = async (
options: string,
exportData: ExportData[]
) => {
const fileExts = options.toLowerCase().split(',')

if (
Expand All @@ -21,6 +26,12 @@ export const saveCoinData = async (
)
}

const exportData: Partial<CoinMarkets>[] = []

for (const result of results) {
exportData.push(result)
}

logSuccess('Exporting coin data...')
if (fileExts.includes(JSONEXT)) {
writeFile(exportData, JSONEXT)
Expand All @@ -33,10 +44,14 @@ export const saveCoinData = async (
logSuccess('Export complete.')
}

const writeFile = async (exportData: ExportData[], fileExt: string) => {
const writeFile = async (
exportData: Partial<CoinMarkets>[],
fileExt: string
) => {
for (const coin of exportData) {
const data =
fileExt === JSONEXT ? JSON.stringify(coin) : await formatCsvFile(coin)

try {
fs.writeFileSync(formatFileName(coin.name as string, fileExt), data, {
encoding: 'utf8'
Expand All @@ -51,15 +66,8 @@ const writeFile = async (exportData: ExportData[], fileExt: string) => {
}
}

const formatFileName = (coinName: string, fileExt: string): string => {
/* use unix timestamp, resolves conflict of same filenames */
const timestamp = new Date().valueOf()

return `${coinName.toLowerCase()}-${timestamp}.${fileExt}`
}

const formatCsvFile = async (coin: ExportData): Promise<string> => {
return await parseAsync(coin as Readonly<ExportData>, {
const formatCsvFile = async (coin: Partial<CoinMarkets>): Promise<string> => {
return await parseAsync(coin, {
delimiter: ',',
excelStrings: false,
fields: [
Expand Down Expand Up @@ -89,7 +97,7 @@ const formatCsvFile = async (coin: ExportData): Promise<string> => {
},
{
label: 'All Time High',
value: 'all_time_high'
value: 'ath'
},
{
label: 'All Time High Percentage',
Expand Down