diff --git a/eslint.config.js b/eslint.config.js deleted file mode 100644 index cc7a828..0000000 --- a/eslint.config.js +++ /dev/null @@ -1,208 +0,0 @@ -import js from '@eslint/js'; -import typescript from '@typescript-eslint/eslint-plugin'; -import typescriptParser from '@typescript-eslint/parser'; -import react from 'eslint-plugin-react'; -import reactHooks from 'eslint-plugin-react-hooks'; -import reactRefresh from 'eslint-plugin-react-refresh'; -import jsxA11y from 'eslint-plugin-jsx-a11y'; - -export default [ - js.configs.recommended, - { - files: ['**/*.{js,jsx,ts,tsx}'], - languageOptions: { - parser: typescriptParser, - parserOptions: { - ecmaVersion: 'latest', - sourceType: 'module', - ecmaFeatures: { - jsx: true, - }, - }, - }, - plugins: { - '@typescript-eslint': typescript, - 'react': react, - 'react-hooks': reactHooks, - 'react-refresh': reactRefresh, - 'jsx-a11y': jsxA11y, - }, - rules: { - // TypeScript rules - ...typescript.configs.recommended.rules, - '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], - '@typescript-eslint/no-explicit-any': 'warn', - '@typescript-eslint/no-non-null-assertion': 'warn', - - // React rules - ...react.configs.recommended.rules, - 'react/react-in-jsx-scope': 'off', // Not needed with React 17+ - 'react/prop-types': 'off', // Using TypeScript instead - 'react/jsx-uses-react': 'off', // Not needed with React 17+ - 'react/jsx-uses-vars': 'error', - 'react/jsx-no-undef': 'error', - 'react/jsx-key': 'error', - 'react/jsx-no-duplicate-props': 'error', - 'react/jsx-pascal-case': 'error', - 'react/no-array-index-key': 'warn', - 'react/no-danger': 'warn', - 'react/no-deprecated': 'error', - 'react/no-direct-mutation-state': 'error', - 'react/no-unescaped-entities': 'error', - 'react/no-unknown-property': 'error', - 'react/require-render-return': 'error', - 'react/self-closing-comp': 'error', - 'react/jsx-wrap-multilines': 'error', - 'react/jsx-closing-bracket-location': 'error', - 'react/jsx-closing-tag-location': 'error', - 'react/jsx-curly-spacing': ['error', 'never'], - 'react/jsx-equals-spacing': ['error', 'never'], - 'react/jsx-first-prop-new-line': ['error', 'multiline-multiprop'], - 'react/jsx-max-props-per-line': ['error', { maximum: 1, when: 'multiline' }], - 'react/jsx-no-bind': 'warn', - 'react/jsx-no-literals': 'off', - 'react/jsx-sort-props': 'off', - - // React Hooks rules - ...reactHooks.configs.recommended.rules, - - // React Refresh rules - 'react-refresh/only-export-components': [ - 'warn', - { allowConstantExport: true }, - ], - - // Accessibility rules - ...jsxA11y.configs.recommended.rules, - 'jsx-a11y/alt-text': 'error', - 'jsx-a11y/anchor-has-content': 'error', - 'jsx-a11y/anchor-is-valid': 'error', - 'jsx-a11y/aria-props': 'error', - 'jsx-a11y/aria-proptypes': 'error', - 'jsx-a11y/aria-unsupported-elements': 'error', - 'jsx-a11y/click-events-have-key-events': 'warn', - 'jsx-a11y/heading-has-content': 'error', - 'jsx-a11y/img-redundant-alt': 'error', - 'jsx-a11y/no-access-key': 'error', - 'jsx-a11y/role-has-required-aria-props': 'error', - 'jsx-a11y/role-supports-aria-props': 'error', - 'jsx-a11y/scope': 'error', - 'jsx-a11y/tabindex-no-positive': 'error', - - // General JavaScript/TypeScript rules - 'no-console': 'warn', - 'no-debugger': 'error', - 'no-unused-vars': 'off', // Handled by TypeScript version - 'prefer-const': 'error', - 'no-var': 'error', - 'eqeqeq': ['error', 'always'], - 'curly': 'warn', // Changed from error to warn - 'brace-style': ['error', '1tbs'], - 'comma-dangle': 'warn', // Changed from error to warn - 'comma-spacing': ['error', { before: false, after: true }], - 'comma-style': ['error', 'last'], - 'computed-property-spacing': ['error', 'never'], - 'func-call-spacing': ['error', 'never'], - 'key-spacing': ['error', { beforeColon: false, afterColon: true }], - 'keyword-spacing': ['error', { before: true, after: true }], - 'object-curly-spacing': ['error', 'always'], - 'semi-spacing': ['error', { before: false, after: true }], - 'space-before-blocks': 'error', - 'space-before-function-paren': ['error', 'never'], - 'space-in-parens': ['error', 'never'], - 'space-infix-ops': 'error', - 'space-unary-ops': ['error', { words: true, nonwords: false }], - 'quotes': 'warn', // Changed from error to warn - 'max-len': ['warn', { code: 120, ignoreUrls: true, ignoreStrings: true }], - }, - settings: { - react: { - version: 'detect', - }, - }, - }, - { - files: ['**/*.js'], - languageOptions: { - globals: { - console: 'readonly', - process: 'readonly', - Buffer: 'readonly', - __dirname: 'readonly', - __filename: 'readonly', - global: 'readonly', - module: 'readonly', - require: 'readonly', - exports: 'readonly', - }, - }, - }, - { - files: ['**/*.ts', '**/*.tsx'], - languageOptions: { - globals: { - // Node.js globals - console: 'readonly', - process: 'readonly', - Buffer: 'readonly', - __dirname: 'readonly', - __filename: 'readonly', - global: 'readonly', - module: 'readonly', - require: 'readonly', - exports: 'readonly', - // Browser globals - window: 'readonly', - document: 'readonly', - navigator: 'readonly', - localStorage: 'readonly', - sessionStorage: 'readonly', - fetch: 'readonly', - setTimeout: 'readonly', - clearTimeout: 'readonly', - setInterval: 'readonly', - clearInterval: 'readonly', - URL: 'readonly', - URLSearchParams: 'readonly', - FormData: 'readonly', - File: 'readonly', - FileReader: 'readonly', - Blob: 'readonly', - crypto: 'readonly', - TextEncoder: 'readonly', - TextDecoder: 'readonly', - CryptoKey: 'readonly', - btoa: 'readonly', - atob: 'readonly', - Element: 'readonly', - HTMLElement: 'readonly', - HTMLImageElement: 'readonly', - HTMLInputElement: 'readonly', - HTMLFormElement: 'readonly', - HTMLTextAreaElement: 'readonly', - HTMLSelectElement: 'readonly', - HTMLButtonElement: 'readonly', - HTMLDivElement: 'readonly', - HTMLSpanElement: 'readonly', - HTMLAnchorElement: 'readonly', - HTMLImageElement: 'readonly', - NodeJS: 'readonly', - React: 'readonly', - }, - }, - }, - { - ignores: [ - 'node_modules/**', - 'dist/**', - 'build/**', - 'out/**', - '*.min.js', - 'coverage/**', - '.nyc_output/**', - 'backend/**', - 'deployment/**', - 'web-calls/**', - ], - }, - ]; diff --git a/frontend/eslint.config.ts b/frontend/eslint.config.ts new file mode 100644 index 0000000..fec82a6 --- /dev/null +++ b/frontend/eslint.config.ts @@ -0,0 +1,138 @@ +import js from "@eslint/js"; +import typescript from "@typescript-eslint/eslint-plugin"; +import typescriptParser from "@typescript-eslint/parser"; +import react from "eslint-plugin-react"; +import reactHooks from "eslint-plugin-react-hooks"; +import reactRefresh from "eslint-plugin-react-refresh"; +import jsxA11y from "eslint-plugin-jsx-a11y"; + +export default [ + js.configs.recommended, + { + files: ["**/*.{js,jsx,ts,tsx}"], + languageOptions: { + parser: typescriptParser, + parserOptions: { + ecmaVersion: "latest", + sourceType: "module", + ecmaFeatures: { + jsx: true + } + } + }, + plugins: { + "@typescript-eslint": typescript, + "react": react, + "react-hooks": reactHooks, + "react-refresh": reactRefresh, + "jsx-a11y": jsxA11y + }, + rules: { + // TypeScript rules + ...typescript.configs.recommended.rules, + "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }], + "@typescript-eslint/no-explicit-any": "warn", + "@typescript-eslint/no-non-null-assertion": "warn", + + // React rules + ...react.configs.recommended.rules, + "react/react-in-jsx-scope": "off", // Not needed with React 17+ + "react/prop-types": "off", // Using TypeScript instead + "react/jsx-uses-react": "off", // Not needed with React 17+ + "react/jsx-uses-vars": "error", + "react/jsx-no-undef": "error", + "react/jsx-key": "error", + "react/jsx-no-duplicate-props": "error", + "react/jsx-pascal-case": "error", + "react/no-array-index-key": "warn", + "react/no-danger": "warn", + "react/no-deprecated": "error", + "react/no-direct-mutation-state": "error", + "react/no-unescaped-entities": "error", + "react/no-unknown-property": "error", + "react/require-render-return": "error", + "react/self-closing-comp": "error", + "react/jsx-wrap-multilines": "error", + "react/jsx-closing-bracket-location": "error", + "react/jsx-closing-tag-location": "error", + "react/jsx-curly-spacing": ["error", "never"], + "react/jsx-equals-spacing": ["error", "never"], + "react/jsx-first-prop-new-line": ["error", "multiline-multiprop"], + "react/jsx-max-props-per-line": ["error", { maximum: 1, when: "multiline" }], + "react/jsx-no-bind": "warn", + "react/jsx-no-literals": "off", + "react/jsx-sort-props": "off", + + // React Hooks rules + ...reactHooks.configs.recommended.rules, + + // React Refresh rules + "react-refresh/only-export-components": [ + "warn", + { allowConstantExport: true } + ], + + // Accessibility rules + ...jsxA11y.configs.recommended.rules, + "jsx-a11y/alt-text": "error", + "jsx-a11y/anchor-has-content": "error", + "jsx-a11y/anchor-is-valid": "error", + "jsx-a11y/aria-props": "error", + "jsx-a11y/aria-proptypes": "error", + "jsx-a11y/aria-unsupported-elements": "error", + "jsx-a11y/click-events-have-key-events": "warn", + "jsx-a11y/heading-has-content": "error", + "jsx-a11y/img-redundant-alt": "error", + "jsx-a11y/no-access-key": "error", + "jsx-a11y/role-has-required-aria-props": "error", + "jsx-a11y/role-supports-aria-props": "error", + "jsx-a11y/scope": "error", + "jsx-a11y/tabindex-no-positive": "error", + + // General JavaScript/TypeScript rules + "no-console": "warn", + "no-debugger": "error", + "no-unused-vars": "off", // Handled by TypeScript version + "prefer-const": "error", + "no-var": "error", + "eqeqeq": ["error", "always"], + "curly": "warn", // Changed from error to warn + "brace-style": ["error", "1tbs"], + "comma-dangle": "warn", // Changed from error to warn + "comma-spacing": ["error", { before: false, after: true }], + "comma-style": ["error", "last"], + "computed-property-spacing": ["error", "never"], + "func-call-spacing": ["error", "never"], + "key-spacing": ["error", { beforeColon: false, afterColon: true }], + "keyword-spacing": ["error", { before: true, after: true }], + "object-curly-spacing": ["error", "always"], + "semi-spacing": ["error", { before: false, after: true }], + "space-before-blocks": "error", + "space-before-function-paren": ["error", "never"], + "space-in-parens": ["error", "never"], + "space-infix-ops": "error", + "space-unary-ops": ["error", { words: true, nonwords: false }], + "quotes": "warn", // Changed from error to warn + "max-len": ["warn", { code: 120, ignoreUrls: true, ignoreStrings: true }] + }, + settings: { + react: { + version: "detect" + } + } + }, + { + ignores: [ + "node_modules/**", + "dist/**", + "build/**", + "out/**", + "*.min.js", + "coverage/**", + ".nyc_output/**", + "backend/**", + "deployment/**", + "web-calls/**" + ] + } +]; diff --git a/package.json b/package.json index 2a136a0..c0b0d0a 100644 --- a/package.json +++ b/package.json @@ -15,8 +15,8 @@ "frontend:dev": "vite frontend", "frontend:typecheck": "tsc --project frontend", "frontend:lint": "eslint frontend/src --ext .js,.jsx,.ts,.tsx", - "frontend:lint:fix": "eslint frontend/src --ext .js,.jsx,.ts,.tsx --fix", - "frontend:build": "npm run frontend:lint && npm run frontend:typecheck && vite build frontend", + "frontend:check": "npm run frontend:lint && npm run frontend:typecheck", + "frontend:build": "npm run frontend:check && vite build frontend", "frontend:electron:dev": "VITE_ELECTRON=true npm run frontend:dev", "frontend:electron:build": "VITE_ELECTRON=true npm run frontend:build && rm -rf out && electron-forge make --force --arch arm64,x64", "frontend:preview": "vite preview frontend", @@ -47,6 +47,7 @@ "@electron-forge/plugin-fuses": "^7.9.0", "@electron/fuses": "^1.0.0", "@eslint/js": "^9.37.0", + "@types/eslint-plugin-jsx-a11y": "^6.10.1", "@types/react": "^19.1.13", "@types/react-dom": "^19.1.9", "@typescript-eslint/eslint-plugin": "^8.46.0",