@jbrowse/plugin-bed 1.5.9 → 1.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,17 +5,17 @@ import {
5
5
  BaseFeatureDataAdapter,
6
6
  BaseOptions,
7
7
  } from '@jbrowse/core/data_adapters/BaseAdapter'
8
- import { Region, FileLocation } from '@jbrowse/core/util/types'
8
+ import { Region } from '@jbrowse/core/util/types'
9
9
  import { openLocation } from '@jbrowse/core/util/io'
10
10
  import { ObservableCreate } from '@jbrowse/core/util/rxjs'
11
11
  import SimpleFeature, { Feature } from '@jbrowse/core/util/simpleFeature'
12
12
  import { map, mergeAll } from 'rxjs/operators'
13
13
  import { readConfObject } from '@jbrowse/core/configuration'
14
- import { Instance } from 'mobx-state-tree'
15
- import configSchema from './configSchema'
16
14
  import { ucscProcessedTranscript } from '../util'
17
- import PluginManager from '@jbrowse/core/PluginManager'
18
- import { getSubAdapterType } from '@jbrowse/core/data_adapters/dataAdapterCache'
15
+
16
+ function isUCSC(f: Feature) {
17
+ return f.get('thickStart') && f.get('blockCount') && f.get('strand') !== 0
18
+ }
19
19
 
