Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,21 @@ const arrayOfThings = gff.parseStringSync(stringOfGFF3)

In GFF3, features can have more than one location. We parse features as
arrayrefs of all the lines that share that feature's ID. Values that are `.` in
the GFF3 are `null` in the output.
the GFF3 are `undefined` in the output.

A simple feature that's located in just one place:

```json
[
{
"seq_id": "ctg123",
"source": null,
"source": undefined,
"type": "gene",
"start": 1000,
"end": 9000,
"score": null,
"score": undefined,
"strand": "+",
"phase": null,
"phase": undefined,
"attributes": {
"ID": ["gene00001"],
"Name": ["EDEN"]
Expand All @@ -61,11 +61,11 @@ A CDS called `cds00001` located in two places:
[
{
"seq_id": "ctg123",
"source": null,
"source": undefined,
"type": "CDS",
"start": 1201,
"end": 1500,
"score": null,
"score": undefined,
"strand": "+",
"phase": "0",
"attributes": {
Expand All @@ -77,11 +77,11 @@ A CDS called `cds00001` located in two places:
},
{
"seq_id": "ctg123",
"source": null,
"source": undefined,
"type": "CDS",
"start": 3000,
"end": 3902,
"score": null,
"score": undefined,
"strand": "+",
"phase": "0",
"attributes": {
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@
"scripts": {
"test": "vitest",
"clean": "rimraf dist esm",
"lint": "eslint src test",
"lint": "eslint --report-unused-disable-directives --max-warnings 0",
"docs": "documentation readme src/api.ts --section=API --shallow && npm run format",
"format": "prettier --write .",
"prebuild": "npm run clean",
"build:esm": "tsc --target es2018 --outDir esm",
"build:es5": "tsc --target es2015 --module commonjs --outDir dist",
"build:esm": "tsc --target es2020 --outDir esm",
"build:es5": "tsc --target es2020 --module commonjs --outDir dist",
"build": "npm run build:es5 && npm run build:esm",
"prepublishOnly": "npm run test run && npm run build",
"postversion": "git push --follow-tags"
Expand Down
2 changes: 1 addition & 1 deletion src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export function parseStringSync(str: string): GFF3Feature[] {
featureCallback: arg => items.push(arg),
disableDerivesFromReferences: true,
errorCallback: err => {
throw err
throw new Error(err)
},
})

Expand Down
41 changes: 25 additions & 16 deletions src/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,14 @@ export default class Parser {

constructor(args: ParserArgs) {
// eslint-disable-next-line @typescript-eslint/no-empty-function
const nullFunc = () => {}

this.featureCallback = args.featureCallback || nullFunc
this.endCallback = args.endCallback || nullFunc
this.commentCallback = args.commentCallback || nullFunc
this.errorCallback = args.errorCallback || nullFunc
this.directiveCallback = args.directiveCallback || nullFunc
this.sequenceCallback = args.sequenceCallback || nullFunc
const undefinedFunc = () => {}

this.featureCallback = args.featureCallback || undefinedFunc
this.endCallback = args.endCallback || undefinedFunc
this.commentCallback = args.commentCallback || undefinedFunc
this.errorCallback = args.errorCallback || undefinedFunc
this.directiveCallback = args.directiveCallback || undefinedFunc
this.sequenceCallback = args.sequenceCallback || undefinedFunc
this.disableDerivesFromReferences =
args.disableDerivesFromReferences || false

Expand Down Expand Up @@ -190,16 +190,19 @@ export default class Parser {
if (item && Array.isArray(item) && item[0].attributes?.ID?.[0]) {
const ids = item[0].attributes.ID
ids.forEach(id => {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete this._underConstructionById[id]

// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete this._completedReferences[id]
})
item.forEach(i => {
if (i.child_features) {
i.child_features.forEach(c => _unbufferItem(c))
}
if (i.derived_features) {
i.derived_features.forEach(d => _unbufferItem(d))
}
i.child_features.forEach(c => {
_unbufferItem(c)
})
i.derived_features.forEach(d => {
_unbufferItem(d)
})
})
}
}
Expand Down Expand Up @@ -263,14 +266,17 @@ export default class Parser {
}

let feature: GFF3.GFF3Feature | undefined = undefined
ids.forEach(id => {
for (const id of ids) {
const existing = this._underConstructionById[id]
if (existing) {
// another location of the same feature
if (existing[existing.length - 1].type !== featureLine.type) {
this._parseError(
`multi-line feature "${id}" has inconsistent types: "${
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
featureLine.type

// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
}", "${existing[existing.length - 1].type}"`,
)
}
Expand All @@ -290,7 +296,7 @@ export default class Parser {
// see if we have anything buffered that refers to it
this._resolveReferencesTo(feature, id)
}
})
}

// try to resolve all its references
this._resolveReferencesFrom(
Expand All @@ -316,11 +322,14 @@ export default class Parser {
feature.forEach(loc => {
loc.derived_features.push(...references.Derives_from)
})
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete this._underConstructionOrphans[id]
}

private _parseError(message: string) {
this.eof = true

// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
this.errorCallback(`${this.lineNumber}: ${message}`)
}

Expand Down
Loading