commit-sheriff 1.7.2 → 1.7.3

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 CHANGED
@@ -276,40 +276,25 @@ npx commit-sheriff add-eslint-react
276
276
  ```
277
277
 
278
278
  This ships as a **flat config** (`eslint.config.*`, ESLint 9+ format), not the legacy
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 Next's own ESLint
289
- rules automatically so you don't lose Next-specific linting; `eslint-config-next` is
290
- auto-installed too if it's missing. Any other hand-written customizations in your previous
291
- `eslint.config.mjs` are not preserved — back it up under a different name first if you need them.
292
-
293
- `eslint-config-next` changed shape between major versions, so the generated entry point checks
294
- the actually-installed version and picks the matching pattern automatically:
295
- - **v16+** (current): ships a native flat-config array
296
- (`import nextCoreWebVitals from "eslint-config-next/core-web-vitals"`, spread directly). Mixing
297
- this with our own module-boundary plugins (which resolve the same plugin _names_ `react`,
298
- `jsx-a11y`, `import`, etc. — through a separate loader) would otherwise throw `Cannot redefine
299
- plugin ...`; the generated config strips those redundant re-registrations automatically so both
300
- rule sets apply cleanly.
301
- - **v15 and earlier**: still ships the legacy eslintrc-style object, so the generated config uses
302
- `FlatCompat.extends("next/core-web-vitals", "next/typescript")` instead — the same bridge
303
- `create-next-app@15` itself generates.
304
-
305
- (An earlier version of this tool hardcoded the v15-style pattern unconditionally, which crashed
306
- with `TypeError: Converting circular structure to JSON` on projects using `eslint-config-next@16+`
307
- — fixed by detecting the installed version instead of assuming one.)
308
-
309
- `.prettierrc.js` is written/refreshed the same way — **always overwritten** with the latest
310
- template (same behavior as the `commit-msg`/`pre-commit` hooks). This trade-off is intentional:
311
- zero manual steps for the common case, at the cost of not preserving bespoke prior ESLint/Prettier
312
- setups.
279
+ `.eslintrc.js` format — see [why](#why-flat-config) below.
280
+
281
+ It writes/refreshes three files every run, **always overwriting** whatever was there before (same
282
+ as the `commit-msg`/`pre-commit` hooks) no manual merge step, ever. If you've hand-edited any of
283
+ these, back them up under a different name first:
284
+
285
+ | File | What it is |
286
+ | ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
287
+ | `eslint.config.commit-sheriff.mjs` | The actual ruleset: module-boundary rules + all the recommended plugins (TypeScript, React, hooks, a11y, sonarjs, import, testing-library, vitest, jest, prettier). |
288
+ | `eslint.config.mjs` | The entry point ESLint actually reads. Just imports the file above — or, if `next` is detected in your dependencies, also folds in Next.js's own ESLint rules so you don't lose Next-specific linting (`eslint-config-next` is auto-installed if missing). |
289
+ | `.prettierrc.js` | Matching Prettier config for the same ruleset. |
290
+
291
+ If your project already had its own `eslint.config.mjs` (e.g. Next.js's own
292
+ `create-next-app`-generated one), it gets replaced by the one above, not merged with it.
293
+
294
+ Next.js support is version-aware: `eslint-config-next` changed its internal shape between major
295
+ versions (a native flat-config array from v16 on, the older eslintrc-style object before that), and
296
+ the generated `eslint.config.mjs` detects which one is actually installed and uses the matching
297
+ pattern automatically you don't need to think about this at all, it's handled for you.
313
298
 
314
299
  The module list for the boundary rule isn't hardcoded — it's read straight from the `modules`
315
300
  array in your root `.commitsheriffrc.json` (the same list the commit-msg/branch-name hooks use
@@ -348,16 +333,14 @@ it yourself.
348
333
  #### Why flat config?
349
334
 
350
335
  ESLint 9+ looks for `eslint.config.*` first and, if one is found, **ignores `.eslintrc.js`
351
- entirely** — there's no fallback. Since frameworks like Next.js already scaffold their own
352
- `eslint.config.mjs`, a legacy-only `.eslintrc.js` template would sit right next to it and never
353
- actually run (this was a real bug: an unused `useState` import went completely unflagged because
354
- the module-boundary config was silently dead). The flat config here uses `FlatCompat` (the same
355
- official migration helper Next.js's own generated config uses internally) so the exact same rule
356
- set works natively under ESLint 9+, whether or not the project already had its own flat config.
336
+ entirely** — there's no fallback. A legacy-only `.eslintrc.js` template sitting next to a
337
+ framework-generated `eslint.config.mjs` (Next.js scaffolds one by default) would simply never run
338
+ this used to be a real bug here, where an unused import went completely unflagged because the
339
+ module-boundary rules were silently dead. Flat config avoids that trap entirely.
357
340
 
358
341
  A legacy `.eslintrc.js` version of this template (`eslintrc.module-boundaries.js`) still ships
359
- inside the package for reference/manual use on pure ESLint 8 projects with no flat config support
360
- at all, but the CLI no longer writes it by default.
342
+ inside the package for reference/manual use on pure ESLint 8 projects with no flat config support,
343
+ but the CLI no longer writes it by default.
361
344
 
362
345
  ## Examples
363
346
 
@@ -49,7 +49,7 @@ const CONFIG_FILE_NAME = ".commitsheriffrc.json";
49
49
  function readPackageJson() {
50
50
  const pkgPath = path.join(cwd, "package.json");
51
51
  if (!fs.existsSync(pkgPath)) {
52
- console.error(" package.json tapılmadı. Əvvəlcə `npm init` işlədin.");
52
+ console.error(" package.json not found. Run `npm init` first.");
53
53
  process.exit(1);
54
54
  }
55
55
  return { pkgPath, pkg: JSON.parse(fs.readFileSync(pkgPath, "utf8")) };
@@ -59,7 +59,7 @@ function ensureHusky() {
59
59
  const huskyDir = path.join(cwd, ".husky");
60
60
  const shimPath = path.join(huskyDir, "_", "husky.sh");
61
61
  if (!fs.existsSync(shimPath)) {
62
- console.log("→ husky quraşdırılır (npx husky init)...");
62
+ console.log("→ setting up husky (npx husky init)...");
63
63
  execSync("npx husky init", { cwd, stdio: "inherit" });
64
64
  }
65
65
  }
@@ -70,7 +70,7 @@ function copyHook(name) {
70
70
  fs.mkdirSync(path.dirname(dest), { recursive: true });
71
71
  fs.copyFileSync(src, dest);
72
72
  fs.chmodSync(dest, 0o755);
73
- console.log(`✔ .husky/${name} yazıldı`);
73
+ console.log(`✔ .husky/${name} written`);
74
74
  }
75
75
 
76
76
  function ensureConfigFile() {
@@ -78,19 +78,19 @@ function ensureConfigFile() {
78
78
  const { pkg } = readPackageJson();
79
79
 
80
80
  if (fs.existsSync(configPath)) {
81
- console.log(`• ${CONFIG_FILE_NAME} artıq var, toxunulmadı`);
81
+ console.log(`• ${CONFIG_FILE_NAME} already exists, left untouched`);
82
82
  return;
83
83
  }
84
84
 
85
85
  if (pkg.commitGuard) {
86
86
  console.log(
87
- `• package.json-da köhnə tərzli 'commitGuard' bloku tapıldı — ${CONFIG_FILE_NAME} yaradılmadı, köhnə konfiqurasiya işləməyə davam edir.`,
87
+ `• Found a legacy-style 'commitGuard' block in package.json — ${CONFIG_FILE_NAME} not created, the old configuration keeps working.`,
88
88
  );
89
89
  return;
90
90
  }
91
91
 
92
92
  fs.writeFileSync(configPath, JSON.stringify(DEFAULT_COMMIT_GUARD, null, 2) + "\n");
93
- console.log(`✔ ${CONFIG_FILE_NAME} yazıldı`);
93
+ console.log(`✔ ${CONFIG_FILE_NAME} written`);
94
94
  }
95
95
 
96
96
  // Installs whatever in `packages` isn't already a listed dependency/devDependency, so the hooks
@@ -111,10 +111,10 @@ function ensureDevDeps(packages) {
111
111
  const deps = Object.assign({}, pkg.dependencies, pkg.devDependencies);
112
112
  const missing = packages.filter((spec) => !deps[packageNameOf(spec)]);
113
113
  if (!missing.length) {
114
- console.log("• Lazımi devDependencies artıq quraşdırılıb, toxunulmadı");
114
+ console.log("• Required devDependencies are already installed, nothing to do");
115
115
  return;
116
116
  }
117
- console.log(`→ Quraşdırılır: ${missing.join(" ")}`);
117
+ console.log(`→ Installing: ${missing.join(" ")}`);
118
118
  try {
119
119
  // --legacy-peer-deps: some ESLint plugins lag behind the newest ESLint major in their
120
120
  // declared peerDependencies (e.g. eslint-plugin-import still capping at ^9 while npm already
@@ -124,10 +124,10 @@ function ensureDevDeps(packages) {
124
124
  cwd,
125
125
  stdio: "inherit",
126
126
  });
127
- console.log("✔ devDependencies quraşdırıldı");
127
+ console.log("✔ devDependencies installed");
128
128
  } catch {
129
129
  console.log(
130
- "\n Avtomatik quraşdırma alınmadı (şəbəkə/npm xətası ola bilər) — özünüz işlədin:\n" +
130
+ "\n Automatic install failed (could be a network/npm error) — run it yourself:\n" +
131
131
  ` npm install --save-dev ${missing.join(" ")}\n`,
132
132
  );
133
133
  }
@@ -142,9 +142,9 @@ function mergeConfig() {
142
142
  if (!pkg["lint-staged"]) {
143
143
  pkg["lint-staged"] = DEFAULT_LINT_STAGED;
144
144
  changed = true;
145
- console.log("✔ package.json → lint-staged konfiqurasiyası əlavə olundu");
145
+ console.log("✔ package.json → lint-staged configuration added");
146
146
  } else {
147
- console.log("• package.json-da lint-staged artıq var, toxunulmadı");
147
+ console.log("• package.json already has a lint-staged block, left untouched");
148
148
  }
149
149
 
150
150
  if (!pkg.scripts) pkg.scripts = {};
@@ -184,18 +184,16 @@ function init() {
184
184
 
185
185
  if (isReactTypescriptProject()) {
186
186
  console.log(
187
- "\n• react + typescript aşkarlandı → TS/React modul-sərhəd ESLint şablonu da əlavə olunur:",
187
+ "\n• react + typescript detectedalso adding the TS/React module-boundary ESLint template:",
188
188
  );
189
189
  addEslintReact();
190
190
  } else {
191
191
  console.log(
192
- "\n(Layihə TS/React kimi aşkarlanmadı istəsəniz `npx commit-sheriff add-eslint-react` ilə əlavə edə bilərsiniz.)",
192
+ "\n(Project not detected as TS/React you can add it manually with `npx commit-sheriff add-eslint-react` if needed.)",
193
193
  );
194
194
  }
195
195
 
196
- console.log(
197
- `\nHazırdır. ${CONFIG_FILE_NAME} faylında 'project' və lazım olsa 'modules' dəyərlərini tənzimləyin.\n`,
198
- );
196
+ console.log(`\nDone. Adjust 'project' and, if needed, 'modules' in ${CONFIG_FILE_NAME}.\n`);
199
197
  }
200
198
 
201
199
  const ESLINT_REACT_DEV_DEPS = [
@@ -240,7 +238,7 @@ function copyTemplateOverwrite(templateName, destName) {
240
238
  const dest = path.join(cwd, destName);
241
239
  const existed = fs.existsSync(dest);
242
240
  fs.copyFileSync(src, dest);
243
- console.log(existed ? `✔ ${destName} yeniləndi (üzərinə yazıldı)` : `✔ ${destName} yazıldı`);
241
+ console.log(existed ? `✔ ${destName} updated (overwritten)` : `✔ ${destName} written`);
244
242
  return dest;
245
243
  }
246
244
 
@@ -248,7 +246,7 @@ function writeFileOverwrite(destName, content) {
248
246
  const dest = path.join(cwd, destName);
249
247
  const existed = fs.existsSync(dest);
250
248
  fs.writeFileSync(dest, content);
251
- console.log(existed ? `✔ ${destName} yeniləndi (üzərinə yazıldı)` : `✔ ${destName} yazıldı`);
249
+ console.log(existed ? `✔ ${destName} updated (overwritten)` : `✔ ${destName} written`);
252
250
  return dest;
253
251
  }
254
252
 
@@ -348,25 +346,26 @@ function addEslintReact() {
348
346
  copyTemplateOverwrite("prettier.module-boundaries.js", ".prettierrc.js");
349
347
 
350
348
  console.log(
351
- "\nBu şablon TypeScript/React + modul-sərhəd (module-boundary) qaydaları üçündür.\n" +
352
- `Modul siyahısı ${CONFIG_FILE_NAME}.modules-dən avtomatik oxunur (boşdursa nümunə\n` +
353
- "siyahı istifadə olunurşablon faylı içindəki şərhi oxuyun).\n\n" +
354
- "Diqqət: eslint.config.mjs, " +
349
+ "\nThis template is for TypeScript/React + module-boundary rules.\n" +
350
+ `The module list is read automatically from ${CONFIG_FILE_NAME}'s "modules" (falls back\n` +
351
+ "to an illustrative default if empty read the comment inside the template file).\n\n" +
352
+ "Note: eslint.config.mjs, " +
355
353
  RULES_FILE +
356
- " .prettierrc.js hər dəfə\n" +
357
- "şablonun ən son versiyası ilə üzərinə yazılır (commit-msg/pre-commit hook-ları kimi) —\n" +
358
- "manual dəyişiklik lazım deyil, amma özünüzə uyğun etdiyiniz dəyişiklikləri qorumaq\n" +
359
- "istəsəniz, əvvəlcə fərqli adla backup götürün.\n" +
354
+ ", and .prettierrc.js are overwritten\n" +
355
+ "with the latest template every run (same as the commit-msg/pre-commit hooks) — no manual\n" +
356
+ "merge step needed, but if you want to keep your own customizations, back them up under a\n" +
357
+ "different name first.\n" +
360
358
  (hasNext
361
- ? "\nNext.js aşkarlandı → next/core-web-vitals next/typescript qaydaları da\n" +
362
- "avtomatik daxil edildi.\n"
359
+ ? "\nNext.js detected → next/core-web-vitals and next/typescript rules are folded in\n" +
360
+ "automatically too.\n"
363
361
  : ""),
364
362
  );
