From 724e8a4cc875917e99cd930fffc8dd5c8439f1a6 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 27 Oct 2025 11:51:06 +0000
Subject: [PATCH 1/3] Initial plan
From 4eb02786a87ba6a9c0105bf71240ec3474bb021d Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 27 Oct 2025 12:00:24 +0000
Subject: [PATCH 2/3] Add rules for className and event handler merging with
spread props
Co-authored-by: siddharthkp <1863771+siddharthkp@users.noreply.github.com>
---
docs/rules/no-unmerged-classname.md | 75 ++++++++++
docs/rules/no-unmerged-event-handler.md | 87 +++++++++++
src/index.js | 2 +
.../__tests__/no-unmerged-classname.test.js | 71 +++++++++
.../no-unmerged-event-handler.test.js | 99 +++++++++++++
src/rules/no-unmerged-classname.js | 68 +++++++++
src/rules/no-unmerged-event-handler.js | 135 ++++++++++++++++++
7 files changed, 537 insertions(+)
create mode 100644 docs/rules/no-unmerged-classname.md
create mode 100644 docs/rules/no-unmerged-event-handler.md
create mode 100644 src/rules/__tests__/no-unmerged-classname.test.js
create mode 100644 src/rules/__tests__/no-unmerged-event-handler.test.js
create mode 100644 src/rules/no-unmerged-classname.js
create mode 100644 src/rules/no-unmerged-event-handler.js
diff --git a/docs/rules/no-unmerged-classname.md b/docs/rules/no-unmerged-classname.md
new file mode 100644
index 0000000..02c253f
--- /dev/null
+++ b/docs/rules/no-unmerged-classname.md
@@ -0,0 +1,75 @@
+# Ensure className is merged with spread props (no-unmerged-classname)
+
+When using spread props (`{...rest}`, `{...props}`, etc.) along with a `className` prop, you should merge the className from the spread props with your custom className to avoid unintentionally overriding classes.
+
+## Rule details
+
+This rule warns when a component has spread props before a `className` prop, but the `className` doesn't appear to be merging values using a utility like `clsx()` or `classNames()`.
+
+👎 Examples of **incorrect** code for this rule:
+
+```jsx
+/* eslint primer-react/no-unmerged-classname: "error" */
+
+// ❌ className may override className from rest
+
+
+// ❌ className expression doesn't merge
+
+
+// ❌ Template literal doesn't merge with rest
+
+```
+
+👍 Examples of **correct** code for this rule:
+
+```jsx
+/* eslint primer-react/no-unmerged-classname: "error" */
+
+// ✅ Using clsx to merge className from rest
+
+
+// ✅ Using classNames to merge
+
+
+// ✅ Using cn utility to merge
+
+
+// ✅ className before spread (spread will override)
+
+
+// ✅ No spread props
+
+```
+
+## Why this matters
+
+When you spread props and then specify a className, you might be overriding a className that was passed in through the spread:
+
+```jsx
+// ❌ Bad: className from rest gets lost
+function MyComponent({className, ...rest}) {
+ return
+ // If rest contains { className: "important-class" }
+ // Result: className="my-custom-class" (important-class is lost!)
+}
+
+// ✅ Good: className from rest is preserved and merged
+function MyComponent({className, ...rest}) {
+ return
+ // If rest contains { className: "important-class" }
+ // Result: className="important-class my-custom-class" (both preserved!)
+}
+```
+
+## Options
+
+This rule has no configuration options.
+
+## When to use this rule
+
+Use this rule when your components accept and spread props that might contain a `className`. This is common in component libraries and wrapper components.
+
+## Related Rules
+
+- [spread-props-first](./spread-props-first.md) - Ensures spread props come before named props
diff --git a/docs/rules/no-unmerged-event-handler.md b/docs/rules/no-unmerged-event-handler.md
new file mode 100644
index 0000000..0bb4cc1
--- /dev/null
+++ b/docs/rules/no-unmerged-event-handler.md
@@ -0,0 +1,87 @@
+# Ensure event handlers are merged with spread props (no-unmerged-event-handler)
+
+When using spread props (`{...rest}`, `{...props}`, etc.) along with event handler props (like `onClick`, `onChange`, etc.), you should merge the event handler from the spread props with your custom handler to avoid unintentionally overriding event handlers.
+
+## Rule details
+
+This rule warns when a component has spread props before an event handler prop, but the event handler doesn't appear to be merging handlers using a utility like `compose()` or `composeEventHandlers()`.
+
+👎 Examples of **incorrect** code for this rule:
+
+```jsx
+/* eslint primer-react/no-unmerged-event-handler: "error" */
+
+// ❌ onClick may override onClick from rest
+
+
+// ❌ Arrow function doesn't merge
+ {}} />
+
+// ❌ onChange expression doesn't merge
+
+```
+
+👍 Examples of **correct** code for this rule:
+
+```jsx
+/* eslint primer-react/no-unmerged-event-handler: "error" */
+
+// ✅ Using compose to merge onClick from rest
+
+
+// ✅ Using composeEventHandlers to merge
+
+
+// ✅ Event handler before spread (spread will override)
+
+
+// ✅ No spread props
+
+```
+
+## Why this matters
+
+When you spread props and then specify an event handler, you might be overriding an event handler that was passed in through the spread:
+
+```jsx
+// ❌ Bad: onClick from rest gets lost
+function MyComponent({onClick, ...rest}) {
+ return