- Add quality-gate-inventory.md documenting baseline verification artifacts - Add before/after lint logs (pnpm-lint.before.log, pnpm-lint.after.log) as baseline comparison - Add pnpm-test.before.log as test baseline artifact - Update eslint.config.mjs with explicit context overrides to clean up linting scope
349 lines
13 KiB
JavaScript
349 lines
13 KiB
JavaScript
import eslint from "@eslint/js";
|
|
import tseslint from "typescript-eslint";
|
|
|
|
/**
|
|
* ESLint Flat Config for Fusion Workspace
|
|
*
|
|
* Configuration hierarchy (order matters for flat configs):
|
|
* 1. Global ignores — files never linted (must come first)
|
|
* 2. Base recommendations — eslint/recommended + typescript-eslint/recommended
|
|
* 3. Context-specific overrides — production, test-support, node, sw, etc.
|
|
*
|
|
* Key scoping decisions:
|
|
* - Global ignores come first to prevent base configs from processing excluded files
|
|
* - Test support files use relaxed rules (no-explicit-any off) without blanket-ignoring them
|
|
* - Node scripts get proper Node globals (process, console, require, etc.)
|
|
* - Service worker gets browser SW globals (self, caches, fetch, etc.)
|
|
* - Production source keeps @typescript-eslint/no-explicit-any as warning
|
|
*/
|
|
export default tseslint.config(
|
|
// ─────────────────────────────────────────────────────────────
|
|
// GLOBAL IGNORES FIRST
|
|
// (per memory guidance: must come before recommended configs)
|
|
// ─────────────────────────────────────────────────────────────
|
|
{
|
|
ignores: [
|
|
// Node modules and build artifacts
|
|
"**/node_modules/**",
|
|
"**/dist/**",
|
|
"**/out/**",
|
|
"**/build/**",
|
|
"coverage/**",
|
|
// Project metadata (fn data, worktrees, etc.)
|
|
".fusion/**",
|
|
".worktrees/**",
|
|
// Lock files
|
|
"*.lock",
|
|
"pnpm-lock.yaml",
|
|
// Git internals
|
|
".git/**",
|
|
// Logs
|
|
"*.log",
|
|
// All test files matching standard patterns — never linted
|
|
"**/*.test.ts",
|
|
"**/*.test.tsx",
|
|
"**/*.spec.ts",
|
|
"**/*.spec.tsx",
|
|
"**/__tests__/**",
|
|
// Dashboard test support directory — test helpers, not production code
|
|
"packages/dashboard/app/test/**",
|
|
],
|
|
},
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
// BASE RECOMMENDATIONS
|
|
// ─────────────────────────────────────────────────────────────
|
|
eslint.configs.recommended,
|
|
...tseslint.configs.recommended,
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
// TEST SUPPORT FILES — relaxed rules for vitest setup/config
|
|
// (runs BEFORE production config to disable no-explicit-any for test helpers)
|
|
// ─────────────────────────────────────────────────────────────
|
|
{
|
|
// Dashboard vitest.setup.ts — test infrastructure, not production source
|
|
// Includes mock factories, vi.fn() signatures, etc. that legitimately use `any`
|
|
files: [
|
|
"packages/dashboard/vitest.setup.ts",
|
|
],
|
|
plugins: {
|
|
"@typescript-eslint": tseslint.plugin,
|
|
},
|
|
languageOptions: {
|
|
parser: tseslint.parser,
|
|
parserOptions: {
|
|
ecmaVersion: "latest",
|
|
sourceType: "module",
|
|
},
|
|
},
|
|
rules: {
|
|
// Test setup files commonly use `any` for mock types and event handlers
|
|
"@typescript-eslint/no-explicit-any": "off",
|
|
// Allow unused vars in test setup (globals, config, etc.)
|
|
"@typescript-eslint/no-unused-vars": "off",
|
|
"no-unused-vars": "off",
|
|
// Allow empty blocks in test setup
|
|
"no-empty": "off",
|
|
},
|
|
},
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
// PRODUCTION TYPESCRIPT FILES — strict rules with project conventions
|
|
// Enforces @typescript-eslint/no-explicit-any for production source
|
|
// ─────────────────────────────────────────────────────────────
|
|
{
|
|
files: [
|
|
"packages/*/src/**/*.ts",
|
|
"packages/*/src/**/*.tsx",
|
|
"packages/dashboard/app/**/*.ts",
|
|
"packages/dashboard/app/**/*.tsx",
|
|
"packages/dashboard/src/**/*.ts",
|
|
"packages/dashboard/src/**/*.tsx",
|
|
// NOTE: vitest.setup.ts is excluded here (handled by test-support block above)
|
|
],
|
|
plugins: {
|
|
"@typescript-eslint": tseslint.plugin,
|
|
},
|
|
languageOptions: {
|
|
parser: tseslint.parser,
|
|
parserOptions: {
|
|
ecmaVersion: "latest",
|
|
sourceType: "module",
|
|
},
|
|
},
|
|
rules: {
|
|
"@typescript-eslint/no-unused-vars": [
|
|
"warn", // Warning for unused vars
|
|
{
|
|
vars: "all",
|
|
args: "after-used",
|
|
ignoreRestSiblings: true,
|
|
varsIgnorePattern: "^_",
|
|
argsIgnorePattern: "^_",
|
|
caughtErrorsIgnorePattern: "^_",
|
|
},
|
|
],
|
|
// Keep no-explicit-any as WARN for production source
|
|
// (use @ts-expect-error or proper types when possible)
|
|
"@typescript-eslint/no-explicit-any": ["warn", {
|
|
"ignoreRestArgs": true,
|
|
}],
|
|
// Allow fallthrough with comment
|
|
"no-fallthrough": ["warn", { "commentPattern": ".*fallthrough.*" }],
|
|
// Allow useless escape
|
|
"no-useless-escape": "warn",
|
|
// Allow empty blocks
|
|
"no-empty": "warn",
|
|
// Allow case declarations
|
|
"no-case-declarations": "warn",
|
|
// Allow unused expressions (for intentional side effects)
|
|
"@typescript-eslint/no-unused-expressions": "warn",
|
|
// Allow empty object types
|
|
"@typescript-eslint/no-empty-object-type": "warn",
|
|
// Allow empty interface
|
|
"@typescript-eslint/no-empty-interface": "warn",
|
|
// Allow @ts-ignore comments
|
|
"@typescript-eslint/ban-ts-comment": "warn",
|
|
// Allow control regex
|
|
"no-control-regex": "warn",
|
|
// Allow prefer-const (warn instead of error)
|
|
"prefer-const": "warn",
|
|
// Allow useless catch
|
|
"no-useless-catch": "warn",
|
|
},
|
|
ignores: ["**/*.gen.ts", "**/*.gen.tsx"],
|
|
},
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
// NODE SCRIPTS — proper Node.js globals
|
|
// (scripts/dev-with-memory.mjs, fix.cjs, etc.)
|
|
// ─────────────────────────────────────────────────────────────
|
|
{
|
|
files: [
|
|
"scripts/**/*.js",
|
|
"scripts/**/*.mjs",
|
|
"*.cjs",
|
|
"fix.cjs",
|
|
],
|
|
languageOptions: {
|
|
ecmaVersion: "latest",
|
|
sourceType: "module",
|
|
globals: {
|
|
// Node.js core globals
|
|
process: "readonly",
|
|
console: "readonly",
|
|
setTimeout: "readonly",
|
|
setInterval: "readonly",
|
|
clearTimeout: "readonly",
|
|
clearInterval: "readonly",
|
|
globalThis: "readonly",
|
|
require: "readonly",
|
|
module: "readonly",
|
|
__dirname: "readonly",
|
|
__filename: "readonly",
|
|
Buffer: "readonly",
|
|
},
|
|
},
|
|
rules: {
|
|
// Node scripts commonly use require()
|
|
"@typescript-eslint/no-require-imports": "off",
|
|
// Allow console in scripts (dev tooling)
|
|
"no-console": "off",
|
|
// Allow unused vars in scripts (tooling often has them)
|
|
"no-unused-vars": "off",
|
|
"@typescript-eslint/no-unused-vars": "off",
|
|
},
|
|
},
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
// DEMO FILES — tooling/linting noise, not production code
|
|
// ─────────────────────────────────────────────────────────────
|
|
{
|
|
files: ["demo/**/*.ts"],
|
|
plugins: {
|
|
"@typescript-eslint": tseslint.plugin,
|
|
},
|
|
languageOptions: {
|
|
parser: tseslint.parser,
|
|
parserOptions: {
|
|
ecmaVersion: "latest",
|
|
sourceType: "module",
|
|
},
|
|
},
|
|
rules: {
|
|
// Allow explicit any in demo files
|
|
"@typescript-eslint/no-explicit-any": "off",
|
|
// Allow unused vars in demo files
|
|
"@typescript-eslint/no-unused-vars": "off",
|
|
// Allow console in demo files
|
|
"no-console": "off",
|
|
},
|
|
},
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
// PLUGIN EXAMPLES — relaxed rules for plugin development
|
|
// ─────────────────────────────────────────────────────────────
|
|
{
|
|
files: ["plugins/**/*.ts", "plugins/**/*.tsx"],
|
|
plugins: {
|
|
"@typescript-eslint": tseslint.plugin,
|
|
},
|
|
languageOptions: {
|
|
parser: tseslint.parser,
|
|
parserOptions: {
|
|
ecmaVersion: "latest",
|
|
sourceType: "module",
|
|
},
|
|
},
|
|
rules: {
|
|
// Allow explicit any for mocks
|
|
"@typescript-eslint/no-explicit-any": "off",
|
|
// Allow unused vars in tests
|
|
"@typescript-eslint/no-unused-vars": "off",
|
|
// Allow unsafe function types
|
|
"@typescript-eslint/no-unsafe-function-type": "off",
|
|
// Allow prefer-const
|
|
"prefer-const": "off",
|
|
// Allow fallthrough
|
|
"no-fallthrough": "off",
|
|
// Allow useless escape
|
|
"no-useless-escape": "off",
|
|
},
|
|
},
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
// AGENT SKILL TEMPLATES — template code with underscore prefix support
|
|
// (agent prompt templates use _prefixed placeholders intentionally)
|
|
// ─────────────────────────────────────────────────────────────
|
|
{
|
|
files: [".pi/agent/skills/**/*.ts", ".pi/agent/skills/**/*.tsx"],
|
|
plugins: {
|
|
"@typescript-eslint": tseslint.plugin,
|
|
},
|
|
languageOptions: {
|
|
parser: tseslint.parser,
|
|
parserOptions: {
|
|
ecmaVersion: "latest",
|
|
sourceType: "module",
|
|
},
|
|
},
|
|
rules: {
|
|
// Allow unused vars with underscore prefix (intentional placeholder pattern)
|
|
"@typescript-eslint/no-unused-vars": [
|
|
"warn",
|
|
{
|
|
vars: "all",
|
|
args: "after-used",
|
|
ignoreRestSiblings: true,
|
|
varsIgnorePattern: "^_",
|
|
argsIgnorePattern: "^_",
|
|
caughtErrorsIgnorePattern: "^_",
|
|
},
|
|
],
|
|
// Allow explicit any in templates
|
|
"@typescript-eslint/no-explicit-any": "off",
|
|
},
|
|
},
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
// ROOT-LEVEL MJS FILES — common JS/ESM patterns at project root
|
|
// ─────────────────────────────────────────────────────────────
|
|
{
|
|
files: ["*.mjs", "*.js"],
|
|
languageOptions: {
|
|
ecmaVersion: "latest",
|
|
sourceType: "module",
|
|
globals: {
|
|
// Common ESM globals
|
|
process: "readonly",
|
|
console: "readonly",
|
|
setTimeout: "readonly",
|
|
setInterval: "readonly",
|
|
clearTimeout: "readonly",
|
|
clearInterval: "readonly",
|
|
globalThis: "readonly",
|
|
},
|
|
},
|
|
rules: {
|
|
"no-console": "off",
|
|
"no-unused-vars": "off",
|
|
},
|
|
},
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
// SERVICE WORKER FILES — browser service worker globals
|
|
// (packages/dashboard/app/public/sw.js uses self, caches, fetch, etc.)
|
|
// ─────────────────────────────────────────────────────────────
|
|
{
|
|
files: ["**/sw.js"],
|
|
languageOptions: {
|
|
ecmaVersion: "latest",
|
|
sourceType: "module",
|
|
globals: {
|
|
// Service worker globals
|
|
self: "readonly",
|
|
caches: "readonly",
|
|
fetch: "readonly",
|
|
console: "readonly",
|
|
URL: "readonly",
|
|
Promise: "readonly",
|
|
Request: "readonly",
|
|
Response: "readonly",
|
|
Headers: "readonly",
|
|
Cache: "readonly",
|
|
CacheStorage: "readonly",
|
|
ExtendableEvent: "readonly",
|
|
FetchEvent: "readonly",
|
|
Clients: "readonly",
|
|
Client: "readonly",
|
|
WindowClient: "readonly",
|
|
},
|
|
},
|
|
rules: {
|
|
"no-undef": "error",
|
|
"no-unused-vars": "off",
|
|
"no-console": "off",
|
|
},
|
|
},
|
|
);
|