@gmod/bam 7.3.3 → 7.4.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.
- package/dist/bai.js +10 -7
- package/dist/bai.js.map +1 -1
- package/dist/bamFile.d.ts +25 -6
- package/dist/bamFile.js +91 -33
- package/dist/bamFile.js.map +1 -1
- package/dist/csi.js +2 -2
- package/dist/csi.js.map +1 -1
- package/dist/htsget.js +2 -2
- package/dist/htsget.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/long.d.ts +0 -2
- package/dist/long.js +2 -4
- package/dist/long.js.map +1 -1
- package/dist/record.d.ts +3 -2
- package/dist/record.js +198 -178
- package/dist/record.js.map +1 -1
- package/dist/util.d.ts +1 -1
- package/dist/util.js +11 -12
- package/dist/util.js.map +1 -1
- package/dist/virtualOffset.d.ts +1 -1
- package/dist/virtualOffset.js +1 -4
- package/dist/virtualOffset.js.map +1 -1
- package/esm/bai.js +10 -7
- package/esm/bai.js.map +1 -1
- package/esm/bamFile.d.ts +25 -6
- package/esm/bamFile.js +91 -33
- package/esm/bamFile.js.map +1 -1
- package/esm/csi.js +2 -2
- package/esm/csi.js.map +1 -1
- package/esm/htsget.js +2 -2
- package/esm/htsget.js.map +1 -1
- package/esm/index.d.ts +1 -1
- package/esm/index.js +1 -1
- package/esm/index.js.map +1 -1
- package/esm/long.d.ts +0 -2
- package/esm/long.js +1 -2
- package/esm/long.js.map +1 -1
- package/esm/record.d.ts +3 -2
- package/esm/record.js +198 -178
- package/esm/record.js.map +1 -1
- package/esm/util.d.ts +1 -1
- package/esm/util.js +11 -11
- package/esm/util.js.map +1 -1
- package/esm/virtualOffset.d.ts +1 -1
- package/esm/virtualOffset.js +1 -4
- package/esm/virtualOffset.js.map +1 -1
- package/package.json +2 -1
- package/src/bai.ts +15 -8
- package/src/bamFile.ts +117 -40
- package/src/csi.ts +10 -2
- package/src/htsget.ts +6 -2
- package/src/index.ts +1 -1
- package/src/long.ts +1 -2
- package/src/record.ts +231 -192
- package/src/util.ts +24 -14
- package/src/virtualOffset.ts +1 -5
package/esm/util.js
CHANGED
|
@@ -103,9 +103,11 @@ export function parseRefSeqs(uncba, start, renameRefSeq) {
|
|
|
103
103
|
if (start + 4 > uncba.length) {
|
|
104
104
|
return undefined;
|
|
105
105
|
}
|
|
106
|
-
const dataView = new DataView(uncba.buffer);
|
|
106
|
+
const dataView = new DataView(uncba.buffer, uncba.byteOffset, uncba.byteLength);
|
|
107
107
|
const nRef = dataView.getInt32(start, true);
|
|
108
|
-
|
|
108
|
+
// null prototype: ref names come from the file, so a contig named
|
|
109
|
+
// "constructor" must not resolve to Object.prototype's
|
|
110
|
+
const chrToIndex = Object.create(null);
|
|
109
111
|
const indexToChr = [];
|
|
110
112
|
const decoder = new TextDecoder('utf8');
|
|
111
113
|
let p = start + 4;
|
|
@@ -138,7 +140,7 @@ export function parseNameBytes(namesBytes, renameRefSeq = s => s) {
|
|
|
138
140
|
let currRefId = 0;
|
|
139
141
|
let currNameStart = 0;
|
|
140
142
|
const refIdToName = [];
|
|
141
|
-
const refNameToId =
|
|
143
|
+
const refNameToId = Object.create(null);
|
|
142
144
|
for (let i = 0; i < namesBytes.length; i++) {
|
|
143
145
|
if (!namesBytes[i]) {
|
|
144
146
|
if (currNameStart < i) {
|
|
@@ -173,13 +175,11 @@ export function filterTagValue(readVal, filterVal) {
|
|
|
173
175
|
? readVal === undefined
|
|
174
176
|
: `${readVal}` !== `${filterVal}`;
|
|
175
177
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
const tagPart = tagFilter ? `:${tagFilter.tag}=${tagFilter.value ?? '*'}` : '';
|
|
182
|
-
return `:f${flagInclude}x${flagExclude}${tagPart}`;
|
|
178
|
+
// Read a single tag, preferring the targeted accessor. Reaching for `tags`
|
|
179
|
+
// instead would decode every unrelated tag on the record (NM/AS/ms/de/… — often
|
|
180
|
+
// ~10 per read) just to test one, which measured 2.6x the cost of getTag.
|
|
181
|
+
function readTag(record, tag) {
|
|
182
|
+
return record.getTag ? record.getTag(tag) : record.tags[tag];
|
|
183
183
|
}
|
|
184
184
|
// Apply flagInclude/flagExclude/tagFilter to a list of records.
|
|
185
185
|
export function applyFilters(records, filterBy) {
|
|
@@ -188,7 +188,7 @@ export function applyFilters(records, filterBy) {
|
|
|
188
188
|
for (let i = 0, l = records.length; i < l; i++) {
|
|
189
189
|
const r = records[i];
|
|
190
190
|
if (!filterReadFlag(r.flags, flagInclude, flagExclude) &&
|
|
191
|
-
!(tagFilter && filterTagValue(r
|
|
191
|
+
!(tagFilter && filterTagValue(readTag(r, tagFilter.tag), tagFilter.value))) {
|
|
192
192
|
out.push(r);
|
|
193
193
|
}
|
|
194
194
|
}
|
package/esm/util.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,YAAY,CAAA;AAC9B,OAAO,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAA;AA0CnD,MAAM,UAAU,cAAc,CAAC,MAAe,EAAE,MAAe;IAC7D,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,CAAA;IACvB,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACZ,OAAO,MAAM,CAAA;IACf,CAAC;IAED,0DAA0D;IAC1D,IAAI,QAAiB,CAAA;IACrB,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,WAAW,GAAG,MAAM,CAAC,aAAa,CAAA;QACxC,MAAM,UAAU,GAAG,MAAM,CAAC,YAAY,CAAA;QACtC,QAAQ,GAAG,EAAE,CAAA;QACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3B,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAE,CAAA;YACxB,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAA;YACvB,MAAM,GAAG,GACP,IAAI,CAAC,aAAa,GAAG,WAAW,IAAI,IAAI,CAAC,YAAY,GAAG,UAAU,CAAA;YACpE,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;gBACZ,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YACtB,CAAC;QACH,CAAC;QACD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO,QAAQ,CAAA;QACjB,CAAC;IACH,CAAC;SAAM,CAAC;QACN,QAAQ,GAAG,MAAM,CAAA;IACnB,CAAC;IAED,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE;QACvB,MAAM,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,aAAa,GAAG,EAAE,CAAC,IAAI,CAAC,aAAa,CAAA;QACzD,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,YAAY,GAAG,EAAE,CAAC,IAAI,CAAC,YAAY,CAAA;IACtE,CAAC,CAAC,CAAA;IAEF,yEAAyE;IACzE,uEAAuE;IACvE,MAAM,YAAY,GAAY,CAAC,QAAQ,CAAC,CAAC,CAAE,CAAC,CAAA;IAC5C,IAAI,YAAY,GAAG,QAAQ,CAAC,CAAC,CAAE,CAAC,IAAI,CAAC,aAAa,CAAA;IAClD,IAAI,YAAY,GAAG,QAAQ,CAAC,CAAC,CAAE,CAAC,IAAI,CAAC,aAAa,CAAA;IAElD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,MAAM,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAE,CAAA;QAC1B,MAAM,aAAa,GAAG,KAAK,CAAC,IAAI,CAAC,aAAa,CAAA;QAC9C,MAAM,aAAa,GAAG,KAAK,CAAC,IAAI,CAAC,aAAa,CAAA;QAC9C,oEAAoE;QACpE,yEAAyE;QACzE,IACE,aAAa,GAAG,YAAY,GAAG,KAAK;YACpC,aAAa,GAAG,YAAY,GAAG,OAAO,EACtC,CAAC;YACD,MAAM,SAAS,GAAG,YAAY,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAE,CAAA;YACxD,MAAM,GAAG,GACP,aAAa,GAAG,YAAY;gBAC5B,KAAK,CAAC,IAAI,CAAC,YAAY,GAAG,SAAS,CAAC,IAAI,CAAC,YAAY,CAAA;YACvD,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;gBACZ,YAAY,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,IAAI,KAAK,CAC/C,SAAS,CAAC,IAAI,EACd,KAAK,CAAC,IAAI,EACV,SAAS,CAAC,GAAG,EACb,KAAK,CAAC,WAAW,CAClB,CAAA;gBACD,YAAY,GAAG,aAAa,CAAA;YAC9B,CAAC;QACH,CAAC;aAAM,CAAC;YACN,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YACxB,YAAY,GAAG,aAAa,CAAA;YAC5B,YAAY,GAAG,aAAa,CAAA;QAC9B,CAAC;IACH,CAAC;IAED,OAAO,YAAY,CAAA;AACrB,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAiB,EAAE,MAAc;IAC9D,OAAO;QACL,SAAS,EAAE,uBAAuB,CAAC,KAAK,EAAE,MAAM,CAAC;KAClD,CAAA;AACH,CAAC;AAED,6EAA6E;AAC7E,kFAAkF;AAClF,kFAAkF;AAClF,iFAAiF;AACjF,kFAAkF;AAClF,iFAAiF;AACjF,yEAAyE;AACzE,MAAM,UAAU,cAAc,CAC5B,MAAe,EACf,kBAA4B,EAAE;IAE9B,MAAM,UAAU,GAAG,CAAC,GAAG,eAAe,CAAC,CAAA;IACvC,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAA;IAC7D,CAAC;IACD,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;IAEhC,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,MAAM,GAAG,GAAG,CAAC,CAAC,IAAI,CAAC,aAAa,CAAA;QAChC,2CAA2C;QAC3C,IAAI,EAAE,GAAG,CAAC,CAAA;QACV,IAAI,EAAE,GAAG,UAAU,CAAC,MAAM,CAAA;QAC1B,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC;YACf,MAAM,GAAG,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,CAAA;YAC3B,IAAI,UAAU,CAAC,GAAG,CAAE,GAAG,GAAG,EAAE,CAAC;gBAC3B,EAAE,GAAG,GAAG,CAAA;YACV,CAAC;iBAAM,CAAC;gBACN,EAAE,GAAG,GAAG,GAAG,CAAC,CAAA;YACd,CAAC;QACH,CAAC;QACD,IAAI,EAAE,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC;YAC3B,CAAC,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,UAAU,CAAC,EAAE,CAAE,CAAC,CAAA;QAC1D,CAAC;IACH,CAAC;AACH,CAAC;AAED,6EAA6E;AAC7E,4EAA4E;AAC5E,eAAe;AACf,MAAM,UAAU,YAAY,CAC1B,KAAiB,EACjB,KAAa,EACb,YAAmC;IAEnC,IAAI,KAAK,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;QAC7B,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAC3B,KAAK,CAAC,MAAM,EACZ,KAAK,CAAC,UAAU,EAChB,KAAK,CAAC,UAAU,CACjB,CAAA;IACD,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;IAC3C,kEAAkE;IAClE,uDAAuD;IACvD,MAAM,UAAU,GAA2B,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IAC9D,MAAM,UAAU,GAA0C,EAAE,CAAA;IAC5D,MAAM,OAAO,GAAG,IAAI,WAAW,CAAC,MAAM,CAAC,CAAA;IAEvC,IAAI,CAAC,GAAG,KAAK,GAAG,CAAC,CAAA;IACjB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;QAC9B,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;YACzB,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,CAAA;QACxC,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;YACjC,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,MAAM,OAAO,GAAG,YAAY,CAC1B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CACzD,CAAA;QACD,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,EAAE,IAAI,CAAC,CAAA;QACnD,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QACvB,UAAU,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAA;QAC1C,CAAC,IAAI,CAAC,GAAG,KAAK,CAAA;IAChB,CAAC;IACD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,CAAA;AACnC,CAAC;AAED,MAAM,UAAU,aAAa,CAC3B,aAAwC,EACxC,aAA4B;IAE5B,OAAO,aAAa;QAClB,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,aAAa,CAAC,GAAG,CAAC;YAC1C,CAAC,CAAC,aAAa;YACf,CAAC,CAAC,aAAa;QACjB,CAAC,CAAC,aAAa,CAAA;AACnB,CAAC;AAED,4FAA4F;AAC5F,MAAM,UAAU,cAAc,CAC5B,UAAsB,EACtB,eAAwC,CAAC,CAAC,EAAE,CAAC,CAAC;IAE9C,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAA;IACjC,IAAI,SAAS,GAAG,CAAC,CAAA;IACjB,IAAI,aAAa,GAAG,CAAC,CAAA;IACrB,MAAM,WAAW,GAAa,EAAE,CAAA;IAChC,MAAM,WAAW,GAA2B,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IAC/D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3C,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;YACnB,IAAI,aAAa,GAAG,CAAC,EAAE,CAAC;gBACtB,MAAM,OAAO,GAAG,YAAY,CAC1B,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,CACtD,CAAA;gBACD,WAAW,CAAC,SAAS,CAAC,GAAG,OAAO,CAAA;gBAChC,WAAW,CAAC,OAAO,CAAC,GAAG,SAAS,CAAA;YAClC,CAAC;YACD,aAAa,GAAG,CAAC,GAAG,CAAC,CAAA;YACrB,SAAS,EAAE,CAAA;QACb,CAAC;IACH,CAAC;IACD,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,CAAA;AACrC,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAkB;IACjD,IAAI,WAAW,GAAG,CAAC,CAAA;IACnB,KAAK,MAAM,KAAK,IAAI,IAAI,EAAE,CAAC;QACzB,WAAW,IAAI,KAAK,CAAC,MAAM,CAAA;IAC7B,CAAC;IACD,MAAM,WAAW,GAAG,IAAI,UAAU,CAAC,WAAW,CAAC,CAAA;IAC/C,IAAI,MAAM,GAAG,CAAC,CAAA;IACd,KAAK,MAAM,KAAK,IAAI,IAAI,EAAE,CAAC;QACzB,WAAW,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;QAC9B,MAAM,IAAI,KAAK,CAAC,MAAM,CAAA;IACxB,CAAC;IACD,OAAO,WAAW,CAAA;AACpB,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,KAAa,EACb,WAAmB,EACnB,WAAmB;IAEnB,OAAO,CAAC,KAAK,GAAG,WAAW,CAAC,KAAK,WAAW,IAAI,CAAC,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,CAAA;AAC7E,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,OAAgB,EAAE,SAAkB;IACjE,OAAO,SAAS,KAAK,GAAG;QACtB,CAAC,CAAC,OAAO,KAAK,SAAS;QACvB,CAAC,CAAC,GAAG,OAAO,EAAE,KAAK,GAAG,SAAS,EAAE,CAAA;AACrC,CAAC;AAUD,2EAA2E;AAC3E,gFAAgF;AAChF,0EAA0E;AAC1E,SAAS,OAAO,CAAC,MAAkB,EAAE,GAAW;IAC9C,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAC9D,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,YAAY,CAC1B,OAAY,EACZ,QAAkB;IAElB,MAAM,EAAE,WAAW,GAAG,CAAC,EAAE,WAAW,GAAG,CAAC,EAAE,SAAS,EAAE,GAAG,QAAQ,CAAA;IAChE,MAAM,GAAG,GAAQ,EAAE,CAAA;IACnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/C,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAE,CAAA;QACrB,IACE,CAAC,cAAc,CAAC,CAAC,CAAC,KAAK,EAAE,WAAW,EAAE,WAAW,CAAC;YAClD,CAAC,CAAC,SAAS,IAAI,cAAc,CAAC,OAAO,CAAC,CAAC,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,EAC1E,CAAC;YACD,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACb,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAQD,0EAA0E;AAC1E,4EAA4E;AAC5E,6EAA6E;AAC7E,iDAAiD;AACjD,MAAM,UAAU,aAAa,CAC3B,OAAY,EACZ,KAAa,EACb,GAAW,EACX,GAAW,EACX,MAAW,EAAE;IAEb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/C,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAE,CAAA;QACrB,IAAI,CAAC,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;YACvB,IAAI,CAAC,CAAC,KAAK,IAAI,GAAG,EAAE,CAAC;gBACnB,MAAK;YACP,CAAC;iBAAM,IAAI,CAAC,CAAC,GAAG,IAAI,GAAG,EAAE,CAAC;gBACxB,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACb,CAAC;QACH,CAAC;aAAM,IAAI,CAAC,CAAC,MAAM,GAAG,KAAK,EAAE,CAAC;YAC5B,MAAK;QACP,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC"}
|
package/esm/virtualOffset.d.ts
CHANGED
|
@@ -11,4 +11,4 @@ export declare class VirtualOffset {
|
|
|
11
11
|
toString(): string;
|
|
12
12
|
compareTo(b: VirtualOffset): number;
|
|
13
13
|
}
|
|
14
|
-
export declare function fromBytes(bytes: Uint8Array, offset?: number
|
|
14
|
+
export declare function fromBytes(bytes: Uint8Array, offset?: number): VirtualOffset;
|
package/esm/virtualOffset.js
CHANGED
|
@@ -12,10 +12,7 @@ export class VirtualOffset {
|
|
|
12
12
|
return (this.blockPosition - b.blockPosition || this.dataPosition - b.dataPosition);
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
|
-
export function fromBytes(bytes, offset = 0
|
|
16
|
-
if (bigendian) {
|
|
17
|
-
throw new Error('big-endian virtual file offsets not implemented');
|
|
18
|
-
}
|
|
15
|
+
export function fromBytes(bytes, offset = 0) {
|
|
19
16
|
return new VirtualOffset(bytes[offset + 7] * 0x10000000000 +
|
|
20
17
|
bytes[offset + 6] * 0x100000000 +
|
|
21
18
|
bytes[offset + 5] * 0x1000000 +
|
package/esm/virtualOffset.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"virtualOffset.js","sourceRoot":"","sources":["../src/virtualOffset.ts"],"names":[],"mappings":"AAOA,MAAM,OAAO,aAAa;IACjB,aAAa,CAAQ;IACrB,YAAY,CAAQ;IAC3B,YAAY,aAAqB,EAAE,YAAoB;QACrD,IAAI,CAAC,aAAa,GAAG,aAAa,CAAA,CAAC,wCAAwC;QAC3E,IAAI,CAAC,YAAY,GAAG,YAAY,CAAA,CAAC,sCAAsC;IACzE,CAAC;IAED,QAAQ;QACN,OAAO,GAAG,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,YAAY,EAAE,CAAA;IACrD,CAAC;IAED,SAAS,CAAC,CAAgB;QACxB,OAAO,CACL,IAAI,CAAC,aAAa,GAAG,CAAC,CAAC,aAAa,IAAI,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC,YAAY,CAC3E,CAAA;IACH,CAAC;CACF;AACD,MAAM,UAAU,SAAS,CAAC,KAAiB,EAAE,MAAM,GAAG,CAAC
|
|
1
|
+
{"version":3,"file":"virtualOffset.js","sourceRoot":"","sources":["../src/virtualOffset.ts"],"names":[],"mappings":"AAOA,MAAM,OAAO,aAAa;IACjB,aAAa,CAAQ;IACrB,YAAY,CAAQ;IAC3B,YAAY,aAAqB,EAAE,YAAoB;QACrD,IAAI,CAAC,aAAa,GAAG,aAAa,CAAA,CAAC,wCAAwC;QAC3E,IAAI,CAAC,YAAY,GAAG,YAAY,CAAA,CAAC,sCAAsC;IACzE,CAAC;IAED,QAAQ;QACN,OAAO,GAAG,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,YAAY,EAAE,CAAA;IACrD,CAAC;IAED,SAAS,CAAC,CAAgB;QACxB,OAAO,CACL,IAAI,CAAC,aAAa,GAAG,CAAC,CAAC,aAAa,IAAI,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC,YAAY,CAC3E,CAAA;IACH,CAAC;CACF;AACD,MAAM,UAAU,SAAS,CAAC,KAAiB,EAAE,MAAM,GAAG,CAAC;IACrD,OAAO,IAAI,aAAa,CACtB,KAAK,CAAC,MAAM,GAAG,CAAC,CAAE,GAAG,aAAa;QAChC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAE,GAAG,WAAW;QAChC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAE,GAAG,SAAS;QAC9B,KAAK,CAAC,MAAM,GAAG,CAAC,CAAE,GAAG,OAAO;QAC5B,KAAK,CAAC,MAAM,GAAG,CAAC,CAAE,GAAG,KAAK;QAC1B,KAAK,CAAC,MAAM,GAAG,CAAC,CAAE,EACpB,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAE,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,CAAE,CAC3C,CAAA;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gmod/bam",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.4.0",
|
|
4
4
|
"description": "Parser for BAM and BAM index (bai) files",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"url": "https://github.com/GMOD/bam-js.git"
|
|
9
9
|
},
|
|
10
10
|
"type": "module",
|
|
11
|
+
"sideEffects": false,
|
|
11
12
|
"main": "dist/index.js",
|
|
12
13
|
"exports": {
|
|
13
14
|
"import": "./esm/index.js",
|
package/src/bai.ts
CHANGED
|
@@ -53,7 +53,11 @@ function reg2bins(beg: number, end: number) {
|
|
|
53
53
|
export default class BAI extends IndexFile<BaiParsed> {
|
|
54
54
|
async _parse(opts: BaseOpts): Promise<BaiParsed> {
|
|
55
55
|
const bytes = await this.filehandle.readFile(opts)
|
|
56
|
-
const dataView = new DataView(
|
|
56
|
+
const dataView = new DataView(
|
|
57
|
+
bytes.buffer,
|
|
58
|
+
bytes.byteOffset,
|
|
59
|
+
bytes.byteLength,
|
|
60
|
+
)
|
|
57
61
|
|
|
58
62
|
// check BAI magic numbers
|
|
59
63
|
if (dataView.getUint32(0, true) !== BAI_MAGIC) {
|
|
@@ -186,26 +190,29 @@ export default class BAI extends IndexFile<BaiParsed> {
|
|
|
186
190
|
}
|
|
187
191
|
const e = end === undefined ? (linearIndex.length - 1) * v : roundUp(end, v)
|
|
188
192
|
const s = start === undefined ? 0 : roundDown(start, v)
|
|
189
|
-
const depths = range
|
|
193
|
+
const depths: IndexCovEntry[] = range
|
|
190
194
|
? new Array((e - s) / v)
|
|
191
195
|
: new Array(linearIndex.length - 1)
|
|
192
196
|
const totalSize = linearIndex[linearIndex.length - 1]!.blockPosition
|
|
193
197
|
if (e > (linearIndex.length - 1) * v) {
|
|
194
198
|
throw new Error('query outside of range of linear index')
|
|
195
199
|
}
|
|
200
|
+
// Scale the block-delta into a read count as we go, rather than building the
|
|
201
|
+
// entries and then rebuilding every one of them to apply the scale. Keep the
|
|
202
|
+
// multiply-then-divide order: hoisting lineCount/totalSize into a factor
|
|
203
|
+
// reassociates the arithmetic and shifts scores by an ulp.
|
|
204
|
+
const lineCount = stats?.lineCount ?? 0
|
|
196
205
|
let currentPos = linearIndex[s / v]!.blockPosition
|
|
197
206
|
for (let i = s / v, j = 0; i < e / v; i++, j++) {
|
|
207
|
+
const nextPos = linearIndex[i + 1]!.blockPosition
|
|
198
208
|
depths[j] = {
|
|
199
|
-
score:
|
|
209
|
+
score: ((nextPos - currentPos) * lineCount) / totalSize,
|
|
200
210
|
start: i * v,
|
|
201
211
|
end: i * v + v,
|
|
202
212
|
}
|
|
203
|
-
currentPos =
|
|
213
|
+
currentPos = nextPos
|
|
204
214
|
}
|
|
205
|
-
return depths
|
|
206
|
-
...d,
|
|
207
|
-
score: (d.score * (stats?.lineCount ?? 0)) / totalSize,
|
|
208
|
-
}))
|
|
215
|
+
return depths
|
|
209
216
|
}
|
|
210
217
|
|
|
211
218
|
protected reg2bins(min: number, max: number) {
|
package/src/bamFile.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { unzip, unzipChunkSlice } from '@gmod/bgzf-filehandle'
|
|
2
|
-
import QuickLRU from '@jbrowse/quick-lru'
|
|
3
2
|
import crc32 from 'crc/calculators/crc32'
|
|
4
3
|
import { LocalFile, RemoteFile } from 'generic-filehandle2'
|
|
5
4
|
|
|
@@ -8,16 +7,11 @@ import CSI from './csi.ts'
|
|
|
8
7
|
import NullFilehandle from './nullFilehandle.ts'
|
|
9
8
|
import BAMFeature from './record.ts'
|
|
10
9
|
import { parseHeaderText } from './sam.ts'
|
|
11
|
-
import {
|
|
12
|
-
appendInRange,
|
|
13
|
-
applyFilters,
|
|
14
|
-
filterCacheKey,
|
|
15
|
-
parseRefSeqs,
|
|
16
|
-
} from './util.ts'
|
|
10
|
+
import { appendInRange, applyFilters, parseRefSeqs } from './util.ts'
|
|
17
11
|
|
|
18
12
|
import type Chunk from './chunk.ts'
|
|
19
13
|
import type { Bytes } from './record.ts'
|
|
20
|
-
import type { BamOpts, BaseOpts
|
|
14
|
+
import type { BamOpts, BaseOpts } from './util.ts'
|
|
21
15
|
import type { GenericFilehandle } from 'generic-filehandle2'
|
|
22
16
|
|
|
23
17
|
export interface BamRecordLike {
|
|
@@ -56,12 +50,83 @@ function resolveFilehandle(
|
|
|
56
50
|
interface ChunkEntry<T> {
|
|
57
51
|
minBlock: number
|
|
58
52
|
maxBlock: number
|
|
53
|
+
// decompressed size of the chunk these features are views into
|
|
54
|
+
bytes: number
|
|
59
55
|
features: T[]
|
|
60
56
|
}
|
|
61
57
|
|
|
62
|
-
|
|
58
|
+
// Keyed on the chunk's byte span only, not on filterBy: the cached value is the
|
|
59
|
+
// unfiltered parsed records (decompression + parse is the expensive part).
|
|
60
|
+
// Filters are applied cheaply on retrieval so toggling a filter over the same
|
|
61
|
+
// region is a cache hit rather than a re-decompress.
|
|
62
|
+
function chunkCacheKey(chunk: Chunk) {
|
|
63
63
|
const { minv, maxv } = chunk
|
|
64
|
-
return `${minv.blockPosition}:${minv.dataPosition}-${maxv.blockPosition}:${maxv.dataPosition}
|
|
64
|
+
return `${minv.blockPosition}:${minv.dataPosition}-${maxv.blockPosition}:${maxv.dataPosition}`
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Every record in an entry is a view into its chunk's decompressed buffer, so
|
|
68
|
+
// caching one entry pins that whole buffer — 8MB apiece on the nanopore and
|
|
69
|
+
// 2kb-read test files, and optimizeChunks merges spans up to 5MB *compressed*,
|
|
70
|
+
// so tens of MB is possible. A count-based LRU therefore gives no bound on
|
|
71
|
+
// memory at all, which is why this budgets by decompressed bytes instead.
|
|
72
|
+
export const DEFAULT_MAX_CACHE_BYTES = 100 * 1024 * 1024
|
|
73
|
+
|
|
74
|
+
class ChunkFeatureCache<T> {
|
|
75
|
+
public maxBytes: number
|
|
76
|
+
private entries = new Map<string, ChunkEntry<T>>()
|
|
77
|
+
private bytes = 0
|
|
78
|
+
|
|
79
|
+
constructor(maxBytes: number) {
|
|
80
|
+
this.maxBytes = maxBytes
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
get size() {
|
|
84
|
+
return this.entries.size
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
get byteSize() {
|
|
88
|
+
return this.bytes
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
get(key: string) {
|
|
92
|
+
const entry = this.entries.get(key)
|
|
93
|
+
if (entry) {
|
|
94
|
+
// re-insert so Map iteration order stays least-recently-used first
|
|
95
|
+
this.entries.delete(key)
|
|
96
|
+
this.entries.set(key, entry)
|
|
97
|
+
}
|
|
98
|
+
return entry
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
set(key: string, entry: ChunkEntry<T>) {
|
|
102
|
+
this.delete(key)
|
|
103
|
+
this.entries.set(key, entry)
|
|
104
|
+
this.bytes += entry.bytes
|
|
105
|
+
// Evict from the least-recently-used end. The size > 1 guard means a single
|
|
106
|
+
// chunk larger than the whole budget is still kept: the caller needs it for
|
|
107
|
+
// the query in flight, and dropping it would only force a re-decompress.
|
|
108
|
+
const lru = this.entries.keys()
|
|
109
|
+
while (this.bytes > this.maxBytes && this.entries.size > 1) {
|
|
110
|
+
this.delete(lru.next().value!)
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
delete(key: string) {
|
|
115
|
+
const entry = this.entries.get(key)
|
|
116
|
+
if (entry) {
|
|
117
|
+
this.entries.delete(key)
|
|
118
|
+
this.bytes -= entry.bytes
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
clear() {
|
|
123
|
+
this.entries.clear()
|
|
124
|
+
this.bytes = 0
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
[Symbol.iterator]() {
|
|
128
|
+
return this.entries[Symbol.iterator]()
|
|
129
|
+
}
|
|
65
130
|
}
|
|
66
131
|
|
|
67
132
|
export default class BamFile<T extends BamRecordLike = BAMFeature> {
|
|
@@ -76,9 +141,7 @@ export default class BamFile<T extends BamRecordLike = BAMFeature> {
|
|
|
76
141
|
|
|
77
142
|
// Cache for parsed features by chunk
|
|
78
143
|
// When a new chunk overlaps a cached chunk, we evict the cached one
|
|
79
|
-
public chunkFeatureCache
|
|
80
|
-
maxSize: 100,
|
|
81
|
-
})
|
|
144
|
+
public chunkFeatureCache: ChunkFeatureCache<T>
|
|
82
145
|
|
|
83
146
|
private RecordClass: BamRecordClass<T>
|
|
84
147
|
|
|
@@ -95,6 +158,7 @@ export default class BamFile<T extends BamRecordLike = BAMFeature> {
|
|
|
95
158
|
htsget,
|
|
96
159
|
renameRefSeqs = n => n,
|
|
97
160
|
recordClass,
|
|
161
|
+
maxCacheBytes = DEFAULT_MAX_CACHE_BYTES,
|
|
98
162
|
}: {
|
|
99
163
|
bamFilehandle?: GenericFilehandle
|
|
100
164
|
bamPath?: string
|
|
@@ -108,9 +172,12 @@ export default class BamFile<T extends BamRecordLike = BAMFeature> {
|
|
|
108
172
|
renameRefSeqs?: (a: string) => string
|
|
109
173
|
htsget?: boolean
|
|
110
174
|
recordClass?: BamRecordClass<T>
|
|
175
|
+
/** budget for the parsed-chunk cache, in decompressed bytes */
|
|
176
|
+
maxCacheBytes?: number
|
|
111
177
|
}) {
|
|
112
178
|
this.renameRefSeq = renameRefSeqs
|
|
113
179
|
this.RecordClass = (recordClass ?? BAMFeature) as BamRecordClass<T>
|
|
180
|
+
this.chunkFeatureCache = new ChunkFeatureCache<T>(maxCacheBytes)
|
|
114
181
|
|
|
115
182
|
const bamFh = resolveFilehandle(bamFilehandle, bamPath, bamUrl)
|
|
116
183
|
if (bamFh) {
|
|
@@ -162,7 +229,11 @@ export default class BamFile<T extends BamRecordLike = BAMFeature> {
|
|
|
162
229
|
? await this.bam.readFile()
|
|
163
230
|
: await this.bam.read(readLen, 0)
|
|
164
231
|
let uncba = await unzip(buffer)
|
|
165
|
-
const dataView = new DataView(
|
|
232
|
+
const dataView = new DataView(
|
|
233
|
+
uncba.buffer,
|
|
234
|
+
uncba.byteOffset,
|
|
235
|
+
uncba.byteLength,
|
|
236
|
+
)
|
|
166
237
|
|
|
167
238
|
if (dataView.getInt32(0, true) !== BAM_MAGIC) {
|
|
168
239
|
throw new Error('Not a BAM file')
|
|
@@ -221,7 +292,7 @@ export default class BamFile<T extends BamRecordLike = BAMFeature> {
|
|
|
221
292
|
return []
|
|
222
293
|
}
|
|
223
294
|
const chunks = await this.index.blocksForRange(chrId, min - 1, max, opts)
|
|
224
|
-
return this.
|
|
295
|
+
return this._fetchChunkFeatures(chunks, chrId, min, max, opts)
|
|
225
296
|
}
|
|
226
297
|
|
|
227
298
|
// Evict any cached chunks whose block range overlaps [minBlock, maxBlock]
|
|
@@ -233,7 +304,7 @@ export default class BamFile<T extends BamRecordLike = BAMFeature> {
|
|
|
233
304
|
}
|
|
234
305
|
}
|
|
235
306
|
|
|
236
|
-
private async
|
|
307
|
+
private async _fetchChunkFeatures(
|
|
237
308
|
chunks: Chunk[],
|
|
238
309
|
chrId: number,
|
|
239
310
|
min: number,
|
|
@@ -252,24 +323,20 @@ export default class BamFile<T extends BamRecordLike = BAMFeature> {
|
|
|
252
323
|
|
|
253
324
|
for (let ci = 0, cl = chunks.length; ci < cl; ci++) {
|
|
254
325
|
const chunk = chunks[ci]!
|
|
255
|
-
const cacheKey = chunkCacheKey(chunk
|
|
326
|
+
const cacheKey = chunkCacheKey(chunk)
|
|
256
327
|
const minBlock = chunk.minv.blockPosition
|
|
257
328
|
const maxBlock = chunk.maxv.blockPosition
|
|
258
329
|
|
|
259
|
-
let
|
|
260
|
-
|
|
261
|
-
if (cached) {
|
|
262
|
-
records = cached.features
|
|
263
|
-
} else {
|
|
330
|
+
let cached = this.chunkFeatureCache.get(cacheKey)
|
|
331
|
+
if (!cached) {
|
|
264
332
|
this.evictOverlappingChunks(minBlock, maxBlock)
|
|
265
|
-
const
|
|
266
|
-
|
|
267
|
-
this.chunkFeatureCache.set(cacheKey,
|
|
268
|
-
minBlock,
|
|
269
|
-
maxBlock,
|
|
270
|
-
features: records,
|
|
271
|
-
})
|
|
333
|
+
const { features, bytes } = await this._readChunkFeatures(chunk, opts)
|
|
334
|
+
cached = { minBlock, maxBlock, bytes, features }
|
|
335
|
+
this.chunkFeatureCache.set(cacheKey, cached)
|
|
272
336
|
}
|
|
337
|
+
const records = filterBy
|
|
338
|
+
? applyFilters(cached.features, filterBy)
|
|
339
|
+
: cached.features
|
|
273
340
|
|
|
274
341
|
downloadedBytes += chunk.fetchedSize()
|
|
275
342
|
onProgress?.(downloadedBytes, totalBytes)
|
|
@@ -288,13 +355,16 @@ export default class BamFile<T extends BamRecordLike = BAMFeature> {
|
|
|
288
355
|
|
|
289
356
|
async fetchPairs(chrId: number, records: T[], opts: BamOpts) {
|
|
290
357
|
const { pairAcrossChr, maxInsertSize = 200000 } = opts
|
|
291
|
-
|
|
358
|
+
// Map, not a plain object: read names come from the file, and on a plain
|
|
359
|
+
// object a read named "constructor" would read back Object.prototype's and
|
|
360
|
+
// make the count NaN.
|
|
361
|
+
const readNameCounts = new Map<string, number>()
|
|
292
362
|
const readIds = new Set<number>()
|
|
293
363
|
|
|
294
364
|
for (let i = 0, l = records.length; i < l; i++) {
|
|
295
365
|
const r = records[i]!
|
|
296
366
|
const name = r.name
|
|
297
|
-
readNameCounts
|
|
367
|
+
readNameCounts.set(name, (readNameCounts.get(name) ?? 0) + 1)
|
|
298
368
|
readIds.add(r.fileOffset)
|
|
299
369
|
}
|
|
300
370
|
|
|
@@ -304,7 +374,7 @@ export default class BamFile<T extends BamRecordLike = BAMFeature> {
|
|
|
304
374
|
const name = f.name
|
|
305
375
|
if (
|
|
306
376
|
this.index &&
|
|
307
|
-
readNameCounts
|
|
377
|
+
readNameCounts.get(name) === 1 &&
|
|
308
378
|
(pairAcrossChr ||
|
|
309
379
|
(f.next_refid === chrId &&
|
|
310
380
|
Math.abs(f.start - f.next_pos) < maxInsertSize))
|
|
@@ -332,12 +402,12 @@ export default class BamFile<T extends BamRecordLike = BAMFeature> {
|
|
|
332
402
|
|
|
333
403
|
const mateFeatLists = await Promise.all(
|
|
334
404
|
[...map.values()].map(async c => {
|
|
335
|
-
const features = await this._readChunkFeatures(c, opts)
|
|
405
|
+
const { features } = await this._readChunkFeatures(c, opts)
|
|
336
406
|
const mateRecs = [] as T[]
|
|
337
407
|
for (let i = 0, l = features.length; i < l; i++) {
|
|
338
408
|
const feature = features[i]!
|
|
339
409
|
if (
|
|
340
|
-
readNameCounts
|
|
410
|
+
readNameCounts.get(feature.name) === 1 &&
|
|
341
411
|
!readIds.has(feature.fileOffset)
|
|
342
412
|
) {
|
|
343
413
|
mateRecs.push(feature)
|
|
@@ -355,18 +425,25 @@ export default class BamFile<T extends BamRecordLike = BAMFeature> {
|
|
|
355
425
|
// filehandle's own streaming onProgress also fired this callback it would
|
|
356
426
|
// report a different `total` (this chunk's size, not the whole query),
|
|
357
427
|
// making the determinate bar jump around.
|
|
358
|
-
const buf = await this.bam.read(
|
|
359
|
-
|
|
360
|
-
|
|
428
|
+
const buf = await this.bam.read(
|
|
429
|
+
chunk.fetchedSize(),
|
|
430
|
+
chunk.minv.blockPosition,
|
|
431
|
+
{
|
|
432
|
+
signal: opts.signal,
|
|
433
|
+
},
|
|
434
|
+
)
|
|
361
435
|
const {
|
|
362
436
|
buffer: data,
|
|
363
437
|
cpositions,
|
|
364
438
|
dpositions,
|
|
365
439
|
} = await unzipChunkSlice(buf, chunk)
|
|
366
|
-
return
|
|
440
|
+
return {
|
|
441
|
+
features: this.readBamFeatures(data, cpositions, dpositions, chunk),
|
|
442
|
+
bytes: data.byteLength,
|
|
443
|
+
}
|
|
367
444
|
}
|
|
368
445
|
|
|
369
|
-
|
|
446
|
+
readBamFeatures(
|
|
370
447
|
ba: Uint8Array,
|
|
371
448
|
cpositions: number[],
|
|
372
449
|
dpositions: number[],
|
|
@@ -376,7 +453,7 @@ export default class BamFile<T extends BamRecordLike = BAMFeature> {
|
|
|
376
453
|
const sink = [] as T[]
|
|
377
454
|
let pos = 0
|
|
378
455
|
|
|
379
|
-
const dataView = new DataView(ba.buffer)
|
|
456
|
+
const dataView = new DataView(ba.buffer, ba.byteOffset, ba.byteLength)
|
|
380
457
|
const hasDpositions = dpositions.length > 0
|
|
381
458
|
const hasCpositions = cpositions.length > 0
|
|
382
459
|
|
package/src/csi.ts
CHANGED
|
@@ -36,7 +36,11 @@ export default class CSI extends IndexFile {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
parseAuxData(bytes: Uint8Array, offset: number) {
|
|
39
|
-
const dataView = new DataView(
|
|
39
|
+
const dataView = new DataView(
|
|
40
|
+
bytes.buffer,
|
|
41
|
+
bytes.byteOffset,
|
|
42
|
+
bytes.byteLength,
|
|
43
|
+
)
|
|
40
44
|
const formatFlags = dataView.getUint32(offset, true)
|
|
41
45
|
const coordinateType =
|
|
42
46
|
formatFlags & 0x10000 ? 'zero-based-half-open' : '1-based-closed'
|
|
@@ -74,7 +78,11 @@ export default class CSI extends IndexFile {
|
|
|
74
78
|
const buffer = await this.filehandle.readFile(opts)
|
|
75
79
|
const bytes = await unzip(buffer)
|
|
76
80
|
|
|
77
|
-
const dataView = new DataView(
|
|
81
|
+
const dataView = new DataView(
|
|
82
|
+
bytes.buffer,
|
|
83
|
+
bytes.byteOffset,
|
|
84
|
+
bytes.byteLength,
|
|
85
|
+
)
|
|
78
86
|
let csiVersion
|
|
79
87
|
const magic = dataView.getUint32(0, true)
|
|
80
88
|
|
package/src/htsget.ts
CHANGED
|
@@ -78,7 +78,7 @@ export default class HtsgetFile<
|
|
|
78
78
|
})
|
|
79
79
|
|
|
80
80
|
const zero = new VirtualOffset(0, 0)
|
|
81
|
-
const allRecords =
|
|
81
|
+
const allRecords = this.readBamFeatures(
|
|
82
82
|
uncba,
|
|
83
83
|
[],
|
|
84
84
|
[],
|
|
@@ -95,7 +95,11 @@ export default class HtsgetFile<
|
|
|
95
95
|
const uncba = await fetchAndConcat(data.htsget.urls, {
|
|
96
96
|
signal: opts.signal,
|
|
97
97
|
})
|
|
98
|
-
const dataView = new DataView(
|
|
98
|
+
const dataView = new DataView(
|
|
99
|
+
uncba.buffer,
|
|
100
|
+
uncba.byteOffset,
|
|
101
|
+
uncba.byteLength,
|
|
102
|
+
)
|
|
99
103
|
|
|
100
104
|
if (dataView.getInt32(0, true) !== BAM_MAGIC) {
|
|
101
105
|
throw new Error('Not a BAM file')
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { default as BAI } from './bai.ts'
|
|
2
|
-
export { default as BamFile } from './bamFile.ts'
|
|
2
|
+
export { DEFAULT_MAX_CACHE_BYTES, default as BamFile } from './bamFile.ts'
|
|
3
3
|
export { default as CSI } from './csi.ts'
|
|
4
4
|
export { default as BamRecord } from './record.ts'
|
|
5
5
|
export { default as HtsgetFile } from './htsget.ts'
|
package/src/long.ts
CHANGED