commit-sheriff 1.6.1 → 1.7.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/README.md +39 -33
- package/bin/commit-sheriff.js +73 -49
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,11 +5,15 @@ Shared [Husky](https://typicode.github.io/husky/) git hooks for any project —
|
|
|
5
5
|
## Quick start
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npm
|
|
8
|
+
npm install --save-dev commit-sheriff husky
|
|
9
9
|
npx commit-sheriff init
|
|
10
|
-
npx commit-sheriff add-eslint-react # optional —
|
|
10
|
+
npx commit-sheriff add-eslint-react # optional — only needed if init didn't auto-detect react+typescript
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
+
This is the full flow end to end. The `Install`, `Usage`, and `What init does` sections below repeat
|
|
14
|
+
these same commands with more context/explanation — you don't need to run anything extra from
|
|
15
|
+
there, they're not additional steps.
|
|
16
|
+
|
|
13
17
|
## Table of contents
|
|
14
18
|
|
|
15
19
|
- [Quick start](#quick-start)
|
|
@@ -77,9 +81,9 @@ Run this once per repo, from the repo root (where `package.json` lives). This wo
|
|
|
77
81
|
4. Adds a default `lint-staged` block to `package.json` **only if one doesn't already exist**.
|
|
78
82
|
5. Adds a `"prepare": "husky"` npm script if missing, so hooks are (re)installed automatically after `npm install`.
|
|
79
83
|
6. Installs `lint-staged`, `eslint`, and `prettier` as devDependencies (via `npm install --save-dev`) if any of them are missing, so the pre-commit lint/format step actually runs instead of silently no-oping.
|
|
80
|
-
7. If `react` and `typescript` are both present in your `dependencies`/`devDependencies`, also runs [`add-eslint-react`](#advanced-eslint-module-boundary-template-typescriptreact) automatically, which
|
|
84
|
+
7. If `react` and `typescript` are both present in your `dependencies`/`devDependencies`, also runs [`add-eslint-react`](#advanced-eslint-module-boundary-template-typescriptreact) automatically, which **overwrites** `eslint.config.mjs` and `.prettierrc.js` with the latest templates (folding in `next/core-web-vitals`/`next/typescript` automatically if `next` is detected) and installs the extra plugins it needs — no manual merge step. Otherwise it's skipped and you can add it manually later.
|
|
81
85
|
|
|
82
|
-
Re-running `npx commit-sheriff init` later (e.g. after updating the package) is safe for your project-specific settings: it refreshes the hook scripts and (on react+typescript projects) the ESLint/Prettier templates to the latest version, but leaves your `.commitsheriffrc.json` / `lint-staged` config alone.
|
|
86
|
+
Re-running `npx commit-sheriff init` later (e.g. after updating the package) is safe for your project-specific settings: it refreshes the hook scripts and (on react+typescript projects) the ESLint/Prettier templates to the latest version, but leaves your `.commitsheriffrc.json` / `lint-staged` config alone. `eslint.config.mjs`, `eslint.config.commit-sheriff.mjs`, and `.prettierrc.js` are **always overwritten** on every re-run — back them up under a different name first if you've hand-edited them.
|
|
83
87
|
|
|
84
88
|
**Why the auto-install matters**: the pre-commit hook only runs `lint-staged` if it can actually
|
|
85
89
|
find the package — if it's missing, older versions of this hook **silently skipped linting
|
|
@@ -272,29 +276,25 @@ npx commit-sheriff add-eslint-react
|
|
|
272
276
|
```
|
|
273
277
|
|
|
274
278
|
This ships as a **flat config** (`eslint.config.*`, ESLint 9+ format), not the legacy
|
|
275
|
-
`.eslintrc.js` format — see [why](#why-flat-config) below.
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
`add-eslint-react` refreshes it to the latest version of the template). If you've customized it
|
|
295
|
-
by hand, back it up under a different name first — your edits will be replaced. The same applies
|
|
296
|
-
to `eslint.config.mjs` when it's the one written directly (the no-existing-config case above); the
|
|
297
|
-
side-file case never touches your own config.
|
|
279
|
+
`.eslintrc.js` format — see [why](#why-flat-config) below. It always writes two files, no manual
|
|
280
|
+
merge step required, ever:
|
|
281
|
+
|
|
282
|
+
- `eslint.config.commit-sheriff.mjs` — the actual ruleset (module-boundary rules + all the
|
|
283
|
+
recommended plugins: TypeScript, React, hooks, a11y, sonarjs, import, testing-library, vitest,
|
|
284
|
+
jest, prettier).
|
|
285
|
+
- `eslint.config.mjs` — the entry point ESLint actually reads, generated fresh every run to import
|
|
286
|
+
the file above. **If you already had an `eslint.config.mjs` (e.g. Next.js's own
|
|
287
|
+
`create-next-app`-generated one), it is fully overwritten** — not merged, not left alone. If
|
|
288
|
+
`next` is detected in your `dependencies`, the generated entry point folds in
|
|
289
|
+
`next/core-web-vitals`/`next/typescript` automatically (via the same `FlatCompat` pattern Next's
|
|
290
|
+
own generated config uses) so you don't lose Next-specific linting; `eslint-config-next` is
|
|
291
|
+
auto-installed too if it's missing. Any other hand-written customizations in your previous
|
|
292
|
+
`eslint.config.mjs` are not preserved — back it up under a different name first if you need them.
|
|
293
|
+
|
|
294
|
+
`.prettierrc.js` is written/refreshed the same way — **always overwritten** with the latest
|
|
295
|
+
template (same behavior as the `commit-msg`/`pre-commit` hooks). This trade-off is intentional:
|
|
296
|
+
zero manual steps for the common case, at the cost of not preserving bespoke prior ESLint/Prettier
|
|
297
|
+
setups.
|
|
298
298
|
|
|
299
299
|
The module list for the boundary rule isn't hardcoded — it's read straight from the `modules`
|
|
300
300
|
array in your root `.commitsheriffrc.json` (the same list the commit-msg/branch-name hooks use
|
|
@@ -310,16 +310,22 @@ It installs whatever it needs automatically (via `npm install --save-dev`, same
|
|
|
310
310
|
`lint-staged`/`eslint`/`prettier`), skipping anything already present:
|
|
311
311
|
|
|
312
312
|
```bash
|
|
313
|
-
npm install --save-dev eslint@^9 typescript @typescript-eslint/parser \
|
|
314
|
-
@typescript-eslint/eslint-plugin @eslint/js @eslint/eslintrc eslint-plugin-sonarjs \
|
|
313
|
+
npm install --save-dev eslint@^9 typescript@^5 @typescript-eslint/parser \
|
|
314
|
+
@typescript-eslint/eslint-plugin @eslint/js@^9 @eslint/eslintrc eslint-plugin-sonarjs \
|
|
315
315
|
eslint-plugin-import eslint-plugin-prettier eslint-config-prettier eslint-plugin-react \
|
|
316
316
|
eslint-plugin-react-hooks eslint-plugin-jsx-a11y eslint-plugin-testing-library \
|
|
317
317
|
@vitest/eslint-plugin eslint-plugin-jest prettier
|
|
318
318
|
```
|
|
319
319
|
|
|
320
|
-
`eslint`
|
|
321
|
-
|
|
322
|
-
|
|
320
|
+
`eslint`, `@eslint/js`, and `typescript` are pinned on purpose rather than left to resolve to
|
|
321
|
+
whatever `latest` is — the plugin ecosystem here regularly lags behind both. Two concrete
|
|
322
|
+
conflicts this has already caused: `@eslint/js`'s own `latest` declares a hard peer on
|
|
323
|
+
`eslint@^10`, so leaving it unpinned next to `eslint@^9` is an instant `ERESOLVE`; and
|
|
324
|
+
`@typescript-eslint/eslint-plugin` currently only supports `typescript` up to `<6.1.0`, so an
|
|
325
|
+
unpinned `typescript` install (which resolves to its own `latest`, e.g. `7.x`) crashes plugin
|
|
326
|
+
loading with "typescript-eslint does not support TS 7.0". Pinning `eslint`/`@eslint/js` together
|
|
327
|
+
to `^9` and `typescript` to `^5` keeps the whole toolchain on versions that are actually
|
|
328
|
+
compatible with each other today.
|
|
323
329
|
|
|
324
330
|
If the install fails (offline, registry issue, etc.), it prints this exact command so you can run
|
|
325
331
|
it yourself.
|
|
@@ -332,7 +338,7 @@ entirely** — there's no fallback. Since frameworks like Next.js already scaffo
|
|
|
332
338
|
actually run (this was a real bug: an unused `useState` import went completely unflagged because
|
|
333
339
|
the module-boundary config was silently dead). The flat config here uses `FlatCompat` (the same
|
|
334
340
|
official migration helper Next.js's own generated config uses internally) so the exact same rule
|
|
335
|
-
set works natively under ESLint 9+,
|
|
341
|
+
set works natively under ESLint 9+, whether or not the project already had its own flat config.
|
|
336
342
|
|
|
337
343
|
A legacy `.eslintrc.js` version of this template (`eslintrc.module-boundaries.js`) still ships
|
|
338
344
|
inside the package for reference/manual use on pure ESLint 8 projects with no flat config support
|
package/bin/commit-sheriff.js
CHANGED
|
@@ -202,11 +202,19 @@ function init() {
|
|
|
202
202
|
const ESLINT_REACT_DEV_DEPS = [
|
|
203
203
|
// Pinned (not left to resolve to "latest") — see the comment on the eslint@^9 install in
|
|
204
204
|
// mergeConfig() for why: the plugin ecosystem here regularly lags behind ESLint's newest major.
|
|
205
|
+
// @eslint/js in particular is versioned in lockstep with ESLint core and its `latest` (10.x)
|
|
206
|
+
// declares a hard peerDependency on eslint@^10 — installing it unpinned alongside eslint@^9
|
|
207
|
+
// produces an immediate ERESOLVE conflict, which is exactly what this pin prevents.
|
|
205
208
|
"eslint@^9",
|
|
206
|
-
|
|
209
|
+
// Same lag problem, different package: @typescript-eslint/eslint-plugin@8.65.0 declares
|
|
210
|
+
// `typescript: ">=4.8.4 <6.1.0"` as a peer, but unpinned "typescript" resolves to npm's
|
|
211
|
+
// "latest" (7.x once TypeScript ships a 7.0) — that's outside the supported range and
|
|
212
|
+
// crashes plugin loading with "typescript-eslint does not support TS 7.0". Pinning to the
|
|
213
|
+
// latest 5.x line keeps us inside the range the plugin actually supports today.
|
|
214
|
+
"typescript@^5",
|
|
207
215
|
"@typescript-eslint/parser",
|
|
208
216
|
"@typescript-eslint/eslint-plugin",
|
|
209
|
-
"@eslint/js",
|
|
217
|
+
"@eslint/js@^9",
|
|
210
218
|
"@eslint/eslintrc",
|
|
211
219
|
"eslint-plugin-sonarjs",
|
|
212
220
|
"eslint-plugin-import",
|
|
@@ -221,17 +229,12 @@ const ESLINT_REACT_DEV_DEPS = [
|
|
|
221
229
|
"prettier",
|
|
222
230
|
];
|
|
223
231
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
const FLAT_CONFIG_SIDE_FILE = "eslint.config.commit-sheriff.mjs";
|
|
231
|
-
|
|
232
|
-
function hasFlatEslintConfig() {
|
|
233
|
-
return FLAT_CONFIG_CANDIDATES.some((name) => fs.existsSync(path.join(cwd, name)));
|
|
234
|
-
}
|
|
232
|
+
// The module-boundary + all-recommended-plugins ruleset lives in this file, copied verbatim from
|
|
233
|
+
// the template every run. `eslint.config.mjs` itself (the file ESLint actually reads) is then
|
|
234
|
+
// generated fresh below to import it — no manual merge step for the user, ever. This intentionally
|
|
235
|
+
// means a fully hand-written `eslint.config.mjs` gets replaced: simplicity/zero-manual-steps was
|
|
236
|
+
// chosen over preserving bespoke prior setups, matching how `.prettierrc.js` already worked.
|
|
237
|
+
const RULES_FILE = "eslint.config.commit-sheriff.mjs";
|
|
235
238
|
|
|
236
239
|
function copyTemplateOverwrite(templateName, destName) {
|
|
237
240
|
const src = path.join(__dirname, "..", "templates", templateName);
|
|
@@ -242,50 +245,71 @@ function copyTemplateOverwrite(templateName, destName) {
|
|
|
242
245
|
return dest;
|
|
243
246
|
}
|
|
244
247
|
|
|
245
|
-
function
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
` Özünüzün eslint.config.* faylınıza əlavə edin, məsələn:\n\n` +
|
|
259
|
-
` import moduleBoundaries from "./${FLAT_CONFIG_SIDE_FILE}";\n` +
|
|
260
|
-
` export default [\n` +
|
|
261
|
-
` ...compat.extends("next/core-web-vitals", "next/typescript"),\n` +
|
|
262
|
-
` ...moduleBoundaries,\n` +
|
|
263
|
-
` ];\n`,
|
|
264
|
-
);
|
|
265
|
-
} else {
|
|
266
|
-
copyTemplateOverwrite("eslint.config.module-boundaries.mjs", "eslint.config.mjs");
|
|
267
|
-
console.log(
|
|
268
|
-
"\n• Layihədə eslint.config.* yox idi — eslint.config.mjs olaraq birbaşa yazıldı.\n",
|
|
248
|
+
function writeFileOverwrite(destName, content) {
|
|
249
|
+
const dest = path.join(cwd, destName);
|
|
250
|
+
const existed = fs.existsSync(dest);
|
|
251
|
+
fs.writeFileSync(dest, content);
|
|
252
|
+
console.log(existed ? `✔ ${destName} yeniləndi (üzərinə yazıldı)` : `✔ ${destName} yazıldı`);
|
|
253
|
+
return dest;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function buildEslintEntryConfig(hasNext) {
|
|
257
|
+
if (!hasNext) {
|
|
258
|
+
return (
|
|
259
|
+
`import moduleBoundaries from "./${RULES_FILE}";\n\n` +
|
|
260
|
+
`export default [...moduleBoundaries];\n`
|
|
269
261
|
);
|
|
270
262
|
}
|
|
263
|
+
// Next.js scaffolds its own eslint.config.mjs with `next/core-web-vitals`/`next/typescript` —
|
|
264
|
+
// those are folded in here (via the same FlatCompat pattern Next's own generated config uses)
|
|
265
|
+
// so overwriting the file doesn't silently drop Next-specific linting.
|
|
266
|
+
return (
|
|
267
|
+
`import { fileURLToPath } from "node:url";\n` +
|
|
268
|
+
`import path from "node:path";\n` +
|
|
269
|
+
`import { FlatCompat } from "@eslint/eslintrc";\n` +
|
|
270
|
+
`import moduleBoundaries from "./${RULES_FILE}";\n\n` +
|
|
271
|
+
`const compat = new FlatCompat({\n` +
|
|
272
|
+
` baseDirectory: path.dirname(fileURLToPath(import.meta.url)),\n` +
|
|
273
|
+
`});\n\n` +
|
|
274
|
+
`export default [\n` +
|
|
275
|
+
` ...compat.extends("next/core-web-vitals", "next/typescript"),\n` +
|
|
276
|
+
` ...moduleBoundaries,\n` +
|
|
277
|
+
`];\n`
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function addEslintReact() {
|
|
282
|
+
const { pkg } = readPackageJson();
|
|
283
|
+
const deps = Object.assign({}, pkg.dependencies, pkg.devDependencies);
|
|
284
|
+
const hasNext = Boolean(deps.next);
|
|
285
|
+
|
|
286
|
+
copyTemplateOverwrite("eslint.config.module-boundaries.mjs", RULES_FILE);
|
|
287
|
+
writeFileOverwrite("eslint.config.mjs", buildEslintEntryConfig(hasNext));
|
|
271
288
|
copyTemplateOverwrite("prettier.module-boundaries.js", ".prettierrc.js");
|
|
289
|
+
|
|
272
290
|
console.log(
|
|
273
|
-
"
|
|
291
|
+
"\nBu şablon TypeScript/React + modul-sərhəd (module-boundary) qaydaları üçündür.\n" +
|
|
274
292
|
`Modul siyahısı ${CONFIG_FILE_NAME}.modules-dən avtomatik oxunur (boşdursa nümunə\n` +
|
|
275
293
|
"siyahı istifadə olunur — şablon faylı içindəki şərhi oxuyun).\n\n" +
|
|
276
|
-
"Diqqət: eslint.config
|
|
277
|
-
|
|
278
|
-
"
|
|
279
|
-
"
|
|
294
|
+
"Diqqət: eslint.config.mjs, " +
|
|
295
|
+
RULES_FILE +
|
|
296
|
+
" və .prettierrc.js hər dəfə\n" +
|
|
297
|
+
"şablonun ən son versiyası ilə üzərinə yazılır (commit-msg/pre-commit hook-ları kimi) —\n" +
|
|
298
|
+
"manual dəyişiklik lazım deyil, amma özünüzə uyğun etdiyiniz dəyişiklikləri qorumaq\n" +
|
|
299
|
+
"istəsəniz, əvvəlcə fərqli adla backup götürün.\n" +
|
|
300
|
+
(hasNext
|
|
301
|
+
? "\nNext.js aşkarlandı → next/core-web-vitals və next/typescript qaydaları da\n" +
|
|
302
|
+
"avtomatik daxil edildi.\n"
|
|
303
|
+
: ""),
|
|
280
304
|
);
|
|
281
|
-
|
|
282
|
-
|
|
305
|
+
|
|
306
|
+
const extraDeps = hasNext && !deps["eslint-config-next"] ? ["eslint-config-next"] : [];
|
|
307
|
+
ensureDevDeps(ESLINT_REACT_DEV_DEPS.concat(extraDeps));
|
|
308
|
+
|
|
309
|
+
if (fs.existsSync(path.join(cwd, ".eslintrc.js"))) {
|
|
283
310
|
console.log(
|
|
284
|
-
|
|
285
|
-
"
|
|
286
|
-
"(yuxarıdakı nümunəyə baxın). Həmçinin, əgər layihənizdə hələ də köhnə .eslintrc.js\n" +
|
|
287
|
-
"varsa, onu silin — flat config varkən ESLint onu oxumur, üstəlik özü də indi\n" +
|
|
288
|
-
"adi .js fayl kimi lint xətaları törədə bilər.\n",
|
|
311
|
+
"\nDiqqət: layihənizdə hələ də köhnə .eslintrc.js var — silin. Flat config varkən\n" +
|
|
312
|
+
"ESLint onu oxumur, üstəlik özü də indi adi .js fayl kimi lint xətaları törədə bilər.\n",
|
|
289
313
|
);
|
|
290
314
|
}
|
|
291
315
|
}
|