[eslint-miner] eslint-miner: add require-new-regexp-try-catch rule
- Dominant language
- Go
- Stars
- 5.1k
- Forks
- 541
- Avg merge
- 5h 48m
- Merged PRs (30d)
- 773
Description
> [!TIP]
> **Your pull request is ready to create! 🎉 ✅**
>
> Everything is OK—the changes have been pushed to a branch. Please review the protected files, then create the pull request when you are ready.
>
> **[Create the pull request](https://github.com/github/gh-aw/compare/main...eslint-miner/require-new-regexp-try-catch-b5859b246fc86439?expand=1&title=%5Beslint-miner%5D%20eslint-miner%3A%20add%20require-new-regexp-try-catch%20rule&body=Closes%20%2361322)**
>
> The original pull request description is below.
---
## ESLint Miner — daily rule
**New rule:** [`require-new-regexp-try-catch`](eslint-factory/src/rules/require-new-regexp-try-catch.ts)
Flags `new RegExp(variable)` calls in `actions/setup/js` where the pattern source is an opaque runtime value (a bare identifier or a property access other than `.source`) and the call is not wrapped in `try/catch`.
### Evidence
- **Live target:** `actions/setup/js/safe_output_type_validator.cjs:523` —
```js
const regex = new RegExp(validation.pattern);
```
`validation.pattern` comes from `GH_AW_VALIDATION_CONFIG` (a Go-compiler-generated JSON config) and flows in via `validateField()` → `validateItem()` → `collect_ndjson_output.cjs`. There is no `try/catch` anywhere in that call chain (confirmed by grepping for `try {` in the file — the nearest try blocks are at unrelated lines 258/609/836/852). A malformed pattern throws an uncaught `SyntaxError` instead of a diagnosable error.
- **Coverage gap:** the existing `require-escaped-regexp-interpolation` rule only fires when the first argument to `new RegExp(...)` is a `TemplateLiteral` with at least one interpolated expression. It does **not** cover bare dynamic arguments like `new RegExp(validation.pattern)` — the exact shape at the live target — leaving this class of risk unguarded.
- Scanned all `new RegExp(...)` call sites under `actions/setup/js/*.cjs` (excluding tests). The ~20 other sites all build the pattern from a template literal, a `.source` read off a fixed regex, or a `.join("|")` composition of known sources — all excluded by design (see "Out of scope" below) since their content is reviewable/fixed at the call site, unlike `validation.pattern`.
### Design (mirrors `require-new-url-try-catch`)
- Flags `new RegExp(pattern)` and `new RegExp(obj.pattern, ...)` when not inside a `try` block (accounting for deferred callbacks that escape an outer try, and for `RegExp` being shadowed by a local binding).
- **Not flagged** (low false-positive risk):
- String/template literals without interpolation, and regex literals.
- `.source` reads off an existing regex (the common "clone a fixed regex" idiom).
- Composed strings such as `patternSources.join("|")`.
- Calls already inside `try { ... } catch { ... }`.
- Provides an autofix suggestion wrapping the call in `try/catch` with `{ cause: err }`, for `ExpressionStatement`/`ReturnStatement` positions (same limitation as `require-new-url-try-catch`: `VariableDeclaration` initializers are reported without an autofix, since wrapping them would move the declared binding out of scope).
### Validation
- `cd eslint-factory && npm install && npm run build` — clean.
- `cd eslint-factory && npx vitest run` — **690/690 tests pass** (9 new tests for this rule, including shadow-binding, try-block, deferred-callback, and autofix-suppression cases).
- `cd eslint-factory && npm run lint:setup-js` — **0 errors, 81 warnings** (1 new warning from this rule, firing exactly once on `safe_output_type_validator.cjs:523`; no other warnings introduced).
### Registration
- Rule implemented in `eslint-factory/src/rules/require-new-regexp-try-catch.ts` (+ test file).
- Registered in `eslint-factory/src/index.ts`.
- Enabled as `"warn"` in `eslint-factory/eslint.config.cjs`.
- Documented in `eslint-factory/README.md` (table entry + full section).
### Mined issues considered but not pursued this run
- #61285 and #61284 are bug reports against the *existing* `require-error-code-in-thrown-error` rule (regex pattern gap; nested-identifier alias resolution gap). Both are currently latent (no live false positive/negative observed today), and fixing an existing rule isn't a "net-new rule" per the mission — left for a future run.
- #61291 flags `azure_devops_work_items.cjs` for missing `ERR_*`/`E0xx` error-code prefixes — a code-fix in a single file rather than a new lint rule; out of scope for this run's "implement one rule" mandate.
### Steering issue
The steering issue number provided in this run's context was blank/`false`, so there was no steering issue to read comments from.
---
> [!NOTE]
> **Protected files**
>
> This patch modifies protected files, which may affect project dependencies, CI/CD pipelines, or agent behaviour.
>
>
> Protected files
>
> - `README.md`
>
>
To route changes like this to a review issue instead of blocking, configure `protected-files: fallback-to-issue` in your workflow configuration.
> Generated by [ESLint Miner](https://github.com/github/gh-aw/actions/runs/35075832182) · copilot · auto · 273 AIC · ⌖ 12.6 AIC · ⊞ 7.2K · [◷](https://github.com/search?q=repo%3Agithub%2Fgh-aw+%22gh-aw-workflow-id%3A+eslint-miner%22&type=pullrequests)
> - [x] expires on Sep 23, 2026, 1:08 AM UTC-08:00
Contributor guide
Research direction
Review eslint-factory/src/rules/require-new-regexp-try-catch.ts and its test file, then check registration in eslint-factory/src/index.ts, configuration in eslint-factory/eslint.config.cjs, and documentation in eslint-factory/README.md. Run npm install, npm run build, npx vitest run, and npm run lint:setup-js in eslint-factory; done means the rule, tests, registration, configuration, and documentation are consistent.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- eslint, javascript, typescript
- Domain
- testing, tooling
- Issue type
- Feature
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 15/100