@exadev/eslint-config 1.1.1 → 1.1.2

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
@@ -1,5 +1,7 @@
1
1
  # @exadev/eslint-config
2
2
 
3
+ [![GitHub](https://img.shields.io/badge/GitHub-181717?logo=github&logoColor=white)](https://github.com/ExaDev/eslint-config) [![npm](https://img.shields.io/badge/npm-CB3837?logo=npm&logoColor=white)](https://www.npmjs.com/package/@exadev/eslint-config) [![Release](https://img.shields.io/github/v/release/ExaDev/eslint-config)](https://github.com/ExaDev/eslint-config/releases/latest) [![CI](https://img.shields.io/github/actions/workflow/status/ExaDev/eslint-config/ci.yml?branch=main)](https://github.com/ExaDev/eslint-config/actions)
4
+
3
5
  > A real ESLint plugin (not a shareable config) exposing custom rules shared across ExaDev projects. Also published under the unscoped alias `exadev-eslint-config`.
4
6
 
5
7
  ## Why
@@ -8,7 +10,9 @@ Multiple ExaDev repos independently carried identical copies of a handful of cus
8
10
 
9
11
  Only the *rules* are centralized here, not a consumer's whole `eslint.config.ts`. A repo's own file-scoping (`files`/`ignores`), tsconfig wiring, and any runtime-isomorphism import bans are genuinely project-specific -- forcing those into one shared config would mean either losing real per-project distinctions or building a heavily-parameterised config just to route around them. Each consumer keeps its own `eslint.config.ts`, importing rule implementations from here instead of a local copy.
10
12
 
11
- ## Usage
13
+ ## Getting started
14
+
15
+ Consumers need `eslint >=10.0.0` as a peer dependency.
12
16
 
13
17
  ```sh
14
18
  pnpm add -D @exadev/eslint-config
@@ -59,10 +63,10 @@ export default defineConfig([
59
63
  | `no-pointless-reassignment` | ✓ | `const foo = bar` where both sides are plain identifiers and the alias adds no transformation. |
60
64
  | `no-side-effects-in-index` | | The public barrel may contain only re-export statements -- nothing that could execute at import time. |
61
65
 
62
- ## Development
66
+ ## Build, test, and lint
63
67
 
64
68
  ```sh
65
- pnpm install
69
+ pnpm install # requires Node >=20 and pnpm 11.6.0 (pinned via packageManager)
66
70
  pnpm lint
67
71
  pnpm typecheck
68
72
  pnpm build
@@ -70,9 +74,37 @@ pnpm build
70
74
 
71
75
  No test suite exists for these rules currently -- each is verified by real-world usage against the repos it was extracted from, the same way it was verified before being centralized here.
72
76
 
77
+ The `lint`/`typecheck`/`build` npm scripts are thin wrappers around turbo tasks whose own names carry a leading underscore (`_lint`/`_typecheck`/`_build`, declared in `turbo.json`) -- run `pnpm build`, not `turbo run build` directly, since turbo's task names don't match the npm script names.
78
+
79
+ `pnpm build` runs `tsdown`, emitting ESM and CJS output plus declaration files from `src/**/*.ts` (platform-neutral, `src/**/*.test.ts` excluded). Before any publish -- local or the CI alias job -- `prepublishOnly` re-runs lint, typecheck, `tsdown`, `publint`, and `attw --pack`, so a broken export shape fails at publish time even outside the main CI pipeline.
80
+
81
+ ## Architecture
82
+
83
+ `src/plugin.ts` builds an `ESLint.Plugin` object (ESLint's own `ESLint.Plugin` type, not a hand-written interface) combining the four rule modules under `src/rules/` into a flat `rules` map. The two bundled configs (`recommended`, `barrel`) are attached via `Object.assign` after the plugin object is constructed, rather than inline in the object literal, so each config's own `plugins: { exadev }` can reference the already-built plugin object -- the same self-reference pattern ESLint's plugin-authoring guide uses. `src/index.ts` is the public entry point and is nothing but `export { default } from './plugin';` -- a genuine pure re-export barrel.
84
+
85
+ `pnpm-workspace.yaml` deliberately declares an empty `packages: []`. This is not a real multi-package pnpm workspace; its only purpose is giving turbo a workspace root to anchor local task caching against, matching the same single-package-workspace pattern used across this repo family.
86
+
87
+ ## Conventions
88
+
89
+ `eslint.config.ts` dogfoods this package's own rules on itself, importing `./src/index` by relative path rather than as an installed dependency. All four rules apply to this repo's own source: `no-non-barrel-reexport` is scoped to `src/**/*.ts` excluding `src/index.ts` (the barrel is where re-exports are meant to live), and `no-side-effects-in-index` is scoped to `src/index.ts` alone -- the plugin-construction logic lives in `src/plugin.ts` specifically so `src/index.ts` can stay a pure re-export point both rules assume.
90
+
91
+ `tsconfig.json` enables `verbatimModuleSyntax` (type-only imports/exports must use `import type`/`export type` explicitly -- enforced too by the `consistent-type-imports` eslint rule) and `noUncheckedIndexedAccess` (indexed access returns `T | undefined`, narrow before use rather than asserting).
92
+
93
+ Conventional commits are enforced by commitlint, restricted to the type-enum defined once in `release.config.ts`'s `commitTypes` -- both commitlint's allowed types and semantic-release's commit-analyzer release rules derive from that single list, so a commit type can't trigger a release without also being accepted by commit-msg validation, or the reverse.
94
+
95
+ ## Gotchas and quirks
96
+
97
+ - `.attw.json` ignores the `false-export-default` rule: tsdown/rolldown's CJS output for this plugin's sole default export doesn't emit the `export =` form `arethetypeswrong`'s check wants under legacy `node10` resolution. The resolution modes an ESLint flat config actually uses (`node16`, `bundler`) are unaffected, so the rule is suppressed rather than moving the plugin away from ESLint's own documented default-export shape.
98
+ - Husky hooks: `pre-commit` runs lint-staged (`eslint --fix` on staged `*.ts`), `commit-msg` runs commitlint against the message, `pre-push` runs `typecheck` and `build` -- pushing here rebuilds the whole package first.
99
+ - The CI release job sets `HUSKY=0` (so the commit-msg hook never fires against the automated release commit) and blanks `NPM_TOKEN`/`NODE_AUTH_TOKEN` explicitly rather than omitting them, so an inherited token can't win over npm's OIDC trusted-publishing exchange.
100
+
101
+ ## Contributing
102
+
103
+ Conventional commits are enforced by commitlint via a husky `commit-msg` hook, and re-checked in CI. CI runs commitlint, lint, and typecheck+build+attw on every push and pull request; the release job only runs on a push to `main`, after all three pass.
104
+
73
105
  ## Release
74
106
 
75
- Conventional commits (enforced by commitlint) drive [semantic-release](https://semantic-release.gitbook.io/semantic-release) on every push to `main`: version bump, `CHANGELOG.md`, GitHub Release, and an npm publish via OIDC trusted publishing (no stored token). A second CI job republishes the identical build under the unscoped alias `exadev-eslint-config`.
107
+ Conventional commits drive [semantic-release](https://semantic-release.gitbook.io/semantic-release) on every push to `main`: version bump, `CHANGELOG.md`, GitHub Release, and an npm publish via OIDC trusted publishing (no stored token). A second CI job then republishes the identical build under the unscoped alias `exadev-eslint-config`.
76
108
 
77
109
  ## License
78
110
 
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- const require_plugin = require("./plugin-jELHVCCw.cjs");
1
+ const require_plugin = require("./plugin-DeBcMjPX.cjs");
2
2
  module.exports = require_plugin.plugin;
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import { t as plugin } from "./plugin-BBix8yMe.js";
1
+ import { t as plugin } from "./plugin-UsvTGA6w.js";
2
2
  export { plugin as default };
@@ -3,7 +3,7 @@
3
3
  const plugin = {
4
4
  meta: {
5
5
  name: "@exadev/eslint-config",
6
- version: "1.1.1",
6
+ version: "1.1.2",
7
7
  namespace: "exadev"
8
8
  },
9
9
  rules: {
@@ -7,7 +7,7 @@ import noSideEffectsInIndex from "./rules/no-side-effects-in-index.js";
7
7
  const plugin = {
8
8
  meta: {
9
9
  name: "@exadev/eslint-config",
10
- version: "1.1.1",
10
+ version: "1.1.2",
11
11
  namespace: "exadev"
12
12
  },
13
13
  rules: {
package/dist/plugin.cjs CHANGED
@@ -1,2 +1,2 @@
1
- const require_plugin = require("./plugin-jELHVCCw.cjs");
1
+ const require_plugin = require("./plugin-DeBcMjPX.cjs");
2
2
  module.exports = require_plugin.plugin;
package/dist/plugin.js CHANGED
@@ -1,2 +1,2 @@
1
- import { t as plugin } from "./plugin-BBix8yMe.js";
1
+ import { t as plugin } from "./plugin-UsvTGA6w.js";
2
2
  export { plugin as default };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exadev/eslint-config",
3
- "version": "1.1.1",
3
+ "version": "1.1.2",
4
4
  "description": "Shared custom ESLint rules and plugin for ExaDev projects",
5
5
  "type": "module",
6
6
  "sideEffects": false,