@jbrowse/plugin-alignments 1.7.7 → 1.7.8
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.
- package/dist/BamAdapter/BamAdapter.d.ts +1 -1
- package/dist/BamAdapter/BamAdapter.js +3 -3
- package/dist/BamAdapter/MismatchParser.d.ts +2 -5
- package/dist/BamAdapter/MismatchParser.js +104 -44
- package/dist/BamAdapter/MismatchParser.test.js +6 -14
- package/dist/CramAdapter/CramAdapter.d.ts +10 -9
- package/dist/CramAdapter/CramAdapter.js +6 -6
- package/dist/CramAdapter/CramSlightlyLazyFeature.js +35 -30
- package/dist/LinearPileupDisplay/model.js +1 -1
- package/dist/LinearSNPCoverageDisplay/components/Tooltip.js +2 -3
- package/dist/LinearSNPCoverageDisplay/models/model.js +1 -1
- package/dist/PileupRenderer/PileupLayoutSession.d.ts +3 -0
- package/dist/PileupRenderer/PileupLayoutSession.js +3 -1
- package/dist/PileupRenderer/PileupRenderer.d.ts +1 -1
- package/dist/PileupRenderer/PileupRenderer.js +125 -162
- package/dist/PileupRenderer/configSchema.js +2 -2
- package/dist/SNPCoverageAdapter/SNPCoverageAdapter.d.ts +4 -6
- package/dist/SNPCoverageAdapter/SNPCoverageAdapter.js +92 -96
- package/package.json +3 -3
- package/src/BamAdapter/BamAdapter.ts +3 -3
- package/src/BamAdapter/MismatchParser.test.ts +5 -7
- package/src/BamAdapter/MismatchParser.ts +69 -58
- package/src/CramAdapter/CramAdapter.ts +14 -10
- package/src/CramAdapter/CramSlightlyLazyFeature.ts +84 -91
- package/src/LinearPileupDisplay/model.ts +1 -1
- package/src/LinearSNPCoverageDisplay/components/Tooltip.tsx +32 -25
- package/src/LinearSNPCoverageDisplay/models/model.ts +1 -1
- package/src/PileupRenderer/PileupLayoutSession.ts +6 -1
- package/src/PileupRenderer/PileupRenderer.tsx +70 -68
- package/src/PileupRenderer/configSchema.ts +2 -2
- package/src/SNPCoverageAdapter/SNPCoverageAdapter.ts +84 -76
|
@@ -57,36 +57,17 @@ function isInterbase(type) {
|
|
|
57
57
|
function inc(bin, strand, type, field) {
|
|
58
58
|
var thisBin = bin[type][field];
|
|
59
59
|
|
|
60
|
-
if (
|
|
60
|
+
if (thisBin === undefined) {
|
|
61
61
|
thisBin = bin[type][field] = {
|
|
62
62
|
total: 0,
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
'1': 0
|
|
67
|
-
}
|
|
63
|
+
'-1': 0,
|
|
64
|
+
'0': 0,
|
|
65
|
+
'1': 0
|
|
68
66
|
};
|
|
69
67
|
}
|
|
70
68
|
|
|
71
69
|
thisBin.total++;
|
|
72
|
-
thisBin
|
|
73
|
-
} // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
function dec(bin, strand, type, field) {
|
|
77
|
-
if (!bin[type][field]) {
|
|
78
|
-
bin[type][field] = {
|
|
79
|
-
total: 0,
|
|
80
|
-
strands: {
|
|
81
|
-
'-1': 0,
|
|
82
|
-
'0': 0,
|
|
83
|
-
'1': 0
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
bin[type][field].total--;
|
|
89
|
-
bin[type][field].strands[strand]--;
|
|
70
|
+
thisBin[strand]++;
|
|
90
71
|
}
|
|
91
72
|
|
|
92
73
|
var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
|
|
@@ -396,36 +377,43 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
|
|
|
396
377
|
|
|
397
378
|
_loop = function _loop(i) {
|
|
398
379
|
var feature = features[i];
|
|
399
|
-
var ops = (0, _MismatchParser.parseCigar)(feature.get('CIGAR'));
|
|
400
380
|
var fstart = feature.get('start');
|
|
401
381
|
var fend = feature.get('end');
|
|
402
382
|
var fstrand = feature.get('strand');
|
|
403
383
|
|
|
404
|
-
for (var j = fstart; j < fend; j++) {
|
|
384
|
+
for (var j = fstart; j < fend + 1; j++) {
|
|
405
385
|
var _i = j - region.start;
|
|
406
386
|
|
|
407
387
|
if (_i >= 0 && _i < binMax) {
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
388
|
+
if (bins[_i] === undefined) {
|
|
389
|
+
bins[_i] = {
|
|
390
|
+
total: 0,
|
|
391
|
+
ref: 0,
|
|
392
|
+
'-1': 0,
|
|
393
|
+
'0': 0,
|
|
394
|
+
'1': 0,
|
|
395
|
+
lowqual: {},
|
|
396
|
+
cov: {},
|
|
397
|
+
delskips: {},
|
|
398
|
+
noncov: {}
|
|
399
|
+
};
|
|
400
|
+
}
|
|
416
401
|
|
|
417
402
|
if (j !== fend) {
|
|
418
|
-
|
|
419
|
-
|
|
403
|
+
bins[_i].total++;
|
|
404
|
+
bins[_i].ref++;
|
|
405
|
+
bins[_i][fstrand]++;
|
|
420
406
|
}
|
|
421
|
-
|
|
422
|
-
bins[_i] = bin;
|
|
423
407
|
}
|
|
424
408
|
}
|
|
425
409
|
|
|
426
410
|
if ((colorBy === null || colorBy === void 0 ? void 0 : colorBy.type) === 'modifications') {
|
|
427
411
|
var seq = feature.get('seq');
|
|
428
412
|
var mm = (0, _util.getTagAlt)(feature, 'MM', 'Mm') || '';
|
|
413
|
+
var ops = (0, _MismatchParser.parseCigar)(feature.get('CIGAR'));
|
|
414
|
+
|
|
415
|
+
var _fend = feature.get('end');
|
|
416
|
+
|
|
429
417
|
(0, _MismatchParser.getModificationPositions)(mm, seq, fstrand).forEach(function (_ref4) {
|
|
430
418
|
var type = _ref4.type,
|
|
431
419
|
positions = _ref4.positions;
|
|
@@ -439,9 +427,14 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
|
|
|
439
427
|
var pos = _step.value;
|
|
440
428
|
var epos = pos + fstart - region.start;
|
|
441
429
|
|
|
442
|
-
if (epos >= 0 && epos < bins.length && pos + fstart <
|
|
443
|
-
var
|
|
444
|
-
|
|
430
|
+
if (epos >= 0 && epos < bins.length && pos + fstart < _fend) {
|
|
431
|
+
var bin = bins[epos];
|
|
432
|
+
|
|
433
|
+
if (bin) {
|
|
434
|
+
inc(bin, fstrand, 'cov', mod);
|
|
435
|
+
} else {
|
|
436
|
+
console.warn('Undefined position in modifications snpcoverage encountered');
|
|
437
|
+
}
|
|
445
438
|
}
|
|
446
439
|
}
|
|
447
440
|
} catch (err) {
|
|
@@ -462,13 +455,16 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
|
|
|
462
455
|
var _mm = (0, _util.getTagAlt)(feature, 'MM', 'Mm') || '';
|
|
463
456
|
|
|
464
457
|
var methBins = new Array(region.end - region.start).fill(0);
|
|
458
|
+
|
|
459
|
+
var _ops = (0, _MismatchParser.parseCigar)(feature.get('CIGAR'));
|
|
460
|
+
|
|
465
461
|
(0, _MismatchParser.getModificationPositions)(_mm, _seq, fstrand).forEach(function (_ref5) {
|
|
466
462
|
var type = _ref5.type,
|
|
467
463
|
positions = _ref5.positions;
|
|
468
464
|
|
|
469
465
|
// we are processing methylation
|
|
470
466
|
if (type === 'm') {
|
|
471
|
-
var _iterator2 = _createForOfIteratorHelper((0, _MismatchParser.getNextRefPos)(
|
|
467
|
+
var _iterator2 = _createForOfIteratorHelper((0, _MismatchParser.getNextRefPos)(_ops, positions)),
|
|
472
468
|
_step2;
|
|
473
469
|
|
|
474
470
|
try {
|
|
@@ -496,80 +492,80 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
|
|
|
496
492
|
|
|
497
493
|
var l2 = regionSeq[_i2 + 1].toLowerCase();
|
|
498
494
|
|
|
499
|
-
var
|
|
495
|
+
var bin = bins[_i2];
|
|
500
496
|
var bin1 = bins[_i2 + 1]; // color
|
|
501
497
|
|
|
502
498
|
if (l1 === 'c' && l2 === 'g') {
|
|
503
499
|
if (methBins[_i2] || methBins[_i2 + 1]) {
|
|
504
|
-
inc(
|
|
500
|
+
inc(bin, fstrand, 'cov', 'meth');
|
|
505
501
|
inc(bin1, fstrand, 'cov', 'meth');
|
|
506
|
-
|
|
507
|
-
|
|
502
|
+
bins[_i2].ref--;
|
|
503
|
+
bins[_i2][fstrand]--;
|
|
504
|
+
bins[_i2 + 1].ref--;
|
|
505
|
+
bins[_i2 + 1][fstrand]--;
|
|
508
506
|
} else {
|
|
509
|
-
inc(
|
|
507
|
+
inc(bin, fstrand, 'cov', 'unmeth');
|
|
510
508
|
inc(bin1, fstrand, 'cov', 'unmeth');
|
|
511
|
-
|
|
512
|
-
|
|
509
|
+
bins[_i2].ref--;
|
|
510
|
+
bins[_i2][fstrand]--;
|
|
511
|
+
bins[_i2 + 1].ref--;
|
|
512
|
+
bins[_i2 + 1][fstrand]--;
|
|
513
513
|
}
|
|
514
514
|
}
|
|
515
515
|
}
|
|
516
516
|
}
|
|
517
517
|
} // normal SNP based coloring
|
|
518
|
-
else {
|
|
519
|
-
var mismatches = feature.get('mismatches');
|
|
520
518
|
|
|
521
|
-
if (mismatches) {
|
|
522
|
-
for (var _i3 = 0; _i3 < mismatches.length; _i3++) {
|
|
523
|
-
var mismatch = mismatches[_i3];
|
|
524
|
-
var mstart = fstart + mismatch.start;
|
|
525
519
|
|
|
526
|
-
|
|
527
|
-
|
|
520
|
+
var mismatches = feature.get('mismatches') || [];
|
|
521
|
+
var colorSNPs = (colorBy === null || colorBy === void 0 ? void 0 : colorBy.type) !== 'modifications' && (colorBy === null || colorBy === void 0 ? void 0 : colorBy.type) !== 'methylation';
|
|
528
522
|
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
523
|
+
for (var _i3 = 0; _i3 < mismatches.length; _i3++) {
|
|
524
|
+
var mismatch = mismatches[_i3];
|
|
525
|
+
var mstart = fstart + mismatch.start;
|
|
526
|
+
var mlen = mismatchLen(mismatch);
|
|
527
|
+
var mend = mstart + mlen;
|
|
534
528
|
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
} else {
|
|
538
|
-
inc(_bin3, fstrand, 'noncov', type);
|
|
539
|
-
}
|
|
529
|
+
for (var _j2 = mstart; _j2 < mstart + mlen; _j2++) {
|
|
530
|
+
var epos = _j2 - region.start;
|
|
540
531
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
}
|
|
532
|
+
if (epos >= 0 && epos < bins.length) {
|
|
533
|
+
var _bin = bins[epos];
|
|
534
|
+
var base = mismatch.base,
|
|
535
|
+
type = mismatch.type;
|
|
536
|
+
var interbase = isInterbase(type);
|
|
550
537
|
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
var mstart = feature.get('start') + mismatch.start;
|
|
555
|
-
var start = mstart;
|
|
556
|
-
var end = mstart + mismatch.length;
|
|
557
|
-
var strand = feature.get('strand');
|
|
558
|
-
var hash = "".concat(start, "_").concat(end, "_").concat(strand);
|
|
559
|
-
|
|
560
|
-
if (!skipmap[hash]) {
|
|
561
|
-
skipmap[hash] = {
|
|
562
|
-
feature: feature,
|
|
563
|
-
start: start,
|
|
564
|
-
end: end,
|
|
565
|
-
strand: strand,
|
|
566
|
-
xs: (0, _util.getTag)(feature, 'XS') || (0, _util.getTag)(feature, 'TS'),
|
|
567
|
-
score: 1
|
|
568
|
-
};
|
|
538
|
+
if (!interbase) {
|
|
539
|
+
_bin.ref--;
|
|
540
|
+
_bin[fstrand]--;
|
|
569
541
|
} else {
|
|
570
|
-
|
|
542
|
+
inc(_bin, fstrand, 'noncov', type);
|
|
571
543
|
}
|
|
572
|
-
|
|
544
|
+
|
|
545
|
+
if (type === 'deletion' || type === 'skip') {
|
|
546
|
+
inc(_bin, fstrand, 'delskips', type);
|
|
547
|
+
_bin.total--;
|
|
548
|
+
} else if (!interbase && colorSNPs) {
|
|
549
|
+
inc(_bin, fstrand, 'cov', base);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
if (mismatch.type === 'skip') {
|
|
555
|
+
var hash = "".concat(mstart, "_").concat(mend, "_").concat(fstrand);
|
|
556
|
+
|
|
557
|
+
if (skipmap[hash] === undefined) {
|
|
558
|
+
skipmap[hash] = {
|
|
559
|
+
feature: feature,
|
|
560
|
+
start: mstart,
|
|
561
|
+
end: mend,
|
|
562
|
+
strand: fstrand,
|
|
563
|
+
xs: (0, _util.getTag)(feature, 'XS') || (0, _util.getTag)(feature, 'TS'),
|
|
564
|
+
score: 0
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
skipmap[hash].score++;
|
|
573
569
|
}
|
|
574
570
|
}
|
|
575
571
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jbrowse/plugin-alignments",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.8",
|
|
4
4
|
"description": "JBrowse 2 alignments adapters, tracks, etc.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jbrowse",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@babel/runtime": "^7.17.9",
|
|
37
37
|
"@gmod/bam": "^1.1.15",
|
|
38
|
-
"@gmod/cram": "^1.6.
|
|
38
|
+
"@gmod/cram": "^1.6.4",
|
|
39
39
|
"@material-ui/icons": "^4.9.1",
|
|
40
40
|
"color": "^3.1.2",
|
|
41
41
|
"copy-to-clipboard": "^3.3.1",
|
|
@@ -57,5 +57,5 @@
|
|
|
57
57
|
"publishConfig": {
|
|
58
58
|
"access": "public"
|
|
59
59
|
},
|
|
60
|
-
"gitHead": "
|
|
60
|
+
"gitHead": "b429fa2bb5734fc8a5380988f6dfdd3f7a41a39f"
|
|
61
61
|
}
|
|
@@ -171,7 +171,7 @@ export default class BamAdapter extends BaseFeatureDataAdapter {
|
|
|
171
171
|
flagInclude: number
|
|
172
172
|
flagExclude: number
|
|
173
173
|
tagFilter: { tag: string; value: unknown }
|
|
174
|
-
|
|
174
|
+
readName: string
|
|
175
175
|
}
|
|
176
176
|
},
|
|
177
177
|
) {
|
|
@@ -187,7 +187,7 @@ export default class BamAdapter extends BaseFeatureDataAdapter {
|
|
|
187
187
|
flagInclude = 0,
|
|
188
188
|
flagExclude = 0,
|
|
189
189
|
tagFilter,
|
|
190
|
-
|
|
190
|
+
readName,
|
|
191
191
|
} = filterBy || {}
|
|
192
192
|
|
|
193
193
|
for (const record of records) {
|
|
@@ -214,7 +214,7 @@ export default class BamAdapter extends BaseFeatureDataAdapter {
|
|
|
214
214
|
}
|
|
215
215
|
}
|
|
216
216
|
|
|
217
|
-
if (
|
|
217
|
+
if (readName && record.get('name') !== readName) {
|
|
218
218
|
continue
|
|
219
219
|
}
|
|
220
220
|
|
|
@@ -233,17 +233,15 @@ test('clipping', () => {
|
|
|
233
233
|
])
|
|
234
234
|
})
|
|
235
235
|
|
|
236
|
-
test('getNextRefPos
|
|
236
|
+
test('getNextRefPos test 1', () => {
|
|
237
237
|
const cigar = parseCigar('10S10M1I4M1D15M')
|
|
238
238
|
const iter = getNextRefPos(cigar, [5, 10, 15, 20, 25, 30, 35])
|
|
239
|
-
|
|
240
|
-
expect(vals).toEqual([-5, 0, 5, 10, 14, 20, 25])
|
|
239
|
+
expect([...iter]).toEqual([0, 5, 15, 20, 25])
|
|
241
240
|
})
|
|
242
|
-
test('getNextRefPos
|
|
243
|
-
const cigar = parseCigar('
|
|
241
|
+
test('getNextRefPos test 2', () => {
|
|
242
|
+
const cigar = parseCigar('10S15M')
|
|
244
243
|
const iter = getNextRefPos(cigar, [5, 10, 15])
|
|
245
|
-
|
|
246
|
-
expect(vals).toEqual([-5, 0, 5])
|
|
244
|
+
expect([...iter]).toEqual([0, 5])
|
|
247
245
|
})
|
|
248
246
|
|
|
249
247
|
test('getModificationPositions', () => {
|
|
@@ -232,26 +232,32 @@ export function getMismatches(
|
|
|
232
232
|
// get relative reference sequence positions for positions given relative to
|
|
233
233
|
// the read sequence
|
|
234
234
|
export function* getNextRefPos(cigarOps: string[], positions: number[]) {
|
|
235
|
-
let cigarIdx = 0
|
|
236
235
|
let readPos = 0
|
|
237
236
|
let refPos = 0
|
|
237
|
+
let currPos = 0
|
|
238
238
|
|
|
239
|
-
for (let i = 0; i < positions.length; i
|
|
240
|
-
const
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
239
|
+
for (let i = 0; i < cigarOps.length && currPos < positions.length; i += 2) {
|
|
240
|
+
const len = +cigarOps[i]
|
|
241
|
+
const op = cigarOps[i + 1]
|
|
242
|
+
if (op === 'S' || op === 'I') {
|
|
243
|
+
for (let i = 0; i < len && currPos < positions.length; i++) {
|
|
244
|
+
if (positions[currPos] === readPos + i) {
|
|
245
|
+
currPos++
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
readPos += len
|
|
249
|
+
} else if (op === 'D' || op === 'N') {
|
|
250
|
+
refPos += len
|
|
251
|
+
} else if (op === 'M' || op === 'X' || op === '=') {
|
|
252
|
+
for (let i = 0; i < len && currPos < positions.length; i++) {
|
|
253
|
+
if (positions[currPos] === readPos + i) {
|
|
254
|
+
yield refPos + i
|
|
255
|
+
currPos++
|
|
256
|
+
}
|
|
251
257
|
}
|
|
258
|
+
readPos += len
|
|
259
|
+
refPos += len
|
|
252
260
|
}
|
|
253
|
-
|
|
254
|
-
yield positions[i] - readPos + refPos
|
|
255
261
|
}
|
|
256
262
|
}
|
|
257
263
|
export function getModificationPositions(
|
|
@@ -260,54 +266,59 @@ export function getModificationPositions(
|
|
|
260
266
|
fstrand: number,
|
|
261
267
|
) {
|
|
262
268
|
const seq = fstrand === -1 ? revcom(fseq) : fseq
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
269
|
+
const mods = mm.split(';').filter(mod => !!mod)
|
|
270
|
+
const result = []
|
|
271
|
+
for (let i = 0; i < mods.length; i++) {
|
|
272
|
+
const mod = mods[i]
|
|
273
|
+
const [basemod, ...skips] = mod.split(',')
|
|
268
274
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
+
// regexes based on parse_mm.pl from hts-specs
|
|
276
|
+
const matches = basemod.match(/([A-Z])([-+])([^,.?]+)([.?])?/)
|
|
277
|
+
if (!matches) {
|
|
278
|
+
throw new Error('bad format for MM tag')
|
|
279
|
+
}
|
|
280
|
+
const [, base, strand, typestr] = matches
|
|
275
281
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
282
|
+
// can be a multi e.g. C+mh for both meth (m) and hydroxymeth (h) so
|
|
283
|
+
// split, and they can also be chemical codes (ChEBI) e.g. C+16061
|
|
284
|
+
const types = typestr.split(/(\d+|.)/).filter(f => !!f)
|
|
279
285
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
286
|
+
if (strand === '-') {
|
|
287
|
+
console.warn('unsupported negative strand modifications')
|
|
288
|
+
// make sure to return a somewhat matching type even in this case
|
|
289
|
+
result.push({ type: 'unsupported', positions: [] as number[] })
|
|
290
|
+
}
|
|
285
291
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
292
|
+
// this logic also based on parse_mm.pl from hts-specs is that in the
|
|
293
|
+
// sequence of the read, if we have a modification type e.g. C+m;2 and a
|
|
294
|
+
// sequence ACGTACGTAC we skip the two instances of C and go to the last
|
|
295
|
+
// C
|
|
296
|
+
for (let j = 0; j < types.length; j++) {
|
|
297
|
+
const type = types[j]
|
|
298
|
+
let i = 0
|
|
299
|
+
const positions = []
|
|
300
|
+
for (let k = 0; k < skips.length; k++) {
|
|
301
|
+
let delta = +skips[k]
|
|
302
|
+
do {
|
|
303
|
+
if (base === 'N' || base === seq[i]) {
|
|
304
|
+
delta--
|
|
305
|
+
}
|
|
306
|
+
i++
|
|
307
|
+
} while (delta >= 0 && i < seq.length)
|
|
308
|
+
|
|
309
|
+
const temp = i - 1
|
|
310
|
+
positions.push(fstrand === -1 ? seq.length - 1 - temp : temp)
|
|
311
|
+
}
|
|
312
|
+
if (fstrand === -1) {
|
|
313
|
+
positions.sort((a, b) => a - b)
|
|
314
|
+
}
|
|
315
|
+
result.push({
|
|
316
|
+
type,
|
|
317
|
+
positions,
|
|
308
318
|
})
|
|
309
|
-
}
|
|
310
|
-
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
return result
|
|
311
322
|
}
|
|
312
323
|
|
|
313
324
|
export function getModificationTypes(mm: string) {
|
|
@@ -20,6 +20,13 @@ interface Header {
|
|
|
20
20
|
readGroups?: number[]
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
interface FilterBy {
|
|
24
|
+
flagInclude: number
|
|
25
|
+
flagExclude: number
|
|
26
|
+
tagFilter: { tag: string; value: unknown }
|
|
27
|
+
readName: string
|
|
28
|
+
}
|
|
29
|
+
|
|
23
30
|
export default class CramAdapter extends BaseFeatureDataAdapter {
|
|
24
31
|
samHeader: Header = {}
|
|
25
32
|
|
|
@@ -206,12 +213,7 @@ export default class CramAdapter extends BaseFeatureDataAdapter {
|
|
|
206
213
|
getFeatures(
|
|
207
214
|
region: Region & { originalRefName?: string },
|
|
208
215
|
opts?: BaseOptions & {
|
|
209
|
-
filterBy:
|
|
210
|
-
flagInclude: number
|
|
211
|
-
flagExclude: number
|
|
212
|
-
tagFilter: { tag: string; value: unknown }
|
|
213
|
-
name: string
|
|
214
|
-
}
|
|
216
|
+
filterBy: FilterBy
|
|
215
217
|
},
|
|
216
218
|
) {
|
|
217
219
|
const { signal, filterBy, statusCallback = () => {} } = opts || {}
|
|
@@ -234,7 +236,7 @@ export default class CramAdapter extends BaseFeatureDataAdapter {
|
|
|
234
236
|
flagInclude = 0,
|
|
235
237
|
flagExclude = 0,
|
|
236
238
|
tagFilter,
|
|
237
|
-
|
|
239
|
+
readName,
|
|
238
240
|
} = filterBy || {}
|
|
239
241
|
|
|
240
242
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -251,9 +253,11 @@ export default class CramAdapter extends BaseFeatureDataAdapter {
|
|
|
251
253
|
})
|
|
252
254
|
}
|
|
253
255
|
|
|
254
|
-
if (
|
|
255
|
-
|
|
256
|
-
|
|
256
|
+
if (readName) {
|
|
257
|
+
filtered = filtered.filter(
|
|
258
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
259
|
+
(record: any) => record.readName === readName,
|
|
260
|
+
)
|
|
257
261
|
}
|
|
258
262
|
|
|
259
263
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|