{"id":20838835,"url":"https://github.com/royalicing/boxset","last_synced_at":"2026-02-26T03:36:03.313Z","repository":{"id":42731476,"uuid":"283724354","full_name":"RoyalIcing/boxset","owner":"RoyalIcing","description":"Work with sets and maps without friction in TypeScript","archived":false,"fork":false,"pushed_at":"2023-01-07T04:52:12.000Z","size":775,"stargazers_count":4,"open_issues_count":14,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-04-14T13:05:02.669Z","etag":null,"topics":["collection","javascript","map","set","typescript"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/boxset","language":"TypeScript","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/RoyalIcing.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":"2020-07-30T09:13:12.000Z","updated_at":"2023-12-05T05:42:27.000Z","dependencies_parsed_at":"2023-02-06T12:16:20.710Z","dependency_job_id":null,"html_url":"https://github.com/RoyalIcing/boxset","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RoyalIcing%2Fboxset","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RoyalIcing%2Fboxset/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RoyalIcing%2Fboxset/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RoyalIcing%2Fboxset/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RoyalIcing","download_url":"https://codeload.github.com/RoyalIcing/boxset/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225110548,"owners_count":17422411,"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":["collection","javascript","map","set","typescript"],"created_at":"2024-11-18T01:11:40.118Z","updated_at":"2026-02-26T03:36:03.271Z","avatar_url":"https://github.com/RoyalIcing.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003ch1\u003e📀 boxset\u003c/h1\u003e\n  \u003ca href=\"https://bundlephobia.com/result?p=boxset\"\u003e\n    \u003cimg src=\"https://badgen.net/bundlephobia/minzip/boxset@0.3.4\" alt=\"minified and gzipped size\"\u003e\n    \u003cimg src=\"https://badgen.net/bundlephobia/min/boxset@0.3.4\" alt=\"minified size\"\u003e\n    \u003cimg src=\"https://badgen.net/bundlephobia/dependency-count/boxset@0.3.4\" alt=\"zero dependencies\"\u003e\n  \u003c/a\u003e\n\u003c/div\u003e\n\n## Lazily evaluated set operations for all collections\n\nProblem: [`Set`][mdn-set] and [`Map`][mdn-map] are fantastic additions to JavaScript, providing better capabilities and performance for common tasks. However, their APIs are threadbare — they don’t provide methods for even merging two sets!\n\nBoxset allows you to work with data structures such as [`Set`][mdn-set], [`Map`][mdn-map], [`Array`][mdn-array], [`Object`][mdn-object] [`FormData`][mdn-formdata], and perform unions, intersections, differences, and interoperate between them.\n\n```ts\nimport {\n  source,\n  complement,\n  union,\n  difference,\n  intersection,\n  create,\n} from 'boxset';\n\nconst dramas = source(['The Americans', 'Breaking Bad', 'The Sopranos']);\nconst comedies = source(['Flight of the Conchords']);\n\nconst shows = union(dramas, comedies);\n\nshows('The Americans'); // true\nshows('Flight of the Conchords'); // true\nshows('The Wire'); // false\n\nconst showsSet = create(shows, Set);\n// Set ['The Americans', 'Breaking Bad', 'The Sopranos', 'Flight of the Conchords']\n\nconst startingWithThe = (title: string) =\u003e title.startsWith('The ');\nconst showsStartingWithThe = intersection(shows, startingWithThe);\n\nconst showsStartingWithTheSet = create(showsStartingWithThe, Set);\n// Set ['The Americans', 'The Sopranos']\n```\n\n## Installation\n\n```console\nnpm add boxset\n```\n\n## Docs\n\n### Types\n\n```typescript\nexport interface Source\u003cI, O\u003e {\n  (input: I): O;\n}\n\nexport interface NotFound {\n  (): undefined | null | false;\n}\n\nexport type Contains\u003cI\u003e = Source\u003cI, boolean\u003e;\n\nexport interface SourceIterable\u003cI, O\u003e\n  extends Source\u003cI, O\u003e,\n    Iterable\u003c[I, O]\u003e,\n    NotFound {}\n```\n\n### `source(collection)`\n\nCreate a `SourceIterable` with the given collection, which may be a `Set`, `Array`, `Map`, `FormData`, or plain object.\n\nThe return types for a given input are as follows:\n\n- `Set\u003cA\u003e` -\u003e `SourceIterable\u003cA, boolean\u003e`\n- `Array\u003cA\u003e` -\u003e `SourceIterable\u003cA, boolean\u003e`\n- `Map\u003cK, V\u003e` -\u003e `SourceIterable\u003cK, V\u003e`\n- `FormData` -\u003e `SourceIterable\u003cstring, string\u003e`\n- `Record\u003cK, V\u003e` (plain object) -\u003e `SourceIterable\u003cK, V\u003e`\n\nCollections are **referenced not copied**, so passing a collection to `source()` and then making changes to the original collection will be reflected.\n\n```typescript\nimport { source } from 'boxset';\n\nconst citrusFruitCosts = source(new Map([['orange', 3.00], ['lemon', 4.50]]));\nconst otherFruitCosts = source({ apple: 2.50, pear: 3.00 });\nconst citrusFruits = source(new Set(['orange', 'lemon']));\nconst greenFruits = source(['apple', 'pear']);\n```\n\n### `union(a, b)`\n\nCombines two sources into a union.\n\nThe sources are referenced not copied. Source `a` is checked before checking `b`.\n\nThe result will be a `SourceIterable` if both sources were iterable, otherwise a non-iterable `Source`.\n\n```typescript\nimport { source, union } from 'boxset';\n\nconst citrusFruitCosts = source(new Map([['orange', 3.00], ['lemon', 4.50]]));\nconst otherFruitCosts = source({ apple: 2.50, pear: 3.00 });\nconst fruitCosts = union(citrusFruitCosts, otherFruitCosts);\n\nconst fruitCostsMap = new Map(fruitCosts);\n// new Map([['orange', 3.00], ['lemon', 4.50], ['apple', 2.50], ['pear', 3.00]])\n\nconst fruitCostsObject = Object.fromEntries(fruitCosts);\n// { orange: 3.00, lemon: 4.50, apple: 2.50, pear: 3.00 }\n```\n\n### `difference(a, b)`\n\nCreates a `SourceIterable` with all the elements of `a` except those that are in `b`.\n\nFor example, we could create a source from a `Map` omitting entries from a `Set` like so:\n\n```typescript\nimport { source, difference } from 'boxset';\n\nconst fruitCosts = source(new Map([['apple', 2.50], ['orange', 3.00], ['lemon', 4.50], ['pear', 3.00]]));\nconst citrusFruits = source(new Set(['orange', 'lemon']));\nconst nonCitrusFruitCosts = difference(fruitCosts, citrusFruits);\nconst nonCitrusFruitCostsMap = new Map(nonCitrusFruitCosts);\n// new Map([['apples', 2.50], ['pears', 3.00]]);\n```\n\nWe could do the same for an object omitting keys from an `Array`:\n\n```typescript\nimport { source, difference } from 'boxset';\n\nconst fruitCosts = source({ apple: 2.50, orange: 3.00, lemon: 4.50, pear: 3.00 });\nconst citrusFruits = source(['orange', 'lemon']);\nconst nonCitrusFruitCosts = difference(fruitCosts, citrusFruits);\nconst nonCitrusFruitCostsObject = Object.fromEntries(nonCitrusFruitCosts);\n// { apple: 2.50, pear: 3.00 }\n```\n\n### `intersection(a, b)`\n\nCreates a `SourceIterable` with all the elements that are both in `a` and `b`.\n\nFor example, we could create a source from a `Map` keeping entries within a `Set` like so:\n\n```typescript\nimport { source, intersection } from 'boxset';\n\nconst fruitCosts = new Map([['apple', 2.50], ['orange', 3.00], ['lemon', 4.50], ['pear', 3.00]]);\nconst citrusFruits = new Set(['orange', 'lemon']);\nconst citrusFruitCosts = intersection(source(fruitCosts), source(citrusFruits));\nconst citrusFruitCostsMap = new Map(citrusFruitCosts);\n// new new Map([['oranges', 3.00], ['lemons', 4.50]]);\n```\n\n### `complement(a)`\n\nReturns the opposite of what `a` would have returned. If a given key returned `true` for `a`, then the result would return `false`. And if a given key returned `false` for `a`, then the result would return `true`.\n\n```typescript\nimport { source, complement } from 'boxset';\n\nconst citrusFruits = new Set(['orange', 'lemon']);\nconst isCitrusFruit = source(citrusFruits);\nconst isNotCitrusFruit = complement(isCitrusFruit);\n\nisCitrusFruit('orange'); // true\nisNotCitrusFruit('orange'); // false\nisCitrusFruit('peach'); // false\nisNotCitrusFruit('peach'); // true\n```\n\n### `single(key, value?)`\n\nCreates a `SourceIterable` with the given key and optional value. If value is not provided, then the result will be a set containing just the key.\n\n```typescript\nimport { single } from 'boxset';\n\nconst pair = single('PI', 3.14159);\npair('PI'); // 3.14159\npair('TAU'); // undefined\n\nconst setOfOne = single('some key');\nsetOfOne('some key'); // true\nsetOfOne('any other key'); // false\n```\n\n### Constants\n\n#### `emptySet`\n\nA collection that contains no keys, i.e. it returns `false` for any key.\n\n#### `universalSet`\n\nA collection that contains all keys, i.e. it returns `true` for any key.\n\n```typescript\nimport { emptySet, universalSet } from 'boxset';\n\nemptySet('any key'); // false\nemptySet(42); // false\n\nuniversalSet('any key'); // true\nuniversalSet(42); // true\n```\n\n[mdn-set]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set\n[mdn-map]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map\n[mdn-object]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object\n[mdn-array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array\n[mdn-formdata]: https://developer.mozilla.org/en-US/docs/Web/API/FormData\n\n---\n\nThis project was bootstrapped with [TSDX](https://github.com/jaredpalmer/tsdx).\n\n## Local Development\n\n### `npm start`\n\nRuns the project in development/watch mode. Your project will be rebuilt upon changes. TSDX has a special logger for you convenience. Error messages are pretty printed and formatted for compatibility VS Code's Problems tab.\n\n### `npm t`\n\nRuns Jest in an interactive mode.\nBy default, runs tests related to files changed since the last commit.\n\n### `npm run build`\n\nBundles the package to the `dist` folder.\nThe package is optimized and bundled with Rollup into multiple formats (CommonJS, UMD, and ES Module).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Froyalicing%2Fboxset","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Froyalicing%2Fboxset","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Froyalicing%2Fboxset/lists"}