@jbrowse/plugin-alignments 2.1.7 → 2.2.0

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.
Files changed (138) hide show
  1. package/dist/AlignmentsTrack/index.d.ts +1 -1
  2. package/dist/AlignmentsTrack/index.js +16 -6
  3. package/dist/AlignmentsTrack/index.js.map +1 -1
  4. package/dist/BamAdapter/BamAdapter.d.ts +6 -2
  5. package/dist/BamAdapter/BamAdapter.js +35 -31
  6. package/dist/BamAdapter/BamAdapter.js.map +1 -1
  7. package/dist/BamAdapter/configSchema.d.ts +2 -2
  8. package/dist/BamAdapter/configSchema.js +27 -2
  9. package/dist/BamAdapter/configSchema.js.map +1 -1
  10. package/dist/CramAdapter/CramAdapter.d.ts +13 -7
  11. package/dist/CramAdapter/CramAdapter.js +56 -61
  12. package/dist/CramAdapter/CramAdapter.js.map +1 -1
  13. package/dist/CramAdapter/CramSlightlyLazyFeature.d.ts +14 -13
  14. package/dist/CramAdapter/CramSlightlyLazyFeature.js +28 -22
  15. package/dist/CramAdapter/CramSlightlyLazyFeature.js.map +1 -1
  16. package/dist/CramAdapter/configSchema.d.ts +2 -3
  17. package/dist/CramAdapter/configSchema.js +44 -22
  18. package/dist/CramAdapter/configSchema.js.map +1 -1
  19. package/dist/CramAdapter/index.js +1 -1
  20. package/dist/CramAdapter/index.js.map +1 -1
  21. package/dist/HtsgetBamAdapter/HtsgetBamAdapter.d.ts +5 -2
  22. package/dist/HtsgetBamAdapter/HtsgetBamAdapter.js +15 -20
  23. package/dist/HtsgetBamAdapter/HtsgetBamAdapter.js.map +1 -1
  24. package/dist/HtsgetBamAdapter/configSchema.d.ts +2 -2
  25. package/dist/HtsgetBamAdapter/configSchema.js +20 -3
  26. package/dist/HtsgetBamAdapter/configSchema.js.map +1 -1
  27. package/dist/LinearAlignmentsDisplay/models/configSchema.d.ts +1 -1
  28. package/dist/LinearAlignmentsDisplay/models/configSchema.js +23 -6
  29. package/dist/LinearAlignmentsDisplay/models/configSchema.js.map +1 -1
  30. package/dist/LinearAlignmentsDisplay/models/model.d.ts +72 -5
  31. package/dist/LinearAlignmentsDisplay/models/model.js +95 -2
  32. package/dist/LinearAlignmentsDisplay/models/model.js.map +1 -1
  33. package/dist/LinearPileupDisplay/configSchema.js +20 -3
  34. package/dist/LinearPileupDisplay/configSchema.js.map +1 -1
  35. package/dist/LinearPileupDisplay/model.d.ts +87 -3
  36. package/dist/LinearPileupDisplay/model.js +616 -503
  37. package/dist/LinearPileupDisplay/model.js.map +1 -1
  38. package/dist/LinearSNPCoverageDisplay/models/configSchema.js +33 -4
  39. package/dist/LinearSNPCoverageDisplay/models/configSchema.js.map +1 -1
  40. package/dist/LinearSNPCoverageDisplay/models/model.d.ts +86 -3
  41. package/dist/LinearSNPCoverageDisplay/models/model.js +240 -159
  42. package/dist/LinearSNPCoverageDisplay/models/model.js.map +1 -1
  43. package/dist/PileupRenderer/PileupRenderer.d.ts +1 -1
  44. package/dist/PileupRenderer/PileupRenderer.js +5 -6
  45. package/dist/PileupRenderer/PileupRenderer.js.map +1 -1
  46. package/dist/PileupRenderer/configSchema.d.ts +2 -2
  47. package/dist/PileupRenderer/configSchema.js +37 -2
  48. package/dist/PileupRenderer/configSchema.js.map +1 -1
  49. package/dist/SNPCoverageAdapter/configSchema.d.ts +2 -2
  50. package/dist/SNPCoverageAdapter/configSchema.js +11 -3
  51. package/dist/SNPCoverageAdapter/configSchema.js.map +1 -1
  52. package/dist/SNPCoverageRenderer/configSchema.d.ts +2 -2
  53. package/dist/SNPCoverageRenderer/configSchema.js +21 -1
  54. package/dist/SNPCoverageRenderer/configSchema.js.map +1 -1
  55. package/dist/SNPCoverageRenderer/index.d.ts +0 -1
  56. package/dist/SNPCoverageRenderer/index.js +1 -4
  57. package/dist/SNPCoverageRenderer/index.js.map +1 -1
  58. package/esm/AlignmentsTrack/index.d.ts +1 -1
  59. package/esm/AlignmentsTrack/index.js +16 -6
  60. package/esm/AlignmentsTrack/index.js.map +1 -1
  61. package/esm/BamAdapter/BamAdapter.d.ts +6 -2
  62. package/esm/BamAdapter/BamAdapter.js +35 -31
  63. package/esm/BamAdapter/BamAdapter.js.map +1 -1
  64. package/esm/BamAdapter/configSchema.d.ts +2 -2
  65. package/esm/BamAdapter/configSchema.js +27 -2
  66. package/esm/BamAdapter/configSchema.js.map +1 -1
  67. package/esm/CramAdapter/CramAdapter.d.ts +13 -7
  68. package/esm/CramAdapter/CramAdapter.js +56 -61
  69. package/esm/CramAdapter/CramAdapter.js.map +1 -1
  70. package/esm/CramAdapter/CramSlightlyLazyFeature.d.ts +14 -13
  71. package/esm/CramAdapter/CramSlightlyLazyFeature.js +28 -22
  72. package/esm/CramAdapter/CramSlightlyLazyFeature.js.map +1 -1
  73. package/esm/CramAdapter/configSchema.d.ts +2 -3
  74. package/esm/CramAdapter/configSchema.js +44 -22
  75. package/esm/CramAdapter/configSchema.js.map +1 -1
  76. package/esm/CramAdapter/index.js +2 -2
  77. package/esm/CramAdapter/index.js.map +1 -1
  78. package/esm/HtsgetBamAdapter/HtsgetBamAdapter.d.ts +5 -2
  79. package/esm/HtsgetBamAdapter/HtsgetBamAdapter.js +15 -20
  80. package/esm/HtsgetBamAdapter/HtsgetBamAdapter.js.map +1 -1
  81. package/esm/HtsgetBamAdapter/configSchema.d.ts +2 -2
  82. package/esm/HtsgetBamAdapter/configSchema.js +20 -3
  83. package/esm/HtsgetBamAdapter/configSchema.js.map +1 -1
  84. package/esm/LinearAlignmentsDisplay/models/configSchema.d.ts +1 -1
  85. package/esm/LinearAlignmentsDisplay/models/configSchema.js +23 -6
  86. package/esm/LinearAlignmentsDisplay/models/configSchema.js.map +1 -1
  87. package/esm/LinearAlignmentsDisplay/models/model.d.ts +72 -5
  88. package/esm/LinearAlignmentsDisplay/models/model.js +95 -2
  89. package/esm/LinearAlignmentsDisplay/models/model.js.map +1 -1
  90. package/esm/LinearPileupDisplay/configSchema.js +20 -3
  91. package/esm/LinearPileupDisplay/configSchema.js.map +1 -1
  92. package/esm/LinearPileupDisplay/model.d.ts +87 -3
  93. package/esm/LinearPileupDisplay/model.js +616 -503
  94. package/esm/LinearPileupDisplay/model.js.map +1 -1
  95. package/esm/LinearSNPCoverageDisplay/models/configSchema.js +33 -4
  96. package/esm/LinearSNPCoverageDisplay/models/configSchema.js.map +1 -1
  97. package/esm/LinearSNPCoverageDisplay/models/model.d.ts +86 -3
  98. package/esm/LinearSNPCoverageDisplay/models/model.js +240 -159
  99. package/esm/LinearSNPCoverageDisplay/models/model.js.map +1 -1
  100. package/esm/PileupRenderer/PileupRenderer.d.ts +1 -1
  101. package/esm/PileupRenderer/PileupRenderer.js +5 -6
  102. package/esm/PileupRenderer/PileupRenderer.js.map +1 -1
  103. package/esm/PileupRenderer/configSchema.d.ts +2 -2
  104. package/esm/PileupRenderer/configSchema.js +37 -2
  105. package/esm/PileupRenderer/configSchema.js.map +1 -1
  106. package/esm/SNPCoverageAdapter/configSchema.d.ts +2 -2
  107. package/esm/SNPCoverageAdapter/configSchema.js +11 -3
  108. package/esm/SNPCoverageAdapter/configSchema.js.map +1 -1
  109. package/esm/SNPCoverageRenderer/configSchema.d.ts +2 -2
  110. package/esm/SNPCoverageRenderer/configSchema.js +21 -1
  111. package/esm/SNPCoverageRenderer/configSchema.js.map +1 -1
  112. package/esm/SNPCoverageRenderer/index.d.ts +0 -1
  113. package/esm/SNPCoverageRenderer/index.js +1 -3
  114. package/esm/SNPCoverageRenderer/index.js.map +1 -1
  115. package/package.json +3 -3
  116. package/src/AlignmentsFeatureDetail/__snapshots__/index.test.js.snap +54 -54
  117. package/src/AlignmentsTrack/index.ts +18 -12
  118. package/src/BamAdapter/BamAdapter.ts +39 -39
  119. package/src/BamAdapter/configSchema.ts +57 -29
  120. package/src/CramAdapter/CramAdapter.test.ts +1 -2
  121. package/src/CramAdapter/CramAdapter.ts +83 -84
  122. package/src/CramAdapter/CramSlightlyLazyFeature.ts +34 -25
  123. package/src/CramAdapter/configSchema.ts +55 -30
  124. package/src/CramAdapter/index.ts +2 -2
  125. package/src/HtsgetBamAdapter/HtsgetBamAdapter.ts +14 -21
  126. package/src/HtsgetBamAdapter/configSchema.ts +36 -19
  127. package/src/LinearAlignmentsDisplay/models/configSchema.ts +23 -10
  128. package/src/LinearAlignmentsDisplay/models/model.tsx +99 -4
  129. package/src/LinearPileupDisplay/configSchema.ts +23 -5
  130. package/src/LinearPileupDisplay/model.ts +120 -4
  131. package/src/LinearSNPCoverageDisplay/models/configSchema.ts +36 -9
  132. package/src/LinearSNPCoverageDisplay/models/model.ts +83 -4
  133. package/src/PileupRenderer/PileupRenderer.tsx +5 -9
  134. package/src/PileupRenderer/configSchema.ts +39 -2
  135. package/src/SNPCoverageAdapter/configSchema.ts +18 -10
  136. package/src/SNPCoverageRenderer/configSchema.ts +23 -1
  137. package/src/SNPCoverageRenderer/index.ts +1 -8
  138. package/src/declare.d.ts +0 -1
