@jbrowse/plugin-alignments 1.6.7 → 1.7.0

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 (94) hide show
  1. package/dist/AlignmentsFeatureDetail/AlignmentsFeatureDetail.js +216 -0
  2. package/dist/AlignmentsFeatureDetail/index.js +63 -0
  3. package/dist/AlignmentsFeatureDetail/index.test.js +60 -0
  4. package/dist/AlignmentsTrack/index.js +37 -0
  5. package/dist/BamAdapter/BamAdapter.js +598 -0
  6. package/dist/BamAdapter/BamAdapter.test.js +177 -0
  7. package/dist/BamAdapter/BamSlightlyLazyFeature.d.ts +1 -10
  8. package/dist/BamAdapter/BamSlightlyLazyFeature.js +176 -0
  9. package/dist/BamAdapter/MismatchParser.d.ts +3 -5
  10. package/dist/BamAdapter/MismatchParser.js +384 -0
  11. package/dist/BamAdapter/MismatchParser.test.js +259 -0
  12. package/dist/BamAdapter/configSchema.js +48 -0
  13. package/dist/BamAdapter/index.js +36 -0
  14. package/dist/CramAdapter/CramAdapter.js +660 -0
  15. package/dist/CramAdapter/CramAdapter.test.js +138 -0
  16. package/dist/CramAdapter/CramSlightlyLazyFeature.d.ts +1 -2
  17. package/dist/CramAdapter/CramSlightlyLazyFeature.js +447 -0
  18. package/dist/CramAdapter/CramTestAdapters.js +234 -0
  19. package/dist/CramAdapter/configSchema.js +40 -0
  20. package/dist/CramAdapter/index.js +36 -0
  21. package/dist/HtsgetBamAdapter/HtsgetBamAdapter.js +97 -0
  22. package/dist/HtsgetBamAdapter/configSchema.js +31 -0
  23. package/dist/HtsgetBamAdapter/index.js +42 -0
  24. package/dist/LinearAlignmentsDisplay/components/AlignmentsDisplay.js +69 -0
  25. package/dist/LinearAlignmentsDisplay/index.js +31 -0
  26. package/dist/LinearAlignmentsDisplay/models/configSchema.js +25 -0
  27. package/dist/LinearAlignmentsDisplay/models/configSchema.test.js +83 -0
  28. package/dist/LinearAlignmentsDisplay/models/model.js +250 -0
  29. package/dist/LinearPileupDisplay/components/ColorByModifications.js +123 -0
  30. package/dist/LinearPileupDisplay/components/ColorByTag.js +98 -0
  31. package/dist/LinearPileupDisplay/components/FilterByTag.js +203 -0
  32. package/dist/LinearPileupDisplay/components/LinearPileupDisplayBlurb.js +32 -0
  33. package/dist/LinearPileupDisplay/components/SetFeatureHeight.js +99 -0
  34. package/dist/LinearPileupDisplay/components/SetMaxHeight.js +90 -0
  35. package/dist/LinearPileupDisplay/components/SortByTag.js +95 -0
  36. package/dist/LinearPileupDisplay/configSchema.js +47 -0
  37. package/dist/LinearPileupDisplay/configSchema.test.js +92 -0
  38. package/dist/LinearPileupDisplay/index.js +30 -0
  39. package/dist/LinearPileupDisplay/model.js +602 -0
  40. package/dist/LinearSNPCoverageDisplay/components/Tooltip.js +63 -0
  41. package/dist/LinearSNPCoverageDisplay/index.js +30 -0
  42. package/dist/LinearSNPCoverageDisplay/models/configSchema.js +57 -0
  43. package/dist/LinearSNPCoverageDisplay/models/configSchema.test.js +62 -0
  44. package/dist/LinearSNPCoverageDisplay/models/model.d.ts +2 -2
  45. package/dist/LinearSNPCoverageDisplay/models/model.js +237 -0
  46. package/dist/NestedFrequencyTable.js +152 -0
  47. package/dist/PileupRPC/rpcMethods.js +285 -0
  48. package/dist/PileupRenderer/PileupLayoutSession.js +79 -0
  49. package/dist/PileupRenderer/PileupRenderer.d.ts +20 -6
  50. package/dist/PileupRenderer/PileupRenderer.js +1220 -0
  51. package/dist/PileupRenderer/components/PileupRendering.js +270 -0
  52. package/dist/PileupRenderer/components/PileupRendering.test.js +36 -0
  53. package/dist/PileupRenderer/configSchema.js +72 -0
  54. package/dist/PileupRenderer/index.js +25 -0
  55. package/dist/PileupRenderer/sortUtil.js +112 -0
  56. package/dist/SNPCoverageAdapter/SNPCoverageAdapter.d.ts +3 -11
  57. package/dist/SNPCoverageAdapter/SNPCoverageAdapter.js +606 -0
  58. package/dist/SNPCoverageAdapter/configSchema.js +22 -0
  59. package/dist/SNPCoverageAdapter/index.js +45 -0
  60. package/dist/SNPCoverageRenderer/SNPCoverageRenderer.js +296 -0
  61. package/dist/SNPCoverageRenderer/configSchema.js +40 -0
  62. package/dist/SNPCoverageRenderer/index.js +34 -0
  63. package/dist/declare.d.js +1 -0
  64. package/dist/index.js +154 -6
  65. package/dist/index.test.js +26 -0
  66. package/dist/plugin-alignments.cjs.development.js +591 -552
  67. package/dist/plugin-alignments.cjs.development.js.map +1 -1
  68. package/dist/plugin-alignments.cjs.production.min.js +1 -1
  69. package/dist/plugin-alignments.cjs.production.min.js.map +1 -1
  70. package/dist/plugin-alignments.esm.js +594 -555
  71. package/dist/plugin-alignments.esm.js.map +1 -1
  72. package/dist/shared.js +96 -0
  73. package/dist/util.d.ts +4 -0
  74. package/dist/util.js +135 -0
  75. package/package.json +5 -9
  76. package/src/BamAdapter/BamAdapter.ts +45 -15
  77. package/src/BamAdapter/BamSlightlyLazyFeature.ts +11 -79
  78. package/src/BamAdapter/MismatchParser.test.ts +53 -297
  79. package/src/BamAdapter/MismatchParser.ts +54 -116
  80. package/src/BamAdapter/configSchema.ts +0 -4
  81. package/src/CramAdapter/CramAdapter.ts +42 -15
  82. package/src/CramAdapter/CramSlightlyLazyFeature.ts +3 -10
  83. package/src/LinearPileupDisplay/components/ColorByModifications.tsx +76 -80
  84. package/src/LinearPileupDisplay/components/ColorByTag.tsx +24 -23
  85. package/src/LinearPileupDisplay/components/FilterByTag.tsx +73 -68
  86. package/src/LinearPileupDisplay/components/SetFeatureHeight.tsx +28 -26
  87. package/src/LinearPileupDisplay/components/SetMaxHeight.tsx +24 -13
  88. package/src/LinearPileupDisplay/components/SortByTag.tsx +29 -21
  89. package/src/LinearPileupDisplay/model.ts +8 -22
  90. package/src/LinearSNPCoverageDisplay/models/model.ts +6 -36
  91. package/src/PileupRenderer/PileupRenderer.tsx +178 -60
  92. package/src/SNPCoverageAdapter/SNPCoverageAdapter.ts +189 -244
  93. package/src/SNPCoverageRenderer/SNPCoverageRenderer.ts +12 -11
  94. package/src/util.ts +25 -0
