blob: c1131c163b659185874b1eca5452fd3e623f64af [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';
Jack Franklinc10b4972025-02-28 16:32:5616import {join} from 'path';
Nikolay Vitkov55adf672025-01-02 12:07:3317
18rulesdirPlugin.RULES_DIR = join(
Jack Franklinc10b4972025-02-28 16:32:5619 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',
Nikolay Vitkov55adf672025-01-02 12:07:3377 ],
78 },
79 {
Nikolay Vitkovb4e8dc72025-01-07 13:03:0280 name: 'JavaScript files',
Nikolay Vitkov55adf672025-01-02 12:07:3381 plugins: {
82 '@typescript-eslint': typescriptPlugin,
Nikolay Vitkovb4e8dc72025-01-07 13:03:0283 '@stylistic': stylisticPlugin,
Nikolay Vitkovf1e3bd82025-02-13 11:55:2284 '@eslint-plugin': eslintPlugin,
Nikolay Vitkov55adf672025-01-02 12:07:3385 mocha: mochaPlugin,
86 rulesdir: rulesdirPlugin,
87 import: importPlugin,
88 jsdoc: jsdocPlugin,
Nikolay Vitkov55adf672025-01-02 12:07:3389 },
90
91 languageOptions: {
Nikolay Vitkovb4e8dc72025-01-07 13:03:0292 ecmaVersion: 'latest',
93 sourceType: 'module',
Nikolay Vitkov55adf672025-01-02 12:07:3394 globals: {
95 ...globals.browser,
96 },
Nikolay Vitkov55adf672025-01-02 12:07:3397 },
98
Nikolay Vitkov5b2bcff2025-01-29 19:21:1299 linterOptions: {
100 reportUnusedDisableDirectives: 'error',
101 },
102
Nikolay Vitkov55adf672025-01-02 12:07:33103 rules: {
104 // syntax preferences
Nikolay Vitkovb4e8dc72025-01-07 13:03:02105 '@stylistic/quotes': [
Nikolay Vitkov55adf672025-01-02 12:07:33106 'error',
107 'single',
108 {
109 avoidEscape: true,
110 allowTemplateLiterals: false,
111 },
112 ],
113
Nikolay Vitkovb4e8dc72025-01-07 13:03:02114 '@stylistic/semi': 'error',
115 '@stylistic/no-extra-semi': 'error',
116 '@stylistic/comma-style': ['error', 'last'],
117 '@stylistic/wrap-iife': ['error', 'inside'],
Nikolay Vitkov55adf672025-01-02 12:07:33118
Nikolay Vitkovb4e8dc72025-01-07 13:03:02119 '@stylistic/spaced-comment': [
Nikolay Vitkov55adf672025-01-02 12:07:33120 'error',
121 'always',
122 {
123 markers: ['*'],
124 },
125 ],
126
127 eqeqeq: 'error',
128
129 'accessor-pairs': [
130 'error',
131 {
132 getWithoutSet: false,
133 setWithoutGet: false,
134 },
135 ],
136
137 curly: 'error',
Nikolay Vitkovb4e8dc72025-01-07 13:03:02138 '@stylistic/new-parens': 'error',
139 '@stylistic/func-call-spacing': 'error',
140 '@stylistic/arrow-parens': ['error', 'as-needed'],
141 '@stylistic/eol-last': 'error',
Nikolay Vitkov55adf672025-01-02 12:07:33142 'object-shorthand': ['error', 'properties'],
143 'no-useless-rename': 'error',
144
145 // anti-patterns
146 'no-caller': 'error',
147 'no-case-declarations': 'error',
148 'no-cond-assign': 'error',
149
150 'no-console': [
151 'error',
152 {
153 allow: [
154 'assert',
155 'context',
156 'error',
157 'timeStamp',
158 'time',
159 'timeEnd',
160 'warn',
161 ],
162 },
163 ],
164
165 'no-debugger': 'error',
166 'no-dupe-keys': 'error',
167 'no-duplicate-case': 'error',
168
169 'no-else-return': [
170 'error',
171 {
172 allowElseIf: false,
173 },
174 ],
175
Nikolay Vitkovd1ebd9e2025-02-26 10:19:45176 'no-empty': [
177 'error',
178 {
179 allowEmptyCatch: true,
180 },
181 ],
182 'no-lonely-if': 'error',
183
Nikolay Vitkov55adf672025-01-02 12:07:33184 'no-empty-character-class': 'error',
185 'no-global-assign': 'error',
186 'no-implied-eval': 'error',
187 'no-labels': 'error',
188 'no-multi-str': 'error',
Nikolay Vitkovb4e8dc72025-01-07 13:03:02189 'no-object-constructor': 'error',
Nikolay Vitkov55adf672025-01-02 12:07:33190 'no-octal-escape': 'error',
191 'no-self-compare': 'error',
192 'no-shadow-restricted-names': 'error',
193 'no-unreachable': 'error',
194 'no-unsafe-negation': 'error',
195
196 'no-unused-vars': [
197 'error',
198 {
199 args: 'none',
200 vars: 'local',
201 },
202 ],
203
204 'no-var': 'error',
205 'no-with': 'error',
206 'prefer-const': 'error',
207 radix: 'error',
208 'valid-typeof': 'error',
209 'no-return-assign': ['error', 'always'],
210 'no-implicit-coercion': 'error',
211
212 // es2015 features
213 'require-yield': 'error',
Nikolay Vitkovb4e8dc72025-01-07 13:03:02214 '@stylistic/template-curly-spacing': ['error', 'never'],
Nikolay Vitkov55adf672025-01-02 12:07:33215
216 // file whitespace
Nikolay Vitkovb4e8dc72025-01-07 13:03:02217 '@stylistic/no-multiple-empty-lines': [
Nikolay Vitkov55adf672025-01-02 12:07:33218 'error',
219 {
220 max: 1,
221 },
222 ],
Nikolay Vitkovb4e8dc72025-01-07 13:03:02223 '@stylistic/no-mixed-spaces-and-tabs': 'error',
224 '@stylistic/no-trailing-spaces': 'error',
225 '@stylistic/linebreak-style': ['error', 'unix'],
Nikolay Vitkov55adf672025-01-02 12:07:33226
227 /**
228 * Disabled, aspirational rules
229 */
Nikolay Vitkovb4e8dc72025-01-07 13:03:02230 '@stylistic/indent': [
Nikolay Vitkov55adf672025-01-02 12:07:33231 'off',
232 2,
233 {
234 SwitchCase: 1,
235 CallExpression: {
236 arguments: 2,
237 },
238 MemberExpression: 2,
239 },
240 ],
241
242 // brace-style is disabled, as eslint cannot enforce 1tbs as default, but allman for functions
Nikolay Vitkovb4e8dc72025-01-07 13:03:02243 '@stylistic/brace-style': [
Nikolay Vitkov55adf672025-01-02 12:07:33244 'off',
245 'allman',
246 {
247 allowSingleLine: true,
248 },
249 ],
250
251 // key-spacing is disabled, as some objects use value-aligned spacing, some not.
Nikolay Vitkovb4e8dc72025-01-07 13:03:02252 '@stylistic/key-spacing': [
Nikolay Vitkov55adf672025-01-02 12:07:33253 'off',
254 {
255 beforeColon: false,
256 afterColon: true,
257 align: 'value',
258 },
259 ],
260
Nikolay Vitkovb4e8dc72025-01-07 13:03:02261 '@stylistic/quote-props': ['error', 'as-needed'],
Nikolay Vitkov55adf672025-01-02 12:07:33262
263 // no-implicit-globals will prevent accidental globals
264 'no-implicit-globals': 'off',
265 'no-unused-private-class-members': 'error',
266
Benedikt Meurer00c39582025-01-31 09:26:27267 // Sort imports first
268 'import/first': 'error',
Nikolay Vitkov55adf672025-01-02 12:07:33269 // Closure does not properly typecheck default exports
270 'import/no-default-export': 'error',
271 /**
272 * Catch duplicate import paths. For example this would catch the following example:
273 * import {Foo} from './foo.js'
274 * import * as FooModule from './foo.js'
275 **/
276 'import/no-duplicates': 'error',
Nikolay Vitkov41c69112025-01-31 15:20:04277 /**
278 * Provides more consistency in the imports.
279 */
280 'import/order': [
281 'error',
282 {
283 // We need to group the builtin and external as clang-format
284 // can't differentiate the two
285 groups: [['builtin', 'external'], 'parent', 'sibling', 'index'],
286 'newlines-between': 'always',
287 // clang-format has it's own logic overriding this
288 named: false,
289 alphabetize: {
290 order: 'asc',
291 caseInsensitive: true,
292 },
293 },
294 ],
Nikolay Vitkov55adf672025-01-02 12:07:33295 // Try to spot '// console.log()' left over from debugging
296 'rulesdir/no-commented-out-console': 'error',
297 // Prevent imports being commented out rather than deleted.
298 'rulesdir/no-commented-out-import': 'error',
Nikolay Vitkov55adf672025-01-02 12:07:33299 'rulesdir/check-license-header': 'error',
Nikolay Vitkov55adf672025-01-02 12:07:33300 /**
301 * Ensures that JS Doc comments are properly aligned - all the starting
302 * `*` are in the right place.
303 */
304 'jsdoc/check-alignment': 'error',
305 },
306 },
307 {
308 name: 'TypeScript files',
309 files: ['**/*.ts'],
310
311 languageOptions: {
312 ecmaVersion: 'latest',
313 sourceType: 'module',
314
Nikolay Vitkovb4e8dc72025-01-07 13:03:02315 parser: tsParser,
Nikolay Vitkov55adf672025-01-02 12:07:33316 parserOptions: {
317 allowAutomaticSingleRunInference: true,
318 project: join(
Jack Franklinc10b4972025-02-28 16:32:56319 import.meta.dirname,
320 'config',
321 'typescript',
322 'tsconfig.eslint.json',
323 ),
Nikolay Vitkov55adf672025-01-02 12:07:33324 },
325 },
326
327 rules: {
Benedikt Meurer84b0fcc2025-02-12 13:57:23328 '@typescript-eslint/array-type': [
329 'error',
330 {
331 default: 'array-simple',
332 },
333 ],
Nikolay Vitkov55adf672025-01-02 12:07:33334 '@typescript-eslint/no-explicit-any': [
335 'error',
336 {
337 ignoreRestArgs: true,
338 },
339 ],
340
341 '@typescript-eslint/explicit-member-accessibility': [
342 'error',
343 {
344 accessibility: 'no-public',
345 },
346 ],
347
Nikolay Vitkov55adf672025-01-02 12:07:33348 // run just the TypeScript unused-vars rule, else we get duplicate errors
349 'no-unused-vars': 'off',
350 '@typescript-eslint/no-unused-vars': [
351 'error',
352 {
353 argsIgnorePattern: '^_',
354 },
355 ],
356
Nikolay Vitkovb4e8dc72025-01-07 13:03:02357 '@stylistic/member-delimiter-style': [
Nikolay Vitkov55adf672025-01-02 12:07:33358 'error',
359 {
360 multiline: {
361 delimiter: 'semi',
362 requireLast: true,
363 },
364
365 singleline: {
366 delimiter: 'comma',
367 requireLast: false,
368 },
369
370 overrides: {
371 interface: {
372 singleline: {
373 delimiter: 'semi',
374 requireLast: false,
375 },
376
377 multiline: {
378 delimiter: 'semi',
379 requireLast: true,
380 },
381 },
382
383 typeLiteral: {
384 singleline: {
385 delimiter: 'comma',
386 requireLast: false,
387 },
388
389 multiline: {
390 delimiter: 'comma',
391 requireLast: true,
392 },
393 },
394 },
395 },
396 ],
397
398 '@typescript-eslint/no-floating-promises': [
399 'error',
400 {
401 ignoreVoid: true,
402 },
403 ],
404
Nikolay Vitkov55adf672025-01-02 12:07:33405 /**
406 * Enforce that enum members are explicitly defined:
407 * const enum Foo { A = 'a' } rather than const enum Foo { A }
408 */
409 '@typescript-eslint/prefer-enum-initializers': 'error',
410 /**
411 * Ban non-null assertion operator, e.g.:
412 * this.foo!.toLowerCase()
413 */
414 '@typescript-eslint/no-non-null-assertion': 'error',
415 '@typescript-eslint/consistent-type-imports': 'error',
416
417 '@typescript-eslint/naming-convention': [
418 'error',
Nikolay Vitkov52a17972025-01-15 12:52:10419 // Forbids interfaces starting with an I prefix.
420 {
421 selector: 'interface',
422 format: ['PascalCase'],
423
424 custom: {
425 regex: '^I[A-Z]',
426 match: false,
427 },
428 },
Nikolay Vitkov55adf672025-01-02 12:07:33429 {
430 selector: [
431 'function',
432 'accessor',
433 'method',
434 'property',
435 'parameterProperty',
436 ],
437 format: ['camelCase'],
438 },
439 {
440 selector: 'variable',
441
442 filter: {
443 // Ignore localization variables.
444 regex: '^(UIStrings|str_)$',
445 match: false,
446 },
447
448 format: ['camelCase'],
449 },
450 {
451 // We are using camelCase, PascalCase and UPPER_CASE for top-level constants, allow the for now.
452 selector: 'variable',
453 modifiers: ['const'],
454 filter: {
455 // Ignore localization variables.
456 regex: '^(UIStrings|str_)$',
457 match: false,
458 },
459
460 format: ['camelCase', 'UPPER_CASE', 'PascalCase'],
461 },
462 {
463 selector: 'classProperty',
464 modifiers: ['static', 'readonly'],
465 format: ['UPPER_CASE', 'camelCase'],
466 },
467 {
468 selector: 'enumMember',
469 format: ['UPPER_CASE'],
470 },
471 {
472 selector: ['typeLike'],
473 format: ['PascalCase'],
474 },
475 {
476 selector: 'parameter',
477 format: ['camelCase'],
478 leadingUnderscore: 'allow',
479 },
480 {
481 // Public methods are currently in transition and may still have leading underscores.
482 selector: 'method',
483 modifiers: ['public'],
484 format: ['camelCase'],
485 leadingUnderscore: 'allow',
486 },
487 {
488 selector: 'property',
489 modifiers: ['public'],
490 format: ['camelCase'],
491 leadingUnderscore: 'allow',
492 },
493 {
494 // Object literals may be constructed as arguments to external libraries which follow different styles.
495 selector: ['objectLiteralMethod', 'objectLiteralProperty'],
496 modifiers: ['public'],
497 format: null,
498 },
499 {
500 // Ignore type properties that require quotes
501 selector: 'typeProperty',
502 format: null,
503 modifiers: ['requiresQuotes'],
504 },
505 ],
506
Nikolay Vitkov44e30062025-01-07 14:33:04507 '@typescript-eslint/consistent-type-definitions': ['error', 'interface'],
508
Nikolay Vitkov93062642025-02-18 09:49:30509 // Disable eslint base rule
510 'no-throw-literal': 'off',
511 '@typescript-eslint/only-throw-error': 'error',
512
Nikolay Vitkov65a5a912025-02-18 18:30:26513 // Disabled this rule while investigating why it creates
514 // certain TypeScript compilation errors after fixes
515 '@typescript-eslint/no-unnecessary-type-assertion': 'off',
516
Nikolay Vitkovd36860c2025-02-19 17:50:27517 '@typescript-eslint/no-inferrable-types': 'error',
518
Nikolay Vitkovd396b272025-02-19 08:37:28519 '@typescript-eslint/consistent-generic-constructors': [
520 'error',
521 'constructor',
522 ],
523
Nikolay Vitkovd36860c2025-02-19 17:50:27524 // This is more performant
525 // And should provide better stack trace when debugging
526 // see https://v8.dev/blog/fast-async.
527 '@typescript-eslint/return-await': ['error', 'always'],
528
529 '@typescript-eslint/ban-ts-comment': [
530 'error',
531 {
532 // Change after we add some placeholder for old errors
533 minimumDescriptionLength: 0,
534 'ts-check': false,
535 'ts-expect-error': 'allow-with-description',
536 'ts-ignore': true,
537 'ts-nocheck': true,
538 },
539 ],
540
Nikolay Vitkov68140172025-02-20 19:25:39541 '@typescript-eslint/prefer-optional-chain': 'error',
542
Nikolay Vitkovb30f3b22025-03-04 13:38:33543 '@typescript-eslint/no-unsafe-function-type': 'error',
544
Nikolay Vitkov55adf672025-01-02 12:07:33545 'rulesdir/no-underscored-properties': 'error',
Nikolay Vitkov55adf672025-01-02 12:07:33546 'rulesdir/inline-type-imports': 'error',
547
548 'rulesdir/enforce-default-import-name': [
549 'error',
550 {
551 // Enforce that any import of models/trace/trace.js names the import Trace.
552 modulePath: join(
Jack Franklinc10b4972025-02-28 16:32:56553 import.meta.dirname,
554 'front_end',
555 'models',
556 'trace',
557 'trace.js',
558 ),
Nikolay Vitkov55adf672025-01-02 12:07:33559 importName: 'Trace',
560 },
561 ],
562 },
563 },
Nikolay Vitkov55adf672025-01-02 12:07:33564 {
565 name: 'Scripts files',
566 files: ['scripts/**/*'],
567 rules: {
568 'no-console': 'off',
Nikolay Vitkovde07efa2025-01-17 12:58:35569 'rulesdir/es-modules-import': 'off',
Nikolay Vitkov55adf672025-01-02 12:07:33570 },
571 },
Nikolay Vitkov55adf672025-01-02 12:07:33572 {
573 name: 'Front-end files',
574 files: ['front_end/**/*'],
575 rules: {
576 // L10n rules are only relevant in 'front_end'.
577 'rulesdir/l10n-filename-matches': [
578 'error',
579 {
580 rootFrontendDirectory: join(import.meta.dirname, 'front_end'),
581 },
582 ],
583 'rulesdir/l10n-i18nString-call-only-with-uistrings': 'error',
584 'rulesdir/l10n-no-i18nString-calls-module-instantiation': 'error',
585 'rulesdir/l10n-no-locked-or-placeholder-only-phrase': 'error',
586 'rulesdir/l10n-no-uistrings-export': 'error',
587 'rulesdir/l10n-no-unused-message': 'error',
588 },
589 },
Nikolay Vitkov55adf672025-01-02 12:07:33590 {
591 name: 'Front-end TypeScript files',
592 files: ['front_end/**/*.ts'],
593 rules: {
594 '@typescript-eslint/explicit-function-return-type': [
595 'error',
596 {
597 allowExpressions: true,
598 allowConciseArrowFunctionExpressionsStartingWithVoid: true,
599 allowIIFEs: true,
600 },
601 ],
602 'rulesdir/no-importing-images-from-src': 'error',
603 'rulesdir/enforce-bound-render-for-schedule-render': 'error',
604 'rulesdir/enforce-custom-event-names': 'error',
605 'rulesdir/set-data-type-reference': 'error',
606 'rulesdir/no-bound-component-methods': 'error',
607 'rulesdir/no-customized-builtin-elements': 'error',
608 'rulesdir/no-self-closing-custom-element-tagnames': 'error',
Benedikt Meurer6e534082025-01-29 10:36:02609 'rulesdir/no-a-tags-in-lit': 'error',
Nikolay Vitkov55adf672025-01-02 12:07:33610 'rulesdir/check-css-import': 'error',
611 'rulesdir/enforce-optional-properties-last': 'error',
612 'rulesdir/check-enumerated-histograms': 'error',
613 'rulesdir/check-was-shown-methods': 'error',
614 'rulesdir/static-custom-event-names': 'error',
Benedikt Meurer6e534082025-01-29 10:36:02615 'rulesdir/lit-no-attribute-quotes': 'error',
Nikolay Vitkov55adf672025-01-02 12:07:33616 'rulesdir/lit-template-result-or-nothing': 'error',
617 'rulesdir/inject-checkbox-styles': 'error',
618 'rulesdir/jslog-context-list': 'error',
Nikolay Vitkovde07efa2025-01-17 12:58:35619 'rulesdir/es-modules-import': 'error',
620 'rulesdir/html-tagged-template': 'error',
Nikolay Vitkov49d12de2025-02-12 14:41:46621 'rulesdir/enforce-custom-element-definitions-location': [
622 'error',
623 {
624 rootFrontendDirectory: join(import.meta.dirname, 'front_end'),
625 },
626 ],
Ergun Erdogmus5efc7e92025-02-21 11:36:50627 'rulesdir/enforce-ui-strings-as-const': 'error',
Nikolay Vitkov55adf672025-01-02 12:07:33628 },
629 },
Nikolay Vitkov55adf672025-01-02 12:07:33630 {
631 name: 'Front-end meta files',
632 files: ['front_end/**/*-meta.ts'],
633 rules: {
634 '@typescript-eslint/naming-convention': [
635 'error',
636 {
637 selector: 'parameter',
638 format: ['camelCase', 'PascalCase'],
639 leadingUnderscore: 'allow',
640 },
641 ],
642 },
643 },
Nikolay Vitkov55adf672025-01-02 12:07:33644 {
645 name: 'TypeScript test files',
646 files: [
647 '*.test.ts',
648 // This makes the specificity greater than the front-end ts files
649 'front_end/**/*.test.ts',
650 'test/**/*.ts',
651 '**/testing/*.ts',
652 'scripts/eslint_rules/test/**/*.js',
Nikolay Vitkov3cace8f2025-02-14 16:37:53653 'extensions/cxx_debugging/e2e/**',
Nikolay Vitkov55adf672025-01-02 12:07:33654 ],
655
656 rules: {
657 // errors on it('test') with no body
658 'mocha/no-pending-tests': 'error',
659
660 // errors on {describe, it}.only
661 'mocha/no-exclusive-tests': 'error',
662
663 'mocha/no-async-describe': 'error',
664 'mocha/no-global-tests': 'error',
665 'mocha/no-nested-tests': 'error',
666
667 '@typescript-eslint/no-non-null-assertion': 'off',
668 '@typescript-eslint/explicit-function-return-type': 'off',
669
Nikolay Vitkov93062642025-02-18 09:49:30670 '@typescript-eslint/only-throw-error': [
671 'error',
672 {
673 allow: [
674 {
675 // Chai AssertionError does not extend Error
676 from: 'package',
677 package: 'chai',
678 name: ['AssertionError'],
679 },
680 ],
681 },
682 ],
683
Nikolay Vitkov55adf672025-01-02 12:07:33684 'rulesdir/check-test-definitions': 'error',
685 'rulesdir/no-assert-strict-equal-for-arrays-and-objects': 'error',
686 'rulesdir/no-assert-deep-strict-equal': 'error',
687 'rulesdir/no-assert-equal': 'error',
688 'rulesdir/no-assert-equal-boolean-null-undefined': 'error',
689 'rulesdir/no-screenshot-test-outside-perf-panel': 'error',
690 'rulesdir/prefer-assert-instance-of': 'error',
691 'rulesdir/prefer-assert-is-ok': 'error',
692 'rulesdir/prefer-assert-length-of': 'error',
Benedikt Meurer39e51332025-01-07 13:17:54693 'rulesdir/prefer-url-string': 'error',
Nikolay Vitkov55adf672025-01-02 12:07:33694 'rulesdir/trace-engine-test-timeouts': 'error',
Nikolay Vitkov49d12de2025-02-12 14:41:46695 'rulesdir/enforce-custom-element-definitions-location': 'off',
Nikolay Vitkov55adf672025-01-02 12:07:33696 },
697
698 settings: {
699 'mocha/additionalCustomNames': [
700 {
701 name: 'describeWithDevtoolsExtension',
702 type: 'suite',
703 interfaces: ['BDD', 'TDD'],
704 },
705 {
706 name: 'describeWithEnvironment',
707 type: 'suite',
708 interfaces: ['BDD', 'TDD'],
709 },
710 {
711 name: 'describeWithLocale',
712 type: 'suite',
713 interfaces: ['BDD', 'TDD'],
714 },
715 {
716 name: 'describeWithMockConnection',
717 type: 'suite',
718 interfaces: ['BDD', 'TDD'],
719 },
720 {
721 name: 'describeWithRealConnection',
722 type: 'suite',
723 interfaces: ['BDD', 'TDD'],
724 },
725 {
726 name: 'itScreenshot',
727 type: 'testCase',
728 interfaces: ['BDD', 'TDD'],
729 },
730 ],
731 },
732 },
Nikolay Vitkov55adf672025-01-02 12:07:33733 {
Nikolay Vitkov52a17972025-01-15 12:52:10734 name: 'Use private class members rule',
Nikolay Vitkov55adf672025-01-02 12:07:33735 files: [
736 'front_end/panels/**/components/*.ts',
737 'front_end/ui/components/**/*.ts',
738 'front_end/entrypoints/**/*.ts',
739 ],
740
741 rules: {
742 'rulesdir/prefer-private-class-members': 'error',
743 },
744 },
Nikolay Vitkov55adf672025-01-02 12:07:33745 {
Nikolay Vitkov52a17972025-01-15 12:52:10746 name: 'Ignore private class members rule',
Nikolay Vitkov55adf672025-01-02 12:07:33747 files: [
748 'front_end/panels/recorder/**/*.ts',
Nikolay Vitkov55adf672025-01-02 12:07:33749 'front_end/ui/components/suggestion_input/*.ts',
750 ],
751 rules: {
752 // TODO(crbug/1402569): Reenable once https://github.com/microsoft/TypeScript/issues/48885 is closed.
753 'rulesdir/prefer-private-class-members': 'off',
754 },
755 },
Nikolay Vitkov55adf672025-01-02 12:07:33756 {
Nikolay Vitkov52a17972025-01-15 12:52:10757 name: 'Supported CSS properties rules',
Nikolay Vitkov55adf672025-01-02 12:07:33758 files: ['front_end/generated/SupportedCSSProperties.js'],
759 rules: {
760 'rulesdir/jslog-context-list': 'error',
761 },
762 },
Nikolay Vitkov55adf672025-01-02 12:07:33763 {
764 name: 'EsLint rules test',
Nikolay Vitkovf1e3bd82025-02-13 11:55:22765 files: ['scripts/eslint_rules/tests/**/*.js'],
Nikolay Vitkov55adf672025-01-02 12:07:33766 rules: {
Nikolay Vitkovf1e3bd82025-02-13 11:55:22767 '@eslint-plugin/no-only-tests': 'error',
Nikolay Vitkov55adf672025-01-02 12:07:33768 },
769 },
Nikolay Vitkov55adf672025-01-02 12:07:33770 {
771 name: 'Legacy test runner',
772 files: ['front_end/legacy_test_runner/**/*'],
773 rules: {
774 'rulesdir/es-modules-import': 'off',
775 },
776 },
777 {
778 name: 'Front end component docs',
779 files: ['front_end/ui/components/docs/**/*.ts'],
780 rules: {
781 // This makes the component doc examples very verbose and doesn't add
782 // anything, so we leave return types to the developer within the
783 // component_docs folder.
784 '@typescript-eslint/explicit-function-return-type': 'off',
Benedikt Meurer6e534082025-01-29 10:36:02785 // We use Lit to help render examples sometimes and we don't use
Nikolay Vitkov55adf672025-01-02 12:07:33786 // {host: this} as often the `this` is the window.
Benedikt Meurer6e534082025-01-29 10:36:02787 'rulesdir/lit-host-this': 'off',
Nikolay Vitkov55adf672025-01-02 12:07:33788 },
789 },
790 {
Nikolay Vitkov52a17972025-01-15 12:52:10791 name: 'Traces import rule',
Nikolay Vitkov55adf672025-01-02 12:07:33792 files: ['front_end/models/trace/handlers/**/*.ts'],
793 rules: {
794 'rulesdir/no-imports-in-directory': [
795 'error',
796 {
797 bannedImportPaths: [
798 join(import.meta.dirname, 'front_end', 'core', 'sdk', 'sdk.js'),
799 ],
800 },
801 ],
802 },
803 },
804 {
Nikolay Vitkov52a17972025-01-15 12:52:10805 name: 'Recorder injected code',
Nikolay Vitkov55adf672025-01-02 12:07:33806 files: ['front_end/panels/recorder/injected/**/*.ts'],
807 rules: {
808 // The code is rolled up and tree-shaken independently from the regular entrypoints.
809 'rulesdir/es-modules-import': 'off',
810 },
811 },
812 {
Nikolay Vitkovb4e8dc72025-01-07 13:03:02813 name: 'Performance panel file',
Nikolay Vitkov55adf672025-01-02 12:07:33814 files: ['front_end/ui/legacy/components/perf_ui/**/*.ts'],
815 rules: {
816 // Enable tracking of canvas save() and
817 // restore() calls to try and catch bugs. Only
818 // enabled in this folder because it is an
819 // expensive rule to run and we do not need it
820 // for any code that doesn't use Canvas.
821 'rulesdir/canvas-context-tracking': 'error',
822 },
823 },
Jack Franklinc10b4972025-02-28 16:32:56824 {
825 name: 'TypeScript type-definitions',
826 files: ['**/*.d.ts'],
827 rules: {
828 // Not a useful rule for .d.ts files where we are
829 // representing an existing module.
830 'import/no-default-export': 'off'
831 }
832 }
Nikolay Vitkov55adf672025-01-02 12:07:33833];