@lichens-innovation/eslint-plugin-coding-guide
v2.0.0
Published
ESLint flat-config plugin enforcing Lichens Innovation TypeScript/React coding standards.
Maintainers
Keywords
Readme
eslint-plugin-coding-guide
ESLint flat-config plugin enforcing Lichens Innovation TypeScript/React coding standards.
Installation
npm install --save-dev @lichens-innovation/eslint-plugin-coding-guidePeer dependency: eslint >= 9.0.0 (flat config only).
Usage
// eslint.config.js
import codingGuide from "@lichens-innovation/eslint-plugin-coding-guide";
export default [
codingGuide.configs.recommended,
// ...your other config objects
];Each rule can also be enabled individually via codingGuide.rules["<rule-name>"] under your own plugin key.
Rules
All rules live under the coding-guide/ namespace and are enabled by configs.recommended. See docs/rules/<name>.md for details on each.
| Rule | Description |
| ------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------- |
| filename-convention-by-export-shape | Enforce filename conventions against a file's exported shape |
| hoist-static-component-constants | Disallow a static array/object literal declared inside a component body |
| max-files-per-folder | Enforce a maximum number of source files per folder |
| max-params-project | Enforce a maximum number of parameters on project-owned functions |
| no-bind-this | Disallow .bind(this) — use an arrow function instead |
| no-double-negation | Disallow double negations such as !isNotBlank(x), !(a !== b) or an isNotDisabled name |
| no-explicit-undefined-optional | Use ? instead of an explicit \| undefined on params/properties that support it |
| no-exported-mutable-state | Disallow exporting a mutable (let/var) module-scoped binding |
| no-hook-returning-jsx | Disallow a use* hook returning JSX |
| no-inline-array-chain-in-jsx | Disallow chained array methods directly inside a JSX expression |
| no-inline-await-access | Disallow operating directly on an awaited value, as in (await promise).property |
| no-inline-curried-handler | Disallow a curried handler factory declared as a local component variable |
| no-inline-guard-chain-handler | Disallow a JSX prop arrow whose body is a long && guard chain |
| no-inline-object-param-type | Disallow inline object type literals on function parameters and nested in interface/type members |
| no-inline-render-function | Disallow local render* helpers that return JSX, and using them from JSX |
| no-jsx-in-variable | Disallow storing a JSX element/fragment in a variable |
| no-mobx-reaction | Disallow MobX reaction — implicit side effects are hard to debug and trace |
| no-nested-try | Disallow nesting a try statement inside another try block or catch handler |
| no-non-hook-use-prefix | Disallow a use* named function whose body calls no hook |
| no-render-fn-in-usecallback | Disallow useCallback wrapping a JSX-returning or render*-named function |
| no-tests-in-dunder-folder | Disallow test files inside a __tests__ folder |
| no-trivial-usememo | Disallow useMemo whose body has no function call (likely unnecessary memoization) |
| no-unguarded-json-parse | Require JSON.parse(...) to be wrapped in a try/catch |
| one-component-per-tsx-file | Allow at most one React component per .tsx file |
| prefer-antd-flex | Prefer Ant Design <Flex> over a <div className="flex …"> in Ant Design apps |
| prefer-blank-helpers | Prefer isBlank/isNotBlank over empty-string, falsy and | | checks on strings |
| prefer-each-table | Prefer the tagged-template table form of .each over an array of tuples |
| prefer-element-ref-type | Prefer useRef<ComponentRef<"tag">>(null) over a raw HTMLXxxElement type argument |
| prefer-get-error-message | Prefer getErrorMessage(error) over a manual error instanceof Error ? error.message : … ternary |
| prefer-includes-over-or-chain | Prefer Array#includes over a chain of === comparisons against the same value |
| prefer-jsx-short-circuit | Prefer && short-circuit for optional JSX, with a boolean left side |
| prefer-nullish-helpers | Prefer isNullish/!isNullish over a manual null-and-undefined comparison pair |
| prefer-positive-condition | Prefer a positive condition in a ternary over a negated one with swapped branches |
| prefer-props-with-children | Prefer PropsWithChildren<Props> over a hand-declared children property |
| prefer-reactnode-over-jsxelement-union | Prefer ReactNode over a JSX.Element \| null \| undefined union |
| prefer-role-query-over-testid | Prefer Testing Library's *ByRole queries over *ByTestId |
| prefer-some-over-find-check | Prefer Array#some over comparing Array#find's result to undefined |
| prefer-state-updater-form | Prefer the updater-function form of a state setter when the new value depends on the current one |
| require-aaa-comments | Require // arrange, // act and // assert comments in multi-statement tests |
| require-effect-cleanup | Require a cleanup return from a useEffect that registers a timer/listener/subscription |
| require-fallback-on-deep-chain | Require a ?? fallback on a deep optional chain |
| require-numeric-enum-initializer | Require an explicit initializer on every enum member |
| require-usestate-useref-generic | Require an explicit generic on useState()/useRef() when the initial value can't infer one |
| todo-ticket-ref | Require a ticket reference in the TODO comment |
Development
Install Bun 1.4+ (see packageManager in package.json), then:
bun installAll Scripts
| Command | Description |
| ------------------- | ----------------------------------------------------------------- |
| bun prepare | Installs husky git hooks (runs on bun install) |
| bun typecheck | Checks TypeScript types without emitting files |
| bun lint | Runs ESLint to check code quality |
| bun lint:fix | Runs ESLint with --fix |
| bun lint:package | Lints package.json via npm-package-json-lint |
| bun lint:unused | Finds unused files, exports, and dependencies (via knip) |
| bun format | Formats all files using Prettier according to .prettierrc rules |
| bun format:check | Checks if files are formatted according to Prettier rules |
| bun build | Cleans dist, then Vite library build (src/index.ts → dist/) |
| bun test | Runs tests using Vitest |
| bun test:coverage | Runs tests with a Vitest coverage report |
Contributions
Contributions to the project are made by improving the current codebase and then creating a Pull Request. Every PR runs the CI workflow (lint, typecheck, test, build). When the PR is merged into main, the release CI pipeline runs automatically. semantic-release determines the next version from conventional commit messages, updates CHANGELOG.md and package.json, and publishes the new version — no manual version bump required.
Library semantic versioning
Versioning is automated by semantic-release using Conventional Commits. The release type is derived from commit message prefixes:
| Commit prefix | Release type |
| ----------------------------- | ----------------------------------------------- |
| fix: | PATCH — backward-compatible bug fix |
| feat: | MINOR — new backward-compatible functionality |
| feat!: / BREAKING CHANGE: | MAJOR — incompatible API change |
Follow Semantic Versioning (MAJOR.MINOR.PATCH) when writing commit messages — the tooling takes care of the rest. Commitlint requires a scope (e.g. feat(rules): add no-foo-bar).
References
License
This project is licensed under the MIT License - see the LICENSE file for details.
