blob: 7aea87280fbfaace402dd7465b27655d21d1aaa2 [file] [log] [blame]
Nikolay Vitkovde07efa2025-01-17 12:58:351// Copyright 2025 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Nikolay Vitkov5b2bcff2025-01-29 19:21:125/* eslint-disable import/no-default-export */
Nikolay Vitkov41c69112025-01-31 15:20:046
7import stylisticPlugin from '@stylistic/eslint-plugin';
Nikolay Vitkov55adf672025-01-02 12:07:338import typescriptPlugin from '@typescript-eslint/eslint-plugin';
Nikolay Vitkov41c69112025-01-31 15:20:049import tsParser from '@typescript-eslint/parser';
Nikolay Vitkovf1e3bd82025-02-13 11:55:2210import eslintPlugin from 'eslint-plugin-eslint-plugin';
Nikolay Vitkov55adf672025-01-02 12:07:3311import importPlugin from 'eslint-plugin-import';
12import jsdocPlugin from 'eslint-plugin-jsdoc';
Nikolay Vitkov41c69112025-01-31 15:20:0413import mochaPlugin from 'eslint-plugin-mocha';
14import rulesdirPlugin from 'eslint-plugin-rulesdir';
Nikolay Vitkov55adf672025-01-02 12:07:3315import globals from 'globals';
Nikolay Vitkovf1e3bd82025-02-13 11:55:2216import { join } from 'path';
Nikolay Vitkov55adf672025-01-02 12:07:3317
18rulesdirPlugin.RULES_DIR = join(
Nikolay Vitkovf1e3bd82025-02-13 11:55:2219 import.meta.dirname,
20 'scripts',
21 'eslint_rules',
22 'lib',
Nikolay Vitkov55adf672025-01-02 12:07:3323);
24
25/**
26 * @type {import('eslint').Linter.Config[]}
27 */
28export default [
29 {
Nikolay Vitkov52a17972025-01-15 12:52:1030 name: 'Ignore list',
Nikolay Vitkov55adf672025-01-02 12:07:3331 ignores: [
Nikolay Vitkov5b2bcff2025-01-29 19:21:1232 // Git submodules that are not in third_party
33 'build/',
34 'buildtools/',
35
Nikolay Vitkov4dc470b2025-02-20 12:44:3236 // Don't include the common build directory
37 'out/',
38 // Don't include third party code
39 'third_party/',
40
Nikolay Vitkov55adf672025-01-02 12:07:3341 'front_end/diff/diff_match_patch.jD',
42 'front_end/models/javascript_metadata/NativeFunctions.js',
43 // All of these scripts are auto-generated so don't lint them.
44 'front_end/generated/ARIAProperties.js',
45 'front_end/generated/Deprecation.ts',
46 'front_end/generated/InspectorBackendCommands.js',
47 'front_end/generated/protocol-mapping.d.ts',
48 'front_end/generated/protocol-proxy-api.d.ts',
49 'front_end/generated/protocol.ts',
50 // Any third_party addition has its source code checked out into
51 // third_party/X/package, so we ignore that code as it's not code we author or
52 // own.
53 'front_end/third_party/*/package/',
54 // Any JS files are also not authored by devtools-frontend, so we ignore those.
Nikolay Vitkov52a17972025-01-15 12:52:1055 'front_end/third_party/**/*',
Nikolay Vitkov55adf672025-01-02 12:07:3356 // Lighthouse doesn't have a package/ folder but has other nested folders, so
57 // we ignore any folders within the lighthouse directory.
58 'front_end/third_party/lighthouse/*/',
59 // The CodeMirror bundle file is auto-generated and rolled-up as part of the',
60 // install script, so we don't need to lint it.
61 'front_end/third_party/codemirror.next/bundle.ts',
62 // Lit lib files are auto-generated and rolled up as part of the install script.
63 'front_end/third_party/lit/src/*.ts',
64 // @puppeteer/replay is auto-generated.
65 'front_end/third_party/puppeteer-replay/**/*.ts',
Nikolay Vitkov52a17972025-01-15 12:52:1066 // Third party code we did not author for extensions
67 'extensions/cxx_debugging/third_party/**/*',
Nikolay Vitkov55adf672025-01-02 12:07:3368
69 '**/node_modules',
70 'scripts/build/typescript/tests',
71 'scripts/migration/**/*.js',
72 'scripts/protocol_typescript/*.js',
73 'scripts/deps/tests/fixtures',
74 'test/**/fixtures/',
75 'test/e2e/**/*.js',
76 'test/shared/**/*.js',
77 '**/*.d.ts',
78 ],
79 },
80 {
Nikolay Vitkovb4e8dc72025-01-07 13:03:0281 name: 'JavaScript files',
Nikolay Vitkov55adf672025-01-02 12:07:3382 plugins: {
83 '@typescript-eslint': typescriptPlugin,
Nikolay Vitkovb4e8dc72025-01-07 13:03:0284 '@stylistic': stylisticPlugin,
Nikolay Vitkovf1e3bd82025-02-13 11:55:2285 '@eslint-plugin': eslintPlugin,
Nikolay Vitkov55adf672025-01-02 12:07:3386 mocha: mochaPlugin,
87 rulesdir: rulesdirPlugin,
88 import: importPlugin,
89 jsdoc: jsdocPlugin,
Nikolay Vitkov55adf672025-01-02 12:07:3390 },
91
92 languageOptions: {
Nikolay Vitkovb4e8dc72025-01-07 13:03:0293 ecmaVersion: 'latest',
94 sourceType: 'module',
Nikolay Vitkov55adf672025-01-02 12:07:3395 globals: {
96 ...globals.browser,
97 },
Nikolay Vitkov55adf672025-01-02 12:07:3398 },
99
Nikolay Vitkov5b2bcff2025-01-29 19:21:12100 linterOptions: {
101 reportUnusedDisableDirectives: 'error',
102 },
103
Nikolay Vitkov55adf672025-01-02 12:07:33104 rules: {
105 // syntax preferences
Nikolay Vitkovb4e8dc72025-01-07 13:03:02106 '@stylistic/quotes': [
Nikolay Vitkov55adf672025-01-02 12:07:33107 'error',
108 'single',
109 {
110 avoidEscape: true,
111 allowTemplateLiterals: false,
112 },
113 ],
114
Nikolay Vitkovb4e8dc72025-01-07 13:03:02115 '@stylistic/semi': 'error',
116 '@stylistic/no-extra-semi': 'error',
117 '@stylistic/comma-style': ['error', 'last'],
118 '@stylistic/wrap-iife': ['error', 'inside'],
Nikolay Vitkov55adf672025-01-02 12:07:33119
Nikolay Vitkovb4e8dc72025-01-07 13:03:02120 '@stylistic/spaced-comment': [
Nikolay Vitkov55adf672025-01-02 12:07:33121 'error',
122 'always',
123 {
124 markers: ['*'],
125 },
126 ],
127
128 eqeqeq: 'error',
129
130 'accessor-pairs': [
131 'error',
132 {
133 getWithoutSet: false,
134 setWithoutGet: false,
135 },
136 ],
137
138 curly: 'error',
Nikolay Vitkovb4e8dc72025-01-07 13:03:02139 '@stylistic/new-parens': 'error',
140 '@stylistic/func-call-spacing': 'error',
141 '@stylistic/arrow-parens': ['error', 'as-needed'],
142 '@stylistic/eol-last': 'error',
Nikolay Vitkov55adf672025-01-02 12:07:33143 'object-shorthand': ['error', 'properties'],
144 'no-useless-rename': 'error',
145
146 // anti-patterns
147 'no-caller': 'error',
148 'no-case-declarations': 'error',
149 'no-cond-assign': 'error',
150
151 'no-console': [
152 'error',
153 {
154 allow: [
155 'assert',
156 'context',
157 'error',
158 'timeStamp',
159 'time',
160 'timeEnd',
161 'warn',
162 ],
163 },
164 ],
165
166 'no-debugger': 'error',
167 'no-dupe-keys': 'error',
168 'no-duplicate-case': 'error',
169
170 'no-else-return': [
171 'error',
172 {
173 allowElseIf: false,
174 },
175 ],
176
177 'no-empty-character-class': 'error',
178 'no-global-assign': 'error',
179 'no-implied-eval': 'error',
180 'no-labels': 'error',
181 'no-multi-str': 'error',
Nikolay Vitkovb4e8dc72025-01-07 13:03:02182 'no-object-constructor': 'error',
Nikolay Vitkov55adf672025-01-02 12:07:33183 'no-octal-escape': 'error',
184 'no-self-compare': 'error',
185 'no-shadow-restricted-names': 'error',
186 'no-unreachable': 'error',
187 'no-unsafe-negation': 'error',
188
189 'no-unused-vars': [
190 'error',
191 {
192 args: 'none',
193 vars: 'local',
194 },
195 ],
196
197 'no-var': 'error',
198 'no-with': 'error',
199 'prefer-const': 'error',
200 radix: 'error',
201 'valid-typeof': 'error',
202 'no-return-assign': ['error', 'always'],
203 'no-implicit-coercion': 'error',
204
205 // es2015 features
206 'require-yield': 'error',
Nikolay Vitkovb4e8dc72025-01-07 13:03:02207 '@stylistic/template-curly-spacing': ['error', 'never'],
Nikolay Vitkov55adf672025-01-02 12:07:33208
209 // file whitespace
Nikolay Vitkovb4e8dc72025-01-07 13:03:02210 '@stylistic/no-multiple-empty-lines': [
Nikolay Vitkov55adf672025-01-02 12:07:33211 'error',
212 {
213 max: 1,
214 },
215 ],
Nikolay Vitkovb4e8dc72025-01-07 13:03:02216 '@stylistic/no-mixed-spaces-and-tabs': 'error',
217 '@stylistic/no-trailing-spaces': 'error',
218 '@stylistic/linebreak-style': ['error', 'unix'],
Nikolay Vitkov55adf672025-01-02 12:07:33219
220 /**
221 * Disabled, aspirational rules
222 */
Nikolay Vitkovb4e8dc72025-01-07 13:03:02223 '@stylistic/indent': [
Nikolay Vitkov55adf672025-01-02 12:07:33224 'off',
225 2,
226 {
227 SwitchCase: 1,
228 CallExpression: {
229 arguments: 2,
230 },
231 MemberExpression: 2,
232 },
233 ],
234
235 // brace-style is disabled, as eslint cannot enforce 1tbs as default, but allman for functions
Nikolay Vitkovb4e8dc72025-01-07 13:03:02236 '@stylistic/brace-style': [
Nikolay Vitkov55adf672025-01-02 12:07:33237 'off',
238 'allman',
239 {
240 allowSingleLine: true,
241 },
242 ],
243
244 // key-spacing is disabled, as some objects use value-aligned spacing, some not.
Nikolay Vitkovb4e8dc72025-01-07 13:03:02245 '@stylistic/key-spacing': [
Nikolay Vitkov55adf672025-01-02 12:07:33246 'off',
247 {
248 beforeColon: false,
249 afterColon: true,
250 align: 'value',
251 },
252 ],
253
Nikolay Vitkovb4e8dc72025-01-07 13:03:02254 '@stylistic/quote-props': ['error', 'as-needed'],
Nikolay Vitkov55adf672025-01-02 12:07:33255
256 // no-implicit-globals will prevent accidental globals
257 'no-implicit-globals': 'off',
258 'no-unused-private-class-members': 'error',
259
Benedikt Meurer00c39582025-01-31 09:26:27260 // Sort imports first
261 'import/first': 'error',
Nikolay Vitkov55adf672025-01-02 12:07:33262 // Closure does not properly typecheck default exports
263 'import/no-default-export': 'error',
264 /**
265 * Catch duplicate import paths. For example this would catch the following example:
266 * import {Foo} from './foo.js'
267 * import * as FooModule from './foo.js'
268 **/
269 'import/no-duplicates': 'error',
Nikolay Vitkov41c69112025-01-31 15:20:04270 /**
271 * Provides more consistency in the imports.
272 */
273 'import/order': [
274 'error',
275 {
276 // We need to group the builtin and external as clang-format
277 // can't differentiate the two
278 groups: [['builtin', 'external'], 'parent', 'sibling', 'index'],
279 'newlines-between': 'always',
280 // clang-format has it's own logic overriding this
281 named: false,
282 alphabetize: {
283 order: 'asc',
284 caseInsensitive: true,
285 },
286 },
287 ],
Nikolay Vitkov55adf672025-01-02 12:07:33288 // Try to spot '// console.log()' left over from debugging
289 'rulesdir/no-commented-out-console': 'error',
290 // Prevent imports being commented out rather than deleted.
291 'rulesdir/no-commented-out-import': 'error',
Nikolay Vitkov55adf672025-01-02 12:07:33292 'rulesdir/check-license-header': 'error',
Nikolay Vitkov55adf672025-01-02 12:07:33293 /**
294 * Ensures that JS Doc comments are properly aligned - all the starting
295 * `*` are in the right place.
296 */
297 'jsdoc/check-alignment': 'error',
298 },
299 },
300 {
301 name: 'TypeScript files',
302 files: ['**/*.ts'],
303
304 languageOptions: {
305 ecmaVersion: 'latest',
306 sourceType: 'module',
307
Nikolay Vitkovb4e8dc72025-01-07 13:03:02308 parser: tsParser,
Nikolay Vitkov55adf672025-01-02 12:07:33309 parserOptions: {
310 allowAutomaticSingleRunInference: true,
311 project: join(
Nikolay Vitkovf1e3bd82025-02-13 11:55:22312 import.meta.dirname,
313 'config',
314 'typescript',
315 'tsconfig.eslint.json',
316 ),
Nikolay Vitkov55adf672025-01-02 12:07:33317 },
318 },
319
320 rules: {
Benedikt Meurer84b0fcc2025-02-12 13:57:23321 '@typescript-eslint/array-type': [
322 'error',
323 {
324 default: 'array-simple',
325 },
326 ],
Nikolay Vitkov55adf672025-01-02 12:07:33327 '@typescript-eslint/no-explicit-any': [
328 'error',
329 {
330 ignoreRestArgs: true,
331 },
332 ],
333
334 '@typescript-eslint/explicit-member-accessibility': [
335 'error',
336 {
337 accessibility: 'no-public',
338 },
339 ],
340
Nikolay Vitkov55adf672025-01-02 12:07:33341 // run just the TypeScript unused-vars rule, else we get duplicate errors
342 'no-unused-vars': 'off',
343 '@typescript-eslint/no-unused-vars': [
344 'error',
345 {
346 argsIgnorePattern: '^_',
347 },
348 ],
349
Nikolay Vitkovb4e8dc72025-01-07 13:03:02350 '@stylistic/member-delimiter-style': [
Nikolay Vitkov55adf672025-01-02 12:07:33351 'error',
352 {
353 multiline: {
354 delimiter: 'semi',
355 requireLast: true,
356 },
357
358 singleline: {
359 delimiter: 'comma',
360 requireLast: false,
361 },
362
363 overrides: {
364 interface: {
365 singleline: {
366 delimiter: 'semi',
367 requireLast: false,
368 },
369
370 multiline: {
371 delimiter: 'semi',
372 requireLast: true,
373 },
374 },
375
376 typeLiteral: {
377 singleline: {
378 delimiter: 'comma',
379 requireLast: false,
380 },
381
382 multiline: {
383 delimiter: 'comma',
384 requireLast: true,
385 },
386 },
387 },
388 },
389 ],
390
391 '@typescript-eslint/no-floating-promises': [
392 'error',
393 {
394 ignoreVoid: true,
395 },
396 ],
397
Nikolay Vitkov55adf672025-01-02 12:07:33398 /**
399 * Enforce that enum members are explicitly defined:
400 * const enum Foo { A = 'a' } rather than const enum Foo { A }
401 */
402 '@typescript-eslint/prefer-enum-initializers': 'error',
403 /**
404 * Ban non-null assertion operator, e.g.:
405 * this.foo!.toLowerCase()
406 */
407 '@typescript-eslint/no-non-null-assertion': 'error',
408 '@typescript-eslint/consistent-type-imports': 'error',
409
410 '@typescript-eslint/naming-convention': [
411 'error',
Nikolay Vitkov52a17972025-01-15 12:52:10412 // Forbids interfaces starting with an I prefix.
413 {
414 selector: 'interface',
415 format: ['PascalCase'],
416
417 custom: {
418 regex: '^I[A-Z]',
419 match: false,
420 },
421 },
Nikolay Vitkov55adf672025-01-02 12:07:33422 {
423 selector: [
424 'function',
425 'accessor',
426 'method',
427 'property',
428 'parameterProperty',
429 ],
430 format: ['camelCase'],
431 },
432 {
433 selector: 'variable',
434
435 filter: {
436 // Ignore localization variables.
437 regex: '^(UIStrings|str_)$',
438 match: false,
439 },
440
441 format: ['camelCase'],
442 },
443 {
444 // We are using camelCase, PascalCase and UPPER_CASE for top-level constants, allow the for now.
445 selector: 'variable',
446 modifiers: ['const'],
447 filter: {
448 // Ignore localization variables.
449 regex: '^(UIStrings|str_)$',
450 match: false,
451 },
452
453 format: ['camelCase', 'UPPER_CASE', 'PascalCase'],
454 },
455 {
456 selector: 'classProperty',
457 modifiers: ['static', 'readonly'],
458 format: ['UPPER_CASE', 'camelCase'],
459 },
460 {
461 selector: 'enumMember',
462 format: ['UPPER_CASE'],
463 },
464 {
465 selector: ['typeLike'],
466 format: ['PascalCase'],
467 },
468 {
469 selector: 'parameter',
470 format: ['camelCase'],
471 leadingUnderscore: 'allow',
472 },
473 {
474 // Public methods are currently in transition and may still have leading underscores.
475 selector: 'method',
476 modifiers: ['public'],
477 format: ['camelCase'],
478 leadingUnderscore: 'allow',
479 },
480 {
481 selector: 'property',
482 modifiers: ['public'],
483 format: ['camelCase'],
484 leadingUnderscore: 'allow',
485 },
486 {
487 // Object literals may be constructed as arguments to external libraries which follow different styles.
488 selector: ['objectLiteralMethod', 'objectLiteralProperty'],
489 modifiers: ['public'],
490 format: null,
491 },
492 {
493 // Ignore type properties that require quotes
494 selector: 'typeProperty',
495 format: null,
496 modifiers: ['requiresQuotes'],
497 },
498 ],
499
Nikolay Vitkov44e30062025-01-07 14:33:04500 '@typescript-eslint/consistent-type-definitions': ['error', 'interface'],
501
Nikolay Vitkov93062642025-02-18 09:49:30502 // Disable eslint base rule
503 'no-throw-literal': 'off',
504 '@typescript-eslint/only-throw-error': 'error',
505
Nikolay Vitkov65a5a912025-02-18 18:30:26506 // Disabled this rule while investigating why it creates
507 // certain TypeScript compilation errors after fixes
508 '@typescript-eslint/no-unnecessary-type-assertion': 'off',
509
Nikolay Vitkovd36860c2025-02-19 17:50:27510 '@typescript-eslint/no-inferrable-types': 'error',
511
Nikolay Vitkovd396b272025-02-19 08:37:28512 '@typescript-eslint/consistent-generic-constructors': [
513 'error',
514 'constructor',
515 ],
516
Nikolay Vitkovd36860c2025-02-19 17:50:27517 // This is more performant
518 // And should provide better stack trace when debugging
519 // see https://v8.dev/blog/fast-async.
520 '@typescript-eslint/return-await': ['error', 'always'],
521
522 '@typescript-eslint/ban-ts-comment': [
523 'error',
524 {
525 // Change after we add some placeholder for old errors
526 minimumDescriptionLength: 0,
527 'ts-check': false,
528 'ts-expect-error': 'allow-with-description',
529 'ts-ignore': true,
530 'ts-nocheck': true,
531 },
532 ],
533
Nikolay Vitkov68140172025-02-20 19:25:39534 '@typescript-eslint/prefer-optional-chain': 'error',
535
Nikolay Vitkov55adf672025-01-02 12:07:33536 'rulesdir/no-underscored-properties': 'error',
Nikolay Vitkov55adf672025-01-02 12:07:33537 'rulesdir/inline-type-imports': 'error',
538
539 'rulesdir/enforce-default-import-name': [
540 'error',
541 {
542 // Enforce that any import of models/trace/trace.js names the import Trace.
543 modulePath: join(
Nikolay Vitkovf1e3bd82025-02-13 11:55:22544 import.meta.dirname,
545 'front_end',
546 'models',
547 'trace',
548 'trace.js',
549 ),
Nikolay Vitkov55adf672025-01-02 12:07:33550 importName: 'Trace',
551 },
552 ],
553 },
554 },
Nikolay Vitkov55adf672025-01-02 12:07:33555 {
556 name: 'Scripts files',
557 files: ['scripts/**/*'],
558 rules: {
559 'no-console': 'off',
Nikolay Vitkovde07efa2025-01-17 12:58:35560 'rulesdir/es-modules-import': 'off',
Nikolay Vitkov55adf672025-01-02 12:07:33561 },
562 },
Nikolay Vitkov55adf672025-01-02 12:07:33563 {
564 name: 'Front-end files',
565 files: ['front_end/**/*'],
566 rules: {
567 // L10n rules are only relevant in 'front_end'.
568 'rulesdir/l10n-filename-matches': [
569 'error',
570 {
571 rootFrontendDirectory: join(import.meta.dirname, 'front_end'),
572 },
573 ],
574 'rulesdir/l10n-i18nString-call-only-with-uistrings': 'error',
575 'rulesdir/l10n-no-i18nString-calls-module-instantiation': 'error',
576 'rulesdir/l10n-no-locked-or-placeholder-only-phrase': 'error',
577 'rulesdir/l10n-no-uistrings-export': 'error',
578 'rulesdir/l10n-no-unused-message': 'error',
579 },
580 },
Nikolay Vitkov55adf672025-01-02 12:07:33581 {
582 name: 'Front-end TypeScript files',
583 files: ['front_end/**/*.ts'],
584 rules: {
585 '@typescript-eslint/explicit-function-return-type': [
586 'error',
587 {
588 allowExpressions: true,
589 allowConciseArrowFunctionExpressionsStartingWithVoid: true,
590 allowIIFEs: true,
591 },
592 ],
593 'rulesdir/no-importing-images-from-src': 'error',
594 'rulesdir/enforce-bound-render-for-schedule-render': 'error',
595 'rulesdir/enforce-custom-event-names': 'error',
596 'rulesdir/set-data-type-reference': 'error',
597 'rulesdir/no-bound-component-methods': 'error',
598 'rulesdir/no-customized-builtin-elements': 'error',
599 'rulesdir/no-self-closing-custom-element-tagnames': 'error',
Benedikt Meurer6e534082025-01-29 10:36:02600 'rulesdir/no-a-tags-in-lit': 'error',
Nikolay Vitkov55adf672025-01-02 12:07:33601 'rulesdir/check-css-import': 'error',
602 'rulesdir/enforce-optional-properties-last': 'error',
603 'rulesdir/check-enumerated-histograms': 'error',
604 'rulesdir/check-was-shown-methods': 'error',
605 'rulesdir/static-custom-event-names': 'error',
Benedikt Meurer6e534082025-01-29 10:36:02606 'rulesdir/lit-no-attribute-quotes': 'error',
Nikolay Vitkov55adf672025-01-02 12:07:33607 'rulesdir/lit-template-result-or-nothing': 'error',
608 'rulesdir/inject-checkbox-styles': 'error',
609 'rulesdir/jslog-context-list': 'error',
Nikolay Vitkovde07efa2025-01-17 12:58:35610 'rulesdir/es-modules-import': 'error',
611 'rulesdir/html-tagged-template': 'error',
Nikolay Vitkov49d12de2025-02-12 14:41:46612 'rulesdir/enforce-custom-element-definitions-location': [
613 'error',
614 {
615 rootFrontendDirectory: join(import.meta.dirname, 'front_end'),
616 },
617 ],
Nikolay Vitkov55adf672025-01-02 12:07:33618 },
619 },
Nikolay Vitkov55adf672025-01-02 12:07:33620 {
621 name: 'Front-end meta files',
622 files: ['front_end/**/*-meta.ts'],
623 rules: {
624 '@typescript-eslint/naming-convention': [
625 'error',
626 {
627 selector: 'parameter',
628 format: ['camelCase', 'PascalCase'],
629 leadingUnderscore: 'allow',
630 },
631 ],
632 },
633 },
Nikolay Vitkov55adf672025-01-02 12:07:33634 {
635 name: 'TypeScript test files',
636 files: [
637 '*.test.ts',
638 // This makes the specificity greater than the front-end ts files
639 'front_end/**/*.test.ts',
640 'test/**/*.ts',
641 '**/testing/*.ts',
642 'scripts/eslint_rules/test/**/*.js',
Nikolay Vitkov3cace8f2025-02-14 16:37:53643 'extensions/cxx_debugging/e2e/**',
Nikolay Vitkov55adf672025-01-02 12:07:33644 ],
645
646 rules: {
647 // errors on it('test') with no body
648 'mocha/no-pending-tests': 'error',
649
650 // errors on {describe, it}.only
651 'mocha/no-exclusive-tests': 'error',
652
653 'mocha/no-async-describe': 'error',
654 'mocha/no-global-tests': 'error',
655 'mocha/no-nested-tests': 'error',
656
657 '@typescript-eslint/no-non-null-assertion': 'off',
658 '@typescript-eslint/explicit-function-return-type': 'off',
659
Nikolay Vitkov93062642025-02-18 09:49:30660 '@typescript-eslint/only-throw-error': [
661 'error',
662 {
663 allow: [
664 {
665 // Chai AssertionError does not extend Error
666 from: 'package',
667 package: 'chai',
668 name: ['AssertionError'],
669 },
670 ],
671 },
672 ],
673
Nikolay Vitkov55adf672025-01-02 12:07:33674 'rulesdir/check-test-definitions': 'error',
675 'rulesdir/no-assert-strict-equal-for-arrays-and-objects': 'error',
676 'rulesdir/no-assert-deep-strict-equal': 'error',
677 'rulesdir/no-assert-equal': 'error',
678 'rulesdir/no-assert-equal-boolean-null-undefined': 'error',
679 'rulesdir/no-screenshot-test-outside-perf-panel': 'error',
680 'rulesdir/prefer-assert-instance-of': 'error',
681 'rulesdir/prefer-assert-is-ok': 'error',
682 'rulesdir/prefer-assert-length-of': 'error',
Benedikt Meurer39e51332025-01-07 13:17:54683 'rulesdir/prefer-url-string': 'error',
Nikolay Vitkov55adf672025-01-02 12:07:33684 'rulesdir/trace-engine-test-timeouts': 'error',
Nikolay Vitkov49d12de2025-02-12 14:41:46685 'rulesdir/enforce-custom-element-definitions-location': 'off',
Nikolay Vitkov55adf672025-01-02 12:07:33686 },
687
688 settings: {
689 'mocha/additionalCustomNames': [
690 {
691 name: 'describeWithDevtoolsExtension',
692 type: 'suite',
693 interfaces: ['BDD', 'TDD'],
694 },
695 {
696 name: 'describeWithEnvironment',
697 type: 'suite',
698 interfaces: ['BDD', 'TDD'],
699 },
700 {
701 name: 'describeWithLocale',
702 type: 'suite',
703 interfaces: ['BDD', 'TDD'],
704 },
705 {
706 name: 'describeWithMockConnection',
707 type: 'suite',
708 interfaces: ['BDD', 'TDD'],
709 },
710 {
711 name: 'describeWithRealConnection',
712 type: 'suite',
713 interfaces: ['BDD', 'TDD'],
714 },
715 {
716 name: 'itScreenshot',
717 type: 'testCase',
718 interfaces: ['BDD', 'TDD'],
719 },
720 ],
721 },
722 },
Nikolay Vitkov55adf672025-01-02 12:07:33723 {
Nikolay Vitkov52a17972025-01-15 12:52:10724 name: 'Use private class members rule',
Nikolay Vitkov55adf672025-01-02 12:07:33725 files: [
726 'front_end/panels/**/components/*.ts',
727 'front_end/ui/components/**/*.ts',
728 'front_end/entrypoints/**/*.ts',
729 ],
730
731 rules: {
732 'rulesdir/prefer-private-class-members': 'error',
733 },
734 },
Nikolay Vitkov55adf672025-01-02 12:07:33735 {
Nikolay Vitkov52a17972025-01-15 12:52:10736 name: 'Ignore private class members rule',
Nikolay Vitkov55adf672025-01-02 12:07:33737 files: [
738 'front_end/panels/recorder/**/*.ts',
Nikolay Vitkov55adf672025-01-02 12:07:33739 'front_end/ui/components/suggestion_input/*.ts',
740 ],
741 rules: {
742 // TODO(crbug/1402569): Reenable once https://github.com/microsoft/TypeScript/issues/48885 is closed.
743 'rulesdir/prefer-private-class-members': 'off',
744 },
745 },
Nikolay Vitkov55adf672025-01-02 12:07:33746 {
Nikolay Vitkov52a17972025-01-15 12:52:10747 name: 'Supported CSS properties rules',
Nikolay Vitkov55adf672025-01-02 12:07:33748 files: ['front_end/generated/SupportedCSSProperties.js'],
749 rules: {
750 'rulesdir/jslog-context-list': 'error',
751 },
752 },
Nikolay Vitkov55adf672025-01-02 12:07:33753 {
754 name: 'EsLint rules test',
Nikolay Vitkovf1e3bd82025-02-13 11:55:22755 files: ['scripts/eslint_rules/tests/**/*.js'],
Nikolay Vitkov55adf672025-01-02 12:07:33756 rules: {
Nikolay Vitkovf1e3bd82025-02-13 11:55:22757 '@eslint-plugin/no-only-tests': 'error',
Nikolay Vitkov55adf672025-01-02 12:07:33758 },
759 },
Nikolay Vitkov55adf672025-01-02 12:07:33760 {
761 name: 'Legacy test runner',
762 files: ['front_end/legacy_test_runner/**/*'],
763 rules: {
764 'rulesdir/es-modules-import': 'off',
765 },
766 },
767 {
768 name: 'Front end component docs',
769 files: ['front_end/ui/components/docs/**/*.ts'],
770 rules: {
771 // This makes the component doc examples very verbose and doesn't add
772 // anything, so we leave return types to the developer within the
773 // component_docs folder.
774 '@typescript-eslint/explicit-function-return-type': 'off',
Benedikt Meurer6e534082025-01-29 10:36:02775 // We use Lit to help render examples sometimes and we don't use
Nikolay Vitkov55adf672025-01-02 12:07:33776 // {host: this} as often the `this` is the window.
Benedikt Meurer6e534082025-01-29 10:36:02777 'rulesdir/lit-host-this': 'off',
Nikolay Vitkov55adf672025-01-02 12:07:33778 },
779 },
780 {
Nikolay Vitkov52a17972025-01-15 12:52:10781 name: 'Traces import rule',
Nikolay Vitkov55adf672025-01-02 12:07:33782 files: ['front_end/models/trace/handlers/**/*.ts'],
783 rules: {
784 'rulesdir/no-imports-in-directory': [
785 'error',
786 {
787 bannedImportPaths: [
788 join(import.meta.dirname, 'front_end', 'core', 'sdk', 'sdk.js'),
789 ],
790 },
791 ],
792 },
793 },
794 {
Nikolay Vitkov52a17972025-01-15 12:52:10795 name: 'Recorder injected code',
Nikolay Vitkov55adf672025-01-02 12:07:33796 files: ['front_end/panels/recorder/injected/**/*.ts'],
797 rules: {
798 // The code is rolled up and tree-shaken independently from the regular entrypoints.
799 'rulesdir/es-modules-import': 'off',
800 },
801 },
802 {
Nikolay Vitkovb4e8dc72025-01-07 13:03:02803 name: 'Performance panel file',
Nikolay Vitkov55adf672025-01-02 12:07:33804 files: ['front_end/ui/legacy/components/perf_ui/**/*.ts'],
805 rules: {
806 // Enable tracking of canvas save() and
807 // restore() calls to try and catch bugs. Only
808 // enabled in this folder because it is an
809 // expensive rule to run and we do not need it
810 // for any code that doesn't use Canvas.
811 'rulesdir/canvas-context-tracking': 'error',
812 },
813 },
814];