Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | 2x 2x 2x 860x 2x 860x 860x 860x 860x 860x 2x 2x 9x 8x 9x 9x 2x 2x 16x 16x 16x 2x 2x 106x 34x 34x | /**
* Typed refusals.
*
* Spec §10: every refusal names the file's actual state and the concrete fix.
* The `code` is what the UI switches on; the `message` is what the user reads;
* `detail` carries the machine-readable actual value so a test can assert on it
* without regex-matching prose.
*/
import { pyList } from './format'
export type ErrorCode =
| 'not-hdf5'
| 'not-a-table'
| 'not-a-cooler'
| 'mmetacool-root'
| 'mcool-root'
| 'pairs-binning-needed'
| 'entry-not-found'
| 'bad-format-version'
| 'bad-ordering'
| 'variable-bins'
| 'unbinned-not-displayable'
| 'dense-too-large'
| 'unknown-label'
| 'cell-not-found'
| 'scool-listing-cost'
| 'hicpro-load-cost'
| 'hicpro-no-bins'
| 'bad-range'
| 'genome-coordinate-suffix'
| 'unsupported'
| 'bigwig-no-overlap'
| 'remote-no-ranges'
| 'remote-compressed'
| 'remote-cors'
| 'remote-too-large'
| 'bad-uri'
| 'format'
export class ViewerError extends Error {
readonly code: ErrorCode
readonly detail: Record<string, unknown>
constructor(code: ErrorCode, message: string, detail: Record<string, unknown> = {}) {
super(message)
this.name = 'ViewerError'
this.code = code
this.detail = detail
}
}
/**
* Whether an error is the browser refusing memory — a typed array it could not
* allocate — rather than anything about the file.
*
* Read off the name and the words, because that is all that crosses the worker
* boundary (`worker/protocol.ts` keeps both) and no engine gives it a code:
* Chrome says *Array buffer allocation failed*, Firefox *out of memory* or
* *invalid array length*, Safari *Out of memory*.
*/
export function isAllocationFailure(err: unknown): boolean {
if (!(err instanceof Error)) return false
const words = /allocation failed|out of memory|invalid array length|array buffer/i
return (err.name === 'RangeError' || err.name === 'InternalError') && words.test(err.message)
}
/** Raised when a file does not conform to the metacooler format. */
export class MetaCoolerFormatError extends ViewerError {
constructor(message: string, detail: Record<string, unknown> = {}, code: ErrorCode = 'format') {
super(code, message, detail)
this.name = 'MetaCoolerFormatError'
}
}
/**
* Render a list of names the way the Python errors do: at most `limit` entries,
* then a count of the remainder.
*
* A port of `_truncate` in `ops/range.py`, down to the quoting.
* `JSON.stringify` would render `["a","b"]` where Python's `str(list)` renders
* `['a', 'b']` — different quotes *and* no space after the comma — and these
* strings end up inside the `unknown-label` refusal, which spec §10 requires
* to read identically in the browser and in `metacooler show`. A user grepping
* for a name they saw in one must find it in the other.
*/
export function truncateNames(names: readonly string[], limit = 20): string {
if (names.length <= limit) return pyList(names)
return `${pyList(names.slice(0, limit))} ... (${names.length - limit} more)`
}
|