@gmod/bam 7.1.4 → 7.1.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.
package/CHANGELOG.md CHANGED
@@ -1,23 +1,17 @@
1
- ## [7.1.4](https://github.com/GMOD/bam-js/compare/v7.1.3...v7.1.4) (2025-12-13)
2
-
1
+ ## [7.1.5](https://github.com/GMOD/bam-js/compare/v7.1.4...v7.1.5) (2025-12-13)
3
2
 
4
3
 
5
- ## [7.1.3](https://github.com/GMOD/bam-js/compare/v7.1.2...v7.1.3) (2025-12-12)
6
4
 
5
+ ## [7.1.4](https://github.com/GMOD/bam-js/compare/v7.1.3...v7.1.4) (2025-12-13)
7
6
 
7
+ ## [7.1.3](https://github.com/GMOD/bam-js/compare/v7.1.2...v7.1.3) (2025-12-12)
8
8
 
9
9
  ## [7.1.2](https://github.com/GMOD/bam-js/compare/v7.1.1...v7.1.2) (2025-12-12)
10
10
 
11
-
12
-
13
11
  ## [7.1.1](https://github.com/GMOD/bam-js/compare/v7.1.0...v7.1.1) (2025-12-12)
14
12
 
15
-
16
-
17
13
  # [7.1.0](https://github.com/GMOD/bam-js/compare/v7.0.6...v7.1.0) (2025-12-11)
18
14
 
19
-
20
-
21
15
  ## [7.0.6](https://github.com/GMOD/bam-js/compare/v7.0.5...v7.0.6) (2025-11-28)
22
16
 
23
17
  ## [7.0.5](https://github.com/GMOD/bam-js/compare/v7.0.4...v7.0.5) (2025-11-27)
@@ -0,0 +1,9 @@
1
+ export declare const CIGAR_MATCH = 0;
2
+ export declare const CIGAR_INS = 1;
3
+ export declare const CIGAR_DEL = 2;
4
+ export declare const CIGAR_REF_SKIP = 3;
5
+ export declare const CIGAR_SOFT_CLIP = 4;
6
+ export declare const CIGAR_HARD_CLIP = 5;
7
+ export declare const CIGAR_PAD = 6;
8
+ export declare const CIGAR_EQUAL = 7;
9
+ export declare const CIGAR_DIFF = 8;
package/dist/cigar.js ADDED
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CIGAR_DIFF = exports.CIGAR_EQUAL = exports.CIGAR_PAD = exports.CIGAR_HARD_CLIP = exports.CIGAR_SOFT_CLIP = exports.CIGAR_REF_SKIP = exports.CIGAR_DEL = exports.CIGAR_INS = exports.CIGAR_MATCH = void 0;
4
+ exports.CIGAR_MATCH = 0;
5
+ exports.CIGAR_INS = 1;
6
+ exports.CIGAR_DEL = 2;
7
+ exports.CIGAR_REF_SKIP = 3;
8
+ exports.CIGAR_SOFT_CLIP = 4;
9
+ exports.CIGAR_HARD_CLIP = 5;
10
+ exports.CIGAR_PAD = 6;
11
+ exports.CIGAR_EQUAL = 7;
12
+ exports.CIGAR_DIFF = 8;
13
+ //# sourceMappingURL=cigar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cigar.js","sourceRoot":"","sources":["../src/cigar.ts"],"names":[],"mappings":";;;AAAa,QAAA,WAAW,GAAG,CAAC,CAAA;AACf,QAAA,SAAS,GAAG,CAAC,CAAA;AACb,QAAA,SAAS,GAAG,CAAC,CAAA;AACb,QAAA,cAAc,GAAG,CAAC,CAAA;AAClB,QAAA,eAAe,GAAG,CAAC,CAAA;AACnB,QAAA,eAAe,GAAG,CAAC,CAAA;AACnB,QAAA,SAAS,GAAG,CAAC,CAAA;AACb,QAAA,WAAW,GAAG,CAAC,CAAA;AACf,QAAA,UAAU,GAAG,CAAC,CAAA"}
package/dist/record.d.ts CHANGED
@@ -3,10 +3,18 @@ interface Bytes {
3
3
  end: number;
4
4
  byteArray: Uint8Array;
5
5
  }
6
+ interface CIGAR_AND_LENGTH {
7
+ length_on_ref: number;
8
+ NUMERIC_CIGAR: Uint32Array;
9
+ }
6
10
  export default class BamRecord {
7
11
  fileOffset: number;
8
12
  private bytes;
9
13
  private _dataView;
14
+ private _cachedFlags?;
15
+ private _cachedTags?;
16
+ private _cachedCigarAndLength?;
17
+ private _cachedNUMERIC_MD?;
10
18
  constructor(args: {
11
19
  bytes: Bytes;
12
20
  fileOffset: number;
@@ -19,43 +27,27 @@ export default class BamRecord {
19
27
  get id(): number;
20
28
  get mq(): number | undefined;
21
29
  get score(): number | undefined;
22
- get qual(): Uint8Array<ArrayBufferLike> | undefined;
30
+ get qual(): Uint8Array<ArrayBufferLike> | null;
23
31
  get strand(): 1 | -1;
24
32
  get b0(): number;
25
33
  get name(): string;
26
34
  get NUMERIC_MD(): Uint8Array<ArrayBufferLike> | undefined;
27
35
  get tags(): Record<string, unknown>;
28
- /**
29
- * @returns {boolean} true if the read is paired, regardless of whether both
30
- * segments are mapped
31
- */
36
+ private _computeTags;
32
37
  isPaired(): boolean;
33
- /** @returns {boolean} true if the read is paired, and both segments are mapped */
34
38
  isProperlyPaired(): boolean;
35
- /** @returns {boolean} true if the read itself is unmapped; conflictive with isProperlyPaired */
36
39
  isSegmentUnmapped(): boolean;
37
- /** @returns {boolean} true if the read itself is unmapped; conflictive with isProperlyPaired */
38
40
  isMateUnmapped(): boolean;
39
- /** @returns {boolean} true if the read is mapped to the reverse strand */
40
41
  isReverseComplemented(): boolean;
41
- /** @returns {boolean} true if the mate is mapped to the reverse strand */
42
42
  isMateReverseComplemented(): boolean;
43
- /** @returns {boolean} true if this is read number 1 in a pair */
44
43
  isRead1(): boolean;
45
- /** @returns {boolean} true if this is read number 2 in a pair */
46
44
  isRead2(): boolean;
47
- /** @returns {boolean} true if this is a secondary alignment */
48
45
  isSecondary(): boolean;
49
- /** @returns {boolean} true if this read has failed QC checks */
50
46
  isFailedQc(): boolean;
51
- /** @returns {boolean} true if the read is an optical or PCR duplicate */
52
47
  isDuplicate(): boolean;
53
- /** @returns {boolean} true if this is a supplementary alignment */
54
48
  isSupplementary(): boolean;
55
- get cigarAndLength(): {
56
- NUMERIC_CIGAR: Uint32Array<ArrayBufferLike>;
57
- length_on_ref: number;
58
- };
49
+ get cigarAndLength(): CIGAR_AND_LENGTH;
50
+ private _computeCigarAndLength;
59
51
  get length_on_ref(): number;
60
52
  get NUMERIC_CIGAR(): Uint32Array<ArrayBufferLike>;
61
53
  get CIGAR(): string;
package/dist/record.js CHANGED
@@ -3,20 +3,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ const cigar_ts_1 = require("./cigar.js");
6
7
  const constants_ts_1 = __importDefault(require("./constants.js"));
7
8
  const SEQRET_DECODER = '=ACMGRSVTWYHKDBN'.split('');
8
9
  const ASCII_CIGAR_CODES = [
9
10
  77, 73, 68, 78, 83, 72, 80, 61, 88, 63, 63, 63, 63, 63, 63, 63,
10
11
  ];
11
- // const CIGAR_MATCH = 0
12
- const CIGAR_INS = 1;
13
- // const CIGAR_DEL = 2
14
- const CIGAR_REF_SKIP = 3;
15
- const CIGAR_SOFT_CLIP = 4;
16
- const CIGAR_HARD_CLIP = 5;
17
- // const CIGAR_PAD = 6
18
12
  // ops that don't consume reference: INS, SOFT_CLIP, HARD_CLIP
19
- const CIGAR_SKIP_MASK = (1 << CIGAR_INS) | (1 << CIGAR_SOFT_CLIP) | (1 << CIGAR_HARD_CLIP);
13
+ const CIGAR_SKIP_MASK = (1 << cigar_ts_1.CIGAR_INS) | (1 << cigar_ts_1.CIGAR_SOFT_CLIP) | (1 << cigar_ts_1.CIGAR_HARD_CLIP);
20
14
  class BamRecord {
21
15
  constructor(args) {
22
16
  this.bytes = args.bytes;
@@ -27,7 +21,12 @@ class BamRecord {
27
21
  return this.bytes.byteArray;
28
22
  }
29
23
  get flags() {
30
- return ((this._dataView.getInt32(this.bytes.start + 16, true) & 0xffff0000) >> 16);
24
+ if (this._cachedFlags === undefined) {
25
+ this._cachedFlags =
26
+ (this._dataView.getInt32(this.bytes.start + 16, true) & 0xffff0000) >>
27
+ 16;
28
+ }
29
+ return this._cachedFlags;
31
30
  }
32
31
  get ref_id() {
33
32
  return this._dataView.getInt32(this.bytes.start + 4, true);
@@ -50,13 +49,15 @@ class BamRecord {
50
49
  }
51
50
  get qual() {
52
51
  if (this.isSegmentUnmapped()) {
53
- return;
52
+ return null;
53
+ }
54
+ else {
55
+ const p = this.b0 +
56
+ this.read_name_length +
57
+ this.num_cigar_bytes +
58
+ this.num_seq_bytes;
59
+ return this.byteArray.subarray(p, p + this.seq_length);
54
60
  }
55
- const p = this.b0 +
56
- this.read_name_length +
57
- this.num_cigar_bytes +
58
- this.num_seq_bytes;
59
- return this.byteArray.subarray(p, p + this.seq_length);
60
61
  }
61
62
  get strand() {
62
63
  return this.isReverseComplemented() ? -1 : 1;
@@ -72,117 +73,127 @@ class BamRecord {
72
73
  return str;
73
74
  }
74
75
  get NUMERIC_MD() {
75
- let p = this.b0 +
76
- this.read_name_length +
77
- this.num_cigar_bytes +
78
- this.num_seq_bytes +
79
- this.seq_length;
80
- const blockEnd = this.bytes.end;
81
- const ba = this.byteArray;
82
- while (p < blockEnd) {
83
- const tag1 = ba[p];
84
- const tag2 = ba[p + 1];
85
- const type = ba[p + 2];
86
- p += 3;
87
- // 'M' = 0x4D, 'D' = 0x44, 'Z' = 0x5A
88
- if (tag1 === 0x4d && tag2 === 0x44 && type === 0x5a) {
89
- const start = p;
90
- while (p < blockEnd && ba[p] !== 0) {
91
- p++;
92
- }
93
- return ba.subarray(start, p);
94
- }
95
- switch (type) {
96
- case 0x41: // 'A'
97
- p += 1;
98
- break;
99
- case 0x69: // 'i'
100
- case 0x49: // 'I'
101
- case 0x66: // 'f'
102
- p += 4;
103
- break;
104
- case 0x63: // 'c'
105
- case 0x43: // 'C'
106
- p += 1;
107
- break;
108
- case 0x73: // 's'
109
- case 0x53: // 'S'
110
- p += 2;
111
- break;
112
- case 0x5a: // 'Z'
113
- case 0x48: // 'H'
114
- while (p <= blockEnd && ba[p++] !== 0) { }
115
- break;
116
- case 0x42: { // 'B'
117
- const Btype = ba[p++];
118
- const limit = this._dataView.getInt32(p, true);
119
- p += 4;
120
- if (Btype === 0x69 || Btype === 0x49 || Btype === 0x66) {
121
- p += limit << 2;
76
+ if (this._cachedNUMERIC_MD === undefined) {
77
+ let p = this.b0 +
78
+ this.read_name_length +
79
+ this.num_cigar_bytes +
80
+ this.num_seq_bytes +
81
+ this.seq_length;
82
+ const blockEnd = this.bytes.end;
83
+ const ba = this.byteArray;
84
+ while (p < blockEnd) {
85
+ const tag1 = ba[p];
86
+ const tag2 = ba[p + 1];
87
+ const type = ba[p + 2];
88
+ p += 3;
89
+ // 'M' = 0x4D, 'D' = 0x44, 'Z' = 0x5A
90
+ if (tag1 === 0x4d && tag2 === 0x44 && type === 0x5a) {
91
+ const start = p;
92
+ while (p < blockEnd && ba[p] !== 0) {
93
+ p++;
122
94
  }
123
- else if (Btype === 0x73 || Btype === 0x53) {
124
- p += limit << 1;
125
- }
126
- else if (Btype === 0x63 || Btype === 0x43) {
127
- p += limit;
95
+ this._cachedNUMERIC_MD = ba.subarray(start, p);
96
+ }
97
+ switch (type) {
98
+ case 0x41: // 'A'
99
+ p += 1;
100
+ break;
101
+ case 0x69: // 'i'
102
+ case 0x49: // 'I'
103
+ case 0x66: // 'f'
104
+ p += 4;
105
+ break;
106
+ case 0x63: // 'c'
107
+ case 0x43: // 'C'
108
+ p += 1;
109
+ break;
110
+ case 0x73: // 's'
111
+ case 0x53: // 'S'
112
+ p += 2;
113
+ break;
114
+ case 0x5a: // 'Z'
115
+ case 0x48: // 'H'
116
+ while (p <= blockEnd && ba[p++] !== 0) { }
117
+ break;
118
+ case 0x42: {
119
+ // 'B'
120
+ const Btype = ba[p++];
121
+ const limit = this._dataView.getInt32(p, true);
122
+ p += 4;
123
+ if (Btype === 0x69 || Btype === 0x49 || Btype === 0x66) {
124
+ p += limit << 2;
125
+ }
126
+ else if (Btype === 0x73 || Btype === 0x53) {
127
+ p += limit << 1;
128
+ }
129
+ else if (Btype === 0x63 || Btype === 0x43) {
130
+ p += limit;
131
+ }
132
+ break;
128
133
  }
129
- break;
130
134
  }
131
135
  }
132
136
  }
133
- return undefined;
137
+ return this._cachedNUMERIC_MD === null ? undefined : this._cachedNUMERIC_MD;
134
138
  }
135
139
  get tags() {
140
+ if (this._cachedTags === undefined) {
141
+ this._cachedTags = this._computeTags();
142
+ }
143
+ return this._cachedTags;
144
+ }
145
+ _computeTags() {
136
146
  let p = this.b0 +
137
147
  this.read_name_length +
138
148
  this.num_cigar_bytes +
139
149
  this.num_seq_bytes +
140
150
  this.seq_length;
141
151
  const blockEnd = this.bytes.end;
152
+ const ba = this.byteArray;
142
153
  const tags = {};
143
154
  while (p < blockEnd) {
144
- const tag = String.fromCharCode(this.byteArray[p]) +
145
- String.fromCharCode(this.byteArray[p + 1]);
146
- const type = String.fromCharCode(this.byteArray[p + 2]);
155
+ const tag = String.fromCharCode(ba[p], ba[p + 1]);
156
+ const type = ba[p + 2];
147
157
  p += 3;
148
158
  switch (type) {
149
- case 'A':
150
- tags[tag] = String.fromCharCode(this.byteArray[p]);
159
+ case 0x41: // 'A'
160
+ tags[tag] = String.fromCharCode(ba[p]);
151
161
  p += 1;
152
162
  break;
153
- case 'i':
163
+ case 0x69: // 'i'
154
164
  tags[tag] = this._dataView.getInt32(p, true);
155
165
  p += 4;
156
166
  break;
157
- case 'I':
167
+ case 0x49: // 'I'
158
168
  tags[tag] = this._dataView.getUint32(p, true);
159
169
  p += 4;
160
170
  break;
161
- case 'c':
171
+ case 0x63: // 'c'
162
172
  tags[tag] = this._dataView.getInt8(p);
163
173
  p += 1;
164
174
  break;
165
- case 'C':
175
+ case 0x43: // 'C'
166
176
  tags[tag] = this._dataView.getUint8(p);
167
177
  p += 1;
168
178
  break;
169
- case 's':
179
+ case 0x73: // 's'
170
180
  tags[tag] = this._dataView.getInt16(p, true);
171
181
  p += 2;
172
182
  break;
173
- case 'S':
183
+ case 0x53: // 'S'
174
184
  tags[tag] = this._dataView.getUint16(p, true);
175
185
  p += 2;
176
186
  break;
177
- case 'f':
187
+ case 0x66: // 'f'
178
188
  tags[tag] = this._dataView.getFloat32(p, true);
179
189
  p += 4;
180
190
  break;
181
- case 'Z':
182
- case 'H': {
191
+ case 0x5a: // 'Z'
192
+ case 0x48: {
193
+ // 'H'
183
194
  const value = [];
184
195
  while (p <= blockEnd) {
185
- const cc = this.byteArray[p++];
196
+ const cc = ba[p++];
186
197
  if (cc !== 0) {
187
198
  value.push(String.fromCharCode(cc));
188
199
  }
@@ -193,66 +204,73 @@ class BamRecord {
193
204
  tags[tag] = value.join('');
194
205
  break;
195
206
  }
196
- case 'B': {
197
- const cc = this.byteArray[p++];
198
- const Btype = String.fromCharCode(cc);
207
+ case 0x42: {
208
+ // 'B'
209
+ const Btype = ba[p++];
199
210
  const limit = this._dataView.getInt32(p, true);
200
211
  p += 4;
201
- const absOffset = this.byteArray.byteOffset + p;
202
- if (Btype === 'i') {
212
+ const absOffset = ba.byteOffset + p;
213
+ if (Btype === 0x69) {
214
+ // 'i'
203
215
  if (absOffset % 4 === 0) {
204
- tags[tag] = new Int32Array(this.byteArray.buffer, absOffset, limit);
216
+ tags[tag] = new Int32Array(ba.buffer, absOffset, limit);
205
217
  }
206
218
  else {
207
- const bytes = this.byteArray.slice(p, p + (limit << 2));
219
+ const bytes = ba.slice(p, p + (limit << 2));
208
220
  tags[tag] = new Int32Array(bytes.buffer, bytes.byteOffset, limit);
209
221
  }
210
222
  p += limit << 2;
211
223
  }
212
- else if (Btype === 'I') {
224
+ else if (Btype === 0x49) {
225
+ // 'I'
213
226
  if (absOffset % 4 === 0) {
214
- tags[tag] = new Uint32Array(this.byteArray.buffer, absOffset, limit);
227
+ tags[tag] = new Uint32Array(ba.buffer, absOffset, limit);
215
228
  }
216
229
  else {
217
- const bytes = this.byteArray.slice(p, p + (limit << 2));
230
+ const bytes = ba.slice(p, p + (limit << 2));
218
231
  tags[tag] = new Uint32Array(bytes.buffer, bytes.byteOffset, limit);
219
232
  }
220
233
  p += limit << 2;
221
234
  }
222
- else if (Btype === 's') {
235
+ else if (Btype === 0x73) {
236
+ // 's'
223
237
  if (absOffset % 2 === 0) {
224
- tags[tag] = new Int16Array(this.byteArray.buffer, absOffset, limit);
238
+ tags[tag] = new Int16Array(ba.buffer, absOffset, limit);
225
239
  }
226
240
  else {
227
- const bytes = this.byteArray.slice(p, p + (limit << 1));
241
+ const bytes = ba.slice(p, p + (limit << 1));
228
242
  tags[tag] = new Int16Array(bytes.buffer, bytes.byteOffset, limit);
229
243
  }
230
244
  p += limit << 1;
231
245
  }
232
- else if (Btype === 'S') {
246
+ else if (Btype === 0x53) {
247
+ // 'S'
233
248
  if (absOffset % 2 === 0) {
234
- tags[tag] = new Uint16Array(this.byteArray.buffer, absOffset, limit);
249
+ tags[tag] = new Uint16Array(ba.buffer, absOffset, limit);
235
250
  }
236
251
  else {
237
- const bytes = this.byteArray.slice(p, p + (limit << 1));
252
+ const bytes = ba.slice(p, p + (limit << 1));
238
253
  tags[tag] = new Uint16Array(bytes.buffer, bytes.byteOffset, limit);
239
254
  }
240
255
  p += limit << 1;
241
256
  }
242
- else if (Btype === 'c') {
243
- tags[tag] = new Int8Array(this.byteArray.buffer, absOffset, limit);
257
+ else if (Btype === 0x63) {
258
+ // 'c'
259
+ tags[tag] = new Int8Array(ba.buffer, absOffset, limit);
244
260
  p += limit;
245
261
  }
246
- else if (Btype === 'C') {
247
- tags[tag] = new Uint8Array(this.byteArray.buffer, absOffset, limit);
262
+ else if (Btype === 0x43) {
263
+ // 'C'
264
+ tags[tag] = new Uint8Array(ba.buffer, absOffset, limit);
248
265
  p += limit;
249
266
  }
250
- else if (Btype === 'f') {
267
+ else if (Btype === 0x66) {
268
+ // 'f'
251
269
  if (absOffset % 4 === 0) {
252
- tags[tag] = new Float32Array(this.byteArray.buffer, absOffset, limit);
270
+ tags[tag] = new Float32Array(ba.buffer, absOffset, limit);
253
271
  }
254
272
  else {
255
- const bytes = this.byteArray.slice(p, p + (limit << 2));
273
+ const bytes = ba.slice(p, p + (limit << 2));
256
274
  tags[tag] = new Float32Array(bytes.buffer, bytes.byteOffset, limit);
257
275
  }
258
276
  p += limit << 2;
@@ -266,58 +284,49 @@ class BamRecord {
266
284
  }
267
285
  return tags;
268
286
  }
269
- /**
270
- * @returns {boolean} true if the read is paired, regardless of whether both
271
- * segments are mapped
272
- */
273
287
  isPaired() {
274
288
  return !!(this.flags & constants_ts_1.default.BAM_FPAIRED);
275
289
  }
276
- /** @returns {boolean} true if the read is paired, and both segments are mapped */
277
290
  isProperlyPaired() {
278
291
  return !!(this.flags & constants_ts_1.default.BAM_FPROPER_PAIR);
279
292
  }
280
- /** @returns {boolean} true if the read itself is unmapped; conflictive with isProperlyPaired */
281
293
  isSegmentUnmapped() {
282
294
  return !!(this.flags & constants_ts_1.default.BAM_FUNMAP);
283
295
  }
284
- /** @returns {boolean} true if the read itself is unmapped; conflictive with isProperlyPaired */
285
296
  isMateUnmapped() {
286
297
  return !!(this.flags & constants_ts_1.default.BAM_FMUNMAP);
287
298
  }
288
- /** @returns {boolean} true if the read is mapped to the reverse strand */
289
299
  isReverseComplemented() {
290
300
  return !!(this.flags & constants_ts_1.default.BAM_FREVERSE);
291
301
  }
292
- /** @returns {boolean} true if the mate is mapped to the reverse strand */
293
302
  isMateReverseComplemented() {
294
303
  return !!(this.flags & constants_ts_1.default.BAM_FMREVERSE);
295
304
  }
296
- /** @returns {boolean} true if this is read number 1 in a pair */
297
305
  isRead1() {
298
306
  return !!(this.flags & constants_ts_1.default.BAM_FREAD1);
299
307
  }
300
- /** @returns {boolean} true if this is read number 2 in a pair */
301
308
  isRead2() {
302
309
  return !!(this.flags & constants_ts_1.default.BAM_FREAD2);
303
310
  }
304
- /** @returns {boolean} true if this is a secondary alignment */
305
311
  isSecondary() {
306
312
  return !!(this.flags & constants_ts_1.default.BAM_FSECONDARY);
307
313
  }
308
- /** @returns {boolean} true if this read has failed QC checks */
309
314
  isFailedQc() {
310
315
  return !!(this.flags & constants_ts_1.default.BAM_FQCFAIL);
311
316
  }
312
- /** @returns {boolean} true if the read is an optical or PCR duplicate */
313
317
  isDuplicate() {
314
318
  return !!(this.flags & constants_ts_1.default.BAM_FDUP);
315
319
  }
316
- /** @returns {boolean} true if this is a supplementary alignment */
317
320
  isSupplementary() {
318
321
  return !!(this.flags & constants_ts_1.default.BAM_FSUPPLEMENTARY);
319
322
  }
320
323
  get cigarAndLength() {
324
+ if (this._cachedCigarAndLength === undefined) {
325
+ this._cachedCigarAndLength = this._computeCigarAndLength();
326
+ }
327
+ return this._cachedCigarAndLength;
328
+ }
329
+ _computeCigarAndLength() {
321
330
  if (this.isSegmentUnmapped()) {
322
331
  return {
323
332
  length_on_ref: 0,
@@ -331,14 +340,14 @@ class BamRecord {
331
340
  const cigop = this._dataView.getInt32(p, true);
332
341
  const lop = cigop >> 4;
333
342
  const op = cigop & 0xf;
334
- if (op === CIGAR_SOFT_CLIP && lop === this.seq_length) {
343
+ if (op === cigar_ts_1.CIGAR_SOFT_CLIP && lop === this.seq_length) {
335
344
  // if there is a CG the second CIGAR field will be a N tag the represents
336
345
  // the length on ref
337
346
  p += 4;
338
347
  const cigop = this._dataView.getInt32(p, true);
339
348
  const lop = cigop >> 4;
340
349
  const op = cigop & 0xf;
341
- if (op !== CIGAR_REF_SKIP) {
350
+ if (op !== cigar_ts_1.CIGAR_REF_SKIP) {
342
351
  console.warn('CG tag with no N tag');
343
352
  }
344
353
  const cgArray = this.tags.CG;
@@ -347,24 +356,22 @@ class BamRecord {
347
356
  length_on_ref: lop,
348
357
  };
349
358
  }
350
- else {
351
- const absOffset = this.byteArray.byteOffset + p;
352
- const cigarView = absOffset % 4 === 0
353
- ? new Uint32Array(this.byteArray.buffer, absOffset, numCigarOps)
354
- : new Uint32Array(this.byteArray.slice(p, p + (numCigarOps << 2)).buffer, 0, numCigarOps);
355
- let lref = 0;
356
- for (let c = 0; c < numCigarOps; ++c) {
357
- const cigop = cigarView[c];
358
- const op = cigop & 0xf;
359
- if (!((1 << op) & CIGAR_SKIP_MASK)) {
360
- lref += cigop >> 4;
361
- }
359
+ const absOffset = this.byteArray.byteOffset + p;
360
+ const cigarView = absOffset % 4 === 0
361
+ ? new Uint32Array(this.byteArray.buffer, absOffset, numCigarOps)
362
+ : new Uint32Array(this.byteArray.slice(p, p + (numCigarOps << 2)).buffer, 0, numCigarOps);
363
+ let lref = 0;
364
+ for (let c = 0; c < numCigarOps; ++c) {
365
+ const cigop = cigarView[c];
366
+ const op = cigop & 0xf;
367
+ if (!((1 << op) & CIGAR_SKIP_MASK)) {
368
+ lref += cigop >> 4;
362
369
  }
363
- return {
364
- NUMERIC_CIGAR: cigarView,
365
- length_on_ref: lref,
366
- };
367
370
  }
371
+ return {
372
+ NUMERIC_CIGAR: cigarView,
373
+ length_on_ref: lref,
374
+ };
368
375
  }
369
376
  get length_on_ref() {
370
377
  return this.cigarAndLength.length_on_ref;
@@ -397,8 +404,7 @@ class BamRecord {
397
404
  }
398
405
  get NUMERIC_SEQ() {
399
406
  const p = this.b0 + this.read_name_length + this.num_cigar_bytes;
400
- const seqBytes = this.byteArray.subarray(p, p + this.num_seq_bytes);
401
- return new Uint8Array(seqBytes.buffer, seqBytes.byteOffset, this.num_seq_bytes);
407
+ return this.byteArray.subarray(p, p + this.num_seq_bytes);
402
408
  }
403
409
  get seq() {
404
410
  const numeric = this.NUMERIC_SEQ;
@@ -495,28 +501,4 @@ class BamRecord {
495
501
  }
496
502
  }
497
503
  exports.default = BamRecord;
498
- function cacheGetter(ctor, prop) {
499
- const desc = Object.getOwnPropertyDescriptor(ctor.prototype, prop);
500
- if (!desc) {
501
- throw new Error('OH NO, NO PROPERTY DESCRIPTOR');
502
- }
503
- // eslint-disable-next-line @typescript-eslint/unbound-method
504
- const getter = desc.get;
505
- if (!getter) {
506
- throw new Error('OH NO, NOT A GETTER');
507
- }
508
- Object.defineProperty(ctor.prototype, prop, {
509
- get() {
510
- const ret = getter.call(this);
511
- Object.defineProperty(this, prop, { value: ret });
512
- return ret;
513
- },
514
- });
515
- }
516
- cacheGetter(BamRecord, 'tags');
517
- cacheGetter(BamRecord, 'cigarAndLength');
518
- cacheGetter(BamRecord, 'seq');
519
- cacheGetter(BamRecord, 'qual');
520
- cacheGetter(BamRecord, 'end');
521
- cacheGetter(BamRecord, 'NUMERIC_MD');
522
504
  //# sourceMappingURL=record.js.map