gff-nostream
Version:
utilities to read GFF3 data
121 lines (91 loc) • 3.27 kB
Markdown
# gff-nostream
[](https://npmjs.org/package/gff-nostream)

Parse GFF3 data. A simplified version of
[@gmod/gff](https://github.com/GMOD/gff-js) with no Node.js stream dependency.
## Install
$ pnpm add gff-nostream
## Usage
```js
import { parseStringSync } from 'gff-nostream'
import fs from 'fs'
const features = parseStringSync(fs.readFileSync('my_annotations.gff3', 'utf8'))
```
In the browser or other non-Node environments, pass any GFF3 string directly —
for example from `fetch`:
```js
import { parseStringSync } from 'gff-nostream'
const text = await fetch('my_annotations.gff3').then(r => r.text())
const features = parseStringSync(text)
```
## Object format
Features are returned as flat objects with coordinates converted to 0-based
half-open, `strand` as a number (`1`/`-1`/`0`), attributes spread as lowercase
top-level keys, single-valued attributes unwrapped from their array, and child
features nested under `subfeatures`. An attribute whose lowercased name collides
with a built-in field (e.g. `Start`, `Type`) is suffixed with `2` (`start2`,
`type2`).
A gene with an mRNA child:
```json
{
"refName": "ctg123",
"source": null,
"type": "gene",
"start": 999,
"end": 9000,
"strand": 1,
"id": "gene00001",
"name": "EDEN",
"subfeatures": [
{
"refName": "ctg123",
"source": null,
"type": "mRNA",
"start": 1049,
"end": 9000,
"strand": 1,
"id": "mRNA00001",
"parent": "gene00001",
"subfeatures": []
}
]
}
```
Multi-location features (the same ID on multiple lines, such as a CDS spanning
several segments) are not merged — each line is its own flat feature, attached
to its parent (or kept as a top-level item) independently.
## API
### `parseStringSync(str: string): GffFeature[]`
Synchronously parse a GFF3 string and return an array of features. Comments,
directives, and `##FASTA` sections are ignored.
### `parseRecords<R>(records: readonly R[]): ParsedRecord<R>[]`
Parse an array of records wrapping raw GFF3 lines. Useful when managing raw line
data directly (e.g. from a tabix-indexed file). Each top-level feature is
returned paired with the record it came from, so a caller can attach its own
stable id (a byte offset, a hash, …) without the parser stamping anything onto
the feature. Records may carry extra fields (`R` is inferred), which pass
through untouched on `record`.
```ts
const features = parseRecords(
lines.map(line => ({ line, offset })),
).map(({ feature, record }) => ({ ...feature, id: record.offset }))
```
### `extractType(line: string): string`
Extract the feature type (GFF3 column 3) from a raw line without fully splitting
it.
### `LineRecord` / `ParsedRecord`
```ts
interface LineRecord {
line: string
}
interface ParsedRecord<R extends LineRecord = LineRecord> {
feature: GffFeature
record: R // the input record this top-level feature was parsed from
}
```
## Publishing
[Trusted publishing](https://docs.npmjs.com/about-trusted-publishing) via GitHub
Actions.
```bash
pnpm version patch # or minor/major
```