Skip to content

Commit 720915b

Browse files
committed
improvement(utils): replace nine local escapeRegExp copies with the shared helper
1 parent d473981 commit 720915b

15 files changed

Lines changed: 29 additions & 67 deletions

File tree

‎apps/sim/app/(landing)/integrations/(shell)/[slug]/page.tsx‎

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ChipLink } from '@sim/emcn'
2-
import { truncate } from '@sim/utils/string'
2+
import { escapeRegExp, truncate } from '@sim/utils/string'
33
import type { Metadata } from 'next'
44
import Link from 'next/link'
55
import { notFound } from 'next/navigation'
@@ -127,10 +127,6 @@ function sentenceWithTerminalPunctuation(value: string): string {
127127
return /[.!?]$/.test(trimmedValue) ? trimmedValue : `${trimmedValue}.`
128128
}
129129

130-
function escapeRegex(value: string): string {
131-
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
132-
}
133-
134130
/**
135131
* Server-side rewrite of bare integration names in a curated template prompt
136132
* to `@`-mention form (`Slack` → `@Slack`) so the prompt chips with brand
@@ -152,7 +148,7 @@ function mentionifyPromptForNames(prompt: string, names: readonly string[]): str
152148
)
153149
if (unique.length === 0) return prompt
154150
const regex = new RegExp(
155-
`(?<![A-Za-z0-9_@])(${unique.map(escapeRegex).join('|')})(?![A-Za-z0-9_])`,
151+
`(?<![A-Za-z0-9_@])(${unique.map(escapeRegExp).join('|')})(?![A-Za-z0-9_])`,
156152
'gi'
157153
)
158154
return prompt.replace(regex, (match) => `@${match}`)

‎apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/prompt-editor/use-prompt-editor.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
22
import { toast } from '@sim/emcn'
33
import { assessTextPaste, PASTE_LIMITS, PASTE_RENDER_THRESHOLDS } from '@sim/utils/paste'
4+
import { escapeRegExp } from '@sim/utils/string'
45
import {
56
attachSelectionContextToClipboard,
67
readSelectionContextFromClipboard,
@@ -28,7 +29,6 @@ import {
2829
} from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/hooks'
2930
import {
3031
areContextsEqual,
31-
escapeRegex,
3232
filterContextsPresentInMessage,
3333
prepareContextForInsert,
3434
restoreSkillTriggerText,
@@ -369,7 +369,7 @@ export function usePromptEditor({
369369

370370
const labelIsUsed = (candidate: string): boolean => {
371371
if (selectedContexts.some((selected) => selected.label === candidate)) return true
372-
return new RegExp(`(^|\\s)@${escapeRegex(candidate)}(?![A-Za-z0-9_])`).test(currentValue)
372+
return new RegExp(`(^|\\s)@${escapeRegExp(candidate)}(?![A-Za-z0-9_])`).test(currentValue)
373373
}
374374

375375
while (labelIsUsed(label)) {

‎apps/sim/app/workspace/[workspaceId]/home/components/user-input/hooks/use-skill-auto-mention.ts‎

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import { useCallback, useMemo, useRef } from 'react'
2-
import {
3-
escapeRegex,
4-
SKILL_CHIP_TRIGGER,
5-
} from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/utils'
2+
import { escapeRegExp } from '@sim/utils/string'
3+
import { SKILL_CHIP_TRIGGER } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/utils'
64
import type { McpServer } from '@/hooks/queries/mcp'
75
import type { SkillDefinition } from '@/hooks/queries/skills'
86
import type { ChatContext } from '@/stores/panel'
@@ -104,8 +102,8 @@ export function useSkillAutoMention({
104102
// Match either trigger: the typed '/' or the stored sentinel, so both fresh
105103
// input and pasted/restored chips resolve. The trigger group is the match's
106104
// first char (`text[match.index]`); group 1 is the skill name.
107-
const trigger = `(?:/|${escapeRegex(SKILL_CHIP_TRIGGER)})`
108-
const pattern = `${trigger}(${names.map(escapeRegex).join('|')})(?![A-Za-z0-9_-])`
105+
const trigger = `(?:/|${escapeRegExp(SKILL_CHIP_TRIGGER)})`
106+
const pattern = `${trigger}(${names.map(escapeRegExp).join('|')})(?![A-Za-z0-9_-])`
109107
return { regex: new RegExp(pattern, 'gi'), byName }
110108
}, [skills, mcpServers])
111109

‎apps/sim/app/workspace/[workspaceId]/home/components/user-message-content/user-message-content.tsx‎

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import { useMemo } from 'react'
44
import { cn } from '@sim/emcn'
5+
import { escapeRegExp } from '@sim/utils/string'
56
import { ContextMentionIcon } from '@/app/workspace/[workspaceId]/home/components/context-mention-icon'
67
import type { ChatMessageContext } from '@/app/workspace/[workspaceId]/home/types'
78
import { getIntegrationMatcher } from '@/blocks/integration-matcher'
@@ -22,10 +23,6 @@ interface UserMessageContentProps {
2223
compact?: boolean
2324
}
2425

25-
function escapeRegex(str: string): string {
26-
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
27-
}
28-
2926
interface MentionRange {
3027
start: number
3128
end: number
@@ -54,7 +51,7 @@ function computeMentionRanges(text: string, contexts: ChatMessageContext[]): Men
5451
const ctx = withResolvedBlockType(rawCtx)
5552
const prefix = ctx.kind === 'skill' || ctx.kind === 'mcp' ? '/' : '@'
5653
const token = `${prefix}${ctx.label}`
57-
const pattern = new RegExp(`(^|\\s)(${escapeRegex(token)})(\\s|$)`, 'g')
54+
const pattern = new RegExp(`(^|\\s)(${escapeRegExp(token)})(\\s|$)`, 'g')
5855
let match: RegExpExecArray | null
5956
while ((match = pattern.exec(text)) !== null) {
6057
const leadingSpace = match[1]

‎apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/utils.ts‎

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { escapeRegExp } from '@sim/utils/string'
12
import {
23
FOLDER_CONFIGS,
34
type MentionFolderId,
@@ -24,15 +25,6 @@ export function restoreSkillTriggerText(text: string): string {
2425
return text.replaceAll(SKILL_CHIP_TRIGGER, '/')
2526
}
2627

27-
/**
28-
* Escapes special regex characters in a string
29-
* @param value - String to escape
30-
* @returns Escaped string safe for use in RegExp
31-
*/
32-
export function escapeRegex(value: string): string {
33-
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
34-
}
35-
3628
/**
3729
* Extracts mention tokens from contexts for display/matching
3830
* Filters out current_workflow contexts and builds prefixed labels
@@ -107,7 +99,7 @@ export function computeMentionHighlightRanges(
10799
if (!tokens.length || !text) return []
108100

109101
const longestFirstTokens = [...new Set(tokens)].sort((a, b) => b.length - a.length)
110-
const pattern = new RegExp(`(${longestFirstTokens.map(escapeRegex).join('|')})`, 'g')
102+
const pattern = new RegExp(`(${longestFirstTokens.map(escapeRegExp).join('|')})`, 'g')
111103
const ranges: MentionHighlightRange[] = []
112104
let match: RegExpExecArray | null
113105

‎apps/sim/blocks/integration-matcher.ts‎

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { escapeRegExp } from '@sim/utils/string'
12
import { LandingPromptStorage } from '@/lib/core/utils/browser-storage'
23
import { getCanonicalBlocksByCategory } from '@/blocks/registry'
34
import type { BlockIcon } from '@/blocks/types'
@@ -32,10 +33,6 @@ export interface IntegrationMatcher {
3233
byName: Map<string, IntegrationDescriptor>
3334
}
3435

35-
function escapeRegex(value: string): string {
36-
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
37-
}
38-
3936
/** Strips ` (Legacy)` / ` V2` suffixes so the display uses the natural name. */
4037
function normalizeDisplayName(name: string): string {
4138
return name
@@ -81,7 +78,7 @@ function buildMatcher(): IntegrationMatcher {
8178

8279
names.sort((a, b) => b.length - a.length)
8380
const regex = names.length
84-
? new RegExp(`(?<![A-Za-z0-9_])(${names.map(escapeRegex).join('|')})(?![A-Za-z0-9_])`, 'gi')
81+
? new RegExp(`(?<![A-Za-z0-9_])(${names.map(escapeRegExp).join('|')})(?![A-Za-z0-9_])`, 'gi')
8582
: null
8683

8784
return { regex, byName }

‎apps/sim/executor/constants.ts‎

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -469,10 +469,6 @@ export function stripCustomToolPrefix(name: string): string {
469469
: name
470470
}
471471

472-
export function escapeRegExp(value: string): string {
473-
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
474-
}
475-
476472
/**
477473
* Normalizes a name for comparison by converting to lowercase and removing
478474
* spaces and dots. Used for both block names and variable names to ensure

‎apps/sim/lib/copilot/chat/process-contents.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
authorizeWorkflowByWorkspacePermission,
55
getActiveWorkflowRecord,
66
} from '@sim/platform-authz/workflow'
7+
import { escapeRegExp } from '@sim/utils/string'
78
import { eq } from 'drizzle-orm'
89
import { createCopilotChatKnowledgePrincipal } from '@/lib/copilot/application/execute-knowledge-use-case'
910
import { createCopilotChatPrincipal } from '@/lib/copilot/auth/application-delegation'
@@ -59,7 +60,6 @@ import { workflowDelegationPolicy } from '@/lib/workflows/application/authorizat
5960
import { readWorkflowMetadata } from '@/lib/workflows/application/read-workflow'
6061
import { readWorkspaceFileMetadata } from '@/lib/workspace-files/application/read-workspace-file-metadata'
6162
import { getBlockRegistry } from '@/blocks/registry'
62-
import { escapeRegExp } from '@/executor/constants'
6363
import type { ResolvedSecretTraceRegistry } from '@/executor/utils/resolved-secret-trace-registry'
6464
import type { BrowserTextSelection, ChatContext, TerminalTextSelection } from '@/stores/panel'
6565

‎apps/sim/lib/core/security/linear-regex.ts‎

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { escapeRegExp } from '@sim/utils/string'
12
import { RE2JS } from 're2js'
23

34
/**
@@ -45,11 +46,6 @@ export interface LinearRegex {
4546

4647
const METACHARACTERS = /[.*+?^${}()|[\]\\]/
4748

48-
/** Escape every regex metacharacter so `input` matches only itself. */
49-
function escapeRegExp(input: string): string {
50-
return input.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
51-
}
52-
5349
/** True when `pattern` has no metacharacter, so both engines behave identically. */
5450
export function isPlainText(pattern: string): boolean {
5551
return !METACHARACTERS.test(pattern)

‎apps/sim/lib/function-execution/execute-request.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { createLogger } from '@sim/logger'
33
import { sha256Hex } from '@sim/security/hash'
44
import { getErrorMessage } from '@sim/utils/errors'
55
import { toRecord } from '@sim/utils/object'
6+
import { escapeRegExp } from '@sim/utils/string'
67
import { NextResponse } from 'next/server'
78
import type { ParsedFunctionExecuteBody } from '@/lib/api/contracts'
89
import {
@@ -108,7 +109,7 @@ import { rebindWorkspaceFileDelegatedPrincipal } from '@/lib/workspace-files/app
108109
import { fileOperations } from '@/lib/workspace-files/application/operations'
109110
import { readWorkspaceFileContent } from '@/lib/workspace-files/application/read-workspace-file-content'
110111
import { resolveWorkspaceFileReference } from '@/lib/workspace-files/application/resolve-workspace-file-reference'
111-
import { escapeRegExp, normalizeName, REFERENCE, sanitizeFileName } from '@/executor/constants'
112+
import { normalizeName, REFERENCE, sanitizeFileName } from '@/executor/constants'
112113
import type { UserFile } from '@/executor/types'
113114
import { type OutputSchema, resolveBlockReference } from '@/executor/utils/block-reference'
114115
import {

0 commit comments

Comments
 (0)