-
Notifications
You must be signed in to change notification settings - Fork 60
/
gff3Adapter.ts
75 lines (69 loc) · 2.12 KB
/
gff3Adapter.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
import { createGunzip } from 'zlib'
import readline from 'readline'
import { Track, decodeURIComponentNoThrow } from '../util'
import { getLocalOrRemoteStream } from './common'
import { checkAbortSignal } from '@jbrowse/core/util'
export async function* indexGff3(
config: Track,
attributes: string[],
inLocation: string,
outLocation: string,
typesToExclude: string[],
quiet: boolean,
statusCallback: (message: string) => void,
signal?: AbortSignal,
) {
const { trackId } = config
let receivedBytes = 0
const { totalBytes, stream } = await getLocalOrRemoteStream(
inLocation,
outLocation,
)
stream.on('data', chunk => {
receivedBytes += chunk.length
// send an update?
const progress = Math.round((receivedBytes / totalBytes) * 100)
statusCallback(`${progress}`)
})
const rl = readline.createInterface({
input: inLocation.match(/.b?gz$/) ? stream.pipe(createGunzip()) : stream,
})
for await (const line of rl) {
if (line.startsWith('#')) {
continue
} else if (line.startsWith('>')) {
break
}
const [seq_id, , type, start, end, , , , col9] = line.split('\t')
const locStr = `${seq_id}:${start}..${end}`
if (!typesToExclude.includes(type)) {
// turns gff3 attrs into a map, and converts the arrays into space
// separated strings
const col9attrs = Object.fromEntries(
col9
.split(';')
.map(f => f.trim())
.filter(f => !!f)
.map(f => f.split('='))
.map(([key, val]) => [
key.trim(),
decodeURIComponentNoThrow(val).trim().split(',').join(' '),
]),
)
const attrs = attributes
.map(attr => col9attrs[attr])
.filter((f): f is string => !!f)
if (attrs.length) {
const record = JSON.stringify([
encodeURIComponent(locStr),
encodeURIComponent(trackId),
...attrs.map(a => encodeURIComponent(a)),
]).replaceAll(',', '|')
// Check abort signal
checkAbortSignal(signal)
yield `${record} ${[...new Set(attrs)].join(' ')}\n`
}
}
}
// console.log('done')
}