@seanmozeik/de-clank
v0.1.8
Published
Opinionated Oxlint rules that reject AI-shaped code, UI, tests, and project structure.
Downloads
3,306
Readme
@seanmozeik/de-clank
De-clank is an opinionated Oxlint rule set for code, tests, UI, React, React Native, Effect, Bun CLIs, and project layout. It rejects common AI-shaped code and UI patterns, weak type evidence, hidden failures, test-only product code, and source files that record planning history.
The package uses the current Oxlint JavaScript plugin API. Its rules use definePlugin and
createOnce. It has no ESLint layer.
De-clank includes:
- 80 owned rules, including 15 rules adapted from anti-slop;
- separate core, Effect, React, and React Native plugin entries;
- 32 domain-neutral and 180 React-specific curated React Doctor AST rules;
- project layout, entry-point, dependency, and test-only reachability checks;
- shared Oxlint and Oxfmt policy;
- an agent skill for applying the same policy during implementation.
Install
Install the package with the current Oxlint tools:
bun add --dev @seanmozeik/de-clank oxlint@^1.79.0 oxlint-tsgolint@^7.0.2001 oxfmt@^0.64.0oxlint-tsgolint is required for the type-aware rules in the core config. Oxfmt is only
required when the project imports the shared formatter config.
De-clank targets the current toolchain. It does not keep compatibility with older Oxlint plugin APIs. Its development and package gates run on Bun 1.4. The built package also supports Node 20.19 or later.
Compose only the domains you use
Each domain is a separate JavaScript plugin. A React and Effect project can import three entries without loading React Native rules:
import { defineConfig } from 'oxlint';
import {
composeDeClankConfig,
coreBaseConfig,
effectConfig,
reactConfig,
} from '@seanmozeik/de-clank/config';
const projectConfig = defineConfig({
rules: {
'de-clank/enforce-import-boundaries': [
'error',
{
boundaries: [
{ from: '/src/domain/', disallow: ['/src/ui/'] },
{ from: '/src/core/', disallow: ['/src/features/'] },
],
},
],
},
});
export default composeDeClankConfig(coreBaseConfig, effectConfig, reactConfig, projectConfig);Add reactNativeConfig for React Native rules. React Native projects normally also add
reactConfig, because the React entry owns shared React and UI rules.
The public plugin subpaths are:
@seanmozeik/de-clank/core@seanmozeik/de-clank/effect@seanmozeik/de-clank/react@seanmozeik/de-clank/react-native
The package gives each plugin a stable Oxlint alias:
de-clankde-clank-effectde-clank-reactde-clank-react-native
composeDeClankConfig flattens extends, categories, environments, globals, ignore patterns,
options, overrides, rules, and settings into one root config. It keeps the stable union of built-in
and JavaScript plugins from every layer. This prevents Oxlint from losing root-only settings or a
layer's plugins when reusable configs are combined.
Core and domain configs
coreBaseConfig is the only base config. It enables the core and Bun rules, type-aware linting, and
TypeScript compiler diagnostics. Type-aware built-in rules and compiler diagnostics run through
oxlint-tsgolint. It also enables JSDoc syntax checks without requiring duplicated parameter,
property, return, throw, or yield prose. Common Jest, Vitest, JSX, and React Native worklet
directives remain valid. De-clank's JavaScript plugin rules remain fast AST rules in the same pass.
The other configs are independent domain layers:
effectConfigadds Effect rules.reactConfigadds the built-in React, JSX accessibility, and React performance plugins, plus the React, UI, React Doctor, and React Query rules.reactNativeConfigadds React Native rules. Compose it withreactConfigwhen the project also uses the shared React rules.
No preset guesses a project's complete stack. Compose coreBaseConfig with only the domain layers
that the project uses.
Normal validation can use the config options directly:
oxlint .Use --tsconfig only when the project uses a non-standard TypeScript config path.
Oxlint exposes worker count on the command line. Measure it on the target repository:
hyperfine --warmup 2 --runs 10 'oxlint --threads=1 .' 'oxlint --threads=4 .' 'oxlint --threads=8 .'Do not put one thread count in a shared config. The best value changes with the CPU and project graph.
React Doctor port
De-clank depends on oxlint-plugin-react-doctor, not on the React Doctor CLI. It does not vendor or
execute that CLI.
The installed React Doctor registry has 884 entries. De-clank handles them as follows:
- 837 AST rules are available through a generated current-API bridge;
- 42 repository-only scanner rules are not included because they belong to the React Doctor CLI;
- 5 retired rules stay unavailable;
- the core preset enables 32 domain-neutral rules;
- the React preset enables 180 React, JSX, hook, and presentation rules and leaves 3 reviewed rules off.
The bridge records the selectors that each upstream rule registers. One createOnce visitor group
then creates state only for active rules. Generation and contract tests fail when an upstream update
adds an unknown visitor or changes the registry shape.
The React preset selects React Doctor's related-component-aware no-multi-component-file rule. The
rigid no-multi-comp one-component-per-file rule remains available for explicit opt-in. The bridge
also narrows known false positives for stable timer cleanups and explicitly bounded native lists. It
adds automatic fixes only for exact, comment-safe edits.
De-clank does not vendor or recreate the React Doctor CLI scanner. The package is only an Oxlint plugin and configuration package.
Cross-file and workspace rules
The core plugin includes five rules that analyse the project import graph and file layout during the Oxlint pass:
- production modules that only their own tests can reach;
- repeated file prefixes that should become a directory;
- a module beside a directory with the same name;
- a directory with more than 40 direct source files;
- heavy transitive imports on CLI startup paths.
The core plugin also rejects relative imports between packages that a root workspaces field
declares. When every condition of an exact package export resolves to the same target, the rule
replaces the relative path with that public package specifier. The rule checks production modules,
so test files, scripts, tool directories, and configuration entry points stay outside this boundary.
Nested package.json files that are not declared workspaces do not create package boundaries.
In a Git worktree, the graph uses tracked files and untracked files that Git does not ignore. It
honours nested .gitignore files and their negations. It also reads production roots from package
metadata, Justfiles, Wrangler configuration, and framework conventions.
Configure non-standard roots, aliases, and exceptions as normal rule options in oxlint.config.ts:
The flat-prefix rule reports clusters of eight or more files by default. Lower the threshold only when smaller naming families are strong evidence that the files need their own directory.
const projectRules = defineConfig({
rules: {
'de-clank/no-flat-prefix-clusters': ['error', { minimumClusterSize: 3 }],
'de-clank/no-heavy-cli-import-paths': [
'error',
{ cliEntrypoints: ['src/cli.ts'], heavyCliPackages: ['effect', 'shiki'] },
],
'de-clank/no-overloaded-directories': ['error', { maximumDirectoryFiles: 40 }],
'de-clank/no-test-only-production-code': [
'error',
{
allowedTestSupport: ['/tests/support/', '/fixtures/'],
ignore: ['generated', 'vendor/client'],
importAliases: { '@/*': 'src/*' },
productionEntrypoints: ['src/index.ts', 'src/worker.ts'],
},
],
},
});Oxlint validates these options against each rule schema. The five project rules share one cached
analysis when they use the same options. no-redundant-path-segments-in-filenames handles a file
name that repeats its package or parent-directory name as a normal per-file rule.
Rule configuration
Environment access is allowed in conventional environment, configuration, script, tool, path, and secret modules. Add verified bootstrap and entry-point files through the normal Oxlint rule options:
'de-clank/no-environment-access-outside-boundary': [
'error',
{ allowedFilePatterns: ['/src/runtime/platform\\.ts$'] },
],no-partial-record-satisfies can prove inline and local finite unions. List imported enum or union
names when the project wants the same exhaustive-map check across module boundaries:
'de-clank/no-partial-record-satisfies': [
'error',
{ finiteKeyTypes: ['CommandName', 'Permission'] },
],require-query-signal recognises fetch, Undici, and TanStack Query's exact callback signal. List
network client modules whose calls must receive the signal in their arguments:
'de-clank-react/require-query-signal': [
'error',
{ additionalClientModules: ['@/lib/api-client'] },
],no-work-item-references ignores common technical prefixes and model families such as UTF, ISO,
RFC, AST, and GPT. Use workItemPrefixes when one of these is a real project issue prefix. Use
allowedPrefixes for another technical prefix. The markers option replaces the default marker
words.
'de-clank/no-work-item-references': [
'error',
{
allowedPrefixes: ['ACME'],
workItemPrefixes: ['AST'],
},
],require-ui-file-kinds treats components and screens as component-only directories. It does not
treat a general ui layer as component-only. Set componentDirectories when the project uses a
different layout.
require-design-system-primitives exempts common primitive implementation directories such as
components/ui/ and ui/primitives/. Add an implementation path when the project uses another
location.
The rule has no automatic fix. Do not mechanically replace a native control with a styled component. Use a shared primitive only when it preserves the existing geometry and behavior. When native browser geometry is intentional, add an unstyled named wrapper in an exempt primitive file.
'de-clank-react/require-design-system-primitives': [
'error',
{ allowedFilePatterns: ['/src/design-system/elements/'] },
],no-overlong-comments reports one diagnostic for a contiguous line-comment group or block comment
that spans more than ten source lines. Required licence headers are exempt. Change the limit in the
normal Oxlint rule entry when a codebase has a stricter documented policy:
'de-clank/no-overlong-comments': ['error', { maximumLines: 4 }],Private test data
Create ~/.config/de-clank/personal.json outside Git:
{ "literals": ["[email protected]", "A Real Person"], "patterns": ["private-domain\\.example"] }Load it from the central config:
import { loadPersonalData } from '@seanmozeik/de-clank/config';
const rules = { 'de-clank/no-personal-test-data': ['error', loadPersonalData()] };The loader rejects unknown keys, non-string entries, and invalid regular expressions. The rule
allows standard fictional home paths such as /Users/example, but reports personal home paths in
tests.
Suppression and fixes
The ownedRulePolicies catalog covers every owned rule. Each entry states whether the rule is
non-negotiable or needs review before an exception. It also lists known false-positive shapes and any
safe automatic fix.
Use a narrow exception when a rule is wrong for a known file or contract. Inline suppressions must name the exact rule and explain why the exception is safe.
De-clank declares a fix only when the edit has one exact result. Current fixes include removal of
separator, narration, closing-label, and redundant JSDoc comments; exact configured palette
replacements; safe generator naming; selected conditional spreads; redundant Testing Library getBy
assertions; and selected React Doctor utility rewrites. Run oxlint --fix and review the diff.
See docs/rules.md for every owned rule, its options, its message, its fix status, and its suppression guidance.
Oxfmt
Use the formatter policy through its separate export:
export { default } from '@seanmozeik/de-clank/oxfmt';The formatter export does not load the lint plugins.
Provenance
The original anti-slop rules are by Dillon Mulroy. React Doctor and its Oxlint plugin are by Aiden Bai and Million Software.
Rule selection also draws on the public pattern catalogs in Asyraf Hussin's code-slop skill and Desloppify, and on the TypeScript examples in ts-slop. These are idea-level influences. De-clank does not include their source code.
Selected runtime-safety, type-safety, React, and performance rules are generalized adaptations of the Stella Oxlint plugins. Their source and fixtures were rewritten for de-clank's current Oxlint API and low-noise cross-project policy.
The Effect schema, public-tag, and workspace-boundary checks draw on rule ideas from
Executor.
The multi-runner focused-test rule adapts the established behavior of
eslint-plugin-no-only-tests to
Oxlint's current plugin API. The explicit useEffect dependency rule and focused-test selection
were also informed by nkzw-tech/oxlint-config.
De-clank keeps local selection, API adaptation, configuration, added rules, tests, and cross-file analysis. See THIRD_PARTY_NOTICES.md for the complete upstream notices and license terms.
Develop
bun run lint:fast
bun run check
bun run benchmarkbun run check checks formatting and generated registries, runs strict type-aware linting and all
tests, builds every package entry, packs a real tarball, installs it in a clean consumer, checks the
public types, verifies config composition, and checks type-aware and cross-file diagnostics through
Oxlint.