@@ -0,0 +1,384 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.cigarToMismatches = cigarToMismatches;
9
+ exports.getMismatches = getMismatches;
10
+ exports.getModificationPositions = getModificationPositions;
11
+ exports.getModificationTypes = getModificationTypes;
12
+ exports.getNextRefPos = getNextRefPos;
13
+ exports.mdToMismatches = mdToMismatches;
14
+ exports.parseCigar = parseCigar;
15
+
16
+ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
17
+
18
+ var _toArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toArray"));
19
+
20
+ var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
21
+
22
+ var _util = require("@jbrowse/core/util");
23
+
24
+ var _marked = /*#__PURE__*/_regenerator["default"].mark(getNextRefPos);
25
+
26
+ var mdRegex = new RegExp(/(\d+|\^[a-z]+|[a-z])/gi);
27
+
28
+ function parseCigar(cigar) {
29
+ return (cigar || '').split(/([MIDNSHPX=])/);
30
+ }
31
+
32
+ function cigarToMismatches(ops, seq, ref, qual) {
33
+ var roffset = 0; // reference offset
34
+
35
+ var soffset = 0; // seq offset
36
+
37
+ var mismatches = [];
38
+ var hasRefAndSeq = ref && seq;
39
+
40
+ for (var i = 0; i < ops.length; i += 2) {
41
+ var len = +ops[i];
42
+ var op = ops[i + 1];
43
+
44
+ if (op === 'M' || op === '=' || op === 'E') {
45
+ if (hasRefAndSeq) {
46
+ for (var j = 0; j < len; j++) {
47
+ if ( // @ts-ignore in the full yarn build of the repo, this says that object is possibly undefined for some reason, ignored
48
+ seq[soffset + j].toUpperCase() !== ref[roffset + j].toUpperCase()) {
49
+ mismatches.push({
50
+ start: roffset + j,
51
+ type: 'mismatch',
52
+ base: seq[soffset + j],
53
+ length: 1
54
+ });
55
+ }
56
+ }
57
+ }
58
+
59
+ soffset += len;
60
+ }
61
+
62
+ if (op === 'I') {
63
+ mismatches.push({
64
+ start: roffset,
65
+ type: 'insertion',
66
+ base: "".concat(len),
67
+ length: 0
68
+ });
69
+ soffset += len;
70
+ } else if (op === 'D') {
71
+ mismatches.push({
72
+ start: roffset,
73
+ type: 'deletion',
74
+ base: '*',
75
+ length: len
76
+ });
77
+ } else if (op === 'N') {
78
+ mismatches.push({
79
+ start: roffset,
80
+ type: 'skip',
81
+ base: 'N',
82
+ length: len
83
+ });
84
+ } else if (op === 'X') {
85
+ var r = seq.slice(soffset, soffset + len);
86
+ var q = (qual === null || qual === void 0 ? void 0 : qual.slice(soffset, soffset + len)) || [];
87
+
88
+ for (var _j = 0; _j < len; _j++) {
89
+ mismatches.push({
90
+ start: roffset + _j,
91
+ type: 'mismatch',
92
+ base: r[_j],
93
+ qual: q[_j],
94
+ length: 1
95
+ });
96
+ }
97
+
98
+ soffset += len;
99
+ } else if (op === 'H') {
100
+ mismatches.push({
101
+ start: roffset,
102
+ type: 'hardclip',
103
+ base: "H".concat(len),
104
+ cliplen: len,
105
+ length: 1
106
+ });
107
+ } else if (op === 'S') {
108
+ mismatches.push({
109
+ start: roffset,
110
+ type: 'softclip',
111
+ base: "S".concat(len),
112
+ cliplen: len,
113
+ length: 1
114
+ });
115
+ soffset += len;
116
+ }
117
+
118
+ if (op !== 'I' && op !== 'S' && op !== 'H') {
119
+ roffset += len;
120
+ }
121
+ }
122
+
123
+ return mismatches;
124
+ }
125
+ /**
126
+ * parse a SAM MD tag to find mismatching bases of the template versus the reference
127
+ * @returns array of mismatches and their positions
128
+ */
129
+
130
+
131
+ function mdToMismatches(mdstring, ops, cigarMismatches, seq, qual) {
132
+ var mismatchRecords = [];
133
+ var curr = {
134
+ start: 0,
135
+ base: '',
136
+ length: 0,
137
+ type: 'mismatch'
138
+ };
139
+ var skips = cigarMismatches.filter(function (cigar) {
140
+ return cigar.type === 'skip';
141
+ });
142
+ var lastCigar = 0;
143
+ var lastTemplateOffset = 0;
144
+ var lastRefOffset = 0;
145
+ var lastSkipPos = 0; // convert a position on the reference sequence to a position
146
+ // on the template sequence, taking into account hard and soft
147
+ // clipping of reads
148
+
149
+ function nextRecord() {
150
+ mismatchRecords.push(curr); // get a new mismatch record ready
151
+
152
+ curr = {
153
+ start: curr.start + curr.length,
154
+ length: 0,
155
+ base: '',
156
+ type: 'mismatch'
157
+ };
158
+ }
159
+
160
+ function getTemplateCoordLocal(refCoord) {
161
+ var templateOffset = lastTemplateOffset;
162
+ var refOffset = lastRefOffset;
163
+
164
+ for (var i = lastCigar; i < ops.length && refOffset <= refCoord; i += 2, lastCigar = i) {
165
+ var len = +ops[i];
166
+ var op = ops[i + 1];
167
+
168
+ if (op === 'S' || op === 'I') {
169
+ templateOffset += len;
170
+ } else if (op === 'D' || op === 'P' || op === 'N') {
171
+ refOffset += len;
172
+ } else if (op !== 'H') {
173
+ templateOffset += len;
174
+ refOffset += len;
175
+ }
176
+ }
177
+
178
+ lastTemplateOffset = templateOffset;
179
+ lastRefOffset = refOffset;
180
+ return templateOffset - (refOffset - refCoord);
181
+ } // now actually parse the MD string
182
+
183
+
184
+ var md = mdstring.match(mdRegex) || [];
185
+
186
+ for (var i = 0; i < md.length; i++) {
187
+ var token = md[i];
188
+ var num = +token;
189
+
190
+ if (!Number.isNaN(num)) {
191
+ curr.start += num;
192
+ } else if (token.startsWith('^')) {
193
+ curr.start += token.length - 1;
194
+ } else {
195
+ // mismatch
196
+ for (var j = 0; j < token.length; j += 1) {
197
+ curr.length = 1;
198
+
199
+ while (lastSkipPos < skips.length) {
200
+ var mismatch = skips[lastSkipPos];
201
+
202
+ if (curr.start >= mismatch.start) {
203
+ curr.start += mismatch.length;
204
+ lastSkipPos++;
205
+ } else {
206
+ break;
207
+ }
208
+ }
209
+
210
+ var s = getTemplateCoordLocal(curr.start);
211
+ curr.base = seq[s] || 'X';
212
+ var qualScore = qual === null || qual === void 0 ? void 0 : qual[s];
213
+
214
+ if (qualScore) {
215
+ curr.qual = qualScore;
216
+ }
217
+
218
+ curr.altbase = token;
219
+ nextRecord();
220
+ }
221
+ }
222
+ }
223
+
224
+ return mismatchRecords;
225
+ }
226
+
227
+ function getMismatches(cigar, md, seq, ref, qual) {
228
+ var mismatches = [];
229
+ var ops = parseCigar(cigar); // parse the CIGAR tag if it has one
230
+
231
+ if (cigar) {
232
+ mismatches = mismatches.concat(cigarToMismatches(ops, seq, ref, qual));
233
+ } // now let's look for CRAM or MD mismatches
234
+
235
+
236
+ if (md) {
237
+ mismatches = mismatches.concat(mdToMismatches(md, ops, mismatches, seq, qual));
238
+ }
239
+
240
+ return mismatches;
241
+ } // get relative reference sequence positions for positions given relative to
242
+ // the read sequence
243
+
244
+
245
+ function getNextRefPos(cigarOps, positions) {
246
+ var cigarIdx, readPos, refPos, i, pos, len, op;
247
+ return _regenerator["default"].wrap(function getNextRefPos$(_context) {
248
+ while (1) {
249
+ switch (_context.prev = _context.next) {
250
+ case 0:
251
+ cigarIdx = 0;
252
+ readPos = 0;
253
+ refPos = 0;
254
+ i = 0;
255
+
256
+ case 4:
257
+ if (!(i < positions.length)) {
258
+ _context.next = 12;
259
+ break;
260
+ }
261
+
262
+ pos = positions[i];
263
+
264
+ for (; cigarIdx < cigarOps.length && readPos < pos; cigarIdx += 2) {
265
+ len = +cigarOps[cigarIdx];
266
+ op = cigarOps[cigarIdx + 1];
267
+
268
+ if (op === 'S' || op === 'I') {
269
+ readPos += len;
270
+ } else if (op === 'D' || op === 'N') {
271
+ refPos += len;
272
+ } else if (op === 'M' || op === 'X' || op === '=') {
273
+ readPos += len;
274
+ refPos += len;
275
+ }
276
+ }
277
+
278
+ _context.next = 9;
279
+ return positions[i] - readPos + refPos;
280
+
281
+ case 9:
282
+ i++;
283
+ _context.next = 4;
284
+ break;
285
+
286
+ case 12:
287
+ case "end":
288
+ return _context.stop();
289
+ }
290
+ }
291
+ }, _marked);
292
+ }
293
+
294
+ function getModificationPositions(mm, fseq, fstrand) {
295
+ var seq = fstrand === -1 ? (0, _util.revcom)(fseq) : fseq;
296
+ return mm.split(';').filter(function (mod) {
297
+ return !!mod;
298
+ }).map(function (mod) {
299
+ var _mod$split = mod.split(','),
300
+ _mod$split2 = (0, _toArray2["default"])(_mod$split),
301
+ basemod = _mod$split2[0],
302
+ skips = _mod$split2.slice(1); // regexes based on parse_mm.pl from hts-specs
303
+
304
+
305
+ var matches = basemod.match(/([A-Z])([-+])([^,.?]+)([.?])?/);
306
+
307
+ if (!matches) {
308
+ throw new Error('bad format for MM tag');
309
+ }
310
+
311
+ var _matches = (0, _slicedToArray2["default"])(matches, 4),
312
+ base = _matches[1],
313
+ strand = _matches[2],
314
+ typestr = _matches[3]; // can be a multi e.g. C+mh for both meth (m) and hydroxymeth (h) so
315
+ // split, and they can also be chemical codes (ChEBI) e.g. C+16061
316
+
317
+
318
+ var types = typestr.split(/(\d+|.)/).filter(function (f) {
319
+ return !!f;
320
+ });
321
+
322
+ if (strand === '-') {
323
+ console.warn('unsupported negative strand modifications'); // make sure to return a somewhat matching type even in this case
324
+
325
+ return {
326
+ type: 'unsupported',
327
+ positions: []
328
+ };
329
+ } // this logic also based on parse_mm.pl from hts-specs is that in the
330
+ // sequence of the read, if we have a modification type e.g. C+m;2 and a
331
+ // sequence ACGTACGTAC we skip the two instances of C and go to the last
332
+ // C
333
+
334
+
335
+ return types.map(function (type) {
336
+ var i = 0;
337
+ return {
338
+ type: type,
339
+ positions: skips.map(function (score) {
340
+ return +score;
341
+ }).map(function (delta) {
342
+ do {
343
+ if (base === 'N' || base === seq[i]) {
344
+ delta--;
345
+ }
346
+
347
+ i++;
348
+ } while (delta >= 0 && i < seq.length);
349
+
350
+ var temp = i - 1;
351
+ return fstrand === -1 ? seq.length - 1 - temp : temp;
352
+ }).sort(function (a, b) {
353
+ return a - b;
354
+ })
355
+ };
356
+ });
357
+ }).flat();
358
+ }
359
+
360
+ function getModificationTypes(mm) {
361
+ var mods = mm.split(';');
362
+ return mods.filter(function (mod) {
363
+ return !!mod;
364
+ }).map(function (mod) {
365
+ var _mod$split3 = mod.split(','),
366
+ _mod$split4 = (0, _slicedToArray2["default"])(_mod$split3, 1),
367
+ basemod = _mod$split4[0];
368
+
369
+ var matches = basemod.match(/([A-Z])([-+])([^,]+)/);
370
+
371
+ if (!matches) {
372
+ throw new Error('bad format for MM tag');
373
+ }
374
+
375
+ var _matches2 = (0, _slicedToArray2["default"])(matches, 4),
376
+ typestr = _matches2[3]; // can be a multi e.g. C+mh for both meth (m) and hydroxymeth (h) so
377
+ // split, and they can also be chemical codes (ChEBI) e.g. C+16061
378
+
379
+
380
+ return typestr.split(/(\d+|.)/).filter(function (f) {
381
+ return !!f;
382
+ });
383
+ }).flat();
384
+ }
@@ -0,0 +1,259 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
5
+ var _toArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toArray"));
6
+
7
+ var _MismatchParser = require("./MismatchParser");
8
+
9
+ var seq = 'AAAAAAAAAACAAAAAAAAAAAAAACCCCCCCCCCCCCCCCCCCCCCCCCGGGGGGGGGGGGGGGGGGGGGGGGGTTTTTTTTTTTTTTTTTTTTTTTTT'; // examples come from https://github.com/vsbuffalo/devnotes/wiki/The-MD-Tag-in-BAM-Files
10
+ // and http://seqanswers.com/forums/showthread.php?t=8978
11
+
12
+ test('cigar to mismatches', function () {
13
+ expect((0, _MismatchParser.cigarToMismatches)((0, _MismatchParser.parseCigar)('56M1D45M'), seq)).toEqual([{
14
+ start: 56,
15
+ type: 'deletion',
16
+ base: '*',
17
+ length: 1
18
+ }]);
19
+ });
20
+ test('md to mismatches', function () {
21
+ var cigarMismatches = (0, _MismatchParser.cigarToMismatches)((0, _MismatchParser.parseCigar)('56M1D45M'), seq);
22
+ expect((0, _MismatchParser.mdToMismatches)('10A80', (0, _MismatchParser.parseCigar)('56M1D45M'), cigarMismatches, seq)).toEqual([{
23
+ start: 10,
24
+ type: 'mismatch',
25
+ base: 'C',
26
+ altbase: 'A',
27
+ length: 1
28
+ }]);
29
+ });
30
+ describe('get mismatches', function () {
31
+ it('simple deletion', function () {
32
+ // simple deletion
33
+ expect((0, _MismatchParser.getMismatches)('56M1D45M', '56^A45', seq)).toEqual([{
34
+ start: 56,
35
+ type: 'deletion',
36
+ base: '*',
37
+ length: 1
38
+ }]);
39
+ });
40
+ it('simple insertion', function () {
41
+ // simple insertion
42
+ expect((0, _MismatchParser.getMismatches)('89M1I11M', '100', 'AAAAAAAAAACAAAAAAAAAAAAAACCCCCCCCCCCCCCCCCCCCCCCCCGGGGGGGGGGGGGGGGGGGGGGGGGTTTTTTTTTTTTTTTTTTTTTTTTTA')).toEqual([{
43
+ start: 89,
44
+ type: 'insertion',
45
+ base: '1',
46
+ length: 0
47
+ }]);
48
+ });
49
+ it('deletion and a SNP', function () {
50
+ // contains a deletion and a SNP
51
+ // read GGGGG--ATTTTTT
52
+ // ||||| ||||||
53
+ // GGGGGACCTTTTTT
54
+ expect((0, _MismatchParser.getMismatches)('5M2D6M', '5^AC0C5', 'GGGGGATTTTTT')).toEqual([{
55
+ start: 5,
56
+ type: 'deletion',
57
+ base: '*',
58
+ length: 2
59
+ }, {
60
+ start: 7,
61
+ type: 'mismatch',
62
+ base: 'A',
63
+ altbase: 'C',
64
+ length: 1
65
+ }]);
66
+ });
67
+ it('0-length MD entries', function () {
68
+ // 0-length MD entries, which indicates two SNPs right next to each other
69
+ // "They generally occur between SNPs, or between a deletion then a SNP."
70
+ // http://seqanswers.com/forums/showthread.php?t=8978
71
+ //
72
+ // read GGGGGCATTTTT
73
+ // ||||| |||||
74
+ // ref GGGGGACTTTTT
75
+ expect((0, _MismatchParser.getMismatches)('12M', '5A0C5', 'GGGGGCATTTTT')).toEqual([{
76
+ altbase: 'A',
77
+ base: 'C',
78
+ length: 1,
79
+ start: 5,
80
+ type: 'mismatch'
81
+ }, {
82
+ altbase: 'C',
83
+ base: 'A',
84
+ length: 1,
85
+ start: 6,
86
+ type: 'mismatch'
87
+ }]);
88
+ });
89
+ it('non-0-length-MD string', function () {
90
+ // same as above but with the non-0-length MD string
91
+ // not sure if it is entirely legal, but may appear in the wild
92
+ expect((0, _MismatchParser.getMismatches)('12M', '5AC5', 'GGGGGCATTTTT')).toEqual([{
93
+ altbase: 'A',
94
+ base: 'C',
95
+ length: 1,
96
+ start: 5,
97
+ type: 'mismatch'
98
+ }, {
99
+ altbase: 'C',
100
+ base: 'A',
101
+ length: 1,
102
+ start: 6,
103
+ type: 'mismatch'
104
+ }]);
105
+ });
106
+ });
107
+ test('basic skip', function () {
108
+ expect((0, _MismatchParser.getMismatches)('6M200N6M', '5AC5', 'GGGGGCATTTTT')).toEqual([{
109
+ base: 'N',
110
+ length: 200,
111
+ start: 6,
112
+ type: 'skip'
113
+ }, {
114
+ altbase: 'A',
115
+ base: 'C',
116
+ length: 1,
117
+ start: 5,
118
+ type: 'mismatch'
119
+ }, {
120
+ altbase: 'C',
121
+ base: 'A',
122
+ length: 1,
123
+ start: 206,
124
+ type: 'mismatch'
125
+ }]);
126
+ });
127
+ test('vsbuffalo', function () {
128
+ // https://github.com/vsbuffalo/devnotes/wiki/The-MD-Tag-in-BAM-Files
129
+ // example 1
130
+ expect((0, _MismatchParser.getMismatches)('89M1I11M', '100', 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA')).toEqual([{
131
+ base: '1',
132
+ length: 0,
133
+ start: 89,
134
+ type: 'insertion'
135
+ }]); // https://github.com/vsbuffalo/devnotes/wiki/The-MD-Tag-in-BAM-Files
136
+ // example 2
137
+
138
+ expect((0, _MismatchParser.getMismatches)('9M1I91M', '48T42G8', 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA')).toEqual([{
139
+ base: '1',
140
+ length: 0,
141
+ start: 9,
142
+ type: 'insertion'
143
+ }, {
144
+ altbase: 'T',
145
+ base: 'A',
146
+ length: 1,
147
+ start: 48,
148
+ type: 'mismatch'
149
+ }, {
150
+ altbase: 'G',
151
+ base: 'A',
152
+ length: 1,
153
+ start: 91,
154
+ type: 'mismatch'
155
+ }]);
156
+ });
157
+ test('more skip', function () {
158
+ expect((0, _MismatchParser.getMismatches)('3M200N3M200N3M', '8A', 'GGGGGCATTTTT')).toEqual([{
159
+ base: 'N',
160
+ length: 200,
161
+ start: 3,
162
+ type: 'skip'
163
+ }, {
164
+ base: 'N',
165
+ length: 200,
166
+ start: 206,
167
+ type: 'skip'
168
+ }, {
169
+ altbase: 'A',
170
+ base: 'T',
171
+ length: 1,
172
+ start: 408,
173
+ type: 'mismatch'
174
+ }]);
175
+ expect((0, _MismatchParser.getMismatches)('31M1I17M1D37M', '6G4C20G1A5C5A1^C3A15G1G15', seq).sort(function (a, b) {
176
+ return a.start - b.start;
177
+ })).toMatchInlineSnapshot("\n Array [\n Object {\n \"altbase\": \"G\",\n \"base\": \"A\",\n \"length\": 1,\n \"start\": 6,\n \"type\": \"mismatch\",\n },\n Object {\n \"altbase\": \"C\",\n \"base\": \"A\",\n \"length\": 1,\n \"start\": 11,\n \"type\": \"mismatch\",\n },\n Object {\n \"base\": \"1\",\n \"length\": 0,\n \"start\": 31,\n \"type\": \"insertion\",\n },\n Object {\n \"altbase\": \"G\",\n \"base\": \"C\",\n \"length\": 1,\n \"start\": 32,\n \"type\": \"mismatch\",\n },\n Object {\n \"altbase\": \"A\",\n \"base\": \"C\",\n \"length\": 1,\n \"start\": 34,\n \"type\": \"mismatch\",\n },\n Object {\n \"altbase\": \"C\",\n \"base\": \"C\",\n \"length\": 1,\n \"start\": 40,\n \"type\": \"mismatch\",\n },\n Object {\n \"altbase\": \"A\",\n \"base\": \"C\",\n \"length\": 1,\n \"start\": 46,\n \"type\": \"mismatch\",\n },\n Object {\n \"base\": \"*\",\n \"length\": 1,\n \"start\": 48,\n \"type\": \"deletion\",\n },\n Object {\n \"altbase\": \"A\",\n \"base\": \"G\",\n \"length\": 1,\n \"start\": 52,\n \"type\": \"mismatch\",\n },\n Object {\n \"altbase\": \"G\",\n \"base\": \"G\",\n \"length\": 1,\n \"start\": 68,\n \"type\": \"mismatch\",\n },\n Object {\n \"altbase\": \"G\",\n \"base\": \"G\",\n \"length\": 1,\n \"start\": 70,\n \"type\": \"mismatch\",\n },\n ]\n ");
178
+ });
179
+ test('clipping', function () {
180
+ expect((0, _MismatchParser.getMismatches)('200H10M200H', '9A', 'AAAAAAAAAC')).toEqual([{
181
+ cliplen: 200,
182
+ base: 'H200',
183
+ length: 1,
184
+ start: 0,
185
+ type: 'hardclip'
186
+ }, {
187
+ cliplen: 200,
188
+ base: 'H200',
189
+ length: 1,
190
+ start: 10,
191
+ type: 'hardclip'
192
+ }, {
193
+ altbase: 'A',
194
+ base: 'C',
195
+ length: 1,
196
+ start: 9,
197
+ type: 'mismatch'
198
+ }]);
199
+ expect((0, _MismatchParser.getMismatches)('10S10M10S', '9A', 'AAAAAAAAAAGGGGGGGGGC')).toEqual([{
200
+ cliplen: 10,
201
+ base: 'S10',
202
+ length: 1,
203
+ start: 0,
204
+ type: 'softclip'
205
+ }, {
206
+ cliplen: 10,
207
+ base: 'S10',
208
+ length: 1,
209
+ start: 10,
210
+ type: 'softclip'
211
+ }, {
212
+ altbase: 'A',
213
+ base: 'C',
214
+ length: 1,
215
+ start: 9,
216
+ type: 'mismatch'
217
+ }]);
218
+ });
219
+ test('getNextRefPos basic', function () {
220
+ var cigar = (0, _MismatchParser.parseCigar)('10S10M1I4M1D15M');
221
+ var iter = (0, _MismatchParser.getNextRefPos)(cigar, [5, 10, 15, 20, 25, 30, 35]);
222
+
223
+ var _iter = (0, _toArray2["default"])(iter),
224
+ vals = _iter.slice(0);
225
+
226
+ expect(vals).toEqual([-5, 0, 5, 10, 14, 20, 25]);
227
+ });
228
+ test('getNextRefPos with many indels', function () {
229
+ var cigar = (0, _MismatchParser.parseCigar)('10S4M1D1IM10');
230
+ var iter = (0, _MismatchParser.getNextRefPos)(cigar, [5, 10, 15]);
231
+
232
+ var _iter2 = (0, _toArray2["default"])(iter),
233
+ vals = _iter2.slice(0);
234
+
235
+ expect(vals).toEqual([-5, 0, 5]);
236
+ });
237
+ test('getModificationPositions', function () {
238
+ var positions = (0, _MismatchParser.getModificationPositions)('C+m,2,2,1,4,1', 'AGCTCTCCAGAGTCGNACGCCATYCGCGCGCCACCA', 1);
239
+ expect(positions[0]).toEqual({
240
+ type: 'm',
241
+ positions: [6, 17, 20, 31, 34]
242
+ });
243
+ }); // ? means "modification status of the skipped bases provided."
244
+
245
+ test('getModificationPositions with unknown (?)', function () {
246
+ var positions = (0, _MismatchParser.getModificationPositions)('C+m?,2,2,1,4,1', 'AGCTCTCCAGAGTCGNACGCCATYCGCGCGCCACCA', 1);
247
+ expect(positions[0]).toEqual({
248
+ type: 'm',
249
+ positions: [6, 17, 20, 31, 34]
250
+ });
251
+ }); // . means "modification status of the skipped bases is low probability"
252
+
253
+ test('getModificationPositions with unknown (.)', function () {
254
+ var positions = (0, _MismatchParser.getModificationPositions)('C+m.,2,2,1,4,1', 'AGCTCTCCAGAGTCGNACGCCATYCGCGCGCCACCA', 1);
255
+ expect(positions[0]).toEqual({
256
+ type: 'm',
257
+ positions: [6, 17, 20, 31, 34]
258
+ });
259
+ });
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports["default"] = void 0;
7
+
8
+ var _configuration = require("@jbrowse/core/configuration");
9
+
10
+ var _mobxStateTree = require("mobx-state-tree");
11
+
12
+ var _default = _mobxStateTree.types.late(function () {
13
+ return (0, _configuration.ConfigurationSchema)('BamAdapter', {
14
+ bamLocation: {
15
+ type: 'fileLocation',
16
+ defaultValue: {
17
+ uri: '/path/to/my.bam',
18
+ locationType: 'UriLocation'
19
+ }
20
+ },
21
+ index: (0, _configuration.ConfigurationSchema)('BamIndex', {
22
+ indexType: {
23
+ model: _mobxStateTree.types.enumeration('IndexType', ['BAI', 'CSI']),
24
+ type: 'stringEnum',
25
+ defaultValue: 'BAI'
26
+ },
27
+ location: {
28
+ type: 'fileLocation',
29
+ defaultValue: {
30
+ uri: '/path/to/my.bam.bai',
31
+ locationType: 'UriLocation'
32
+ }
33
+ }
34
+ }),
35
+ fetchSizeLimit: {
36
+ type: 'number',
37
+ defaultValue: 5000000
38
+ },
39
+ sequenceAdapter: {
40
+ type: 'frozen',
41
+ defaultValue: null
42
+ }
43
+ }, {
44
+ explicitlyTyped: true
45
+ });
46
+ });
47
+
48
+ exports["default"] = _default;