@gmod/bam 8.5.1 → 8.6.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 (51) hide show
  1. package/README.md +30 -0
  2. package/dist/bamFile.d.ts +94 -1
  3. package/dist/bamFile.js +94 -3
  4. package/dist/bamFile.js.map +1 -1
  5. package/dist/htsget.d.ts +8 -1
  6. package/dist/htsget.js +4 -1
  7. package/dist/htsget.js.map +1 -1
  8. package/dist/index.d.ts +5 -1
  9. package/dist/index.js +15 -1
  10. package/dist/index.js.map +1 -1
  11. package/dist/mismatches.d.ts +114 -0
  12. package/dist/mismatches.js +397 -0
  13. package/dist/mismatches.js.map +1 -0
  14. package/dist/record.d.ts +45 -0
  15. package/dist/record.js +76 -10
  16. package/dist/record.js.map +1 -1
  17. package/dist/reference.d.ts +45 -0
  18. package/dist/reference.js +61 -0
  19. package/dist/reference.js.map +1 -0
  20. package/dist/seqAlphabet.d.ts +3 -0
  21. package/dist/seqAlphabet.js +14 -0
  22. package/dist/seqAlphabet.js.map +1 -0
  23. package/esm/bamFile.d.ts +94 -1
  24. package/esm/bamFile.js +94 -3
  25. package/esm/bamFile.js.map +1 -1
  26. package/esm/htsget.d.ts +8 -1
  27. package/esm/htsget.js +4 -1
  28. package/esm/htsget.js.map +1 -1
  29. package/esm/index.d.ts +5 -1
  30. package/esm/index.js +6 -0
  31. package/esm/index.js.map +1 -1
  32. package/esm/mismatches.d.ts +114 -0
  33. package/esm/mismatches.js +393 -0
  34. package/esm/mismatches.js.map +1 -0
  35. package/esm/record.d.ts +45 -0
  36. package/esm/record.js +69 -3
  37. package/esm/record.js.map +1 -1
  38. package/esm/reference.d.ts +45 -0
  39. package/esm/reference.js +55 -0
  40. package/esm/reference.js.map +1 -0
  41. package/esm/seqAlphabet.d.ts +3 -0
  42. package/esm/seqAlphabet.js +11 -0
  43. package/esm/seqAlphabet.js.map +1 -0
  44. package/package.json +1 -1
  45. package/src/bamFile.ts +178 -1
  46. package/src/htsget.ts +16 -2
  47. package/src/index.ts +26 -1
  48. package/src/mismatches.ts +623 -0
  49. package/src/record.ts +95 -3
  50. package/src/reference.ts +87 -0
  51. package/src/seqAlphabet.ts +10 -0
