eslint.config.js 5.69 KB
/*
 * @Date: 2026-01-28 20:45:00
 * @Description: ESLint 配置 - 使用 ESLint 9 扁平配置格式
 */
import vue from 'eslint-plugin-vue'
import prettier from 'eslint-config-prettier'
import vueParser from 'vue-eslint-parser'

export default [
  {
    // 忽略文件
    ignores: [
      'node_modules/**',
      'dist/**',
      'dist.*',
      'build/**',
      '*.min.js',
      'public/**',
      'VITE*.md',
      '.cursor/**',
      '.history/**',
      'coverage/**',
      '.nyc_output/**',
      'src/auto-imports.d.ts',
      'src/components.d.ts',
      'mlaj/**',
    ],
  },

  // JavaScript / Vue 文件配置
  {
    files: ['**/*.{js,mjs,cjs,vue}'],
    languageOptions: {
      ecmaVersion: 'latest',
      sourceType: 'module',
      parser: vueParser,
      parserOptions: {
        ecmaVersion: 'latest',
        sourceType: 'module',
        ecmaFeatures: {
          jsx: true,
        },
      },
      globals: {
        // 浏览器环境
        window: 'readonly',
        document: 'readonly',
        navigator: 'readonly',
        localStorage: 'readonly',
        sessionStorage: 'readonly',
        history: 'readonly',
        location: 'readonly',
        fetch: 'readonly',
        URL: 'readonly',
        XMLHttpRequest: 'readonly',
        WebSocket: 'readonly',
        HTMLElement: 'readonly',
        customElements: 'readonly',

        // 微信环境
        wx: 'readonly',
        WeixinJSBridge: 'readonly',

        // Node.js 环境
        process: 'readonly',
        Buffer: 'readonly',
        __dirname: 'readonly',
        __filename: 'readonly',
        module: 'readonly',
        require: 'readonly',
        exports: 'readonly',

        // Vitest 测试环境
        describe: 'readonly',
        it: 'readonly',
        test: 'readonly',
        expect: 'readonly',
        vi: 'readonly',
        beforeEach: 'readonly',
        afterEach: 'readonly',
        beforeAll: 'readonly',
        afterAll: 'readonly',
      },
    },
    plugins: {
      vue,
    },
    rules: {
      // Vue 3 规则
      'vue/multi-word-component-names': 'off', // 允许单词组件名
      'vue/no-v-html': 'warn', // v-html 需谨慎使用
      'vue/require-default-prop': 'off', // props 不强制默认值
      'vue/require-prop-types': 'error', // props 必须有类型
      'vue/no-mutating-props': 'error', // 禁止直接修改 props
      'vue/component-definition-name-casing': ['error', 'PascalCase'], // 组件名 PascalCase
      'vue/component-name-in-template-casing': ['error', 'PascalCase'], // 模板中组件名 PascalCase
      'vue/no-unused-vars': 'error', // 禁止未使用的变量
      'vue/padding-line-between-blocks': 'warn', // 块之间空行

      // 通用 JavaScript 规则
      'no-console': ['warn', { allow: ['warn', 'error'] }], // 禁止 console.log(允许 warn/error)
      'no-debugger': 'error', // 禁止 debugger
      'no-alert': 'warn', // 警告使用 alert
      'no-var': 'error', // 禁止 var,使用 const/let
      'prefer-const': 'error', // 优先使用 const
      'no-duplicate-imports': 'error', // 禁止重复导入
      'no-unused-vars': 'off', // Vue 已处理
      'no-const-assign': 'error', // 禁止重新赋值 const
      'prefer-template': 'warn', // 优先使用模板字符串
      'template-curly-spacing': 'error', // 模板字符串空格
      'object-shorthand': ['warn', 'always'], // 对象简写
      'prefer-arrow-callback': 'warn', // 优先使用箭头函数
      'arrow-spacing': 'error', // 箭头函数空格
      'arrow-parens': ['warn', 'as-needed'], // 箭头函数括号
      'arrow-body-style': ['warn', 'as-needed'], // 箭头函数体

      // 代码质量
      eqeqeq: ['error', 'always', { null: 'ignore' }], // 强制 ===
      curly: ['error', 'all'], // 强制花括号
      'brace-style': ['error', '1tbs', { allowSingleLine: true }], // 花括号风格
      'no-else-return': 'warn', // if 中 return 后不要 else
      'no-nested-ternary': 'warn', // 禁止嵌套三元
      'no-unneeded-ternary': 'error', // 禁止不必要的三元
      'prefer-destructuring': ['warn', { array: true, object: true }], // 优先解构

      // 异步
      'no-async-promise-executor': 'error', // 禁止 async promise executor
      'no-await-in-loop': 'warn', // 循环中的 await 警告
      'require-await': 'error', // async 函数必须有 await
      'prefer-promise-reject-errors': 'error', // Promise reject 必须有 Error

      // 错误处理
      'no-throw-literal': 'error', // throw 必须是 Error 对象
      'prefer-promise-reject-errors': 'error', // Promise reject 必须是 Error

      // 性能
      'no-loop-func': 'warn', // 循环中不要创建函数
      'no-new-func': 'error', // 禁止 new Function

      // 安全
      'no-eval': 'error', // 禁止 eval
      'no-implied-eval': 'error', // 禁止隐式 eval
      'no-new-object': 'error', // 禁止 new Object()
      'no-script-url': 'error', // 禁止 javascript:
    },
  },

  // 测试文件配置(Vitest)
  {
    files: ['**/*.test.js', '**/*.spec.js', 'test/**'],
    languageOptions: {
      globals: {
        describe: 'readonly',
        it: 'readonly',
        test: 'readonly',
        expect: 'readonly',
        vi: 'readonly',
        beforeEach: 'readonly',
        afterEach: 'readonly',
        beforeAll: 'readonly',
        afterAll: 'readonly',
      },
    },
  },

  // E2E 测试文件配置(Playwright)
  {
    files: ['e2e/**/*.{js,ts}'],
    languageOptions: {
      globals: {
        test: 'readonly',
        expect: 'readonly',
        beforeAll: 'readonly',
        afterAll: 'readonly',
        beforeEach: 'readonly',
        afterEach: 'readonly',
      },
    },
  },

  // Prettier 配置(必须最后)
  prettier,
]