tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

eslint.config.mjs (11582B)


      1 /**
      2 * @license
      3 * Copyright 2024 Google Inc.
      4 * SPDX-License-Identifier: Apache-2.0
      5 */
      6 import fs from 'node:fs';
      7 import path from 'node:path';
      8 
      9 import stylisticPlugin from '@stylistic/eslint-plugin';
     10 import {defineConfig, globalIgnores} from 'eslint/config';
     11 import importPlugin from 'eslint-plugin-import';
     12 import mocha from 'eslint-plugin-mocha';
     13 import eslintPrettierPluginRecommended from 'eslint-plugin-prettier/recommended';
     14 import rulesdir from 'eslint-plugin-rulesdir';
     15 import tsdoc from 'eslint-plugin-tsdoc';
     16 import globals from 'globals';
     17 import typescriptEslint from 'typescript-eslint';
     18 rulesdir.RULES_DIR = 'tools/eslint/lib';
     19 
     20 function getThirdPartyPackages() {
     21  return fs
     22    .readdirSync(
     23      path.join(import.meta.dirname, 'packages/puppeteer-core/third_party'),
     24      {
     25        withFileTypes: true,
     26      },
     27    )
     28    .filter(dirent => {
     29      return dirent.isDirectory();
     30    })
     31    .map(({name}) => {
     32      return {
     33        name,
     34        message: `Import \`${name}\` from the vendored location: third_party/${name}/index.js`,
     35      };
     36    });
     37 }
     38 
     39 export default defineConfig([
     40  globalIgnores([
     41    '**/node_modules',
     42    '**/build/',
     43    '**/lib/',
     44    '**/bin/',
     45    '**/*.tsbuildinfo',
     46    '**/*.api.json',
     47    '**/*.tgz',
     48    '**/yarn.lock',
     49    '**/.docusaurus/',
     50    '**/.cache-loader',
     51    'test/output-*/',
     52    '**/.dev_profile*',
     53    '**/coverage/',
     54    '**/generated/',
     55    '**/.eslintcache',
     56    '**/.cache/',
     57    '**/.vscode',
     58    '!.vscode/extensions.json',
     59    '!.vscode/*.template.json',
     60    '**/.devcontainer',
     61    '**/.DS_Store',
     62    '**/.env.local',
     63    '**/.env.development.local',
     64    '**/.env.test.local',
     65    '**/.env.production.local',
     66    '**/npm-debug.log*',
     67    '**/yarn-debug.log*',
     68    '**/yarn-error.log*',
     69    '**/.wireit',
     70    '**/assets/',
     71    '**/third_party/',
     72    'packages/ng-schematics/sandbox/**/*',
     73    'packages/ng-schematics/multi/**/*',
     74    'packages/ng-schematics/src/**/files/',
     75    'examples/puppeteer-in-browser/out/**/*',
     76    'examples/puppeteer-in-browser/node_modules/**/*',
     77    'examples/puppeteer-in-extension/out/**/*',
     78    'examples/puppeteer-in-extension/node_modules/**/*',
     79  ]),
     80  eslintPrettierPluginRecommended,
     81  importPlugin.flatConfigs.typescript,
     82  {
     83    name: 'JavaScript rules',
     84    plugins: {
     85      mocha,
     86      '@typescript-eslint': typescriptEslint.plugin,
     87      import: importPlugin,
     88      rulesdir,
     89      '@stylistic': stylisticPlugin,
     90    },
     91 
     92    languageOptions: {
     93      ecmaVersion: 'latest',
     94      sourceType: 'module',
     95 
     96      globals: {
     97        ...globals.node,
     98      },
     99 
    100      parser: typescriptEslint.parser,
    101    },
    102 
    103    settings: {
    104      'import/resolver': {
    105        typescript: true,
    106      },
    107    },
    108 
    109    rules: {
    110      curly: ['error', 'all'],
    111      'arrow-body-style': ['error', 'always'],
    112      'prettier/prettier': 'error',
    113 
    114      'spaced-comment': [
    115        'error',
    116        'always',
    117        {
    118          markers: ['*', '/'],
    119        },
    120      ],
    121 
    122      eqeqeq: ['error'],
    123 
    124      'accessor-pairs': [
    125        'error',
    126        {
    127          getWithoutSet: false,
    128          setWithoutGet: false,
    129        },
    130      ],
    131 
    132      'new-parens': 'error',
    133 
    134      'prefer-const': 'error',
    135 
    136      'max-len': [
    137        'error',
    138        {
    139          /* this setting doesn't impact things as we use Prettier to format
    140           * our code and hence dictate the line length.
    141           * Prettier aims for 80 but sometimes makes the decision to go just
    142           * over 80 chars as it decides that's better than wrapping. ESLint's
    143           * rule defaults to 80 but therefore conflicts with Prettier. So we
    144           * set it to something far higher than Prettier would allow to avoid
    145           * it causing issues and conflicting with Prettier.
    146           */
    147          code: 200,
    148          comments: 90,
    149          ignoreTemplateLiterals: true,
    150          ignoreUrls: true,
    151          ignoreStrings: true,
    152          ignoreRegExpLiterals: true,
    153        },
    154      ],
    155 
    156      'no-var': 'error',
    157      'no-with': 'error',
    158      'no-multi-str': 'error',
    159      'no-caller': 'error',
    160      'no-implied-eval': 'error',
    161      'no-labels': 'error',
    162      'no-new-object': 'error',
    163      'no-octal-escape': 'error',
    164      'no-self-compare': 'error',
    165      'no-shadow-restricted-names': 'error',
    166      'no-cond-assign': 'error',
    167      'no-debugger': 'error',
    168      'no-dupe-keys': 'error',
    169      'no-duplicate-case': 'error',
    170      'no-empty-character-class': 'error',
    171      'no-unreachable': 'error',
    172      'no-unsafe-negation': 'error',
    173      radix: 'error',
    174      'valid-typeof': 'error',
    175 
    176      'no-unused-vars': [
    177        'error',
    178        {
    179          args: 'none',
    180          vars: 'local',
    181          varsIgnorePattern:
    182            '([fx]?describe|[fx]?it|beforeAll|beforeEach|afterAll|afterEach)',
    183        },
    184      ],
    185 
    186      // Disabled as it now reports issues - https://eslint.org/docs/latest/rules/no-implicit-globals
    187      // 'no-implicit-globals': ['error'],
    188      'require-yield': 'error',
    189      'template-curly-spacing': ['error', 'never'],
    190      'mocha/no-exclusive-tests': 'error',
    191 
    192      'import/order': [
    193        'error',
    194        {
    195          'newlines-between': 'always',
    196 
    197          alphabetize: {
    198            order: 'asc',
    199            caseInsensitive: true,
    200          },
    201        },
    202      ],
    203 
    204      'import/no-cycle': [
    205        'error',
    206        {
    207          maxDepth: Infinity,
    208        },
    209      ],
    210 
    211      // TODO: enable with next version
    212      // 'import/enforce-node-protocol-usage': 'error',
    213 
    214      '@stylistic/func-call-spacing': 'error',
    215      '@stylistic/semi': 'error',
    216 
    217      // Keeps comments formatted.
    218      'rulesdir/prettier-comments': 'error',
    219      // Enforces consistent file extension
    220      'rulesdir/extensions': 'error',
    221      // Enforces license headers on files
    222      'rulesdir/check-license': 'error',
    223    },
    224  },
    225  ...[
    226    typescriptEslint.configs.eslintRecommended,
    227    typescriptEslint.configs.recommended,
    228    typescriptEslint.configs.stylistic,
    229  ]
    230    .flat()
    231    .map(config => {
    232      return {
    233        ...config,
    234        files: ['**/*.ts'],
    235      };
    236    }),
    237  {
    238    name: 'TypeScript rules',
    239    files: ['**/*.ts'],
    240 
    241    plugins: {
    242      tsdoc,
    243    },
    244 
    245    languageOptions: {
    246      ecmaVersion: 'latest',
    247      sourceType: 'module',
    248 
    249      parserOptions: {
    250        allowAutomaticSingleRunInference: true,
    251        project: './tsconfig.base.json',
    252      },
    253    },
    254 
    255    rules: {
    256      // Enforces clean up of used resources.
    257      'rulesdir/use-using': 'error',
    258 
    259      '@typescript-eslint/array-type': [
    260        'error',
    261        {
    262          default: 'array-simple',
    263        },
    264      ],
    265 
    266      'no-unused-vars': 'off',
    267 
    268      '@typescript-eslint/no-unused-vars': [
    269        'error',
    270        {
    271          argsIgnorePattern: '^_',
    272          varsIgnorePattern: '^_',
    273        },
    274      ],
    275 
    276      '@typescript-eslint/no-empty-function': 'off',
    277      '@typescript-eslint/no-use-before-define': 'off',
    278      // We have to use any on some types so the warning isn't valuable.
    279      '@typescript-eslint/no-explicit-any': 'off',
    280      // We don't require explicit return types on basic functions or
    281      // dummy functions in tests, for example
    282      '@typescript-eslint/explicit-function-return-type': 'off',
    283      // We allow non-null assertions if the value was asserted using `assert` API.
    284      '@typescript-eslint/no-non-null-assertion': 'off',
    285      '@typescript-eslint/no-unnecessary-template-expression': 'error',
    286      '@typescript-eslint/no-unsafe-function-type': 'error',
    287      '@typescript-eslint/no-wrapper-object-types': 'error',
    288 
    289      // By default this is a warning but we want it to error.
    290      '@typescript-eslint/explicit-module-boundary-types': 'error',
    291 
    292      'no-restricted-syntax': [
    293        'error',
    294        {
    295          selector: "CallExpression[callee.name='require']",
    296          message: '`require` statements are not allowed. Use `import`.',
    297        },
    298      ],
    299 
    300      '@typescript-eslint/no-floating-promises': [
    301        'error',
    302        {
    303          ignoreVoid: true,
    304          ignoreIIFE: true,
    305        },
    306      ],
    307 
    308      '@typescript-eslint/prefer-ts-expect-error': 'error',
    309      // This is more performant; see https://v8.dev/blog/fast-async.
    310      '@typescript-eslint/return-await': ['error', 'always'],
    311      // This optimizes the dependency tracking for type-only files.
    312      '@typescript-eslint/consistent-type-imports': 'error',
    313      // So type-only exports get elided.
    314      '@typescript-eslint/consistent-type-exports': 'error',
    315      // Don't want to trigger unintended side-effects.
    316      '@typescript-eslint/no-import-type-side-effects': 'error',
    317      // Prefer interfaces over types for shape like.
    318      '@typescript-eslint/consistent-type-definitions': ['error', 'interface'],
    319    },
    320  },
    321  {
    322    name: 'Puppeteer Core syntax',
    323    files: ['packages/puppeteer-core/src/**/*.ts'],
    324    rules: {
    325      'no-restricted-syntax': [
    326        'error',
    327        {
    328          message: 'Use method `Deferred.race()` instead.',
    329          selector:
    330            'MemberExpression[object.name="Promise"][property.name="race"]',
    331        },
    332        {
    333          message:
    334            'Deferred `valueOrThrow` should not be called in `Deferred.race()` pass deferred directly',
    335          selector:
    336            'CallExpression[callee.object.name="Deferred"][callee.property.name="race"] > ArrayExpression > CallExpression[callee.property.name="valueOrThrow"]',
    337        },
    338      ],
    339      'no-restricted-imports': [
    340        'error',
    341        {
    342          patterns: ['*Events', '*.test.js'],
    343          paths: [...getThirdPartyPackages()],
    344        },
    345      ],
    346    },
    347  },
    348  {
    349    name: 'Packages',
    350    files: [
    351      'packages/puppeteer-core/src/**/*.test.ts',
    352      'tools/mocha-runner/src/test.ts',
    353    ],
    354    rules: {
    355      // With the Node.js test runner, `describe` and `it` are technically
    356      // promises, but we don't need to await them.
    357      '@typescript-eslint/no-floating-promises': 'off',
    358    },
    359  },
    360  {
    361    files: ['packages/**/*.ts'],
    362 
    363    rules: {
    364      'tsdoc/syntax': 'error',
    365    },
    366  },
    367  {
    368    name: 'Mocha',
    369    files: ['test/**/*.ts'],
    370    rules: {
    371      'no-restricted-imports': [
    372        'error',
    373        {
    374          /**
    375           * The mocha tests run on the compiled output in the /lib directory
    376           * so we should avoid importing from src.
    377           */
    378          patterns: ['*src*'],
    379        },
    380      ],
    381    },
    382  },
    383  {
    384    name: 'Mocha Tests',
    385    files: ['test/**/*.spec.ts'],
    386 
    387    rules: {
    388      '@typescript-eslint/no-unused-vars': [
    389        'error',
    390        {
    391          argsIgnorePattern: '^_',
    392          varsIgnorePattern: '^_',
    393        },
    394      ],
    395 
    396      'no-restricted-syntax': [
    397        'error',
    398        {
    399          message:
    400            'Use helper command `launch` to make sure the browsers get cleaned',
    401          selector:
    402            'MemberExpression[object.name="puppeteer"][property.name="launch"]',
    403        },
    404        {
    405          message: 'Unexpected debugging mocha test.',
    406          selector:
    407            'CallExpression[callee.object.name="it"] > MemberExpression > Identifier[name="deflake"], CallExpression[callee.object.name="it"] > MemberExpression > Identifier[name="deflakeOnly"]',
    408        },
    409        {
    410          message: 'No `expect` in EventHandler. They will never throw errors',
    411          selector:
    412            'CallExpression[callee.property.name="on"] BlockStatement > :not(TryStatement) > ExpressionStatement > CallExpression[callee.object.callee.name="expect"]',
    413        },
    414      ],
    415 
    416      'mocha/no-pending-tests': 'error',
    417      'mocha/no-identical-title': 'error',
    418    },
    419  },
    420 ]);