@jbrowse/plugin-legacy-jbrowse 1.4.4 → 1.5.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.
Files changed (31) hide show
  1. package/dist/JBrowse1Connection/jb1ToJb2.d.ts +1 -0
  2. package/dist/JBrowse1Connection/types.d.ts +2 -0
  3. package/dist/JBrowse1TextSeachAdapter/HttpMap.d.ts +1 -15
  4. package/dist/JBrowse1TextSeachAdapter/JBrowse1TextSearchAdapter.d.ts +12 -8
  5. package/dist/NCListAdapter/NCListAdapter.d.ts +3 -1
  6. package/dist/plugin-legacy-jbrowse.cjs.development.js +334 -398
  7. package/dist/plugin-legacy-jbrowse.cjs.development.js.map +1 -1
  8. package/dist/plugin-legacy-jbrowse.cjs.production.min.js +1 -1
  9. package/dist/plugin-legacy-jbrowse.cjs.production.min.js.map +1 -1
  10. package/dist/plugin-legacy-jbrowse.esm.js +336 -399
  11. package/dist/plugin-legacy-jbrowse.esm.js.map +1 -1
  12. package/package.json +5 -3
  13. package/src/JBrowse1Connection/configSchema.ts +4 -1
  14. package/src/JBrowse1Connection/jb1ConfigLoad.ts +24 -27
  15. package/src/JBrowse1Connection/jb1ConfigParse.ts +10 -12
  16. package/src/JBrowse1Connection/jb1ToJb2.ts +93 -43
  17. package/src/JBrowse1Connection/types.ts +2 -0
  18. package/src/JBrowse1TextSeachAdapter/HttpMap.test.ts +8 -20
  19. package/src/JBrowse1TextSeachAdapter/HttpMap.ts +17 -75
  20. package/src/JBrowse1TextSeachAdapter/JBrowse1TextSearchAdapter.test.ts +2 -4
  21. package/src/JBrowse1TextSeachAdapter/JBrowse1TextSearchAdapter.ts +42 -58
  22. package/src/JBrowse1TextSeachAdapter/configSchema.ts +2 -2
  23. package/src/NCListAdapter/NCListAdapter.test.ts +4 -1
  24. package/src/NCListAdapter/NCListAdapter.ts +15 -8
  25. package/src/NCListAdapter/configSchema.ts +4 -1
  26. package/src/__snapshots__/index.test.js.snap +3 -0
  27. package/src/index.test.js +1 -0
  28. package/src/index.ts +23 -0
  29. package/dist/JBrowse1TextSeachAdapter/Crc32.d.ts +0 -19
  30. package/src/JBrowse1TextSeachAdapter/Crc32.test.ts +0 -21
  31. package/src/JBrowse1TextSeachAdapter/Crc32.ts +0 -77
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jbrowse/plugin-legacy-jbrowse",
3
- "version": "1.4.4",
3
+ "version": "1.5.3",
4
4
  "description": "JBrowse 2 plugin for connecting to and reading JBrowse 1 data",
5
5
  "keywords": [
6
6
  "jbrowse",
@@ -36,8 +36,10 @@
36
36
  },
37
37
  "dependencies": {
38
38
  "@gmod/nclist": "^0.1.1",
39
+ "buffer-crc32": "^0.2.13",
40
+ "generic-filehandle": "^2.2.2",
39
41
  "get-value": "^3.0.1",
40
- "set-value": "^3.0.0"
42
+ "set-value": "^4.0.1"
41
43
  },
42
44
  "peerDependencies": {
43
45
  "@jbrowse/core": "^1.0.0",
@@ -47,5 +49,5 @@
47
49
  "publishConfig": {
48
50
  "access": "public"
49
51
  },
50
- "gitHead": "c12a2b1cef07dbc5ea40be5c76e03b655b7f3636"
52
+ "gitHead": "cea9023ebce8bbe5c08ae9e00c4e74fe3f02a7f1"
51
53
  }
