@gmod/bbi
Version:
Parser for BigWig/BigBed files
78 lines (70 loc) • 2.1 kB
text/typescript
export class AbortError extends Error {
public code: string
public constructor(message: string) {
super(message)
this.code = 'ERR_ABORTED'
}
}
interface Block {
offset: number
length: number
}
// sort blocks by file offset and
// group blocks that are within 2KB of eachother
export function groupBlocks(blocks: Block[]) {
blocks.sort((b0, b1) => b0.offset - b1.offset)
const blockGroups = []
let lastBlock: (Block & { blocks: Block[] }) | undefined
let lastBlockEnd: number | undefined
for (const block of blocks) {
if (lastBlock && lastBlockEnd && block.offset - lastBlockEnd <= 2000) {
lastBlock.length =
lastBlock.length + block.length - lastBlockEnd + block.offset
lastBlock.blocks.push(block)
} else {
blockGroups.push(
(lastBlock = {
blocks: [block],
length: block.length,
offset: block.offset,
}),
)
}
lastBlockEnd = lastBlock.offset + lastBlock.length
}
return blockGroups
}
/**
* Properly check if the given AbortSignal is aborted. Per the standard, if the
* signal reads as aborted, this function throws either a DOMException
* AbortError, or a regular error with a `code` attribute set to `ERR_ABORTED`.
*
* For convenience, passing `undefined` is a no-op
*
* @param {AbortSignal} [signal] an AbortSignal, or anything with an `aborted` attribute
* @returns nothing
*/
export function checkAbortSignal(signal?: AbortSignal): void {
if (!signal) {
return
}
if (signal.aborted) {
if (typeof DOMException === 'undefined') {
const e = new AbortError('aborted')
e.code = 'ERR_ABORTED'
throw e
} else {
throw new DOMException('aborted', 'AbortError')
}
}
}
/**
* Skips to the next tick, then runs `checkAbortSignal`.
* Await this to inside an otherwise synchronous loop to
* provide a place to break when an abort signal is received.
* @param {AbortSignal} signal
*/
export async function abortBreakPoint(signal?: AbortSignal): Promise<void> {
await Promise.resolve()
checkAbortSignal(signal)
}