53 lines
1.5 KiB
JavaScript
53 lines
1.5 KiB
JavaScript
/**
|
|
* Escapes a string for use in a regular expression.
|
|
*/
|
|
export function escapeRegExp(str) {
|
|
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
}
|
|
/**
|
|
* Casts a value to an array if it's not one.
|
|
*/
|
|
export function castArray(value) {
|
|
return (Array.isArray(value) ? value : value != null ? [value] : []);
|
|
}
|
|
/**
|
|
* Splits a string on `delimiter`, ignoring delimiters inside parentheses.
|
|
* Trims each segment and discards empty ones.
|
|
*
|
|
* Examples:
|
|
* splitOutsideParens('red,rgb(255,0,0),blue', ',') → ['red', 'rgb(255,0,0)', 'blue']
|
|
* splitOutsideParens('black.bgHex(#533AFD).dim', '.') → ['black', 'bgHex(#533AFD)', 'dim']
|
|
*/
|
|
export function splitOutsideParens(input, delimiter) {
|
|
const segments = [];
|
|
let current = '';
|
|
let parenDepth = 0;
|
|
for (const char of input) {
|
|
if (char === '(')
|
|
parenDepth++;
|
|
else if (char === ')')
|
|
parenDepth--;
|
|
if (char === delimiter && parenDepth === 0) {
|
|
const trimmed = current.trim();
|
|
if (trimmed)
|
|
segments.push(trimmed);
|
|
current = '';
|
|
}
|
|
else {
|
|
current += char;
|
|
}
|
|
}
|
|
const trimmed = current.trim();
|
|
if (trimmed)
|
|
segments.push(trimmed);
|
|
return segments;
|
|
}
|
|
/**
|
|
* Error thrown when a condition is reached that should be impossible.
|
|
*/
|
|
export class UnreachableError extends Error {
|
|
constructor(value) {
|
|
super(`Unreachable condition: ${value}`);
|
|
}
|
|
}
|