initial commit
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
import type { RuleFunction } from "@eslint-react/kit";
|
||||
import { type TSESTree, AST_NODE_TYPES } from "@typescript-eslint/types";
|
||||
|
||||
/** Enforce `import * as React from "react"` only. */
|
||||
export function preferNamespaceImport(): RuleFunction {
|
||||
return (context, { settings }) => {
|
||||
const { importSource } = settings;
|
||||
|
||||
return {
|
||||
[`ImportDeclaration[source.value="${importSource}"]`](
|
||||
node: TSESTree.ImportDeclaration,
|
||||
) {
|
||||
const specifiers = node.specifiers;
|
||||
|
||||
// already valid
|
||||
if (
|
||||
specifiers.length === 1 &&
|
||||
specifiers[0]?.type ===
|
||||
AST_NODE_TYPES.ImportNamespaceSpecifier
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// choose React identifier:
|
||||
// import React from "react" -> React
|
||||
// import { useState } -> React
|
||||
// import Foo, { useState } -> Foo
|
||||
const localName =
|
||||
specifiers.find(
|
||||
(s) =>
|
||||
s.type === AST_NODE_TYPES.ImportDefaultSpecifier ||
|
||||
s.type === AST_NODE_TYPES.ImportNamespaceSpecifier,
|
||||
)?.local.name ?? "React";
|
||||
|
||||
context.report({
|
||||
node,
|
||||
data: { importSource },
|
||||
message: `Prefer importing React only as 'import * as ${localName} from "${importSource}"'`,
|
||||
|
||||
fix(fixer) {
|
||||
const original = context.sourceCode.getText(node);
|
||||
const semi = original.endsWith(";") ? ";" : "";
|
||||
const quote = node.source.raw.at(0) ?? "'";
|
||||
const isTypeImport = node.importKind === "type";
|
||||
|
||||
return fixer.replaceText(
|
||||
node,
|
||||
[
|
||||
`import${isTypeImport ? " type" : ""}`,
|
||||
`* as ${localName}`,
|
||||
`from ${quote}${importSource}${quote}${semi}`,
|
||||
].join(" "),
|
||||
);
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user