Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
faa6d8c
feat(collections): add groupBy function
hey-amanthakur Jul 10, 2026
bae5747
feat(collections): add shuffle function
hey-amanthakur Jul 10, 2026
899888c
feat(collections): add range function
hey-amanthakur Jul 10, 2026
096e70d
feat(collections): add difference function
hey-amanthakur Jul 10, 2026
3163525
feat(collections): add flatten function
hey-amanthakur Jul 10, 2026
a87fcf2
feat(collections): add countBy function
hey-amanthakur Jul 10, 2026
0933eb9
feat(collections): register new exports in mod.ts and deno.json
hey-amanthakur Jul 10, 2026
6d467b8
feat(text): add capitalize function
hey-amanthakur Jul 10, 2026
65ac39f
feat(text): add stripAnsi function
hey-amanthakur Jul 10, 2026
59155bc
feat(text): add isAlpha function
hey-amanthakur Jul 10, 2026
0dce091
feat(text): add isNumeric function
hey-amanthakur Jul 10, 2026
4a1b304
feat(text): add isAlphanumeric function
hey-amanthakur Jul 10, 2026
81c80b7
feat(text): add escapeHtml function
hey-amanthakur Jul 10, 2026
af6b069
feat(text): add unescapeHtml function
hey-amanthakur Jul 10, 2026
0c1eb49
feat(text): register new exports in mod.ts and deno.json
hey-amanthakur Jul 10, 2026
f129d5e
Merge pull request #1 from jhonsnow456/feat/collections
hey-amanthakur Jul 10, 2026
ac27661
Merge pull request #2 from jhonsnow456/feat/text
hey-amanthakur Jul 10, 2026
f78d38c
chore(collections): fix formatting in groupBy test
hey-amanthakur Jul 10, 2026
0d81869
removal(collections,text): remove redundant utility functions
hey-amanthakur Jul 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions collections/count_by.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright 2018-2026 the Deno authors. MIT license.
// This module is browser compatible.

/**
* Counts the occurrences of each key returned by the given function.
*
* @typeParam T The type of the array elements
* @typeParam K The type of the keys
*
* @param array The array to count
* @param keyFn The function that returns the key for each element
*
* @returns An object mapping keys to their counts
*
* @example Basic usage
* ```ts
* import { countBy } from "@std/collections/count-by";
* import { assertEquals } from "@std/assert";
*
* const pets = [
* { type: "dog", name: "Fido" },
* { type: "cat", name: "Whiskers" },
* { type: "dog", name: "Rover" },
* ];
*
* const counts = countBy(pets, (pet) => pet.type);
* assertEquals(counts, { dog: 2, cat: 1 });
* ```
*/
export function countBy<T, K extends PropertyKey>(
array: readonly T[],
keyFn: (element: T) => K,
): Record<K, number> {
const result = {} as Record<K, number>;
for (const element of array) {
const key = keyFn(element);
if (Object.prototype.hasOwnProperty.call(result, key)) {
result[key]!++;
} else {
result[key] = 1;
}
}
return result;
}
32 changes: 32 additions & 0 deletions collections/count_by_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 2018-2026 the Deno authors. MIT license.
import { assertEquals } from "@std/assert";
import { countBy } from "./count_by.ts";

Deno.test({
name: "countBy() counts elements by key",
fn() {
const pets = [
{ type: "dog", name: "Fido" },
{ type: "cat", name: "Whiskers" },
{ type: "dog", name: "Rover" },
];
assertEquals(countBy(pets, (pet) => pet.type), { dog: 2, cat: 1 });
},
});

Deno.test({
name: "countBy() handles empty array",
fn() {
assertEquals(countBy([], (x: number) => x % 2), {});
},
});

Deno.test({
name: "countBy() counts numbers by parity",
fn() {
assertEquals(
countBy([1, 2, 3, 4, 5, 6], (n) => n % 2 === 0 ? "even" : "odd"),
{ odd: 3, even: 3 },
);
},
});
2 changes: 2 additions & 0 deletions collections/deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"./associate-by": "./associate_by.ts",
"./associate-with": "./associate_with.ts",
"./chunk": "./chunk.ts",
"./count-by": "./count_by.ts",
"./deep-merge": "./deep_merge.ts",
"./distinct": "./distinct.ts",
"./distinct-by": "./distinct_by.ts",
Expand Down Expand Up @@ -38,6 +39,7 @@
"./partition-entries": "./partition_entries.ts",
"./permutations": "./permutations.ts",
"./pick": "./pick.ts",
"./range": "./range.ts",
"./reduce-groups": "./reduce_groups.ts",
"./running-reduce": "./running_reduce.ts",
"./sample": "./sample.ts",
Expand Down
2 changes: 2 additions & 0 deletions collections/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export * from "./aggregate_groups.ts";
export * from "./associate_by.ts";
export * from "./associate_with.ts";
export * from "./chunk.ts";
export * from "./count_by.ts";
export * from "./deep_merge.ts";
export * from "./distinct.ts";
export * from "./distinct_by.ts";
Expand Down Expand Up @@ -63,6 +64,7 @@ export * from "./partition.ts";
export * from "./partition_entries.ts";
export * from "./permutations.ts";
export * from "./pick.ts";
export * from "./range.ts";
export * from "./reduce_groups.ts";
export * from "./running_reduce.ts";
export * from "./sample.ts";
Expand Down
64 changes: 64 additions & 0 deletions collections/range.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright 2018-2026 the Deno authors. MIT license.
// This module is browser compatible.

