@saifulapm/oxc-config
v0.2.0
Published
Saiful's shareable Oxlint + Oxfmt config — antfu-style factory with bundled anti-slop rules
Maintainers
Readme
@saifulapm/oxc-config
Saiful's shareable Oxlint + Oxfmt config — an antfu-style factory with the anti-slop rules bundled in.
- One factory call per project, everything else auto-detected (TypeScript, React, Vue, Svelte, Astro, Vitest) across pnpm and npm workspaces
- 300+ native rules, zero plugin dependencies
- anti-slop's 15 AI-slop guardrails run as a bundled oxlint JS plugin — no per-repo vendoring
- Matching oxfmt config: no semicolons, single quotes, import sorting, package.json sorting
- Editor-aware: disruptive rules (unused vars, focused tests) soften to warnings while editing
Setup
pnpm add -D oxlint oxfmt @saifulapm/oxc-configoxlint.config.ts:
import saiful from '@saifulapm/oxc-config'
export default saiful({
// everything is auto-detected; set options only to override
ignores: ['generated/**'],
})oxfmt.config.ts:
import { fmt } from '@saifulapm/oxc-config/fmt'
export default fmt()package.json scripts:
{
"lint": "oxlint",
"fmt": "oxfmt"
}Options
export default saiful(
{
typescript: true, // auto: typescript installed
react: { overrides: { 'react/no-array-index-key': 'off' } },
vue: false, // auto: vue/nuxt/vitepress installed (script blocks only — oxc has no template linting yet)
svelte: false, // auto: svelte installed
astro: false, // auto: astro installed
test: true, // auto: vitest installed
antiSlop: true, // default on (requires typescript)
typeAware: false, // needs `oxlint-tsgolint` + TS 7
type: 'app', // 'lib' adds explicit-function-return-type
ignores: [],
globals: { shopify: 'readonly' },
cwd: process.cwd(), // where auto-detection looks; see Monorepos below
},
// extra partial configs, merged last (highest priority)
{ rules: { 'no-console': 'off' } },
)Merge semantics: later entries win for rules/globals/env/settings/categories/options;
overrides/ignorePatterns/jsPlugins concatenate; plugins union.
Monorepos
One config at the repo root is enough. When a framework is missing from the root
package.json, detection reads the workspace packages too — the packages: list in
pnpm-workspace.yaml, or the workspaces field (array or { packages }) for npm and yarn.
React found only in workspace packages is scoped to those packages:
// apps/admin depends on react, packages/api does not
{
"overrides": [{ "files": ["apps/admin/**"], "plugins": ["react"], "rules": {/* … */} }],
}React is the only one scoped this way, because react/rules-of-hooks and friends fire on
plain .ts files — a backend useQueue() helper is not a hook. Vue, Svelte and Astro are
already limited to their own file extensions, and vitest rules to test globs, so those stay
global. Passing react: true yourself opts back into project-wide rules.
Inside a workspace root, only the root's own package.json makes rules global: hoisted
node_modules says nothing about which package actually uses a dependency. Point detection
somewhere other than process.cwd() with cwd.
anti-slop
The generic rules from dmmulroy/anti-slop are vendored
under src/plugins/anti-slop (MIT) and exposed as @saifulapm/oxc-config/anti-slop. All 15 are
enabled as errors by default; mocking/loose-typing rules are relaxed in test files. Disable with
antiSlop: false or tune with antiSlop: { overrides: { ... } }.
Development
pnpm typecheck
pnpm lint # self-hosted: lints this repo with its own config
pnpm fmt
pnpm test # factory snapshots + end-to-end fixture lint
pnpm test:rules # vendored anti-slop RuleTester suites
pnpm build # tsdown → dist/Rule-set changes show up as readable diffs in test/__snapshots__/*.json — review them like
lockfile diffs.
