@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,36 +1,19 @@
1
- import BED from '@gmod/bed';
2
1
  import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter';
3
- import { IntervalTree } from '@jbrowse/core/util';
2
+ import type { BedAdapterConfig } from './configSchema.ts';
4
3
  import type { BaseOptions } from '@jbrowse/core/data_adapters/BaseAdapter';
5
4
  import type { Feature, Region } from '@jbrowse/core/util';
6
- export default class BedAdapter extends BaseFeatureDataAdapter {
7
- protected bedFeatures?: Promise<{
5
+ export default class BedAdapter extends BaseFeatureDataAdapter<BedAdapterConfig> {
6
+ loadData: (opts?: BaseOptions) => Promise<{
8
7
  header: string;
9
8
  features: Record<string, string[]>;
10
- parser: BED;
11
- columnNames: string[];
12
- scoreColumn: string;
13
- colRef: number;
14
- colStart: number;
15
- colEnd: number;
16
9
  }>;
17
- protected intervalTrees: Record<string, Promise<IntervalTree<Feature> | undefined> | undefined>;
10
+ private getParser;
18
11
  static capabilities: string[];
19
12
  private loadDataP;
20
- loadData(opts?: BaseOptions): Promise<{
21
- header: string;
22
- features: Record<string, string[]>;
23
- parser: BED;
24
- columnNames: string[];
25
- scoreColumn: string;
26
- colRef: number;
27
- colStart: number;
28
- colEnd: number;
29
- }>;
30
13
  getRefNames(opts?: BaseOptions): Promise<string[]>;
31
14
  getHeader(opts?: BaseOptions): Promise<string>;
32
15
  getNames(): Promise<string[] | undefined>;
33
16
  private loadFeatureIntervalTreeHelper;
34
- loadFeatureIntervalTree(refName: string): Promise<IntervalTree<Feature> | undefined>;
17
+ private treeFeatures;
35
18
  getFeatures(query: Region, opts?: BaseOptions): import("rxjs").Observable<Feature>;
36
19
  }
@@ -1,60 +1,23 @@
1
- import BED from '@gmod/bed';
2
- import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter';
1
+ import { BaseFeatureDataAdapter, cachedSetup, } from '@jbrowse/core/data_adapters/BaseAdapter';
3
2
  import { IntervalTree, SimpleFeature, fetchAndMaybeUnzip, } from '@jbrowse/core/util';
4
3
  import { openLocation } from '@jbrowse/core/util/io';
5
- import { parseLineByLine } from '@jbrowse/core/util/parseLineByLine';
6
- import { ObservableCreate } from '@jbrowse/core/util/rxjs';
7
- import { featureData } from "../util.js";
4
+ import { intervalTreeFeatures } from '../adapterUtil.js';
5
+ import { bedFeatureLocus, bucketBedLines, featureData, makeParser, resolveColumnNames, } from '../util.js';
8
6
  export default class BedAdapter extends BaseFeatureDataAdapter {
9
- bedFeatures;
10
- intervalTrees = {};
7
+ // No `label`: `fetchAndMaybeUnzip` narrates the download from inside.
8
+ loadData = cachedSetup({ setup: opts => this.loadDataP(opts) });
9
+ // the parser needs the column names, which come from the header, so it can
10
+ // only be built once the file is loaded
11
+ getParser = cachedSetup({
12
+ setup: async () => makeParser({
13
+ autoSql: this.getConf('autoSql'),
14
+ columnNames: await this.getNames(),
15
+ }),
16
+ });
11
17
  static capabilities = ['getFeatures', 'getRefNames'];
12
18
  async loadDataP(opts) {
13
- const bedLoc = this.getConf('bedLocation');
14
- const buffer = await fetchAndMaybeUnzip(openLocation(bedLoc, this.pluginManager), opts);
15
- const headerLines = [];
16
- const features = {};
17
- parseLineByLine(buffer, line => {
18
- if (line.startsWith('#')) {
19
- headerLines.push(line);
20
- }
21
- else {
22
- const tab = line.indexOf('\t');
23
- const refName = line.slice(0, tab);
24
- if (!features[refName]) {
25
- features[refName] = [];
26
- }
27
- features[refName].push(line);
28
- }
29
- return true;
30
- }, opts?.statusCallback);
31
- const header = headerLines.join('\n');
32
- const autoSql = this.getConf('autoSql');
33
- const parser = new BED({ autoSql });
34
- const columnNames = this.getConf('columnNames');
35
- const scoreColumn = this.getConf('scoreColumn');
36
- const colRef = this.getConf('colRef');
37
- const colStart = this.getConf('colStart');
38
- const colEnd = this.getConf('colEnd');
39
- return {
40
- header,
41
- features,
42
- parser,
43
- columnNames,
44
- scoreColumn,
45
- colRef,
46
- colStart,
47
- colEnd,
48
- };
49
- }
50
- async loadData(opts = {}) {
51
- if (!this.bedFeatures) {
52
- this.bedFeatures = this.loadDataP(opts).catch((e) => {
53
- this.bedFeatures = undefined;
54
- throw e;
55
- });
56
- }
57
- return this.bedFeatures;
19
+ const buffer = await fetchAndMaybeUnzip(openLocation(this.getConf('bedLocation'), this.pluginManager), opts);
20
+ return bucketBedLines(buffer, opts?.statusCallback);
58
21
  }
59
22
  async getRefNames(opts = {}) {
60
23
  const { features } = await this.loadData(opts);
@@ -65,39 +28,30 @@ export default class BedAdapter extends BaseFeatureDataAdapter {
65
28
  return header;
66
29
  }
67
30
  async getNames() {
68
- const { header, columnNames } = await this.loadData();
69
- if (columnNames.length) {
70
- return columnNames;
71
- }
72
- const defs = header.split(/\n|\r\n|\r/).filter(f => !!f);
73
- const defline = defs.at(-1);
74
- return defline?.includes('\t')
75
- ? defline
76
- .slice(1)
77
- .split('\t')
78
- .map(field => field.trim())
79
- : undefined;
31
+ return resolveColumnNames(this.getConf('columnNames'), async () => (await this.loadData()).header);
80
32
  }
81
33
  async loadFeatureIntervalTreeHelper(refName) {
82
- const { colRef, colStart, colEnd, features, parser, scoreColumn } = await this.loadData();
34
+ const { features } = await this.loadData();
83
35
  const lines = features[refName];
84
36
  if (!lines) {
85
37
  return undefined;
86
38
  }
87
39
  const names = await this.getNames();
40
+ const parser = await this.getParser();
41
+ const scoreColumn = this.getConf('scoreColumn');
42
+ const colRef = this.getConf('colRef');
43
+ const colStart = this.getConf('colStart');
44
+ const colEnd = this.getConf('colEnd');
88
45
  const disableGeneHeuristic = this.getConf('disableGeneHeuristic');
89
46
  const intervalTree = new IntervalTree();
90
47
  for (let i = 0; i < lines.length; i++) {
91
- const line = lines[i];
92
- const uniqueId = `${this.id}-${refName}-${i}`;
48
+ const splitLine = lines[i].split('\t');
93
49
  const feat = new SimpleFeature(featureData({
94
- line,
95
- colRef,
96
- colStart,
97
- colEnd,
50
+ splitLine,
51
+ ...bedFeatureLocus({ splitLine, colRef, colStart, colEnd }),
98
52
  scoreColumn,
99
53
  parser,
100
- uniqueId,
54
+ uniqueId: `${this.id}-${refName}-${i}`,
101
55
  names,
102
56
  disableGeneHeuristic,
103
57
  }));
@@ -105,26 +59,8 @@ export default class BedAdapter extends BaseFeatureDataAdapter {
105
59
  }
106
60
  return intervalTree;
107
61
  }
108
- async loadFeatureIntervalTree(refName) {
109
- if (!this.intervalTrees[refName]) {
110
- this.intervalTrees[refName] = this.loadFeatureIntervalTreeHelper(refName).catch((e) => {
111
- this.intervalTrees[refName] = undefined;
112
- throw e;
113
- });
114
- }
115
- return this.intervalTrees[refName];
116
- }
117
- getFeatures(query, opts = {}) {
118
- return ObservableCreate(async (observer) => {
119
- const { start, end, refName } = query;
120
- const intervalTree = await this.loadFeatureIntervalTree(refName);
121
- const features = intervalTree?.search([start, end]);
122
- if (features) {
123
- for (const f of features) {
124
- observer.next(f);
125
- }
126
- }
127
- observer.complete();
128
- }, opts.stopToken);
62
+ treeFeatures = intervalTreeFeatures(opts => this.loadData(opts), refName => this.loadFeatureIntervalTreeHelper(refName));
63
+ getFeatures(query, opts) {
64
+ return this.treeFeatures(query, opts);
129
65
  }
130
66
  }
@@ -1,46 +1,73 @@
1
+ import type { Instance } from '@jbrowse/mobx-state-tree';
2
+ export declare function normalizeSnapshot(snap: Record<string, unknown>): Record<string, unknown>;
3
+ /**
4
+ * #config BedAdapter
5
+ * #trackType FeatureTrack
6
+ * #fileFormat feature | BED (plain) | Loaded entirely into memory; for small files
7
+ * #gotcha Named BED columns past `name`/`score`/`strand` (`itemRgb`,
8
+ * `thickStart`, ...) are only guaranteed for BED12 or a track with an
9
+ * `autoSql`/`columnNames`. For a BED7-BED11 file JBrowse cannot know what the
10
+ * extra columns mean, so it exposes them generically as `field6`, `field7`,
11
+ * ... and a jexl callback reading `feature.itemRgb` gets `undefined`. Set
12
+ * `columnNames` to refer to them by name.
13
+ *
14
+ * used to load plain-text BED files. Loads the whole file into memory, so
15
+ * prefer the BedTabixAdapter for large files.
16
+ *
17
+ * #example
18
+ * ```js
19
+ * {
20
+ * type: 'BedAdapter',
21
+ * uri: 'https://example.com/features.bed',
22
+ * }
23
+ * ```
24
+ */
1
25
  declare const BedAdapter: import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{
2
- bedLocation: {
3
- type: string;
4
- description: string;
5
- defaultValue: {
6
- uri: string;
7
- locationType: string;
8
- };
9
- };
10
- columnNames: {
11
- type: string;
12
- description: string;
13
- defaultValue: never[];
14
- };
15
- scoreColumn: {
16
- type: string;
17
- description: string;
26
+ type: {
27
+ type: "string";
28
+ } & {
18
29
  defaultValue: string;
19
30
  };
20
- autoSql: {
21
- type: string;
22
- description: string;
31
+ readonly bedLocation: {
32
+ type: "fileLocation";
33
+ } & {
34
+ defaultValue: unknown;
35
+ };
36
+ readonly columnNames: {
37
+ type: "stringArray";
38
+ } & {
39
+ defaultValue: unknown;
40
+ };
41
+ readonly scoreColumn: {
42
+ type: "string";
43
+ } & {
44
+ defaultValue: string;
45
+ };
46
+ readonly autoSql: {
47
+ type: "string";
48
+ } & {
23
49
  defaultValue: string;
24
50
  };
25
- colRef: {
26
- type: string;
27
- description: string;
51
+ readonly colRef: {
52
+ type: "number";
53
+ } & {
28
54
  defaultValue: number;
29
55
  };
30
- colStart: {
31
- type: string;
32
- description: string;
56
+ readonly colStart: {
57
+ type: "number";
58
+ } & {
33
59
  defaultValue: number;
34
60
  };
35
- colEnd: {
36
- type: string;
37
- description: string;
61
+ readonly colEnd: {
62
+ type: "number";
63
+ } & {
38
64
  defaultValue: number;
39
65
  };
40
- disableGeneHeuristic: {
41
- type: string;
42
- description: string;
66
+ readonly disableGeneHeuristic: {
67
+ type: "boolean";
68
+ } & {
43
69
  defaultValue: boolean;
44
70
  };
45
- }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined>>;
71
+ }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined, true, import("@jbrowse/core/configuration").ConfigurationSchemaRequirement<Partial<Record<string, string[]>>, string>, any>>;
72
+ export type BedAdapterConfig = Instance<typeof BedAdapter>;
46
73
  export default BedAdapter;
@@ -1,6 +1,33 @@
1
- import { ConfigurationSchema } from '@jbrowse/core/configuration';
2
- function x() { }
1
+ import { ConfigurationSchema, expandUriShorthand, } from '@jbrowse/core/configuration';
2
+ export function normalizeSnapshot(snap) {
3
+ return expandUriShorthand(snap, 'bedLocation');
4
+ }
5
+ /**
6
+ * #config BedAdapter
7
+ * #trackType FeatureTrack
8
+ * #fileFormat feature | BED (plain) | Loaded entirely into memory; for small files
9
+ * #gotcha Named BED columns past `name`/`score`/`strand` (`itemRgb`,
10
+ * `thickStart`, ...) are only guaranteed for BED12 or a track with an
11
+ * `autoSql`/`columnNames`. For a BED7-BED11 file JBrowse cannot know what the
12
+ * extra columns mean, so it exposes them generically as `field6`, `field7`,
13
+ * ... and a jexl callback reading `feature.itemRgb` gets `undefined`. Set
14
+ * `columnNames` to refer to them by name.
15
+ *
16
+ * used to load plain-text BED files. Loads the whole file into memory, so
17
+ * prefer the BedTabixAdapter for large files.
18
+ *
19
+ * #example
20
+ * ```js
21
+ * {
22
+ * type: 'BedAdapter',
23
+ * uri: 'https://example.com/features.bed',
24
+ * }
25
+ * ```
26
+ */
3
27
  const BedAdapter = ConfigurationSchema('BedAdapter', {
28
+ /**
29
+ * #slot
30
+ */
4
31
  bedLocation: {
5
32
  type: 'fileLocation',
6
33
  description: 'path to bed file, also allows gzipped bed',
@@ -9,36 +36,57 @@ const BedAdapter = ConfigurationSchema('BedAdapter', {
9
36
  locationType: 'UriLocation',
10
37
  },
11
38
  },
39
+ /**
40
+ * #slot
41
+ */
12
42
  columnNames: {
13
43
  type: 'stringArray',
14
- description: 'List of column names',
44
+ 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",
15
45
  defaultValue: [],
16
46
  },
47
+ /**
48
+ * #slot
49
+ */
17
50
  scoreColumn: {
18
51
  type: 'string',
19
52
  description: 'The column to use as a "score" attribute',
20
53
  defaultValue: '',
21
54
  },
55
+ /**
56
+ * #slot
57
+ */
22
58
  autoSql: {
23
59
  type: 'string',
24
60
  description: 'The autoSql definition for the data fields in the file',
25
61
  defaultValue: '',
26
62
  },
63
+ /**
64
+ * #slot
65
+ */
27
66
  colRef: {
28
67
  type: 'number',
29
68
  description: 'The column to use as a "refName" attribute',
30
69
  defaultValue: 0,
31
70
  },
71
+ /**
72
+ * #slot
73
+ */
32
74
  colStart: {
33
75
  type: 'number',
34
76
  description: 'The column to use as a "start" attribute',
35
77
  defaultValue: 1,
36
78
  },
79
+ /**
80
+ * #slot
81
+ */
37
82
  colEnd: {
38
83
  type: 'number',
39
84
  description: 'The column to use as a "end" attribute',
40
85
  defaultValue: 2,
41
86
  },
87
+ /**
88
+ * #slot
89
+ */
42
90
  disableGeneHeuristic: {
43
91
  type: 'boolean',
44
92
  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)',
@@ -46,16 +94,18 @@ const BedAdapter = ConfigurationSchema('BedAdapter', {
46
94
  },
47
95
  }, {
48
96
  explicitlyTyped: true,
49
- preProcessSnapshot: snap => {
50
- return snap.uri
51
- ? {
52
- ...snap,
53
- bedLocation: {
54
- uri: snap.uri,
55
- baseUri: snap.baseUri,
56
- },
57
- }
58
- : snap;
59
- },
97
+ /**
98
+ * #preProcessSnapshot
99
+ *
100
+ *
101
+ * preprocessor to allow minimal config:
102
+ * ```json
103
+ * {
104
+ * "type": "BedAdapter",
105
+ * "uri": "yourfile.bed"
106
+ * }
107
+ * ```
108
+ */
109
+ preProcessSnapshot: normalizeSnapshot,
60
110
  });
61
111
  export default BedAdapter;
@@ -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 BedAdapterF(pluginManager) {
4
4
  pluginManager.addAdapterType(() => new AdapterType({
5
5
  name: 'BedAdapter',
6
6
  displayName: 'BED adapter',
7
7
  configSchema,
8
- getAdapterClass: () => import("./BedAdapter.js").then(r => r.default),
8
+ getAdapterClass: () => import('./BedAdapter.js').then(r => r.default),
9
+ locationKey: 'bedLocation',
10
+ normalizeSnapshot,
9
11
  }));
10
12
  }
@@ -1,23 +1,16 @@
1
1
  import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter';
2
- import { IntervalTree } from '@jbrowse/core/util';
2
+ import type { BedGraphAdapterConfig } from './configSchema.ts';
3
3
  import type { BaseOptions } from '@jbrowse/core/data_adapters/BaseAdapter';
4
4
  import type { Feature, Region } from '@jbrowse/core/util';
5
- export default class BedGraphAdapter extends BaseFeatureDataAdapter {
6
- protected bedFeatures?: Promise<{
5
+ export default class BedGraphAdapter extends BaseFeatureDataAdapter<BedGraphAdapterConfig> {
6
+ loadData: (opts?: BaseOptions) => Promise<{
7
7
  header: string;
8
8
  features: Record<string, string[]>;
9
- columnNames: string[];
10
9
  }>;
11
- protected intervalTrees: Record<string, Promise<IntervalTree<Feature> | undefined> | undefined>;
12
10
  getNames(): Promise<string[] | undefined>;
13
11
  private loadFeatureIntervalTreeHelper;
14
12
  getRefNames(opts?: BaseOptions): Promise<string[]>;
15
13
  private loadDataP;
16
- loadFeatureIntervalTree(refName: string): Promise<IntervalTree<Feature> | undefined>;
17
- loadData(opts?: BaseOptions): Promise<{
18
- header: string;
19
- features: Record<string, string[]>;
20
- columnNames: string[];
21
- }>;
22
- getFeatures(query: Region, _opts?: BaseOptions): import("rxjs").Observable<Feature>;
14
+ private treeFeatures;
15
+ getFeatures(query: Region, opts?: BaseOptions): import("rxjs").Observable<Feature>;
23
16
  }
@@ -1,24 +1,14 @@
1
- import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter';
2
- import { IntervalTree, SimpleFeature, fetchAndMaybeUnzip, } from '@jbrowse/core/util';
1
+ import { BaseFeatureDataAdapter, cachedSetup, } from '@jbrowse/core/data_adapters/BaseAdapter';
2
+ import { IntervalTree, fetchAndMaybeUnzip } from '@jbrowse/core/util';
3
3
  import { openLocation } from '@jbrowse/core/util/io';
4
- import { parseLineByLine } from '@jbrowse/core/util/parseLineByLine';
5
- import { ObservableCreate } from '@jbrowse/core/util/rxjs';
4
+ import { intervalTreeFeatures } from '../adapterUtil.js';
5
+ import { makeBedGraphFeature } from '../bedGraphUtil.js';
6
+ import { bucketBedLines, resolveColumnNames } from '../util.js';
6
7
  export default class BedGraphAdapter extends BaseFeatureDataAdapter {
7
- bedFeatures;
8
- intervalTrees = {};
8
+ // No `label`: `fetchAndMaybeUnzip` narrates the download from inside.
9
+ loadData = cachedSetup({ setup: opts => this.loadDataP(opts) });
9
10
  async getNames() {
10
- const { header, columnNames } = await this.loadData();
11
- if (columnNames.length) {
12
- return columnNames;
13
- }
14
- const defs = header.split(/\n|\r\n|\r/).filter(f => !!f);
15
- const defline = defs.at(-1);
16
- return defline?.includes('\t')
17
- ? defline
18
- .slice(1)
19
- .split('\t')
20
- .map(field => field.trim())
21
- : undefined;
11
+ return resolveColumnNames(this.getConf('columnNames'), async () => (await this.loadData()).header);
22
12
  }
23
13
  async loadFeatureIntervalTreeHelper(refName) {
24
14
  const { features } = await this.loadData();
@@ -26,28 +16,29 @@ export default class BedGraphAdapter extends BaseFeatureDataAdapter {
26
16
  if (!lines) {
27
17
  return undefined;
28
18
  }
29
- const names = (await this.getNames())?.slice(3) || [];
19
+ const names = (await this.getNames())?.slice(3) ?? [];
20
+ const sourceColumn = names.indexOf('source');
30
21
  const intervalTree = new IntervalTree();
31
22
  for (let i = 0, l = lines.length; i < l; i++) {
32
- const line = lines[i];
33
- const [refName, s, e, ...rest] = line.split('\t');
23
+ const [refName, s, e, ...rest] = lines[i].split('\t');
24
+ const start = +s;
25
+ const end = +e;
34
26
  for (let j = 0, l2 = rest.length; j < l2; j++) {
35
- const uniqueId = `${this.id}-${refName}-${i}-${j}`;
36
- const start = +s;
37
- const end = +e;
38
- const score = +rest[j];
39
- const source = names[j] || `col${j}`;
40
- if (score) {
41
- intervalTree.insert([start, end], new SimpleFeature({
42
- id: uniqueId,
43
- data: {
44
- refName,
45
- start,
46
- end,
47
- score,
48
- source,
49
- },
50
- }));
27
+ if (j === sourceColumn) {
28
+ continue;
29
+ }
30
+ const feat = makeBedGraphFeature({
31
+ uniqueId: `${this.id}-${refName}-${i}-${j}`,
32
+ refName: refName,
33
+ start,
34
+ end,
35
+ names,
36
+ j,
37
+ value: rest[j],
38
+ rowSource: rest[sourceColumn],
39
+ });
40
+ if (feat) {
41
+ intervalTree.insert([start, end], feat);
51
42
  }
52
43
  }
53
44
  }
@@ -58,58 +49,11 @@ export default class BedGraphAdapter extends BaseFeatureDataAdapter {
58
49
  return Object.keys(features);
59
50
  }
60
51
  async loadDataP(opts = {}) {
61
- const pm = this.pluginManager;
62
- const bedLoc = this.getConf('bedGraphLocation');
63
- const buffer = await fetchAndMaybeUnzip(openLocation(bedLoc, pm), opts);
64
- const features = {};
65
- const headerLines = [];
66
- parseLineByLine(buffer, line => {
67
- if (line.startsWith('#')) {
68
- headerLines.push(line);
69
- }
70
- else {
71
- const tab = line.indexOf('\t');
72
- const refName = line.slice(0, tab);
73
- if (!features[refName]) {
74
- features[refName] = [];
75
- }
76
- features[refName].push(line);
77
- }
78
- return true;
79
- }, opts.statusCallback);
80
- const columnNames = this.getConf('columnNames');
81
- return {
82
- header: headerLines.join('\n'),
83
- features,
84
- columnNames,
85
- };
52
+ const buffer = await fetchAndMaybeUnzip(openLocation(this.getConf('bedGraphLocation'), this.pluginManager), opts);
53
+ return bucketBedLines(buffer, opts.statusCallback);
86
54
  }
87
- async loadFeatureIntervalTree(refName) {
88
- if (!this.intervalTrees[refName]) {
89
- this.intervalTrees[refName] = this.loadFeatureIntervalTreeHelper(refName).catch((e) => {
90
- this.intervalTrees[refName] = undefined;
91
- throw e;
92
- });
93
- }
94
- return this.intervalTrees[refName];
95
- }
96
- async loadData(opts = {}) {
97
- if (!this.bedFeatures) {
98
- this.bedFeatures = this.loadDataP(opts).catch((e) => {
99
- this.bedFeatures = undefined;
100
- throw e;
101
- });
102
- }
103
- return this.bedFeatures;
104
- }
105
- getFeatures(query, _opts = {}) {
106
- return ObservableCreate(async (observer) => {
107
- const { start, end, refName } = query;
108
- const intervalTree = await this.loadFeatureIntervalTree(refName);
109
- for (const feature of intervalTree?.search([start, end]) || []) {
110
- observer.next(feature);
111
- }
112
- observer.complete();
113
- });
55
+ treeFeatures = intervalTreeFeatures(opts => this.loadData(opts), refName => this.loadFeatureIntervalTreeHelper(refName));
56
+ getFeatures(query, opts) {
57
+ return this.treeFeatures(query, opts);
114
58
  }
115
59
  }
@@ -1,15 +1,39 @@
1
+ import type { Instance } from '@jbrowse/mobx-state-tree';
2
+ export declare function normalizeSnapshot(snap: Record<string, unknown>): Record<string, unknown>;
3
+ /**
4
+ * #config BedGraphAdapter
5
+ * #trackType QuantitativeTrack
6
+ * #fileFormat quantitative | BedGraph (plain) | Loaded entirely into memory; for small files
7
+ * used to load plain-text bedGraph signal files. Loads the whole file into
8
+ * memory, so prefer the BedGraphTabixAdapter for large files.
9
+ * Several signals in one file are a `MultiQuantitativeTrack`'s subtracks:
10
+ * one value column each, named by the header, or a `source` column naming each
11
+ * row's, which is the form Save track data writes.
12
+ *
13
+ * #example
14
+ * ```js
15
+ * {
16
+ * type: 'BedGraphAdapter',
17
+ * uri: 'https://example.com/signal.bedGraph',
18
+ * }
19
+ * ```
20
+ */
1
21
  declare const BedGraphAdapter: import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{
2
- bedGraphLocation: {
3
- type: string;
4
- defaultValue: {
5
- uri: string;
6
- locationType: string;
7
- };
22
+ type: {
23
+ type: "string";
24
+ } & {
25
+ defaultValue: string;
8
26
  };
9
- columnNames: {
10
- type: string;
11
- description: string;
12
- defaultValue: never[];
27
+ readonly bedGraphLocation: {
28
+ type: "fileLocation";
29
+ } & {
30
+ defaultValue: unknown;
13
31
  };
14
- }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined>>;
32
+ readonly columnNames: {
33
+ type: "stringArray";
34
+ } & {
35
+ defaultValue: unknown;
36
+ };
37
+ }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined, true, import("@jbrowse/core/configuration").ConfigurationSchemaRequirement<Partial<Record<string, string[]>>, string>, any>>;
38
+ export type BedGraphAdapterConfig = Instance<typeof BedGraphAdapter>;
15
39
  export default BedGraphAdapter;