feat(ts): implement caughtErrorCauses rule#2948
Conversation
🦋 Changeset detectedLatest commit: 21ed556 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
This comment has been minimized.
This comment has been minimized.
…R recipe Marks flint-fyi#1363 caughtErrorCauses done (draft PR flint-fyi#2948; its flint-fyi#400 blocker closed 2026-06-06). The draft-PR section now leads with the PR-template checklist octoguide enforces (literal 'fixes #' link, [x] on every task, ~~strikethrough~~ N/A form), notes octoguide re-runs on body edits only, documents the gh pr edit GraphQL failure + REST workaround, and de-mangles the placeholder syntax prettier was corrupting. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
❌ Deploy Preview for flint-fyi failed.
|
Revives flint-fyi#1363, porting it from the legacy typescriptLanguage.createRule API to the current ruleCreator(language, ...)/services API. The old preset/strictness pair (logical + strict) maps to presets: ["logicalStrict"]. hasErrorCause is simplified to the presence check it always effectively was (the original's identifier comparison was dead code), and an undefined guard was added for noUncheckedIndexedAccess. The blocker recorded on flint-fyi#1363 (scope analysis, flint-fyi#400) has since lifted: the TypeScript scope manager landed in flint-fyi#2828/flint-fyi#2916. Upgrading the rule to verify the cause is actually the caught error is left as a maintainer-scoped follow-up. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
f9b612a to
21ed556
Compare
Preset doctrine per Javier: strict tiers are supersets of their base tier — plain-preset rules declare both tiers, strictness:strict stubs declare the Strict tier only. Backlog entries updated with the 2026-06-09 review fixes applied to flint-fyi#2944/flint-fyi#2945/flint-fyi#2946/flint-fyi#2948/flint-fyi#2949. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Hi, thanks for your contributions. To be clear, we don't have any issue with AI-generated code itself. However, as a first-time contributor, you may not yet have enough familiarity with the project's architecture, coding conventions, and established patterns to effectively steer AI-generated suggestions. This can sometimes lead to changes that don't align well with the codebase, creating additional review overhead and maintenance challenges. For example, the new code we're adding now is specifically designed to avoid these issues(#2395, #2772 and #1404), but the AI-generated code you submitted managed to hit every single pitfall we were trying to avoid. |
PR Checklist
status: accepting prs— caveat: The issue is labeledstatus: blocked(its original draft, feat(ts): implement caughtErrorCauses rule #1363, was blocked on 🚀 Feature: Create a scope manager for TypeScript #400 scope analysis — 🚀 Feature: Create a scope manager for TypeScript #400 has since closed; see below) — this PR is the revival of that draft, opened as a draft for maintainer reviewOverview
Revives #1363 (
caughtErrorCauses), which stalled on the legacy rule API and on #400. This branch ports it to the currentruleCreator.createRule(language, …)+ visitor-servicesAPI.The rule reports
throw new <Error>(…)inside acatchblock when nocauseoption is passed, so the original error chain isn't lost.Porting notes
preset: "logical"+strictness: "strict"pair maps topresets: ["logicalStrict"]— flag if you'd rather have it in both tiers.hasErrorCausewas simplified to the presence check it always effectively was: the original compared thecauseinitializer against the catch parameter but then returnedtrueunconditionally, so the comparison was dead code. Anycause:property still satisfies the rule (e.g.{ cause: wrapError(error) }).preserve-caught-error's semantics, fixing three false positives the original draft had:AggregateErrortakes its options as the third argument —new AggregateError([e], "msg", { cause: e })is now valid (andnew AggregateError([e], "msg")is now correctly reported).{ cause }and string-literal{ "cause": e }keys are now recognized.UNKNOWN_CAUSEbail-out.undefinedguard on the options argument was added fornoUncheckedIndexedAccess.console, so the test usesdomLibRuleTester; fixtures cover all the cases above.The #400 blocker has lifted — follow-up opportunity
#1363 was marked blocked because verifying that the thrown error's
causeis actually the caught error (vs. any value) needs scope analysis (#400). The TypeScript scope manager has since landed (#2828, extended in #2916 withScopeManager.getScope). This revival preserves the original lenient behavior; tightening it to verify the caught error flows into thecause(directly or wrapped) is now implementable and left as a maintainer-scoped decision — happy to do it in this PR or a follow-up if wanted.Files
packages/ts/src/rules/caughtErrorCauses.ts— the rulepackages/ts/src/rules/caughtErrorCauses.test.ts— co-located rule-tester snapshotspackages/site/src/content/docs/rules/ts/caughtErrorCauses.mdx— docspackages/ts/src/plugin.ts— alphabetical registrationpackages/comparisons/src/data.json— entry flipped tostatus: implemented.changeset/caught-error-causes.mdLocal gates
eslint --max-warnings 0·tsc -b packages/ts·vitest(17/17, rule test) ·comparisons/data.test.ts(28/28) ·prettier --check— all pass locally.🤖 Generated with Claude Code