20
20
  interface BEDFeature {
21
21
  chrom: string
@@ -26,50 +26,51 @@ interface BEDFeature {
26
26
 
27
27
  interface Parser {
28
28
  parseLine: (line: string, opts: { uniqueId: string | number }) => BEDFeature
29
+ autoSql: { fields: { name: string; comment: string }[] }
29
30
  }
30
31
 
31
32
  export default class BigBedAdapter extends BaseFeatureDataAdapter {
32
- private bigbed: BigBed
33
+ private cached?: Promise<{ bigbed: BigBed; header: any; parser: Parser }>
33
34
 
34
- private parser: Promise<Parser>
35
-
36
- public constructor(
37
- config: Instance<typeof configSchema>,
38
- getSubAdapter?: getSubAdapterType,
39
- pluginManager?: PluginManager,
40
- ) {
41
- super(config, getSubAdapter, pluginManager)
42
- const bigBedLocation = readConfObject(
43
- config,
44
- 'bigBedLocation',
45
- ) as FileLocation
46
- this.bigbed = new BigBed({
47
- filehandle: openLocation(bigBedLocation, this.pluginManager),
35
+ public async configurePre(opts?: BaseOptions) {
36
+ const bigbed = new BigBed({
37
+ filehandle: openLocation(
38
+ readConfObject(this.config, 'bigBedLocation'),
39
+ this.pluginManager,
40
+ ),
48
41
  })
49
-
50
- this.parser = this.bigbed
51
- .getHeader()
52
- .then(({ autoSql }: { autoSql: string }) => new BED({ autoSql }))
42
+ const header = await bigbed.getHeader(opts)
43
+ const parser = new BED({ autoSql: header.autoSql }) as Parser
44
+ return { bigbed, header, parser }
53
45
  }
54
46
 
55
- public async getRefNames() {
56
- return Object.keys((await this.bigbed.getHeader()).refsByName)
47
+ public async configure(opts?: BaseOptions) {
48
+ if (!this.cached) {
49
+ this.cached = this.configurePre(opts).catch(e => {
50
+ this.cached = undefined
51
+ throw e
52
+ })
53
+ }
54
+ return this.cached
57
55
  }
58
56
 
59
- async getHeader(opts?: BaseOptions) {
60
- const { version, fileType } = await this.bigbed.getHeader(opts)
61
- // @ts-ignore
62
- const { autoSql } = await this.parser
63
- const { fields, ...rest } = autoSql
64
- const f = Object.fromEntries(
65
- // @ts-ignore
66
- fields.map(({ name, comment }) => [name, comment]),
67
- )
68
- return { version, fileType, autoSql: { ...rest }, fields: f }
57
+ public async getRefNames(opts?: BaseOptions) {
58
+ const { header } = await this.configure(opts)
59
+ return Object.keys(header.refsByName)
69
60
  }
70
61
 
71
- public async refIdToName(refId: number) {
72
- return ((await this.bigbed.getHeader()).refsByNumber[refId] || {}).name
62
+ async getHeader(opts?: BaseOptions) {
63
+ const { parser, header } = await this.configure(opts)
64
+ const { version, fileType } = header
65
+ const { fields, ...rest } = parser.autoSql
66
+ return {
67
+ version,
68
+ fileType,
69
+ autoSql: { ...rest },
70
+ fields: Object.fromEntries(
71
+ fields.map(({ name, comment }) => [name, comment]),
72
+ ),
73
+ }
73
74
  }
74
75
 
75
76
  public getFeatures(region: Region, opts: BaseOptions = {}) {
@@ -77,70 +78,59 @@ export default class BigBedAdapter extends BaseFeatureDataAdapter {
77
78
  const { signal } = opts
78
79
  return ObservableCreate<Feature>(async observer => {
79
80
  try {
80
- const parser = await this.parser
81
- const ob = await this.bigbed.getFeatureStream(refName, start, end, {
81
+ const { parser, bigbed } = await this.configure(opts)
82
+ const ob = await bigbed.getFeatureStream(refName, start, end, {
82
83
  signal,
83
84
  basesPerSpan: end - start,
84
85
  })
85
86
  ob.pipe(
86
87
  mergeAll(),
87
- map(
88
- (r: {
89
- start: number
90
- end: number
91
- rest?: string
92
- uniqueId?: string
93
- }) => {
94
- const data = parser.parseLine(
95
- `${refName}\t${r.start}\t${r.end}\t${r.rest}`,
96
- {
97
- uniqueId: r.uniqueId as string,
98
- },
99
- )
88
+ map(r => {
89
+ const data = parser.parseLine(
90
+ `${refName}\t${r.start}\t${r.end}\t${r.rest}`,
91
+ {
92
+ uniqueId: r.uniqueId as string,
93
+ },
94
+ )
100
95
 
101
- const { blockCount, blockSizes, blockStarts, chromStarts } = data
102
- if (blockCount) {
103
- const starts = chromStarts || blockStarts || []
104
- const sizes = blockSizes
105
- const blocksOffset = r.start
106
- data.subfeatures = []
96
+ const { blockCount, blockSizes, blockStarts, chromStarts } = data
97
+ if (blockCount) {
98
+ const starts = chromStarts || blockStarts || []
99
+ const sizes = blockSizes
100
+ const blocksOffset = r.start
101
+ data.subfeatures = []
107
102
 
108
- for (let b = 0; b < blockCount; b += 1) {
109
- const bmin = (starts[b] || 0) + blocksOffset
110
- const bmax = bmin + (sizes[b] || 0)
111
- data.subfeatures.push({
112
- uniqueId: `${r.uniqueId}-${b}`,
113
- start: bmin,
114
- end: bmax,
115
- type: 'block',
116
- })
117
- }
118
- }
119
- if (r.uniqueId === undefined) {
120
- throw new Error('invalid bbi feature')
103
+ for (let b = 0; b < blockCount; b += 1) {
104
+ const bmin = (starts[b] || 0) + blocksOffset
105
+ const bmax = bmin + (sizes[b] || 0)
106
+ data.subfeatures.push({
107
+ uniqueId: `${r.uniqueId}-${b}`,
108
+ start: bmin,
109
+ end: bmax,
110
+ type: 'block',
111
+ })
121
112
  }
122
- const { chromStart, chromEnd, chrom, ...rest } = data
113
+ }
114
+ if (r.uniqueId === undefined) {
115
+ throw new Error('invalid bbi feature')
116
+ }
117
+ const { chromStart, chromEnd, chrom, ...rest } = data
123
118
 
124
- const f = new SimpleFeature({
125
- id: `${this.id}-${r.uniqueId}`,
126
- data: {
127
- ...rest,
128
- start: r.start,
129
- end: r.end,
130
- refName,
131
- },
132
- })
119
+ const f = new SimpleFeature({
120
+ id: `${this.id}-${r.uniqueId}`,
121
+ data: {
122
+ ...rest,
123
+ start: r.start,
124
+ end: r.end,
125
+ refName,
126
+ },
127
+ })
133
128
 
134
- // collection of heuristics for suggesting that this feature
135
- // should be converted to a gene, CNV bigbed has many gene like
136
- // features including thickStart and blockCount but no strand
137
- return f.get('thickStart') &&
138
- f.get('blockCount') &&
139
- f.get('strand') !== 0
140
- ? ucscProcessedTranscript(f)
141
- : f
142
- },
143
- ),
129
+ // collection of heuristics for suggesting that this feature
130
+ // should be converted to a gene, CNV bigbed has many gene like
131
+ // features including thickStart and blockCount but no strand
132
+ return isUCSC(f) ? ucscProcessedTranscript(f) : f
133
+ }),
144
134
  ).subscribe(observer)
145
135
  } catch (e) {
146
136
  observer.error(e)
package/src/index.ts CHANGED
@@ -35,11 +35,15 @@ export default class BedPlugin extends Plugin {
35
35
  const regexGuess = /\.(bb|bigbed)$/i
36
36
  const adapterName = 'BigBedAdapter'
37
37
  const fileName = getFileName(file)
38
- if (regexGuess.test(fileName) || adapterHint === adapterName) {
39
- return {
40
- type: adapterName,
41
- bigBedLocation: file,
42
- }
38
+ const obj = {
39
+ type: adapterName,
40
+ bigBedLocation: file,
41
+ }
42
+
43
+ if (regexGuess.test(fileName) && !adapterHint) {
44
+ return obj
45
+ } else if (adapterHint === adapterName) {
46
+ return obj
43
47
  }
44
48
  return adapterGuesser(file, index, adapterHint)
45
49
  }