blob: 73f62805931253cb71cab951a400d2675dfe8f0e [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 Vitkov41c69112025-01-31 15:20:045import stylisticPlugin from '@stylistic/eslint-plugin';
Nikolay Vitkova0951482025-07-07 12:17:526import { defineConfig, globalIgnores } from 'eslint/config';
Nikolay Vitkovf1e3bd82025-02-13 11:55:227import eslintPlugin from 'eslint-plugin-eslint-plugin';
Nikolay Vitkov55adf672025-01-02 12:07:338import importPlugin from 'eslint-plugin-import';
9import jsdocPlugin from 'eslint-plugin-jsdoc';
Nikolay Vitkov41c69112025-01-31 15:20:0410import mochaPlugin from 'eslint-plugin-mocha';
Nikolay Vitkov55adf672025-01-02 12:07:3311import globals from 'globals';
Nikolay Vitkova0951482025-07-07 12:17:5212import { join } from 'path';
Nikolay Vitkovf1e99c02025-05-09 12:21:4213import typescriptEslint from 'typescript-eslint';
Nikolay Vitkov55adf672025-01-02 12:07:3314
Nikolay Vitkovc9178752025-04-02 13:37:0715import rulesdirPlugin from './scripts/eslint_rules/rules-dir.mjs';
Nikolay Vitkov55adf672025-01-02 12:07:3316
Nikolay Vitkov856215c2025-04-23 14:32:5717export default defineConfig([
18 globalIgnores([
19 // Git submodules that are not in third_party
20 'build/',
21 'buildtools/',
Nikolay Vitkov5b2bcff2025-01-29 19:21:1222
Nikolay Vitkov856215c2025-04-23 14:32:5723 // Don't include the common build directory
24 'out/',
25 // Don't include third party code
26 'third_party/',
Nikolay Vitkov4dc470b2025-02-20 12:44:3227
Jack Franklin825d7532025-07-03 08:43:2428 'front_end/diff/diff_match_patch.js',
Nikolay Vitkov856215c2025-04-23 14:32:5729 'front_end/models/javascript_metadata/NativeFunctions.js',
30 // All of these scripts are auto-generated so don't lint them.
31 'front_end/generated/ARIAProperties.js',
32 'front_end/generated/Deprecation.ts',
33 'front_end/generated/InspectorBackendCommands.js',
34 'front_end/generated/protocol-mapping.d.ts',
35 'front_end/generated/protocol-proxy-api.d.ts',
36 'front_end/generated/protocol.ts',
37 // Any third_party addition has its source code checked out into
38 // third_party/X/package, so we ignore that code as it's not code we author or
39 // own.
40 'front_end/third_party/*/package/',
41 // Any JS files are also not authored by devtools-frontend, so we ignore those.
42 'front_end/third_party/**/*',
43 // Lighthouse doesn't have a package/ folder but has other nested folders, so
44 // we ignore any folders within the lighthouse directory.
45 'front_end/third_party/lighthouse/*/',
46 // The CodeMirror bundle file is auto-generated and rolled-up as part of the',
47 // install script, so we don't need to lint it.
48 'front_end/third_party/codemirror.next/bundle.ts',
49 // Lit lib files are auto-generated and rolled up as part of the install script.
50 'front_end/third_party/lit/src/*.ts',
51 // @puppeteer/replay is auto-generated.
52 'front_end/third_party/puppeteer-replay/**/*.ts',
53 // Third party code we did not author for extensions
54 'extensions/cxx_debugging/third_party/**/*',
Nikolay Vitkov55adf672025-01-02 12:07:3355
Nikolay Vitkov856215c2025-04-23 14:32:5756 '**/node_modules',
57 'scripts/build/typescript/tests',
58 'scripts/migration/**/*.js',
59 'scripts/protocol_typescript/*.js',
60 'scripts/deps/tests/fixtures',
61 'test/**/fixtures/',
62 'test/e2e/**/*.js',
63 'test/shared/**/*.js',
64 ]),
Nikolay Vitkov55adf672025-01-02 12:07:3365 {
Nikolay Vitkovb4e8dc72025-01-07 13:03:0266 name: 'JavaScript files',
Nikolay Vitkov55adf672025-01-02 12:07:3367 plugins: {
Nikolay Vitkovf1e99c02025-05-09 12:21:4268 '@typescript-eslint': typescriptEslint.plugin,
Nikolay Vitkovb4e8dc72025-01-07 13:03:0269 '@stylistic': stylisticPlugin,
Nikolay Vitkovf1e3bd82025-02-13 11:55:2270 '@eslint-plugin': eslintPlugin,
Nikolay Vitkov55adf672025-01-02 12:07:3371 mocha: mochaPlugin,
72 rulesdir: rulesdirPlugin,
73 import: importPlugin,
74 jsdoc: jsdocPlugin,
Nikolay Vitkov55adf672025-01-02 12:07:3375 },
76
77 languageOptions: {
Nikolay Vitkovb4e8dc72025-01-07 13:03:0278 ecmaVersion: 'latest',
79 sourceType: 'module',
Nikolay Vitkov55adf672025-01-02 12:07:3380 globals: {
81 ...globals.browser,
82 },
Nikolay Vitkov55adf672025-01-02 12:07:3383 },
84
Nikolay Vitkov5b2bcff2025-01-29 19:21:1285 linterOptions: {
86 reportUnusedDisableDirectives: 'error',
87 },
88
Nikolay Vitkov55adf672025-01-02 12:07:3389 rules: {
90 // syntax preferences
Nikolay Vitkovb4e8dc72025-01-07 13:03:0291 '@stylistic/quotes': [
Nikolay Vitkov55adf672025-01-02 12:07:3392 'error',
93 'single',
94 {
95 avoidEscape: true,
96 allowTemplateLiterals: false,
97 },
98 ],
99
Nikolay Vitkovb4e8dc72025-01-07 13:03:02100 '@stylistic/semi': 'error',
101 '@stylistic/no-extra-semi': 'error',
102 '@stylistic/comma-style': ['error', 'last'],
103 '@stylistic/wrap-iife': ['error', 'inside'],
Nikolay Vitkov55adf672025-01-02 12:07:33104
Nikolay Vitkovb4e8dc72025-01-07 13:03:02105 '@stylistic/spaced-comment': [
Nikolay Vitkov55adf672025-01-02 12:07:33106 'error',
107 'always',
108 {
109 markers: ['*'],
110 },
111 ],
112
113 eqeqeq: 'error',
114
115 'accessor-pairs': [
116 'error',
117 {
118 getWithoutSet: false,
119 setWithoutGet: false,
120 },
121 ],
122
123 curly: 'error',
Nikolay Vitkovb4e8dc72025-01-07 13:03:02124 '@stylistic/new-parens': 'error',
125 '@stylistic/func-call-spacing': 'error',
126 '@stylistic/arrow-parens': ['error', 'as-needed'],
127 '@stylistic/eol-last': 'error',
Nikolay Vitkov55adf672025-01-02 12:07:33128 'object-shorthand': ['error', 'properties'],
129 'no-useless-rename': 'error',
130
131 // anti-patterns
132 'no-caller': 'error',
133 'no-case-declarations': 'error',
134 'no-cond-assign': 'error',
135
136 'no-console': [
137 'error',
138 {
139 allow: [
140 'assert',
141 'context',
142 'error',
143 'timeStamp',
144 'time',
145 'timeEnd',
146 'warn',
147 ],
148 },
149 ],
150
151 'no-debugger': 'error',
152 'no-dupe-keys': 'error',
153 'no-duplicate-case': 'error',
154
155 'no-else-return': [
156 'error',
157 {
158 allowElseIf: false,
159 },
160 ],
161
Nikolay Vitkovd1ebd9e2025-02-26 10:19:45162 'no-empty': [
163 'error',
164 {
165 allowEmptyCatch: true,
166 },
167 ],
168 'no-lonely-if': 'error',
169
Nikolay Vitkov55adf672025-01-02 12:07:33170 'no-empty-character-class': 'error',
171 'no-global-assign': 'error',
172 'no-implied-eval': 'error',
173 'no-labels': 'error',
174 'no-multi-str': 'error',
Nikolay Vitkovb4e8dc72025-01-07 13:03:02175 'no-object-constructor': 'error',
Nikolay Vitkov55adf672025-01-02 12:07:33176 'no-octal-escape': 'error',
177 'no-self-compare': 'error',
178 'no-shadow-restricted-names': 'error',
179 'no-unreachable': 'error',
180 'no-unsafe-negation': 'error',
181
182 'no-unused-vars': [
183 'error',
184 {
185 args: 'none',
186 vars: 'local',
187 },
188 ],
189
190 'no-var': 'error',
191 'no-with': 'error',
192 'prefer-const': 'error',
193 radix: 'error',
194 'valid-typeof': 'error',
195 'no-return-assign': ['error', 'always'],
Nikolay Vitkova0951482025-07-07 12:17:52196 'no-implicit-coercion': ['error', { allow: ['!!'] }],
Nikolay Vitkov55adf672025-01-02 12:07:33197
Nikolay Vitkovc32e3bb2025-03-10 10:56:34198 'no-array-constructor': 'error',
199
Nikolay Vitkov55adf672025-01-02 12:07:33200 // es2015 features
201 'require-yield': 'error',
Nikolay Vitkovb4e8dc72025-01-07 13:03:02202 '@stylistic/template-curly-spacing': ['error', 'never'],
Nikolay Vitkov55adf672025-01-02 12:07:33203
204 // file whitespace
Nikolay Vitkovb4e8dc72025-01-07 13:03:02205 '@stylistic/no-multiple-empty-lines': [
Nikolay Vitkov55adf672025-01-02 12:07:33206 'error',
207 {
208 max: 1,
209 },
210 ],
Nikolay Vitkovb4e8dc72025-01-07 13:03:02211 '@stylistic/no-mixed-spaces-and-tabs': 'error',
212 '@stylistic/no-trailing-spaces': 'error',
213 '@stylistic/linebreak-style': ['error', 'unix'],
Nikolay Vitkov55adf672025-01-02 12:07:33214
215 /**
216 * Disabled, aspirational rules
217 */
Nikolay Vitkovb4e8dc72025-01-07 13:03:02218 '@stylistic/indent': [
Nikolay Vitkov55adf672025-01-02 12:07:33219 'off',
220 2,
221 {
222 SwitchCase: 1,
223 CallExpression: {
224 arguments: 2,
225 },
226 MemberExpression: 2,
227 },
228 ],
229
230 // brace-style is disabled, as eslint cannot enforce 1tbs as default, but allman for functions
Nikolay Vitkovb4e8dc72025-01-07 13:03:02231 '@stylistic/brace-style': [
Nikolay Vitkov55adf672025-01-02 12:07:33232 'off',
233 'allman',
234 {
235 allowSingleLine: true,
236 },
237 ],
238
239 // key-spacing is disabled, as some objects use value-aligned spacing, some not.
Nikolay Vitkovb4e8dc72025-01-07 13:03:02240 '@stylistic/key-spacing': [
Nikolay Vitkov55adf672025-01-02 12:07:33241 'off',
242 {
243 beforeColon: false,
244 afterColon: true,
245 align: 'value',
246 },
247 ],
248
Nikolay Vitkovb4e8dc72025-01-07 13:03:02249 '@stylistic/quote-props': ['error', 'as-needed'],
Nikolay Vitkov55adf672025-01-02 12:07:33250
251 // no-implicit-globals will prevent accidental globals
252 'no-implicit-globals': 'off',
253 'no-unused-private-class-members': 'error',
Nikolay Vitkova3e7ae12025-05-26 17:43:51254 'no-useless-constructor': 'error',
Nikolay Vitkov55adf672025-01-02 12:07:33255
Benedikt Meurer00c39582025-01-31 09:26:27256 // Sort imports first
257 'import/first': 'error',
Nikolay Vitkov55adf672025-01-02 12:07:33258 // Closure does not properly typecheck default exports
259 'import/no-default-export': 'error',
260 /**
261 * Catch duplicate import paths. For example this would catch the following example:
262 * import {Foo} from './foo.js'
263 * import * as FooModule from './foo.js'
264 **/
265 'import/no-duplicates': 'error',
Nikolay Vitkov41c69112025-01-31 15:20:04266 /**
267 * Provides more consistency in the imports.
268 */
269 'import/order': [
270 'error',
271 {
272 // We need to group the builtin and external as clang-format
273 // can't differentiate the two
274 groups: [['builtin', 'external'], 'parent', 'sibling', 'index'],
275 'newlines-between': 'always',
276 // clang-format has it's own logic overriding this
277 named: false,
278 alphabetize: {
279 order: 'asc',
280 caseInsensitive: true,
281 },
282 },
283 ],
Nikolay Vitkov55adf672025-01-02 12:07:33284 // Try to spot '// console.log()' left over from debugging
285 'rulesdir/no-commented-out-console': 'error',
286 // Prevent imports being commented out rather than deleted.
287 'rulesdir/no-commented-out-import': 'error',
Nikolay Vitkov55adf672025-01-02 12:07:33288 'rulesdir/check-license-header': 'error',
Nikolay Vitkov55adf672025-01-02 12:07:33289 /**
290 * Ensures that JS Doc comments are properly aligned - all the starting
291 * `*` are in the right place.
292 */
293 'jsdoc/check-alignment': 'error',
294 },
295 },
296 {
297 name: 'TypeScript files',
298 files: ['**/*.ts'],
299
300 languageOptions: {
301 ecmaVersion: 'latest',
302 sourceType: 'module',
303
Nikolay Vitkovf1e99c02025-05-09 12:21:42304 parser: typescriptEslint.parser,
Nikolay Vitkov55adf672025-01-02 12:07:33305 parserOptions: {
306 allowAutomaticSingleRunInference: true,
307 project: join(
Nikolay Vitkova0951482025-07-07 12:17:52308 import.meta.dirname,
309 'config',
310 'typescript',
311 'tsconfig.eslint.json',
312 ),
Nikolay Vitkov55adf672025-01-02 12:07:33313 },
314 },
315
316 rules: {
Benedikt Meurer84b0fcc2025-02-12 13:57:23317 '@typescript-eslint/array-type': [
318 'error',
319 {
320 default: 'array-simple',
321 },
322 ],
Nikolay Vitkov55adf672025-01-02 12:07:33323 '@typescript-eslint/no-explicit-any': [
324 'error',
325 {
326 ignoreRestArgs: true,
327 },
328 ],
329
330 '@typescript-eslint/explicit-member-accessibility': [
331 'error',
332 {
333 accessibility: 'no-public',
334 },
335 ],
336
Nikolay Vitkov55adf672025-01-02 12:07:33337 // run just the TypeScript unused-vars rule, else we get duplicate errors
338 'no-unused-vars': 'off',
339 '@typescript-eslint/no-unused-vars': [
340 'error',
341 {
342 argsIgnorePattern: '^_',
343 },
344 ],
345
Nikolay Vitkovb4e8dc72025-01-07 13:03:02346 '@stylistic/member-delimiter-style': [
Nikolay Vitkov55adf672025-01-02 12:07:33347 'error',
348 {
349 multiline: {
350 delimiter: 'semi',
351 requireLast: true,
352 },
353
354 singleline: {
355 delimiter: 'comma',
356 requireLast: false,
357 },
358
359 overrides: {
360 interface: {
361 singleline: {
362 delimiter: 'semi',
363 requireLast: false,
364 },
365
366 multiline: {
367 delimiter: 'semi',
368 requireLast: true,
369 },
370 },
371
372 typeLiteral: {
373 singleline: {
374 delimiter: 'comma',
375 requireLast: false,
376 },
377
378 multiline: {
379 delimiter: 'comma',
380 requireLast: true,
381 },
382 },
383 },
384 },
385 ],
386
387 '@typescript-eslint/no-floating-promises': [
388 'error',
389 {
390 ignoreVoid: true,
391 },
392 ],
393
Nikolay Vitkov55adf672025-01-02 12:07:33394 /**
395 * Enforce that enum members are explicitly defined:
396 * const enum Foo { A = 'a' } rather than const enum Foo { A }
397 */
398 '@typescript-eslint/prefer-enum-initializers': 'error',
399 /**
400 * Ban non-null assertion operator, e.g.:
401 * this.foo!.toLowerCase()
402 */
403 '@typescript-eslint/no-non-null-assertion': 'error',
404 '@typescript-eslint/consistent-type-imports': 'error',
405
406 '@typescript-eslint/naming-convention': [
407 'error',
Nikolay Vitkov52a17972025-01-15 12:52:10408 // Forbids interfaces starting with an I prefix.
409 {
410 selector: 'interface',
411 format: ['PascalCase'],
412
413 custom: {
414 regex: '^I[A-Z]',
415 match: false,
416 },
417 },
Nikolay Vitkov55adf672025-01-02 12:07:33418 {
419 selector: [
420 'function',
421 'accessor',
422 'method',
423 'property',
424 'parameterProperty',
425 ],
426 format: ['camelCase'],
427 },
428 {
429 selector: 'variable',
430
431 filter: {
432 // Ignore localization variables.
433 regex: '^(UIStrings|str_)$',
434 match: false,
435 },
436
437 format: ['camelCase'],
438 },
439 {
440 // We are using camelCase, PascalCase and UPPER_CASE for top-level constants, allow the for now.
441 selector: 'variable',
442 modifiers: ['const'],
443 filter: {
444 // Ignore localization variables.
445 regex: '^(UIStrings|str_)$',
446 match: false,
447 },
448
449 format: ['camelCase', 'UPPER_CASE', 'PascalCase'],
450 },
451 {
452 selector: 'classProperty',
453 modifiers: ['static', 'readonly'],
454 format: ['UPPER_CASE', 'camelCase'],
455 },
456 {
457 selector: 'enumMember',
458 format: ['UPPER_CASE'],
459 },
460 {
461 selector: ['typeLike'],
462 format: ['PascalCase'],
463 },
464 {
465 selector: 'parameter',
466 format: ['camelCase'],
467 leadingUnderscore: 'allow',
468 },
469 {
470 // Public methods are currently in transition and may still have leading underscores.
471 selector: 'method',
472 modifiers: ['public'],
473 format: ['camelCase'],
474 leadingUnderscore: 'allow',
475 },
476 {
477 selector: 'property',
478 modifiers: ['public'],
479 format: ['camelCase'],
480 leadingUnderscore: 'allow',
481 },
482 {
483 // Object literals may be constructed as arguments to external libraries which follow different styles.
484 selector: ['objectLiteralMethod', 'objectLiteralProperty'],
485 modifiers: ['public'],
486 format: null,
487 },
488 {
489 // Ignore type properties that require quotes
490 selector: 'typeProperty',
491 format: null,
492 modifiers: ['requiresQuotes'],
493 },
494 ],
495
Nikolay Vitkov44e30062025-01-07 14:33:04496 '@typescript-eslint/consistent-type-definitions': ['error', 'interface'],
497
Nikolay Vitkov93062642025-02-18 09:49:30498 // Disable eslint base rule
499 'no-throw-literal': 'off',
500 '@typescript-eslint/only-throw-error': 'error',
501
Nikolay Vitkov65a5a912025-02-18 18:30:26502 // Disabled this rule while investigating why it creates
503 // certain TypeScript compilation errors after fixes
504 '@typescript-eslint/no-unnecessary-type-assertion': 'off',
505
Nikolay Vitkovd36860c2025-02-19 17:50:27506 '@typescript-eslint/no-inferrable-types': 'error',
507
Nikolay Vitkovd396b272025-02-19 08:37:28508 '@typescript-eslint/consistent-generic-constructors': [
509 'error',
510 'constructor',
511 ],
512
Nikolay Vitkovd36860c2025-02-19 17:50:27513 // This is more performant
514 // And should provide better stack trace when debugging
515 // see https://v8.dev/blog/fast-async.
516 '@typescript-eslint/return-await': ['error', 'always'],
517
518 '@typescript-eslint/ban-ts-comment': [
519 'error',
520 {
521 // Change after we add some placeholder for old errors
522 minimumDescriptionLength: 0,
523 'ts-check': false,
524 'ts-expect-error': 'allow-with-description',
525 'ts-ignore': true,
526 'ts-nocheck': true,
527 },
528 ],
529
Nikolay Vitkov68140172025-02-20 19:25:39530 '@typescript-eslint/prefer-optional-chain': 'error',
531
Nikolay Vitkovb30f3b22025-03-04 13:38:33532 '@typescript-eslint/no-unsafe-function-type': 'error',
533
Nikolay Vitkova2ced3f2025-03-05 11:58:03534 '@typescript-eslint/no-empty-object-type': [
535 'error',
536 {
537 allowInterfaces: 'with-single-extends',
538 },
539 ],
540
Nikolay Vitkovc32e3bb2025-03-10 10:56:34541 'no-array-constructor': 'off',
542 '@typescript-eslint/no-array-constructor': 'error',
543
Nikolay Vitkov74a532c2025-05-16 10:55:58544 '@typescript-eslint/consistent-indexed-object-style': 'error',
545
Nikolay Vitkova3e7ae12025-05-26 17:43:51546 'no-useless-constructor': 'off',
547 '@typescript-eslint/no-useless-constructor': 'error',
548
Nikolay Vitkov55adf672025-01-02 12:07:33549 'rulesdir/no-underscored-properties': 'error',
Nikolay Vitkov55adf672025-01-02 12:07:33550 'rulesdir/inline-type-imports': 'error',
551
552 'rulesdir/enforce-default-import-name': [
553 'error',
554 {
555 // Enforce that any import of models/trace/trace.js names the import Trace.
556 modulePath: join(
Nikolay Vitkova0951482025-07-07 12:17:52557 import.meta.dirname,
558 'front_end',
559 'models',
560 'trace',
561 'trace.js',
562 ),
Nikolay Vitkov55adf672025-01-02 12:07:33563 importName: 'Trace',
564 },
565 ],
Connor Clark4d3add72025-06-17 21:58:12566
567 'rulesdir/validate-timing-types': 'error',
Nikolay Vitkov55adf672025-01-02 12:07:33568 },
569 },
Nikolay Vitkov55adf672025-01-02 12:07:33570 {
571 name: 'Scripts files',
572 files: ['scripts/**/*'],
573 rules: {
574 'no-console': 'off',
Nikolay Vitkovde07efa2025-01-17 12:58:35575 'rulesdir/es-modules-import': 'off',
Nikolay Vitkov77ba8df2025-03-27 15:06:08576 'import/no-default-export': 'off',
Nikolay Vitkov55adf672025-01-02 12:07:33577 },
578 },
Nikolay Vitkov55adf672025-01-02 12:07:33579 {
580 name: 'Front-end files',
581 files: ['front_end/**/*'],
582 rules: {
583 // L10n rules are only relevant in 'front_end'.
584 'rulesdir/l10n-filename-matches': [
585 'error',
586 {
587 rootFrontendDirectory: join(import.meta.dirname, 'front_end'),
588 },
589 ],
590 'rulesdir/l10n-i18nString-call-only-with-uistrings': 'error',
591 'rulesdir/l10n-no-i18nString-calls-module-instantiation': 'error',
592 'rulesdir/l10n-no-locked-or-placeholder-only-phrase': 'error',
593 'rulesdir/l10n-no-uistrings-export': 'error',
594 'rulesdir/l10n-no-unused-message': 'error',
595 },
596 },
Nikolay Vitkov55adf672025-01-02 12:07:33597 {
598 name: 'Front-end TypeScript files',
599 files: ['front_end/**/*.ts'],
600 rules: {
601 '@typescript-eslint/explicit-function-return-type': [
602 'error',
603 {
604 allowExpressions: true,
605 allowConciseArrowFunctionExpressionsStartingWithVoid: true,
606 allowIIFEs: true,
607 },
608 ],
Danil Somsikovd12440f2025-03-31 18:45:43609 'rulesdir/no-imperative-dom-api': 'error',
Danil Somsikov9f442bb2025-04-02 09:58:27610 'rulesdir/no-lit-render-outside-of-view': 'error',
Nikolay Vitkov55adf672025-01-02 12:07:33611 'rulesdir/no-importing-images-from-src': 'error',
Nikolay Vitkov55adf672025-01-02 12:07:33612 'rulesdir/enforce-custom-event-names': 'error',
613 'rulesdir/set-data-type-reference': 'error',
614 'rulesdir/no-bound-component-methods': 'error',
Benedikt Meurer07ad6092025-04-24 15:28:53615 'rulesdir/no-adopted-style-sheets': 'error',
Nikolay Vitkov55adf672025-01-02 12:07:33616 'rulesdir/no-customized-builtin-elements': 'error',
Kateryna Prokopenko0e68ea42025-05-30 09:46:26617 'rulesdir/no-deprecated-component-usages': 'error',
Nikolay Vitkov55adf672025-01-02 12:07:33618 'rulesdir/no-self-closing-custom-element-tagnames': 'error',
Benedikt Meurer6e534082025-01-29 10:36:02619 'rulesdir/no-a-tags-in-lit': 'error',
Nikolay Vitkov55adf672025-01-02 12:07:33620 'rulesdir/check-css-import': 'error',
621 'rulesdir/enforce-optional-properties-last': 'error',
622 'rulesdir/check-enumerated-histograms': 'error',
623 'rulesdir/check-was-shown-methods': 'error',
624 'rulesdir/static-custom-event-names': 'error',
Benedikt Meurer6e534082025-01-29 10:36:02625 'rulesdir/lit-no-attribute-quotes': 'error',
Nikolay Vitkov55adf672025-01-02 12:07:33626 'rulesdir/lit-template-result-or-nothing': 'error',
627 'rulesdir/inject-checkbox-styles': 'error',
628 'rulesdir/jslog-context-list': 'error',
Nikolay Vitkovde07efa2025-01-17 12:58:35629 'rulesdir/es-modules-import': 'error',
630 'rulesdir/html-tagged-template': 'error',
Nikolay Vitkov49d12de2025-02-12 14:41:46631 'rulesdir/enforce-custom-element-definitions-location': [
632 'error',
633 {
634 rootFrontendDirectory: join(import.meta.dirname, 'front_end'),
635 },
636 ],
Ergun Erdogmus5efc7e92025-02-21 11:36:50637 'rulesdir/enforce-ui-strings-as-const': 'error',
Nikolay Vitkova0951482025-07-07 12:17:52638 'rulesdir/no-new-lit-element-components': 'error',
Nikolay Vitkov55adf672025-01-02 12:07:33639 },
640 },
Nikolay Vitkov55adf672025-01-02 12:07:33641 {
642 name: 'Front-end meta files',
643 files: ['front_end/**/*-meta.ts'],
644 rules: {
645 '@typescript-eslint/naming-convention': [
646 'error',
647 {
648 selector: 'parameter',
649 format: ['camelCase', 'PascalCase'],
650 leadingUnderscore: 'allow',
651 },
652 ],
653 },
654 },
Nikolay Vitkov55adf672025-01-02 12:07:33655 {
656 name: 'TypeScript test files',
657 files: [
658 '*.test.ts',
659 // This makes the specificity greater than the front-end ts files
660 'front_end/**/*.test.ts',
661 'test/**/*.ts',
662 '**/testing/*.ts',
Nikolay Vitkov856215c2025-04-23 14:32:57663 'scripts/eslint_rules/test/**/*',
Nikolay Vitkov3cace8f2025-02-14 16:37:53664 'extensions/cxx_debugging/e2e/**',
Nikolay Vitkov55adf672025-01-02 12:07:33665 ],
666
667 rules: {
668 // errors on it('test') with no body
669 'mocha/no-pending-tests': 'error',
670
671 // errors on {describe, it}.only
672 'mocha/no-exclusive-tests': 'error',
673
674 'mocha/no-async-describe': 'error',
675 'mocha/no-global-tests': 'error',
676 'mocha/no-nested-tests': 'error',
677
678 '@typescript-eslint/no-non-null-assertion': 'off',
679 '@typescript-eslint/explicit-function-return-type': 'off',
680
Nikolay Vitkov93062642025-02-18 09:49:30681 '@typescript-eslint/only-throw-error': [
682 'error',
683 {
684 allow: [
685 {
686 // Chai AssertionError does not extend Error
687 from: 'package',
688 package: 'chai',
689 name: ['AssertionError'],
690 },
691 ],
692 },
693 ],
694
Nikolay Vitkov55adf672025-01-02 12:07:33695 'rulesdir/check-test-definitions': 'error',
696 'rulesdir/no-assert-strict-equal-for-arrays-and-objects': 'error',
697 'rulesdir/no-assert-deep-strict-equal': 'error',
698 'rulesdir/no-assert-equal': 'error',
699 'rulesdir/no-assert-equal-boolean-null-undefined': 'error',
Danil Somsikovd12440f2025-03-31 18:45:43700 'rulesdir/no-imperative-dom-api': 'off',
Danil Somsikov9f442bb2025-04-02 09:58:27701 'rulesdir/no-lit-render-outside-of-view': 'off',
Nikolay Vitkov55adf672025-01-02 12:07:33702 'rulesdir/prefer-assert-instance-of': 'error',
703 'rulesdir/prefer-assert-is-ok': 'error',
704 'rulesdir/prefer-assert-length-of': 'error',
Benedikt Meurerebef25a2025-04-11 12:28:21705 'rulesdir/prefer-assert-strict-equal': 'error',
Benedikt Meureradbf0df2025-04-11 08:48:52706 'rulesdir/prefer-sinon-assert': 'error',
Benedikt Meurer39e51332025-01-07 13:17:54707 'rulesdir/prefer-url-string': 'error',
Nikolay Vitkov55adf672025-01-02 12:07:33708 'rulesdir/trace-engine-test-timeouts': 'error',
Jack Franklin25931062025-06-02 15:20:46709 'rulesdir/no-document-body-mutation': 'error',
Nikolay Vitkov49d12de2025-02-12 14:41:46710 'rulesdir/enforce-custom-element-definitions-location': 'off',
Nikolay Vitkov55adf672025-01-02 12:07:33711 },
712
713 settings: {
714 'mocha/additionalCustomNames': [
715 {
716 name: 'describeWithDevtoolsExtension',
717 type: 'suite',
718 interfaces: ['BDD', 'TDD'],
719 },
720 {
721 name: 'describeWithEnvironment',
722 type: 'suite',
723 interfaces: ['BDD', 'TDD'],
724 },
725 {
726 name: 'describeWithLocale',
727 type: 'suite',
728 interfaces: ['BDD', 'TDD'],
729 },
730 {
731 name: 'describeWithMockConnection',
732 type: 'suite',
733 interfaces: ['BDD', 'TDD'],
734 },
Nikolay Vitkov55adf672025-01-02 12:07:33735 ],
736 },
737 },
Nikolay Vitkov55adf672025-01-02 12:07:33738 {
Nikolay Vitkov52a17972025-01-15 12:52:10739 name: 'Use private class members rule',
Nikolay Vitkov55adf672025-01-02 12:07:33740 files: [
741 'front_end/panels/**/components/*.ts',
742 'front_end/ui/components/**/*.ts',
743 'front_end/entrypoints/**/*.ts',
744 ],
745
746 rules: {
747 'rulesdir/prefer-private-class-members': 'error',
748 },
749 },
Nikolay Vitkov55adf672025-01-02 12:07:33750 {
Nikolay Vitkov52a17972025-01-15 12:52:10751 name: 'Ignore private class members rule',
Nikolay Vitkov55adf672025-01-02 12:07:33752 files: [
753 'front_end/panels/recorder/**/*.ts',
Nikolay Vitkov55adf672025-01-02 12:07:33754 'front_end/ui/components/suggestion_input/*.ts',
755 ],
756 rules: {
757 // TODO(crbug/1402569): Reenable once https://github.com/microsoft/TypeScript/issues/48885 is closed.
758 'rulesdir/prefer-private-class-members': 'off',
759 },
760 },
Nikolay Vitkov55adf672025-01-02 12:07:33761 {
Nikolay Vitkov52a17972025-01-15 12:52:10762 name: 'Supported CSS properties rules',
Nikolay Vitkov55adf672025-01-02 12:07:33763 files: ['front_end/generated/SupportedCSSProperties.js'],
764 rules: {
765 'rulesdir/jslog-context-list': 'error',
766 },
767 },
Nikolay Vitkov55adf672025-01-02 12:07:33768 {
769 name: 'EsLint rules test',
Nikolay Vitkov856215c2025-04-23 14:32:57770 files: ['scripts/eslint_rules/tests/**/*'],
Nikolay Vitkov55adf672025-01-02 12:07:33771 rules: {
Nikolay Vitkovf1e3bd82025-02-13 11:55:22772 '@eslint-plugin/no-only-tests': 'error',
Nikolay Vitkov55adf672025-01-02 12:07:33773 },
774 },
Nikolay Vitkov55adf672025-01-02 12:07:33775 {
776 name: 'Legacy test runner',
777 files: ['front_end/legacy_test_runner/**/*'],
778 rules: {
779 'rulesdir/es-modules-import': 'off',
780 },
781 },
782 {
Nikolay Vitkova0951482025-07-07 12:17:52783 name: 'Front-end component docs',
Nikolay Vitkov55adf672025-01-02 12:07:33784 files: ['front_end/ui/components/docs/**/*.ts'],
785 rules: {
786 // This makes the component doc examples very verbose and doesn't add
787 // anything, so we leave return types to the developer within the
788 // component_docs folder.
789 '@typescript-eslint/explicit-function-return-type': 'off',
Benedikt Meurer6e534082025-01-29 10:36:02790 // We use Lit to help render examples sometimes and we don't use
Nikolay Vitkov55adf672025-01-02 12:07:33791 // {host: this} as often the `this` is the window.
Benedikt Meurer6e534082025-01-29 10:36:02792 'rulesdir/lit-host-this': 'off',
Danil Somsikovd12440f2025-03-31 18:45:43793 'rulesdir/no-imperative-dom-api': 'off',
Danil Somsikov9f442bb2025-04-02 09:58:27794 'rulesdir/no-lit-render-outside-of-view': 'off',
Nikolay Vitkov55adf672025-01-02 12:07:33795 },
796 },
797 {
Jack Franklin48705342025-06-17 11:59:57798 name: 'No SDK in models/trace',
799 files: ['front_end/models/trace/**/*.ts'],
800 ignores: ['front_end/models/trace/**/*.test.ts'],
Nikolay Vitkov55adf672025-01-02 12:07:33801 rules: {
802 'rulesdir/no-imports-in-directory': [
803 'error',
804 {
Nikolay Vitkov19a227c2025-07-01 11:25:29805 bannedImportPaths: [
806 {
807 bannedPath: join(
Nikolay Vitkova0951482025-07-07 12:17:52808 import.meta.dirname,
809 'front_end',
810 'core',
811 'sdk',
812 'sdk.js',
813 ),
Nikolay Vitkov19a227c2025-07-01 11:25:29814 allowTypeImports: true,
815 },
816 ],
Nikolay Vitkov55adf672025-01-02 12:07:33817 },
818 ],
819 },
820 },
821 {
Nikolay Vitkov52a17972025-01-15 12:52:10822 name: 'Recorder injected code',
Nikolay Vitkov55adf672025-01-02 12:07:33823 files: ['front_end/panels/recorder/injected/**/*.ts'],
824 rules: {
825 // The code is rolled up and tree-shaken independently from the regular entrypoints.
826 'rulesdir/es-modules-import': 'off',
827 },
828 },
829 {
Nikolay Vitkovb4e8dc72025-01-07 13:03:02830 name: 'Performance panel file',
Nikolay Vitkov55adf672025-01-02 12:07:33831 files: ['front_end/ui/legacy/components/perf_ui/**/*.ts'],
832 rules: {
833 // Enable tracking of canvas save() and
834 // restore() calls to try and catch bugs. Only
835 // enabled in this folder because it is an
836 // expensive rule to run and we do not need it
837 // for any code that doesn't use Canvas.
838 'rulesdir/canvas-context-tracking': 'error',
839 },
840 },
Jack Franklinc10b4972025-02-28 16:32:56841 {
842 name: 'TypeScript type-definitions',
843 files: ['**/*.d.ts'],
844 rules: {
845 // Not a useful rule for .d.ts files where we are
846 // representing an existing module.
Nikolay Vitkova2ced3f2025-03-05 11:58:03847 'import/no-default-export': 'off',
848 },
849 },
Nikolay Vitkovafc8a8c2025-03-17 10:05:28850 {
851 name: 'Config files',
852 files: ['eslint.config.mjs', '**/*/rollup.config.mjs'],
853 rules: {
854 // The config operate on the default export
855 // So allow it for them
856 'import/no-default-export': 'off',
857 },
858 },
Nikolay Vitkov856215c2025-04-23 14:32:57859]);