diff --git a/lib/util/emoji.ts b/lib/util/emoji.ts index 9e2a8b73ea93e96d27fc83c56199c286c8f87f90..7f6edaa8de1689a93c07c4ed3f03d9408e38b83c 100644 --- a/lib/util/emoji.ts +++ b/lib/util/emoji.ts @@ -55,7 +55,7 @@ export function emojify(text: string): string { const emojiRegexSrc = [emojibaseEmojiRegex, mathiasBynensEmojiRegex()].map( ({ source }) => source ); -const emojiRegex = new RegExp(`(?:${emojiRegexSrc.join('|')})`, 'g'); +const emojiRegex = new RegExp(`(?:${emojiRegexSrc.join('|')})`, 'g'); // TODO #12070 const excludedModifiers = new Set([ '20E3', '200D', diff --git a/lib/util/exec/docker/index.ts b/lib/util/exec/docker/index.ts index a6a160653dce6e5ea265b683b3405f3656b6e4fc..50ca989205ca8e7a3e5695b794cb25fc70ee8b1f 100644 --- a/lib/util/exec/docker/index.ts +++ b/lib/util/exec/docker/index.ts @@ -4,6 +4,7 @@ import { SYSTEM_INSUFFICIENT_MEMORY } from '../../../constants/error-messages'; import { getPkgReleases } from '../../../datasource'; import { logger } from '../../../logger'; import * as versioning from '../../../versioning'; +import { regEx } from '../../regex'; import { ensureTrailingSlash } from '../../url'; import { DockerOptions, @@ -119,7 +120,7 @@ export async function getDockerTag( } function getContainerName(image: string, prefix?: string): string { - return `${prefix || 'renovate_'}${image}`.replace(/\//g, '_'); + return `${prefix || 'renovate_'}${image}`.replace(regEx(/\//g), '_'); } function getContainerLabel(prefix: string): string { @@ -257,7 +258,7 @@ export async function generateDockerCommand( ...commands, ...prepareCommands(postCommands), ].join(' && '); - result.push(`bash -l -c "${bashCommand.replace(/"/g, '\\"')}"`); // lgtm [js/incomplete-sanitization] + result.push(`bash -l -c "${bashCommand.replace(regEx(/"/g), '\\"')}"`); // lgtm [js/incomplete-sanitization] return result.join(' '); } diff --git a/lib/util/git/author.ts b/lib/util/git/author.ts index 5fe82349f1ef15284c32924e7c820bb8ad11e103..f029ebc3363762127d81232736ff97d616182b9c 100644 --- a/lib/util/git/author.ts +++ b/lib/util/git/author.ts @@ -1,5 +1,6 @@ import addrs from 'email-addresses'; import { logger } from '../../logger'; +import { regEx } from '../regex'; export interface GitAuthor { name?: string; @@ -20,7 +21,7 @@ export function parseGitAuthor(input: string): GitAuthor | null { let massagedBotEmail = false; if (input.includes('<') && input.includes('>')) { // try wrapping the name part in quotations - massagedInput = '"' + input.replace(/(\s?<)/, '"$1'); + massagedInput = '"' + input.replace(regEx(/(\s?<)/), '"$1'); } if (input.includes('[bot]@')) { // invalid github app/bot addresses @@ -33,7 +34,7 @@ export function parseGitAuthor(input: string): GitAuthor | null { const parsed = addrs.parseOneAddress(massagedInput) as addrs.ParsedMailbox; if (parsed?.address) { result = { - name: parsed.name || input.replace(/@.*/, ''), + name: parsed.name || input.replace(regEx(/@.*/), ''), address: parsed.address, }; if (massagedBotEmail) { diff --git a/lib/util/git/index.ts b/lib/util/git/index.ts index bf6ea96a1bbccd04e9c6e249aa0b079560ab5306..0422aecf0eb6576a45c194dd1db1aa704971ef94 100644 --- a/lib/util/git/index.ts +++ b/lib/util/git/index.ts @@ -24,6 +24,7 @@ import { logger } from '../../logger'; import { ExternalHostError } from '../../types/errors/external-host-error'; import { GitOptions, GitProtocol } from '../../types/git'; import { Limit, incLimitedValue } from '../../workers/global/limits'; +import { regEx } from '../regex'; import { parseGitAuthor } from './author'; import { GitNoVerifyOption, getNoVerify, simpleGitConfig } from './config'; import { configSigningKey, writePrivateKey } from './private-key'; @@ -120,7 +121,7 @@ function checkForPlatformFailure(err: Error): void { } function localName(branchName: string): string { - return branchName.replace(/^origin\//, ''); + return branchName.replace(regEx(/^origin\//), ''); // TODO #12071 } async function isDirectory(dir: string): Promise<boolean> { @@ -168,7 +169,7 @@ async function fetchBranchCommits(): Promise<void> { (await git.raw(opts)) .split('\n') .filter(Boolean) - .map((line) => line.trim().split(/\s+/)) + .map((line) => line.trim().split(regEx(/\s+/))) // TODO #12071 .forEach(([sha, ref]) => { config.branchCommits[ref.replace('refs/heads/', '')] = sha; }); @@ -272,7 +273,7 @@ export async function getSubmodules(): Promise<string[]> { ])) || '' ) .trim() - .split(/[\n\s]/) + .split(regEx(/[\n\s]/)) .filter((_e: string, i: number) => i % 2); } catch (err) /* istanbul ignore next */ { logger.warn({ err }, 'Error getting submodules'); @@ -459,7 +460,7 @@ export async function getFileList(): Promise<string[]> { .split('\n') .filter(Boolean) .filter((line) => line.startsWith('100')) - .map((line) => line.split(/\t/).pop()) + .map((line) => line.split(regEx(/\t/)).pop()) // TODO #12071 .filter((file: string) => submodules.every((submodule: string) => !file.startsWith(submodule)) ); diff --git a/lib/util/git/url.ts b/lib/util/git/url.ts index 881de8722b3c6fc1aec98a485e6e58a96c83f02e..e7a6ef0d3093fa1c4095a72f57ed2c6535591394 100644 --- a/lib/util/git/url.ts +++ b/lib/util/git/url.ts @@ -1,13 +1,14 @@ import GitUrlParse from 'git-url-parse'; import { logger } from '../../logger'; import * as hostRules from '../host-rules'; +import { regEx } from '../regex'; export function getHttpUrl(url: string, token?: string): string { const parsedUrl = GitUrlParse(url); parsedUrl.token = token; - const protocol = /^https?$/.exec(parsedUrl.protocol) + const protocol = regEx(/^https?$/).exec(parsedUrl.protocol) // TODO #12071 ? parsedUrl.protocol : 'https'; return parsedUrl.toString(protocol); diff --git a/lib/util/http/gitea.ts b/lib/util/http/gitea.ts index ff53983fc856d72d166f0e7503452891f36186dd..2631c5e0d7ba713a4a1d487e37a1c82c1fe830fb 100644 --- a/lib/util/http/gitea.ts +++ b/lib/util/http/gitea.ts @@ -2,9 +2,9 @@ import { PlatformId } from '../../constants'; import { resolveBaseUrl } from '../url'; import { Http, HttpOptions, HttpResponse, InternalHttpOptions } from '.'; -let baseUrl; +let baseUrl: string; export const setBaseUrl = (newBaseUrl: string): void => { - baseUrl = newBaseUrl.replace(/\/*$/, '/'); + baseUrl = newBaseUrl.replace(/\/*$/, '/'); // TODO #12070 #12071 }; export interface GiteaHttpOptions extends InternalHttpOptions { diff --git a/lib/util/http/github.ts b/lib/util/http/github.ts index ec267a4f5ad29d8d3cb30953f05d321b4f878034..daba1c8b632b3a996c3a7c0331b85e6e7981beb4 100644 --- a/lib/util/http/github.ts +++ b/lib/util/http/github.ts @@ -11,6 +11,7 @@ import { import { logger } from '../../logger'; import { ExternalHostError } from '../../types/errors/external-host-error'; import { maskToken } from '../mask'; +import { regEx } from '../regex'; import { GotLegacyError } from './legacy'; import { Http, HttpPostOptions, HttpResponse, InternalHttpOptions } from '.'; @@ -153,7 +154,8 @@ interface GraphqlOptions { function constructAcceptString(input?: any): string { const defaultAccept = 'application/vnd.github.v3+json'; - const acceptStrings = typeof input === 'string' ? input.split(/\s*,\s*/) : []; + const acceptStrings = + typeof input === 'string' ? input.split(regEx(/\s*,\s*/)) : []; if ( !acceptStrings.some((x) => x.startsWith('application/vnd.github.')) || acceptStrings.length < 2 diff --git a/lib/util/ignore.ts b/lib/util/ignore.ts index b6d6f41f6a4cee92763487c9a7615e85d1627481..6ef218d970996c24a5303b909ca04fc0414f1b8a 100644 --- a/lib/util/ignore.ts +++ b/lib/util/ignore.ts @@ -1,7 +1,9 @@ import { logger } from '../logger'; +import { regEx } from './regex'; export function isSkipComment(comment?: string): boolean { - if (/^(renovate|pyup):/.test(comment)) { + if (regEx(/^(renovate|pyup):/).test(comment)) { + // TODO #12070 #12071 needs to be checked manually const command = comment.split('#')[0].split(':')[1].trim(); if (command === 'ignore') { return true; diff --git a/lib/util/markdown.ts b/lib/util/markdown.ts index 73648a7c4d76500d448c5d486cfae59fea1f166c..962f0cf11848b1479a5b0a72d2cff178dd6594f1 100644 --- a/lib/util/markdown.ts +++ b/lib/util/markdown.ts @@ -1,22 +1,23 @@ import remark from 'remark'; import github from 'remark-github'; +import { regEx } from './regex'; // Generic replacements/link-breakers export function sanitizeMarkdown(markdown: string): string { let res = markdown; // Put a zero width space after every # followed by a digit - res = res.replace(/#(\d)/gi, '#​$1'); + res = res.replace(regEx(/#(\d)/gi), '#​$1'); // TODO #12071 // Put a zero width space after every @ symbol to prevent unintended hyperlinking - res = res.replace(/@/g, '@​'); - res = res.replace(/(`\[?@)​/g, '$1'); - res = res.replace(/([a-z]@)​/gi, '$1'); - res = res.replace(/\/compare\/@​/g, '/compare/@'); - res = res.replace(/(\(https:\/\/[^)]*?)\.\.\.@​/g, '$1...@'); - res = res.replace(/([\s(])#(\d+)([)\s]?)/g, '$1#​$2$3'); + res = res.replace(regEx(/@/g), '@​'); // TODO #12071 + res = res.replace(regEx(/(`\[?@)​/g), '$1'); // TODO #12071 + res = res.replace(regEx(/([a-z]@)​/gi), '$1'); // TODO #12071 + res = res.replace(regEx(/\/compare\/@​/g), '/compare/@'); // TODO #12071 + res = res.replace(regEx(/(\(https:\/\/[^)]*?)\.\.\.@​/g), '$1...@'); // TODO #12071 + res = res.replace(regEx(/([\s(])#(\d+)([)\s]?)/g), '$1#​$2$3'); // TODO #12071 // convert escaped backticks back to ` - const backTickRe = /`([^/]*?)`/g; + const backTickRe = regEx(/`([^/]*?)`/g); // TODO #12071 res = res.replace(backTickRe, '`$1`'); - res = res.replace(/`#​(\d+)`/g, '`#$1`'); + res = res.replace(regEx(/`#​(\d+)`/g), '`#$1`'); // TODO #12071 return res; } diff --git a/lib/util/modules.ts b/lib/util/modules.ts index ba4bfe3625cb4f9d58bcb2ca118623085112a856..9d988ac1095be3abe5643ef378f2f3af6fd2fa19 100644 --- a/lib/util/modules.ts +++ b/lib/util/modules.ts @@ -1,9 +1,10 @@ import fs from 'fs'; import { join, normalizeTrim } from 'upath'; +import { regEx } from './regex'; function relatePath(here: string, there: string): string { - const thereParts = normalizeTrim(there).split(/[\\/]/); - const hereParts = normalizeTrim(here).split(/[\\/]/); + const thereParts = normalizeTrim(there).split(regEx(/[\\/]/)); // TODO #12070 needs to be tested manually + const hereParts = normalizeTrim(here).split(regEx(/[\\/]/)); // TODO #12070 needs to be tested manually let idx = 0; while ( diff --git a/lib/util/package-rules.ts b/lib/util/package-rules.ts index 1fa29033778434b7b950f1340569a6252dae4f01..2f21b91bcd611f406eb893e0f0cafa1245435a48 100644 --- a/lib/util/package-rules.ts +++ b/lib/util/package-rules.ts @@ -142,7 +142,7 @@ function matchesRule( packagePattern === '^*$' || packagePattern === '*' ? '.*' : packagePattern - ); + ); // TODO #12071 if (packageRegex.test(depName)) { logger.trace(`${depName} matches against ${String(packageRegex)}`); isMatch = true; @@ -172,7 +172,7 @@ function matchesRule( for (const pattern of excludePackagePatterns) { const packageRegex = regEx( pattern === '^*$' || pattern === '*' ? '.*' : pattern - ); + ); // TODO #12071 if (packageRegex.test(depName)) { logger.trace(`${depName} matches against ${String(packageRegex)}`); isMatch = true; diff --git a/lib/util/regex.ts b/lib/util/regex.ts index 78d4814227a505c52dd042b8eaa6265ba533302f..19b203ea51204686b91c67c976563d60564633bd 100644 --- a/lib/util/regex.ts +++ b/lib/util/regex.ts @@ -29,11 +29,11 @@ export function regEx(pattern: string | RegExp, flags?: string): RegExp { } export function escapeRegExp(input: string): string { - return input.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string + return input.replace(regEx(/[.*+\-?^${}()|[\]\\]/g), '\\$&'); // $& means the whole matched string // TODO #12071 } -const configValStart = /^!?\//; -const configValEnd = /\/$/; +const configValStart = regEx(/^!?\//); +const configValEnd = regEx(/\/$/); export function isConfigRegex(input: unknown): input is string { return ( diff --git a/lib/util/template/index.ts b/lib/util/template/index.ts index cde48e5796d4fed65a5d7922cbb78b279f4dc576..cb61a66b105587a9d37be15662dd8fdd3f61401b 100644 --- a/lib/util/template/index.ts +++ b/lib/util/template/index.ts @@ -7,8 +7,9 @@ import { clone } from '../clone'; handlebars.registerHelper('encodeURIComponent', encodeURIComponent); // istanbul ignore next -handlebars.registerHelper('replace', (find, replace, context) => - context.replace(new RegExp(find, 'g'), replace) +handlebars.registerHelper( + 'replace', + (find, replace, context) => context.replace(new RegExp(find, 'g'), replace) // TODO #12070 ); export const exposedConfigOptions = [ @@ -139,7 +140,7 @@ function getFilteredObject(input: CompileInput): any { return res; } -const templateRegex = /{{(#(if|unless) )?([a-zA-Z]+)}}/g; +const templateRegex = /{{(#(if|unless) )?([a-zA-Z]+)}}/g; // TODO #12070 export function compile( template: string, diff --git a/lib/util/url.ts b/lib/util/url.ts index 245e0be5fdfa93bc2fac43d86426ed160ddafa9f..070773525b85a430d99932b21c5544f9d8ca3a75 100644 --- a/lib/util/url.ts +++ b/lib/util/url.ts @@ -1,4 +1,5 @@ import urlJoin from 'url-join'; +import { regEx } from './regex'; export function joinUrlParts(...parts: string[]): string { return urlJoin(...parts); @@ -14,11 +15,11 @@ export function ensurePathPrefix(url: string, prefix: string): string { } export function ensureTrailingSlash(url: string): string { - return url.replace(/\/?$/, '/'); + return url.replace(/\/?$/, '/'); // TODO #12070 #12071 add tests for this one } export function trimTrailingSlash(url: string): string { - return url.replace(/\/+$/, ''); + return url.replace(regEx(/\/+$/), ''); // TODO #12071 } export function resolveBaseUrl(baseUrl: string, input: string | URL): string { diff --git a/lib/versioning/cargo/index.ts b/lib/versioning/cargo/index.ts index cc01043b3f265e0eb4f008c9ec7e369b5c626ea4..ee33955a0954ca898a6d490b60538206fd865997 100644 --- a/lib/versioning/cargo/index.ts +++ b/lib/versioning/cargo/index.ts @@ -1,4 +1,5 @@ import { logger } from '../../logger'; +import { regEx } from '../../util/regex'; import { api as npm } from '../npm'; import type { NewValueConfig, VersioningApi } from '../types'; @@ -40,7 +41,7 @@ function npm2cargo(input: string): string { } // Note: this doesn't remove the ^ const res = input - .split(/\s+,?\s*|\s*,?\s+/) + .split(regEx(/\s+,?\s*|\s*,?\s+/)) .map((str) => str.trim()) .filter(notEmpty); const operators = ['^', '~', '=', '>', '<', '<=', '>=']; diff --git a/lib/versioning/composer/index.ts b/lib/versioning/composer/index.ts index fb47e5433a2f98074304e772cd303fd82a6686e2..226f826f188b694d399894794096ec56643e10a5 100644 --- a/lib/versioning/composer/index.ts +++ b/lib/versioning/composer/index.ts @@ -1,6 +1,7 @@ import { coerce } from 'semver'; import { parseRange } from 'semver-utils'; import { logger } from '../../logger'; +import { regEx } from '../../util/regex'; import { api as npm } from '../npm'; import type { NewValueConfig, VersioningApi } from '../types'; @@ -43,7 +44,7 @@ function convertStabilityModifier(input: string): string { // 1.0@beta2 to 1.0-beta.2 const stability = versionParts[1].replace( - /(?:^|\s)(beta|alpha|rc)([1-9][0-9]*)(?: |$)/gi, + regEx(/(?:^|\s)(beta|alpha|rc)([1-9][0-9]*)(?: |$)/gi), '$1.$2' ); @@ -54,7 +55,7 @@ function convertStabilityModifier(input: string): string { function normalizeVersion(input: string): string { let output = input; - output = output.replace(/(^|>|>=|\^|~)v/i, '$1'); + output = output.replace(regEx(/(^|>|>=|\^|~)v/i), '$1'); return convertStabilityModifier(output); } @@ -70,9 +71,15 @@ function composer2npm(input: string): string { let output = versionId; // ~4 to ^4 and ~4.1 to ^4.1 - output = output.replace(/(?:^|\s)~([1-9][0-9]*(?:\.[0-9]*)?)(?: |$)/g, '^$1'); + output = output.replace( + regEx(/(?:^|\s)~([1-9][0-9]*(?:\.[0-9]*)?)(?: |$)/g), + '^$1' + ); // ~0.4 to >=0.4 <1 - output = output.replace(/(?:^|\s)~(0\.[1-9][0-9]*)(?: |$)/g, '>=$1 <1'); + output = output.replace( + regEx(/(?:^|\s)~(0\.[1-9][0-9]*)(?: |$)/g), + '>=$1 <1' + ); return output + stability; } @@ -141,7 +148,7 @@ function getNewValue({ let newValue: string; if (isVersion(currentValue)) { newValue = newVersion; - } else if (/^[~^](0\.[1-9][0-9]*)$/.test(currentValue)) { + } else if (regEx(/^[~^](0\.[1-9][0-9]*)$/).test(currentValue)) { const operator = currentValue.substr(0, 1); // handle ~0.4 case first if (toMajor === 0) { @@ -149,11 +156,11 @@ function getNewValue({ } else { newValue = `${operator}${toMajor}.0`; } - } else if (/^[~^]([0-9]*)$/.test(currentValue)) { + } else if (regEx(/^[~^]([0-9]*)$/).test(currentValue)) { // handle ~4 case const operator = currentValue.substr(0, 1); newValue = `${operator}${toMajor}`; - } else if (/^[~^]([0-9]*(?:\.[0-9]*)?)$/.test(currentValue)) { + } else if (regEx(/^[~^]([0-9]*(?:\.[0-9]*)?)$/).test(currentValue)) { const operator = currentValue.substr(0, 1); // handle ~4.1 case if (currentVersion && toMajor > getMajor(currentVersion)) { @@ -212,7 +219,7 @@ function getNewValue({ newValue = newVersion; } if (currentValue.split('.')[0].includes('v')) { - newValue = newValue.replace(/([0-9])/, 'v$1'); + newValue = newValue.replace(regEx(/([0-9])/), 'v$1'); } // Preserve original min-stability specifier diff --git a/lib/versioning/docker/index.ts b/lib/versioning/docker/index.ts index 874ccb335708844592f707ba1dfad7d740b4fff6..1ec88bb36ed330f993b69f373795d997160e1f12 100644 --- a/lib/versioning/docker/index.ts +++ b/lib/versioning/docker/index.ts @@ -1,3 +1,4 @@ +import { regEx } from '../../util/regex'; import * as generic from '../loose/generic'; import type { VersioningApi } from '../types'; @@ -8,15 +9,15 @@ export const urls = [ ]; export const supportsRanges = false; -const versionPattern = /^(?<version>\d+(?:\.\d+)*)(?<prerelease>.*)$/; -const commitHashPattern = /^[a-f0-9]{7,40}$/; -const numericPattern = /^[0-9]+$/; +const versionPattern = regEx(/^(?<version>\d+(?:\.\d+)*)(?<prerelease>.*)$/); +const commitHashPattern = regEx(/^[a-f0-9]{7,40}$/); +const numericPattern = regEx(/^[0-9]+$/); function parse(version: string): generic.GenericVersion { if (commitHashPattern.test(version) && !numericPattern.test(version)) { return null; } - const versionPieces = version.replace(/^v/, '').split('-'); + const versionPieces = version.replace(regEx(/^v/), '').split('-'); const prefix = versionPieces.shift(); const suffix = versionPieces.join('-'); const m = versionPattern.exec(prefix); diff --git a/lib/versioning/gradle/compare.ts b/lib/versioning/gradle/compare.ts index abb1e25fc0cdc22ecbd049820ceed218dbbda742..bd5c85bfb08053b6b641d5d6cd9405cf2897b910 100644 --- a/lib/versioning/gradle/compare.ts +++ b/lib/versioning/gradle/compare.ts @@ -1,3 +1,5 @@ +import { regEx } from '../../util/regex'; + export enum TokenType { Number = 1, String, @@ -20,11 +22,11 @@ function iterateChars(str: string, cb: (p: string, n: string) => void): void { } function isSeparator(char: string): boolean { - return /^[-._+]$/i.test(char); + return regEx(/^[-._+]$/i).test(char); } function isDigit(char: string): boolean { - return /^\d$/.test(char); + return regEx(/^\d$/).test(char); } function isLetter(char: string): boolean { @@ -48,7 +50,7 @@ export function tokenize(versionStr: string): Token[] | null { } if (result) { const val = currentVal; - if (/^\d+$/.test(val)) { + if (regEx(/^\d+$/).test(val)) { result.push({ type: TokenType.Number, val: parseInt(val, 10), @@ -191,11 +193,11 @@ export function isVersion(input: string): boolean { return false; } - if (!/^[-._+a-zA-Z0-9]+$/i.test(input)) { + if (!regEx(/^[-._+a-zA-Z0-9]+$/i).test(input)) { return false; } - if (/^latest\.?/i.test(input)) { + if (regEx(/^latest\.?/i).test(input)) { return false; } @@ -231,9 +233,9 @@ export function parsePrefixRange(input: string): PrefixRange | null { return { tokens: [] }; } - const postfixRegex = /[-._]\+$/; + const postfixRegex = regEx(/[-._]\+$/); if (postfixRegex.test(input)) { - const prefixValue = input.replace(/[-._]\+$/, ''); + const prefixValue = input.replace(regEx(/[-._]\+$/), ''); const tokens = tokenize(prefixValue); return tokens ? { tokens } : null; } @@ -241,8 +243,9 @@ export function parsePrefixRange(input: string): PrefixRange | null { return null; } -const mavenBasedRangeRegex = - /^(?<leftBoundStr>[[\](]\s*)(?<leftVal>[-._+a-zA-Z0-9]*?)(?<separator>\s*,\s*)(?<rightVal>[-._+a-zA-Z0-9]*?)(?<rightBoundStr>\s*[[\])])$/; +const mavenBasedRangeRegex = regEx( + /^(?<leftBoundStr>[[\](]\s*)(?<leftVal>[-._+a-zA-Z0-9]*?)(?<separator>\s*,\s*)(?<rightVal>[-._+a-zA-Z0-9]*?)(?<rightBoundStr>\s*[[\])])$/ +); export function parseMavenBasedRange(input: string): MavenBasedRange | null { if (!input) { diff --git a/lib/versioning/gradle/index.ts b/lib/versioning/gradle/index.ts index d72d9d4cd3e399f9fe53477c1a1c9b8127fcfcb7..990f3d7ff7314f810cc88e02900b1afe9892abf1 100644 --- a/lib/versioning/gradle/index.ts +++ b/lib/versioning/gradle/index.ts @@ -1,3 +1,4 @@ +import { regEx } from '../../util/regex'; import type { NewValueConfig, VersioningApi } from '../types'; import { RangeBound, @@ -22,7 +23,7 @@ const equals = (a: string, b: string): boolean => compare(a, b) === 0; const getMajor = (version: string): number | null => { if (isVersion(version)) { - const tokens = tokenize(version.replace(/^v/i, '')); + const tokens = tokenize(version.replace(regEx(/^v/i), '')); const majorToken = tokens[0]; if (majorToken && majorToken.type === TokenType.Number) { return +majorToken.val; @@ -33,7 +34,7 @@ const getMajor = (version: string): number | null => { const getMinor = (version: string): number | null => { if (isVersion(version)) { - const tokens = tokenize(version.replace(/^v/i, '')); + const tokens = tokenize(version.replace(regEx(/^v/i), '')); const majorToken = tokens[0]; const minorToken = tokens[1]; if ( @@ -51,7 +52,7 @@ const getMinor = (version: string): number | null => { const getPatch = (version: string): number | null => { if (isVersion(version)) { - const tokens = tokenize(version.replace(/^v/i, '')); + const tokens = tokenize(version.replace(regEx(/^v/i), '')); const majorToken = tokens[0]; const minorToken = tokens[1]; const patchToken = tokens[2]; diff --git a/lib/versioning/hashicorp/index.ts b/lib/versioning/hashicorp/index.ts index b5890b0dea3be87eecaf477955e5ec9b68204fd3..79749443b08a0e8f86ec3525e74ceac0c2a877f2 100644 --- a/lib/versioning/hashicorp/index.ts +++ b/lib/versioning/hashicorp/index.ts @@ -1,3 +1,4 @@ +import { regEx } from '../../util/regex'; import { api as npm } from '../npm'; import type { NewValueConfig, VersioningApi } from '../types'; @@ -11,7 +12,7 @@ export const supportedRangeStrategies = ['bump', 'extend', 'pin', 'replace']; function hashicorp2npm(input: string): string { // The only case incompatible with semver is a "short" ~>, e.g. ~> 1.2 - return input.replace(/~>(\s*\d+\.\d+$)/, '^$1').replace(',', ''); + return input.replace(regEx(/~>(\s*\d+\.\d+$)/), '^$1').replace(',', ''); } const isLessThanRange = (version: string, range: string): boolean => @@ -36,8 +37,11 @@ function getNewValue({ newVersion, }: NewValueConfig): string { if (['replace', 'update-lockfile'].includes(rangeStrategy)) { - if (/~>\s*0\.\d+/.test(currentValue) && npm.getMajor(newVersion) === 0) { - const testFullVersion = /(~>\s*0\.)(\d+)\.\d$/; + if ( + regEx(/~>\s*0\.\d+/).test(currentValue) && + npm.getMajor(newVersion) === 0 + ) { + const testFullVersion = regEx(/(~>\s*0\.)(\d+)\.\d$/); let replaceValue = ''; if (testFullVersion.test(currentValue)) { replaceValue = `$<prefix>${npm.getMinor(newVersion)}.0`; @@ -45,14 +49,14 @@ function getNewValue({ replaceValue = `$<prefix>${npm.getMinor(newVersion)}$<suffix>`; } return currentValue.replace( - /(?<prefix>~>\s*0\.)\d+(?<suffix>.*)$/, + /(?<prefix>~>\s*0\.)\d+(?<suffix>.*)$/, // TODO #12070 replaceValue ); } // handle special ~> 1.2 case - if (/(~>\s*)\d+\.\d+$/.test(currentValue)) { + if (regEx(/(~>\s*)\d+\.\d+$/).test(currentValue)) { return currentValue.replace( - /(?<prefix>~>\s*)\d+\.\d+$/, + /(?<prefix>~>\s*)\d+\.\d+$/, // TODO #12070 `$<prefix>${npm.getMajor(newVersion)}.0` ); } diff --git a/lib/versioning/hex/index.ts b/lib/versioning/hex/index.ts index 10e475f605c33a452cddaea20aecadf9d77ffbd8..828837720ba36e60f58005af92dc2dfe03aa547c 100644 --- a/lib/versioning/hex/index.ts +++ b/lib/versioning/hex/index.ts @@ -1,3 +1,4 @@ +import { regEx } from '../../util/regex'; import { api as npm } from '../npm'; import type { NewValueConfig, VersioningApi } from '../types'; @@ -9,11 +10,11 @@ export const supportedRangeStrategies = ['bump', 'extend', 'pin', 'replace']; function hex2npm(input: string): string { return input - .replace(/~>\s*(\d+\.\d+)$/, '^$1') - .replace(/~>\s*(\d+\.\d+\.\d+)/, '~$1') - .replace(/==|and/, '') + .replace(regEx(/~>\s*(\d+\.\d+)$/), '^$1') // TODO #12071 + .replace(regEx(/~>\s*(\d+\.\d+\.\d+)/), '~$1') // TODO #12071 + .replace(regEx(/==|and/), '') // TODO #12071 .replace('or', '||') - .replace(/!=\s*(\d+\.\d+(\.\d+.*)?)/, '>$1 <$1') + .replace(regEx(/!=\s*(\d+\.\d+(\.\d+.*)?)/), '>$1 <$1') // TODO #12071 .trim(); } @@ -69,18 +70,18 @@ const getNewValue = ({ newVersion, }); newSemver = npm2hex(newSemver); - if (/~>\s*(\d+\.\d+\.\d+)$/.test(currentValue)) { + if (regEx(/~>\s*(\d+\.\d+\.\d+)$/).test(currentValue)) { newSemver = newSemver.replace( - /[\^~]\s*(\d+\.\d+\.\d+)/, + regEx(/[\^~]\s*(\d+\.\d+\.\d+)/), (_str, p1: string) => `~> ${p1}` ); - } else if (/~>\s*(\d+\.\d+)$/.test(currentValue)) { + } else if (regEx(/~>\s*(\d+\.\d+)$/).test(currentValue)) { newSemver = newSemver.replace( - /\^\s*(\d+\.\d+)(\.\d+)?/, + regEx(/\^\s*(\d+\.\d+)(\.\d+)?/), (_str, p1: string) => `~> ${p1}` ); } else { - newSemver = newSemver.replace(/~\s*(\d+\.\d+\.\d)/, '~> $1'); + newSemver = newSemver.replace(regEx(/~\s*(\d+\.\d+\.\d)/), '~> $1'); } if (npm.isVersion(newSemver)) { newSemver = `== ${newSemver}`; diff --git a/lib/versioning/ivy/parse.ts b/lib/versioning/ivy/parse.ts index 568bdb5eff3202b06b5e333ad70e24282c4d10e7..94e9d2cf351b1bc0f9519a4fd77652a89a8be2b5 100644 --- a/lib/versioning/ivy/parse.ts +++ b/lib/versioning/ivy/parse.ts @@ -1,3 +1,4 @@ +import { regEx } from '../../util/regex'; import { isSingleVersion, parseRange, rangeToStr } from '../maven/compare'; const REV_TYPE_LATEST = 'REV_TYPE_LATEST'; @@ -10,7 +11,7 @@ export interface Revision { value: string; } -export const LATEST_REGEX = /^latest\.|^latest$/i; +export const LATEST_REGEX = regEx(/^latest\.|^latest$/i); function parseDynamicRevision(str: string): Revision | null { if (!str) { @@ -25,7 +26,7 @@ function parseDynamicRevision(str: string): Revision | null { }; } - const SUBREV_REGEX = /\.\+$/; + const SUBREV_REGEX = regEx(/\.\+$/); if (str.endsWith('.+')) { const value = str.replace(SUBREV_REGEX, ''); if (isSingleVersion(value)) { diff --git a/lib/versioning/loose/index.ts b/lib/versioning/loose/index.ts index 9b0ba7723502cf9028da64dabffbd6c375690ae1..32cba9301f3fb086570fdd755e3075d893b2004f 100644 --- a/lib/versioning/loose/index.ts +++ b/lib/versioning/loose/index.ts @@ -1,3 +1,4 @@ +import { regEx } from '../../util/regex'; import type { VersioningApi } from '../types'; import * as generic from './generic'; @@ -6,9 +7,9 @@ export const displayName = 'Loose'; export const urls = []; export const supportsRanges = false; -const versionPattern = /^v?(\d+(?:\.\d+)*)(.*)$/; -const commitHashPattern = /^[a-f0-9]{7,40}$/; -const numericPattern = /^[0-9]+$/; +const versionPattern = regEx(/^v?(\d+(?:\.\d+)*)(.*)$/); +const commitHashPattern = regEx(/^[a-f0-9]{7,40}$/); +const numericPattern = regEx(/^[0-9]+$/); function parse(version: string): any { if (commitHashPattern.test(version) && !numericPattern.test(version)) { diff --git a/lib/versioning/maven/compare.ts b/lib/versioning/maven/compare.ts index cf3980772a6db256cd5030b98123fa6b558e901f..308ff9609b45243c16e3d0e8837dd9ea2dab9902 100644 --- a/lib/versioning/maven/compare.ts +++ b/lib/versioning/maven/compare.ts @@ -1,3 +1,5 @@ +import { regEx } from '../../util/regex'; + const PREFIX_DOT = 'PREFIX_DOT'; const PREFIX_HYPHEN = 'PREFIX_HYPHEN'; @@ -35,11 +37,11 @@ function iterateChars(str: string, cb: (p: string, n: string) => void): void { } function isDigit(char: string): boolean { - return /^\d$/.test(char); + return regEx(/^\d$/).test(char); } function isLetter(char: string): boolean { - return /^[a-z]$/i.test(char); + return regEx(/^[a-z]$/i).test(char); } function isTransition(prevChar: string, nextChar: string): boolean { @@ -55,7 +57,7 @@ function iterateTokens(versionStr: string, cb: (token: Token) => void): void { function yieldToken(transition = false): void { const val = currentVal || '0'; - if (/^\d+$/.test(val)) { + if (regEx(/^\d+$/).test(val)) { cb({ prefix: currentPrefix, type: TYPE_NUMBER, @@ -117,7 +119,7 @@ function tokenize(versionStr: string, preserveMinorZeroes = false): Token[] { let buf: Token[] = []; let result: Token[] = []; let leadingZero = true; - iterateTokens(versionStr.toLowerCase().replace(/^v/i, ''), (token) => { + iterateTokens(versionStr.toLowerCase().replace(regEx(/^v/i), ''), (token) => { if (token.prefix === PREFIX_HYPHEN) { buf = []; } @@ -276,13 +278,13 @@ function isVersion(version: string): boolean { if (!version) { return false; } - if (!/^[a-z0-9.-]+$/i.test(version)) { + if (!regEx(/^[a-z0-9.-]+$/i).test(version)) { return false; } - if (/^[.-]/.test(version)) { + if (regEx(/^[.-]/).test(version)) { return false; } - if (/[.-]$/.test(version)) { + if (regEx(/[.-]$/).test(version)) { return false; } if (['latest', 'release'].includes(version.toLowerCase())) { @@ -316,7 +318,7 @@ function parseRange(rangeStr: string): Range[] { return; } if (interval.leftType === null) { - if (/^\[.*]$/.test(subStr)) { + if (regEx(/^\[.*]$/).test(subStr)) { const ver = subStr.slice(1, -1); result.push({ leftType: INCLUDING_POINT, diff --git a/lib/versioning/npm/range.ts b/lib/versioning/npm/range.ts index e4e6027cbfa8100ab0fd3391c70490a040780de0..fb4d15815ec2c079874b85d6f57933ab18a0ef83 100644 --- a/lib/versioning/npm/range.ts +++ b/lib/versioning/npm/range.ts @@ -9,6 +9,7 @@ import { } from 'semver'; import { parseRange } from 'semver-utils'; import { logger } from '../../logger'; +import { regEx } from '../../util/regex'; import type { NewValueConfig } from '../types'; function replaceCaretValue(oldValue: string, newValue: string): string { @@ -234,7 +235,7 @@ export function getNewValue({ res = `<${toVersionMajor + 1}`; } if (currentValue.includes('< ')) { - res = res.replace(/</g, '< '); + res = res.replace(regEx(/</g), '< '); } return res; } diff --git a/lib/versioning/nuget/index.ts b/lib/versioning/nuget/index.ts index 387aad98a5af4c3a1baa6d24326951657b7a53f5..0c94eccdb78c8327c65cbabd9cef91c20ad7cfc6 100644 --- a/lib/versioning/nuget/index.ts +++ b/lib/versioning/nuget/index.ts @@ -1,3 +1,4 @@ +import { regEx } from '../../util/regex'; import * as generic from '../loose/generic'; import type { VersioningApi } from '../types'; @@ -8,7 +9,7 @@ export const urls = [ ]; export const supportsRanges = false; -const pattern = /^(\d+(?:\.\d+)*)(-[^+]+)?(\+.*)?$/; +const pattern = regEx(/^(\d+(?:\.\d+)*)(-[^+]+)?(\+.*)?$/); function parse(version: string): any { const matches = pattern.exec(version); diff --git a/lib/versioning/pep440/range.ts b/lib/versioning/pep440/range.ts index c2c9d85627927aeca67b88fd2bac5cf33b98a422..9e7785a9e09c85cd33e4e13c504afc68ef7798d9 100644 --- a/lib/versioning/pep440/range.ts +++ b/lib/versioning/pep440/range.ts @@ -2,6 +2,7 @@ import { gte, lt, lte, satisfies } from '@renovate/pep440'; import { parse as parseRange } from '@renovate/pep440/lib/specifier'; import { parse as parseVersion } from '@renovate/pep440/lib/version'; import { logger } from '../../logger'; +import { regEx } from '../../util/regex'; import type { NewValueConfig } from '../types'; function getFutureVersion( @@ -140,7 +141,7 @@ export function getNewValue({ .join(', '); if (result.includes(', ') && !currentValue.includes(', ')) { - result = result.replace(/, /g, ','); + result = result.replace(regEx(/, /g), ','); } if (!satisfies(newVersion, result)) { @@ -163,8 +164,8 @@ export function isLessThanRange(input: string, range: string): boolean { .split(',') .map((x) => x - .replace(/\s*/g, '') - .split(/(~=|==|!=|<=|>=|<|>|===)/) + .replace(regEx(/\s*/g), '') // TODO #12071 + .split(regEx(/(~=|==|!=|<=|>=|<|>|===)/)) // TODO #12071 .slice(1) ) .map(([op, version]) => { diff --git a/lib/versioning/rez/index.ts b/lib/versioning/rez/index.ts index 6b848afcfbe64525b546e2d910cdff188386c046..f027ed5254212dc15c6ab03d1d7a6d507a58a1d5 100644 --- a/lib/versioning/rez/index.ts +++ b/lib/versioning/rez/index.ts @@ -1,3 +1,4 @@ +import { regEx } from '../../util/regex'; import { api as npm } from '../npm'; import { api as pep440 } from '../pep440'; import type { NewValueConfig, VersioningApi } from '../types'; @@ -146,12 +147,8 @@ function getNewValue({ const lowerAscVersionCurrent = match.groups.range_lower_asc_version; const upperAscVersionCurrent = match.groups.range_upper_asc_version; const [lowerBoundAscPep440, upperBoundAscPep440] = pep440Value.split(', '); - const lowerAscVersionNew = new RegExp(versionGroup).exec( - lowerBoundAscPep440 - )[0]; - const upperAscVersionNew = new RegExp(versionGroup).exec( - upperBoundAscPep440 - )[0]; + const lowerAscVersionNew = regEx(versionGroup).exec(lowerBoundAscPep440)[0]; + const upperAscVersionNew = regEx(versionGroup).exec(upperBoundAscPep440)[0]; const lowerBoundAscNew = lowerBoundAscCurrent.replace( lowerAscVersionCurrent, lowerAscVersionNew @@ -175,12 +172,10 @@ function getNewValue({ const [lowerBoundDescPep440, upperBoundDescPep440] = pep440Value.split(', '); - const upperDescVersionNew = new RegExp(versionGroup).exec( - upperBoundDescPep440 - )[0]; - const lowerDescVersionNew = new RegExp(versionGroup).exec( - lowerBoundDescPep440 - )[0]; + const upperDescVersionNew = + regEx(versionGroup).exec(upperBoundDescPep440)[0]; + const lowerDescVersionNew = + regEx(versionGroup).exec(lowerBoundDescPep440)[0]; const upperBoundDescNew = upperBoundDescCurrent.replace( upperDescVersionCurrent, upperDescVersionNew diff --git a/lib/versioning/rez/pattern.ts b/lib/versioning/rez/pattern.ts index 9132efa141fdeedfc8bb66aa85c70c46630cc4dd..d2d7c98e46d39acf9fa29c7bb6dd89be3966cff2 100644 --- a/lib/versioning/rez/pattern.ts +++ b/lib/versioning/rez/pattern.ts @@ -59,31 +59,34 @@ // - Replace {version_group} -> ${versionGroup} // - Replace (?P<...>) -> (?<...>) // - Replace ?(...) -> \k<...> + +import { regEx } from '../../util/regex'; + // - Replace single \ -> double \ export const versionGroup = '([0-9a-zA-Z_]+(?:[.-][0-9a-zA-Z_]+)*)'; -export const matchVersion = new RegExp( +export const matchVersion = regEx( `^(?<version>${versionGroup})$` ); /* Match a version number (e.g. 1.0.0) */ -export const exactVersion = new RegExp( +export const exactVersion = regEx( `^(?<exact_version>==(?<exact_version_group>${versionGroup})?)$` ); /* Match an exact version number (e.g. ==1.0.0) */ // inclusiveBound is called inclusive but behaviour in rez is this: // package-1..3 will match versions 1.2.3, 2.3.4, but not 3.0.0 or above -export const inclusiveBound = new RegExp( +export const inclusiveBound = regEx( `^(?<inclusive_bound>(?<inclusive_lower_version>${versionGroup})?\\.\\.(?<inclusive_upper_version>${versionGroup})?)$` ); /* Match an inclusive bound (e.g. 1.0.0..2.0.0) */ // Add ? after |\\+) in order to match >=1.15 -export const lowerBound = new RegExp( +export const lowerBound = new RegExp( // TODO #12070 `^(?<lower_bound>(?<lower_bound_prefix>>|>=)?(?<lower_version>${versionGroup})?(\\k<lower_bound_prefix>|\\+)?)$` ); /* Match a lower bound (e.g. 1.0.0+) */ -export const upperBound = new RegExp( +export const upperBound = new RegExp( // TODO #12070 `^(?<upper_bound>(?<upper_bound_prefix><(?=${versionGroup})|<=)?(?<upper_version>${versionGroup})?)$` ); /* Match an upper bound (e.g. <=1.0.0) */ // Add ,? to match >=7,<9 (otherwise it just matches >=7<9) -export const ascendingRange = new RegExp( +export const ascendingRange = new RegExp( // TODO #12070 `^(?<range_asc>(?<range_lower_asc>(?<range_lower_asc_prefix>>|>=)?(?<range_lower_asc_version>${versionGroup})?(\\k<range_lower_asc_prefix>|\\+)?),?(?<range_upper_asc>(\\k<range_lower_asc_version>,?|)(?<range_upper_asc_prefix><(?=${versionGroup})|<=)(?<range_upper_asc_version>${versionGroup})?))$` ); /* Match a range in ascending order (e.g. 1.0.0+<2.0.0) */ // Add , to match <9,>=7 (otherwise it just matches <9>=7) -export const descendingRange = new RegExp( +export const descendingRange = new RegExp( // TODO #12070 `^(?<range_desc>(?<range_upper_desc>(?<range_upper_desc_prefix><|<=)?(?<range_upper_desc_version>${versionGroup})?(\\k<range_upper_desc_prefix>|\\+)?),(?<range_lower_desc>(\\k<range_upper_desc_version>,|)(?<range_lower_desc_prefix><(?=${versionGroup})|>=?)(?<range_lower_desc_version>${versionGroup})?))$` ); /* Match a range in descending order (e.g. <=2.0.0,1.0.0+) */ diff --git a/lib/versioning/rez/transform.ts b/lib/versioning/rez/transform.ts index b5685560821795200e78c246996431d012aa7746..9b1cb5556da5fbc370581880d5b345e161903cee 100644 --- a/lib/versioning/rez/transform.ts +++ b/lib/versioning/rez/transform.ts @@ -1,3 +1,4 @@ +import { regEx } from '../../util/regex'; import { ascendingRange, descendingRange, @@ -18,7 +19,7 @@ function getVersionParts(input: string): [string, string] { } export function padZeroes(input: string): string { - if (/[~^*]/.test(input)) { + if (regEx(/[~^*]/).test(input)) { // ignore ranges return input; } @@ -47,7 +48,7 @@ export function rez2npm(input: string): string { return input.replace('==', '='); } if (inclusiveBound.test(input)) { - return '>=' + input.replace(/\.\./g, ' <'); + return '>=' + input.replace(regEx(/\.\./g), ' <'); } if (lowerBound.test(input)) { return plus2npm(input); @@ -78,7 +79,7 @@ export function rez2pep440(input: string): string { return input; } if (inclusiveBound.test(input)) { - return '>=' + input.replace(/\.\./g, ', <'); + return '>=' + input.replace(regEx(/\.\./g), ', <'); } if (lowerBound.test(input)) { return plus2npm(input); @@ -104,7 +105,7 @@ export function rez2pep440(input: string): string { export function pep4402rezInclusiveBound(input: string): string { return input .split(',') - .map((v) => v.trim().replace(/[<>=]/g, '')) + .map((v) => v.trim().replace(regEx(/[<>=]/g), '')) // TODO #12071 .join('..'); } diff --git a/lib/versioning/ruby/index.ts b/lib/versioning/ruby/index.ts index e682c9fe4196bf02f160ab106bd0d01eeac9e69e..929e267ae90ff062bdcbd49b2bffc3b1e2aa002d 100644 --- a/lib/versioning/ruby/index.ts +++ b/lib/versioning/ruby/index.ts @@ -7,6 +7,7 @@ import { valid, } from '@renovatebot/ruby-semver'; import { logger } from '../../logger'; +import { regEx } from '../../util/regex'; import type { NewValueConfig, VersioningApi } from '../types'; import { isSingleOperator, isValidOperator } from './operator'; import { ltr, parse as parseRange } from './range'; @@ -25,7 +26,7 @@ export const supportedRangeStrategies = ['bump', 'extend', 'pin', 'replace']; function vtrim<T = unknown>(version: T): string | T { if (typeof version === 'string') { - return version.replace(/^v/, '').replace(/('|")/g, ''); + return version.replace(regEx(/^v/), '').replace(regEx(/('|")/g), ''); } return version; } @@ -87,7 +88,7 @@ const getNewValue = ({ let newValue = null; if (isVersion(currentValue)) { newValue = currentValue.startsWith('v') ? 'v' + newVersion : newVersion; - } else if (currentValue.replace(/^=\s*/, '') === currentVersion) { + } else if (currentValue.replace(regEx(/^=\s*/), '') === currentVersion) { newValue = currentValue.replace(currentVersion, newVersion); } else { switch (rangeStrategy) { @@ -122,15 +123,17 @@ const getNewValue = ({ logger.warn(`Unsupported strategy ${rangeStrategy}`); } } - if (/^('|")/.exec(currentValue)) { + if (regEx(/^('|")/).exec(currentValue)) { const delimiter = currentValue[0]; return newValue .split(',') - .map((element) => - element.replace(/^(?<whitespace>\s*)/, `$<whitespace>${delimiter}`) + .map( + (element) => + element.replace(/^(?<whitespace>\s*)/, `$<whitespace>${delimiter}`) // TODO #12071 #12070 ) - .map((element) => - element.replace(/(?<whitespace>\s*)$/, `${delimiter}$<whitespace>`) + .map( + (element) => + element.replace(/(?<whitespace>\s*)$/, `${delimiter}$<whitespace>`) // TODO #12071 #12070 ) .join(','); } diff --git a/lib/versioning/ruby/range.ts b/lib/versioning/ruby/range.ts index 3677f81d79664c7105b72af1f37eb98b37512245..3304337f1142cc890887cebbe6c7b7a952bf57f6 100644 --- a/lib/versioning/ruby/range.ts +++ b/lib/versioning/ruby/range.ts @@ -1,6 +1,7 @@ import { parse as _parse } from '@renovatebot/ruby-semver/dist/ruby/requirement'; import { Version, create } from '@renovatebot/ruby-semver/dist/ruby/version'; import { logger } from '../../logger'; +import { regEx } from '../../util/regex'; import { EQUAL, GT, GTE, LT, LTE, NOT_EQUAL, PGTE } from './operator'; export interface Range { @@ -10,8 +11,9 @@ export interface Range { } const parse = (range: string): Range => { - const regExp = - /^(?<operator>[^\d\s]+)?(?<delimiter>\s*)(?<version>[0-9a-zA-Z-.]+)$/; + const regExp = regEx( + /^(?<operator>[^\d\s]+)?(?<delimiter>\s*)(?<version>[0-9a-zA-Z-.]+)$/ + ); const value = (range || '').trim(); diff --git a/lib/versioning/ruby/version.ts b/lib/versioning/ruby/version.ts index f6f7b44a934893bf66e2d1fe368a20cc556c645a..6ae868859b066ca15e51dee9ca671e8eb576e1e7 100644 --- a/lib/versioning/ruby/version.ts +++ b/lib/versioning/ruby/version.ts @@ -3,6 +3,7 @@ import { SegmentElement, create, } from '@renovatebot/ruby-semver/dist/ruby/version'; +import { regEx } from '../../util/regex'; interface RubyVersion { major: number; @@ -71,7 +72,7 @@ const increment = (from: string, to: string): string => { return incrementLastSegment(from); } - const isStable = (x: string): boolean => /^[0-9.-/]+$/.test(x); + const isStable = (x: string): boolean => regEx(/^[0-9.-/]+$/).test(x); if (major(from) !== major(adapted)) { nextVersion = [incrementMajor(maj, min, ptch, pre || []), 0, 0].join('.'); } else if (minor(from) !== minor(adapted)) { diff --git a/lib/versioning/swift/index.ts b/lib/versioning/swift/index.ts index c34127c895bd0e4f688ad26c983c9e5c358fa1cd..fa7ba22a6bee6b8d834d7122c483920a72100842 100644 --- a/lib/versioning/swift/index.ts +++ b/lib/versioning/swift/index.ts @@ -1,5 +1,6 @@ import semver from 'semver'; import stable from 'semver-stable'; +import { regEx } from '../../util/regex'; import type { VersioningApi } from '../types'; import { getNewValue, toSemverRange } from './range'; @@ -31,12 +32,12 @@ export const isValid = (input: string): boolean => export const isVersion = (input: string): boolean => !!valid(input); const getSatisfyingVersion = (versions: string[], range: string): string => maxSatisfying( - versions.map((v) => v.replace(/^v/, '')), + versions.map((v) => v.replace(regEx(/^v/), '')), // TODO #12071 toSemverRange(range) ); const minSatisfyingVersion = (versions: string[], range: string): string => minSatisfying( - versions.map((v) => v.replace(/^v/, '')), + versions.map((v) => v.replace(regEx(/^v/), '')), // TODO #12071 #12070 toSemverRange(range) ); const isLessThanRange = (version: string, range: string): boolean => diff --git a/lib/versioning/swift/range.ts b/lib/versioning/swift/range.ts index 52f6321d08e7d83b1f9b4d51a67359cb800dbec7..18ce3d20e0638b5f871dd0dbaa7397bc1e5f5a94 100644 --- a/lib/versioning/swift/range.ts +++ b/lib/versioning/swift/range.ts @@ -1,10 +1,11 @@ import semver from 'semver'; +import { regEx } from '../../util/regex'; import type { NewValueConfig } from '../types'; -const fromParam = /^\s*from\s*:\s*"([^"]+)"\s*$/; -const fromRange = /^\s*"([^"]+)"\s*\.\.\.\s*$/; -const binaryRange = /^\s*"([^"]+)"\s*(\.\.[.<])\s*"([^"]+)"\s*$/; -const toRange = /^\s*(\.\.[.<])\s*"([^"]+)"\s*$/; +const fromParam = regEx(/^\s*from\s*:\s*"([^"]+)"\s*$/); +const fromRange = regEx(/^\s*"([^"]+)"\s*\.\.\.\s*$/); +const binaryRange = regEx(/^\s*"([^"]+)"\s*(\.\.[.<])\s*"([^"]+)"\s*$/); +const toRange = regEx(/^\s*(\.\.[.<])\s*"([^"]+)"\s*$/); function toSemverRange(range: string): string { if (fromParam.test(range)) { @@ -40,7 +41,7 @@ function getNewValue({ newVersion, }: NewValueConfig): string { if (fromParam.test(currentValue)) { - return currentValue.replace(/".*?"/, `"${newVersion}"`); + return currentValue.replace(regEx(/".*?"/), `"${newVersion}"`); } if (fromRange.test(currentValue)) { const [, version] = fromRange.exec(currentValue); diff --git a/lib/versioning/ubuntu/index.ts b/lib/versioning/ubuntu/index.ts index 9e7d2921b0feaecb3e9dfad314fcc0c3b614020d..0e4d3a22dd7a6c796d2e8db7bc1a9e344401721a 100644 --- a/lib/versioning/ubuntu/index.ts +++ b/lib/versioning/ubuntu/index.ts @@ -1,3 +1,4 @@ +import { regEx } from '../../util/regex'; import type { NewValueConfig, VersioningApi } from '../types'; export const id = 'ubuntu'; @@ -10,7 +11,7 @@ export const supportsRanges = false; function isValid(input: string): string | boolean | null { return ( typeof input === 'string' && - /^(0[4-5]|[6-9]|[1-9][0-9])\.[0-9][0-9](\.[0-9]{1,2})?$/.test(input) + regEx(/^(0[4-5]|[6-9]|[1-9][0-9])\.[0-9][0-9](\.[0-9]{1,2})?$/).test(input) ); } @@ -33,7 +34,7 @@ function isStable(version: string): boolean { if (!isValid(version)) { return false; } - return /^\d?[02468]\.04/.test(version); + return regEx(/^\d?[02468]\.04/).test(version); } // digestion of version diff --git a/lib/workers/branch/index.ts b/lib/workers/branch/index.ts index da893445930b4a6d3380b4028ca6dd21051ec254..00d27a9ac4fc8364e4e54aa89acfb51dda0a7123 100644 --- a/lib/workers/branch/index.ts +++ b/lib/workers/branch/index.ts @@ -32,6 +32,7 @@ import { isActiveConfidenceLevel, satisfiesConfidenceLevel, } from '../../util/merge-confidence'; +import { regEx } from '../../util/regex'; import { Limit, isLimitReached } from '../global/limits'; import { ensurePr, getPlatformPrOptions } from '../pr'; import { checkAutoMerge } from '../pr/automerge'; @@ -57,7 +58,7 @@ function rebaseCheck(config: RenovateConfig, branchPr: Pr): boolean { return titleRebase || labelRebase || prRebaseChecked; } -const rebasingRegex = /\*\*Rebasing\*\*: .*/; +const rebasingRegex = regEx(/\*\*Rebasing\*\*: .*/); async function deleteBranchSilently(branchName: string): Promise<void> { try { diff --git a/lib/workers/branch/schedule.ts b/lib/workers/branch/schedule.ts index 443510053c43ef4faca0cec13bbe28c66fcf28bc..71696d72ff125560e987e99a0ba03e30a5d4215a 100644 --- a/lib/workers/branch/schedule.ts +++ b/lib/workers/branch/schedule.ts @@ -3,6 +3,7 @@ import is from '@sindresorhus/is'; import { DateTime } from 'luxon'; import type { RenovateConfig } from '../../config/types'; import { logger } from '../../logger'; +import { regEx } from '../../util/regex'; const scheduleMappings: Record<string, string> = { 'every month': 'before 3am on the first day of the month', @@ -10,7 +11,7 @@ const scheduleMappings: Record<string, string> = { }; function fixShortHours(input: string): string { - return input.replace(/( \d?\d)((a|p)m)/g, '$1:00$2'); + return input.replace(regEx(/( \d?\d)((a|p)m)/g), '$1:00$2'); } export function hasValidTimezone( diff --git a/lib/workers/global/config/parse/cli.ts b/lib/workers/global/config/parse/cli.ts index 1e224a736ed17e48a405911a7d411537460d470f..a318e9944151c1ff3af5f9360101832de767106b 100644 --- a/lib/workers/global/config/parse/cli.ts +++ b/lib/workers/global/config/parse/cli.ts @@ -2,12 +2,13 @@ import { Command } from 'commander'; import { version } from '../../../../../package.json'; import { getOptions } from '../../../../config/options'; import type { AllConfig, RenovateOptions } from '../../../../config/types'; +import { regEx } from '../../../../util/regex'; export function getCliName(option: Partial<RenovateOptions>): string { if (option.cli === false) { return ''; } - const nameWithHyphens = option.name.replace(/([A-Z])/g, '-$1'); + const nameWithHyphens = option.name.replace(regEx(/([A-Z])/g), '-$1'); return `--${nameWithHyphens.toLowerCase()}`; } diff --git a/lib/workers/global/config/parse/env.ts b/lib/workers/global/config/parse/env.ts index 3571174e4f2082842384e99564ad7accb3fe6b2c..51353ef48bca8546eeed25eb56d73de680a05aae 100644 --- a/lib/workers/global/config/parse/env.ts +++ b/lib/workers/global/config/parse/env.ts @@ -1,5 +1,4 @@ import is from '@sindresorhus/is'; - import { getOptions } from '../../../../config/options'; import type { AllConfig, RenovateOptions } from '../../../../config/types'; import { PlatformId } from '../../../../constants'; diff --git a/lib/workers/pr/body/changelogs.ts b/lib/workers/pr/body/changelogs.ts index a0e62d6910b346b315c9c58711629adee7fcbb28..73aa37c51d5f776a64dfe5bdc1af9eaf011e91ed 100644 --- a/lib/workers/pr/body/changelogs.ts +++ b/lib/workers/pr/body/changelogs.ts @@ -1,5 +1,6 @@ import { unemojify } from '../../../util/emoji'; import { sanitizeMarkdown } from '../../../util/markdown'; +import { regEx } from '../../../util/regex'; import * as template from '../../../util/template'; import type { BranchConfig } from '../../types'; import releaseNotesHbs from '../changelog/hbs-template'; @@ -12,7 +13,7 @@ export function getChangelogs(config: BranchConfig): string { } releaseNotes += '\n\n---\n\n' + template.compile(releaseNotesHbs, config, false) + '\n\n'; - releaseNotes = releaseNotes.replace(/### \[`vv/g, '### [`v'); + releaseNotes = releaseNotes.replace(regEx(/### \[`vv/g), '### [`v'); releaseNotes = sanitizeMarkdown(releaseNotes); releaseNotes = unemojify(releaseNotes); diff --git a/lib/workers/pr/body/index.ts b/lib/workers/pr/body/index.ts index 275476d77e9905a512fb3144456700436e73cf10..6aa5a015af8b6452bfdf29a01d8ae72e7c0a5f2f 100644 --- a/lib/workers/pr/body/index.ts +++ b/lib/workers/pr/body/index.ts @@ -1,4 +1,5 @@ import { platform } from '../../../platform'; +import { regEx } from '../../../util/regex'; import * as template from '../../../util/template'; import type { BranchConfig } from '../../types'; import { getChangelogs } from './changelogs'; @@ -43,7 +44,7 @@ function massageUpdateMetadata(config: BranchConfig): void { let fullUrl = sourceUrl; if (sourceDirectory) { fullUrl = - sourceUrl.replace(/\/?$/, '/') + + sourceUrl.replace(regEx(/\/?$/), '/') + 'tree/HEAD/' + sourceDirectory.replace('^/?/', ''); } @@ -71,7 +72,7 @@ export async function getPrBody(config: BranchConfig): Promise<string> { const prBodyTemplate = config.prBodyTemplate; let prBody = template.compile(prBodyTemplate, content, false); prBody = prBody.trim(); - prBody = prBody.replace(/\n\n\n+/g, '\n\n'); + prBody = prBody.replace(regEx(/\n\n\n+/g), '\n\n'); prBody = platform.massageMarkdown(prBody); return prBody; } diff --git a/lib/workers/pr/body/updates-table.ts b/lib/workers/pr/body/updates-table.ts index 06607b31c38dc90a3f9cd9edf10c4b4909399522..173fe873c94748061fe3bc0ebc6d87e52ba9a5de 100644 --- a/lib/workers/pr/body/updates-table.ts +++ b/lib/workers/pr/body/updates-table.ts @@ -1,4 +1,5 @@ import { logger } from '../../../logger'; +import { regEx } from '../../../util/regex'; import * as template from '../../../util/template'; import type { BranchConfig } from '../../types'; @@ -43,7 +44,9 @@ export function getPrUpdatesTable(config: BranchConfig): string { try { // istanbul ignore else if (value) { - res[header] = template.compile(value, upgrade).replace(/^``$/, ''); + res[header] = template + .compile(value, upgrade) + .replace(regEx(/^``$/), ''); // TODO #12071 } else { res[header] = ''; } @@ -62,7 +65,9 @@ export function getPrUpdatesTable(config: BranchConfig): string { let val = '|'; for (const column of tableColumns) { const content = row[column] - ? row[column].replace(/^@/, '@​').replace(/\|/g, '\\|') + ? row[column] + .replace(regEx(/^@/), '@​') + .replace(regEx(/\|/g), '\\|') // TODO #12071 : ''; val += ` ${content} |`; } diff --git a/lib/workers/pr/changelog/gitlab/index.ts b/lib/workers/pr/changelog/gitlab/index.ts index 282e2f5c218b1fe80a2e6bb52b43fcb20fb7ccad..3364cffb9e1a44b54afced7f592e0844cf4bbac0 100644 --- a/lib/workers/pr/changelog/gitlab/index.ts +++ b/lib/workers/pr/changelog/gitlab/index.ts @@ -4,13 +4,14 @@ import type { GitlabTag } from '../../../../datasource/gitlab-tags/types'; import { logger } from '../../../../logger'; import type { GitlabTreeNode } from '../../../../types/platform/gitlab'; import { GitlabHttp } from '../../../../util/http/gitlab'; +import { regEx } from '../../../../util/regex'; import { ensureTrailingSlash } from '../../../../util/url'; import type { ChangeLogFile, ChangeLogNotes } from '../types'; const http = new GitlabHttp(); function getRepoId(repository: string): string { - return repository.replace(/\//g, '%2f'); + return repository.replace(regEx(/\//g), '%2f'); } export async function getTags( diff --git a/lib/workers/pr/changelog/release-notes.ts b/lib/workers/pr/changelog/release-notes.ts index 43067c97094d56de29623305858325e067b57607..f365fde6e9a468d4a07dbf37774be6cb0a145621 100644 --- a/lib/workers/pr/changelog/release-notes.ts +++ b/lib/workers/pr/changelog/release-notes.ts @@ -6,6 +6,7 @@ import { logger } from '../../../logger'; import * as memCache from '../../../util/cache/memory'; import * as packageCache from '../../../util/cache/package'; import { linkify } from '../../../util/markdown'; +import { regEx } from '../../../util/regex'; import * as github from './github'; import * as gitlab from './gitlab'; import type { @@ -67,25 +68,23 @@ export function massageBody( ): string { let body = input || ''; // Convert line returns - body = body.replace(/\r\n/g, '\n'); + body = body.replace(regEx(/\r\n/g), '\n'); // TODO #12071 // semantic-release cleanup - body = body.replace(/^<a name="[^"]*"><\/a>\n/, ''); + body = body.replace(regEx(/^<a name="[^"]*"><\/a>\n/), ''); // TODO #12071 body = body.replace( - new RegExp( - `^##? \\[[^\\]]*\\]\\(${baseUrl}[^/]*\\/[^/]*\\/compare\\/.*?\\n` - ), + regEx(`^##? \\[[^\\]]*\\]\\(${baseUrl}[^/]*\\/[^/]*\\/compare\\/.*?\\n`), '' - ); + ); // TODO #12071 // Clean-up unnecessary commits link body = `\n${body}\n`.replace( - new RegExp(`\\n${baseUrl}[^/]+\\/[^/]+\\/compare\\/[^\\n]+(\\n|$)`), + regEx(`\\n${baseUrl}[^/]+\\/[^/]+\\/compare\\/[^\\n]+(\\n|$)`), '\n' - ); + ); // TODO #12071 // Reduce headings size body = body - .replace(/\n\s*####? /g, '\n##### ') - .replace(/\n\s*## /g, '\n#### ') - .replace(/\n\s*# /g, '\n### '); + .replace(regEx(/\n\s*####? /g), '\n##### ') // TODO #12071 + .replace(regEx(/\n\s*## /g), '\n#### ') // TODO #12071 + .replace(regEx(/\n\s*# /g), '\n### '); // TODO #12071 // Trim whitespace return body.trim(); } @@ -236,7 +235,7 @@ export async function getReleaseNotesMd( } const { changelogFile } = changelog; const changelogMd = changelog.changelogMd.replace( - /\n\s*<a name="[^"]*">.*?<\/a>\n/g, + regEx(/\n\s*<a name="[^"]*">.*?<\/a>\n/g), '\n' ); for (const level of [1, 2, 3, 4, 5, 6, 7]) { @@ -245,19 +244,22 @@ export async function getReleaseNotesMd( for (const section of changelogParsed) { try { // replace brackets and parenthesis with space - const deParenthesizedSection = section.replace(/[[\]()]/g, ' '); + const deParenthesizedSection = section.replace( + regEx(/[[\]()]/g), + ' ' + ); // TODO #12071 const [heading] = deParenthesizedSection.split('\n'); const title = heading - .replace(/^\s*#*\s*/, '') + .replace(regEx(/^\s*#*\s*/), '') // TODO #12071 .split(' ') .filter(Boolean); - let body = section.replace(/.*?\n(-{3,}\n)?/, '').trim(); + let body = section.replace(regEx(/.*?\n(-{3,}\n)?/), '').trim(); // TODO #12071 for (const word of title) { if (word.includes(version) && !isUrl(word)) { logger.trace({ body }, 'Found release notes for v' + version); // TODO: fix url let url = `${baseUrl}${repository}/blob/master/${changelogFile}#`; - url += title.join('-').replace(/[^A-Za-z0-9-]/g, ''); + url += title.join('-').replace(regEx(/[^A-Za-z0-9-]/g), ''); // TODO #12071 body = massageBody(body, baseUrl); if (body?.length) { try { diff --git a/lib/workers/pr/changelog/source-github.ts b/lib/workers/pr/changelog/source-github.ts index 720ef8c4d8b0c18b0f78146fcdb23744820a5c84..963103752b0797f46dfbf82fad0010f48faeb7d8 100644 --- a/lib/workers/pr/changelog/source-github.ts +++ b/lib/workers/pr/changelog/source-github.ts @@ -5,6 +5,7 @@ import { logger } from '../../../logger'; import * as memCache from '../../../util/cache/memory'; import * as packageCache from '../../../util/cache/package'; import * as hostRules from '../../../util/host-rules'; +import { regEx } from '../../../util/regex'; import * as allVersioning from '../../../versioning'; import type { BranchUpgradeConfig } from '../../types'; import { getTags } from './github'; @@ -70,8 +71,8 @@ export async function getChangeLogJSON({ : baseUrl + 'api/v3/'; const repository = pathname .slice(1) - .replace(/\/$/, '') - .replace(/\.git$/, ''); + .replace(regEx(/\/$/), '') + .replace(regEx(/\.git$/), ''); if (repository.split('/').length !== 2) { logger.debug({ sourceUrl }, 'Invalid github URL found'); return null; @@ -96,7 +97,7 @@ export async function getChangeLogJSON({ if (!tags) { tags = await getCachedTags(apiBaseUrl, repository); } - const regex = new RegExp(`(?:${depName}|release)[@-]`); + const regex = regEx(`(?:${depName}|release)[@-]`); const tagName = tags .filter((tag) => version.isVersion(tag.replace(regex, ''))) .find((tag) => version.equals(tag.replace(regex, ''), release.version)); diff --git a/lib/workers/pr/changelog/source-gitlab.ts b/lib/workers/pr/changelog/source-gitlab.ts index 9eb713d13b03f1050976147c8e9cf6984a857a4c..f7a0505142b6f7346b4458da56beab9b65481c0b 100644 --- a/lib/workers/pr/changelog/source-gitlab.ts +++ b/lib/workers/pr/changelog/source-gitlab.ts @@ -46,8 +46,8 @@ export async function getChangeLogJSON({ const apiBaseUrl = baseUrl.concat('api/v4/'); const repository = pathname .slice(1) - .replace(/\/$/, '') - .replace(/\.git$/, ''); + .replace(regEx(/\/$/), '') + .replace(regEx(/\.git$/), ''); if (repository.split('/').length < 2) { logger.info({ sourceUrl }, 'Invalid gitlab URL found'); return null; diff --git a/lib/workers/pr/code-owners.ts b/lib/workers/pr/code-owners.ts index 731c9e4e7b504e8aed022830b790e2cbe0e55a67..22f7681adb6a0a9afc5e4aaa114494814a481500 100644 --- a/lib/workers/pr/code-owners.ts +++ b/lib/workers/pr/code-owners.ts @@ -3,6 +3,7 @@ import { logger } from '../../logger'; import { Pr } from '../../platform'; import { readLocalFile } from '../../util/fs'; import { getBranchFiles } from '../../util/git'; +import { regEx } from '../../util/regex'; export async function codeOwnersForPr(pr: Pr): Promise<string[]> { logger.debug('Searching for CODEOWNERS file'); @@ -26,7 +27,7 @@ export async function codeOwnersForPr(pr: Pr): Promise<string[]> { .map((line) => line.trim()) .filter((line) => line && !line.startsWith('#')) .map((line) => { - const [pattern, ...usernames] = line.split(/\s+/); + const [pattern, ...usernames] = line.split(regEx(/\s+/)); // TODO #12071 return { usernames, match: (path: string) => { diff --git a/lib/workers/pr/index.ts b/lib/workers/pr/index.ts index fb8bda96179a52eee62da0218aea5b603088b1dc..e84858b73fa86b75670b5ba5f116c5696cd46378 100644 --- a/lib/workers/pr/index.ts +++ b/lib/workers/pr/index.ts @@ -12,6 +12,7 @@ import { ExternalHostError } from '../../types/errors/external-host-error'; import { sampleSize } from '../../util'; import { stripEmojis } from '../../util/emoji'; import { deleteBranch, getBranchLastCommitTime } from '../../util/git'; +import { regEx } from '../../util/regex'; import * as template from '../../util/template'; import { resolveBranchStatus } from '../branch/status-checks'; import { Limit, incLimitedValue, isLimitReached } from '../global/limits'; @@ -21,7 +22,7 @@ import { ChangeLogError } from './changelog/types'; import { codeOwnersForPr } from './code-owners'; function noWhitespaceOrHeadings(input: string): string { - return input.replace(/\r?\n|\r|\s|#/g, ''); + return input.replace(regEx(/\r?\n|\r|\s|#/g), ''); } function noLeadingAtSymbol(input: string): string { diff --git a/lib/workers/repository/dependency-dashboard.ts b/lib/workers/repository/dependency-dashboard.ts index 3366d963ce73d149e6dc5078b5bab1992191b46b..6dc1dded4dcd2f2242cbd2a403e17da7f7c58d22 100644 --- a/lib/workers/repository/dependency-dashboard.ts +++ b/lib/workers/repository/dependency-dashboard.ts @@ -4,6 +4,7 @@ import { getGlobalConfig } from '../../config/global'; import type { RenovateConfig } from '../../config/types'; import { getProblems, logger } from '../../logger'; import { platform } from '../../platform'; +import { regEx } from '../../util/regex'; import { BranchConfig, BranchResult } from '../types'; interface DependencyDashboard { @@ -13,10 +14,10 @@ interface DependencyDashboard { function parseDashboardIssue(issueBody: string): DependencyDashboard { const checkMatch = ' - \\[x\\] <!-- ([a-zA-Z]+)-branch=([^\\s]+) -->'; - const checked = issueBody.match(new RegExp(checkMatch, 'g')); + const checked = issueBody.match(regEx(checkMatch, 'g')); const dependencyDashboardChecks: Record<string, string> = {}; if (checked?.length) { - const re = new RegExp(checkMatch); + const re = regEx(checkMatch); checked.forEach((check) => { const [, type, branchName] = re.exec(check); dependencyDashboardChecks[branchName] = type; diff --git a/lib/workers/repository/error-config.ts b/lib/workers/repository/error-config.ts index 752c46edc2b9cfe4ed1487e67a908defd0549d98..5b10967bac489b9aea043305b24d7591ec6928fd 100644 --- a/lib/workers/repository/error-config.ts +++ b/lib/workers/repository/error-config.ts @@ -3,6 +3,7 @@ import type { RenovateConfig } from '../../config/types'; import { logger } from '../../logger'; import { platform } from '../../platform'; import { PrState } from '../../types'; +import { regEx } from '../../util/regex'; export async function raiseConfigWarningIssue( config: RenovateConfig, @@ -15,7 +16,10 @@ export async function raiseConfigWarningIssue( } body += `Error type: ${error.validationError}\n`; if (error.validationMessage) { - body += `Message: \`${error.validationMessage.replace(/`/g, "'")}\`\n`; + body += `Message: \`${error.validationMessage.replace( + regEx(/`/g), + "'" + )}\`\n`; } const pr = await platform.getBranchPr(config.onboardingBranch); if (pr?.state === PrState.Open) { diff --git a/lib/workers/repository/init/vulnerability.ts b/lib/workers/repository/init/vulnerability.ts index 4bd4a5e87198d122bbaa914391e64f2875a2ebf2..85cbb3744d72ae2f3c3b8147ec7469b0d26701dc 100644 --- a/lib/workers/repository/init/vulnerability.ts +++ b/lib/workers/repository/init/vulnerability.ts @@ -9,6 +9,7 @@ import { logger } from '../../../logger'; import { platform } from '../../../platform'; import { SecurityAdvisory } from '../../../types'; import { sanitizeMarkdown } from '../../../util/markdown'; +import { regEx } from '../../../util/regex'; import * as allVersioning from '../../../versioning'; import * as mavenVersioning from '../../../versioning/maven'; import * as npmVersioning from '../../../versioning/npm'; @@ -110,7 +111,10 @@ export async function detectVulnerabilityAlerts( } } if (datasource === PypiDatasource.id) { - vulnerableRequirements = vulnerableRequirements.replace(/^= /, '== '); + vulnerableRequirements = vulnerableRequirements.replace( + regEx(/^= /), + '== ' + ); // TODO #12071 } combinedAlerts[fileName] ||= {}; combinedAlerts[fileName][datasource] ||= {}; diff --git a/lib/workers/repository/onboarding/pr/pr-list.ts b/lib/workers/repository/onboarding/pr/pr-list.ts index f5adce06102e47be6ec817a2d04be26d624516b9..b381c9f485966a77faf3ab0d99f6cddf0de6eb6d 100644 --- a/lib/workers/repository/onboarding/pr/pr-list.ts +++ b/lib/workers/repository/onboarding/pr/pr-list.ts @@ -1,6 +1,7 @@ import type { RenovateConfig } from '../../../../config/types'; import { logger } from '../../../../logger'; import { emojify } from '../../../../util/emoji'; +import { regEx } from '../../../../util/regex'; import type { BranchConfig } from '../../../types'; export function getPrList( @@ -17,7 +18,7 @@ export function getPrList( prDesc += branches.length > 1 ? `s:\n\n` : `:\n\n`; for (const branch of branches) { - const prTitleRe = /@([a-z]+\/[a-z]+)/; + const prTitleRe = regEx(/@([a-z]+\/[a-z]+)/); // TODO #12071 prDesc += `<details>\n<summary>${branch.prTitle.replace( prTitleRe, '@​$1' diff --git a/lib/workers/repository/process/lookup/current.ts b/lib/workers/repository/process/lookup/current.ts index 83ff6103318f9f6def958761e47856fd35ce3f04..94f8d12fd4e7d99ebc807868e8652f27c8c88246 100644 --- a/lib/workers/repository/process/lookup/current.ts +++ b/lib/workers/repository/process/lookup/current.ts @@ -1,5 +1,6 @@ import is from '@sindresorhus/is'; import { logger } from '../../../../logger'; +import { regEx } from '../../../../util/regex'; import type { VersioningApi } from '../../../../versioning/types'; import type { LookupUpdateConfig } from './types'; @@ -19,7 +20,7 @@ export function getCurrentVersion( return currentValue; } if (versioning.isSingleVersion(currentValue)) { - return currentValue.replace(/=/g, '').trim(); + return currentValue.replace(regEx(/=/g), '').trim(); } logger.trace(`currentValue ${currentValue} is range`); let useVersions = allVersions.filter((v) => diff --git a/lib/workers/repository/process/lookup/index.ts b/lib/workers/repository/process/lookup/index.ts index cf3143ade095b89fd53ca40d3ff5a1dc6783b38b..9f82d0191bd69aa5cba3b0704e7f1446c629e3cc 100644 --- a/lib/workers/repository/process/lookup/index.ts +++ b/lib/workers/repository/process/lookup/index.ts @@ -14,6 +14,7 @@ import { getRangeStrategy } from '../../../../manager'; import { SkipReason } from '../../../../types'; import { clone } from '../../../../util/clone'; import { applyPackageRules } from '../../../../util/package-rules'; +import { regEx } from '../../../../util/regex'; import * as allVersioning from '../../../../versioning'; import { getBucket } from './bucket'; import { getCurrentVersion } from './current'; @@ -284,7 +285,7 @@ export async function lookupUpdates( res.currentVersion = lockedVersion; res.fixedVersion = lockedVersion; } else if (currentValue && versioning.isSingleVersion(currentValue)) { - res.fixedVersion = currentValue.replace(/^=+/, ''); + res.fixedVersion = currentValue.replace(regEx(/^=+/), ''); } // Add digests if necessary if (supportsDigests(config)) { diff --git a/lib/workers/repository/updates/branch-name.ts b/lib/workers/repository/updates/branch-name.ts index e56e2da710fee664638ba40c2b368cd58e563a66..32211dca8760a65e7107f82def49f0059bb5f1d4 100644 --- a/lib/workers/repository/updates/branch-name.ts +++ b/lib/workers/repository/updates/branch-name.ts @@ -3,11 +3,12 @@ import hasha from 'hasha'; import slugify from 'slugify'; import type { RenovateConfig } from '../../../config/types'; import { logger } from '../../../logger'; +import { regEx } from '../../../util/regex'; import * as template from '../../../util/template'; const MIN_HASH_LENGTH = 6; -const RE_MULTIPLE_DASH = /--+/g; +const RE_MULTIPLE_DASH = regEx(/--+/g); /** * Clean git branch name * @@ -19,9 +20,10 @@ const RE_MULTIPLE_DASH = /--+/g; */ function cleanBranchName(branchName: string): string { return cleanGitRef(branchName) - .replace(/^\.|\.$/, '') // leading or trailing dot - .replace(/\/\./g, '/') // leading dot after slash - .replace(/\s/g, '') // whitespace + .replace(regEx(/^\.|\.$/), '') // leading or trailing dot + .replace(regEx(/\/\./g), '/') // leading dot after slash + .replace(regEx(/\s/g), '') // whitespace + .replace(regEx(/[[\]?:\\^~]/g), '-') // massage out all these characters: : ? [ \ ^ ~ .replace(RE_MULTIPLE_DASH, '-'); // chained dashes } diff --git a/lib/workers/repository/updates/flatten.ts b/lib/workers/repository/updates/flatten.ts index a6becaed1900ccc407e5d253d10aabb616ef1d00..22f3070e48c637d32c3fe84ab0c3eccf6e240170 100644 --- a/lib/workers/repository/updates/flatten.ts +++ b/lib/workers/repository/updates/flatten.ts @@ -7,6 +7,7 @@ import type { RenovateConfig } from '../../../config/types'; import { getDefaultConfig } from '../../../datasource'; import { get } from '../../../manager'; import { applyPackageRules } from '../../../util/package-rules'; +import { regEx } from '../../../util/regex'; import { parseUrl } from '../../../util/url'; import type { BranchUpgradeConfig } from '../../types'; import { generateBranchName } from './branch-name'; @@ -22,18 +23,18 @@ export function applyUpdateConfig(input: BranchUpgradeConfig): any { ? updateConfig.depName .replace('@types/', '') .replace('@', '') - .replace(/\//g, '-') - .replace(/\s+/g, '-') - .replace(/-+/, '-') + .replace(regEx(/\//g), '-') // TODO #12071 + .replace(regEx(/\s+/g), '-') // TODO #12071 + .replace(regEx(/-+/), '-') .toLowerCase() : undefined; if (updateConfig.sourceUrl) { const parsedSourceUrl = parseUrl(updateConfig.sourceUrl); if (parsedSourceUrl?.pathname) { updateConfig.sourceRepoSlug = parsedSourceUrl.pathname - .replace(/^\//, '') // remove leading slash - .replace(/\//g, '-') // change slashes to hyphens - .replace(/-+/g, '-'); // remove multiple hyphens + .replace(regEx(/^\//), '') // remove leading slash // TODO #12071 + .replace(regEx(/\//g), '-') // change slashes to hyphens // TODO #12071 + .replace(regEx(/-+/g), '-'); // remove multiple hyphens } } generateBranchName(updateConfig); diff --git a/lib/workers/repository/updates/generate.ts b/lib/workers/repository/updates/generate.ts index 05ea64a7e548dbc396ee8fb2856779b00c05d258..4ff74aff11938226c98e4f61b9f4eee4b99430b9 100644 --- a/lib/workers/repository/updates/generate.ts +++ b/lib/workers/repository/updates/generate.ts @@ -4,6 +4,7 @@ import semver from 'semver'; import { mergeChildConfig } from '../../../config'; import { CONFIG_SECRETS_EXPOSED } from '../../../constants/error-messages'; import { logger } from '../../../logger'; +import { regEx } from '../../../util/regex'; import { sanitize } from '../../../util/sanitize'; import * as template from '../../../util/template'; import type { BranchConfig, BranchUpgradeConfig } from '../../types'; @@ -160,8 +161,7 @@ export function generateBranchConfig( } upgrade.commitMessagePrefix = CommitMessage.formatPrefix(semanticPrefix); upgrade.toLowerCase = - // eslint-disable-next-line @typescript-eslint/prefer-regexp-exec - upgrade.semanticCommitType.match(/[A-Z]/) === null && + regEx(/[A-Z]/).exec(upgrade.semanticCommitType) === null && // TODO #12071 !upgrade.semanticCommitType.startsWith(':'); } // Compile a few times in case there are nested templates @@ -176,9 +176,9 @@ export function generateBranchConfig( throw new Error(CONFIG_SECRETS_EXPOSED); } upgrade.commitMessage = upgrade.commitMessage.trim(); // Trim exterior whitespace - upgrade.commitMessage = upgrade.commitMessage.replace(/\s+/g, ' '); // Trim extra whitespace inside string + upgrade.commitMessage = upgrade.commitMessage.replace(regEx(/\s+/g), ' '); // Trim extra whitespace inside string // TODO #12071 upgrade.commitMessage = upgrade.commitMessage.replace( - /to vv(\d)/, + regEx(/to vv(\d)/), // TODO #12071 'to v$1' ); if (upgrade.toLowerCase) { @@ -200,7 +200,7 @@ export function generateBranchConfig( upgrade.prTitle = template .compile(upgrade.prTitle, upgrade) .trim() - .replace(/\s+/g, ' '); + .replace(regEx(/\s+/g), ' '); // TODO #12071 // istanbul ignore if if (upgrade.prTitle !== sanitize(upgrade.prTitle)) { throw new Error(CONFIG_SECRETS_EXPOSED); diff --git a/test/exec-util.ts b/test/exec-util.ts index 6e12081cc5811cb5b9fdde88774b01f05bb01506..7e4d4e14972a4f058befa2302fd7cf44ad012930 100644 --- a/test/exec-util.ts +++ b/test/exec-util.ts @@ -3,6 +3,7 @@ import is from '@sindresorhus/is'; import traverse from 'traverse'; import { toUnix } from 'upath'; import { ExecOptions } from '../lib/util/exec'; +import { regEx } from '../lib/util/regex'; type CallOptions = ExecOptions | null | undefined; @@ -29,7 +30,9 @@ export function execSnapshot(cmd: string, options?: CallOptions): ExecSnapshot { // eslint-disable-next-line array-callback-return return traverse(snapshot).map(function fixup(v) { if (is.string(v)) { - const val = v.replace(/\\(\w)/g, '/$1').replace(cwd, '/root/project'); + const val = v + .replace(regEx(/\\(\w)/g), '/$1') + .replace(cwd, '/root/project'); // TODO #12071 this.update(val); } }); diff --git a/tools/generate-imports.mjs b/tools/generate-imports.mjs index 4633a0d09e64408b5b9086c282a887b1637475bd..e9508e15874902ff4b718e1836c62cb0a0c2bafc 100644 --- a/tools/generate-imports.mjs +++ b/tools/generate-imports.mjs @@ -73,7 +73,7 @@ async function generateData() { /** @type {string[]} */ const contentMapAssignments = []; for (const file of files) { - const key = file.replace(/\\/g, '/'); + const key = file.replace(/\\/g, '/'); // TODO #12071 const rawFileContent = await fs.readFile(file, 'utf8'); const value = JSON.stringify(rawFileContent);