renovate/lib/util/regex.ts

68 lines
1.7 KiB
TypeScript
Raw Normal View History

import is from '@sindresorhus/is';
import { CONFIG_VALIDATION } from '../constants/error-messages';
2020-05-01 16:03:48 +00:00
import { logger } from '../logger';
2019-08-25 12:29:51 +00:00
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;
2019-08-25 12:29:51 +00:00
}
export function regEx(pattern: string, flags?: string): RegExp {
2019-08-25 12:29:51 +00:00
try {
return new RegEx(pattern, flags);
2019-08-25 12:29:51 +00:00
} catch (err) {
const error = new Error(CONFIG_VALIDATION);
error.configFile = pattern;
error.validationError = `Invalid regular expression: ${pattern}`;
throw error;
2019-08-25 12:29:51 +00:00
}
}
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;
}