@mahounou/uconv 0.1.0

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/README.md ADDED
@@ -0,0 +1,67 @@
1
+ # UConv Node.js
2
+
3
+ Lightweight unit converter for Node.js with zero runtime dependencies.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```javascript
14
+ import { convert } from './src/index.js';
15
+
16
+ // Distance conversions
17
+ convert("10km", "m"); // 10000
18
+ convert("5ft", "cm"); // 152.4
19
+
20
+ // Weight conversions
21
+ convert("5lbs", "kg"); // 2.26796
22
+ convert("1kg", "g"); // 1000
23
+
24
+ // Time conversions
25
+ convert("1hr", "min"); // 60
26
+ convert("30min", "s"); // 1800
27
+
28
+ // Currency conversions (example rates)
29
+ convert("100USD", "EUR"); // ~85
30
+ ```
31
+
32
+ ## Supported Units
33
+
34
+ ### Distance
35
+ - Metric: m, km, cm, mm
36
+ - Imperial: ft, in, yd, mi
37
+
38
+ ### Weight
39
+ - Metric: g, kg, mg, t
40
+ - Imperial: lb, oz, st
41
+
42
+ ### Time
43
+ - s, min, hr, day, week, month, year
44
+
45
+ ### Currency
46
+ - USD, EUR, GBP, JPY, CAD, AUD, CHF, CNY
47
+
48
+ ## Error Handling
49
+
50
+ The library throws specific errors for different failure cases:
51
+
52
+ - `UnknownUnitError`: When a unit is not recognized
53
+ - `InvalidInputError`: When input format is invalid
54
+ - `IncompatibleUnitsError`: When trying to convert between different unit types
55
+
56
+ ## Testing
57
+
58
+ ```bash
59
+ npm test
60
+ ```
61
+
62
+ ## Base Units
63
+
64
+ - Distance: meter (m)
65
+ - Weight: gram (g)
66
+ - Time: second (s)
67
+ - Currency: USD
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "@mahounou/uconv",
3
+ "version": "0.1.0",
4
+ "description": "Lightweight unit converter library",
5
+ "type": "module",
6
+ "main": "src/index.js",
7
+ "exports": {
8
+ ".": "./src/index.js"
9
+ },
10
+ "files": [
11
+ "src/",
12
+ "README.md"
13
+ ],
14
+ "scripts": {
15
+ "test": "vitest",
16
+ "test:watch": "vitest --watch"
17
+ },
18
+ "keywords": ["units", "converter", "measurement", "distance", "weight", "time", "currency"],
19
+ "author": "",
20
+ "license": "MIT",
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "https://github.com/ksnjkdppdojdim-star/Uconv"
24
+ },
25
+ "devDependencies": {
26
+ "vitest": "latest"
27
+ }
28
+ }
@@ -0,0 +1,36 @@
1
+ import { getConversionFactor } from '../units.js';
2
+ import { getConversionFactor } from '../units.js';
3
+ import { factorConvert } from '../utils/convert.js';
4
+
5
+
6
+ /**
7
+ * Convert currency units
8
+ * Note: In production, exchange rates should be fetched from a live API
9
+ * @param {number} value - Value to convert
10
+ * @param {string} fromUnit - Source currency
11
+ * @param {string} toUnit - Target currency
12
+ * @returns {number} Converted value
13
+ */
14
+
15
+
16
+ export function convertCurrency(value, fromUnit, toUnit) {
17
+ const from = getConversionFactor(fromUnit);
18
+ const to = getConversionFactor(toUnit);
19
+ if (from === null || to === null) throw new Error('Invalid currency unit');
20
+ return factorConvert(value, from, to);
21
+ }
22
+
23
+ // Async live rates — optional
24
+ export async function convertCurrencyLive(value, fromUnit, toUnit) {
25
+ const res = await fetch(`https://api.exchangerate-api.com/v4/latest/USD`);
26
+ if (!res.ok) throw new Error('Failed to fetch live exchange rates');
27
+ const { rates } = await res.json();
28
+
29
+ const from = fromUnit.toUpperCase();
30
+ const to = toUnit.toUpperCase();
31
+
32
+ if (!rates[from]) throw new Error(`Unknown currency: ${from}`);
33
+ if (!rates[to]) throw new Error(`Unknown currency: ${to}`);
34
+
35
+ return (value / rates[from]) * rates[to];
36
+ }
@@ -0,0 +1,20 @@
1
+ import { getConversionFactor } from '../units.js';
2
+ import { getConversionFactor } from '../units.js';
3
+ import { factorConvert } from '../utils/convert.js';
4
+
5
+
6
+ /**
7
+ * Convert distance units
8
+ * @param {number} value - Value to convert
9
+ * @param {string} fromUnit - Source unit
10
+ * @param {string} toUnit - Target unit
11
+ * @returns {number} Converted value
12
+ */
13
+
14
+
15
+ export function convertDistance(value, fromUnit, toUnit) {
16
+ const from = getConversionFactor(fromUnit);
17
+ const to = getConversionFactor(toUnit);
18
+ if (from === null || to === null) throw new Error('Invalid distance unit');
19
+ return factorConvert(value, from, to);
20
+ }
@@ -0,0 +1,19 @@
1
+ import { getConversionFactor } from '../units.js';
2
+ import { getConversionFactor } from '../units.js';
3
+ import { factorConvert } from '../utils/convert.js';
4
+
5
+ /**
6
+ * Convert time units
7
+ * @param {number} value - Value to convert
8
+ * @param {string} fromUnit - Source unit
9
+ * @param {string} toUnit - Target unit
10
+ * @returns {number} Converted value
11
+ */
12
+
13
+
14
+ export function convertTime(value, fromUnit, toUnit) {
15
+ const from = getConversionFactor(fromUnit);
16
+ const to = getConversionFactor(toUnit);
17
+ if (from === null || to === null) throw new Error('Invalid time unit');
18
+ return factorConvert(value, from, to);
19
+ }
@@ -0,0 +1,3 @@
1
+ export function factorConvert(value, fromFactor, toFactor) {
2
+ return (value * fromFactor) / toFactor;
3
+ }
@@ -0,0 +1,20 @@
1
+ import { getConversionFactor } from '../units.js';
2
+ import { getConversionFactor } from '../units.js';
3
+ import { factorConvert } from '../utils/convert.js';
4
+
5
+
6
+ /**
7
+ * Convert weight units
8
+ * @param {number} value - Value to convert
9
+ * @param {string} fromUnit - Source unit
10
+ * @param {string} toUnit - Target unit
11
+ * @returns {number} Converted value
12
+ */
13
+
14
+
15
+ export function convertWeight(value, fromUnit, toUnit) {
16
+ const from = getConversionFactor(fromUnit);
17
+ const to = getConversionFactor(toUnit);
18
+ if (from === null || to === null) throw new Error('Invalid weight unit');
19
+ return factorConvert(value, from, to);
20
+ }
package/src/index.js ADDED
@@ -0,0 +1,77 @@
1
+ import { parseInput } from './parser.js';
2
+ import { getUnitCategory, isValidUnit } from './units.js';
3
+ import { convertDistance } from './converters/distance.js';
4
+ import { convertWeight } from './converters/weight.js';
5
+ import { convertTime } from './converters/time.js';
6
+ import { convertCurrency } from './converters/currency.js';
7
+
8
+ // Custom error classes
9
+ export class UnknownUnitError extends Error {
10
+ constructor(unit) {
11
+ super(`Unknown unit: ${unit}`);
12
+ this.name = 'UnknownUnitError';
13
+ }
14
+ }
15
+
16
+ export class InvalidInputError extends Error {
17
+ constructor(input) {
18
+ super(`Invalid input format: ${input}`);
19
+ this.name = 'InvalidInputError';
20
+ }
21
+ }
22
+
23
+ export class IncompatibleUnitsError extends Error {
24
+ constructor(fromUnit, toUnit) {
25
+ super(`Cannot convert from ${fromUnit} to ${toUnit}: incompatible unit types`);
26
+ this.name = 'IncompatibleUnitsError';
27
+ }
28
+ }
29
+
30
+ const converters = {
31
+ distance: convertDistance,
32
+ weight: convertWeight,
33
+ time: convertTime,
34
+ currency: convertCurrency
35
+ };
36
+
37
+ /**
38
+ * Convert between units
39
+ * @param {string} from - Source value and unit (e.g., "10km")
40
+ * @param {string} to - Target unit (e.g., "m")
41
+ * @returns {number} Converted value
42
+ */
43
+ export function convert(from, to) {
44
+ if (typeof to !== 'string' || !to.trim()) {
45
+ throw new InvalidInputError(to);
46
+ }
47
+
48
+ const toUnit = to.trim().toLowerCase();
49
+
50
+ try {
51
+ const parsed = parseInput(from);
52
+ if (!parsed) throw new InvalidInputError(from);
53
+
54
+ const { value, unit: fromUnit } = parsed;
55
+
56
+ if (!isValidUnit(fromUnit)) throw new UnknownUnitError(fromUnit);
57
+ if (!isValidUnit(toUnit)) throw new UnknownUnitError(toUnit);
58
+
59
+ const fromCategory = getUnitCategory(fromUnit);
60
+ const toCategory = getUnitCategory(toUnit);
61
+
62
+ if (fromCategory !== toCategory) throw new IncompatibleUnitsError(fromUnit, toUnit);
63
+
64
+ const converter = converters[fromCategory];
65
+ if (!converter) throw new Error(`No converter for: ${fromCategory}`);
66
+
67
+ return converter(value, fromUnit, toUnit);
68
+
69
+ } catch (error) {
70
+ if (error instanceof UnknownUnitError ||
71
+ error instanceof InvalidInputError ||
72
+ error instanceof IncompatibleUnitsError) {
73
+ throw error;
74
+ }
75
+ throw new Error(`Conversion failed: ${error.message}`);
76
+ }
77
+ }
package/src/parser.js ADDED
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Parse input string containing value and unit
3
+ * @param {string} input - Input string like "10km", "5.5 lbs", "100 USD"
4
+ * @returns {Object|null} Parsed object {value, unit} or null if invalid
5
+ */
6
+ const MAX_INPUT_LENGTH = 50;
7
+ const MAX_VALUE = 1e15;
8
+ const PARSE_REGEX = /^(-?\d+(?:\.\d+)?(?:e[+-]?\d+)?)\s*([a-zA-Z°]+)$/i;
9
+
10
+ export function parseInput(input) {
11
+ if (typeof input !== 'string') return null;
12
+
13
+ const clean = input.trim();
14
+ if (!clean || clean.length > MAX_INPUT_LENGTH) return null;
15
+
16
+ const match = clean.match(PARSE_REGEX);
17
+ if (!match) return null;
18
+
19
+ const value = parseFloat(match[1]);
20
+
21
+ if (!isFinite(value)) return null;
22
+ if (Math.abs(value) > MAX_VALUE) return null;
23
+
24
+ return { value, unit: match[2].toLowerCase() };
25
+ }
package/src/units.js ADDED
@@ -0,0 +1,129 @@
1
+ // Base units for each category
2
+ export const BASE_UNITS = {
3
+ distance: 'm', // meter
4
+ weight: 'g', // gram
5
+ time: 's', // second
6
+ currency: 'usd' // US Dollar
7
+ };
8
+
9
+ // Unit definitions with conversion factors to base units
10
+ export const UNITS = {
11
+ // Distance (base: meter)
12
+ distance: {
13
+ // Metric
14
+ 'm': 1,
15
+ 'meter': 1,
16
+ 'metre': 1,
17
+ 'km': 1000,
18
+ 'kilometer': 1000,
19
+ 'kilometre': 1000,
20
+ 'cm': 0.01,
21
+ 'centimeter': 0.01,
22
+ 'centimetre': 0.01,
23
+ 'mm': 0.001,
24
+ 'millimeter': 0.001,
25
+ 'millimetre': 0.001,
26
+
27
+ // Imperial
28
+ 'ft': 0.3048,
29
+ 'foot': 0.3048,
30
+ 'feet': 0.3048,
31
+ 'in': 0.0254,
32
+ 'inch': 0.0254,
33
+ 'yd': 0.9144,
34
+ 'yard': 0.9144,
35
+ 'mi': 1609.344,
36
+ 'mile': 1609.344
37
+ },
38
+
39
+ // Weight (base: gram)
40
+ weight: {
41
+ // Metric
42
+ 'g': 1,
43
+ 'gram': 1,
44
+ 'kg': 1000,
45
+ 'kilogram': 1000,
46
+ 'mg': 0.001,
47
+ 'milligram': 0.001,
48
+ 't': 1000000,
49
+ 'ton': 1000000,
50
+ 'tonne': 1000000,
51
+
52
+ // Imperial
53
+ 'lb': 453.592,
54
+ 'lbs': 453.592,
55
+ 'pound': 453.592,
56
+ 'oz': 28.3495,
57
+ 'ounce': 28.3495,
58
+ 'st': 6350.29,
59
+ 'stone': 6350.29
60
+ },
61
+
62
+ // Time (base: second)
63
+ time: {
64
+ 's': 1,
65
+ 'sec': 1,
66
+ 'second': 1,
67
+ 'min': 60,
68
+ 'minute': 60,
69
+ 'hr': 3600,
70
+ 'hour': 3600,
71
+ 'day': 86400,
72
+ 'week': 604800,
73
+ 'month': 2629746, // Average month
74
+ 'year': 31556952 // Average year
75
+ },
76
+
77
+ // Currency (base: USD)
78
+ // Note: In a real implementation, these would be fetched from an API
79
+ currency: {
80
+ // ⚠️ Static rates as of 2024-01-01 — use live option for accuracy
81
+ // CURRENCY_RATES_DATE: '2024-01-01'
82
+ 'usd': 1,
83
+ 'eur': 0.85, // Example rates
84
+ 'gbp': 0.75,
85
+ 'jpy': 110,
86
+ 'cad': 1.25,
87
+ 'aud': 1.35,
88
+ 'chf': 0.92,
89
+ 'cny': 6.45
90
+ }
91
+ };
92
+
93
+ /**
94
+ * Get the category of a unit
95
+ * @param {string} unit - Unit name
96
+ * @returns {string|null} Category name or null if not found
97
+ */
98
+ export function getUnitCategory(unit) {
99
+ const normalizedUnit = unit.toLowerCase();
100
+ for (const [category, units] of Object.entries(UNITS)) {
101
+ if (Object.hasOwn(units, normalizedUnit)) {
102
+ return category;
103
+ }
104
+ }
105
+ return null;
106
+ }
107
+
108
+ /**
109
+ * Check if a unit is valid
110
+ * @param {string} unit - Unit name
111
+ * @returns {boolean} True if unit exists
112
+ */
113
+ export function isValidUnit(unit) {
114
+ return getUnitCategory(unit) !== null;
115
+ }
116
+
117
+ /**
118
+ * Get conversion factor to base unit
119
+ * @param {string} unit - Unit name
120
+ * @returns {number|null} Conversion factor or null if not found
121
+ */
122
+ export function getConversionFactor(unit) {
123
+ const category = getUnitCategory(unit);
124
+ if (!category) {
125
+ return null;
126
+ }
127
+
128
+ return UNITS[category][unit.toLowerCase()];
129
+ }