@cemalidev/trate 1.4.1
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/.env.example +16 -0
- package/.github/workflows/ci.yml +61 -0
- package/.github/workflows/cleanup.yml +36 -0
- package/.github/workflows/release.yml +56 -0
- package/.husky/pre-commit +4 -0
- package/.prettierrc +10 -0
- package/CHANGELOG.md +40 -0
- package/CONTRIBUTING.md +120 -0
- package/LICENSE +21 -0
- package/README.md +140 -0
- package/build.cjs +27 -0
- package/dist/index.js +1587 -0
- package/eslint.config.mjs +42 -0
- package/package.json +67 -0
- package/src/config/config.ts +130 -0
- package/src/config/types.ts +9 -0
- package/src/convert.ts +562 -0
- package/src/dashboard.ts +76 -0
- package/src/i18n/de.ts +90 -0
- package/src/i18n/en.ts +94 -0
- package/src/i18n/es.ts +90 -0
- package/src/i18n/fr.ts +90 -0
- package/src/i18n/index.ts +108 -0
- package/src/i18n/tr.ts +90 -0
- package/src/index.ts +390 -0
- package/src/logo.ts +33 -0
- package/src/types/errors.ts +38 -0
- package/src/ui.ts +40 -0
- package/src/utils/logger.ts +84 -0
- package/tests/config.test.ts +95 -0
- package/tests/i18n.test.ts +121 -0
- package/tests/validation.test.ts +149 -0
- package/tsconfig.json +18 -0
- package/vitest.config.ts +15 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import eslint from '@eslint/js';
|
|
2
|
+
import tseslint from '@typescript-eslint/eslint-plugin';
|
|
3
|
+
import tsparser from '@typescript-eslint/parser';
|
|
4
|
+
import prettier from 'eslint-config-prettier';
|
|
5
|
+
import globals from 'globals';
|
|
6
|
+
|
|
7
|
+
export default [
|
|
8
|
+
{
|
|
9
|
+
ignores: ['dist/', 'node_modules/', '*.js', 'build.cjs', 'vitest.config.ts'],
|
|
10
|
+
},
|
|
11
|
+
eslint.configs.recommended,
|
|
12
|
+
{
|
|
13
|
+
files: ['**/*.ts'],
|
|
14
|
+
languageOptions: {
|
|
15
|
+
parser: tsparser,
|
|
16
|
+
parserOptions: {
|
|
17
|
+
ecmaVersion: 2022,
|
|
18
|
+
sourceType: 'module',
|
|
19
|
+
},
|
|
20
|
+
globals: {
|
|
21
|
+
...globals.node,
|
|
22
|
+
console: 'readonly',
|
|
23
|
+
process: 'readonly',
|
|
24
|
+
setTimeout: 'readonly',
|
|
25
|
+
clearTimeout: 'readonly',
|
|
26
|
+
AbortController: 'readonly',
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
plugins: {
|
|
30
|
+
'@typescript-eslint': tseslint,
|
|
31
|
+
},
|
|
32
|
+
rules: {
|
|
33
|
+
...tseslint.configs.recommended.rules,
|
|
34
|
+
...prettier.rules,
|
|
35
|
+
'@typescript-eslint/no-explicit-any': 'warn',
|
|
36
|
+
'@typescript-eslint/explicit-function-return-type': 'off',
|
|
37
|
+
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
|
|
38
|
+
'no-console': 'off',
|
|
39
|
+
'no-undef': 'error',
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
];
|
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cemalidev/trate",
|
|
3
|
+
"version": "1.4.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Terminal-based currency tracker - convert fiat, crypto, and precious metals instantly",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"trate": "./dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "node build.cjs",
|
|
12
|
+
"start": "node dist/index.js",
|
|
13
|
+
"dev": "node build.cjs && node dist/index.js",
|
|
14
|
+
"test": "vitest",
|
|
15
|
+
"test:watch": "vitest --watch",
|
|
16
|
+
"test:coverage": "vitest run --coverage",
|
|
17
|
+
"typecheck": "tsc --noEmit",
|
|
18
|
+
"lint": "eslint src tests --ext .ts",
|
|
19
|
+
"lint:fix": "eslint src tests --ext .ts --fix",
|
|
20
|
+
"prepare": "husky install",
|
|
21
|
+
"link": "npm run build && npm link"
|
|
22
|
+
},
|
|
23
|
+
"lint-staged": {
|
|
24
|
+
"*.ts": [
|
|
25
|
+
"eslint --fix",
|
|
26
|
+
"prettier --write"
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"currency",
|
|
31
|
+
"exchange",
|
|
32
|
+
"rate",
|
|
33
|
+
"cli",
|
|
34
|
+
"crypto",
|
|
35
|
+
"bitcoin"
|
|
36
|
+
],
|
|
37
|
+
"author": "",
|
|
38
|
+
"license": "MIT",
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"commander": "^12.0.0",
|
|
41
|
+
"conf": "^12.0.0",
|
|
42
|
+
"figlet": "^1.11.0",
|
|
43
|
+
"inquirer": "^13.3.2",
|
|
44
|
+
"node-fetch": "^2.7.0"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@eslint/js": "^9.39.4",
|
|
48
|
+
"@types/figlet": "^1.5.8",
|
|
49
|
+
"@types/node": "^20.0.0",
|
|
50
|
+
"@types/node-fetch": "^2.6.13",
|
|
51
|
+
"@typescript-eslint/eslint-plugin": "^8.57.2",
|
|
52
|
+
"@typescript-eslint/parser": "^8.57.2",
|
|
53
|
+
"@vitest/coverage-v8": "^4.1.1",
|
|
54
|
+
"esbuild": "^0.27.4",
|
|
55
|
+
"eslint": "^9.39.4",
|
|
56
|
+
"eslint-config-prettier": "^9.1.2",
|
|
57
|
+
"globals": "^17.4.0",
|
|
58
|
+
"husky": "^9.1.7",
|
|
59
|
+
"lint-staged": "^16.4.0",
|
|
60
|
+
"prettier": "^3.8.1",
|
|
61
|
+
"typescript": "^5.3.0",
|
|
62
|
+
"vitest": "^4.1.1"
|
|
63
|
+
},
|
|
64
|
+
"engines": {
|
|
65
|
+
"node": ">=18.0.0"
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import Conf from 'conf';
|
|
2
|
+
import { Config } from './types';
|
|
3
|
+
import { Locale, getSystemLocale } from '../i18n';
|
|
4
|
+
|
|
5
|
+
const schema = {
|
|
6
|
+
baseCurrency: {
|
|
7
|
+
type: 'string' as const,
|
|
8
|
+
default: 'TRY',
|
|
9
|
+
description: 'Base currency for exchange rates',
|
|
10
|
+
},
|
|
11
|
+
favorites: {
|
|
12
|
+
type: 'array' as const,
|
|
13
|
+
default: ['USD', 'EUR', 'GBP', 'JPY'],
|
|
14
|
+
description: 'Favorite currency pairs',
|
|
15
|
+
},
|
|
16
|
+
locale: {
|
|
17
|
+
type: 'string' as const,
|
|
18
|
+
default: getSystemLocale(),
|
|
19
|
+
description: 'Language preference (tr, en, de, fr, es)',
|
|
20
|
+
},
|
|
21
|
+
aliases: {
|
|
22
|
+
type: 'object' as const,
|
|
23
|
+
default: {},
|
|
24
|
+
description: 'Custom currency aliases',
|
|
25
|
+
},
|
|
26
|
+
} as const;
|
|
27
|
+
|
|
28
|
+
export class ConfigService {
|
|
29
|
+
private store: Conf<Config>;
|
|
30
|
+
|
|
31
|
+
constructor() {
|
|
32
|
+
this.store = new Conf<Config>({
|
|
33
|
+
projectName: 'trate',
|
|
34
|
+
schema: schema as any,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
get baseCurrency(): string {
|
|
39
|
+
return this.store.get('baseCurrency');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
set baseCurrency(value: string) {
|
|
43
|
+
this.store.set('baseCurrency', value.toUpperCase());
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
get favorites(): string[] {
|
|
47
|
+
return this.store.get('favorites');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
set favorites(value: string[]) {
|
|
51
|
+
this.store.set(
|
|
52
|
+
'favorites',
|
|
53
|
+
value.map(v => v.toUpperCase())
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
get locale(): Locale {
|
|
58
|
+
const stored = this.store.get('locale');
|
|
59
|
+
return (stored as Locale) || getSystemLocale();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
set locale(value: Locale) {
|
|
63
|
+
this.store.set('locale', value);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
get clientId(): string {
|
|
67
|
+
const stored = this.store.get('clientId');
|
|
68
|
+
if (!stored) {
|
|
69
|
+
const newId = crypto.randomUUID();
|
|
70
|
+
this.store.set('clientId', newId);
|
|
71
|
+
return newId;
|
|
72
|
+
}
|
|
73
|
+
return stored;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
get aliases(): Record<string, string> {
|
|
77
|
+
return this.store.get('aliases') || {};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
set aliases(value: Record<string, string>) {
|
|
81
|
+
const normalized: Record<string, string> = {};
|
|
82
|
+
for (const [key, val] of Object.entries(value)) {
|
|
83
|
+
normalized[key.toLowerCase()] = val.toUpperCase();
|
|
84
|
+
}
|
|
85
|
+
this.store.set('aliases', normalized);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
addAlias(alias: string, currency: string): void {
|
|
89
|
+
const current = this.aliases;
|
|
90
|
+
current[alias.toLowerCase()] = currency.toUpperCase();
|
|
91
|
+
this.aliases = current;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
removeAlias(alias: string): boolean {
|
|
95
|
+
const current = this.aliases;
|
|
96
|
+
if (current[alias.toLowerCase()]) {
|
|
97
|
+
delete current[alias.toLowerCase()];
|
|
98
|
+
this.aliases = current;
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
addFavorite(currency: string): void {
|
|
105
|
+
const current = this.favorites;
|
|
106
|
+
if (!current.includes(currency.toUpperCase())) {
|
|
107
|
+
this.favorites = [...current, currency.toUpperCase()];
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
removeFavorite(currency: string): void {
|
|
112
|
+
this.favorites = this.favorites.filter(f => f !== currency.toUpperCase());
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
getAll(): Config {
|
|
116
|
+
return {
|
|
117
|
+
baseCurrency: this.baseCurrency,
|
|
118
|
+
favorites: this.favorites,
|
|
119
|
+
locale: this.locale,
|
|
120
|
+
clientId: this.clientId,
|
|
121
|
+
aliases: this.aliases,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
reset(): void {
|
|
126
|
+
this.store.clear();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export const configService = new ConfigService();
|