shelving
Version:
Toolkit for using data in JavaScript.
124 lines (123 loc) • 5.34 kB
JavaScript
import { RequiredError } from "../error/RequiredError.js";
import { ValueError } from "../error/ValueError.js";
import { requireArray } from "./array.js";
import { isNullish } from "./null.js";
/** Regular expression that always matches everything. */
export const ALWAYS_REGEXP = /^.*$/;
/** Regular expression that never matches anything. */
export const NEVER_REGEXP = /^(?=a)a/;
/** Is an unknown value a `RegExp` instance? */
export function isRegExp(value) {
return value instanceof RegExp;
}
/** Assert that an unknown value is a `RegExp` instance. */
export function assertRegExp(value) {
if (!(value instanceof RegExp))
throw new RequiredError("Must be regular expression", { received: value, caller: assertRegExp });
}
export function getRegExp(pattern, flags) {
return typeof pattern === "string" ? new RegExp(pattern, flags) : pattern;
}
/** Convert a regular expression to its string source. */
export function getRegExpSource(regexp) {
return typeof regexp === "string" ? regexp : regexp.source;
}
/** Escape special characters in a string regular expression. */
export function escapeRegExp(pattern) {
return pattern.replace(REPLACE_ESCAPED, "\\$&");
}
const REPLACE_ESCAPED = /[-[\]/{}()*+?.\\^$|]/g;
/** Create regular expression that matches any of a list of other expressions. */
export function createRegExpAny(patterns, flags) {
const arr = requireArray(patterns).filter(Boolean);
// If there are no patterns to match against then _no_ string can ever match against any of nothing.
if (!arr.length)
return NEVER_REGEXP;
// Create RegExp using multiple joined matches like `(?:AAA)|(?:BBB)`
return new RegExp(`(?:${requireArray(patterns).map(getRegExpSource).join(")|(?:")})`, flags);
}
/** Create regular expression that matches all of a list of other expressions. */
export function createRegExpAll(patterns, flags) {
const arr = requireArray(patterns).filter(Boolean);
// If there are no patterns to match against then _every_ string will match against the entire list of nothing.
if (!arr.length)
return ALWAYS_REGEXP;
// Create RegExp using multiple lookaheads like `^(?=.*?(?:AAA))(?=.*?(?:BBB))`
return new RegExp(`^(?=.*?(?:${requireArray(patterns).map(getRegExpSource).join("))(?=.*?(?:")}))`, flags);
}
/**
* Does a string match against a regular expressions or string.
* - Use with `filter()` to positively filter iterable sets of items.
*
* @param str String to test against the regular expression.
* @param regexp Regular expression to test against the string.
* - If `regexp` is a `RegExp` it is tested against the string using `RegExp.test()`.
* - If `regexp` is a `string` it is simply tested against the string using `===` equality.
* @returns `true` if the string matches the regular expression, otherwise `false`.
*/
export function isMatch(str, regexp) {
return typeof regexp === "string" ? regexp === str : regexp.test(str);
}
/**
* Does a string not match against a regular expressions or string.
* - Use with `filter()` to negatively filter iterable sets of items.
*
* @param str String to test against the regular expression.
* @param regexp Regular expression to test against the string.
* - If `regexp` is a `RegExp` it is tested against the string using `RegExp.test()`.
* - If `regexp` is a `string` it is simply tested against the string using `!==` equality.
* @returns `true` if the string matches the regular expression, otherwise `false`.
*/
export function notMatch(str, regexp) {
return !isMatch(str, regexp);
}
/**
* All of the provided regular expressions match the string.
*
* @param regexps - Regular expressions to match against the string.
* - If empty the function returns `true` (since all zero of the provided regexps match everything).
* - If a `RegExp` it is tested against the string using `RegExp.test()`.
* - If a `string` it is simply tested against the string using `===` equality.
* - If `null` or `undefined` it is ignored.
*/
export function allMatch(str, ...regexps) {
for (const x of regexps) {
if (isNullish(x))
continue;
if (!isMatch(str, x))
return false;
}
return true;
}
/** At least one of the provided regular expressions matches the string. */
export function anyMatch(str, ...regexps) {
for (const x of regexps) {
if (isNullish(x))
continue;
if (isMatch(str, x))
return true;
}
return false;
}
/** None of the provided regular expressions match the string. */
export function noneMatch(str, ...regexps) {
return !allMatch(str, ...regexps);
}
export function getMatch(str, regexp) {
return regexp.exec(str) || undefined;
}
export function requireMatch(str, regexp) {
const match = getMatch(str, regexp);
if (!match)
throw new ValueError("Must match regular expression", { received: str, expected: regexp, caller: requireMatch });
return match;
}
export function getMatchGroups(str, regexp) {
return regexp.exec(str)?.groups || undefined;
}
export function requireMatchGroups(str, regexp) {
const groups = getMatchGroups(str, regexp);
if (!groups)
throw new ValueError("Must match regular expression", { received: str, expected: regexp, caller: requireMatchGroups });
return groups;
}