- drop exec and execAll in favor of the much simpler regexr based solution

- define regex, define target pattern. success 🎉
This commit is contained in:
Mike Penz
2024-03-01 16:42:29 +00:00
committed by GitHub
parent 40d2beb495
commit 2a0a3aa6dc
5 changed files with 135 additions and 118 deletions
+40 -52
View File
@@ -34,7 +34,7 @@ export function buildRegex(
regex: Regex,
target: string | undefined,
onProperty?: Property[] | undefined,
method?: 'replace' | 'replaceAll' | 'match' | 'exec' | 'execAll' | undefined,
method?: 'replace' | 'replaceAll' | 'match' | 'regexr' | undefined,
onEmpty?: string | undefined
): RegexTransformer | null {
try {
@@ -51,66 +51,19 @@ export function buildRegex(
}
}
// eslint-disable-next-line no-undef
export function applyCaptureGroup(value: RegExpMatchArray, target: string): string | null {
const groups = value['groups']
if (groups) {
const matched = groups[target]
if (matched) {
// if we had a perfect group match return that.
return matched
}
}
if (target.startsWith('$') && !target.startsWith('$$')) {
// if we start with $ offer support for matching index based capture groups
const index = Number(target.substring(1))
if (!isNaN(index) && index < value.length) {
return value[index]
}
}
return null
}
export function transformStringToValues(value: string, extractor: RegexTransformer): string[] | null {
if (extractor.pattern == null) {
return null
}
if (extractor.method === 'exec' || extractor.method === 'execAll') {
// eslint-disable-next-line no-undef
let matches: RegExpMatchArray | null
const result: Set<string> = new Set()
// match regex to all occurrences in the string if we run `execAll`
// otherwise just do the first match with exec
do {
matches = extractor.pattern.exec(value)
if (matches) {
if (extractor.target) {
const matchedGroup = applyCaptureGroup(matches, extractor.target)
if (matchedGroup) {
result.add(matchedGroup)
}
} else {
for (const match of matches) {
result.add(match)
}
}
}
} while (matches && extractor.method === 'execAll')
if (result.size > 0) {
return [...result]
if (extractor.method === 'regexr') {
const matches = transformRegexr(extractor.pattern, value, extractor.target)
if (matches !== null && matches.size > 0) {
return [...matches]
}
} else if (extractor.method === 'match') {
const matches = value.match(extractor.pattern)
if (matches !== null && matches.length > 0) {
if (extractor.target) {
const matchedGroup = applyCaptureGroup(matches, extractor.target)
if (matchedGroup) {
return [matchedGroup]
}
}
return matches.map(match => match || '')
}
} else if (extractor.method === 'replaceAll') {
@@ -142,3 +95,38 @@ export function transformStringToOptionalValue(value: string, extractor: RegexTr
export function transformStringToValue(value: string, extractor: RegexTransformer): string {
return transformStringToOptionalValue(value, extractor) || ''
}
function transformRegexr(regex: RegExp, source: string, target: string): Set<string> | null {
/**
* Util funtion extracted from regexr and is licensed under:
*
* RegExr: Learn, Build, & Test RegEx
* Copyright (C) 2017 gskinner.com, inc.
* https://github.com/gskinner/regexr/blob/master/dev/src/helpers/BrowserSolver.js#L111-L136
*/
let repl
let ref
if (target.search(/\$[&1-9`']/) === -1) {
target = `$&${target}`
}
const firstOnly = true // for now we don't support multi matches for PRs, future improvement
const adaptedRegex = new RegExp(regex.source, regex.flags.replace('g', ''))
const result = new Set<string>()
do {
ref = source.replace(adaptedRegex, '\b') // bell char - just a placeholder to find
const index = ref.indexOf('\b')
const empty = ref.length > source.length
if (index === -1) {
break
}
repl = source.replace(adaptedRegex, target)
result.add(repl.substr(index, repl.length - ref.length + 1))
source = ref.substr(index + (empty ? 2 : 1))
if (firstOnly) {
break
}
} while (source.length)
return result
}
+2 -2
View File
@@ -43,7 +43,7 @@ export interface Regex {
pattern: string // the regex pattern to match
flags?: string // the regex flag to use for RegExp
target?: string // the target string to transform the source string using the regex to
method?: 'replace' | 'replaceAll' | 'match' | 'exec' | 'execAll' | undefined // the method to use to extract the value, `match` will not use the `target` property
method?: 'replace' | 'replaceAll' | 'match' | 'regexr' | undefined // the method to use to extract the value, `match` will not use the `target` property
on_empty?: string | undefined // in case the regex results in an empty string, this value is gonna be used instead (only for label_extractor currently)
}
@@ -55,6 +55,6 @@ export interface RegexTransformer {
pattern: RegExp | null
target: string
onProperty?: Property[]
method?: 'replace' | 'replaceAll' | 'match' | 'exec' | 'execAll'
method?: 'replace' | 'replaceAll' | 'match' | 'regexr'
onEmpty?: string
}