365
363
 
366
364
  if (fs.existsSync(path.join(cwd, ".eslintrc.js"))) {
367
365
  console.log(
368
- "\nDiqqət: layihənizdə hələ köhnə .eslintrc.js var silin. Flat config varkən\n" +
369
- "ESLint onu oxumur, üstəlik özü indi adi .js fayl kimi lint xətaları törədə bilər.\n",
366
+ "\nNote: your project still has a legacy .eslintrc.js — delete it. With a flat config\n" +
367
+ "present, ESLint never reads it, and it can itself start producing lint errors as a\n" +
368
+ "plain .js file.\n",
370
369
  );
371
370
  }
372
371
  }
@@ -376,9 +375,9 @@ if (command === "init") {
376
375
  } else if (command === "add-eslint-react") {
377
376
  addEslintReact();
378
377
  } else {
379
- console.log("İstifadə: npx commit-sheriff init");
378
+ console.log("Usage: npx commit-sheriff init");
380
379
  console.log(
381
- " : npx commit-sheriff add-eslint-react (opsional, TS/React modul-sərhəd ESLint şablonu)",
380
+ " : npx commit-sheriff add-eslint-react (optional, TS/React module-boundary ESLint template)",
382
381
  );
383
382
  process.exit(command ? 1 : 0);
384
383
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "commit-sheriff",
3
- "version": "1.7.2",
3
+ "version": "1.7.3",
4
4
  "description": "Shared husky commit-msg / pre-commit hooks enforcing ticket-based commit messages and branch naming",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -84,10 +84,10 @@ if [ "$HAS_LINT_CONFIG" = "1" ]; then
84
84
  npx lint-staged --verbose || exit 1
85
85
  else
86
86
  echo ""
87
- echo " package.json-da 'lint-staged' konfiqurasiyası var, amma paketin özü"
88
- echo " node_modules-də tapılmadı — lint/format yoxlanışı keçirilə bilmədi."
87
+ echo " package.json has a 'lint-staged' configuration, but the package itself"
88
+ echo " was not found in node_modules — the lint/format check could not run."
89
89
  echo ""
90
- echo " Düzəltmək üçün:"
90
+ echo " To fix:"
91
91
  echo " npm install --save-dev lint-staged"
92
92
  echo ""
93
93
  exit 1