Skip to content

Commit

Permalink
Add hook names option
Browse files Browse the repository at this point in the history
  • Loading branch information
leroykorterink committed Dec 8, 2023
1 parent 96169c8 commit 78f6d06
Show file tree
Hide file tree
Showing 13 changed files with 96 additions and 86 deletions.
5 changes: 5 additions & 0 deletions lint-staged.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const scriptExtensionsGlob = '?(m|c){j,t}s?x';

export default {
'**/*': () => 'prettier . --write --loglevel=warn',
};
7 changes: 2 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
"eslint": "npm run eslint --workspaces --if-present",
"eslint:fix": "npm run eslint:fix --workspaces --if-present",
"build": "npm run build --workspaces --if-present",
"format": "prettier --write \"./**/*.{ts,js,tsx,jsx,json}\"",
"prepare": "husky install"
"format": "prettier . --write --loglevel=warn",
"postinstall": "husky install"
},
"devDependencies": {
"@mediamonks/eslint-config": "*",
Expand All @@ -36,8 +36,5 @@
"parserOptions": {
"ecmaVersion": "latest"
}
},
"lint-staged": {
"*.{js,jsx,ts,tsx,md,json}": "prettier --write"
}
}
6 changes: 3 additions & 3 deletions packages/eslint-plugin-react/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ Or use the recommended config
💡 Manually fixable by
[editor suggestions](https://eslint.org/docs/developer-guide/working-with-rules#providing-suggestions).

| Name | Description | 💼 | 💡 |
| :------------------------------------------------------------------------------------------- | :---------------------------------------------------------- | :-- | :-- |
| [throttle-use-resize-observer-callback](docs/rules/throttle-use-resize-observer-callback.md) | Callback function in useResizeObserver should be throttled. || 💡 |
| Name | Description | 💼 | 💡 |
| :------------------------------------------------------------- | :------------------------------------ | :-- | :-- |
| [throttle-hook-callback](docs/rules/throttle-hook-callback.md) | Callback in hook should be throttled. || 💡 |

<!-- end auto-generated rules list -->
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Callback function in useResizeObserver should be throttled (`@mediamonks/react/throttle-use-resize-observer-callback`)
# Callback in hook should be throttled (`@mediamonks/react/throttle-hook-callback`)

💼 This rule is enabled in the ✅ `recommended` config.

Expand All @@ -9,8 +9,8 @@

## Rule details

This rule enforces that the callback function in useResizeObserver should be wrapped with a
throttling function. By default, the rule supports the following throttle function names:
This rule enforces that the callback in a hook should be wrapped with a throttle function. By
default, the rule allows the following throttle functions:

- `useRafCallback`
- `useDebounceCallback`
Expand Down Expand Up @@ -43,6 +43,8 @@ useResizeObserver(

This rule has an optional object configuration:

- `hookNames`: An array of strings specifying custom hook names. Default hook names will be used if
this option is not provided.
- `throttleFunctionNames`: An array of strings specifying custom throttle function names. Default
throttle function names will be used if this option is not provided.

Expand All @@ -56,6 +58,7 @@ This rule takes one optional object argument of type object:
"@mediamonks/react/use-resize-observer-throttle-callback": [
"error",
{
"hookNames": ["useCustomHook"],
"throttleFunctionNames": ["customThrottleFunction"]
}
]
Expand Down
10 changes: 3 additions & 7 deletions packages/eslint-plugin-react/index.cts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { type ESLint } from 'eslint';
import useThrottleFunction from './rules/throttleUseResizeObserverCallback';
import * as throttleCallback from './rules/throttleHookCallback';

export = {
rules: {
/* eslint-disable @typescript-eslint/naming-convention */
'throttle-use-resize-observer-callback': useThrottleFunction,
/* eslint-enable */
[throttleCallback.name]: throttleCallback.default,
},
configs: {
recommended: {
Expand All @@ -15,9 +13,7 @@ export = {
},
plugins: ['@mediamonks/react'],
rules: {
/* eslint-disable @typescript-eslint/naming-convention */
'@mediamonks/react/throttle-use-resize-observer-callback': 'error',
/* eslint-enable */
[`@mediamonks/react/${throttleCallback.name}`]: 'error',
},
},
},
Expand Down
5 changes: 5 additions & 0 deletions packages/eslint-plugin-react/lib/getRuleDocumentationPath.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { repository } from '../package.json';

export function getRuleDocumentationPath(ruleName: string): string {
return `${repository.url.slice(0, -4)}/${repository.directory}/docs/rules/${ruleName}.md`;
}
3 changes: 2 additions & 1 deletion packages/eslint-plugin-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
},
"repository": {
"type": "git",
"url": "git+https://github.com/mediamonks/eslint-config.git"
"url": "https://github.com/mediamonks/eslint-config.git",
"directory": "packages/eslint-plugin-react"
},
"description": "Sharable eslint config based on Media.Monks Frontend Coding Standards",
"keywords": [
Expand Down
45 changes: 45 additions & 0 deletions packages/eslint-plugin-react/rules/throttleHookCallback.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { RuleTester } from 'eslint';
import * as throttleHookCallback from './throttleHookCallback';

const ruleTester = new RuleTester({
parserOptions: { ecmaVersion: 6 },
});

ruleTester.run(`@mediamonks/react/${throttleHookCallback.name}`, throttleHookCallback.default, {
valid: [
{
code: 'useResizeObserver({}, useRafCallback(() => {}));',
},
{
code: 'useResizeObserver({}, useDebounceCallback(() => {}, 200));',
},
{
code: 'useResizeObserver({}, useThrottleCallback(() => {}, 200));',
},
],

invalid: [
{
code: 'useResizeObserver({}, function() {});',
errors: [{ message: 'Callback in hook should be throttled.' }],
},
{
code: 'useResizeObserver({}, () => {});',
errors: [{ message: 'Callback in hook should be throttled.' }],
},
{
code: `
function myFunction() {}
useResizeObserver({}, myFunction);
`,
errors: [{ message: 'Callback in hook should be throttled.' }],
},
{
code: `
const myFunction = () => {};
useResizeObserver({}, myFunction);
`,
errors: [{ message: 'Callback in hook should be throttled.' }],
},
],
});
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import { type Rule } from 'eslint';
import { getRuleDocumentationPath } from '../lib/getRuleDocumentationPath';

export const name = 'throttle-hook-callback';

const messages = {
missingThrottleFunction: 'Callback function in useResizeObserver should be throttled.',
missingThrottleFunction: 'Callback in hook should be throttled.',
wrapWithUseRafCallback: 'Wrap callback with useRafCallback',
wrapWithUseDebounceCallback: 'Wrap callback with useDebounceCallback',
wrapWithUseThrottleCallback: 'Wrap callback with useThrottleCallback',
};

const defaultHookNames = ['useResizeObserver', 'useMutationObserver'];

const defaultThrottleFunctionNames = [
'useRafCallback',
'useDebounceCallback',
Expand All @@ -20,9 +25,9 @@ export default {
meta: {
messages,
docs: {
description: 'Callback function in useResizeObserver should be throttled.',
description: 'Callback in hook should be throttled.',
recommended: true,
url: 'https://example.com/',
url: getRuleDocumentationPath(name),
},
schema: [
{
Expand All @@ -45,7 +50,12 @@ export default {
return {
// eslint-disable-next-line @typescript-eslint/naming-convention
CallExpression(node): void {
if ('name' in node.callee && node.callee.name !== 'useResizeObserver') {
const {
throttleFunctionNames = defaultThrottleFunctionNames,
hookNames = defaultHookNames,
} = context.options.at(0) ?? {};

if ('name' in node.callee && !hookNames.includes(node.callee.name)) {
return;
}

Expand All @@ -55,17 +65,13 @@ export default {
return;
}

// Check if CallExpression is one of the throttle functions
if (callbackNode.type === 'CallExpression') {
const { throttleFunctionNames = defaultThrottleFunctionNames } =
context.options.at(0) ?? {};

if (
'name' in callbackNode.callee &&
throttleFunctionNames.includes(callbackNode.callee.name)
) {
return;
}
if (
callbackNode.type === 'CallExpression' &&
'name' in callbackNode.callee &&
// Check if CallExpression is one of the throttle functions
throttleFunctionNames.includes(callbackNode.callee.name)
) {
return;
}

context.report({
Expand Down

This file was deleted.

3 changes: 2 additions & 1 deletion packages/eslint-plugin-react/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
"skipLibCheck": true,
"resolveJsonModule": true
},
"exclude": ["**/*.test.ts"]
}
2 changes: 1 addition & 1 deletion packages/test-eslint-config-react/testJs.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ function MyComponent() {

useResizeObserver(
{},
// eslint-disable-next-line @mediamonks/react/throttle-use-resize-observer-callback
// eslint-disable-next-line @mediamonks/react/throttle-hook-callback
noop,
);

Expand Down
2 changes: 1 addition & 1 deletion packages/test-eslint-config-typescript-react/TestTs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ function _MyComponent(): null {

useResizeObserver(
useRef(document.createElement('div')),
// eslint-disable-next-line @mediamonks/react/throttle-use-resize-observer-callback
// eslint-disable-next-line @mediamonks/react/throttle-hook-callback
noop,
);

Expand Down

0 comments on commit 78f6d06

Please sign in to comment.