Comparing version 4.0.3 to 4.0.4
@@ -1,12 +0,16 @@ | ||
## [4.0.3](https://github.com/GMOD/bbi-js/compare/v4.0.2...v4.0.3) (2024-01-16) | ||
## [4.0.4](https://github.com/GMOD/bbi-js/compare/v4.0.3...v4.0.4) (2024-3-5) | ||
### Performance Improvements | ||
* optimize `parseBigBedBlock` ([#58](https://github.com/GMOD/bbi-js/issues/58)) ([eb3f7a4](https://github.com/GMOD/bbi-js/commit/eb3f7a4885c4e8262c6e3e63696b533e53072463)) | ||
- Fix issue fetching data from file where refNames are not sorted (#59) | ||
## [4.0.3](https://github.com/GMOD/bbi-js/compare/v4.0.2...v4.0.3) (2024-01-16) | ||
### Performance Improvements | ||
- Small perf improvement (#58) | ||
- optimize `parseBigBedBlock` ([#58](https://github.com/GMOD/bbi-js/issues/58)) | ||
([eb3f7a4](https://github.com/GMOD/bbi-js/commit/eb3f7a4885c4e8262c6e3e63696b533e53072463)) | ||
* Small perf improvement (#58) | ||
## [4.0.2](https://github.com/GMOD/bbi-js/compare/v4.0.1...v4.0.2) (2023-07-30) | ||
@@ -13,0 +17,0 @@ |
@@ -206,4 +206,4 @@ "use strict"; | ||
try { | ||
const length = fr.max() - fr.min(); | ||
const offset = fr.min(); | ||
const length = fr.max - fr.min; | ||
const offset = fr.min; | ||
const resultBuffer = yield this.featureCache.get(`${length}_${offset}`, { length, offset }, opts === null || opts === void 0 ? void 0 : opts.signal); | ||
@@ -215,3 +215,3 @@ for (const element of off) { | ||
if (outstanding === 0) { | ||
this.readFeatures(observer, blocksToFetch, Object.assign(Object.assign({}, opts), { request })); | ||
this.readFeatures(observer, blocksToFetch, Object.assign(Object.assign({}, opts), { request })).catch(e => observer.error(e)); | ||
} | ||
@@ -230,5 +230,9 @@ } | ||
const maxCirBlockSpan = 4 + Number(cirBlockSize) * 32; | ||
let spans = new range_1.default(offset[0], offset[0] + maxCirBlockSpan); | ||
let spans = new range_1.default([ | ||
{ min: offset[0], max: offset[0] + maxCirBlockSpan }, | ||
]); | ||
for (let i = 1; i < offset.length; i += 1) { | ||
const blockSpan = new range_1.default(offset[i], offset[i] + maxCirBlockSpan); | ||
const blockSpan = new range_1.default([ | ||
{ min: offset[i], max: offset[i] + maxCirBlockSpan }, | ||
]); | ||
spans = spans.union(blockSpan); | ||
@@ -235,0 +239,0 @@ } |
@@ -5,7 +5,11 @@ /** | ||
*/ | ||
export interface IRange { | ||
min: number; | ||
max: number; | ||
} | ||
export default class Range { | ||
ranges: any; | ||
constructor(arg1: any, arg2?: any); | ||
min(): number; | ||
max(): number; | ||
ranges: IRange[]; | ||
constructor(arg1: IRange[]); | ||
get min(): number; | ||
get max(): number; | ||
contains(pos: number): boolean; | ||
@@ -16,5 +20,2 @@ isContiguous(): boolean; | ||
union(s1: Range): Range; | ||
intersection(arg: Range): Range; | ||
coverage(): number; | ||
rangeOrder(tmpa: Range, tmpb: Range): number; | ||
} |
"use strict"; | ||
/* eslint prefer-rest-params:0, no-nested-ternary:0 */ | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
/** | ||
* Adapted from a combination of Range and _Compound in the | ||
* Dalliance Genome Explorer, (c) Thomas Down 2006-2010. | ||
*/ | ||
class Range { | ||
constructor(arg1, arg2) { | ||
this.ranges = | ||
arguments.length === 2 | ||
? [{ min: arg1, max: arg2 }] | ||
: 0 in arg1 | ||
? Object.assign({}, arg1) | ||
: [arg1]; | ||
constructor(arg1) { | ||
this.ranges = arg1; | ||
} | ||
min() { | ||
get min() { | ||
return this.ranges[0].min; | ||
} | ||
max() { | ||
get max() { | ||
return this.ranges[this.ranges.length - 1].max; | ||
} | ||
contains(pos) { | ||
for (let s = 0; s < this.ranges.length; s += 1) { | ||
const r = this.ranges[s]; | ||
for (const r of this.ranges) { | ||
if (r.min <= pos && r.max >= pos) { | ||
@@ -36,9 +26,25 @@ return true; | ||
getRanges() { | ||
return this.ranges.map((r) => new Range(r.min, r.max)); | ||
return this.ranges.map(r => new Range([{ min: r.min, max: r.max }])); | ||
} | ||
toString() { | ||
return this.ranges.map((r) => `[${r.min}-${r.max}]`).join(','); | ||
return this.ranges.map(r => `[${r.min}-${r.max}]`).join(','); | ||
} | ||
union(s1) { | ||
const ranges = this.getRanges().concat(s1.getRanges()).sort(this.rangeOrder); | ||
const ranges = [...this.getRanges(), ...s1.getRanges()].sort((a, b) => { | ||
if (a.min < b.min) { | ||
return -1; | ||
} | ||
else if (a.min > b.min) { | ||
return 1; | ||
} | ||
else if (a.max < b.max) { | ||
return -1; | ||
} | ||
else if (b.max > a.max) { | ||
return 1; | ||
} | ||
else { | ||
return 0; | ||
} | ||
}); | ||
const oranges = []; | ||
@@ -48,82 +54,15 @@ let current = ranges[0]; | ||
const nxt = ranges[i]; | ||
if (nxt.min() > current.max() + 1) { | ||
if (nxt.min > current.max + 1) { | ||
oranges.push(current); | ||
current = nxt; | ||
} | ||
else if (nxt.max() > current.max()) { | ||
current = new Range(current.min(), nxt.max()); | ||
else if (nxt.max > current.max) { | ||
current = new Range([{ min: current.min, max: nxt.max }]); | ||
} | ||
} | ||
oranges.push(current); | ||
if (oranges.length === 1) { | ||
return oranges[0]; | ||
} | ||
return new Range(oranges); | ||
return oranges.length === 1 ? oranges[0] : new Range(oranges); | ||
} | ||
intersection(arg) { | ||
// eslint-disable-next-line @typescript-eslint/no-this-alias,unicorn/no-this-assignment | ||
let s0 = this; | ||
let s1 = arg; | ||
const r0 = this.ranges(); | ||
const r1 = s1.ranges(); | ||
const l0 = r0.length; | ||
const l1 = r1.length; | ||
let i0 = 0; | ||
let i1 = 0; | ||
const or = []; | ||
while (i0 < l0 && i1 < l1) { | ||
s0 = r0[i0]; | ||
s1 = r1[i1]; | ||
const lapMin = Math.max(s0.min(), s1.min()); | ||
const lapMax = Math.min(s0.max(), s1.max()); | ||
if (lapMax >= lapMin) { | ||
or.push(new Range(lapMin, lapMax)); | ||
} | ||
if (s0.max() > s1.max()) { | ||
i1 += 1; | ||
} | ||
else { | ||
i0 += 1; | ||
} | ||
} | ||
if (or.length === 0) { | ||
throw new Error('found range of length 0'); | ||
} | ||
if (or.length === 1) { | ||
return or[0]; | ||
} | ||
return new Range(or); | ||
} | ||
coverage() { | ||
let tot = 0; | ||
const rl = this.ranges(); | ||
for (const r of rl) { | ||
tot += r.max() - r.min() + 1; | ||
} | ||
return tot; | ||
} | ||
rangeOrder(tmpa, tmpb) { | ||
let a = tmpa; | ||
let b = tmpb; | ||
if (arguments.length < 2) { | ||
b = a; | ||
// eslint-disable-next-line @typescript-eslint/no-this-alias,unicorn/no-this-assignment | ||
a = this; | ||
} | ||
if (a.min() < b.min()) { | ||
return -1; | ||
} | ||
if (a.min() > b.min()) { | ||
return 1; | ||
} | ||
if (a.max() < b.max()) { | ||
return -1; | ||
} | ||
if (b.max() > a.max()) { | ||
return 1; | ||
} | ||
return 0; | ||
} | ||
} | ||
exports.default = Range; | ||
//# sourceMappingURL=range.js.map |
@@ -190,4 +190,4 @@ import { Buffer } from 'buffer'; | ||
try { | ||
const length = fr.max() - fr.min(); | ||
const offset = fr.min(); | ||
const length = fr.max - fr.min; | ||
const offset = fr.min; | ||
const resultBuffer = await this.featureCache.get(`${length}_${offset}`, { length, offset }, opts === null || opts === void 0 ? void 0 : opts.signal); | ||
@@ -199,3 +199,6 @@ for (const element of off) { | ||
if (outstanding === 0) { | ||
this.readFeatures(observer, blocksToFetch, { ...opts, request }); | ||
this.readFeatures(observer, blocksToFetch, { | ||
...opts, | ||
request, | ||
}).catch(e => observer.error(e)); | ||
} | ||
@@ -214,5 +217,9 @@ } | ||
const maxCirBlockSpan = 4 + Number(cirBlockSize) * 32; | ||
let spans = new Range(offset[0], offset[0] + maxCirBlockSpan); | ||
let spans = new Range([ | ||
{ min: offset[0], max: offset[0] + maxCirBlockSpan }, | ||
]); | ||
for (let i = 1; i < offset.length; i += 1) { | ||
const blockSpan = new Range(offset[i], offset[i] + maxCirBlockSpan); | ||
const blockSpan = new Range([ | ||
{ min: offset[i], max: offset[i] + maxCirBlockSpan }, | ||
]); | ||
spans = spans.union(blockSpan); | ||
@@ -219,0 +226,0 @@ } |
@@ -5,7 +5,11 @@ /** | ||
*/ | ||
export interface IRange { | ||
min: number; | ||
max: number; | ||
} | ||
export default class Range { | ||
ranges: any; | ||
constructor(arg1: any, arg2?: any); | ||
min(): number; | ||
max(): number; | ||
ranges: IRange[]; | ||
constructor(arg1: IRange[]); | ||
get min(): number; | ||
get max(): number; | ||
contains(pos: number): boolean; | ||
@@ -16,5 +20,2 @@ isContiguous(): boolean; | ||
union(s1: Range): Range; | ||
intersection(arg: Range): Range; | ||
coverage(): number; | ||
rangeOrder(tmpa: Range, tmpb: Range): number; | ||
} |
117
esm/range.js
/* eslint prefer-rest-params:0, no-nested-ternary:0 */ | ||
/** | ||
* Adapted from a combination of Range and _Compound in the | ||
* Dalliance Genome Explorer, (c) Thomas Down 2006-2010. | ||
*/ | ||
export default class Range { | ||
constructor(arg1, arg2) { | ||
this.ranges = | ||
arguments.length === 2 | ||
? [{ min: arg1, max: arg2 }] | ||
: 0 in arg1 | ||
? Object.assign({}, arg1) | ||
: [arg1]; | ||
constructor(arg1) { | ||
this.ranges = arg1; | ||
} | ||
min() { | ||
get min() { | ||
return this.ranges[0].min; | ||
} | ||
max() { | ||
get max() { | ||
return this.ranges[this.ranges.length - 1].max; | ||
} | ||
contains(pos) { | ||
for (let s = 0; s < this.ranges.length; s += 1) { | ||
const r = this.ranges[s]; | ||
for (const r of this.ranges) { | ||
if (r.min <= pos && r.max >= pos) { | ||
@@ -34,9 +24,25 @@ return true; | ||
getRanges() { | ||
return this.ranges.map((r) => new Range(r.min, r.max)); | ||
return this.ranges.map(r => new Range([{ min: r.min, max: r.max }])); | ||
} | ||
toString() { | ||
return this.ranges.map((r) => `[${r.min}-${r.max}]`).join(','); | ||
return this.ranges.map(r => `[${r.min}-${r.max}]`).join(','); | ||
} | ||
union(s1) { | ||
const ranges = this.getRanges().concat(s1.getRanges()).sort(this.rangeOrder); | ||
const ranges = [...this.getRanges(), ...s1.getRanges()].sort((a, b) => { | ||
if (a.min < b.min) { | ||
return -1; | ||
} | ||
else if (a.min > b.min) { | ||
return 1; | ||
} | ||
else if (a.max < b.max) { | ||
return -1; | ||
} | ||
else if (b.max > a.max) { | ||
return 1; | ||
} | ||
else { | ||
return 0; | ||
} | ||
}); | ||
const oranges = []; | ||
@@ -46,81 +52,14 @@ let current = ranges[0]; | ||
const nxt = ranges[i]; | ||
if (nxt.min() > current.max() + 1) { | ||
if (nxt.min > current.max + 1) { | ||
oranges.push(current); | ||
current = nxt; | ||
} | ||
else if (nxt.max() > current.max()) { | ||
current = new Range(current.min(), nxt.max()); | ||
else if (nxt.max > current.max) { | ||
current = new Range([{ min: current.min, max: nxt.max }]); | ||
} | ||
} | ||
oranges.push(current); | ||
if (oranges.length === 1) { | ||
return oranges[0]; | ||
} | ||
return new Range(oranges); | ||
return oranges.length === 1 ? oranges[0] : new Range(oranges); | ||
} | ||
intersection(arg) { | ||
// eslint-disable-next-line @typescript-eslint/no-this-alias,unicorn/no-this-assignment | ||
let s0 = this; | ||
let s1 = arg; | ||
const r0 = this.ranges(); | ||
const r1 = s1.ranges(); | ||
const l0 = r0.length; | ||
const l1 = r1.length; | ||
let i0 = 0; | ||
let i1 = 0; | ||
const or = []; | ||
while (i0 < l0 && i1 < l1) { | ||
s0 = r0[i0]; | ||
s1 = r1[i1]; | ||
const lapMin = Math.max(s0.min(), s1.min()); | ||
const lapMax = Math.min(s0.max(), s1.max()); | ||
if (lapMax >= lapMin) { | ||
or.push(new Range(lapMin, lapMax)); | ||
} | ||
if (s0.max() > s1.max()) { | ||
i1 += 1; | ||
} | ||
else { | ||
i0 += 1; | ||
} | ||
} | ||
if (or.length === 0) { | ||
throw new Error('found range of length 0'); | ||
} | ||
if (or.length === 1) { | ||
return or[0]; | ||
} | ||
return new Range(or); | ||
} | ||
coverage() { | ||
let tot = 0; | ||
const rl = this.ranges(); | ||
for (const r of rl) { | ||
tot += r.max() - r.min() + 1; | ||
} | ||
return tot; | ||
} | ||
rangeOrder(tmpa, tmpb) { | ||
let a = tmpa; | ||
let b = tmpb; | ||
if (arguments.length < 2) { | ||
b = a; | ||
// eslint-disable-next-line @typescript-eslint/no-this-alias,unicorn/no-this-assignment | ||
a = this; | ||
} | ||
if (a.min() < b.min()) { | ||
return -1; | ||
} | ||
if (a.min() > b.min()) { | ||
return 1; | ||
} | ||
if (a.max() < b.max()) { | ||
return -1; | ||
} | ||
if (b.max() > a.max()) { | ||
return 1; | ||
} | ||
return 0; | ||
} | ||
} | ||
//# sourceMappingURL=range.js.map |
{ | ||
"name": "@gmod/bbi", | ||
"version": "4.0.3", | ||
"version": "4.0.4", | ||
"description": "Parser for BigWig/BigBed files", | ||
@@ -54,17 +54,17 @@ "license": "MIT", | ||
"@gmod/bed": "^2.1.2", | ||
"@types/jest": "^29.5.3", | ||
"@types/node": "^20.4.5", | ||
"@types/jest": "^29.5.12", | ||
"@types/node": "^20.11.16", | ||
"@types/pako": "^2.0.0", | ||
"@typescript-eslint/eslint-plugin": "^6.2.0", | ||
"@typescript-eslint/parser": "^6.2.0", | ||
"@typescript-eslint/eslint-plugin": "^6.21.0", | ||
"@typescript-eslint/parser": "^6.21.0", | ||
"eslint": "^8.46.0", | ||
"eslint-config-prettier": "^9.1.0", | ||
"eslint-plugin-prettier": "^5.1.3", | ||
"eslint-plugin-unicorn": "^50.0.1", | ||
"eslint-plugin-unicorn": "^51.0.0", | ||
"jest": "^29.6.2", | ||
"jest-environment-jsdom": "^29.6.2", | ||
"prettier": "^3.0.0", | ||
"prettier": "^3.2.5", | ||
"rimraf": "^5.0.1", | ||
"standard-changelog": "^3.0.0", | ||
"ts-jest": "^29.1.1", | ||
"standard-changelog": "^5.0.0", | ||
"ts-jest": "^29.1.2", | ||
"typescript": "^5.1.6" | ||
@@ -71,0 +71,0 @@ }, |
@@ -32,3 +32,4 @@ # bbi-js | ||
// if running in the browser, RemoteFile will use the the global fetch | ||
// if running in the browser or newer versions of node.js, RemoteFile will use | ||
// the the global fetch | ||
const file = new BigWig({ | ||
@@ -38,3 +39,3 @@ filehandle: new RemoteFile('volvox.bw'), | ||
// if running under node.js you must supply the fetch function to RemoteFile | ||
// old versions of node.js without a global fetch, supply custom fetch function | ||
const fetch = require('node-fetch') | ||
@@ -41,0 +42,0 @@ const file = new BigWig({ |
@@ -271,4 +271,4 @@ import { Buffer } from 'buffer' | ||
try { | ||
const length = fr.max() - fr.min() | ||
const offset = fr.min() | ||
const length = fr.max - fr.min | ||
const offset = fr.min | ||
const resultBuffer: Buffer = await this.featureCache.get( | ||
@@ -284,3 +284,6 @@ `${length}_${offset}`, | ||
if (outstanding === 0) { | ||
this.readFeatures(observer, blocksToFetch, { ...opts, request }) | ||
this.readFeatures(observer, blocksToFetch, { | ||
...opts, | ||
request, | ||
}).catch(e => observer.error(e)) | ||
} | ||
@@ -299,5 +302,9 @@ } | ||
const maxCirBlockSpan = 4 + Number(cirBlockSize) * 32 | ||
let spans = new Range(offset[0], offset[0] + maxCirBlockSpan) | ||
let spans = new Range([ | ||
{ min: offset[0], max: offset[0] + maxCirBlockSpan }, | ||
]) | ||
for (let i = 1; i < offset.length; i += 1) { | ||
const blockSpan = new Range(offset[i], offset[i] + maxCirBlockSpan) | ||
const blockSpan = new Range([ | ||
{ min: offset[i], max: offset[i] + maxCirBlockSpan }, | ||
]) | ||
spans = spans.union(blockSpan) | ||
@@ -304,0 +311,0 @@ } |
127
src/range.ts
@@ -7,25 +7,24 @@ /* eslint prefer-rest-params:0, no-nested-ternary:0 */ | ||
*/ | ||
export interface IRange { | ||
min: number | ||
max: number | ||
} | ||
export default class Range { | ||
public ranges: any | ||
public ranges: IRange[] | ||
public constructor(arg1: any, arg2?: any) { | ||
this.ranges = | ||
arguments.length === 2 | ||
? [{ min: arg1, max: arg2 }] | ||
: 0 in arg1 | ||
? Object.assign({}, arg1) | ||
: [arg1] | ||
public constructor(arg1: IRange[]) { | ||
this.ranges = arg1 | ||
} | ||
public min(): number { | ||
get min() { | ||
return this.ranges[0].min | ||
} | ||
public max(): number { | ||
get max() { | ||
return this.ranges[this.ranges.length - 1].max | ||
} | ||
public contains(pos: number): boolean { | ||
for (let s = 0; s < this.ranges.length; s += 1) { | ||
const r = this.ranges[s] | ||
public contains(pos: number) { | ||
for (const r of this.ranges) { | ||
if (r.min <= pos && r.max >= pos) { | ||
@@ -42,12 +41,24 @@ return true | ||
public getRanges(): Range[] { | ||
return this.ranges.map((r: Range) => new Range(r.min, r.max)) | ||
public getRanges() { | ||
return this.ranges.map(r => new Range([{ min: r.min, max: r.max }])) | ||
} | ||
public toString(): string { | ||
return this.ranges.map((r: Range) => `[${r.min}-${r.max}]`).join(',') | ||
return this.ranges.map(r => `[${r.min}-${r.max}]`).join(',') | ||
} | ||
public union(s1: Range): Range { | ||
const ranges = this.getRanges().concat(s1.getRanges()).sort(this.rangeOrder) | ||
const ranges = [...this.getRanges(), ...s1.getRanges()].sort((a, b) => { | ||
if (a.min < b.min) { | ||
return -1 | ||
} else if (a.min > b.min) { | ||
return 1 | ||
} else if (a.max < b.max) { | ||
return -1 | ||
} else if (b.max > a.max) { | ||
return 1 | ||
} else { | ||
return 0 | ||
} | ||
}) | ||
const oranges = [] | ||
@@ -58,7 +69,7 @@ let current = ranges[0] | ||
const nxt = ranges[i] | ||
if (nxt.min() > current.max() + 1) { | ||
if (nxt.min > current.max + 1) { | ||
oranges.push(current) | ||
current = nxt | ||
} else if (nxt.max() > current.max()) { | ||
current = new Range(current.min(), nxt.max()) | ||
} else if (nxt.max > current.max) { | ||
current = new Range([{ min: current.min, max: nxt.max }]) | ||
} | ||
@@ -68,78 +79,4 @@ } | ||
if (oranges.length === 1) { | ||
return oranges[0] | ||
} | ||
return new Range(oranges) | ||
return oranges.length === 1 ? oranges[0] : new Range(oranges) | ||
} | ||
public intersection(arg: Range): Range { | ||
// eslint-disable-next-line @typescript-eslint/no-this-alias,unicorn/no-this-assignment | ||
let s0 = this | ||
let s1 = arg | ||
const r0 = this.ranges() | ||
const r1 = s1.ranges() | ||
const l0 = r0.length | ||
const l1 = r1.length | ||
let i0 = 0 | ||
let i1 = 0 | ||
const or = [] | ||
while (i0 < l0 && i1 < l1) { | ||
s0 = r0[i0] | ||
s1 = r1[i1] | ||
const lapMin = Math.max(s0.min(), s1.min()) | ||
const lapMax = Math.min(s0.max(), s1.max()) | ||
if (lapMax >= lapMin) { | ||
or.push(new Range(lapMin, lapMax)) | ||
} | ||
if (s0.max() > s1.max()) { | ||
i1 += 1 | ||
} else { | ||
i0 += 1 | ||
} | ||
} | ||
if (or.length === 0) { | ||
throw new Error('found range of length 0') | ||
} | ||
if (or.length === 1) { | ||
return or[0] | ||
} | ||
return new Range(or) | ||
} | ||
public coverage(): number { | ||
let tot = 0 | ||
const rl = this.ranges() | ||
for (const r of rl) { | ||
tot += r.max() - r.min() + 1 | ||
} | ||
return tot | ||
} | ||
public rangeOrder(tmpa: Range, tmpb: Range): number { | ||
let a = tmpa | ||
let b = tmpb | ||
if (arguments.length < 2) { | ||
b = a | ||
// eslint-disable-next-line @typescript-eslint/no-this-alias,unicorn/no-this-assignment | ||
a = this | ||
} | ||
if (a.min() < b.min()) { | ||
return -1 | ||
} | ||
if (a.min() > b.min()) { | ||
return 1 | ||
} | ||
if (a.max() < b.max()) { | ||
return -1 | ||
} | ||
if (b.max() > a.max()) { | ||
return 1 | ||
} | ||
return 0 | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
226
240218
4007