Skip to content

Complete rewrite of linting setup#62

Merged
marek-saji merged 200 commits into
mainfrom
feat/rewrite
May 28, 2026
Merged

Complete rewrite of linting setup#62
marek-saji merged 200 commits into
mainfrom
feat/rewrite

Conversation

@marek-saji

@marek-saji marek-saji commented Oct 28, 2025

Copy link
Copy Markdown
Contributor

Note

  • This will influence the way you work — we will migrate all repos from old config to this.
  • Even if not reviewing the code, feel free to just read the README and leave feedback on that.
  • This PR seems huge, bu it’s mostly npm lockfile. It is not small, but you can focus on README, eslint/index.ts and eslint/custom.ts.

Why?

  • Switch to new EsLint config
  • Stop using unmaintained airbnb config as a base
  • Simplify
  • Make it detect on its own what settings to use — e.g. if it detects typescript, it will use rules for typescript

Closes https://verkstedt.atlassian.net/browse/VIP-19

Discussion

Caution

Do not discuss any internal verkstedt projects here. Discuss here: https://verkstedt.slack.com/archives/C8U48QUBA/p1767627900680289

Rollout

  • Publish the PR for reviews
  • Get few reviews on the PR
  • Release @verkstedt/lint@11.0.0-rc.1 on npm
  • Test out in few projects
  • Change required checks for PRs on this repo
  • Merge
  • Release @verkstedt/lint@11.0.0 on npm
  • Rename this repo to lint
  • Mark @verkstedt/eslint-config-verkstedt as deprecated on npm and suggest migrating to @verkstedt/lint

Known issues

Collect first, then decide if any of these need to be addressed before the 11.0.0 release.

  • a11y eslint plugin has been temporarily removed, because maintenance there is slow. Will bring it back once [New] Add ESLint 10 support jsx-eslint/eslint-plugin-jsx-a11y#1081 lands.
  • Automatic installation might fail or produce unexpected results if tsconfig it contains comments
  • Automatic installation overwrites extends in tsconfig. A project might already extend something else, e.g. @tsconfig/vite-react. In that case, copy values from typescript/tsconfig.base.json into your tsconfig.
  • We disabled css/use-baseline, but we should detect if features not defined in browserslist are used. There’s stylelint-no-unsupported-browser-features (not ideal, but it’s there), but I don’t think there’s anything like that for EsLint yet.

Delayed to future versions

  • eslint-mdx
  • Look into lowering peer dependency versions and/or change install script to detect which peer dependencies are already installed and in lower version and update them before installing this package.
  • Look into integrating some rules from existing projects (see VIP-19 for a list)

What’s included?

Give README a read.

Prettier

Mostly defaults. Few overwrites where I tried to explain why.

StyleLint

Initially I thought I’d include style lint config as well, but nowadays eslint can do CSS as well, so maybe we don’t need it.

EsLint

Ignored files

  • Some built–in ignores
  • Ignore stuff from .gitignore from the root of the repo
  • Ignore stuff from .prettierignore — if your project has .eslintignore file, please remove it and use only .prettierignore, so we can maintain only one of those

Configs

Custom config

Additional rules in https://github.com/verkstedt/eslint-config-verkstedt/blob/feat/rewrite/eslint/custom.ts

Testing

Assuming you have this repo cloned at e.g. ~/src/eslint-config-verkstedt, you can test it out in a different project using:

npm install --save-dev ~/src/eslint-config-verkstedt

@coderabbitai ignore

@marek-saji marek-saji self-assigned this Oct 28, 2025
@coderabbitai

coderabbitai Bot commented Oct 28, 2025

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Replaces legacy CommonJS ESLint/Stylelint presets with a TypeScript flat-config system, adds an installer and CLI validators, reorganizes Prettier, updates CI/workflows and package metadata/exports, introduces workspace test packages, updates Node/TS targets, and removes many legacy wrapper modules and the publish workflow.

Changes

