Ghost's shared ESLint rules live in two internal packages:
@internal/cfg-eslintprovides shared rule atoms andnodeLibConfig()for Node.js libraries.@internal/cfg-eslint-reactprovidesreactAppConfig()for React apps underapps/.
Both factories are synchronous and document their options with JSDoc and
examples in their index.mjs files. Add the relevant package as a
workspace:* development dependency and consume the factory by name.
import {reactAppConfig} from '@internal/cfg-eslint-react';
export default reactAppConfig({
tailwindCssPath: `${import.meta.dirname}/../admin/src/index.css`,
shadeRestricted: true
});Factory consumers use error or off, not warn. Parameters prefixed with
legacy, including legacyTailwindV3ConfigPath and legacyJsTsSplit, mark
temporary migration exceptions rather than defaults for new work.
Ghost Core keeps a standalone configuration because its rule set does not fit
a shared factory. Read that file directly. It can still import shared atoms such as correctnessRules, nodeLibRules,
localFilenamesPlugin, and strictLinterOptions from @internal/cfg-eslint.
A workspace must declare every ESLint plugin that its configuration resolves.
- A factory consumer only needs the config package because the factory supplies its plugins as objects.
- A hand-written config that imports a plugin directly must declare that plugin
in its own
devDependencies. Do not rely on root dependency hoisting. - A workspace using Tailwind must declare
tailwindcsslocally. Legacy Tailwind v3 apps also use thetailwind3catalog entry foreslint-plugin-tailwindcss.
Run the workspace's pnpm lint target after changing its config. Run the root
lint when changing shared rule atoms or either factory.