Extracted shared ESLint rules + filename shim into root eslint.shared.mjs#28833
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
WalkthroughA new root-level shared module Possibly related PRs
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
| Command | Status | Duration | Result |
|---|---|---|---|
nx run-many --target=build --projects=@tryghost... |
✅ Succeeded | 15s | View ↗ |
💡 Verify your cache is correct by running tasks in a sandbox. Read docs ↗
☁️ Nx Cloud last updated this comment at 2026-06-23 16:19:35 UTC
|
| Command | Status | Duration | Result |
|---|---|---|---|
nx run @tryghost/admin-x-settings:test:acceptance |
✅ Succeeded | 11m 11s | View ↗ |
nx run ghost:test:ci:integration:no-coverage |
✅ Succeeded | 2m 34s | View ↗ |
nx run ghost:test:ci:integration |
✅ Succeeded | 2m 27s | View ↗ |
nx run ghost:test:ci:legacy |
✅ Succeeded | 2m 54s | View ↗ |
nx run ghost:test:ci:e2e |
✅ Succeeded | 2m 37s | View ↗ |
nx run ghost:test:ci:e2e:no-coverage |
✅ Succeeded | 2m 17s | View ↗ |
nx build @tryghost/activitypub |
✅ Succeeded | 2s | View ↗ |
nx build @tryghost/signup-form |
✅ Succeeded | <1s | View ↗ |
Additional runs (15) |
✅ Succeeded | ... | View ↗ |
💡 Verify your cache is correct by running tasks in a sandbox. Read docs ↗
☁️ Nx Cloud last updated this comment at 2026-06-23 16:52:27 UTC
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #28833 +/- ##
==========================================
+ Coverage 74.07% 74.10% +0.02%
==========================================
Files 1560 1560
Lines 134884 134884
Branches 16332 16335 +3
==========================================
+ Hits 99913 99952 +39
+ Misses 33991 33952 -39
Partials 980 980
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
….mjs no ref - added eslint.shared.mjs at repo root exporting: correctnessRules (12 shared rules), tsUnusedVarsRule, jsUnusedVarsRule, sortImportsRule, shadeLayeredImportsRule, reactDefaultsOff, reactStrictRules, tailwindRulesV4, tailwindRulesWithConfig(cfg) for v3, mochaRulesOff(ghostPlugin), and localFilenamesPlugin (an ESLint 9-compatible replacement for eslint-plugin-filenames-ts's match-regex) - refactored 14 React/TS workspace flat configs (apps/activitypub, admin-x-design-system, admin-x-framework, admin-x-settings, announcement-bar, comments-ui, portal, posts, shade, signup-form, sodo-search, stats; ghost/i18n, ghost/parse-email-address) to import from the shared module — each config keeps its workspace-specific extras inline - replaced inline filenamesMatchRegex shims in ghost/core, ghost/admin, and ghost/i18n with the shared localFilenamesPlugin (the shared version includes ignoreExporting support, previously only in ghost/core) - ghost/i18n explicitly disables ghost/filenames/match-regex (added by correctnessRules) since this workspace uses the local-filenames variant instead - net: -450 lines across 16 configs; lint output verified byte-identical to baseline for every workspace touched
no ref Patch-bumped portal, comments-ui, signup-form, sodo-search, and announcement-bar — they ship as UMD bundles to the CDN and the version-bump CI gate requires a bump whenever any file in their workspace changes (eslint.config.js in this case).
6d558f2 to
0a55e86
Compare
no ref - tailwindcss/enforces-negative-arbitrary-values: warn → error - tailwindcss/enforces-shorthand: warn → error - tailwindcss/migration-from-tailwind-2: warn → off (Ghost is on Tailwind v4; this rule was a v2→v3 migration helper, no longer providing value) Ghost's stance is error-or-off; warn-level rules get ignored by humans and agents and just pollute the lint output. The per-workspace warn-level rules (no-explicit-any, no-var, etc.) will be addressed in the profile-convergence follow-up.
…workspaces no ref Added three profile rule-sets to eslint.shared.mjs: - tsReactAppRules — universal TS React subset (9 workspaces) - viteTsReactExtras — react-hooks/react-refresh defaults for Vite apps (7 workspaces) - jsReactAppRules — vanilla JS React (portal, sodo-search, announcement-bar) - nodeLibRules — backend Node lib base (ghost/i18n, parse-email-address; ghost/core uses it too) - noGhostIgnitionRequireRule — restricted-require helper for ghost/i18n - strictLinterOptions — sets reportUnusedDisableDirectives to error so stale inline directives fail CI Each affected workspace's config now spreads its profile preset instead of redefining the rule sets inline. Decisions were data-driven: every contested rule was probed at 'error' across its consumers and either kept at 'error' (zero violations) or dropped to 'off' (any violations). No source-code fixes for violations — Ghost's stance is opinionated config, not silent warnings. Specifically flipped 'warn' → 'error' (zero violations): - tailwindcss rules (already done in #28833) - @typescript-eslint/no-explicit-any in ghost/core (4 places) - no-var (1 violation in portal/src/utils/contrast-color.js fixed inline; var → const) - one-var ['error', 'never'] in node libs Dropped to 'off' (had violations): - @typescript-eslint/no-explicit-any in profile (41+ violations across comments-ui/admin-x-settings) - react-refresh/only-export-components (195) - @typescript-eslint/no-non-null-assertion (97) - @typescript-eslint/no-empty-function (121) - react-hooks/exhaustive-deps (7) - react/jsx-key (22) - tailwindcss/migration-from-tailwind-2 (Ghost is on v4, rule no longer relevant) Enabling reportUnusedDisableDirectives: 'error' caused autofix to delete ~70 stale inline eslint-disable comments across 40+ source files — those rules don't fire anymore and the comments were dead weight. Result: 0 errors and 0 warnings across every affected workspace (apps/{12 frontend apps}, ghost/{i18n, parse-email-address, core, admin}).
…workspaces no ref Added three profile rule-sets to eslint.shared.mjs: - tsReactAppRules — universal TS React subset (9 workspaces) - viteTsReactExtras — react-hooks/react-refresh defaults for Vite apps (7 workspaces) - jsReactAppRules — vanilla JS React (portal, sodo-search, announcement-bar) - nodeLibRules — backend Node lib base (ghost/i18n, parse-email-address; ghost/core uses it too) - noGhostIgnitionRequireRule — restricted-require helper for ghost/i18n - strictLinterOptions — sets reportUnusedDisableDirectives to error so stale inline directives fail CI Each affected workspace's config now spreads its profile preset instead of redefining the rule sets inline. Decisions were data-driven: every contested rule was probed at 'error' across its consumers and either kept at 'error' (zero violations) or dropped to 'off' (any violations). No source-code fixes for violations — Ghost's stance is opinionated config, not silent warnings. Specifically flipped 'warn' → 'error' (zero violations): - tailwindcss rules (already done in #28833) - @typescript-eslint/no-explicit-any in ghost/core (4 places) - no-var (1 violation in portal/src/utils/contrast-color.js fixed inline; var → const) - one-var ['error', 'never'] in node libs Dropped to 'off' (had violations): - @typescript-eslint/no-explicit-any in profile (41+ violations across comments-ui/admin-x-settings) - react-refresh/only-export-components (195) - @typescript-eslint/no-non-null-assertion (97) - @typescript-eslint/no-empty-function (121) - react-hooks/exhaustive-deps (7) - react/jsx-key (22) - tailwindcss/migration-from-tailwind-2 (Ghost is on v4, rule no longer relevant) Enabling reportUnusedDisableDirectives: 'error' caused autofix to delete ~70 stale inline eslint-disable comments across 40+ source files — those rules don't fire anymore and the comments were dead weight. Result: 0 errors and 0 warnings across every affected workspace (apps/{12 frontend apps}, ghost/{i18n, parse-email-address, core, admin}).
…workspaces no ref Added three profile rule-sets to eslint.shared.mjs: - tsReactAppRules — universal TS React subset (9 workspaces) - viteTsReactExtras — react-hooks/react-refresh defaults for Vite apps (7 workspaces) - jsReactAppRules — vanilla JS React (portal, sodo-search, announcement-bar) - nodeLibRules — backend Node lib base (ghost/i18n, parse-email-address; ghost/core uses it too) - noGhostIgnitionRequireRule — restricted-require helper for ghost/i18n - strictLinterOptions — sets reportUnusedDisableDirectives to error so stale inline directives fail CI Each affected workspace's config now spreads its profile preset instead of redefining the rule sets inline. Decisions were data-driven: every contested rule was probed at 'error' across its consumers and either kept at 'error' (zero violations) or dropped to 'off' (any violations). No source-code fixes for violations — Ghost's stance is opinionated config, not silent warnings. Specifically flipped 'warn' → 'error' (zero violations): - tailwindcss rules (already done in #28833) - @typescript-eslint/no-explicit-any in ghost/core (4 places) - no-var (1 violation in portal/src/utils/contrast-color.js fixed inline; var → const) - one-var ['error', 'never'] in node libs Dropped to 'off' (had violations): - @typescript-eslint/no-explicit-any in profile (41+ violations across comments-ui/admin-x-settings) - react-refresh/only-export-components (195) - @typescript-eslint/no-non-null-assertion (97) - @typescript-eslint/no-empty-function (121) - react-hooks/exhaustive-deps (7) - react/jsx-key (22) - tailwindcss/migration-from-tailwind-2 (Ghost is on v4, rule no longer relevant) Enabling reportUnusedDisableDirectives: 'error' caused autofix to delete ~70 stale inline eslint-disable comments across 40+ source files — those rules don't fire anymore and the comments were dead weight. Result: 0 errors and 0 warnings across every affected workspace (apps/{12 frontend apps}, ghost/{i18n, parse-email-address, core, admin}).

Summary
Adds
eslint.shared.mjsat the repo root and refactors 16 workspace flat configs to import from it instead of redefining the same rule objects inline.Shared module exports:
correctnessRules— the 12 shared correctness rules (eqeqeq, no-eval, no-console, no-shadow, etc.)tsUnusedVarsRule/jsUnusedVarsRule— the two unused-vars shapes (TS-aware vs vanilla withcaughtErrors: 'none')sortImportsRule—ghost/sort-imports-es6-autofix/sort-imports-es6(used by ~6 workspaces)shadeLayeredImportsRule— restricts barrel imports of@tryghost/shadereactDefaultsOff/reactStrictRules— common React rule sets across the React workspacestailwindRulesV4(settings-based) /tailwindRulesWithConfig(cfg)(v3, per-rule config)mochaRulesOff(ghostPlugin)— helper that disables everyghost/mocha/*rulelocalFilenamesPlugin— ESLint-9-compatible replacement foreslint-plugin-filenames-ts'smatch-regex(the upstream still callscontext.getScope(), removed in ESLint 9). IncludesignoreExportingsupport that previously onlyghost/corehad.Workspaces refactored (each keeps its workspace-specific extras inline):
apps/{activitypub, admin-x-design-system, admin-x-framework, admin-x-settings, announcement-bar, comments-ui, portal, posts, shade, signup-form, sodo-search, stats}ghost/{i18n, parse-email-address}ghost/{core, admin}(their rule sets stay inline; just the shim was extracted)Notes:
ghost/i18nexplicitly disablesghost/filenames/match-regex(added bycorrectnessRules) because this workspace uses thelocal-filenames/match-regexvariant instead.reactStrictRulesand inline 3 of its 4 rules — they don't wantreact/jsx-key: 'off'.Test plan
pnpm exec eslintoutput diffed before/after — zero changes)ghost/coreandghost/adminlint counts match baseline (47 and 9 warnings respectively)