@supercmd/calculator 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 SuperCmdLabs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,217 @@
1
+ # @supercmd/calculator
2
+
3
+ A Raycast-style natural language calculator. One function, one string input, structured JSON output.
4
+
5
+ Supports math expressions, unit conversions, time zones, date calculations, currency, and crypto — all from natural language.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install @supercmd/calculator
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ ```ts
16
+ import { calculate } from '@supercmd/calculator';
17
+
18
+ // Math
19
+ await calculate('3 + 43 + 23'); // { type: "math", result: 69, formatted: "69" }
20
+ await calculate('sqrt(144)'); // { type: "math", result: 12, formatted: "12" }
21
+ await calculate('2^10'); // { type: "math", result: 1024, formatted: "1,024" }
22
+ await calculate('0xFF'); // { type: "math", result: 255, formatted: "255" }
23
+ await calculate('5!'); // { type: "math", result: 120, formatted: "120" }
24
+
25
+ // Unit Conversions
26
+ await calculate('3 km to m'); // { type: "unit", result: 3000, formatted: "3,000 meter" }
27
+ await calculate('100 fahrenheit to celsius'); // { type: "unit", result: 37.78, formatted: "37.78 celsius" }
28
+ await calculate('5 kg to lb'); // { type: "unit", result: 11.02, formatted: "11.02 pound" }
29
+ await calculate('1 gb to mb'); // { type: "unit", result: 1000, formatted: "1,000 megabyte" }
30
+
31
+ // Time Zones
32
+ await calculate('time in tokyo'); // { type: "time", formatted: "Mon, Mar 2, 2026, 05:46 AM JST" }
33
+ await calculate('time in madison'); // { type: "time", formatted: "Sun, Mar 1, 2026, 02:46 PM CST" }
34
+ await calculate('india to us time'); // { type: "time", formatted: "... IST → ... EST" }
35
+
36
+ // Dates
37
+ await calculate('tomorrow'); // { type: "date", formatted: "Tuesday, March 3, 2026 at 02:16 AM" }
38
+ await calculate('next friday'); // { type: "date", formatted: "Friday, March 6, 2026 ..." }
39
+ await calculate('3 days from now'); // { type: "date", formatted: "..." }
40
+ await calculate('1741000000'); // { type: "date", formatted: "Monday, March 3, 2025 ..." } (unix timestamp)
41
+
42
+ // Currency (works out of the box — free APIs with fallbacks)
43
+ await calculate('usd to inr'); // { type: "currency", formatted: "₹91.08" }
44
+ await calculate('100 usd to inr'); // { type: "currency", formatted: "₹9,108" }
45
+ await calculate('500 jpy to usd'); // { type: "currency", formatted: "$3.21" }
46
+
47
+ // Crypto (works out of the box — CoinGecko → Binance → CoinCap)
48
+ await calculate('btc to usd'); // { type: "crypto", formatted: "$65,295" }
49
+ await calculate('1 eth to usd'); // { type: "crypto", formatted: "$1,914.12" }
50
+ await calculate('100 usd to btc'); // { type: "crypto", formatted: "0.00153 Bitcoin" }
51
+ await calculate('1.5 eth to inr'); // { type: "crypto", formatted: "₹261,743" }
52
+ await calculate('doge to inr'); // { type: "crypto", formatted: "₹8.28" }
53
+ ```
54
+
55
+ ## API
56
+
57
+ ### `calculate(input: string, options?: Config): Promise<CalculateOutput>`
58
+
59
+ Single entry point. Accepts any natural language string.
60
+
61
+ #### Config
62
+
63
+ ```ts
64
+ interface Config {
65
+ rateProvider?: RateProvider; // Optional — built-in free providers used by default
66
+ timezone?: string; // User's IANA timezone (default: system)
67
+ locale?: string; // Locale for formatting (default: 'en-US')
68
+ precision?: number; // Max significant digits (default: 10)
69
+ }
70
+ ```
71
+
72
+ #### Output
73
+
74
+ ```ts
75
+ // Success
76
+ interface CalculateResult {
77
+ type: 'math' | 'unit' | 'currency' | 'crypto' | 'time' | 'date';
78
+ input: string;
79
+ result: number | string;
80
+ formatted: string;
81
+ metadata?: Record<string, unknown>;
82
+ }
83
+
84
+ // Failure
85
+ interface ErrorResult {
86
+ type: 'error';
87
+ input: string;
88
+ error: string;
89
+ }
90
+ ```
91
+
92
+ ## Rate Provider
93
+
94
+ Currency and crypto conversions work **out of the box** using built-in free API providers:
95
+
96
+ - **Fiat**: Frankfurter (ECB) → ExchangeRate API → Fawaz Ahmed Currency API
97
+ - **Crypto**: CoinGecko → Binance → CoinCap
98
+
99
+ Each has automatic fallback — if one API is down, the next is tried. No API keys needed.
100
+
101
+ You can override with a custom provider:
102
+
103
+ ```ts
104
+ interface RateProvider {
105
+ getFiatRate(base: string, target: string): Promise<number>;
106
+ getCryptoRate(base: string, target: string): Promise<number>;
107
+ }
108
+ ```
109
+
110
+ ### Example: Custom Provider
111
+
112
+ ```ts
113
+ const myProvider: RateProvider = {
114
+ async getFiatRate(base, target) {
115
+ const res = await fetch(`https://api.example.com/rates?from=${base}&to=${target}`);
116
+ const data = await res.json();
117
+ return data.rate;
118
+ },
119
+ async getCryptoRate(base, target) {
120
+ const res = await fetch(`https://api.example.com/crypto?from=${base}&to=${target}`);
121
+ const data = await res.json();
122
+ return data.rate;
123
+ },
124
+ };
125
+
126
+ const result = await calculate('100 usd to eur', { rateProvider: myProvider });
127
+ ```
128
+
129
+ ## What's Supported
130
+
131
+ ### Math Expressions
132
+ - Arithmetic: `+`, `-`, `*`, `/`, `%` (modulo)
133
+ - Exponentiation: `^`, `**`
134
+ - Parentheses: `(3 + 4) * 2`
135
+ - Functions: `sqrt`, `cbrt`, `abs`, `ceil`, `floor`, `round`, `log`, `log2`, `log10`, `ln`, `sin`, `cos`, `tan`, `asin`, `acos`, `atan`, `exp`, `sinh`, `cosh`, `tanh`, `pow`, `max`, `min`
136
+ - Constants: `pi`, `e`, `tau`, `phi`, `infinity`
137
+ - Factorial: `5!`
138
+ - Percentage: `50%` → 0.5
139
+ - Bitwise: `&`, `|`, `~`, `<<`, `>>`
140
+ - Base literals: `0xFF`, `0b1010`, `0o77`
141
+ - Scientific notation: `1e10`, `2.5e-3`
142
+
143
+ ### Unit Conversions (16 categories, 250+ units)
144
+ - **Length**: nm, mm, cm, m, km, in, ft, yd, mi, nmi, au, light year, parsec
145
+ - **Mass**: mg, g, kg, tonne, oz, lb, stone, carat, grain
146
+ - **Volume**: ml, l, tsp, tbsp, fl oz, cup, pint, quart, gallon, barrel
147
+ - **Area**: mm², cm², m², km², in², ft², yd², mi², acre, hectare
148
+ - **Temperature**: celsius, fahrenheit, kelvin
149
+ - **Speed**: m/s, km/h, mph, knots, mach
150
+ - **Time**: ns, ms, s, min, hr, day, week, month, year, decade, century
151
+ - **Data**: bit, byte, KB, MB, GB, TB, PB, KiB, MiB, GiB, TiB
152
+ - **Pressure**: Pa, kPa, bar, atm, psi, torr, mmHg
153
+ - **Energy**: J, kJ, cal, kcal, Wh, kWh, BTU, eV
154
+ - **Power**: W, kW, MW, GW, hp
155
+ - **Angle**: rad, deg, grad, arcmin, arcsec, revolution
156
+ - **Frequency**: Hz, kHz, MHz, GHz, THz, RPM
157
+ - **Electric current**: A, mA, kA, μA
158
+ - **Voltage**: V, mV, kV, μV
159
+ - **Fuel economy**: km/l, mpg
160
+
161
+ ### Currencies (150+ fiat codes)
162
+ Full ISO 4217 coverage including USD, EUR, GBP, JPY, INR, CNY, BRL, and 140+ more.
163
+ Common names work: `dollar`, `euro`, `pound`, `rupee`, `yuan`, `yen`.
164
+
165
+ ### Cryptocurrencies (40+)
166
+ BTC, ETH, SOL, XRP, USDT, USDC, BNB, DOGE, ADA, MATIC, DOT, LTC, AVAX, LINK, UNI, ATOM, XLM, TON, SHIB, and more.
167
+ Names work: `bitcoin`, `ethereum`, `solana`, etc.
168
+
169
+ ### Time Zones (200+ cities/regions)
170
+ - Cities: `time in tokyo`, `time in new york`, `time in madison`
171
+ - Countries: `time in india`, `time in germany`
172
+ - Abbreviations: `time in pst`, `time in ist`, `time in jst`
173
+ - Conversions: `india to us time`, `utc to ist`
174
+
175
+ ### Dates
176
+ - Relative: `today`, `tomorrow`, `yesterday`
177
+ - Named days: `next monday`, `last friday`, `this wednesday`
178
+ - Offsets: `3 days from now`, `2 weeks ago`, `in 5 months`
179
+ - Unix timestamps: `1741000000`
180
+ - ISO parsing: `2025-03-03`
181
+ - To unix: `now to unix`, `today to timestamp`
182
+ - Date diff: `from 2025-01-01 to 2025-12-31`
183
+
184
+ ## Intent Resolution Order
185
+
186
+ When input is ambiguous, the parser resolves in this order:
187
+
188
+ 1. **Time** — if input matches "time in X" or "X to Y time"
189
+ 2. **Date** — if input matches relative dates, timestamps, or date patterns
190
+ 3. **Currency/Crypto** — if both sides of "X to Y" resolve to currencies or crypto
191
+ 4. **Unit** — if both sides resolve to units in the same category
192
+ 5. **Math** — fallback for any arithmetic expression
193
+
194
+ ## Offline vs Online
195
+
196
+ | Feature | Offline | Needs Internet | Provider |
197
+ |---------|---------|----------------|----------|
198
+ | Math | Yes | | |
199
+ | Units | Yes | | |
200
+ | Time zones | Yes | | |
201
+ | Dates | Yes | | |
202
+ | Fiat currency | | Yes | Frankfurter → ExchangeRate → Fawaz Ahmed |
203
+ | Crypto | | Yes | CoinGecko → Binance → CoinCap |
204
+
205
+ ## Edge Cases
206
+
207
+ - **Empty input** → `{ type: "error", error: "Empty input" }`
208
+ - **Invalid math** → `{ type: "error", error: "Unexpected character..." }`
209
+ - **Unknown currency** → falls through to math (likely error)
210
+ - **All APIs down** → `{ type: "error", error: "All providers failed" }`
211
+ - **Division by zero** → `{ type: "error", error: "Division by zero" }`
212
+ - **Large numbers** → handled via JavaScript's native number precision
213
+ - **Ambiguous `m`** → resolved as meter (length), not minute — use `min` for minutes
214
+
215
+ ## License
216
+
217
+ MIT
@@ -0,0 +1,98 @@
1
+ type ResultType = 'math' | 'unit' | 'currency' | 'crypto' | 'time' | 'date';
2
+ interface CalculateResult {
3
+ type: ResultType;
4
+ input: string;
5
+ result: number | string;
6
+ formatted: string;
7
+ metadata?: Record<string, unknown>;
8
+ }
9
+ interface ErrorResult {
10
+ type: 'error';
11
+ input: string;
12
+ error: string;
13
+ }
14
+ type CalculateOutput = CalculateResult | ErrorResult;
15
+ interface RateProvider {
16
+ getFiatRate(base: string, target: string): Promise<number>;
17
+ getCryptoRate(base: string, target: string): Promise<number>;
18
+ }
19
+ interface Config {
20
+ rateProvider?: RateProvider;
21
+ /** User's local timezone (IANA), defaults to system timezone */
22
+ timezone?: string;
23
+ /** Locale for number formatting, defaults to 'en-US' */
24
+ locale?: string;
25
+ /** Maximum decimal places for results */
26
+ precision?: number;
27
+ }
28
+
29
+ /** ISO 4217 fiat currency codes + common names/symbols */
30
+ declare const FIAT_CURRENCIES: Record<string, string>;
31
+ /** Crypto symbols → canonical ticker */
32
+ declare const CRYPTO_CURRENCIES: Record<string, string>;
33
+ declare function resolveFiat(token: string): string | null;
34
+ declare function resolveCrypto(token: string): string | null;
35
+
36
+ interface UnitDef {
37
+ /** Multiplier to convert 1 of this unit to the base unit */
38
+ factor: number;
39
+ /** Additive offset (for temperature) — applied before factor */
40
+ offset?: number;
41
+ /** Display name */
42
+ name: string;
43
+ }
44
+ interface UnitCategory {
45
+ name: string;
46
+ base: string;
47
+ units: Record<string, UnitDef>;
48
+ }
49
+ declare const UNIT_CATEGORIES: UnitCategory[];
50
+ /** Build a flat lookup: alias → { category, unitDef } */
51
+ interface UnitLookupEntry {
52
+ category: UnitCategory;
53
+ key: string;
54
+ def: UnitDef;
55
+ }
56
+ declare function lookupUnit(token: string): UnitLookupEntry | undefined;
57
+ /** Convert value from one unit to another within the same category */
58
+ declare function convertUnit(value: number, from: UnitLookupEntry, to: UnitLookupEntry): number;
59
+
60
+ /** City/region name → IANA timezone identifier */
61
+ declare const TIMEZONE_MAP: Record<string, string>;
62
+ /** Common timezone abbreviations → IANA or UTC offset */
63
+ declare const TZ_ABBREVIATIONS: Record<string, string>;
64
+ declare function resolveTimezone(name: string): string | null;
65
+
66
+ /**
67
+ * Built-in rate provider with automatic fallback chains.
68
+ *
69
+ * Fiat: Frankfurter (ECB) → ExchangeRate API → Fawaz Ahmed Currency API
70
+ * Crypto: CoinGecko → Binance → CoinCap (with fiat routing when needed)
71
+ *
72
+ * All APIs are free and require no API key.
73
+ */
74
+ declare function createDefaultProvider(): RateProvider;
75
+
76
+ /**
77
+ * Natural language calculator — the single entry point.
78
+ *
79
+ * Accepts a string input and returns a structured result.
80
+ * Works offline for math, units, time, and dates.
81
+ * Uses built-in free API providers for currency/crypto by default.
82
+ * Pass a custom `rateProvider` in options to override.
83
+ *
84
+ * @example
85
+ * ```ts
86
+ * const result = await calculate("3 + 4 * 2");
87
+ * // { type: "math", result: 11, formatted: "11", ... }
88
+ *
89
+ * const result = await calculate("3 km to m");
90
+ * // { type: "unit", result: 3000, formatted: "3,000 meter", ... }
91
+ *
92
+ * const result = await calculate("time in tokyo");
93
+ * // { type: "time", result: "...", formatted: "...", ... }
94
+ * ```
95
+ */
96
+ declare function calculate(input: string, options?: Config): Promise<CalculateOutput>;
97
+
98
+ export { CRYPTO_CURRENCIES, type CalculateOutput, type CalculateResult, type Config, type ErrorResult, FIAT_CURRENCIES, type RateProvider, type ResultType, TIMEZONE_MAP, TZ_ABBREVIATIONS, UNIT_CATEGORIES, calculate, convertUnit, createDefaultProvider, lookupUnit, resolveCrypto, resolveFiat, resolveTimezone };
@@ -0,0 +1,98 @@
1
+ type ResultType = 'math' | 'unit' | 'currency' | 'crypto' | 'time' | 'date';
2
+ interface CalculateResult {
3
+ type: ResultType;
4
+ input: string;
5
+ result: number | string;
6
+ formatted: string;
7
+ metadata?: Record<string, unknown>;
8
+ }
9
+ interface ErrorResult {
10
+ type: 'error';
11
+ input: string;
12
+ error: string;
13
+ }
14
+ type CalculateOutput = CalculateResult | ErrorResult;
15
+ interface RateProvider {
16
+ getFiatRate(base: string, target: string): Promise<number>;
17
+ getCryptoRate(base: string, target: string): Promise<number>;
18
+ }
19
+ interface Config {
20
+ rateProvider?: RateProvider;
21
+ /** User's local timezone (IANA), defaults to system timezone */
22
+ timezone?: string;
23
+ /** Locale for number formatting, defaults to 'en-US' */
24
+ locale?: string;
25
+ /** Maximum decimal places for results */
26
+ precision?: number;
27
+ }
28
+
29
+ /** ISO 4217 fiat currency codes + common names/symbols */
30
+ declare const FIAT_CURRENCIES: Record<string, string>;
31
+ /** Crypto symbols → canonical ticker */
32
+ declare const CRYPTO_CURRENCIES: Record<string, string>;
33
+ declare function resolveFiat(token: string): string | null;
34
+ declare function resolveCrypto(token: string): string | null;
35
+
36
+ interface UnitDef {
37
+ /** Multiplier to convert 1 of this unit to the base unit */
38
+ factor: number;
39
+ /** Additive offset (for temperature) — applied before factor */
40
+ offset?: number;
41
+ /** Display name */
42
+ name: string;
43
+ }
44
+ interface UnitCategory {
45
+ name: string;
46
+ base: string;
47
+ units: Record<string, UnitDef>;
48
+ }
49
+ declare const UNIT_CATEGORIES: UnitCategory[];
50
+ /** Build a flat lookup: alias → { category, unitDef } */
51
+ interface UnitLookupEntry {
52
+ category: UnitCategory;
53
+ key: string;
54
+ def: UnitDef;
55
+ }
56
+ declare function lookupUnit(token: string): UnitLookupEntry | undefined;
57
+ /** Convert value from one unit to another within the same category */
58
+ declare function convertUnit(value: number, from: UnitLookupEntry, to: UnitLookupEntry): number;
59
+
60
+ /** City/region name → IANA timezone identifier */
61
+ declare const TIMEZONE_MAP: Record<string, string>;
62
+ /** Common timezone abbreviations → IANA or UTC offset */
63
+ declare const TZ_ABBREVIATIONS: Record<string, string>;
64
+ declare function resolveTimezone(name: string): string | null;
65
+
66
+ /**
67
+ * Built-in rate provider with automatic fallback chains.
68
+ *
69
+ * Fiat: Frankfurter (ECB) → ExchangeRate API → Fawaz Ahmed Currency API
70
+ * Crypto: CoinGecko → Binance → CoinCap (with fiat routing when needed)
71
+ *
72
+ * All APIs are free and require no API key.
73
+ */
74
+ declare function createDefaultProvider(): RateProvider;
75
+
76
+ /**
77
+ * Natural language calculator — the single entry point.
78
+ *
79
+ * Accepts a string input and returns a structured result.
80
+ * Works offline for math, units, time, and dates.
81
+ * Uses built-in free API providers for currency/crypto by default.
82
+ * Pass a custom `rateProvider` in options to override.
83
+ *
84
+ * @example
85
+ * ```ts
86
+ * const result = await calculate("3 + 4 * 2");
87
+ * // { type: "math", result: 11, formatted: "11", ... }
88
+ *
89
+ * const result = await calculate("3 km to m");
90
+ * // { type: "unit", result: 3000, formatted: "3,000 meter", ... }
91
+ *
92
+ * const result = await calculate("time in tokyo");
93
+ * // { type: "time", result: "...", formatted: "...", ... }
94
+ * ```
95
+ */
96
+ declare function calculate(input: string, options?: Config): Promise<CalculateOutput>;
97
+
98
+ export { CRYPTO_CURRENCIES, type CalculateOutput, type CalculateResult, type Config, type ErrorResult, FIAT_CURRENCIES, type RateProvider, type ResultType, TIMEZONE_MAP, TZ_ABBREVIATIONS, UNIT_CATEGORIES, calculate, convertUnit, createDefaultProvider, lookupUnit, resolveCrypto, resolveFiat, resolveTimezone };