Skip to content

Instantly share code, notes, and snippets.

@Nick2bad4u
Created August 23, 2025 19:58
Show Gist options
  • Save Nick2bad4u/b8321af5eefb511fa4732b1dedd1eddc to your computer and use it in GitHub Desktop.
Save Nick2bad4u/b8321af5eefb511fa4732b1dedd1eddc to your computer and use it in GitHub Desktop.
The most insane ESLINT for Typescript Ever
// @ts-nocheck
/**
* Optimized ESLint configuration for Uptime Watcher
*
* This configuration is specifically tailored for:
*
* - Electron + React + TypeScript architecture
* - Domain-driven design with Zustand stores
* - Service-based backend architecture
* - High code quality with reduced false positives
* - Modern ES2024+ features
* - Enhanced security and performance rules
*/
/* eslint-disable import-x/namespace */
/* eslint-disable import-x/no-named-as-default-member */
/* eslint-disable no-underscore-dangle */
/* eslint-disable n/no-unpublished-import */
/* eslint-disable perfectionist/sort-imports */
/* eslint-disable perfectionist/sort-objects */
import { importX } from "eslint-plugin-import-x";
import { plugin as ex } from "eslint-plugin-exception-handling";
import * as nodeDependenciesPlugin from "eslint-plugin-node-dependencies";
import arrayFunc from "eslint-plugin-array-func";
import depend from "eslint-plugin-depend";
import eslintConfigPrettier from "eslint-config-prettier";
import eslintPluginJsonc from "eslint-plugin-jsonc";
import eslintPluginJsonSchemaValidator from "eslint-plugin-json-schema-validator";
import eslintPluginMath from "eslint-plugin-math";
import eslintPluginNoUseExtendNative from "eslint-plugin-no-use-extend-native";
import eslintPluginToml from "eslint-plugin-toml";
import eslintPluginYml from "eslint-plugin-yml";
import eslintReact from "@eslint-react/eslint-plugin";
import eslintReactDom from "eslint-plugin-react-dom";
import eslintReactHooksExtra from "eslint-plugin-react-hooks-extra";
import reactHooksAddons from "eslint-plugin-react-hooks-addons";
import eslintReactNamingConvention from "eslint-plugin-react-naming-convention";
import eslintReactWeb from "eslint-plugin-react-web-api";
import globals from "globals";
// import html from "eslint-plugin-html";
import html from "@html-eslint/eslint-plugin";
import * as htmlParser from "@html-eslint/parser";
import implicitDependencies from "@jcoreio/eslint-plugin-implicit-dependencies";
import istanbul from "eslint-plugin-istanbul";
import js from "@eslint/js";
import json from "@eslint/json";
import jsoncEslintParser from "jsonc-eslint-parser";
import jsxA11y from "eslint-plugin-jsx-a11y";
import listeners from "eslint-plugin-listeners";
import markdown from "@eslint/markdown";
import noBarrelFiles from "eslint-plugin-no-barrel-files";
import nodePlugin from "eslint-plugin-n";
import nounsanitized from "eslint-plugin-no-unsanitized";
import observers from "eslint-plugin-observers";
import pluginBoundaries from "eslint-plugin-boundaries";
import pluginCanonical from "eslint-plugin-canonical";
// eslint-disable-next-line depend/ban-dependencies -- Recommended one sucks
import pluginComments from "eslint-plugin-eslint-comments";
// eslint-disable-next-line import-x/no-unresolved -- Works fine
import pluginCompat from "eslint-plugin-compat";
import pluginFunctional from "eslint-plugin-functional";
import pluginMicrosoftSdl from "@microsoft/eslint-plugin-sdl";
import pluginNoOnly from "eslint-plugin-no-only-tests";
import pluginPerfectionist from "eslint-plugin-perfectionist";
import pluginPreferArrow from "eslint-plugin-prefer-arrow";
import pluginPrettier from "eslint-plugin-prettier";
import pluginPromise from "eslint-plugin-promise";
// eslint-disable-next-line depend/ban-dependencies -- Recommended one sucks
import pluginReact from "eslint-plugin-react";
// eslint-disable-next-line import-x/default -- Works fine
import reactHooks from "eslint-plugin-react-hooks";
import pluginRedos from "eslint-plugin-redos";
import pluginRegexp from "eslint-plugin-regexp";
import pluginSecurity from "eslint-plugin-security";
import pluginSonarjs from "eslint-plugin-sonarjs";
import pluginSortClassMembers from "eslint-plugin-sort-class-members";
import pluginSortDestructure from "eslint-plugin-sort-destructure-keys";
import pluginTestingLibrary from "eslint-plugin-testing-library";
import pluginTsdoc from "eslint-plugin-tsdoc";
import pluginUnicorn from "eslint-plugin-unicorn";
import pluginUnusedImports from "eslint-plugin-unused-imports";
import pluginWriteGood from "eslint-plugin-write-good-comments";
import progress from "eslint-plugin-file-progress";
import putout from "eslint-plugin-putout";
import reactCompiler from "eslint-plugin-react-compiler";
import reactRefresh from "eslint-plugin-react-refresh";
import tailwind from "eslint-plugin-tailwindcss";
import tomlEslintParser from "toml-eslint-parser";
import tseslint from "@typescript-eslint/eslint-plugin";
import tseslintParser from "@typescript-eslint/parser";
import vitest from "@vitest/eslint-plugin";
import xss from "eslint-plugin-xss";
import yamlEslintParser from "yaml-eslint-parser";
import sqlTemplate from "eslint-plugin-sql-template";
import * as pluginNFDAR from "eslint-plugin-no-function-declare-after-return";
import * as pluginJSDoc from "eslint-plugin-require-jsdoc";
import eslintPluginCommentLength from "eslint-plugin-comment-length";
import pluginSortReactDependency from "eslint-plugin-sort-react-dependency-arrays";
import pluginRegexLook from "eslint-plugin-no-lookahead-lookbehind-regexp";
import * as pluginDesignTokens from "@metamask/eslint-plugin-design-tokens";
import * as pluginFunctionNames from "eslint-plugin-function-name";
import * as pluginCleanCode from "eslint-plugin-clean-code";
import pluginFilenameExport from "eslint-plugin-filename-export";
import nitpick from "eslint-plugin-nitpick";
// Zod Tree Shaking Plugin https://github.com/colinhacks/zod/issues/4433#issuecomment-2921500831
import importZod from "eslint-plugin-import-zod";
import pluginUseMemo from "eslint-plugin-usememo-recommendations";
import pluginGoodEffects from "eslint-plugin-goodeffects";
import pluginJsxPlus from "eslint-plugin-jsx-plus";
import pluginNoUnary from "eslint-plugin-no-unary-plus";
import pluginGranular from "eslint-plugin-granular-selectors";
import moduleInterop from "eslint-plugin-module-interop";
import pluginNoUnwaited from "eslint-plugin-no-unawaited-dot-catch-throw";
import pluginTopLevel from "eslint-plugin-toplevel";
import pluginFormatSQL from "eslint-plugin-format-sql";
import pluginNeverThrow from "eslint-plugin-neverthrow";
import pluginNoExplicitTypeExports from "eslint-plugin-no-explicit-type-exports";
import pluginDeprecation from "eslint-plugin-deprecation";
import pluginReactTest from "eslint-plugin-react-require-testid";
import reactUseEffect from "eslint-plugin-react-useeffect";
import pluginNoConstructBind from "eslint-plugin-no-constructor-bind";
import pluginTotalFunctions from "eslint-plugin-total-functions";
import pluginValidateJSX from "eslint-plugin-validate-jsx-nesting";
import styledA11y from "eslint-plugin-styled-components-a11y";
import pluginReactFormFields from "eslint-plugin-react-form-fields";
import pluginReactHookForm from "eslint-plugin-react-hook-form";
// eslint-disable-next-line import-x/default -- Working fine just old
import preferFunctionComponent from "eslint-plugin-react-prefer-function-component";
import pluginSSR from "eslint-plugin-ssr-friendly";
import reactPerfPlugin from "eslint-plugin-react-perf";
import pluginUseMemo2 from "@arthurgeron/eslint-plugin-react-usememo";
import etc from "eslint-plugin-etc";
import packageJson from "eslint-plugin-package-json";
import pluginSafeJSX from "eslint-plugin-safe-jsx";
import pluginLoadableImports from "eslint-plugin-loadable-imports";
import zod from "eslint-plugin-zod";
import pluginUndefinedCss from "eslint-plugin-undefined-css-classes";
import css from "@eslint/css";
// * as cssPlugin from "eslint-plugin-css"
import * as mdx from "eslint-plugin-mdx";
// import * as tailwind4 from "tailwind-csstree";
import pluginNoHardcoded from "eslint-plugin-no-hardcoded-strings";
import * as publint from "eslint-plugin-publint";
import pluginCssModules from "eslint-plugin-css-modules";
import pluginDocusaurus from "@docusaurus/eslint-plugin";
import publintParser from "eslint-plugin-publint/jsonc-eslint-parser";
import { createTypeScriptImportResolver } from "eslint-import-resolver-typescript";
import { fixupPluginRules } from "@eslint/compat";
// Unused and Uninstalled Plugins:
// eslint-config-prettier
// eslint-find-rules
// eslint-formatter-compact -- Built into eslint
// eslint-import-resolver-node -- Replaced by import-x
// eslint-plugin-json
// eslint-plugin-no-inferred-method-name
// eslint-plugin-react-native
// eslint-plugin-react-x
// eslint-plugin-no-inferred-method-name
// @stylistic/eslint-plugin
// eslint-plugin-fsecond
// eslint-plugin-es-x
// @dword-design/import-alias
// eslint-plugin-typesafe -- Broken
// eslint-plugin-use-selector-with -- Broken
// eslint-plugin-zod-import -- Didn't test but does similar function to import-zod
// @fluentui/eslint-plugin-react-components
// eslint-plugin-solid
// @ospm/eslint-plugin-react-signals-hooks
// eslint-plugin-pkg-json -- Package appears to be broken or incompatible
// ESLint Tools
// Import { FlatCompat } from "@eslint/eslintrc";
// Const flatCompat = new FlatCompat();
// Don't use
// eslint-plugin-import -- Replaced by import-x
// Schema: https://www.schemastore.org/eslintrc.json
import path from "node:path";
// const __filename = fileURLToPath(import.meta.url);
// const gitignorePath = path.resolve(__dirname, ".gitignore");
const __dirname = import.meta.dirname;
export default [
importX.flatConfigs.typescript,
progress.configs.recommended,
...nodeDependenciesPlugin.configs["flat/recommended"],
noBarrelFiles.flat,
nitpick.configs.recommended,
// Global ignores - must be first and more comprehensive
{
ignores: [
"CHANGELOG.md",
"_ZENTASKS*",
".agentic-tools*",
".devskim.json",
".github/chatmodes/**",
".github/instructions/**",
".github/ISSUE_TEMPLATE/**",
".github/prompts/**",
".github/PULL_REQUEST_TEMPLATE/**",
"**/_ZENTASKS*",
"**/.agentic-tools*",
"**/chatproject.md",
"**/coverage-results.json",
"**/Coverage/**",
"**/coverage/**",
"**/dist-electron/**",
"**/dist/**",
"**/shared/**",
"**/node_modules/**",
"**/release/**",
"vite.config.ts", // Ignore vite config due to parsing issues
"vitest.config.ts", // Ignore vitest config due to parsing issues
"vitest.electron.config.ts", // Ignore vitest electron config
"Coverage/",
"coverage/",
"dist-electron/",
"dist/",
"shared/",
"docs/docusaurus/docs/**",
"docs/docusaurus/build/**",
"docs/docusaurus/.docusaurus/**",
"docs/Archive/**",
"docs/Packages/**",
"docs/Reviews/**",
"node_modules/**",
"docs/Logger-Error-report.md",
"release/",
"coverage-report.json",
"html/**",
"report/**",
// "**/*.config.{js,mjs,ts}",
],
},
// Global browser environment
{
languageOptions: {
globals: {
...globals.node,
...vitest.environments.env.globals,
__dirname: "readonly",
__filename: "readonly",
afterAll: "readonly",
afterEach: "readonly",
beforeAll: "readonly",
beforeEach: "readonly",
Buffer: "readonly",
describe: "readonly",
document: "readonly",
expect: "readonly",
global: "readonly",
globalThis: "readonly",
it: "readonly",
module: "readonly",
process: "readonly",
require: "readonly",
test: "readonly",
vi: "readonly",
window: "readonly",
},
},
},
{
settings: {
"import-x/resolver": {
node: true,
},
react: { version: "19" },
"import-x/resolver-next": [
createTypeScriptImportResolver({
alwaysTryTypes: true, // Always try to resolve types under `<root>@types` directory even if it doesn't contain any source code, like `@types/unist`
noWarnOnMultipleProjects: true, // Don't warn about multiple projects
bun: true, // Resolve Bun modules (https://github.com/import-js/eslint-import-resolver-typescript#bun)
// Use an array
project: [
"tsconfig.electron.json",
"tsconfig.electron.test.json",
"tsconfig.json",
"tsconfig.test.json",
"tsconfig.shared.json",
"tsconfig.shared.test.json",
"docs/docusaurus/tsconfig.json",
"docs/docusaurus/tsconfig.eslint.json",
"docs/docusaurus/tsconfig.typedoc.json",
"docs/docusaurus/tsconfig.local.typedoc.json",
],
}),
],
},
},
// YAML files
{
plugins: { eslintPluginYml: eslintPluginYml },
files: ["*.yaml", "*.yml"],
ignores: [],
rules: {
...eslintPluginYml.configs["flat/prettier"].rules,
...eslintPluginJsonSchemaValidator.configs["flat/recommended"]
.rules,
},
languageOptions: {
parser: yamlEslintParser,
// Options used with yaml-eslint-parser.
parserOptions: {
defaultYAMLVersion: "1.2",
},
},
},
// HTML files
{
plugins: {
"@html-eslint": html,
},
languageOptions: {
parser: htmlParser,
},
files: [
"**/*.html",
"**/*.htm",
"*.html",
"*.htm",
"*.xhtml",
],
ignores: ["report/**"],
rules: {
...html.configs["flat/recommended"].rules,
"@html-eslint/indent": "error",
"@html-eslint/require-closing-tags": [
"error",
{ selfClosing: "always" },
],
"@html-eslint/no-extra-spacing-attrs": [
"error",
{ enforceBeforeSelfClose: true },
],
},
},
// Package.json Linting
{
files: ["**/package.json"],
languageOptions: {
parser: publintParser,
},
plugins: { publint },
rules: {
// /**
// * The 'suggestion' type messages created by publint will cause
// * eslint warns
// */
// "publint/suggestion": "warn",
// /**
// * The 'warning' type messages created by publint will cause eslint
// * warns
// */
// "publint/warning": "warn",
// /**
// * The 'error' type messages created by publint will cause eslint
// * errors
// */
// "publint/error": "error",
},
},
{
files: ["**/package.json"],
plugins: { "package-json": packageJson },
languageOptions: {
parser: jsoncEslintParser,
parserOptions: { jsonSyntax: "JSON" },
},
...packageJson.configs.recommended,
rules: {
// "pkg-json/no-conflict-types": "error", // Plugin disabled - appears broken
"package-json/no-redundant-files": "warn",
"package-json/require-author": "warn",
"package-json/require-bugs": "warn",
"package-json/require-bundleDependencies": "off",
"package-json/require-optionalDependencies": "off", // Not needed for Electron applications
"package-json/require-peerDependencies": "off",
"package-json/require-dependencies": "warn",
"package-json/require-devDependencies": "warn",
"package-json/restrict-dependency-ranges": "warn",
"package-json/require-engines": "warn",
"package-json/require-files": "off", // Not needed for Electron applications
"package-json/require-keywords": "warn",
"package-json/require-types": "off", // Not needed for Electron applications
"package-json/valid-local-dependency": "off",
},
},
// MDX files
{
files: ["**/*.mdx"],
plugins: { mdx: mdx },
rules: {
...mdx.flat.rules,
...mdx.flatCodeBlocks.rules,
"no-var": "error",
"prefer-const": "error",
},
settings: {
processor: mdx.createRemarkProcessor({
lintCodeBlocks: true,
// optional, if you want to disable language mapper, set it to `false`
// if you want to override the default language mapper inside, you can provide your own
languageMapper: {},
// optional, same as the `parserOptions.ignoreRemarkConfig`, you have to specify it twice unfortunately
ignoreRemarkConfig: true,
// optional, same as the `parserOptions.remarkConfigPath`, you have to specify it twice unfortunately
// remarkConfigPath: "path/to/your/remarkrc",
}),
},
},
// Markdown files
{
files: ["**/*.md"],
rules: {
...markdown.configs.recommended.rules,
...eslintPluginJsonSchemaValidator.configs["flat/recommended"]
.rules,
},
plugins: { markdown },
language: "markdown/gfm",
},
// CSS files
{
files: ["**/*.css"],
ignores: ["docs/**", "**/test/**"],
plugins: {
css: css,
},
language: "css/css",
languageOptions: {
tolerant: true,
},
rules: {
...css.configs.recommended.rules,
"css/no-empty-blocks": "error",
"css/no-invalid-properties": "off",
"css/use-baseline": "off",
"css/no-invalid-at-rules": "off",
},
},
// JSON files
{
files: [
"**/*.json",
"**/*.json5",
"**/*.jsonc",
"*.json",
"*.json5",
"*.jsonc",
],
ignores: [],
plugins: { eslintPluginJsonc: eslintPluginJsonc },
...json.configs.recommended[0],
...eslintPluginJsonc.configs["flat/prettier"][0],
...eslintPluginJsonSchemaValidator.configs["flat/recommended"].rules,
languageOptions: {
parser: jsoncEslintParser,
parserOptions: { jsonSyntax: "JSON" },
},
},
// TOML files
{
files: ["**/*.toml"],
ignores: ["lychee.toml"],
plugins: { eslintPluginToml: eslintPluginToml },
...eslintPluginToml.configs["flat/standard"][0],
...eslintPluginJsonSchemaValidator.configs["flat/recommended"].rules,
languageOptions: {
parser: tomlEslintParser,
parserOptions: { tomlVersion: "1.0.0" },
},
},
// TSX Tailwind +Linting files
{
files: ["src/**/*.tsx"],
ignores: [],
languageOptions: {
parser: tseslintParser,
parserOptions: {
ecmaVersion: "latest",
project: "tsconfig.json",
sourceType: "module",
tsconfigRootDir: path.resolve(import.meta.dirname),
ecmaFeatures: {
jsx: true,
impliedStrict: true,
},
jsDocParsingMode: "all",
warnOnUnsupportedTypeScriptVersion: true,
},
globals: {
...globals.browser,
...globals.node,
document: "readonly",
globalThis: "readonly",
window: "readonly",
},
},
settings: {
tailwindcss: {
config: `${__dirname}/src/index.css`,
},
react: { version: "19" },
"boundaries/elements": [
{ type: "app", pattern: "src/App.tsx" },
{ type: "components", pattern: "src/components/**/*" },
{ type: "stores", pattern: "src/stores/**/*" },
{ type: "hooks", pattern: "src/hooks/**/*" },
{ type: "services", pattern: "src/services/**/*" },
{ type: "theme", pattern: "src/theme/**/*" },
{ type: "utils", pattern: "src/utils/**/*" },
{ type: "types", pattern: "src/types.ts" },
],
},
plugins: {
css: css,
tailwind: tailwind,
"undefined-css-classes": pluginUndefinedCss,
"no-hardcoded-strings": pluginNoHardcoded,
},
rules: {
// TypeScript rules
...tailwind.configs["flat/recommended"].rules,
...css.configs.recommended.rules,
...pluginUndefinedCss.configs["with-tailwind"].rules,
// Disable undefined-css-classes as it's producing false positives for valid Tailwind classes
"undefined-css-classes/no-undefined-css-classes": "off",
// "no-hardcoded-strings/no-hardcoded-strings": [
// "warn",
// {
// allowedFunctionNames: ["t", "translate", "i18n"],
// ignoreStrings: ["OK", "Cancel"],
// ignorePatterns: [/^[\s\d\-:]+$/v], // Ignore dates, times, numbers
// },
// ],
// Tailwind CSS
"tailwind/classnames-order": "warn",
"tailwind/enforces-negative-arbitrary-values": "warn",
"tailwind/enforces-shorthand": "warn",
"tailwind/migration-from-tailwind-2": "warn",
"tailwind/no-arbitrary-value": "warn",
"tailwind/no-contradicting-classname": "warn",
"tailwind/no-custom-classname": [
"warn",
{
skipClassAttribute: true,
},
],
"tailwind/no-unnecessary-arbitrary-value": "warn",
},
},
// Docusaurus files
{
files: [
"docs/docusaurus/**/*.ts",
"docs/docusaurus/**/*.tsx",
"docs/docusaurus/**/*.mjs",
"docs/docusaurus/**/*.cjs",
"docs/docusaurus/**/*.js",
"docs/docusaurus/**/*.jsx",
"docs/docusaurus/**/*.mts",
"docs/docusaurus/**/*.cts",
],
ignores: [
"docs/docusaurus/docs/**",
"docs/docusaurus/build/**",
"docs/docusaurus/.docusaurus/**",
"docs/docusaurus/**/*.css",
],
languageOptions: {
parser: tseslintParser,
parserOptions: {
ecmaVersion: "latest",
project: "./docs/docusaurus/tsconfig.eslint.json",
sourceType: "module",
tsconfigRootDir: path.resolve(import.meta.dirname),
ecmaFeatures: {
jsx: true,
impliedStrict: true,
},
jsDocParsingMode: "all",
warnOnUnsupportedTypeScriptVersion: true,
},
globals: {
...globals.browser,
...globals.node,
document: "readonly",
globalThis: "readonly",
window: "readonly",
},
},
settings: {
"import-x/resolver": {
// You will also need to install and configure the TypeScript resolver
// See also https://github.com/import-js/eslint-import-resolver-typescript#configuration
typescript: true,
node: true,
project: ["./docs/docusaurus/tsconfig.eslint.json"],
},
"import/resolver": {
// You will also need to install and configure the TypeScript resolver
// See also https://github.com/import-js/eslint-import-resolver-typescript#configuration
typescript: {
alwaysTryTypes: true, // Always try to resolve types under `<root>@types` directory even if it doesn't contain any source code, like `@types/unist`
project: ["./docs/docusaurus/tsconfig.eslint.json"],
},
},
},
plugins: {
"@typescript-eslint": tseslint,
"jsx-a11y": jsxA11y,
"no-unsanitized": nounsanitized,
"prefer-arrow": pluginPreferArrow,
"react-hooks": reactHooks,
"sort-class-members": pluginSortClassMembers,
"unused-imports": pluginUnusedImports,
"write-good-comments": pluginWriteGood,
boundaries: pluginBoundaries,
compat: pluginCompat,
css: css,
depend: depend,
functional: pluginFunctional,
js: js,
math: eslintPluginMath,
n: nodePlugin,
perfectionist: pluginPerfectionist,
"import-x": importX,
prettier: pluginPrettier,
promise: pluginPromise,
putout: putout,
react: pluginReact,
redos: pluginRedos,
regexp: pluginRegexp,
security: pluginSecurity,
sonarjs: pluginSonarjs,
tsdoc: pluginTsdoc,
unicorn: pluginUnicorn,
"eslint-comments": pluginComments,
ex: ex,
canonical: pluginCanonical,
"@eslint-react": eslintReact,
"@eslint-react/dom": eslintReactDom,
"@eslint-react/web-api": eslintReactWeb,
"@eslint-react/hooks-extra": eslintReactHooksExtra,
"react-hooks-addons": reactHooksAddons,
"@eslint-react/naming-convention": eslintReactNamingConvention,
xss: xss,
"array-func": arrayFunc,
"no-use-extend-native": eslintPluginNoUseExtendNative,
"@microsoft/sdl": pluginMicrosoftSdl,
"sort-destructure-keys": pluginSortDestructure,
istanbul: istanbul,
observers: observers,
"@jcoreio/implicit-dependencies": implicitDependencies,
listeners: listeners,
"sql-template": sqlTemplate,
"no-function-declare-after-return": pluginNFDAR,
"require-jsdoc": pluginJSDoc,
"comment-length": eslintPluginCommentLength,
"no-lookahead-lookbehind-regexp": pluginRegexLook,
"@metamask/design-tokens": pluginDesignTokens,
"function-name": pluginFunctionNames,
"clean-code": pluginCleanCode,
"import-zod": importZod,
"usememo-recommendations": pluginUseMemo,
"eslint-plugin-goodeffects": pluginGoodEffects,
"jsx-plus": pluginJsxPlus,
"no-unary-plus": pluginNoUnary,
"module-interop": moduleInterop,
"granular-selectors": pluginGranular,
"no-unawaited-dot-catch-throw": pluginNoUnwaited,
"eslint-plugin-toplevel": pluginTopLevel,
"format-sql": pluginFormatSQL,
neverthrow: fixupPluginRules(pluginNeverThrow),
"no-explicit-type-exports": pluginNoExplicitTypeExports,
deprecation: fixupPluginRules(pluginDeprecation),
"no-constructor-bind": pluginNoConstructBind,
"total-functions": fixupPluginRules(pluginTotalFunctions),
"validate-jsx-nesting": pluginValidateJSX,
"styled-components-a11y": styledA11y,
"ssr-friendly": fixupPluginRules(pluginSSR),
etc: fixupPluginRules(etc),
"safe-jsx": pluginSafeJSX,
"loadable-imports": pluginLoadableImports,
zod: zod,
"@docusaurus": pluginDocusaurus,
},
rules: {
// TypeScript backend rules
...js.configs.all.rules,
...tseslint.configs.recommendedTypeChecked,
...tseslint.configs.recommended.rules,
...tseslint.configs.strictTypeChecked,
...tseslint.configs.strict.rules,
...tseslint.configs.stylisticTypeChecked,
...tseslint.configs.stylistic.rules,
...pluginRegexp.configs["flat/all"].rules,
...importX.flatConfigs.recommended.rules,
...importX.flatConfigs.electron.rules,
...importX.flatConfigs.react.rules,
...importX.flatConfigs.typescript.rules,
...importX.flatConfigs.electron.rules,
...pluginPromise.configs["flat/recommended"].rules,
...pluginUnicorn.configs["flat/all"].rules,
...pluginReact.configs.all.rules,
...reactHooks.configs["recommended-latest"].rules,
...jsxA11y.flatConfigs.strict.rules,
...pluginSonarjs.configs.recommended.rules,
...pluginPerfectionist.configs["recommended-natural"].rules,
...pluginRedos.configs.recommended.rules,
...pluginSecurity.configs.recommended.rules,
...nodePlugin.configs["flat/all"].rules,
...depend.configs["flat/recommended"].rules,
...eslintPluginMath.configs.recommended.rules,
...css.configs.recommended.rules,
...pluginComments.configs.recommended.rules,
...pluginCanonical.configs.recommended.rules,
...eslintReact.configs["recommended-typescript"].rules,
...arrayFunc.configs.all.rules,
...pluginSortClassMembers.configs["flat/recommended"].rules,
...eslintPluginNoUseExtendNative.configs.recommended.rules,
...pluginMicrosoftSdl.configs.required.rules,
...listeners.configs.strict.rules,
...pluginNFDAR.rules,
...pluginJSDoc.rules,
...eslintPluginCommentLength.configs["flat/recommended"].rules,
...pluginRegexLook.configs.recommended.rules,
...pluginJsxPlus.configs.all.rules,
...moduleInterop.configs.recommended.rules,
...pluginTotalFunctions.configs.recommended.rules,
...styledA11y.flatConfigs.strict.rules,
...etc.configs.recommended.rules,
"react/jsx-props-no-multi-spaces": "warn",
"react/jsx-props-no-spread-multi": "warn",
"react/jsx-props-no-spreading": "off",
"react/jsx-filename-extension": ["error", { extensions: [".tsx"] }], // Enforce .tsx for JSX files
"total-functions/require-strict-mode": "off",
"react/react-in-jsx-scope": "off",
"react/no-multi-comp": "off",
"react/jsx-no-literals": "off",
"react/jsx-max-depth": "off",
"react/forbid-component-props": "off",
"no-lookahead-lookbehind-regexp/no-lookahead-lookbehind-regexp":
"off",
"css/no-invalid-properties": "off",
// Docusaurus Rules
"@docusaurus/string-literal-i18n-messages": "off",
"@docusaurus/no-untranslated-text": "off",
"@docusaurus/no-html-links": "warn",
"@docusaurus/prefer-docusaurus-heading": "warn",
// Disable problematic rules for Docusaurus
"react/function-component-definition": "off", // Allow Docusaurus component patterns
"react/prefer-read-only-props": "off", // Allow mutable props in Docusaurus components
"react/prop-types": "off", // TypeScript provides type checking
"sonarjs/function-return-type": "off", // Allow flexible return types in Docusaurus
"perfectionist/sort-imports": "off", // Will handle this manually to avoid conflicts
"react/jsx-sort-props": "off", // Allow flexible prop ordering in Docusaurus
"perfectionist/sort-jsx-props": "off", // Allow flexible JSX prop ordering
"react-hooks-addons/no-unused-deps": "warn",
"comment-length/limit-single-line-comments": [
"warn",
{
mode: "compact-on-overflow",
maxLength: 120,
logicalWrap: true,
ignoreUrls: true,
ignoreCommentsWithCode: true,
tabSize: 2,
},
],
"comment-length/limit-multi-line-comments": [
"warn",
{
mode: "compact-on-overflow",
maxLength: 120,
logicalWrap: true,
ignoreUrls: true,
ignoreCommentsWithCode: true,
tabSize: 2,
},
],
"zod/prefer-enum": "error",
"zod/require-strict": "error",
"loadable-imports/sort": "error",
"safe-jsx/jsx-explicit-boolean": "error",
"etc/no-internal": "off",
"etc/no-t": "off",
"etc/no-const-enum": "warn",
"etc/no-misused-generics": "warn",
"etc/prefer-interface": "warn",
"etc/throw-error": "warn",
"ssr-friendly/no-dom-globals-in-module-scope": "error",
"ssr-friendly/no-dom-globals-in-constructor": "error",
"ssr-friendly/no-dom-globals-in-react-cc-render": "error",
"ssr-friendly/no-dom-globals-in-react-fc": "error",
"validate-jsx-nesting/no-invalid-jsx-nesting": "error",
"total-functions/no-unsafe-type-assertion": "off",
"total-functions/no-unsafe-readonly-mutable-assignment": "off",
"total-functions/no-partial-division": "off",
"total-functions/no-partial-url-constructor": "off",
"no-constructor-bind/no-constructor-bind": "error",
"no-constructor-bind/no-constructor-state": "error",
"one-var": "off",
"no-magic-numbers": "off",
"func-style": "off",
"capitalized-comments": "off",
"class-methods-use-this": "off",
"sort-imports": "off",
"no-inline-comments": "off",
"require-await": "off",
"no-ternary": "off",
"max-lines": "off",
"id-length": "off",
"max-lines-per-function": "off",
"max-statements": "off",
"max-params": "off",
"sort-keys": "off",
"dot-notation": "off",
"no-console": "off",
"no-plusplus": "off",
"no-undefined": "off",
"no-void": "off",
"require-unicode-regexp": "off",
"prefer-arrow-callback": "off",
"no-undef-init": "off",
"object-shorthand": "off",
camelcase: "off",
"max-classes-per-file": "off",
"deprecation/deprecation": "error",
"no-explicit-type-exports/no-explicit-type-exports": "error",
"neverthrow/must-use-result": "error",
"format-sql/format": "warn",
"eslint-plugin-toplevel/no-toplevel-var": "error",
"eslint-plugin-toplevel/no-toplevel-let": "error",
"eslint-plugin-toplevel/no-toplevel-side-effect": "off",
"no-unawaited-dot-catch-throw/enforce-no-unawaited-dot-catch-throw":
"error",
"no-unary-plus/no-unary-plus": "error",
// Note: granular-selectors plugin rules need to be added manually since
// Note: The plugin config are not available after fixupPluginRules wrapping (Below)
"granular-selectors/granular-selectors": "error",
"eslint-plugin-goodeffects/enforceNamedEffectCallbacks": "error",
"usememo-recommendations/detect-heavy-operations": "warn",
"import-zod/prefer-zod-namespace": "error",
// "clean-code/feature-envy": "error",
// "clean-code/exception-handling": "error",
"function-name/starts-with-verb": [
"error",
{
whitelist: [
"success",
"all",
"supports",
"safe",
"timeout",
"with",
"cleanup",
"deep",
"handler",
"component",
"typed",
"persist",
"invalidate",
"bulk",
"evict",
"migrate",
"rows",
"row",
"settings",
"shutdown",
"configure",
"rollback",
"prune",
"upsert",
"exists",
"history",
"increment",
],
},
],
"@metamask/design-tokens/no-deprecated-classnames": [
"warn",
{
"bg-opacity-*": "Use opacity modifiers like 'bg-black/50'.",
"text-opacity-*":
"Use opacity modifiers like 'text-black/50'.",
"border-opacity-*":
"Use opacity modifiers like 'border-black/50'.",
"divide-opacity-*":
"Use opacity modifiers like 'divide-black/50'.",
"ring-opacity-*":
"Use opacity modifiers like 'ring-black/50'.",
"placeholder-opacity-*":
"Use opacity modifiers like 'placeholder-black/50'.",
"flex-shrink-*": "Use 'shrink-*' instead.",
"flex-grow-*": "Use 'grow-*' instead.",
"overflow-ellipsis": "Use 'text-ellipsis' instead.",
"decoration-slice": "Use 'box-decoration-slice' instead.",
"decoration-clone": "Use 'box-decoration-clone' instead.",
"shadow-sm": "Use 'shadow-xs' instead.",
shadow: "Use 'shadow-sm' instead.",
"drop-shadow-sm": "Use 'drop-shadow-xs' instead.",
"drop-shadow": "Use 'drop-shadow-sm' instead.",
"blur-sm": "Use 'blur-xs' instead.",
blur: "Use 'blur-sm' instead.",
"backdrop-blur-sm": "Use 'backdrop-blur-xs' instead.",
"backdrop-blur": "Use 'backdrop-blur-sm' instead.",
"rounded-sm": "Use 'rounded-xs' instead.",
rounded: "Use 'rounded-sm' instead.",
"outline-none": "Use 'outline-hidden' instead.",
ring: "Use 'ring-3' instead.",
},
],
"@metamask/design-tokens/prefer-theme-color-classnames": "error",
"@metamask/design-tokens/color-no-hex": "off",
"sql-template/no-unsafe-query": "error",
"@jcoreio/implicit-dependencies/no-implicit": [
"error",
{
ignore: [
"@shared",
"electron-devtools-installer",
"electron",
"@site",
"@site/src",
"@theme",
"@docusaurus",
],
},
],
"observers/no-missing-unobserve-or-disconnect": "error",
"observers/matching-unobserve-target": "error",
"istanbul/no-ignore-file": "error",
"istanbul/prefer-ignore-reason": "error",
"sort-destructure-keys/sort-destructure-keys": "off",
"@eslint-react/naming-convention/component-name": "warn",
"@eslint-react/naming-convention/context-name": "warn",
"@eslint-react/naming-convention/use-state": "warn",
"sort-class-members/sort-class-members": [
"warn",
{
accessorPairPositioning: "together",
stopAfterFirstProblem: false,
sortInterfaces: true,
order: [
"[static-properties]",
"[properties]",
"[conventional-private-properties]",
"[arrow-function-properties]",
"[everything-else]",
"[accessor-pairs]",
"[getters]",
"[setters]",
"[static-methods]",
"[async-methods]",
"[methods]",
"[conventional-private-methods]",
],
},
],
"perfectionist/sort-classes": "off",
"perfectionist/sort-modules": [
"off",
{
type: "alphabetical",
order: "asc",
ignoreCase: true,
specialCharacters: "keep",
partitionByComment: false,
partitionByNewLine: false,
newlinesBetween: "ignore",
groups: [
"declare-enum",
"declare-export-enum",
"enum",
"export-enum",
"declare-interface",
"declare-export-interface",
"declare-default-interface",
"export-declare-interface",
"default-interface",
"export-default-interface",
"interface",
"export-interface",
"declare-type",
"declare-export-type",
"type",
"export-type",
"declare-class",
"declare-export-class",
"declare-default-class",
"declare-default-decorated-class",
"declare-default-export-class",
"declare-default-export-decorated-class",
"export-declare-class",
"export-declare-decorated-class",
"export-default-class",
"export-default-decorated-class",
"default-class",
"default-decorated-class",
"class",
"export-class",
"decorated-class",
"export-decorated-class",
"declare-function",
"declare-async-function",
"declare-export-function",
"declare-export-async-function",
"declare-default-function",
"declare-default-async-function",
"declare-default-export-function",
"declare-default-export-async-function",
"export-declare-function",
"export-declare-async-function",
"export-default-function",
"export-default-async-function",
"default-function",
"default-async-function",
"function",
"async-function",
"export-function",
"export-async-function",
],
customGroups: [],
},
],
"xss/no-location-href-assign": "error",
"canonical/destructuring-property-newline": "off",
"canonical/export-specifier-newline": "off",
"canonical/filename-match-exported": "off",
"canonical/filename-match-regex": "off", // Taken care of by unicorn rules
"canonical/filename-no-index": "off",
"canonical/import-specifier-newline": "off",
"canonical/no-barrel-import": "error",
"canonical/no-export-all": "error",
"canonical/no-re-export": "warn",
"canonical/no-reassign-imports": "error",
"canonical/prefer-inline-type-import": "off",
"canonical/prefer-use-mount": "warn",
"canonical/sort-react-dependencies": "warn",
"canonical/prefer-import-alias": [
"error",
{
aliases: [
{
alias: "@shared/",
matchParent: path.resolve(import.meta.dirname),
matchPath: "^shared/",
maxRelativeDepth: 0,
},
],
},
],
"ex/no-unhandled": "warn",
"no-unsanitized/method": "error",
"no-unsanitized/property": "error",
"n/file-extension-in-import": "off", // Allow missing file extensions for imports
"n/no-missing-file-extension": "off", // Allow missing file extensions for imports
"n/no-missing-import": "off", // Allow missing imports for dynamic imports
"n/no-unsupported-features/es-syntax": "off", // Allow modern ES2024+ syntax
// "write-good-comments/write-good-comments": "warn",
"unicorn/no-null": "off", // Null is common in SQLite and IPC
"unicorn/prefer-global-this": "off", // Not suitable for Electron
"unicorn/prevent-abbreviations": "off", // Too many false positives
"unicorn/prefer-spread": "off", // Prefer Array.From for readability
// Node.js specific
complexity: "off",
// Core quality rules
// "no-console": "warn", // Allow in development, but warn - DISABLED FOR NOW
"consistent-return": "warn",
"no-debugger": "error",
"no-duplicate-imports": [
"error",
{
allowSeparateTypeImports: true,
},
],
"prefer-const": "error",
"prefer-template": "warn",
curly: ["error", "all"],
eqeqeq: ["error", "always"],
// Code spacing and formatting rules
"lines-around-comment": [
"error",
{
beforeBlockComment: true,
afterBlockComment: false,
beforeLineComment: true,
afterLineComment: false,
allowBlockStart: true,
allowBlockEnd: false,
allowObjectStart: true,
allowObjectEnd: false,
allowArrayStart: true,
allowArrayEnd: false,
allowClassStart: true,
allowClassEnd: false,
applyDefaultIgnorePatterns: true,
ignorePattern: String.raw`^\s*@`, // Ignore TSDoc tags like @param, @returns
},
],
"lines-between-class-members": [
"error",
"always",
{
exceptAfterSingleLine: false,
},
],
"padding-line-between-statements": [
"error",
{
blankLine: "always",
prev: "function",
next: "*",
},
{
blankLine: "always",
prev: "*",
next: "function",
},
{
blankLine: "always",
prev: "class",
next: "*",
},
{
blankLine: "always",
prev: "*",
next: "class",
},
],
"putout/align-spaces": "off",
"putout/array-element-newline": "off",
"putout/destructuring-as-function-argument": "off",
"putout/function-declaration-paren-newline": "off",
"putout/long-properties-destructuring": "off",
"putout/multiple-properties-destructuring": "off",
"putout/newline-function-call-arguments": "off",
"putout/object-property-newline": "error",
"putout/objects-braces-inside-array": "error",
"putout/single-property-destructuring": "off",
// Import management
"unused-imports/no-unused-imports": "error",
"unused-imports/no-unused-vars": [
"warn",
{
vars: "all",
varsIgnorePattern: "^_",
args: "after-used",
argsIgnorePattern: "^_",
},
],
// Architecture boundaries for Electron
"boundaries/element-types": [
"error",
{
default: "disallow",
rules: [
{ from: "events", allow: ["types"] },
{
from: "main",
allow: [
"managers",
"services",
"utils",
"events",
"types",
],
},
{
from: "managers",
allow: [
"services",
"utils",
"events",
"types",
],
},
{
from: "preload",
allow: ["utils", "types"],
},
{
from: "services",
allow: [
"services",
"utils",
"types",
],
},
{ from: "types", allow: [] },
{
from: "utils",
allow: [
"managers",
"services",
"utils",
"events",
"types",
],
},
{ from: "utils", allow: ["types"] },
],
},
],
// Backend-specific unicorn rules
"unicorn/filename-case": [
"warn",
{
cases: {
camelCase: true,
pascalCase: true, // Service classes
},
},
],
"unicorn/no-keyword-prefix": [
"error",
{
disallowedPrefixes: [
"interface",
"type",
"enum",
],
checkProperties: false,
},
],
"unicorn/no-array-callback-reference": "off", // Conflicts with React
"unicorn/no-array-for-each": "off", // ForEach is fine
"unicorn/no-negated-condition": "warn", // Sometimes clearer
"unicorn/prefer-includes": "warn",
"unicorn/prefer-string-slice": "warn",
"unicorn/prefer-string-starts-ends-with": "warn",
"unicorn/prefer-ternary": "off", // Can hurt readability
"unicorn/prefer-module": "warn", // CommonJS required for Electron
"unicorn/prefer-node-protocol": "error", // Enforce for backend
"unicorn/prefer-top-level-await": "off", // Not suitable for Electron main
// Security for backend
"redos/no-vulnerable": "error",
"security/detect-non-literal-fs-filename": "error",
"security/detect-non-literal-require": "error",
"security/detect-non-literal-regexp": "warn",
"security/detect-object-injection": "off",
// Documentation
"tsdoc/syntax": "warn",
// Allow more flexibility for backend patterns
"@typescript-eslint/no-explicit-any": "warn",
"functional/functional-parameters": "off",
"functional/immutable-data": "off",
"functional/no-class-inheritance": "off", // Classes are common in Electron services
"functional/no-classes": "off", // Classes are common in Electron services
"functional/no-conditional-statement": "off",
"functional/no-conditional-statements": "off",
"functional/no-expression-statements": "off",
"functional/no-let": "off",
"functional/no-loop-statements": "off",
"functional/no-mixed-types": "off", // Mixed types are common in Electron services
"functional/no-return-void": "off",
"functional/no-throw-statements": "off", // Throwing errors is common in Electron
"functional/prefer-immutable-types": "off",
// Function and type safety rules (same as frontend)
"@typescript-eslint/consistent-type-assertions": "error",
"@typescript-eslint/no-restricted-types": [
"error",
{
types: {
Function: {
message: [
"The `Function` type accepts any function-like value.",
"It provides no type safety when calling the function, which can be a common source of bugs.",
"If you are expecting the function to accept certain arguments, you should explicitly define the function shape.",
"Use '(...args: unknown[]) => unknown' for generic handlers or define specific function signatures.",
].join("\n"),
},
},
},
],
"@typescript-eslint/no-empty-object-type": "error",
"@typescript-eslint/no-unsafe-function-type": "error",
"@typescript-eslint/no-wrapper-object-types": "error",
"@typescript-eslint/prefer-function-type": "error",
"@typescript-eslint/no-empty-function": [
"error",
{
allow: ["arrowFunctions"], // Allow empty arrow functions for React useEffect cleanup
},
],
"prettier/prettier": ["warn", { usePrettierrc: true }],
// Advanced type-checked rules for backend async safety and runtime error prevention
"@typescript-eslint/no-floating-promises": [
"error",
{
ignoreVoid: true, // Allow void for intentionally ignored promises
ignoreIIFE: false, // Catch floating IIFEs which can cause issues in Node.js
},
],
"@typescript-eslint/await-thenable": "error", // Prevent awaiting non-promises
"@typescript-eslint/no-misused-promises": [
"error",
{
checksConditionals: true, // Check if Promises used in conditionals
checksSpreads: true, // Check Promise spreads
checksVoidReturn: true, // Critical for Electron IPC handlers
},
],
"@typescript-eslint/require-await": "error", // Functions marked async must use await
"@typescript-eslint/return-await": ["error", "in-try-catch"], // Proper await handling in try-catch
// Enhanced type safety for backend services
"@typescript-eslint/no-unnecessary-type-assertion": "error", // Remove redundant type assertions
"@typescript-eslint/no-unsafe-argument": "warn", // Warn on passing any to typed parameters
"@typescript-eslint/no-unsafe-assignment": "warn", // Warn on unsafe assignments to any
"@typescript-eslint/no-unsafe-call": "warn", // Warn on calling any-typed functions
"@typescript-eslint/no-unsafe-member-access": "warn", // Warn on accessing any-typed properties
"@typescript-eslint/no-unsafe-return": "warn", // Warn on returning any from typed functions
// Backend-specific type safety
"@typescript-eslint/prefer-readonly": "warn", // Prefer readonly for service class properties
"@typescript-eslint/switch-exhaustiveness-check": "error", // Ensure switch statements are exhaustive
// Null safety for backend operations
"@typescript-eslint/no-unnecessary-condition": [
"warn",
{
allowConstantLoopConditions: true, // Allow while(true) patterns in services
},
],
"@typescript-eslint/prefer-nullish-coalescing": [
"error",
{
ignoreConditionalTests: false, // Check conditionals for nullish coalescing opportunities
ignoreMixedLogicalExpressions: false, // Check complex logical expressions
},
],
"@typescript-eslint/prefer-optional-chain": "error", // Use optional chaining instead of logical AND,
"@typescript-eslint/no-inferrable-types": "off", // Allow explicit types for React components
"@typescript-eslint/array-type": [
"error",
{ default: "array-simple" },
], // Prefer T[] for simple types, Array<T> for complex types
"@typescript-eslint/adjacent-overload-signatures": "warn",
"@typescript-eslint/ban-ts-comment": "warn",
"@typescript-eslint/ban-tslint-comment": "warn",
"@typescript-eslint/class-literal-property-style": "warn",
"@typescript-eslint/class-methods-use-this": "off",
"@typescript-eslint/consistent-generic-constructors": "warn",
"@typescript-eslint/consistent-indexed-object-style": "warn",
"@typescript-eslint/consistent-return": "warn",
"@typescript-eslint/consistent-type-definitions": "warn",
"@typescript-eslint/consistent-type-exports": "warn",
"@typescript-eslint/consistent-type-imports": "warn",
"@typescript-eslint/default-param-last": "warn",
"@typescript-eslint/dot-notation": "warn",
"@typescript-eslint/explicit-function-return-type": [
"warn",
{
allowConciseArrowFunctionExpressionsStartingWithVoid: false,
allowDirectConstAssertionInArrowFunctions: true,
allowedNames: [],
allowExpressions: false,
allowFunctionsWithoutTypeParameters: false,
allowHigherOrderFunctions: true,
allowIIFEs: false,
allowTypedFunctionExpressions: true,
},
],
"@typescript-eslint/explicit-member-accessibility": "warn",
"@typescript-eslint/explicit-module-boundary-types": "warn",
"init-declarations": "off",
"@typescript-eslint/init-declarations": "warn",
"@typescript-eslint/max-params": "off",
"@typescript-eslint/member-ordering": "off",
"@typescript-eslint/method-signature-style": "warn",
"@typescript-eslint/naming-convention": "off",
"@typescript-eslint/no-array-constructor": "warn",
"@typescript-eslint/no-array-delete": "warn",
"@typescript-eslint/no-base-to-string": "warn",
"@typescript-eslint/no-confusing-non-null-assertion": "warn",
"@typescript-eslint/no-confusing-void-expression": "warn",
"@typescript-eslint/no-deprecated": "warn",
"@typescript-eslint/no-dupe-class-members": "warn",
"@typescript-eslint/no-duplicate-enum-values": "warn",
"@typescript-eslint/no-duplicate-type-constituents": "warn",
"@typescript-eslint/no-dynamic-delete": "warn",
"@typescript-eslint/no-extra-non-null-assertion": "warn",
"@typescript-eslint/no-extraneous-class": "warn",
"@typescript-eslint/no-for-in-array": "warn",
"@typescript-eslint/no-implied-eval": "warn",
// Keep enabled: Helps with bundle optimization and makes type vs runtime imports clearer.
// Can be resolved incrementally as warnings.
"@typescript-eslint/no-import-type-side-effects": "warn",
"@typescript-eslint/no-invalid-this": "warn",
"@typescript-eslint/no-invalid-void-type": "warn",
"@typescript-eslint/no-loop-func": "warn",
"@typescript-eslint/no-magic-numbers": "off",
"@typescript-eslint/no-meaningless-void-operator": "warn",
"@typescript-eslint/no-misused-new": "warn",
"@typescript-eslint/no-misused-spread": "warn",
"@typescript-eslint/no-mixed-enums": "warn",
"@typescript-eslint/no-namespace": "warn",
"@typescript-eslint/no-non-null-asserted-nullish-coalescing":
"warn",
"@typescript-eslint/no-non-null-asserted-optional-chain": "warn",
"@typescript-eslint/no-redeclare": "warn",
"@typescript-eslint/no-redundant-type-constituents": "warn",
"@typescript-eslint/no-require-imports": "warn",
"@typescript-eslint/no-restricted-imports": "warn",
"@typescript-eslint/no-shadow": "warn",
"@typescript-eslint/no-this-alias": "warn",
"@typescript-eslint/no-unnecessary-boolean-literal-compare": "warn",
"@typescript-eslint/no-unnecessary-parameter-property-assignment":
"warn",
"@typescript-eslint/no-unnecessary-qualifier": "warn",
"@typescript-eslint/no-unnecessary-template-expression": "warn",
"@typescript-eslint/no-unnecessary-type-arguments": "warn",
"@typescript-eslint/no-unnecessary-type-constraint": "warn",
"@typescript-eslint/no-unnecessary-type-conversion": "warn",
"@typescript-eslint/no-unnecessary-type-parameters": "warn",
"@typescript-eslint/no-unsafe-declaration-merging": "warn",
"@typescript-eslint/no-unsafe-enum-comparison": "warn",
"@typescript-eslint/no-unsafe-type-assertion": "warn",
"@typescript-eslint/no-unsafe-unary-minus": "warn",
"@typescript-eslint/no-unused-expressions": "warn",
"@typescript-eslint/no-unused-vars": "warn",
// Disabled: Function declarations are hoisted in JS/TS, and this rule creates unnecessary constraints
// For Electron projects that often organize helper functions after main functions for better readability
"@typescript-eslint/no-use-before-define": "off",
"@typescript-eslint/no-useless-constructor": "warn",
"@typescript-eslint/no-useless-empty-export": "warn",
"@typescript-eslint/non-nullable-type-assertion-style": "warn",
"@typescript-eslint/only-throw-error": "warn",
"@typescript-eslint/parameter-properties": "warn",
"@typescript-eslint/prefer-as-const": "warn",
"@typescript-eslint/prefer-destructuring": "warn",
"@typescript-eslint/prefer-enum-initializers": "warn",
"@typescript-eslint/prefer-find": "warn",
"@typescript-eslint/prefer-for-of": "warn",
"@typescript-eslint/prefer-includes": "warn",
"@typescript-eslint/prefer-literal-enum-member": "warn",
"@typescript-eslint/prefer-namespace-keyword": "warn",
"@typescript-eslint/prefer-promise-reject-errors": "warn",
// Disabled: Too noisy for Electron projects with React/Zustand stores.
// Readonly parameters are often impractical and TypeScript already provides strong typing.
"@typescript-eslint/prefer-readonly-parameter-types": "off",
"@typescript-eslint/prefer-reduce-type-parameter": "warn",
"@typescript-eslint/prefer-regexp-exec": "warn",
"@typescript-eslint/prefer-return-this-type": "warn",
"@typescript-eslint/prefer-string-starts-ends-with": "warn",
// Configured: Allows non-async functions that return promises (like utility wrappers around Promise.all)
// But encourages async for most cases. This is more flexible for Electron projects.
"@typescript-eslint/promise-function-async": [
"warn",
{
allowAny: true,
allowedPromiseNames: ["Promise"],
checkArrowFunctions: false,
},
],
"@typescript-eslint/related-getter-setter-pairs": "warn",
"@typescript-eslint/require-array-sort-compare": "warn",
"@typescript-eslint/restrict-plus-operands": "warn",
"@typescript-eslint/restrict-template-expressions": "warn",
"@typescript-eslint/strict-boolean-expressions": "off",
"@typescript-eslint/triple-slash-reference": "warn",
"@typescript-eslint/unbound-method": "warn",
"@typescript-eslint/unified-signatures": "warn",
"@typescript-eslint/use-unknown-in-catch-callback-variable": "warn",
// RegExp
"regexp/grapheme-string-literal": "warn",
"regexp/hexadecimal-escape": "warn",
"regexp/letter-case": "warn",
"regexp/no-control-character": "warn",
"regexp/no-octal": "warn",
"regexp/no-standalone-backslash": "warn",
"regexp/no-super-linear-move": "warn",
"regexp/prefer-escape-replacement-dollar-char": "warn",
"regexp/prefer-lookaround": "warn",
"regexp/prefer-named-backreference": "warn",
"regexp/prefer-named-capture-group": "warn",
"regexp/prefer-named-replacement": "warn",
"regexp/prefer-quantifier": "warn",
"regexp/prefer-regexp-exec": "warn",
"regexp/prefer-regexp-test": "warn",
"regexp/prefer-result-array-groups": "warn",
"regexp/require-unicode-regexp": "off",
"regexp/require-unicode-sets-regexp": "warn",
"regexp/sort-alternatives": "warn",
"regexp/sort-character-class-elements": "off",
"regexp/unicode-escape": "warn",
"regexp/unicode-property": "warn",
// Import Rules
"import-x/consistent-type-specifier-style": "off",
"import-x/default": "warn",
"import-x/dynamic-import-chunkname": "warn",
"import-x/export": "warn",
"import-x/exports-last": "off",
"import-x/extensions": "warn",
"import-x/first": "warn",
"import-x/group-exports": "off",
"import-x/max-dependencies": "off",
"import-x/namespace": "warn",
"import-x/newline-after-import": "warn",
"import-x/no-absolute-path": "warn",
"import-x/no-amd": "warn",
"import-x/no-anonymous-default-export": "warn",
"import-x/no-commonjs": "warn",
"import-x/no-cycle": "warn",
"import-x/no-default-export": "off",
"import-x/no-deprecated": "warn",
"import-x/no-duplicates": "warn",
"import-x/no-dynamic-require": "warn",
"import-x/no-empty-named-blocks": "warn",
"import-x/no-extraneous-dependencies": "warn",
"import-x/no-import-module-exports": "warn",
"import-x/no-internal-modules": "off",
"import-x/no-mutable-exports": "warn",
"import-x/no-named-as-default": "off",
"import-x/no-named-as-default-member": "off",
"import-x/no-named-default": "warn",
"import-x/no-named-export": "off",
"import-x/no-namespace": "off",
"import-x/no-nodejs-modules": "off", // Allow Node.js modules for Electron backend
"import-x/no-relative-packages": "warn",
"import-x/no-relative-parent-imports": "off",
"import-x/no-rename-default": "warn",
"import-x/no-restricted-paths": "warn",
"import-x/no-self-import": "warn",
"import-x/no-unresolved": "off",
"import-x/no-unused-modules": "warn",
"import-x/no-useless-path-segments": "warn",
"import-x/no-webpack-loader-syntax": "warn",
"import-x/order": "off", // Conflicts with other rules
"import-x/prefer-default-export": "off",
"import-x/prefer-namespace-import": "warn",
"import-x/unambiguous": "warn",
// Accessibility (jsx-a11y)
"jsx-a11y/lang": "warn",
"jsx-a11y/no-aria-hidden-on-focusable": "warn",
"jsx-a11y/prefer-tag-over-role": "warn",
// Math
"math/abs": "warn",
"math/prefer-exponentiation-operator": "warn",
"math/prefer-math-sum-precise": "warn",
// Node
"n/callback-return": "warn",
"n/exports-style": "warn",
"n/global-require": "warn",
"n/handle-callback-err": "warn",
"n/no-callback-literal": "warn",
"n/no-mixed-requires": "warn",
"n/no-new-require": "warn",
"n/no-path-concat": "warn",
"n/no-process-env": "warn",
"n/no-restricted-import": "warn",
"n/no-restricted-require": "warn",
"n/no-sync": "warn",
"n/no-top-level-await": "warn",
"n/prefer-global/buffer": "warn",
"n/prefer-global/console": "warn",
"n/prefer-global/process": "warn",
"n/prefer-global/text-decoder": "warn",
"n/prefer-global/text-encoder": "warn",
"n/prefer-global/url": "warn",
"n/prefer-global/url-search-params": "warn",
"n/prefer-node-protocol": "warn",
"n/prefer-promises/dns": "warn",
"n/prefer-promises/fs": "warn",
// Promise
"promise/no-multiple-resolved": "warn",
"promise/prefer-await-to-callbacks": "off",
"promise/prefer-await-to-then": "warn",
"promise/prefer-catch": "warn",
"promise/spec-only": "warn",
},
},
// Docusaurus CSS
{
files: ["docs/docusaurus/**/*.css"],
ignores: [
"docs/docusaurus/docs/**",
"docs/docusaurus/build/**",
"docs/docusaurus/.docusaurus/**",
],
language: "css/css",
languageOptions: {
tolerant: true,
},
settings: {},
plugins: {
css: css,
"undefined-css-classes": pluginUndefinedCss,
"no-hardcoded-strings": pluginNoHardcoded,
"@docusaurus": pluginDocusaurus,
"css-modules": pluginCssModules,
},
rules: {
...css.configs.recommended.rules,
...pluginUndefinedCss.configs.recommended.rules,
...pluginCssModules.configs.recommended.rules,
// Docusaurus Rules
"@docusaurus/string-literal-i18n-messages": "off",
"@docusaurus/no-untranslated-text": "off",
"@docusaurus/no-html-links": "warn",
"@docusaurus/prefer-docusaurus-heading": "warn",
"undefined-css-classes/no-undefined-css-classes": "warn",
// CSS Rules - Allow Docusaurus CSS variables and !important
"css/no-invalid-properties": "off", // Disable for Docusaurus CSS custom properties
"css/no-important": "off", // Allow !important in Docusaurus CSS
// "no-hardcoded-strings/no-hardcoded-strings": [
// "warn",
// {
// allowedFunctionNames: ["t", "translate", "i18n"],
// ignoreStrings: ["OK", "Cancel"],
// ignorePatterns: [/^[\s\d\-:]+$/v], // Ignore dates, times, numbers
// },
// ],
},
},
// TypeScript frontend files (React + Zustand)
{
files: [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.mts",
"src/**/*.cts",
],
ignores: [
"**/*.spec.{ts,tsx,mts,cts}",
"**/*.test.{ts,tsx,mts,cts}",
"shared/**/*.spec.{ts,tsx,mts,cts}",
"shared/**/*.test.{ts,tsx,mts,cts}",
"shared/test/**/*.{ts,tsx,mts,cts}",
"src/test/**/*.{ts,tsx,mts,cts}",
],
languageOptions: {
parser: tseslintParser,
parserOptions: {
ecmaVersion: "latest",
project: "tsconfig.json",
sourceType: "module",
tsconfigRootDir: path.resolve(import.meta.dirname),
ecmaFeatures: {
jsx: true,
impliedStrict: true,
},
jsDocParsingMode: "all",
warnOnUnsupportedTypeScriptVersion: true,
},
globals: {
...globals.browser,
...globals.node,
document: "readonly",
globalThis: "readonly",
window: "readonly",
NodeJS: "readonly",
},
},
settings: {
tailwind: {
config: "./tailwind.config.mjs",
},
react: { version: "19" },
"boundaries/elements": [
{ type: "app", pattern: "src/App.tsx" },
{ type: "components", pattern: "src/components/**/*" },
{ type: "stores", pattern: "src/stores/**/*" },
{ type: "hooks", pattern: "src/hooks/**/*" },
{ type: "services", pattern: "src/services/**/*" },
{ type: "theme", pattern: "src/theme/**/*" },
{ type: "utils", pattern: "src/utils/**/*" },
{ type: "types", pattern: "src/types.ts" },
],
n: {
allowModules: [
"electron",
"node",
"electron-devtools-installer",
],
},
"import-x/resolver": {
// You will also need to install and configure the TypeScript resolver
// See also https://github.com/import-js/eslint-import-resolver-typescript#configuration
typescript: true,
node: true,
project: ["tsconfig.json"],
},
"import/resolver": {
// You will also need to install and configure the TypeScript resolver
// See also https://github.com/import-js/eslint-import-resolver-typescript#configuration
typescript: {
alwaysTryTypes: true, // Always try to resolve types under `<root>@types` directory even if it doesn't contain any source code, like `@types/unist`
project: ["tsconfig.json"],
},
},
},
plugins: {
"@typescript-eslint": tseslint,
"jsx-a11y": jsxA11y,
"no-unsanitized": nounsanitized,
"prefer-arrow": pluginPreferArrow,
"react-hooks": reactHooks,
"react-refresh": reactRefresh,
"sort-class-members": pluginSortClassMembers,
"unused-imports": pluginUnusedImports,
"write-good-comments": pluginWriteGood,
boundaries: pluginBoundaries,
compat: pluginCompat,
css: css,
depend: depend,
functional: pluginFunctional,
js: js,
math: eslintPluginMath,
n: nodePlugin,
perfectionist: pluginPerfectionist,
"import-x": importX,
prettier: pluginPrettier,
promise: pluginPromise,
putout: putout,
react: pluginReact,
redos: pluginRedos,
regexp: pluginRegexp,
security: pluginSecurity,
sonarjs: pluginSonarjs,
tailwind: tailwind,
tsdoc: pluginTsdoc,
unicorn: pluginUnicorn,
"eslint-comments": pluginComments,
ex: ex,
canonical: pluginCanonical,
"@eslint-react": eslintReact,
"@eslint-react/dom": eslintReactDom,
"@eslint-react/web-api": eslintReactWeb,
"@eslint-react/hooks-extra": eslintReactHooksExtra,
"react-hooks-addons": reactHooksAddons,
"@eslint-react/naming-convention": eslintReactNamingConvention,
xss: xss,
"array-func": arrayFunc,
"no-use-extend-native": eslintPluginNoUseExtendNative,
"@microsoft/sdl": pluginMicrosoftSdl,
"sort-destructure-keys": pluginSortDestructure,
"react-compiler": reactCompiler,
istanbul: istanbul,
observers: observers,
"@jcoreio/implicit-dependencies": implicitDependencies,
listeners: listeners,
"sql-template": sqlTemplate,
"no-function-declare-after-return": pluginNFDAR,
"require-jsdoc": pluginJSDoc,
"comment-length": eslintPluginCommentLength,
"sort-react-dependency-arrays": pluginSortReactDependency,
"no-lookahead-lookbehind-regexp": pluginRegexLook,
"@metamask/design-tokens": pluginDesignTokens,
"function-name": pluginFunctionNames,
"clean-code": pluginCleanCode,
"filename-export": pluginFilenameExport,
"import-zod": importZod,
"usememo-recommendations": pluginUseMemo,
"eslint-plugin-goodeffects": pluginGoodEffects,
"jsx-plus": pluginJsxPlus,
"no-unary-plus": pluginNoUnary,
"granular-selectors": pluginGranular,
"module-interop": moduleInterop,
"no-unawaited-dot-catch-throw": pluginNoUnwaited,
"eslint-plugin-toplevel": pluginTopLevel,
"format-sql": pluginFormatSQL,
neverthrow: fixupPluginRules(pluginNeverThrow),
"no-explicit-type-exports": pluginNoExplicitTypeExports,
deprecation: fixupPluginRules(pluginDeprecation),
"react-require-testid": pluginReactTest,
"react-useeffect": reactUseEffect,
"no-constructor-bind": pluginNoConstructBind,
"total-functions": fixupPluginRules(pluginTotalFunctions),
"validate-jsx-nesting": pluginValidateJSX,
"styled-components-a11y": styledA11y,
"react-form-fields": pluginReactFormFields,
"react-hook-form": pluginReactHookForm,
"react-prefer-function-component": preferFunctionComponent,
"ssr-friendly": fixupPluginRules(pluginSSR),
"react-perf": reactPerfPlugin,
"@arthurgeron/react-usememo": pluginUseMemo2,
etc: fixupPluginRules(etc),
"safe-jsx": pluginSafeJSX,
"loadable-imports": pluginLoadableImports,
zod: zod,
},
rules: {
// TypeScript rules
...js.configs.all.rules,
...tseslint.configs.recommendedTypeChecked,
...tseslint.configs.recommended.rules,
...tseslint.configs.strictTypeChecked,
...tseslint.configs.strict.rules,
...tseslint.configs.stylisticTypeChecked,
...tseslint.configs.stylistic.rules,
...pluginRegexp.configs["flat/all"].rules,
...reactRefresh.configs.vite.rules,
...importX.flatConfigs.recommended.rules,
...importX.flatConfigs.electron.rules,
...importX.flatConfigs.react.rules,
...importX.flatConfigs.typescript.rules,
...pluginPromise.configs["flat/recommended"].rules,
...pluginUnicorn.configs["flat/all"].rules,
...pluginReact.configs.all.rules,
...reactHooks.configs["recommended-latest"].rules,
...jsxA11y.flatConfigs.strict.rules,
...pluginSonarjs.configs.recommended.rules,
...pluginPerfectionist.configs["recommended-natural"].rules,
...pluginBoundaries.configs.recommended.rules,
...pluginRedos.configs.recommended.rules,
...pluginSecurity.configs.recommended.rules,
...nodePlugin.configs["flat/all"].rules,
...depend.configs["flat/recommended"].rules,
...eslintPluginMath.configs.recommended.rules,
...css.configs.recommended.rules,
...pluginComments.configs.recommended.rules,
...pluginCanonical.configs.recommended.rules,
...eslintReact.configs["recommended-typescript"].rules,
...arrayFunc.configs.all.rules,
...pluginSortClassMembers.configs["flat/recommended"].rules,
...eslintPluginNoUseExtendNative.configs.recommended.rules,
...pluginMicrosoftSdl.configs.required.rules,
...reactCompiler.configs.recommended.rules,
...listeners.configs.strict.rules,
...pluginNFDAR.rules,
...pluginJSDoc.rules,
...eslintPluginCommentLength.configs["flat/recommended"].rules,
...pluginRegexLook.configs.recommended.rules,
...pluginJsxPlus.configs.all.rules,
...moduleInterop.configs.recommended.rules,
...pluginTotalFunctions.configs.recommended.rules,
...styledA11y.flatConfigs.strict.rules,
...pluginReactHookForm.configs.recommended.rules,
...reactPerfPlugin.configs.all.rules,
...etc.configs.recommended.rules,
"react-hooks-addons/no-unused-deps": "warn",
"comment-length/limit-single-line-comments": [
"warn",
{
mode: "compact-on-overflow",
maxLength: 120,
logicalWrap: true,
ignoreUrls: true,
ignoreCommentsWithCode: true,
tabSize: 2,
},
],
"comment-length/limit-multi-line-comments": [
"warn",
{
mode: "compact-on-overflow",
maxLength: 120,
logicalWrap: true,
ignoreUrls: true,
ignoreCommentsWithCode: true,
tabSize: 2,
},
],
"zod/prefer-enum": "error",
"zod/require-strict": "error",
"loadable-imports/sort": "error",
"safe-jsx/jsx-explicit-boolean": "error",
"etc/no-internal": "off",
"etc/no-t": "off",
"etc/no-const-enum": "warn",
"etc/no-misused-generics": "warn",
"etc/prefer-interface": "warn",
"etc/throw-error": "warn",
"@arthurgeron/react-usememo/require-usememo": "error",
"@arthurgeron/react-usememo/require-memo": "off",
"@arthurgeron/react-usememo/require-usememo-children": "off",
"ssr-friendly/no-dom-globals-in-module-scope": "error",
"ssr-friendly/no-dom-globals-in-constructor": "error",
"ssr-friendly/no-dom-globals-in-react-cc-render": "error",
"ssr-friendly/no-dom-globals-in-react-fc": "error",
"react-prefer-function-component/react-prefer-function-component": [
"error",
{ allowComponentDidCatch: false },
],
"react-hook-form/no-use-watch": "error",
"react-form-fields/no-mix-controlled-with-uncontrolled": "error",
"react-form-fields/no-only-value-prop": "error",
"react-form-fields/styled-no-mix-controlled-with-uncontrolled":
"error",
"react-form-fields/styled-no-only-value-prop": "error",
"validate-jsx-nesting/no-invalid-jsx-nesting": "error",
"total-functions/no-unsafe-type-assertion": "off",
"total-functions/no-unsafe-readonly-mutable-assignment": "off",
"total-functions/no-partial-division": "off",
"total-functions/no-partial-url-constructor": "off",
"no-constructor-bind/no-constructor-bind": "error",
"no-constructor-bind/no-constructor-state": "error",
"react-useeffect/no-non-function-return": "error",
"react-require-testid/testid-missing": [
"warn",
{
disableDefaultComponents: [
"a",
"abbr",
"address",
"area",
"article",
"aside",
"audio",
"b",
"base",
"bdi",
"bdo",
"blockquote",
"body",
"br",
"button",
"canvas",
"caption",
"cite",
"code",
"col",
"colgroup",
"data",
"datalist",
"dd",
"del",
"details",
"dfn",
"dialog",
"div",
"dl",
"dt",
"em",
"embed",
"fieldset",
"figcaption",
"figure",
"footer",
"form",
"h1",
"h2",
"h3",
"h4",
"h5",
"h6",
"head",
"header",
"hr",
"html",
"i",
"iframe",
"img",
"input",
"ins",
"kbd",
"label",
"legend",
"li",
"link",
"main",
"map",
"mark",
"meta",
"meter",
"nav",
"noscript",
"object",
"ol",
"optgroup",
"option",
"output",
"p",
"param",
"picture",
"pre",
"progress",
"q",
"rp",
"rt",
"ruby",
"s",
"samp",
"script",
"section",
"select",
"small",
"source",
"span",
"strong",
"style",
"sub",
"summary",
"sup",
"table",
"tbody",
"td",
"template",
"textarea",
"tfoot",
"th",
"thead",
"time",
"title",
"tr",
"track",
"u",
"ul",
"var",
"video",
"wbr",
],
enableComponents: [],
},
],
"one-var": "off",
"no-magic-numbers": "off",
"func-style": "off",
"capitalized-comments": "off",
"class-methods-use-this": "off",
"sort-imports": "off",
"no-inline-comments": "off",
"require-await": "off",
"no-ternary": "off",
"max-lines": "off",
"id-length": "off",
"max-lines-per-function": "off",
"max-statements": "off",
"max-params": "off",
"sort-keys": "off",
"dot-notation": "off",
"no-console": "off",
"no-plusplus": "off",
"no-undefined": "off",
"no-void": "off",
"require-unicode-regexp": "off",
"prefer-arrow-callback": "off",
"no-undef-init": "off",
"object-shorthand": "off",
camelcase: "off",
"max-classes-per-file": "off",
"deprecation/deprecation": "error",
"no-explicit-type-exports/no-explicit-type-exports": "error",
"neverthrow/must-use-result": "error",
"format-sql/format": "warn",
"eslint-plugin-toplevel/no-toplevel-var": "error",
"eslint-plugin-toplevel/no-toplevel-let": "error",
"eslint-plugin-toplevel/no-toplevel-side-effect": "off",
"no-unawaited-dot-catch-throw/enforce-no-unawaited-dot-catch-throw":
"error",
// Note: granular-selectors plugin rules need to be added manually since
// Note: The plugin config are not available after fixupPluginRules wrapping (Below)
"granular-selectors/granular-selectors": "error",
"no-unary-plus/no-unary-plus": "error",
"eslint-plugin-goodeffects/enforceNamedEffectCallbacks": "error",
"usememo-recommendations/detect-heavy-operations": "warn",
"import-zod/prefer-zod-namespace": "error",
// "filename-export/match-named-export": "error",
// "filename-export/match-default-export": "error",
// "clean-code/feature-envy": "error",
// "clean-code/exception-handling": "error",
"function-name/starts-with-verb": [
"error",
{
whitelist: [
"success",
"all",
"supports",
"safe",
"timeout",
"with",
"cleanup",
"deep",
"handler",
"component",
"typed",
"persist",
"invalidate",
"bulk",
"evict",
"migrate",
"rows",
"row",
"settings",
"shutdown",
"configure",
"rollback",
"prune",
"upsert",
"exists",
"history",
"increment",
],
},
],
"@metamask/design-tokens/no-deprecated-classnames": [
"warn",
{
"bg-opacity-*": "Use opacity modifiers like 'bg-black/50'.",
"text-opacity-*":
"Use opacity modifiers like 'text-black/50'.",
"border-opacity-*":
"Use opacity modifiers like 'border-black/50'.",
"divide-opacity-*":
"Use opacity modifiers like 'divide-black/50'.",
"ring-opacity-*":
"Use opacity modifiers like 'ring-black/50'.",
"placeholder-opacity-*":
"Use opacity modifiers like 'placeholder-black/50'.",
"flex-shrink-*": "Use 'shrink-*' instead.",
"flex-grow-*": "Use 'grow-*' instead.",
"overflow-ellipsis": "Use 'text-ellipsis' instead.",
"decoration-slice": "Use 'box-decoration-slice' instead.",
"decoration-clone": "Use 'box-decoration-clone' instead.",
"shadow-sm": "Use 'shadow-xs' instead.",
shadow: "Use 'shadow-sm' instead.",
"drop-shadow-sm": "Use 'drop-shadow-xs' instead.",
"drop-shadow": "Use 'drop-shadow-sm' instead.",
"blur-sm": "Use 'blur-xs' instead.",
blur: "Use 'blur-sm' instead.",
"backdrop-blur-sm": "Use 'backdrop-blur-xs' instead.",
"backdrop-blur": "Use 'backdrop-blur-sm' instead.",
"rounded-sm": "Use 'rounded-xs' instead.",
rounded: "Use 'rounded-sm' instead.",
"outline-none": "Use 'outline-hidden' instead.",
ring: "Use 'ring-3' instead.",
},
],
"@metamask/design-tokens/prefer-theme-color-classnames": "error",
"@metamask/design-tokens/color-no-hex": "error",
"sort-react-dependency-arrays/sort": "error",
"sql-template/no-unsafe-query": "error",
"@jcoreio/implicit-dependencies/no-implicit": [
"error",
{
ignore: [
"@shared",
"electron-devtools-installer",
"electron",
"@site",
"@theme",
"@docusaurus",
],
},
],
"observers/no-missing-unobserve-or-disconnect": "error",
"observers/matching-unobserve-target": "error",
"istanbul/no-ignore-file": "error",
"istanbul/prefer-ignore-reason": "error",
"sort-destructure-keys/sort-destructure-keys": "off",
"@eslint-react/naming-convention/component-name": "warn",
"@eslint-react/naming-convention/context-name": "warn",
"@eslint-react/naming-convention/use-state": "warn",
"sort-class-members/sort-class-members": [
"warn",
{
accessorPairPositioning: "together",
stopAfterFirstProblem: false,
sortInterfaces: true,
order: [
"[static-properties]",
"[properties]",
"[conventional-private-properties]",
"[arrow-function-properties]",
"[everything-else]",
"[accessor-pairs]",
"[getters]",
"[setters]",
"[static-methods]",
"[async-methods]",
"[methods]",
"[conventional-private-methods]",
],
},
],
"perfectionist/sort-classes": "off",
"perfectionist/sort-modules": [
"off",
{
type: "alphabetical",
order: "asc",
ignoreCase: true,
specialCharacters: "keep",
partitionByComment: false,
partitionByNewLine: false,
newlinesBetween: "ignore",
groups: [
"declare-enum",
"declare-export-enum",
"enum",
"export-enum",
"declare-interface",
"declare-export-interface",
"declare-default-interface",
"export-declare-interface",
"default-interface",
"export-default-interface",
"interface",
"export-interface",
"declare-type",
"declare-export-type",
"type",
"export-type",
"declare-class",
"declare-export-class",
"declare-default-class",
"declare-default-decorated-class",
"declare-default-export-class",
"declare-default-export-decorated-class",
"export-declare-class",
"export-declare-decorated-class",
"export-default-class",
"export-default-decorated-class",
"default-class",
"default-decorated-class",
"class",
"export-class",
"decorated-class",
"export-decorated-class",
"declare-function",
"declare-async-function",
"declare-export-function",
"declare-export-async-function",
"declare-default-function",
"declare-default-async-function",
"declare-default-export-function",
"declare-default-export-async-function",
"export-declare-function",
"export-declare-async-function",
"export-default-function",
"export-default-async-function",
"default-function",
"default-async-function",
"function",
"async-function",
"export-function",
"export-async-function",
],
customGroups: [],
},
],
"xss/no-location-href-assign": "error",
"canonical/destructuring-property-newline": "off",
"canonical/export-specifier-newline": "off",
"canonical/filename-match-exported": "warn",
"canonical/filename-match-regex": "off", // Taken care of by unicorn rules
"canonical/filename-no-index": "error",
"canonical/import-specifier-newline": "off",
"canonical/no-barrel-import": "error",
"canonical/no-export-all": "error",
"canonical/no-re-export": "warn",
"canonical/no-reassign-imports": "error",
"canonical/prefer-inline-type-import": "off",
"canonical/prefer-use-mount": "warn",
"canonical/sort-react-dependencies": "warn",
"canonical/prefer-import-alias": [
"error",
{
aliases: [
{
alias: "@shared/",
matchParent: path.resolve(import.meta.dirname),
matchPath: "^shared/",
maxRelativeDepth: 0,
},
],
},
],
"ex/no-unhandled": "warn",
"n/file-extension-in-import": "off", // Allow missing file extensions for imports
"n/no-missing-file-extension": "off", // Allow missing file extensions for imports
"n/no-missing-import": "off", // Allow missing imports for dynamic imports
"n/no-unsupported-features/es-syntax": "off", // Allow modern ES2024+ syntax
"no-unsanitized/method": "error",
"no-unsanitized/property": "error",
// "write-good-comments/write-good-comments": "warn",
"putout/align-spaces": "off",
"putout/array-element-newline": "off",
"putout/destructuring-as-function-argument": "off",
"putout/function-declaration-paren-newline": "off",
"putout/long-properties-destructuring": "off",
"putout/multiple-properties-destructuring": "off",
"putout/newline-function-call-arguments": "off",
"putout/object-property-newline": "error",
"putout/objects-braces-inside-array": "off",
"putout/single-property-destructuring": "off",
"unicorn/prefer-spread": "off",
"unicorn/prefer-global-this": "off", // Not suitable for Electron
"unicorn/prevent-abbreviations": "off", // Too many false positives
"unicorn/no-null": "off", // React commonly uses null for conditional rendering
// Import rules
"import-x/no-unassigned-import": [
"error",
{
allow: ["**/*.css", "**/*.scss"], // Allow CSS imports without assignment
},
],
// Core quality rules
// "no-console": "warn", // Allow in development, but warn - DISABLED FOR NOW
"consistent-return": "warn",
"no-debugger": "error",
"no-duplicate-imports": [
"error",
{
allowSeparateTypeImports: true,
},
],
"prefer-const": "error",
"prefer-template": "warn",
curly: ["error", "all"],
eqeqeq: ["error", "always"],
// Code spacing and formatting rules
"lines-around-comment": [
"error",
{
beforeBlockComment: true,
afterBlockComment: false,
beforeLineComment: true,
afterLineComment: false,
allowBlockStart: true,
allowBlockEnd: false,
allowObjectStart: true,
allowObjectEnd: false,
allowArrayStart: true,
allowArrayEnd: false,
allowClassStart: true,
allowClassEnd: false,
applyDefaultIgnorePatterns: true,
ignorePattern: String.raw`^\s*@`, // Ignore TSDoc tags like @param, @returns
},
],
"lines-between-class-members": [
"error",
"always",
{
exceptAfterSingleLine: false,
},
],
"padding-line-between-statements": [
"error",
{
blankLine: "always",
prev: "function",
next: "*",
},
{
blankLine: "always",
prev: "*",
next: "function",
},
{
blankLine: "always",
prev: "class",
next: "*",
},
{
blankLine: "always",
prev: "*",
next: "class",
},
],
// Import management
"unused-imports/no-unused-imports": "error",
"unused-imports/no-unused-vars": [
"warn",
{
vars: "all",
varsIgnorePattern: "^_",
args: "after-used",
argsIgnorePattern: "^_",
},
],
// React 19 optimized rules
"react/jsx-boolean-value": "warn",
"react/jsx-fragments": ["warn", "syntax"],
"react/jsx-key": "error",
"react/jsx-no-useless-fragment": "warn",
"react/jsx-uses-react": "warn",
"react/no-array-index-key": "warn",
"react/no-unstable-nested-components": "error",
"react/prop-types": "warn",
"react/react-in-jsx-scope": "off",
"react/self-closing-comp": "warn",
// React Hooks
"react-hooks/exhaustive-deps": "warn",
"react-hooks/rules-of-hooks": "error",
// Accessibility
"jsx-a11y/alt-text": "warn",
"jsx-a11y/anchor-is-valid": "warn",
"jsx-a11y/no-autofocus": "warn",
// Code organization and architecture
"boundaries/element-types": [
"error",
{
default: "disallow",
rules: [
{
from: "app",
allow: [
"components",
"stores",
"hooks",
"services",
"theme",
"utils",
"types",
],
},
{
from: "components",
allow: [
"components",
"hooks",
"services",
"theme",
"utils",
"types",
"stores",
],
},
{
from: "hooks",
allow: [
"stores",
"services",
"types",
"utils",
],
},
{
from: "services",
allow: ["types", "utils"],
},
{
from: "stores",
allow: [
"services",
"types",
"utils",
"stores",
"components",
],
},
{ from: "theme", allow: ["types"] },
{ from: "types", allow: [] },
{ from: "utils", allow: ["types"] },
],
},
],
// Optimized Unicorn rules (reduced false positives)
"unicorn/filename-case": [
"warn",
{
cases: {
camelCase: true,
kebabCase: true,
pascalCase: true,
},
},
],
"unicorn/no-keyword-prefix": [
"error",
{
disallowedPrefixes: [
"interface",
"type",
"enum",
],
checkProperties: false,
},
], // Allow "class" prefix for className and other legitimate uses
"unicorn/no-array-callback-reference": "off", // Conflicts with React
"unicorn/no-array-for-each": "off", // ForEach is fine
"unicorn/no-negated-condition": "warn", // Sometimes clearer
"unicorn/prefer-includes": "warn",
"unicorn/prefer-module": "warn", // CommonJS needed for Electron
"unicorn/prefer-node-protocol": "warn",
"unicorn/prefer-string-slice": "warn",
"unicorn/prefer-string-starts-ends-with": "warn",
"unicorn/prefer-ternary": "off", // Can hurt readability
"unicorn/prefer-top-level-await": "off", // Not suitable for React
// Function style preferences - disabled as too aggressive
// "prefer-arrow/prefer-arrow-functions": [
// "warn",
// {
// DisallowPrototype: true,
// SingleReturnOnly: false,
// ClassPropertiesAllowed: false,
// },
// ],
// Security for Frontend
"redos/no-vulnerable": "error",
"security/detect-non-literal-fs-filename": "error",
"security/detect-non-literal-require": "error",
"security/detect-non-literal-regexp": "warn",
"security/detect-object-injection": "off",
// Performance and compatibility
"compat/compat": "off", // Electron supports modern APIs, Opera Mini not a target
// Code style
"prettier/prettier": ["warn", { usePrettierrc: true }],
// Documentation
"tsdoc/syntax": "warn",
// RegExp rules for security and performance
"regexp/no-potentially-useless-backreference": "warn",
"regexp/no-super-linear-backtracking": "error",
"regexp/no-unused-capturing-group": "warn",
"regexp/no-useless-escape": "warn",
"regexp/no-useless-quantifier": "warn",
"regexp/optimal-quantifier-concatenation": "warn",
"regexp/prefer-character-class": "warn",
"regexp/prefer-plus-quantifier": "warn",
"regexp/prefer-star-quantifier": "warn",
// Disable overly strict rules for this project
"@typescript-eslint/no-explicit-any": "warn", // Sometimes needed
"@typescript-eslint/no-non-null-assertion": "warn", // Zustand patterns
"functional/immutable-data": "off",
"functional/no-let": "off", // Let is necessary in many React patterns
// Function and type safety rules
"@typescript-eslint/consistent-type-assertions": "error",
"@typescript-eslint/no-restricted-types": [
"error",
{
types: {
Function: {
message: [
"The `Function` type accepts any function-like value.",
"It provides no type safety when calling the function, which can be a common source of bugs.",
"If you are expecting the function to accept certain arguments, you should explicitly define the function shape.",
"Use '(...args: unknown[]) => unknown' for generic handlers or define specific function signatures.",
].join("\n"),
},
},
},
],
"@typescript-eslint/no-empty-object-type": "error",
"@typescript-eslint/no-unsafe-function-type": "error",
"@typescript-eslint/no-wrapper-object-types": "error",
"@typescript-eslint/prefer-function-type": "error",
"@typescript-eslint/no-empty-function": [
"error",
{
allow: ["arrowFunctions"], // Allow empty arrow functions for React useEffect cleanup
},
],
// Advanced type-checked rules for async safety and runtime error prevention
"@typescript-eslint/no-floating-promises": [
"error",
{
ignoreVoid: true, // Allow void for intentionally ignored promises
ignoreIIFE: false, // Catch floating IIFEs which can cause issues
},
],
"@typescript-eslint/await-thenable": "error", // Prevent awaiting non-promises
"@typescript-eslint/no-misused-promises": [
"error",
{
checksConditionals: true, // Check if Promises used in conditionals
checksVoidReturn: true, // Critical for Electron IPC handlers
checksSpreads: true, // Check Promise spreads
},
],
"@typescript-eslint/require-await": "error", // Functions marked async must use await
"@typescript-eslint/return-await": ["error", "in-try-catch"], // Proper await handling in try-catch
// Enhanced type safety for backend services
"@typescript-eslint/no-unnecessary-type-assertion": "error", // Remove redundant type assertions
"@typescript-eslint/no-unsafe-argument": "warn", // Warn on passing any to typed parameters
"@typescript-eslint/no-unsafe-assignment": "warn", // Warn on unsafe assignments to any
"@typescript-eslint/no-unsafe-call": "warn", // Warn on calling any-typed functions
"@typescript-eslint/no-unsafe-member-access": "warn", // Warn on accessing any-typed properties
"@typescript-eslint/no-unsafe-return": "warn", // Warn on returning any from typed functions
// Backend-specific type safety
"@typescript-eslint/prefer-readonly": "warn", // Prefer readonly for service class properties
"@typescript-eslint/switch-exhaustiveness-check": "error", // Ensure switch statements are exhaustive
// Null safety for backend operations
"@typescript-eslint/no-unnecessary-condition": [
"warn",
{
allowConstantLoopConditions: true, // Allow while(true) patterns in services
},
],
"@typescript-eslint/prefer-nullish-coalescing": [
"error",
{
ignoreConditionalTests: false, // Check conditionals for nullish coalescing opportunities
ignoreMixedLogicalExpressions: false, // Check complex logical expressions
},
],
"@typescript-eslint/prefer-optional-chain": "error", // Use optional chaining instead of logical AND
"@typescript-eslint/no-inferrable-types": "off", // Allow explicit types for React components
"@typescript-eslint/array-type": [
"error",
{ default: "array-simple" },
], // Prefer T[] for simple types, Array<T> for complex types
"@typescript-eslint/adjacent-overload-signatures": "warn",
"@typescript-eslint/ban-ts-comment": "warn",
"@typescript-eslint/ban-tslint-comment": "warn",
"@typescript-eslint/class-literal-property-style": "warn",
"@typescript-eslint/class-methods-use-this": "off",
"@typescript-eslint/consistent-generic-constructors": "warn",
"@typescript-eslint/consistent-indexed-object-style": "warn",
"@typescript-eslint/consistent-return": "warn",
"@typescript-eslint/consistent-type-definitions": "warn",
"@typescript-eslint/consistent-type-exports": "warn",
"@typescript-eslint/consistent-type-imports": "warn",
"@typescript-eslint/default-param-last": "warn",
"@typescript-eslint/dot-notation": "warn",
"@typescript-eslint/explicit-function-return-type": [
"warn",
{
allowConciseArrowFunctionExpressionsStartingWithVoid: false,
allowDirectConstAssertionInArrowFunctions: true,
allowedNames: [],
allowExpressions: false,
allowFunctionsWithoutTypeParameters: false,
allowHigherOrderFunctions: true,
allowIIFEs: false,
allowTypedFunctionExpressions: true,
},
],
"@typescript-eslint/explicit-member-accessibility": "warn",
"@typescript-eslint/explicit-module-boundary-types": "warn",
"init-declarations": "off",
"@typescript-eslint/init-declarations": "warn",
"@typescript-eslint/max-params": "off",
"@typescript-eslint/member-ordering": "off",
"@typescript-eslint/method-signature-style": "warn",
"@typescript-eslint/naming-convention": "off",
"@typescript-eslint/no-array-constructor": "warn",
"@typescript-eslint/no-array-delete": "warn",
"@typescript-eslint/no-base-to-string": "warn",
"@typescript-eslint/no-confusing-non-null-assertion": "warn",
"@typescript-eslint/no-confusing-void-expression": "warn",
"@typescript-eslint/no-deprecated": "warn",
"@typescript-eslint/no-dupe-class-members": "warn",
"@typescript-eslint/no-duplicate-enum-values": "warn",
"@typescript-eslint/no-duplicate-type-constituents": "warn",
"@typescript-eslint/no-dynamic-delete": "warn",
"@typescript-eslint/no-extra-non-null-assertion": "warn",
"@typescript-eslint/no-extraneous-class": "warn",
"@typescript-eslint/no-for-in-array": "warn",
"@typescript-eslint/no-implied-eval": "warn",
// Keep enabled: Helps with bundle optimization and makes type vs runtime imports clearer.
// Can be resolved incrementally as warnings.
"@typescript-eslint/no-import-type-side-effects": "warn",
"@typescript-eslint/no-invalid-this": "warn",
"@typescript-eslint/no-invalid-void-type": "warn",
"@typescript-eslint/no-loop-func": "warn",
"@typescript-eslint/no-magic-numbers": "off",
"@typescript-eslint/no-meaningless-void-operator": "warn",
"@typescript-eslint/no-misused-new": "warn",
"@typescript-eslint/no-misused-spread": "warn",
"@typescript-eslint/no-mixed-enums": "warn",
"@typescript-eslint/no-namespace": "warn",
"@typescript-eslint/no-non-null-asserted-nullish-coalescing":
"warn",
"@typescript-eslint/no-non-null-asserted-optional-chain": "warn",
"@typescript-eslint/no-redeclare": "warn",
"@typescript-eslint/no-redundant-type-constituents": "warn",
"@typescript-eslint/no-require-imports": "warn",
"@typescript-eslint/no-restricted-imports": "warn",
"@typescript-eslint/no-shadow": "warn",
"@typescript-eslint/no-this-alias": "warn",
"@typescript-eslint/no-unnecessary-boolean-literal-compare": "warn",
"@typescript-eslint/no-unnecessary-parameter-property-assignment":
"warn",
"@typescript-eslint/no-unnecessary-qualifier": "warn",
"@typescript-eslint/no-unnecessary-template-expression": "warn",
"@typescript-eslint/no-unnecessary-type-arguments": "warn",
"@typescript-eslint/no-unnecessary-type-constraint": "warn",
"@typescript-eslint/no-unnecessary-type-conversion": "warn",
"@typescript-eslint/no-unnecessary-type-parameters": "warn",
"@typescript-eslint/no-unsafe-declaration-merging": "warn",
"@typescript-eslint/no-unsafe-enum-comparison": "warn",
"@typescript-eslint/no-unsafe-type-assertion": "warn",
"@typescript-eslint/no-unsafe-unary-minus": "warn",
"@typescript-eslint/no-unused-expressions": "warn",
"@typescript-eslint/no-unused-vars": "warn",
// Disabled: Function declarations are hoisted in JS/TS, and this rule creates unnecessary constraints
// For Electron projects that often organize helper functions after main functions for better readability
"@typescript-eslint/no-use-before-define": "warn",
"@typescript-eslint/no-useless-constructor": "warn",
"@typescript-eslint/no-useless-empty-export": "warn",
"@typescript-eslint/non-nullable-type-assertion-style": "warn",
"@typescript-eslint/only-throw-error": "warn",
"@typescript-eslint/parameter-properties": "warn",
"@typescript-eslint/prefer-as-const": "warn",
"@typescript-eslint/prefer-destructuring": "warn",
"@typescript-eslint/prefer-enum-initializers": "warn",
"@typescript-eslint/prefer-find": "warn",
"@typescript-eslint/prefer-for-of": "warn",
"@typescript-eslint/prefer-includes": "warn",
"@typescript-eslint/prefer-literal-enum-member": "warn",
"@typescript-eslint/prefer-namespace-keyword": "warn",
"@typescript-eslint/prefer-promise-reject-errors": "warn",
// Disabled: Too noisy for Electron projects with React/Zustand stores.
// Readonly parameters are often impractical and TypeScript already provides strong typing.
"@typescript-eslint/prefer-readonly-parameter-types": "off",
"@typescript-eslint/prefer-reduce-type-parameter": "warn",
"@typescript-eslint/prefer-regexp-exec": "warn",
"@typescript-eslint/prefer-return-this-type": "warn",
"@typescript-eslint/prefer-string-starts-ends-with": "warn",
// Configured: Allows non-async functions that return promises (like utility wrappers around Promise.all)
// But encourages async for most cases. This is more flexible for Electron projects.
"@typescript-eslint/promise-function-async": [
"warn",
{
allowAny: true,
allowedPromiseNames: ["Promise"],
checkArrowFunctions: false,
},
],
"@typescript-eslint/related-getter-setter-pairs": "warn",
"@typescript-eslint/require-array-sort-compare": "warn",
"@typescript-eslint/restrict-plus-operands": "warn",
"@typescript-eslint/restrict-template-expressions": "warn",
"@typescript-eslint/strict-boolean-expressions": "off",
"@typescript-eslint/triple-slash-reference": "warn",
"@typescript-eslint/unbound-method": "warn",
"@typescript-eslint/unified-signatures": "warn",
"@typescript-eslint/use-unknown-in-catch-callback-variable": "warn",
// React
"react/boolean-prop-naming": "warn",
"react/button-has-type": "warn",
"react/checked-requires-onchange-or-readonly": "warn",
"react/default-props-match-prop-types": "warn",
"react/destructuring-assignment": "warn",
"react/forbid-component-props": "off",
"react/forbid-dom-props": "warn",
"react/forbid-elements": "warn",
"react/forbid-foreign-prop-types": "warn",
"react/forbid-prop-types": "warn",
"react/forward-ref-uses-ref": "warn",
"react/function-component-definition": [
"error",
{
namedComponents: "arrow-function",
unnamedComponents: "arrow-function",
},
], // Enforce consistent arrow function components
"react/hook-use-state": "warn",
"react/iframe-missing-sandbox": "warn",
"react/jsx-child-element-spacing": "warn",
"react/jsx-closing-bracket-location": "warn",
"react/jsx-closing-tag-location": "warn",
"react/jsx-curly-brace-presence": "warn",
"react/jsx-curly-newline": "off",
"react/jsx-curly-spacing": "off",
"react/jsx-equals-spacing": "off",
"react/jsx-filename-extension": ["error", { extensions: [".tsx"] }], // Enforce .tsx for JSX files
"react/jsx-first-prop-new-line": "off",
"react/jsx-handler-names": "warn", // Enforce consistent handler names
"react/jsx-indent": "off",
"react/jsx-indent-props": "off",
"react/jsx-max-depth": ["warn", { max: 7 }], // Warn on deeply nested JSX to encourage component extraction
"react/jsx-max-props-per-line": "off",
"react/jsx-newline": "off",
"react/jsx-no-bind": "warn", // Allow inline functions for development speed
"react/jsx-no-constructed-context-values": "warn",
"react/jsx-no-leaked-render": "warn",
"react/jsx-no-literals": "off",
"react/jsx-no-script-url": "warn",
"react/jsx-one-expression-per-line": "warn",
"react/jsx-pascal-case": "warn",
"react/jsx-props-no-multi-spaces": "warn",
"react/jsx-props-no-spread-multi": "warn",
"react/jsx-props-no-spreading": "off",
"react/jsx-sort-props": "warn",
"react/jsx-tag-spacing": "warn",
"react/jsx-wrap-multilines": "warn",
"react/no-access-state-in-setstate": "warn",
"react/no-adjacent-inline-elements": "warn",
"react/no-arrow-function-lifecycle": "warn",
"react/no-danger": "warn",
"react/no-did-mount-set-state": "warn",
"react/no-did-update-set-state": "warn",
"react/no-invalid-html-attribute": "warn",
"react/no-multi-comp": "warn",
"react/no-namespace": "warn",
"react/no-object-type-as-default-prop": "warn",
"react/no-redundant-should-component-update": "warn",
"react/no-set-state": "warn",
"react/no-this-in-sfc": "warn",
"react/no-typos": "warn",
"react/no-unused-class-component-methods": "warn",
"react/no-unused-prop-types": "warn",
"react/no-unused-state": "warn",
"react/no-will-update-set-state": "warn",
"react/prefer-es6-class": "warn",
"react/prefer-exact-props": "warn",
"react/prefer-read-only-props": "warn",
"react/prefer-stateless-function": "warn",
"react/require-default-props": "off",
"react/require-optimization": "warn",
"react/sort-comp": "warn",
"react/sort-default-props": "warn",
"react/sort-prop-types": "warn",
"react/state-in-constructor": "warn",
"react/static-property-placement": "warn",
"react/style-prop-object": "warn",
"react/void-dom-elements-no-children": "warn",
// RegExp
"regexp/grapheme-string-literal": "warn",
"regexp/hexadecimal-escape": "warn",
"regexp/letter-case": "warn",
"regexp/no-control-character": "warn",
"regexp/no-octal": "warn",
"regexp/no-standalone-backslash": "warn",
"regexp/no-super-linear-move": "warn",
"regexp/prefer-escape-replacement-dollar-char": "warn",
"regexp/prefer-lookaround": "warn",
"regexp/prefer-named-backreference": "warn",
"regexp/prefer-named-capture-group": "warn",
"regexp/prefer-named-replacement": "warn",
"regexp/prefer-quantifier": "warn",
"regexp/prefer-regexp-exec": "warn",
"regexp/prefer-regexp-test": "warn",
"regexp/prefer-result-array-groups": "warn",
"regexp/require-unicode-regexp": "off",
"regexp/require-unicode-sets-regexp": "warn",
"regexp/sort-alternatives": "warn",
"regexp/sort-character-class-elements": "warn",
"regexp/unicode-escape": "warn",
"regexp/unicode-property": "warn",
// // Tailwind CSS
// "tailwind/classnames-order": "warn",
// "tailwind/enforces-negative-arbitrary-values": "warn",
// "tailwind/enforces-shorthand": "warn",
// "tailwind/migration-from-tailwind-2": "warn",
// "tailwind/no-arbitrary-value": "warn",
// "tailwind/no-contradicting-classname": "warn",
// "tailwind/no-custom-classname": "off",
// "tailwind/no-unnecessary-arbitrary-value": "warn",
// CSS
"import-x/no-extraneous-dependencies": "warn",
"import-x/no-import-module-exports": "warn",
"import-x/no-internal-modules": "off",
"import-x/no-mutable-exports": "warn",
"import-x/no-named-as-default": "warn",
"import-x/no-named-as-default-member": "off",
"import-x/no-named-default": "warn",
"import-x/no-named-export": "off",
"import-x/no-namespace": "off",
"import-x/no-nodejs-modules": "error", // Dont allow on frontend or shared
"import-x/no-relative-packages": "warn",
"import-x/no-relative-parent-imports": "off",
"import-x/no-rename-default": "warn",
"import-x/no-restricted-paths": "warn",
"import-x/no-self-import": "warn",
"import-x/no-unresolved": "warn",
"import-x/no-unused-modules": "warn",
"import-x/no-useless-path-segments": "warn",
"import-x/no-webpack-loader-syntax": "warn",
"import-x/order": "off", // Conflicts with other rules
"import-x/prefer-default-export": "off",
"import-x/prefer-namespace-import": "warn",
"import-x/unambiguous": "warn",
// Accessibility (jsx-a11y)
"jsx-a11y/lang": "warn",
"jsx-a11y/no-aria-hidden-on-focusable": "warn",
"jsx-a11y/prefer-tag-over-role": "warn",
// Math
"math/abs": "warn",
"math/prefer-exponentiation-operator": "warn",
"math/prefer-math-sum-precise": "warn",
// Node
"n/callback-return": "warn",
"n/exports-style": "warn",
"n/global-require": "warn",
"n/handle-callback-err": "warn",
"n/no-callback-literal": "warn",
"n/no-mixed-requires": "warn",
"n/no-new-require": "warn",
"n/no-path-concat": "warn",
"n/no-process-env": "warn",
"n/no-restricted-import": "warn",
"n/no-restricted-require": "warn",
"n/no-sync": "warn",
"n/no-top-level-await": "warn",
"n/prefer-global/buffer": "warn",
"n/prefer-global/console": "warn",
"n/prefer-global/process": "warn",
"n/prefer-global/text-decoder": "warn",
"n/prefer-global/text-encoder": "warn",
"n/prefer-global/url": "warn",
"n/prefer-global/url-search-params": "warn",
"n/prefer-node-protocol": "warn",
"n/prefer-promises/dns": "warn",
"n/prefer-promises/fs": "warn",
// Promise
"promise/no-multiple-resolved": "warn",
"promise/prefer-await-to-callbacks": "off",
"promise/prefer-await-to-then": "warn",
"promise/prefer-catch": "warn",
"promise/spec-only": "warn",
},
},
// Electron backend files
{
files: [
"electron/**/*.ts",
"electron/**/*.cts",
"electron/**/*.mts",
],
ignores: [
"electron/**/*.spec.{ts,tsx,mts,cts}",
"electron/**/*.test.{ts,tsx,mts,cts}",
"electron/test/**/*.{ts,tsx,mts,cts}",
"shared/**/*.spec.{ts,tsx,mts,cts}",
"shared/**/*.test.{ts,tsx,mts,cts}",
"shared/test/**/*.{ts,tsx,mts,cts}",
],
languageOptions: {
parser: tseslintParser,
parserOptions: {
ecmaVersion: "latest",
project: "tsconfig.electron.json",
sourceType: "module",
tsconfigRootDir: path.resolve(import.meta.dirname),
ecmaFeatures: {
jsx: true,
impliedStrict: true,
},
jsDocParsingMode: "all",
warnOnUnsupportedTypeScriptVersion: true,
},
globals: {
...globals.node,
__dirname: "readonly",
__filename: "readonly",
process: "readonly",
Buffer: "readonly",
global: "readonly",
require: "readonly",
module: "readonly",
NodeJS: "readonly",
},
},
settings: {
react: { version: "19" },
n: {
allowModules: [
"electron",
"node",
"electron-devtools-installer",
],
},
"boundaries/elements": [
{ type: "main", pattern: "electron/main.ts" },
{ type: "preload", pattern: "electron/preload.ts" },
{ type: "managers", pattern: "electron/managers/**/*" },
{ type: "services", pattern: "electron/services/**/*" },
{ type: "utils", pattern: "electron/utils/**/*" },
{ type: "events", pattern: "electron/events/**/*" },
{ type: "types", pattern: "electron/types.ts" },
],
"import-x/resolver": {
// You will also need to install and configure the TypeScript resolver
// See also https://github.com/import-js/eslint-import-resolver-typescript#configuration
typescript: true,
node: true,
project: ["tsconfig.electron.json"],
},
"import/resolver": {
// You will also need to install and configure the TypeScript resolver
// See also https://github.com/import-js/eslint-import-resolver-typescript#configuration
typescript: {
alwaysTryTypes: true, // Always try to resolve types under `<root>@types` directory even if it doesn't contain any source code, like `@types/unist`
project: ["tsconfig.electron.json"],
},
},
},
plugins: {
"@typescript-eslint": tseslint,
"jsx-a11y": jsxA11y,
"no-unsanitized": nounsanitized,
"prefer-arrow": pluginPreferArrow,
"react-hooks": reactHooks,
"sort-class-members": pluginSortClassMembers,
"unused-imports": pluginUnusedImports,
"write-good-comments": pluginWriteGood,
boundaries: pluginBoundaries,
compat: pluginCompat,
css: css,
depend: depend,
functional: pluginFunctional,
js: js,
math: eslintPluginMath,
n: nodePlugin,
perfectionist: pluginPerfectionist,
"import-x": importX,
prettier: pluginPrettier,
promise: pluginPromise,
putout: putout,
react: pluginReact,
redos: pluginRedos,
regexp: pluginRegexp,
security: pluginSecurity,
sonarjs: pluginSonarjs,
tsdoc: pluginTsdoc,
unicorn: pluginUnicorn,
"eslint-comments": pluginComments,
ex: ex,
canonical: pluginCanonical,
"@eslint-react": eslintReact,
"@eslint-react/dom": eslintReactDom,
"@eslint-react/web-api": eslintReactWeb,
"@eslint-react/hooks-extra": eslintReactHooksExtra,
"react-hooks-addons": reactHooksAddons,
"@eslint-react/naming-convention": eslintReactNamingConvention,
xss: xss,
"array-func": arrayFunc,
"no-use-extend-native": eslintPluginNoUseExtendNative,
"@microsoft/sdl": pluginMicrosoftSdl,
"sort-destructure-keys": pluginSortDestructure,
istanbul: istanbul,
observers: observers,
"@jcoreio/implicit-dependencies": implicitDependencies,
listeners: listeners,
"sql-template": sqlTemplate,
"no-function-declare-after-return": pluginNFDAR,
"require-jsdoc": pluginJSDoc,
"comment-length": eslintPluginCommentLength,
"no-lookahead-lookbehind-regexp": pluginRegexLook,
"@metamask/design-tokens": pluginDesignTokens,
"function-name": pluginFunctionNames,
"clean-code": pluginCleanCode,
"import-zod": importZod,
"usememo-recommendations": pluginUseMemo,
"eslint-plugin-goodeffects": pluginGoodEffects,
"jsx-plus": pluginJsxPlus,
"no-unary-plus": pluginNoUnary,
"module-interop": moduleInterop,
"granular-selectors": pluginGranular,
"no-unawaited-dot-catch-throw": pluginNoUnwaited,
"eslint-plugin-toplevel": pluginTopLevel,
"format-sql": pluginFormatSQL,
neverthrow: fixupPluginRules(pluginNeverThrow),
"no-explicit-type-exports": pluginNoExplicitTypeExports,
deprecation: fixupPluginRules(pluginDeprecation),
"no-constructor-bind": pluginNoConstructBind,
"total-functions": fixupPluginRules(pluginTotalFunctions),
"validate-jsx-nesting": pluginValidateJSX,
"styled-components-a11y": styledA11y,
"ssr-friendly": fixupPluginRules(pluginSSR),
etc: fixupPluginRules(etc),
"safe-jsx": pluginSafeJSX,
"loadable-imports": pluginLoadableImports,
zod: zod,
},
rules: {
// TypeScript backend rules
...js.configs.all.rules,
...tseslint.configs.recommendedTypeChecked,
...tseslint.configs.recommended.rules,
...tseslint.configs.strictTypeChecked,
...tseslint.configs.strict.rules,
...tseslint.configs.stylisticTypeChecked,
...tseslint.configs.stylistic.rules,
...pluginRegexp.configs["flat/all"].rules,
...importX.flatConfigs.recommended.rules,
...importX.flatConfigs.electron.rules,
...importX.flatConfigs.react.rules,
...importX.flatConfigs.typescript.rules,
...importX.flatConfigs.electron.rules,
...pluginPromise.configs["flat/recommended"].rules,
...pluginUnicorn.configs["flat/all"].rules,
...pluginReact.configs.all.rules,
...reactHooks.configs["recommended-latest"].rules,
...jsxA11y.flatConfigs.strict.rules,
...pluginSonarjs.configs.recommended.rules,
...pluginPerfectionist.configs["recommended-natural"].rules,
...pluginBoundaries.configs.recommended.rules,
...pluginRedos.configs.recommended.rules,
...pluginSecurity.configs.recommended.rules,
...nodePlugin.configs["flat/all"].rules,
...depend.configs["flat/recommended"].rules,
...eslintPluginMath.configs.recommended.rules,
...css.configs.recommended.rules,
...pluginComments.configs.recommended.rules,
...pluginCanonical.configs.recommended.rules,
...eslintReact.configs["recommended-typescript"].rules,
...arrayFunc.configs.all.rules,
...pluginSortClassMembers.configs["flat/recommended"].rules,
...eslintPluginNoUseExtendNative.configs.recommended.rules,
...pluginMicrosoftSdl.configs.required.rules,
...listeners.configs.strict.rules,
...pluginNFDAR.rules,
...pluginJSDoc.rules,
...eslintPluginCommentLength.configs["flat/recommended"].rules,
...pluginRegexLook.configs.recommended.rules,
...pluginJsxPlus.configs.all.rules,
...moduleInterop.configs.recommended.rules,
...pluginTotalFunctions.configs.recommended.rules,
...styledA11y.flatConfigs.strict.rules,
...etc.configs.recommended.rules,
"react-hooks-addons/no-unused-deps": "warn",
"comment-length/limit-single-line-comments": [
"warn",
{
mode: "compact-on-overflow",
maxLength: 120,
logicalWrap: true,
ignoreUrls: true,
ignoreCommentsWithCode: true,
tabSize: 2,
},
],
"comment-length/limit-multi-line-comments": [
"warn",
{
mode: "compact-on-overflow",
maxLength: 120,
logicalWrap: true,
ignoreUrls: true,
ignoreCommentsWithCode: true,
tabSize: 2,
},
],
"zod/prefer-enum": "error",
"zod/require-strict": "error",
"loadable-imports/sort": "error",
"safe-jsx/jsx-explicit-boolean": "error",
"etc/no-internal": "off",
"etc/no-t": "off",
"etc/no-const-enum": "warn",
"etc/no-misused-generics": "warn",
"etc/prefer-interface": "warn",
"etc/throw-error": "warn",
"ssr-friendly/no-dom-globals-in-module-scope": "error",
"ssr-friendly/no-dom-globals-in-constructor": "error",
"ssr-friendly/no-dom-globals-in-react-cc-render": "error",
"ssr-friendly/no-dom-globals-in-react-fc": "error",
"validate-jsx-nesting/no-invalid-jsx-nesting": "error",
"total-functions/no-unsafe-type-assertion": "off",
"total-functions/no-unsafe-readonly-mutable-assignment": "off",
"total-functions/no-partial-division": "off",
"total-functions/no-partial-url-constructor": "off",
"no-constructor-bind/no-constructor-bind": "error",
"no-constructor-bind/no-constructor-state": "error",
"one-var": "off",
"no-magic-numbers": "off",
"func-style": "off",
"capitalized-comments": "off",
"class-methods-use-this": "off",
"sort-imports": "off",
"no-inline-comments": "off",
"require-await": "off",
"no-ternary": "off",
"max-lines": "off",
"id-length": "off",
"max-lines-per-function": "off",
"max-statements": "off",
"max-params": "off",
"sort-keys": "off",
"dot-notation": "off",
"no-console": "off",
"no-plusplus": "off",
"no-undefined": "off",
"no-void": "off",
"require-unicode-regexp": "off",
"prefer-arrow-callback": "off",
"no-undef-init": "off",
"object-shorthand": "off",
camelcase: "off",
"max-classes-per-file": "off",
"deprecation/deprecation": "error",
"no-explicit-type-exports/no-explicit-type-exports": "error",
"neverthrow/must-use-result": "error",
"format-sql/format": "warn",
"eslint-plugin-toplevel/no-toplevel-var": "error",
"eslint-plugin-toplevel/no-toplevel-let": "error",
"eslint-plugin-toplevel/no-toplevel-side-effect": "off",
"no-unawaited-dot-catch-throw/enforce-no-unawaited-dot-catch-throw":
"error",
"no-unary-plus/no-unary-plus": "error",
// Note: granular-selectors plugin rules need to be added manually since
// Note: The plugin config are not available after fixupPluginRules wrapping (Below)
"granular-selectors/granular-selectors": "error",
"eslint-plugin-goodeffects/enforceNamedEffectCallbacks": "error",
"usememo-recommendations/detect-heavy-operations": "warn",
"import-zod/prefer-zod-namespace": "error",
// "clean-code/feature-envy": "error",
// "clean-code/exception-handling": "error",
"function-name/starts-with-verb": [
"error",
{
whitelist: [
"success",
"all",
"supports",
"safe",
"timeout",
"with",
"cleanup",
"deep",
"handler",
"component",
"typed",
"persist",
"invalidate",
"bulk",
"evict",
"migrate",
"rows",
"row",
"settings",
"shutdown",
"configure",
"rollback",
"prune",
"upsert",
"exists",
"history",
"increment",
],
},
],
"@metamask/design-tokens/no-deprecated-classnames": [
"warn",
{
"bg-opacity-*": "Use opacity modifiers like 'bg-black/50'.",
"text-opacity-*":
"Use opacity modifiers like 'text-black/50'.",
"border-opacity-*":
"Use opacity modifiers like 'border-black/50'.",
"divide-opacity-*":
"Use opacity modifiers like 'divide-black/50'.",
"ring-opacity-*":
"Use opacity modifiers like 'ring-black/50'.",
"placeholder-opacity-*":
"Use opacity modifiers like 'placeholder-black/50'.",
"flex-shrink-*": "Use 'shrink-*' instead.",
"flex-grow-*": "Use 'grow-*' instead.",
"overflow-ellipsis": "Use 'text-ellipsis' instead.",
"decoration-slice": "Use 'box-decoration-slice' instead.",
"decoration-clone": "Use 'box-decoration-clone' instead.",
"shadow-sm": "Use 'shadow-xs' instead.",
shadow: "Use 'shadow-sm' instead.",
"drop-shadow-sm": "Use 'drop-shadow-xs' instead.",
"drop-shadow": "Use 'drop-shadow-sm' instead.",
"blur-sm": "Use 'blur-xs' instead.",
blur: "Use 'blur-sm' instead.",
"backdrop-blur-sm": "Use 'backdrop-blur-xs' instead.",
"backdrop-blur": "Use 'backdrop-blur-sm' instead.",
"rounded-sm": "Use 'rounded-xs' instead.",
rounded: "Use 'rounded-sm' instead.",
"outline-none": "Use 'outline-hidden' instead.",
ring: "Use 'ring-3' instead.",
},
],
"@metamask/design-tokens/prefer-theme-color-classnames": "error",
"@metamask/design-tokens/color-no-hex": "error",
"sql-template/no-unsafe-query": "error",
"@jcoreio/implicit-dependencies/no-implicit": [
"error",
{
ignore: [
"@shared",
"electron-devtools-installer",
"electron",
"@site",
"@theme",
"@docusaurus",
],
},
],
"observers/no-missing-unobserve-or-disconnect": "error",
"observers/matching-unobserve-target": "error",
"istanbul/no-ignore-file": "error",
"istanbul/prefer-ignore-reason": "error",
"sort-destructure-keys/sort-destructure-keys": "off",
"@eslint-react/naming-convention/component-name": "warn",
"@eslint-react/naming-convention/context-name": "warn",
"@eslint-react/naming-convention/use-state": "warn",
"sort-class-members/sort-class-members": [
"warn",
{
accessorPairPositioning: "together",
stopAfterFirstProblem: false,
sortInterfaces: true,
order: [
"[static-properties]",
"[properties]",
"[conventional-private-properties]",
"[arrow-function-properties]",
"[everything-else]",
"[accessor-pairs]",
"[getters]",
"[setters]",
"[static-methods]",
"[async-methods]",
"[methods]",
"[conventional-private-methods]",
],
},
],
"perfectionist/sort-classes": "off",
"perfectionist/sort-modules": [
"off",
{
type: "alphabetical",
order: "asc",
ignoreCase: true,
specialCharacters: "keep",
partitionByComment: false,
partitionByNewLine: false,
newlinesBetween: "ignore",
groups: [
"declare-enum",
"declare-export-enum",
"enum",
"export-enum",
"declare-interface",
"declare-export-interface",
"declare-default-interface",
"export-declare-interface",
"default-interface",
"export-default-interface",
"interface",
"export-interface",
"declare-type",
"declare-export-type",
"type",
"export-type",
"declare-class",
"declare-export-class",
"declare-default-class",
"declare-default-decorated-class",
"declare-default-export-class",
"declare-default-export-decorated-class",
"export-declare-class",
"export-declare-decorated-class",
"export-default-class",
"export-default-decorated-class",
"default-class",
"default-decorated-class",
"class",
"export-class",
"decorated-class",
"export-decorated-class",
"declare-function",
"declare-async-function",
"declare-export-function",
"declare-export-async-function",
"declare-default-function",
"declare-default-async-function",
"declare-default-export-function",
"declare-default-export-async-function",
"export-declare-function",
"export-declare-async-function",
"export-default-function",
"export-default-async-function",
"default-function",
"default-async-function",
"function",
"async-function",
"export-function",
"export-async-function",
],
customGroups: [],
},
],
"xss/no-location-href-assign": "error",
"canonical/destructuring-property-newline": "off",
"canonical/export-specifier-newline": "off",
"canonical/filename-match-exported": "warn",
"canonical/filename-match-regex": "off", // Taken care of by unicorn rules
"canonical/filename-no-index": "error",
"canonical/import-specifier-newline": "off",
"canonical/no-barrel-import": "error",
"canonical/no-export-all": "error",
"canonical/no-re-export": "warn",
"canonical/no-reassign-imports": "error",
"canonical/prefer-inline-type-import": "off",
"canonical/prefer-use-mount": "warn",
"canonical/sort-react-dependencies": "warn",
"canonical/prefer-import-alias": [
"error",
{
aliases: [
{
alias: "@shared/",
matchParent: path.resolve(import.meta.dirname),
matchPath: "^shared/",
maxRelativeDepth: 0,
},
],
},
],
"ex/no-unhandled": "warn",
"no-unsanitized/method": "error",
"no-unsanitized/property": "error",
"n/file-extension-in-import": "off", // Allow missing file extensions for imports
"n/no-missing-file-extension": "off", // Allow missing file extensions for imports
"n/no-missing-import": "off", // Allow missing imports for dynamic imports
"n/no-unsupported-features/es-syntax": "off", // Allow modern ES2024+ syntax
// "write-good-comments/write-good-comments": "warn",
"unicorn/no-null": "off", // Null is common in SQLite and IPC
"unicorn/prefer-global-this": "off", // Not suitable for Electron
"unicorn/prevent-abbreviations": "off", // Too many false positives
"unicorn/prefer-spread": "off", // Prefer Array.From for readability
// Node.js specific
complexity: "off",
// Core quality rules
// "no-console": "warn", // Allow in development, but warn - DISABLED FOR NOW
"consistent-return": "warn",
"no-debugger": "error",
"no-duplicate-imports": [
"error",
{
allowSeparateTypeImports: true,
},
],
"prefer-const": "error",
"prefer-template": "warn",
curly: ["error", "all"],
eqeqeq: ["error", "always"],
// Code spacing and formatting rules
"lines-around-comment": [
"error",
{
beforeBlockComment: true,
afterBlockComment: false,
beforeLineComment: true,
afterLineComment: false,
allowBlockStart: true,
allowBlockEnd: false,
allowObjectStart: true,
allowObjectEnd: false,
allowArrayStart: true,
allowArrayEnd: false,
allowClassStart: true,
allowClassEnd: false,
applyDefaultIgnorePatterns: true,
ignorePattern: String.raw`^\s*@`, // Ignore TSDoc tags like @param, @returns
},
],
"lines-between-class-members": [
"error",
"always",
{
exceptAfterSingleLine: false,
},
],
"padding-line-between-statements": [
"error",
{
blankLine: "always",
prev: "function",
next: "*",
},
{
blankLine: "always",
prev: "*",
next: "function",
},
{
blankLine: "always",
prev: "class",
next: "*",
},
{
blankLine: "always",
prev: "*",
next: "class",
},
],
"putout/align-spaces": "off",
"putout/array-element-newline": "off",
"putout/destructuring-as-function-argument": "off",
"putout/function-declaration-paren-newline": "off",
"putout/long-properties-destructuring": "off",
"putout/multiple-properties-destructuring": "off",
"putout/newline-function-call-arguments": "off",
"putout/object-property-newline": "error",
"putout/objects-braces-inside-array": "error",
"putout/single-property-destructuring": "off",
// Import management
"unused-imports/no-unused-imports": "error",
"unused-imports/no-unused-vars": [
"warn",
{
vars: "all",
varsIgnorePattern: "^_",
args: "after-used",
argsIgnorePattern: "^_",
},
],
// Architecture boundaries for Electron
"boundaries/element-types": [
"error",
{
default: "disallow",
rules: [
{ from: "events", allow: ["types"] },
{
from: "main",
allow: [
"managers",
"services",
"utils",
"events",
"types",
],
},
{
from: "managers",
allow: [
"services",
"utils",
"events",
"types",
],
},
{
from: "preload",
allow: ["utils", "types"],
},
{
from: "services",
allow: [
"services",
"utils",
"types",
],
},
{ from: "types", allow: [] },
{
from: "utils",
allow: [
"managers",
"services",
"utils",
"events",
"types",
],
},
{ from: "utils", allow: ["types"] },
],
},
],
// Backend-specific unicorn rules
"unicorn/filename-case": [
"warn",
{
cases: {
camelCase: true,
pascalCase: true, // Service classes
},
},
],
"unicorn/no-keyword-prefix": [
"error",
{
disallowedPrefixes: [
"interface",
"type",
"enum",
],
checkProperties: false,
},
],
"unicorn/no-array-callback-reference": "off", // Conflicts with React
"unicorn/no-array-for-each": "off", // ForEach is fine
"unicorn/no-negated-condition": "warn", // Sometimes clearer
"unicorn/prefer-includes": "warn",
"unicorn/prefer-string-slice": "warn",
"unicorn/prefer-string-starts-ends-with": "warn",
"unicorn/prefer-ternary": "off", // Can hurt readability
"unicorn/prefer-module": "warn", // CommonJS required for Electron
"unicorn/prefer-node-protocol": "error", // Enforce for backend
"unicorn/prefer-top-level-await": "off", // Not suitable for Electron main
// Security for backend
"redos/no-vulnerable": "error",
"security/detect-non-literal-fs-filename": "error",
"security/detect-non-literal-require": "error",
"security/detect-non-literal-regexp": "warn",
"security/detect-object-injection": "off",
// Documentation
"tsdoc/syntax": "warn",
// Allow more flexibility for backend patterns
"@typescript-eslint/no-explicit-any": "warn",
"functional/functional-parameters": "off",
"functional/immutable-data": "off",
"functional/no-class-inheritance": "off", // Classes are common in Electron services
"functional/no-classes": "off", // Classes are common in Electron services
"functional/no-conditional-statement": "off",
"functional/no-conditional-statements": "off",
"functional/no-expression-statements": "off",
"functional/no-let": "off",
"functional/no-loop-statements": "off",
"functional/no-mixed-types": "off", // Mixed types are common in Electron services
"functional/no-return-void": "off",
"functional/no-throw-statements": "off", // Throwing errors is common in Electron
"functional/prefer-immutable-types": "off",
// Function and type safety rules (same as frontend)
"@typescript-eslint/consistent-type-assertions": "error",
"@typescript-eslint/no-restricted-types": [
"error",
{
types: {
Function: {
message: [
"The `Function` type accepts any function-like value.",
"It provides no type safety when calling the function, which can be a common source of bugs.",
"If you are expecting the function to accept certain arguments, you should explicitly define the function shape.",
"Use '(...args: unknown[]) => unknown' for generic handlers or define specific function signatures.",
].join("\n"),
},
},
},
],
"@typescript-eslint/no-empty-object-type": "error",
"@typescript-eslint/no-unsafe-function-type": "error",
"@typescript-eslint/no-wrapper-object-types": "error",
"@typescript-eslint/prefer-function-type": "error",
"@typescript-eslint/no-empty-function": [
"error",
{
allow: ["arrowFunctions"], // Allow empty arrow functions for React useEffect cleanup
},
],
"prettier/prettier": ["warn", { usePrettierrc: true }],
// Advanced type-checked rules for backend async safety and runtime error prevention
"@typescript-eslint/no-floating-promises": [
"error",
{
ignoreVoid: true, // Allow void for intentionally ignored promises
ignoreIIFE: false, // Catch floating IIFEs which can cause issues in Node.js
},
],
"@typescript-eslint/await-thenable": "error", // Prevent awaiting non-promises
"@typescript-eslint/no-misused-promises": [
"error",
{
checksConditionals: true, // Check if Promises used in conditionals
checksSpreads: true, // Check Promise spreads
checksVoidReturn: true, // Critical for Electron IPC handlers
},
],
"@typescript-eslint/require-await": "error", // Functions marked async must use await
"@typescript-eslint/return-await": ["error", "in-try-catch"], // Proper await handling in try-catch
// Enhanced type safety for backend services
"@typescript-eslint/no-unnecessary-type-assertion": "error", // Remove redundant type assertions
"@typescript-eslint/no-unsafe-argument": "warn", // Warn on passing any to typed parameters
"@typescript-eslint/no-unsafe-assignment": "warn", // Warn on unsafe assignments to any
"@typescript-eslint/no-unsafe-call": "warn", // Warn on calling any-typed functions
"@typescript-eslint/no-unsafe-member-access": "warn", // Warn on accessing any-typed properties
"@typescript-eslint/no-unsafe-return": "warn", // Warn on returning any from typed functions
// Backend-specific type safety
"@typescript-eslint/prefer-readonly": "warn", // Prefer readonly for service class properties
"@typescript-eslint/switch-exhaustiveness-check": "error", // Ensure switch statements are exhaustive
// Null safety for backend operations
"@typescript-eslint/no-unnecessary-condition": [
"warn",
{
allowConstantLoopConditions: true, // Allow while(true) patterns in services
},
],
"@typescript-eslint/prefer-nullish-coalescing": [
"error",
{
ignoreConditionalTests: false, // Check conditionals for nullish coalescing opportunities
ignoreMixedLogicalExpressions: false, // Check complex logical expressions
},
],
"@typescript-eslint/prefer-optional-chain": "error", // Use optional chaining instead of logical AND,
"@typescript-eslint/no-inferrable-types": "off", // Allow explicit types for React components
"@typescript-eslint/array-type": [
"error",
{ default: "array-simple" },
], // Prefer T[] for simple types, Array<T> for complex types
"@typescript-eslint/adjacent-overload-signatures": "warn",
"@typescript-eslint/ban-ts-comment": "warn",
"@typescript-eslint/ban-tslint-comment": "warn",
"@typescript-eslint/class-literal-property-style": "warn",
"@typescript-eslint/class-methods-use-this": "off",
"@typescript-eslint/consistent-generic-constructors": "warn",
"@typescript-eslint/consistent-indexed-object-style": "warn",
"@typescript-eslint/consistent-return": "warn",
"@typescript-eslint/consistent-type-definitions": "warn",
"@typescript-eslint/consistent-type-exports": "warn",
"@typescript-eslint/consistent-type-imports": "warn",
"@typescript-eslint/default-param-last": "warn",
"@typescript-eslint/dot-notation": "warn",
"@typescript-eslint/explicit-function-return-type": [
"warn",
{
allowConciseArrowFunctionExpressionsStartingWithVoid: false,
allowDirectConstAssertionInArrowFunctions: true,
allowedNames: [],
allowExpressions: false,
allowFunctionsWithoutTypeParameters: false,
allowHigherOrderFunctions: true,
allowIIFEs: false,
allowTypedFunctionExpressions: true,
},
],
"@typescript-eslint/explicit-member-accessibility": "warn",
"@typescript-eslint/explicit-module-boundary-types": "warn",
"init-declarations": "off",
"@typescript-eslint/init-declarations": "warn",
"@typescript-eslint/max-params": "off",
"@typescript-eslint/member-ordering": "off",
"@typescript-eslint/method-signature-style": "warn",
"@typescript-eslint/naming-convention": "off",
"@typescript-eslint/no-array-constructor": "warn",
"@typescript-eslint/no-array-delete": "warn",
"@typescript-eslint/no-base-to-string": "warn",
"@typescript-eslint/no-confusing-non-null-assertion": "warn",
"@typescript-eslint/no-confusing-void-expression": "warn",
"@typescript-eslint/no-deprecated": "warn",
"@typescript-eslint/no-dupe-class-members": "warn",
"@typescript-eslint/no-duplicate-enum-values": "warn",
"@typescript-eslint/no-duplicate-type-constituents": "warn",
"@typescript-eslint/no-dynamic-delete": "warn",
"@typescript-eslint/no-extra-non-null-assertion": "warn",
"@typescript-eslint/no-extraneous-class": "warn",
"@typescript-eslint/no-for-in-array": "warn",
"@typescript-eslint/no-implied-eval": "warn",
// Keep enabled: Helps with bundle optimization and makes type vs runtime imports clearer.
// Can be resolved incrementally as warnings.
"@typescript-eslint/no-import-type-side-effects": "warn",
"@typescript-eslint/no-invalid-this": "warn",
"@typescript-eslint/no-invalid-void-type": "warn",
"@typescript-eslint/no-loop-func": "warn",
"@typescript-eslint/no-magic-numbers": "off",
"@typescript-eslint/no-meaningless-void-operator": "warn",
"@typescript-eslint/no-misused-new": "warn",
"@typescript-eslint/no-misused-spread": "warn",
"@typescript-eslint/no-mixed-enums": "warn",
"@typescript-eslint/no-namespace": "warn",
"@typescript-eslint/no-non-null-asserted-nullish-coalescing":
"warn",
"@typescript-eslint/no-non-null-asserted-optional-chain": "warn",
"@typescript-eslint/no-redeclare": "warn",
"@typescript-eslint/no-redundant-type-constituents": "warn",
"@typescript-eslint/no-require-imports": "warn",
"@typescript-eslint/no-restricted-imports": "warn",
"@typescript-eslint/no-shadow": "warn",
"@typescript-eslint/no-this-alias": "warn",
"@typescript-eslint/no-unnecessary-boolean-literal-compare": "warn",
"@typescript-eslint/no-unnecessary-parameter-property-assignment":
"warn",
"@typescript-eslint/no-unnecessary-qualifier": "warn",
"@typescript-eslint/no-unnecessary-template-expression": "warn",
"@typescript-eslint/no-unnecessary-type-arguments": "warn",
"@typescript-eslint/no-unnecessary-type-constraint": "warn",
"@typescript-eslint/no-unnecessary-type-conversion": "warn",
"@typescript-eslint/no-unnecessary-type-parameters": "warn",
"@typescript-eslint/no-unsafe-declaration-merging": "warn",
"@typescript-eslint/no-unsafe-enum-comparison": "warn",
"@typescript-eslint/no-unsafe-type-assertion": "warn",
"@typescript-eslint/no-unsafe-unary-minus": "warn",
"@typescript-eslint/no-unused-expressions": "warn",
"@typescript-eslint/no-unused-vars": "warn",
// Disabled: Function declarations are hoisted in JS/TS, and this rule creates unnecessary constraints
// For Electron projects that often organize helper functions after main functions for better readability
"@typescript-eslint/no-use-before-define": "off",
"@typescript-eslint/no-useless-constructor": "warn",
"@typescript-eslint/no-useless-empty-export": "warn",
"@typescript-eslint/non-nullable-type-assertion-style": "warn",
"@typescript-eslint/only-throw-error": "warn",
"@typescript-eslint/parameter-properties": "warn",
"@typescript-eslint/prefer-as-const": "warn",
"@typescript-eslint/prefer-destructuring": "warn",
"@typescript-eslint/prefer-enum-initializers": "warn",
"@typescript-eslint/prefer-find": "warn",
"@typescript-eslint/prefer-for-of": "warn",
"@typescript-eslint/prefer-includes": "warn",
"@typescript-eslint/prefer-literal-enum-member": "warn",
"@typescript-eslint/prefer-namespace-keyword": "warn",
"@typescript-eslint/prefer-promise-reject-errors": "warn",
// Disabled: Too noisy for Electron projects with React/Zustand stores.
// Readonly parameters are often impractical and TypeScript already provides strong typing.
"@typescript-eslint/prefer-readonly-parameter-types": "off",
"@typescript-eslint/prefer-reduce-type-parameter": "warn",
"@typescript-eslint/prefer-regexp-exec": "warn",
"@typescript-eslint/prefer-return-this-type": "warn",
"@typescript-eslint/prefer-string-starts-ends-with": "warn",
// Configured: Allows non-async functions that return promises (like utility wrappers around Promise.all)
// But encourages async for most cases. This is more flexible for Electron projects.
"@typescript-eslint/promise-function-async": [
"warn",
{
allowAny: true,
allowedPromiseNames: ["Promise"],
checkArrowFunctions: false,
},
],
"@typescript-eslint/related-getter-setter-pairs": "warn",
"@typescript-eslint/require-array-sort-compare": "warn",
"@typescript-eslint/restrict-plus-operands": "warn",
"@typescript-eslint/restrict-template-expressions": "warn",
"@typescript-eslint/strict-boolean-expressions": "off",
"@typescript-eslint/triple-slash-reference": "warn",
"@typescript-eslint/unbound-method": "warn",
"@typescript-eslint/unified-signatures": "warn",
"@typescript-eslint/use-unknown-in-catch-callback-variable": "warn",
// RegExp
"regexp/grapheme-string-literal": "warn",
"regexp/hexadecimal-escape": "warn",
"regexp/letter-case": "warn",
"regexp/no-control-character": "warn",
"regexp/no-octal": "warn",
"regexp/no-standalone-backslash": "warn",
"regexp/no-super-linear-move": "warn",
"regexp/prefer-escape-replacement-dollar-char": "warn",
"regexp/prefer-lookaround": "warn",
"regexp/prefer-named-backreference": "warn",
"regexp/prefer-named-capture-group": "warn",
"regexp/prefer-named-replacement": "warn",
"regexp/prefer-quantifier": "warn",
"regexp/prefer-regexp-exec": "warn",
"regexp/prefer-regexp-test": "warn",
"regexp/prefer-result-array-groups": "warn",
"regexp/require-unicode-regexp": "off",
"regexp/require-unicode-sets-regexp": "warn",
"regexp/sort-alternatives": "warn",
"regexp/sort-character-class-elements": "off",
"regexp/unicode-escape": "warn",
"regexp/unicode-property": "warn",
// Import Rules
"import-x/consistent-type-specifier-style": "off",
"import-x/default": "warn",
"import-x/dynamic-import-chunkname": "warn",
"import-x/export": "warn",
"import-x/exports-last": "off",
"import-x/extensions": "warn",
"import-x/first": "warn",
"import-x/group-exports": "off",
"import-x/max-dependencies": "off",
"import-x/namespace": "warn",
"import-x/newline-after-import": "warn",
"import-x/no-absolute-path": "warn",
"import-x/no-amd": "warn",
"import-x/no-anonymous-default-export": "warn",
"import-x/no-commonjs": "warn",
"import-x/no-cycle": "warn",
"import-x/no-default-export": "off",
"import-x/no-deprecated": "warn",
"import-x/no-duplicates": "warn",
"import-x/no-dynamic-require": "warn",
"import-x/no-empty-named-blocks": "warn",
"import-x/no-extraneous-dependencies": "warn",
"import-x/no-import-module-exports": "warn",
"import-x/no-internal-modules": "off",
"import-x/no-mutable-exports": "warn",
"import-x/no-named-as-default": "warn",
"import-x/no-named-as-default-member": "off",
"import-x/no-named-default": "warn",
"import-x/no-named-export": "off",
"import-x/no-namespace": "off",
"import-x/no-nodejs-modules": "off", // Allow Node.js modules for Electron backend
"import-x/no-relative-packages": "warn",
"import-x/no-relative-parent-imports": "off",
"import-x/no-rename-default": "warn",
"import-x/no-restricted-paths": "warn",
"import-x/no-self-import": "warn",
"import-x/no-unresolved": "warn",
"import-x/no-unused-modules": "warn",
"import-x/no-useless-path-segments": "warn",
"import-x/no-webpack-loader-syntax": "warn",
"import-x/order": "off", // Conflicts with other rules
"import-x/prefer-default-export": "off",
"import-x/prefer-namespace-import": "warn",
"import-x/unambiguous": "warn",
// Accessibility (jsx-a11y)
"jsx-a11y/lang": "warn",
"jsx-a11y/no-aria-hidden-on-focusable": "warn",
"jsx-a11y/prefer-tag-over-role": "warn",
// Math
"math/abs": "warn",
"math/prefer-exponentiation-operator": "warn",
"math/prefer-math-sum-precise": "warn",
// Node
"n/callback-return": "warn",
"n/exports-style": "warn",
"n/global-require": "warn",
"n/handle-callback-err": "warn",
"n/no-callback-literal": "warn",
"n/no-mixed-requires": "warn",
"n/no-new-require": "warn",
"n/no-path-concat": "warn",
"n/no-process-env": "warn",
"n/no-restricted-import": "warn",
"n/no-restricted-require": "warn",
"n/no-sync": "warn",
"n/no-top-level-await": "warn",
"n/prefer-global/buffer": "warn",
"n/prefer-global/console": "warn",
"n/prefer-global/process": "warn",
"n/prefer-global/text-decoder": "warn",
"n/prefer-global/text-encoder": "warn",
"n/prefer-global/url": "warn",
"n/prefer-global/url-search-params": "warn",
"n/prefer-node-protocol": "warn",
"n/prefer-promises/dns": "warn",
"n/prefer-promises/fs": "warn",
// Promise
"promise/no-multiple-resolved": "warn",
"promise/prefer-await-to-callbacks": "off",
"promise/prefer-await-to-then": "warn",
"promise/prefer-catch": "warn",
"promise/spec-only": "warn",
},
},
// TypeScript frontend files (React + Zustand)
{
files: [
"shared/**/*.ts",
"shared/**/*.tsx",
"src/**/*.cts",
"src/**/*.mts",
],
ignores: [
"**/*.spec.{ts,tsx,mts,cts}",
"**/*.test.{ts,tsx,mts,cts}",
"shared/**/*.spec.{ts,tsx,mts,cts}",
"shared/**/*.test.{ts,tsx,mts,cts}",
"shared/test/**/*.{ts,tsx,mts,cts}",
"src/test/**/*.{ts,tsx,mts,cts}",
],
languageOptions: {
parser: tseslintParser,
parserOptions: {
ecmaVersion: "latest",
project: "tsconfig.shared.json",
sourceType: "module",
tsconfigRootDir: path.resolve(import.meta.dirname),
ecmaFeatures: {
jsx: true,
impliedStrict: true,
},
jsDocParsingMode: "all",
warnOnUnsupportedTypeScriptVersion: true,
},
globals: {
...globals.browser,
...globals.node,
document: "readonly",
globalThis: "readonly",
window: "readonly",
NodeJS: "readonly",
},
},
settings: {
tailwind: {
config: "./tailwind.config.mjs",
},
react: { version: "19" },
"boundaries/elements": [
{ type: "app", pattern: "src/App.tsx" },
{ type: "components", pattern: "src/components/**/*" },
{ type: "stores", pattern: "src/stores/**/*" },
{ type: "hooks", pattern: "src/hooks/**/*" },
{ type: "services", pattern: "src/services/**/*" },
{ type: "theme", pattern: "src/theme/**/*" },
{ type: "utils", pattern: "src/utils/**/*" },
{ type: "types", pattern: "src/types.ts" },
],
n: {
allowModules: [
"electron",
"node",
"electron-devtools-installer",
],
},
"import-x/resolver": {
// You will also need to install and configure the TypeScript resolver
// See also https://github.com/import-js/eslint-import-resolver-typescript#configuration
typescript: true,
node: true,
project: ["tsconfig.shared.json"],
},
"import/resolver": {
// You will also need to install and configure the TypeScript resolver
// See also https://github.com/import-js/eslint-import-resolver-typescript#configuration
typescript: {
alwaysTryTypes: true, // Always try to resolve types under `<root>@types` directory even if it doesn't contain any source code, like `@types/unist`
project: ["tsconfig.shared.json"],
},
},
},
plugins: {
"@typescript-eslint": tseslint,
"jsx-a11y": jsxA11y,
"no-unsanitized": nounsanitized,
"prefer-arrow": pluginPreferArrow,
"react-hooks": reactHooks,
"react-refresh": reactRefresh,
"sort-class-members": pluginSortClassMembers,
"unused-imports": pluginUnusedImports,
"write-good-comments": pluginWriteGood,
boundaries: pluginBoundaries,
compat: pluginCompat,
css: css,
depend: depend,
functional: pluginFunctional,
js: js,
math: eslintPluginMath,
n: nodePlugin,
perfectionist: pluginPerfectionist,
"import-x": importX,
prettier: pluginPrettier,
promise: pluginPromise,
putout: putout,
react: pluginReact,
redos: pluginRedos,
regexp: pluginRegexp,
security: pluginSecurity,
sonarjs: pluginSonarjs,
tailwind: tailwind,
tsdoc: pluginTsdoc,
unicorn: pluginUnicorn,
"eslint-comments": pluginComments,
ex: ex,
canonical: pluginCanonical,
"@eslint-react": eslintReact,
"@eslint-react/dom": eslintReactDom,
"@eslint-react/web-api": eslintReactWeb,
"@eslint-react/hooks-extra": eslintReactHooksExtra,
"react-hooks-addons": reactHooksAddons,
"@eslint-react/naming-convention": eslintReactNamingConvention,
xss: xss,
"array-func": arrayFunc,
"no-use-extend-native": eslintPluginNoUseExtendNative,
"@microsoft/sdl": pluginMicrosoftSdl,
"sort-destructure-keys": pluginSortDestructure,
"react-compiler": reactCompiler,
istanbul: istanbul,
observers: observers,
"@jcoreio/implicit-dependencies": implicitDependencies,
listeners: listeners,
"sql-template": sqlTemplate,
"no-function-declare-after-return": pluginNFDAR,
"require-jsdoc": pluginJSDoc,
"comment-length": eslintPluginCommentLength,
"sort-react-dependency-arrays": pluginSortReactDependency,
"no-lookahead-lookbehind-regexp": pluginRegexLook,
"@metamask/design-tokens": pluginDesignTokens,
"function-name": pluginFunctionNames,
"clean-code": pluginCleanCode,
"filename-export": pluginFilenameExport,
"import-zod": importZod,
"usememo-recommendations": pluginUseMemo,
"eslint-plugin-goodeffects": pluginGoodEffects,
"jsx-plus": pluginJsxPlus,
"no-unary-plus": pluginNoUnary,
"granular-selectors": pluginGranular,
"module-interop": moduleInterop,
"no-unawaited-dot-catch-throw": pluginNoUnwaited,
"eslint-plugin-toplevel": pluginTopLevel,
"format-sql": pluginFormatSQL,
neverthrow: fixupPluginRules(pluginNeverThrow),
"no-explicit-type-exports": pluginNoExplicitTypeExports,
deprecation: fixupPluginRules(pluginDeprecation),
"react-require-testid": pluginReactTest,
"react-useeffect": reactUseEffect,
"no-constructor-bind": pluginNoConstructBind,
"total-functions": fixupPluginRules(pluginTotalFunctions),
"validate-jsx-nesting": pluginValidateJSX,
"styled-components-a11y": styledA11y,
"react-form-fields": pluginReactFormFields,
"react-hook-form": pluginReactHookForm,
"react-prefer-function-component": preferFunctionComponent,
"ssr-friendly": fixupPluginRules(pluginSSR),
"react-perf": reactPerfPlugin,
"@arthurgeron/react-usememo": pluginUseMemo2,
etc: fixupPluginRules(etc),
"safe-jsx": pluginSafeJSX,
"loadable-imports": pluginLoadableImports,
zod: zod,
},
rules: {
// TypeScript rules
...js.configs.all.rules,
...tseslint.configs.recommendedTypeChecked,
...tseslint.configs.recommended.rules,
...tseslint.configs.strictTypeChecked,
...tseslint.configs.strict.rules,
...tseslint.configs.stylisticTypeChecked,
...tseslint.configs.stylistic.rules,
...pluginRegexp.configs["flat/all"].rules,
...reactRefresh.configs.vite.rules,
...importX.flatConfigs.recommended.rules,
...importX.flatConfigs.electron.rules,
...importX.flatConfigs.react.rules,
...importX.flatConfigs.typescript.rules,
...pluginPromise.configs["flat/recommended"].rules,
...pluginUnicorn.configs["flat/all"].rules,
...pluginReact.configs.all.rules,
...reactHooks.configs["recommended-latest"].rules,
...jsxA11y.flatConfigs.strict.rules,
...pluginSonarjs.configs.recommended.rules,
...pluginPerfectionist.configs["recommended-natural"].rules,
...pluginBoundaries.configs.recommended.rules,
...pluginRedos.configs.recommended.rules,
...pluginSecurity.configs.recommended.rules,
...nodePlugin.configs["flat/all"].rules,
...depend.configs["flat/recommended"].rules,
...eslintPluginMath.configs.recommended.rules,
...css.configs.recommended.rules,
...pluginComments.configs.recommended.rules,
...pluginCanonical.configs.recommended.rules,
...eslintReact.configs["recommended-typescript"].rules,
...arrayFunc.configs.all.rules,
...pluginSortClassMembers.configs["flat/recommended"].rules,
...eslintPluginNoUseExtendNative.configs.recommended.rules,
...pluginMicrosoftSdl.configs.required.rules,
...reactCompiler.configs.recommended.rules,
...listeners.configs.strict.rules,
...pluginNFDAR.rules,
...pluginJSDoc.rules,
...eslintPluginCommentLength.configs["flat/recommended"].rules,
...pluginRegexLook.configs.recommended.rules,
...pluginJsxPlus.configs.all.rules,
...moduleInterop.configs.recommended.rules,
...pluginTotalFunctions.configs.recommended.rules,
...styledA11y.flatConfigs.strict.rules,
...pluginReactHookForm.configs.recommended.rules,
...reactPerfPlugin.configs.all.rules,
...etc.configs.recommended.rules,
"react-hooks-addons/no-unused-deps": "warn",
"comment-length/limit-single-line-comments": [
"warn",
{
mode: "compact-on-overflow",
maxLength: 120,
logicalWrap: true,
ignoreUrls: true,
ignoreCommentsWithCode: true,
tabSize: 2,
},
],
"comment-length/limit-multi-line-comments": [
"warn",
{
mode: "compact-on-overflow",
maxLength: 120,
logicalWrap: true,
ignoreUrls: true,
ignoreCommentsWithCode: true,
tabSize: 2,
},
],
"zod/prefer-enum": "error",
"zod/require-strict": "error",
"loadable-imports/sort": "error",
"safe-jsx/jsx-explicit-boolean": "error",
"etc/no-internal": "off",
"etc/no-t": "off",
"etc/no-const-enum": "warn",
"etc/no-misused-generics": "warn",
"etc/prefer-interface": "warn",
"etc/throw-error": "warn",
"@arthurgeron/react-usememo/require-usememo": "error",
"@arthurgeron/react-usememo/require-memo": "off",
"@arthurgeron/react-usememo/require-usememo-children": "off",
"ssr-friendly/no-dom-globals-in-module-scope": "error",
"ssr-friendly/no-dom-globals-in-constructor": "error",
"ssr-friendly/no-dom-globals-in-react-cc-render": "error",
"ssr-friendly/no-dom-globals-in-react-fc": "error",
"react-prefer-function-component/react-prefer-function-component": [
"error",
{ allowComponentDidCatch: false },
],
"react-hook-form/no-use-watch": "error",
"react-form-fields/no-mix-controlled-with-uncontrolled": "error",
"react-form-fields/no-only-value-prop": "error",
"react-form-fields/styled-no-mix-controlled-with-uncontrolled":
"error",
"react-form-fields/styled-no-only-value-prop": "error",
"validate-jsx-nesting/no-invalid-jsx-nesting": "error",
"total-functions/no-unsafe-type-assertion": "off",
"total-functions/no-unsafe-readonly-mutable-assignment": "off",
"total-functions/no-partial-division": "off",
"total-functions/no-partial-url-constructor": "off",
"no-constructor-bind/no-constructor-bind": "error",
"no-constructor-bind/no-constructor-state": "error",
"react-useeffect/no-non-function-return": "error",
"react-require-testid/testid-missing": [
"warn",
{
disableDefaultComponents: [
"a",
"abbr",
"address",
"area",
"article",
"aside",
"audio",
"b",
"base",
"bdi",
"bdo",
"blockquote",
"body",
"br",
"button",
"canvas",
"caption",
"cite",
"code",
"col",
"colgroup",
"data",
"datalist",
"dd",
"del",
"details",
"dfn",
"dialog",
"div",
"dl",
"dt",
"em",
"embed",
"fieldset",
"figcaption",
"figure",
"footer",
"form",
"h1",
"h2",
"h3",
"h4",
"h5",
"h6",
"head",
"header",
"hr",
"html",
"i",
"iframe",
"img",
"input",
"ins",
"kbd",
"label",
"legend",
"li",
"link",
"main",
"map",
"mark",
"meta",
"meter",
"nav",
"noscript",
"object",
"ol",
"optgroup",
"option",
"output",
"p",
"param",
"picture",
"pre",
"progress",
"q",
"rp",
"rt",
"ruby",
"s",
"samp",
"script",
"section",
"select",
"small",
"source",
"span",
"strong",
"style",
"sub",
"summary",
"sup",
"table",
"tbody",
"td",
"template",
"textarea",
"tfoot",
"th",
"thead",
"time",
"title",
"tr",
"track",
"u",
"ul",
"var",
"video",
"wbr",
],
enableComponents: [],
},
],
"one-var": "off",
"no-magic-numbers": "off",
"func-style": "off",
"capitalized-comments": "off",
"class-methods-use-this": "off",
"sort-imports": "off",
"no-inline-comments": "off",
"require-await": "off",
"no-ternary": "off",
"max-lines": "off",
"id-length": "off",
"max-lines-per-function": "off",
"max-statements": "off",
"max-params": "off",
"sort-keys": "off",
"dot-notation": "off",
"no-console": "off",
"no-plusplus": "off",
"no-undefined": "off",
"no-void": "off",
"require-unicode-regexp": "off",
"prefer-arrow-callback": "off",
"no-undef-init": "off",
"object-shorthand": "off",
camelcase: "off",
"max-classes-per-file": "off",
"deprecation/deprecation": "error",
"no-explicit-type-exports/no-explicit-type-exports": "error",
"neverthrow/must-use-result": "error",
"format-sql/format": "warn",
"eslint-plugin-toplevel/no-toplevel-var": "error",
"eslint-plugin-toplevel/no-toplevel-let": "error",
"eslint-plugin-toplevel/no-toplevel-side-effect": "off",
"no-unawaited-dot-catch-throw/enforce-no-unawaited-dot-catch-throw":
"error",
// Note: granular-selectors plugin rules need to be added manually since
// Note: The plugin config are not available after fixupPluginRules wrapping (Below)
"granular-selectors/granular-selectors": "error",
"no-unary-plus/no-unary-plus": "error",
"eslint-plugin-goodeffects/enforceNamedEffectCallbacks": "error",
"usememo-recommendations/detect-heavy-operations": "warn",
"import-zod/prefer-zod-namespace": "error",
// "filename-export/match-named-export": "error",
// "filename-export/match-default-export": "error",
// "clean-code/feature-envy": "error",
// "clean-code/exception-handling": "error",
"function-name/starts-with-verb": [
"error",
{
whitelist: [
"success",
"all",
"supports",
"safe",
"timeout",
"with",
"cleanup",
"deep",
"handler",
"component",
"typed",
"persist",
"invalidate",
"bulk",
"evict",
"migrate",
"rows",
"row",
"settings",
"shutdown",
"configure",
"rollback",
"prune",
"upsert",
"exists",
"history",
"increment",
],
},
],
"@metamask/design-tokens/no-deprecated-classnames": [
"warn",
{
"bg-opacity-*": "Use opacity modifiers like 'bg-black/50'.",
"text-opacity-*":
"Use opacity modifiers like 'text-black/50'.",
"border-opacity-*":
"Use opacity modifiers like 'border-black/50'.",
"divide-opacity-*":
"Use opacity modifiers like 'divide-black/50'.",
"ring-opacity-*":
"Use opacity modifiers like 'ring-black/50'.",
"placeholder-opacity-*":
"Use opacity modifiers like 'placeholder-black/50'.",
"flex-shrink-*": "Use 'shrink-*' instead.",
"flex-grow-*": "Use 'grow-*' instead.",
"overflow-ellipsis": "Use 'text-ellipsis' instead.",
"decoration-slice": "Use 'box-decoration-slice' instead.",
"decoration-clone": "Use 'box-decoration-clone' instead.",
"shadow-sm": "Use 'shadow-xs' instead.",
shadow: "Use 'shadow-sm' instead.",
"drop-shadow-sm": "Use 'drop-shadow-xs' instead.",
"drop-shadow": "Use 'drop-shadow-sm' instead.",
"blur-sm": "Use 'blur-xs' instead.",
blur: "Use 'blur-sm' instead.",
"backdrop-blur-sm": "Use 'backdrop-blur-xs' instead.",
"backdrop-blur": "Use 'backdrop-blur-sm' instead.",
"rounded-sm": "Use 'rounded-xs' instead.",
rounded: "Use 'rounded-sm' instead.",
"outline-none": "Use 'outline-hidden' instead.",
ring: "Use 'ring-3' instead.",
},
],
"@metamask/design-tokens/prefer-theme-color-classnames": "error",
"@metamask/design-tokens/color-no-hex": "error",
"sort-react-dependency-arrays/sort": "error",
"sql-template/no-unsafe-query": "error",
"@jcoreio/implicit-dependencies/no-implicit": [
"error",
{
ignore: [
"@shared",
"electron-devtools-installer",
"electron",
"@site",
"@theme",
"@docusaurus",
],
},
],
"observers/no-missing-unobserve-or-disconnect": "error",
"observers/matching-unobserve-target": "error",
"istanbul/no-ignore-file": "error",
"istanbul/prefer-ignore-reason": "error",
"sort-destructure-keys/sort-destructure-keys": "off",
"@eslint-react/naming-convention/component-name": "warn",
"@eslint-react/naming-convention/context-name": "warn",
"@eslint-react/naming-convention/use-state": "warn",
"sort-class-members/sort-class-members": [
"warn",
{
accessorPairPositioning: "together",
stopAfterFirstProblem: false,
sortInterfaces: true,
order: [
"[static-properties]",
"[properties]",
"[conventional-private-properties]",
"[arrow-function-properties]",
"[everything-else]",
"[accessor-pairs]",
"[getters]",
"[setters]",
"[static-methods]",
"[async-methods]",
"[methods]",
"[conventional-private-methods]",
],
},
],
"perfectionist/sort-classes": "off",
"perfectionist/sort-modules": [
"off",
{
type: "alphabetical",
order: "asc",
ignoreCase: true,
specialCharacters: "keep",
partitionByComment: false,
partitionByNewLine: false,
newlinesBetween: "ignore",
groups: [
"declare-enum",
"declare-export-enum",
"enum",
"export-enum",
"declare-interface",
"declare-export-interface",
"declare-default-interface",
"export-declare-interface",
"default-interface",
"export-default-interface",
"interface",
"export-interface",
"declare-type",
"declare-export-type",
"type",
"export-type",
"declare-class",
"declare-export-class",
"declare-default-class",
"declare-default-decorated-class",
"declare-default-export-class",
"declare-default-export-decorated-class",
"export-declare-class",
"export-declare-decorated-class",
"export-default-class",
"export-default-decorated-class",
"default-class",
"default-decorated-class",
"class",
"export-class",
"decorated-class",
"export-decorated-class",
"declare-function",
"declare-async-function",
"declare-export-function",
"declare-export-async-function",
"declare-default-function",
"declare-default-async-function",
"declare-default-export-function",
"declare-default-export-async-function",
"export-declare-function",
"export-declare-async-function",
"export-default-function",
"export-default-async-function",
"default-function",
"default-async-function",
"function",
"async-function",
"export-function",
"export-async-function",
],
customGroups: [],
},
],
"xss/no-location-href-assign": "error",
"canonical/destructuring-property-newline": "off",
"canonical/export-specifier-newline": "off",
"canonical/filename-match-exported": "warn",
"canonical/filename-match-regex": "off", // Taken care of by unicorn rules
"canonical/filename-no-index": "error",
"canonical/import-specifier-newline": "off",
"canonical/no-barrel-import": "error",
"canonical/no-export-all": "error",
"canonical/no-re-export": "warn",
"canonical/no-reassign-imports": "error",
"canonical/prefer-inline-type-import": "off",
"canonical/prefer-use-mount": "warn",
"canonical/sort-react-dependencies": "warn",
"canonical/prefer-import-alias": [
"error",
{
aliases: [
{
alias: "@shared/",
matchParent: path.resolve(import.meta.dirname),
matchPath: "^shared/",
maxRelativeDepth: 0,
},
],
},
],
"ex/no-unhandled": "warn",
"n/file-extension-in-import": "off", // Allow missing file extensions for imports
"n/no-missing-file-extension": "off", // Allow missing file extensions for imports
"n/no-missing-import": "off", // Allow missing imports for dynamic imports
"n/no-unsupported-features/es-syntax": "off", // Allow modern ES2024+ syntax
"no-unsanitized/method": "error",
"no-unsanitized/property": "error",
// "write-good-comments/write-good-comments": "warn",
"putout/align-spaces": "off",
"putout/array-element-newline": "off",
"putout/destructuring-as-function-argument": "off",
"putout/function-declaration-paren-newline": "off",
"putout/long-properties-destructuring": "off",
"putout/multiple-properties-destructuring": "off",
"putout/newline-function-call-arguments": "off",
"putout/object-property-newline": "error",
"putout/objects-braces-inside-array": "off",
"putout/single-property-destructuring": "off",
"unicorn/prefer-spread": "off",
"unicorn/prefer-global-this": "off", // Not suitable for Electron
"unicorn/prevent-abbreviations": "off", // Too many false positives
"unicorn/no-null": "off", // React commonly uses null for conditional rendering
// Import rules
"import-x/no-unassigned-import": [
"error",
{
allow: ["**/*.css", "**/*.scss"], // Allow CSS imports without assignment
},
],
// Core quality rules
// "no-console": "warn", // Allow in development, but warn - DISABLED FOR NOW
"consistent-return": "warn",
"no-debugger": "error",
"no-duplicate-imports": [
"error",
{
allowSeparateTypeImports: true,
},
],
"prefer-const": "error",
"prefer-template": "warn",
curly: ["error", "all"],
eqeqeq: ["error", "always"],
// Code spacing and formatting rules
"lines-around-comment": [
"error",
{
beforeBlockComment: true,
afterBlockComment: false,
beforeLineComment: true,
afterLineComment: false,
allowBlockStart: true,
allowBlockEnd: false,
allowObjectStart: true,
allowObjectEnd: false,
allowArrayStart: true,
allowArrayEnd: false,
allowClassStart: true,
allowClassEnd: false,
applyDefaultIgnorePatterns: true,
ignorePattern: String.raw`^\s*@`, // Ignore TSDoc tags like @param, @returns
},
],
"lines-between-class-members": [
"error",
"always",
{
exceptAfterSingleLine: false,
},
],
"padding-line-between-statements": [
"error",
{
blankLine: "always",
prev: "function",
next: "*",
},
{
blankLine: "always",
prev: "*",
next: "function",
},
{
blankLine: "always",
prev: "class",
next: "*",
},
{
blankLine: "always",
prev: "*",
next: "class",
},
],
// Import management
"unused-imports/no-unused-imports": "error",
"unused-imports/no-unused-vars": [
"warn",
{
vars: "all",
varsIgnorePattern: "^_",
args: "after-used",
argsIgnorePattern: "^_",
},
],
// React 19 optimized rules
"react/jsx-boolean-value": "warn",
"react/jsx-fragments": ["warn", "syntax"],
"react/jsx-key": "error",
"react/jsx-no-useless-fragment": "warn",
"react/jsx-uses-react": "warn",
"react/no-array-index-key": "warn",
"react/no-unstable-nested-components": "error",
"react/prop-types": "warn",
"react/react-in-jsx-scope": "off",
"react/self-closing-comp": "warn",
// React Hooks
"react-hooks/exhaustive-deps": "warn",
"react-hooks/rules-of-hooks": "error",
// Accessibility
"jsx-a11y/alt-text": "warn",
"jsx-a11y/anchor-is-valid": "warn",
"jsx-a11y/no-autofocus": "warn",
// Code organization and architecture
"boundaries/element-types": [
"error",
{
default: "disallow",
rules: [
{
from: "app",
allow: [
"components",
"stores",
"hooks",
"services",
"theme",
"utils",
"types",
],
},
{
from: "components",
allow: [
"components",
"hooks",
"services",
"theme",
"utils",
"types",
"stores",
],
},
{
from: "hooks",
allow: [
"stores",
"services",
"types",
"utils",
],
},
{
from: "services",
allow: ["types", "utils"],
},
{
from: "stores",
allow: [
"services",
"types",
"utils",
"stores",
"components",
],
},
{ from: "theme", allow: ["types"] },
{ from: "types", allow: [] },
{ from: "utils", allow: ["types"] },
],
},
],
// Optimized Unicorn rules (reduced false positives)
"unicorn/filename-case": [
"warn",
{
cases: {
camelCase: true,
kebabCase: true,
pascalCase: true,
},
},
],
"unicorn/no-keyword-prefix": [
"error",
{
disallowedPrefixes: [
"interface",
"type",
"enum",
],
checkProperties: false,
},
], // Allow "class" prefix for className and other legitimate uses
"unicorn/no-array-callback-reference": "off", // Conflicts with React
"unicorn/no-array-for-each": "off", // ForEach is fine
"unicorn/no-negated-condition": "warn", // Sometimes clearer
"unicorn/prefer-includes": "warn",
"unicorn/prefer-module": "warn", // CommonJS needed for Electron
"unicorn/prefer-node-protocol": "warn",
"unicorn/prefer-string-slice": "warn",
"unicorn/prefer-string-starts-ends-with": "warn",
"unicorn/prefer-ternary": "off", // Can hurt readability
"unicorn/prefer-top-level-await": "off", // Not suitable for React
// Function style preferences - disabled as too aggressive
// "prefer-arrow/prefer-arrow-functions": [
// "warn",
// {
// DisallowPrototype: true,
// SingleReturnOnly: false,
// ClassPropertiesAllowed: false,
// },
// ],
// Security for Frontend
"redos/no-vulnerable": "error",
"security/detect-non-literal-fs-filename": "error",
"security/detect-non-literal-require": "error",
"security/detect-non-literal-regexp": "warn",
"security/detect-object-injection": "off",
// Performance and compatibility
"compat/compat": "off", // Electron supports modern APIs, Opera Mini not a target
// Code style
"prettier/prettier": ["warn", { usePrettierrc: true }],
// Documentation
"tsdoc/syntax": "warn",
// RegExp rules for security and performance
"regexp/no-potentially-useless-backreference": "warn",
"regexp/no-super-linear-backtracking": "error",
"regexp/no-unused-capturing-group": "warn",
"regexp/no-useless-escape": "warn",
"regexp/no-useless-quantifier": "warn",
"regexp/optimal-quantifier-concatenation": "warn",
"regexp/prefer-character-class": "warn",
"regexp/prefer-plus-quantifier": "warn",
"regexp/prefer-star-quantifier": "warn",
// Disable overly strict rules for this project
"@typescript-eslint/no-explicit-any": "warn", // Sometimes needed
"@typescript-eslint/no-non-null-assertion": "warn", // Zustand patterns
"functional/immutable-data": "off",
"functional/no-let": "off", // Let is necessary in many React patterns
// Function and type safety rules
"@typescript-eslint/consistent-type-assertions": "error",
"@typescript-eslint/no-restricted-types": [
"error",
{
types: {
Function: {
message: [
"The `Function` type accepts any function-like value.",
"It provides no type safety when calling the function, which can be a common source of bugs.",
"If you are expecting the function to accept certain arguments, you should explicitly define the function shape.",
"Use '(...args: unknown[]) => unknown' for generic handlers or define specific function signatures.",
].join("\n"),
},
},
},
],
"@typescript-eslint/no-empty-object-type": "error",
"@typescript-eslint/no-unsafe-function-type": "error",
"@typescript-eslint/no-wrapper-object-types": "error",
"@typescript-eslint/prefer-function-type": "error",
"@typescript-eslint/no-empty-function": [
"error",
{
allow: ["arrowFunctions"], // Allow empty arrow functions for React useEffect cleanup
},
],
// Advanced type-checked rules for async safety and runtime error prevention
"@typescript-eslint/no-floating-promises": [
"error",
{
ignoreVoid: true, // Allow void for intentionally ignored promises
ignoreIIFE: false, // Catch floating IIFEs which can cause issues
},
],
"@typescript-eslint/await-thenable": "error", // Prevent awaiting non-promises
"@typescript-eslint/no-misused-promises": [
"error",
{
checksConditionals: true, // Check if Promises used in conditionals
checksVoidReturn: true, // Critical for Electron IPC handlers
checksSpreads: true, // Check Promise spreads
},
],
"@typescript-eslint/require-await": "error", // Functions marked async must use await
"@typescript-eslint/return-await": ["error", "in-try-catch"], // Proper await handling in try-catch
// Enhanced type safety for backend services
"@typescript-eslint/no-unnecessary-type-assertion": "error", // Remove redundant type assertions
"@typescript-eslint/no-unsafe-argument": "warn", // Warn on passing any to typed parameters
"@typescript-eslint/no-unsafe-assignment": "warn", // Warn on unsafe assignments to any
"@typescript-eslint/no-unsafe-call": "warn", // Warn on calling any-typed functions
"@typescript-eslint/no-unsafe-member-access": "warn", // Warn on accessing any-typed properties
"@typescript-eslint/no-unsafe-return": "warn", // Warn on returning any from typed functions
// Backend-specific type safety
"@typescript-eslint/prefer-readonly": "warn", // Prefer readonly for service class properties
"@typescript-eslint/switch-exhaustiveness-check": "error", // Ensure switch statements are exhaustive
// Null safety for backend operations
"@typescript-eslint/no-unnecessary-condition": [
"warn",
{
allowConstantLoopConditions: true, // Allow while(true) patterns in services
},
],
"@typescript-eslint/prefer-nullish-coalescing": [
"error",
{
ignoreConditionalTests: false, // Check conditionals for nullish coalescing opportunities
ignoreMixedLogicalExpressions: false, // Check complex logical expressions
},
],
"@typescript-eslint/prefer-optional-chain": "error", // Use optional chaining instead of logical AND
"@typescript-eslint/no-inferrable-types": "off", // Allow explicit types for React components
"@typescript-eslint/array-type": [
"error",
{ default: "array-simple" },
], // Prefer T[] for simple types, Array<T> for complex types
"@typescript-eslint/adjacent-overload-signatures": "warn",
"@typescript-eslint/ban-ts-comment": "warn",
"@typescript-eslint/ban-tslint-comment": "warn",
"@typescript-eslint/class-literal-property-style": "warn",
"@typescript-eslint/class-methods-use-this": "off",
"@typescript-eslint/consistent-generic-constructors": "warn",
"@typescript-eslint/consistent-indexed-object-style": "warn",
"@typescript-eslint/consistent-return": "warn",
"@typescript-eslint/consistent-type-definitions": "warn",
"@typescript-eslint/consistent-type-exports": "warn",
"@typescript-eslint/consistent-type-imports": "warn",
"@typescript-eslint/default-param-last": "warn",
"@typescript-eslint/dot-notation": "warn",
"@typescript-eslint/explicit-function-return-type": [
"warn",
{
allowConciseArrowFunctionExpressionsStartingWithVoid: false,
allowDirectConstAssertionInArrowFunctions: true,
allowedNames: [],
allowExpressions: false,
allowFunctionsWithoutTypeParameters: false,
allowHigherOrderFunctions: true,
allowIIFEs: false,
allowTypedFunctionExpressions: true,
},
],
"@typescript-eslint/explicit-member-accessibility": "warn",
"@typescript-eslint/explicit-module-boundary-types": "warn",
"init-declarations": "off",
"@typescript-eslint/init-declarations": "warn",
"@typescript-eslint/max-params": "off",
"@typescript-eslint/member-ordering": "off",
"@typescript-eslint/method-signature-style": "warn",
"@typescript-eslint/naming-convention": "off",
"@typescript-eslint/no-array-constructor": "warn",
"@typescript-eslint/no-array-delete": "warn",
"@typescript-eslint/no-base-to-string": "warn",
"@typescript-eslint/no-confusing-non-null-assertion": "warn",
"@typescript-eslint/no-confusing-void-expression": "warn",
"@typescript-eslint/no-deprecated": "warn",
"@typescript-eslint/no-dupe-class-members": "warn",
"@typescript-eslint/no-duplicate-enum-values": "warn",
"@typescript-eslint/no-duplicate-type-constituents": "warn",
"@typescript-eslint/no-dynamic-delete": "warn",
"@typescript-eslint/no-extra-non-null-assertion": "warn",
"@typescript-eslint/no-extraneous-class": "warn",
"@typescript-eslint/no-for-in-array": "warn",
"@typescript-eslint/no-implied-eval": "warn",
// Keep enabled: Helps with bundle optimization and makes type vs runtime imports clearer.
// Can be resolved incrementally as warnings.
"@typescript-eslint/no-import-type-side-effects": "warn",
"@typescript-eslint/no-invalid-this": "warn",
"@typescript-eslint/no-invalid-void-type": "warn",
"@typescript-eslint/no-loop-func": "warn",
"@typescript-eslint/no-magic-numbers": "off",
"@typescript-eslint/no-meaningless-void-operator": "warn",
"@typescript-eslint/no-misused-new": "warn",
"@typescript-eslint/no-misused-spread": "warn",
"@typescript-eslint/no-mixed-enums": "warn",
"@typescript-eslint/no-namespace": "warn",
"@typescript-eslint/no-non-null-asserted-nullish-coalescing":
"warn",
"@typescript-eslint/no-non-null-asserted-optional-chain": "warn",
"@typescript-eslint/no-redeclare": "warn",
"@typescript-eslint/no-redundant-type-constituents": "warn",
"@typescript-eslint/no-require-imports": "warn",
"@typescript-eslint/no-restricted-imports": "warn",
"@typescript-eslint/no-shadow": "warn",
"@typescript-eslint/no-this-alias": "warn",
"@typescript-eslint/no-unnecessary-boolean-literal-compare": "warn",
"@typescript-eslint/no-unnecessary-parameter-property-assignment":
"warn",
"@typescript-eslint/no-unnecessary-qualifier": "warn",
"@typescript-eslint/no-unnecessary-template-expression": "warn",
"@typescript-eslint/no-unnecessary-type-arguments": "warn",
"@typescript-eslint/no-unnecessary-type-constraint": "warn",
"@typescript-eslint/no-unnecessary-type-conversion": "warn",
"@typescript-eslint/no-unnecessary-type-parameters": "warn",
"@typescript-eslint/no-unsafe-declaration-merging": "warn",
"@typescript-eslint/no-unsafe-enum-comparison": "warn",
"@typescript-eslint/no-unsafe-type-assertion": "warn",
"@typescript-eslint/no-unsafe-unary-minus": "warn",
"@typescript-eslint/no-unused-expressions": "warn",
"@typescript-eslint/no-unused-vars": "warn",
// Disabled: Function declarations are hoisted in JS/TS, and this rule creates unnecessary constraints
// For Electron projects that often organize helper functions after main functions for better readability
"@typescript-eslint/no-use-before-define": "warn",
"@typescript-eslint/no-useless-constructor": "warn",
"@typescript-eslint/no-useless-empty-export": "warn",
"@typescript-eslint/non-nullable-type-assertion-style": "warn",
"@typescript-eslint/only-throw-error": "warn",
"@typescript-eslint/parameter-properties": "warn",
"@typescript-eslint/prefer-as-const": "warn",
"@typescript-eslint/prefer-destructuring": "warn",
"@typescript-eslint/prefer-enum-initializers": "warn",
"@typescript-eslint/prefer-find": "warn",
"@typescript-eslint/prefer-for-of": "warn",
"@typescript-eslint/prefer-includes": "warn",
"@typescript-eslint/prefer-literal-enum-member": "warn",
"@typescript-eslint/prefer-namespace-keyword": "warn",
"@typescript-eslint/prefer-promise-reject-errors": "warn",
// Disabled: Too noisy for Electron projects with React/Zustand stores.
// Readonly parameters are often impractical and TypeScript already provides strong typing.
"@typescript-eslint/prefer-readonly-parameter-types": "off",
"@typescript-eslint/prefer-reduce-type-parameter": "warn",
"@typescript-eslint/prefer-regexp-exec": "warn",
"@typescript-eslint/prefer-return-this-type": "warn",
"@typescript-eslint/prefer-string-starts-ends-with": "warn",
// Configured: Allows non-async functions that return promises (like utility wrappers around Promise.all)
// But encourages async for most cases. This is more flexible for Electron projects.
"@typescript-eslint/promise-function-async": [
"warn",
{
allowAny: true,
allowedPromiseNames: ["Promise"],
checkArrowFunctions: false,
},
],
"@typescript-eslint/related-getter-setter-pairs": "warn",
"@typescript-eslint/require-array-sort-compare": "warn",
"@typescript-eslint/restrict-plus-operands": "warn",
"@typescript-eslint/restrict-template-expressions": "warn",
"@typescript-eslint/strict-boolean-expressions": "off",
"@typescript-eslint/triple-slash-reference": "warn",
"@typescript-eslint/unbound-method": "warn",
"@typescript-eslint/unified-signatures": "warn",
"@typescript-eslint/use-unknown-in-catch-callback-variable": "warn",
// React
"react/boolean-prop-naming": "warn",
"react/button-has-type": "warn",
"react/checked-requires-onchange-or-readonly": "warn",
"react/default-props-match-prop-types": "warn",
"react/destructuring-assignment": "warn",
"react/forbid-component-props": "off",
"react/forbid-dom-props": "warn",
"react/forbid-elements": "warn",
"react/forbid-foreign-prop-types": "warn",
"react/forbid-prop-types": "warn",
"react/forward-ref-uses-ref": "warn",
"react/function-component-definition": [
"error",
{
namedComponents: "arrow-function",
unnamedComponents: "arrow-function",
},
], // Enforce consistent arrow function components
"react/hook-use-state": "warn",
"react/iframe-missing-sandbox": "warn",
"react/jsx-child-element-spacing": "warn",
"react/jsx-closing-bracket-location": "warn",
"react/jsx-closing-tag-location": "warn",
"react/jsx-curly-brace-presence": "warn",
"react/jsx-curly-newline": "off",
"react/jsx-curly-spacing": "off",
"react/jsx-equals-spacing": "off",
"react/jsx-filename-extension": ["error", { extensions: [".tsx"] }], // Enforce .tsx for JSX files
"react/jsx-first-prop-new-line": "off",
"react/jsx-handler-names": "warn", // Enforce consistent handler names
"react/jsx-indent": "off",
"react/jsx-indent-props": "off",
"react/jsx-max-depth": ["warn", { max: 7 }], // Warn on deeply nested JSX to encourage component extraction
"react/jsx-max-props-per-line": "off",
"react/jsx-newline": "off",
"react/jsx-no-bind": "warn", // Allow inline functions for development speed
"react/jsx-no-constructed-context-values": "warn",
"react/jsx-no-leaked-render": "warn",
"react/jsx-no-literals": "off",
"react/jsx-no-script-url": "warn",
"react/jsx-one-expression-per-line": "warn",
"react/jsx-pascal-case": "warn",
"react/jsx-props-no-multi-spaces": "warn",
"react/jsx-props-no-spread-multi": "warn",
"react/jsx-props-no-spreading": "off",
"react/jsx-sort-props": "warn",
"react/jsx-tag-spacing": "warn",
"react/jsx-wrap-multilines": "warn",
"react/no-access-state-in-setstate": "warn",
"react/no-adjacent-inline-elements": "warn",
"react/no-arrow-function-lifecycle": "warn",
"react/no-danger": "warn",
"react/no-did-mount-set-state": "warn",
"react/no-did-update-set-state": "warn",
"react/no-invalid-html-attribute": "warn",
"react/no-multi-comp": "warn",
"react/no-namespace": "warn",
"react/no-object-type-as-default-prop": "warn",
"react/no-redundant-should-component-update": "warn",
"react/no-set-state": "warn",
"react/no-this-in-sfc": "warn",
"react/no-typos": "warn",
"react/no-unused-class-component-methods": "warn",
"react/no-unused-prop-types": "warn",
"react/no-unused-state": "warn",
"react/no-will-update-set-state": "warn",
"react/prefer-es6-class": "warn",
"react/prefer-exact-props": "warn",
"react/prefer-read-only-props": "warn",
"react/prefer-stateless-function": "warn",
"react/require-default-props": "off",
"react/require-optimization": "warn",
"react/sort-comp": "warn",
"react/sort-default-props": "warn",
"react/sort-prop-types": "warn",
"react/state-in-constructor": "warn",
"react/static-property-placement": "warn",
"react/style-prop-object": "warn",
"react/void-dom-elements-no-children": "warn",
// RegExp
"regexp/grapheme-string-literal": "warn",
"regexp/hexadecimal-escape": "warn",
"regexp/letter-case": "warn",
"regexp/no-control-character": "warn",
"regexp/no-octal": "warn",
"regexp/no-standalone-backslash": "warn",
"regexp/no-super-linear-move": "warn",
"regexp/prefer-escape-replacement-dollar-char": "warn",
"regexp/prefer-lookaround": "warn",
"regexp/prefer-named-backreference": "warn",
"regexp/prefer-named-capture-group": "warn",
"regexp/prefer-named-replacement": "warn",
"regexp/prefer-quantifier": "warn",
"regexp/prefer-regexp-exec": "warn",
"regexp/prefer-regexp-test": "warn",
"regexp/prefer-result-array-groups": "warn",
"regexp/require-unicode-regexp": "off",
"regexp/require-unicode-sets-regexp": "warn",
"regexp/sort-alternatives": "warn",
"regexp/sort-character-class-elements": "warn",
"regexp/unicode-escape": "warn",
"regexp/unicode-property": "warn",
// // Tailwind CSS
// "tailwind/classnames-order": "warn",
// "tailwind/enforces-negative-arbitrary-values": "warn",
// "tailwind/enforces-shorthand": "warn",
// "tailwind/migration-from-tailwind-2": "warn",
// "tailwind/no-arbitrary-value": "warn",
// "tailwind/no-contradicting-classname": "warn",
// "tailwind/no-custom-classname": "off",
// "tailwind/no-unnecessary-arbitrary-value": "warn",
// CSS
"import-x/no-extraneous-dependencies": "warn",
"import-x/no-import-module-exports": "warn",
"import-x/no-internal-modules": "off",
"import-x/no-mutable-exports": "warn",
"import-x/no-named-as-default": "warn",
"import-x/no-named-as-default-member": "off",
"import-x/no-named-default": "warn",
"import-x/no-named-export": "off",
"import-x/no-namespace": "off",
"import-x/no-nodejs-modules": "error", // Dont allow on frontend or shared
"import-x/no-relative-packages": "warn",
"import-x/no-relative-parent-imports": "off",
"import-x/no-rename-default": "warn",
"import-x/no-restricted-paths": "warn",
"import-x/no-self-import": "warn",
"import-x/no-unresolved": "warn",
"import-x/no-unused-modules": "warn",
"import-x/no-useless-path-segments": "warn",
"import-x/no-webpack-loader-syntax": "warn",
"import-x/order": "off", // Conflicts with other rules
"import-x/prefer-default-export": "off",
"import-x/prefer-namespace-import": "warn",
"import-x/unambiguous": "warn",
// Accessibility (jsx-a11y)
"jsx-a11y/lang": "warn",
"jsx-a11y/no-aria-hidden-on-focusable": "warn",
"jsx-a11y/prefer-tag-over-role": "warn",
// Math
"math/abs": "warn",
"math/prefer-exponentiation-operator": "warn",
"math/prefer-math-sum-precise": "warn",
// Node
"n/callback-return": "warn",
"n/exports-style": "warn",
"n/global-require": "warn",
"n/handle-callback-err": "warn",
"n/no-callback-literal": "warn",
"n/no-mixed-requires": "warn",
"n/no-new-require": "warn",
"n/no-path-concat": "warn",
"n/no-process-env": "warn",
"n/no-restricted-import": "warn",
"n/no-restricted-require": "warn",
"n/no-sync": "warn",
"n/no-top-level-await": "warn",
"n/prefer-global/buffer": "warn",
"n/prefer-global/console": "warn",
"n/prefer-global/process": "warn",
"n/prefer-global/text-decoder": "warn",
"n/prefer-global/text-encoder": "warn",
"n/prefer-global/url": "warn",
"n/prefer-global/url-search-params": "warn",
"n/prefer-node-protocol": "warn",
"n/prefer-promises/dns": "warn",
"n/prefer-promises/fs": "warn",
// Promise
"promise/no-multiple-resolved": "warn",
"promise/prefer-await-to-callbacks": "off",
"promise/prefer-await-to-then": "warn",
"promise/prefer-catch": "warn",
"promise/spec-only": "warn",
},
},
// Test files (Frontend)
{
files: [
"src/**/*.spec.{ts,tsx,cts,mts}",
"src/**/*.test.{ts,tsx,cts,mts}",
"src/test/**/*.{ts,tsx,cts,mts}",
"tests/**/*.{ts,tsx,cts,mts}",
"tests/**/*.spec.{ts,tsx,cts,mts}",
"tests/**/*.test.{ts,tsx,cts,mts}",
],
languageOptions: {
parser: tseslintParser,
parserOptions: {
ecmaVersion: "latest",
project: "tsconfig.test.json",
sourceType: "module",
tsconfigRootDir: path.resolve(import.meta.dirname),
ecmaFeatures: {
jsx: true,
},
jsDocParsingMode: "all",
warnOnUnsupportedTypeScriptVersion: true,
},
globals: {
...globals.browser,
...globals.node,
...vitest.environments.env.globals,
afterAll: "readonly",
afterEach: "readonly",
beforeAll: "readonly",
beforeEach: "readonly",
describe: "readonly",
expect: "readonly",
it: "readonly",
test: "readonly",
vi: "readonly",
},
},
settings: {
vitest: {
typecheck: true,
},
react: { version: "19" },
n: {
allowModules: [
"electron",
"node",
"electron-devtools-installer",
],
},
"import-x/resolver": {
// You will also need to install and configure the TypeScript resolver
// See also https://github.com/import-js/eslint-import-resolver-typescript#configuration
typescript: true,
node: true,
project: ["tsconfig.test.json"],
},
"import/resolver": {
// You will also need to install and configure the TypeScript resolver
// See also https://github.com/import-js/eslint-import-resolver-typescript#configuration
typescript: {
alwaysTryTypes: true, // Always try to resolve types under `<root>@types` directory even if it doesn't contain any source code, like `@types/unist`
project: ["tsconfig.test.json"],
},
},
},
plugins: {
"@typescript-eslint": tseslint,
vitest: vitest,
"testing-library": pluginTestingLibrary,
"import-x": importX,
"unused-imports": pluginUnusedImports,
react: pluginReact,
"react-hooks": reactHooks,
n: nodePlugin,
"eslint-comments": pluginComments,
unicorn: pluginUnicorn,
"loadable-imports": pluginLoadableImports,
"undefined-css-classes": pluginUndefinedCss,
},
rules: {
...js.configs.all.rules,
...tseslint.configs.recommendedTypeChecked,
...tseslint.configs.recommended.rules,
...tseslint.configs.strictTypeChecked,
...tseslint.configs.strict.rules,
...tseslint.configs.stylisticTypeChecked,
...tseslint.configs.stylistic.rules,
...vitest.configs.recommended.rules,
...pluginComments.configs.recommended.rules,
...pluginTestingLibrary.configs["flat/react"].rules,
...pluginUnicorn.configs["flat/all"].rules,
"undefined-css-classes/no-undefined-css-classes": "off",
"loadable-imports/sort": "error",
"unicorn/no-keyword-prefix": [
"error",
{
disallowedPrefixes: [
"interface",
"type",
"enum",
],
checkProperties: false,
},
], // Allow "class" prefix for className and other legitimate uses
"unicorn/no-useless-undefined": "off", // Allow undefined in test setups
"unicorn/consistent-function-scoping": "off", // Tests often use different scoping
"unicorn/no-unused-properties": "off", // Allow unused properties in test setups
"unicorn/no-null": "off", // Null is common in test setups
"unicorn/no-await-expression-member": "off", // Allow await in test expressions
"unicorn/filename-case": "off", // Allow test files to have any case
"unicorn/prevent-abbreviations": "off", // Too many false positives in tests
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-unused-vars": "off",
"testing-library/no-node-access": "off",
"testing-library/await-async-queries": "error",
"testing-library/no-await-sync-queries": "error",
"testing-library/no-debugging-utils": "off",
"testing-library/prefer-screen-queries": "warn",
// Relaxed function rules for tests (explicit for clarity)
"@typescript-eslint/no-empty-function": "off", // Empty mocks/stubs are common
"@typescript-eslint/no-restricted-types": "off", // Tests may need generic Function types
"@typescript-eslint/no-unsafe-function-type": "off", // Tests may use generic handlers
"new-cap": "off", // Allow new-cap for class constructors
"no-throw-literal": "off",
"no-new": "off", // Allow new for class constructors
"prefer-destructuring": "off",
"init-declarations": "off",
"nitpick/no-redundant-vars": "off", // Allow redundant vars in tests
"no-use-before-define": "off", // Allow use before define in tests
"@typescript-eslint/no-use-before-define": "off", // Allow use before define in tests
"unicorn/prefer-optional-catch-binding": "off", // Allow optional catch binding for test flexibility
"unicorn/prefer-global-this": "off", // Allow globalThis for test setups
eqeqeq: "off", // Allow == and != in tests for flexibility
"func-name-matching": "off", // Allow function names to not match variable names
"@typescript-eslint/no-inferrable-types": "off", // Allow explicit types for React components
"max-depth": "off",
"no-loop-func": "off", // Allow functions in loops for test setups
"no-duplicate-imports": "off", // Allow duplicate imports for test setups
"no-redeclare": "off", // Allow redeclaring variables in tests
"no-promise-executor-return": "off", // Allow returning values from promise executors
"no-await-in-loop": "off", // Allow await in loops for sequential operations
"no-shadow": "off",
complexity: "off",
"no-useless-assignment": "off",
"no-underscore-dangle": "off",
"default-case": "off",
"func-names": "off",
"one-var": "off",
"no-magic-numbers": "off",
"func-style": "off",
"capitalized-comments": "off",
"class-methods-use-this": "off",
"sort-imports": "off",
"no-inline-comments": "off",
"require-await": "off",
"no-ternary": "off",
"max-lines": "off",
"id-length": "off",
"max-lines-per-function": "off",
"max-statements": "off",
"max-params": "off",
"sort-keys": "off",
"dot-notation": "off",
"no-console": "off",
"no-plusplus": "off",
"no-undefined": "off",
"no-void": "off",
"require-unicode-regexp": "off",
"prefer-arrow-callback": "off",
"no-undef-init": "off",
"object-shorthand": "off",
camelcase: "off",
"max-classes-per-file": "off",
},
},
// Test files (Backend)
{
files: [
"electron/**/*.spec.{ts,tsx,cts,mts}",
"electron/**/*.test.{ts,tsx,cts,mts}",
"electron/test/**/*.{ts,tsx,cts,mts}",
],
languageOptions: {
parser: tseslintParser,
parserOptions: {
ecmaVersion: "latest",
project: "tsconfig.electron.test.json",
sourceType: "module",
tsconfigRootDir: path.resolve(import.meta.dirname),
ecmaFeatures: {
jsx: true,
},
jsDocParsingMode: "all",
warnOnUnsupportedTypeScriptVersion: true,
},
globals: {
...globals.node,
...vitest.environments.env.globals,
afterAll: "readonly",
afterEach: "readonly",
beforeAll: "readonly",
beforeEach: "readonly",
describe: "readonly",
expect: "readonly",
it: "readonly",
test: "readonly",
vi: "readonly",
NodeJS: "readonly",
},
},
plugins: {
"@typescript-eslint": tseslint,
"no-only-tests": pluginNoOnly,
"unused-imports": pluginUnusedImports,
"import-x": importX,
unicorn: pluginUnicorn,
vitest: vitest,
n: nodePlugin,
"testing-library": pluginTestingLibrary,
"loadable-imports": pluginLoadableImports,
},
rules: {
...js.configs.all.rules,
...tseslint.configs.recommendedTypeChecked,
...tseslint.configs.recommended.rules,
...tseslint.configs.strictTypeChecked,
...tseslint.configs.strict.rules,
...tseslint.configs.stylisticTypeChecked,
...tseslint.configs.stylistic.rules,
...vitest.configs.recommended.rules,
...pluginUnicorn.configs["flat/all"].rules,
...pluginTestingLibrary.configs["flat/react"].rules,
"loadable-imports/sort": "error",
"testing-library/no-node-access": "off",
"testing-library/await-async-queries": "error",
"testing-library/no-await-sync-queries": "error",
"testing-library/no-debugging-utils": "off",
"testing-library/prefer-screen-queries": "warn",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-unused-vars": "off",
"unicorn/no-keyword-prefix": [
"error",
{
disallowedPrefixes: [
"interface",
"type",
"enum",
],
checkProperties: false,
},
], // Allow "class" prefix for className and other legitimate uses
"unicorn/no-useless-undefined": "off", // Allow undefined in test setups
"unicorn/consistent-function-scoping": "off", // Tests often use different scoping
"unicorn/no-unused-properties": "off", // Allow unused properties in test setups
"unicorn/no-null": "off", // Null is common in test setups
"unicorn/no-await-expression-member": "off", // Allow await in test expressions
"unicorn/filename-case": "off", // Allow test files to have any case
"unicorn/prevent-abbreviations": "off", // Too many false positives in tests
// Relaxed function rules for backend tests (explicit for clarity)
"@typescript-eslint/no-empty-function": "off", // Empty mocks/stubs are common
"@typescript-eslint/no-restricted-types": "off", // Tests may need generic Function types
"@typescript-eslint/no-unsafe-function-type": "off", // Tests may use generic handlers
// No Only Tests
"no-only-tests/no-only-tests": "error",
"new-cap": "off", // Allow new-cap for class constructors
"no-throw-literal": "off",
"no-new": "off", // Allow new for class constructors
"prefer-destructuring": "off",
"init-declarations": "off",
"no-use-before-define": "off", // Allow use before define in tests
"@typescript-eslint/no-use-before-define": "off", // Allow use before define in tests
"unicorn/prefer-optional-catch-binding": "off", // Allow optional catch binding for test flexibility
"unicorn/prefer-global-this": "off", // Allow globalThis for test setups
eqeqeq: "off", // Allow == and != in tests for flexibility
"func-name-matching": "off", // Allow function names to not match variable names
"@typescript-eslint/no-inferrable-types": "off", // Allow explicit types for React components
"max-depth": "off",
"no-loop-func": "off", // Allow functions in loops for test setups
"no-duplicate-imports": "off", // Allow duplicate imports for test setups
"no-redeclare": "off", // Allow redeclaring variables in tests
"no-promise-executor-return": "off", // Allow returning values from promise executors
"no-await-in-loop": "off", // Allow await in loops for sequential operations
"no-shadow": "off",
complexity: "off",
"no-useless-assignment": "off",
"no-underscore-dangle": "off",
"default-case": "off",
"func-names": "off",
"one-var": "off",
"no-magic-numbers": "off",
"func-style": "off",
"capitalized-comments": "off",
"class-methods-use-this": "off",
"sort-imports": "off",
"no-inline-comments": "off",
"require-await": "off",
"no-ternary": "off",
"max-lines": "off",
"id-length": "off",
"max-lines-per-function": "off",
"max-statements": "off",
"max-params": "off",
"sort-keys": "off",
"dot-notation": "off",
"no-console": "off",
"no-plusplus": "off",
"no-undefined": "off",
"no-void": "off",
"require-unicode-regexp": "off",
"prefer-arrow-callback": "off",
"no-undef-init": "off",
"object-shorthand": "off",
camelcase: "off",
"max-classes-per-file": "off",
},
settings: {
vitest: {
typecheck: true,
},
n: {
allowModules: [
"electron",
"node",
"electron-devtools-installer",
],
},
"import-x/resolver": {
// You will also need to install and configure the TypeScript resolver
// See also https://github.com/import-js/eslint-import-resolver-typescript#configuration
typescript: true,
node: true,
project: ["tsconfig.electron.test.json"],
},
"import/resolver": {
// You will also need to install and configure the TypeScript resolver
// See also https://github.com/import-js/eslint-import-resolver-typescript#configuration
typescript: {
alwaysTryTypes: true, // Always try to resolve types under `<root>@types` directory even if it doesn't contain any source code, like `@types/unist`
project: ["tsconfig.electron.test.json"],
},
},
},
},
// Shared Test Files
{
files: [
"shared/**/*.spec.{ts,tsx,cts,mts}",
"shared/**/*.test.{ts,tsx,cts,mts}",
"shared/test/**/*.{ts,tsx,cts,mts}",
],
languageOptions: {
parser: tseslintParser,
parserOptions: {
ecmaVersion: "latest",
project: "tsconfig.shared.test.json",
sourceType: "module",
tsconfigRootDir: path.resolve(import.meta.dirname),
ecmaFeatures: {
jsx: true,
},
jsDocParsingMode: "all",
warnOnUnsupportedTypeScriptVersion: true,
},
globals: {
...globals.browser,
...globals.node,
...vitest.environments.env.globals,
afterAll: "readonly",
afterEach: "readonly",
beforeAll: "readonly",
beforeEach: "readonly",
describe: "readonly",
expect: "readonly",
it: "readonly",
test: "readonly",
vi: "readonly",
},
},
settings: {
vitest: {
typecheck: true,
},
react: { version: "19" },
n: {
allowModules: [
"electron",
"node",
"electron-devtools-installer",
],
},
"import-x/resolver": {
// You will also need to install and configure the TypeScript resolver
// See also https://github.com/import-js/eslint-import-resolver-typescript#configuration
typescript: true,
node: true,
project: ["tsconfig.shared.test.json"],
},
"import/resolver": {
// You will also need to install and configure the TypeScript resolver
// See also https://github.com/import-js/eslint-import-resolver-typescript#configuration
typescript: {
alwaysTryTypes: true, // Always try to resolve types under `<root>@types` directory even if it doesn't contain any source code, like `@types/unist`
project: ["tsconfig.shared.test.json"],
},
},
},
plugins: {
"@typescript-eslint": tseslint,
vitest: vitest,
"testing-library": pluginTestingLibrary,
"import-x": importX,
"unused-imports": pluginUnusedImports,
react: pluginReact,
"react-hooks": reactHooks,
n: nodePlugin,
"eslint-comments": pluginComments,
unicorn: pluginUnicorn,
"loadable-imports": pluginLoadableImports,
"undefined-css-classes": pluginUndefinedCss,
},
rules: {
...js.configs.all.rules,
...tseslint.configs.recommendedTypeChecked,
...tseslint.configs.recommended.rules,
...tseslint.configs.strictTypeChecked,
...tseslint.configs.strict.rules,
...tseslint.configs.stylisticTypeChecked,
...tseslint.configs.stylistic.rules,
...vitest.configs.recommended.rules,
...pluginComments.configs.recommended.rules,
...pluginTestingLibrary.configs["flat/react"].rules,
...pluginUnicorn.configs["flat/all"].rules,
"undefined-css-classes/no-undefined-css-classes": "off",
"loadable-imports/sort": "error",
"unicorn/no-keyword-prefix": [
"error",
{
disallowedPrefixes: [
"interface",
"type",
"enum",
],
checkProperties: false,
},
], // Allow "class" prefix for className and other legitimate uses
"unicorn/no-useless-undefined": "off", // Allow undefined in test setups
"unicorn/consistent-function-scoping": "off", // Tests often use different scoping
"unicorn/no-unused-properties": "off", // Allow unused properties in test setups
"unicorn/no-null": "off", // Null is common in test setups
"unicorn/no-await-expression-member": "off", // Allow await in test expressions
"unicorn/filename-case": "off", // Allow test files to have any case
"unicorn/prevent-abbreviations": "off", // Too many false positives in tests
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-unused-vars": "off",
"testing-library/no-node-access": "off",
"testing-library/await-async-queries": "error",
"testing-library/no-await-sync-queries": "error",
"testing-library/no-debugging-utils": "off",
"testing-library/prefer-screen-queries": "warn",
// Relaxed function rules for tests (explicit for clarity)
"@typescript-eslint/no-empty-function": "off", // Empty mocks/stubs are common
"@typescript-eslint/no-restricted-types": "off", // Tests may need generic Function types
"@typescript-eslint/no-unsafe-function-type": "off", // Tests may use generic handlers
"one-var": "off",
"no-magic-numbers": "off",
"func-style": "off",
"capitalized-comments": "off",
"class-methods-use-this": "off",
"sort-imports": "off",
"no-inline-comments": "off",
"require-await": "off",
"no-ternary": "off",
"max-lines": "off",
"id-length": "off",
"max-lines-per-function": "off",
"max-statements": "off",
"max-params": "off",
"sort-keys": "off",
"dot-notation": "off",
"no-console": "off",
"no-plusplus": "off",
"no-undefined": "off",
"no-void": "off",
"require-unicode-regexp": "off",
"prefer-arrow-callback": "off",
"no-undef-init": "off",
"object-shorthand": "off",
camelcase: "off",
"max-classes-per-file": "off",
},
},
// Benchmark files
{
files: [
"benchmarks/**/*.bench.{ts,tsx,cts,mts}",
"benchmarks/**/*.{ts,tsx,cts,mts}",
],
languageOptions: {
parser: tseslintParser,
parserOptions: {
ecmaVersion: "latest",
project: ["tsconfig.bench.json"],
sourceType: "module",
tsconfigRootDir: path.resolve(import.meta.dirname),
ecmaFeatures: {
jsx: true,
},
jsDocParsingMode: "all",
warnOnUnsupportedTypeScriptVersion: true,
},
globals: {
...globals.browser,
...globals.node,
...vitest.environments.env.globals,
afterAll: "readonly",
afterEach: "readonly",
beforeAll: "readonly",
beforeEach: "readonly",
describe: "readonly",
expect: "readonly",
it: "readonly",
test: "readonly",
vi: "readonly",
bench: "readonly",
NodeJS: "readonly",
},
},
settings: {
vitest: {
typecheck: true,
},
react: { version: "19" },
n: {
allowModules: [
"electron",
"node",
"electron-devtools-installer",
],
},
"import-x/resolver": {
typescript: true,
node: true,
project: [
"tsconfig.json",
"tsconfig.test.json",
"tsconfig.bench.json",
],
},
"import/resolver": {
typescript: {
alwaysTryTypes: true,
project: [
"tsconfig.json",
"tsconfig.test.json",
"tsconfig.bench.json",
],
},
},
},
plugins: {
"@typescript-eslint": tseslint,
vitest: vitest,
"import-x": importX,
"unused-imports": pluginUnusedImports,
react: pluginReact,
"react-hooks": reactHooks,
n: nodePlugin,
"eslint-comments": pluginComments,
unicorn: pluginUnicorn,
},
rules: {
...js.configs.all.rules,
...tseslint.configs.recommendedTypeChecked,
...tseslint.configs.recommended.rules,
...tseslint.configs.strictTypeChecked,
...tseslint.configs.strict.rules,
...tseslint.configs.stylisticTypeChecked,
...tseslint.configs.stylistic.rules,
...vitest.configs.recommended.rules,
...pluginComments.configs.recommended.rules,
...pluginUnicorn.configs["flat/all"].rules,
"nitpick/no-redundant-vars": "off", // Allow redundant vars in benchmarks
"no-continue": "off",
"no-use-before-define": "off", // Allow use before define in benchmarks
"no-div-regex": "off", // Allow division regex in benchmarks
// Allow performance-focused code patterns in benchmarks
"unicorn/no-keyword-prefix": [
"error",
{
disallowedPrefixes: [
"interface",
"type",
"enum",
],
checkProperties: false,
},
],
"unicorn/no-useless-undefined": "off",
"unicorn/consistent-function-scoping": "off",
"unicorn/no-unused-properties": "off",
"unicorn/no-null": "off",
"unicorn/no-await-expression-member": "off",
"unicorn/filename-case": "off", // Allow benchmark files to have any case
"unicorn/prevent-abbreviations": "off",
"unicorn/no-array-for-each": "off", // Benchmarks may use forEach for testing
"unicorn/prefer-spread": "off", // Benchmarks may test different patterns
"unicorn/prefer-set-has": "off", // Benchmarks may compare different approaches
"unicorn/no-array-reduce": "off", // Benchmarks may test reduce performance
// Allow flexible patterns for benchmark mock implementations
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-restricted-types": "off",
"@typescript-eslint/no-unsafe-function-type": "off",
"@typescript-eslint/require-await": "off", // Benchmarks may have async patterns
"@typescript-eslint/no-floating-promises": "off", // Benchmarks may not await all promises
"@typescript-eslint/no-misused-promises": "off",
// Import rules relaxed for mock implementations
"import-x/no-unused-modules": "off",
"import-x/no-extraneous-dependencies": "off",
// Allow large files and classes for comprehensive benchmarks
"max-lines": "off",
"max-lines-per-function": "off",
"max-classes-per-file": "off",
"new-cap": "off", // Allow new-cap for class constructors
"no-throw-literal": "off",
"no-new": "off", // Allow new for class constructors
"prefer-destructuring": "off",
"init-declarations": "off",
"@typescript-eslint/no-inferrable-types": "off", // Allow explicit types for React components
"max-depth": "off",
"no-loop-func": "off", // Allow functions in loops for test setups
"no-duplicate-imports": "off", // Allow duplicate imports for test setups
"no-redeclare": "off", // Allow redeclaring variables in tests
"no-promise-executor-return": "off", // Allow returning values from promise executors
"no-await-in-loop": "off", // Allow await in loops for sequential operations
"no-shadow": "off",
complexity: "off",
"no-useless-assignment": "off",
"no-underscore-dangle": "off",
"default-case": "off",
"func-names": "off",
"one-var": "off",
"no-magic-numbers": "off",
"func-style": "off",
"capitalized-comments": "off",
"class-methods-use-this": "off",
"sort-imports": "off",
"no-inline-comments": "off",
"require-await": "off",
"no-ternary": "off",
"id-length": "off",
"max-statements": "off",
"max-params": "off",
"sort-keys": "off",
"dot-notation": "off",
"no-console": "off",
"no-plusplus": "off",
"no-undefined": "off",
"no-void": "off",
"require-unicode-regexp": "off",
"prefer-arrow-callback": "off",
"no-undef-init": "off",
"object-shorthand": "off",
camelcase: "off",
},
},
// TypeScript Config files using Electron Test TSConfig
{
files: [
"**/*.config.{ts,mts,tsx}", // Configuration files
],
ignores: ["./.*/**"],
languageOptions: {
parser: tseslintParser,
parserOptions: {
ecmaVersion: "latest",
project: "tsconfig.electron.test.json",
sourceType: "module",
tsconfigRootDir: path.resolve(import.meta.dirname),
ecmaFeatures: {
jsx: true,
},
jsDocParsingMode: "all",
warnOnUnsupportedTypeScriptVersion: true,
},
globals: {
...globals.node,
...vitest.environments.env.globals,
__dirname: "readonly",
__filename: "readonly",
process: "readonly",
Buffer: "readonly",
global: "readonly",
require: "readonly",
module: "readonly",
},
},
settings: {
react: { version: "19" },
n: {
allowModules: [
"electron",
"node",
"electron-devtools-installer",
],
},
"boundaries/elements": [
{ type: "main", pattern: "electron/main.ts" },
{ type: "preload", pattern: "electron/preload.ts" },
{ type: "managers", pattern: "electron/managers/**/*" },
{ type: "services", pattern: "electron/services/**/*" },
{ type: "utils", pattern: "electron/utils/**/*" },
{ type: "events", pattern: "electron/events/**/*" },
{ type: "types", pattern: "electron/types.ts" },
],
"import-x/resolver": {
// You will also need to install and configure the TypeScript resolver
// See also https://github.com/import-js/eslint-import-resolver-typescript#configuration
typescript: true,
node: true,
project: ["tsconfig.electron.test.json"],
},
"import/resolver": {
// You will also need to install and configure the TypeScript resolver
// See also https://github.com/import-js/eslint-import-resolver-typescript#configuration
typescript: {
alwaysTryTypes: true, // Always try to resolve types under `<root>@types` directory even if it doesn't contain any source code, like `@types/unist`
project: ["tsconfig.electron.test.json"],
},
},
},
plugins: {
"@typescript-eslint": tseslint,
"jsx-a11y": jsxA11y,
"no-unsanitized": nounsanitized,
"prefer-arrow": pluginPreferArrow,
"sort-class-members": pluginSortClassMembers,
"unused-imports": pluginUnusedImports,
"write-good-comments": pluginWriteGood,
boundaries: pluginBoundaries,
compat: pluginCompat,
css: css,
depend: depend,
functional: pluginFunctional,
js: js,
math: eslintPluginMath,
n: nodePlugin,
perfectionist: pluginPerfectionist,
"import-x": importX,
prettier: pluginPrettier,
promise: pluginPromise,
putout: putout,
redos: pluginRedos,
regexp: pluginRegexp,
security: pluginSecurity,
sonarjs: pluginSonarjs,
tsdoc: pluginTsdoc,
unicorn: pluginUnicorn,
"eslint-comments": pluginComments,
ex: ex,
canonical: pluginCanonical,
xss: xss,
"array-func": arrayFunc,
},
rules: {
// TypeScript backend rules
...js.configs.all.rules,
...tseslint.configs.recommendedTypeChecked,
...tseslint.configs.recommended.rules,
...tseslint.configs.strictTypeChecked,
...tseslint.configs.strict.rules,
...tseslint.configs.stylisticTypeChecked,
...tseslint.configs.stylistic.rules,
...pluginRegexp.configs["flat/all"].rules,
...importX.flatConfigs.recommended.rules,
...importX.flatConfigs.electron.rules,
...importX.flatConfigs.react.rules,
...importX.flatConfigs.typescript.rules,
...pluginPromise.configs["flat/recommended"].rules,
...pluginUnicorn.configs["flat/all"].rules,
...jsxA11y.flatConfigs.strict.rules,
...pluginSonarjs.configs.recommended.rules,
...pluginPerfectionist.configs["recommended-natural"].rules,
...pluginBoundaries.configs.recommended.rules,
...pluginRedos.configs.recommended.rules,
...pluginSecurity.configs.recommended.rules,
...nodePlugin.configs["flat/all"].rules,
...depend.configs["flat/recommended"].rules,
...eslintPluginMath.configs.recommended.rules,
...css.configs.recommended.rules,
...pluginComments.configs.recommended.rules,
...pluginCanonical.configs.recommended.rules,
...arrayFunc.configs.all.rules,
"new-cap": "off", // Allow new-cap for class constructors
"no-throw-literal": "off",
"no-new": "off", // Allow new for class constructors
"prefer-destructuring": "off",
"init-declarations": "off",
"@typescript-eslint/no-inferrable-types": "off", // Allow explicit types for React components
"max-depth": "off",
"no-loop-func": "off", // Allow functions in loops for test setups
"no-duplicate-imports": "off", // Allow duplicate imports for test setups
"no-redeclare": "off", // Allow redeclaring variables in tests
"no-promise-executor-return": "off", // Allow returning values from promise executors
"no-await-in-loop": "off", // Allow await in loops for sequential operations
"no-shadow": "off",
complexity: "off",
"no-useless-assignment": "off",
"no-underscore-dangle": "off",
"default-case": "off",
"func-names": "off",
"one-var": "off",
"no-magic-numbers": "off",
"func-style": "off",
"capitalized-comments": "off",
"class-methods-use-this": "off",
"sort-imports": "off",
"no-inline-comments": "off",
"require-await": "off",
"no-ternary": "off",
"max-lines": "off",
"id-length": "off",
"max-lines-per-function": "off",
"max-statements": "off",
"max-params": "off",
"sort-keys": "off",
"dot-notation": "off",
"no-console": "off",
"no-plusplus": "off",
"no-undefined": "off",
"no-void": "off",
"require-unicode-regexp": "off",
"prefer-arrow-callback": "off",
"no-undef-init": "off",
"object-shorthand": "off",
camelcase: "off",
"max-classes-per-file": "off",
"n/no-unpublished-import": "off",
"n/no-process-env": "off", // Allow process.env usage in Electron
"xss/no-location-href-assign": "error",
"canonical/no-barrel-import": "error",
"canonical/export-specifier-newline": "off",
"canonical/destructuring-property-newline": "off",
"canonical/import-specifier-newline": "off",
"canonical/filename-no-index": "error",
"ex/no-unhandled": "warn",
"no-unsanitized/method": "error",
"no-unsanitized/property": "error",
"n/file-extension-in-import": "off", // Allow missing file extensions for imports
"n/no-missing-file-extension": "off", // Allow missing file extensions for imports
"n/no-missing-import": "off", // Allow missing imports for dynamic imports
"n/no-unsupported-features/es-syntax": "off", // Allow modern ES2024+ syntax
// "write-good-comments/write-good-comments": "warn",
"unicorn/no-null": "off", // Null is common in SQLite and IPC
"unicorn/prefer-global-this": "off", // Not suitable for Electron
"unicorn/prevent-abbreviations": "off", // Too many false positives
"unicorn/prefer-spread": "off", // Prefer Array.From for readability
// Node.js specific
// "no-console": "off", // Logging is important for backend - DISABLED FOR NOW
"no-var": "error",
"prefer-const": "error",
"putout/align-spaces": "off",
"putout/array-element-newline": "off",
"putout/destructuring-as-function-argument": "off",
"putout/function-declaration-paren-newline": "off",
"putout/long-properties-destructuring": "off",
"putout/multiple-properties-destructuring": "off",
"putout/newline-function-call-arguments": "off",
"putout/object-property-newline": "error",
"putout/objects-braces-inside-array": "error",
"putout/single-property-destructuring": "off",
// Import management
"unused-imports/no-unused-imports": "error",
"unused-imports/no-unused-vars": [
"warn",
{
vars: "all",
varsIgnorePattern: "^_",
args: "after-used",
argsIgnorePattern: "^_",
},
],
// Architecture boundaries for Electron
"boundaries/element-types": [
"error",
{
default: "disallow",
rules: [
{ from: "events", allow: ["types"] },
{
from: "main",
allow: [
"managers",
"services",
"utils",
"events",
"types",
],
},
{
from: "managers",
allow: [
"services",
"utils",
"events",
"types",
],
},
{
from: "preload",
allow: ["utils", "types"],
},
{
from: "services",
allow: [
"services",
"utils",
"types",
],
},
{ from: "types", allow: [] },
{
from: "utils",
allow: [
"managers",
"services",
"utils",
"events",
"types",
],
},
{ from: "utils", allow: ["types"] },
],
},
],
// Backend-specific unicorn rules
"unicorn/filename-case": [
"warn",
{
cases: {
camelCase: true,
pascalCase: true, // Service classes
},
},
],
"unicorn/no-keyword-prefix": [
"error",
{
disallowedPrefixes: [
"interface",
"type",
"enum",
],
checkProperties: false,
},
],
"unicorn/prefer-module": "off", // CommonJS required for Electron
"unicorn/prefer-node-protocol": "error", // Enforce for backend
"unicorn/prefer-top-level-await": "off", // Not suitable for Electron main
// Security for backend
"redos/no-vulnerable": "error",
"security/detect-non-literal-fs-filename": "error",
"security/detect-non-literal-require": "error",
"security/detect-non-literal-regexp": "warn",
"security/detect-object-injection": "off",
// Documentation
"tsdoc/syntax": "warn",
// Allow more flexibility for backend patterns
"@typescript-eslint/no-explicit-any": "warn",
"functional/functional-parameters": "off",
"functional/immutable-data": "off",
"functional/no-class-inheritance": "off", // Classes are common in Electron services
"functional/no-classes": "off", // Classes are common in Electron services
"functional/no-conditional-statement": "off",
"functional/no-conditional-statements": "off",
"functional/no-expression-statements": "off",
"functional/no-let": "off",
"functional/no-loop-statements": "off",
"functional/no-mixed-types": "off", // Mixed types are common in Electron services
"functional/no-return-void": "off",
"functional/no-throw-statements": "off", // Throwing errors is common in Electron
"functional/prefer-immutable-types": "off",
// Function and type safety rules (same as frontend)
"@typescript-eslint/no-restricted-types": [
"error",
{
types: {
Function: {
message: [
"The `Function` type accepts any function-like value.",
"It provides no type safety when calling the function, which can be a common source of bugs.",
"If you are expecting the function to accept certain arguments, you should explicitly define the function shape.",
"Use '(...args: unknown[]) => unknown' for generic handlers or define specific function signatures.",
].join("\n"),
},
},
},
],
"@typescript-eslint/no-empty-object-type": "error",
"@typescript-eslint/no-unsafe-function-type": "error",
"@typescript-eslint/no-wrapper-object-types": "error",
"@typescript-eslint/prefer-function-type": "error",
"@typescript-eslint/no-empty-function": [
"error",
{
allow: ["arrowFunctions"], // Allow empty arrow functions for React useEffect cleanup
},
],
"prettier/prettier": ["warn", { usePrettierrc: true }],
// Advanced type-checked rules for backend async safety and runtime error prevention
"@typescript-eslint/no-floating-promises": [
"error",
{
ignoreVoid: true, // Allow void for intentionally ignored promises
ignoreIIFE: false, // Catch floating IIFEs which can cause issues in Node.js
},
],
"@typescript-eslint/await-thenable": "error", // Prevent awaiting non-promises
"@typescript-eslint/no-misused-promises": [
"error",
{
checksConditionals: true, // Check if Promises used in conditionals
checksSpreads: true, // Check Promise spreads
checksVoidReturn: true, // Critical for Electron IPC handlers
},
],
"@typescript-eslint/require-await": "error", // Functions marked async must use await
"@typescript-eslint/return-await": ["error", "in-try-catch"], // Proper await handling in try-catch
// Enhanced type safety for backend services
"@typescript-eslint/no-unnecessary-type-assertion": "off", // Remove redundant type assertions
"@typescript-eslint/no-unsafe-argument": "warn", // Warn on passing any to typed parameters
"@typescript-eslint/no-unsafe-assignment": "warn", // Warn on unsafe assignments to any
"@typescript-eslint/no-unsafe-call": "warn", // Warn on calling any-typed functions
"@typescript-eslint/no-unsafe-member-access": "warn", // Warn on accessing any-typed properties
"@typescript-eslint/no-unsafe-return": "warn", // Warn on returning any from typed functions
// Backend-specific type safety
"@typescript-eslint/prefer-readonly": "warn", // Prefer readonly for service class properties
"@typescript-eslint/switch-exhaustiveness-check": "error", // Ensure switch statements are exhaustive
// Null safety for backend operations
"@typescript-eslint/no-unnecessary-condition": [
"warn",
{
allowConstantLoopConditions: true, // Allow while(true) patterns in services
},
],
"@typescript-eslint/prefer-nullish-coalescing": [
"error",
{
ignoreConditionalTests: false, // Check conditionals for nullish coalescing opportunities
ignoreMixedLogicalExpressions: false, // Check complex logical expressions
},
],
"@typescript-eslint/prefer-optional-chain": "error", // Use optional chaining instead of logical AND
"@typescript-eslint/array-type": [
"error",
{ default: "array-simple" },
], // Prefer T[] for simple types, Array<T> for complex types
// RegExp
"regexp/grapheme-string-literal": "warn",
"regexp/hexadecimal-escape": "warn",
"regexp/letter-case": "warn",
"regexp/no-control-character": "warn",
"regexp/no-octal": "warn",
"regexp/no-standalone-backslash": "warn",
"regexp/no-super-linear-move": "warn",
"regexp/prefer-escape-replacement-dollar-char": "warn",
"regexp/prefer-lookaround": "warn",
"regexp/prefer-named-backreference": "warn",
"regexp/prefer-named-capture-group": "warn",
"regexp/prefer-named-replacement": "warn",
"regexp/prefer-quantifier": "warn",
"regexp/prefer-regexp-exec": "warn",
"regexp/prefer-regexp-test": "warn",
"regexp/prefer-result-array-groups": "warn",
"regexp/require-unicode-regexp": "off",
"regexp/require-unicode-sets-regexp": "warn",
"regexp/sort-alternatives": "warn",
"regexp/sort-character-class-elements": "off",
"regexp/unicode-escape": "warn",
"regexp/unicode-property": "warn",
// Import Rules
"import-x/consistent-type-specifier-style": "off",
"import-x/default": "warn",
"import-x/dynamic-import-chunkname": "warn",
"import-x/export": "warn",
"import-x/exports-last": "off",
"import-x/extensions": "warn",
"import-x/first": "warn",
"import-x/group-exports": "off",
"import-x/max-dependencies": "off",
"import-x/namespace": "warn",
"import-x/newline-after-import": "warn",
"import-x/no-absolute-path": "warn",
"import-x/no-amd": "warn",
"import-x/no-anonymous-default-export": "warn",
"import-x/no-commonjs": "warn",
"import-x/no-cycle": "warn",
"import-x/no-default-export": "off",
"import-x/no-deprecated": "warn",
"import-x/no-duplicates": "warn",
"import-x/no-dynamic-require": "warn",
"import-x/no-empty-named-blocks": "warn",
"import-x/no-extraneous-dependencies": "warn",
"import-x/no-import-module-exports": "warn",
"import-x/no-internal-modules": "off",
"import-x/no-mutable-exports": "warn",
"import-x/no-named-as-default": "warn",
"import-x/no-named-as-default-member": "off",
"import-x/no-named-default": "warn",
"import-x/no-named-export": "off",
"import-x/no-namespace": "off",
"import-x/no-nodejs-modules": "off",
"import-x/no-relative-packages": "warn",
"import-x/no-relative-parent-imports": "off",
"import-x/no-rename-default": "off",
"import-x/no-restricted-paths": "warn",
"import-x/no-self-import": "warn",
"import-x/no-unassigned-import": "warn",
"import-x/no-unresolved": "warn",
"import-x/no-unused-modules": "warn",
"import-x/no-useless-path-segments": "warn",
"import-x/no-webpack-loader-syntax": "warn",
"import-x/order": "off",
"import-x/prefer-default-export": "off",
"import-x/prefer-namespace-import": "warn",
"import-x/unambiguous": "warn",
// Accessibility (jsx-a11y)
"jsx-a11y/lang": "warn",
"jsx-a11y/no-aria-hidden-on-focusable": "warn",
"jsx-a11y/prefer-tag-over-role": "warn",
// Math
"math/abs": "warn",
"math/prefer-exponentiation-operator": "warn",
"math/prefer-math-sum-precise": "warn",
// Node
"n/callback-return": "warn",
"n/exports-style": "warn",
"n/global-require": "warn",
"n/handle-callback-err": "warn",
"n/no-callback-literal": "warn",
"n/no-mixed-requires": "warn",
"n/no-new-require": "warn",
"n/no-path-concat": "warn",
"n/no-restricted-import": "warn",
"n/no-restricted-require": "warn",
"n/no-sync": "warn",
"n/no-top-level-await": "warn",
"n/prefer-global/buffer": "warn",
"n/prefer-global/console": "warn",
"n/prefer-global/process": "warn",
"n/prefer-global/text-decoder": "warn",
"n/prefer-global/text-encoder": "warn",
"n/prefer-global/url": "warn",
"n/prefer-global/url-search-params": "warn",
"n/prefer-node-protocol": "warn",
"n/prefer-promises/dns": "warn",
"n/prefer-promises/fs": "warn",
// Promise
"promise/no-multiple-resolved": "warn",
"promise/prefer-await-to-callbacks": "off",
"promise/prefer-await-to-then": "warn",
"promise/prefer-catch": "warn",
"promise/spec-only": "warn",
},
},
// JS/MJS Configuration files
{
files: ["**/*.config.{js,mjs,cts,cjs}"],
languageOptions: {
globals: {
...globals.node,
__dirname: "readonly",
__filename: "readonly",
process: "readonly",
require: "readonly",
module: "readonly",
},
},
plugins: {
"@typescript-eslint": tseslint,
"jsx-a11y": jsxA11y,
"no-unsanitized": nounsanitized,
"prefer-arrow": pluginPreferArrow,
"react-hooks": reactHooks,
"sort-class-members": pluginSortClassMembers,
"unused-imports": pluginUnusedImports,
"write-good-comments": pluginWriteGood,
boundaries: pluginBoundaries,
compat: pluginCompat,
css: css,
depend: depend,
functional: pluginFunctional,
js: js,
math: eslintPluginMath,
n: nodePlugin,
perfectionist: pluginPerfectionist,
"import-x": importX,
prettier: pluginPrettier,
promise: pluginPromise,
putout: putout,
react: pluginReact,
redos: pluginRedos,
regexp: pluginRegexp,
security: pluginSecurity,
sonarjs: pluginSonarjs,
tsdoc: pluginTsdoc,
unicorn: pluginUnicorn,
},
rules: {
...js.configs.all.rules,
...pluginRegexp.configs["flat/all"].rules,
...importX.flatConfigs.recommended.rules,
...importX.flatConfigs.electron.rules,
...importX.flatConfigs.react.rules,
...importX.flatConfigs.typescript.rules,
...pluginPromise.configs["flat/recommended"].rules,
...pluginUnicorn.configs["flat/all"].rules,
...pluginReact.configs.all.rules,
...reactHooks.configs["recommended-latest"].rules,
...jsxA11y.flatConfigs.strict.rules,
...pluginSonarjs.configs.recommended.rules,
...pluginPerfectionist.configs["recommended-natural"].rules,
...pluginRedos.configs.recommended.rules,
...pluginSecurity.configs.recommended.rules,
...nodePlugin.configs["flat/recommended"].rules,
...depend.configs["flat/recommended"].rules,
...eslintPluginMath.configs.recommended.rules,
"one-var": "off",
"no-magic-numbers": "off",
"func-style": "off",
"capitalized-comments": "off",
"class-methods-use-this": "off",
"sort-imports": "off",
"no-inline-comments": "off",
"require-await": "off",
"no-ternary": "off",
"max-lines": "off",
"id-length": "off",
"max-lines-per-function": "off",
"max-statements": "off",
"max-params": "off",
"sort-keys": "off",
"dot-notation": "off",
"no-console": "off",
"no-plusplus": "off",
"no-undefined": "off",
"no-void": "off",
"require-unicode-regexp": "off",
"prefer-arrow-callback": "off",
"no-undef-init": "off",
"object-shorthand": "off",
camelcase: "off",
"max-classes-per-file": "off",
"unicorn/no-keyword-prefix": [
"error",
{
disallowedPrefixes: [
"interface",
"type",
"enum",
],
checkProperties: false,
},
], // Allow "class" prefix for className and other legitimate uses
"unicorn/no-useless-undefined": "off", // Allow undefined in config setups
"unicorn/consistent-function-scoping": "off", // Configs often use different scoping
"unicorn/no-unused-properties": "off", // Allow unused properties in config setups
"unicorn/no-null": "off", // Null is common in config setups
"unicorn/no-await-expression-member": "off", // Allow await in config expressions
"unicorn/filename-case": "off", // Allow config files to have any case
"unicorn/prevent-abbreviations": "off", // Too many false positives in configs
"unused-imports/no-unused-imports": "error",
},
settings: {
n: {
allowModules: [
"electron",
"node",
"electron-devtools-installer",
],
},
"import-x/resolver": {
node: true,
},
react: { version: "19" },
},
},
// Strategic overrides for @typescript-eslint/no-unsafe-type-assertion
// These files/patterns require type assertions due to their nature
{
files: [
// Database utilities: handle SQLite's untyped results
"electron/services/database/utils/typedQueries.ts",
// Type utilities: centralized type manipulation helpers
"shared/utils/typeHelpers.ts",
// Database repositories: controlled SQL with known structure
"electron/services/database/*Repository.ts",
// Database utilities: type mapping and conversion
"electron/services/database/utils/*.ts",
// Validation utilities: runtime type checking
"shared/validation/*.ts",
// IPC layer: Electron boundary type assertions
"electron/preload.ts",
"electron/services/ipc/*.ts",
// Event system core: generic type manipulation
"electron/events/TypedEventBus.ts",
"electron/events/middleware.ts",
// Service containers and dependency injection
"electron/services/ServiceContainer.ts",
// Shared type utilities and safety helpers
"shared/utils/*.ts",
"shared/types/*.ts",
// Theme and configuration types
"src/theme/*.ts",
"src/types/*.ts",
// Chart and UI utilities with third-party integrations
"src/services/chartConfig.ts",
"src/utils/*.ts",
// Store utilities for state management
"src/stores/utils.ts",
"src/stores/**/utils/*.ts",
// Component utilities and form handling
"src/components/**/use*.ts",
"src/hooks/**/*.ts",
// Monitor and system utilities with complex type assertions
"electron/services/monitoring/*.ts",
"electron/utils/*.ts",
// React components with complex third-party integrations
"src/components/**/*.tsx",
"src/components/**/*.ts",
// Additional utility files with necessary type assertions
"electron/services/monitoring/utils/httpClient.ts",
"electron/utils/database/DataImportExportService.ts",
"src/services/logger.ts",
],
rules: {
// Allow type assertions in these contexts where they're necessary and well-documented
"@typescript-eslint/no-unsafe-type-assertion": "off",
},
},
// Store-specific overrides to handle false positives
{
files: [
"src/stores/**/*.ts",
"src/stores/**/*.tsx",
"src/stores/**/*.cts",
"src/stores/**/*.mts",
],
rules: {
// Disable ex/no-unhandled for stores due to false positives with variable access
// The rule incorrectly flags simple parameter/variable access as potential exceptions
"ex/no-unhandled": "off",
},
},
// Strict Test files (Frontend)
{
files: [
"shared/test/StrictTests/*.{ts,tsx,cts,mts}",
"src/test/StrictTests/*.{ts,tsx,cts,mts}",
],
plugins: {
vitest: vitest,
},
rules: {
...vitest.configs.all.rules,
},
settings: {
vitest: {
typecheck: true,
},
},
},
// Strict Test files (Backend)
{
files: ["electron/test/StrictTests/*.{ts,tsx,cts,mts}"],
plugins: {
vitest: vitest,
},
rules: {
...vitest.configs.all.rules,
},
settings: {
vitest: {
typecheck: true,
},
},
},
// Theme components override - disable react-perf rule for inline styling
{
files: ["src/theme/**/*.{ts,tsx,cts,mts}"],
rules: {
// Theme components legitimately need inline styles for dynamic theming
"react-perf/jsx-no-new-object-as-prop": "off",
},
},
// eslint-config-prettier MUST be last to override conflicting rules
eslintConfigPrettier,
];
{
"$schema": "https://www.schemastore.org/package.json",
"name": "uptime-watcher",
"version": "12.3.0",
"description": "An Electron app to monitor website uptime status",
"keywords": [
"electron",
"react",
"uptime",
"monitoring"
],
"homepage": "https://github.com/Nick2bad4u/Uptime-Watcher",
"bugs": {
"url": "https://github.com/Nick2bad4u/Uptime-Watcher/issues",
"email": "[email protected]"
},
"repository": {
"type": "git",
"url": "https://github.com/Nick2bad4u/Uptime-Watcher.git"
},
"license": "Unlicense",
"author": "Nick2bad4u <[email protected]> (https://nick2bad4u.github.io/Uptime-Watcher/)",
"maintainers": [
{
"name": "Nick2bad4u",
"email": "[email protected]"
}
],
"contributors": [
{
"name": "Nick2bad4u",
"email": "[email protected]",
"url": "https://github.com/Nick2bad4u"
}
],
"type": "commonjs",
"main": "dist-electron/main.js",
"scripts": {
"ai:context": "repomix --compress --include \"src/**,electron/**\" --ignore \"**/test/**\"",
"bench": "vitest bench --run",
"bench:tsnode": "ts-node ./benchmarks/eventSystem.bench.ts",
"bench:tsnode:loader": "node --loader ts-node/esm ./benchmarks/eventSystem.bench.ts",
"bench:compare": "vitest bench --run --compare",
"bench:ui": "vitest bench --ui",
"bench:watch": "vitest bench",
"build": "npm run build:electron-vite && npm run postbuild",
"postbuild": "cpy node_modules/node-sqlite3-wasm/dist/node-sqlite3-wasm.wasm dist-electron/ --flat",
"build:electron-main": "npm run build:shared && tsc -p tsconfig.electron.json && npm run postbuild",
"build:electron-vite": "vite build --config ./vite.config.ts",
"build:prepublish": "npm run lint && npm run test && npm run build",
"build:shared": "tsc --project tsconfig.shared.json",
"check-types": "npm run check:shared && npm run check:electron && npm run check:frontend",
"check-types:all": "npm run check:shared && npm run check:electron && npm run check:frontend && npm run check:electron:test && npm run check:frontend:test && npm run check:shared:test",
"check:all": "npm run check:shared && npm run check:electron && npm run check:frontend",
"check:all:test": "npm run check:shared:test && npm run check:electron:test && npm run check:frontend:test",
"check:electron": "tsc --project tsconfig.electron.json --noEmit",
"check:electron:test": "tsc --project tsconfig.electron.test.json --noEmit",
"check:frontend": "tsc --project tsconfig.json --noEmit",
"check:frontend:test": "tsc --project tsconfig.test.json --noEmit",
"check:shared": "tsc --project tsconfig.shared.json --noEmit",
"check:shared:test": "tsc --project tsconfig.shared.test.json --noEmit",
"clean": "rimraf dist dist-electron dist-shared coverage .vite .turbo",
"postclean": "npm run clean && npm run postbuild",
"cognitive-complexity": "cognitive-complexity-ts --threshold 10",
"commit": "git-cz",
"context": "repomix --compress --include \"src/**,electron/**\" --ignore \"**/test/**\"",
"copy-sqlite": "cpy node_modules/node-sqlite3-wasm/dist/node-sqlite3-wasm.wasm dist-electron/ --flat",
"copy-wasm": "cpy node_modules/node-sqlite3-wasm/dist/node-sqlite3-wasm.wasm dist-electron/ --flat",
"debug:electron": "electron --inspect=5858 .",
"debug:main": "electron --inspect-brk=5858 .",
"debug:renderer": "vite --debug",
"debug:transform": "vite --debug plugin-transform",
"debug:vite": "vite --debug",
"dep:check": "npm-check",
"dep:update": "npm-check-updates -u && npm install",
"detect-secrets": "detect-secrets scan",
"dev": "vite",
"dev:profile": "vite --profile",
"dev:sqlite3": "cpy node_modules/node-sqlite3-wasm/dist/node-sqlite3-wasm.wasm dist-electron/ --flat",
"dev:warmup": "vite --debug transform",
"dev:with-sqlite3": "npm run dev:sqlite3 && npm run dev",
"dist": "npm run build && electron-builder --publish=never",
"docs": "typedoc --out docs src",
"docs:build": "npm run docs:typedoc && cd docs/docusaurus && yarn build",
"docs:build:local": "npm run docs:typedoc:local && cd docs/docusaurus && yarn build",
"docs:clean": "rimraf docs",
"docs:deploy": "npm run docs:typedoc && cd docs/docusaurus && yarn deploy",
"docs:deploy:local": "npm run docs:typedoc:local && cd docs/docusaurus && yarn deploy",
"docs:download:all": "npm run docs:download:axios && npm run docs:download:react && npm run docs:download:chartjs && npm run docs:download:zustand && npm run docs:download:electron && npm run docs:download:validator && npm run docs:download:zod && npm run docs:download:sqlite3 && npm run docs:download:sqlite3-wasm && npm run docs:download:nodeping && npm run docs:download:tsdoc",
"docs:download:axios": "node scripts/download-axios-docs.mjs",
"docs:download:chartjs": "node scripts/download-chartjs-docs.mjs",
"docs:download:electron": "node scripts/download-electron-docs.mjs",
"docs:download:nodeping": "node scripts/download-NodePing-docs.mjs",
"docs:download:react": "node scripts/download-react-docs.mjs",
"docs:download:sqlite3": "node scripts/download-nodeSqlite3-docs.mjs",
"docs:download:sqlite3-wasm": "node scripts/download-nodeSqlite3Wasm-docs.mjs",
"docs:download:tsdoc": "node scripts/download-tsdoc-tags.mjs",
"docs:download:validator": "node scripts/download-validator-docs.mjs",
"docs:download:zod": "node scripts/download-Zod-docs.mjs",
"docs:download:zustand": "node scripts/download-zustand-docs.mjs",
"docs:preview": "serve docs",
"docs:typedoc": "cd docs/docusaurus && typedoc --options typedoc.config.json",
"docs:typedoc:local": "cd docs/docusaurus && typedoc --options typedoc.local.config.json",
"docusaurus:broken-links": "npm run docs:typedoc && cd docs/docusaurus && npx docusaurus check",
"docusaurus:broken-links:local": "npm run docs:typedoc:local && cd docs/docusaurus && npx docusaurus check",
"docusaurus:build": "npm run docs:typedoc && cd docs/docusaurus && npx docusaurus build",
"docusaurus:build:local": "npm run docs:typedoc:local && cd docs/docusaurus && npx docusaurus build",
"docusaurus:clean": "npm run docs:typedoc && cd docs/docusaurus && npx docusaurus clear",
"docusaurus:clean:local": "npm run docs:typedoc:local && cd docs/docusaurus && npx docusaurus clear",
"docusaurus:serve": "npm run docs:typedoc && cd docs/docusaurus && npx docusaurus serve",
"docusaurus:serve:local": "npm run docs:typedoc:local && cd docs/docusaurus && npx docusaurus serve",
"docusaurus:sitemap": "npm run docs:typedoc && cd docs/docusaurus && npx docusaurus sitemap",
"docusaurus:sitemap:local": "npm run docs:typedoc:local && cd docs/docusaurus && npx docusaurus sitemap",
"docusaurus:start": "npm run docs:typedoc && cd docs/docusaurus && npx docusaurus start",
"docusaurus:start:local": "npm run docs:typedoc:local && cd docs/docusaurus && npx docusaurus start",
"dupes": "jscpd src/ electron/ shared/",
"duplicates": "jscpd src/ electron/ shared/",
"electron": "wait-on tcp:5173 && electron .",
"electron-dev": "concurrently \"npm run dev\" \"npm run electron\"",
"electron-dev:debug": "concurrently \"npm run dev\" \"npm run electron:debug\"",
"electron-dev:info": "concurrently \"npm run dev\" \"npm run electron:info\"",
"electron-dev:production": "concurrently \"npm run dev\" \"npm run electron:production\"",
"electron-main:debug": "npm run build:electron-main && NODE_ENV=development ./node_modules/.bin/electron ./dist-electron/main.js",
"electron-pack": "electron-builder",
"electron:debug": "wait-on tcp:5173 && electron . --debug",
"electron:info": "wait-on tcp:5173 && electron . --log-info",
"electron:log:debug": "electron --log-debug .",
"electron:log:info": "electron --log-info .",
"electron:log:prod": "electron --log-production .",
"electron:production": "wait-on tcp:5173 && electron . --log-production",
"eslint-find-rules:all": "eslint-find-rules --all-available --flatConfig .\\eslint.config.mjs",
"eslint-find-rules:current": "eslint-find-rules --current --flatConfig .\\eslint.config.mjs",
"eslint-find-rules:deprecated": "eslint-find-rules --deprecated --flatConfig .\\eslint.config.mjs",
"eslint-find-rules:plugin": "eslint-find-rules --plugin --flatConfig .\\eslint.config.mjs",
"eslint-find-rules:unused": "eslint-find-rules --unused --flatConfig .\\eslint.config.mjs",
"fetch-tsdoc": "node scripts/download-tsdoc-tags.mjs",
"find-empty-dirs": "node .\\scripts\\find-empty-dirs.mjs",
"find-empty-dirs:all": "node .\\scripts\\find-empty-dirs.mjs --dirs \".\\\"",
"find-empty-dirs:all:delete": "node .\\scripts\\find-empty-dirs.mjs --dirs \".\\\" --delete",
"find-empty-dirs:delete": "node .\\scripts\\find-empty-dirs.mjs --delete",
"fix-db": "npm run postbuild",
"format": "npm run lint:prettier-fix && npm run lint:css-fix && npm run lint:fix",
"format:check": "npm run lint:prettier && npm run lint:css && npm run lint:check",
"postinstall": "node ./scripts/download-sqlite3-wasm.mjs",
"knip": "knip",
"lint": "eslint --cache .",
"lint:actions": "actionlint -config-file .\\ActionLintConfig.yaml -color",
"lint:action": "actionlint -config-file .\\ActionLintConfig.yaml -color",
"lint:all": "npm run lint && npm run lint:circular && npm run lint:circular:electron && npm run lint:dupes && npm run type-check && npm run type-check:test && npm run lint:madge && npm run knip",
"lint:biome": "@biomejs/biome check",
"lint:biome:fix": "@biomejs/biome check --fix",
"lint:biome:write": "@biomejs/biome check --write",
"lint:ci": "npm run lint:full && npm run lint:strict",
"lint:circular": "madge --circular --ts-config tsconfig.json --extensions ts,tsx,js,jsx src/ electron/ shared/ --exclude \"(^|[\\\\/])(test|dist|dist-electron|node_modules)($|[\\\\/])\"",
"lint:circular:electron": "madge --circular --ts-config tsconfig.electron.json --extensions ts,mts,cts,tsx,js,jsx src/ electron/ shared/ --exclude \"(^|[\\\\/])(test|dist|dist-electron|node_modules)($|[\\\\/])\"",
"lint:cognitive-complexity:electron": "cognitive-complexity-ts --threshold 10 electron/",
"lint:cognitive-complexity:shared": "cognitive-complexity-ts --threshold 10 shared/",
"lint:cognitive-complexity:src": "cognitive-complexity-ts --threshold 10 src/",
"lint:commit": "commitlint --from HEAD~1 --to HEAD --verbose",
"lint:complexity": "eslint --cache . --ext .js,.jsx,.ts,.mts,.cts,.tsx --rule '{\"complexity\": [\"warn\", 10], \"max-lines-per-function\": [\"warn\", 50], \"max-depth\": [\"warn\", 3]}' --format @eslint/eslint-formatter-compact",
"lint:complexity:report": "eslint --cache . --ext .js,.jsx,.ts,.mts,.cts,.tsx --rule '{\"complexity\": [\"warn\", 10], \"max-lines-per-function\": [\"warn\", 50], \"max-depth\": [\"warn\", 3]}' --format json --output-file complexity-report.json",
"lint:css": "stylelint --cache --config stylelint.config.mjs --cache-strategy content --cache-location .\\stylelintcache --cache src/ electron/ shared/ --formatter=verbose",
"lint:css-fix": "stylelint --cache --config stylelint.config.mjs --cache-strategy content --cache-location .\\stylelintcache src/ electron/ shared/ --formatter=verbose --fix",
"lint:css:fix": "stylelint --cache --config stylelint.config.mjs --cache-strategy content --cache-location .\\stylelintcache src/ electron/ shared/ --formatter=verbose --fix",
"lint:current": "eslint --cache .",
"lint:depcheck": "depcheck",
"lint:deps": "depcheck && npx knip",
"lint:dupes": "jscpd src/ electron/ shared/ --config .jscpd.json",
"lint:dupes:all": "jscpd src/ electron/ shared/ --config .jscpd.json --min-lines 3",
"lint:dupes:skiplocal": "jscpd src/ electron/ shared/ --skipLocal --config .jscpd.json",
"lint:dupes:skiplocal:all": "jscpd src/ electron/ shared/ --skipLocal --config .jscpd.json --min-lines 3",
"lint:duplicates": "jscpd src/ electron/ shared/ --config .jscpd.json",
"lint:duplicates:all": "jscpd src/ electron/ shared/ --config .jscpd.json --min-lines 3",
"lint:duplicates:nonlocal": "jscpd src/ electron/ shared/ --skipLocal --config .jscpd.json",
"lint:duplicates:nonlocal:all": "jscpd src/ electron/ shared/ --skipLocal --config .jscpd.json --min-lines 3",
"lint:exports": "ts-unused-exports src/main.tsx",
"lint:exports:electron": "ts-unused-exports electron/main.ts",
"lint:fix": "eslint --cache . --fix",
"lint:format": "prettier . --cache --cache-location=.prettier-cache --check",
"lint:grype": "grype . -c .grype.yaml --name Uptime-Watcher",
"lint:html": "eslint --cache \"**/*.html\" --plugin html",
"lint:imports": "eslint --cache . --ext .js,.jsx,.ts,.mts,.cts,.tsx --rule '{\"import/order\": \"error\", \"import/no-duplicates\": \"error\", \"unused-imports/no-unused-imports\": \"error\"}'",
"lint:js": "eslint --cache \"**/*.{js,jsx}\"",
"lint:json": "eslint --cache \"**/*.json\"",
"lint:knip": "knip",
"lint:leaves": "madge --leaves --ts-config tsconfig.json --extensions ts,tsx,js,jsx src/ electron/ shared/ --exclude \"(^|[\\\\/])(test|dist|dist-electron|node_modules)($|[\\\\/])\"",
"lint:madge": "madge --circular --ts-config tsconfig.json --extensions ts,tsx,js,jsx src/ electron/ shared/ --exclude \"(^|[\\\\/])(test|dist|dist-electron|node_modules)($|[\\\\/])\"",
"lint:madge:circular": "madge --circular --ts-config tsconfig.json --extensions ts,tsx,js,jsx src/ electron/ shared/ --exclude \"(^|[\\\\/])(test|dist|dist-electron|node_modules)($|[\\\\/])\"",
"lint:madge:electron": "madge --circular --ts-config tsconfig.electron.json --extensions ts,tsx,js,jsx src/ electron/ shared/ --exclude \"(^|[\\\\/])(test|dist|dist-electron|node_modules)($|[\\\\/])\"",
"lint:madge:leaves": "madge --leaves --ts-config tsconfig.json --extensions ts,tsx,js,jsx src/ electron/ shared/ --exclude \"(^|[\\\\/])(test|dist|dist-electron|node_modules)($|[\\\\/])\"",
"lint:madge:orphans": "madge --orphans --ts-config tsconfig.json --extensions ts,tsx,js,jsx src/ electron/ shared/ --exclude \"(^|[\\\\/])(test|dist|dist-electron|node_modules)($|[\\\\/])\"",
"lint:markdown": "markdownlint \"**/*.md\"",
"lint:markdown-links": "markdown-link-check README.md",
"lint:markdown:fix": "markdownlint \"**/*.md\" --fix",
"lint:md": "markdownlint \"**/*.md\"",
"lint:metrics": "sloc src/ electron/ shared/",
"lint:orphans": "madge --orphans --ts-config tsconfig.json --extensions ts,tsx,js,jsx src/ electron/ shared/ --exclude \"(^|[\\\\/])(test|dist|dist-electron|node_modules)($|[\\\\/])\"",
"lint:ossf-scorecard": "scorecard-check",
"lint:package": "sort-package-json && npm run lint:package-check",
"lint:package-check": "publint && attw --pack .",
"lint:package-sort": "sort-package-json",
"lint:package-sort-check": "sort-package-json --check",
"lint:pre-commit": "npm run lint:staged && npm run lint:quick",
"lint:prettier": "prettier . --cache --cache-location=.prettier-cache --check",
"lint:prettier-fix": "prettier . --cache --cache-location=.prettier-cache --write",
"lint:pretty": "prettier . --cache --cache-location=.prettier-cache --write",
"lint:prettynow": "prettier . --cache --cache-location=.prettier-cache --write",
"lint:publint": "publint",
"lint:quick": "npm run lint:js && npm run lint:ts && npm run lint:prettier",
"lint:resolve-audit": "resolve-audit --skip-dev",
"lint:secrets": "detect-secrets scan",
"lint:security": "npm run lint:security:resolve-audit && npm run lint:security:sensitive",
"lint:security:resolve-audit": "resolve-audit --skip-dev",
"lint:security:sensitive": "detect-secrets scan",
"lint:sloc": "sloc src/ electron/ shared/",
"lint:sort-package": "sort-package-json",
"lint:sort-package-check": "sort-package-json --check",
"lint:spell": "cspell \"**/*.{js,jsx,ts,tsx,md,css,scss,json}\" --cache --cache-strategy content --color --show-suggestions --show-context --gitignore --config .cspell.json",
"lint:spell-all": "cspell . --cache --cache-strategy content --color --show-suggestions --show-context --gitignore --config .cspell.json",
"lint:spell-export": "cspell \"**/*.{js,jsx,ts,tsx,md,css,scss,json}\" --gitignore --config .cspell.json --words-only --unique --no-progress",
"lint:spell-export:fix": "node .\\scripts\\add-cspell-words.mjs",
"lint:spell:fix": "node .\\scripts\\add-cspell-words.mjs",
"lint:staged": "lint-staged",
"lint:strict": "eslint --cache . --ext .js,.jsx,.ts,.mts,.cts,.tsx --max-warnings 0",
"lint:stylelint": "stylelint --cache --config stylelint.config.mjs --cache-strategy content --cache-location .\\stylelintcache --cache src/ electron/ shared/ --formatter=verbose",
"lint:stylelint:fix": "stylelint --cache --config stylelint.config.mjs --cache-strategy content --cache-location .\\stylelintcache src/ electron/ shared/ --formatter=verbose --fix",
"lint:todo": "leasot 'src/**/*.{js,jsx,ts,tsx}' --reporter json",
"lint:todos": "leasot 'src/**/*.{js,jsx,ts,tsx}' --reporter markdown",
"lint:toml": "eslint --cache \"**/*.toml\" --parser toml-eslint-parser",
"lint:ts": "eslint --cache \"**/*.{ts,tsx}\"",
"lint:unused": "knip --include unlisted,unresolved,duplicates",
"lint:unused-deps": "depcheck --ignores='@types/*,@testing-library/*,@vitest/*'",
"lint:unused-exports": "ts-unused-exports src/main.tsx",
"lint:unused-exports:electron": "ts-unused-exports electron/main.ts",
"lint:vuln": "grype . -c .grype.yaml --name Uptime-Watcher",
"lint:vulnerability": "grype . -c .grype.yaml --name Uptime-Watcher",
"lint:yaml": "yamllint -c .\\.yamllint ./** -f colored",
"madge:circular": "madge --circular --ts-config tsconfig.json --extensions ts,tsx,js,jsx src/ electron/ shared/ --exclude \"(^|[\\\\/])(test|dist|dist-electron|node_modules)($|[\\\\/])\"",
"madge:leaves": "madge --leaves --ts-config tsconfig.json --extensions ts,tsx,js,jsx src/ electron/ shared/ --exclude \"(^|[\\\\/])(test|dist|dist-electron|node_modules)($|[\\\\/])\"",
"madge:orphans": "madge --orphans --ts-config tsconfig.json --extensions ts,tsx,js,jsx src/ electron/ shared/ --exclude \"(^|[\\\\/])(test|dist|dist-electron|node_modules)($|[\\\\/])\"",
"open:coverage": "open-cli coverage/index.html",
"open:docs": "open-cli docs/index.html",
"ossf-scorecard": "scorecard-check",
"prebuild:off": "npm run lint && npm run type-check",
"prepare": "husky",
"prestart:old": "npm run lint && npm run type-check",
"pretest:old": "npm run lint && npm run type-check",
"preview": "vite preview",
"profile": "vite --profile",
"profile:debug": "vite --profile --debug",
"profile:transform": "vite --debug transform",
"prune": "npm prune",
"quality": "npm run lint:full && npm run test:all:coverage",
"quality:check": "npm run lint:ci && npm run test:all:coverage",
"rebuild": "npm run clean && npm install && npm run build",
"reset": "npm run clean && npm install",
"postreset": "npm run reset && npm run postbuild",
"resolve-audit": "resolve-audit --skip-dev",
"scripts:docs:download:all": "npm run docs:download:all",
"scripts:docs:download:axios": "node scripts/download-axios-docs.mjs",
"scripts:docs:download:chartjs": "node scripts/download-chartjs-docs.mjs",
"scripts:docs:download:electron": "node scripts/download-electron-docs.mjs",
"scripts:docs:download:nodeping": "node scripts/download-NodePing-docs.mjs",
"scripts:docs:download:react": "node scripts/download-react-docs.mjs",
"scripts:docs:download:sqlite3": "node scripts/download-nodeSqlite3-docs.mjs",
"scripts:docs:download:sqlite3-wasm": "node scripts/download-nodeSqlite3Wasm-docs.mjs",
"scripts:docs:download:tsdoc": "node scripts/download-tsdoc-tags.mjs",
"scripts:docs:download:validator": "node scripts/download-validator-docs.mjs",
"scripts:docs:download:zod": "node scripts/download-Zod-docs.mjs",
"scripts:docs:download:zustand": "node scripts/download-zustand-docs.mjs",
"scripts:fetch-tsdoc": "node scripts/download-tsdoc-tags.mjs",
"scripts:find-empty-dirs": "node .\\scripts\\find-empty-dirs.mjs",
"scripts:find-empty-dirs:all": "node .\\scripts\\find-empty-dirs.mjs --dirs \".\\\"",
"scripts:find-empty-dirs:all:delete": "node .\\scripts\\find-empty-dirs.mjs --dirs \".\\\" --delete",
"scripts:find-empty-dirs:delete": "node .\\scripts\\find-empty-dirs.mjs --delete",
"scripts:lint:spell-export:fix": "node .\\scripts\\add-cspell-words.mjs",
"scripts:lint:spell:fix": "node .\\scripts\\add-cspell-words.mjs",
"scripts:postinstall": "node ./scripts/download-sqlite3-wasm.mjs",
"scripts:sqlite:download-wasm": "node ./scripts/download-sqlite3-wasm.mjs",
"scripts:sqlite:verify-wasm": "node ./scripts/verify-sqlite3-wasm.mjs || echo 'Verification script not implemented yet.'",
"scripts:tsdoc-update": "node scripts/download-tsdoc-tags.mjs",
"scripts:update-tsdoc": "node scripts/download-tsdoc-tags.mjs",
"scripts:validate:components": "node ./scripts/validate-components.mjs",
"security:check": "npm audit",
"security:fix": "npm audit fix",
"sloc": "sloc src/ electron/ shared/",
"sort-eslint-rules": "node scripts/sort-eslint-rules.mjs",
"sort-package": "sort-package-json",
"sort-package-check": "sort-package-json --check",
"sqlite:clean-wasm": "rm -f dist-electron/node-sqlite3-wasm.wasm",
"sqlite:download-wasm": "node ./scripts/download-sqlite3-wasm.mjs",
"sqlite:reinstall-wasm": "npm run sqlite:clean-wasm && npm run sqlite:download-wasm",
"sqlite:verify-wasm": "node ./scripts/verify-sqlite3-wasm.js || echo 'Verification script not implemented yet.'",
"start": "npm run dev",
"start-both": "concurrently \"npm run dev\" \"npm run electron-dev\"",
"start-fix": "npm run postbuild && npm run dev",
"start:clean": "npm run clean && npm run start",
"start:debug": "npm run debug:electron",
"start:electron": "electron .",
"start:prod": "npm run build && npm run start:electron",
"start:renderer": "vite",
"start:reset": "npm run clean && npm run build && npm run start",
"stylelint-find-rules:all": "stylelint-find-new-rules ./stylelint.config.mjs --available",
"stylelint-find-rules:current": "stylelint-find-new-rules ./stylelint.config.mjs --current",
"stylelint-find-rules:deprecated": "stylelint-find-new-rules ./stylelint.config.mjs --deprecated",
"stylelint-find-rules:invalid": "stylelint-find-new-rules ./stylelint.config.mjs --invalid",
"stylelint-find-rules:unused": "stylelint-find-new-rules ./stylelint.config.mjs --unused",
"test": "vitest run",
"test:all": "npm run test && npm run test:electron && npm run test:shared",
"test:all:coverage": "npm run test:coverage && npm run test:electron:coverage && npm run test:shared:coverage",
"test:bail": "vitest --bail 50",
"test:coverage": "vitest run --coverage",
"test:coverage:open": "npm run test:coverage && npm run open:coverage",
"test:debug": "vitest run --debug",
"test:debug:coverage": "vitest run --coverage --debug",
"test:debug:ui": "vitest --ui --debug",
"test:debug:watch": "vitest --watch --debug",
"test:electron": "vitest run --config vitest.electron.config.ts",
"test:electron:coverage": "vitest run --config vitest.electron.config.ts --coverage",
"test:electron:ui": "vitest --config vitest.electron.config.ts --ui",
"test:run": "vitest run",
"test:run:bail": "vitest run --bail 50",
"test:run:watch": "vitest run --watch",
"test:shared": "vitest run --config vitest.shared.config.ts",
"test:shared:coverage": "vitest run --config vitest.shared.config.ts --coverage",
"test:shared:ui": "vitest --config vitest.shared.config.ts --ui",
"test:ui": "vitest run --ui",
"test:watch": "vitest run --watch",
"test:watch:electron": "vitest run --config vitest.electron.config.ts --watch",
"test:watch:frontend": "vitest run --config vitest.config.ts --watch",
"test:watch:shared": "vitest run --config vitest.shared.config.ts --watch",
"tsdoc-update": "node scripts/download-tsdoc-tags.mjs",
"tsg:graph:electron": "tsg --TB --config tsconfig.electron.json",
"tsg:graph:src": "tsg --TB --config tsconfig.json",
"tsg:graph:stats": "tsg --TB --metrics --measure-instability",
"type-check": "npm run check-types",
"type-check:all": "npm run check:all",
"type-check:test": "npm run check:all:test",
"update-tsdoc": "node scripts/download-tsdoc-tags.mjs",
"validate:components": "node ./scripts/validate-components.mjs"
},
"eslintConfig": {
"extends": "eslint.config.mjs"
},
"overrides": {
"@codecov/vite-plugin": {
"vite": "$vite"
},
"@react-scan/vite-plugin-react-scan": {
"react-scan": "$react-scan",
"vite": "$vite"
},
"@typescript-eslint/eslint-plugin": "$@typescript-eslint/eslint-plugin",
"@typescript-eslint/experimental-utils": {
"eslint": "$eslint"
},
"@typescript-eslint/parser": "$@typescript-eslint/parser",
"*": {
"vite": "$vite",
"eslint": "$eslint",
"@typescript-eslint/parser": "$@typescript-eslint/parser",
"@typescript-eslint/utils": "$@typescript-eslint/utils",
"prettier": "$prettier",
"stylelint": "$stylelint",
"typescript": "$typescript",
"tsx": "$tsx",
"typedoc": "$typedoc",
"vitest": "$vitest",
"@typescript-eslint/eslint-plugin": "$@typescript-eslint/eslint-plugin"
},
"eslint-etc": {
"eslint": "$eslint"
},
"eslint-plugin-deprecation": {
"eslint": "$eslint"
},
"eslint-plugin-etc": {
"eslint": "$eslint"
},
"eslint-plugin-fsecond": {
"@typescript-eslint/parser": {
"eslint": "$eslint"
},
"@typescript-eslint/utils": {
"eslint": "$eslint"
},
"eslint": "$eslint"
},
"eslint-plugin-istanbul": {
"eslint": "$eslint"
},
"eslint-plugin-no-lookahead-lookbehind-regexp": {
"eslint": "$eslint"
},
"eslint-plugin-react-form-fields": {
"@typescript-eslint/experimental-utils": {
"eslint": "$eslint"
},
"eslint": "$eslint"
},
"eslint-plugin-safe-jsx": {
"eslint": "$eslint"
},
"eslint-plugin-total-functions": {
"eslint": "$eslint"
},
"eslint-plugin-usememo-recommendations": {
"@typescript-eslint/utils": {
"eslint": "$eslint"
},
"eslint": "$eslint"
},
"is-immutable-type": {
"eslint": "$eslint"
},
"stylelint-config-standard-scss": {
"stylelint": "$stylelint"
},
"stylelint-group-selectors": {
"stylelint": "$stylelint"
},
"stylelint-high-performance-animation": {
"stylelint": "$stylelint"
},
"vite": {
"tsx": "$tsx"
}
},
"dependencies": {
"@shared/types": "file:./shared/types",
"@shared/utils": "file:./shared/utils",
"@shared/validation": "file:./shared/validation",
"axios": "^1.11.0",
"chart.js": "^4.5.0",
"chartjs-adapter-date-fns": "^3.0.0",
"chartjs-plugin-zoom": "^2.2.0",
"electron-log": "^5.4.3",
"electron-updater": "^6.6.2",
"is-port-reachable": "^4.0.0",
"node-sqlite3-wasm": "^0.8.47",
"ping": "^0.4.4",
"react": "^19.1.1",
"react-chartjs-2": "^5.3.0",
"react-dom": "^19.1.1",
"react-icons": "^5.5.0",
"validator": "^13.15.15",
"zod": "^4.0.17",
"zustand": "^5.0.8"
},
"devDependencies": {
"@arethetypeswrong/cli": "^0.18.2",
"@arthurgeron/eslint-plugin-react-usememo": "^2.5.0",
"@awmottaz/prettier-plugin-void-html": "^1.9.0",
"@biomejs/biome": "2.2.0",
"@codecov/vite-plugin": "^1.9.1",
"@commitlint/cli": "^19.8.1",
"@commitlint/config-conventional": "^19.8.1",
"@commitlint/prompt": "^19.8.1",
"@commitlint/prompt-cli": "^19.8.1",
"@commitlint/types": "^19.8.1",
"@cspell/cspell-bundled-dicts": "^9.2.0",
"@cspell/cspell-types": "^9.2.0",
"@docusaurus/eslint-plugin": "^3.8.1",
"@dword-design/eslint-plugin-import-alias": "^6.0.3",
"@electron/notarize": "^3.0.2",
"@eslint-community/eslint-plugin-eslint-comments": "^4.5.0",
"@eslint-react/eslint-plugin": "^1.52.6",
"@eslint/compat": "^1.3.2",
"@eslint/css": "^0.10.0",
"@eslint/eslintrc": "^3.3.1",
"@eslint/js": "^9.33.0",
"@eslint/json": "^0.13.1",
"@eslint/markdown": "^7.1.0",
"@eslint/mcp": "^0.1.1",
"@executeautomation/database-server": "^1.1.0",
"@html-eslint/eslint-plugin": "^0.45.0",
"@html-eslint/parser": "^0.45.0",
"@jcoreio/eslint-plugin-implicit-dependencies": "^1.2.0",
"@jscpd/badge-reporter": "^4.0.1",
"@metamask/eslint-plugin-design-tokens": "^1.1.1",
"@microsoft/eslint-plugin-sdl": "^1.1.0",
"@microsoft/tsdoc-config": "^0.17.1",
"@playwright/test": "^1.55.0",
"@putout/eslint": "^4.1.0",
"@putout/eslint-flat": "^3.0.1",
"@react-scan/vite-plugin-react-scan": "^0.1.8",
"@secretlint/secretlint-rule-no-dotenv": "^11.0.2",
"@secretlint/secretlint-rule-no-homedir": "^11.0.2",
"@secretlint/secretlint-rule-pattern": "^11.0.2",
"@secretlint/secretlint-rule-preset-recommend": "^11.0.2",
"@secretlint/secretlint-rule-secp256k1-privatekey": "^11.0.2",
"@styled/typescript-styled-plugin": "^1.0.1",
"@stylistic/eslint-plugin": "^5.2.3",
"@tailwindcss/forms": "^0.5.10",
"@tailwindcss/postcss": "^4.1.12",
"@tailwindcss/typography": "^0.5.16",
"@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^6.8.0",
"@testing-library/react": "^16.3.0",
"@testing-library/user-event": "^14.6.1",
"@types/async": "^3.2.25",
"@types/cssnano": "^5.1.3",
"@types/eslint": "^9.6.1",
"@types/eslint-plugin-jsx-a11y": "^6.10.0",
"@types/eslint-plugin-prettier": "^3.1.3",
"@types/eslint-plugin-react-refresh": "^0.4.0",
"@types/eslint-plugin-security": "^3.0.0",
"@types/eslint-plugin-tailwindcss": "^3.17.0",
"@types/jest": "^30.0.0",
"@types/jsdom": "^21.1.7",
"@types/json-schema": "^7.0.15",
"@types/lint-staged": "^14.0.0",
"@types/madge": "^5.0.3",
"@types/mocha": "^10.0.10",
"@types/node": "^24.3.0",
"@types/ping": "^0.4.4",
"@types/postcss-flexbugs-fixes": "^5.0.3",
"@types/postcss-import": "^14.0.3",
"@types/postcss-normalize": "^9.0.4",
"@types/prop-types": "^15.7.15",
"@types/react": "^19.1.10",
"@types/react-dom": "^19.1.7",
"@types/react-refresh": "^0.14.6",
"@types/semver": "^7.7.0",
"@types/sqlite3": "^5.1.0",
"@types/trusted-types": "^2.0.7",
"@types/validator": "^13.15.2",
"@types/wait-on": "^5.3.4",
"@types/webpack": "^5.28.5",
"@typescript-eslint/eslint-plugin": "^8.40.0",
"@typescript-eslint/parser": "^8.40.0",
"@typescript-eslint/types": "^8.40.0",
"@typescript/native-preview": "^7.0.0-dev.20250821.1",
"@vitejs/plugin-react": "^5.0.1",
"@vitest/coverage-istanbul": "^3.2.4",
"@vitest/coverage-v8": "^3.2.4",
"@vitest/eslint-plugin": "^1.3.4",
"@vitest/snapshot": "^3.2.4",
"@vitest/ui": "^3.2.4",
"async": "^3.2.6",
"autoprefixer": "^10.4.21",
"canvas": "^3.2.0",
"cognitive-complexity-ts": "^0.6.5",
"concurrently": "^9.2.0",
"cpy-cli": "^6.0.0",
"cross-env": "^10.0.0",
"cspell": "^9.2.0",
"cssnano": "^7.1.0",
"cssnano-preset-advanced": "^7.0.8",
"depcheck": "^1.4.7",
"docusaurus-plugin-typedoc": "^1.4.2",
"electron": "^37.3.1",
"electron-builder": "^26.0.12",
"electron-builder-squirrel-windows": "^26.0.12",
"electron-devtools-installer": "^4.0.0",
"electron-publish": "^26.0.11",
"eslint": "^9.33.0",
"eslint-config-prettier": "^10.1.8",
"eslint-formatter-compact": "^8.40.0",
"eslint-import-resolver-typescript": "^4.4.4",
"eslint-plugin-array-func": "^5.0.2",
"eslint-plugin-boundaries": "^5.0.1",
"eslint-plugin-canonical": "^5.1.3",
"eslint-plugin-clean-code": "^0.1.12",
"eslint-plugin-comment-length": "^2.2.2",
"eslint-plugin-compat": "^6.0.2",
"eslint-plugin-css": "^0.11.0",
"eslint-plugin-css-modules": "^2.12.0",
"eslint-plugin-depend": "^1.2.0",
"eslint-plugin-deprecation": "^3.0.0",
"eslint-plugin-es-x": "^9.0.0",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-etc": "^2.0.3",
"eslint-plugin-exception-handling": "^1.5.4",
"eslint-plugin-file-progress": "^3.0.2",
"eslint-plugin-filename-export": "^2.0.0",
"eslint-plugin-format-sql": "^1.1.1",
"eslint-plugin-fsecond": "^1.3.0",
"eslint-plugin-function-name": "^2.0.5",
"eslint-plugin-functional": "^9.0.2",
"eslint-plugin-goodeffects": "^1.0.2",
"eslint-plugin-granular-selectors": "^1.3.1",
"eslint-plugin-html": "^8.1.3",
"eslint-plugin-import-x": "^4.16.1",
"eslint-plugin-import-zod": "^1.2.0",
"eslint-plugin-istanbul": "^0.1.2",
"eslint-plugin-json-schema-validator": "^5.4.1",
"eslint-plugin-jsonc": "^2.20.1",
"eslint-plugin-jsx-a11y": "^6.10.2",
"eslint-plugin-jsx-plus": "^0.1.0",
"eslint-plugin-listeners": "^1.5.1",
"eslint-plugin-loadable-imports": "^1.0.1",
"eslint-plugin-math": "^0.13.0",
"eslint-plugin-mdx": "^3.6.2",
"eslint-plugin-module-interop": "^0.3.1",
"eslint-plugin-n": "^17.21.3",
"eslint-plugin-neverthrow": "^1.1.4",
"eslint-plugin-nitpick": "^0.12.0",
"eslint-plugin-no-barrel-files": "^1.2.2",
"eslint-plugin-no-constructor-bind": "^2.0.4",
"eslint-plugin-no-explicit-type-exports": "^0.12.1",
"eslint-plugin-no-function-declare-after-return": "^1.1.0",
"eslint-plugin-no-hardcoded-strings": "^1.0.0",
"eslint-plugin-no-lookahead-lookbehind-regexp": "^0.3.0",
"eslint-plugin-no-only-tests": "^3.3.0",
"eslint-plugin-no-unary-plus": "^0.3.1",
"eslint-plugin-no-unawaited-dot-catch-throw": "^0.1.1",
"eslint-plugin-no-unsanitized": "^4.1.2",
"eslint-plugin-no-use-extend-native": "^0.7.2",
"eslint-plugin-node-dependencies": "^1.1.2",
"eslint-plugin-observers": "^1.0.1",
"eslint-plugin-package-json": "^0.54.0",
"eslint-plugin-perfectionist": "^4.15.0",
"eslint-plugin-prefer-arrow": "^1.2.3",
"eslint-plugin-prettier": "^5.5.4",
"eslint-plugin-promise": "^7.2.1",
"eslint-plugin-publint": "^0.3.2-beta.0",
"eslint-plugin-putout": "^28.0.4",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-compiler": "^19.1.0-rc.2",
"eslint-plugin-react-dom": "^1.52.6",
"eslint-plugin-react-form-fields": "^1.2.22",
"eslint-plugin-react-hook-form": "^0.3.1",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-hooks-addons": "^0.5.0",
"eslint-plugin-react-hooks-extra": "^1.52.6",
"eslint-plugin-react-naming-convention": "^1.52.6",
"eslint-plugin-react-perf": "^3.3.3",
"eslint-plugin-react-prefer-function-component": "^4.0.1",
"eslint-plugin-react-refresh": "^0.4.20",
"eslint-plugin-react-require-testid": "^1.0.4",
"eslint-plugin-react-useeffect": "^1.0.12",
"eslint-plugin-react-web-api": "^1.52.6",
"eslint-plugin-redos": "^4.5.0",
"eslint-plugin-regexp": "^2.10.0",
"eslint-plugin-require-jsdoc": "^1.0.4",
"eslint-plugin-safe-jsx": "^1.1.1",
"eslint-plugin-security": "^3.0.1",
"eslint-plugin-sonarjs": "^3.0.4",
"eslint-plugin-sort-class-members": "^1.21.0",
"eslint-plugin-sort-destructure-keys": "^2.0.0",
"eslint-plugin-sort-react-dependency-arrays": "^1.0.0",
"eslint-plugin-sql-template": "^3.1.0",
"eslint-plugin-ssr-friendly": "^1.3.0",
"eslint-plugin-styled-components-a11y": "^2.2.1",
"eslint-plugin-tailwindcss": "^4.0.0-beta.0",
"eslint-plugin-testing-library": "^7.6.6",
"eslint-plugin-toml": "^0.12.0",
"eslint-plugin-toplevel": "^1.2.0",
"eslint-plugin-total-functions": "^7.1.0",
"eslint-plugin-tree-shaking": "^1.12.2",
"eslint-plugin-tsdoc": "^0.4.0",
"eslint-plugin-undefined-css-classes": "^0.1.3",
"eslint-plugin-unicorn": "^60.0.0",
"eslint-plugin-unused-imports": "^4.2.0",
"eslint-plugin-usememo-recommendations": "^1.0.2",
"eslint-plugin-validate-jsx-nesting": "^0.1.1",
"eslint-plugin-write-good-comments": "^0.2.0",
"eslint-plugin-xss": "^0.1.12",
"eslint-plugin-yml": "^1.18.0",
"eslint-plugin-zod": "^1.4.0",
"git-cliff": "^2.10.0",
"globals": "^16.3.0",
"globals-vitest": "^3.2.4",
"husky": "^9.1.7",
"jiti": "^2.5.1",
"jscpd": "^4.0.5",
"jsdom": "^26.1.0",
"jsonc-eslint-parser": "^2.4.0",
"knip": "^5.63.0",
"leasot": "^14.4.0",
"lint-staged": "^16.1.5",
"madge": "^8.0.0",
"markdown-link-check": "^3.13.7",
"markdownlint": "^0.38.0",
"msw": "^2.10.5",
"nyc": "^17.1.0",
"pkg-types": "^2.3.0",
"postcss": "^8.5.6",
"postcss-assets": "^6.0.0",
"postcss-clamp": "^4.1.0",
"postcss-combine-duplicated-selectors": "^10.0.3",
"postcss-flexbugs-fixes": "^5.0.2",
"postcss-import": "^16.1.1",
"postcss-inline-svg": "^6.0.0",
"postcss-logical": "^8.1.0",
"postcss-normalize": "^13.0.1",
"postcss-reporter": "^7.1.0",
"postcss-round-subpixels": "^2.0.0",
"postcss-sort-media-queries": "^5.2.0",
"postcss-viewport-height-correction": "^1.1.1",
"prettier": "^3.6.2",
"prettier-eslint": "^16.4.2",
"prettier-plugin-ini": "^1.3.0",
"prettier-plugin-interpolated-html-tags": "^2.0.1",
"prettier-plugin-jsdoc": "^1.3.3",
"prettier-plugin-merge": "^0.8.0",
"prettier-plugin-multiline-arrays": "^4.0.3",
"prettier-plugin-packagejson": "^2.5.19",
"prettier-plugin-properties": "^0.3.0",
"prettier-plugin-sort-json": "^4.1.1",
"prettier-plugin-sql": "^0.19.2",
"prettier-plugin-tailwindcss": "^0.6.14",
"publint": "^0.3.12",
"putout": "^40.6.0",
"react-refresh": "^0.17.0",
"react-scan": "^0.4.3",
"remark-github": "^12.0.0",
"remark-mdx": "^3.1.0",
"rollup-plugin-visualizer": "^6.0.3",
"secretlint": "^11.0.2",
"sort-package-json": "^3.4.0",
"stylelint": "^16.23.1",
"stylelint-config-alphabetical-order": "^1.0.0",
"stylelint-config-idiomatic-order": "^10.0.0",
"stylelint-config-recess-order": "^7.2.0",
"stylelint-config-recommended": "^17.0.0",
"stylelint-config-standard": "^39.0.0",
"stylelint-config-standard-scss": "^15.0.1",
"stylelint-config-tailwindcss": "^1.0.0",
"stylelint-declaration-block-no-ignored-properties": "^2.8.0",
"stylelint-declaration-strict-value": "^1.10.11",
"stylelint-find-new-rules": "^5.0.0",
"stylelint-gamut": "^1.3.4",
"stylelint-group-selectors": "^1.0.10",
"stylelint-high-performance-animation": "^1.11.0",
"stylelint-order": "^7.0.0",
"stylelint-plugin-defensive-css": "^1.0.4",
"stylelint-plugin-logical-css": "^1.2.3",
"stylelint-prettier": "^5.0.3",
"stylelint-react-native": "^2.7.0",
"stylelint-use-nesting": "^6.0.0",
"tailwind-csstree": "^0.1.3",
"tailwind-scrollbar-hide": "^4.0.0",
"tailwindcss": "^4.1.12",
"toml-eslint-parser": "^0.10.0",
"ts-morph": "^26.0.0",
"ts-morph-helpers": "^0.6.3",
"ts-unused-exports": "^11.0.1",
"tslib": "^2.8.1",
"tsx": "^4.20.4",
"tw-animate-css": "^1.3.7",
"type-fest": "^4.41.0",
"typedoc": "^0.28.10",
"typedoc-plugin-coverage": "^4.0.1",
"typedoc-plugin-dt-links": "^2.0.15",
"typedoc-plugin-external-package-links": "^0.1.0",
"typedoc-plugin-markdown": "^4.8.1",
"typedoc-plugin-mdn-links": "^5.0.8",
"typedoc-plugin-missing-exports": "^4.1.0",
"typedoc-plugin-remark": "^2.0.1",
"typedoc-plugin-rename-defaults": "^0.7.3",
"typedoc-plugin-replace-text": "^4.2.0",
"typedoc-plugin-zod": "^1.4.2",
"typescript": "^5.9.2",
"typescript-eslint": "^8.40.0",
"typescript-eslint-language-service": "^5.0.5",
"typestat": "^0.8.18",
"vite": "^7.1.3",
"vite-bundle-analyzer": "^1.2.1",
"vite-bundle-visualizer": "^1.2.1",
"vite-css-modules": "^1.10.0",
"vite-plugin-checker": "^0.10.2",
"vite-plugin-devtools-json": "^1.0.0",
"vite-plugin-electron": "^0.29.0",
"vite-plugin-mcp": "^0.2.4",
"vite-plugin-package-version": "^1.1.0",
"vite-plugin-static-copy": "^3.1.2",
"vitest": "^3.2.4",
"wait-on": "^8.0.4",
"yaml-eslint-parser": "^1.3.0"
},
"peerDependencies": {
"react-scan": "^0.4.3"
},
"bundleDependencies": [
"@shared/types",
"@shared/utils",
"@shared/validation"
],
"packageManager": "[email protected]",
"engines": {
"node": ">=23.0.0"
},
"os": [
"windows",
"linux",
"mac",
"macOS",
"win64",
"win64-exe",
"win64-squirrel",
"win64-msi",
"win64-zip",
"win64-7z",
"win64-nsis",
"win64-nsis-web",
"win64-portable",
"win64-tar.bz2",
"win64-tar.gz",
"win64-tar.xz",
"win32",
"win32-exe",
"win32-squirrel",
"win32-msi",
"win32-zip",
"win32-7z",
"win32-nsis",
"win32-nsis-web",
"win32-portable",
"win32-tar.bz2",
"win32-tar.gz",
"win32-tar.xz",
"mac-x64-dmg",
"mac-x64-pkg",
"mac-x64-tar.xz",
"mac-x64-tar.gz",
"mac-x64-tar.bz2",
"mac-arm64-dmg",
"mac-arm64-pkg",
"mac-arm64-tar.xz",
"mac-arm64-tar.gz",
"mac-arm64-tar.bz2",
"darwin",
"freebsd",
"apk",
"pacman",
"deb",
"rpm",
"snap"
],
"icon": "icons/favicon.ico",
"appid": "io.github.uptime-watcher",
"build": {
"icon": "icons/favicon.ico",
"appId": "io.github.uptime-watcher",
"artifactName": "Uptime-Watcher-${platform}-${arch}-${version}.${ext}",
"asar": true,
"publish": [
{
"provider": "github",
"owner": "Nick2bad4u",
"repo": "Uptime-Watcher"
}
],
"productName": "Uptime-Watcher",
"directories": {
"output": "dist"
},
"files": [
"dist-electron/**/*",
"dist/**/*",
"node_modules/**/*",
"!node_modules/@tailwindcss/oxide-*",
"!node_modules/@tailwindcss/oxide-*/**",
"!dist/mac-universal-*",
"!dist/*.app",
"!dist/*.dmg",
"!dist/*.zip"
],
"win": {
"icon": "icons/favicon-256x256.ico",
"target": [
"nsis",
"nsis-web",
"zip",
"7z",
"portable",
"squirrel",
"msi",
"tar.xz",
"tar.gz",
"tar.bz2"
],
"legalTrademarks": "Uptime Watcher",
"requestedExecutionLevel": "asInvoker"
},
"nsis": {
"oneClick": false,
"allowElevation": true,
"allowToChangeInstallationDirectory": true,
"createDesktopShortcut": true,
"createStartMenuShortcut": true,
"runAfterFinish": true,
"artifactName": "Uptime-Watcher-nsis-${arch}-${version}.${ext}"
},
"nsisWeb": {
"artifactName": "Uptime-Watcher-nsis-web-${arch}-${version}.${ext}"
},
"portable": {
"artifactName": "Uptime-Watcher-portable-${arch}-${version}.${ext}"
},
"squirrelWindows": {
"artifactName": "Uptime-Watcher-squirrel-${arch}-${version}.${ext}"
},
"msi": {
"artifactName": "Uptime-Watcher-msi-${arch}-${version}.${ext}"
},
"appImage": {
"artifactName": "Uptime-Watcher-appimage-${arch}-${version}.${ext}"
},
"deb": {
"artifactName": "Uptime-Watcher-deb-${arch}-${version}.${ext}"
},
"rpm": {
"artifactName": "Uptime-Watcher-rpm-${arch}-${version}.${ext}"
},
"snap": {
"artifactName": "Uptime-Watcher-snap-${arch}-${version}.${ext}"
},
"freebsd": {
"artifactName": "Uptime-Watcher-freebsd-${arch}-${version}.${ext}"
},
"pacman": {
"artifactName": "Uptime-Watcher-pacman-${arch}-${version}.${ext}"
},
"p5p": {
"artifactName": "Uptime-Watcher-p5p-${arch}-${version}.${ext}"
},
"apk": {
"artifactName": "Uptime-Watcher-apk-${arch}-${version}.${ext}"
},
"dmg": {
"artifactName": "Uptime-Watcher-dmg-${arch}-${version}.${ext}"
},
"pkg": {
"artifactName": "Uptime-Watcher-pkg-${arch}-${version}.${ext}"
},
"flatpak": {
"artifactName": "Uptime-Watcher-flatpak-${arch}-${version}.${ext}"
},
"mac": {
"icon": "icons/favicon-512x512.icns",
"target": [
"dmg",
"zip",
"pkg",
"tar.xz",
"tar.gz",
"tar.bz2"
],
"category": "public.app-category.productivity",
"hardenedRuntime": true,
"gatekeeperAssess": true,
"x64ArchFiles": "Contents/Resources/app.asar.unpacked/node_modules/lightningcss-darwin-arm64/**"
},
"linux": {
"icon": "icons/favicon-256x256.png",
"target": [
"AppImage",
"deb",
"rpm",
"snap",
"freebsd",
"pacman",
"apk",
"zip",
"tar.xz",
"tar.gz",
"tar.bz2"
],
"category": "Utility",
"synopsis": "A cross-platform Electron app to monitor website uptime status",
"maintainer": "Nick2bad4u <[email protected]>",
"desktop": {
"entry": {
"Name": "Uptime Watcher",
"Comment": "View and analyze Website Uptime",
"Categories": "Utility;"
}
}
}
},
"readme": "README.md"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment