eslint-plugin-nextfriday 2.0.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +61 -0
- package/README.md +261 -12
- package/docs/rules/BOOLEAN_NAMING_PREFIX.md +13 -0
- package/docs/rules/ENFORCE_CONSTANT_CASE.md +93 -0
- package/docs/rules/FILE_KEBAB_CASE.md +37 -0
- package/docs/rules/JSX_PASCAL_CASE.md +34 -0
- package/lib/index.cjs +448 -468
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +30 -62
- package/lib/index.d.ts +30 -62
- package/lib/index.js +101 -123
- package/lib/index.js.map +1 -1
- package/package.json +2 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,66 @@
|
|
|
1
1
|
# eslint-plugin-nextfriday
|
|
2
2
|
|
|
3
|
+
## 3.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#116](https://github.com/next-friday/eslint-plugin-nextfriday/pull/116) [`64ced55`](https://github.com/next-friday/eslint-plugin-nextfriday/commit/64ced556b4099a40ca2f4750523c7a079d2c81d8) Thanks [@joetakara](https://github.com/joetakara)! - `nextjs` and `nextjs/recommended` presets now also disable `nextfriday/file-kebab-case` (in addition to `nextfriday/jsx-pascal-case`) for files under `app/**`, `src/app/**`, `pages/**`, and `src/pages/**`. The override globs are expanded from `*.{jsx,tsx}` to `*.{js,jsx,ts,tsx}` so `route.ts`, `middleware.ts`, and other framework-named `.ts`/`.js` files in those directories are no longer flagged by either filename rule. Filename conventions in routing directories are owned by the framework, not by this plugin.
|
|
8
|
+
|
|
9
|
+
The `react` and `react/recommended` presets are unchanged — projects using them still enforce `file-kebab-case` on every `.ts`/`.js` and `jsx-pascal-case` on every `.tsx`/`.jsx`.
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- [#116](https://github.com/next-friday/eslint-plugin-nextfriday/pull/116) [`64ced55`](https://github.com/next-friday/eslint-plugin-nextfriday/commit/64ced556b4099a40ca2f4750523c7a079d2c81d8) Thanks [@joetakara](https://github.com/joetakara)! - Documentation quality improvements targeting Context7 scoring gaps:
|
|
14
|
+
- `README.md` — "Per-Directory Configuration" section now explains how flat config resolves rules (config-array order, `files`/`ignores` precedence, why flat replaces `.eslintrc` overrides), adds a preset-tier-per-directory table, and lists common edge cases (glob ordering, top-level vs scoped `ignores`, spreading array-shaped presets, `--print-config` for debugging).
|
|
15
|
+
- `README.md` — "Migration Strategy" section is restructured around six concrete phases: surveying violations with `eslint --format json | jq`, isolating the auto-fix pass into its own PR, adopting the warn-level preset, ratcheting clean directories to `/recommended`, managing exceptions (severity override → directory override → disable comment, in that order of preference), and tracking violation count over time. The "Prioritize rules by impact" table is unchanged.
|
|
16
|
+
- `docs/rules/ENFORCE_CONSTANT_CASE.md` — Configuration section split into install / enable-just-this-rule / enable-with-related-rules / enable-via-preset / scope-to-directory subsections, plus a "Severity-only — no rule options" callout clarifying that the legacy `["error", { ... }]` array form is not accepted because no rule in this plugin has options.
|
|
17
|
+
|
|
18
|
+
## 3.0.0
|
|
19
|
+
|
|
20
|
+
### Major Changes
|
|
21
|
+
|
|
22
|
+
- [#114](https://github.com/next-friday/eslint-plugin-nextfriday/pull/114) [`7933269`](https://github.com/next-friday/eslint-plugin-nextfriday/commit/793326971cbbf15aaf2015f13622b7eff0fd51b2) Thanks [@joetakara](https://github.com/joetakara)! - Remove bundled `configs.sonarjs` and `configs.unicorn`. These configs are no longer exported. Consumers that previously did `...nextfriday.configs.sonarjs` or `...nextfriday.configs.unicorn` must install `eslint-plugin-sonarjs` and/or `eslint-plugin-unicorn` directly and configure them in their own flat config.
|
|
23
|
+
|
|
24
|
+
Migration:
|
|
25
|
+
|
|
26
|
+
```js
|
|
27
|
+
import sonarjs from "eslint-plugin-sonarjs";
|
|
28
|
+
import unicorn from "eslint-plugin-unicorn";
|
|
29
|
+
|
|
30
|
+
export default [
|
|
31
|
+
{
|
|
32
|
+
plugins: { sonarjs },
|
|
33
|
+
rules: { ...sonarjs.configs.recommended.rules },
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
plugins: { unicorn },
|
|
37
|
+
rules: { ...unicorn.configs.recommended.rules },
|
|
38
|
+
},
|
|
39
|
+
];
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The remaining six presets (`base`, `base/recommended`, `react`, `react/recommended`, `nextjs`, `nextjs/recommended`) are unchanged.
|
|
43
|
+
|
|
44
|
+
- [#114](https://github.com/next-friday/eslint-plugin-nextfriday/pull/114) [`7933269`](https://github.com/next-friday/eslint-plugin-nextfriday/commit/793326971cbbf15aaf2015f13622b7eff0fd51b2) Thanks [@joetakara](https://github.com/joetakara)! - `nextjs` and `nextjs/recommended` presets are now arrays of flat-config objects instead of a single object. The first object enables the rules; the second disables `nextfriday/jsx-pascal-case` for files matching `app/**/*.{jsx,tsx}`, `src/app/**/*.{jsx,tsx}`, `pages/**/*.{jsx,tsx}`, and `src/pages/**/*.{jsx,tsx}` — Next.js's official routing directories where filenames are owned by the framework (`page.tsx`, `layout.tsx`, `error.tsx`, etc.).
|
|
45
|
+
|
|
46
|
+
`base`, `base/recommended`, `react`, and `react/recommended` are unchanged — they remain single config objects and `jsx-pascal-case` is enforced everywhere when those presets are used.
|
|
47
|
+
|
|
48
|
+
The `jsx-pascal-case` rule itself no longer special-cases any filename or directory. Scope is expressed in the preset via ESLint's `files` glob, not via rule-internal allowlists. Consumers using `react`/`react/recommended` on a Next.js project must either switch to the `nextjs` preset or add their own `files`-scoped override.
|
|
49
|
+
|
|
50
|
+
Migration:
|
|
51
|
+
|
|
52
|
+
```js
|
|
53
|
+
import nextfriday from "eslint-plugin-nextfriday";
|
|
54
|
+
|
|
55
|
+
export default [nextfriday.configs["nextjs/recommended"]];
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
ESLint 9+ flattens nested config arrays automatically, so existing usage continues to work.
|
|
59
|
+
|
|
60
|
+
### Patch Changes
|
|
61
|
+
|
|
62
|
+
- [#114](https://github.com/next-friday/eslint-plugin-nextfriday/pull/114) [`7933269`](https://github.com/next-friday/eslint-plugin-nextfriday/commit/793326971cbbf15aaf2015f13622b7eff0fd51b2) Thanks [@joetakara](https://github.com/joetakara)! - Fix `enforce-constant-case` flagging conventional names in framework config files. The rule now skips entirely when run on `*.config.{ts,mjs,cjs,js}`, `*.rc.*`, `*.setup.*`, `*.spec.*`, `*.test.*`, `.eslintrc*`, `.babelrc*`, and `.prettierrc*`. Frameworks like Next.js require `nextConfig` in `next.config.ts`, Vite/Tailwind require `config`, etc. — these conventions can no longer be incorrectly flagged as needing `SCREAMING_SNAKE_CASE`.
|
|
63
|
+
|
|
3
64
|
## 2.0.0
|
|
4
65
|
|
|
5
66
|
### Major Changes
|
package/README.md
CHANGED
|
@@ -46,24 +46,49 @@ export default [nextfriday.configs.nextjs];
|
|
|
46
46
|
export default [nextfriday.configs["nextjs/recommended"]];
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
### Extending a Preset with Rule Overrides
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
To use a preset and adjust individual rules, append a second config object after the preset. Later objects override earlier ones, so you can change severity, swap options, or add rules without re-declaring the entire preset.
|
|
52
|
+
|
|
53
|
+
For example, enforce PascalCase for React components via the `react/recommended` preset (which already runs `nextfriday/jsx-pascal-case` and `nextfriday/enforce-camel-case` as errors), and add a rule override on top:
|
|
52
54
|
|
|
53
55
|
```js
|
|
54
56
|
import nextfriday from "eslint-plugin-nextfriday";
|
|
55
57
|
|
|
56
|
-
export default [
|
|
58
|
+
export default [
|
|
59
|
+
nextfriday.configs["react/recommended"],
|
|
60
|
+
|
|
61
|
+
{
|
|
62
|
+
rules: {
|
|
63
|
+
"nextfriday/jsx-pascal-case": "error",
|
|
64
|
+
"nextfriday/enforce-props-suffix": "error",
|
|
65
|
+
"nextfriday/sort-imports": "warn",
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
];
|
|
57
69
|
```
|
|
58
70
|
|
|
59
|
-
|
|
60
|
-
| --------- | --------------------- | ---------------------------------------------------------------------------------------------------------- |
|
|
61
|
-
| `sonarjs` | eslint-plugin-sonarjs | SonarJS recommended rules for bug detection and code quality |
|
|
62
|
-
| `unicorn` | eslint-plugin-unicorn | Unicorn recommended rules (with `filename-case` and `prevent-abbreviations` off, `no-null` off in JSX/TSX) |
|
|
71
|
+
The first object enables every rule in `react/recommended`. The second object reaffirms `jsx-pascal-case` (already enforced — useful when you want it loud and explicit), enables `enforce-props-suffix`, and downgrades `sort-imports` from error to warning.
|
|
63
72
|
|
|
64
73
|
### Manual Configuration
|
|
65
74
|
|
|
66
|
-
|
|
75
|
+
#### When to use manual configuration vs a preset
|
|
76
|
+
|
|
77
|
+
Reach for a preset (`base`, `react`, `nextjs`, or any `/recommended` variant) by default. Presets are curated, kept in sync with new rules as the plugin grows, and require almost no maintenance on your side.
|
|
78
|
+
|
|
79
|
+
Choose manual configuration when one of these applies:
|
|
80
|
+
|
|
81
|
+
| Scenario | Why manual fits better |
|
|
82
|
+
| ----------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
|
83
|
+
| You only need a few specific rules | Presets enable the full set; manual lets you adopt rules one at a time. |
|
|
84
|
+
| You want to opt out of new rules added in future plugin releases | Manual configs are explicit — new rules added to a preset would automatically apply, manual configs don't change without your edit. |
|
|
85
|
+
| You're consolidating multiple ESLint plugins and want fine-grained per-rule control | Avoids preset rules conflicting with rules from other plugins. |
|
|
86
|
+
| You're building a higher-level shared config for your org | You can hand-pick exactly which NextFriday rules to bundle into your own preset. |
|
|
87
|
+
| You're debugging a rule conflict | Manual makes the active rule set unambiguous. |
|
|
88
|
+
|
|
89
|
+
For every other case — new projects, gradual adoption, library code, application code — start from a preset and use [Extending a Preset with Rule Overrides](#extending-a-preset-with-rule-overrides) when you need to adjust specific rules.
|
|
90
|
+
|
|
91
|
+
#### Manual configuration example
|
|
67
92
|
|
|
68
93
|
```js
|
|
69
94
|
import nextfriday from "eslint-plugin-nextfriday";
|
|
@@ -151,8 +176,230 @@ export default [
|
|
|
151
176
|
|
|
152
177
|
> **Note:** This plugin requires ESLint 9+ and only supports the flat config format. Legacy `.eslintrc` configurations are not supported.
|
|
153
178
|
|
|
179
|
+
### Per-Directory Configuration
|
|
180
|
+
|
|
181
|
+
#### How ESLint flat config resolves rules
|
|
182
|
+
|
|
183
|
+
Flat config (the only format this plugin supports) is an **array of config objects** evaluated in order. For every file ESLint lints, it walks the array and merges every object whose `files` glob matches and whose `ignores` glob does not. Later objects override earlier ones rule-by-rule, so the **last matching object wins** for any given rule. Objects with no `files` field apply globally; objects with only `ignores` at the top level remove files from the entire run.
|
|
184
|
+
|
|
185
|
+
This is why per-directory configuration works: you stack a global default first, then layer narrower `files`-scoped objects on top. ESLint 9+ also flattens nested arrays automatically, so spreading a preset that ships as an array (like `nextfriday.configs.nextjs`) works the same as spreading a single object.
|
|
186
|
+
|
|
187
|
+
The legacy `.eslintrc` format used `overrides` and an inheritance tree to express the same thing. Flat config replaces that tree with a flat, deterministic array — easier to reason about, no implicit merging across `extends`, and no `parserOptions` plumbing per directory. The plugin does not ship `.eslintrc` shims, so projects on ESLint 8 or below cannot consume it without upgrading.
|
|
188
|
+
|
|
189
|
+
#### Layering strict and loose presets
|
|
190
|
+
|
|
191
|
+
Apply different rule severities to different directories by stacking config objects:
|
|
192
|
+
|
|
193
|
+
```js
|
|
194
|
+
import nextfriday from "eslint-plugin-nextfriday";
|
|
195
|
+
|
|
196
|
+
export default [
|
|
197
|
+
{
|
|
198
|
+
ignores: ["src/legacy/**", "dist/**", "build/**", "**/*.generated.ts"],
|
|
199
|
+
},
|
|
200
|
+
|
|
201
|
+
nextfriday.configs.react,
|
|
202
|
+
|
|
203
|
+
{
|
|
204
|
+
files: ["src/components/**/*.{ts,tsx}", "src/hooks/**/*.{ts,tsx}"],
|
|
205
|
+
...nextfriday.configs["react/recommended"],
|
|
206
|
+
},
|
|
207
|
+
|
|
208
|
+
{
|
|
209
|
+
files: ["src/utils/**/*.ts", "src/lib/**/*.ts"],
|
|
210
|
+
rules: {
|
|
211
|
+
"nextfriday/require-explicit-return-type": "error",
|
|
212
|
+
"nextfriday/no-relative-imports": "error",
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
|
|
216
|
+
{
|
|
217
|
+
files: ["**/*.{test,spec}.{ts,tsx}"],
|
|
218
|
+
rules: {
|
|
219
|
+
"nextfriday/require-explicit-return-type": "off",
|
|
220
|
+
"nextfriday/no-single-char-variables": "off",
|
|
221
|
+
"nextfriday/no-direct-date": "off",
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
];
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Reading top to bottom:
|
|
228
|
+
|
|
229
|
+
1. **Top-level `ignores`** removes legacy and build artifacts from the entire run. A config object containing _only_ `ignores` is treated as a global ignore — narrower `ignores` inside a `files`-scoped object only affect that object.
|
|
230
|
+
2. **`nextfriday.configs.react`** applies as the warn-level baseline to every file ESLint sees (no `files` glob).
|
|
231
|
+
3. **Component and hook directories** get promoted to `react/recommended` (errors). Because this object comes after the baseline, its severities win.
|
|
232
|
+
4. **Utility directories** keep the warn-level baseline but selectively promote two correctness rules to `error`. Use this pattern when you don't want the full `/recommended` preset but do want specific rules treated as blocking.
|
|
233
|
+
5. **Test files** keep most rules but turn off rules that conflict with common test patterns (single-letter loop counters, frozen `Date.now()` mocks, void-returning `it()` callbacks).
|
|
234
|
+
|
|
235
|
+
#### Choosing a preset tier per directory
|
|
236
|
+
|
|
237
|
+
| Code area | Suggested preset | Why |
|
|
238
|
+
| --------------------------------- | ------------------------------------------- | -------------------------------------------------------------------------- |
|
|
239
|
+
| Library / SDK code | `base/recommended` or `react/recommended` | Public surface should be tightest. `error` blocks regressions at PR time. |
|
|
240
|
+
| New product code | `react/recommended` or `nextjs/recommended` | New code starts clean; lock the conventions in immediately. |
|
|
241
|
+
| Mature product code mid-migration | `react` or `nextjs` (warn) | Ship while migrating. Switch to `/recommended` after a clean run. |
|
|
242
|
+
| Tests, scripts, fixtures | preset + targeted overrides | Keep the core lint signal; turn off rules that mismatch test/CLI patterns. |
|
|
243
|
+
| Legacy / vendored / generated | top-level `ignores` | No lint signal at all. Don't waste reviewer attention or CI time. |
|
|
244
|
+
|
|
245
|
+
#### Edge cases and troubleshooting
|
|
246
|
+
|
|
247
|
+
- **Glob precedence is order-dependent, not specificity-based.** A more specific glob later in the array wins; a more specific glob _earlier_ in the array does not. If `files: ["src/**"]` appears after `files: ["src/components/**"]`, the broader rule set wins for components. Put broader configs first.
|
|
248
|
+
- **`files` and `ignores` are anchored to the project root** (the directory containing `eslint.config.{js,mjs,ts}`), not the file's directory. Use `**/` prefixes for matches anywhere in the tree (e.g., `**/*.test.ts`).
|
|
249
|
+
- **Top-level `ignores` ≠ `ignores` inside a config object.** A standalone object `{ ignores: [...] }` removes files from the entire run; an `ignores` field next to `files` and `rules` only narrows that one config object's match.
|
|
250
|
+
- **Spreading a preset replaces, not merges, the `plugins` field.** If you spread `...nextfriday.configs.react` and then a different config later, the later object's `plugins` wins. Re-declare `plugins: { nextfriday }` if you add rules in a later object.
|
|
251
|
+
- **`nextfriday.configs.nextjs` is an array, not a single object.** Spreading it inline with `...nextfriday.configs.nextjs` only spreads array indices, not the inner objects. Use it as an array entry (`nextfriday.configs.nextjs,`) instead, so ESLint 9+ flattens it.
|
|
252
|
+
- **Two presets in one project.** Use scoped `files` rather than two unscoped presets — unscoped presets stack and the later one's rule severities win for every file, which is rarely what you want.
|
|
253
|
+
- **Verifying the resolved config for a file:** `pnpm eslint --print-config path/to/file.tsx` prints the merged config ESLint would actually use. Reach for this when a rule fires (or doesn't) and you can't tell why.
|
|
254
|
+
|
|
255
|
+
### Migration Strategy
|
|
256
|
+
|
|
257
|
+
For an existing codebase with many violations, treat the migration as a phased rollout — survey, fix, lock in, repeat.
|
|
258
|
+
|
|
259
|
+
#### 1. Survey violations before changing anything
|
|
260
|
+
|
|
261
|
+
Install the plugin as a dev dependency, drop a warn-level preset into `eslint.config.mjs`, and run a read-only lint. Don't `--fix` yet — you want to see the raw shape of the codebase first.
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
pnpm add -D eslint-plugin-nextfriday eslint
|
|
265
|
+
pnpm eslint . --no-fix
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
Group violations by rule so you can plan the work. Most CI dashboards do this for you, but a one-liner works locally:
|
|
269
|
+
|
|
270
|
+
```bash
|
|
271
|
+
pnpm eslint . --no-fix --format json | jq -r '.[].messages[].ruleId' | sort | uniq -c | sort -rn
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
The output tells you which rules account for most of the noise. A rule with 3 violations is a 10-minute fix; a rule with 800 is a multi-week project. Plan accordingly.
|
|
275
|
+
|
|
276
|
+
#### 2. Run the auto-fixers in an isolated PR
|
|
277
|
+
|
|
278
|
+
Roughly a third of this plugin's rules are auto-fixable (the `Fixable ✅` column in the [Rules](#rules) table). Run them in a dedicated commit so the diff is purely mechanical and reviewers don't have to read every line:
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
pnpm eslint . --fix
|
|
282
|
+
git add -u && git commit -m "style(lint): autofix nextfriday rules"
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
Open this as its own PR. Mixing auto-fix output with hand-written changes in the same diff makes review almost impossible.
|
|
286
|
+
|
|
287
|
+
#### 3. Adopt the warn-level preset
|
|
288
|
+
|
|
289
|
+
After the auto-fix pass, drop in the warn-level preset so the remaining violations surface during local dev and CI without breaking the build:
|
|
290
|
+
|
|
291
|
+
```js
|
|
292
|
+
import nextfriday from "eslint-plugin-nextfriday";
|
|
293
|
+
|
|
294
|
+
export default [nextfriday.configs.react];
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
Warnings don't fail `eslint --max-warnings=0`, so add that flag in CI only when you're ready to block on warnings. Until then, warnings are visible signal without pressure.
|
|
298
|
+
|
|
299
|
+
#### 4. Lock in clean directories one at a time
|
|
300
|
+
|
|
301
|
+
As individual directories or features reach zero violations, promote them to `/recommended` (errors) so regressions block at PR time. Everything else stays on the warn-level preset.
|
|
302
|
+
|
|
303
|
+
```js
|
|
304
|
+
import nextfriday from "eslint-plugin-nextfriday";
|
|
305
|
+
|
|
306
|
+
export default [
|
|
307
|
+
nextfriday.configs.react,
|
|
308
|
+
|
|
309
|
+
{
|
|
310
|
+
files: ["src/components/v2/**/*.{ts,tsx}", "src/lib/**/*.ts"],
|
|
311
|
+
...nextfriday.configs["react/recommended"],
|
|
312
|
+
},
|
|
313
|
+
];
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
Repeat per directory. This is how you ratchet without flag-day rewrites.
|
|
317
|
+
|
|
318
|
+
#### 5. Manage exceptions explicitly
|
|
319
|
+
|
|
320
|
+
Three ways to carve out an exception, in order of preference. Pick the narrowest one that solves the problem.
|
|
321
|
+
|
|
322
|
+
**Per-rule severity override** — turn off a single noisy rule globally until you can fix it at the codebase level:
|
|
323
|
+
|
|
324
|
+
```js
|
|
325
|
+
export default [
|
|
326
|
+
nextfriday.configs["react/recommended"],
|
|
327
|
+
|
|
328
|
+
{
|
|
329
|
+
rules: {
|
|
330
|
+
"nextfriday/require-explicit-return-type": "warn",
|
|
331
|
+
"nextfriday/sort-imports": "off",
|
|
332
|
+
},
|
|
333
|
+
},
|
|
334
|
+
];
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
**Per-directory exception** — keep the rule strict everywhere except one stubborn corner:
|
|
338
|
+
|
|
339
|
+
```js
|
|
340
|
+
export default [
|
|
341
|
+
nextfriday.configs["react/recommended"],
|
|
342
|
+
|
|
343
|
+
{
|
|
344
|
+
files: ["src/legacy/**/*.{ts,tsx}"],
|
|
345
|
+
rules: {
|
|
346
|
+
"nextfriday/no-relative-imports": "off",
|
|
347
|
+
"nextfriday/enforce-camel-case": "off",
|
|
348
|
+
},
|
|
349
|
+
},
|
|
350
|
+
];
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
**Per-file or per-line disable comments** — last resort, for genuinely irreducible cases:
|
|
354
|
+
|
|
355
|
+
```ts
|
|
356
|
+
// eslint-disable-next-line nextfriday/no-direct-date
|
|
357
|
+
const epochAnchor = new Date(0);
|
|
358
|
+
|
|
359
|
+
/* eslint-disable nextfriday/no-emoji */
|
|
360
|
+
export const FLAG_EMOJIS = ["🇹🇭", "🇯🇵", "🇺🇸"];
|
|
361
|
+
/* eslint-enable nextfriday/no-emoji */
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
Always disable a _named_ rule, never blanket-disable ESLint. A blanket `// eslint-disable` mutes every rule including correctness ones, so legitimate bugs slip through later.
|
|
365
|
+
|
|
366
|
+
**Skip vendored or generated files entirely** with a top-level ignore — these aren't exceptions to manage, they're code you don't lint at all:
|
|
367
|
+
|
|
368
|
+
```js
|
|
369
|
+
export default [
|
|
370
|
+
{
|
|
371
|
+
ignores: ["dist/**", "build/**", "coverage/**", "**/*.generated.ts"],
|
|
372
|
+
},
|
|
373
|
+
|
|
374
|
+
nextfriday.configs["react/recommended"],
|
|
375
|
+
];
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
#### 6. Track progress so the migration actually lands
|
|
379
|
+
|
|
380
|
+
Migrations stall when nobody can see how close you are. Two cheap signals:
|
|
381
|
+
|
|
382
|
+
- **Violation count over time.** Pipe `pnpm eslint . --no-fix --format compact | wc -l` into your CI metrics or a daily Slack post. Trend it weekly. If the number stops dropping, the migration has stalled.
|
|
383
|
+
- **Verify a single file's resolved config.** When a contributor asks "why did this rule fire on my file?", run `pnpm eslint --print-config path/to/file.tsx`. The output shows exactly which severity ESLint resolved for every rule on that file — usually answers the question in seconds.
|
|
384
|
+
|
|
385
|
+
Once a directory hits zero, lock it in (step 4). Once the warn-level count hits zero across the whole repo, switch the global preset to `/recommended` and add `--max-warnings=0` to CI. The migration is done.
|
|
386
|
+
|
|
387
|
+
#### Prioritize rules by impact
|
|
388
|
+
|
|
389
|
+
When the warn-level preset surfaces hundreds of violations, fix them in this order — high-impact rules catch real bugs, while low-impact rules are style preferences that can wait.
|
|
390
|
+
|
|
391
|
+
| Tier | Examples | Why first |
|
|
392
|
+
| ------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
|
393
|
+
| High — correctness and runtime safety | `no-direct-date`, `no-env-fallback`, `nextjs-require-public-env`, `enforce-readonly-component-props`, `jsx-no-non-component-function`, `enforce-hook-naming`, `no-logic-in-params` | Each violation can mask a bug, leak config, or break React's rules of hooks. Fix before they ship. |
|
|
394
|
+
| Medium — structure and naming | `boolean-naming-prefix`, `enforce-camel-case`, `enforce-constant-case`, `file-kebab-case`, `jsx-pascal-case`, `enforce-props-suffix`, `prefer-import-type` | No runtime impact, but inconsistent naming compounds review and onboarding cost. Fix once the high tier is clean. |
|
|
395
|
+
| Low — formatting and ordering | `sort-imports`, `sort-exports`, `sort-type-alphabetically`, `jsx-sort-props`, `newline-before-return`, `newline-after-multiline-block`, `no-emoji` | Cosmetic. Most are auto-fixable, so a single `pnpm eslint --fix` pass typically clears the whole codebase. Save these for last. |
|
|
396
|
+
|
|
397
|
+
In practice: turn the high tier on as `"error"` first, leave the medium tier as `"warn"` while you migrate, and run the auto-fixers for the low tier in a single dedicated PR.
|
|
398
|
+
|
|
154
399
|
## Rules
|
|
155
400
|
|
|
401
|
+
> All rules in this plugin have no configurable options (`schema: []`). The only knob is severity — set each rule to `"error"`, `"warn"`, or `"off"`. Behavior is intentionally fixed so that the same rule means the same thing across every project.
|
|
402
|
+
|
|
156
403
|
### Variable Naming Rules
|
|
157
404
|
|
|
158
405
|
| Rule | Description | Fixable |
|
|
@@ -253,10 +500,12 @@ export default [
|
|
|
253
500
|
| -------------------- | -------- | ---------- | --------- | ------------- | ----------- |
|
|
254
501
|
| `base` | warn | 40 | 0 | 0 | 40 |
|
|
255
502
|
| `base/recommended` | error | 40 | 0 | 0 | 40 |
|
|
256
|
-
| `react` | warn | 40 |
|
|
257
|
-
| `react/recommended` | error | 40 |
|
|
258
|
-
| `nextjs` | warn | 40 |
|
|
259
|
-
| `nextjs/recommended` | error | 40 |
|
|
503
|
+
| `react` | warn | 40 | 16 | 0 | 56 |
|
|
504
|
+
| `react/recommended` | error | 40 | 16 | 0 | 56 |
|
|
505
|
+
| `nextjs` | warn | 40 | 16 | 1 | 57 |
|
|
506
|
+
| `nextjs/recommended` | error | 40 | 16 | 1 | 57 |
|
|
507
|
+
|
|
508
|
+
The `nextjs` and `nextjs/recommended` presets ship as an array of two flat-config objects: the rule set above, plus a routing override that disables `nextfriday/file-kebab-case` and `nextfriday/jsx-pascal-case` for files matching `app/**/*.{js,jsx,ts,tsx}`, `src/app/**/*.{js,jsx,ts,tsx}`, `pages/**/*.{js,jsx,ts,tsx}`, and `src/pages/**/*.{js,jsx,ts,tsx}`. Next.js owns the filenames in those directories (`page.tsx`, `layout.tsx`, `route.ts`, `middleware.ts`, etc.), so the plugin steps out of the way. ESLint 9+ flattens nested config arrays automatically, so spreading the preset works as expected.
|
|
260
509
|
|
|
261
510
|
### Base Configuration Rules (40 rules)
|
|
262
511
|
|
|
@@ -80,6 +80,19 @@ The rule identifies boolean variables and parameters by:
|
|
|
80
80
|
| `does` | Action capability | `doesExist`, `doesMatch`, `doesContain` |
|
|
81
81
|
| `had` | Past possession | `hadError`, `hadAccess`, `hadPrevious` |
|
|
82
82
|
|
|
83
|
+
## Not Checked
|
|
84
|
+
|
|
85
|
+
To keep the rule unobtrusive on patterns that are usually shaped by external APIs or framework conventions, these locations are intentionally ignored:
|
|
86
|
+
|
|
87
|
+
- **Class methods, getters, and setters.** `class Foo { get valid() {...} }` and `class Foo { set valid(v) {...} }` are not checked.
|
|
88
|
+
- **Class fields (property definitions).** `class Foo { valid = true }` is not checked.
|
|
89
|
+
- **Object literal properties.** `{ valid: true }` and `{ open: true, closed: false }` are not checked. Object keys often mirror an external schema (API responses, config payloads, DB rows) where renaming would be incorrect.
|
|
90
|
+
- **Computed property names.** `{ [key]: true }` is not checked because the name is dynamic.
|
|
91
|
+
- **Destructuring patterns.** `const { valid } = result;` is not checked — rename at the source instead, or use a destructuring alias (`const { valid: isValid } = result;`).
|
|
92
|
+
- **Property access.** `if (user.valid) {}` is not checked.
|
|
93
|
+
|
|
94
|
+
If you need stricter coverage of object/class members, pair this rule with [`@typescript-eslint/naming-convention`](https://typescript-eslint.io/rules/naming-convention/), which can target `classProperty`, `objectLiteralProperty`, `accessor`, and other selectors with custom prefix patterns.
|
|
95
|
+
|
|
83
96
|
## When Not To Use It
|
|
84
97
|
|
|
85
98
|
- When working with external APIs that return boolean fields with different naming conventions
|
|
@@ -8,6 +8,8 @@ This rule ensures that global-scope `const` declarations with static values use
|
|
|
8
8
|
|
|
9
9
|
Only global scope (top-level of a file) is checked. Local scope constants inside functions are not checked by this rule.
|
|
10
10
|
|
|
11
|
+
**Config files are exempt.** Files matching `*.config.{ts,mjs,cjs,js}`, `*.rc.*`, `*.setup.*`, `*.spec.*`, `*.test.*`, `.eslintrc*`, `.babelrc*`, and `.prettierrc*` skip this rule entirely. This avoids conflicts with framework conventions that require specific identifier names — e.g. Next.js expects `nextConfig` (not `NEXT_CONFIG`) in `next.config.ts`, Vite expects `config`, Tailwind expects `config`, etc.
|
|
12
|
+
|
|
11
13
|
## Examples
|
|
12
14
|
|
|
13
15
|
### Incorrect
|
|
@@ -54,6 +56,97 @@ function foo() {
|
|
|
54
56
|
}
|
|
55
57
|
```
|
|
56
58
|
|
|
59
|
+
## Configuration
|
|
60
|
+
|
|
61
|
+
This rule has no options — only severity is configurable (`"error"`, `"warn"`, `"off"`). It pairs with [`no-misleading-constant-case`](./NO_MISLEADING_CONSTANT_CASE.md) so that static globals use `SCREAMING_SNAKE_CASE` while local scopes and dynamic values keep `camelCase`.
|
|
62
|
+
|
|
63
|
+
### Install
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
pnpm add -D eslint-plugin-nextfriday eslint
|
|
67
|
+
# npm install --save-dev eslint-plugin-nextfriday eslint
|
|
68
|
+
# yarn add --dev eslint-plugin-nextfriday eslint
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Enable just this rule
|
|
72
|
+
|
|
73
|
+
Use this when you want the rule but not the rest of the preset (e.g., adopting one rule at a time during a migration). The `plugins` field registers the plugin under the `nextfriday` namespace; the `rules` field turns on the rule by name:
|
|
74
|
+
|
|
75
|
+
```js
|
|
76
|
+
import nextfriday from "eslint-plugin-nextfriday";
|
|
77
|
+
|
|
78
|
+
export default [
|
|
79
|
+
{
|
|
80
|
+
plugins: { nextfriday },
|
|
81
|
+
rules: {
|
|
82
|
+
"nextfriday/enforce-constant-case": "error",
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
];
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Enable with related rules
|
|
89
|
+
|
|
90
|
+
Constants, locals, and dynamic values each need a different naming convention. Enable the trio together so violations from any direction surface:
|
|
91
|
+
|
|
92
|
+
```js
|
|
93
|
+
import nextfriday from "eslint-plugin-nextfriday";
|
|
94
|
+
|
|
95
|
+
export default [
|
|
96
|
+
{
|
|
97
|
+
plugins: { nextfriday },
|
|
98
|
+
rules: {
|
|
99
|
+
"nextfriday/enforce-constant-case": "error",
|
|
100
|
+
"nextfriday/no-misleading-constant-case": "error",
|
|
101
|
+
"nextfriday/enforce-camel-case": "error",
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
];
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Enable via a preset
|
|
108
|
+
|
|
109
|
+
Every preset includes this rule at the preset's severity (`warn` or `error`). This is the simplest setup and the recommended one for most projects:
|
|
110
|
+
|
|
111
|
+
```js
|
|
112
|
+
import nextfriday from "eslint-plugin-nextfriday";
|
|
113
|
+
|
|
114
|
+
export default [nextfriday.configs["base/recommended"]];
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Scope to a directory
|
|
118
|
+
|
|
119
|
+
If you're migrating an existing codebase, scope the rule to a clean directory first and leave the rest of the project on `"warn"` until you've fixed the violations there. ESLint 9+ flat config layers configs in array order; the later object's severity wins for any file matching its `files` glob:
|
|
120
|
+
|
|
121
|
+
```js
|
|
122
|
+
import nextfriday from "eslint-plugin-nextfriday";
|
|
123
|
+
|
|
124
|
+
export default [
|
|
125
|
+
nextfriday.configs.base,
|
|
126
|
+
|
|
127
|
+
{
|
|
128
|
+
files: ["src/config/**/*.ts", "src/lib/**/*.ts"],
|
|
129
|
+
rules: {
|
|
130
|
+
"nextfriday/enforce-constant-case": "error",
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
];
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Severity-only — no rule options
|
|
137
|
+
|
|
138
|
+
Each rule in this plugin uses `schema: []` and `defaultOptions: []` (no options). The flat-config value is **only** the severity string — `"error"`, `"warn"`, or `"off"`. The legacy `["error", { ... }]` array form is not accepted because there are no options to pass.
|
|
139
|
+
|
|
140
|
+
```js
|
|
141
|
+
// Correct
|
|
142
|
+
"nextfriday/enforce-constant-case": "error"
|
|
143
|
+
|
|
144
|
+
// Won't apply — there are no options to override
|
|
145
|
+
"nextfriday/enforce-constant-case": ["error", { allowCamelCase: true }]
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
This plugin only supports ESLint 9+ flat config — legacy `.eslintrc` is not supported. Projects on ESLint 8 or below cannot consume it without upgrading.
|
|
149
|
+
|
|
57
150
|
## When Not To Use It
|
|
58
151
|
|
|
59
152
|
- If your project uses different naming conventions for constants
|
|
@@ -28,6 +28,43 @@ This rule enforces that all TypeScript (.ts) and JavaScript (.js) files use keba
|
|
|
28
28
|
- `user-service.ts`
|
|
29
29
|
- `api-utils.ts`
|
|
30
30
|
|
|
31
|
+
## Allowed Patterns and Edge Cases
|
|
32
|
+
|
|
33
|
+
- **Only `.ts` and `.js` are checked.** `.tsx` and `.jsx` files are ignored — use [`jsx-pascal-case`](./JSX_PASCAL_CASE.md) for React component filenames.
|
|
34
|
+
- **Compound extensions are allowed when each segment is kebab-case.** Both the basename and the trailing token before the file extension are validated independently. This pattern is useful for config, setup, spec, test, and rc files:
|
|
35
|
+
- `next.config.ts` ✓
|
|
36
|
+
- `vitest.setup.ts` ✓
|
|
37
|
+
- `user-service.test.ts` ✓
|
|
38
|
+
- `auth.spec.ts` ✓
|
|
39
|
+
- `eslint.rc.ts` ✓
|
|
40
|
+
- **Numbers are allowed inside segments.** `file-with-numbers-123.ts` ✓
|
|
41
|
+
- **Single-word filenames are valid.** `single.ts` ✓ (no hyphens needed)
|
|
42
|
+
|
|
43
|
+
## Scoping the Rule
|
|
44
|
+
|
|
45
|
+
This rule has **no built-in framework detection**. It checks every `.ts`/`.js` file it sees against kebab-case. In Next.js projects, routing directories (`app/`, `pages/`) contain framework-named files (`route.ts`, `middleware.ts`) that already happen to be kebab-case — but if you colocate helpers there with non-kebab names (`useThing.ts`, `MyHelper.ts`), the rule will flag them.
|
|
46
|
+
|
|
47
|
+
The `nextjs` and `nextjs/recommended` presets ship with an override that **automatically disables this rule** for files under `app/**`, `src/app/**`, `pages/**`, and `src/pages/**` (matched against `*.{js,jsx,ts,tsx}`). Filename conventions in those directories are owned by the framework, not by this plugin. The `base` and `react` presets do **not** include this override — they enforce `file-kebab-case` on every `.ts`/`.js` regardless of directory.
|
|
48
|
+
|
|
49
|
+
## Disabling the Rule
|
|
50
|
+
|
|
51
|
+
To opt out for additional directories or file patterns, add an override in your flat config:
|
|
52
|
+
|
|
53
|
+
```js
|
|
54
|
+
import nextfriday from "eslint-plugin-nextfriday";
|
|
55
|
+
|
|
56
|
+
export default [
|
|
57
|
+
nextfriday.configs["base/recommended"],
|
|
58
|
+
|
|
59
|
+
{
|
|
60
|
+
files: ["src/legacy/**/*.ts", "src/vendor/**/*.js"],
|
|
61
|
+
rules: {
|
|
62
|
+
"nextfriday/file-kebab-case": "off",
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
];
|
|
66
|
+
```
|
|
67
|
+
|
|
31
68
|
## When Not To Use It
|
|
32
69
|
|
|
33
70
|
If your project has established naming conventions that conflict with kebab-case, or if you're working with frameworks that require specific filename patterns, you may want to disable this rule.
|
|
@@ -28,6 +28,40 @@ This rule enforces that JSX and TSX files use PascalCase naming convention for t
|
|
|
28
28
|
- `LoginForm.tsx`
|
|
29
29
|
- `UserProfile2.jsx` (PascalCase with numbers)
|
|
30
30
|
|
|
31
|
+
## Scoping the Rule
|
|
32
|
+
|
|
33
|
+
This rule has **no built-in framework detection** and no allowlist of "known" filenames. It checks every `.jsx`/`.tsx` it sees against PascalCase.
|
|
34
|
+
|
|
35
|
+
The `nextjs` and `nextjs/recommended` presets ship with an override that **automatically disables this rule** for files under `app/**`, `src/app/**`, `pages/**`, and `src/pages/**` — Next.js owns those filenames (`page.tsx`, `layout.tsx`, `error.tsx`, etc.). If you use a `nextjs` preset, you do not need to add a routing override yourself.
|
|
36
|
+
|
|
37
|
+
The `base` and `react` presets do **not** include this override. If you use `react` on a Next.js project (or any project that mixes PascalCase component files with lowercase framework routing files), scope the rule explicitly via ESLint's `files` glob:
|
|
38
|
+
|
|
39
|
+
```js
|
|
40
|
+
import nextfriday from "eslint-plugin-nextfriday";
|
|
41
|
+
|
|
42
|
+
export default [
|
|
43
|
+
nextfriday.configs.react,
|
|
44
|
+
|
|
45
|
+
{
|
|
46
|
+
files: ["src/components/**/*.{jsx,tsx}", "components/**/*.{jsx,tsx}"],
|
|
47
|
+
rules: {
|
|
48
|
+
"nextfriday/jsx-pascal-case": "error",
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
{
|
|
53
|
+
files: ["src/app/**/*.{jsx,tsx}", "app/**/*.{jsx,tsx}", "src/pages/**/*.{jsx,tsx}", "pages/**/*.{jsx,tsx}"],
|
|
54
|
+
rules: {
|
|
55
|
+
"nextfriday/jsx-pascal-case": "off",
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
];
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The first override turns the rule on only inside component directories where PascalCase is the convention. The second override explicitly disables the rule for Next.js routing directories where the framework owns the filename.
|
|
62
|
+
|
|
63
|
+
The plugin deliberately does not try to detect Next.js, Remix, or other framework conventions outside of the `nextjs` preset — folder structures vary across projects (monorepos, custom `app` locations, hybrid Pages + App Router setups), and a built-in allowlist would inevitably go stale. ESLint's `files` glob is the deterministic way to express the scope you actually want.
|
|
64
|
+
|
|
31
65
|
## When Not To Use It
|
|
32
66
|
|
|
33
67
|
If your project uses different naming conventions for JSX/TSX files, you can disable this rule.
|