@jbrowse/plugin-gtf 1.7.4 → 1.7.5

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.
@@ -4,11 +4,18 @@ import IntervalTree from '@flatten-js/interval-tree';
4
4
  import { Feature } from '@jbrowse/core/util/simpleFeature';
5
5
  export default class extends BaseFeatureDataAdapter {
6
6
  protected gtfFeatures?: Promise<{
7
- intervalTree: Record<string, IntervalTree>;
7
+ feats: {
8
+ [key: string]: string[];
9
+ };
8
10
  }>;
11
+ protected intervalTrees: {
12
+ [key: string]: Promise<IntervalTree | undefined> | undefined;
13
+ };
9
14
  private loadDataP;
10
15
  private loadData;
11
16
  getRefNames(opts?: BaseOptions): Promise<string[]>;
17
+ private loadFeatureIntervalTreeHelper;
18
+ private loadFeatureIntervalTree;
12
19
  getFeatures(query: NoAssemblyRegion, opts?: BaseOptions): import("rxjs").Observable<Feature>;
13
20
  freeResources(): void;
14
21
  }
@@ -27,8 +27,6 @@ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/de
27
27
 
28
28
  var _BaseAdapter = require("@jbrowse/core/data_adapters/BaseAdapter");
29
29
 
30
- var _configuration = require("@jbrowse/core/configuration");
31
-
32
30
  var _io = require("@jbrowse/core/util/io");
33
31
 
34
32
  var _rxjs = require("@jbrowse/core/util/rxjs");
@@ -67,6 +65,7 @@ var _default = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
67
65
 
68
66
  _this = _super.call.apply(_super, [this].concat(args));
69
67
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "gtfFeatures", void 0);
68
+ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "intervalTrees", {});
70
69
  return _this;
71
70
  }
72
71
 
@@ -74,15 +73,13 @@ var _default = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
74
73
  key: "loadDataP",
