import is from '@sindresorhus/is'; import { CONFIG_VALIDATION } from '../constants/error-messages'; import { logger } from '../logger'; let RegEx: RegExpConstructor; try { // eslint-disable-next-line const RE2 = require('re2'); // Test if native is working new RE2('.*').exec('test'); logger.debug('Using RE2 as regex engine'); RegEx = RE2; } catch (err) { logger.warn({ err }, 'RE2 not usable, falling back to RegExp'); RegEx = RegExp; } export function regEx(pattern: string, flags?: string): RegExp { try { return new RegEx(pattern, flags); } catch (err) { const error = new Error(CONFIG_VALIDATION); error.validationSource = pattern; error.validationError = `Invalid regular expression: ${pattern}`; throw error; } } export function escapeRegExp(input: string): string { return input.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string } const configValStart = /^!?\//; const configValEnd = /\/$/; export function isConfigRegex(input: unknown): input is string { return ( is.string(input) && configValStart.test(input) && configValEnd.test(input) ); } function parseConfigRegex(input: string): RegExp | null { try { const regexString = input .replace(configValStart, '') .replace(configValEnd, ''); return regEx(regexString); } catch (err) { // no-op } return null; } type ConfigRegexPredicate = (string) => boolean; export function configRegexPredicate(input: string): ConfigRegexPredicate { const configRegex = parseConfigRegex(input); if (configRegex) { const isPositive = !input.startsWith('!'); return (x: string): boolean => { const res = configRegex.test(x); return isPositive ? res : !res; }; } return null; }