/** Options for {@linkcode range}. */
export type RangeOptions = {
/**
* The step value.
* @default {1 or -1}
*/
step?: number;
};

/**
* Returns an array of numbers progressing from start up to but not including
* end, with an optional step value.
*
* If only one argument is provided, it is treated as the end value with start
* defaulting to 0.
*
* @param startOrEnd The start value (or end if only one arg)
* @param end The end value (exclusive)
* @param options Options for the range
*
* @returns An array of numbers
*
* @example Basic usage
* ```ts
* import { range } from "@std/collections/range";
* import { assertEquals } from "@std/assert";
*
* assertEquals(range(5), [0, 1, 2, 3, 4]);
* assertEquals(range(1, 5), [1, 2, 3, 4]);
* assertEquals(range(0, 10, { step: 2 }), [0, 2, 4, 6, 8]);
* assertEquals(range(5, 0, { step: -1 }), [5, 4, 3, 2, 1]);
* ```
*/
export function range(
startOrEnd: number,
end?: number,
options?: RangeOptions,
): number[] {
const start = end === undefined ? 0 : startOrEnd;
const stop = end === undefined ? startOrEnd : end;
const stepValue = options?.step ?? (stop < start ? -1 : 1);

if (stepValue === 0) {
throw new RangeError("`step` must not be zero");
}
if (!Number.isFinite(start) || !Number.isFinite(stop)) {
throw new RangeError("`start` and `end` must be finite numbers");
}

const result: number[] = [];
if (stepValue > 0) {
for (let i = start; i < stop; i += stepValue) {
result.push(i);
}
} else {
for (let i = start; i > stop; i += stepValue) {
result.push(i);
}
}
return result;
}
68 changes: 68 additions & 0 deletions collections/range_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright 2018-2026 the Deno authors. MIT license.
import { assertEquals, assertThrows } from "@std/assert";
import { range } from "./range.ts";

Deno.test({
name: "range() generates sequence with only end argument",
fn() {
assertEquals(range(5), [0, 1, 2, 3, 4]);
},
});

Deno.test({
name: "range() generates sequence with start and end",
fn() {
assertEquals(range(1, 5), [1, 2, 3, 4]);
},
});

Deno.test({
name: "range() generates sequence with step",
fn() {
assertEquals(range(0, 10, { step: 2 }), [0, 2, 4, 6, 8]);
},
});

Deno.test({
name: "range() generates descending sequence",
fn() {
assertEquals(range(5, 0, { step: -1 }), [5, 4, 3, 2, 1]);
},
});

Deno.test({
name: "range() returns empty array when start equals end",
fn() {
assertEquals(range(5, 5), []);
},
});

Deno.test({
name: "range() returns empty array when start <= end for descending",
fn() {
assertEquals(range(0, 0, { step: -1 }), []);
assertEquals(range(1, 2, { step: -1 }), []);
},
});

Deno.test({
name: "range() throws on step = 0",
fn() {
assertThrows(
() => range(0, 5, { step: 0 }),
RangeError,
"`step` must not be zero",
);
},
});

Deno.test({
name: "range() throws on non-finite numbers",
fn() {
assertThrows(
() => range(Infinity, 5),
RangeError,
"`start` and `end` must be finite numbers",
);
},
});
13 changes: 8 additions & 5 deletions text/deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,21 @@
".": "./mod.ts",
"./closest-string": "./closest_string.ts",
"./compare-similarity": "./compare_similarity.ts",
"./unstable-dedent": "./unstable_dedent.ts",
"./is-alpha": "./is_alpha.ts",
"./is-alphanumeric": "./is_alphanumeric.ts",
"./is-numeric": "./is_numeric.ts",
"./levenshtein-distance": "./levenshtein_distance.ts",
"./to-camel-case": "./to_camel_case.ts",
"./to-kebab-case": "./to_kebab_case.ts",
"./to-pascal-case": "./to_pascal_case.ts",
"./to-snake-case": "./to_snake_case.ts",
"./unstable-dedent": "./unstable_dedent.ts",
"./unstable-longest-common-prefix": "./unstable_longest_common_prefix.ts",
"./unstable-reverse": "./unstable_reverse.ts",
"./unstable-slugify": "./unstable_slugify.ts",
"./unstable-trim-by": "./unstable_trim_by.ts",
"./to-camel-case": "./to_camel_case.ts",
"./unstable-to-constant-case": "./unstable_to_constant_case.ts",
"./to-kebab-case": "./to_kebab_case.ts",
"./to-pascal-case": "./to_pascal_case.ts",
"./unstable-to-sentence-case": "./unstable_to_sentence_case.ts",
"./to-snake-case": "./to_snake_case.ts",
"./unstable-to-title-case": "./unstable_to_title_case.ts",
"./unstable-truncate": "./unstable_truncate.ts",
"./word-similarity-sort": "./word_similarity_sort.ts"
Expand Down
21 changes: 21 additions & 0 deletions text/is_alpha.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright 2018-2026 the Deno authors. MIT license.
// This module is browser compatible.

/**
* Checks if a string contains only alphabetic characters.
*
* @param input The string to check
* @returns `true` if the string contains only alphabetic characters
*
* @example Usage
* ```ts
* import { isAlpha } from "@std/text/is-alpha";
* import { assertEquals } from "@std/assert";
*
* assertEquals(isAlpha("hello"), true);
* assertEquals(isAlpha("hello123"), false);
* ```
*/
export function isAlpha(input: string): boolean {
return /^[A-Za-z]+$/.test(input);
}
22 changes: 22 additions & 0 deletions text/is_alpha_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2018-2026 the Deno authors. MIT license.

import { assertEquals } from "@std/assert";
import { isAlpha } from "./is_alpha.ts";

Deno.test("isAlpha() returns true for alphabetic strings", () => {
assertEquals(isAlpha("hello"), true);
assertEquals(isAlpha("HELLO"), true);
});

Deno.test("isAlpha() returns false for strings with numbers", () => {
assertEquals(isAlpha("hello123"), false);
});

Deno.test("isAlpha() returns false for strings with special characters", () => {
assertEquals(isAlpha("hello world"), false);
assertEquals(isAlpha("hello!"), false);
});

Deno.test("isAlpha() returns false for empty string", () => {
assertEquals(isAlpha(""), false);
});
21 changes: 21 additions & 0 deletions text/is_alphanumeric.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright 2018-2026 the Deno authors. MIT license.
// This module is browser compatible.

/**
* Checks if a string contains only alphabetic and numeric characters.
*
* @param input The string to check
* @returns `true` if the string contains only alphanumeric characters
*
* @example Usage
* ```ts
* import { isAlphanumeric } from "@std/text/is-alphanumeric";
* import { assertEquals } from "@std/assert";
*
* assertEquals(isAlphanumeric("hello123"), true);
* assertEquals(isAlphanumeric("hello 123"), false);
* ```
*/
export function isAlphanumeric(input: string): boolean {
return /^[A-Za-z0-9]+$/.test(input);
}
19 changes: 19 additions & 0 deletions text/is_alphanumeric_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright 2018-2026 the Deno authors. MIT license.

import { assertEquals } from "@std/assert";
import { isAlphanumeric } from "./is_alphanumeric.ts";

Deno.test("isAlphanumeric() returns true for alphanumeric strings", () => {
assertEquals(isAlphanumeric("hello123"), true);
assertEquals(isAlphanumeric("abc"), true);
assertEquals(isAlphanumeric("123"), true);
});

Deno.test("isAlphanumeric() returns false for strings with special characters", () => {
assertEquals(isAlphanumeric("hello 123"), false);
assertEquals(isAlphanumeric("hello!"), false);
});

Deno.test("isAlphanumeric() returns false for empty string", () => {
assertEquals(isAlphanumeric(""), false);
});
21 changes: 21 additions & 0 deletions text/is_numeric.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright 2018-2026 the Deno authors. MIT license.
// This module is browser compatible.

/**
* Checks if a string contains only numeric characters.
*
* @param input The string to check
* @returns `true` if the string contains only numeric characters
*
* @example Usage
* ```ts
* import { isNumeric } from "@std/text/is-numeric";
* import { assertEquals } from "@std/assert";
*
* assertEquals(isNumeric("123"), true);
* assertEquals(isNumeric("123abc"), false);
* ```
*/
export function isNumeric(input: string): boolean {
return /^[0-9]+$/.test(input);
}
Loading
Loading