UNPKG

shelving

Version:

Toolkit for using data in JavaScript.

124 lines (123 loc) 5.34 kB
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; }