@@ -28,6 +28,9 @@ interface ReadChunk {
2828export default class TabixIndexedFile {
2929 private filehandle : GenericFilehandle
3030 private index : IndexFile
31+ private fallbackIndex ?: IndexFile
32+ private indexResolved = false
33+ private indexResolvePromise ?: Promise < void >
3134 private renameRefSeq : ( n : string ) => string
3235 private chunkCache : AbortablePromiseCache < Chunk , ReadChunk >
3336 public cache = new LRU <
@@ -98,7 +101,16 @@ export default class TabixIndexedFile {
98101 throw new TypeError ( 'must provide either filehandle or path' )
99102 }
100103
101- if ( tbiFilehandle ) {
104+ if ( tbiFilehandle && csiFilehandle ) {
105+ this . index = new TBI ( {
106+ filehandle : tbiFilehandle ,
107+ renameRefSeqs,
108+ } )
109+ this . fallbackIndex = new CSI ( {
110+ filehandle : csiFilehandle ,
111+ renameRefSeqs,
112+ } )
113+ } else if ( tbiFilehandle ) {
102114 this . index = new TBI ( {
103115 filehandle : tbiFilehandle ,
104116 renameRefSeqs,
@@ -108,6 +120,15 @@ export default class TabixIndexedFile {
108120 filehandle : csiFilehandle ,
109121 renameRefSeqs,
110122 } )
123+ } else if ( tbiPath && csiPath ) {
124+ this . index = new TBI ( {
125+ filehandle : new LocalFile ( tbiPath ) ,
126+ renameRefSeqs,
127+ } )
128+ this . fallbackIndex = new CSI ( {
129+ filehandle : new LocalFile ( csiPath ) ,
130+ renameRefSeqs,
131+ } )
111132 } else if ( tbiPath ) {
112133 this . index = new TBI ( {
113134 filehandle : new LocalFile ( tbiPath ) ,
@@ -123,17 +144,37 @@ export default class TabixIndexedFile {
123144 filehandle : new LocalFile ( `${ path } .tbi` ) ,
124145 renameRefSeqs,
125146 } )
147+ this . fallbackIndex = new CSI ( {
148+ filehandle : new LocalFile ( `${ path } .csi` ) ,
149+ renameRefSeqs,
150+ } )
151+ } else if ( tbiUrl && csiUrl ) {
152+ this . index = new TBI ( {
153+ filehandle : new RemoteFile ( tbiUrl ) ,
154+ renameRefSeqs,
155+ } )
156+ this . fallbackIndex = new CSI ( {
157+ filehandle : new RemoteFile ( csiUrl ) ,
158+ renameRefSeqs,
159+ } )
126160 } else if ( csiUrl ) {
127161 this . index = new CSI ( {
128162 filehandle : new RemoteFile ( csiUrl ) ,
163+ renameRefSeqs,
129164 } )
130165 } else if ( tbiUrl ) {
131166 this . index = new TBI ( {
132167 filehandle : new RemoteFile ( tbiUrl ) ,
168+ renameRefSeqs,
133169 } )
134170 } else if ( url ) {
135171 this . index = new TBI ( {
136172 filehandle : new RemoteFile ( `${ url } .tbi` ) ,
173+ renameRefSeqs,
174+ } )
175+ this . fallbackIndex = new CSI ( {
176+ filehandle : new RemoteFile ( `${ url } .csi` ) ,
177+ renameRefSeqs,
137178 } )
138179 } else {
139180 throw new TypeError (
@@ -149,6 +190,38 @@ export default class TabixIndexedFile {
149190 } )
150191 }
151192
193+ private async ensureIndex ( opts : Options = { } ) {
194+ if ( this . indexResolved ) {
195+ return
196+ }
197+ if ( ! this . indexResolvePromise ) {
198+ this . indexResolvePromise = this . resolveIndex ( opts )
199+ }
200+ return this . indexResolvePromise
201+ }
202+
203+ private async resolveIndex ( opts : Options = { } ) {
204+ if ( ! this . fallbackIndex ) {
205+ this . indexResolved = true
206+ return
207+ }
208+ try {
209+ await this . index . parse ( opts )
210+ this . indexResolved = true
211+ } catch ( e ) {
212+ const isNotFound =
213+ e instanceof Error &&
214+ ( / H T T P 4 0 4 / . test ( e . message ) || / E N O E N T / . test ( e . message ) )
215+ if ( isNotFound ) {
216+ this . index = this . fallbackIndex
217+ this . fallbackIndex = undefined
218+ this . indexResolved = true
219+ } else {
220+ throw e
221+ }
222+ }
223+ }
224+
152225 /**
153226 * @param refName name of the reference sequence
154227 *
@@ -195,6 +268,7 @@ export default class TabixIndexedFile {
195268 signal = opts . signal
196269 }
197270
271+ await this . ensureIndex ( options )
198272 const metadata = await this . index . getMetadata ( options )
199273 checkAbortSignal ( signal )
200274 const start = s ?? 0
@@ -328,6 +402,7 @@ export default class TabixIndexedFile {
328402 }
329403
330404 async getMetadata ( opts : Options = { } ) {
405+ await this . ensureIndex ( opts )
331406 return this . index . getMetadata ( opts )
332407 }
333408
@@ -538,6 +613,7 @@ export default class TabixIndexedFile {
538613 * @returns number of data lines present on that reference sequence
539614 */
540615 async lineCount ( refName : string , opts : Options = { } ) {
616+ await this . ensureIndex ( opts )
541617 return this . index . lineCount ( refName , opts )
542618 }
543619
0 commit comments