eslint-plugin-jimdo-custom-rules
v1.4.0
Published
eslint rule to define eslint custom rules for jimdo
Readme
eslint-plugin-jimdo-custom-rules
Custom ESLint rules for Jimdo projects.
Installation
Install the ESLint plugin by running:
npm install --save-dev eslint-plugin-jimdo-custom-rulesRules
disallow-imports-in-folder
Some projects have files that aren't meant to be executed in the same environment. For instance, think about a web application with distinct code for the server and the client. In such cases, importing server-only files in client code can lead to issues.
This ESLint rule allows you to specify paths that should be restricted from imports in certain areas of your project. By defining these restricted zones, you can ensure that files intended for a specific environment (e.g., server or client) are not inadvertently imported into the wrong context.
Parameters for the rule
0 - error level, [error | warning]
1 - rules for a folder
Configuration
Add the plugin to your ESLint configuration file, for example, .eslintrc.js.
e.g. disallow imports containing @apps/wizard in folder workspace/apps/cms
module.exports = {
plugins: ['jimdo-custom-rules'],
rules: {
'jimdo-custom-rules/disallow-imports-in-folder': ['error', {
folderRules: [
// Define your restricted folders here
folder: 'workspace/apps/cms',
disallowedImports: [
'@apps/wizard',
...
],
],
}],
},
};safe-exhaustive-deps
An enhanced version of React's exhaustive-deps rule that prevents infinite render loops by detecting and excluding functions that are redeclared on each render from dependency array warnings.
Why this rule?
The standard react-hooks/exhaustive-deps rule is helpful for ensuring all dependencies are included in React Hook dependency arrays. However, it can sometimes suggest including functions that get redeclared on each render (like inline functions or non-memoized function declarations inside components). Including such functions in dependency arrays causes infinite render loops.
This rule extends the behavior of exhaustive-deps to:
- Detect functions declared inline within components (arrow functions, function expressions)
- Detect function declarations within component bodies
- Exclude these "unsafe" functions from dependency warnings
- Still warn about other missing dependencies as usual
What it detects
The rule identifies these patterns as unsafe for dependency arrays:
- Inline arrow functions and function expressions:
function MyComponent() {
const handleClick = () => { // ❌ Unsafe - redeclared each render
console.log('clicked');
};
useEffect(() => {
handleClick();
}, [handleClick]); // This would cause infinite renders
}- Function declarations inside components:
function MyComponent() {
function handleClick() { // ❌ Unsafe - redeclared each render
console.log('clicked');
}
useEffect(() => {
handleClick();
}, [handleClick]); // This would cause infinite renders
}- Functions wrapped in useCallback/useMemo are safe:
function MyComponent() {
const handleClick = useCallback(() => { // ✅ Safe - memoized
console.log('clicked');
}, []);
useEffect(() => {
handleClick();
}, [handleClick]); // This is safe and won't be flagged
}Usage
This rule is automatically enabled when you use @jimdo/eslint-config-jimdo. It replaces the standard react-hooks/exhaustive-deps rule with this safer version.
The rule works with all React Hooks that accept dependency arrays:
useEffectuseLayoutEffectuseCallbackuseMemouseImperativeHandle
Examples
Problem:
function MyComponent({ id }) {
// This function is redeclared on every render
const fetchData = () => {
fetch(`/api/data/${id}`).then(/*...*/);
};
useEffect(() => {
fetchData();
}, [fetchData]); // ❌ Would cause infinite renders!
}Solution 1 - Use useCallback:
function MyComponent({ id }) {
const fetchData = useCallback(() => {
fetch(`/api/data/${id}`).then(/*...*/);
}, [id]); // ✅ Memoized with proper dependencies
useEffect(() => {
fetchData();
}, [fetchData]); // ✅ Safe to include
}Solution 2 - Move function outside component:
const fetchData = (id) => {
fetch(`/api/data/${id}`).then(/*...*/);
};
function MyComponent({ id }) {
useEffect(() => {
fetchData(id);
}, [id]); // ✅ Safe - fetchData is stable
}Solution 3 - Inline the function:
function MyComponent({ id }) {
useEffect(() => {
fetch(`/api/data/${id}`).then(/*...*/);
}, [id]); // ✅ Safe - no function in deps
}polymorphic-component-a11y
An enhanced accessibility rule that extends jsx-a11y's no-static-element-interactions and click-events-have-key-events rules to support polymorphic components using the component prop pattern.
Why this rule?
Jimdo design system often use polymorphic components where a single component (like Box) can render as different HTML elements via a component prop:
<Box component="button" onClick={handleClick}>Click me</Box>
<Box component={Button} onClick={handleClick}>Click me</Box>The standard jsx-a11y rules don't understand this pattern and would incorrectly flag these as accessibility violations. This rule properly resolves the component prop (including imported components) and only reports errors when non-interactive elements have interaction handlers without proper keyboard accessibility.
How it works
The rule:
- Wraps the upstream
jsx-a11y/no-static-element-interactionsandjsx-a11y/click-events-have-key-eventsrules - Resolves the
componentprop to determine the actual HTML element being rendered - Uses the jsx-a11y settings to map component names (like
Button) to their native element types - Only reports violations for definitively non-interactive elements with interaction handlers
Usage
This rule is automatically enabled when you use @jimdo/eslint-config-jimdo. The standard jsx-a11y rules are disabled in favor of this polymorphic-aware version.
Examples
Valid - Interactive elements with onClick:
// Native interactive element
<Box component="button" onClick={handleClick}>Click</Box>
// Mapped to interactive element
<Box component={Button} onClick={handleClick}>Click</Box>
// Non-interactive without handlers
<Box component="p">Text content</Box>Invalid - Non-interactive elements with onClick:
// Native non-interactive element
<Box onClick={handleClick}>Click</Box>
// Error: Static elements should not have mouse or keyboard event handlers
// Error: Elements with onClick handlers must have a keyboard event handler
// Mapped to non-interactive element
<Box component={Tag} onClick={handleClick}>Click</Box>
// Error: Static elements should not have mouse or keyboard event handlers
// Error: Elements with onClick handlers must have a keyboard event handlerFixes:
// Option 1: Use an interactive component
<Box component="button" onClick={handleClick}>Click</Box>
// Option 2: Add keyboard handler and role
<Box
component="div"
onClick={handleClick}
onKeyDown={handleKeyDown}
role="button"
tabIndex={0}
>
Click
</Box>
// Option 3: Don't use interaction handlers on non-interactive elements
<button onClick={handleClick}>Click</button>no-redundant-icon-aria-hidden
Prevents redundant aria-hidden attribute on Icon component since it's already included in the component implementation.
Why this rule?
The Jimdo design system's Icon component automatically applies aria-hidden={true} in its implementation. Adding it manually creates redundancy and may cause confusion.
What it checks
The rule flags any Icon component that has an explicit aria-hidden attribute:
// ❌ Invalid - aria-hidden is redundant
<Icon icon={CheckIcon} aria-hidden />
<Icon icon={CheckIcon} aria-hidden={true} />
<Icon icon={CheckIcon} aria-hidden={false} />
<Icon icon={CheckIcon} aria-hidden="true" />// ✅ Valid - no aria-hidden needed
<Icon icon={CheckIcon} />
<Icon icon={CheckIcon} size="small" />Auto-fix
This rule includes an auto-fix that removes the redundant aria-hidden attribute:
eslint --fixUsage
This rule is automatically enabled when you use @jimdo/eslint-config-jimdo.
