Quickstart
import { strings, arrays, objects, dates } from '@cl3m/corekit'; strings.slugify('Hello World!'); // "hello-world" strings.toCamelCase('hello-world'); // "helloWorld" arrays.chunk([1,2,3,4,5], 2); // [[1,2],[3,4],[5]] arrays.groupBy(users, u => u.role); // { admin: [...], user: [...] } objects.pick({ a:1, b:2, c:3 }, ['a','c']); // { a:1, c:3 } objects.deepMerge(defaults, overrides); // deep merged object dates.timeAgo(new Date('2024-01-01')); // "X months ago" dates.formatDate(now, 'YYYY-MM-DD'); // "2026-03-05"
const { strings, arrays } = require('@cl3m/corekit'); strings.capitalize('hello'); // "Hello" arrays.unique([1,2,2,3]); // [1, 2, 3]
// Import only what you need — better tree-shaking import { slugify, truncate } from '@cl3m/corekit/strings'; import { chunk, groupBy } from '@cl3m/corekit/arrays'; import { pick, omit } from '@cl3m/corekit/objects'; import { formatDate } from '@cl3m/corekit/dates';
Browser Support
All core modules are browser-compatible. The CLI is Node.js only.
📦 CDN (script tag)
<script src="https://cdn.jsdelivr.net/npm/ @cl3m/corekit/dist/browser.global.js"></script> <script> corekit.strings.slugify('Hello!'); corekit.arrays.range(1, 5); </script>
⚡ ESM (modern browser)
<script type="module"> import { strings } from 'cdn.jsdelivr.net/.../browser.esm.js'; strings.toCamelCase('hello-world'); </script>
🔧 Bundler (Vite / Webpack)
import { strings, dates } from '@cl3m/corekit/browser';
✅ Compatibility
// Targets ES2017+
// Chrome 67+, Firefox 60+
// Safari 11+, Edge 18+
// Node.js 18+
CLI
Run utilities directly from your terminal. Install globally or use with npx.
# Install globally npm install -g @cl3m/corekit # Or run without installing npx @cl3m/corekit --help
$ corekit slugify "Hello World!"
hello-world
$ corekit camel "hello-world"
helloWorld
$ corekit chunk 3 a b c d e f
[["a","b","c"],["d","e","f"]]
$ corekit range 1 10
[1,2,3,4,5,6,7,8,9,10]
$ corekit format 2024-03-15 YYYY/MM/DD
2024/03/15
$ corekit timeago 2024-01-01
14 months ago
strings
Import: import { strings } from '@cl3m/corekit' or import { ... } from '@cl3m/corekit/strings'
capitalize(str: string) → string
▶
Capitalize the first letter of a string.
Example
capitalize("hello world") // → "Hello world" capitalize("") // → ""
toCamelCase(str: string) → string
▶
Convert a string to camelCase. Handles hyphens, underscores, and spaces.
toCamelCase("hello-world") // → "helloWorld" toCamelCase("foo_bar_baz") // → "fooBarBaz" toCamelCase("hello world") // → "helloWorld"
toKebabCase(str: string) → string
▶
Convert a string to kebab-case.
toKebabCase("helloWorld") // → "hello-world" toKebabCase("foo_bar") // → "foo-bar"
toSnakeCase(str: string) → string
▶
Convert a string to snake_case.
toSnakeCase("helloWorld") // → "hello_world" toSnakeCase("hello-world") // → "hello_world"
truncate(str: string, maxLength: number, ellipsis?: string) → string
▶
Truncate a string to a max length, appending an ellipsis if needed. Default ellipsis is
"...".truncate("Hello, world!", 8) // → "Hello..." truncate("Hi", 8) // → "Hi" truncate("Long text here", 7, "…") // → "Long t…"
slugify(str: string) → string
▶
Convert a string to a URL-safe slug. Normalizes unicode, removes special chars.
slugify("Hello World!") // → "hello-world" slugify("Héllo Wörld") // → "hello-world" slugify(" Foo Bar ") // → "foo-bar"
countOccurrences(str: string, sub: string) → number
▶
Count non-overlapping occurrences of a substring.
countOccurrences("banana", "an") // → 2 countOccurrences("hello", "") // → 0
isEmail(str: string) → boolean
▶
Check if a string is a valid email address format.
isEmail("user@example.com") // → true isEmail("not-an-email") // → false
reverseString(str: string) → string
▶
Reverse a string. Unicode-safe (handles emoji and multi-byte chars).
reverseString("hello") // → "olleh" reverseString("racecar") // → "racecar"
arrays
Import: import { arrays } from '@cl3m/corekit' or import { ... } from '@cl3m/corekit/arrays'
unique<T>(arr: T[]) → T[]
▶
Remove duplicate values from an array. Uses
Set internally.unique([1, 2, 2, 3, 3]) // → [1, 2, 3] unique(['a', 'b', 'a', 'c']) // → ["a", "b", "c"]
chunk<T>(arr: T[], size: number) → T[][]
▶
Split an array into chunks of a given size. Last chunk may be smaller.
chunk([1,2,3,4,5], 2) // → [[1,2],[3,4],[5]] chunk([1,2,3], 3) // → [[1,2,3]]
flatten<T>(arr: (T | T[])[], deep?: boolean) → T[]
▶
Flatten a nested array by one level, or deeply if
deep=true.flatten([[1,2],[3,[4]]]) // → [1, 2, 3, [4]] flatten([[1,2],[3,[4]]], true) // → [1, 2, 3, 4]
intersection<T>(a: T[], b: T[]) → T[]
▶
Return elements present in both arrays.
intersection([1,2,3], [2,3,4]) // → [2, 3]
difference<T>(a: T[], b: T[]) → T[]
▶
Return elements in
a that are not in b.difference([1,2,3], [2,3,4]) // → [1]
groupBy<T>(arr: T[], keyFn: (item: T) => string) → Record<string, T[]>
▶
Group array elements into an object by a key derived from a callback function.
const users = [ { name: 'Alice', role: 'admin' }, { name: 'Bob', role: 'user' }, { name: 'Carol', role: 'admin' }, ]; groupBy(users, u => u.role); // → { admin: [Alice, Carol], user: [Bob] }
shuffle<T>(arr: T[]) → T[]
▶
Shuffle an array using Fisher-Yates. Returns a new array, does not mutate.
shuffle([1, 2, 3, 4, 5]) // → [3, 1, 5, 2, 4] (random)
sum(arr: number[]) → number
▶
Sum all numbers in an array.
sum([1, 2, 3, 4]) // → 10 sum([]) // → 0
minMax(arr: number[]) → {'{ min: number; max: number }'}
▶
Get the minimum and maximum values of a numeric array in one pass.
minMax([3, 1, 4, 1, 5, 9]) // → { min: 1, max: 9 }
range(start: number, end: number, step?: number) → number[]
▶
Generate an array of numbers from start to end (inclusive), with optional step.
range(1, 5) // → [1, 2, 3, 4, 5] range(0, 10, 2) // → [0, 2, 4, 6, 8, 10]
objects
Import: import { objects } from '@cl3m/corekit' or import { ... } from '@cl3m/corekit/objects'
deepClone<T>(obj: T) → T
▶
Deep clone a plain object or array via JSON serialization. Does not handle functions, Dates, or circular refs.
const original = { a: { b: 1 } }; const clone = deepClone(original); clone.a.b = 99; original.a.b; // → 1 (unchanged)
deepMerge<T>(target: T, source: Partial<T>) → T
▶
Recursively merge two objects. Nested objects are merged; arrays are replaced.
deepMerge( { x: 1, y: { z: 2, w: 3 } }, { y: { z: 99 } } ) // → { x: 1, y: { z: 99, w: 3 } }
pick<T, K>(obj: T, keys: K[]) → Pick<T, K>
▶
Create a new object with only the specified keys. Fully type-safe.
pick({ a:1, b:2, c:3 }, ['a', 'c']) // → { a:1, c:3 }
omit<T, K>(obj: T, keys: K[]) → Omit<T, K>
▶
Create a new object excluding the specified keys. Complement of
pick.omit({ a:1, b:2, c:3 }, ['b']) // → { a:1, c:3 }
flattenObject(obj: Record<string, unknown>, prefix?: string) → Record<string, unknown>
▶
Flatten a deeply nested object using dot-notation keys.
flattenObject({ a: { b: { c: 1 }, d: 2 } }) // → { 'a.b.c': 1, 'a.d': 2 }
invertObject(obj: Record<string, string>) → Record<string, string>
▶
Swap all keys and values of an object.
invertObject({ a: '1', b: '2' }) // → { '1': 'a', '2': 'b' }
getByPath(obj: Record<string, unknown>, path: string) → unknown
▶
Safely get a nested value using a dot-notation path. Returns
undefined if path doesn't exist.getByPath({ a: { b: 42 } }, 'a.b') // → 42 getByPath({ a: {} }, 'a.b.c') // → undefined
isEmpty(obj: Record<string, unknown>) → boolean
▶
Check if an object has no own enumerable keys.
isEmpty({}) // → true isEmpty({ a: 1 }) // → false
dates
Import: import { dates } from '@cl3m/corekit' or import { ... } from '@cl3m/corekit/dates'
formatDate(date: Date, template: string) → string
▶
Format a date using a template. Tokens:
YYYY MM DD HH mm ss.const d = new Date('2024-03-15T09:05:00'); formatDate(d, 'YYYY-MM-DD') // → "2024-03-15" formatDate(d, 'DD/MM/YYYY') // → "15/03/2024" formatDate(d, 'HH:mm:ss') // → "09:05:00"
addToDate(date: Date, amount: number, unit: 'days' | 'months' | 'years') → Date
▶
Add a duration to a date. Returns a new Date object without mutating the original.
const d = new Date('2024-01-15'); addToDate(d, 10, 'days') // → 2024-01-25 addToDate(d, 2, 'months') // → 2024-03-15 addToDate(d, 1, 'years') // → 2025-01-15
diffDates(a: Date, b: Date, unit: 'milliseconds' | 'seconds' | 'minutes' | 'hours' | 'days') → number
▶
Get the difference between two dates in the specified unit. Can be negative.
const a = new Date('2024-01-01'); const b = new Date('2024-01-11'); diffDates(a, b, 'days') // → 10 diffDates(a, b, 'hours') // → 240
timeAgo(date: Date, now?: Date) → string
▶
Return a human-readable relative time string. Handles both past and future dates.
timeAgo(new Date(Date.now() - 30000)) // → "just now" timeAgo(new Date(Date.now() - 3600000)) // → "1 hour ago" timeAgo(new Date('2024-01-01')) // → "14 months ago" timeAgo(new Date(Date.now() + 86400000)) // → "in 1 day"
isBetween(date: Date, start: Date, end: Date) → boolean
▶
Check if a date falls within a range, inclusive of both endpoints.
isBetween( new Date('2024-06-15'), new Date('2024-01-01'), new Date('2024-12-31') ) // → true
isSameDay(a: Date, b: Date) → boolean
▶
Check if two dates fall on the same calendar day, regardless of time.
isSameDay(new Date('2024-03-15'), new Date('2024-03-15')) // → true isSameDay(new Date('2024-03-15'), new Date('2024-03-16')) // → false
startOf(date: Date, unit: 'day' | 'month' | 'year') → Date
▶
Get the start of a day, month, or year for a given date.
const d = new Date('2024-03-15T14:30:00'); startOf(d, 'day') // → 2024-03-15 00:00:00 startOf(d, 'month') // → 2024-03-01 00:00:00 startOf(d, 'year') // → 2024-01-01 00:00:00
isValidDate(val: unknown) → val is Date
▶
Type guard that checks if a value is a valid, non-NaN Date object.
isValidDate(new Date()) // → true isValidDate(new Date('invalid')) // → false isValidDate('2024-01-01') // → false