UNPKG

boosted-calc

Version:

A powerful terminal-based calculator with unit conversions, currency support, and more

1,670 lines (1,658 loc) 420 kB
#!/usr/bin/env node var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __esm = (fn, res) => function __init() { return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; }; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // node_modules/tsup/assets/esm_shims.js import path from "path"; import { fileURLToPath } from "url"; var init_esm_shims = __esm({ "node_modules/tsup/assets/esm_shims.js"() { "use strict"; } }); // src/data/units.ts function isUnit(value) { const lower = value.toLowerCase(); return lower in unitDefinitions || temperatureUnits.includes(lower) || value in derivedUnits; } function isTemperature(unit) { return temperatureUnits.includes(unit.toLowerCase()); } var unitDefinitions, temperatureUnits, derivedUnits; var init_units = __esm({ "src/data/units.ts"() { "use strict"; init_esm_shims(); unitDefinitions = { // Length - base unit: meter meter: { baseUnit: "meter", factor: 1 }, meters: { baseUnit: "meter", factor: 1 }, m: { baseUnit: "meter", factor: 1 }, centimeter: { baseUnit: "meter", factor: 0.01 }, centimeters: { baseUnit: "meter", factor: 0.01 }, cm: { baseUnit: "meter", factor: 0.01 }, millimeter: { baseUnit: "meter", factor: 1e-3 }, millimeters: { baseUnit: "meter", factor: 1e-3 }, mm: { baseUnit: "meter", factor: 1e-3 }, kilometer: { baseUnit: "meter", factor: 1e3 }, kilometers: { baseUnit: "meter", factor: 1e3 }, km: { baseUnit: "meter", factor: 1e3 }, inch: { baseUnit: "meter", factor: 0.0254 }, inches: { baseUnit: "meter", factor: 0.0254 }, in: { baseUnit: "meter", factor: 0.0254 }, foot: { baseUnit: "meter", factor: 0.3048 }, feet: { baseUnit: "meter", factor: 0.3048 }, ft: { baseUnit: "meter", factor: 0.3048 }, yard: { baseUnit: "meter", factor: 0.9144 }, yards: { baseUnit: "meter", factor: 0.9144 }, yd: { baseUnit: "meter", factor: 0.9144 }, mile: { baseUnit: "meter", factor: 1609.344 }, miles: { baseUnit: "meter", factor: 1609.344 }, mi: { baseUnit: "meter", factor: 1609.344 }, // Weight - base unit: gram gram: { baseUnit: "gram", factor: 1 }, grams: { baseUnit: "gram", factor: 1 }, g: { baseUnit: "gram", factor: 1 }, kilogram: { baseUnit: "gram", factor: 1e3 }, kilograms: { baseUnit: "gram", factor: 1e3 }, kg: { baseUnit: "gram", factor: 1e3 }, milligram: { baseUnit: "gram", factor: 1e-3 }, milligrams: { baseUnit: "gram", factor: 1e-3 }, mg: { baseUnit: "gram", factor: 1e-3 }, pound: { baseUnit: "gram", factor: 453.59237 }, pounds: { baseUnit: "gram", factor: 453.59237 }, lb: { baseUnit: "gram", factor: 453.59237 }, lbs: { baseUnit: "gram", factor: 453.59237 }, ounce: { baseUnit: "gram", factor: 28.349523125 }, ounces: { baseUnit: "gram", factor: 28.349523125 }, oz: { baseUnit: "gram", factor: 28.349523125 }, stone: { baseUnit: "gram", factor: 6350.29318 }, stones: { baseUnit: "gram", factor: 6350.29318 }, st: { baseUnit: "gram", factor: 6350.29318 }, // Time - base unit: second millisecond: { baseUnit: "second", factor: 1e-3 }, milliseconds: { baseUnit: "second", factor: 1e-3 }, ms: { baseUnit: "second", factor: 1e-3 }, second: { baseUnit: "second", factor: 1 }, seconds: { baseUnit: "second", factor: 1 }, s: { baseUnit: "second", factor: 1 }, sec: { baseUnit: "second", factor: 1 }, minute: { baseUnit: "second", factor: 60 }, minutes: { baseUnit: "second", factor: 60 }, min: { baseUnit: "second", factor: 60 }, hour: { baseUnit: "second", factor: 3600 }, hours: { baseUnit: "second", factor: 3600 }, h: { baseUnit: "second", factor: 3600 }, hr: { baseUnit: "second", factor: 3600 }, day: { baseUnit: "second", factor: 86400 }, days: { baseUnit: "second", factor: 86400 }, d: { baseUnit: "second", factor: 86400 }, week: { baseUnit: "second", factor: 604800 }, weeks: { baseUnit: "second", factor: 604800 }, w: { baseUnit: "second", factor: 604800 }, month: { baseUnit: "second", factor: 2592e3 }, // 30 days months: { baseUnit: "second", factor: 2592e3 }, year: { baseUnit: "second", factor: 31536e3 }, // 365 days years: { baseUnit: "second", factor: 31536e3 }, yr: { baseUnit: "second", factor: 31536e3 }, // Volume - base unit: liter liter: { baseUnit: "liter", factor: 1 }, liters: { baseUnit: "liter", factor: 1 }, l: { baseUnit: "liter", factor: 1 }, L: { baseUnit: "liter", factor: 1 }, milliliter: { baseUnit: "liter", factor: 1e-3 }, milliliters: { baseUnit: "liter", factor: 1e-3 }, ml: { baseUnit: "liter", factor: 1e-3 }, gallon: { baseUnit: "liter", factor: 3.785411784 }, gallons: { baseUnit: "liter", factor: 3.785411784 }, gal: { baseUnit: "liter", factor: 3.785411784 }, quart: { baseUnit: "liter", factor: 0.946352946 }, quarts: { baseUnit: "liter", factor: 0.946352946 }, qt: { baseUnit: "liter", factor: 0.946352946 }, pint: { baseUnit: "liter", factor: 0.473176473 }, pints: { baseUnit: "liter", factor: 0.473176473 }, pt: { baseUnit: "liter", factor: 0.473176473 }, cup: { baseUnit: "liter", factor: 0.2365882365 }, cups: { baseUnit: "liter", factor: 0.2365882365 }, tablespoon: { baseUnit: "liter", factor: 0.0147867648 }, tablespoons: { baseUnit: "liter", factor: 0.0147867648 }, tbsp: { baseUnit: "liter", factor: 0.0147867648 }, teaspoon: { baseUnit: "liter", factor: 0.00492892159 }, teaspoons: { baseUnit: "liter", factor: 0.00492892159 }, tsp: { baseUnit: "liter", factor: 0.00492892159 }, // Area hectare: { baseUnit: "meter^2", factor: 1e4 }, hectares: { baseUnit: "meter^2", factor: 1e4 }, ha: { baseUnit: "meter^2", factor: 1e4 }, acre: { baseUnit: "meter^2", factor: 4046.8564224 }, acres: { baseUnit: "meter^2", factor: 4046.8564224 }, // Data - base unit: byte byte: { baseUnit: "byte", factor: 1 }, bytes: { baseUnit: "byte", factor: 1 }, b: { baseUnit: "byte", factor: 1 }, kilobyte: { baseUnit: "byte", factor: 1e3 }, kilobytes: { baseUnit: "byte", factor: 1e3 }, kb: { baseUnit: "byte", factor: 1e3 }, megabyte: { baseUnit: "byte", factor: 1e6 }, megabytes: { baseUnit: "byte", factor: 1e6 }, mb: { baseUnit: "byte", factor: 1e6 }, gigabyte: { baseUnit: "byte", factor: 1e9 }, gigabytes: { baseUnit: "byte", factor: 1e9 }, gb: { baseUnit: "byte", factor: 1e9 }, terabyte: { baseUnit: "byte", factor: 1e12 }, terabytes: { baseUnit: "byte", factor: 1e12 }, tb: { baseUnit: "byte", factor: 1e12 }, kibibyte: { baseUnit: "byte", factor: 1024 }, kibibytes: { baseUnit: "byte", factor: 1024 }, kib: { baseUnit: "byte", factor: 1024 }, mebibyte: { baseUnit: "byte", factor: 1048576 }, mebibytes: { baseUnit: "byte", factor: 1048576 }, mib: { baseUnit: "byte", factor: 1048576 }, gibibyte: { baseUnit: "byte", factor: 1073741824 }, gibibytes: { baseUnit: "byte", factor: 1073741824 }, gib: { baseUnit: "byte", factor: 1073741824 }, // Electric current - base unit: ampere ampere: { baseUnit: "ampere", factor: 1 }, amperes: { baseUnit: "ampere", factor: 1 }, amp: { baseUnit: "ampere", factor: 1 }, amps: { baseUnit: "ampere", factor: 1 }, A: { baseUnit: "ampere", factor: 1 }, milliampere: { baseUnit: "ampere", factor: 1e-3 }, milliamperes: { baseUnit: "ampere", factor: 1e-3 }, milliamp: { baseUnit: "ampere", factor: 1e-3 }, milliamps: { baseUnit: "ampere", factor: 1e-3 }, mA: { baseUnit: "ampere", factor: 1e-3 } }; temperatureUnits = [ "celsius", "c", "C", "fahrenheit", "f", "F", "kelvin", "k", "K" ]; derivedUnits = { // Frequency Hz: "s^-1", hz: "s^-1", hertz: "s^-1", // Force N: "kg*m*s^-2", newton: "kg*m*s^-2", newtons: "kg*m*s^-2", // Pressure Pa: "kg*m^-1*s^-2", pa: "kg*m^-1*s^-2", pascal: "kg*m^-1*s^-2", pascals: "kg*m^-1*s^-2", // Energy J: "kg*m^2*s^-2", joule: "kg*m^2*s^-2", joules: "kg*m^2*s^-2", // Power W: "kg*m^2*s^-3", watt: "kg*m^2*s^-3", watts: "kg*m^2*s^-3", // Electric charge C: "A*s", coulomb: "A*s", coulombs: "A*s", // Voltage V: "kg*m^2*s^-3*A^-1", volt: "kg*m^2*s^-3*A^-1", volts: "kg*m^2*s^-3*A^-1", // Resistance (using Ohm instead of Ω for input) Ohm: "kg*m^2*s^-3*A^-2", ohm: "kg*m^2*s^-3*A^-2", ohms: "kg*m^2*s^-3*A^-2" }; } }); // src/utils/decimal-math.ts var decimal_math_exports = {}; __export(decimal_math_exports, { Decimal: () => Decimal2, E: () => E, ONE: () => ONE, PI: () => PI, TEN: () => TEN, TWO: () => TWO, ZERO: () => ZERO, abs: () => abs, acos: () => acos, add: () => add, asin: () => asin, atan: () => atan, atan2: () => atan2, ceil: () => ceil, cos: () => cos, divide: () => divide, equals: () => equals, exp: () => exp, floor: () => floor, formatDecimal: () => formatDecimal, fromDecimal: () => fromDecimal, fromPercentage: () => fromPercentage, greaterThan: () => greaterThan, greaterThanOrEqual: () => greaterThanOrEqual, isDecimalFinite: () => isDecimalFinite, isDecimalNaN: () => isDecimalNaN, isInteger: () => isInteger, isNegative: () => isNegative, isPositive: () => isPositive, isValidDecimal: () => isValidDecimal, isZero: () => isZero, lessThan: () => lessThan, lessThanOrEqual: () => lessThanOrEqual, ln: () => ln, log10: () => log10, log2: () => log2, max: () => max, min: () => min, modulo: () => modulo, multiply: () => multiply, negate: () => negate, notEquals: () => notEquals, power: () => power, random: () => random, round: () => round, sin: () => sin, sqrt: () => sqrt, subtract: () => subtract, tan: () => tan, toDecimal: () => toDecimal, toPercentage: () => toPercentage, trunc: () => trunc }); import Decimal from "decimal.js"; import { Decimal as Decimal2 } from "decimal.js"; function toDecimal(value) { if (value instanceof Decimal) { return value; } if (typeof value === "string") { if (value.startsWith("0x") || value.startsWith("0X")) { return new Decimal(Number.parseInt(value, 16)); } if (value.startsWith("0b") || value.startsWith("0B")) { return new Decimal(Number.parseInt(value.slice(2), 2)); } } return new Decimal(value); } function fromDecimal(value) { return value.toNumber(); } function formatDecimal(value, precision) { if (precision !== void 0) { return value.toFixed(precision); } return value.toSignificantDigits().toString(); } function isValidDecimal(value) { try { new Decimal(value); return true; } catch { return false; } } var add, subtract, multiply, divide, modulo, power, equals, lessThan, lessThanOrEqual, greaterThan, greaterThanOrEqual, notEquals, abs, negate, sqrt, floor, ceil, round, trunc, sin, cos, tan, asin, acos, atan, atan2, ln, log10, log2, exp, isZero, isNegative, isPositive, isInteger, isDecimalFinite, isDecimalNaN, min, max, random, ZERO, ONE, TWO, TEN, PI, E, toPercentage, fromPercentage; var init_decimal_math = __esm({ "src/utils/decimal-math.ts"() { "use strict"; init_esm_shims(); Decimal.set({ precision: 40, rounding: Decimal.ROUND_HALF_UP, toExpNeg: -20, toExpPos: 20, maxE: 9e15, minE: -9e15, modulo: Decimal.ROUND_DOWN }); add = (a, b) => a.plus(b); subtract = (a, b) => a.minus(b); multiply = (a, b) => a.times(b); divide = (a, b) => a.div(b); modulo = (a, b) => a.mod(b); power = (a, b) => a.pow(b); equals = (a, b) => a.equals(b); lessThan = (a, b) => a.lessThan(b); lessThanOrEqual = (a, b) => a.lessThanOrEqualTo(b); greaterThan = (a, b) => a.greaterThan(b); greaterThanOrEqual = (a, b) => a.greaterThanOrEqualTo(b); notEquals = (a, b) => !a.equals(b); abs = (a) => a.abs(); negate = (a) => a.neg(); sqrt = (a) => a.sqrt(); floor = (a) => a.floor(); ceil = (a) => a.ceil(); round = (a, places = 0) => a.toDecimalPlaces(places); trunc = (a) => a.truncated(); sin = (a) => a.sin(); cos = (a) => a.cos(); tan = (a) => a.tan(); asin = (a) => a.asin(); acos = (a) => a.acos(); atan = (a) => a.atan(); atan2 = (y, x) => Decimal.atan2(y, x); ln = (a) => a.ln(); log10 = (a) => a.log(10); log2 = (a) => a.log(2); exp = (a) => a.exp(); isZero = (a) => a.isZero(); isNegative = (a) => a.isNegative(); isPositive = (a) => a.isPositive(); isInteger = (a) => a.isInteger(); isDecimalFinite = (a) => a.isFinite(); isDecimalNaN = (a) => a.isNaN(); min = (...values) => Decimal.min(...values); max = (...values) => Decimal.max(...values); random = () => Decimal.random(); ZERO = toDecimal(0); ONE = toDecimal(1); TWO = toDecimal(2); TEN = toDecimal(10); PI = toDecimal( "3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679" ); E = toDecimal( "2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664274" ); toPercentage = (a) => a.times(100); fromPercentage = (a) => a.div(100); } }); // src/utils/currency-manager.ts var currency_manager_exports = {}; __export(currency_manager_exports, { CurrencyManager: () => CurrencyManager }); import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "fs"; import { homedir } from "os"; import { join } from "path"; var CONFIG_DIR, CURRENCY_FILE, CURRENCY_API_URL, UPDATE_INTERVAL, CurrencyManager; var init_currency_manager = __esm({ "src/utils/currency-manager.ts"() { "use strict"; init_esm_shims(); CONFIG_DIR = join(homedir(), ".config", "boomi"); CURRENCY_FILE = join(CONFIG_DIR, "currencies.json"); CURRENCY_API_URL = "https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@latest/v1/currencies/usd.json"; UPDATE_INTERVAL = 24 * 60 * 60 * 1e3; CurrencyManager = class _CurrencyManager { static instance; currencyRates = {}; constructor() { } static getInstance() { if (!_CurrencyManager.instance) { _CurrencyManager.instance = new _CurrencyManager(); } return _CurrencyManager.instance; } async initialize() { if (!existsSync(CONFIG_DIR)) { mkdirSync(CONFIG_DIR, { recursive: true }); } this.loadCurrencyData(); if (this.shouldUpdate()) { await this.updateCurrencyData(); } } loadCurrencyData() { try { if (existsSync(CURRENCY_FILE)) { const content = readFileSync(CURRENCY_FILE, "utf-8"); const data = JSON.parse(content); this.currencyRates = {}; for (const [currency, rate] of Object.entries(data.usd)) { this.currencyRates[currency.toUpperCase()] = rate; } } } catch (error) { console.error("Failed to load currency data:", error); } } shouldUpdate() { if (!existsSync(CURRENCY_FILE)) { return true; } try { const stats = statSync(CURRENCY_FILE); const lastModified = stats.mtime.getTime(); const now = Date.now(); return now - lastModified > UPDATE_INTERVAL; } catch { return true; } } async updateCurrencyData() { try { console.log("Updating currency exchange rates..."); const response = await fetch(CURRENCY_API_URL); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); const currencyData = { date: data.date, usd: data.usd, lastUpdated: Date.now() }; writeFileSync(CURRENCY_FILE, JSON.stringify(currencyData, null, 2)); this.currencyRates = {}; for (const [currency, rate] of Object.entries( data.usd )) { this.currencyRates[currency.toUpperCase()] = rate; } console.log( `Currency rates updated successfully. Found ${Object.keys(this.currencyRates).length} currencies.` ); } catch (error) { console.error("Failed to update currency data:", error); this.currencyRates = { USD: 1, EUR: 0.85, GBP: 0.73, JPY: 110, CAD: 1.25, AUD: 1.35, CHF: 0.92, CNY: 6.45, INR: 74.5, KRW: 1180 }; } } getRates() { if (Object.keys(this.currencyRates).length === 0) { return { USD: 1, EUR: 0.85, GBP: 0.73, JPY: 110, CAD: 1.25, AUD: 1.35, CHF: 0.92, CNY: 6.45, INR: 74.5, KRW: 1180 }; } return this.currencyRates; } getRate(currency) { const rates = this.getRates(); return rates[currency.toUpperCase()]; } getAvailableCurrencies() { return Object.keys(this.currencyRates); } }; } }); // src/evaluator/dimensions.ts function getConversionTable(dimension) { switch (dimension) { case "length": return LENGTH_CONVERSIONS; case "mass": return MASS_CONVERSIONS; case "time": return TIME_CONVERSIONS; case "current": return CURRENT_CONVERSIONS; case "temperature": return TEMPERATURE_CONVERSIONS; case "angle": return ANGLE_CONVERSIONS; case "volume": return VOLUME_CONVERSIONS; case "data": return DATA_CONVERSIONS; case "amount": return { mol: { coefficient: 1 } }; // Only one unit case "luminosity": return { cd: { coefficient: 1 } }; // Only one unit case "currency": return getCurrencyConversions(); default: throw new Error(`Unknown dimension: ${dimension}`); } } function getCurrencyConversions() { const { CurrencyManager: CurrencyManager2 } = (init_currency_manager(), __toCommonJS(currency_manager_exports)); const currencyManager = CurrencyManager2.getInstance(); const conversions = { USD: { coefficient: 1 } // Base currency }; try { const knownCurrencies = [ "EUR", "GBP", "JPY", "CNY", "CAD", "AUD", "CHF", "SEK", "NOK", "DKK", "PLN", "CZK", "HUF", "RON", "BGN", "HRK", "RUB", "TRY", "BRL", "MXN", "INR", "IDR", "KRW", "THB", "MYR", "PHP", "SGD", "HKD", "NZD", "ZAR" ]; for (const currency of knownCurrencies) { const rate = currencyManager.getRate(currency); if (rate !== void 0) { conversions[currency] = { coefficient: rate }; } } } catch (e) { console.error("Failed to get currency conversions:", e); } return conversions; } function convertUnit(value, fromUnit, toUnit, dimension) { if (fromUnit === toUnit) { return value; } const conversions = getConversionTable(dimension); if (!conversions) { throw new Error(`Cannot get conversion table for dimension: ${dimension}`); } const fromConv = conversions[fromUnit]; const toConv = conversions[toUnit]; if (!(fromConv && toConv)) { throw new Error(`Unknown unit: ${fromConv ? toUnit : fromUnit}`); } if (dimension === "temperature") { let kelvin; if (fromConv.offset) { kelvin = multiply( add(value, toDecimal(fromConv.offset)), toDecimal(fromConv.coefficient) ); } else { kelvin = multiply(value, toDecimal(fromConv.coefficient)); } if (toConv.offset) { return subtract( divide(kelvin, toDecimal(toConv.coefficient)), toDecimal(toConv.offset) ); } return divide(kelvin, toDecimal(toConv.coefficient)); } if (dimension === "currency") { const fromCurrencyCoef = toDecimal(fromConv.coefficient); const toCurrencyCoef = toDecimal(toConv.coefficient); const usdValue = divide(value, fromCurrencyCoef); return multiply(usdValue, toCurrencyCoef); } const { coefficient: fromCoef, exponent: fromExp = 0 } = fromConv; const baseValue = multiply( multiply(value, toDecimal(fromCoef)), power(toDecimal(10), toDecimal(fromExp)) ); const { coefficient: toCoef, exponent: toExp = 0 } = toConv; return divide( baseValue, multiply( toDecimal(toCoef), power(toDecimal(10), toDecimal(toExp)) ) ); } function multiplyDimensions(a, b) { const result = {}; for (const dim of Object.keys(a)) { const info = a[dim]; if (info) { if (dim === "currency") { result.currency = { ...info }; } else { Object.assign(result, { [dim]: { ...info } }); } } } for (const dim of Object.keys(b)) { const infoB = b[dim]; if (!infoB) { continue; } const existing = result[dim]; if (existing) { existing.exponent += infoB.exponent; if (dim === "currency") { const existingCurrency = existing; const infoBCurrency = infoB; if (!existingCurrency.code && infoBCurrency.code) { existingCurrency.code = infoBCurrency.code; } } else if ("unit" in existing && "unit" in infoB && !existing.unit && infoB.unit) { existing.unit = infoB.unit; } } else if (dim === "currency") { result.currency = { ...infoB }; } else { Object.assign(result, { [dim]: { ...infoB } }); } } for (const dim of Object.keys(result)) { if (result[dim]?.exponent === 0) { delete result[dim]; } } return result; } function divideDimensions(a, b) { const result = {}; for (const dim of Object.keys(a)) { const info = a[dim]; if (info) { if (dim === "currency") { result.currency = { ...info }; } else { Object.assign(result, { [dim]: { ...info } }); } } } for (const dim of Object.keys(b)) { const infoB = b[dim]; if (!infoB) { continue; } const existing = result[dim]; if (existing) { existing.exponent -= infoB.exponent; } else if (dim === "currency") { const infoBCurrency = infoB; result.currency = { exponent: -infoBCurrency.exponent, code: infoBCurrency.code }; } else { const negatedInfo = { ...infoB, exponent: -infoB.exponent }; Object.assign(result, { [dim]: negatedInfo }); } } for (const dim of Object.keys(result)) { if (result[dim]?.exponent === 0) { delete result[dim]; } } return result; } function areDimensionsCompatible(a, b) { const keysA = Object.keys(a).sort(); const keysB = Object.keys(b).sort(); if (keysA.length !== keysB.length) { return false; } for (let i = 0; i < keysA.length; i++) { const key = keysA[i]; if (key !== keysB[i] || a[key]?.exponent !== b[key]?.exponent) { return false; } } return true; } function convertCompoundUnit(value, fromDimensions, toDimensions) { if (!areDimensionsCompatible(fromDimensions, toDimensions)) { throw new Error("Incompatible dimensions for conversion"); } if (Object.keys(fromDimensions).length === 1 && Object.keys(toDimensions).length === 1 && fromDimensions.temperature && toDimensions.temperature) { const fromUnit = fromDimensions.temperature.unit; const toUnit = toDimensions.temperature.unit; if (fromUnit && toUnit) { return convertUnit(value, fromUnit, toUnit, "temperature"); } } let result = value; for (const dim of Object.keys(fromDimensions)) { const fromInfo = fromDimensions[dim]; const toInfo = toDimensions[dim]; if (!(fromInfo && toInfo)) { continue; } if (dim === "currency" && fromInfo && toInfo) { const fromCurrency = fromInfo; const toCurrency = toInfo; if (fromCurrency.code !== toCurrency.code) { const conversionFactor = convertUnit( toDecimal(1), fromCurrency.code, toCurrency.code, dim ); result = multiply( result, power(conversionFactor, toDecimal(fromCurrency.exponent)) ); } } else if (fromInfo && toInfo && "unit" in fromInfo && "unit" in toInfo && fromInfo.unit && toInfo.unit && fromInfo.unit !== toInfo.unit) { if (dim === "temperature" && fromInfo.exponent !== 1) { throw new Error( "Temperature cannot be raised to a power in conversions" ); } const conversionFactor = convertUnit( toDecimal(1), fromInfo.unit, toInfo.unit, dim ); result = multiply( result, power(conversionFactor, toDecimal(fromInfo.exponent)) ); } } return result; } function powerDimensions(dimensions, power2) { const result = {}; for (const [dim, info] of Object.entries(dimensions)) { if (dim === "currency") { result.currency = { exponent: info.exponent * power2, code: info.code }; } else { Object.assign(result, { [dim]: { ...info, exponent: info.exponent * power2 } }); } } return result; } function isDimensionless(dimensions) { return Object.keys(dimensions).length === 0; } function getDimensionForUnit(unit) { if (unit in LENGTH_CONVERSIONS) { return "length"; } if (unit in MASS_CONVERSIONS) { return "mass"; } if (unit in TIME_CONVERSIONS) { return "time"; } if (unit in CURRENT_CONVERSIONS) { return "current"; } if (unit in TEMPERATURE_CONVERSIONS) { return "temperature"; } if (unit in ANGLE_CONVERSIONS) { return "angle"; } if (unit in VOLUME_CONVERSIONS) { return "volume"; } if (unit in DATA_CONVERSIONS) { return "data"; } if (unit === "mol") { return "amount"; } if (unit === "cd") { return "luminosity"; } if (unit === "A" || unit === "amp" || unit === "amps" || unit === "ampere" || unit === "amperes" || unit === "mA" || unit === "milliamp" || unit === "milliamps" || unit === "milliampere" || unit === "milliamperes") { return "current"; } if (CURRENCY_CODE_PATTERN.test(unit)) { return "currency"; } return null; } function createDimensionFromUnit(unit) { if (derivedUnits[unit]) { return parseUnit(derivedUnits[unit]); } const dimension = getDimensionForUnit(unit); if (!dimension) { throw new Error(`Unknown unit: ${unit}`); } if (dimension === "currency") { return { currency: { exponent: 1, code: unit } }; } const dimensionMap = {}; if (dimension === "length") { dimensionMap.length = { exponent: 1, unit }; } else if (dimension === "mass") { dimensionMap.mass = { exponent: 1, unit }; } else if (dimension === "time") { dimensionMap.time = { exponent: 1, unit }; } else if (dimension === "current") { dimensionMap.current = { exponent: 1, unit }; } else if (dimension === "temperature") { dimensionMap.temperature = { exponent: 1, unit }; } else if (dimension === "angle") { dimensionMap.angle = { exponent: 1, unit }; } else if (dimension === "volume") { dimensionMap.volume = { exponent: 1, unit }; } else if (dimension === "data") { dimensionMap.data = { exponent: 1, unit }; } else if (dimension === "amount") { dimensionMap.amount = { exponent: 1, unit }; } else if (dimension === "luminosity") { dimensionMap.luminosity = { exponent: 1, unit }; } return dimensionMap; } function parseUnitTerm(term) { const parts = term.split("^"); const unit = parts[0]?.trim() || ""; const exponent = parts[1] ? Number.parseFloat(parts[1]) : 1; return { unit, exponent }; } function normalizeUnitExpression(expression) { if (!expression.includes("/")) { return expression; } const [numerator, ...denominatorParts] = expression.split("/"); let normalized = numerator || ""; for (const denomPart of denominatorParts) { if (!denomPart) { continue; } const denomTerms = denomPart.split("*"); for (const denomTerm of denomTerms) { const { unit, exponent } = parseUnitTerm(denomTerm); if (unit) { if (normalized) { normalized += "*"; } normalized += `${unit}^${-exponent}`; } } } return normalized; } function addDimensionToMap(dimensions, typedDim, dimInfo, exponent) { const existingDim = dimensions[typedDim]; if (existingDim && "exponent" in existingDim) { existingDim.exponent += dimInfo.exponent * exponent; } else if (typedDim === "currency" && "code" in dimInfo) { dimensions[typedDim] = { exponent: dimInfo.exponent * exponent, code: dimInfo.code }; } else if ("unit" in dimInfo) { const dimEntry = { exponent: dimInfo.exponent * exponent, unit: dimInfo.unit }; dimensions[typedDim] = dimEntry; } else { const dimEntry = { exponent: dimInfo.exponent * exponent }; dimensions[typedDim] = dimEntry; } } function parseUnit(unitExpression) { const dimensions = {}; const normalizedExpression = normalizeUnitExpression(unitExpression); const terms = normalizedExpression.split("*"); for (const term of terms) { const { unit, exponent } = parseUnitTerm(term); if (!unit) { continue; } const unitDimensions = createDimensionFromUnit(unit); for (const [dim, info] of Object.entries(unitDimensions)) { const typedDim = dim; if (info && typeof info === "object" && "exponent" in info) { const dimInfo = info; addDimensionToMap(dimensions, typedDim, dimInfo, exponent); } } } for (const dim of Object.keys(dimensions)) { const dimInfo = dimensions[dim]; if (dimInfo && "exponent" in dimInfo && dimInfo.exponent === 0) { delete dimensions[dim]; } } return dimensions; } var CURRENCY_CODE_PATTERN, LENGTH_CONVERSIONS, MASS_CONVERSIONS, TIME_CONVERSIONS, TEMPERATURE_CONVERSIONS, CURRENT_CONVERSIONS, ANGLE_CONVERSIONS, VOLUME_CONVERSIONS, DATA_CONVERSIONS; var init_dimensions = __esm({ "src/evaluator/dimensions.ts"() { "use strict"; init_esm_shims(); init_units(); init_decimal_math(); CURRENCY_CODE_PATTERN = /^[A-Z]{3}$/; LENGTH_CONVERSIONS = { // Base unit m: { coefficient: 1 }, meter: { coefficient: 1 }, meters: { coefficient: 1 }, // Metric km: { coefficient: 1, exponent: 3 }, kilometer: { coefficient: 1, exponent: 3 }, kilometers: { coefficient: 1, exponent: 3 }, cm: { coefficient: 1, exponent: -2 }, centimeter: { coefficient: 1, exponent: -2 }, centimeters: { coefficient: 1, exponent: -2 }, mm: { coefficient: 1, exponent: -3 }, millimeter: { coefficient: 1, exponent: -3 }, millimeters: { coefficient: 1, exponent: -3 }, // Imperial ft: { coefficient: 0.3048 }, foot: { coefficient: 0.3048 }, feet: { coefficient: 0.3048 }, in: { coefficient: 0.0254 }, inch: { coefficient: 0.0254 }, inches: { coefficient: 0.0254 }, yd: { coefficient: 0.9144 }, yard: { coefficient: 0.9144 }, yards: { coefficient: 0.9144 }, mi: { coefficient: 1609.34 }, mile: { coefficient: 1609.34 }, miles: { coefficient: 1609.34 } }; MASS_CONVERSIONS = { // Base unit kg: { coefficient: 1 }, kilogram: { coefficient: 1 }, kilograms: { coefficient: 1 }, // Metric g: { coefficient: 1, exponent: -3 }, gram: { coefficient: 1, exponent: -3 }, grams: { coefficient: 1, exponent: -3 }, mg: { coefficient: 1, exponent: -6 }, milligram: { coefficient: 1, exponent: -6 }, milligrams: { coefficient: 1, exponent: -6 }, t: { coefficient: 1, exponent: 3 }, ton: { coefficient: 1, exponent: 3 }, tons: { coefficient: 1, exponent: 3 }, // Imperial lb: { coefficient: 0.453592 }, lbs: { coefficient: 0.453592 }, pound: { coefficient: 0.453592 }, pounds: { coefficient: 0.453592 }, oz: { coefficient: 0.0283495 }, ounce: { coefficient: 0.0283495 }, ounces: { coefficient: 0.0283495 } }; TIME_CONVERSIONS = { // Base unit s: { coefficient: 1 }, sec: { coefficient: 1 }, second: { coefficient: 1 }, seconds: { coefficient: 1 }, ms: { coefficient: 1, exponent: -3 }, millisecond: { coefficient: 1, exponent: -3 }, milliseconds: { coefficient: 1, exponent: -3 }, min: { coefficient: 60 }, minute: { coefficient: 60 }, minutes: { coefficient: 60 }, h: { coefficient: 3600 }, hr: { coefficient: 3600 }, hour: { coefficient: 3600 }, hours: { coefficient: 3600 }, day: { coefficient: 86400 }, days: { coefficient: 86400 }, d: { coefficient: 86400 }, week: { coefficient: 604800 }, // 7 * 86400 weeks: { coefficient: 604800 }, w: { coefficient: 604800 }, month: { coefficient: 2629800 }, // Average month in seconds months: { coefficient: 2629800 }, year: { coefficient: 31557600 }, // Average year in seconds years: { coefficient: 31557600 }, yr: { coefficient: 31557600 } }; TEMPERATURE_CONVERSIONS = { // Base unit (Kelvin) K: { coefficient: 1 }, k: { coefficient: 1 }, kelvin: { coefficient: 1 }, C: { coefficient: 1, offset: 273.15 }, c: { coefficient: 1, offset: 273.15 }, celsius: { coefficient: 1, offset: 273.15 }, F: { coefficient: 5 / 9, offset: 459.67 }, f: { coefficient: 5 / 9, offset: 459.67 }, fahrenheit: { coefficient: 5 / 9, offset: 459.67 } }; CURRENT_CONVERSIONS = { // Base unit A: { coefficient: 1 }, amp: { coefficient: 1 }, amps: { coefficient: 1 }, ampere: { coefficient: 1 }, amperes: { coefficient: 1 }, mA: { coefficient: 1, exponent: -3 }, milliamp: { coefficient: 1, exponent: -3 }, milliamps: { coefficient: 1, exponent: -3 }, milliampere: { coefficient: 1, exponent: -3 }, milliamperes: { coefficient: 1, exponent: -3 }, \u03BCA: { coefficient: 1, exponent: -6 } }; ANGLE_CONVERSIONS = { // Base unit rad: { coefficient: 1 }, deg: { coefficient: Math.PI / 180 }, "\xB0": { coefficient: Math.PI / 180 } }; VOLUME_CONVERSIONS = { // Base unit (liter) l: { coefficient: 1 }, L: { coefficient: 1 }, liter: { coefficient: 1 }, liters: { coefficient: 1 }, ml: { coefficient: 1e-3 }, milliliter: { coefficient: 1e-3 }, milliliters: { coefficient: 1e-3 }, gal: { coefficient: 3.785411784 }, gallon: { coefficient: 3.785411784 }, gallons: { coefficient: 3.785411784 }, qt: { coefficient: 0.946352946 }, quart: { coefficient: 0.946352946 }, quarts: { coefficient: 0.946352946 }, pt: { coefficient: 0.473176473 }, pint: { coefficient: 0.473176473 }, pints: { coefficient: 0.473176473 }, cup: { coefficient: 0.2365882365 }, cups: { coefficient: 0.2365882365 }, tbsp: { coefficient: 0.0147867648 }, tablespoon: { coefficient: 0.0147867648 }, tablespoons: { coefficient: 0.0147867648 }, tsp: { coefficient: 0.0049289216 }, teaspoon: { coefficient: 0.0049289216 }, teaspoons: { coefficient: 0.0049289216 }, "fl oz": { coefficient: 0.0295735296 }, floz: { coefficient: 0.0295735296 } }; DATA_CONVERSIONS = { // Base unit (byte) byte: { coefficient: 1 }, bytes: { coefficient: 1 }, b: { coefficient: 1 }, // Decimal units kb: { coefficient: 1e3 }, kilobyte: { coefficient: 1e3 }, kilobytes: { coefficient: 1e3 }, mb: { coefficient: 1e6 }, megabyte: { coefficient: 1e6 }, megabytes: { coefficient: 1e6 }, gb: { coefficient: 1e9 }, gigabyte: { coefficient: 1e9 }, gigabytes: { coefficient: 1e9 }, tb: { coefficient: 1e12 }, terabyte: { coefficient: 1e12 }, terabytes: { coefficient: 1e12 }, // Binary units kib: { coefficient: 1024 }, kibibyte: { coefficient: 1024 }, kibibytes: { coefficient: 1024 }, mib: { coefficient: 1048576 }, mebibyte: { coefficient: 1048576 }, mebibytes: { coefficient: 1048576 }, gib: { coefficient: 1073741824 }, gibibyte: { coefficient: 1073741824 }, gibibytes: { coefficient: 1073741824 } }; } }); // src/types/index.ts var TokenType; var init_types = __esm({ "src/types/index.ts"() { "use strict"; init_esm_shims(); TokenType = { NUMBER: "NUMBER", OPERATOR: "OPERATOR", UNIT: "UNIT", FUNCTION: "FUNCTION", VARIABLE: "VARIABLE", KEYWORD: "KEYWORD", CURRENCY: "CURRENCY", CONSTANT: "CONSTANT", DATE_LITERAL: "DATE_LITERAL", TIME_LITERAL: "TIME_LITERAL", TIMEZONE: "TIMEZONE", AT_SYMBOL: "AT_SYMBOL", LPAREN: "LPAREN", RPAREN: "RPAREN", COMMA: "COMMA", EQUALS: "EQUALS", PLUS_EQUALS: "PLUS_EQUALS", MINUS_EQUALS: "MINUS_EQUALS", STRING_LITERAL: "STRING_LITERAL", SINGLE_QUOTE_STRING: "SINGLE_QUOTE_STRING", DOUBLE_QUOTE_STRING: "DOUBLE_QUOTE_STRING", DOT: "DOT", AS: "AS", TRUE: "TRUE", FALSE: "FALSE", NULL: "NULL", QUESTION: "QUESTION", COLON: "COLON", EQUAL: "EQUAL", NOT_EQUAL: "NOT_EQUAL", LESS_THAN: "LESS_THAN", GREATER_THAN: "GREATER_THAN", LESS_EQUAL: "LESS_EQUAL", GREATER_EQUAL: "GREATER_EQUAL", AND: "AND", OR: "OR", NOT: "NOT", PIPE: "PIPE", NULLISH_COALESCING: "NULLISH_COALESCING", LBRACE: "LBRACE", RBRACE: "RBRACE", LBRACKET: "LBRACKET", RBRACKET: "RBRACKET", ARROW: "ARROW", EOF: "EOF" }; } }); // src/parser/lambda-parser.ts function parseLambda(parser) { const parameters = []; if (parser.current.type === TokenType.VARIABLE) { parameters.push(parser.current.value); parser.advance(); if (parser.current.type !== TokenType.ARROW) { return null; } parser.advance(); } else if (parser.current.type === TokenType.LPAREN) { parser.advance(); if (parser.current.type === TokenType.RPAREN) { parser.advance(); } else { while (true) { if (parser.current.type !== TokenType.VARIABLE) { throw new Error("Expected parameter name in lambda"); } parameters.push(parser.current.value); parser.advance(); if (parser.current.type === TokenType.COMMA) { parser.advance(); } else if (parser.current.type === TokenType.RPAREN) { parser.advance(); break; } else { throw new Error("Expected ',' or ')' in lambda parameter list"); } } } if (parser.current.type !== TokenType.ARROW) { return null; } parser.advance(); } else { return null; } const body = parser.parseExpression(); return { type: "lambda", parameters, body }; } function isLambdaStart(parser) { const current = parser.current; if (current.type === TokenType.VARIABLE) { const next = parser.peek(); return next !== null && next.type === TokenType.ARROW; } if (current.type === TokenType.LPAREN) { let i = 1; let token = parser.peek(i); if (token && token.type === TokenType.RPAREN) { const arrow = parser.peek(i + 1); return arrow !== null && arrow.type === TokenType.ARROW; } if (token && token.type === TokenType.VARIABLE) { i++; token = parser.peek(i); while (token) { if (token.type === TokenType.COMMA) { i++; token = parser.peek(i); if (!token || token.type !== TokenType.VARIABLE) { return false; } i++; token = parser.peek(i); } else if (token.type === TokenType.RPAREN) { const arrow = parser.peek(i + 1); return arrow !== null && arrow.type === TokenType.ARROW; } else { return false; } } } } return false; } var init_lambda_parser = __esm({ "src/parser/lambda-parser.ts"() { "use strict"; init_esm_shims(); init_types(); } }); // src/parser/unit-parser.ts function parseCompoundUnit(tokens, startPos) { const units = []; let pos = startPos; let expectingUnit = true; let currentSign = 1; while (pos < tokens.length) { const token = tokens[pos]; if (expectingUnit) { if (token?.type !== TokenType.UNIT && token?.type !== TokenType.CURRENCY) { if (units.length === 0) { return null; } break; } let exponent = currentSign; if (pos + 1 < tokens.length && tokens[pos + 1]?.type === TokenType.OPERATOR && tokens[pos + 1]?.value === "^" && pos + 2 < tokens.length) { const expToken = tokens[pos + 2]; if (expToken?.type === TokenType.NUMBER) { exponent = currentSign * Number.parseFloat(expToken.value); pos += 2; } else if (expToken?.type === TokenType.OPERATOR && expToken.value === "-" && pos + 3 < tokens.length && tokens[pos + 3]?.type === TokenType.NUMBER) { exponent = currentSign * -Number.parseFloat(tokens[pos + 3]?.value || "1"); pos += 3; } } units.push({ unit: token.value, exponent }); pos++; expectingUnit = false; } else if (token?.type === TokenType.OPERATOR) { if (token.value === "*") { currentSign = 1; pos++; expectingUnit = true; } else if (token.value === "/") { currentSign = -1; pos++; expectingUnit = true; } else { break; } } else { break; } } if (expectingUnit && units.length > 0) { return null; } return units.length > 0 ? { units, endPos: pos } : null; } function unitsToExpression(units) { return units.map(({ unit, exponent }) => { if (exponent === 1) { return unit; } return `${unit}^${exponent}`; }).join("*"); } var init_unit_parser = __esm({ "src/parser/unit-parser.ts"() { "use strict"; init_esm_shims(); init_types(); } }); // src/data/keywords.ts function isKeyword(value) { return keywords.includes(value.toLowerCase()); } function isFunction(value) { const lowerValue = value.toLowerCase(); if (functions.includes(lowerValue)) { return true; } if (lowerValue.endsWith("!") && lowerValue.length > 1) { const baseName = lowerValue.slice(0, -1); return [ "push", "pop", "shift", "unshift", "append", "prepend", "slice", "filter", "map" ].includes(baseName); } return false; } function isMathConstant(value) { return mathConstants.includes( value.toLowerCase() ); } var dateKeywords, keywords, functions, mathConstants; var init_keywords = __esm({ "src/data/keywords.ts"() { "use strict"; init_esm_shims(); dateKeywords = [ "today", "tomorrow", "yesterday", "now", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday" ]; keywords = [ "in", "to", "as", "of", "is", "prev", "total", "agg", "aggregate", ...dateKeywords ]; functions = [ "sqrt", "cbrt", "root", "abs", "log", "ln", "fact", "round", "ceil", "floor", "sin", "cos", "tan", "arcsin", "arccos", "arctan", "sinh", "cosh", "tanh", "sum", "average", "avg", "fromunix", "format", "len", "substr", "charat", "trim", // Array functions "push", "pop", "shift", "unshift", "append", "prepend", "first", "last", "length", "slice", "find", "findIndex", "filter", "map", // Object functions "keys", "values", "has", // Environment and argument functions "env", "arg", // Type inspection functions "unit", "timezone", "type" ]; mathConstants = ["pi", "e"]; } }); // src/data/operators.ts var operatorMap, singleCharTokens, wordOperators; var init_operators = __esm({ "src/data/operators.ts"() { "use strict"; init_esm_shims(); init_types(); operatorMap = { "+": { tokenType: TokenType.OPERATOR, value: "+" }, "-": { tokenType: TokenType.OPERATOR, value: "-" }, "*": { tokenType: TokenType.OPERATOR, value: "*" }, "/": { tokenType: TokenType.OPERATOR, value: "/" }, "^": { tokenType: TokenType.OPERATOR, value: "^" }, "%": { tokenType: TokenType.OPERATOR, value: "%" }, "&": { tokenType: TokenType.OPERATOR, value: "&", consumeNext: "&" }, "|": { tokenType: TokenType.PIPE, value: "|" }, "||": { tokenType: TokenType.OR, value: "||", multiChar: true }, "??": { tokenType: TokenType.NULLISH_COALESCING, value: "??", multiChar: true }, "<<": { tokenType: TokenType.OPERATOR, value: "<<", multiChar: true }, ">>": { tokenType: TokenType.OPERATOR, value: ">>", multiChar: true } }; singleCharTokens = { "(": TokenType.LPAREN, ")": TokenType.RPAREN, ",": TokenType.COMMA, "=": TokenType.EQUALS, "@": TokenType.AT_SYMBOL, "{": TokenType.LBRACE, "}": TokenType.RBRACE, "[": TokenType.LBRACKET, "]": TokenType.RBRACKET }; wordOperators = { plus: "+", minus: "-", times: "*", multiplied: "*", divided: "/", mod: "%", xor: "^" }; } }); // src/data/timezones.ts function isTimezone(value) { const lowerValue = value.toLowerCase(); if (UTC_OFFSET_PATTERN.test(lowerValue)) { return true; } return timezones.includes(lowerValue); } var UTC_OFFSET_PATTERN, timezones, multiWordTimezoneStarts; var init_timezones = __esm({ "src/data/timezones.ts"() { "use strict"; init_esm_shims(); UTC_OFFSET_PATTERN = /^utc[+-]\d{1,2}$/; timezones = [ "utc", "gmt", "est", "edt", "cst", "cdt", "mst", "mdt", "pst", "pdt", "moscow", "yerevan", "london", "paris", "berlin", "tokyo", "sydney", "new york", "newyork", "ny", "nyc", "la", "los angeles", "losangeles", "chicago", "denver", "dubai", "singapore", "hong kong", "hongkong", "shanghai", "beijing", "mumbai", "delhi", "bangalore", "kolkata", "bangkok", "seoul", "istanbul", "cairo", "lagos", "nairobi", "johannesburg", "cape town", "capetown", "sao paulo", "saopaulo", "buenos aires", "buenosaires", "mexico", "mexico city", "mexicocity", "toronto", "vancouver", "montreal", "bst", "cet", "cest", "jst", "ist", "aest", "aedt" ]; multiWordTimezoneStarts = [ "new", "los", "hong", "san", "cape", "sao", "buenos", "mexico" ]; } }); // src/parser/tokenizer.ts var tokenizer_exports = {}; __export(tokenizer_exports, { DATE_KEYWORDS: () => DATE_KEYWORDS, MATH_CONSTANTS: () => MATH_CONSTANTS, Tokenizer: () => Tokenizer }); var WHITESPACE_PATTERN, DIGIT_PATTERN, UNICODE_LETTER_PATTERN, UNICODE_LETTER_OR_DIGIT_PATTERN, DATETIME_LOOKAHEAD_PATTERN, CURRENCY_CODE_PATTERN2, HEX_DIGIT_PATTERN, BINARY_DIGIT_PATTERN, DATE_KEYWORDS, MATH_CONSTANTS, Tokenizer; var init_tokenizer = __esm({ "src/parser/tokenizer.ts"() { "use strict"; init_esm_shims(); init_keywords(); init_operators(); init_timezones(); init_units(); init_types(); init_currency_manager(); WHITESPACE_PATTERN = /\s/; DIGIT_PATTERN = /[0-9]/; UNICODE_LETTER_PATTERN = new RegExp("\\p{L}", "u"); UNICODE_LETTER_OR_DIGIT_PATTERN = /[\p{L}\p{N}_]/u; DATETIME_LOOKAHEAD_PATTERN = /^\d{1,2}[./]\d{1,2}[./]\d{4}[Tt]/; CURRENCY_CODE_PATTERN2 = /^[A-Za-z]{3}$/; HE