@jbrowse/plugin-bed 4.3.0 → 5.0.0-beta.10

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 (64) hide show
  1. package/esm/BedAdapter/BedAdapter.d.ts +5 -22
  2. package/esm/BedAdapter/BedAdapter.js +29 -93
  3. package/esm/BedAdapter/configSchema.d.ts +59 -32
  4. package/esm/BedAdapter/configSchema.js +64 -14
  5. package/esm/BedAdapter/index.js +4 -2
  6. package/esm/BedGraphAdapter/BedGraphAdapter.d.ts +5 -12
  7. package/esm/BedGraphAdapter/BedGraphAdapter.js +33 -89
  8. package/esm/BedGraphAdapter/configSchema.d.ts +35 -11
  9. package/esm/BedGraphAdapter/configSchema.js +43 -13
  10. package/esm/BedGraphAdapter/index.js +3 -2
  11. package/esm/BedGraphTabixAdapter/BedGraphTabixAdapter.d.ts +5 -5
  12. package/esm/BedGraphTabixAdapter/BedGraphTabixAdapter.js +65 -57
  13. package/esm/BedGraphTabixAdapter/configSchema.d.ts +46 -22
  14. package/esm/BedGraphTabixAdapter/configSchema.js +50 -34
  15. package/esm/BedGraphTabixAdapter/index.js +3 -2
  16. package/esm/BedTabixAdapter/BedTabixAdapter.d.ts +34 -38
  17. package/esm/BedTabixAdapter/BedTabixAdapter.js +82 -72
  18. package/esm/BedTabixAdapter/configSchema.d.ts +55 -31
  19. package/esm/BedTabixAdapter/configSchema.js +58 -35
  20. package/esm/BedTabixAdapter/index.js +4 -2
  21. package/esm/BedpeAdapter/BedpeAdapter.d.ts +6 -13
  22. package/esm/BedpeAdapter/BedpeAdapter.js +26 -74
  23. package/esm/BedpeAdapter/configSchema.d.ts +31 -12
  24. package/esm/BedpeAdapter/configSchema.js +37 -13
  25. package/esm/BedpeAdapter/index.js +4 -2
  26. package/esm/BedpeAdapter/util.js +25 -25
  27. package/esm/BigBedAdapter/BigBedAdapter.d.ts +8 -7
  28. package/esm/BigBedAdapter/BigBedAdapter.js +99 -107
  29. package/esm/BigBedAdapter/configSchema.d.ts +38 -16
  30. package/esm/BigBedAdapter/configSchema.js +46 -13
  31. package/esm/BigBedAdapter/index.js +3 -2
  32. package/esm/BigBedTextSearchAdapter/BigBedTextSearchAdapter.d.ts +27 -0
  33. package/esm/BigBedTextSearchAdapter/BigBedTextSearchAdapter.js +128 -0
  34. package/esm/BigBedTextSearchAdapter/configSchema.d.ts +51 -0
  35. package/esm/BigBedTextSearchAdapter/configSchema.js +57 -0
  36. package/esm/BigBedTextSearchAdapter/index.d.ts +2 -0
  37. package/esm/BigBedTextSearchAdapter/index.js +11 -0
  38. package/esm/StarFusionAdapter/StarFusionAdapter.d.ts +14 -0
  39. package/esm/StarFusionAdapter/StarFusionAdapter.js +66 -0
  40. package/esm/StarFusionAdapter/configSchema.d.ts +30 -0
  41. package/esm/StarFusionAdapter/configSchema.js +43 -0
  42. package/esm/StarFusionAdapter/index.d.ts +2 -0
  43. package/esm/StarFusionAdapter/index.js +12 -0
  44. package/esm/adapterUtil.d.ts +5 -0
  45. package/esm/adapterUtil.js +43 -0
  46. package/esm/bedGraphUtil.d.ts +11 -0
  47. package/esm/bedGraphUtil.js +20 -0
  48. package/esm/copyExcept.d.ts +1 -0
  49. package/esm/copyExcept.js +11 -0
  50. package/esm/generateBedMethylFeature.d.ts +1 -1
  51. package/esm/generateBedMethylFeature.js +24 -6
  52. package/esm/generateRastairMethylFeature.d.ts +28 -0
  53. package/esm/generateRastairMethylFeature.js +38 -0
  54. package/esm/generateRepeatMaskerFeature.d.ts +17 -51
  55. package/esm/generateRepeatMaskerFeature.js +27 -37
  56. package/esm/generateUcscTranscript.d.ts +15 -7
  57. package/esm/generateUcscTranscript.js +106 -29
  58. package/esm/index.d.ts +2 -0
  59. package/esm/index.js +12 -8
  60. package/esm/util.d.ts +32 -27
  61. package/esm/util.js +139 -98
  62. package/package.json +10 -13
  63. package/esm/GuessAdapter/index.d.ts +0 -2
  64. package/esm/GuessAdapter/index.js +0 -71
