@supercmd/calculator 1.0.2 → 1.0.3
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/dist/index.js +139 -1
- package/dist/index.mjs +139 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1870,7 +1870,10 @@ var DATE_PATTERNS = [
|
|
|
1870
1870
|
/^(?:what(?:'s| is) )?(?:the )?(?:current )?date(?: today)?$/i,
|
|
1871
1871
|
/^(?:(?:what(?:'s|s| is))\s+today|(?:what(?:'s|s| is))\s+today'?s date|what day is it|what date is .+|todays date|today'?s date|date today|current date|what day is .+|when is .+)$/i,
|
|
1872
1872
|
// Days between dates
|
|
1873
|
-
/^(?:days?\s+)?(?:between|from)\s+.+\s+(?:to|and|until)\s+.+$/i
|
|
1873
|
+
/^(?:days?\s+)?(?:between|from)\s+.+\s+(?:to|and|until)\s+.+$/i,
|
|
1874
|
+
// Days until
|
|
1875
|
+
/^(?:days?\s+)?(?:until|till|to)\s+.+$/i,
|
|
1876
|
+
/^(?:how many days?\s+)?(?:until|till|to|before)\s+.+$/i
|
|
1874
1877
|
];
|
|
1875
1878
|
function tryDateIntent(input) {
|
|
1876
1879
|
for (const pattern of DATE_PATTERNS) {
|
|
@@ -2643,6 +2646,25 @@ function evaluateDate(query) {
|
|
|
2643
2646
|
return formatDateResult(query, d, { iso: d.toISOString(), unix: Math.floor(d.getTime() / 1e3) });
|
|
2644
2647
|
}
|
|
2645
2648
|
}
|
|
2649
|
+
const daysUntilMatch = lower.match(/^(?:(?:how many )?days?\s+)?(?:until|till|to|before)\s+(.+)$/);
|
|
2650
|
+
if (daysUntilMatch) {
|
|
2651
|
+
const target = parseDateTarget(daysUntilMatch[1].trim());
|
|
2652
|
+
if (target) {
|
|
2653
|
+
const now = /* @__PURE__ */ new Date();
|
|
2654
|
+
now.setHours(0, 0, 0, 0);
|
|
2655
|
+
const targetDate = new Date(target);
|
|
2656
|
+
targetDate.setHours(0, 0, 0, 0);
|
|
2657
|
+
const diffMs = targetDate.getTime() - now.getTime();
|
|
2658
|
+
const diffDays = Math.round(diffMs / (1e3 * 60 * 60 * 24));
|
|
2659
|
+
return {
|
|
2660
|
+
type: "date",
|
|
2661
|
+
input: query,
|
|
2662
|
+
result: diffDays,
|
|
2663
|
+
formatted: `${diffDays} days`,
|
|
2664
|
+
metadata: { from: now.toISOString(), to: target.toISOString() }
|
|
2665
|
+
};
|
|
2666
|
+
}
|
|
2667
|
+
}
|
|
2646
2668
|
const betweenMatch = lower.match(/^(?:days?\s+)?(?:between|from)\s+(.+)\s+(?:to|and|until)\s+(.+)$/);
|
|
2647
2669
|
if (betweenMatch) {
|
|
2648
2670
|
const d1 = parseFlexibleDate(betweenMatch[1].trim());
|
|
@@ -2735,6 +2757,82 @@ function formatDateResult(input, d, extraMeta) {
|
|
|
2735
2757
|
}
|
|
2736
2758
|
};
|
|
2737
2759
|
}
|
|
2760
|
+
function getNextOccurrence(month, day) {
|
|
2761
|
+
const now = /* @__PURE__ */ new Date();
|
|
2762
|
+
const thisYear = new Date(now.getFullYear(), month - 1, day);
|
|
2763
|
+
if (thisYear.getTime() >= new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime()) {
|
|
2764
|
+
return thisYear;
|
|
2765
|
+
}
|
|
2766
|
+
return new Date(now.getFullYear() + 1, month - 1, day);
|
|
2767
|
+
}
|
|
2768
|
+
var NAMED_DATES = {
|
|
2769
|
+
"christmas": () => getNextOccurrence(12, 25),
|
|
2770
|
+
"christmas day": () => getNextOccurrence(12, 25),
|
|
2771
|
+
"christmas eve": () => getNextOccurrence(12, 24),
|
|
2772
|
+
"new year": () => getNextOccurrence(1, 1),
|
|
2773
|
+
"new years": () => getNextOccurrence(1, 1),
|
|
2774
|
+
"new year's": () => getNextOccurrence(1, 1),
|
|
2775
|
+
"new year's day": () => getNextOccurrence(1, 1),
|
|
2776
|
+
"new years day": () => getNextOccurrence(1, 1),
|
|
2777
|
+
"new years eve": () => getNextOccurrence(12, 31),
|
|
2778
|
+
"new year's eve": () => getNextOccurrence(12, 31),
|
|
2779
|
+
"valentines": () => getNextOccurrence(2, 14),
|
|
2780
|
+
"valentines day": () => getNextOccurrence(2, 14),
|
|
2781
|
+
"valentine's day": () => getNextOccurrence(2, 14),
|
|
2782
|
+
"halloween": () => getNextOccurrence(10, 31),
|
|
2783
|
+
"independence day": () => getNextOccurrence(7, 4),
|
|
2784
|
+
"st patricks day": () => getNextOccurrence(3, 17),
|
|
2785
|
+
"st patrick's day": () => getNextOccurrence(3, 17)
|
|
2786
|
+
};
|
|
2787
|
+
var MONTH_NAMES = {
|
|
2788
|
+
january: 1,
|
|
2789
|
+
jan: 1,
|
|
2790
|
+
february: 2,
|
|
2791
|
+
feb: 2,
|
|
2792
|
+
march: 3,
|
|
2793
|
+
mar: 3,
|
|
2794
|
+
april: 4,
|
|
2795
|
+
apr: 4,
|
|
2796
|
+
may: 5,
|
|
2797
|
+
june: 6,
|
|
2798
|
+
jun: 6,
|
|
2799
|
+
july: 7,
|
|
2800
|
+
jul: 7,
|
|
2801
|
+
august: 8,
|
|
2802
|
+
aug: 8,
|
|
2803
|
+
september: 9,
|
|
2804
|
+
sep: 9,
|
|
2805
|
+
sept: 9,
|
|
2806
|
+
october: 10,
|
|
2807
|
+
oct: 10,
|
|
2808
|
+
november: 11,
|
|
2809
|
+
nov: 11,
|
|
2810
|
+
december: 12,
|
|
2811
|
+
dec: 12
|
|
2812
|
+
};
|
|
2813
|
+
function parseMonthDay(str) {
|
|
2814
|
+
const cleaned = str.replace(/(\d+)(?:st|nd|rd|th)/gi, "$1");
|
|
2815
|
+
let match = cleaned.match(/^(\d{1,2})\s+([a-z]+)$/i);
|
|
2816
|
+
if (match) {
|
|
2817
|
+
const day = parseInt(match[1]);
|
|
2818
|
+
const month = MONTH_NAMES[match[2].toLowerCase()];
|
|
2819
|
+
if (month && day >= 1 && day <= 31) return getNextOccurrence(month, day);
|
|
2820
|
+
}
|
|
2821
|
+
match = cleaned.match(/^([a-z]+)\s+(\d{1,2})$/i);
|
|
2822
|
+
if (match) {
|
|
2823
|
+
const month = MONTH_NAMES[match[1].toLowerCase()];
|
|
2824
|
+
const day = parseInt(match[2]);
|
|
2825
|
+
if (month && day >= 1 && day <= 31) return getNextOccurrence(month, day);
|
|
2826
|
+
}
|
|
2827
|
+
return null;
|
|
2828
|
+
}
|
|
2829
|
+
function parseDateTarget(str) {
|
|
2830
|
+
const lower = str.toLowerCase().trim();
|
|
2831
|
+
if (NAMED_DATES[lower]) return NAMED_DATES[lower]();
|
|
2832
|
+
const monthDay = parseMonthDay(lower);
|
|
2833
|
+
if (monthDay) return monthDay;
|
|
2834
|
+
return parseFlexibleDate(lower);
|
|
2835
|
+
}
|
|
2738
2836
|
function parseFlexibleDate(str) {
|
|
2739
2837
|
if (str === "today" || str === "now" || str === "date") return /* @__PURE__ */ new Date();
|
|
2740
2838
|
if (str === "tomorrow") {
|
|
@@ -2873,6 +2971,46 @@ async function calculate(input, options) {
|
|
|
2873
2971
|
const locale = options?.locale ?? "en-US";
|
|
2874
2972
|
const precision = options?.precision ?? 10;
|
|
2875
2973
|
const rateProvider = options?.rateProvider ?? getDefaultProvider();
|
|
2974
|
+
const convMathMatch = trimmed.match(
|
|
2975
|
+
/^(.+?\s+(?:to|in)\s+[a-zA-Z$€£¥₹₩₽₺₦₵₪฿]+(?:\s+[a-zA-Z]+)?)\s*([+\-*/^])\s*(.+)$/i
|
|
2976
|
+
);
|
|
2977
|
+
if (convMathMatch) {
|
|
2978
|
+
const convPart = convMathMatch[1].trim();
|
|
2979
|
+
const operator = convMathMatch[2];
|
|
2980
|
+
const mathPart = convMathMatch[3].trim();
|
|
2981
|
+
const convIntent = detectIntent(convPart);
|
|
2982
|
+
if (convIntent.kind === "currency" || convIntent.kind === "crypto" || convIntent.kind === "unit") {
|
|
2983
|
+
let convResult;
|
|
2984
|
+
switch (convIntent.kind) {
|
|
2985
|
+
case "currency":
|
|
2986
|
+
convResult = await evaluateCurrency(convIntent.amount, convIntent.from, convIntent.to, rateProvider, locale, precision);
|
|
2987
|
+
break;
|
|
2988
|
+
case "crypto":
|
|
2989
|
+
convResult = await evaluateCrypto(convIntent.amount, convIntent.from, convIntent.to, rateProvider, locale, precision);
|
|
2990
|
+
break;
|
|
2991
|
+
case "unit":
|
|
2992
|
+
convResult = evaluateUnit(convIntent.amount, convIntent.from, convIntent.to, locale, precision);
|
|
2993
|
+
break;
|
|
2994
|
+
}
|
|
2995
|
+
if (convResult.type !== "error" && typeof convResult.result === "number") {
|
|
2996
|
+
const mathExpr = `${convResult.result} ${operator} ${mathPart}`;
|
|
2997
|
+
const mathResult = evaluateMath(mathExpr, locale, precision);
|
|
2998
|
+
if (mathResult.type !== "error") {
|
|
2999
|
+
return {
|
|
3000
|
+
...mathResult,
|
|
3001
|
+
type: convResult.type,
|
|
3002
|
+
input: trimmed,
|
|
3003
|
+
metadata: {
|
|
3004
|
+
...mathResult.metadata,
|
|
3005
|
+
conversionResult: convResult.result,
|
|
3006
|
+
conversionFormatted: convResult.formatted,
|
|
3007
|
+
operation: `${convResult.formatted} ${operator} ${mathPart}`
|
|
3008
|
+
}
|
|
3009
|
+
};
|
|
3010
|
+
}
|
|
3011
|
+
}
|
|
3012
|
+
}
|
|
3013
|
+
}
|
|
2876
3014
|
const intent = detectIntent(trimmed);
|
|
2877
3015
|
switch (intent.kind) {
|
|
2878
3016
|
case "time":
|
package/dist/index.mjs
CHANGED
|
@@ -1833,7 +1833,10 @@ var DATE_PATTERNS = [
|
|
|
1833
1833
|
/^(?:what(?:'s| is) )?(?:the )?(?:current )?date(?: today)?$/i,
|
|
1834
1834
|
/^(?:(?:what(?:'s|s| is))\s+today|(?:what(?:'s|s| is))\s+today'?s date|what day is it|what date is .+|todays date|today'?s date|date today|current date|what day is .+|when is .+)$/i,
|
|
1835
1835
|
// Days between dates
|
|
1836
|
-
/^(?:days?\s+)?(?:between|from)\s+.+\s+(?:to|and|until)\s+.+$/i
|
|
1836
|
+
/^(?:days?\s+)?(?:between|from)\s+.+\s+(?:to|and|until)\s+.+$/i,
|
|
1837
|
+
// Days until
|
|
1838
|
+
/^(?:days?\s+)?(?:until|till|to)\s+.+$/i,
|
|
1839
|
+
/^(?:how many days?\s+)?(?:until|till|to|before)\s+.+$/i
|
|
1837
1840
|
];
|
|
1838
1841
|
function tryDateIntent(input) {
|
|
1839
1842
|
for (const pattern of DATE_PATTERNS) {
|
|
@@ -2606,6 +2609,25 @@ function evaluateDate(query) {
|
|
|
2606
2609
|
return formatDateResult(query, d, { iso: d.toISOString(), unix: Math.floor(d.getTime() / 1e3) });
|
|
2607
2610
|
}
|
|
2608
2611
|
}
|
|
2612
|
+
const daysUntilMatch = lower.match(/^(?:(?:how many )?days?\s+)?(?:until|till|to|before)\s+(.+)$/);
|
|
2613
|
+
if (daysUntilMatch) {
|
|
2614
|
+
const target = parseDateTarget(daysUntilMatch[1].trim());
|
|
2615
|
+
if (target) {
|
|
2616
|
+
const now = /* @__PURE__ */ new Date();
|
|
2617
|
+
now.setHours(0, 0, 0, 0);
|
|
2618
|
+
const targetDate = new Date(target);
|
|
2619
|
+
targetDate.setHours(0, 0, 0, 0);
|
|
2620
|
+
const diffMs = targetDate.getTime() - now.getTime();
|
|
2621
|
+
const diffDays = Math.round(diffMs / (1e3 * 60 * 60 * 24));
|
|
2622
|
+
return {
|
|
2623
|
+
type: "date",
|
|
2624
|
+
input: query,
|
|
2625
|
+
result: diffDays,
|
|
2626
|
+
formatted: `${diffDays} days`,
|
|
2627
|
+
metadata: { from: now.toISOString(), to: target.toISOString() }
|
|
2628
|
+
};
|
|
2629
|
+
}
|
|
2630
|
+
}
|
|
2609
2631
|
const betweenMatch = lower.match(/^(?:days?\s+)?(?:between|from)\s+(.+)\s+(?:to|and|until)\s+(.+)$/);
|
|
2610
2632
|
if (betweenMatch) {
|
|
2611
2633
|
const d1 = parseFlexibleDate(betweenMatch[1].trim());
|
|
@@ -2698,6 +2720,82 @@ function formatDateResult(input, d, extraMeta) {
|
|
|
2698
2720
|
}
|
|
2699
2721
|
};
|
|
2700
2722
|
}
|
|
2723
|
+
function getNextOccurrence(month, day) {
|
|
2724
|
+
const now = /* @__PURE__ */ new Date();
|
|
2725
|
+
const thisYear = new Date(now.getFullYear(), month - 1, day);
|
|
2726
|
+
if (thisYear.getTime() >= new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime()) {
|
|
2727
|
+
return thisYear;
|
|
2728
|
+
}
|
|
2729
|
+
return new Date(now.getFullYear() + 1, month - 1, day);
|
|
2730
|
+
}
|
|
2731
|
+
var NAMED_DATES = {
|
|
2732
|
+
"christmas": () => getNextOccurrence(12, 25),
|
|
2733
|
+
"christmas day": () => getNextOccurrence(12, 25),
|
|
2734
|
+
"christmas eve": () => getNextOccurrence(12, 24),
|
|
2735
|
+
"new year": () => getNextOccurrence(1, 1),
|
|
2736
|
+
"new years": () => getNextOccurrence(1, 1),
|
|
2737
|
+
"new year's": () => getNextOccurrence(1, 1),
|
|
2738
|
+
"new year's day": () => getNextOccurrence(1, 1),
|
|
2739
|
+
"new years day": () => getNextOccurrence(1, 1),
|
|
2740
|
+
"new years eve": () => getNextOccurrence(12, 31),
|
|
2741
|
+
"new year's eve": () => getNextOccurrence(12, 31),
|
|
2742
|
+
"valentines": () => getNextOccurrence(2, 14),
|
|
2743
|
+
"valentines day": () => getNextOccurrence(2, 14),
|
|
2744
|
+
"valentine's day": () => getNextOccurrence(2, 14),
|
|
2745
|
+
"halloween": () => getNextOccurrence(10, 31),
|
|
2746
|
+
"independence day": () => getNextOccurrence(7, 4),
|
|
2747
|
+
"st patricks day": () => getNextOccurrence(3, 17),
|
|
2748
|
+
"st patrick's day": () => getNextOccurrence(3, 17)
|
|
2749
|
+
};
|
|
2750
|
+
var MONTH_NAMES = {
|
|
2751
|
+
january: 1,
|
|
2752
|
+
jan: 1,
|
|
2753
|
+
february: 2,
|
|
2754
|
+
feb: 2,
|
|
2755
|
+
march: 3,
|
|
2756
|
+
mar: 3,
|
|
2757
|
+
april: 4,
|
|
2758
|
+
apr: 4,
|
|
2759
|
+
may: 5,
|
|
2760
|
+
june: 6,
|
|
2761
|
+
jun: 6,
|
|
2762
|
+
july: 7,
|
|
2763
|
+
jul: 7,
|
|
2764
|
+
august: 8,
|
|
2765
|
+
aug: 8,
|
|
2766
|
+
september: 9,
|
|
2767
|
+
sep: 9,
|
|
2768
|
+
sept: 9,
|
|
2769
|
+
october: 10,
|
|
2770
|
+
oct: 10,
|
|
2771
|
+
november: 11,
|
|
2772
|
+
nov: 11,
|
|
2773
|
+
december: 12,
|
|
2774
|
+
dec: 12
|
|
2775
|
+
};
|
|
2776
|
+
function parseMonthDay(str) {
|
|
2777
|
+
const cleaned = str.replace(/(\d+)(?:st|nd|rd|th)/gi, "$1");
|
|
2778
|
+
let match = cleaned.match(/^(\d{1,2})\s+([a-z]+)$/i);
|
|
2779
|
+
if (match) {
|
|
2780
|
+
const day = parseInt(match[1]);
|
|
2781
|
+
const month = MONTH_NAMES[match[2].toLowerCase()];
|
|
2782
|
+
if (month && day >= 1 && day <= 31) return getNextOccurrence(month, day);
|
|
2783
|
+
}
|
|
2784
|
+
match = cleaned.match(/^([a-z]+)\s+(\d{1,2})$/i);
|
|
2785
|
+
if (match) {
|
|
2786
|
+
const month = MONTH_NAMES[match[1].toLowerCase()];
|
|
2787
|
+
const day = parseInt(match[2]);
|
|
2788
|
+
if (month && day >= 1 && day <= 31) return getNextOccurrence(month, day);
|
|
2789
|
+
}
|
|
2790
|
+
return null;
|
|
2791
|
+
}
|
|
2792
|
+
function parseDateTarget(str) {
|
|
2793
|
+
const lower = str.toLowerCase().trim();
|
|
2794
|
+
if (NAMED_DATES[lower]) return NAMED_DATES[lower]();
|
|
2795
|
+
const monthDay = parseMonthDay(lower);
|
|
2796
|
+
if (monthDay) return monthDay;
|
|
2797
|
+
return parseFlexibleDate(lower);
|
|
2798
|
+
}
|
|
2701
2799
|
function parseFlexibleDate(str) {
|
|
2702
2800
|
if (str === "today" || str === "now" || str === "date") return /* @__PURE__ */ new Date();
|
|
2703
2801
|
if (str === "tomorrow") {
|
|
@@ -2836,6 +2934,46 @@ async function calculate(input, options) {
|
|
|
2836
2934
|
const locale = options?.locale ?? "en-US";
|
|
2837
2935
|
const precision = options?.precision ?? 10;
|
|
2838
2936
|
const rateProvider = options?.rateProvider ?? getDefaultProvider();
|
|
2937
|
+
const convMathMatch = trimmed.match(
|
|
2938
|
+
/^(.+?\s+(?:to|in)\s+[a-zA-Z$€£¥₹₩₽₺₦₵₪฿]+(?:\s+[a-zA-Z]+)?)\s*([+\-*/^])\s*(.+)$/i
|
|
2939
|
+
);
|
|
2940
|
+
if (convMathMatch) {
|
|
2941
|
+
const convPart = convMathMatch[1].trim();
|
|
2942
|
+
const operator = convMathMatch[2];
|
|
2943
|
+
const mathPart = convMathMatch[3].trim();
|
|
2944
|
+
const convIntent = detectIntent(convPart);
|
|
2945
|
+
if (convIntent.kind === "currency" || convIntent.kind === "crypto" || convIntent.kind === "unit") {
|
|
2946
|
+
let convResult;
|
|
2947
|
+
switch (convIntent.kind) {
|
|
2948
|
+
case "currency":
|
|
2949
|
+
convResult = await evaluateCurrency(convIntent.amount, convIntent.from, convIntent.to, rateProvider, locale, precision);
|
|
2950
|
+
break;
|
|
2951
|
+
case "crypto":
|
|
2952
|
+
convResult = await evaluateCrypto(convIntent.amount, convIntent.from, convIntent.to, rateProvider, locale, precision);
|
|
2953
|
+
break;
|
|
2954
|
+
case "unit":
|
|
2955
|
+
convResult = evaluateUnit(convIntent.amount, convIntent.from, convIntent.to, locale, precision);
|
|
2956
|
+
break;
|
|
2957
|
+
}
|
|
2958
|
+
if (convResult.type !== "error" && typeof convResult.result === "number") {
|
|
2959
|
+
const mathExpr = `${convResult.result} ${operator} ${mathPart}`;
|
|
2960
|
+
const mathResult = evaluateMath(mathExpr, locale, precision);
|
|
2961
|
+
if (mathResult.type !== "error") {
|
|
2962
|
+
return {
|
|
2963
|
+
...mathResult,
|
|
2964
|
+
type: convResult.type,
|
|
2965
|
+
input: trimmed,
|
|
2966
|
+
metadata: {
|
|
2967
|
+
...mathResult.metadata,
|
|
2968
|
+
conversionResult: convResult.result,
|
|
2969
|
+
conversionFormatted: convResult.formatted,
|
|
2970
|
+
operation: `${convResult.formatted} ${operator} ${mathPart}`
|
|
2971
|
+
}
|
|
2972
|
+
};
|
|
2973
|
+
}
|
|
2974
|
+
}
|
|
2975
|
+
}
|
|
2976
|
+
}
|
|
2839
2977
|
const intent = detectIntent(trimmed);
|
|
2840
2978
|
switch (intent.kind) {
|
|
2841
2979
|
case "time":
|
package/package.json
CHANGED