Cohort / File(s) Summary
Removed legacy CommonJS presets & wrappers
base.js, babel.js, react.js, typescript.js, typescript-react.js, typescript-next.js, next.js, vanilla.js, index.js, lib/withBabel.js, lib/withReact.js, lib/withTypescript.js, lib/withNext.js, lib/withPrettier.js, stylelint-config.cjs
Deleted many CommonJS composition entry points and wrapper modules that previously exported composed ESLint/Stylelint configs. Review callers that imported these legacy entrypoints.
New ESLint flat-config implementation
eslint.config.ts, eslint/index.ts, eslint/custom.ts, eslint/file-globs.ts, eslint-plugin-css-modules.d.ts, eslint/eslint-plugin-eslint-comments.d.ts
Adds a TypeScript-based flat-config builder and helpers, plus typings. Exports createVerkstedtConfig() and includeIgnoreFile(); inspect async config composition and dependency resolution/error exit behavior.
Prettier consolidation & re-exports
prettier/index.ts, prettier.config.ts, prettier/.prettierignore, (removed) prettier-config.json, (removed) .prettierrc.js, .prettierignore
Replaces prior JSON/JS Prettier config with a TypeScript entrypoint and new ignore files; removed legacy re-export files.
Package manifest and metadata changes
package.json, CODEOWNERS, LICENSE, README.md
Renamed package to @verkstedt/lint, bumped version, switched to ESM ("type": "module"), added exports/workspaces/bin, changed dependencies and scripts. Verify exports and workspace layout.
Installer & CLI validation tooling
install.sh, scripts/lint-package-json.ts, scripts/lint-node.ts, scripts/utils/ansi.ts, scripts/utils/parseArgs.ts
Adds installer and TypeScript CLI validators with utilities. Check shell safety, CLI help/exit codes, color handling, and parsing behavior.
CI and GitHub workflow updates
.github/workflows/ci.yaml, .github/workflows/create-release.yaml, .github/workflows/jira.yaml, .github/workflows/ref-comment-in-commit.yaml, (removed) .github/workflows/publish.yaml
Rewires CI jobs/triggers, introduces reusable release/Jira/ref workflows, ensures secrets inheritance and consistent working-directory usage; removed prior publish workflow.
Test monorepo workspaces & sample packages
test/* (e.g. test/001-js/*, test/002-ts/*, test/003-react/*, test/004-next.js/*, test/005-css-modules/*)
Adds workspace test packages with ESLint configs, Prettier ignores, package.json entries and sample sources for JS/TS/React/Next/CSS-modules. Verify test scripts and imports.
TypeScript & Node version updates
.nvmrc, tsconfig.json, typescript/tsconfig.base.json
Bumps Node to v24.12.0 and adds/updates TypeScript base configs and compilerOptions (nodenext, outDir esm, declaration settings).
Removed legacy validation & tests
validate-deps.js, test.mjs, test-input.ts, (removed) prettier-config.json
Removes older validation/test harness; new scripts assume replacement responsibilities. Confirm no consumers expect removed scripts.
Misc project housekeeping
.gitignore, (removed) .eslintrc.json, .prettierignore, test/**/.prettierignore
Reorganized .gitignore (added /esm), removed root .eslintrc.json, added per-test Prettier ignore files — confirm ignore merging with the new config system.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Dev as Developer
  participant Installer as install.sh
  participant FS as File System
  participant NPM as Package Manager
  participant ESLintBuilder as createVerkstedtConfig
  participant Prettier as Prettier module

  Dev->>Installer: run verkstedt-lint-setup <target-dir>
  Installer->>FS: probe project files (package.json, tsconfig.json, .prettierignore)
  Installer->>Installer: detect features (TypeScript, React, Next, CSS modules)
  Installer->>NPM: install devDependencies (including local `@verkstedt/lint`)
  Installer->>FS: create or update Prettier config and .prettierignore
  Installer->>FS: write ESLint config referencing createVerkstedtConfig
  Installer->>ESLintBuilder: invoke createVerkstedtConfig(dir, allowDefaultProject?)
  ESLintBuilder->>FS: read package.json, .gitignore, tsconfig
  ESLintBuilder->>ESLintBuilder: compose flat-config modules and resolve plugins
  ESLintBuilder-->>Installer: return assembled config array (or error with missing deps)
  Installer->>Prettier: validate or re-export Prettier config
  Installer-->>Dev: exit with success or error
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐇 I nibble wrappers, unroll the old braid,
Flat configs sprout where CommonJS swayed.
I bump Node’s burrow, plant an installer script,
Tests in tidy workspaces, CI paths re-equipped.
Hops of change — the lint garden’s freshly flipped.

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.81% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The pull request successfully addresses all major objectives from VIP-19: adopts new ESLint format, removes Airbnb base, implements auto-detection for TypeScript/React/Next.js, renames package to @verkstedt/lint, and provides comprehensive preset integration.
Out of Scope Changes check ✅ Passed All changes are in scope with VIP-19 objectives: config rewrite, package rename, workflow updates, and new supporting scripts. No unrelated changes detected.
Title check ✅ Passed The title 'Complete rewrite of linting setup' accurately summarizes the main change: a comprehensive rewrite of the ESLint and linting configuration system, replacing the Airbnb-based approach with a new auto-detecting setup.
Description check ✅ Passed The pull request description comprehensively explains the motivation (switch to new ESLint config, stop using unmaintained Airbnb base, auto-detect project settings), includes detailed rollout steps, lists known issues, and documents what's included.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Comment @coderabbitai help to get the list of available commands and usage tips.

