{"id":21467405,"url":"https://github.com/elusivecodes/frostcore","last_synced_at":"2026-04-01T17:32:53.765Z","repository":{"id":52022251,"uuid":"138688971","full_name":"elusivecodes/FrostCore","owner":"elusivecodes","description":"FrostCore is a free, open-source utility library for JavaScript.","archived":false,"fork":false,"pushed_at":"2024-06-24T01:07:08.000Z","size":877,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-11-15T00:38:17.687Z","etag":null,"topics":["array","function","javascript","math","object","string","testing","utility"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/elusivecodes.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-06-26T05:29:54.000Z","updated_at":"2024-09-21T23:35:37.000Z","dependencies_parsed_at":"2023-02-01T05:46:27.469Z","dependency_job_id":null,"html_url":"https://github.com/elusivecodes/FrostCore","commit_stats":null,"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elusivecodes%2FFrostCore","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elusivecodes%2FFrostCore/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elusivecodes%2FFrostCore/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elusivecodes%2FFrostCore/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/elusivecodes","download_url":"https://codeload.github.com/elusivecodes/FrostCore/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":226017469,"owners_count":17560519,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["array","function","javascript","math","object","string","testing","utility"],"created_at":"2024-11-23T08:17:53.892Z","updated_at":"2026-04-01T17:32:53.752Z","avatar_url":"https://github.com/elusivecodes.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# FrostCore\n\n[![CI](https://github.com/elusivecodes/FrostCore/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/elusivecodes/FrostCore/actions/workflows/ci.yml)\n[![npm version](https://img.shields.io/npm/v/%40fr0st%2Fcore?style=flat-square)](https://www.npmjs.com/package/@fr0st/core)\n[![npm downloads](https://img.shields.io/npm/dm/%40fr0st%2Fcore?style=flat-square)](https://www.npmjs.com/package/@fr0st/core)\n[![minzipped size](https://img.shields.io/bundlejs/size/%40fr0st/core?format=minzip\u0026style=flat-square)](https://bundlejs.com/?q=@fr0st/core)\n[![license](https://img.shields.io/github/license/elusivecodes/FrostCore?style=flat-square)](./LICENSE)\n\nSmall, focused utilities for arrays, functions, math, objects, strings, and type checks. FrostCore has zero runtime dependencies, works in Node and bundlers, and also ships a browser-friendly UMD bundle that exposes `globalThis._`.\n\n## Highlights\n\n- Named exports for tree-shaking\n- Browser UMD bundle in `dist/`\n- No runtime dependencies\n- JSDoc-powered IntelliSense\n\n## Installation\n\n### Node / bundlers\n\n```bash\nnpm i @fr0st/core\n```\n\nFrostCore is ESM-only. Use `import` syntax in Node and bundlers.\n\n### Browser (UMD)\n\nLoad the bundle from your own copy or a CDN:\n\n```html\n\u003cscript src=\"/path/to/dist/frost-core.min.js\"\u003e\u003c/script\u003e\n\u003c!-- or --\u003e\n\u003cscript src=\"https://cdn.jsdelivr.net/npm/@fr0st/core@latest/dist/frost-core.min.js\"\u003e\u003c/script\u003e\n\u003cscript\u003e\n    const { clamp, randomInt } = globalThis._;\n    console.log(clamp(randomInt(10), 0, 9));\n\u003c/script\u003e\n```\n\n## Quick Start\n\n```js\nimport {\n    clamp,\n    debounce,\n    humanize,\n    range,\n    setDot,\n} from '@fr0st/core';\n\nconst state = { user: { profile: { name: 'Ada' } } };\n\nsetDot(state, 'user.profile.name', 'Ada Lovelace');\n\nconst values = range(0, 10, 2);\nconst label = humanize('favoriteColor');\n\nconst save = debounce(() =\u003e {\n    console.log('saving', state, values, label);\n}, 250);\n\nconsole.log(clamp(14, 0, 10)); // 10\nsave();\n```\n\nTypeScript note: FrostCore is written in JavaScript and uses JSDoc types, which most editors surface as IntelliSense.\n\n## API\n\nAll utilities are exported from `@fr0st/core` as named ESM exports.\n\n### Arrays\n\n- `diff(array, ...arrays)`: values that exist only in the first array\n- `intersect(...arrays)`: unique values shared by all arrays\n- `merge(array, ...arrays)`: appends arrays or array-like values into the first array\n- `randomValue(array)`: random element from an array, or `null` for an empty array\n- `range(start, end, step = 1)`: numeric sequence from `start` toward `end`\n- `unique(array)`: remove duplicate values\n- `wrap(value)`: normalize a value into an array\n\n```js\nimport { diff, merge, range, unique, wrap } from '@fr0st/core';\n\ndiff([1, 2, 3], [2]); // [1, 3]\nrange(0, 5); // [0, 1, 2, 3, 4, 5]\nunique([1, 1, 2]); // [1, 2]\nwrap(undefined); // []\n\nconst out = [1];\nmerge(out, [2, 3]);\n// out === [1, 2, 3]\n```\n\n### Functions\n\n- `animation(callback, options)`: run at most once per animation frame\n- `compose(...callbacks)`: right-to-left function composition\n- `curry(callback)`: curry a function until its arity is satisfied\n- `debounce(callback, wait, options)`: delay execution until calls settle\n- `evaluate(value)`: call a function or return a non-function as-is\n- `once(callback)`: run a function once and cache the result\n- `partial(callback, ...defaultArgs)`: partially apply arguments\n- `pipe(...callbacks)`: left-to-right function composition\n- `throttle(callback, wait, options)`: run at most once per wait period\n- `times(callback, amount)`: execute a callback repeatedly\n\n```js\nimport { compose, debounce, once, partial, pipe, throttle } from '@fr0st/core';\n\nconst add1 = (n) =\u003e n + 1;\nconst double = (n) =\u003e n * 2;\n\ncompose(add1, double)(3); // 7\npipe(add1, double)(3); // 8\n\nconst init = once(() =\u003e Math.random());\ninit() === init(); // true\n\npartial((a, b) =\u003e [a, b], undefined, 2)(1); // [1, 2]\n\nconst debounced = debounce((value) =\u003e console.log(value), 100);\nconst throttled = throttle(() =\u003e console.log('tick'), 100);\n\ndebounced('last');\nthrottled();\n```\n\n### Math\n\n- `clamp(value, min, max)`: clamp a number between bounds\n- `clampPercent(value)`: clamp a number between `0` and `100`\n- `dist(x1, y1, x2, y2)`: distance between two points\n- `inverseLerp(v1, v2, value)`: interpolation amount between two values\n- `len(x, y)`: vector length\n- `lerp(v1, v2, amount)`: linear interpolation\n- `map(value, fromMin, fromMax, toMin, toMax)`: remap a value from one range to another\n- `random(a, b)`: random floating-point value\n- `randomInt(a, b)`: random integer\n- `toStep(value, step)`: round a number to a step size\n\n```js\nimport { clamp, dist, lerp, map, random, randomInt, toStep } from '@fr0st/core';\n\nclamp(10, 0, 1); // 1\ndist(0, 0, 3, 4); // 5\nlerp(0, 10, 0.25); // 2.5\nmap(0.5, 0, 1, 0, 10); // 5\nrandom(10); // 0 \u003c= n \u003c 10\nrandomInt(10, 50); // 10 \u003c= n \u003c 50\ntoStep(0.123, 0.05); // 0.1\n```\n\n### Objects\n\n- `extend(object, ...objects)`: deep-merge values into the first object\n- `flatten(object)`: flatten plain-object paths into dot notation\n- `forgetDot(object, key)`: delete a path from an object\n- `getDot(object, key, defaultValue)`: read a path from an object\n- `hasDot(object, key)`: test whether a path exists\n- `pluckDot(objects, key, defaultValue)`: read the same path from many objects\n- `setDot(object, key, value, options)`: assign a path in an object\n\n```js\nimport { extend, flatten, getDot, pluckDot, setDot } from '@fr0st/core';\n\nconst obj = extend({ a: 1 }, { b: { c: 2 } });\n\ngetDot(obj, 'b.c'); // 2\nflatten({ a: { b: 1 } }); // { 'a.b': 1 }\npluckDot([{ a: { b: 1 } }, { a: { b: 2 } }], 'a.b'); // [1, 2]\n\nsetDot(obj, 'b.c', 3);\n```\n\n### Strings\n\n- `camelCase(string)`: convert text to `camelCase`\n- `capitalize(string)`: upper-case the first character and lower-case the rest\n- `escape(string)`: escape HTML entities\n- `escapeRegExp(string)`: escape RegExp control characters\n- `humanize(string)`: convert identifiers into readable words\n- `kebabCase(string)`: convert text to `kebab-case`\n- `pascalCase(string)`: convert text to `PascalCase`\n- `randomString(length, chars)`: create a random string\n- `snakeCase(string)`: convert text to `snake_case`\n- `unescape(string)`: unescape HTML entities\n\n```js\nimport { camelCase, escape, humanize, kebabCase, randomString, snakeCase } from '@fr0st/core';\n\ncamelCase('hello world'); // 'helloWorld'\nhumanize('helloWorld'); // 'Hello world'\nkebabCase('helloWorld'); // 'hello-world'\nsnakeCase('helloWorld'); // 'hello_world'\nescape('\u003cdiv class=\"x\"\u003e'); // '\u0026lt;div class=\u0026quot;x\u0026quot;\u0026gt;'\nrandomString(8); // e.g. 'aZ02kLmP'\n```\n\n### Testing\n\n- `isArray(value)`\n- `isArrayLike(value)`\n- `isBoolean(value)`\n- `isDocument(value)`\n- `isElement(value)`\n- `isFragment(value)`\n- `isFunction(value)`\n- `isNaN(value)`\n- `isNode(value)`\n- `isNull(value)`\n- `isNumeric(value)`\n- `isObject(value)`\n- `isPlainObject(value)`\n- `isShadow(value)`\n- `isString(value)`\n- `isText(value)`\n- `isUndefined(value)`\n- `isWindow(value)`\n\n```js\nimport {\n    isArray,\n    isArrayLike,\n    isFunction,\n    isNumeric,\n    isPlainObject,\n} from '@fr0st/core';\n\nisArray([]); // true\nisArrayLike({ 0: 'a', length: 1 }); // true\nisFunction(() =\u003e {}); // true\nisNumeric('123.45'); // true\nisPlainObject({}); // true\n```\n\n## Behavior Notes\n\n- `merge()` and `extend()` mutate and return the first argument.\n- `debounce()`, `throttle()`, and `animation()` return wrapped functions with `cancel()`.\n- `range()` uses the absolute value of `step`, returns `[]` for `step === 0`, and includes `end` when the step lands on it exactly.\n- `setDot()` supports `*` wildcard segments and an `{ overwrite }` option.\n- `random()` and `randomInt()` use an exclusive upper bound.\n\n## Development\n\n```bash\nnpm test\nnpm run js-lint\nnpm run build\n```\n\n## License\n\nFrostCore is released under the [MIT License](./LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felusivecodes%2Ffrostcore","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Felusivecodes%2Ffrostcore","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felusivecodes%2Ffrostcore/lists"}