@@ -1,7 +1,8 @@
1
- import { CraiIndex, IndexedCramFile } from '@gmod/cram'
1
+ import { CraiIndex, IndexedCramFile, CramRecord } from '@gmod/cram'
2
2
  import {
3
3
  BaseFeatureDataAdapter,
4
4
  BaseOptions,
5
+ BaseSequenceAdapter,
5
6
  } from '@jbrowse/core/data_adapters/BaseAdapter'
6
7
  import { checkAbortSignal, Region, Feature } from '@jbrowse/core/util'
7
8
  import { openLocation } from '@jbrowse/core/util/io'
@@ -9,15 +10,10 @@ import { ObservableCreate } from '@jbrowse/core/util/rxjs'
9
10
  import { toArray } from 'rxjs/operators'
10
11
  import CramSlightlyLazyFeature from './CramSlightlyLazyFeature'
11
12
 
12
- interface HeaderLine {
13
- tag: string
14
- value: any // eslint-disable-line @typescript-eslint/no-explicit-any
15
- data: HeaderLine[]
16
- }
17
13
  interface Header {
18
14
  idToName?: string[]
19
15
  nameToId?: Record<string, number>
20
- readGroups?: number[]
16
+ readGroups?: (string | undefined)[]
21
17
  }
22
18
 
