summaryrefslogtreecommitdiff
path: root/src/utils
diff options
context:
space:
mode:
Diffstat (limited to 'src/utils')
-rw-r--r--src/utils/anonymous.test.ts32
-rw-r--r--src/utils/anonymous.ts1
-rw-r--r--src/utils/datetime.ts18
-rw-r--r--src/utils/iterator.ts27
4 files changed, 78 insertions, 0 deletions
diff --git a/src/utils/anonymous.test.ts b/src/utils/anonymous.test.ts
index 2da613f..45896bf 100644
--- a/src/utils/anonymous.test.ts
+++ b/src/utils/anonymous.test.ts
@@ -9,6 +9,7 @@ import {
identity,
instanciate,
pass,
+ transform,
} from "./anonymous.ts";
import { assertSpyCalls, spy } from "@std/testing/mock";
import { FALSE, TRUE } from "../../tests/fixtures/test_data.ts";
@@ -128,3 +129,34 @@ describe("extremeBy", () => {
assertEquals(extremeBy(data, "min"), Infinity);
});
});
+
+describe("transform", () => {
+ it("applies the function to the input", () => {
+ const result = transform(5, (x) => x * 2);
+ assertEquals(result, 10);
+ });
+
+ it("works with strings", () => {
+ const result = transform("hello", (x) => x.toUpperCase());
+ assertEquals(result, "HELLO");
+ });
+
+ it("works with objects", () => {
+ const input = { a: 1, b: 2 };
+ const result = transform(input, ({ a, b }) => a + b);
+ assertEquals(result, 3);
+ });
+
+ it("returns the correct type", () => {
+ const TRUE = true;
+ const FALSE = false;
+ const result = transform(TRUE, (x) => !x);
+ assertEquals(result, FALSE);
+ });
+
+ it("works with identity function", () => {
+ const input = [1, 2, 3];
+ const result = transform(input, identity);
+ assertEquals(result, input);
+ });
+});
diff --git a/src/utils/anonymous.ts b/src/utils/anonymous.ts
index ddd28bd..58e5a0a 100644
--- a/src/utils/anonymous.ts
+++ b/src/utils/anonymous.ts
@@ -23,3 +23,4 @@ export const pass = <T>(fn: (x: T) => void): (x: T) => T => (x: T): T => {
export const equal = <T>(x: T): (y: T) => boolean => (y: T): boolean => x === y;
export const extremeBy = (arr: number[], mode: "max" | "min"): number =>
Math[mode](...arr);
+export const transform = <T, U>(x: T, y: (x: T) => U): U => y(x);
diff --git a/src/utils/datetime.ts b/src/utils/datetime.ts
index c32fde0..be2ce08 100644
--- a/src/utils/datetime.ts
+++ b/src/utils/datetime.ts
@@ -1,3 +1,5 @@
+import { createRanges } from "./iterator.ts";
+
export function toIso8601Full(date: Date): string {
const yearN = date.getFullYear();
const isNegativeYear = yearN <= 0;
@@ -66,3 +68,19 @@ export function getRelativeTimeUnit(
if (Math.abs(minutes) >= 1) return [Math.round(minutes), "minute"];
return [Math.round(seconds), "second"];
}
+
+export function listDates(dates: Date[], { date, locale, list }: {
+ date: Intl.DateTimeFormatOptions;
+ locale: Intl.LocalesArgument;
+ list: Intl.ListFormatOptions;
+}): string {
+ const formatter = new Intl.DateTimeFormat(locale, date);
+ return new Intl.ListFormat(locale, list).format(dates.map(formatter.format));
+}
+
+export function listYearsWithRanges(years: number[], { locale, list }: {
+ locale: Intl.LocalesArgument;
+ list: Intl.ListFormatOptions;
+}): string {
+ return new Intl.ListFormat(locale, list).format(createRanges(years));
+}
diff --git a/src/utils/iterator.ts b/src/utils/iterator.ts
index fa58fc9..43437b6 100644
--- a/src/utils/iterator.ts
+++ b/src/utils/iterator.ts
@@ -50,3 +50,30 @@ export async function findMapAsync<T, R>(
return await tryNext(0);
}
+
+export function createRanges(nums: Iterable<number>): string[] {
+ const ns = new Set(nums).values().toArray().sort((
+ a,
+ b,
+ ) => a - b);
+
+ const result = [];
+ let start = ns[0];
+ let end = ns[0];
+
+ for (let i = 1; i <= ns.length; i++) {
+ if (ns[i] === end + 1) {
+ end = ns[i];
+ } else {
+ if (start === end) {
+ result.push(`${start}`);
+ } else {
+ result.push(`${start}-${end}`);
+ }
+ start = ns[i];
+ end = ns[i];
+ }
+ }
+
+ return result;
+}