Skip to content

Commit 3b5b600

Browse files
committed
Fix false positive with as const (fixes #80)
1 parent ee193a1 commit 3b5b600

File tree

3 files changed

+26
-9
lines changed

3 files changed

+26
-9
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
- Fix false positive with `as const` (fixes [#80](https://github.com/ArnaudBarre/eslint-plugin-react-refresh/issues/80))
6+
37
## 0.4.19
48

59
Add name to configs for [ESLint Config Inspector](https://github.com/eslint/config-inspector)

src/only-export-components.test.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,11 @@ const valid = [
198198
name: "Local constant with component casing and non component function",
199199
code: "const SomeConstant = 42; export function someUtility() { return SomeConstant }",
200200
},
201+
{
202+
name: "Component and as const constant with allowConstantExport",
203+
code: "export const MyComponent = () => {}; export const MENU_WIDTH = 232 as const;",
204+
options: [{ allowConstantExport: true }],
205+
},
201206
];
202207

203208
const invalid = [

src/only-export-components.ts

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,7 @@ export const onlyExportComponents: TSESLint.RuleModule<
112112
if (
113113
allowConstantExport &&
114114
init &&
115-
(init.type === "Literal" || // 1, "foo"
116-
init.type === "UnaryExpression" || // -1
117-
init.type === "TemplateLiteral" || // `Some ${template}`
118-
init.type === "BinaryExpression") // 24 * 60
115+
constantExportExpressions.has(skipTSWrapper(init).type)
119116
) {
120117
return;
121118
}
@@ -223,11 +220,7 @@ export const onlyExportComponents: TSESLint.RuleModule<
223220
context.report({ messageId: "exportAll", node });
224221
} else if (node.type === "ExportDefaultDeclaration") {
225222
hasExports = true;
226-
const declaration =
227-
node.declaration.type === "TSAsExpression" ||
228-
node.declaration.type === "TSSatisfiesExpression"
229-
? node.declaration.expression
230-
: node.declaration;
223+
const declaration = skipTSWrapper(node.declaration);
231224
if (
232225
declaration.type === "VariableDeclaration" ||
233226
declaration.type === "FunctionDeclaration" ||
@@ -301,7 +294,22 @@ export const onlyExportComponents: TSESLint.RuleModule<
301294
},
302295
};
303296

297+
const skipTSWrapper = <T extends TSESTree.Node>(node: T) => {
298+
if (node.type === "TSAsExpression" || node.type === "TSSatisfiesExpression") {
299+
return node.expression;
300+
}
301+
return node;
302+
};
303+
304304
type ToString<T> = T extends `${infer V}` ? V : never;
305+
const constantExportExpressions = new Set<
306+
ToString<TSESTree.Expression["type"]>
307+
>([
308+
"Literal", // 1, "foo"
309+
"UnaryExpression", // -1
310+
"TemplateLiteral", // `Some ${template}`
311+
"BinaryExpression", // 24 * 60
312+
]);
305313
const notReactComponentExpression = new Set<
306314
ToString<TSESTree.Expression["type"]>
307315
>([

0 commit comments

Comments
 (0)