@@ -1,104 +1,114 @@
1
- import BED from '@gmod/bed';
2
1
  import { TabixIndexedFile } from '@gmod/tabix';
3
- import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter';
4
- import { SimpleFeature, updateStatus } from '@jbrowse/core/util';
5
- import { openLocation } from '@jbrowse/core/util/io';
2
+ import { readConfObject } from '@jbrowse/core/configuration';
3
+ import { BaseFeatureDataAdapter, cachedSetup, } from '@jbrowse/core/data_adapters/BaseAdapter';
4
+ import { SimpleFeature, downloadStatus } from '@jbrowse/core/util';
5
+ import { checkAbortSignal } from '@jbrowse/core/util/aborting';
6
+ import { sharedBgzfWorkerPool } from '@jbrowse/core/util/bgzfWorkerPool';
7
+ import { decompressedBytesBudget } from '@jbrowse/core/util/cacheBudgets';
8
+ import { openLocation, openTabixIndexFilehandle } from '@jbrowse/core/util/io';
6
9
  import { ObservableCreate } from '@jbrowse/core/util/rxjs';
7
- import { checkStopToken } from '@jbrowse/core/util/stopToken';
8
- import { featureData } from "../util.js";
10
+ import { readTabixHeaderLines } from '@jbrowse/core/util/tabix';
11
+ import { featureData, makeParser, parseNamesFromHeader } from '../util.js';
9
12
  export default class BedTabixAdapter extends BaseFeatureDataAdapter {
10
- parser;
13
+ // the parser needs the column names, which come from the file's header, so
14
+ // it cannot be built in the constructor
15
+ getParser = cachedSetup({
16
+ setup: async () => makeParser({
17
+ autoSql: readConfObject(this.config, 'autoSql'),
18
+ columnNames: await this.getNames(),
19
+ }),
20
+ });
21
+ bedGzLoc;
11
22
  bed;
12
- columnNames;
13
- scoreColumn;
14
23
  static capabilities = ['getFeatures', 'getRefNames'];
15
- setupP;
24
+ // `label` because the index metadata download narrates nothing itself; the
25
+ // helper shows it only while the first attempt is in flight, so pan/zoom
26
+ // re-entry (every getFeatures awaits it) doesn't re-flash "Downloading index"
27
+ getMetadata = cachedSetup({
28
+ label: 'Downloading index',
29
+ setup: () => this.bed.getMetadata(),
30
+ });
31
+ // Memoized: getFeatures needs the names on every query, and reading them goes
32
+ // to the file's leading blocks — a fetch and a decompress that was being
33
+ // repeated on every pan and zoom. Resolves undefined when the file declares
34
+ // no column names — parseNamesFromHeader's answer for a header it can't read
35
+ // names out of.
36
+ getNames = cachedSetup({ setup: () => this.readNames() });
16
37
  constructor(config, getSubAdapter, pluginManager) {
17
38
  super(config, getSubAdapter, pluginManager);
18
- const bedGzLoc = this.getConf('bedGzLocation');
19
- const type = this.getConf(['index', 'indexType']);
20
- const loc = this.getConf(['index', 'location']);
21
- const autoSql = this.getConf('autoSql');
39
+ this.bedGzLoc = readConfObject(this.config, 'bedGzLocation');
40
+ const type = readConfObject(this.config, ['index', 'indexType']);
41
+ const loc = readConfObject(this.config, ['index', 'location']);
22
42
  const pm = this.pluginManager;
23
43
  this.bed = new TabixIndexedFile({
24
- filehandle: openLocation(bedGzLoc, pm),
25
- csiFilehandle: type === 'CSI' ? openLocation(loc, pm) : undefined,
26
- tbiFilehandle: type !== 'CSI' ? openLocation(loc, pm) : undefined,
27
- chunkCacheSize: 50 * 2 ** 20,
44
+ filehandle: openLocation(this.bedGzLoc, pm),
45
+ ...openTabixIndexFilehandle(loc, type, pm),
46
+ chunkCacheBudget: decompressedBytesBudget,
47
+ bgzfWorkerPool: sharedBgzfWorkerPool(),
28
48
  });
29
- this.columnNames = this.getConf('columnNames');
30
- this.scoreColumn = this.getConf('scoreColumn');
31
- this.parser = new BED({ autoSql });
32
49
  }
33
50
  async getRefNames(opts = {}) {
34
- return this.bed.getReferenceSequenceNames(opts);
51
+ return downloadStatus('Downloading index', opts.statusCallback, onProgress => this.bed.getReferenceSequenceNames({ ...opts, onProgress }));
35
52
  }
36
53
  async getHeader(opts) {
37
54
  return this.bed.getHeader(opts);
38
55
  }
39
- async getMetadataPre2(_opts) {
40
- if (!this.setupP) {
41
- this.setupP = this.getMetadataPre().catch((e) => {
42
- this.setupP = undefined;
43
- throw e;
44
- });
45
- }
46
- return this.setupP;
47
- }
48
- async getMetadataPre() {
49
- const meta = await this.bed.getMetadata();
50
- return { meta };
51
- }
52
- async getMetadata(opts) {
53
- const { statusCallback = () => { } } = opts || {};
54
- return updateStatus('Downloading index', statusCallback, () => this.getMetadataPre2(opts));
56
+ /**
57
+ * Estimate compressed bytes for regions straight from the tabix index — no
58
+ * feature download. Lets wrapping adapters (e.g. MafTabix) byte-budget a
59
+ * fetch before pulling the (potentially huge) per-line payload.
60
+ */
61
+ async getRegionByteSize(regions, opts) {
62
+ return this.bed.bytesForRegions(regions, opts);
55
63
  }
56
- async getNames() {
57
- if (this.columnNames.length) {
58
- return this.columnNames;
64
+ async readNames() {
65
+ const columnNames = readConfObject(this.config, 'columnNames');
66
+ if (columnNames.length) {
67
+ return columnNames;
59
68
  }
60
- const header = await this.getHeader();
61
- const defs = header.split(/\n|\r\n|\r/).filter(f => !!f);
62
- const defline = defs.at(-1);
63
- return defline?.includes('\t')
64
- ? defline
65
- .slice(1)
66
- .split('\t')
67
- .map(f => f.trim())
68
- : undefined;
69
+ // readTabixHeaderLines covers both ways a tabix file keeps a header: a
70
+ // `#`-commented block, which getHeader() returns, and a plain row skipped
71
+ // via `tabix -S N`, which it does not.
72
+ return parseNamesFromHeader((await readTabixHeaderLines(this.bed)).join('\n'));
69
73
  }
70
74
  getFeatures(query, opts) {
71
- const { stopToken, statusCallback = () => { } } = opts || {};
75
+ const { signal, statusCallback } = opts ?? {};
72
76
  return ObservableCreate(async (observer) => {
73
- const { meta } = await this.getMetadata();
74
- const { columnNumbers } = meta;
75
- const colRef = columnNumbers.ref - 1;
76
- const colStart = columnNumbers.start - 1;
77
- const colEnd = columnNumbers.end - 1;
77
+ // warms the index under its own status label — getLines would otherwise
78
+ // download it under "Downloading features"
79
+ await this.getMetadata(opts);
78
80
  const names = await this.getNames();
79
- const disableGeneHeuristic = this.getConf('disableGeneHeuristic');
80
- let start = performance.now();
81
- checkStopToken(stopToken);
82
- await updateStatus('Downloading features', statusCallback, () => this.bed.getLines(query.refName, query.start, query.end, {
83
- lineCallback: (line, fileOffset) => {
84
- if (performance.now() - start > 500) {
85
- checkStopToken(stopToken);
86
- start = performance.now();
87
- }
81
+ const parser = await this.getParser();
82
+ const scoreColumn = readConfObject(this.config, 'scoreColumn');
83
+ const disableGeneHeuristic = readConfObject(this.config, 'disableGeneHeuristic');
84
+ checkAbortSignal(signal);
85
+ await downloadStatus('Downloading features', statusCallback, onProgress =>
86
+ // start/end come from @gmod/tabix rather than being re-derived from
87
+ // the line: it located the coordinate columns to find these lines at
88
+ // all, and already applied the index's coordinate offset (-1 for a
89
+ // 1-based-closed preset) and its no-end-column convention (a single
90
+ // position becomes start..start+1). refName is likewise the query's
91
+ // — getLines only calls back for lines whose ref column matches it.
92
+ this.bed.getLines(query.refName, query.start, query.end, {
93
+ lineCallback: (line, fileOffset, start, end) => {
94
+ checkAbortSignal(signal);
95
+ const splitLine = line.split('\t');
88
96
  observer.next(new SimpleFeature(featureData({
89
- line,
90
- colRef,
91
- colStart,
92
- colEnd,
93
- scoreColumn: this.scoreColumn,
94
- parser: this.parser,
97
+ splitLine,
98
+ refName: query.refName,
99
+ start,
100
+ end,
101
+ scoreColumn,
102
+ parser,
95
103
  uniqueId: `${this.id}-${fileOffset}`,
96
104
  names,
97
105
  disableGeneHeuristic,
98
106
  })));
99
107
  },
108
+ onProgress,
109
+ signal,
100
110
  }));
101
111
  observer.complete();
102
- }, stopToken);
112
+ }, signal);
103
113
  }
104
114
  }
@@ -1,44 +1,68 @@
1
+ import type { Instance } from '@jbrowse/mobx-state-tree';
2
+ export declare function normalizeSnapshot(snap: Record<string, unknown>): Record<string, unknown>;
3
+ /**
4
+ * #config BedTabixAdapter
5
+ * #trackType FeatureTrack
6
+ * #fileFormat feature | BED (tabix)
7
+ *
8
+ * #example
9
+ * The `uri` shorthand auto-resolves the `.tbi` index; add `csi: true` for a
10
+ * `.csi` index instead:
11
+ * ```js
12
+ * {
13
+ * type: 'BedTabixAdapter',
14
+ * uri: 'https://example.com/features.bed.gz',
15
+ * }
16
+ * ```
17
+ */
1
18
  declare const BedTabixAdapter: import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{
2
- bedGzLocation: {
3
- type: string;
4
- defaultValue: {
5
- uri: string;
6
- locationType: string;
7
- };
19
+ readonly densityAdapter: {
20
+ type: "maybeFrozen";
21
+ };
22
+ type: {
23
+ type: "string";
24
+ } & {
25
+ defaultValue: string;
26
+ };
27
+ readonly bedGzLocation: {
28
+ type: "fileLocation";
29
+ } & {
30
+ defaultValue: unknown;
8
31
  };
9
- index: import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{
10
- indexType: {
11
- model: import("@jbrowse/mobx-state-tree").ISimpleType<"TBI" | "CSI">;
12
- type: string;
32
+ readonly index: import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{
33
+ readonly indexType: {
34
+ type: "stringEnum";
35
+ } & {
36
+ model: import("@jbrowse/mobx-state-tree").ISimpleType<"CSI" | "TBI">;
37
+ } & {
13
38
  defaultValue: string;
14
39
  };
15
- location: {
16
- type: string;
17
- defaultValue: {
18
- uri: string;
19
- locationType: string;
20
- };
40
+ readonly location: {
41
+ type: "fileLocation";
42
+ } & {
43
+ defaultValue: unknown;
21
44
  };
22
- }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined>>;
23
- columnNames: {
24
- type: string;
25
- description: string;
26
- defaultValue: never[];
45
+ }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined, undefined, import("@jbrowse/core/configuration").ConfigurationSchemaRequirement<Partial<Record<string, string[]>>, string>, any>>;
46
+ readonly columnNames: {
47
+ type: "stringArray";
48
+ } & {
49
+ defaultValue: unknown;
27
50
  };
28
- scoreColumn: {
29
- type: string;
30
- description: string;
51
+ readonly scoreColumn: {
52
+ type: "string";
53
+ } & {
31
54
  defaultValue: string;
32
55
  };
33
- autoSql: {
34
- type: string;
35
- description: string;
56
+ readonly autoSql: {
57
+ type: "string";
58
+ } & {
36
59
  defaultValue: string;
37
60
  };
38
- disableGeneHeuristic: {
39
- type: string;
40
- description: string;
61
+ readonly disableGeneHeuristic: {
62
+ type: "boolean";
63
+ } & {
41
64
  defaultValue: boolean;
42
65
  };
43
- }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined>>;
66
+ }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined, true, import("@jbrowse/core/configuration").ConfigurationSchemaRequirement<Partial<Record<string, string[]>>, string>, any>>;
67
+ export type BedTabixAdapterConfig = Instance<typeof BedTabixAdapter>;
44
68
  export default BedTabixAdapter;
@@ -1,7 +1,29 @@
1
- import { ConfigurationSchema } from '@jbrowse/core/configuration';
2
- import { types } from '@jbrowse/mobx-state-tree';
3
- function x() { }
1
+ import { ConfigurationSchema, expandTabixShorthand, tabixIndexSchema, } from '@jbrowse/core/configuration';
2
+ import { densityAdapterConfigSchemaFields } from '@jbrowse/core/data_adapters/BaseAdapter';
3
+ export function normalizeSnapshot(snap) {
4
+ return expandTabixShorthand(snap, 'bedGzLocation');
5
+ }
6
+ /**
7
+ * #config BedTabixAdapter
8
+ * #trackType FeatureTrack
9
+ * #fileFormat feature | BED (tabix)
10
+ *
11
+ * #example
12
+ * The `uri` shorthand auto-resolves the `.tbi` index; add `csi: true` for a
13
+ * `.csi` index instead:
14
+ * ```js
15
+ * {
16
+ * type: 'BedTabixAdapter',
17
+ * uri: 'https://example.com/features.bed.gz',
18
+ * }
19
+ * ```
20
+ */
4
21
  const BedTabixAdapter = ConfigurationSchema('BedTabixAdapter', {
22
+ /**
23
+ * #slot
24
+ * location of the bgzip-compressed BED, sorted by position. Must be bgzip
25
+ * rather than plain gzip, which tabix cannot index.
26
+ */
5
27
  bedGzLocation: {
6
28
  type: 'fileLocation',
7
29
  defaultValue: {
@@ -9,58 +31,59 @@ const BedTabixAdapter = ConfigurationSchema('BedTabixAdapter', {
9
31
  locationType: 'UriLocation',
10
32
  },
11
33
  },
12
- index: ConfigurationSchema('TabixIndex', {
13
- indexType: {
14
- model: types.enumeration('IndexType', ['TBI', 'CSI']),
15
- type: 'stringEnum',
16
- defaultValue: 'TBI',
17
- },
18
- location: {
19
- type: 'fileLocation',
20
- defaultValue: {
21
- uri: '/path/to/my.bed.gz.tbi',
22
- locationType: 'UriLocation',
23
- },
24
- },
25
- }),
34
+ /**
35
+ * #slot
36
+ * where the tabix index is and which kind it is. The `uri` shorthand derives
37
+ * both, so a config using it states neither.
38
+ */
39
+ index: tabixIndexSchema(),
40
+ /**
41
+ * #slot
42
+ */
26
43
  columnNames: {
27
44
  type: 'stringArray',
28
- description: 'List of column names',
45
+ description: "List of column names. A column named like a standard BED column is parsed as that column's type (chromStart numeric, blockSizes a numeric list); any other column is text",
29
46
  defaultValue: [],
30
47
  },
48
+ /**
49
+ * #slot
50
+ */
31
51
  scoreColumn: {
32
52
  type: 'string',
33
53
  description: 'The column to use as a "score" attribute',
34
54
  defaultValue: '',
35
55
  },
56
+ /**
57
+ * #slot
58
+ */
36
59
  autoSql: {
37
60
  type: 'string',
38
61
  description: 'The autoSql definition for the data fields in the file',
39
62
  defaultValue: '',
40
63
  },
64
+ /**
65
+ * #slot
66
+ */
41
67
  disableGeneHeuristic: {
42
68
  type: 'boolean',
43
69
  description: 'Disable the heuristic that auto-detects BED12 features as gene/transcript structures. Useful for files that have BED12-like structure but are not genes (e.g. tandem duplications)',
44
70
  defaultValue: false,
45
71
  },
72
+ ...densityAdapterConfigSchemaFields,
46
73
  }, {
47
74
  explicitlyTyped: true,
48
- preProcessSnapshot: snap => {
49
- return snap.uri
50
- ? {
51
- ...snap,
52
- bedGzLocation: {
53
- uri: snap.uri,
54
- baseUri: snap.baseUri,
55
- },
56
- index: {
57
- location: {
58
- uri: `${snap.uri}.tbi`,
59
- baseUri: snap.baseUri,
60
- },
61
- },
62
- }
63
- : snap;
64
- },
75
+ /**
76
+ * #preProcessSnapshot
77
+ *
78
+ *
79
+ * preprocessor to allow minimal config, assumes yourfile.bed.gz.tbi:
80
+ * ```json
81
+ * {
82
+ * "type": "BedTabixAdapter",
83
+ * "uri": "yourfile.bed.gz"
84
+ * }
85
+ * ```
86
+ */
87
+ preProcessSnapshot: normalizeSnapshot,
65
88
  });
66
89
  export default BedTabixAdapter;
@@ -1,10 +1,12 @@
1
1
  import AdapterType from '@jbrowse/core/pluggableElementTypes/AdapterType';
2
- import configSchema from "./configSchema.js";
2
+ import configSchema, { normalizeSnapshot } from './configSchema.js';
3
3
  export default function BedTabixAdapterF(pluginManager) {
4
4
  pluginManager.addAdapterType(() => new AdapterType({
5
5
  name: 'BedTabixAdapter',
6
6
  displayName: 'BED tabix adapter',
7
7
  configSchema,
8
- getAdapterClass: () => import("./BedTabixAdapter.js").then(r => r.default),
8
+ getAdapterClass: () => import('./BedTabixAdapter.js').then(r => r.default),
9
+ locationKey: 'bedGzLocation',
10
+ normalizeSnapshot,
9
11
  }));
10
12
  }
@@ -1,22 +1,15 @@
1
1
  import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter';
2
- import { IntervalTree } from '@jbrowse/core/util';
2
+ import type { BedpeAdapterConfig } from './configSchema.ts';
3
3
  import type { BaseOptions } from '@jbrowse/core/data_adapters/BaseAdapter';
4
- import type { Feature, Region } from '@jbrowse/core/util';
5
- export default class BedpeAdapter extends BaseFeatureDataAdapter {
6
- protected bedpeFeatures?: Promise<{
7
- header: string;
8
- feats1: Record<string, string[]>;
9
- feats2: Record<string, string[]>;
10
- columnNames: string[];
11
- }>;
12
- protected intervalTrees: Record<string, Promise<IntervalTree<Feature> | undefined> | undefined>;
4
+ import type { Region } from '@jbrowse/core/util';
5
+ export default class BedpeAdapter extends BaseFeatureDataAdapter<BedpeAdapterConfig> {
6
+ private loadData;
13
7
  static capabilities: string[];
14
8
  private loadDataP;
15
- private loadData;
16
9
  getRefNames(opts?: BaseOptions): Promise<string[]>;
17
10
  getHeader(opts?: BaseOptions): Promise<string>;
18
11
  getNames(): Promise<string[] | undefined>;
19
12
  private loadFeatureTreeP;
20
- private loadFeatureTree;
21
- getFeatures(query: Region, opts?: BaseOptions): import("rxjs").Observable<Feature>;
13
+ private treeFeatures;
14
+ getFeatures(query: Region, opts?: BaseOptions): import("rxjs").Observable<import("@jbrowse/core/util").Feature>;
22
15
  }
@@ -1,54 +1,38 @@
1
- import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter';
2
- import { IntervalTree, fetchAndMaybeUnzipText } from '@jbrowse/core/util';
1
+ import { BaseFeatureDataAdapter, cachedSetup, } from '@jbrowse/core/data_adapters/BaseAdapter';
2
+ import { fetchAndMaybeUnzip } from '@jbrowse/core/util';
3
3
  import { openLocation } from '@jbrowse/core/util/io';
4
- import { ObservableCreate } from '@jbrowse/core/util/rxjs';
5
- import { featureData } from "./util.js";
4
+ import { parseLineByLine } from '@jbrowse/core/util/parseLineByLine';
5
+ import { buildPairedIntervalTree, intervalTreeFeatures, } from '../adapterUtil.js';
6
+ import { resolveColumnNames } from '../util.js';
7
+ import { featureData } from './util.js';
6
8
  export default class BedpeAdapter extends BaseFeatureDataAdapter {
7
- bedpeFeatures;
8
- intervalTrees = {};
9
+ // No `label`: `fetchAndMaybeUnzip` narrates the download from inside.
10
+ loadData = cachedSetup({ setup: opts => this.loadDataP(opts) });
9
11
  static capabilities = ['getFeatures', 'getRefNames'];
10
12
  async loadDataP(opts) {
11
- const data = await fetchAndMaybeUnzipText(openLocation(this.getConf('bedpeLocation'), this.pluginManager), opts);
12
- const lines = data.split(/\n|\r\n|\r/).filter(f => !!f);
13
+ const buffer = await fetchAndMaybeUnzip(openLocation(this.getConf('bedpeLocation'), this.pluginManager), opts);
13
14
  const headerLines = [];
14
- let i = 0;
15
- for (; i < lines.length && lines[i].startsWith('#'); i++) {
16
- headerLines.push(lines[i]);
17
- }
18
- const header = headerLines.join('\n');
19
15
  const feats1 = {};
20
16
  const feats2 = {};
21
- for (; i < lines.length; i++) {
22
- const line = lines[i];
23
- const cols = line.split('\t');
24
- const r1 = cols[0];
25
- const r2 = cols[3];
26
- if (!feats1[r1]) {
27
- feats1[r1] = [];
17
+ parseLineByLine(buffer, line => {
18
+ if (line.startsWith('#')) {
19
+ headerLines.push(line);
28
20
  }
29
- if (!feats2[r2]) {
30
- feats2[r2] = [];
21
+ else if (!line.startsWith('track') && !line.startsWith('browser')) {
22
+ const cols = line.split('\t');
23
+ const r1 = cols[0];
24
+ const r2 = cols[3];
25
+ (feats1[r1] ??= []).push(line);
26
+ (feats2[r2] ??= []).push(line);
31
27
  }
32
- feats1[r1].push(line);
33
- feats2[r2].push(line);
34
- }
35
- const columnNames = this.getConf('columnNames');
28
+ return true;
29
+ }, opts?.statusCallback);
36
30
  return {
37
- header,
31
+ header: headerLines.join('\n'),
38
32
  feats1,
39
33
  feats2,
40
- columnNames,
41
34
  };
42
35
  }
43
- async loadData(opts = {}) {
44
- if (!this.bedpeFeatures) {
45
- this.bedpeFeatures = this.loadDataP(opts).catch((e) => {
46
- this.bedpeFeatures = undefined;
47
- throw e;
48
- });
49
- }
50
- return this.bedpeFeatures;
51
- }
52
36
  async getRefNames(opts = {}) {
53
37
  const { feats1, feats2 } = await this.loadData(opts);
54
38
  return [...new Set([...Object.keys(feats1), ...Object.keys(feats2)])];
@@ -58,47 +42,15 @@ export default class BedpeAdapter extends BaseFeatureDataAdapter {
58
42
  return header;
59
43
  }
60
44
  async getNames() {
61
- const { header, columnNames } = await this.loadData();
62
- if (columnNames.length) {
63
- return columnNames;
64
- }
65
- const defs = header.split(/\n|\r\n|\r/).filter(f => !!f);
66
- const defline = defs.at(-1);
67
- return defline?.includes('\t')
68
- ? defline
69
- .slice(1)
70
- .split('\t')
71
- .map(field => field.trim())
72
- : undefined;
45
+ return resolveColumnNames(this.getConf('columnNames'), async () => (await this.loadData()).header);
73
46
  }
74
47
  async loadFeatureTreeP(refName) {
75
48
  const { feats1, feats2 } = await this.loadData();
76
49
  const names = await this.getNames();
77
- const intervalTree = new IntervalTree();
78
- const ret1 = feats1[refName]?.map((f, i) => featureData(f, `${this.id}-${refName}-${i}-r1`, false, names)) ?? [];
79
- const ret2 = feats2[refName]?.map((f, i) => featureData(f, `${this.id}-${refName}-${i}-r2`, true, names)) ?? [];
80
- for (const obj of [...ret1, ...ret2]) {
81
- intervalTree.insert([obj.get('start'), obj.get('end')], obj);
82
- }
83
- return intervalTree;
84
- }
85
- async loadFeatureTree(refName) {
86
- if (!this.intervalTrees[refName]) {
87
- this.intervalTrees[refName] = this.loadFeatureTreeP(refName).catch((e) => {
88
- this.intervalTrees[refName] = undefined;
89
- throw e;
90
- });
91
- }
92
- return this.intervalTrees[refName];
50
+ return buildPairedIntervalTree(feats1, feats2, refName, this.id, (line, uniqueId, flip) => featureData(line, uniqueId, flip, names));
93
51
  }
94
- getFeatures(query, opts = {}) {
95
- return ObservableCreate(async (observer) => {
96
- const { start, end, refName } = query;
97
- const intervalTree = await this.loadFeatureTree(refName);
98
- for (const f of intervalTree?.search([start, end]) || []) {
99
- observer.next(f);
100
- }
101
- observer.complete();
102
- }, opts.stopToken);
52
+ treeFeatures = intervalTreeFeatures(opts => this.loadData(opts), refName => this.loadFeatureTreeP(refName));
53
+ getFeatures(query, opts) {
54
+ return this.treeFeatures(query, opts);
103
55
  }
104
56
  }
@@ -1,16 +1,35 @@
1
+ import type { Instance } from '@jbrowse/mobx-state-tree';
2
+ export declare function normalizeSnapshot(snap: Record<string, unknown>): Record<string, unknown>;
3
+ /**
4
+ * #config BedpeAdapter
5
+ * #trackType VariantTrack
6
+ * #fileFormat variants | BEDPE | Paired/breakend records, e.g. SV calls or Hi-C loops
7
+ * intended for SVs in a single assembly
8
+ *
9
+ * #example
10
+ * ```js
11
+ * {
12
+ * type: 'BedpeAdapter',
13
+ * uri: 'https://example.com/sv.bedpe',
14
+ * }
15
+ * ```
16
+ */
1
17
  declare const BedpeAdapter: import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{
2
- bedpeLocation: {
3
- type: string;
4
- description: string;
5
- defaultValue: {
6
- uri: string;
7
- locationType: string;
8
- };
18
+ type: {
19
+ type: "string";
20
+ } & {
21
+ defaultValue: string;
9
22
  };
10
- columnNames: {
11
- type: string;
12
- description: string;
13
- defaultValue: never[];
23
+ readonly bedpeLocation: {
24
+ type: "fileLocation";
25
+ } & {
26
+ defaultValue: unknown;
14
27
  };
15
- }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined>>;
28
+ readonly columnNames: {
29
+ type: "stringArray";
30
+ } & {
31
+ defaultValue: unknown;
32
+ };
33
+ }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined, true, import("@jbrowse/core/configuration").ConfigurationSchemaRequirement<Partial<Record<string, string[]>>, string>, any>>;
34
+ export type BedpeAdapterConfig = Instance<typeof BedpeAdapter>;
16
35
  export default BedpeAdapter;