23
19
  interface FilterBy {
@@ -32,8 +28,13 @@ export default class CramAdapter extends BaseFeatureDataAdapter {
32
28
 
33
29
  private setupP?: Promise<{
34
30
  samHeader: Header
35
- cram: any // eslint-disable-line @typescript-eslint/no-explicit-any
36
- sequenceAdapter: any // eslint-disable-line @typescript-eslint/no-explicit-any
31
+ cram: IndexedCramFile
32
+ sequenceAdapter: BaseSequenceAdapter
33
+ }>
34
+
35
+ private configureP?: Promise<{
36
+ cram: IndexedCramFile
37
+ sequenceAdapter: BaseSequenceAdapter
37
38
  }>
38
39
 
39
40
  // maps a refname to an id
@@ -42,7 +43,7 @@ export default class CramAdapter extends BaseFeatureDataAdapter {
42
43
  // maps a seqId to original refname, passed specially to render args, to a seqid
43
44
  private seqIdToOriginalRefName: string[] = []
44
45
 
45
- public async configure() {
46
+ public async configurePre() {
46
47
  const cramLocation = this.getConf('cramLocation')
47
48
  const craiLocation = this.getConf('craiLocation')
48
49
  if (!cramLocation) {
@@ -51,48 +52,55 @@ export default class CramAdapter extends BaseFeatureDataAdapter {
51
52
  if (!craiLocation) {
52
53
  throw new Error('missing craiLocation argument')
53
54
  }
55
+ const pm = this.pluginManager
54
56
 
55
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
56
- const cram: any = new IndexedCramFile({
57
- cramFilehandle: openLocation(cramLocation, this.pluginManager),
58
- index: new CraiIndex({
59
- filehandle: openLocation(craiLocation, this.pluginManager),
60
- }),
61
- seqFetch: this.seqFetch.bind(this),
57
+ const cram = new IndexedCramFile({
58
+ cramFilehandle: openLocation(cramLocation, pm),
59
+ index: new CraiIndex({ filehandle: openLocation(craiLocation, pm) }),
60
+ seqFetch: (...args) => this.seqFetch(...args),
62
61
  checkSequenceMD5: false,
63
62
  fetchSizeLimit: 200_000_000, // just make this a large size to avoid hitting it
64
63
  })
65
- // instantiate the sequence adapter
66
- const sequenceAdapterType = this.getConf(['sequenceAdapter', 'type'])
67
64
 
68
65
  if (!this.getSubAdapter) {
69
66
  throw new Error('Error getting subadapter')
70
67
  }
71
68
 
72
69
  const seqConf = this.getConf('sequenceAdapter')
73
- const { dataAdapter: sequenceAdapter } = await this.getSubAdapter(seqConf)
70
+ const subadapter = await this.getSubAdapter(seqConf)
74
71
 
75
- if (!(sequenceAdapter instanceof BaseFeatureDataAdapter)) {
76
- throw new Error(
77
- `CRAM feature adapters cannot use sequence adapters of type '${sequenceAdapterType}'`,
78
- )
72
+ return {
73
+ cram,
74
+ sequenceAdapter: subadapter.dataAdapter as BaseSequenceAdapter,
79
75
  }
76
+ }
80
77
 
81
- return { cram, sequenceAdapter }
78
+ public async configure() {
79
+ if (!this.configureP) {
80
+ this.configureP = this.configurePre().catch(e => {
81
+ this.configureP = undefined
82
+ throw e
83
+ })
84
+ }
85
+ return this.configureP
82
86
  }
83
87
 
84
88
  async getHeader(opts?: BaseOptions) {
85
89
  const { cram } = await this.configure()
86
- return cram.cram.getHeaderText(opts)
90
+ return cram.cram.getHeaderText()
87
91
  }
88
92
 
89
- private async seqFetch(seqId: number, start: number, end: number) {
93
+ private async seqFetch(
94
+ seqId: number,
95
+ start: number,
96
+ end: number,
97
+ ): Promise<string> {
90
98
  start -= 1 // convert from 1-based closed to interbase
91
99
 
92
100
  const { sequenceAdapter } = await this.configure()
93
101
  const refName = this.refIdToOriginalName(seqId) || this.refIdToName(seqId)
94
102
  if (!refName) {
95
- return undefined
103
+ throw new Error('unknown')
96
104
  }
97
105
 
98
106
  const seqChunks = await sequenceAdapter
@@ -132,10 +140,10 @@ export default class CramAdapter extends BaseFeatureDataAdapter {
132
140
 
133
141
  private async setupPre(opts?: BaseOptions) {
134
142
  const { statusCallback = () => {} } = opts || {}
135
- const configured = await this.configure()
143
+ const conf = await this.configure()
136
144
  statusCallback('Downloading index')
137
- const { cram } = configured
138
- const samHeader: HeaderLine[] = await cram.cram.getSamHeader(opts?.signal)
145
+ const { cram } = conf
146
+ const samHeader = await cram.cram.getSamHeader()
139
147
 
140
148
  // use the @SQ lines in the header to figure out the
141
149
  // mapping between ref ID numbers and names
@@ -161,7 +169,7 @@ export default class CramAdapter extends BaseFeatureDataAdapter {
161
169
  const data = { idToName, nameToId, readGroups }
162
170
  statusCallback('')
163
171
  this.samHeader = data
164
- return { samHeader: data, ...configured }
172
+ return { samHeader: data, ...conf }
165
173
  }
166
174
 
167
175
  private async setup(opts?: BaseOptions) {
@@ -197,13 +205,7 @@ export default class CramAdapter extends BaseFeatureDataAdapter {
197
205
  // use info from the SAM header if possible, but fall back to using
198
206
  // the ref seq order from when the browser's refseqs were loaded
199
207
  refIdToName(refId: number) {
200
- if (this.samHeader.idToName) {
201
- return this.samHeader.idToName[refId]
202
- }
203
- if (this.seqIdToRefName) {
204
- return this.seqIdToRefName[refId]
205
- }
206
- return undefined
208
+ return this.samHeader.idToName?.[refId] || this.seqIdToRefName?.[refId]
207
209
  }
208
210
 
209
211
  refIdToOriginalName(refId: number) {
@@ -220,53 +222,48 @@ export default class CramAdapter extends BaseFeatureDataAdapter {
220
222
  const { refName, start, end, originalRefName } = region
221
223
 
222
224
  return ObservableCreate<Feature>(async observer => {
223
- const { cram, sequenceAdapter } = await this.setup(opts)
224
- statusCallback('Downloading alignments')
225
- if (!this.seqIdToRefName) {
226
- this.seqIdToRefName = await sequenceAdapter.getRefNames(opts)
227
- }
225
+ const { cram } = await this.setup(opts)
226
+
228
227
  const refId = this.refNameToId(refName)
229
- if (refId !== undefined) {
230
- if (originalRefName) {
231
- this.seqIdToOriginalRefName[refId] = originalRefName
232
- }
233
- const records = await cram.getRecordsForRange(refId, start, end, opts)
234
- checkAbortSignal(signal)
235
- const {
236
- flagInclude = 0,
237
- flagExclude = 0,
238
- tagFilter,
239
- readName,
240
- } = filterBy || {}
241
-
242
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
243
- let filtered = records.filter((record: any) => {
244
- const flags = record.flags
245
- return (flags & flagInclude) === flagInclude && !(flags & flagExclude)
246
- })
228
+ if (refId === undefined) {
229
+ console.warn('Unknown refName', refName)
230
+ observer.complete()
231
+ return
232
+ }
233
+
234
+ if (originalRefName) {
235
+ this.seqIdToOriginalRefName[refId] = originalRefName
236
+ }
237
+ statusCallback('Downloading alignments')
238
+ const records = await cram.getRecordsForRange(refId, start, end)
239
+ checkAbortSignal(signal)
240
+ const {
241
+ flagInclude = 0,
242
+ flagExclude = 0,
243
+ tagFilter,
244
+ readName,
245
+ } = filterBy || {}
246
+
247
+ let filtered = records.filter(record => {
248
+ const flags = record.flags
249
+ return (flags & flagInclude) === flagInclude && !(flags & flagExclude)
250
+ })
247
251
 
248
- if (tagFilter) {
249
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
250
- filtered = filtered.filter((record: any) => {
251
- const val = record[tagFilter.tag]
252
- return val === '*' ? val !== undefined : val === tagFilter.value
253
- })
254
- }
255
-
256
- if (readName) {
257
- filtered = filtered.filter(
258
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
259
- (record: any) => record.readName === readName,
260
- )
261
- }
262
-
263
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
264
- filtered.forEach((record: any) => {
265
- observer.next(this.cramRecordToFeature(record))
252
+ if (tagFilter) {
253
+ filtered = filtered.filter(record => {
254
+ // @ts-ignore
255
+ const val = record[tagFilter.tag]
256
+ return val === '*' ? val !== undefined : val === tagFilter.value
266
257
  })
267
- } else {
268
- console.warn('Unknown refName', refName)
269
258
  }
259
+
260
+ if (readName) {
261
+ filtered = filtered.filter(record => record.readName === readName)
262
+ }
263
+
264
+ filtered.forEach(record => {
265
+ observer.next(this.cramRecordToFeature(record))
266
+ })
270
267
  statusCallback('')
271
268
  observer.complete()
272
269
  }, signal)
@@ -274,7 +271,7 @@ export default class CramAdapter extends BaseFeatureDataAdapter {
274
271
 
275
272
  freeResources(/* { region } */): void {}
276
273
 
277
- cramRecordToFeature(record: unknown) {
274
+ cramRecordToFeature(record: CramRecord) {
278
275
  return new CramSlightlyLazyFeature(record, this)
279
276
  }
280
277
 
@@ -299,7 +296,9 @@ export default class CramAdapter extends BaseFeatureDataAdapter {
299
296
  regions.map(region => {
300
297
  const { refName, start, end } = region
301
298
  const chrId = this.refNameToId(refName)
302
- return cram.index.getEntriesForRange(chrId, start, end)
299
+ return chrId !== undefined
300
+ ? cram.index.getEntriesForRange(chrId, start, end)
301
+ : [{ sliceBytes: 0 }]
303
302
  }),
304
303
  )
305
304
 
@@ -3,7 +3,7 @@ import {
3
3
  Feature,
4
4
  SimpleFeatureSerialized,
5
5
  } from '@jbrowse/core/util/simpleFeature'
6
-
6
+ import { CramRecord } from '@gmod/cram'
7
7
  import CramAdapter from './CramAdapter'
8
8
 
9
9
  export interface Mismatch {
@@ -20,8 +20,8 @@ export interface Mismatch {
20
20
  export default class CramSlightlyLazyFeature implements Feature {
21
21
  // uses parameter properties to automatically create fields on the class
22
22
  // https://www.typescriptlang.org/docs/handbook/classes.html#parameter-properties
23
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
24
- constructor(private record: any, private _store: CramAdapter) {}
23
+
24
+ constructor(private record: CramRecord, private _store: CramAdapter) {}
25
25
 
26
26
  _get_name() {
27
27
  return this.record.readName
@@ -32,7 +32,7 @@ export default class CramSlightlyLazyFeature implements Feature {
32
32
  }
33
33
 
34
34
  _get_end() {
35
- return this.record.alignmentStart + this.record.lengthOnRef - 1
35
+ return this.record.alignmentStart + (this.record.lengthOnRef ?? 1) - 1
36
36
  }
37
37
 
38
38
  _get_cram_read_features() {
@@ -123,6 +123,9 @@ export default class CramSlightlyLazyFeature implements Feature {
123
123
  let cigar = ''
124
124
  let op = 'M'
125
125
  let oplen = 0
126
+ if (!this.record._refRegion) {
127
+ return ''
128
+ }
126
129
 
127
130
  // not sure I should access these, but...
128
131
  const ref = this.record._refRegion.seq
@@ -130,6 +133,7 @@ export default class CramSlightlyLazyFeature implements Feature {
130
133
  let last_pos = this.record.alignmentStart
131
134
  let sublen = 0
132
135
  if (typeof this.record.readFeatures !== 'undefined') {
136
+ let insLen = 0
133
137
  // @ts-ignore
134
138
  for (let i = 0; i < this.record.readFeatures.length; i++) {
135
139
  const { code, refPos, sub, data } = this.record.readFeatures[i]
@@ -145,6 +149,10 @@ export default class CramSlightlyLazyFeature implements Feature {
145
149
  op = 'M'
146
150
  oplen += sublen
147
151
  }
152
+ if (insLen > 0 && code !== 'i') {
153
+ cigar += `${insLen}I`
154
+ insLen = 0
155
+ }
148
156
 
149
157
  if (code === 'b') {
150
158
  // An array of bases stored verbatim
@@ -181,11 +189,11 @@ export default class CramSlightlyLazyFeature implements Feature {
181
189
  oplen = 0
182
190
  } else if (code === 'i') {
183
191
  // Single base insertion
184
- seq += data
192
+ // seq += data
185
193
  if (oplen) {
186
194
  cigar += oplen + op
187
195
  }
188
- cigar += `${1}I`
196
+ insLen++
189
197
  oplen = 0
190
198
  } else if (code === 'P') {
191
199
  // Padding
@@ -280,19 +288,12 @@ export default class CramSlightlyLazyFeature implements Feature {
280
288
  }
281
289
 
282
290
  toJSON(): SimpleFeatureSerialized {
283
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
284
- const tags: Record<string, any> = {}
285
- this.tags().forEach((t: string) => {
286
- const val = this.get(t)
287
- if (val !== undefined) {
288
- tags[t] = val
289
- }
290
- })
291
-
292
291
  return {
293
- ...tags,
294
- name: this.get('name'),
295
- type: this.get('type'),
292
+ ...Object.fromEntries(
293
+ this.tags()
294
+ .map(t => [t, this.get(t)])
295
+ .filter(elt => elt[1] !== undefined),
296
+ ),
296
297
  uniqueId: this.id(),
297
298
  }
298
299
  }
@@ -306,10 +307,23 @@ export default class CramSlightlyLazyFeature implements Feature {
306
307
  const start = this.get('start')
307
308
  const mismatches: Mismatch[] = new Array(readFeatures.length)
308
309
  let j = 0
310
+ let insLen = 0
311
+
312
+ let refPos = 0
309
313
  for (let i = 0; i < readFeatures.length; i++) {
310
314
  const f = readFeatures[i]
311
315
  const { code, pos, data, sub, ref } = f
312
- const refPos = f.refPos - 1 - start
316
+ if (insLen > 0 && code !== 'i') {
317
+ mismatches[j++] = {
318
+ start: refPos,
319
+ type: 'insertion',
320
+ base: `${insLen}`,
321
+ length: 0,
322
+ }
323
+ insLen = 0
324
+ }
325
+ refPos = f.refPos - 1 - start
326
+
313
327
  if (code === 'X') {
314
328
  // substitution
315
329
  mismatches[j++] = {
@@ -375,12 +389,7 @@ export default class CramSlightlyLazyFeature implements Feature {
375
389
  } else if (code === 'i') {
376
390
  // single-base insertion
377
391
  // insertion
378
- mismatches[j++] = {
379
- start: refPos,
380
- type: 'insertion',
381
- base: data,
382
- length: 1,
383
- }
392
+ insLen++
384
393
  } else if (code === 'Q') {
385
394
  // single quality value
386
395
  }
@@ -1,33 +1,58 @@
1
- import PluginManager from '@jbrowse/core/PluginManager'
2
1
  import { ConfigurationSchema } from '@jbrowse/core/configuration'
3
- import { types } from 'mobx-state-tree'
4
2
 
5
- export default (pluginManager: PluginManager) => {
6
- return types.late(() =>
7
- ConfigurationSchema(
8
- 'CramAdapter',
9
- {
10
- fetchSizeLimit: {
11
- type: 'number',
12
- defaultValue: 3_000_000,
13
- },
14
- cramLocation: {
15
- type: 'fileLocation',
16
- defaultValue: {
17
- uri: '/path/to/my.cram',
18
- locationType: 'UriLocation',
19
- },
20
- },
21
- craiLocation: {
22
- type: 'fileLocation',
23
- defaultValue: {
24
- uri: '/path/to/my.cram.crai',
25
- locationType: 'UriLocation',
26
- },
27
- },
28
- sequenceAdapter: pluginManager.pluggableConfigSchemaType('adapter'),
3
+ /**
4
+ * #config CramAdapter
5
+ * used to configure CRAM adapter
6
+ */
7
+ function x() {} // eslint-disable-line @typescript-eslint/no-unused-vars
8
+
9
+ const configSchema = ConfigurationSchema(
10
+ 'CramAdapter',
11
+ {
12
+ /**
13
+ * #slot fetchSizeLimit
14
+ */
15
+ fetchSizeLimit: {
16
+ type: 'number',
17
+ description:
18
+ 'used to determine when to display a warning to the user that too much data will be fetched',
19
+ defaultValue: 3_000_000,
20
+ },
21
+
22
+ /**
23
+ * #slot cramLocation
24
+ */
25
+ cramLocation: {
26
+ type: 'fileLocation',
27
+ defaultValue: {
28
+ uri: '/path/to/my.cram',
29
+ locationType: 'UriLocation',
29
30
  },
30
- { explicitlyTyped: true },
31
- ),
32
- )
33
- }
31
+ },
32
+
33
+ /**
34
+ * #slot craiLocation
35
+ */
36
+ craiLocation: {
37
+ type: 'fileLocation',
38
+ defaultValue: {
39
+ uri: '/path/to/my.cram.crai',
40
+ locationType: 'UriLocation',
41
+ },
42
+ },
43
+
44
+ /**
45
+ * #slot sequenceAdapter
46
+ * generally refers to the reference genome assembly's sequence adapter
47
+ * currently needs to be manually added
48
+ */
49
+ sequenceAdapter: {
50
+ type: 'frozen',
51
+ description:
52
+ 'sequence data adapter, used to calculate SNPs when BAM reads lacking MD tags',
53
+ defaultValue: null,
54
+ },
55
+ },
56
+ { explicitlyTyped: true },
57
+ )
58
+ export default configSchema
@@ -2,14 +2,14 @@ import PluginManager from '@jbrowse/core/PluginManager'
2
2
  import AdapterType from '@jbrowse/core/pluggableElementTypes/AdapterType'
3
3
 
4
4
  // locals
5
- import configSchemaF from './configSchema'
5
+ import configSchema from './configSchema'
6
6
 
7
7
  export default (pluginManager: PluginManager) => {
8
8
  pluginManager.addAdapterType(
9
9
  () =>
10
10
  new AdapterType({
11
11
  name: 'CramAdapter',
12
- configSchema: pluginManager.load(configSchemaF),
12
+ configSchema,
13
13
  getAdapterClass: () => import('./CramAdapter').then(r => r.default),
14
14
  }),
15
15
  )
@@ -1,31 +1,24 @@
1
1
  import { BamFile, HtsgetFile } from '@gmod/bam'
2
- import { readConfObject } from '@jbrowse/core/configuration'
3
2
  import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter'
4
3
  import BamAdapter from '../BamAdapter/BamAdapter'
5
4
 
6
5
  export default class HtsgetBamAdapter extends BamAdapter {
7
- protected async configure() {
8
- if (!this.configured) {
9
- const htsgetBase = readConfObject(this.config, 'htsgetBase')
10
- const htsgetTrackId = readConfObject(this.config, 'htsgetTrackId')
11
- const bam = new HtsgetFile({
12
- baseUrl: htsgetBase,
13
- trackId: htsgetTrackId,
14
- }) as unknown as BamFile
6
+ protected async configurePre() {
7
+ const htsgetBase = this.getConf('htsgetBase')
8
+ const htsgetTrackId = this.getConf('htsgetTrackId')
9
+ const bam = new HtsgetFile({
10
+ baseUrl: htsgetBase,
11
+ trackId: htsgetTrackId,
12
+ }) as unknown as BamFile
15
13
 
16
- const adapterConfig = readConfObject(this.config, 'sequenceAdapter')
17
- if (adapterConfig && this.getSubAdapter) {
18
- this.configured = this.getSubAdapter(adapterConfig).then(
19
- ({ dataAdapter }) => {
20
- return {
21
- bam,
22
- sequenceAdapter: dataAdapter as BaseFeatureDataAdapter,
23
- }
24
- },
25
- )
14
+ const adapterConfig = this.getConf('sequenceAdapter')
15
+ if (adapterConfig && this.getSubAdapter) {
16
+ const adapter = await this.getSubAdapter(adapterConfig)
17
+ return {
18
+ bam,
19
+ sequenceAdapter: adapter.dataAdapter as BaseFeatureDataAdapter,
26
20
  }
27
- this.configured = Promise.resolve({ bam })
28
21
  }
29
- return this.configured
22
+ return { bam }
30
23
  }
31
24
  }
@@ -1,23 +1,40 @@
1
1
  import { ConfigurationSchema } from '@jbrowse/core/configuration'
2
- import { types } from 'mobx-state-tree'
2
+ /**
3
+ * #config HtsgetBamAdapter
4
+ * Used to fetch data from Htsget endpoints in BAM format, using the gmod/bam library
5
+ */
6
+ function x() {} // eslint-disable-line @typescript-eslint/no-unused-vars
3
7
 
4
- export default types.late(() =>
5
- ConfigurationSchema(
6
- 'HtsgetBamAdapter',
7
- {
8
- htsgetBase: {
9
- type: 'string',
10
- defaultValue: '',
11
- },
12
- htsgetTrackId: {
13
- type: 'string',
14
- defaultValue: '',
15
- },
16
- sequenceAdapter: {
17
- type: 'frozen',
18
- defaultValue: null,
19
- },
8
+ const HtsgetBamAdapter = ConfigurationSchema(
9
+ 'HtsgetBamAdapter',
10
+ {
11
+ /**
12
+ * #slot
13
+ */
14
+ htsgetBase: {
15
+ type: 'string',
16
+ description: 'the base URL to fetch from',
17
+ defaultValue: '',
20
18
  },
21
- { explicitlyTyped: true },
22
- ),
19
+ /**
20
+ * #slot
21
+ */
22
+ htsgetTrackId: {
23
+ type: 'string',
24
+ description: 'the trackId, which is appended to the base URL',
25
+ defaultValue: '',
26
+ },
27
+ /**
28
+ * #slot
29
+ */
30
+ sequenceAdapter: {
31
+ type: 'frozen',
32
+ description:
33
+ 'sequence data adapter, used to calculate SNPs when BAM reads lacking MD tags',
34
+ defaultValue: null,
35
+ },
36
+ },
37
+ { explicitlyTyped: true },
23
38
  )
39
+
40
+ export default HtsgetBamAdapter
@@ -2,21 +2,34 @@ import { ConfigurationSchema } from '@jbrowse/core/configuration'
2
2
  import { baseLinearDisplayConfigSchema } from '@jbrowse/plugin-linear-genome-view'
3
3
  import PluginManager from '@jbrowse/core/PluginManager'
4
4
 
5
- const configModelFactory = (pluginManager: PluginManager) => {
6
- const PileupDisplayConfigSchema = pluginManager.getDisplayType(
7
- 'LinearPileupDisplay',
8
- ).configSchema
9
- const SNPCoverageDisplayConfigSchema = pluginManager.getDisplayType(
10
- 'LinearSNPCoverageDisplay',
11
- ).configSchema
5
+ /**
6
+ * #config LinearAlignmentsDisplay
7
+ * has a "pileup" sub-display, where you can see individual reads and a
8
+ * quantitative "snpcoverage" sub-display track showing SNP frequencies
9
+ */
10
+ function x() {} // eslint-disable-line @typescript-eslint/no-unused-vars
12
11
 
12
+ const configModelFactory = (pm: PluginManager) => {
13
13
  return ConfigurationSchema(
14
14
  'LinearAlignmentsDisplay',
15
15
  {
16
- pileupDisplay: PileupDisplayConfigSchema,
17
- snpCoverageDisplay: SNPCoverageDisplayConfigSchema,
16
+ /**
17
+ * #slot
18
+ */
19
+ pileupDisplay: pm.getDisplayType('LinearPileupDisplay').configSchema,
20
+ /**
21
+ * #slot
22
+ */
23
+ snpCoverageDisplay: pm.getDisplayType('LinearSNPCoverageDisplay')
24
+ .configSchema,
25
+ },
26
+ {
27
+ /**
28
+ * #baseConfiguration
29
+ */
30
+ baseConfiguration: baseLinearDisplayConfigSchema,
31
+ explicitlyTyped: true,
18
32
  },
19
- { baseConfiguration: baseLinearDisplayConfigSchema, explicitlyTyped: true },
20
33
  )
21
34
  }
22
35