@jbrowse/core
Version:
JBrowse 2 core libraries used by plugins
63 lines (62 loc) • 2.51 kB
JavaScript
const COORD_REGEX = /^(-?\d+)(?:(?:\.\.|[-–])(-?\d+))?(\.\.|[-–])?$/;
const ASSEMBLY_REGEX = /^(?:\{([^}]+)\})?(.+)/;
function parseCoords(suffix, locString) {
const match = COORD_REGEX.exec(suffix.replaceAll(',', ''));
if (!match) {
throw new Error(`could not parse range "${suffix}" on location "${locString}"`);
}
const [, startStr, endStr, trailing] = match;
const start = +startStr;
return { start, end: endStr ? +endStr : trailing ? undefined : start };
}
export function parseLocStringOneBased(locString, isValidRefName) {
if (!locString) {
throw new Error('no location string provided, could not parse');
}
let reversed = false;
if (locString.endsWith('[rev]')) {
reversed = true;
locString = locString.slice(0, -5);
}
locString = locString.replaceAll(/\s/g, '');
const assemblyMatch = ASSEMBLY_REGEX.exec(locString);
if (!assemblyMatch) {
throw new Error(`invalid location string: "${locString}"`);
}
const [, assemblyName, location] = assemblyMatch;
if (!assemblyName && location.startsWith('{}')) {
throw new Error(`no assembly name was provided in location "${location}"`);
}
const lastColonIdx = location.lastIndexOf(':');
if (lastColonIdx === -1) {
if (isValidRefName(location, assemblyName)) {
return { assemblyName, refName: location, reversed };
}
throw new Error(`Unknown feature or sequence "${location}"`);
}
const prefix = location.slice(0, lastColonIdx);
const suffix = location.slice(lastColonIdx + 1);
const prefixValid = isValidRefName(prefix, assemblyName);
const locationValid = isValidRefName(location, assemblyName);
if (prefixValid && locationValid) {
throw new Error(`ambiguous location string: "${locString}"`);
}
if (locationValid) {
return { assemblyName, refName: location, reversed };
}
if (prefixValid) {
if (!suffix) {
return { assemblyName, refName: prefix, reversed };
}
const coords = parseCoords(suffix, locString);
return { assemblyName, refName: prefix, reversed, ...coords };
}
throw new Error(`unknown reference sequence name in location "${locString}"`);
}
export function parseLocString(locString, isValidRefName) {
const parsed = parseLocStringOneBased(locString, isValidRefName);
if (typeof parsed.start === 'number') {
parsed.start -= 1;
}
return parsed;
}