@@ -0,0 +1,397 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MISMATCH_HARD_CLIP = exports.MISMATCH_SOFT_CLIP = exports.MISMATCH_REF_SKIP = exports.MISMATCH_DELETION = exports.MISMATCH_INSERTION = exports.MISMATCH_SUBST = void 0;
4
+ exports.forEachMismatchNumeric = forEachMismatchNumeric;
5
+ const cigar_ts_1 = require("./cigar.js");
6
+ const reference_ts_1 = require("./reference.js");
7
+ const seqAlphabet_ts_1 = require("./seqAlphabet.js");
8
+ /**
9
+ * The kind of difference a {@link Mismatch} reports, as the CIGAR-style char
10
+ * code it corresponds to. `@gmod/cram`'s `forEachMismatch` emits the same
11
+ * values (its `RF_*` constants), so one `switch` handles records from either
12
+ * format.
13
+ *
14
+ * Note these are char codes and NOT the packed-CIGAR op numbers in `cigar.ts`
15
+ * — `MISMATCH_DELETION` is 68 (`'D'`), where `CIGAR_DEL` is 2.
16
+ */
17
+ exports.MISMATCH_SUBST = 88; // 'X'
18
+ exports.MISMATCH_INSERTION = 73; // 'I'
19
+ exports.MISMATCH_DELETION = 68; // 'D'
20
+ exports.MISMATCH_REF_SKIP = 78; // 'N'
21
+ exports.MISMATCH_SOFT_CLIP = 83; // 'S'
22
+ exports.MISMATCH_HARD_CLIP = 72; // 'H'
23
+ // M and = both mean "aligned to the reference", differing only in whether the
24
+ // file promises the bases match. Which is exactly the distinction MD (or the
25
+ // reference) exists to settle, so the walk treats them identically.
26
+ const CIGAR_M_EQ_MASK = (1 << cigar_ts_1.CIGAR_MATCH) | (1 << cigar_ts_1.CIGAR_EQUAL);
27
+ // A clip has no bases to report — its length travels in `clipLength`, which is
28
+ // what every consumer reads.
29
+ const NO_BASES = '';
30
+ function reportRefMismatch(callback, refPos, seqNibble, qual, refNibble) {
31
+ callback(exports.MISMATCH_SUBST, refPos, 1, seqAlphabet_ts_1.SEQRET_DECODER[seqNibble], qual, reference_ts_1.CHAR_CODE_FROM_NIBBLE[refNibble], 0);
32
+ }
33
+ // One base compared on its own: the ends of a run whose length or alignment
34
+ // leaves it without a partner in the same byte.
35
+ function compareRefBase(callback, numericSeq, qual, ref, seqIdx, refIdx, refPos) {
36
+ const seqNibble = (numericSeq[seqIdx >> 1] >> ((1 - (seqIdx & 1)) << 2)) & 0xf;
37
+ const refNibble = (0, reference_ts_1.referenceNibble)(ref, refIdx);
38
+ if (seqNibble !== refNibble) {
39
+ reportRefMismatch(callback, refPos, seqNibble, qual ? qual[seqIdx] : -1, refNibble);
40
+ }
41
+ }
42
+ /**
43
+ * The mismatch walk over a record's already-packed fields, for callers holding
44
+ * BAM's arrays without a {@link BamRecord} around them — a SAM parser, or a
45
+ * worker that was handed the typed arrays rather than the record.
46
+ * `record.forEachMismatch()` is this function with the record's own fields
47
+ * filled in, and is what most code should call.
48
+ *
49
+ * Nothing here allocates per difference except the `bases` string, and that
50
+ * only for substitutions and insertions.
51
+ *
52
+ * @param cigar packed CIGAR ops, i.e. `record.NUMERIC_CIGAR`
53
+ * @param numericSeq 4-bit packed SEQ, i.e. `record.NUMERIC_SEQ`
54
+ * @param seqLength bases in `numericSeq`; 0 for a read stored with `SEQ` of `*`
55
+ * @param md the MD tag's bytes (`record.NUMERIC_MD`), or undefined. Preferred
56
+ * over `ref` when present, being both cheaper and what the aligner asserted
57
+ * @param qual per-base quality scores, or null/undefined when the read has none
58
+ * @param ref reference bases to compare against when there is no MD tag. Bases
59
+ * the region does not cover are left uncompared
60
+ * @param refStart the record's own 0-based start, which every reported position
61
+ * is relative to
62
+ * @param windowStart 0-based half-open reference window to report within. Pass
63
+ * `-Infinity`/`Infinity` for the whole read; a viewport that clips the walk
64
+ * is what keeps a chromosome-spanning contig alignment from being walked in
65
+ * full for every screenful
66
+ * @param windowEnd
67
+ * @param callback `(code, refPos, length, bases, qual, refBaseCode, clipLength)`
68
+ */
69
+ function forEachMismatchNumeric(cigar, numericSeq, seqLength, md, qual, ref, refStart, windowStart, windowEnd, callback) {
70
+ // The walk runs in read-relative offsets — `roffset` reference bases and
71
+ // `soffset` read bases consumed — and converts back at the callback, so the
72
+ // window is converted once here rather than per op.
73
+ //
74
+ // Clamped to int32 rather than left at the ±Infinity an unwindowed walk
75
+ // passes, because every op of the walk compares an offset against these and
76
+ // Infinity makes each of those a Float64 comparison. BAM positions are int32,
77
+ // so this cannot narrow a window anyone can express.
78
+ const winLo = windowStart <= -0x80000000 ? -0x80000000 : windowStart - refStart;
79
+ const winHi = windowEnd >= 0x7fffffff ? 0x7fffffff : windowEnd - refStart;
80
+ // Fast path for reads with no sequence (e.g. secondary alignments with SEQ='*')
81
+ if (seqLength === 0) {
82
+ let roffset = 0;
83
+ for (let i = 0, l = cigar.length; i < l; i++) {
84
+ // `roffset` only grows, and nothing at or past the window's right edge is
85
+ // reported, so the rest of the CIGAR cannot produce anything (see the
86
+ // same check in the main loop)
87
+ if (roffset >= winHi) {
88
+ break;
89
+ }
90
+ const packed = cigar[i];
91
+ const len = packed >>> 4;
92
+ const op = packed & 0xf;
93
+ // X consumes the reference exactly like M/=; without a sequence there are
94
+ // no bases to report for it, but it still has to advance — leaving it out
95
+ // shifted every later op left by the total X length, which is every indel
96
+ // in an --eqx CIGAR walked without a sequence.
97
+ if ((1 << op) & CIGAR_M_EQ_MASK || op === cigar_ts_1.CIGAR_DIFF) {
98
+ roffset += len;
99
+ }
100
+ else if (op === cigar_ts_1.CIGAR_INS) {
101
+ if (roffset >= winLo && roffset < winHi) {
102
+ callback(exports.MISMATCH_INSERTION, refStart + roffset, 0, '', -1, 0, len);
103
+ }
104
+ }
105
+ else if (op === cigar_ts_1.CIGAR_DEL) {
106
+ if (roffset < winHi && roffset + len > winLo) {
107
+ callback(exports.MISMATCH_DELETION, refStart + roffset, len, NO_BASES, -1, 0, 0);
108
+ }
109
+ roffset += len;
110
+ }
111
+ else if (op === cigar_ts_1.CIGAR_REF_SKIP) {
112
+ if (roffset < winHi && roffset + len > winLo) {
113
+ callback(exports.MISMATCH_REF_SKIP, refStart + roffset, len, NO_BASES, -1, 0, 0);
114
+ }
115
+ roffset += len;
116
+ }
117
+ else if (op === cigar_ts_1.CIGAR_SOFT_CLIP) {
118
+ if (roffset >= winLo && roffset < winHi) {
119
+ callback(exports.MISMATCH_SOFT_CLIP, refStart + roffset, 0, NO_BASES, -1, 0, len);
120
+ }
121
+ }
122
+ else if (op === cigar_ts_1.CIGAR_HARD_CLIP) {
123
+ if (roffset >= winLo && roffset < winHi) {
124
+ callback(exports.MISMATCH_HARD_CLIP, refStart + roffset, 0, NO_BASES, -1, 0, len);
125
+ }
126
+ }
127
+ }
128
+ return;
129
+ }
130
+ const mdLength = md?.length ?? 0;
131
+ const hasQual = !!qual;
132
+ const hasMD = md && mdLength > 0;
133
+ // Where the reference region sits in read-relative offsets, and the window
134
+ // narrowed to it. Only base COMPARISON is bounded by the region — an indel or
135
+ // a clip needs no reference base, so a region covering part of a read still
136
+ // reports every one of them.
137
+ //
138
+ // Ternaries rather than Math.max/Math.min, which matters more than it looks:
139
+ // an unwindowed walk has `winLo`/`winHi` at ±Infinity, so Math.min would hand
140
+ // back a Float64 and `cmpHi` would carry that all the way into `jHi`, the
141
+ // bound of the innermost (two-bases-per-byte) loop. This way an unwindowed
142
+ // walk keeps that bound a Smi, which measured ~8% of the reference path on
143
+ // dense short reads.
144
+ let refOffset = 0;
145
+ let cmpLo = 0;
146
+ let cmpHi = 0;
147
+ if (ref !== undefined) {
148
+ refOffset = refStart - ref.start;
149
+ const refLo = -refOffset;
150
+ const refHi = ref.length - refOffset;
151
+ cmpLo = winLo > refLo ? winLo : refLo;
152
+ cmpHi = winHi < refHi ? winHi : refHi;
153
+ }
154
+ let roffset = 0;
155
+ let soffset = 0;
156
+ let mdIdx = 0;
157
+ let mdMatchRemaining = 0;
158
+ if (hasMD) {
159
+ while (mdIdx < mdLength) {
160
+ const c = md[mdIdx];
161
+ if (c >= 48 && c <= 57) {
162
+ mdMatchRemaining = mdMatchRemaining * 10 + (c - 48);
163
+ mdIdx++;
164
+ }
165
+ else {
166
+ break;
167
+ }
168
+ }
169
+ }
170
+ for (let i = 0, l = cigar.length; i < l; i++) {
171
+ // Stop at the window's right edge rather than walking the rest of the
172
+ // CIGAR: `roffset` only grows, and every report below needs
173
+ // `roffset < winHi`, so nothing past here can produce anything. Matters for
174
+ // a whole chromosome stored as one BAM read, whose CIGAR runs to millions
175
+ // of ops for a screenful of them — and costs one compare per op otherwise,
176
+ // since an unwindowed walk has `winHi` at +Infinity.
177
+ if (roffset >= winHi) {
178
+ break;
179
+ }
180
+ const packed = cigar[i];
181
+ const len = packed >>> 4;
182
+ const op = packed & 0xf;
183
+ if ((1 << op) & CIGAR_M_EQ_MASK) {
184
+ if (hasMD) {
185
+ let remaining = len;
186
+ let localOffset = 0;
187
+ while (remaining > 0) {
188
+ if (mdMatchRemaining >= remaining) {
189
+ mdMatchRemaining -= remaining;
190
+ localOffset += remaining;
191
+ remaining = 0;
192
+ }
193
+ else {
194
+ localOffset += mdMatchRemaining;
195
+ remaining -= mdMatchRemaining;
196
+ mdMatchRemaining = 0;
197
+ if (mdIdx < mdLength && md[mdIdx] >= 65 && md[mdIdx] <= 90) {
198
+ const pos = roffset + localOffset;
199
+ if (pos >= winLo && pos < winHi) {
200
+ const seqIdx = soffset + localOffset;
201
+ const sb = numericSeq[seqIdx >> 1];
202
+ const nibble = (sb >> ((1 - (seqIdx & 1)) << 2)) & 0xf;
203
+ callback(exports.MISMATCH_SUBST, refStart + pos, 1, seqAlphabet_ts_1.SEQRET_DECODER[nibble], hasQual ? qual[seqIdx] : -1, md[mdIdx], 0);
204
+ }
205
+ mdIdx++;
206
+ localOffset++;
207
+ remaining--;
208
+ mdMatchRemaining = 0;
209
+ while (mdIdx < mdLength) {
210
+ const c = md[mdIdx];
211
+ if (c >= 48 && c <= 57) {
212
+ mdMatchRemaining = mdMatchRemaining * 10 + (c - 48);
213
+ mdIdx++;
214
+ }
215
+ else {
216
+ break;
217
+ }
218
+ }
219
+ }
220
+ else {
221
+ break;
222
+ }
223
+ }
224
+ }
225
+ }
226
+ else if (ref) {
227
+ // Only compare bases whose reference position falls in the window AND
228
+ // in the region. A whole-chromosome contig has M ops totalling ~250M
229
+ // bases; without this clip every one is compared (and `ref` would have
230
+ // to cover the whole chromosome).
231
+ const jLo = cmpLo > roffset ? cmpLo - roffset : 0;
232
+ const jHi = cmpHi < roffset + len ? cmpHi - roffset : len;
233
+ let j = jLo;
234
+ // A leading odd read index has no partner in its byte, so compare it
235
+ // alone and let the pair loop start on a byte boundary.
236
+ if (j < jHi && (soffset + j) & 1) {
237
+ compareRefBase(callback, numericSeq, qual, ref, soffset + j, refOffset + roffset + j, refStart + roffset + j);
238
+ j++;
239
+ }
240
+ // Two bases per byte load and compare. `even`/`odd` differ only in
241
+ // which reference parity they put on a byte boundary, so one of them
242
+ // always lines up with the read's packed sequence; the nibbles are
243
+ // unpacked only for the byte that actually differs.
244
+ const refIdx = refOffset + roffset + j;
245
+ const refPairs = refIdx & 1 ? ref.odd : ref.even;
246
+ let refByte = (refIdx + (refIdx & 1)) >> 1;
247
+ let seqByte = (soffset + j) >> 1;
248
+ for (; j + 1 < jHi; j += 2, refByte++, seqByte++) {
249
+ const seqPair = numericSeq[seqByte];
250
+ const refPair = refPairs[refByte];
251
+ if (seqPair !== refPair) {
252
+ const seqHi = (seqPair >> 4) & 0xf;
253
+ const refHi = (refPair >> 4) & 0xf;
254
+ if (seqHi !== refHi) {
255
+ reportRefMismatch(callback, refStart + roffset + j, seqHi, hasQual ? qual[soffset + j] : -1, refHi);
256
+ }
257
+ const seqLo = seqPair & 0xf;
258
+ const refLo = refPair & 0xf;
259
+ if (seqLo !== refLo) {
260
+ reportRefMismatch(callback, refStart + roffset + j + 1, seqLo, hasQual ? qual[soffset + j + 1] : -1, refLo);
261
+ }
262
+ }
263
+ }
264
+ if (j < jHi) {
265
+ compareRefBase(callback, numericSeq, qual, ref, soffset + j, refOffset + roffset + j, refStart + roffset + j);
266
+ }
267
+ }
268
+ soffset += len;
269
+ roffset += len;
270
+ }
271
+ else if (op === cigar_ts_1.CIGAR_INS) {
272
+ if (roffset >= winLo && roffset < winHi) {
273
+ // Optimized insertion base extraction - avoid string concat for common
274
+ // cases
275
+ let insertedBases;
276
+ if (len === 1) {
277
+ // Single base insertion - most common case
278
+ const sb = numericSeq[soffset >> 1];
279
+ const nibble = (sb >> ((1 - (soffset & 1)) << 2)) & 0xf;
280
+ insertedBases = seqAlphabet_ts_1.SEQRET_DECODER[nibble];
281
+ }
282
+ else if (len === 2) {
283
+ // Two base insertion - second most common
284
+ const seqIdx0 = soffset;
285
+ const sb0 = numericSeq[seqIdx0 >> 1];
286
+ const nibble0 = (sb0 >> ((1 - (seqIdx0 & 1)) << 2)) & 0xf;
287
+ const seqIdx1 = soffset + 1;
288
+ const sb1 = numericSeq[seqIdx1 >> 1];
289
+ const nibble1 = (sb1 >> ((1 - (seqIdx1 & 1)) << 2)) & 0xf;
290
+ insertedBases = seqAlphabet_ts_1.SEQRET_DECODER[nibble0] + seqAlphabet_ts_1.SEQRET_DECODER[nibble1];
291
+ }
292
+ else {
293
+ const bases = new Array(len);
294
+ for (let j = 0; j < len; j++) {
295
+ const seqIdx = soffset + j;
296
+ const sb = numericSeq[seqIdx >> 1];
297
+ const nibble = (sb >> ((1 - (seqIdx & 1)) << 2)) & 0xf;
298
+ bases[j] = seqAlphabet_ts_1.SEQRET_DECODER[nibble];
299
+ }
300
+ insertedBases = bases.join('');
301
+ }
302
+ callback(exports.MISMATCH_INSERTION, refStart + roffset, 0, insertedBases, -1, 0, len);
303
+ }
304
+ soffset += len;
305
+ }
306
+ else if (op === cigar_ts_1.CIGAR_DEL) {
307
+ if (roffset < winHi && roffset + len > winLo) {
308
+ callback(exports.MISMATCH_DELETION, refStart + roffset, len, NO_BASES, -1, 0, 0);
309
+ }
310
+ // MD spells a deletion as ^ then the deleted reference bases, which are
311
+ // not a difference this reports (the D above already is) but do have to
312
+ // be stepped over, or every later position in the read reads off the
313
+ // wrong part of the tag.
314
+ // eslint-disable-next-line @typescript-eslint/no-confusing-non-null-assertion
315
+ if (hasMD && mdIdx < mdLength && md[mdIdx] === 94) {
316
+ mdIdx++;
317
+ while (mdIdx < mdLength && md[mdIdx] >= 65) {
318
+ mdIdx++;
319
+ }
320
+ mdMatchRemaining = 0;
321
+ while (mdIdx < mdLength) {
322
+ const c = md[mdIdx];
323
+ if (c >= 48 && c <= 57) {
324
+ mdMatchRemaining = mdMatchRemaining * 10 + (c - 48);
325
+ mdIdx++;
326
+ }
327
+ else {
328
+ break;
329
+ }
330
+ }
331
+ }
332
+ roffset += len;
333
+ }
334
+ else if (op === cigar_ts_1.CIGAR_REF_SKIP) {
335
+ if (roffset < winHi && roffset + len > winLo) {
336
+ callback(exports.MISMATCH_REF_SKIP, refStart + roffset, len, NO_BASES, -1, 0, 0);
337
+ }
338
+ roffset += len;
339
+ }
340
+ else if (op === cigar_ts_1.CIGAR_DIFF) {
341
+ for (let j = 0; j < len; j++) {
342
+ const seqIdx = soffset + j;
343
+ const sb = numericSeq[seqIdx >> 1];
344
+ const nibble = (sb >> ((1 - (seqIdx & 1)) << 2)) & 0xf;
345
+ // An X op says a substitution is here without saying what it replaces,
346
+ // so the reference base comes from MD or the region — and is 0, i.e.
347
+ // unknown, when the read carries neither.
348
+ let refBaseCode = 0;
349
+ if (hasMD) {
350
+ if (mdMatchRemaining === 0 && mdIdx < mdLength && md[mdIdx] >= 65) {
351
+ refBaseCode = md[mdIdx];
352
+ mdIdx++;
353
+ mdMatchRemaining = 0;
354
+ while (mdIdx < mdLength) {
355
+ const c = md[mdIdx];
356
+ if (c >= 48 && c <= 57) {
357
+ mdMatchRemaining = mdMatchRemaining * 10 + (c - 48);
358
+ mdIdx++;
359
+ }
360
+ else {
361
+ break;
362
+ }
363
+ }
364
+ }
365
+ else if (mdMatchRemaining > 0) {
366
+ mdMatchRemaining--;
367
+ }
368
+ }
369
+ else if (ref) {
370
+ const refIdx = refOffset + roffset + j;
371
+ if (refIdx >= 0 && refIdx < ref.length) {
372
+ refBaseCode = reference_ts_1.CHAR_CODE_FROM_NIBBLE[(0, reference_ts_1.referenceNibble)(ref, refIdx)];
373
+ }
374
+ }
375
+ const pos = roffset + j;
376
+ if (pos >= winLo && pos < winHi) {
377
+ callback(exports.MISMATCH_SUBST, refStart + pos, 1, seqAlphabet_ts_1.SEQRET_DECODER[nibble], hasQual ? qual[seqIdx] : -1, refBaseCode, 0);
378
+ }
379
+ }
380
+ soffset += len;
381
+ roffset += len;
382
+ }
383
+ else if (op === cigar_ts_1.CIGAR_SOFT_CLIP) {
384
+ if (roffset >= winLo && roffset < winHi) {
385
+ callback(exports.MISMATCH_SOFT_CLIP, refStart + roffset, 0, NO_BASES, -1, 0, len);
386
+ }
387
+ soffset += len;
388
+ }
389
+ else if (op === cigar_ts_1.CIGAR_HARD_CLIP) {
390
+ if (roffset >= winLo && roffset < winHi) {
391
+ callback(exports.MISMATCH_HARD_CLIP, refStart + roffset, 0, NO_BASES, -1, 0, len);
392
+ }
393
+ }
394
+ // P (padding) consumes neither read nor reference and is not a difference
395
+ }
396
+ }
397
+ //# sourceMappingURL=mismatches.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mismatches.js","sourceRoot":"","sources":["../src/mismatches.ts"],"names":[],"mappings":"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"}
package/dist/record.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import type { Mismatch, MismatchCallback, MismatchOptions } from './mismatches.ts';
2
+ import type { PackedReference } from './reference.ts';
1
3
  export type NumericCigar = Uint32Array | Int32Array | number[];
2
4
  export default class BamRecord {
3
5
  fileOffset: number;
@@ -11,6 +13,7 @@ export default class BamRecord {
11
13
  private _cachedNumericCigar?;
12
14
  private _cachedNUMERIC_MD?;
13
15
  private _cachedSeqStart?;
16
+ private _reference?;
14
17
  constructor(byteArray: Uint8Array, start: number, end: number, fileOffset: number, dataView: DataView);
15
18
  get byteArray(): Uint8Array<ArrayBufferLike>;
16
19
  get flags(): number;
@@ -79,5 +82,47 @@ export default class BamRecord {
79
82
  get next_pos(): number;
80
83
  get template_length(): number;
81
84
  seqAt(idx: number): string | undefined;
85
+ /**
86
+ * Bind reference bases for this read to resolve its substitutions against,
87
+ * for a read with no MD tag. `BamFile` calls this for you when it was given a
88
+ * `fetchReferenceSequence`; call it yourself when you have the bases from
89
+ * somewhere else.
90
+ *
91
+ * **`ref` must cover the whole read**, and this throws if it does not. The
92
+ * reason is that records are cached and shared between queries (ADR 0006), so
93
+ * a binding that varied by query would make one query's reads answer out of
94
+ * another's region. A region covering the read is the same data whichever
95
+ * query fetched it, so binding it is safe; a partial one is not, and the
96
+ * per-call `forEachMismatch(cb, {ref})` is where that belongs.
97
+ */
98
+ setReference(ref: PackedReference | undefined): void;
99
+ /** the region {@link setReference} bound, if any */
100
+ get reference(): PackedReference | undefined;
101
+ /**
102
+ * Report each difference between this read and the reference —
103
+ * substitutions, insertions, deletions, reference skips and clips — without
104
+ * allocating an object per difference. This is the intended way to read a
105
+ * record's differences; deriving them from `CIGAR` and `MD` yourself takes
106
+ * rather more of the format to interpret correctly (see {@link Mismatch}).
107
+ *
108
+ * Substitutions come from the MD tag when the read has one, and otherwise
109
+ * from comparing SEQ against reference bases — which have to come from
110
+ * {@link setReference}, `opts.ref`, or the file's `fetchReferenceSequence`.
111
+ * With neither MD nor reference, indels and clips are still reported in full
112
+ * and substitutions are not reported at all: nothing in the record says where
113
+ * they are.
114
+ *
115
+ * @param callback called as
116
+ * `(code, refPos, length, bases, qual, refBaseCode, clipLength)`
117
+ * @param opts optional reference window to restrict to, and an optional
118
+ * per-call reference region; see {@link MismatchOptions}
119
+ */
120
+ forEachMismatch(callback: MismatchCallback, opts?: MismatchOptions): void;
121
+ /**
122
+ * The same differences {@link forEachMismatch} reports, as an array of
123
+ * {@link Mismatch} objects. Convenient; allocates one object per difference,
124
+ * so the callback form is the one to reach for on a hot path.
125
+ */
126
+ getMismatches(opts?: MismatchOptions): Mismatch[];
82
127
  toJSON(): Record<string, unknown>;
83
128
  }
package/dist/record.js CHANGED
@@ -5,9 +5,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const cigar_ts_1 = require("./cigar.js");
7
7
  const constants_ts_1 = __importDefault(require("./constants.js"));
8
- const SEQRET = '=ACMGRSVTWYHKDBN';
9
- const SEQRET_DECODER = SEQRET.split('');
10
- const SEQRET_CODES = Uint8Array.from(SEQRET, c => c.charCodeAt(0));
8
+ const mismatches_ts_1 = require("./mismatches.js");
9
+ const reference_ts_1 = require("./reference.js");
10
+ const seqAlphabet_ts_1 = require("./seqAlphabet.js");
11
11
  // Both bases of a SEQ byte, precomputed for all 256 bytes so decoding advances a
12
12
  // byte at a time. Two forms because `seq` has two strategies (see below): packed
13
13
  // ASCII codes for a single Uint16Array store, and the 2-char string to append.
@@ -17,13 +17,13 @@ const SEQRET_PAIR_CODES = new Uint16Array(256);
17
17
  const SEQRET_PAIR_STRINGS = new Array(256);
18
18
  for (let hi = 0; hi < 16; hi++) {
19
19
  for (let lo = 0; lo < 16; lo++) {
20
- const h = SEQRET_CODES[hi];
21
- const l = SEQRET_CODES[lo];
20
+ const h = seqAlphabet_ts_1.SEQRET_CODES[hi];
21
+ const l = seqAlphabet_ts_1.SEQRET_CODES[lo];
22
22
  SEQRET_PAIR_CODES[(hi << 4) | lo] = LITTLE_ENDIAN
23
23
  ? h | (l << 8)
24
24
  : (h << 8) | l;
25
25
  SEQRET_PAIR_STRINGS[(hi << 4) | lo] =
26
- SEQRET_DECODER[hi] + SEQRET_DECODER[lo];
26
+ seqAlphabet_ts_1.SEQRET_DECODER[hi] + seqAlphabet_ts_1.SEQRET_DECODER[lo];
27
27
  }
28
28
  }
29
29
  // Read length at which building a byte buffer and calling TextDecoder once
@@ -325,6 +325,7 @@ class BamRecord {
325
325
  _cachedNumericCigar;
326
326
  _cachedNUMERIC_MD;
327
327
  _cachedSeqStart;
328
+ _reference;
328
329
  // Positional rather than an options object, because every argument is
329
330
  // unpacked into a field immediately and nothing keeps the wrapper. The
330
331
  // options form allocated two throwaway objects for each of the ~200k records
@@ -742,7 +743,7 @@ class BamRecord {
742
743
  }
743
744
  }
744
745
  if (len & 1) {
745
- seq += SEQRET_DECODER[(ba[p + nPairs] & 0xf0) >> 4];
746
+ seq += seqAlphabet_ts_1.SEQRET_DECODER[(ba[p + nPairs] & 0xf0) >> 4];
746
747
  }
747
748
  }
748
749
  else {
@@ -754,7 +755,7 @@ class BamRecord {
754
755
  pairs[j] = SEQRET_PAIR_CODES[ba[p + j]];
755
756
  }
756
757
  if (len & 1) {
757
- out[len - 1] = SEQRET_CODES[(ba[p + nPairs] & 0xf0) >> 4];
758
+ out[len - 1] = seqAlphabet_ts_1.SEQRET_CODES[(ba[p + nPairs] & 0xf0) >> 4];
758
759
  }
759
760
  seq = textDecoder.decode(out.subarray(0, len));
760
761
  }
@@ -809,13 +810,78 @@ class BamRecord {
809
810
  if (idx < this.seq_length) {
810
811
  const sb = this._byteArray[this.seqStart + (idx >> 1)];
811
812
  return (idx & 1) === 0
812
- ? SEQRET_DECODER[(sb & 0xf0) >> 4]
813
- : SEQRET_DECODER[sb & 0x0f];
813
+ ? seqAlphabet_ts_1.SEQRET_DECODER[(sb & 0xf0) >> 4]
814
+ : seqAlphabet_ts_1.SEQRET_DECODER[sb & 0x0f];
814
815
  }
815
816
  else {
816
817
  return undefined;
817
818
  }
818
819
  }
820
+ /**
821
+ * Bind reference bases for this read to resolve its substitutions against,
822
+ * for a read with no MD tag. `BamFile` calls this for you when it was given a
823
+ * `fetchReferenceSequence`; call it yourself when you have the bases from
824
+ * somewhere else.
825
+ *
826
+ * **`ref` must cover the whole read**, and this throws if it does not. The
827
+ * reason is that records are cached and shared between queries (ADR 0006), so
828
+ * a binding that varied by query would make one query's reads answer out of
829
+ * another's region. A region covering the read is the same data whichever
830
+ * query fetched it, so binding it is safe; a partial one is not, and the
831
+ * per-call `forEachMismatch(cb, {ref})` is where that belongs.
832
+ */
833
+ setReference(ref) {
834
+ if (ref !== undefined && !(0, reference_ts_1.referenceCovers)(ref, this.start, this.end)) {
835
+ throw new Error(`reference region ${ref.start}-${ref.start + ref.length} does not cover the record at ${this.start}-${this.end}. Records are shared between queries, so only a region covering the whole read can be bound to one; pass a partial region per call instead, as forEachMismatch(cb, {ref})`);
836
+ }
837
+ this._reference = ref;
838
+ }
839
+ /** the region {@link setReference} bound, if any */
840
+ get reference() {
841
+ return this._reference;
842
+ }
843
+ /**
844
+ * Report each difference between this read and the reference —
845
+ * substitutions, insertions, deletions, reference skips and clips — without
846
+ * allocating an object per difference. This is the intended way to read a
847
+ * record's differences; deriving them from `CIGAR` and `MD` yourself takes
848
+ * rather more of the format to interpret correctly (see {@link Mismatch}).
849
+ *
850
+ * Substitutions come from the MD tag when the read has one, and otherwise
851
+ * from comparing SEQ against reference bases — which have to come from
852
+ * {@link setReference}, `opts.ref`, or the file's `fetchReferenceSequence`.
853
+ * With neither MD nor reference, indels and clips are still reported in full
854
+ * and substitutions are not reported at all: nothing in the record says where
855
+ * they are.
856
+ *
857
+ * @param callback called as
858
+ * `(code, refPos, length, bases, qual, refBaseCode, clipLength)`
859
+ * @param opts optional reference window to restrict to, and an optional
860
+ * per-call reference region; see {@link MismatchOptions}
861
+ */
862
+ forEachMismatch(callback, opts) {
863
+ (0, mismatches_ts_1.forEachMismatchNumeric)(this.NUMERIC_CIGAR, this.NUMERIC_SEQ, this.seq_length, this.NUMERIC_MD, this.qual, opts?.ref ?? this._reference, this.start, opts?.start ?? Number.NEGATIVE_INFINITY, opts?.end ?? Number.POSITIVE_INFINITY, callback);
864
+ }
865
+ /**
866
+ * The same differences {@link forEachMismatch} reports, as an array of
867
+ * {@link Mismatch} objects. Convenient; allocates one object per difference,
868
+ * so the callback form is the one to reach for on a hot path.
869
+ */
870
+ getMismatches(opts) {
871
+ const out = [];
872
+ this.forEachMismatch((code, refPos, length, bases, qual, refBaseCode, clipLength) => {
873
+ out.push({
874
+ code,
875
+ refPos,
876
+ length,
877
+ bases,
878
+ qual,
879
+ refBaseCode,
880
+ clipLength,
881
+ });
882
+ }, opts);
883
+ return out;
884
+ }
819
885
  // Most public BamRecord fields are getters on the prototype, so
820
886
  // Object.keys(this) wouldn't include them — JSON.stringify needs an explicit
821
887
  // list. Returns the meaningful BAM-spec fields. Return type is widened so