{"id":22356326,"url":"https://github.com/do-/node-csv-events","last_synced_at":"2026-05-01T15:39:44.345Z","repository":{"id":153973107,"uuid":"631286046","full_name":"do-/node-csv-events","owner":"do-","description":"An event based CSV parser","archived":false,"fork":false,"pushed_at":"2026-03-07T18:25:19.000Z","size":173,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-03-07T22:32:27.872Z","etag":null,"topics":["csv","events","nodejs"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/do-.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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-04-22T14:38:23.000Z","updated_at":"2026-03-07T18:25:23.000Z","dependencies_parsed_at":null,"dependency_job_id":"8836ab1a-1ed7-44a0-a462-f295bafbf06b","html_url":"https://github.com/do-/node-csv-events","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/do-/node-csv-events","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/do-%2Fnode-csv-events","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/do-%2Fnode-csv-events/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/do-%2Fnode-csv-events/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/do-%2Fnode-csv-events/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/do-","download_url":"https://codeload.github.com/do-/node-csv-events/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/do-%2Fnode-csv-events/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32503203,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-30T13:12:12.517Z","status":"online","status_checked_at":"2026-05-01T02:00:05.856Z","response_time":64,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["csv","events","nodejs"],"created_at":"2024-12-04T14:09:54.487Z","updated_at":"2026-05-01T15:39:44.331Z","avatar_url":"https://github.com/do-.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"![workflow](https://github.com/do-/node-csv-events/actions/workflows/main.yml/badge.svg)\n![Jest coverage](./badges/coverage-jest%20coverage.svg)\n[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/do-/node-csv-events)\n\n[`csv-events`](https://github.com/do-/node-csv-events) is a node.js library for reading [CSV](https://datatracker.ietf.org/doc/html/rfc4180) files featuring two classes:\n\n* `CSVEventEmitter`: a low level event emitter;\n* `CSVReader`: an application level object stream transformer.\n\n# Installation\n```\nnpm install csv-events\n```\n\n# `CSVReader` \n\nThis is an asynchronous [CSV](https://datatracker.ietf.org/doc/html/rfc4180) parser implemented as an object mode [stream.Transform](https://nodejs.org/docs/latest/api/stream.html#class-streamtransform).\n\n```js\nconst {CSVReader, CSVColumn} = require ('csv-events')\n\nconst csv = CSVReader ({\n//  delimiter: ',',\n//  skip: 0,             // header lines\n//  rowNumField: '#',    // how to name the line # property\n//  rowNumBase: 1,       // what # has the 1st not skipped line\n//  empty: null,         // how to interpret empty values (`''`)\n\n//  recordClass: Array   // to get [id, name] instead of {id, name}\n//  recordClass: class {\n//    valueOf () {       // skip records with _error set\n//      return this._error ? null : this\n//    }\n//  }\n\n//  columnClassSelector: (name, ...) =\u003e {/* some CSVColumn descendants */}\n//  ...or...\n//  columnClass: class extends CSVColumn {...} // one custom for all\n\n    columns: [\n      'id',              // 1st column: read as `id`\n      null,              // 2nd column: to ignore\n      [\n        'name',          // 3rd column: read as `name`\n//      'VARCHAR2',      // may be used by the custom `columnClass`\n//      ...\n      ]\n\n//    header: 2,         // to read `columns` from first two CSV lines \n//    mask: 0b101,       // only the 1st and 3rd column will be read\n//    maxColumns: 16384, // leak protection: 16384 is the Excel limit\n\n})\n\nconst note = err =\u003e csv.record._error ??= err\n\ncsv\n  .on ('c-error', note)\n  .on ('r-error', note)\n\nmyReadUtf8CsvTextStream.pipe (csv)\n\nfor await (const {id, name} of csv) {\n// do something with `id` and `name` \n}\n```\n\n# Description\n## General Structure\n\nThe input stream must be a CSV text.\n\nThe encoding is determined by the first bytes:\n* `FE FF` is recognized as the `utf-16le` [BOM](https://en.wikipedia.org/wiki/Byte_order_mark);\n* `EF BB BF` — as the `utf-8` BOM;\n* any text starting otherwise is considered BOMless `utf-8`.\n\nWhen the BOM is present, it must entirely fit in the first chunk fed to the reader.\n\nFor line breaks, both `CRLF` (`'\\r\\n'`) and `LF` (`'\\n'`) work. They can even coexist in one stream.\n\nIn general, the text may contain:\n* first, `${skip} \u003e= 0` totally ignored lines (the margin);\n* then, `${header} \u003e= 0` lines describing the column model (e. g. one line with column names, but maybe more to specify types etc.);\n* finally, the body: a sequence of uniformly formatted lines.\n\n`CSVReader` skips the margin, reads the header and then yields one record object for each line of the body. The one exception is for a source consisting of a single line break (this is how MS Excel saves empty sheets) — in this case, no record is yielded at all.\n\n## Columns\n\nIt's presumed that all body lines have the same structure: at least, the same number of cells. The data model is \n* either provided as the `columns` option, \n* or is read from the first `${header}` lines.\n\nIn all cases, for each definition provided (except for `${mask}`ed out ones, when the `mask` option is set), a [CSVColumn](https://github.com/do-/node-csv-events/wiki/CSVColumn) or its descendant instance is created.\n\nBasically, each column is an object that:\n* knows its `name`;\n* reads the (unquoted) `value` of the current cell;\n* provides those `name` and `value` when the current record is filled in.\n\nCustom `columnClass`es may carry extra metainformation (e. g. column type, default value etc.) and use it to alter output records content by \noverloading the `value` property getter:\n* performing validation / throwing errors (that's safe, see below);\n* adding extra formatting.\n\nDifferent columns may be represented by different classes: this is determined by a function set as the `columnClassSelector`.\n\n## Records\n\nBy default, each incoming CSV line is transformed into a plain object with properties corresponding to `CSVReader's` columns.\n\nAlternatively, you can have records in form of `Array`s of values (again, one element per column) by setting `recordClass: Array`.\n\nMore flexibility is available by using a custom `recordClass`. It can:\n* implement specific setters for individual fields (bound by name to corresponding columns);\n* override the [`valueOf()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/valueOf) method, which result is passed to [`push`](https://nodejs.org/docs/latest/api/stream.html#readablepushchunk-encoding) and so goes into the stream;\n  * except for [nullish](https://developer.mozilla.org/en-US/docs/Glossary/Nullish) values that are silently ignored.\n\nEach record may be augmented with an extra property containing the row number: this is configured via `rowNumField` and `rowNumBase` options.\n\n## Error handling\nWith `CSVReader`, developers can safely throw errors from custom constructors, `value` getters, setters, `valueOf()` etc.\n\nAll errors thrown from within `'c'` event handlers (that is, at the end of a cell) are emitted as `'c-error'` events.\n\nAll errors thrown from within `'r'` event handlers (that is, at the end of a line) are emitted as `'r-error'` events.\n\nIn both cases, unless a custom handler is installed, the `CSVReader` instance is [destroy](https://nodejs.org/docs/latest/api/stream.html#readabledestroyerror)ed with the incoming error.\n\n# Constructor Options\n## Low Level \nThese options are passed to the internal [CSVEventEmitter](https://github.com/do-/node-csv-events/wiki/CSVEventEmitter) instance:\n|Name|Default value|Description|\n|-|-|-|\n|`delimiter`|`','`|Column delimiter|\n|`empty`|`null`|The `value` corresponding to zero length cell content|\n|`maxLength`|1e6|The maximum cell length allowed (to prevent a memory overflow)|\n\n## Column Definitions\n|Name|Default value|Description|\n|-|-|-|\n|`columnClass`|[CSVColumn](https://github.com/do-/node-csv-events/wiki/CSVColumn)|the class of column definition objects (if one for all)|\n|`columnClassSelector`|`(name,...) =\u003e this.columnClass`| column definition class selector |\n|`columns`||Explicit column definitions|\n|`mask`|`0`|Unless `0` with `header` set, only `mask`ed columns will be read|\n|`maxColumns`|`16384`|Maximum # of columns in the `header` (to prevent a memory overflow)|\n|`header`|`0`|Number of lines to gather `columns` definition|\n\n## Row Selection and Numbering\n|Name|Default value|Description|\n|-|-|-|\n|`recordClass`|`Object`|May be set as `Array`|\n|`rowNumBase`|`1`|The 1st output record line # |\n|`rowNumField`|`null`|The name of the line # property (`null` for no numbering)|\n|`skip`|`0`|Number of top lines to ignore (before `header`, if any)|\n\n\n# `CSVEventEmitter` \n\nThis is an [events](https://nodejs.org/dist/latest/docs/api/events.html) based synchronous [CSV](https://datatracker.ietf.org/doc/html/rfc4180) parser.\n\n```js\nconst {CSVEventEmitter} = require ('csv-events')\n\nconst ee = new CSVEventEmitter ({\n   mask: 0b101 // only 1st and 3rd column will be signaled\n// delimiter: ',',\n// empty: null,\n// maxLength: 1e6,\n})\n\nconst names = []\n\nee.on ('c', () =\u003e {\n  if (ee.row !== 0n \u0026\u0026 ee.column === 1) names.push (ee.value)\n})\n\nee.on ('r', () =\u003e {\n  console.log (`The row #${ee.row} consisted of ${ee.column} cell(s)`)\n})\n\nee.write ('ID,NAME\\r\\n')\nee.write ('1,admin\\n')\nee.end   ('2,user\\n') // `names` will be ['admin', 'user']\n```\n\nIncoming data are supplied as [String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) arguments to `write ()` and `end ()` methods.\n\nDuring each of that calls, a series of `'c'` (_\"cell\"_) and `'r'` (_[end of] \"row\"_) events is emitted.\n\nNo event carries any payload. Subscribers have access to the current cell's `value` along with its `row` and `column` number via the emitter's properties.\n\nSo, each one chunk of a CSV source is processed synchronously. Parsing а huge text at once may lead to a considerable performance degradation. In applications, using [CSVReader](https://github.com/do-/node-csv-events/wiki/CSVReader) or a similar streaming wrapper is strongly encouraged.\n\n# Constructor Options\n|Name|Default value|Description|\n|-|-|-|\n|`mask`|`0`|Bit mask of required fields, `0` means 'all'|\n|`delimiter`|`','`|Column delimiter|\n|`empty`|`null`|The `value` corresponding to zero length cell content|\n|`emptyDoc`|`\\r\\n`|If this equals the complete CSV text, no event is emitted at all|\n|`maxLength`|1e6|The maximum `buf.length` allowed (inherently, the maximum length of `write` and `end` arguments)|\n\n# Events\n|Name|Payload|Description|\n|-|-|-|\n|`c`|`column`| Emitted for each cell which number satisfies `mask` when its content is available (via `value` and `raw` properties, see below)|\n|`r`| | Emitted for each row completed|\n\n# Properties\n|Name|Type|Description|\n|-|-|-|\n|`unit`|Number or Bigint|`1` corresponding to `mask` by type|\n|`row`|BigInt|Number of the current row: `0n` for the CSV header, if present|\n|`column`|Number|Number of the current column, `0` based|\n|`index`|Number or Bigint|Single bit mask corresponding to `column` (2**column)|\n|`buf`|String|The internal buffer containing unparsed portion of the text gathered from `write` arguments|\n|`from`|Number|Starting position of the current cell in `buf`|\n|`to`|Number|Ending position of the current cell in `buf`|\n|`raw`|String|Verbatim copy of `buf` between `from` and `to`, except row delimiters (computed property)|\n|`value`|String|Unquoted `raw`, replaced with `empty` for an unquoted zero length string (computed property)|\n\n# Methods\n## `end ([s])`\nA wrapper for `write (s)` (see below) called for the last text portion `s` or without arguments which means `s === ''`.\n\nGuarantees the last CSV line parsed to be `'\\n'` terminated.\n\n## `write (s)`\nAppends `s` to the internal buffer and emits all events for its parseable part, unless `maxLength` is exceeded in wich case an error is thrown.\n\nThe unparsed text is keept buffered.\n\n# Limitations\n## Line Breaks\n`CSVEventEmitter` always recognizes both:\n* `CRLF` (`'\\r\\n'`, RFC 4180, Windows style) and\n* `LF`  (`'\\n'`, UNIX style)\n\nas line breaks without explicit option setting.\n\nThere is no way to apply `CSVEventEmitter` directly to texts generated with MacOS pre-X, Commodore, Amiga etc. neither any plans to implement such compatibility features.\n\n## CSV Validity\n`CSVEventEmitter` doesn't make any attempt to restore data from broken CSV source. So, a single unbalanced double quote will mess up the rest of file.\n\nThe best `CSVEventEmitter` can do in such case is not to waste too much memory by keeping its internal buffer limited with `maxLength`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdo-%2Fnode-csv-events","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdo-%2Fnode-csv-events","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdo-%2Fnode-csv-events/lists"}