@marek-saji marek-saji force-pushed the feat/rewrite branch 2 times, most recently from b6fd720 to 345e8ef Compare October 30, 2025 15:51
marek-saji and others added 13 commits May 6, 2026 12:07
Currently only showed as a debug information.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Switch from eslint-config-next to @next/eslint-plugin-next. The config
package bundled React, React Hooks, import, jsx-a11y, parser, and
TypeScript config pieces that overlap with our own setup or block later
ESLint 10 migration work.

Keep the React rules that eslint-config-next previously contributed and
that are still useful for JSX runtime projects, including JSX variable
usage and selected Next-compatible React rule overrides.

eslint-plugin-jsx-a11y@6.10.2 still caps its `eslint` peer at `^9` and
no maintained fork supports ESLint 10 either. Drop the plugin entirely
until upstream PR
jsx-eslint/eslint-plugin-jsx-a11y#1081 ships.
Documents the gap in README "Known caveats".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: codex gpt-5.5 <codex@openai.com>
eslint-plugin-import does not support ESLint 10 yet.
eslint-plugin-import-x is a maintained fork that already declares ESLint
10 in peerDependencies.

Drop eslint-import-resolver-exports because its eslint-plugin-import
peer pulls the incompatible package back in, and the exports resolver
setting is not supported by eslint-plugin-import-x.

Adds eslint-plugin-n purely for its prefer-node-protocol rule, which
replaces the dropped import/enforce-node-protocol-usage rule that
eslint-plugin-import-x doesn't ship. eslint-plugin-n was preferred over
eslint-plugin-unicorn here because its 29 rules are all narrowly
Node.js-focused and don't overlap with anything we already configure.
Only n/prefer-node-protocol is enabled; the rest of the plugin is
dormant.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: codex gpt-5.5 <codex@openai.com>
eslint-plugin-css-modules (last released 2023) calls
context.getFilename(), which was removed in ESLint 10.
@bhollis/eslint-plugin-css-modules is a maintained fork (released
2026-04-04) that ships flat configs and works with ESLint 10.

Rule names are unchanged (`css-modules/no-unused-class`,
`css-modules/no-undef-class`), so existing disable directives keep
working.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: codex gpt-5.5 <codex@openai.com>
@eslint-react/eslint-plugin requires ESLint ^10.2.1, while
eslint-plugin-react 7.37.5 only peers through ESLint 9.7. Move the React
plugin migration and ESLint 10 upgrade together so npm install has no
invalid peer intermediate state.

Switch React rules to the @eslint-react namespace, keep
eslint-plugin-react-hooks as the hook rules source, and update test
fixtures to ESLint 10.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: codex gpt-5.5 <codex@openai.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
typescript-eslint caps its `typescript` peer at `<6.1.0`. Mirror that
range in both peerDependencies and devDependencies so `npm install`
resolves cleanly without npm coercing our spec on every install.

Teaches `lint:pkg` to accept bounded peer specs (`^X <Y`) in addition to
the existing `>=X` form, so the new TS pin doesn't trip the linter.

Documented in a new "Known caveats" README section.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@marek-saji

marek-saji commented May 6, 2026

Copy link
Copy Markdown
Contributor Author

Published new rc: https://npmx.dev/package/@verkstedt/lint/v/11.0.0-rc.8 (tagged next)

@marek-saji marek-saji merged commit 8015ba4 into main May 28, 2026
19 checks passed
@marek-saji marek-saji deleted the feat/rewrite branch May 28, 2026 14:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants