RepoPilotOpen in app →

sindresorhus/escape-string-regexp

Escape RegExp special characters

WAIT

Slowing — last commit 12mo ago

worst-case
Use as dependencyGO

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyGO

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromGO

Documented and popular — useful reference codebase to read through.

Deploy as-isWAIT

last commit was 12mo ago; Scorecard "Branch-Protection" is 0/10…

  • Last commit 12mo ago
  • 5 active contributors
  • MIT licensed
  • CI configured
  • Tests present
  • Slowing — last commit 12mo ago
  • Small team — 5 top contributors
  • Concentrated ownership — top contributor handles 60% of commits
  • Scorecard: marked unmaintained (0/10)
  • Scorecard: default branch unprotected (0/10)
What would change the verdict?
  • Deploy as-is WAITGO if: 1 commit in the last 180 days; bring "Branch-Protection" to ≥3/10 (see scorecard report)

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests + OpenSSF Scorecard

Embed this verdict

[![RepoPilot: WAIT](https://repopilot.app/api/badge/sindresorhus/escape-string-regexp)](https://repopilot.app/r/sindresorhus/escape-string-regexp)

Paste into your README — the badge live-updates from the latest cached analysis.

Onboarding doc

Onboarding: sindresorhus/escape-string-regexp

Generated by RepoPilot · 2026-05-05 · Source

Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/sindresorhus/escape-string-regexp shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

Verdict

WAIT — Slowing — last commit 12mo ago

  • Last commit 12mo ago
  • 5 active contributors
  • MIT licensed
  • CI configured
  • Tests present
  • ⚠ Slowing — last commit 12mo ago
  • ⚠ Small team — 5 top contributors
  • ⚠ Concentrated ownership — top contributor handles 60% of commits
  • ⚠ Scorecard: marked unmaintained (0/10)
  • ⚠ Scorecard: default branch unprotected (0/10)

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests + OpenSSF Scorecard</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live sindresorhus/escape-string-regexp repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/sindresorhus/escape-string-regexp.

What it runs against: a local clone of sindresorhus/escape-string-regexp — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in sindresorhus/escape-string-regexp | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch main exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 394 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>sindresorhus/escape-string-regexp</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of sindresorhus/escape-string-regexp. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/sindresorhus/escape-string-regexp.git
#   cd escape-string-regexp
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of sindresorhus/escape-string-regexp and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "sindresorhus/escape-string-regexp(\\.git)?\\b" \\
  && ok "origin remote is sindresorhus/escape-string-regexp" \\
  || miss "origin remote is not sindresorhus/escape-string-regexp (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
  && ok "default branch main exists" \\
  || miss "default branch main no longer exists"

# 4. Critical files exist
test -f "index.js" \\
  && ok "index.js" \\
  || miss "missing critical file: index.js"
test -f "index.d.ts" \\
  && ok "index.d.ts" \\
  || miss "missing critical file: index.d.ts"
test -f "package.json" \\
  && ok "package.json" \\
  || miss "missing critical file: package.json"
test -f "test.js" \\
  && ok "test.js" \\
  || miss "missing critical file: test.js"
test -f "readme.md" \\
  && ok "readme.md" \\
  || miss "missing critical file: readme.md"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 394 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~364d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/sindresorhus/escape-string-regexp"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

escape-string-regexp is a minimal utility that escapes RegExp special characters in JavaScript strings, converting unsafe input like 'How much $ for a 🦄?' into safely usable regex patterns. It handles only the 14 mandatory regex metacharacters that need escaping (^ $ \ . * + ? ( ) [ ] { } |), preserving unicode and non-special characters untouched so the output stays readable and compatible with character class contexts. Simple single-file library: index.js exports a default function that applies a regex replacement to escape special characters; index.d.ts provides TypeScript types; test.js contains comprehensive test cases; package.json configures it as an ESM-only module (type: 'module') with no build step.

Who it's for

JavaScript developers building search/filter features, text processors, or dynamic regex builders who need to safely convert user input or variable strings into regex patterns without injection vulnerabilities or unexpected pattern behavior.

Maturity & risk

Highly mature and stable. This is a well-established Sindre Sorhus utility (written in 1,097 lines of JS/TS across 2 files) with a comprehensive test suite (test.js and index.test-d.ts), TypeScript definitions, xo linting, and active CI via GitHub Actions (see .github/workflows/main.yml). However, the README notes this is now available natively as RegExp.escape() in modern JavaScript, making this library primarily relevant for Node.js <12 or legacy browser support.

Extremely low risk. Zero production dependencies (sideEffects: false), minimal surface area (only index.js and index.d.ts in distribution), and maintained by a highly reputable author with no open issues or breaking changes visible. The only 'risk' is obsolescence: the native RegExp.escape() will eventually supersede this library, but that's a strength signal, not a weakness.

Active areas of work

The repository is in maintenance mode. The README prominently recommends using the native RegExp.escape() API instead (with a [!TIP] callout). No active development is visible, but the codebase is stable and well-tested.

Get running

git clone https://github.com/sindresorhus/escape-string-regexp.git
cd escape-string-regexp
npm install
npm test

Daily commands: This is not a runnable application—it's a library. To test: npm test (runs xo linter, ava test suite, and tsd type definitions).

Map of the codebase

  • index.js — Core implementation that escapes RegExp special characters—the entire purpose of the library.
  • index.d.ts — TypeScript type definitions that define the public API contract for all consumers.
  • package.json — Declares the module type (ESM), entry point, and test scripts that gate quality.
  • test.js — Unit tests that verify correctness of character escaping across all RegExp special characters.
  • readme.md — Documents the minimal API, usage patterns, and important caveat about context-aware escaping.

Components & responsibilities

  • escapeStringRegexp function (JavaScript (ESM), regex pattern matching, string iteration) — Accepts a string and returns a new string with all RegExp special characters escaped with a backslash.
    • Failure mode: Returns non-escaped string if special character is missed in the regex pattern, allowing unintended RegExp interpretation.
  • TypeScript type definition (TypeScript .d.ts) — Declares the function signature and ensures type-safe consumption in TypeScript projects.
    • Failure mode: Type mismatch errors if definition does not match runtime signature; consumers may pass wrong types without errors.
  • Test suite (AVA test framework, TSD) — Validates that each RegExp special character is correctly escaped and that normal characters pass through unchanged.
    • Failure mode: Regression in character escaping detection; new edge cases or characters not covered by tests.

Data flow

  • User codeescapeStringRegexp(input) — Caller passes a string that may contain RegExp special characters
  • escapeStringRegexp(input)Regex engine (internal) — Input string is matched character-by-character against the special character pattern
  • Regex engine (internal)String replace() — Matched special characters are replaced with escaped versions (backslash + character)
  • String replace()User code (return value) — Escaped string is returned to caller for safe use in a RegExp constructor

How to make changes

Add support for a new RegExp special character

  1. Identify the RegExp special character that needs escaping (e.g., a metacharacter not currently handled) (index.js)
  2. Add the character to the regex pattern in index.js that matches all escapable characters (index.js)
  3. Add test cases to test.js covering the new character in isolation and in context (test.js)
  4. Run 'npm test' to verify the character is properly escaped and type-checked (package.json)

Fix a reported escaping bug or edge case

  1. Write a regression test in test.js that demonstrates the bug with the problematic input string (test.js)
  2. Modify the escaping logic or regex pattern in index.js to handle the edge case (index.js)
  3. Verify all tests pass including the new regression test via 'npm test' (package.json)
  4. Update readme.md if the fix requires documenting new limitations or usage patterns (readme.md)

Publish a new version to npm

  1. Update the version field in package.json following semantic versioning (package.json)
  2. Ensure all tests pass with 'npm test' including linting, ava tests, and type checks (package.json)
  3. Use npm publish (configured by .npmrc) to release the new version to the npm registry (.npmrc)

Why these technologies

  • ESM (ES modules) — Modern JavaScript standard for dependency-free, tree-shakeable distribution; no CommonJS overhead.
  • TypeScript definitions (.d.ts) — Provides type safety for consumers without requiring transpilation of the library itself.
  • AVA test framework — Minimal, concurrent test runner suitable for a small utility library with clear pass/fail cases.
  • TSD for type testing — Ensures TypeScript definitions match the runtime behavior and catch type-level regressions.

Trade-offs already made

  • Minimal escaping—only escape what RegExp requires

    • Why: Keeps output simple and readable; users understand the escaped string at a glance.
    • Consequence: Escaped strings must be inserted at safe positions in a RegExp. Context-aware escaping (e.g., after \0 or \c) requires external tools like the 'regex' package.
  • No built-in context awareness or mode parameter

    • Why: Reduces API surface, keeps the module lightweight and single-purpose.
    • Consequence: Users inserting escaped strings into character classes or after certain tokens must validate correct placement manually.
  • No polyfill or fallback—rely on native RegExp.escape() in modern runtimes

    • Why: Future-proofs the library and encourages migration to native functionality.
    • Consequence: Library is a shim; newer Node.js versions may not need it, but it remains safe to use for backward compatibility.

Non-goals (don't propose these)

  • Does not handle context-aware escaping (placement after \0 or \c sequences)
  • Does not provide a regex builder or combinator library
  • Does not escape strings for non-RegExp contexts (HTML, SQL, etc.)
  • Does not validate that the resulting RegExp is syntactically correct

Code metrics

  • Avg cyclomatic complexity: ~1 — The codebase is intentionally minimal—a single one-liner regex replace. No complex control flow, branching, or nested logic.
  • Largest file: test.js (45 lines)
  • Estimated quality issues: ~0 — Code passes xo linting, comprehensive tests cover all RegExp special characters, and TypeScript definitions are type-checked by TSD. No known quality gaps.

Anti-patterns to avoid

  • Incomplete special character set (High)index.js: If the regex pattern does not include all RegExp special characters (|, , ^, $, ., *, +, ?, (, ), [, ], {, }), some metacharacters will not be escaped and will have unintended meaning in a RegExp.
  • Over-escaping creates false positives (Low)index.js: Escaping characters that are not RegExp special characters (e.g., a-z, 0-9) creates bloated output and may cause confusion, though it is not functionally incorrect.
  • No validation of placement context (Medium)readme.md: Documentation warns users to place escaped strings at safe positions but provides no helper or validation; users must manually ensure correct placement.

Performance hotspots

  • index.js (Algorithmic) — String iteration and character-by-character matching is O(n) where n is string length. For very large strings, performance is dominated by regex matching and string concatenation.

Traps & gotchas

No hidden traps. The library is intentionally simple: it does minimal, context-unaware escaping and explicitly documents that developers are responsible for inserting escaped strings at 'safe positions' in regex patterns. The only gotcha is that after \0 or \c, the escaped value can change meaning—mitigated by using the regex package for context-aware escaping if needed.

Architecture

Concepts to learn

  • RegExp Metacharacters — This library exists solely to escape the 14 special metacharacters that have semantic meaning in regex patterns; understanding which characters need escaping and why is fundamental to using this tool correctly.
  • Character Class Context — The README explicitly notes that escaped strings can be safely inserted into character class contexts; understanding the difference between . (any char) and [.] (literal dot) helps you know when/where to use this library.
  • Minimal Escaping Strategy — This library intentionally escapes only the minimum needed to make a string safe for regex; understanding why fuller escaping is avoided (readability, simplicity) and when you might need context-aware escaping (after \0 or \c) informs correct usage.
  • ESM Modules (ES2020+) — This library is ESM-only (type: 'module' in package.json); contributors and users must understand import syntax and module resolution to use or develop it.
  • String Replacement with Regex — The core implementation uses String.prototype.replace() with a regex pattern to escape characters; understanding how capture groups and replace functions work is essential to reading and modifying the code.
  • TypeScript Type Definitions (.d.ts files) — index.d.ts provides type safety for TypeScript users; contributors must understand .d.ts syntax and tsd testing to maintain type correctness when updating the function signature.
  • Unicode Preservation — The library intentionally does not escape unicode characters (e.g., 🦄 stays as-is); understanding why and when unicode is safe in regex patterns is important for expected output.

Related repos

  • lodash/lodash — Lodash includes escapeRegExp as a utility function in its string methods; the main competitor/alternative to this focused library.
  • slevithan/regex — The regex package is explicitly recommended in this repo's README for context-aware escaping when the string is inserted after \0 or \c tokens.
  • sindresorhus/awesome — Sindre Sorhus's curated list of awesome projects; escape-string-regexp is part of the broader ecosystem of minimal, well-crafted utilities.
  • microsoft/TypeScript — TypeScript is used for type definitions in index.d.ts and validated via tsd; understanding TS strict mode is essential for maintaining type safety in this library.
  • avajs/ava — ava is the test runner used in test.js; familiarity with ava's assertion API and test structure is required to extend the test suite.

PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive edge-case tests for character classes and lookahead/lookbehind patterns

The README acknowledges that 'escaped strings at safe positions in a RegExp' are expected, and mentions edge cases like strings following \0 or \c. However, test.js likely lacks comprehensive coverage for these dangerous placements. Adding tests that verify behavior when escaped strings are used in character classes [escaped-string], lookaheads (?=escaped-string), and after control characters would help contributors and users understand safe usage patterns.

  • [ ] Review current test.js to identify missing edge case coverage
  • [ ] Add test cases for escaped strings within character classes: [a-z$(escaped)z-a]
  • [ ] Add test cases for escaped strings after control sequences like \0, \c, \x, \u
  • [ ] Add test cases for escaped strings in lookaheads/lookbehinds: (?=escaped-string)
  • [ ] Document expected behavior vs. actual behavior in test comments
  • [ ] Run full test suite with: npm test

Migrate from deprecated ava@3 to latest ava major version

The package.json pins ava@^3.15.0, which is now several years old and likely has security advisories or deprecated APIs. Modern ava versions have improved TypeScript support, better error messages, and performance improvements. This is a straightforward dependency upgrade that would modernize the test infrastructure.

  • [ ] Update package.json: change 'ava': '^3.15.0' to '^5.0.0' or latest major
  • [ ] Run npm install to resolve new ava version
  • [ ] Review ava migration guide for any breaking changes to test syntax
  • [ ] Verify test.js runs without deprecation warnings: npm test
  • [ ] Check if any ava configuration in package.json needs updates
  • [ ] Ensure CI passes in .github/workflows/main.yml

Add explicit test coverage for Unicode and non-ASCII characters in index.test-d.ts

The TypeScript definition file index.d.ts exists, but index.test-d.ts is minimal. The README example shows emoji (🦄) being handled correctly, but TypeScript type tests don't verify that Unicode strings, surrogate pairs, and non-Latin characters are properly typed. Adding tsd tests would catch any future type regressions and document expected behavior for international users.

  • [ ] Review current index.test-d.ts for existing type test coverage
  • [ ] Add tsd test cases for: emoji strings, CJK characters, RTL text (Arabic, Hebrew)
  • [ ] Add tsd test cases for surrogate pair handling: '𝐀𝐁𝐂' (mathematical alphanumeric)
  • [ ] Add tsd test cases verifying return type is always string
  • [ ] Add tsd test cases verifying no generics or overloads exist (function is simple)
  • [ ] Run npm test to ensure tsd validation passes

Good first issues

  • Add a test case for escaping special characters inside regex lookahead/lookbehind patterns (e.g., (?<=prefix)search(?=suffix)) to document edge cases and extend the test suite in test.js.
  • Expand the readme.md with examples showing the library's output when used inside character classes (e.g., [escaped-string]) and middle-of-regex contexts, since the README mentions but doesn't show these scenarios.
  • Create a TypeScript example file or expand index.test-d.ts to demonstrate type inference and strict typing when escapeStringRegexp is used in real-world patterns like dynamic search builders.

Top contributors

Recent commits

  • cbc4240 — Document native API (sindresorhus)
  • 6ced614 — Meta tweaks (sindresorhus)
  • 6fe67c0 — Clarify that minimal escaping is done and describe edge cases (#40) (slevithan)
  • ba9a447 — 5.0.0 (sindresorhus)
  • aebb6e8 — Require Node.js 12 and move to ESM (sindresorhus)
  • 34ec4c6 — Move to GitHub Actions (#31) (Richienb)
  • b3eb767 — Fix code comment (sindresorhus)
  • 71083e8 — 4.0.0 (sindresorhus)
  • ec45c70 — Escape - in a way that’s compatible with PCRE (#23) (charmander)
  • d248d82 — 3.0.0 (sindresorhus)

Security observations

This is a well-maintained, minimal utility package with strong security posture. The codebase shows no signs of injection vulnerabilities, hardcoded secrets, or infrastructure misconfigurations. As a simple string escaping library with no runtime dependencies, the attack surface is extremely limited. The only minor concerns are the outdated devDependencies and liberal Node.js version requirement, which are low-risk issues. The package follows security best practices with clear licensing, minimal exports, and proper TypeScript support.

  • Low · Outdated Development Dependencies — package.json - devDependencies. The devDependencies include older versions of testing and linting tools (ava@^3.15.0, tsd@^0.14.0, xo@^0.38.2). While not direct runtime dependencies, outdated dev tools may contain known vulnerabilities that could affect the development environment. Fix: Update devDependencies to their latest stable versions. Run 'npm audit' to identify any known vulnerabilities and update accordingly.
  • Low · Minimal Node.js Version Requirement — package.json - engines. The package supports Node.js >=12, which is very old (released in 2019). EOL versions may have unpatched security vulnerabilities in the runtime environment. Fix: Consider updating the minimum Node.js version requirement to a more recent LTS version (e.g., >=16 or >=18) to ensure users benefit from security patches and modern JavaScript features.

LLM-derived; treat as a starting point, not a security audit.

Where to read next


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.