@kevinmichaelchen/oxlint-plugin-naming-convention
v0.1.1
Published
Oxlint JS plugin port of @typescript-eslint/naming-convention (syntactic subset, no type information)
Maintainers
Readme
@kevinmichaelchen/oxlint-plugin-naming-convention
An Oxlint JS plugin that ports
@typescript-eslint/naming-convention
— the syntactic subset that is possible without a type checker. Same options,
same selectors and modifiers, same messages; the only thing missing is the
type-aware types option (see INCOMPATIBILITIES.md).
Built with effect-oxlint.
Why this exists
Oxlint has no native naming-convention rule. The oxc PR that implemented one
(oxc-project/oxc#26168) was
closed because the maintainers want the rule to be type-aware and to live in
tsgolint; the tsgolint implementations
(#1075,
#1167) are open and
undecided. This plugin is the syntactic subset you can use today, validated
against typescript-eslint's own test fixtures.
Install
pnpm add -D oxlint @kevinmichaelchen/oxlint-plugin-naming-convention [email protected]effect (v4 rc) is a peer dependency of effect-oxlint.
Configure
.oxlintrc.json:
{
"jsPlugins": ["@kevinmichaelchen/oxlint-plugin-naming-convention"],
"rules": {
"naming-convention/naming-convention": [
"error",
{ "selector": "default", "format": ["camelCase"], "leadingUnderscore": "allow" },
{ "selector": "typeLike", "format": ["PascalCase"] },
{ "selector": "enumMember", "format": ["UPPER_CASE"] },
{
"selector": "variable",
"modifiers": ["const", "global"],
"format": ["camelCase", "UPPER_CASE"],
},
{ "selector": "memberLike", "modifiers": ["requiresQuotes"], "format": null },
],
},
}oxlint.config.ts:
import { defineConfig } from "oxlint";
import namingConvention from "@kevinmichaelchen/oxlint-plugin-naming-convention";
export default defineConfig({
extends: [namingConvention.configs.recommended], // loads the plugin, rule at "error" with upstream defaults
rules: {
"naming-convention/naming-convention": [
"error",
{ selector: "default", format: ["camelCase"] },
{ selector: "typeLike", format: ["PascalCase"] },
],
},
});With no options the rule applies upstream's defaults (camelCase everything,
camelCase | PascalCase imports, camelCase | UPPER_CASE variables,
PascalCase type-like names).
Options
The options array is identical to upstream — each entry is a selector object:
| Key | Values |
| ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| selector | default, variableLike, memberLike, typeLike, method, property, accessor, variable, function, parameter, parameterProperty, classicAccessor, autoAccessor, enumMember, classMethod, objectLiteralMethod, typeMethod, classProperty, objectLiteralProperty, typeProperty, class, interface, typeAlias, enum, typeParameter, import (or an array of them) |
| format | array of camelCase, strictCamelCase, PascalCase, StrictPascalCase, snake_case, UPPER_CASE, or null |
| modifiers | const, readonly, static, public, protected, private, #private, abstract, destructured, global, exported, unused, requiresQuotes, override, async, default, namespace (per-selector allow-list as upstream) |
| leadingUnderscore / trailingUnderscore | forbid, require, requireDouble, allow, allowDouble, allowSingleOrDouble |
| prefix / suffix | arrays of strings |
| custom | { regex, match } |
| filter | string or { regex, match } |
| types | accepted for config compatibility; a selector with types never matches (no type information) |
See the typescript-eslint documentation for the full semantics, selector precedence and examples — they apply unchanged.
Fidelity
- Every upstream ESLint selector string is used verbatim as an Oxlint visitor key; Oxlint's selector support covers all of them.
pnpm testreplays typescript-eslint's hand-written fixtures (81 cases that do not need a type checker) and its full generated selector matrix (16,024 cases) through Oxlint'sRuleTester.pnpm differential(indifferential/naming-convention) runs all 16,112 upstream fixtures through ESLint + typescript-eslint and through Oxlint + this plugin and diffs the diagnostics: 0 unexplained differences.pnpm benchthere benchmarks both; on a 300-file synthetic corpus Oxlint + this plugin is ~2.9x faster than ESLint running only the upstream rule (seedifferential/naming-convention/results/bench.md). What that number is made of, and what was tried to get there, is in PERFORMANCE.md.
Known, documented divergences: INCOMPATIBILITIES.md. License notices for the ported code: NOTICE.md.
Development
pnpm build # tsdown -> dist/
pnpm test # vitest; SAMPLE_STEP=7 pnpm test to sample the generated matrix
pnpm typecheck