75
74
  value: function () {
76
75
  var _loadDataP = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
77
- var _this2 = this;
78
-
79
- var buffer, buf, data, feats, intervalTree;
76
+ var buffer, buf, data, lines, feats, i, refName;
80
77
  return _regenerator.default.wrap(function _callee$(_context) {
81
78
  while (1) {
82
79
  switch (_context.prev = _context.next) {
83
80
  case 0:
84
81
  _context.next = 2;
85
- return (0, _io.openLocation)((0, _configuration.readConfObject)(this.config, 'gtfLocation'), this.pluginManager).readFile();
82
+ return (0, _io.openLocation)(this.getConf('gtfLocation'), this.pluginManager).readFile();
86
83
 
87
84
  case 2:
88
85
  buffer = _context.sent;
@@ -117,32 +114,26 @@ var _default = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
117
114
  data = new TextDecoder('utf8', {
118
115
  fatal: true
119
116
  }).decode(buf);
120
- feats = _gtf.default.parseStringSync(data, {
121
- parseFeatures: true,
122
- parseComments: false,
123
- parseDirectives: false,
124
- parseSequences: false
117
+ lines = data.split('\n').filter(function (f) {
118
+ return !!f && !f.startsWith('#');
125
119
  });
126
- intervalTree = feats.flat().map(function (f, i) {
127
- return new _simpleFeature.default({
128
- data: (0, _util.featureData)(f),
129
- id: "".concat(_this2.id, "-offset-").concat(i)
130
- });
131
- }).reduce(function (acc, obj) {
132
- var key = obj.get('refName');
120
+ feats = {};
121
+
122
+ for (i = 0; i < lines.length; i++) {
123
+ refName = lines[i].split('\t')[0];
133
124
 
134
- if (!acc[key]) {
135
- acc[key] = new _intervalTree.default();
125
+ if (!feats[refName]) {
126
+ feats[refName] = [];
136
127
  }
137
128
 
138
- acc[key].insert([obj.get('start'), obj.get('end')], obj);
139
- return acc;
140
- }, {});
129
+ feats[refName].push(lines[i]);
130
+ }
131
+
141
132
  return _context.abrupt("return", {
142
- intervalTree: intervalTree
133
+ feats: feats
143
134
  });
144
135
 
145
- case 17:
136
+ case 18:
146
137
  case "end":
147
138
  return _context.stop();
148
139
  }
@@ -160,7 +151,7 @@ var _default = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
160
151
  key: "loadData",
161
152
  value: function () {
162
153
  var _loadData = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2() {
163
- var _this3 = this;
154
+ var _this2 = this;
164
155
 
165
156
  return _regenerator.default.wrap(function _callee2$(_context2) {
166
157
  while (1) {
@@ -168,7 +159,7 @@ var _default = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
168
159
  case 0:
169
160
  if (!this.gtfFeatures) {
170
161
  this.gtfFeatures = this.loadDataP().catch(function (e) {
171
- _this3.gtfFeatures = undefined;
162
+ _this2.gtfFeatures = undefined;
172
163
  throw e;
173
164
  });
174
165
  }
@@ -195,7 +186,7 @@ var _default = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
195
186
  var _getRefNames = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee3() {
196
187
  var opts,
197
188
  _yield$this$loadData,
198
- intervalTree,
189
+ feats,
199
190
  _args3 = arguments;
200
191
 
201
192
  return _regenerator.default.wrap(function _callee3$(_context3) {
@@ -208,8 +199,8 @@ var _default = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
208
199
 
209
200
  case 3:
210
201
  _yield$this$loadData = _context3.sent;
211
- intervalTree = _yield$this$loadData.intervalTree;
212
- return _context3.abrupt("return", Object.keys(intervalTree));
202
+ feats = _yield$this$loadData.feats;
203
+ return _context3.abrupt("return", Object.keys(feats));
213
204
 
214
205
  case 6:
215
206
  case "end":
@@ -225,49 +216,143 @@ var _default = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
225
216
 
226
217
  return getRefNames;
227
218
  }()
219
+ }, {
220
+ key: "loadFeatureIntervalTreeHelper",
221
+ value: function () {
222
+ var _loadFeatureIntervalTreeHelper = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee4(refName) {
223
+ var _this3 = this;
224
+
225
+ var _yield$this$loadData2, feats, lines, data, intervalTree, ret, i, obj;
226
+
227
+ return _regenerator.default.wrap(function _callee4$(_context4) {
228
+ while (1) {
229
+ switch (_context4.prev = _context4.next) {
230
+ case 0:
231
+ _context4.next = 2;
232
+ return this.loadData();
233
+
234
+ case 2:
235
+ _yield$this$loadData2 = _context4.sent;
236
+ feats = _yield$this$loadData2.feats;
237
+ lines = feats[refName];
238
+
239
+ if (lines) {
240
+ _context4.next = 7;
241
+ break;
242
+ }
243
+
244
+ return _context4.abrupt("return", undefined);
245
+
246
+ case 7:
247
+ data = _gtf.default.parseStringSync(lines.join('\n'), {
248
+ parseFeatures: true,
249
+ parseComments: false,
250
+ parseDirectives: false,
251
+ parseSequences: false
252
+ });
253
+ intervalTree = new _intervalTree.default();
254
+ ret = data.flat().map(function (f, i) {
255
+ return new _simpleFeature.default({
256
+ data: (0, _util.featureData)(f),
257
+ id: "".concat(_this3.id, "-offset-").concat(i)
258
+ });
259
+ });
260
+
261
+ for (i = 0; i < ret.length; i++) {
262
+ obj = ret[i];
263
+ intervalTree.insert([obj.get('start'), obj.get('end')], obj);
264
+ }
265
+
266
+ return _context4.abrupt("return", intervalTree);
267
+
268
+ case 12:
269
+ case "end":
270
+ return _context4.stop();
271
+ }
272
+ }
273
+ }, _callee4, this);
274
+ }));
275
+
276
+ function loadFeatureIntervalTreeHelper(_x) {
277
+ return _loadFeatureIntervalTreeHelper.apply(this, arguments);
278
+ }
279
+
280
+ return loadFeatureIntervalTreeHelper;
281
+ }()
282
+ }, {
283
+ key: "loadFeatureIntervalTree",
284
+ value: function () {
285
+ var _loadFeatureIntervalTree = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee5(refName) {
286
+ var _this4 = this;
287
+
288
+ return _regenerator.default.wrap(function _callee5$(_context5) {
289
+ while (1) {
290
+ switch (_context5.prev = _context5.next) {
291
+ case 0:
292
+ if (!this.intervalTrees[refName]) {
293
+ this.intervalTrees[refName] = this.loadFeatureIntervalTreeHelper(refName).catch(function (e) {
294
+ _this4.intervalTrees[refName] = undefined;
295
+ throw e;
296
+ });
297
+ }
298
+
299
+ return _context5.abrupt("return", this.intervalTrees[refName]);
300
+
301
+ case 2:
302
+ case "end":
303
+ return _context5.stop();
304
+ }
305
+ }
306
+ }, _callee5, this);
307
+ }));
308
+
309
+ function loadFeatureIntervalTree(_x2) {
310
+ return _loadFeatureIntervalTree.apply(this, arguments);
311
+ }
312
+
313
+ return loadFeatureIntervalTree;
314
+ }()
228
315
  }, {
229
316
  key: "getFeatures",
230
317
  value: function getFeatures(query) {
231
- var _this4 = this;
318
+ var _this5 = this;
232
319
 
233
320
  var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
234
321
  return (0, _rxjs.ObservableCreate)( /*#__PURE__*/function () {
235
- var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee4(observer) {
236
- var _intervalTree$refName, start, end, refName, _yield$_this4$loadDat, intervalTree;
237
-
238
- return _regenerator.default.wrap(function _callee4$(_context4) {
322
+ var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee6(observer) {
323
+ var start, end, refName, intervalTree;
324
+ return _regenerator.default.wrap(function _callee6$(_context6) {
239
325
  while (1) {
240
- switch (_context4.prev = _context4.next) {
326
+ switch (_context6.prev = _context6.next) {
241
327
  case 0:
242
- _context4.prev = 0;
328
+ _context6.prev = 0;
243
329
  start = query.start, end = query.end, refName = query.refName;
244
- _context4.next = 4;
245
- return _this4.loadData();
330
+ _context6.next = 4;
331
+ return _this5.loadFeatureIntervalTree(refName);
246
332
 
247
333
  case 4:
248
- _yield$_this4$loadDat = _context4.sent;
249
- intervalTree = _yield$_this4$loadDat.intervalTree;
250
- (_intervalTree$refName = intervalTree[refName]) === null || _intervalTree$refName === void 0 ? void 0 : _intervalTree$refName.search([start, end]).forEach(function (f) {
334
+ intervalTree = _context6.sent;
335
+ intervalTree === null || intervalTree === void 0 ? void 0 : intervalTree.search([start, end]).forEach(function (f) {
251
336
  return observer.next(f);
252
337
  });
253
338
  observer.complete();
254
- _context4.next = 13;
339
+ _context6.next = 12;
255
340
  break;
256
341
 
257
- case 10:
258
- _context4.prev = 10;
259
- _context4.t0 = _context4["catch"](0);
260
- observer.error(_context4.t0);
342
+ case 9:
343
+ _context6.prev = 9;
344
+ _context6.t0 = _context6["catch"](0);
345
+ observer.error(_context6.t0);
261
346
 
262
- case 13:
347
+ case 12:
263
348
  case "end":
264
- return _context4.stop();
349
+ return _context6.stop();
265
350
  }
266
351
  }
267
- }, _callee4, null, [[0, 10]]);
352
+ }, _callee6, null, [[0, 9]]);
268
353
  }));
269
354
 
270
- return function (_x) {
355
+ return function (_x3) {
271
356
  return _ref.apply(this, arguments);
272
357
  };
273
358
  }(), opts.signal);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jbrowse/plugin-gtf",
3
- "version": "1.7.4",
3
+ "version": "1.7.5",
4
4
  "description": "JBrowse 2 gtf feature adapter",
5
5
  "keywords": [
6
6
  "jbrowse",
@@ -51,5 +51,5 @@
51
51
  "publishConfig": {
52
52
  "access": "public"
53
53
  },
54
- "gitHead": "0a3e0c58055bbab8e3ab0270c139291b96eff403"
54
+ "gitHead": "2c3a1f0c95a47b24eba790eaeb49274caf297aeb"
55
55
  }
@@ -3,13 +3,11 @@ import {
3
3
  BaseOptions,
4
4
  } from '@jbrowse/core/data_adapters/BaseAdapter'
5
5
  import { NoAssemblyRegion } from '@jbrowse/core/util/types'
6
- import { readConfObject } from '@jbrowse/core/configuration'
7
6
  import { openLocation } from '@jbrowse/core/util/io'
8
7
  import { ObservableCreate } from '@jbrowse/core/util/rxjs'
9
8
  import IntervalTree from '@flatten-js/interval-tree'
10
9
  import SimpleFeature, { Feature } from '@jbrowse/core/util/simpleFeature'
11
10
  import { unzip } from '@gmod/bgzf-filehandle'
12
-
13
11
  import gtf from '@gmod/gtf'
14
12
  import { FeatureLoc, featureData } from '../util'
15
13
  function isGzip(buf: Buffer) {
@@ -18,12 +16,16 @@ function isGzip(buf: Buffer) {
18
16
 
19
17
  export default class extends BaseFeatureDataAdapter {
20
18
  protected gtfFeatures?: Promise<{
21
- intervalTree: Record<string, IntervalTree>
19
+ feats: { [key: string]: string[] }
22
20
  }>
23
21
 
22
+ protected intervalTrees: {
23
+ [key: string]: Promise<IntervalTree | undefined> | undefined
24
+ } = {}
25
+
24
26
  private async loadDataP() {
25
27
  const buffer = await openLocation(
26
- readConfObject(this.config, 'gtfLocation'),
28
+ this.getConf('gtfLocation'),
27
29
  this.pluginManager,
28
30
  ).readFile()
29
31
 
@@ -33,31 +35,18 @@ export default class extends BaseFeatureDataAdapter {
33
35
  throw new Error('Data exceeds maximum string length (512MB)')
34
36
  }
35
37
  const data = new TextDecoder('utf8', { fatal: true }).decode(buf)
36
- const feats = gtf.parseStringSync(data, {
37
- parseFeatures: true,
38
- parseComments: false,
39
- parseDirectives: false,
40
- parseSequences: false,
41
- }) as FeatureLoc[][]
42
38
 
43
- const intervalTree = feats
44
- .flat()
45
- .map(
46
- (f, i) =>
47
- new SimpleFeature({
48
- data: featureData(f),
49
- id: `${this.id}-offset-${i}`,
50
- }),
51
- )
52
- .reduce((acc, obj) => {
53
- const key = obj.get('refName')
54
- if (!acc[key]) {
55
- acc[key] = new IntervalTree()
56
- }
57
- acc[key].insert([obj.get('start'), obj.get('end')], obj)
58
- return acc
59
- }, {} as Record<string, IntervalTree>)
60
- return { intervalTree }
39
+ const lines = data.split('\n').filter(f => !!f && !f.startsWith('#'))
40
+ const feats = {} as { [key: string]: string[] }
41
+ for (let i = 0; i < lines.length; i++) {
42
+ const refName = lines[i].split('\t')[0]
43
+ if (!feats[refName]) {
44
+ feats[refName] = []
45
+ }
46
+ feats[refName].push(lines[i])
47
+ }
48
+
49
+ return { feats }
61
50
  }
62
51
 
63
52
  private async loadData() {
@@ -72,18 +61,57 @@ export default class extends BaseFeatureDataAdapter {
72
61
  }
73
62
 
74
63
  public async getRefNames(opts: BaseOptions = {}) {
75
- const { intervalTree } = await this.loadData()
76
- return Object.keys(intervalTree)
64
+ const { feats } = await this.loadData()
65
+ return Object.keys(feats)
66
+ }
67
+
68
+ private async loadFeatureIntervalTreeHelper(refName: string) {
69
+ const { feats } = await this.loadData()
70
+ const lines = feats[refName]
71
+ if (!lines) {
72
+ return undefined
73
+ }
74
+ const data = gtf.parseStringSync(lines.join('\n'), {
75
+ parseFeatures: true,
76
+ parseComments: false,
77
+ parseDirectives: false,
78
+ parseSequences: false,
79
+ }) as FeatureLoc[][]
80
+
81
+ const intervalTree = new IntervalTree()
82
+ const ret = data.flat().map(
83
+ (f, i) =>
84
+ new SimpleFeature({
85
+ data: featureData(f),
86
+ id: `${this.id}-offset-${i}`,
87
+ }),
88
+ )
89
+
90
+ for (let i = 0; i < ret.length; i++) {
91
+ const obj = ret[i]
92
+ intervalTree.insert([obj.get('start'), obj.get('end')], obj)
93
+ }
94
+ return intervalTree
95
+ }
96
+
97
+ private async loadFeatureIntervalTree(refName: string) {
98
+ if (!this.intervalTrees[refName]) {
99
+ this.intervalTrees[refName] = this.loadFeatureIntervalTreeHelper(
100
+ refName,
101
+ ).catch(e => {
102
+ this.intervalTrees[refName] = undefined
103
+ throw e
104
+ })
105
+ }
106
+ return this.intervalTrees[refName]
77
107
  }
78
108
 
79
109
  public getFeatures(query: NoAssemblyRegion, opts: BaseOptions = {}) {
80
110
  return ObservableCreate<Feature>(async observer => {
81
111
  try {
82
112
  const { start, end, refName } = query
83
- const { intervalTree } = await this.loadData()
84
- intervalTree[refName]
85
- ?.search([start, end])
86
- .forEach(f => observer.next(f))
113
+ const intervalTree = await this.loadFeatureIntervalTree(refName)
114
+ intervalTree?.search([start, end]).forEach(f => observer.next(f))
87
115
  observer.complete()
88
116
  } catch (e) {
89
117
  observer.error(e)