Shareable ESLint flat-config profiles (MVP: TypeScript) for normalizing lint across repos.
npm install @stride.it/appoint-lint-governance



Shareable ESLint v9 flat-config builders to normalize linting across repositories.
This package provides two domains:
- TypeScript domain: framework-agnostic TypeScript quality gates (correctness, imports hygiene, security, maintainability, and optional type-aware checks).
- Framework domain: React + Next.js + Accessibility (a11y) presets.
Everything is designed to be composed in consumer repos (flat config is order-dependent); this is not an all-or-nothing mega-config.
- Composable flat-config builders (arrays of ESLint config objects).
- A minimal baseline for fast adoption.
- A recommended preset that composes the major rule groups.
- Optional type-aware rules (requires a TSConfig project).
- Optional Prettier interop preset to disable formatting-rule conflicts.
Non-goals:
- No test-runner targeting (Vitest/Jest/Playwright rules are out of scope for now).
- No formatting (Prettier remains the formatter; ESLint formatting conflicts are disabled via the interop preset).
In a consumer repo:
``bash`
pnpm add -D @stride.it/appoint-lint-governance eslint
ESLint is a peer dependency; your repo owns the ESLint version.
Create (or edit) eslint.config.mjs:
`js
import { typescriptMinimal } from "@stride.it/appoint-lint-governance";
export default [...typescriptMinimal()];
`
Run ESLint in your repo as usual:
`bash`
pnpm lint
These builders return arrays you spread into your eslint.config.*:
- typescriptBase(options?)\typescriptMinimal(options?)
Baseline correctness + safe defaults (files globs, languageOptions).
- \typescriptRecommended(options?)
Minimal preset (fast adoption baseline).
- \typescriptPrettierInterop(options?)
Recommended preset that composes core groups and can optionally enable type-aware rules.
- \
Disables formatting-rule conflicts when the consumer repo uses Prettier.
Framework domain builders/presets:
- react(options?), reactRecommendeda11y(options?)
- , a11yRecommendednextjs(options?)
- , nextjsRecommended (composes React + A11y + Next rules)
Additionally:
- plugin\
Optional plugin export used by internal configs.
`js
import { typescriptRecommended } from "@stride.it/appoint-lint-governance";
export default [...typescriptRecommended()];
`
Type-aware rules can catch issues ESLint cannot detect from syntax alone (for example: misused promises, unsafe operations). They require a TSConfig project.
`js
import { typescriptRecommended } from "@stride.it/appoint-lint-governance";
export default [
...typescriptRecommended({
typeChecked: true,
tsconfigPath: "./tsconfig.json",
tsconfigRootDir: import.meta.dirname,
// Optional: fail CI on deprecated APIs surfaced by type definitions
reportDeprecated: true,
}),
];
`
If your Node.js version does not support import.meta.dirname, use this portable alternative:
`js
import { fileURLToPath } from "node:url";
const tsconfigRootDir = fileURLToPath(new URL(".", import.meta.url));
`
Then pass tsconfigRootDir into typescriptRecommended({ ... }).
Use this when you want “framework linting” as a single preset. This includes React + A11y + Next.js rules.
`js
import { nextjsRecommended, typescriptRecommended } from "@stride.it/appoint-lint-governance";
export default [
...typescriptRecommended({
typeChecked: true,
tsconfigPath: "./tsconfig.json",
tsconfigRootDir: import.meta.dirname,
}),
...nextjsRecommended,
];
`
Use this when you want React / A11y / Next.js as separate “domain lines”.
Important: do not use nextjsRecommended together with reactRecommended and a11yRecommended (it would duplicate rules).
`js
import {
a11yRecommended,
nextjs,
reactRecommended,
typescriptRecommended,
} from "@stride.it/appoint-lint-governance";
export default [
...typescriptRecommended({
typeChecked: true,
tsconfigPath: "./tsconfig.json",
tsconfigRootDir: import.meta.dirname,
}),
...reactRecommended,
...a11yRecommended,
...nextjs(),
];
`
Flat config is a single array, but you can run “per-domain” by creating multiple config files and selecting them with eslint --config.
Example scripts:
`json`
{
"scripts": {
"lint:ts": "eslint --config ./eslint.typescript-only.config.mjs \"src/*/.{ts,tsx}\"",
"lint:react": "eslint --config ./eslint.react-only.config.mjs \"src/*/.{tsx,jsx}\"",
"lint:a11y": "eslint --config ./eslint.a11y-only.config.mjs \"src/*/.{tsx,jsx}\"",
"lint:next": "eslint --config ./eslint.nextjs-only.config.mjs \"src/*/.{tsx,jsx}\""
}
}
If your project uses Prettier, include the interop preset last so it can override earlier formatting rules:
`js
import {
typescriptPrettierInterop,
typescriptRecommended,
} from "@stride.it/appoint-lint-governance";
export default [
...typescriptRecommended(),
...typescriptPrettierInterop(),
];
`
Flat config is order-dependent: later entries win. Consumers can override by appending their own config object after spreading a preset.
If your organization wants to prevent overrides, ESLint itself cannot lock consumer rules; enforce that with CI/policy checks on the consumer repo’s eslint.config.*.
This package intentionally focuses on ESLint rules. Many teams also enforce these CI gates:
- Type checking: tsc --noEmitpnpm audit
- Dependency audit: (or your org-approved alternative)
- Secret scanning and SAST (org-dependent)
`bash`
pnpm install
pnpm test
pnpm build
To validate the publish output locally:
`bash`
npm pack
Then install the generated .tgz into a consumer repo.
1) Bump version:
`bash`
pnpm version patch
1) Dry run:
`bash`
pnpm publish --dry-run
1) Publish (requires npm credentials with access to the @stride.it scope):
`bash``
pnpm publish --access public