{"id":20453438,"url":"https://github.com/blackaslight/iterstar","last_synced_at":"2026-05-08T05:54:30.004Z","repository":{"id":215060004,"uuid":"738031127","full_name":"BlackAsLight/IterStar","owner":"BlackAsLight","description":"For when working with generators, ReadableStreams and any other iterable imaginable.","archived":false,"fork":false,"pushed_at":"2024-03-29T07:27:47.000Z","size":53,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-16T01:34:41.830Z","etag":null,"topics":["array","browser","deno","iterable","javascript","stream","typescript"],"latest_commit_sha":null,"homepage":"https://jsr.io/@doctor/iterstar","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/BlackAsLight.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-01-02T08:51:09.000Z","updated_at":"2024-03-26T01:09:33.000Z","dependencies_parsed_at":"2024-01-02T09:33:13.031Z","dependency_job_id":"489bc908-69e0-44cc-a70f-40921fabd6af","html_url":"https://github.com/BlackAsLight/IterStar","commit_stats":null,"previous_names":["blackaslight/iterstar"],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BlackAsLight%2FIterStar","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BlackAsLight%2FIterStar/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BlackAsLight%2FIterStar/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BlackAsLight%2FIterStar/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/BlackAsLight","download_url":"https://codeload.github.com/BlackAsLight/IterStar/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242005733,"owners_count":20056432,"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","browser","deno","iterable","javascript","stream","typescript"],"created_at":"2024-11-15T11:12:47.702Z","updated_at":"2025-12-06T05:01:40.581Z","avatar_url":"https://github.com/BlackAsLight.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# IterStar\n\nIter* is a simple lib providing ways to iterate over array like objects in ways\nwhere a traditional array preforms inefficiently for the desired movement, or\nwould cause spikes in memory usage. It offers ways to work with Generators and\nReadableStreams in similar ways to the traditional array, without needing to\npull it all into memory first.\n\nIter* offers three classes of interest here. Iter, AsyncIter and Queue.\n\n## class Iter\n\nThe Iter class is good for when you'd want to work with a large amount of\ngenerative data in an array type fashion. I don't see this class getting used\nthat much, but it's good to have a sync version of the async type.\n\n```ts\nimport { Iter } from '@doctor/iterstar'\n\n// Without Iter\nfor (let i = 0; i \u003c Number.MAX_SAFE_INTEGER; ++i)\n\tconsole.log(i)\n\n// With Iter\nnew Iter(range(0, Number.MAX_SAFE_INTEGER))\n\t.forEach(console.log)\n```\n\n## class AsyncIter\n\nThe AsyncIter class is good for when working with streaming data such as from a\nReadableStream. For instance, if you wanted to process a zipped csv file all in\nmemory from a fetch request.\n\n```ts\nimport { AsyncIter } from '@doctor/iterstar'\nimport { CsvParseStream } from '@std/csv'\nimport { Entry, ZipReaderStream } from '@zip-js/zip-js'\n\n// Without AsyncIter\nconst gen: AsyncGenerator\u003cstring[]\u003e = unzipCSV(\n\t(await fetch('')).body!.pipeThrough(new ZipReaderStream())\n)\nconst keys: string[] = (await gen.next()).value!\nfor await (const values of gen) {\n\tconst row = values.reduce((obj, value, i) =\u003e (obj[keys[i]] = value, obj), {} as Record\u003cstring, string\u003e)\n\t//code\n}\n\nasync function* unzipCSV(\n\treadable: ReadableStream\u003cOmit\u003cEntry, \"getData\"\u003e \u0026 { readable?: ReadableStream\u003cUint8Array\u003e | undefined }\u003e\n): AsyncGenerator\u003cstring[]\u003e {\n\tfor await (const entry of readable)\n\t\tif (entry.readable)\n\t\t\tfor await (const x of entry.readable.pipeThrough(new TextDecoderStream()).pipeThrough(new CsvParseStream()))\n\t\t\t\tyield x\n}\n\n// With AsyncIter\nconst iter: AsyncIter\u003cstring[]\u003e = new AsyncIter(\n\t(await fetch('')).body!.pipeThrough(new ZipReaderStream())\n)\n\t.filter(entry =\u003e entry.readable)\n\t.map(entry =\u003e entry.readable!.pipeThrough(new TextDecoderStream()).pipeThrough(new CsvParseStream()))\n\t.flat()\n\nconst keys: string[] = (await iter.shift())!\niter\n\t.map(values =\u003e values.reduce((obj, value, i) =\u003e (obj[keys[i]] = value, obj), {} as Record\u003cstring, string\u003e))\n\t.forEach(row =\u003e {\n\t\t// code\n\t})\n```\n\n## class Queue\n\nThe Queue class is really only good for if you want to do a lot of\n`.shift()`-ing. In most instances a traditional array will out preform this\nQueue by magnitudes, but if your data structure has you working with queues\ninstead of stacks, and quite large queues then this queue is orders of magnitude\nfaster to shift than to shift on a traditional array.\n\n```ts\nimport { Queue } from '@doctor/iterstar'\n\nconst sleep = (ms: number) =\u003e new Promise(a =\u003e setTimeout(() =\u003e a(true), ms))\n\nconst queue = new Queue(range(0, 10))\nfor (const value of queue) {\n\tconsole.log(value)\n\tif (Math.random() \u003c 0.5)\n\t\tqueue.push(value)\n\tawait sleep(200)\n}\n```\n\nLooping like the above example will cause the underlining index to keep\nincrementing, if said underlining value surpasses `Number.MAX_SAFE_INTEGER` then\nall hell could break loose. However if we assumes that it took 1ms to loop once\nhere then it would take ~2,926 centuries to reach that max number. If you did\nhappen to reach this number, you could always just pass it into another Queue to\nreset the internal indexes.\n\n```ts\nlet queue = new Queue(data);\n\n// Centuries Later...\n\nqueue = new Queue(queue);\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fblackaslight%2Fiterstar","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fblackaslight%2Fiterstar","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fblackaslight%2Fiterstar/lists"}