frontend/infra/eslint-plugin/README.md
A comprehensive ESLint plugin designed for Flow applications, providing essential linting rules for code quality, import management, and Zustand state management best practices.
# Install the package
rush update
# Or using pnpm in workspace
pnpm add @coze-arch/eslint-plugin@workspace:*
Add the plugin to your ESLint configuration:
// eslint.config.js
import flowPlugin from '@coze-arch/eslint-plugin';
export default [
{
plugins: {
'@coze-arch': flowPlugin,
},
rules: {
'@coze-arch/no-deep-relative-import': ['error', { max: 4 }],
'@coze-arch/max-line-per-function': ['error', { max: 150 }],
'@coze-arch/tsx-no-leaked-render': 'warn',
},
},
];
// eslint.config.js
import flowPlugin from '@coze-arch/eslint-plugin';
export default [
...flowPlugin.configs.recommended,
];
// eslint.config.js
import zustandPlugin from '@coze-arch/eslint-plugin/zustand';
export default [
{
plugins: {
'@coze-arch/zustand': zustandPlugin,
},
...zustandPlugin.configs.recommended,
},
];
no-deep-relative-importPrevents excessive relative import nesting.
// ❌ Bad (default max: 3)
import something from '../../../deep/path';
// ✅ Good
import something from '../../shallow/path';
Options:
max (number): Maximum allowed relative path depth (default: 3)max-line-per-functionEnforces maximum lines per function.
// ❌ Bad (exceeds limit)
function longFunction() {
// ... 200 lines of code
}
// ✅ Good
function shortFunction() {
// ... less than 150 lines
}
Options:
max (number): Maximum lines per function (default: 150)tsx-no-leaked-renderPrevents leaked renders in TSX components.
// ❌ Bad
{count && <Component />} // count could be 0
// ✅ Good
{count > 0 && <Component />}
{Boolean(count) && <Component />}
no-pkg-dir-importPrevents importing from package directories.
// ❌ Bad
import something from 'package/src/internal';
// ✅ Good
import something from 'package';
use-error-in-catchEnforces proper error handling in catch blocks.
// ❌ Bad
try {
doSomething();
} catch (e) {
console.log('error occurred');
}
// ✅ Good
try {
doSomething();
} catch (error) {
console.error('error occurred:', error);
}
no-empty-catchPrevents empty catch blocks.
// ❌ Bad
try {
doSomething();
} catch (error) {
// empty
}
// ✅ Good
try {
doSomething();
} catch (error) {
console.error(error);
}
no-new-errorDiscourages creating new Error instances.
// ❌ Bad
throw new Error('Something went wrong');
// ✅ Good (when configured)
throw createError('Something went wrong');
no-state-mutationPrevents direct state mutation in Zustand stores.
// ❌ Bad
const state = useStore.getState();
state.count = 5;
// ✅ Good
useStore.setState({ count: 5 });
prefer-selectorEncourages using selectors for state access.
// ❌ Bad
const { count, name } = useStore();
// ✅ Good
const count = useStore(state => state.count);
const name = useStore(state => state.name);
store-name-conventionEnforces naming conventions for stores.
// ❌ Bad
const myStore = create(() => ({}));
// ✅ Good
const useMyStore = create(() => ({}));
prefer-shallowEncourages using shallow equality for object selections.
// ❌ Bad
const { user, settings } = useStore(state => ({
user: state.user,
settings: state.settings
}));
// ✅ Good
const { user, settings } = useStore(
state => ({ user: state.user, settings: state.settings }),
shallow
);
package-require-authorEnsures package.json has an author field.
{
"name": "my-package",
"author": "[email protected]"
}
package-disallow-depsPrevents usage of disallowed dependencies (configurable).
# Install dependencies
rush update
# Run tests
rushx test
# Run with coverage
rushx test:cov
# Lint code
rushx lint
# Build (no-op for this package)
rushx build
src/
├── index.ts # Main plugin entry
├── processors/
│ └── json.ts # JSON processor for package.json
├── rules/ # Core ESLint rules
│ ├── no-deep-relative-import/
│ ├── max-lines-per-function/
│ ├── tsx-no-leaked-render/
│ └── ...
└── zustand/ # Zustand-specific rules
├── index.ts # Zustand plugin entry
└── rules/
├── no-state-mutation/
├── prefer-selector/
└── ...
src/rules/ or src/zustand/rules/index.tsindex.test.tsTests are written using ESLint's RuleTester:
import { RuleTester } from 'eslint';
import { myRule } from './index';
const ruleTester = new RuleTester();
ruleTester.run('my-rule', myRule, {
valid: [
// Valid code examples
],
invalid: [
// Invalid code examples with expected errors
],
});
@typescript-eslint/utils - TypeScript ESLint utilitieseslint-module-utils - ESLint module resolution utilitieseslint-rule-composer - Rule composition utilitieseslint-traverse - AST traversal utilitieseslint-utils - General ESLint utilitiessemver - Semantic versioning utilities@typescript-eslint/rule-tester - Rule testing utilitiesvitest - Test runnereslint - ESLint coreApache-2.0 License
For more information about ESLint plugin development, see the ESLint Plugin Developer Guide.