@@ -6,7 +6,10 @@ export default ConfigurationSchema(
6
6
  {
7
7
  dataDirLocation: {
8
8
  type: 'fileLocation',
9
- defaultValue: { uri: 'http://mysite.com/jbrowse/data/' },
9
+ defaultValue: {
10
+ uri: 'http://mysite.com/jbrowse/data/',
11
+ locationType: 'UriLocation',
12
+ },
10
13
  description:
11
14
  'the location of the JBrowse 1 data directory, often something like http://mysite.com/jbrowse/data/',
12
15
  },
@@ -21,11 +21,11 @@ function isLocalPathLocation(
21
21
  }
22
22
 
23
23
  export async function fetchJb1(
24
- dataRoot: JBLocation = { uri: '' },
24
+ dataRoot: JBLocation = { uri: '', locationType: 'UriLocation' },
25
25
  baseConfig: Config = {
26
26
  include: ['{dataRoot}/trackList.json', '{dataRoot}/tracks.conf'],
27
27
  },
28
- baseConfigRoot: JBLocation = { uri: '' },
28
+ baseConfigRoot: JBLocation = { uri: '', locationType: 'UriLocation' },
29
29
  ): Promise<Config> {
30
30
  const protocol = 'uri' in dataRoot ? 'uri' : 'localPath'
31
31
  const dataRootReg = JSON.parse(JSON.stringify(dataRoot))
@@ -224,15 +224,14 @@ async function loadIncludes(inputConfig: Config): Promise<Config> {
224
224
  )
225
225
  delete config.include
226
226
 
227
- const loads = includes.map(
228
- async (include): Promise<Config> => {
229
- include.cacheBuster = inputConfig.cacheBuster
230
- const includedData = await fetchConfigFile({
231
- uri: new URL(include.url, sourceUrl).href,
232
- })
233
- return loadRecur(includedData, newUpstreamConf)
234
- },
235
- )
227
+ const loads = includes.map(async (include): Promise<Config> => {
228
+ include.cacheBuster = inputConfig.cacheBuster
229
+ const includedData = await fetchConfigFile({
230
+ uri: new URL(include.url, sourceUrl).href,
231
+ locationType: 'UriLocation',
232
+ })
233
+ return loadRecur(includedData, newUpstreamConf)
234
+ })
236
235
  const includedDataObjects = await Promise.all(loads)
237
236
  includedDataObjects.forEach((includedData): void => {
238
237
  config = mergeConfigs(config, includedData) || config
@@ -255,23 +254,21 @@ function regularizeIncludes(
255
254
  includes = [includes]
256
255
  }
257
256
 
258
- return includes.map(
259
- (include): Include => {
260
- // coerce bare strings in the includes to URLs
261
- if (typeof include === 'string') {
262
- include = { url: include }
263
- }
257
+ return includes.map((include): Include => {
258
+ // coerce bare strings in the includes to URLs
259
+ if (typeof include === 'string') {
260
+ include = { url: include }
261
+ }
264
262
 
265
- // set defaults for format and version
266
- if (!('format' in include)) {
267
- include.format = include.url.endsWith('.conf') ? 'conf' : 'JB_json'
268
- }
269
- if (include.format === 'JB_json' && !('version' in include)) {
270
- include.version = 1
271
- }
272
- return include
273
- },
274
- )
263
+ // set defaults for format and version
264
+ if (!('format' in include)) {
265
+ include.format = include.url.endsWith('.conf') ? 'conf' : 'JB_json'
266
+ }
267
+ if (include.format === 'JB_json' && !('version' in include)) {
268
+ include.version = 1
269
+ }
270
+ return include
271
+ })
275
272
  }
276
273
 
277
274
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -208,19 +208,17 @@ export function regularizeConf(conf: Config, url: string): Config {
208
208
  }
209
209
 
210
210
  // coerce any string source defs to be URLs, and try to detect their types
211
- meta.sources = meta.sources.map(
212
- (sourceDef: string | Source): Source => {
213
- if (typeof sourceDef === 'string') {
214
- const newSourceDef: Source = { url: sourceDef }
215
- const typeMatch = sourceDef.match(/\.(\w+)$/)
216
- if (typeMatch) {
217
- newSourceDef.type = typeMatch[1].toLowerCase()
218
- }
219
- return newSourceDef
211
+ meta.sources = meta.sources.map((sourceDef: string | Source): Source => {
212
+ if (typeof sourceDef === 'string') {
213
+ const newSourceDef: Source = { url: sourceDef }
214
+ const typeMatch = sourceDef.match(/\.(\w+)$/)
215
+ if (typeMatch) {
216
+ newSourceDef.type = typeMatch[1].toLowerCase()
220
217
  }
221
- return sourceDef
222
- },
223
- )
218
+ return newSourceDef
219
+ }
220
+ return sourceDef
221
+ })
224
222
  }
225
223
 
226
224
  conf.sourceUrl = conf.sourceUrl || url
@@ -51,6 +51,7 @@ interface Jb2Location {
51
51
  uri?: string
52
52
  localPath?: string
53
53
  blobId?: string
54
+ locationType?: string
54
55
  }
55
56
 
56
57
  export function convertTrackConfig(
@@ -102,19 +103,27 @@ export function convertTrackConfig(
102
103
  if (storeClass === 'JBrowse/Store/SeqFeature/BAM') {
103
104
  const adapter: Jb2Adapter = {
104
105
  type: 'BamAdapter',
105
- bamLocation: { uri: urlTemplate },
106
+ bamLocation: { uri: urlTemplate, locationType: 'UriLocation' },
106
107
  }
107
108
  if (jb1TrackConfig.baiUrlTemplate) {
108
109
  adapter.index = {
109
- location: { uri: resolveUrlTemplate(jb1TrackConfig.baiUrlTemplate) },
110
+ location: {
111
+ uri: resolveUrlTemplate(jb1TrackConfig.baiUrlTemplate),
112
+ locationType: 'UriLocation',
113
+ },
110
114
  }
111
115
  } else if (jb1TrackConfig.csiUrlTemplate) {
112
116
  adapter.index = {
113
- location: { uri: resolveUrlTemplate(jb1TrackConfig.csiUrlTemplate) },
117
+ location: {
118
+ uri: resolveUrlTemplate(jb1TrackConfig.csiUrlTemplate),
119
+ locationType: 'UriLocation',
120
+ },
114
121
  indexType: 'CSI',
115
122
  }
116
123
  } else {
117
- adapter.index = { location: { uri: `${urlTemplate}.bai` } }
124
+ adapter.index = {
125
+ location: { uri: `${urlTemplate}.bai`, locationType: 'UriLocation' },
126
+ }
118
127
  }
119
128
  return {
120
129
  ...jb2TrackConfig,
@@ -125,15 +134,19 @@ export function convertTrackConfig(
125
134
  if (storeClass === 'JBrowse/Store/SeqFeature/CRAM') {
126
135
  const adapter: Jb2Adapter = {
127
136
  type: 'CramAdapter',
128
- cramLocation: { uri: urlTemplate },
137
+ cramLocation: { uri: urlTemplate, locationType: 'UriLocation' },
129
138
  sequenceAdapter,
130
139
  }
131
140
  if (jb1TrackConfig.craiUrlTemplate) {
132
141
  adapter.craiLocation = {
133
142
  uri: resolveUrlTemplate(jb1TrackConfig.craiUrlTemplate),
143
+ locationType: 'UriLocation',
134
144
  }
135
145
  } else {
136
- adapter.craiLocation = { uri: `${urlTemplate}.crai` }
146
+ adapter.craiLocation = {
147
+ uri: `${urlTemplate}.crai`,
148
+ locationType: 'UriLocation',
149
+ }
137
150
  }
138
151
  return {
139
152
  ...jb2TrackConfig,
@@ -147,7 +160,7 @@ export function convertTrackConfig(
147
160
  type: 'FeatureTrack',
148
161
  adapter: {
149
162
  type: 'NCListAdapter',
150
- rootUrlTemplate: { uri: urlTemplate },
163
+ rootUrlTemplate: { uri: urlTemplate, locationType: 'UriLocation' },
151
164
  },
152
165
  }
153
166
  }
@@ -168,26 +181,34 @@ export function convertTrackConfig(
168
181
  type: 'QuantitativeTrack',
169
182
  adapter: {
170
183
  type: 'BigWigAdapter',
171
- bigWigLocation: { uri: urlTemplate },
184
+ bigWigLocation: { uri: urlTemplate, locationType: 'UriLocation' },
172
185
  },
173
186
  }
174
187
  }
175
188
  if (storeClass === 'JBrowse/Store/SeqFeature/VCFTabix') {
176
189
  const adapter: Jb2Adapter = {
177
190
  type: 'VcfTabixAdapter',
178
- vcfGzLocation: { uri: urlTemplate },
191
+ vcfGzLocation: { uri: urlTemplate, locationType: 'UriLocation' },
179
192
  }
180
193
  if (jb1TrackConfig.tbiUrlTemplate) {
181
194
  adapter.index = {
182
- location: { uri: resolveUrlTemplate(jb1TrackConfig.tbiUrlTemplate) },
195
+ location: {
196
+ uri: resolveUrlTemplate(jb1TrackConfig.tbiUrlTemplate),
197
+ locationType: 'UriLocation',
198
+ },
183
199
  }
184
200
  } else if (jb1TrackConfig.csiUrlTemplate) {
185
201
  adapter.index = {
186
- location: { uri: resolveUrlTemplate(jb1TrackConfig.csiUrlTemplate) },
202
+ location: {
203
+ uri: resolveUrlTemplate(jb1TrackConfig.csiUrlTemplate),
204
+ locationType: 'UriLocation',
205
+ },
187
206
  indexType: 'CSI',
188
207
  }
189
208
  } else {
190
- adapter.index = { location: { uri: `${urlTemplate}.tbi` } }
209
+ adapter.index = {
210
+ location: { uri: `${urlTemplate}.tbi`, locationType: 'UriLocation' },
211
+ }
191
212
  }
192
213
  return {
193
214
  ...jb2TrackConfig,
@@ -215,26 +236,34 @@ export function convertTrackConfig(
215
236
  type: 'FeatureTrack',
216
237
  adapter: {
217
238
  type: 'BigBedAdapter',
218
- bigBedLocation: { uri: urlTemplate },
239
+ bigBedLocation: { uri: urlTemplate, locationType: 'UriLocation' },
219
240
  },
220
241
  }
221
242
  }
222
243
  if (storeClass === 'JBrowse/Store/SeqFeature/GFF3Tabix') {
223
244
  const adapter: Jb2Adapter = {
224
245
  type: 'Gff3TabixAdapter',
225
- gffGzLocation: { uri: urlTemplate },
246
+ gffGzLocation: { uri: urlTemplate, locationType: 'UriLocation' },
226
247
  }
227
248
  if (jb1TrackConfig.tbiUrlTemplate) {
228
249
  adapter.index = {
229
- location: { uri: resolveUrlTemplate(jb1TrackConfig.tbiUrlTemplate) },
250
+ location: {
251
+ uri: resolveUrlTemplate(jb1TrackConfig.tbiUrlTemplate),
252
+ locationType: 'UriLocation',
253
+ },
230
254
  }
231
255
  } else if (jb1TrackConfig.csiUrlTemplate) {
232
256
  adapter.index = {
233
- location: { uri: resolveUrlTemplate(jb1TrackConfig.csiUrlTemplate) },
257
+ location: {
258
+ uri: resolveUrlTemplate(jb1TrackConfig.csiUrlTemplate),
259
+ locationType: 'UriLocation',
260
+ },
234
261
  indexType: 'CSI',
235
262
  }
236
263
  } else {
237
- adapter.index = { location: { uri: `${urlTemplate}.tbi` } }
264
+ adapter.index = {
265
+ location: { uri: `${urlTemplate}.tbi`, locationType: 'UriLocation' },
266
+ }
238
267
  }
239
268
  return {
240
269
  ...jb2TrackConfig,
@@ -252,19 +281,27 @@ export function convertTrackConfig(
252
281
  if (storeClass === 'JBrowse/Store/SeqFeature/BEDTabix') {
253
282
  const adapter: Jb2Adapter = {
254
283
  type: 'BedTabixAdapter',
255
- bedGzLocation: { uri: urlTemplate },
284
+ bedGzLocation: { uri: urlTemplate, locationType: 'UriLocation' },
256
285
  }
257
286
  if (jb1TrackConfig.tbiUrlTemplate) {
258
287
  adapter.index = {
259
- location: { uri: resolveUrlTemplate(jb1TrackConfig.tbiUrlTemplate) },
288
+ location: {
289
+ uri: resolveUrlTemplate(jb1TrackConfig.tbiUrlTemplate),
290
+ locationType: 'UriLocation',
291
+ },
260
292
  }
261
293
  } else if (jb1TrackConfig.csiUrlTemplate) {
262
294
  adapter.index = {
263
- location: { uri: resolveUrlTemplate(jb1TrackConfig.csiUrlTemplate) },
295
+ location: {
296
+ uri: resolveUrlTemplate(jb1TrackConfig.csiUrlTemplate),
297
+ locationType: 'UriLocation',
298
+ },
264
299
  indexType: 'CSI',
265
300
  }
266
301
  } else {
267
- adapter.index = { location: { uri: `${urlTemplate}.tbi` } }
302
+ adapter.index = {
303
+ location: { uri: `${urlTemplate}.tbi`, locationType: 'UriLocation' },
304
+ }
268
305
  }
269
306
  return {
270
307
  ...jb2TrackConfig,
@@ -299,14 +336,18 @@ export function convertTrackConfig(
299
336
  if (storeClass === 'JBrowse/Store/SeqFeature/IndexedFasta') {
300
337
  const adapter: Jb2Adapter = {
301
338
  type: 'IndexedFastaAdapter',
302
- fastaLocation: { uri: urlTemplate },
339
+ fastaLocation: { uri: urlTemplate, locationType: 'UriLocation' },
303
340
  }
304
341
  if (jb1TrackConfig.faiUrlTemplate) {
305
342
  adapter.faiLocation = {
306
343
  uri: resolveUrlTemplate(jb1TrackConfig.faiUrlTemplate),
344
+ locationType: 'UriLocation',
307
345
  }
308
346
  } else {
309
- adapter.faiLocation = { uri: `${urlTemplate}.fai` }
347
+ adapter.faiLocation = {
348
+ uri: `${urlTemplate}.fai`,
349
+ locationType: 'UriLocation',
350
+ }
310
351
  }
311
352
  return {
312
353
  ...jb2TrackConfig,
@@ -317,21 +358,29 @@ export function convertTrackConfig(
317
358
  if (storeClass === 'JBrowse/Store/SeqFeature/BgzipIndexedFasta') {
318
359
  const adapter: Jb2Adapter = {
319
360
  type: 'BgzipFastaAdapter',
320
- fastaLocation: { uri: urlTemplate },
361
+ fastaLocation: { uri: urlTemplate, locationType: 'UriLocation' },
321
362
  }
322
363
  if (jb1TrackConfig.faiUrlTemplate) {
323
364
  adapter.faiLocation = {
324
365
  uri: resolveUrlTemplate(jb1TrackConfig.faiUrlTemplate),
366
+ locationType: 'UriLocation',
325
367
  }
326
368
  } else {
327
- adapter.faiLocation = { uri: `${urlTemplate}.fai` }
369
+ adapter.faiLocation = {
370
+ uri: `${urlTemplate}.fai`,
371
+ locationType: 'UriLocation',
372
+ }
328
373
  }
329
374
  if (jb1TrackConfig.gziUrlTemplate) {
330
375
  adapter.gziLocation = {
331
376
  uri: resolveUrlTemplate(jb1TrackConfig.gziUrlTemplate),
377
+ locationType: 'UriLocation',
332
378
  }
333
379
  } else {
334
- adapter.gziLocation = { uri: `${urlTemplate}.gzi` }
380
+ adapter.gziLocation = {
381
+ uri: `${urlTemplate}.gzi`,
382
+ locationType: 'UriLocation',
383
+ }
335
384
  }
336
385
  return {
337
386
  ...jb2TrackConfig,
@@ -345,7 +394,7 @@ export function convertTrackConfig(
345
394
  type: 'ReferenceSequenceTrack',
346
395
  adapter: {
347
396
  type: 'TwoBitAdapter',
348
- twoBitLocation: { uri: urlTemplate },
397
+ twoBitLocation: { uri: urlTemplate, locationType: 'UriLocation' },
349
398
  },
350
399
  }
351
400
  }
@@ -353,9 +402,9 @@ export function convertTrackConfig(
353
402
 
354
403
  // If we don't recogize the store class, make a best effort to guess by file type
355
404
  jb2TrackConfig.adapter = guessAdapter(
356
- { uri: urlTemplate },
405
+ { uri: urlTemplate, locationType: 'UriLocation' },
357
406
  undefined,
358
- () => urlTemplate,
407
+ urlTemplate,
359
408
  )
360
409
  if (!jb2TrackConfig.adapter) {
361
410
  throw new Error('Could not determine adapter')
@@ -394,16 +443,14 @@ function generateFromConfigTrackConfig(
394
443
  jb2TrackConfig: Jb2Track,
395
444
  ): Jb2Track {
396
445
  const jb1Features = jb1TrackConfig.features || []
397
- const jb2Features = jb1Features.map(
398
- (feature): Jb2Feature => {
399
- const jb2Feature: Jb2Feature = JSON.parse(JSON.stringify(feature))
400
- jb2Feature.refName = feature.seq_id
401
- jb2Feature.uniqueId = `${feature.seq_id}:${feature.start}-${
402
- feature.end
403
- }:${feature.name || ''}`
404
- return jb2Feature
405
- },
406
- )
446
+ const jb2Features = jb1Features.map((feature): Jb2Feature => {
447
+ const jb2Feature: Jb2Feature = JSON.parse(JSON.stringify(feature))
448
+ jb2Feature.refName = feature.seq_id
449
+ jb2Feature.uniqueId = `${feature.seq_id}:${feature.start}-${feature.end}:${
450
+ feature.name || ''
451
+ }`
452
+ return jb2Feature
453
+ })
407
454
  jb2TrackConfig.adapter = {
408
455
  type: 'FromConfigAdapter',
409
456
  features: jb2Features,
@@ -429,16 +476,18 @@ export async function createRefSeqsAdapter(
429
476
  type: 'IndexedFastaAdapter',
430
477
  fastaLocation: {
431
478
  uri: refSeqs.url.slice(0, -4),
479
+ locationType: 'UriLocation',
432
480
  },
433
481
  faiLocation: {
434
482
  uri: refSeqs.url,
483
+ locationType: 'UriLocation',
435
484
  },
436
485
  }
437
486
  }
438
487
  if (refSeqs.url.match(/.2bit$/)) {
439
488
  return {
440
489
  type: 'TwoBitAdapter',
441
- twoBitLocation: { uri: refSeqs.url },
490
+ twoBitLocation: { uri: refSeqs.url, locationType: 'UriLocation' },
442
491
  }
443
492
  }
444
493
  if (refSeqs.url.match(/.fa$/)) {
@@ -447,9 +496,10 @@ export async function createRefSeqsAdapter(
447
496
  if (refSeqs.url.match(/.sizes/)) {
448
497
  throw new Error('chromosome SIZES adapter not available')
449
498
  }
450
- const refSeqsJson = await openLocation({ uri: refSeqs.url }).readFile(
451
- 'utf8',
452
- )
499
+ const refSeqsJson = await openLocation({
500
+ uri: refSeqs.url,
501
+ locationType: 'UriLocation',
502
+ }).readFile('utf8')
453
503
  const refSeqsData: RefSeq[] = JSON.parse(refSeqsJson as string)
454
504
  return refSeqAdapterFromConfig(refSeqsData)
455
505
  }
@@ -94,10 +94,12 @@ export interface Config {
94
94
  export interface UriLocation {
95
95
  uri: string
96
96
  baseUri?: string
97
+ locationType: 'UriLocation'
97
98
  }
98
99
 
99
100
  export interface LocalPathLocation {
100
101
  localPath: string
102
+ locationType: 'LocalPathLocation'
101
103
  }
102
104
 
103
105
  export type JBLocation = UriLocation | LocalPathLocation
@@ -22,19 +22,13 @@ describe('test JBrowse1 hash implementation', () => {
22
22
  spy.mockImplementation(mockFetch as any)
23
23
  const hashMap = new HttpMap({
24
24
  url: rootTemplate,
25
- isElectron: false,
26
25
  })
27
- const headers = {
28
- 'Access-Control-Allow-Origin': '*',
29
- 'Content-Type': 'application/json',
30
- }
26
+
31
27
  await hashMap.getBucket('apple')
32
- expect(spy).toHaveBeenNthCalledWith(1, `${rootTemplate}/meta.json`, {
33
- headers,
34
- })
28
+
35
29
  // test compress and hash hex characters are set after initial search
36
- expect(hashMap.compress).toBe(0)
37
- expect(hashMap.hash_hex_characters).toBe(1)
30
+ expect(await hashMap.getHashHexCharacters()).toBe(1)
31
+ expect(await hashMap.getCompress()).toBe(0)
38
32
  })
39
33
  test('get bucket contents', async () => {
40
34
  function mockFetch(url: string): Promise<Response> {
@@ -59,18 +53,12 @@ describe('test JBrowse1 hash implementation', () => {
59
53
  spy.mockImplementation(mockFetch as any)
60
54
  const hashMap = new HttpMap({
61
55
  url: rootTemplate,
62
- isElectron: false,
63
56
  })
64
- const headers = {
65
- 'Access-Control-Allow-Origin': '*',
66
- 'Content-Type': 'application/json',
67
- }
57
+
68
58
  await hashMap.getBucket('apple')
69
- expect(spy).toHaveBeenNthCalledWith(1, `${rootTemplate}/meta.json`, {
70
- headers,
71
- })
72
- expect(spy).toHaveBeenLastCalledWith(`${rootTemplate}/0.json`, { headers })
59
+ expect(spy).toHaveBeenLastCalledWith(`${rootTemplate}/0.json`)
60
+
73
61
  await hashMap.getBucket('apple3')
74
- expect(spy).toHaveBeenLastCalledWith(`${rootTemplate}/f.json`, { headers })
62
+ expect(spy).toHaveBeenLastCalledWith(`${rootTemplate}/f.json`)
75
63
  })
76
64
  })
@@ -1,75 +1,38 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
1
  /*
3
2
  * Helper class allows reading names index generated in JBrowse1
4
3
  * Adapted from https://github.com/GMOD/jbrowse/blob/master/src/JBrowse/Store/Hash.js
5
4
  */
6
- import { crc32 } from './Crc32'
5
+ import crc32 from 'buffer-crc32'
7
6
 
8
7
  export default class HttpMap {
9
8
  url: string
10
9
 
11
- isElectron: boolean
12
-
13
- hash_hex_characters?: number
14
-
15
- compress?: number
16
-
17
- tracks?: string[]
18
-
19
- constructor(args: { url: string; isElectron: boolean }) {
10
+ constructor(args: { url: string }) {
20
11
  // make sure url has a trailing slash
21
12
  this.url = /\/$/.test(args.url) ? args.url : `${args.url}/`
22
-
23
- this.isElectron = args.isElectron
24
13
  }
25
14
 
26
15
  /**
27
16
  * loads meta.json file from names directory and reads number of hash_bits used
28
17
  */
29
18
  async readMeta() {
30
- try {
31
- const meta = await this.loadFile('meta.json')
32
- if (meta !== {}) {
33
- const { compress, track_names: tracks } = meta
34
- this.compress = compress
35
- const hashHexCharacters = Math.ceil(meta.hash_bits / 4)
36
- this.hash_hex_characters = hashHexCharacters
37
- this.tracks = tracks
38
- return { hashHexCharacters, compress, tracks }
39
- }
40
- throw new Error('Error parsing meta.json')
41
-
42
- // const { compress } = meta
43
- // this.compress = compress
44
- // const hashHexCharacters = Math.ceil(meta.hash_bits / 4)
45
- // this.hash_hex_characters = hashHexCharacters
46
- } catch (err) {
47
- // throw Error(err)
48
- console.warn(`Error: ${err}`)
49
- }
50
- return {}
19
+ const meta = await this.loadFile('meta.json')
20
+ const { compress, track_names: tracks } = meta
21
+ const hashHexCharacters = Math.ceil(meta.hash_bits / 4)
22
+ return { hashHexCharacters, compress, tracks }
51
23
  }
52
24
 
53
25
  async getHashHexCharacters() {
54
- if (this.hash_hex_characters) {
55
- return this.hash_hex_characters
56
- }
57
26
  const meta = await this.readMeta()
58
27
  return meta.hashHexCharacters
59
28
  }
60
29
 
61
30
  async getCompress() {
62
- if (this.compress) {
63
- return this.compress
64
- }
65
31
  const meta = await this.readMeta()
66
32
  return meta.compress
67
33
  }
68
34
 
69
35
  async getTrackNames() {
70
- if (this.tracks) {
71
- return this.tracks
72
- }
73
36
  const meta = await this.readMeta()
74
37
  return meta.tracks
75
38
  }
@@ -79,7 +42,7 @@ export default class HttpMap {
79
42
  * @param key - string
80
43
  */
81
44
  async get(key: string) {
82
- const bucket: Record<string, any> = await this.getBucket(key)
45
+ const bucket = await this.getBucket(key)
83
46
  return bucket[key]
84
47
  }
85
48
 
@@ -89,17 +52,8 @@ export default class HttpMap {
89
52
  */
90
53
  async getBucket(key: string) {
91
54
  const bucketIdent = this.hash(key)
92
- try {
93
- const hexToDirPath = await this.hexToDirPath(bucketIdent)
94
- const value = await this.loadFile(hexToDirPath)
95
- return value
96
- } catch (err) {
97
- if (this.isElectron || err.status === 404) {
98
- // 404 is expected if the name is not in the store
99
- return {}
100
- }
101
- }
102
- return {}
55
+ const hexToDirPath = await this.hexToDirPath(bucketIdent)
56
+ return this.loadFile(hexToDirPath)
103
57
  }
104
58
 
105
59
  /**
@@ -108,21 +62,11 @@ export default class HttpMap {
108
62
  * @param id - string
109
63
  */
110
64
  async loadFile(id: string) {
111
- const response = await fetch(`${this.url}${id}`, {
112
- headers: {
113
- 'Content-Type': 'application/json',
114
- 'Access-Control-Allow-Origin': '*',
115
- },
116
- })
117
- try {
118
- const data = await response.json()
119
- return data
120
- } catch (err) {
121
- // handle error
122
- // throw Error(err)
123
- console.warn(`Error: ${err}`)
65
+ const response = await fetch(`${this.url}${id}`)
66
+ if (!response.ok) {
67
+ throw new Error(`HTTP ${response.status} ${response.statusText}`)
124
68
  }
125
- return {}
69
+ return response.json()
126
70
  }
127
71
 
128
72
  /**
@@ -147,12 +91,10 @@ export default class HttpMap {
147
91
  return ''
148
92
  }
149
93
 
150
- /**
151
- * Returns crc32 hash given a string.
152
- * (Note: this is using JBrowse1 implementation of crc32.)
153
- * @param data - string
154
- */
155
94
  hash(data: string) {
156
- return crc32(data).toString(16).toLowerCase().replace('-', 'n')
95
+ return crc32(Buffer.from(data))
96
+ .toString('hex')
97
+ .toLowerCase()
98
+ .replace('-', 'n')
157
99
  }
158
100
  }