@arthurgeron/eslint-plugin-react-usememo
Advanced tools
Comparing version 2.0.1 to 2.1.0
@@ -128,2 +128,37 @@ 'use strict'; | ||
} | ||
function addReactImports(context, kind, reactImportData, fixer) { | ||
var _a, _b, _c, _d, _e, _f; | ||
var sourceCode = context.getSourceCode(); | ||
var importsDisabled = ((_c = (_b = (_a = context.options) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.fix) === null || _c === void 0 ? void 0 : _c.addImports) === false; | ||
var specifier = undefined; | ||
if (importsDisabled) { | ||
return; | ||
} | ||
if (!reactImportData["".concat(kind, "Imported")]) { | ||
// Create a new ImportSpecifier for useMemo/useCallback hook. | ||
specifier = { | ||
type: 'ImportSpecifier', | ||
imported: { type: 'Identifier', name: kind }, | ||
local: { type: 'Identifier', name: kind } | ||
}; | ||
if (reactImportData.importDeclaration) { | ||
reactImportData.importDeclaration.specifiers.push(specifier); | ||
return fixer.insertTextAfter(reactImportData.importDeclaration.specifiers[reactImportData.importDeclaration.specifiers.length - 2], ", ".concat(kind)); | ||
} | ||
} | ||
// If React is not imported, create a new ImportDeclaration for it. | ||
if (!reactImportData.reactImported && !reactImportData.importDeclaration) { | ||
reactImportData.importDeclaration = { | ||
type: 'ImportDeclaration', | ||
specifiers: [specifier], | ||
source: { type: 'Literal', value: 'react' } | ||
}; | ||
reactImportData.reactImported = true; | ||
reactImportData["".concat(kind, "Imported")] = true; | ||
((_f = (_e = (_d = sourceCode.ast.body[0]) === null || _d === void 0 ? void 0 : _d.leadingComments) === null || _e === void 0 ? void 0 : _e[0]) === null || _f === void 0 ? void 0 : _f.value) || ""; | ||
// Add an extra new line before const component and use indentSpace for proper spacing. | ||
return fixer.insertTextBeforeRange([0, 0], "import { ".concat(kind, " } from 'react';\n")); | ||
} | ||
return; | ||
} | ||
function getIsHook(node) { | ||
@@ -160,3 +195,3 @@ if (node.type === "Identifier") { | ||
var funcParams = params.map(function (node) { return sourceCode.getText(node); }); | ||
var fixedCode = "React.useCallback((".concat(funcParams.join(', '), ") => ").concat(funcBody, ", [])").concat(shouldSetName ? ';' : ''); | ||
var fixedCode = "useCallback((".concat(funcParams.join(', '), ") => ").concat(funcBody, ", [])").concat(shouldSetName ? ';' : ''); | ||
if (shouldSetName && ((_a = node === null || node === void 0 ? void 0 : node.id) === null || _a === void 0 ? void 0 : _a.name)) { | ||
@@ -179,3 +214,3 @@ var name_2 = (_b = node === null || node === void 0 ? void 0 : node.id) === null || _b === void 0 ? void 0 : _b.name; | ||
// Eslint Auto-fix logic, functional components/hooks only | ||
function fixBasedOnMessageId(node, messageId, fixer, context) { | ||
function fixBasedOnMessageId(node, messageId, fixer, context, reactImportData) { | ||
var _a, _b, _c, _d; | ||
@@ -189,2 +224,3 @@ var sourceCode = context.getSourceCode(); | ||
var isCorrectableFunctionExpression = isFunctionExpression || (isArrowFunctionExpression && parentIsVariableDeclarator); | ||
var fixes = []; | ||
// Determine what type of behavior to follow according to the error message | ||
@@ -195,8 +231,6 @@ switch (messageId) { | ||
case 'usememo-const': { | ||
var sourceCode_1 = context.getSourceCode(); | ||
var variableDeclaration = node.type === 'VariableDeclaration' ? node : findParentType(node, 'VariableDeclaration'); | ||
var fixes = []; | ||
// Check if it is a hook being stored in let/var, change to const if so | ||
if (variableDeclaration && variableDeclaration.kind !== 'const') { | ||
var tokens = sourceCode_1.getTokens(variableDeclaration); | ||
var tokens = sourceCode.getTokens(variableDeclaration); | ||
var letKeywordToken = tokens === null || tokens === void 0 ? void 0 : tokens[0]; | ||
@@ -209,3 +243,5 @@ if ((letKeywordToken === null || letKeywordToken === void 0 ? void 0 : letKeywordToken.value) !== 'const') { | ||
if ((isObjExpression || isCorrectableFunctionExpression)) { | ||
var fixed_1 = isCorrectableFunctionExpression ? fixFunction(node, context) : "React.useMemo(() => (".concat(sourceCode_1.getText(node), "), [])"); | ||
var importStatementFixes_1 = addReactImports(context, isCorrectableFunctionExpression ? 'useCallback' : 'useMemo', reactImportData, fixer); | ||
importStatementFixes_1 && fixes.push(importStatementFixes_1); | ||
var fixed_1 = isCorrectableFunctionExpression ? fixFunction(node, context) : "useMemo(() => (".concat(sourceCode.getText(node), "), [])"); | ||
var parent_1 = node.parent; | ||
@@ -218,3 +254,3 @@ // Means we have a object expression declared directly in jsx | ||
if (returnStatement) { | ||
var indentationLevel = sourceCode_1.lines[returnStatement.loc.start.line - 1].search(/\S/); | ||
var indentationLevel = sourceCode.lines[returnStatement.loc.start.line - 1].search(/\S/); | ||
var indentation = ' '.repeat(indentationLevel); | ||
@@ -241,3 +277,5 @@ // Creates a declaration for the variable and inserts it before the return statement | ||
// Simpler cases bellow, all of them are just adding useMemo/Callback | ||
var fixed = "React.".concat(hook, "(() => ").concat(isObjExpression ? "(" : '').concat(sourceCode.getText(node)).concat(isObjExpression ? ")" : '', ", [])"); | ||
var fixed = "".concat(hook, "(() => ").concat(isObjExpression ? "(" : '').concat(sourceCode.getText(node)).concat(isObjExpression ? ")" : '', ", [])"); | ||
var importStatementFixes = addReactImports(context, hook, reactImportData, fixer); | ||
importStatementFixes && fixes.push(importStatementFixes); | ||
if (node.type === 'FunctionDeclaration') { | ||
@@ -250,7 +288,8 @@ var _node = node; | ||
if ('computed' in node && ((_d = node === null || node === void 0 ? void 0 : node.computed) === null || _d === void 0 ? void 0 : _d.type) === 'ArrowFunctionExpression') { | ||
return fixer.replaceText(node.computed, fixed); | ||
fixes.push(fixer.replaceText(node.computed, fixed)); | ||
} | ||
else { | ||
return fixer.replaceText(node, fixed); | ||
fixes.push(fixer.replaceText(node, fixed)); | ||
} | ||
return fixes; | ||
} | ||
@@ -463,8 +502,8 @@ | ||
var MessagesRequireUseMemoChildren = { | ||
"object-usememo-children": "Object literal should be wrapped in React.useMemo() when used as children", | ||
"array-usememo-children": "Array literal should be wrapped in React.useMemo() when used as children", | ||
"instance-usememo-children": "Object instantiation should be wrapped in React.useMemo() when used as children", | ||
"jsx-usememo-children": "JSX should be wrapped in React.useMemo() when used as children", | ||
"function-usecallback-children": "Function definition should be wrapped in React.useCallback() when used as children", | ||
"unknown-usememo-children": "Unknown value may need to be wrapped in React.useMemo() when used as children", | ||
"object-usememo-children": "Object literal should be wrapped in React's useMemo() when used as children", | ||
"array-usememo-children": "Array literal should be wrapped in React's useMemo() when used as children", | ||
"instance-usememo-children": "Object instantiation should be wrapped in React's useMemo() when used as children", | ||
"jsx-usememo-children": "JSX should be wrapped in React's useMemo() when used as children", | ||
"function-usecallback-children": "Function definition should be wrapped in useCallback() when used as children", | ||
"unknown-usememo-children": "Unknown value may need to be wrapped in React's useMemo() when used as children", | ||
"usememo-const": "useMemo/useCallback return value should be assigned to a `const` to prevent reassignment" | ||
@@ -485,3 +524,5 @@ }; | ||
type: "object", | ||
properties: { strict: { type: "boolean" }, checkHookReturnObject: { type: "boolean" }, checkHookCalls: { type: "boolean" }, ignoredHookCallsNames: { type: "object" } }, | ||
properties: { strict: { type: "boolean" }, checkHookReturnObject: { type: "boolean" }, checkHookCalls: { type: "boolean" }, ignoredHookCallsNames: { type: "object" }, fix: { | ||
addImports: "boolean" | ||
} }, | ||
additionalProperties: false | ||
@@ -493,2 +534,7 @@ }, | ||
var isClass = false; | ||
var importData = { | ||
reactImported: false, | ||
useMemoImported: false, | ||
useCallbackImported: false | ||
}; | ||
function report(node, messageId) { | ||
@@ -499,3 +545,3 @@ context.report({ node: node, messageId: messageId, fix: function (fixer) { | ||
} | ||
return fixBasedOnMessageId(node, messageId, fixer, context); | ||
return fixBasedOnMessageId(node, messageId, fixer, context, importData); | ||
} }); | ||
@@ -533,2 +579,11 @@ } | ||
}, | ||
ImportDeclaration: function (node) { | ||
if (node.source.value === 'react') { | ||
importData.reactImported = true; | ||
importData.importDeclaration = node; | ||
var specifiers = node.specifiers; | ||
importData.useMemoImported = specifiers.some(function (specifier) { return specifier.local.name === 'useMemo'; }); | ||
importData.useCallbackImported = specifiers.some(function (specifier) { return specifier.local.name === 'useCallback'; }); | ||
} | ||
}, | ||
ReturnStatement: function (node) { | ||
@@ -535,0 +590,0 @@ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p; |
{ | ||
"name": "@arthurgeron/eslint-plugin-react-usememo", | ||
"version": "2.0.1", | ||
"version": "2.1.0", | ||
"description": "", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
@@ -41,3 +41,3 @@ # ESLint-Plugin-React-UseMemo | ||
``` | ||
> For more details, please refer to React Native's [documentation](https://reactnative.dev/docs/0.61/optimizing-flatlist-configuration#avoid-anonymous-function-on-renderitem) on the importance of using static or memoized props for complex children. | ||
> For more details, please refer to React's [documentation](https://react.dev/reference/react/useMemo) on hooks, re-rendering and memoization. | ||
@@ -79,3 +79,3 @@ ## Installation | ||
For detailed examples, options available for this rule, and information about the autofix functionality, please refer to our rules documentation. | ||
For detailed examples, options available for this rule, and information about the autofix functionality, please refer to our [rules documentation](https://github.com/arthurgeron/eslint-plugin-react-usememo/blob/main/docs/rules/require-usememo.md). | ||
@@ -93,2 +93,2 @@ ## Rule #2: `require-memo` | ||
## Conclusion | ||
By efficiently using `useMemo`, `useCallback`, and `React.memo()`, we can optimize our React and React Native applications. It allows us to control the re-calculation and re-rendering of components, offering better scalability and performance. | ||
By efficiently using `useMemo`, `useCallback`, and `React.memo()`, we can optimize our React and React Native applications. It allows us to control the re-calculation and re-rendering of components, offering better scalability and performance. |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
41245
674
92