From da73178171a85a38d9b739038d189a00fed99f3f Mon Sep 17 00:00:00 2001 From: RahulGautamSingh <rahultesnik@gmail.com> Date: Wed, 20 Oct 2021 10:23:49 +0545 Subject: [PATCH] fix: refactor regex to use re2 (#12216) Co-authored-by: Rhys Arkins <rhys@arkins.net> --- lib/manager/ansible-galaxy/collections.ts | 10 +- lib/manager/ansible-galaxy/extract.ts | 9 +- lib/manager/ansible-galaxy/roles.ts | 7 +- lib/manager/ansible-galaxy/util.ts | 12 +- lib/manager/ansible/extract.ts | 3 +- lib/manager/argocd/util.ts | 9 +- lib/manager/batect-wrapper/extract.ts | 3 +- lib/manager/bazel/extract.ts | 36 +++--- lib/manager/bazel/update.ts | 28 ++--- lib/manager/buildkite/extract.ts | 14 ++- lib/manager/bundler/artifacts.ts | 7 +- lib/manager/bundler/extract.ts | 29 ++--- lib/manager/bundler/locked-version.ts | 2 +- lib/manager/cake/index.ts | 11 +- lib/manager/cargo/artifacts.ts | 3 +- lib/manager/cdnurl/extract.ts | 6 +- lib/manager/circleci/extract.ts | 9 +- lib/manager/cocoapods/artifacts.ts | 5 +- lib/manager/cocoapods/extract.ts | 26 ++--- lib/manager/composer/artifacts.ts | 3 +- lib/manager/composer/extract.ts | 7 +- lib/manager/deps-edn/extract.ts | 5 +- lib/manager/docker-compose/extract.ts | 3 +- lib/manager/dockerfile/extract.ts | 7 +- lib/manager/droneci/extract.ts | 3 +- lib/manager/git-submodules/extract.ts | 11 +- lib/manager/github-actions/extract.ts | 10 +- lib/manager/gitlabci-include/extract.ts | 5 +- lib/manager/gitlabci/extract.ts | 17 ++- lib/manager/gomod/artifacts.ts | 13 ++- lib/manager/gomod/extract.ts | 14 ++- lib/manager/gomod/update.ts | 11 +- .../gradle/deep/gradle-updates-report.ts | 6 +- lib/manager/gradle/shallow/tokenizer.ts | 21 ++-- lib/manager/gradle/shallow/utils.ts | 2 +- lib/manager/helm-values/util.ts | 3 +- lib/manager/helmfile/extract.ts | 3 +- lib/manager/helmv3/update.ts | 2 +- lib/manager/homebrew/extract.ts | 7 +- lib/manager/html/extract.ts | 7 +- lib/manager/jenkins/extract.ts | 8 +- lib/manager/kubernetes/extract.ts | 6 +- lib/manager/kustomize/extract.ts | 6 +- lib/manager/leiningen/extract.ts | 24 ++-- lib/manager/maven/extract.ts | 30 ++--- lib/manager/meteor/extract.ts | 7 +- lib/manager/mix/extract.ts | 8 +- lib/manager/npm/extract/index.ts | 22 ++-- lib/manager/npm/extract/pnpm.ts | 2 +- lib/manager/npm/post-update/index.ts | 7 +- lib/manager/npm/post-update/node-version.ts | 3 +- lib/manager/npm/post-update/rules.ts | 3 +- lib/manager/npm/post-update/yarn.ts | 3 +- .../locked-dependency/dep-constraints.ts | 3 +- .../npm/update/package-version/index.ts | 2 +- lib/manager/nuget/artifacts.ts | 3 +- lib/manager/nuget/extract.ts | 2 +- lib/manager/nuget/util.ts | 3 +- lib/manager/pip-compile/artifacts.ts | 3 +- lib/manager/pip_requirements/artifacts.ts | 3 +- lib/manager/pip_requirements/extract.ts | 17 ++- lib/manager/pip_setup/extract.ts | 5 +- lib/manager/pipenv/extract.ts | 7 +- lib/manager/pre-commit/extract.ts | 4 +- lib/manager/sbt/extract.ts | 110 ++++++++++-------- lib/manager/sbt/update.ts | 3 +- lib/manager/setup-cfg/extract.ts | 11 +- lib/manager/swift/extract.ts | 35 +++--- lib/manager/terraform/extract.ts | 6 +- lib/manager/terraform/lockfile/hash.ts | 2 +- lib/manager/terraform/lockfile/util.ts | 8 +- lib/manager/terraform/modules.ts | 15 ++- lib/manager/terraform/providers.ts | 11 +- lib/manager/terraform/required-providers.ts | 3 +- lib/manager/terraform/required-version.ts | 4 +- lib/manager/terraform/util.ts | 13 ++- lib/manager/terragrunt/extract.ts | 3 +- lib/manager/terragrunt/modules.ts | 15 ++- lib/manager/terragrunt/providers.ts | 6 +- lib/manager/terragrunt/util.ts | 5 +- lib/platform/azure/index.ts | 3 +- lib/platform/bitbucket-server/index.ts | 11 +- lib/platform/bitbucket/index.ts | 13 ++- lib/platform/gitea/utils.ts | 4 +- lib/platform/github/index.ts | 16 ++- lib/platform/github/massage-markdown-links.ts | 5 +- lib/platform/gitlab/index.ts | 17 ++- lib/platform/utils/read-only-issue-body.ts | 6 +- 88 files changed, 519 insertions(+), 376 deletions(-) diff --git a/lib/manager/ansible-galaxy/collections.ts b/lib/manager/ansible-galaxy/collections.ts index 87072e3e34..a15ee60d9f 100644 --- a/lib/manager/ansible-galaxy/collections.ts +++ b/lib/manager/ansible-galaxy/collections.ts @@ -2,6 +2,7 @@ import { GalaxyCollectionDatasource } from '../../datasource/galaxy-collection'; import * as datasourceGitTags from '../../datasource/git-tags'; import * as datasourceGithubTags from '../../datasource/github-tags'; import { SkipReason } from '../../types'; +import { regEx } from '../../util/regex'; import type { PackageDependency } from '../types'; import { blockLineRegEx, @@ -17,7 +18,7 @@ function interpretLine( ): void { const localDependency = dependency; const key = lineMatch[2]; - const value = lineMatch[3].replace(/["']/g, ''); + const value = lineMatch[3].replace(regEx(/["']/g), ''); switch (key) { case 'name': { localDependency.managerData.name = value; @@ -60,10 +61,13 @@ function handleGitDep( } // source definition without version appendix const source = nameMatch.groups.source; - const massagedDepName = nameMatch.groups.depName.replace(/.git$/, ''); + const massagedDepName = nameMatch.groups.depName.replace( + regEx(/.git$/), + '' + ); dep.depName = `${nameMatch.groups.hostname}/${massagedDepName}`; // remove leading `git+` from URLs like `git+https://...` - dep.lookupName = source.replace(/git\+/, ''); + dep.lookupName = source.replace(regEx(/git\+/), ''); // if version is declared using version appendix `<source url>,v1.2.0`, use it if (nameMatch.groups.version) { diff --git a/lib/manager/ansible-galaxy/extract.ts b/lib/manager/ansible-galaxy/extract.ts index fc270adddd..bd010432a5 100644 --- a/lib/manager/ansible-galaxy/extract.ts +++ b/lib/manager/ansible-galaxy/extract.ts @@ -1,4 +1,5 @@ import { logger } from '../../logger'; +import { regEx } from '../../util/regex'; import type { PackageDependency, PackageFile } from '../types'; import { extractCollections } from './collections'; import { extractCollectionsMetaDataFile } from './collections-metadata'; @@ -26,7 +27,7 @@ export default function extractPackageFile( fileName: string ): PackageFile | null { logger.trace('ansible-galaxy.extractPackageFile()'); - const galaxyFileNameRegEx = /galaxy\.ya?ml$/; + const galaxyFileNameRegEx = regEx(/galaxy\.ya?ml$/); const deps: PackageDependency[] = []; const lines = content.split('\n'); @@ -44,10 +45,12 @@ export default function extractPackageFile( }; // find role and collection block lines.forEach((line, index) => { - if (/^collections:/.exec(line)) { + if (regEx(/^collections:/).exec(line)) { + // TODO #12071 positions.collections = index; } - if (/^roles:/.exec(line)) { + if (regEx(/^roles:/).exec(line)) { + // TODO #12071 positions.roles = index; } }); diff --git a/lib/manager/ansible-galaxy/roles.ts b/lib/manager/ansible-galaxy/roles.ts index a1e73e548d..21b3f9646e 100644 --- a/lib/manager/ansible-galaxy/roles.ts +++ b/lib/manager/ansible-galaxy/roles.ts @@ -1,6 +1,7 @@ import { GalaxyDatasource } from '../../datasource/galaxy'; import * as datasourceGitTags from '../../datasource/git-tags'; import { SkipReason } from '../../types'; +import { regEx } from '../../util/regex'; import type { PackageDependency } from '../types'; import { blockLineRegEx, @@ -16,7 +17,7 @@ function interpretLine( ): PackageDependency { const localDependency: PackageDependency = dependency; const key = lineMatch[2]; - const value = lineMatch[3].replace(/["']/g, ''); + const value = lineMatch[3].replace(regEx(/["']/g), ''); switch (key) { case 'name': { localDependency.managerData.name = value; @@ -54,9 +55,9 @@ function finalize(dependency: PackageDependency): boolean { const sourceMatch = nameMatchRegex.exec(source); if (sourceMatch) { dep.datasource = datasourceGitTags.id; - dep.depName = sourceMatch.groups.depName.replace(/.git$/, ''); + dep.depName = sourceMatch.groups.depName.replace(regEx(/.git$/), ''); // remove leading `git+` from URLs like `git+https://...` - dep.lookupName = source.replace(/git\+/, ''); + dep.lookupName = source.replace(regEx(/git\+/), ''); } else if (galaxyDepRegex.exec(source)) { dep.datasource = GalaxyDatasource.id; dep.depName = dep.managerData.src; diff --git a/lib/manager/ansible-galaxy/util.ts b/lib/manager/ansible-galaxy/util.ts index b0b57d19d0..e88be41652 100644 --- a/lib/manager/ansible-galaxy/util.ts +++ b/lib/manager/ansible-galaxy/util.ts @@ -1,8 +1,12 @@ +import { regEx } from '../../util/regex'; + export const newBlockRegEx = /^\s*-\s*((\w+):\s*(.*))$/; export const blockLineRegEx = /^\s*((\w+):\s*(.*))$/; export const galaxyDepRegex = /[\w-]+\.[\w-]+/; export const dependencyRegex = /^dependencies:/; -export const galaxyRegEx = - /^\s+(?<lookupName>[\w.]+):\s*["'](?<version>.+)["']\s*/; -export const nameMatchRegex = - /(?<source>((git\+)?(?:(git|ssh|https?):\/\/)?(.*@)?(?<hostname>[\w.-]+)(?:(:\d+)?\/|:))(?<depName>[\w./-]+)(?:\.git)?)(,(?<version>[\w.]*))?/; +export const galaxyRegEx = regEx( + /^\s+(?<lookupName>[\w.]+):\s*["'](?<version>.+)["']\s*/ +); +export const nameMatchRegex = regEx( + /(?<source>((git\+)?(?:(git|ssh|https?):\/\/)?(.*@)?(?<hostname>[\w.-]+)(?:(:\d+)?\/|:))(?<depName>[\w./-]+)(?:\.git)?)(,(?<version>[\w.]*))?/ +); diff --git a/lib/manager/ansible/extract.ts b/lib/manager/ansible/extract.ts index b97d032fdf..4ee13ef36f 100644 --- a/lib/manager/ansible/extract.ts +++ b/lib/manager/ansible/extract.ts @@ -1,4 +1,5 @@ import { logger } from '../../logger'; +import { regEx } from '../../util/regex'; import * as dockerVersioning from '../../versioning/docker'; import { getDep } from '../dockerfile/extract'; import type { PackageDependency, PackageFile } from '../types'; @@ -8,7 +9,7 @@ export default function extractPackageFile( ): PackageFile | null { logger.trace('ansible.extractPackageFile()'); let deps: PackageDependency[] = []; - const re = /^\s*image:\s*'?"?([^\s'"]+)'?"?\s*$/; + const re = regEx(/^\s*image:\s*'?"?([^\s'"]+)'?"?\s*$/); for (const line of content.split('\n')) { const match = re.exec(line); if (match) { diff --git a/lib/manager/argocd/util.ts b/lib/manager/argocd/util.ts index 13c7146055..31939dc1c8 100644 --- a/lib/manager/argocd/util.ts +++ b/lib/manager/argocd/util.ts @@ -1,4 +1,7 @@ -export const keyValueExtractionRegex = - /^\s*(?<key>[^\s]+):\s+"?(?<value>[^"\s]+)"?\s*$/; +import { regEx } from '../../util/regex'; + +export const keyValueExtractionRegex = regEx( + /^\s*(?<key>[^\s]+):\s+"?(?<value>[^"\s]+)"?\s*$/ +); // looks for `apiVersion: argoproj.io/ -export const fileTestRegex = /\s*apiVersion:\s*argoproj.io\/\s*/; +export const fileTestRegex = regEx(/\s*apiVersion:\s*argoproj.io\/\s*/); diff --git a/lib/manager/batect-wrapper/extract.ts b/lib/manager/batect-wrapper/extract.ts index a4366eac93..3738893207 100644 --- a/lib/manager/batect-wrapper/extract.ts +++ b/lib/manager/batect-wrapper/extract.ts @@ -1,9 +1,10 @@ import { id as githubReleaseDatasource } from '../../datasource/github-releases'; import { logger } from '../../logger'; +import { regEx } from '../../util/regex'; import { id as semverVersioning } from '../../versioning/semver'; import type { PackageDependency, PackageFile } from '../types'; -const VERSION_REGEX = /^\s+VERSION="(.*)"$/m; +const VERSION_REGEX = regEx(/^\s+VERSION="(.*)"$/m); export function extractPackageFile(fileContent: string): PackageFile | null { logger.trace('batect.extractPackageFile()'); diff --git a/lib/manager/bazel/extract.ts b/lib/manager/bazel/extract.ts index 1b0782ef59..123f54d75f 100644 --- a/lib/manager/bazel/extract.ts +++ b/lib/manager/bazel/extract.ts @@ -8,6 +8,7 @@ import * as datasourceGithubTags from '../../datasource/github-tags'; import * as datasourceGo from '../../datasource/go'; import { logger } from '../../logger'; import { SkipReason } from '../../types'; +import { regEx } from '../../util/regex'; import * as dockerVersioning from '../../versioning/docker'; import type { PackageDependency, PackageFile } from '../types'; import type { UrlParsedResult } from './types'; @@ -50,7 +51,7 @@ function parseUrl(urlString: string): UrlParsedResult | null { const lexer = moo.states({ main: { - lineComment: { match: /#.*?$/ }, + lineComment: { match: /#.*?$/ }, // TODO #12070 leftParen: { match: '(' }, rightParen: { match: ')' }, longDoubleQuoted: { @@ -178,48 +179,48 @@ export function extractPackageFile( let digest: string; let repository: string; let registry: string; - let match = /name\s*=\s*"([^"]+)"/.exec(def); + let match = regEx(/name\s*=\s*"([^"]+)"/).exec(def); if (match) { [, depName] = match; } - match = /digest\s*=\s*"([^"]+)"/.exec(def); + match = regEx(/digest\s*=\s*"([^"]+)"/).exec(def); if (match) { [, digest] = match; } - match = /registry\s*=\s*"([^"]+)"/.exec(def); + match = regEx(/registry\s*=\s*"([^"]+)"/).exec(def); if (match) { [, registry] = match; } - match = /repository\s*=\s*"([^"]+)"/.exec(def); + match = regEx(/repository\s*=\s*"([^"]+)"/).exec(def); if (match) { [, repository] = match; } - match = /remote\s*=\s*"([^"]+)"/.exec(def); + match = regEx(/remote\s*=\s*"([^"]+)"/).exec(def); if (match) { [, remote] = match; } - match = /tag\s*=\s*"([^"]+)"/.exec(def); + match = regEx(/tag\s*=\s*"([^"]+)"/).exec(def); if (match) { [, currentValue] = match; } - match = /url\s*=\s*"([^"]+)"/.exec(def); + match = regEx(/url\s*=\s*"([^"]+)"/).exec(def); if (match) { [, url] = match; } - match = /urls\s*=\s*\[\s*"([^\]]+)",?\s*\]/.exec(def); + match = regEx(/urls\s*=\s*\[\s*"([^\]]+)",?\s*\]/).exec(def); if (match) { - const urls = match[1].replace(/\s/g, '').split('","'); + const urls = match[1].replace(regEx(/\s/g), '').split('","'); url = urls.find(parseUrl); } - match = /commit\s*=\s*"([^"]+)"/.exec(def); + match = regEx(/commit\s*=\s*"([^"]+)"/).exec(def); if (match) { [, commit] = match; } - match = /sha256\s*=\s*"([^"]+)"/.exec(def); + match = regEx(/sha256\s*=\s*"([^"]+)"/).exec(def); if (match) { [, sha256] = match; } - match = /importpath\s*=\s*"([^"]+)"/.exec(def); + match = regEx(/importpath\s*=\s*"([^"]+)"/).exec(def); if (match) { [, importpath] = match; } @@ -256,10 +257,9 @@ export function extractPackageFile( dep.datasource = datasourceGo.id; dep.lookupName = importpath; if (remote) { - const remoteMatch = - /https:\/\/github\.com(?:.*\/)(([a-zA-Z]+)([-])?([a-zA-Z]+))/.exec( - remote - ); + const remoteMatch = regEx( + /https:\/\/github\.com(?:.*\/)(([a-zA-Z]+)([-])?([a-zA-Z]+))/ + ).exec(remote); if (remoteMatch && remoteMatch[0].length === remote.length) { dep.lookupName = remote.replace('https://', ''); } else { @@ -282,7 +282,7 @@ export function extractPackageFile( const parsedUrl = parseUrl(url); dep.depName = depName; dep.repo = parsedUrl.repo; - if (/^[a-f0-9]{40}$/i.test(parsedUrl.currentValue)) { + if (regEx(/^[a-f0-9]{40}$/i).test(parsedUrl.currentValue)) { dep.currentDigest = parsedUrl.currentValue; } else { dep.currentValue = parsedUrl.currentValue; diff --git a/lib/manager/bazel/update.ts b/lib/manager/bazel/update.ts index c08beb7df6..2e40e88468 100644 --- a/lib/manager/bazel/update.ts +++ b/lib/manager/bazel/update.ts @@ -12,8 +12,8 @@ function updateWithNewVersion( currentValue: string, newValue: string ): string { - const replaceFrom = currentValue.replace(/^v/, ''); - const replaceTo = newValue.replace(/^v/, ''); + const replaceFrom = currentValue.replace(regEx(/^v/), ''); + const replaceTo = newValue.replace(regEx(/^v/), ''); let newContent = content; do { newContent = newContent.replace(replaceFrom, replaceTo); @@ -22,7 +22,7 @@ function updateWithNewVersion( } function extractUrl(flattened: string): string[] | null { - const urlMatch = /url="(.*?)"/.exec(flattened); + const urlMatch = regEx(/url="(.*?)"/).exec(flattened); if (!urlMatch) { logger.debug('Cannot locate urls in new definition'); return null; @@ -31,16 +31,16 @@ function extractUrl(flattened: string): string[] | null { } function extractUrls(content: string): string[] | null { - const flattened = content.replace(/\n/g, '').replace(/\s/g, ''); - const urlsMatch = /urls?=\[.*?\]/.exec(flattened); + const flattened = content.replace(regEx(/\n/g), '').replace(regEx(/\s/g), ''); + const urlsMatch = regEx(/urls?=\[.*?\]/).exec(flattened); if (!urlsMatch) { return extractUrl(flattened); } const urls = urlsMatch[0] - .replace(/urls?=\[/, '') - .replace(/,?\]$/, '') + .replace(regEx(/urls?=\[/), '') + .replace(regEx(/,?\]$/), '') .split(',') - .map((url) => url.replace(/"/g, '')); + .map((url) => url.replace(regEx(/"/g), '')); return urls; } @@ -83,7 +83,7 @@ async function getHashFromUrls(urls: string[]): Promise<string | null> { } function setNewHash(content: string, hash: string): string { - return content.replace(/(sha256\s*=\s*)"[^"]+"/, `$1"${hash}"`); + return content.replace(regEx(/(sha256\s*=\s*)"[^"]+"/), `$1"${hash}"`); } export async function updateDependency({ @@ -97,19 +97,19 @@ export async function updateDependency({ let newDef: string; if (upgrade.depType === 'container_pull') { newDef = upgrade.managerData.def - .replace(/(tag\s*=\s*)"[^"]+"/, `$1"${upgrade.newValue}"`) - .replace(/(digest\s*=\s*)"[^"]+"/, `$1"${upgrade.newDigest}"`); + .replace(regEx(/(tag\s*=\s*)"[^"]+"/), `$1"${upgrade.newValue}"`) + .replace(regEx(/(digest\s*=\s*)"[^"]+"/), `$1"${upgrade.newDigest}"`); } if ( upgrade.depType === 'git_repository' || upgrade.depType === 'go_repository' ) { newDef = upgrade.managerData.def - .replace(/(tag\s*=\s*)"[^"]+"/, `$1"${upgrade.newValue}"`) - .replace(/(commit\s*=\s*)"[^"]+"/, `$1"${upgrade.newDigest}"`); + .replace(regEx(/(tag\s*=\s*)"[^"]+"/), `$1"${upgrade.newValue}"`) + .replace(regEx(/(commit\s*=\s*)"[^"]+"/), `$1"${upgrade.newDigest}"`); if (upgrade.currentDigest && upgrade.updateType !== 'digest') { newDef = newDef.replace( - /(commit\s*=\s*)"[^"]+".*?\n/, + regEx(/(commit\s*=\s*)"[^"]+".*?\n/), `$1"${upgrade.newDigest}", # ${upgrade.newValue}\n` ); } diff --git a/lib/manager/buildkite/extract.ts b/lib/manager/buildkite/extract.ts index 0dc99d9391..2c4ae344b5 100644 --- a/lib/manager/buildkite/extract.ts +++ b/lib/manager/buildkite/extract.ts @@ -1,6 +1,7 @@ import * as datasourceGithubTags from '../../datasource/github-tags'; import { logger } from '../../logger'; import { SkipReason } from '../../types'; +import { regEx } from '../../util/regex'; import { isVersion } from '../../versioning/semver'; import type { PackageDependency, PackageFile } from '../types'; @@ -13,16 +14,21 @@ export function extractPackageFile(content: string): PackageFile | null { for (let lineNumber = 1; lineNumber <= lines.length; lineNumber += 1) { const lineIdx = lineNumber - 1; const line = lines[lineIdx]; - const pluginsSection = /^(?<pluginsIndent>\s*)(-?\s*)plugins:/.exec(line); + const pluginsSection = regEx( + /^(?<pluginsIndent>\s*)(-?\s*)plugins:/ + ).exec(line); // TODO #12071 if (pluginsSection) { logger.trace(`Matched plugins on line ${lineNumber}`); isPluginsSection = true; pluginsIndent = pluginsSection.groups.pluginsIndent; } else if (isPluginsSection) { logger.debug(`serviceImageLine: "${line}"`); - const { currentIndent } = /^(?<currentIndent>\s*)/.exec(line).groups; - const depLineMatch = - /^\s+(?:-\s+)?(?<depName>[^#]+)#(?<currentValue>[^:]+)/.exec(line); + const { currentIndent } = regEx(/^(?<currentIndent>\s*)/).exec( + line + ).groups; // TODO #12071 + const depLineMatch = regEx( + /^\s+(?:-\s+)?(?<depName>[^#]+)#(?<currentValue>[^:]+)/ + ).exec(line); // TODO #12071 if (currentIndent.length <= pluginsIndent.length) { isPluginsSection = false; pluginsIndent = ''; diff --git a/lib/manager/bundler/artifacts.ts b/lib/manager/bundler/artifacts.ts index e99063850f..f4d4860d0d 100644 --- a/lib/manager/bundler/artifacts.ts +++ b/lib/manager/bundler/artifacts.ts @@ -16,6 +16,7 @@ import { writeLocalFile, } from '../../util/fs'; import { getRepoStatus } from '../../util/git'; +import { regEx } from '../../util/regex'; import { add } from '../../util/sanitize'; import { isValid } from '../../versioning/ruby'; import type { UpdateArtifact, UpdateArtifactsResult } from '../types'; @@ -46,8 +47,8 @@ async function getRubyConstraint( if (rubyVersionFileContent) { logger.debug('Using ruby version specified in .ruby-version'); rubyConstraint = rubyVersionFileContent - .replace(/^ruby-/, '') - .replace(/\n/g, '') + .replace(regEx(/^ruby-/), '') + .replace(regEx(/\n/g), '') .trim(); } } @@ -234,7 +235,7 @@ export async function updateArtifacts( memCache.set('bundlerArtifactsError', BUNDLER_INVALID_CREDENTIALS); throw new Error(BUNDLER_INVALID_CREDENTIALS); } - const resolveMatchRe = new RegExp('\\s+(.*) was resolved to', 'g'); + const resolveMatchRe = regEx('\\s+(.*) was resolved to', 'g'); if (output.match(resolveMatchRe) && !config.isLockFileMaintenance) { logger.debug({ err }, 'Bundler has a resolve error'); const resolveMatches = []; diff --git a/lib/manager/bundler/extract.ts b/lib/manager/bundler/extract.ts index a9cd7ca5fd..19b5fe5c5d 100644 --- a/lib/manager/bundler/extract.ts +++ b/lib/manager/bundler/extract.ts @@ -23,6 +23,7 @@ export async function extractPackageFile( sourceMatch = sourceMatch || regEx(`^source ${delimiter}([^${delimiter}]+)${delimiter}\\s*$`).exec( + // TODO #12071 line ); } @@ -33,13 +34,13 @@ export async function extractPackageFile( for (const delimiter of delimiters) { rubyMatch = rubyMatch || - regEx(`^ruby ${delimiter}([^${delimiter}]+)${delimiter}`).exec(line); + regEx(`^ruby ${delimiter}([^${delimiter}]+)${delimiter}`).exec(line); // TODO #12071 } if (rubyMatch) { res.constraints = { ruby: rubyMatch[1] }; } const gemMatchRegex = - /^\s*gem\s+(['"])(?<depName>[^'"]+)\1(\s*,\s*(?<currentValue>(['"])[^'"]+\5(\s*,\s*\5[^'"]+\5)?))?/; + /^\s*gem\s+(['"])(?<depName>[^'"]+)\1(\s*,\s*(?<currentValue>(['"])[^'"]+\5(\s*,\s*\5[^'"]+\5)?))?/; // TODO #12070 #12071 const gemMatch = gemMatchRegex.exec(line); if (gemMatch) { const dep: PackageDependency = { @@ -48,7 +49,7 @@ export async function extractPackageFile( }; if (gemMatch.groups.currentValue) { const currentValue = gemMatch.groups.currentValue; - dep.currentValue = /\s*,\s*/.test(currentValue) + dep.currentValue = regEx(/\s*,\s*/).test(currentValue) // TODO #12071 ? currentValue : currentValue.slice(1, -1); } else { @@ -59,12 +60,12 @@ export async function extractPackageFile( } res.deps.push(dep); } - const groupMatch = /^group\s+(.*?)\s+do/.exec(line); + const groupMatch = regEx(/^group\s+(.*?)\s+do/).exec(line); // TODO #12071 if (groupMatch) { const depTypes = groupMatch[1] .split(',') .map((group) => group.trim()) - .map((group) => group.replace(/^:/, '')); + .map((group) => group.replace(regEx(/^:/), '')); // TODO #12071 const groupLineNumber = lineNumber; let groupContent = ''; let groupLine = ''; @@ -72,7 +73,7 @@ export async function extractPackageFile( lineNumber += 1; groupLine = lines[lineNumber]; if (groupLine !== 'end') { - groupContent += (groupLine || '').replace(/^ {2}/, '') + '\n'; + groupContent += (groupLine || '').replace(regEx(/^ {2}/), '') + '\n'; // TODO #12071 } } const groupRes = await extractPackageFile(groupContent); @@ -91,7 +92,7 @@ export async function extractPackageFile( } for (const delimiter of delimiters) { const sourceBlockMatch = regEx( - `^source\\s+${delimiter}(.*?)${delimiter}\\s+do` + `^source\\s+${delimiter}(.*?)${delimiter}\\s+do` // TODO #12071 ).exec(line); if (sourceBlockMatch) { const repositoryUrl = sourceBlockMatch[1]; @@ -107,7 +108,7 @@ export async function extractPackageFile( sourceLine = 'end'; } if (sourceLine !== 'end') { - sourceContent += sourceLine.replace(/^ {2}/, '') + '\n'; + sourceContent += sourceLine.replace(regEx(/^ {2}/), '') + '\n'; // TODO #12071 } } const sourceRes = await extractPackageFile(sourceContent); @@ -125,7 +126,7 @@ export async function extractPackageFile( } } } - const platformsMatch = /^platforms\s+(.*?)\s+do/.test(line); + const platformsMatch = regEx(/^platforms\s+(.*?)\s+do/).test(line); // TODO #12071 if (platformsMatch) { const platformsLineNumber = lineNumber; let platformsContent = ''; @@ -134,7 +135,7 @@ export async function extractPackageFile( lineNumber += 1; platformsLine = lines[lineNumber]; if (platformsLine !== 'end') { - platformsContent += platformsLine.replace(/^ {2}/, '') + '\n'; + platformsContent += platformsLine.replace(regEx(/^ {2}/), '') + '\n'; // TODO #12071 } } const platformsRes = await extractPackageFile(platformsContent); @@ -151,7 +152,7 @@ export async function extractPackageFile( ); } } - const ifMatch = /^if\s+(.*?)/.test(line); + const ifMatch = regEx(/^if\s+(.*?)/).test(line); // TODO #12071 if (ifMatch) { const ifLineNumber = lineNumber; let ifContent = ''; @@ -160,7 +161,7 @@ export async function extractPackageFile( lineNumber += 1; ifLine = lines[lineNumber]; if (ifLine !== 'end') { - ifContent += ifLine.replace(/^ {2}/, '') + '\n'; + ifContent += ifLine.replace(regEx(/^ {2}/), '') + '\n'; // TODO #12071 } } const ifRes = await extractPackageFile(ifContent); @@ -194,7 +195,9 @@ export async function extractPackageFile( dep.lockedVersion = lockedDepValue; } } - const bundledWith = /\nBUNDLED WITH\n\s+(.*?)(\n|$)/.exec(lockContent); + const bundledWith = regEx(/\nBUNDLED WITH\n\s+(.*?)(\n|$)/).exec( + lockContent + ); if (bundledWith) { res.constraints = res.constraints || {}; res.constraints.bundler = bundledWith[1]; diff --git a/lib/manager/bundler/locked-version.ts b/lib/manager/bundler/locked-version.ts index 49bec3d29f..ca9e477284 100644 --- a/lib/manager/bundler/locked-version.ts +++ b/lib/manager/bundler/locked-version.ts @@ -1,7 +1,7 @@ import { logger } from '../../logger'; import { isVersion } from '../../versioning/ruby'; -const DEP_REGEX = new RegExp('(?<=\\().*(?=\\))'); +const DEP_REGEX = new RegExp('(?<=\\().*(?=\\))'); // TODO #12070 export function extractLockFileEntries( lockFileContent: string ): Map<string, string> { diff --git a/lib/manager/cake/index.ts b/lib/manager/cake/index.ts index 8f15b921ba..c469a3e29f 100644 --- a/lib/manager/cake/index.ts +++ b/lib/manager/cake/index.ts @@ -2,6 +2,7 @@ import moo from 'moo'; import { ProgrammingLanguage } from '../../constants'; import { id as datasource } from '../../datasource/nuget'; import { SkipReason } from '../../types'; +import { regEx } from '../../util/regex'; import { PackageDependency, PackageFile } from '../types'; export const language = ProgrammingLanguage.NET; @@ -12,13 +13,13 @@ export const defaultConfig = { const lexer = moo.states({ main: { - lineComment: { match: /\/\/.*?$/ }, - multiLineComment: { match: /\/\*[^]*?\*\//, lineBreaks: true }, + lineComment: { match: /\/\/.*?$/ }, // TODO #12070 + multiLineComment: { match: /\/\*[^]*?\*\//, lineBreaks: true }, // TODO #12070 dependency: { - match: /^#(?:addin|tool|module|load|l)\s+(?:nuget|dotnet):.*$/, + match: /^#(?:addin|tool|module|load|l)\s+(?:nuget|dotnet):.*$/, // TODO #12070 }, dependencyQuoted: { - match: /^#(?:addin|tool|module|load|l)\s+"(?:nuget|dotnet):[^"]+"\s*$/, + match: /^#(?:addin|tool|module|load|l)\s+"(?:nuget|dotnet):[^"]+"\s*$/, // TODO #12070 value: (s: string) => s.trim().slice(1, -1), }, unknown: moo.fallback, @@ -27,7 +28,7 @@ const lexer = moo.states({ function parseDependencyLine(line: string): PackageDependency | null { try { - let url = line.replace(/^[^:]*:/, ''); + let url = line.replace(regEx(/^[^:]*:/), ''); const isEmptyHost = url.startsWith('?'); url = isEmptyHost ? `http://localhost/${url}` : url; diff --git a/lib/manager/cargo/artifacts.ts b/lib/manager/cargo/artifacts.ts index 02a3562dc7..6898b9d4b9 100644 --- a/lib/manager/cargo/artifacts.ts +++ b/lib/manager/cargo/artifacts.ts @@ -7,6 +7,7 @@ import { readLocalFile, writeLocalFile, } from '../../util/fs'; +import { regEx } from '../../util/regex'; import type { UpdateArtifact, UpdateArtifactsResult } from '../types'; async function cargoUpdate( @@ -39,7 +40,7 @@ async function cargoUpdate( // by the outer try { } catch {} and processed normally. const msgStart = 'error: There are multiple'; if (err.code === 101 && err.stderr.startsWith(msgStart)) { - cmd = cmd.replace(/ --package.*/, ''); + cmd = cmd.replace(regEx(/ --package.*/), ''); await exec(cmd, execOptions); } else { throw err; // this is caught below diff --git a/lib/manager/cdnurl/extract.ts b/lib/manager/cdnurl/extract.ts index 650ea66067..16df9bf6c3 100644 --- a/lib/manager/cdnurl/extract.ts +++ b/lib/manager/cdnurl/extract.ts @@ -1,8 +1,10 @@ import { CdnJsDatasource } from '../../datasource/cdnjs'; +import { regEx } from '../../util/regex'; import type { PackageDependency, PackageFile } from '../types'; -export const cloudflareUrlRegex = - /\/\/cdnjs\.cloudflare\.com\/ajax\/libs\/(?<depName>[^/]+?)\/(?<currentValue>[^/]+?)\/(?<asset>[-/_.a-zA-Z0-9]+)/; +export const cloudflareUrlRegex = regEx( + /\/\/cdnjs\.cloudflare\.com\/ajax\/libs\/(?<depName>[^/]+?)\/(?<currentValue>[^/]+?)\/(?<asset>[-/_.a-zA-Z0-9]+)/ +); export function extractPackageFile(content: string): PackageFile { const deps: PackageDependency[] = []; diff --git a/lib/manager/circleci/extract.ts b/lib/manager/circleci/extract.ts index 0ffe5ce1ea..5b76e9cd3e 100644 --- a/lib/manager/circleci/extract.ts +++ b/lib/manager/circleci/extract.ts @@ -1,5 +1,6 @@ import { OrbDatasource } from '../../datasource/orb'; import { logger } from '../../logger'; +import { regEx } from '../../util/regex'; import * as npmVersioning from '../../versioning/npm'; import { getDep } from '../dockerfile/extract'; import type { PackageDependency, PackageFile } from '../types'; @@ -10,7 +11,7 @@ export function extractPackageFile(content: string): PackageFile | null { const lines = content.split('\n'); for (let lineNumber = 0; lineNumber < lines.length; lineNumber += 1) { const line = lines[lineNumber]; - const orbs = /^\s*orbs:\s*$/.exec(line); + const orbs = regEx(/^\s*orbs:\s*$/).exec(line); // TODO #12071 if (orbs) { logger.trace(`Matched orbs on line ${lineNumber}`); let foundOrbOrNoop: boolean; @@ -18,14 +19,14 @@ export function extractPackageFile(content: string): PackageFile | null { foundOrbOrNoop = false; const orbLine = lines[lineNumber + 1]; logger.trace(`orbLine: "${orbLine}"`); - const yamlNoop = /^\s*(#|$)/.exec(orbLine); + const yamlNoop = regEx(/^\s*(#|$)/).exec(orbLine); // TODO #12071 if (yamlNoop) { logger.debug('orbNoop'); foundOrbOrNoop = true; lineNumber += 1; continue; // eslint-disable-line no-continue } - const orbMatch = /^\s+([^:]+):\s(.+)$/.exec(orbLine); + const orbMatch = regEx(/^\s+([^:]+):\s(.+)$/).exec(orbLine); // TODO #12071 if (orbMatch) { logger.trace('orbMatch'); foundOrbOrNoop = true; @@ -46,7 +47,7 @@ export function extractPackageFile(content: string): PackageFile | null { } } while (foundOrbOrNoop); } - const match = /^\s*-? image:\s*'?"?([^\s'"]+)'?"?\s*$/.exec(line); + const match = regEx(/^\s*-? image:\s*'?"?([^\s'"]+)'?"?\s*$/).exec(line); // TODO #12071 if (match) { const currentFrom = match[1]; const dep = getDep(currentFrom); diff --git a/lib/manager/cocoapods/artifacts.ts b/lib/manager/cocoapods/artifacts.ts index 247eea7dda..3fc124fa06 100644 --- a/lib/manager/cocoapods/artifacts.ts +++ b/lib/manager/cocoapods/artifacts.ts @@ -10,9 +10,10 @@ import { writeLocalFile, } from '../../util/fs'; import { getRepoStatus } from '../../util/git'; +import { regEx } from '../../util/regex'; import type { UpdateArtifact, UpdateArtifactsResult } from '../types'; -const pluginRegex = /^\s*plugin\s*(['"])(?<plugin>[^'"]+)\1/; +const pluginRegex = /^\s*plugin\s*(['"])(?<plugin>[^'"]+)\1/; // TODO #12070 function getPluginCommands(content: string): string[] { const result = new Set<string>(); @@ -62,7 +63,7 @@ export async function updateArtifacts({ return null; } - const match = new RegExp(/^COCOAPODS: (?<cocoapodsVersion>.*)$/m).exec( + const match = regEx(/^COCOAPODS: (?<cocoapodsVersion>.*)$/m).exec( existingLockFileContent ); const tagConstraint = match?.groups?.cocoapodsVersion ?? null; diff --git a/lib/manager/cocoapods/extract.ts b/lib/manager/cocoapods/extract.ts index 9535e783fc..b170cd24f1 100644 --- a/lib/manager/cocoapods/extract.ts +++ b/lib/manager/cocoapods/extract.ts @@ -5,16 +5,17 @@ import * as datasourcePod from '../../datasource/pod'; import { logger } from '../../logger'; import { SkipReason } from '../../types'; import { getSiblingFileName, localPathExists } from '../../util/fs'; +import { regEx } from '../../util/regex'; import type { PackageDependency, PackageFile } from '../types'; import type { ParsedLine } from './types'; const regexMappings = [ - /^\s*pod\s+(['"])(?<spec>[^'"/]+)(\/(?<subspec>[^'"]+))?\1/, - /^\s*pod\s+(['"])[^'"]+\1\s*,\s*(['"])(?<currentValue>[^'"]+)\2\s*$/, - /,\s*:git\s*=>\s*(['"])(?<git>[^'"]+)\1/, - /,\s*:tag\s*=>\s*(['"])(?<tag>[^'"]+)\1/, - /,\s*:path\s*=>\s*(['"])(?<path>[^'"]+)\1/, - /^\s*source\s*(['"])(?<source>[^'"]+)\1/, + /^\s*pod\s+(['"])(?<spec>[^'"/]+)(\/(?<subspec>[^'"]+))?\1/, // TODO #12070 + /^\s*pod\s+(['"])[^'"]+\1\s*,\s*(['"])(?<currentValue>[^'"]+)\2\s*$/, // TODO #12070 + /,\s*:git\s*=>\s*(['"])(?<git>[^'"]+)\1/, // TODO #12070 + /,\s*:tag\s*=>\s*(['"])(?<tag>[^'"]+)\1/, // TODO #12070 + /,\s*:path\s*=>\s*(['"])(?<path>[^'"]+)\1/, // TODO #12070 + /^\s*source\s*(['"])(?<source>[^'"]+)\1/, // TODO #12070 ]; export function parseLine(line: string): ParsedLine { @@ -23,7 +24,7 @@ export function parseLine(line: string): ParsedLine { return result; } for (const regex of Object.values(regexMappings)) { - const match = regex.exec(line.replace(/#.*$/, '')); + const match = regex.exec(line.replace(regEx(/#.*$/), '')); // TODO #12071 if (match?.groups) { result = { ...result, ...match.groups }; } @@ -50,10 +51,9 @@ export function parseLine(line: string): ParsedLine { export function gitDep(parsedLine: ParsedLine): PackageDependency | null { const { depName, git, tag } = parsedLine; - const platformMatch = - /[@/](?<platform>github|gitlab)\.com[:/](?<account>[^/]+)\/(?<repo>[^/]+)/.exec( - git - ); + const platformMatch = regEx( + /[@/](?<platform>github|gitlab)\.com[:/](?<account>[^/]+)\/(?<repo>[^/]+)/ + ).exec(git); if (platformMatch) { const { account, repo, platform } = platformMatch?.groups || {}; @@ -65,7 +65,7 @@ export function gitDep(parsedLine: ParsedLine): PackageDependency | null { return { datasource, depName, - lookupName: `${account}/${repo.replace(/\.git$/, '')}`, + lookupName: `${account}/${repo.replace(regEx(/\.git$/), '')}`, currentValue: tag, }; } @@ -103,7 +103,7 @@ export async function extractPackageFile( }: ParsedLine = parsedLine; if (source) { - registryUrls.push(source.replace(/\/*$/, '')); + registryUrls.push(source.replace(regEx(/\/*$/), '')); // TODO #12071 } if (depName) { diff --git a/lib/manager/composer/artifacts.ts b/lib/manager/composer/artifacts.ts index 0506e26c0e..f4493ab28f 100644 --- a/lib/manager/composer/artifacts.ts +++ b/lib/manager/composer/artifacts.ts @@ -19,6 +19,7 @@ import { } from '../../util/fs'; import { getRepoStatus } from '../../util/git'; import * as hostRules from '../../util/host-rules'; +import { regEx } from '../../util/regex'; import type { UpdateArtifact, UpdateArtifactsResult } from '../types'; import type { AuthJson } from './types'; import { @@ -80,7 +81,7 @@ export async function updateArtifacts({ }: UpdateArtifact): Promise<UpdateArtifactsResult[] | null> { logger.debug(`composer.updateArtifacts(${packageFileName})`); - const lockFileName = packageFileName.replace(/\.json$/, '.lock'); + const lockFileName = packageFileName.replace(regEx(/\.json$/), '.lock'); const existingLockFileContent = await readLocalFile(lockFileName, 'utf8'); if (!existingLockFileContent) { logger.debug('No composer.lock found'); diff --git a/lib/manager/composer/extract.ts b/lib/manager/composer/extract.ts index e651bd9d81..f12b8b4ff6 100644 --- a/lib/manager/composer/extract.ts +++ b/lib/manager/composer/extract.ts @@ -4,6 +4,7 @@ import * as datasourcePackagist from '../../datasource/packagist'; import { logger } from '../../logger'; import { SkipReason } from '../../types'; import { readLocalFile } from '../../util/fs'; +import { regEx } from '../../util/regex'; import { api as semverComposer } from '../../versioning/composer'; import type { PackageDependency, PackageFile } from '../types'; import type { @@ -21,7 +22,7 @@ import type { * See https://github.com/composer/composer/blob/750a92b4b7aecda0e5b2f9b963f1cb1421900675/src/Composer/Repository/ComposerRepository.php#L815 */ function transformRegUrl(url: string): string { - return url.replace(/(\/packages\.json)$/, ''); + return url.replace(regEx(/(\/packages\.json)$/), ''); // TODO #12071 } /** @@ -94,7 +95,7 @@ export async function extractPackageFile( const res: PackageFile = { deps: [] }; // handle lockfile - const lockfilePath = fileName.replace(/\.json$/, '.lock'); + const lockfilePath = fileName.replace(regEx(/\.json$/), '.lock'); const lockContents = await readLocalFile(lockfilePath, 'utf8'); let lockParsed: ComposerLock; if (lockContents) { @@ -163,7 +164,7 @@ export async function extractPackageFile( (item) => item.name === dep.depName ); if (lockedDep && semverComposer.isVersion(lockedDep.version)) { - dep.lockedVersion = lockedDep.version.replace(/^v/i, ''); + dep.lockedVersion = lockedDep.version.replace(regEx(/^v/i), ''); // TODO #12071 } } deps.push(dep); diff --git a/lib/manager/deps-edn/extract.ts b/lib/manager/deps-edn/extract.ts index 76aaadfacc..af43268cdd 100644 --- a/lib/manager/deps-edn/extract.ts +++ b/lib/manager/deps-edn/extract.ts @@ -1,11 +1,14 @@ import { ClojureDatasource } from '../../datasource/clojure'; +import { regEx } from '../../util/regex'; import { expandDepName } from '../leiningen/extract'; import type { PackageDependency, PackageFile } from '../types'; export function extractPackageFile(content: string): PackageFile { const deps: PackageDependency[] = []; - const regex = /([^{\s,]*)[\s,]*{[\s,]*:mvn\/version[\s,]+"([^"]+)"[\s,]*}/; + const regex = regEx( + /([^{\s,]*)[\s,]*{[\s,]*:mvn\/version[\s,]+"([^"]+)"[\s,]*}/ + ); let rest = content; let match = regex.exec(rest); let offset = 0; diff --git a/lib/manager/docker-compose/extract.ts b/lib/manager/docker-compose/extract.ts index 5e17f93000..ce5e937300 100644 --- a/lib/manager/docker-compose/extract.ts +++ b/lib/manager/docker-compose/extract.ts @@ -1,6 +1,7 @@ import is from '@sindresorhus/is'; import { load } from 'js-yaml'; import { logger } from '../../logger'; +import { regEx } from '../../util/regex'; import { getDep } from '../dockerfile/extract'; import type { PackageFile } from '../types'; import type { DockerComposeConfig } from './types'; @@ -56,7 +57,7 @@ export function extractPackageFile( return null; } try { - const lineMapper = new LineMapper(content, /^\s*image:/); + const lineMapper = new LineMapper(content, regEx(/^\s*image:/)); // docker-compose v1 places the services at the top level, // docker-compose v2+ places the services within a 'services' key diff --git a/lib/manager/dockerfile/extract.ts b/lib/manager/dockerfile/extract.ts index 4a0b6f11ec..b792195379 100644 --- a/lib/manager/dockerfile/extract.ts +++ b/lib/manager/dockerfile/extract.ts @@ -2,6 +2,7 @@ import is from '@sindresorhus/is'; import * as datasourceDocker from '../../datasource/docker'; import { logger } from '../../logger'; import { SkipReason } from '../../types'; +import { regEx } from '../../util/regex'; import * as ubuntuVersioning from '../../versioning/ubuntu'; import type { PackageDependency, PackageFile } from '../types'; @@ -32,7 +33,7 @@ export function splitImageParts(currentFrom: string): PackageDependency { return dep; } -const quayRegex = /^quay\.io(?::[1-9][0-9]{0,4})?/i; +const quayRegex = regEx(/^quay\.io(?::[1-9][0-9]{0,4})?/i); export function getDep( currentFrom: string, @@ -89,7 +90,7 @@ export function extractPackageFile(content: string): PackageFile | null { const stageNames: string[] = []; const fromMatches = content.matchAll( - /^[ \t]*FROM(?:\\\r?\n| |\t|#.*?\r?\n|[ \t]--[a-z]+=\w+?)*[ \t](?<image>\S+)(?:(?:\\\r?\n| |\t|#.*\r?\n)+as[ \t]+(?<name>\S+))?/gim + /^[ \t]*FROM(?:\\\r?\n| |\t|#.*?\r?\n|[ \t]--[a-z]+=\w+?)*[ \t](?<image>\S+)(?:(?:\\\r?\n| |\t|#.*\r?\n)+as[ \t]+(?<name>\S+))?/gim // TODO #12070 ); for (const fromMatch of fromMatches) { @@ -116,7 +117,7 @@ export function extractPackageFile(content: string): PackageFile | null { } const copyFromMatches = content.matchAll( - /^[ \t]*COPY(?:\\\r?\n| |\t|#.*\r?\n|[ \t]--[a-z]+=\w+?)*[ \t]--from=(?<image>\S+)/gim + /^[ \t]*COPY(?:\\\r?\n| |\t|#.*\r?\n|[ \t]--[a-z]+=\w+?)*[ \t]--from=(?<image>\S+)/gim // TODO #12070 ); for (const copyFromMatch of copyFromMatches) { diff --git a/lib/manager/droneci/extract.ts b/lib/manager/droneci/extract.ts index 7a8a9ecbcb..b02dffd55c 100644 --- a/lib/manager/droneci/extract.ts +++ b/lib/manager/droneci/extract.ts @@ -1,4 +1,5 @@ import { logger } from '../../logger'; +import { regEx } from '../../util/regex'; import { getDep } from '../dockerfile/extract'; import type { PackageDependency, PackageFile } from '../types'; @@ -8,7 +9,7 @@ export function extractPackageFile(content: string): PackageFile | null { const lines = content.split('\n'); for (let lineNumber = 0; lineNumber < lines.length; lineNumber += 1) { const line = lines[lineNumber]; - const match = /^\s* image:\s*'?"?([^\s'"]+)'?"?\s*$/.exec(line); + const match = regEx(/^\s* image:\s*'?"?([^\s'"]+)'?"?\s*$/).exec(line); // TODO #12071 if (match) { const currentFrom = match[1]; const dep = getDep(currentFrom); diff --git a/lib/manager/git-submodules/extract.ts b/lib/manager/git-submodules/extract.ts index b5083af836..ae09c10ecf 100644 --- a/lib/manager/git-submodules/extract.ts +++ b/lib/manager/git-submodules/extract.ts @@ -6,6 +6,7 @@ import * as datasourceGitRefs from '../../datasource/git-refs'; import { logger } from '../../logger'; import { simpleGitConfig } from '../../util/git/config'; import { getHttpUrl, getRemoteUrlWithToken } from '../../util/git/url'; +import { regEx } from '../../util/regex'; import type { ExtractConfig, PackageFile } from '../types'; import { GitModule } from './types'; @@ -32,7 +33,7 @@ async function getUrl( return URL.resolve(`${remoteUrl}/`, path); } -const headRefRe = /ref: refs\/heads\/(?<branch>\w+)\s/; +const headRefRe = regEx(/ref: refs\/heads\/(?<branch>\w+)\s/); async function getDefaultBranch(subModuleUrl: string): Promise<string> { const val = await Git().listRemote(['--symref', subModuleUrl, 'HEAD']); @@ -71,11 +72,11 @@ async function getModules( ])) ?? /* istanbul ignore next: should never happen */ '' ) .trim() - .split(/\n/) + .split(regEx(/\n/)) .filter((s) => !!s); for (const line of modules) { - const [, name, path] = line.split(/submodule\.(.+?)\.path\s(.+)/); + const [, name, path] = line.split(regEx(/submodule\.(.+?)\.path\s(.+)/)); // TODO #12071 res.push({ name, path }); } } catch (err) /* istanbul ignore next */ { @@ -104,8 +105,8 @@ export default async function extractPackageFile( try { const [currentDigest] = (await git.subModule(['status', path])) .trim() - .replace(/^[-+]/, '') - .split(/\s/); + .replace(regEx(/^[-+]/), '') // TODO #12071 + .split(regEx(/\s/)); // TODO #12071 const subModuleUrl = await getUrl(git, gitModulesPath, name); // hostRules only understands HTTP URLs // Find HTTP URL, then apply token diff --git a/lib/manager/github-actions/extract.ts b/lib/manager/github-actions/extract.ts index cea79172fb..d5a7bbd234 100644 --- a/lib/manager/github-actions/extract.ts +++ b/lib/manager/github-actions/extract.ts @@ -1,16 +1,18 @@ import * as githubTagsDatasource from '../../datasource/github-tags'; import { logger } from '../../logger'; import { SkipReason } from '../../types'; +import { regEx } from '../../util/regex'; import * as dockerVersioning from '../../versioning/docker'; import { getDep } from '../dockerfile/extract'; import type { PackageDependency, PackageFile } from '../types'; -const dockerRe = /^\s+uses: docker:\/\/([^"]+)\s*$/; -const actionRe = - /^\s+-?\s+?uses: (?<replaceString>(?<depName>[\w-]+\/[\w-]+)(?<path>\/.*)?@(?<currentValue>.+?)(?: # renovate: tag=(?<tag>.+?))?)\s*?$/; +const dockerRe = regEx(/^\s+uses: docker:\/\/([^"]+)\s*$/); +const actionRe = regEx( + /^\s+-?\s+?uses: (?<replaceString>(?<depName>[\w-]+\/[\w-]+)(?<path>\/.*)?@(?<currentValue>.+?)(?: # renovate: tag=(?<tag>.+?))?)\s*?$/ +); // SHA1 or SHA256, see https://github.blog/2020-10-19-git-2-29-released/ -const shaRe = /^[a-z0-9]{40}|[a-z0-9]{64}$/; +const shaRe = regEx(/^[a-z0-9]{40}|[a-z0-9]{64}$/); export function extractPackageFile(content: string): PackageFile | null { logger.trace('github-actions.extractPackageFile()'); diff --git a/lib/manager/gitlabci-include/extract.ts b/lib/manager/gitlabci-include/extract.ts index 63e8921b5b..cd5c5a7392 100644 --- a/lib/manager/gitlabci-include/extract.ts +++ b/lib/manager/gitlabci-include/extract.ts @@ -3,6 +3,7 @@ import { load } from 'js-yaml'; import * as datasourceGitlabTags from '../../datasource/gitlab-tags'; import { logger } from '../../logger'; import { SkipReason } from '../../types'; +import { regEx } from '../../util/regex'; import { replaceReferenceTags } from '../gitlabci/utils'; import type { ExtractConfig, PackageDependency, PackageFile } from '../types'; @@ -45,7 +46,9 @@ export function extractPackageFile( if (includeObj?.file && includeObj.project) { const dep = extractDepFromIncludeFile(includeObj); if (config.endpoint) { - dep.registryUrls = [config.endpoint.replace(/\/api\/v4\/?/, '')]; + dep.registryUrls = [ + config.endpoint.replace(regEx(/\/api\/v4\/?/), ''), + ]; // TODO #12071 } deps.push(dep); } diff --git a/lib/manager/gitlabci/extract.ts b/lib/manager/gitlabci/extract.ts index 3ec54aff72..2d0fee6ce6 100644 --- a/lib/manager/gitlabci/extract.ts +++ b/lib/manager/gitlabci/extract.ts @@ -7,13 +7,12 @@ import type { ExtractConfig, PackageDependency, PackageFile } from '../types'; import type { GitlabPipeline } from './types'; import { replaceReferenceTags } from './utils'; -const commentsRe = /^\s*#/; -const whitespaceRe = /^(?<whitespace>\s*)/; +const commentsRe = /^\s*#/; // TODO #12070 +const whitespaceRe = /^(?<whitespace>\s*)/; // TODO #12070 const imageRe = - /^(?<whitespace>\s*)image:(?:\s+['"]?(?<image>[^\s'"]+)['"]?)?\s*$/; -const nameRe = /^\s*name:\s+['"]?(?<depName>[^\s'"]+)['"]?\s*$/; -const serviceRe = /^\s*-\s*(?:name:\s+)?['"]?(?<depName>[^\s'"]+)['"]?\s*$/; - + /^(?<whitespace>\s*)image:(?:\s+['"]?(?<image>[^\s'"]+)['"]?)?\s*$/; // TODO #12070 +const nameRe = /^\s*name:\s+['"]?(?<depName>[^\s'"]+)['"]?\s*$/; // TODO #12070 +const serviceRe = /^\s*-\s*(?:name:\s+)?['"]?(?<depName>[^\s'"]+)['"]?\s*$/; // TODO #12070 function skipCommentLines( lines: string[], lineNumber: number @@ -62,7 +61,7 @@ export function extractPackageFile(content: string): PackageFile | null { } } } - const services = /^\s*services:\s*$/.test(line); + const services = /^\s*services:\s*$/.test(line); // TODO #12071 #12070 if (services) { logger.trace(`Matched services on line ${lineNumber}`); let foundImage: boolean; @@ -121,7 +120,7 @@ export async function extractAllPackageFiles( if (is.array(doc?.include)) { for (const includeObj of doc.include) { if (is.string(includeObj.local)) { - const fileObj = includeObj.local.replace(/^\//, ''); + const fileObj = includeObj.local.replace(/^\//, ''); // TODO #12071 #12070 if (!seen.has(fileObj)) { seen.add(fileObj); filesToExamine.push(fileObj); @@ -129,7 +128,7 @@ export async function extractAllPackageFiles( } } } else if (is.string(doc?.include)) { - const fileObj = doc.include.replace(/^\//, ''); + const fileObj = doc.include.replace(/^\//, ''); // TODO #12071 #12070 if (!seen.has(fileObj)) { seen.add(fileObj); filesToExamine.push(fileObj); diff --git a/lib/manager/gomod/artifacts.ts b/lib/manager/gomod/artifacts.ts index a4dc7a33b8..9b6f08de39 100644 --- a/lib/manager/gomod/artifacts.ts +++ b/lib/manager/gomod/artifacts.ts @@ -9,6 +9,7 @@ import { ExecOptions, exec } from '../../util/exec'; import { ensureCacheDir, readLocalFile, writeLocalFile } from '../../util/fs'; import { getRepoStatus } from '../../util/git'; import { find } from '../../util/host-rules'; +import { regEx } from '../../util/regex'; import { isValid } from '../../versioning/semver'; import type { PackageDependency, @@ -48,10 +49,10 @@ function getUpdateImportPathCmds( if (gomodModCompatibility) { if ( gomodModCompatibility.startsWith('v') && - isValid(gomodModCompatibility.replace(/^v/, '')) + isValid(gomodModCompatibility.replace(regEx(/^v/), '')) ) { installMarwanModArgs = installMarwanModArgs.replace( - /@latest$/, + regEx(/@latest$/), `@${gomodModCompatibility}` ); } else { @@ -76,7 +77,7 @@ function useModcacherw(goVersion: string): boolean { return true; } - const [, majorPart, minorPart] = /(\d+)\.(\d+)/.exec(goVersion) ?? []; + const [, majorPart, minorPart] = regEx(/(\d+)\.(\d+)/).exec(goVersion) ?? []; const [major, minor] = [majorPart, minorPart].map((x) => parseInt(x, 10)); return ( @@ -94,7 +95,7 @@ export async function updateArtifacts({ }: UpdateArtifact): Promise<UpdateArtifactsResult[] | null> { logger.debug(`gomod.updateArtifacts(${goModFileName})`); - const sumFileName = goModFileName.replace(/\.mod$/, '.sum'); + const sumFileName = goModFileName.replace(regEx(/\.mod$/), '.sum'); const existingGoSumContent = await readLocalFile(sumFileName); if (!existingGoSumContent) { logger.debug('No go.sum found'); @@ -107,7 +108,7 @@ export async function updateArtifacts({ try { const massagedGoMod = newGoModContent.replace( - /\n(replace\s+[^\s]+\s+=>\s+\.\.\/.*)/g, + regEx(/\n(replace\s+[^\s]+\s+=>\s+\.\.\/.*)/g), '\n// renovate-replace $1' ); if (massagedGoMod !== newGoModContent) { @@ -237,7 +238,7 @@ export async function updateArtifacts({ const finalGoModContent = ( await readLocalFile(goModFileName, 'utf8') - ).replace(/\/\/ renovate-replace /g, ''); + ).replace(regEx(/\/\/ renovate-replace /g), ''); if (finalGoModContent !== newGoModContent) { logger.debug('Found updated go.mod after go.sum update'); res.push({ diff --git a/lib/manager/gomod/extract.ts b/lib/manager/gomod/extract.ts index 74e3482ac2..beaeed66d1 100644 --- a/lib/manager/gomod/extract.ts +++ b/lib/manager/gomod/extract.ts @@ -2,6 +2,7 @@ import { validRange } from 'semver'; import * as datasourceGo from '../../datasource/go'; import { logger } from '../../logger'; import { SkipReason } from '../../types'; +import { regEx } from '../../util/regex'; import { isVersion } from '../../versioning/semver'; import type { PackageDependency, PackageFile } from '../types'; @@ -12,7 +13,7 @@ function getDep( ): PackageDependency { const [, , currentValue] = match; let [, depName] = match; - depName = depName.replace(/"/g, ''); + depName = depName.replace(regEx(/"/g), ''); const dep: PackageDependency = { managerData: { lineNumber, @@ -26,7 +27,7 @@ function getDep( } else { dep.skipReason = SkipReason.UnsupportedVersion; } - const digestMatch = /v0\.0.0-\d{14}-([a-f0-9]{12})/.exec(currentValue); + const digestMatch = regEx(/v0\.0.0-\d{14}-([a-f0-9]{12})/).exec(currentValue); if (digestMatch) { [, dep.currentDigest] = digestMatch; dep.digestOneAndOnly = true; @@ -45,13 +46,14 @@ export function extractPackageFile(content: string): PackageFile | null { if (line.startsWith('go ') && validRange(line.replace('go ', ''))) { constraints.go = line.replace('go ', '^'); } - const replaceMatch = - /^replace\s+[^\s]+[\s]+[=][>]\s+([^\s]+)\s+([^\s]+)/.exec(line); + const replaceMatch = regEx( + /^replace\s+[^\s]+[\s]+[=][>]\s+([^\s]+)\s+([^\s]+)/ + ).exec(line); // TODO #12071 if (replaceMatch) { const dep = getDep(lineNumber, replaceMatch, 'replace'); deps.push(dep); } - const requireMatch = /^require\s+([^\s]+)\s+([^\s]+)/.exec(line); + const requireMatch = regEx(/^require\s+([^\s]+)\s+([^\s]+)/).exec(line); // TODO #12071 if (requireMatch && !line.endsWith('// indirect')) { logger.trace({ lineNumber }, `require line: "${line}"`); const dep = getDep(lineNumber, requireMatch, 'require'); @@ -62,7 +64,7 @@ export function extractPackageFile(content: string): PackageFile | null { do { lineNumber += 1; line = lines[lineNumber]; - const multiMatch = /^\s+([^\s]+)\s+([^\s]+)/.exec(line); + const multiMatch = regEx(/^\s+([^\s]+)\s+([^\s]+)/).exec(line); // TODO #12071 logger.trace(`reqLine: "${line}"`); if (multiMatch && !line.endsWith('// indirect')) { logger.trace({ lineNumber }, `require line: "${line}"`); diff --git a/lib/manager/gomod/update.ts b/lib/manager/gomod/update.ts index eef2923c62..49aa13d185 100644 --- a/lib/manager/gomod/update.ts +++ b/lib/manager/gomod/update.ts @@ -1,10 +1,11 @@ import { logger } from '../../logger'; +import { regEx } from '../../util/regex'; import type { UpdateDependencyConfig } from '../types'; function getDepNameWithNoVersion(depName: string): string { let depNameNoVersion = depName.split('/').slice(0, 3).join('/'); if (depNameNoVersion.startsWith('gopkg.in')) { - depNameNoVersion = depNameNoVersion.replace(/\.v\d+$/, ''); + depNameNoVersion = depNameNoVersion.replace(regEx(/\.v\d+$/), ''); } return depNameNoVersion; } @@ -31,14 +32,14 @@ export function updateDependency({ } let updateLineExp: RegExp; if (depType === 'replace') { - updateLineExp = new RegExp( + updateLineExp = regEx( /^(replace\s+[^\s]+[\s]+[=][>]+\s+)([^\s]+\s+)([^\s]+)/ ); } else if (depType === 'require') { if (upgrade.managerData.multiLine) { - updateLineExp = new RegExp(/^(\s+[^\s]+)(\s+)([^\s]+)/); + updateLineExp = regEx(/^(\s+[^\s]+)(\s+)([^\s]+)/); } else { - updateLineExp = new RegExp(/^(require\s+[^\s]+)(\s+)([^\s]+)/); + updateLineExp = regEx(/^(require\s+[^\s]+)(\s+)([^\s]+)/); } } if (updateLineExp && !updateLineExp.test(lineToChange)) { @@ -86,7 +87,7 @@ export function updateDependency({ // Replace version const [oldV] = upgrade.currentValue.split('.'); newLine = newLine.replace( - new RegExp(`/${oldV}(\\s+)`), + regEx(`/${oldV}(\\s+)`), `/v${upgrade.newMajor}$1` ); } diff --git a/lib/manager/gradle/deep/gradle-updates-report.ts b/lib/manager/gradle/deep/gradle-updates-report.ts index 917caf1e67..59ec47b264 100644 --- a/lib/manager/gradle/deep/gradle-updates-report.ts +++ b/lib/manager/gradle/deep/gradle-updates-report.ts @@ -6,6 +6,7 @@ import { readLocalFile, writeLocalFile, } from '../../../util/fs'; +import { regEx } from '../../../util/regex'; import type { BuildDependency, GradleDependencyWithRepos, @@ -144,11 +145,12 @@ export async function extractDependenciesFromUpdatesReport( if (depName.endsWith('_%%')) { return { ...dep, - depName: depName.replace(/_%%/, ''), + depName: depName.replace(regEx(/_%%/), ''), // TODO #12071 datasource: datasourceSbtPackage.id, }; } - if (/^%.*%$/.test(currentValue)) { + if (regEx(/^%.*%$/).test(currentValue)) { + // TODO #12071 return { ...dep, skipReason: 'version-placeholder' }; } return dep; diff --git a/lib/manager/gradle/shallow/tokenizer.ts b/lib/manager/gradle/shallow/tokenizer.ts index 73a698bcd2..728fcbe2a8 100644 --- a/lib/manager/gradle/shallow/tokenizer.ts +++ b/lib/manager/gradle/shallow/tokenizer.ts @@ -1,8 +1,9 @@ import moo from 'moo'; +import { regEx } from '../../../util/regex'; import { TokenType } from './common'; import type { StringInterpolation, Token } from './types'; -const escapedCharRegex = /\\['"bfnrt\\]/; +const escapedCharRegex = /\\['"bfnrt\\]/; // TODO #12070 const escapedChars = { [TokenType.EscapedChar]: { match: escapedCharRegex, @@ -23,17 +24,17 @@ const escapedChars = { const lexer = moo.states({ // Top-level Groovy lexemes main: { - [TokenType.LineComment]: { match: /\/\/.*?$/ }, - [TokenType.MultiComment]: { match: /\/\*[^]*?\*\//, lineBreaks: true }, - [TokenType.Newline]: { match: /\r?\n/, lineBreaks: true }, - [TokenType.Space]: { match: /[ \t\r]+/ }, + [TokenType.LineComment]: { match: /\/\/.*?$/ }, // TODO #12070 + [TokenType.MultiComment]: { match: /\/\*[^]*?\*\//, lineBreaks: true }, // TODO #12070 + [TokenType.Newline]: { match: /\r?\n/, lineBreaks: true }, // TODO #12070 + [TokenType.Space]: { match: /[ \t\r]+/ }, // TODO #12070 [TokenType.Semicolon]: ';', [TokenType.Colon]: ':', [TokenType.Dot]: '.', [TokenType.Comma]: ',', - [TokenType.Operator]: /(?:==|\+=?|-=?|\/=?|\*\*?|\.+|:)/, + [TokenType.Operator]: /(?:==|\+=?|-=?|\/=?|\*\*?|\.+|:)/, // TODO #12070 [TokenType.Assignment]: '=', - [TokenType.Word]: { match: /[a-zA-Z$_][a-zA-Z0-9$_]+/ }, + [TokenType.Word]: { match: /[a-zA-Z$_][a-zA-Z0-9$_]+/ }, // TODO #12070 [TokenType.LeftParen]: { match: '(' }, [TokenType.RightParen]: { match: ')' }, [TokenType.LeftBracket]: { match: '[' }, @@ -85,12 +86,12 @@ const lexer = moo.states({ variable: { // Supported: ${foo}, $foo, ${ foo.bar.baz }, $foo.bar.baz match: - /\${\s*[a-zA-Z_][a-zA-Z0-9_]*(?:\s*\.\s*[a-zA-Z_][a-zA-Z0-9_]*)*\s*}|\$[a-zA-Z_][a-zA-Z0-9_]*(?:\.[a-zA-Z_][a-zA-Z0-9_]*)*/, + /\${\s*[a-zA-Z_][a-zA-Z0-9_]*(?:\s*\.\s*[a-zA-Z_][a-zA-Z0-9_]*)*\s*}|\$[a-zA-Z_][a-zA-Z0-9_]*(?:\.[a-zA-Z_][a-zA-Z0-9_]*)*/, // TODO #12070 value: (x: string): string => - x.replace(/^\${?\s*/, '').replace(/\s*}$/, ''), + x.replace(regEx(/^\${?\s*/), '').replace(regEx(/\s*}$/), ''), }, [TokenType.IgnoredInterpolationStart]: { - match: /\${/, + match: /\${/, // TODO #12070 push: TokenType.IgnoredInterpolationStart, }, [TokenType.Chars]: moo.fallback, diff --git a/lib/manager/gradle/shallow/utils.ts b/lib/manager/gradle/shallow/utils.ts index e1da8b2a79..c9c2a36a79 100644 --- a/lib/manager/gradle/shallow/utils.ts +++ b/lib/manager/gradle/shallow/utils.ts @@ -111,7 +111,7 @@ export function isTOMLFile(path: string): boolean { } export function toAbsolutePath(packageFile: string): string { - return upath.join(packageFile.replace(/^[/\\]*/, '/')); + return upath.join(packageFile.replace(regEx(/^[/\\]*/), '/')); } export function reorderFiles(packageFiles: string[]): string[] { diff --git a/lib/manager/helm-values/util.ts b/lib/manager/helm-values/util.ts index f1707aef7b..d435b451c3 100644 --- a/lib/manager/helm-values/util.ts +++ b/lib/manager/helm-values/util.ts @@ -1,7 +1,8 @@ import { hasKey } from '../../util/object'; +import { regEx } from '../../util/regex'; import { HelmDockerImageDependency } from './types'; -const parentKeyRe = /image$/i; +const parentKeyRe = regEx(/image$/i); /** * Type guard to determine whether a given partial Helm values.yaml object potentially diff --git a/lib/manager/helmfile/extract.ts b/lib/manager/helmfile/extract.ts index c2cc664568..39544b7456 100644 --- a/lib/manager/helmfile/extract.ts +++ b/lib/manager/helmfile/extract.ts @@ -3,11 +3,12 @@ import { loadAll } from 'js-yaml'; import { HelmDatasource } from '../../datasource/helm'; import { logger } from '../../logger'; import { SkipReason } from '../../types'; +import { regEx } from '../../util/regex'; import type { ExtractConfig, PackageDependency, PackageFile } from '../types'; import type { Doc } from './types'; const isValidChartName = (name: string): boolean => - !/[!@#$%^&*(),.?":{}/|<>A-Z]/.test(name); + !regEx(/[!@#$%^&*(),.?":{}/|<>A-Z]/).test(name); export function extractPackageFile( content: string, diff --git a/lib/manager/helmv3/update.ts b/lib/manager/helmv3/update.ts index f43af27cb7..2ffd5c9e3e 100644 --- a/lib/manager/helmv3/update.ts +++ b/lib/manager/helmv3/update.ts @@ -20,7 +20,7 @@ export function bumpPackageVersion( } logger.debug({ newChartVersion }); bumpedContent = content.replace( - /^(version:\s*).*$/m, + /^(version:\s*).*$/m, // TODO #12070 `$1${newChartVersion}` ); if (bumpedContent === content) { diff --git a/lib/manager/homebrew/extract.ts b/lib/manager/homebrew/extract.ts index 04803fc6c5..fbe78c91bd 100644 --- a/lib/manager/homebrew/extract.ts +++ b/lib/manager/homebrew/extract.ts @@ -1,6 +1,7 @@ import * as datasourceGithubTags from '../../datasource/github-tags'; import { logger } from '../../logger'; import { SkipReason } from '../../types'; +import { regEx } from '../../util/regex'; import type { PackageDependency, PackageFile } from '../types'; import type { UrlPathParsedResult } from './types'; import { isSpace, removeComments, skip } from './util'; @@ -19,7 +20,7 @@ function parseSha256(idx: number, content: string): string | null { } function extractSha256(content: string): string | null { - const sha256RegExp = /(^|\s)sha256(\s)/; + const sha256RegExp = regEx(/(^|\s)sha256(\s)/); let i = content.search(sha256RegExp); if (isSpace(content[i])) { i += 1; @@ -42,7 +43,7 @@ function parseUrl(idx: number, content: string): string | null { } function extractUrl(content: string): string | null { - const urlRegExp = /(^|\s)url(\s)/; + const urlRegExp = regEx(/(^|\s)url(\s)/); let i = content.search(urlRegExp); // content.search() returns -1 if not found if (i === -1) { @@ -117,7 +118,7 @@ function parseClassHeader(idx: number, content: string): string | null { } function extractClassName(content: string): string | null { - const classRegExp = /(^|\s)class\s/; + const classRegExp = regEx(/(^|\s)class\s/); let i = content.search(classRegExp); if (isSpace(content[i])) { i += 1; diff --git a/lib/manager/html/extract.ts b/lib/manager/html/extract.ts index b027836e78..6bb3383e06 100644 --- a/lib/manager/html/extract.ts +++ b/lib/manager/html/extract.ts @@ -1,10 +1,13 @@ import { CdnJsDatasource } from '../../datasource/cdnjs'; +import { regEx } from '../../util/regex'; import { cloudflareUrlRegex } from '../cdnurl/extract'; import type { PackageDependency, PackageFile } from '../types'; -const regex = /<\s*(script|link)\s+[^>]*?\/?>/i; +const regex = regEx(/<\s*(script|link)\s+[^>]*?\/?>/i); -const integrityRegex = /\s+integrity\s*=\s*("|')(?<currentDigest>[^"']+)/; +const integrityRegex = regEx( + /\s+integrity\s*=\s*("|')(?<currentDigest>[^"']+)/ +); export function extractDep(tag: string): PackageDependency | null { const match = cloudflareUrlRegex.exec(tag); diff --git a/lib/manager/jenkins/extract.ts b/lib/manager/jenkins/extract.ts index 1ea64b039d..c5e9d013eb 100644 --- a/lib/manager/jenkins/extract.ts +++ b/lib/manager/jenkins/extract.ts @@ -3,11 +3,12 @@ import * as datasourceJenkins from '../../datasource/jenkins-plugins'; import { logger } from '../../logger'; import { SkipReason } from '../../types'; import { isSkipComment } from '../../util/ignore'; +import { regEx } from '../../util/regex'; import * as dockerVersioning from '../../versioning/docker'; import type { PackageDependency, PackageFile } from '../types'; import type { JenkinsPlugin, JenkinsPlugins } from './types'; -const YamlExtension = /\.ya?ml$/; +const YamlExtension = regEx(/\.ya?ml$/); function getDependency(plugin: JenkinsPlugin): PackageDependency { const dep: PackageDependency = { @@ -70,8 +71,9 @@ function extractYaml(content: string): PackageDependency[] { function extractText(content: string): PackageDependency[] { const deps: PackageDependency[] = []; - const regex = - /^\s*(?<depName>[\d\w-]+):(?<currentValue>[^#\s]+)[#\s]*(?<comment>.*)$/; + const regex = regEx( + /^\s*(?<depName>[\d\w-]+):(?<currentValue>[^#\s]+)[#\s]*(?<comment>.*)$/ + ); for (const line of content.split('\n')) { const match = regex.exec(line); diff --git a/lib/manager/kubernetes/extract.ts b/lib/manager/kubernetes/extract.ts index cdd2827ca6..1eb9b20c27 100644 --- a/lib/manager/kubernetes/extract.ts +++ b/lib/manager/kubernetes/extract.ts @@ -1,4 +1,5 @@ import { logger } from '../../logger'; +import { regEx } from '../../util/regex'; import { getDep } from '../dockerfile/extract'; import type { PackageDependency, PackageFile } from '../types'; @@ -7,13 +8,14 @@ export function extractPackageFile(content: string): PackageFile | null { let deps: PackageDependency[] = []; const isKubernetesManifest = - /\s*apiVersion\s*:/.test(content) && /\s*kind\s*:/.test(content); + regEx(/\s*apiVersion\s*:/).test(content) && + regEx(/\s*kind\s*:/).test(content); if (!isKubernetesManifest) { return null; } for (const line of content.split('\n')) { - const match = /^\s*-?\s*image:\s*'?"?([^\s'"]+)'?"?\s*$/.exec(line); + const match = regEx(/^\s*-?\s*image:\s*'?"?([^\s'"]+)'?"?\s*$/).exec(line); // TODO #12071 if (match) { const currentFrom = match[1]; const dep = getDep(currentFrom); diff --git a/lib/manager/kustomize/extract.ts b/lib/manager/kustomize/extract.ts index f4cd424f8b..8c3f3ade85 100644 --- a/lib/manager/kustomize/extract.ts +++ b/lib/manager/kustomize/extract.ts @@ -5,14 +5,16 @@ import * as datasourceGitTags from '../../datasource/git-tags'; import * as datasourceGitHubTags from '../../datasource/github-tags'; import { logger } from '../../logger'; import { SkipReason } from '../../types'; +import { regEx } from '../../util/regex'; import { splitImageParts } from '../dockerfile/extract'; import type { PackageDependency, PackageFile } from '../types'; import type { Image, Kustomize } from './types'; // URL specifications should follow the hashicorp URL format // https://github.com/hashicorp/go-getter#url-format -const gitUrl = - /^(?:git::)?(?<url>(?:(?:(?:http|https|ssh):\/\/)?(?:.*@)?)?(?<path>(?:[^:/\s]+(?::[0-9]+)?[:/])?(?<project>[^/\s]+\/[^/\s]+)))(?<subdir>[^?\s]*)\?ref=(?<currentValue>.+)$/; +const gitUrl = regEx( + /^(?:git::)?(?<url>(?:(?:(?:http|https|ssh):\/\/)?(?:.*@)?)?(?<path>(?:[^:/\s]+(?::[0-9]+)?[:/])?(?<project>[^/\s]+\/[^/\s]+)))(?<subdir>[^?\s]*)\?ref=(?<currentValue>.+)$/ +); export function extractBase(base: string): PackageDependency | null { const match = gitUrl.exec(base); diff --git a/lib/manager/leiningen/extract.ts b/lib/manager/leiningen/extract.ts index e219db21b2..90e51d0278 100644 --- a/lib/manager/leiningen/extract.ts +++ b/lib/manager/leiningen/extract.ts @@ -1,15 +1,16 @@ import { ClojureDatasource } from '../../datasource/clojure'; +import { regEx } from '../../util/regex'; import type { PackageDependency, PackageFile } from '../types'; import type { ExtractContext, ExtractedVariables } from './types'; export function trimAtKey(str: string, kwName: string): string | null { - const regex = new RegExp(`:${kwName}(?=\\s)`); + const regex = new RegExp(`:${kwName}(?=\\s)`); // TODO #12070 const keyOffset = str.search(regex); if (keyOffset < 0) { return null; } const withSpaces = str.slice(keyOffset + kwName.length + 1); - const valueOffset = withSpaces.search(/[^\s]/); + const valueOffset = withSpaces.search(regEx(/[^\s]/)); if (valueOffset < 0) { return null; } @@ -35,16 +36,16 @@ export function extractFromVectors( let artifactId = ''; let version = ''; - const isSpace = (ch: string): boolean => ch && /[\s,]/.test(ch); + const isSpace = (ch: string): boolean => ch && regEx(/[\s,]/).test(ch); const cleanStrLiteral = (s: string): string => - s.replace(/^"/, '').replace(/"$/, ''); + s.replace(regEx(/^"/), '').replace(regEx(/"$/), ''); const yieldDep = (): void => { if (artifactId && version) { const depName = expandDepName(cleanStrLiteral(artifactId)); if (version.startsWith('~')) { - const currentValue = vars[version.replace(/^~\s*/, '')]; + const currentValue = vars[version.replace(regEx(/^~\s*/), '')]; if (currentValue) { result.push({ ...ctx, @@ -102,7 +103,7 @@ function extractLeinRepos(content: string): string[] { const result = []; const repoContent = trimAtKey( - content.replace(/;;.*(?=[\r\n])/g, ''), // get rid of comments + content.replace(/;;.*(?=[\r\n])/g, ''), // get rid of comments // TODO #12070 'repositories' ); @@ -122,16 +123,19 @@ function extractLeinRepos(content: string): string[] { } } const repoSectionContent = repoContent.slice(0, endIdx); - const matches = repoSectionContent.match(/"https?:\/\/[^"]*"/g) || []; - const urls = matches.map((x) => x.replace(/^"/, '').replace(/"$/, '')); + const matches = repoSectionContent.match(/"https?:\/\/[^"]*"/g) || []; // TODO #12070 + const urls = matches.map((x) => + x.replace(regEx(/^"/), '').replace(regEx(/"$/), '') + ); // TODO #12071 urls.forEach((url) => result.push(url)); } return result; } -const defRegex = - /^[\s,]*\([\s,]*def[\s,]+(?<varName>[-+*=<>.!?#$%&_|a-zA-Z][-+*=<>.!?#$%&_|a-zA-Z0-9']+)[\s,]*"(?<stringValue>[^"]*)"[\s,]*\)[\s,]*$/; +const defRegex = regEx( + /^[\s,]*\([\s,]*def[\s,]+(?<varName>[-+*=<>.!?#$%&_|a-zA-Z][-+*=<>.!?#$%&_|a-zA-Z0-9']+)[\s,]*"(?<stringValue>[^"]*)"[\s,]*\)[\s,]*$/ +); export function extractVariables(content: string): ExtractedVariables { const result: ExtractedVariables = {}; diff --git a/lib/manager/maven/extract.ts b/lib/manager/maven/extract.ts index a8721584c6..28e72a8054 100644 --- a/lib/manager/maven/extract.ts +++ b/lib/manager/maven/extract.ts @@ -6,6 +6,7 @@ import { MAVEN_REPO } from '../../datasource/maven/common'; import { logger } from '../../logger'; import { SkipReason } from '../../types'; import { readLocalFile } from '../../util/fs'; +import { regEx } from '../../util/regex'; import type { ExtractConfig, PackageDependency, PackageFile } from '../types'; import type { MavenProp } from './types'; @@ -33,7 +34,7 @@ export function parsePom(raw: string): XmlDocument | null { } function containsPlaceholder(str: string): boolean { - return /\${.*?}/g.test(str); + return regEx(/\${.*?}/g).test(str); } function depFromNode(node: XmlElement): PackageDependency | null { @@ -95,7 +96,7 @@ function applyProps( props: MavenProp ): PackageDependency<Record<string, any>> { const replaceAll = (str: string): string => - str.replace(/\${.*?}/g, (substr) => { + str.replace(regEx(/\${.*?}/g), (substr) => { const propKey = substr.slice(2, -1).trim(); const propValue = props[propKey]; return propValue ? propValue.val : substr; @@ -107,19 +108,22 @@ function applyProps( let fileReplacePosition = dep.fileReplacePosition; let propSource = null; let groupName = null; - const currentValue = dep.currentValue.replace(/^\${.*?}$/, (substr) => { - const propKey = substr.slice(2, -1).trim(); - const propValue = props[propKey]; - if (propValue) { - if (!groupName) { - groupName = propKey; + const currentValue = dep.currentValue.replace( + regEx(/^\${.*?}$/), + (substr) => { + const propKey = substr.slice(2, -1).trim(); + const propValue = props[propKey]; + if (propValue) { + if (!groupName) { + groupName = propKey; + } + fileReplacePosition = propValue.fileReplacePosition; + propSource = propValue.packageFile; + return propValue.val; } - fileReplacePosition = propValue.fileReplacePosition; - propSource = propValue.packageFile; - return propValue.val; + return substr; } - return substr; - }); + ); const result: PackageDependency = { ...dep, diff --git a/lib/manager/meteor/extract.ts b/lib/manager/meteor/extract.ts index 651827aa92..943842d904 100644 --- a/lib/manager/meteor/extract.ts +++ b/lib/manager/meteor/extract.ts @@ -1,20 +1,21 @@ import { id as npmId } from '../../datasource/npm'; import { logger } from '../../logger'; +import { regEx } from '../../util/regex'; import type { PackageDependency, PackageFile } from '../types'; export function extractPackageFile(content: string): PackageFile | null { let deps: PackageDependency[] = []; - const npmDepends = /\nNpm\.depends\({([\s\S]*?)}\);/.exec(content); + const npmDepends = regEx(/\nNpm\.depends\({([\s\S]*?)}\);/).exec(content); if (!npmDepends) { return null; } try { deps = npmDepends[1] - .replace(/(\s|\\n|\\t|'|")/g, '') + .replace(regEx(/(\s|\\n|\\t|'|")/g), '') .split(',') .map((dep) => dep.trim()) .filter((dep) => dep.length) - .map((dep) => dep.split(/:(.*)/)) + .map((dep) => dep.split(regEx(/:(.*)/))) // TODO #12071 .map((arr) => { const [depName, currentValue] = arr; // istanbul ignore if diff --git a/lib/manager/mix/extract.ts b/lib/manager/mix/extract.ts index 0f13f92387..c55a334eea 100644 --- a/lib/manager/mix/extract.ts +++ b/lib/manager/mix/extract.ts @@ -2,11 +2,13 @@ import { HexDatasource } from '../../datasource/hex'; import { logger } from '../../logger'; import { SkipReason } from '../../types'; import { findLocalSiblingOrParent, localPathExists } from '../../util/fs'; +import { regEx } from '../../util/regex'; import type { PackageDependency, PackageFile } from '../types'; -const depSectionRegExp = /defp\s+deps.*do/g; -const depMatchRegExp = - /{:(\w+),\s*([^:"]+)?:?\s*"([^"]+)",?\s*(organization: "(.*)")?.*}/gm; +const depSectionRegExp = regEx(/defp\s+deps.*do/g); +const depMatchRegExp = regEx( + /{:(\w+),\s*([^:"]+)?:?\s*"([^"]+)",?\s*(organization: "(.*)")?.*}/gm +); export async function extractPackageFile( content: string, diff --git a/lib/manager/npm/extract/index.ts b/lib/manager/npm/extract/index.ts index 174d1a0543..2ce178ba19 100644 --- a/lib/manager/npm/extract/index.ts +++ b/lib/manager/npm/extract/index.ts @@ -26,12 +26,12 @@ function parseDepName(depType: string, key: string): string { return key; } - const [, depName] = /((?:@[^/]+\/)?[^/@]+)$/.exec(key) ?? []; + const [, depName] = /((?:@[^/]+\/)?[^/@]+)$/.exec(key) ?? []; // TODO #12070 return depName; } const RE_REPOSITORY_GITHUB_SSH_FORMAT = - /(?:git@)github.com:([^/]+)\/([^/.]+)(?:\.git)?/; + /(?:git@)github.com:([^/]+)\/([^/.]+)(?:\.git)?/; // TODO #12070 export async function extractPackageFile( content: string, @@ -106,11 +106,11 @@ export async function extractPackageFile( } else { npmrc = config.npmrc || ''; if (npmrc.length) { - npmrc = npmrc.replace(/\n?$/, '\n'); + npmrc = npmrc.replace(/\n?$/, '\n'); // TODO #12070 } if (repoNpmrc?.includes('package-lock')) { logger.debug('Stripping package-lock setting from .npmrc'); - repoNpmrc = repoNpmrc.replace(/(^|\n)package-lock.*?(\n|$)/g, '\n'); + repoNpmrc = repoNpmrc.replace(/(^|\n)package-lock.*?(\n|$)/g, '\n'); // TODO #12070 } if (repoNpmrc.includes('=${') && !getGlobalConfig().exposeAllEnv) { logger.debug( @@ -272,10 +272,10 @@ export async function extractPackageFile( const matchUrlSshFormat = RE_REPOSITORY_GITHUB_SSH_FORMAT.exec(depNamePart); if (matchUrlSshFormat === null) { githubOwnerRepo = depNamePart - .replace(/^github:/, '') - .replace(/^git\+/, '') - .replace(/^https:\/\/github\.com\//, '') - .replace(/\.git$/, ''); + .replace(/^github:/, '') // TODO #12070 + .replace(/^git\+/, '') // TODO #12070 + .replace(/^https:\/\/github\.com\//, '') // TODO #12070 + .replace(/\.git$/, ''); // TODO #12070 const githubRepoSplit = githubOwnerRepo.split('/'); if (githubRepoSplit.length !== 2) { dep.skipReason = SkipReason.UnknownVersion; @@ -287,7 +287,7 @@ export async function extractPackageFile( githubRepo = matchUrlSshFormat[2]; githubOwnerRepo = `${githubOwner}/${githubRepo}`; } - const githubValidRegex = /^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}$/; + const githubValidRegex = /^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}$/; // TODO #12070 if ( !githubValidRegex.test(githubOwner) || !githubValidRegex.test(githubRepo) @@ -302,8 +302,8 @@ export async function extractPackageFile( dep.lookupName = githubOwnerRepo; dep.pinDigests = false; } else if ( - /^[0-9a-f]{7}$/.test(depRefPart) || - /^[0-9a-f]{40}$/.test(depRefPart) + /^[0-9a-f]{7}$/.test(depRefPart) || // TODO #12070 + /^[0-9a-f]{40}$/.test(depRefPart) // TODO #12070 ) { dep.currentRawValue = dep.currentValue; dep.currentValue = null; diff --git a/lib/manager/npm/extract/pnpm.ts b/lib/manager/npm/extract/pnpm.ts index 022ef6c8f4..a394c6aafe 100644 --- a/lib/manager/npm/extract/pnpm.ts +++ b/lib/manager/npm/extract/pnpm.ts @@ -105,7 +105,7 @@ export async function detectPnpmWorkspaces( packageFilters !== null && matchesAnyPattern( packageFile, - packageFilters.map((filter) => filter.replace(/\/?$/, '/package.json')) + packageFilters.map((filter) => filter.replace(/\/?$/, '/package.json')) // TODO #12070 #12071 ); if (isPackageInWorkspace) { p.pnpmShrinkwrap = lockFilePath; diff --git a/lib/manager/npm/post-update/index.ts b/lib/manager/npm/post-update/index.ts index 0742fbafbc..fa6830da0b 100644 --- a/lib/manager/npm/post-update/index.ts +++ b/lib/manager/npm/post-update/index.ts @@ -23,6 +23,7 @@ import { } from '../../../util/fs'; import { branchExists, getFile, getRepoStatus } from '../../../util/git'; import * as hostRules from '../../../util/host-rules'; +import { regEx } from '../../../util/regex'; import type { PackageFile, PostUpdateConfig, Upgrade } from '../../types'; import { getZeroInstallPaths } from '../extract/yarn'; import * as lerna from './lerna'; @@ -340,8 +341,8 @@ async function updateYarnOffline( if (mirrorLine) { const mirrorPath = mirrorLine .split(' ')[1] - .replace(/"/g, '') - .replace(/\/?$/, '/'); + .replace(regEx(/"/g), '') + .replace(regEx(/\/?$/), '/'); resolvedPaths.push(upath.join(lockFileDir, mirrorPath)); } } @@ -489,7 +490,7 @@ export async function getAdditionalFiles( logger.debug(`${npmLock} needs updating`); updatedArtifacts.push({ name: npmLock, - contents: res.lockFile.replace(new RegExp(`${token}`, 'g'), ''), + contents: res.lockFile.replace(regEx(`${token}`, 'g'), ''), }); } } diff --git a/lib/manager/npm/post-update/node-version.ts b/lib/manager/npm/post-update/node-version.ts index 7c4daa8baf..8c44d201ea 100644 --- a/lib/manager/npm/post-update/node-version.ts +++ b/lib/manager/npm/post-update/node-version.ts @@ -1,6 +1,7 @@ import { satisfies, validRange } from 'semver'; import { logger } from '../../../logger'; import { getSiblingFileName, readLocalFile } from '../../../util/fs'; +import { regEx } from '../../../util/regex'; import { isStable } from '../../../versioning/node'; import type { PostUpdateConfig } from '../../types'; @@ -8,7 +9,7 @@ async function getNodeFile(filename: string): Promise<string> | null { try { const constraint = (await readLocalFile(filename, 'utf8')) .split('\n')[0] - .replace(/^v/, ''); + .replace(regEx(/^v/), ''); if (validRange(constraint)) { logger.debug(`Using node constraint "${constraint}" from ${filename}`); return constraint; diff --git a/lib/manager/npm/post-update/rules.ts b/lib/manager/npm/post-update/rules.ts index a228783513..0b7cc70bd1 100644 --- a/lib/manager/npm/post-update/rules.ts +++ b/lib/manager/npm/post-update/rules.ts @@ -1,5 +1,6 @@ import is from '@sindresorhus/is'; import * as hostRules from '../../../util/host-rules'; +import { regEx } from '../../../util/regex'; import { validateUrl } from '../../../util/url'; export interface HostRulesResult { @@ -18,7 +19,7 @@ export function processHostRules(): HostRulesResult { for (const hostRule of npmHostRules) { if (hostRule.resolvedHost) { let uri = hostRule.matchHost; - uri = validateUrl(uri) ? uri.replace(/^https?:/, '') : `//${uri}/`; + uri = validateUrl(uri) ? uri.replace(regEx(/^https?:/), '') : `//${uri}/`; // TODO #12071 if (hostRule.token) { const key = hostRule.authType === 'Basic' ? '_auth' : '_authToken'; additionalNpmrcContent.push(`${uri}:${key}=${hostRule.token}`); diff --git a/lib/manager/npm/post-update/yarn.ts b/lib/manager/npm/post-update/yarn.ts index 24e15f9ef6..1ca1c95233 100644 --- a/lib/manager/npm/post-update/yarn.ts +++ b/lib/manager/npm/post-update/yarn.ts @@ -12,6 +12,7 @@ import { logger } from '../../../logger'; import { ExternalHostError } from '../../../types/errors/external-host-error'; import { ExecOptions, exec } from '../../../util/exec'; import { readFile, remove } from '../../../util/fs'; +import { regEx } from '../../../util/regex'; import type { PostUpdateConfig, Upgrade } from '../../types'; import { getNodeConstraint } from './node-version'; import { GenerateLockFileResult } from './types'; @@ -32,7 +33,7 @@ export async function checkYarnrc( .split('\n') .find((line) => line.startsWith('yarn-path ')); if (pathLine) { - yarnPath = pathLine.replace(/^yarn-path\s+"?(.+?)"?$/, '$1'); + yarnPath = pathLine.replace(regEx(/^yarn-path\s+"?(.+?)"?$/), '$1'); } } } catch (err) /* istanbul ignore next */ { diff --git a/lib/manager/npm/update/locked-dependency/dep-constraints.ts b/lib/manager/npm/update/locked-dependency/dep-constraints.ts index 3bdb1c8404..88e4eb4853 100644 --- a/lib/manager/npm/update/locked-dependency/dep-constraints.ts +++ b/lib/manager/npm/update/locked-dependency/dep-constraints.ts @@ -1,5 +1,6 @@ import type { PackageJson } from 'type-fest'; import { logger } from '../../../../logger'; +import { regEx } from '../../../../util/regex'; import { api as semver } from '../../../../versioning/npm'; import type { PackageLockOrEntry, ParentDependency } from './types'; @@ -31,7 +32,7 @@ export function findDepConstraints( if (parentDepName && requires) { let constraint = requires[depName]; if (constraint) { - constraint = constraint.replace(/(\d)rc$/, '$1-rc'); + constraint = constraint.replace(regEx(/(\d)rc$/), '$1-rc'); // istanbul ignore else if (semver.isValid(constraint)) { if (semver.matches(currentVersion, constraint)) { diff --git a/lib/manager/npm/update/package-version/index.ts b/lib/manager/npm/update/package-version/index.ts index f45f1e1dfe..9644b59b47 100644 --- a/lib/manager/npm/update/package-version/index.ts +++ b/lib/manager/npm/update/package-version/index.ts @@ -31,7 +31,7 @@ export function bumpPackageVersion( } logger.debug({ newPjVersion }); bumpedContent = content.replace( - /("version":\s*")[^"]*/, + /("version":\s*")[^"]*/, // TODO #12070 `$1${newPjVersion}` ); if (bumpedContent === content) { diff --git a/lib/manager/nuget/artifacts.ts b/lib/manager/nuget/artifacts.ts index 45175f3c15..34a910aad3 100644 --- a/lib/manager/nuget/artifacts.ts +++ b/lib/manager/nuget/artifacts.ts @@ -13,6 +13,7 @@ import { writeLocalFile, } from '../../util/fs'; import * as hostRules from '../../util/host-rules'; +import { regEx } from '../../util/regex'; import type { UpdateArtifact, UpdateArtifactsConfig, @@ -88,7 +89,7 @@ export async function updateArtifacts({ }: UpdateArtifact): Promise<UpdateArtifactsResult[] | null> { logger.debug(`nuget.updateArtifacts(${packageFileName})`); - if (!/(?:cs|vb|fs)proj$/i.test(packageFileName)) { + if (!regEx(/(?:cs|vb|fs)proj$/i).test(packageFileName)) { // This could be implemented in the future if necessary. // It's not that easy though because the questions which // project file to restore how to determine which lock files diff --git a/lib/manager/nuget/extract.ts b/lib/manager/nuget/extract.ts index f4d3af4cb2..a5e6ab86a7 100644 --- a/lib/manager/nuget/extract.ts +++ b/lib/manager/nuget/extract.ts @@ -21,7 +21,7 @@ import { getConfiguredRegistries } from './util'; * so we don't include it in the extracting regexp */ const checkVersion = - /^\s*(?:[[])?(?:(?<currentValue>[^"(,[\]]+)\s*(?:,\s*[)\]]|])?)\s*$/; + /^\s*(?:[[])?(?:(?<currentValue>[^"(,[\]]+)\s*(?:,\s*[)\]]|])?)\s*$/; // TODO #12070 const elemNames = new Set([ 'PackageReference', 'PackageVersion', diff --git a/lib/manager/nuget/util.ts b/lib/manager/nuget/util.ts index d7fcd54f03..526474edbc 100644 --- a/lib/manager/nuget/util.ts +++ b/lib/manager/nuget/util.ts @@ -5,6 +5,7 @@ import { XmlDocument } from 'xmldoc'; import * as datasourceNuget from '../../datasource/nuget'; import { logger } from '../../logger'; import { readFile } from '../../util/fs'; +import { regEx } from '../../util/regex'; import type { Registry } from './types'; async function readFileAsXmlDocument(file: string): Promise<XmlDocument> { @@ -68,7 +69,7 @@ export async function getConfiguredRegistries( logger.debug(`clearing registry URLs`); registries.length = 0; } else if (child.name === 'add') { - const isHttpUrl = /^https?:\/\//i.test(child.attr.value); + const isHttpUrl = regEx(/^https?:\/\//i).test(child.attr.value); // TODO #12071 if (isHttpUrl) { let registryUrl = child.attr.value; if (child.attr.protocolVersion) { diff --git a/lib/manager/pip-compile/artifacts.ts b/lib/manager/pip-compile/artifacts.ts index 58056c07d9..ecd23f1c79 100644 --- a/lib/manager/pip-compile/artifacts.ts +++ b/lib/manager/pip-compile/artifacts.ts @@ -5,6 +5,7 @@ import { logger } from '../../logger'; import { ExecOptions, exec } from '../../util/exec'; import { deleteLocalFile, readLocalFile, writeLocalFile } from '../../util/fs'; import { getRepoStatus } from '../../util/git'; +import { regEx } from '../../util/regex'; import type { UpdateArtifact, UpdateArtifactsConfig, @@ -42,7 +43,7 @@ export async function updateArtifacts({ newPackageFileContent: newInputContent, config, }: UpdateArtifact): Promise<UpdateArtifactsResult[] | null> { - const outputFileName = inputFileName.replace(/(\.in)?$/, '.txt'); + const outputFileName = inputFileName.replace(regEx(/(\.in)?$/), '.txt'); logger.debug( `pipCompile.updateArtifacts(${inputFileName}->${outputFileName})` ); diff --git a/lib/manager/pip_requirements/artifacts.ts b/lib/manager/pip_requirements/artifacts.ts index ade3806b51..4725a5a938 100644 --- a/lib/manager/pip_requirements/artifacts.ts +++ b/lib/manager/pip_requirements/artifacts.ts @@ -3,6 +3,7 @@ import { TEMPORARY_ERROR } from '../../constants/error-messages'; import { logger } from '../../logger'; import { ExecOptions, exec } from '../../util/exec'; import { readLocalFile } from '../../util/fs'; +import { regEx } from '../../util/regex'; import type { UpdateArtifact, UpdateArtifactsResult } from '../types'; export async function updateArtifacts({ @@ -18,7 +19,7 @@ export async function updateArtifacts({ } try { const cmd: string[] = []; - const rewrittenContent = newPackageFileContent.replace(/\\\n/g, ''); + const rewrittenContent = newPackageFileContent.replace(regEx(/\\\n/g), ''); const lines = rewrittenContent.split('\n').map((line) => line.trim()); for (const dep of updatedDeps) { const hashLine = lines.find( diff --git a/lib/manager/pip_requirements/extract.ts b/lib/manager/pip_requirements/extract.ts index 183abeb53c..01cff069da 100644 --- a/lib/manager/pip_requirements/extract.ts +++ b/lib/manager/pip_requirements/extract.ts @@ -5,6 +5,7 @@ import { PypiDatasource } from '../../datasource/pypi'; import { logger } from '../../logger'; import { SkipReason } from '../../types'; import { isSkipComment } from '../../util/ignore'; +import { regEx } from '../../util/regex'; import type { ExtractConfig, PackageDependency, PackageFile } from '../types'; export const packagePattern = @@ -12,7 +13,10 @@ export const packagePattern = const extrasPattern = '(?:\\s*\\[[^\\]]+\\])?'; const rangePattern: string = RANGE_PATTERN; -const specifierPartPattern = `\\s*${rangePattern.replace(/\?<\w+>/g, '?:')}`; +const specifierPartPattern = `\\s*${rangePattern.replace( + regEx(/\?<\w+>/g), + '?:' +)}`; const specifierPattern = `${specifierPartPattern}(?:\\s*,${specifierPartPattern})*`; export const dependencyPattern = `(${packagePattern})(${extrasPattern})(${specifierPattern})`; @@ -49,7 +53,7 @@ export function extractPackageFile( } registryUrls = registryUrls.concat(extraUrls); - const regex = new RegExp(`^${dependencyPattern}$`, 'g'); + const regex = regEx(`^${dependencyPattern}$`, 'g'); const deps = content .split('\n') .map((rawline) => { @@ -84,15 +88,18 @@ export function extractPackageFile( if (registryUrls.length > 0) { res.registryUrls = registryUrls.map((url) => { // handle the optional quotes in eg. `--extra-index-url "https://foo.bar"` - const cleaned = url.replace(/^"/, '').replace(/"$/, ''); + const cleaned = url.replace(regEx(/^"/), '').replace(regEx(/"$/), ''); // TODO #12071 if (!getGlobalConfig().exposeAllEnv) { return cleaned; } // interpolate any environment variables return cleaned.replace( - /(\$[A-Za-z\d_]+)|(\${[A-Za-z\d_]+})/g, + regEx(/(\$[A-Za-z\d_]+)|(\${[A-Za-z\d_]+})/g), // TODO #12071 (match) => { - const envvar = match.substring(1).replace(/^{/, '').replace(/}$/, ''); + const envvar = match + .substring(1) + .replace(regEx(/^{/), '') + .replace(regEx(/}$/), ''); // TODO #12071 const sub = process.env[envvar]; return sub || match; } diff --git a/lib/manager/pip_setup/extract.ts b/lib/manager/pip_setup/extract.ts index 1745e85ea6..97cb24ce76 100644 --- a/lib/manager/pip_setup/extract.ts +++ b/lib/manager/pip_setup/extract.ts @@ -4,6 +4,7 @@ import { logger } from '../../logger'; import { SkipReason } from '../../types'; import { exec } from '../../util/exec'; import { isSkipComment } from '../../util/ignore'; +import { regEx } from '../../util/regex'; import { dependencyPattern } from '../pip_requirements/extract'; import type { ExtractConfig, PackageDependency, PackageFile } from '../types'; import type { PythonSetup } from './types'; @@ -63,7 +64,7 @@ export async function extractSetupFile( }); if (res.stderr) { const stderr = res.stderr - .replace(/.*\n\s*import imp/, '') + .replace(regEx(/.*\n\s*import imp/), '') .trim() .replace('fatal: No names found, cannot describe anything.', ''); if (stderr.length) { @@ -97,7 +98,7 @@ export async function extractPackageFile( requires.push(...req); } } - const regex = new RegExp(`^${dependencyPattern}`); + const regex = regEx(`^${dependencyPattern}`); const lines = content.split('\n'); const deps = requires .map((req) => { diff --git a/lib/manager/pipenv/extract.ts b/lib/manager/pipenv/extract.ts index 9c6cbe5361..1bad1beb61 100644 --- a/lib/manager/pipenv/extract.ts +++ b/lib/manager/pipenv/extract.ts @@ -5,15 +5,16 @@ import { PypiDatasource } from '../../datasource/pypi'; import { logger } from '../../logger'; import { SkipReason } from '../../types'; import { localPathExists } from '../../util/fs'; +import { regEx } from '../../util/regex'; import type { PackageDependency, PackageFile } from '../types'; import type { PipFile } from './types'; // based on https://www.python.org/dev/peps/pep-0508/#names -const packageRegex = /^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$/i; +const packageRegex = regEx(/^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$/i); const rangePattern: string = RANGE_PATTERN; const specifierPartPattern = `\\s*${rangePattern.replace( - /\?<\w+>/g, + regEx(/\?<\w+>/g), '?:' )}\\s*`; const specifierPattern = `${specifierPartPattern}(?:,${specifierPartPattern})*`; @@ -24,7 +25,7 @@ function extractFromSection( if (!(section in pipfile)) { return []; } - const specifierRegex = new RegExp(`^${specifierPattern}$`); + const specifierRegex = regEx(`^${specifierPattern}$`); const pipfileSection = pipfile[section]; const deps = Object.entries(pipfileSection) diff --git a/lib/manager/pre-commit/extract.ts b/lib/manager/pre-commit/extract.ts index aef244b22b..9e0dec1d7b 100644 --- a/lib/manager/pre-commit/extract.ts +++ b/lib/manager/pre-commit/extract.ts @@ -89,13 +89,13 @@ function extractDependency( // This splits "git@private.registry.com:user/repo" -> "private.registry.com" "user/repo regEx('^git@(?<hostname>[^:]+):(?<depName>\\S*)'), // This split "git://github.com/pre-commit/pre-commit-hooks" -> "github.com" "pre-commit/pre-commit-hooks" - /^git:\/\/(?<hostname>[^/]+)\/(?<depName>\S*)/, + regEx(/^git:\/\/(?<hostname>[^/]+)\/(?<depName>\S*)/), ]; for (const urlMatcher of urlMatchers) { const match = urlMatcher.exec(repository); if (match) { const hostname = match.groups.hostname; - const depName = match.groups.depName.replace(/\.git$/i, ''); + const depName = match.groups.depName.replace(regEx(/\.git$/i), ''); // TODO 12071 const sourceDef = determineDatasource(repository, hostname); return { ...sourceDef, diff --git a/lib/manager/sbt/extract.ts b/lib/manager/sbt/extract.ts index f83f81648c..25d11b30cd 100644 --- a/lib/manager/sbt/extract.ts +++ b/lib/manager/sbt/extract.ts @@ -2,38 +2,42 @@ import * as datasourceMaven from '../../datasource/maven'; import { MAVEN_REPO } from '../../datasource/maven/common'; import * as datasourceSbtPackage from '../../datasource/sbt-package'; import * as datasourceSbtPlugin from '../../datasource/sbt-plugin'; +import { regEx } from '../../util/regex'; import { get } from '../../versioning'; import * as mavenVersioning from '../../versioning/maven'; import type { PackageDependency, PackageFile } from '../types'; import type { ParseContext, ParseOptions } from './types'; -const stripComment = (str: string): string => str.replace(/(^|\s+)\/\/.*$/, ''); +const stripComment = (str: string): string => + str.replace(regEx(/(^|\s+)\/\/.*$/), ''); const isSingleLineDep = (str: string): boolean => - /^\s*(libraryDependencies|dependencyOverrides)\s*\+=\s*/.test(str); + regEx(/^\s*(libraryDependencies|dependencyOverrides)\s*\+=\s*/).test(str); const isDepsBegin = (str: string): boolean => - /^\s*(libraryDependencies|dependencyOverrides)\s*\+\+=\s*/.test(str); + regEx(/^\s*(libraryDependencies|dependencyOverrides)\s*\+\+=\s*/).test(str); const isPluginDep = (str: string): boolean => - /^\s*addSbtPlugin\s*\(.*\)\s*$/.test(str); + regEx(/^\s*addSbtPlugin\s*\(.*\)\s*$/).test(str); -const isStringLiteral = (str: string): boolean => /^"[^"]*"$/.test(str); +const isStringLiteral = (str: string): boolean => regEx(/^"[^"]*"$/).test(str); const isScalaVersion = (str: string): boolean => - /^\s*scalaVersion\s*:=\s*"[^"]*"[\s,]*$/.test(str); + regEx(/^\s*scalaVersion\s*:=\s*"[^"]*"[\s,]*$/).test(str); const getScalaVersion = (str: string): string => - str.replace(/^\s*scalaVersion\s*:=\s*"/, '').replace(/"[\s,]*$/, ''); + str + .replace(regEx(/^\s*scalaVersion\s*:=\s*"/), '') + .replace(regEx(/"[\s,]*$/), ''); const isPackageFileVersion = (str: string): boolean => - /^(version\s*:=\s*).*$/.test(str); + regEx(/^(version\s*:=\s*).*$/).test(str); const getPackageFileVersion = (str: string): string => str - .replace(/^\s*version\s*:=\s*/, '') - .replace(/[\s,]*$/, '') - .replace(/"/g, ''); + .replace(regEx(/^\s*version\s*:=\s*/), '') + .replace(regEx(/[\s,]*$/), '') + .replace(regEx(/"/g), ''); /* https://www.scala-sbt.org/release/docs/Cross-Build.html#Publishing+conventions @@ -54,62 +58,64 @@ const normalizeScalaVersion = (str: string): string => { return str; } } - if (/^\d+\.\d+\.\d+$/.test(str)) { - return str.replace(/^(\d+)\.(\d+)\.\d+$/, '$1.$2'); + if (regEx(/^\d+\.\d+\.\d+$/).test(str)) { + return str.replace(regEx(/^(\d+)\.(\d+)\.\d+$/), '$1.$2'); } // istanbul ignore next return str; }; const isScalaVersionVariable = (str: string): boolean => - /^\s*scalaVersion\s*:=\s*[_a-zA-Z][_a-zA-Z0-9]*[\s,]*$/.test(str); + regEx(/^\s*scalaVersion\s*:=\s*[_a-zA-Z][_a-zA-Z0-9]*[\s,]*$/).test(str); const getScalaVersionVariable = (str: string): string => - str.replace(/^\s*scalaVersion\s*:=\s*/, '').replace(/[\s,]*$/, ''); + str + .replace(regEx(/^\s*scalaVersion\s*:=\s*/), '') + .replace(regEx(/[\s,]*$/), ''); const isResolver = (str: string): boolean => - /^\s*(resolvers\s*\+\+?=\s*(Seq\()?)?"[^"]*"\s*at\s*"[^"]*"[\s,)]*$/.test( - str - ); + regEx( + /^\s*(resolvers\s*\+\+?=\s*(Seq\()?)?"[^"]*"\s*at\s*"[^"]*"[\s,)]*$/ + ).test(str); const getResolverUrl = (str: string): string => str - .replace(/^\s*(resolvers\s*\+\+?=\s*(Seq\()?)?"[^"]*"\s*at\s*"/, '') - .replace(/"[\s,)]*$/, ''); + .replace(regEx(/^\s*(resolvers\s*\+\+?=\s*(Seq\()?)?"[^"]*"\s*at\s*"/), '') + .replace(regEx(/"[\s,)]*$/), ''); const isVarDependency = (str: string): boolean => - /^\s*(private\s*)?(lazy\s*)?val\s[_a-zA-Z][_a-zA-Z0-9]*\s*=.*(%%?).*%.*/.test( - str - ); + regEx( + /^\s*(private\s*)?(lazy\s*)?val\s[_a-zA-Z][_a-zA-Z0-9]*\s*=.*(%%?).*%.*/ + ).test(str); const isVarDef = (str: string): boolean => - /^\s*(private\s*)?(lazy\s*)?val\s+[_a-zA-Z][_a-zA-Z0-9]*\s*=\s*"[^"]*"\s*$/.test( - str - ); + regEx( + /^\s*(private\s*)?(lazy\s*)?val\s+[_a-zA-Z][_a-zA-Z0-9]*\s*=\s*"[^"]*"\s*$/ + ).test(str); const isVarSeqSingleLine = (str: string): boolean => - /^\s*(private\s*)?(lazy\s*)?val\s+[_a-zA-Z][_a-zA-Z0-9]*\s*=\s*Seq\(.*\).*\s*$/.test( - str - ); + regEx( + /^\s*(private\s*)?(lazy\s*)?val\s+[_a-zA-Z][_a-zA-Z0-9]*\s*=\s*Seq\(.*\).*\s*$/ + ).test(str); const isVarSeqMultipleLine = (str: string): boolean => - /^\s*(private\s*)?(lazy\s*)?val\s+[_a-zA-Z][_a-zA-Z0-9]*\s*=\s*Seq\(.*[^)]*.*$/.test( - str - ); + regEx( + /^\s*(private\s*)?(lazy\s*)?val\s+[_a-zA-Z][_a-zA-Z0-9]*\s*=\s*Seq\(.*[^)]*.*$/ + ).test(str); const getVarName = (str: string): string => str - .replace(/^\s*(private\s*)?(lazy\s*)?val\s+/, '') - .replace(/\s*=\s*"[^"]*"\s*$/, ''); + .replace(regEx(/^\s*(private\s*)?(lazy\s*)?val\s+/), '') + .replace(regEx(/\s*=\s*"[^"]*"\s*$/), ''); const isVarName = (str: string): boolean => - /^[_a-zA-Z][_a-zA-Z0-9]*$/.test(str); + regEx(/^[_a-zA-Z][_a-zA-Z0-9]*$/).test(str); const getVarInfo = (str: string, ctx: ParseContext): { val: string } => { const rightPart = str.replace( - /^\s*(private\s*)?(lazy\s*)?val\s+[_a-zA-Z][_a-zA-Z0-9]*\s*=\s*"/, + regEx(/^\s*(private\s*)?(lazy\s*)?val\s+[_a-zA-Z][_a-zA-Z0-9]*\s*=\s*"/), '' ); - const val = rightPart.replace(/"\s*$/, ''); + const val = rightPart.replace(regEx(/"\s*$/), ''); return { val }; }; @@ -125,15 +131,15 @@ function parseDepExpr( const resolveToken = (str: string): string => isStringLiteral(str) - ? str.replace(/^"/, '').replace(/"$/, '') + ? str.replace(regEx(/^"/), '').replace(regEx(/"$/), '') : variables[str].val; const tokens = expr .trim() - .split(/("[^"]*")/g) - .map((x) => (/"[^"]*"/.test(x) ? x : x.replace(/[()]+/g, ''))) + .split(regEx(/("[^"]*")/g)) + .map((x) => (regEx(/"[^"]*"/).test(x) ? x : x.replace(regEx(/[()]+/g), ''))) // TODO #12071 .join('') - .split(/\s*(%%?)\s*|\s*classifier\s*/); + .split(regEx(/\s*(%%?)\s*|\s*classifier\s*/)); const [ rawGroupId, @@ -183,7 +189,7 @@ function parseDepExpr( const currentValue = resolveToken(rawVersion); if (!depType && rawScope) { - depType = rawScope.replace(/^"/, '').replace(/"$/, ''); + depType = rawScope.replace(regEx(/^"/), '').replace(regEx(/"$/), ''); } const result: PackageDependency = { @@ -243,13 +249,15 @@ function parseSbtLine( registryUrls.push(url); } else if (isVarSeqSingleLine(line)) { isMultiDeps = false; - const depExpr = line.replace(/^.*Seq\(\s*/, '').replace(/\).*$/, ''); + const depExpr = line + .replace(regEx(/^.*Seq\(\s*/), '') + .replace(regEx(/\).*$/), ''); dep = parseDepExpr(depExpr, { ...ctx, }); } else if (isVarSeqMultipleLine(line)) { isMultiDeps = true; - const depExpr = line.replace(/^.*Seq\(\s*/, ''); + const depExpr = line.replace(regEx(/^.*Seq\(\s*/), ''); dep = parseDepExpr(depExpr, { ...ctx, }); @@ -258,7 +266,7 @@ function parseSbtLine( } else if (isVarDependency(line)) { isMultiDeps = false; const depExpr = line.replace( - /^\s*(private\s*)?(lazy\s*)?val\s[_a-zA-Z][_a-zA-Z0-9]*\s*=\s*/, + regEx(/^\s*(private\s*)?(lazy\s*)?val\s[_a-zA-Z][_a-zA-Z0-9]*\s*=\s*/), '' ); dep = parseDepExpr(depExpr, { @@ -266,14 +274,14 @@ function parseSbtLine( }); } else if (isSingleLineDep(line)) { isMultiDeps = false; - const depExpr = line.replace(/^.*\+=\s*/, ''); + const depExpr = line.replace(regEx(/^.*\+=\s*/), ''); dep = parseDepExpr(depExpr, { ...ctx, }); } else if (isPluginDep(line)) { isMultiDeps = false; - const rightPart = line.replace(/^\s*addSbtPlugin\s*\(/, ''); - const depExpr = rightPart.replace(/\)\s*$/, ''); + const rightPart = line.replace(regEx(/^\s*addSbtPlugin\s*\(/), ''); + const depExpr = rightPart.replace(regEx(/\)\s*$/), ''); dep = parseDepExpr(depExpr, { ...ctx, depType: 'plugin', @@ -281,8 +289,8 @@ function parseSbtLine( } else if (isDepsBegin(line)) { isMultiDeps = true; } else if (isMultiDeps) { - const rightPart = line.replace(/^[\s,]*/, ''); - const depExpr = rightPart.replace(/[\s,]*$/, ''); + const rightPart = line.replace(regEx(/^[\s,]*/), ''); + const depExpr = rightPart.replace(regEx(/[\s,]*$/), ''); dep = parseDepExpr(depExpr, { ...ctx, }); @@ -332,7 +340,7 @@ export function extractPackageFile(content: string): PackageFile { if (!content) { return null; } - const lines = content.split(/\n/).map(stripComment); + const lines = content.split(regEx(/\n/)).map(stripComment); return lines.reduce(parseSbtLine, { registryUrls: [MAVEN_REPO], deps: [], diff --git a/lib/manager/sbt/update.ts b/lib/manager/sbt/update.ts index afab698d95..f15ef8882f 100644 --- a/lib/manager/sbt/update.ts +++ b/lib/manager/sbt/update.ts @@ -1,5 +1,6 @@ import { ReleaseType, inc } from 'semver'; import { logger } from '../../logger'; +import { regEx } from '../../util/regex'; import type { BumpPackageVersionResult } from '../types'; export function bumpPackageVersion( @@ -18,7 +19,7 @@ export function bumpPackageVersion( return { bumpedContent }; } bumpedContent = content.replace( - /^(version\s*:=\s*).*$/m, + regEx(/^(version\s*:=\s*).*$/m), `$1"${bumpedVersion}"` ); diff --git a/lib/manager/setup-cfg/extract.ts b/lib/manager/setup-cfg/extract.ts index 6fdb150fa6..7ab666964a 100644 --- a/lib/manager/setup-cfg/extract.ts +++ b/lib/manager/setup-cfg/extract.ts @@ -1,14 +1,15 @@ import { PypiDatasource } from '../../datasource/pypi'; +import { regEx } from '../../util/regex'; import pep440 from '../../versioning/pep440'; import type { PackageDependency, PackageFile, Result } from '../types'; function getSectionName(str: string): string { - const [, sectionName] = /^\[\s*([^\s]+)\s*]\s*$/.exec(str) || []; + const [, sectionName] = regEx(/^\[\s*([^\s]+)\s*]\s*$/).exec(str) || []; // TODO #12071 return sectionName; } function getSectionRecord(str: string): string { - const [, sectionRecord] = /^([^\s]+)\s+=/.exec(str) || []; + const [, sectionRecord] = regEx(/^([^\s]+)\s+=/).exec(str) || []; // TODO #12071 return sectionRecord; } @@ -33,7 +34,7 @@ function parseDep( record: string ): PackageDependency | null { const [, depName, , currentValue] = - /\s+([-_a-zA-Z0-9]*)(\[.*\])?\s*(.*)/.exec(line) || []; + regEx(/\s+([-_a-zA-Z0-9]*)(\[.*\])?\s*(.*)/).exec(line) || []; if ( section && record && @@ -64,7 +65,7 @@ export function extractPackageFile( const deps: PackageDependency[] = []; content .split('\n') - .map((line) => line.replace(/[;#].*$/, '').trimRight()) + .map((line) => line.replace(regEx(/[;#].*$/), '').trimRight()) // TODO #12071 .forEach((rawLine) => { let line = rawLine; const newSectionName = getSectionName(line); @@ -74,7 +75,7 @@ export function extractPackageFile( } else { if (newSectionRecord) { sectionRecord = newSectionRecord; - line = rawLine.replace(/^[^=]*=\s*/, '\t'); + line = rawLine.replace(regEx(/^[^=]*=\s*/), '\t'); // TODO #12071 } const dep = parseDep(line, sectionName, sectionRecord); if (dep) { diff --git a/lib/manager/swift/extract.ts b/lib/manager/swift/extract.ts index f7feb08408..2000dd184c 100644 --- a/lib/manager/swift/extract.ts +++ b/lib/manager/swift/extract.ts @@ -1,21 +1,22 @@ import * as datasourceGitTags from '../../datasource/git-tags'; +import { regEx } from '../../util/regex'; import type { PackageDependency, PackageFile } from '../types'; import type { MatchResult } from './types'; const regExps = { - wildcard: /^.*?/, - space: /(\s+|\/\/[^\n]*|\/\*.*\*\/)+/s, - depsKeyword: /dependencies/, - colon: /:/, - beginSection: /\[/, - endSection: /],?/, - package: /\s*.\s*package\s*\(\s*/, - urlKey: /url/, - stringLiteral: /"[^"]+"/, - comma: /,/, - from: /from/, - rangeOp: /\.\.[.<]/, - exactVersion: /\.\s*exact\s*\(\s*/, + wildcard: regEx(/^.*?/), + space: regEx(/(\s+|\/\/[^\n]*|\/\*.*\*\/)+/, 's'), + depsKeyword: regEx(/dependencies/), + colon: regEx(/:/), + beginSection: regEx(/\[/), + endSection: regEx(/],?/), + package: regEx(/\s*.\s*package\s*\(\s*/), + urlKey: regEx(/url/), + stringLiteral: regEx(/"[^"]+"/), + comma: regEx(/,/), + from: regEx(/from/), + rangeOp: regEx(/\.\.[.<]/), + exactVersion: regEx(/\.\s*exact\s*\(\s*/), }; const WILDCARD = 'wildcard'; @@ -116,9 +117,9 @@ function getDepName(url: string): string | null { const { host, pathname } = new URL(url); if (host === 'github.com' || host === 'gitlab.com') { return pathname - .replace(/^\//, '') - .replace(/\.git$/, '') - .replace(/\/$/, ''); + .replace(regEx(/^\//), '') + .replace(regEx(/\.git$/), '') + .replace(regEx(/\/$/), ''); } return url; } catch (e) { @@ -224,7 +225,7 @@ export function extractPackageFile( yieldDep(); state = null; } else if (label === STRING_LITERAL) { - lookupName = substr.replace(/^"/, '').replace(/"$/, ''); + lookupName = substr.replace(regEx(/^"/), '').replace(regEx(/"$/), ''); state = '.package(url: [depName]'; } else if (label === PACKAGE) { yieldDep(); diff --git a/lib/manager/terraform/extract.ts b/lib/manager/terraform/extract.ts index e9912586b0..ad18986475 100644 --- a/lib/manager/terraform/extract.ts +++ b/lib/manager/terraform/extract.ts @@ -1,5 +1,6 @@ import is from '@sindresorhus/is'; import { logger } from '../../logger'; +import { regEx } from '../../util/regex'; import type { ExtractConfig, PackageDependency, PackageFile } from '../types'; import { TerraformDependencyTypes } from './common'; import { extractLocks, findLockFile, readLockFile } from './lockfile/util'; @@ -26,8 +27,9 @@ import { getTerraformDependencyType, } from './util'; -const dependencyBlockExtractionRegex = - /^\s*(?<type>[a-z_]+)\s+("(?<lookupName>[^"]+)"\s+)?("(?<terraformName>[^"]+)"\s+)?{\s*$/; +const dependencyBlockExtractionRegex = regEx( + /^\s*(?<type>[a-z_]+)\s+("(?<lookupName>[^"]+)"\s+)?("(?<terraformName>[^"]+)"\s+)?{\s*$/ +); const contentCheckList = [ 'module "', 'provider "', diff --git a/lib/manager/terraform/lockfile/hash.ts b/lib/manager/terraform/lockfile/hash.ts index 4862d444da..94799f362c 100644 --- a/lib/manager/terraform/lockfile/hash.ts +++ b/lib/manager/terraform/lockfile/hash.ts @@ -31,7 +31,7 @@ export class TerraformProviderHash { // add double space, the filename and a new line char rootHash.update(' '); - const fileName = file.replace(/^.*[\\/]/, ''); + const fileName = file.replace(/^.*[\\/]/, ''); // TODO #12070 rootHash.update(fileName); rootHash.update('\n'); } diff --git a/lib/manager/terraform/lockfile/util.ts b/lib/manager/terraform/lockfile/util.ts index d8282800fa..b439866582 100644 --- a/lib/manager/terraform/lockfile/util.ts +++ b/lib/manager/terraform/lockfile/util.ts @@ -9,12 +9,12 @@ import type { } from './types'; const providerStartLineRegex = - /^provider "(?<registryUrl>[^/]*)\/(?<namespace>[^/]*)\/(?<depName>[^/]*)"/; + /^provider "(?<registryUrl>[^/]*)\/(?<namespace>[^/]*)\/(?<depName>[^/]*)"/; // TODO #12070 const versionLineRegex = - /^(?<prefix>[\s]*version[\s]*=[\s]*")(?<version>[^"']+)(?<suffix>".*)$/; + /^(?<prefix>[\s]*version[\s]*=[\s]*")(?<version>[^"']+)(?<suffix>".*)$/; // TODO #12070 const constraintLineRegex = - /^(?<prefix>[\s]*constraints[\s]*=[\s]*")(?<constraint>[^"']+)(?<suffix>".*)$/; -const hashLineRegex = /^(?<prefix>\s*")(?<hash>[^"]+)(?<suffix>",.*)$/; + /^(?<prefix>[\s]*constraints[\s]*=[\s]*")(?<constraint>[^"']+)(?<suffix>".*)$/; // TODO #12070 +const hashLineRegex = /^(?<prefix>\s*")(?<hash>[^"]+)(?<suffix>",.*)$/; // TODO #12070 const lockFile = '.terraform.lock.hcl'; diff --git a/lib/manager/terraform/modules.ts b/lib/manager/terraform/modules.ts index a7903a0233..34f0d6c8f4 100644 --- a/lib/manager/terraform/modules.ts +++ b/lib/manager/terraform/modules.ts @@ -3,16 +3,19 @@ import * as datasourceGithubTags from '../../datasource/github-tags'; import { TerraformModuleDatasource } from '../../datasource/terraform-module'; import { logger } from '../../logger'; import { SkipReason } from '../../types'; +import { regEx } from '../../util/regex'; import type { PackageDependency } from '../types'; import { TerraformDependencyTypes } from './common'; import { extractTerraformProvider } from './providers'; import type { ExtractionResult } from './types'; -export const githubRefMatchRegex = - /github\.com([/:])(?<project>[^/]+\/[a-z0-9-_.]+).*\?ref=(?<tag>.*)$/i; -export const gitTagsRefMatchRegex = - /(?:git::)?(?<url>(?:http|https|ssh):\/\/(?:.*@)?(?<path>.*.*\/(?<project>.*\/.*)))\?ref=(?<tag>.*)$/; -const hostnameMatchRegex = /^(?<hostname>([\w|\d]+\.)+[\w|\d]+)/; +export const githubRefMatchRegex = regEx( + /github\.com([/:])(?<project>[^/]+\/[a-z0-9-_.]+).*\?ref=(?<tag>.*)$/i +); +export const gitTagsRefMatchRegex = regEx( + /(?:git::)?(?<url>(?:http|https|ssh):\/\/(?:.*@)?(?<path>.*.*\/(?<project>.*\/.*)))\?ref=(?<tag>.*)$/ +); +const hostnameMatchRegex = regEx(/^(?<hostname>([\w|\d]+\.)+[\w|\d]+)/); export function extractTerraformModule( startingLine: number, @@ -32,7 +35,7 @@ export function analyseTerraformModule(dep: PackageDependency): void { const gitTagsRefMatch = gitTagsRefMatchRegex.exec(dep.managerData.source); /* eslint-disable no-param-reassign */ if (githubRefMatch) { - dep.lookupName = githubRefMatch.groups.project.replace(/\.git$/, ''); + dep.lookupName = githubRefMatch.groups.project.replace(regEx(/\.git$/), ''); dep.depType = 'module'; dep.depName = 'github.com/' + dep.lookupName; dep.currentValue = githubRefMatch.groups.tag; diff --git a/lib/manager/terraform/providers.ts b/lib/manager/terraform/providers.ts index 09e925df26..0b07a7251b 100644 --- a/lib/manager/terraform/providers.ts +++ b/lib/manager/terraform/providers.ts @@ -2,6 +2,7 @@ import is from '@sindresorhus/is'; import { TerraformProviderDatasource } from '../../datasource/terraform-provider'; import { logger } from '../../logger'; import { SkipReason } from '../../types'; +import { regEx } from '../../util/regex'; import type { PackageDependency } from '../types'; import { TerraformDependencyTypes } from './common'; import type { ProviderLock } from './lockfile/types'; @@ -12,8 +13,9 @@ import { massageProviderLookupName, } from './util'; -export const sourceExtractionRegex = - /^(?:(?<hostname>(?:[a-zA-Z0-9]+\.+)+[a-zA-Z0-9]+)\/)?(?:(?<namespace>[^/]+)\/)?(?<type>[^/]+)/; +export const sourceExtractionRegex = regEx( + /^(?:(?<hostname>(?:[a-zA-Z0-9]+\.+)+[a-zA-Z0-9]+)\/)?(?:(?<namespace>[^/]+)\/)?(?<type>[^/]+)/ +); export function extractTerraformProvider( startingLine: number, @@ -36,11 +38,12 @@ export function extractTerraformProvider( } const line = lines[lineNumber]; + // istanbul ignore next if (is.string(line)) { // `{` will be counted wit +1 and `}` with -1. Therefore if we reach braceCounter == 0. We have found the end of the terraform block - const openBrackets = (line.match(/\{/g) || []).length; - const closedBrackets = (line.match(/\}/g) || []).length; + const openBrackets = (line.match(/\{/g) || []).length; // TODO #12071 #12070 + const closedBrackets = (line.match(/\}/g) || []).length; // TODO #12071 #12070 braceCounter = braceCounter + openBrackets - closedBrackets; // only update fields inside the root block diff --git a/lib/manager/terraform/required-providers.ts b/lib/manager/terraform/required-providers.ts index 95c7f0d25f..6ac73de512 100644 --- a/lib/manager/terraform/required-providers.ts +++ b/lib/manager/terraform/required-providers.ts @@ -1,3 +1,4 @@ +import { regEx } from '../../util/regex'; import type { PackageDependency } from '../types'; import { TerraformDependencyTypes } from './common'; import type { ProviderLock } from './lockfile/types'; @@ -5,7 +6,7 @@ import { analyzeTerraformProvider } from './providers'; import type { ExtractionResult } from './types'; import { keyValueExtractionRegex } from './util'; -export const providerBlockExtractionRegex = /^\s*(?<key>[^\s]+)\s+=\s+{/; +export const providerBlockExtractionRegex = regEx(/^\s*(?<key>[^\s]+)\s+=\s+{/); function extractBlock( lineNum: number, diff --git a/lib/manager/terraform/required-version.ts b/lib/manager/terraform/required-version.ts index d5f6020389..dc16f52211 100644 --- a/lib/manager/terraform/required-version.ts +++ b/lib/manager/terraform/required-version.ts @@ -20,8 +20,8 @@ export function extractTerraformRequiredVersion( const line = lines[lineNumber]; // `{` will be counted wit +1 and `}` with -1. Therefore if we reach braceCounter == 0. We have found the end of the terraform block - const openBrackets = (line.match(/\{/g) || []).length; - const closedBrackets = (line.match(/\}/g) || []).length; + const openBrackets = (line.match(/\{/g) || []).length; // TODO #12070 + const closedBrackets = (line.match(/\}/g) || []).length; // TODO #12070 braceCounter = braceCounter + openBrackets - closedBrackets; const kvMatch = keyValueExtractionRegex.exec(line); diff --git a/lib/manager/terraform/util.ts b/lib/manager/terraform/util.ts index 10082d7d55..9793c547c1 100644 --- a/lib/manager/terraform/util.ts +++ b/lib/manager/terraform/util.ts @@ -1,12 +1,15 @@ import { TerraformProviderDatasource } from '../../datasource/terraform-provider'; +import { regEx } from '../../util/regex'; import type { PackageDependency } from '../types'; import { TerraformDependencyTypes } from './common'; import type { ProviderLock } from './lockfile/types'; -export const keyValueExtractionRegex = - /^\s*(?<key>[^\s]+)\s+=\s+"(?<value>[^"]+)"\s*$/; -export const resourceTypeExtractionRegex = - /^\s*resource\s+"(?<type>[^\s]+)"\s+"(?<name>[^"]+)"\s*{/; +export const keyValueExtractionRegex = regEx( + /^\s*(?<key>[^\s]+)\s+=\s+"(?<value>[^"]+)"\s*$/ +); +export const resourceTypeExtractionRegex = regEx( + /^\s*resource\s+"(?<type>[^\s]+)"\s+"(?<name>[^"]+)"\s*{/ +); export function getTerraformDependencyType( value: string @@ -40,7 +43,7 @@ export function checkFileContainsDependency( return checkList.some((check) => content.includes(check)); } -const pathStringRegex = /(.|..)?(\/[^/])+/; +const pathStringRegex = regEx(/(.|..)?(\/[^/])+/); export function checkIfStringIsPath(path: string): boolean { const match = pathStringRegex.exec(path); return !!match; diff --git a/lib/manager/terragrunt/extract.ts b/lib/manager/terragrunt/extract.ts index 6f114a45f1..978359b6a8 100644 --- a/lib/manager/terragrunt/extract.ts +++ b/lib/manager/terragrunt/extract.ts @@ -1,4 +1,5 @@ import { logger } from '../../logger'; +import { regEx } from '../../util/regex'; import type { PackageDependency, PackageFile } from '../types'; import { TerragruntDependencyTypes } from './common'; import { analyseTerragruntModule, extractTerragruntModule } from './modules'; @@ -8,7 +9,7 @@ import { getTerragruntDependencyType, } from './util'; -const dependencyBlockExtractionRegex = /^\s*(?<type>[a-z_]+)\s+{\s*$/; +const dependencyBlockExtractionRegex = regEx(/^\s*(?<type>[a-z_]+)\s+{\s*$/); const contentCheckList = ['terraform {']; export function extractPackageFile(content: string): PackageFile | null { diff --git a/lib/manager/terragrunt/modules.ts b/lib/manager/terragrunt/modules.ts index 3b3f0e4ba5..be070cbd40 100644 --- a/lib/manager/terragrunt/modules.ts +++ b/lib/manager/terragrunt/modules.ts @@ -3,16 +3,19 @@ import * as datasourceGithubTags from '../../datasource/github-tags'; import { TerraformModuleDatasource } from '../../datasource/terraform-module'; import { logger } from '../../logger'; import { SkipReason } from '../../types'; +import { regEx } from '../../util/regex'; import type { PackageDependency } from '../types'; import { TerragruntDependencyTypes } from './common'; import { extractTerragruntProvider } from './providers'; import type { ExtractionResult } from './types'; -export const githubRefMatchRegex = - /github\.com([/:])(?<project>[^/]+\/[a-z0-9-_.]+).*\?ref=(?<tag>.*)$/i; -export const gitTagsRefMatchRegex = - /(?:git::)?(?<url>(?:http|https|ssh):\/\/(?:.*@)?(?<path>.*.*\/(?<project>.*\/.*)))\?ref=(?<tag>.*)$/; -const hostnameMatchRegex = /^(?<hostname>([\w|\d]+\.)+[\w|\d]+)/; +export const githubRefMatchRegex = regEx( + /github\.com([/:])(?<project>[^/]+\/[a-z0-9-_.]+).*\?ref=(?<tag>.*)$/i +); +export const gitTagsRefMatchRegex = regEx( + /(?:git::)?(?<url>(?:http|https|ssh):\/\/(?:.*@)?(?<path>.*.*\/(?<project>.*\/.*)))\?ref=(?<tag>.*)$/ +); +const hostnameMatchRegex = regEx(/^(?<hostname>([\w|\d]+\.)+[\w|\d]+)/); export function extractTerragruntModule( startingLine: number, @@ -34,7 +37,7 @@ export function analyseTerragruntModule(dep: PackageDependency): void { /* eslint-disable no-param-reassign */ if (githubRefMatch) { dep.depType = 'github'; - dep.lookupName = githubRefMatch.groups.project.replace(/\.git$/, ''); + dep.lookupName = githubRefMatch.groups.project.replace(regEx(/\.git$/), ''); dep.depName = 'github.com/' + dep.lookupName; dep.currentValue = githubRefMatch.groups.tag; dep.datasource = datasourceGithubTags.id; diff --git a/lib/manager/terragrunt/providers.ts b/lib/manager/terragrunt/providers.ts index 284a6053a3..f44650ecee 100644 --- a/lib/manager/terragrunt/providers.ts +++ b/lib/manager/terragrunt/providers.ts @@ -1,10 +1,12 @@ +import { regEx } from '../../util/regex'; import type { PackageDependency } from '../types'; import { TerragruntDependencyTypes } from './common'; import type { ExtractionResult } from './types'; import { keyValueExtractionRegex } from './util'; -export const sourceExtractionRegex = - /^(?:(?<hostname>(?:[a-zA-Z0-9]+\.+)+[a-zA-Z0-9]+)\/)?(?:(?<namespace>[^/]+)\/)?(?<type>[^/]+)/; +export const sourceExtractionRegex = regEx( + /^(?:(?<hostname>(?:[a-zA-Z0-9]+\.+)+[a-zA-Z0-9]+)\/)?(?:(?<namespace>[^/]+)\/)?(?<type>[^/]+)/ +); function extractBracesContent(content): number { const stack = []; diff --git a/lib/manager/terragrunt/util.ts b/lib/manager/terragrunt/util.ts index 63ebc18956..b920ebb934 100644 --- a/lib/manager/terragrunt/util.ts +++ b/lib/manager/terragrunt/util.ts @@ -1,6 +1,9 @@ +import { regEx } from '../../util/regex'; import { TerragruntDependencyTypes } from './common'; -export const keyValueExtractionRegex = /^\s*source\s+=\s+"(?<value>[^"]+)"\s*$/; +export const keyValueExtractionRegex = regEx( + /^\s*source\s+=\s+"(?<value>[^"]+)"\s*$/ +); export function getTerragruntDependencyType( value: string diff --git a/lib/platform/azure/index.ts b/lib/platform/azure/index.ts index 60185e64fb..f0bfd15f20 100644 --- a/lib/platform/azure/index.ts +++ b/lib/platform/azure/index.ts @@ -14,6 +14,7 @@ import { logger } from '../../logger'; import { BranchStatus, PrState, VulnerabilityAlert } from '../../types'; import * as git from '../../util/git'; import * as hostRules from '../../util/host-rules'; +import { regEx } from '../../util/regex'; import { sanitize } from '../../util/sanitize'; import { ensureTrailingSlash } from '../../util/url'; import type { @@ -678,7 +679,7 @@ export function massageMarkdown(input: string): string { 'you tick the rebase/retry checkbox', 'rename PR to start with "rebase!"' ) - .replace(new RegExp(`\n---\n\n.*?<!-- rebase-check -->.*?\n`), ''); + .replace(regEx(`\n---\n\n.*?<!-- rebase-check -->.*?\n`), ''); } /* istanbul ignore next */ diff --git a/lib/platform/bitbucket-server/index.ts b/lib/platform/bitbucket-server/index.ts index d88faecdf3..9612e13570 100644 --- a/lib/platform/bitbucket-server/index.ts +++ b/lib/platform/bitbucket-server/index.ts @@ -20,6 +20,7 @@ import { BitbucketServerHttp, setBaseUrl, } from '../../util/http/bitbucket-server'; +import { regEx } from '../../util/regex'; import { sanitize } from '../../util/sanitize'; import { ensureTrailingSlash, getQueryString } from '../../util/url'; import type { @@ -784,7 +785,7 @@ export async function ensureCommentRemoval({ // Pull Request const escapeHash = (input: string): string => - input ? input.replace(/#/g, '%23') : input; + input ? input.replace(regEx(/#/g), '%23') : input; export async function createPr({ sourceBranch, @@ -991,10 +992,10 @@ export function massageMarkdown(input: string): string { 'you tick the rebase/retry checkbox', 'rename PR to start with "rebase!"' ) - .replace(/<\/?summary>/g, '**') - .replace(/<\/?details>/g, '') - .replace(new RegExp(`\n---\n\n.*?<!-- rebase-check -->.*?(\n|$)`), '') - .replace(new RegExp('<!--.*?-->', 'g'), ''); + .replace(regEx(/<\/?summary>/g), '**') + .replace(regEx(/<\/?details>/g), '') + .replace(regEx(`\n---\n\n.*?<!-- rebase-check -->.*?(\n|$)`), '') + .replace(regEx('<!--.*?-->', 'g'), ''); } export function getVulnerabilityAlerts(): Promise<VulnerabilityAlert[]> { diff --git a/lib/platform/bitbucket/index.ts b/lib/platform/bitbucket/index.ts index aca5adc95b..c2e4db583b 100644 --- a/lib/platform/bitbucket/index.ts +++ b/lib/platform/bitbucket/index.ts @@ -8,6 +8,7 @@ import { BranchStatus, PrState, VulnerabilityAlert } from '../../types'; import * as git from '../../util/git'; import * as hostRules from '../../util/host-rules'; import { BitbucketHttp, setBaseUrl } from '../../util/http/bitbucket'; +import { regEx } from '../../util/regex'; import { sanitize } from '../../util/sanitize'; import type { BranchStatusConfig, @@ -173,7 +174,7 @@ export async function initRepo({ // Converts API hostnames to their respective HTTP git hosts: // `api.bitbucket.org` to `bitbucket.org` // `api-staging.<host>` to `staging.<host>` - const hostnameWithoutApiPrefix = /api[.|-](.+)/.exec(hostname)[1]; + const hostnameWithoutApiPrefix = regEx(/api[.|-](.+)/).exec(hostname)[1]; const url = git.getUrl({ protocol: 'https', @@ -286,7 +287,7 @@ export async function getPr(prNo: number): Promise<Pr | null> { } const escapeHash = (input: string): string => - input ? input.replace(/#/g, '%23') : input; + input ? input.replace(regEx(/#/g), '%23') : input; interface BranchResponse { target: { @@ -462,10 +463,10 @@ export function massageMarkdown(input: string): string { 'you tick the rebase/retry checkbox', 'rename PR to start with "rebase!"' ) - .replace(/<\/?summary>/g, '**') - .replace(/<\/?details>/g, '') - .replace(new RegExp(`\n---\n\n.*?<!-- rebase-check -->.*?\n`), '') - .replace(/\]\(\.\.\/pull\//g, '](../../pull-requests/'); + .replace(regEx(/<\/?summary>/g), '**') + .replace(regEx(/<\/?details>/g), '') + .replace(regEx(`\n---\n\n.*?<!-- rebase-check -->.*?\n`), '') + .replace(regEx(/\]\(\.\.\/pull\//g), '](../../pull-requests/'); } export async function ensureIssue({ diff --git a/lib/platform/gitea/utils.ts b/lib/platform/gitea/utils.ts index d9cfe3495f..492644bf7d 100644 --- a/lib/platform/gitea/utils.ts +++ b/lib/platform/gitea/utils.ts @@ -1,3 +1,5 @@ +import { regEx } from '../../util/regex'; + export function smartLinks(body: string): string { - return body?.replace(/\]\(\.\.\/pull\//g, '](pulls/'); + return body?.replace(regEx(/\]\(\.\.\/pull\//g), '](pulls/'); } diff --git a/lib/platform/github/index.ts b/lib/platform/github/index.ts index aa7debfa87..457cd5bb67 100644 --- a/lib/platform/github/index.ts +++ b/lib/platform/github/index.ts @@ -23,6 +23,7 @@ import { getCache } from '../../util/cache/repository'; import * as git from '../../util/git'; import * as hostRules from '../../util/host-rules'; import * as githubHttp from '../../util/http/github'; +import { regEx } from '../../util/regex'; import { sanitize } from '../../util/sanitize'; import { ensureTrailingSlash } from '../../util/url'; import type { @@ -78,7 +79,7 @@ const defaults = { }; const escapeHash = (input: string): string => - input ? input.replace(/#/g, '%23') : input; + input ? input.replace(regEx(/#/g), '%23') : input; export async function initPlatform({ endpoint, @@ -768,7 +769,7 @@ export async function getBranchPr(branchName: string): Promise<Pr | null> { return null; } try { - const title = autoclosedPr.title.replace(/ - autoclosed$/, ''); + const title = autoclosedPr.title.replace(regEx(/ - autoclosed$/), ''); await githubApi.patchJson(`repos/${config.repository}/pulls/${number}`, { body: { state: 'open', @@ -1181,7 +1182,7 @@ export async function addReviewers( const userReviewers = reviewers.filter((e) => !e.startsWith('team:')); const teamReviewers = reviewers .filter((e) => e.startsWith('team:')) - .map((e) => e.replace(/^team:/, '')); + .map((e) => e.replace(regEx(/^team:/), '')); // TODO #12071 try { await githubApi.postJson( `repos/${ @@ -1623,9 +1624,12 @@ export function massageMarkdown(input: string): string { } const massagedInput = massageMarkdownLinks(input) // to be safe, replace all github.com links with renovatebot redirector - .replace(/href="https?:\/\/github.com\//g, 'href="https://togithub.com/') - .replace(/]\(https:\/\/github\.com\//g, '](https://togithub.com/') - .replace(/]: https:\/\/github\.com\//g, ']: https://togithub.com/'); + .replace( + regEx(/href="https?:\/\/github.com\//g), + 'href="https://togithub.com/' + ) + .replace(regEx(/]\(https:\/\/github\.com\//g), '](https://togithub.com/') + .replace(regEx(/]: https:\/\/github\.com\//g), ']: https://togithub.com/'); return smartTruncate(massagedInput, 60000); } diff --git a/lib/platform/github/massage-markdown-links.ts b/lib/platform/github/massage-markdown-links.ts index 7c788b3f67..cbff68d00f 100644 --- a/lib/platform/github/massage-markdown-links.ts +++ b/lib/platform/github/massage-markdown-links.ts @@ -3,6 +3,7 @@ import remark from 'remark'; import type { Plugin, Transformer } from 'unified'; import { logger } from '../../logger'; import { hasKey } from '../../util/object'; +import { regEx } from '../../util/regex'; interface UrlMatch { start: number; @@ -11,10 +12,10 @@ interface UrlMatch { } const urlRegex = - /(?:https?:)?(?:\/\/)?(?:www\.)?(?<!api\.)(?:to)?github\.com\/[-_a-z0-9]+\/[-_a-z0-9]+\/(?:discussions|issues|pull)\/[0-9]+(?:#[-_a-z0-9]+)?/i; + /(?:https?:)?(?:\/\/)?(?:www\.)?(?<!api\.)(?:to)?github\.com\/[-_a-z0-9]+\/[-_a-z0-9]+\/(?:discussions|issues|pull)\/[0-9]+(?:#[-_a-z0-9]+)?/i; // TODO #12070 function massageLink(input: string): string { - return input.replace(/(?:to)?github\.com/i, 'togithub.com'); + return input.replace(regEx(/(?:to)?github\.com/i), 'togithub.com'); // TODO #12071 } function collectLinkPosition(input: string, matches: UrlMatch[]): Plugin { diff --git a/lib/platform/gitlab/index.ts b/lib/platform/gitlab/index.ts index 6d6f784419..348372468e 100644 --- a/lib/platform/gitlab/index.ts +++ b/lib/platform/gitlab/index.ts @@ -22,6 +22,7 @@ import * as git from '../../util/git'; import * as hostRules from '../../util/host-rules'; import { HttpResponse } from '../../util/http'; import { setBaseUrl } from '../../util/http/gitlab'; +import { regEx } from '../../util/regex'; import { sanitize } from '../../util/sanitize'; import { ensureTrailingSlash, getQueryString, parseUrl } from '../../util/url'; import type { @@ -150,7 +151,7 @@ export async function getRepos(): Promise<string[]> { } function urlEscape(str: string): string { - return str ? str.replace(/\//g, '%2F') : str; + return str ? str.replace(regEx(/\//g), '%2F') : str; } export async function getRawFile( @@ -669,9 +670,9 @@ export async function mergePr({ id }: MergePRConfig): Promise<boolean> { export function massageMarkdown(input: string): string { let desc = input - .replace(/Pull Request/g, 'Merge Request') - .replace(/PR/g, 'MR') - .replace(/\]\(\.\.\/pull\//g, '](!'); + .replace(regEx(/Pull Request/g), 'Merge Request') + .replace(regEx(/PR/g), 'MR') + .replace(regEx(/\]\(\.\.\/pull\//g), '](!'); if (lt(defaults.version, '13.4.0')) { logger.debug( @@ -1073,7 +1074,9 @@ export async function ensureComment({ }: EnsureCommentConfig): Promise<boolean> { const sanitizedContent = sanitize(content); const massagedTopic = topic - ? topic.replace(/Pull Request/g, 'Merge Request').replace(/PR/g, 'MR') + ? topic + .replace(regEx(/Pull Request/g), 'Merge Request') + .replace(regEx(/PR/g), 'MR') : topic; const comments = await getComments(number); let body: string; @@ -1082,7 +1085,9 @@ export async function ensureComment({ if (topic) { logger.debug(`Ensuring comment "${massagedTopic}" in #${number}`); body = `### ${topic}\n\n${sanitizedContent}`; - body = body.replace(/Pull Request/g, 'Merge Request').replace(/PR/g, 'MR'); + body = body + .replace(regEx(/Pull Request/g), 'Merge Request') + .replace(regEx(/PR/g), 'MR'); comments.forEach((comment: { body: string; id: number }) => { if (comment.body.startsWith(`### ${massagedTopic}\n\n`)) { commentId = comment.id; diff --git a/lib/platform/utils/read-only-issue-body.ts b/lib/platform/utils/read-only-issue-body.ts index d2ffa1d4de..43bca3bcfd 100644 --- a/lib/platform/utils/read-only-issue-body.ts +++ b/lib/platform/utils/read-only-issue-body.ts @@ -1,10 +1,12 @@ +import { regEx } from '../../util/regex'; + export function readOnlyIssueBody(body: string): string { return body .replace(' only once you click their checkbox below', '') .replace(' unless you click a checkbox below', '') .replace(' To discard all commits and start over, click on a checkbox.', '') - .replace(/ Click (?:on |)a checkbox.*\./g, '') - .replace(/\[ ] <!-- \w*-branch.*-->/g, ''); + .replace(regEx(/ Click (?:on |)a checkbox.*\./g), '') + .replace(regEx(/\[ ] <!-- \w*-branch.*-->/g), ''); } export default readOnlyIssueBody; -- GitLab