refactor(web): replace String.match() with RegExp.exec() for non-global regex (#32386)
Some checks are pending
autofix.ci / autofix (push) Waiting to run
Build and Push API & Web / build (api, DIFY_API_IMAGE_NAME, linux/amd64, build-api-amd64) (push) Waiting to run
Build and Push API & Web / build (api, DIFY_API_IMAGE_NAME, linux/arm64, build-api-arm64) (push) Waiting to run
Build and Push API & Web / build (web, DIFY_WEB_IMAGE_NAME, linux/amd64, build-web-amd64) (push) Waiting to run
Build and Push API & Web / build (web, DIFY_WEB_IMAGE_NAME, linux/arm64, build-web-arm64) (push) Waiting to run
Build and Push API & Web / create-manifest (api, DIFY_API_IMAGE_NAME, merge-api-images) (push) Blocked by required conditions
Build and Push API & Web / create-manifest (web, DIFY_WEB_IMAGE_NAME, merge-web-images) (push) Blocked by required conditions
Main CI Pipeline / Check Changed Files (push) Waiting to run
Main CI Pipeline / API Tests (push) Blocked by required conditions
Main CI Pipeline / Web Tests (push) Blocked by required conditions
Main CI Pipeline / Style Check (push) Waiting to run
Main CI Pipeline / VDB Tests (push) Blocked by required conditions
Main CI Pipeline / DB Migration Test (push) Blocked by required conditions

This commit is contained in:
Apoorv Darshan 2026-02-18 14:16:38 +05:30 committed by GitHub
parent 41a4a57d2e
commit 00591a592c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 22 additions and 22 deletions

View File

@ -588,7 +588,7 @@ export default translation
const trimmedKeyLine = keyLine.trim()
// If key line ends with ":" (not complete value), it's likely multiline
if (trimmedKeyLine.endsWith(':') && !trimmedKeyLine.includes('{') && !trimmedKeyLine.match(/:\s*['"`]/)) {
if (trimmedKeyLine.endsWith(':') && !trimmedKeyLine.includes('{') && !/:\s*['"`]/.exec(trimmedKeyLine)) {
// Find the value lines that belong to this key
let currentLine = targetLineIndex + 1
let foundValue = false
@ -604,7 +604,7 @@ export default translation
}
// Check if this line starts a new key (indicates end of current value)
if (trimmed.match(/^\w+\s*:/))
if (/^\w+\s*:/.exec(trimmed))
break
// Check if this line is part of the value

View File

@ -109,7 +109,7 @@ const Configuration: FC = () => {
const [hasFetchedDetail, setHasFetchedDetail] = useState(false)
const isLoading = !hasFetchedDetail
const pathname = usePathname()
const matched = pathname.match(/\/app\/([^/]+)/)
const matched = /\/app\/([^/]+)/.exec(pathname)
const appId = (matched?.length && matched[1]) ? matched[1] : ''
const [mode, setMode] = useState<AppModeEnum>(AppModeEnum.CHAT)
const [publishedConfig, setPublishedConfig] = useState<PublishConfig | null>(null)

View File

@ -70,7 +70,7 @@ const BlockInput: FC<IBlockInputProps> = ({
const renderSafeContent = (value: string) => {
const parts = value.split(/(\{\{[^}]+\}\}|\n)/g)
return parts.map((part, index) => {
const variableMatch = part.match(/^\{\{([^}]+)\}\}$/)
const variableMatch = /^\{\{([^}]+)\}\}$/.exec(part)
if (variableMatch) {
return (
<VarHighlight

View File

@ -17,7 +17,7 @@ const ContentItem = ({
const extractFieldName = (str: string): string => {
const outputVarRegex = /\{\{#\$output\.([^#]+)#\}\}/
const match = str.match(outputVarRegex)
const match = outputVarRegex.exec(str)
return match ? match[1] : ''
}

View File

@ -111,7 +111,7 @@ export const convertTimezoneToOffsetStr = (timezone?: string) => {
return DEFAULT_OFFSET_STR
// Extract offset from name format like "-11:00 Niue Time" or "+05:30 India Time"
// Name format is always "{offset}:{minutes} {timezone name}"
const offsetMatch = tzItem.name.match(/^([+-]?\d{1,2}):(\d{2})/)
const offsetMatch = /^([+-]?\d{1,2}):(\d{2})/.exec(tzItem.name)
if (!offsetMatch)
return DEFAULT_OFFSET_STR
// Parse hours and minutes separately

View File

@ -27,7 +27,7 @@ const AnnotationReply = ({
const { t } = useTranslation()
const router = useRouter()
const pathname = usePathname()
const matched = pathname.match(/\/app\/([^/]+)/)
const matched = /\/app\/([^/]+)/.exec(pathname)
const appId = (matched?.length && matched[1]) ? matched[1] : ''
const featuresStore = useFeaturesStore()
const annotationReply = useFeatures(s => s.features.annotationReply)

View File

@ -29,7 +29,7 @@ const VoiceParamConfig = ({
}: VoiceParamConfigProps) => {
const { t } = useTranslation()
const pathname = usePathname()
const matched = pathname.match(/\/app\/([^/]+)/)
const matched = /\/app\/([^/]+)/.exec(pathname)
const appId = (matched?.length && matched[1]) ? matched[1] : ''
const text2speech = useFeatures(state => state.features.text2speech)
const featuresStore = useFeaturesStore()

View File

@ -21,7 +21,7 @@ export type IGAProps = {
const extractNonceFromCSP = (cspHeader: string | null): string | undefined => {
if (!cspHeader)
return undefined
const nonceMatch = cspHeader.match(/'nonce-([^']+)'/)
const nonceMatch = /'nonce-([^']+)'/.exec(cspHeader)
return nonceMatch ? nonceMatch[1] : undefined
}

View File

@ -239,7 +239,7 @@ const Flowchart = (props: FlowchartProps) => {
.split('\n')
.map((line) => {
// Gantt charts have specific syntax needs.
const taskMatch = line.match(/^\s*([^:]+?)\s*:\s*(.*)/)
const taskMatch = /^\s*([^:]+?)\s*:\s*(.*)/.exec(line)
if (!taskMatch)
return line // Not a task line, return as is.

View File

@ -185,7 +185,7 @@ export function isMermaidCodeComplete(code: string): boolean {
const hasNoSyntaxErrors = !trimmedCode.includes('undefined')
&& !trimmedCode.includes('[object Object]')
&& trimmedCode.split('\n').every(line =>
!(line.includes('-->') && !line.match(/\S+\s*-->\s*\S+/)))
!(line.includes('-->') && !/\S+\s*-->\s*\S+/.exec(line)))
return hasValidStart && isBalanced && hasNoSyntaxErrors
}

View File

@ -7,7 +7,7 @@ import { ALL_PLANS, NUM_INFINITE } from '@/app/components/billing/config'
* @example "50MB" -> 50, "5GB" -> 5120, "20GB" -> 20480
*/
export const parseVectorSpaceToMB = (vectorSpace: string): number => {
const match = vectorSpace.match(/^(\d+)(MB|GB)$/i)
const match = /^(\d+)(MB|GB)$/i.exec(vectorSpace)
if (!match)
return 0

View File

@ -98,8 +98,8 @@ describe('CredentialIcon', () => {
const classes1 = wrapper1.className
const classes2 = wrapper2.className
const bgClass1 = classes1.match(/bg-components-icon-bg-\S+/)?.[0]
const bgClass2 = classes2.match(/bg-components-icon-bg-\S+/)?.[0]
const bgClass1 = /bg-components-icon-bg-\S+/.exec(classes1)?.[0]
const bgClass2 = /bg-components-icon-bg-\S+/.exec(classes2)?.[0]
expect(bgClass1).toBe(bgClass2)
})
@ -112,8 +112,8 @@ describe('CredentialIcon', () => {
const wrapper1 = container1.firstChild as HTMLElement
const wrapper2 = container2.firstChild as HTMLElement
const bgClass1 = wrapper1.className.match(/bg-components-icon-bg-\S+/)?.[0]
const bgClass2 = wrapper2.className.match(/bg-components-icon-bg-\S+/)?.[0]
const bgClass1 = /bg-components-icon-bg-\S+/.exec(wrapper1.className)?.[0]
const bgClass2 = /bg-components-icon-bg-\S+/.exec(wrapper2.className)?.[0]
expect(bgClass1).toBeDefined()
expect(bgClass2).toBeDefined()

View File

@ -12,7 +12,7 @@ import { uploadRemoteFileInfo } from '@/service/common'
const DEFAULT_ICON = { type: 'emoji', icon: '🔗', background: '#6366F1' }
const extractFileId = (url: string) => {
const match = url.match(/files\/(.+?)\/file-preview/)
const match = /files\/(.+?)\/file-preview/.exec(url)
return match ? match[1] : null
}

View File

@ -140,7 +140,7 @@ export class ComponentAnalyzer {
maxMessages.forEach((msg) => {
if (msg.ruleId === 'sonarjs/cognitive-complexity') {
const match = msg.message.match(complexityPattern)
const match = complexityPattern.exec(msg.message)
if (match && match[1])
max = Math.max(max, Number.parseInt(match[1], 10))
}

View File

@ -377,7 +377,7 @@ async function main(): Promise<void> {
for (const openapiPath of openApiPaths) {
// Determine language from path
const langMatch = openapiPath.match(/^(en|zh|ja)\//)
const langMatch = /^(en|zh|ja)\//.exec(openapiPath)
if (!langMatch)
continue

View File

@ -31,7 +31,7 @@ export const parsePluginErrorMessage = async (error: any): Promise<string> => {
// Try to extract nested JSON from PluginInvokeError
// Use greedy match .+ to capture the complete JSON object with nested braces
const pluginErrorPattern = /PluginInvokeError:\s*(\{.+\})/
const match = rawMessage.match(pluginErrorPattern)
const match = pluginErrorPattern.exec(rawMessage)
if (match) {
try {

View File

@ -39,7 +39,7 @@ export const formatNumber = (num: number | string) => {
// Force fixed decimal for small numbers to avoid scientific notation
if (Math.abs(n) < 0.001 && n !== 0) {
const str = n.toString()
const match = str.match(/e-(\d+)$/)
const match = /e-(\d+)$/.exec(str)
let precision: number
if (match) {
// Scientific notation: precision is exponent + decimal digits in mantissa

View File

@ -39,7 +39,7 @@ export function isPrivateOrLocalAddress(url: string): boolean {
// Check for private IP ranges
const ipv4Regex = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/
const ipv4Match = hostname.match(ipv4Regex)
const ipv4Match = ipv4Regex.exec(hostname)
if (ipv4Match) {
const [, a, b] = ipv4Match.map(Number)
// 10.0.0.0/8