mirror of
https://github.com/kuhyx/utils.git
synced 2026-11-11 13:27:44 +01:00
Evil Martians' "ten anti-AI-slop moves" as a package: strict tsconfig base (noUncheckedIndexedAccess, exactOptionalPropertyTypes), type-checked typescript-eslint strict+stylistic, unicorn/sonarjs/perfectionist, behaviour rules for tests (expect-expect, no-focused-tests), React (hooks, @eslint-react, jsx-a11y strict, you-might-not-need-an-effect), Playwright, and layer boundaries via eslint-plugin-boundaries 7 with the article's default policies. Knip / jscpd / Stryker bases; Stryker carries no break threshold on purpose. Plugins are dependencies, not devDependencies: a flat config imports them from this package's own node_modules, so a consumer installing from the git tag gets them or the lint cannot run. No build step, so the tag needs no prepare. test/fixture is a mini repo with one planted violation per rule family; test/expected.js names the rule that must catch each, and the suite runs the real CLI over it (in a child process -- v8 coverage merges natively-loaded and transformed copies of the same module into "uncovered"). 35 tests, 100% branch coverage on the factories. eslint/fast.js is the type-free subset for a per-edit hook: 0.52 s cold on one file, measured against 1.28 s for base() without types -- importing a plugin is the cost, so it loads none, nor base.js which imports them. Probed under ESLint 10: jsx-a11y 6.10.2 (peer says <=9) and boundaries 7.2.0 both run; the fixture pins that. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DnAYyNH1Sm4iJNidfYbrZJ
54 lines
1.9 KiB
JavaScript
54 lines
1.9 KiB
JavaScript
// One call for the common case, the pieces for everything else.
|
|
//
|
|
// import { defineConfig } from "@kuhyx/ts-config";
|
|
// export default defineConfig({
|
|
// tsconfigRootDir: import.meta.dirname,
|
|
// react: true,
|
|
// boundaries: { elements: folderElements(["components", "services"]) },
|
|
// });
|
|
import { base } from "./base.js";
|
|
import { boundaries } from "./boundaries.js";
|
|
import { playwrightConfig } from "./playwright.js";
|
|
import { react } from "./react.js";
|
|
import { vitestConfig } from "./vitest.js";
|
|
|
|
export { base } from "./base.js";
|
|
export { boundaries, DEFAULT_ALLOW, folderElements } from "./boundaries.js";
|
|
export { playwrightConfig } from "./playwright.js";
|
|
export { react } from "./react.js";
|
|
export { vitestConfig } from "./vitest.js";
|
|
|
|
/**
|
|
* @param {object} options
|
|
* @param {string} options.tsconfigRootDir `import.meta.dirname` of the
|
|
* consumer's eslint.config.js.
|
|
* @param {string[]} [options.ignores]
|
|
* @param {boolean} [options.aliasOnly]
|
|
* @param {boolean} [options.react] Stack the React layer.
|
|
* @param {boolean} [options.vitest] Stack the vitest rules (default true).
|
|
* @param {boolean} [options.playwright] Stack the Playwright rules.
|
|
* @param {object} [options.boundaries] Options for boundaries(); omitted
|
|
* means no layer enforcement (a repo that has not declared its layers).
|
|
* @param {import("eslint").Linter.Config[]} [options.overrides] Repo-specific
|
|
* config objects appended last, so they win. Each needs a reason comment.
|
|
*/
|
|
export function defineConfig({
|
|
aliasOnly,
|
|
boundaries: boundariesOptions,
|
|
ignores,
|
|
overrides = [],
|
|
playwright = false,
|
|
react: withReact = false,
|
|
tsconfigRootDir,
|
|
vitest = true,
|
|
}) {
|
|
return [
|
|
...base({ aliasOnly, ignores, tsconfigRootDir }),
|
|
...(withReact ? react : []),
|
|
...(vitest ? vitestConfig : []),
|
|
...(playwright ? playwrightConfig : []),
|
|
...(boundariesOptions ? boundaries({ tsconfigRootDir, ...boundariesOptions }) : []),
|
|
...overrides,
|
|
];
|
|
}
|