From f46e53b971440a9894135679ef87287cb5e9abb4 Mon Sep 17 00:00:00 2001 From: Kyle Hensel Date: Wed, 11 Jun 2025 04:01:59 +1400 Subject: [PATCH] feat: add autofix for `no-missing-context-display-name` --- .../no-missing-context-display-name.spec.ts | 46 +++++++++++++++++++ .../rules/no-missing-context-display-name.ts | 4 ++ 2 files changed, 50 insertions(+) diff --git a/packages/plugins/eslint-plugin-react-x/src/rules/no-missing-context-display-name.spec.ts b/packages/plugins/eslint-plugin-react-x/src/rules/no-missing-context-display-name.spec.ts index 96131a1b05..55bd7ac255 100644 --- a/packages/plugins/eslint-plugin-react-x/src/rules/no-missing-context-display-name.spec.ts +++ b/packages/plugins/eslint-plugin-react-x/src/rules/no-missing-context-display-name.spec.ts @@ -12,6 +12,10 @@ ruleTester.run(RULE_NAME, rule, { { code: tsx`const ctx = createContext();`, errors: [{ messageId: "noMissingContextDisplayName" }], + output: tsx` + const ctx = createContext() + ctx.displayName = "ctx"; + `, }, { code: tsx` @@ -20,6 +24,12 @@ ruleTester.run(RULE_NAME, rule, { ctx1.displayName = "ctx"; `, errors: [{ messageId: "noMissingContextDisplayName" }], + output: tsx` + const ctx1 = createContext(); + const ctx2 = createContext() + ctx2.displayName = "ctx2"; + ctx1.displayName = "ctx"; + `, }, { code: tsx` @@ -27,6 +37,11 @@ ruleTester.run(RULE_NAME, rule, { ctx.displayname = "ctx"; `, errors: [{ messageId: "noMissingContextDisplayName" }], + output: tsx` + const ctx = createContext() + ctx.displayName = "ctx"; + ctx.displayname = "ctx"; + `, }, { code: tsx` @@ -35,6 +50,37 @@ ruleTester.run(RULE_NAME, rule, { `, errors: [{ messageId: "noMissingContextDisplayName" }], }, + { + // this doesn't make sense, it's just to test the autofixer + code: tsx` + const [nonsense] = createContext(); + const { invalid } = createContext(); + `, + errors: [ + { messageId: "noMissingContextDisplayName" }, + { messageId: "noMissingContextDisplayName" }, + ], + }, + { + // not autofixable + code: tsx` + const contexts = { a: createContext(), b: createContext() }; + `, + errors: [ + { messageId: "noMissingContextDisplayName" }, + { messageId: "noMissingContextDisplayName" }, + ], + }, + { + // not autofixable + code: tsx` + const [a, b] = [createContext(), createContext()]; + `, + errors: [ + { messageId: "noMissingContextDisplayName" }, + { messageId: "noMissingContextDisplayName" }, + ], + }, ], valid: [ ...allFunctions, diff --git a/packages/plugins/eslint-plugin-react-x/src/rules/no-missing-context-display-name.ts b/packages/plugins/eslint-plugin-react-x/src/rules/no-missing-context-display-name.ts index 60abcd5544..cf4636c2f8 100644 --- a/packages/plugins/eslint-plugin-react-x/src/rules/no-missing-context-display-name.ts +++ b/packages/plugins/eslint-plugin-react-x/src/rules/no-missing-context-display-name.ts @@ -20,6 +20,7 @@ export default createRule<[], MessageID>({ description: "Enforces that all contexts have a `displayName` which can be used in devtools.", [Symbol.for("rule_features")]: RULE_FEATURES, }, + fixable: "code", messages: { noMissingContextDisplayName: "Add missing 'displayName' for context.", }, @@ -62,6 +63,9 @@ export function create(context: RuleContext): RuleListener { context.report({ messageId: "noMissingContextDisplayName", node: id, + fix: id.type === T.Identifier && id.parent === call.parent + ? ((fixer) => fixer.insertTextAfter(call, `\n${id.name}.displayName = ${JSON.stringify(id.name)}`)) + : null, }); } }