Pop-up dictionary browser extension for language learning. Successor to Yomichan. (PERSONAL FORK)
at lambda-fork/main 931 lines 32 kB view raw
1/* 2 * Copyright (C) 2024-2025 Yomitan Authors 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <https://www.gnu.org/licenses/>. 16 */ 17 18import {FlatCompat} from '@eslint/eslintrc'; 19import js from '@eslint/js'; 20import stylistic from '@stylistic/eslint-plugin'; 21import vitest from '@vitest/eslint-plugin'; 22import esbuild from 'esbuild'; 23import header from 'eslint-plugin-header'; 24// @ts-expect-error - Missing types https://github.com/import-js/eslint-plugin-import/issues/3133 25import importPlugin from 'eslint-plugin-import'; 26import jsdoc from 'eslint-plugin-jsdoc'; 27import jsonc from 'eslint-plugin-jsonc'; 28import noUnsanitized from 'eslint-plugin-no-unsanitized'; 29import sonarjs from 'eslint-plugin-sonarjs'; 30import unicorn from 'eslint-plugin-unicorn'; 31import unusedImports from 'eslint-plugin-unused-imports'; 32import globals from 'globals'; 33import parser from 'jsonc-eslint-parser'; 34import path from 'node:path'; 35import {fileURLToPath} from 'node:url'; 36import typescriptEslint from 'typescript-eslint'; 37 38const compat = new FlatCompat({ 39 baseDirectory: path.dirname(fileURLToPath(import.meta.url)), 40 recommendedConfig: js.configs.recommended, 41 allConfig: js.configs.all, 42}); 43 44// @ts-expect-error - This is a workaround https://github.com/Stuk/eslint-plugin-header/issues/57 45header.rules.header.meta.schema = false; 46 47/** 48 * @param {string[]} scriptPaths 49 * @returns {Promise<string[]>} 50 */ 51async function getDependencies(scriptPaths) { 52 const v = await esbuild.build({ 53 entryPoints: scriptPaths, 54 bundle: true, 55 minify: false, 56 sourcemap: true, 57 target: 'es2022', 58 format: 'esm', 59 write: false, 60 metafile: true, 61 }); 62 const dependencies = Object.keys(v.metafile.inputs); 63 const stringComparer = new Intl.Collator('en-US'); // Invariant locale 64 dependencies.sort((a, b) => stringComparer.compare(a, b)); 65 return dependencies; 66} 67 68/** 69 * @type {import('eslint').Linter.Config[]} 70 */ 71export default [ 72 { 73 ignores: ['ext/lib/', 'dev/lib/handlebars/', '**/node_modules/', '**/builds/', 'test-results/'], 74 }, 75 ...compat.extends( 76 'eslint:recommended', 77 'plugin:jsonc/recommended-with-json', 78 'plugin:eslint-comments/recommended', 79 ), 80 { 81 plugins: { 82 'no-unsanitized': noUnsanitized, 83 header, 84 jsdoc, 85 jsonc, 86 'unused-imports': unusedImports, 87 '@typescript-eslint': typescriptEslint.plugin, 88 '@stylistic': stylistic, 89 unicorn, 90 sonarjs, 91 'import': importPlugin, 92 }, 93 94 languageOptions: { 95 globals: { 96 ...globals.browser, 97 ...globals.webextensions, 98 }, 99 100 parser: typescriptEslint.parser, 101 ecmaVersion: 2022, 102 sourceType: 'module', 103 104 parserOptions: { 105 ecmaFeatures: { 106 globalReturn: false, 107 impliedStrict: true, 108 }, 109 110 project: [ 111 './jsconfig.json', 112 './dev/jsconfig.json', 113 './test/jsconfig.json', 114 './benches/jsconfig.json', 115 ], 116 }, 117 }, 118 119 rules: { 120 'accessor-pairs': 'error', 121 'curly': ['error', 'all'], 122 'default-case-last': 'error', 123 'dot-notation': 'error', 124 'eqeqeq': 'error', 125 'func-names': ['error', 'always'], 126 'guard-for-in': 'error', 127 'grouped-accessor-pairs': 'error', 128 'new-cap': 'error', 129 'no-alert': 'error', 130 'no-case-declarations': 'error', 131 'no-caller': 'error', 132 'no-const-assign': 'error', 133 134 'no-constant-condition': ['error', { 135 checkLoops: false, 136 }], 137 138 'no-constructor-return': 'error', 139 'no-duplicate-imports': 'error', 140 'no-eval': 'error', 141 'no-extend-native': 'error', 142 'no-global-assign': 'error', 143 'no-implicit-globals': 'error', 144 'no-implied-eval': 'error', 145 'no-new': 'error', 146 'no-new-native-nonconstructor': 'error', 147 'no-octal': 'error', 148 'no-octal-escape': 'error', 149 'no-param-reassign': 'off', 150 'no-promise-executor-return': 'error', 151 'no-prototype-builtins': 'error', 152 153 'no-restricted-syntax': ['error', { 154 message: 'Avoid using JSON.parse(), prefer parseJson.', 155 selector: 'MemberExpression[object.name=JSON][property.name=parse]', 156 }, { 157 message: 'Avoid using Response.json(), prefer readResponseJson.', 158 selector: 'MemberExpression[property.name=json]', 159 }, { 160 message: 'Avoid using performance, prefer safePerformance.', 161 selector: 'MemberExpression[object.name=performance]', 162 }], 163 164 'no-self-compare': 'error', 165 'no-sequences': 'error', 166 167 'no-shadow': ['error', { 168 builtinGlobals: false, 169 }], 170 171 'no-shadow-restricted-names': 'error', 172 'no-template-curly-in-string': 'error', 173 'no-undef': 'error', 174 'no-undefined': 'error', 175 176 'no-underscore-dangle': ['error', { 177 allowAfterThis: true, 178 allowAfterSuper: false, 179 allowAfterThisConstructor: false, 180 }], 181 182 'no-unexpected-multiline': 'error', 183 'no-unneeded-ternary': 'error', 184 185 'no-unused-vars': ['error', { 186 vars: 'local', 187 args: 'after-used', 188 argsIgnorePattern: '^_', 189 caughtErrors: 'none', 190 }], 191 192 'no-unused-expressions': 'error', 193 'no-var': 'error', 194 'no-with': 'error', 195 196 'prefer-const': ['error', { 197 destructuring: 'all', 198 }], 199 200 'radix': 'error', 201 'require-atomic-updates': 'off', 202 'sort-imports': 'off', 203 'yoda': ['error', 'never'], 204 '@stylistic/array-bracket-newline': ['error', 'consistent'], 205 '@stylistic/array-bracket-spacing': ['error', 'never'], 206 '@stylistic/array-element-newline': ['error', 'consistent'], 207 '@stylistic/arrow-parens': ['error', 'always'], 208 209 '@stylistic/arrow-spacing': ['error', { 210 before: true, 211 after: true, 212 }], 213 214 '@stylistic/block-spacing': ['error', 'always'], 215 216 '@stylistic/brace-style': ['error', '1tbs', { 217 allowSingleLine: true, 218 }], 219 220 '@stylistic/comma-dangle': ['error', 'always-multiline'], 221 222 '@stylistic/comma-spacing': ['error', { 223 before: false, 224 after: true, 225 }], 226 227 '@stylistic/comma-style': ['error', 'last'], 228 '@stylistic/computed-property-spacing': ['error', 'never'], 229 '@stylistic/dot-location': ['error', 'property'], 230 '@stylistic/eol-last': ['error', 'always'], 231 '@stylistic/func-call-spacing': ['error', 'never'], 232 '@stylistic/function-call-argument-newline': ['error', 'consistent'], 233 '@stylistic/function-call-spacing': ['error', 'never'], 234 '@stylistic/function-paren-newline': ['error', 'multiline-arguments'], 235 '@stylistic/generator-star-spacing': ['error', 'before'], 236 '@stylistic/implicit-arrow-linebreak': ['error', 'beside'], 237 238 '@stylistic/indent': ['error', 4, { 239 SwitchCase: 1, 240 MemberExpression: 1, 241 flatTernaryExpressions: true, 242 ignoredNodes: ['ConditionalExpression'], 243 }], 244 245 '@stylistic/indent-binary-ops': ['error', 0], 246 247 '@stylistic/key-spacing': ['error', { 248 beforeColon: false, 249 afterColon: true, 250 mode: 'strict', 251 }], 252 253 '@stylistic/keyword-spacing': ['error', { 254 before: true, 255 after: true, 256 }], 257 258 '@stylistic/linebreak-style': ['error', 'unix'], 259 '@stylistic/lines-around-comment': 'off', 260 261 '@stylistic/lines-between-class-members': ['error', 'always', { 262 exceptAfterSingleLine: true, 263 }], 264 265 '@stylistic/max-len': 'off', 266 267 '@stylistic/max-statements-per-line': ['error', { 268 max: 2, 269 }], 270 271 '@stylistic/member-delimiter-style': ['error', { 272 multiline: { 273 delimiter: 'semi', 274 requireLast: true, 275 }, 276 277 singleline: { 278 delimiter: 'comma', 279 requireLast: false, 280 }, 281 282 multilineDetection: 'brackets', 283 }], 284 285 '@stylistic/multiline-ternary': ['error', 'always-multiline'], 286 '@stylistic/new-parens': 'error', 287 288 '@stylistic/newline-per-chained-call': ['error', { 289 ignoreChainWithDepth: 3, 290 }], 291 292 '@stylistic/no-confusing-arrow': 'error', 293 '@stylistic/no-extra-parens': 'off', 294 '@stylistic/no-extra-semi': 'error', 295 '@stylistic/no-floating-decimal': 'error', 296 297 '@stylistic/no-mixed-operators': ['error', { 298 allowSamePrecedence: true, 299 groups: [['&&', '||']], 300 }], 301 302 '@stylistic/no-mixed-spaces-and-tabs': 'error', 303 '@stylistic/no-multi-spaces': 'error', 304 305 '@stylistic/no-multiple-empty-lines': ['error', { 306 max: 2, 307 maxEOF: 0, 308 maxBOF: 0, 309 }], 310 311 '@stylistic/no-tabs': 'error', 312 '@stylistic/no-trailing-spaces': 'error', 313 '@stylistic/no-whitespace-before-property': 'error', 314 '@stylistic/nonblock-statement-body-position': ['error', 'beside'], 315 '@stylistic/object-curly-newline': 'error', 316 '@stylistic/object-curly-spacing': ['error', 'never'], 317 318 '@stylistic/object-property-newline': ['error', { 319 allowAllPropertiesOnSameLine: true, 320 }], 321 322 '@stylistic/one-var-declaration-per-line': ['error', 'initializations'], 323 '@stylistic/operator-linebreak': ['error', 'after'], 324 '@stylistic/padded-blocks': ['error', 'never'], 325 326 '@stylistic/padding-line-between-statements': ['error', { 327 blankLine: 'always', 328 prev: '*', 329 next: 'import', 330 }, { 331 blankLine: 'always', 332 prev: 'import', 333 next: '*', 334 }, { 335 blankLine: 'always', 336 prev: '*', 337 next: 'export', 338 }, { 339 blankLine: 'always', 340 prev: 'import', 341 next: 'let', 342 }, { 343 blankLine: 'always', 344 prev: 'import', 345 next: 'const', 346 }, { 347 blankLine: 'always', 348 prev: 'export', 349 next: 'let', 350 }, { 351 blankLine: 'always', 352 prev: 'export', 353 next: 'const', 354 }, { 355 blankLine: 'always', 356 prev: 'export', 357 next: 'export', 358 }, { 359 blankLine: 'always', 360 prev: 'export', 361 next: 'type', 362 }, { 363 blankLine: 'always', 364 prev: 'type', 365 next: 'export', 366 }, { 367 blankLine: 'always', 368 prev: 'type', 369 next: 'type', 370 }, { 371 blankLine: 'never', 372 prev: 'import', 373 next: 'import', 374 }], 375 376 '@stylistic/quote-props': ['error', 'consistent-as-needed', { 377 numbers: true, 378 }], 379 380 '@stylistic/quotes': ['error', 'single', 'avoid-escape'], 381 '@stylistic/rest-spread-spacing': ['error', 'never'], 382 '@stylistic/semi': 'error', 383 384 '@stylistic/semi-spacing': ['error', { 385 before: false, 386 after: true, 387 }], 388 389 '@stylistic/semi-style': ['error', 'last'], 390 '@stylistic/space-before-blocks': ['error', 'always'], 391 392 '@stylistic/space-before-function-paren': ['error', { 393 anonymous: 'never', 394 named: 'never', 395 asyncArrow: 'always', 396 }], 397 398 '@stylistic/space-in-parens': ['error', 'never'], 399 400 '@stylistic/space-infix-ops': ['error', { 401 int32Hint: false, 402 }], 403 404 '@stylistic/space-unary-ops': 'error', 405 '@stylistic/spaced-comment': ['error', 'always'], 406 407 '@stylistic/switch-colon-spacing': ['error', { 408 after: true, 409 before: false, 410 }], 411 412 '@stylistic/template-curly-spacing': ['error', 'never'], 413 '@stylistic/template-tag-spacing': ['error', 'never'], 414 415 '@stylistic/type-annotation-spacing': ['error', { 416 before: false, 417 after: true, 418 419 overrides: { 420 arrow: { 421 before: true, 422 after: true, 423 }, 424 }, 425 }], 426 427 '@stylistic/type-generic-spacing': 'error', 428 '@stylistic/type-named-tuple-spacing': 'error', 429 '@stylistic/wrap-iife': ['error', 'inside'], 430 '@stylistic/wrap-regex': 'off', 431 432 '@stylistic/yield-star-spacing': ['error', { 433 before: true, 434 after: false, 435 }], 436 437 'no-unsanitized/method': 'error', 438 'no-unsanitized/property': 'error', 439 'jsdoc/check-access': 'error', 440 'jsdoc/check-alignment': 'error', 441 442 'jsdoc/check-line-alignment': ['error', 'never', { 443 wrapIndent: ' ', 444 }], 445 446 'jsdoc/check-param-names': 'error', 447 'jsdoc/check-property-names': 'error', 448 'jsdoc/check-tag-names': 'error', 449 'jsdoc/empty-tags': 'error', 450 'jsdoc/check-types': 'error', 451 'jsdoc/check-values': 'error', 452 'jsdoc/implements-on-classes': 'error', 453 'jsdoc/multiline-blocks': 'error', 454 'jsdoc/no-bad-blocks': 'error', 455 'jsdoc/no-multi-asterisks': 'error', 456 'jsdoc/no-undefined-types': 'error', 457 'jsdoc/require-asterisk-prefix': 'error', 458 'jsdoc/require-description': 'off', 459 'jsdoc/require-hyphen-before-param-description': ['error', 'never'], 460 461 'jsdoc/require-jsdoc': ['error', { 462 require: { 463 ClassDeclaration: false, 464 FunctionDeclaration: true, 465 MethodDefinition: false, 466 }, 467 468 contexts: [ 469 'MethodDefinition[kind=constructor]>FunctionExpression>BlockStatement>ExpressionStatement>AssignmentExpression[left.object.type=ThisExpression]', 470 'ClassDeclaration>Classbody>PropertyDefinition', 471 'MethodDefinition[kind!=constructor][kind!=set]', 472 'MethodDefinition[kind=constructor][value.params.length>0]', 473 ], 474 475 checkGetters: 'no-setter', 476 checkSetters: 'no-getter', 477 }], 478 479 'jsdoc/require-param': 'error', 480 'jsdoc/require-param-description': 'off', 481 'jsdoc/require-param-name': 'error', 482 'jsdoc/require-param-type': 'error', 483 'jsdoc/require-property': 'error', 484 'jsdoc/require-property-description': 'off', 485 'jsdoc/require-property-name': 'error', 486 'jsdoc/require-property-type': 'error', 487 'jsdoc/require-returns': 'error', 488 'jsdoc/require-returns-check': 'error', 489 'jsdoc/require-returns-description': 'off', 490 'jsdoc/require-returns-type': 'error', 491 'jsdoc/require-throws': 'error', 492 'jsdoc/require-yields': 'error', 493 'jsdoc/require-yields-check': 'error', 494 495 'jsdoc/tag-lines': ['error', 'never', { 496 startLines: 0, 497 }], 498 499 'jsdoc/valid-types': 'error', 500 'jsonc/indent': ['error', 4], 501 'jsonc/array-bracket-newline': ['error', 'consistent'], 502 'jsonc/array-bracket-spacing': ['error', 'never'], 503 'jsonc/array-element-newline': ['error', 'consistent'], 504 'jsonc/comma-style': ['error', 'last'], 505 506 'jsonc/key-spacing': ['error', { 507 beforeColon: false, 508 afterColon: true, 509 mode: 'strict', 510 }], 511 512 'jsonc/no-octal-escape': 'error', 513 514 'jsonc/object-curly-newline': ['error', { 515 consistent: true, 516 }], 517 518 'jsonc/object-curly-spacing': ['error', 'never'], 519 520 'jsonc/object-property-newline': ['error', { 521 allowAllPropertiesOnSameLine: true, 522 }], 523 524 'eslint-comments/no-unused-disable': 'error', 525 'unused-imports/no-unused-imports': 'error', 526 'import/extensions': ['error', 'ignorePackages'], 527 528 'unicorn/catch-error-name': ['error', { 529 ignore: ['^(e|error2?)$'], 530 }], 531 532 'unicorn/custom-error-definition': 'error', 533 'unicorn/empty-brace-spaces': 'error', 534 'unicorn/error-message': 'error', 535 'unicorn/expiring-todo-comments': 'error', 536 'unicorn/explicit-length-check': 'error', 537 'unicorn/new-for-builtins': 'error', 538 'unicorn/no-abusive-eslint-disable': 'error', 539 'unicorn/no-array-for-each': 'error', 540 'unicorn/no-array-method-this-argument': 'error', 541 'unicorn/no-array-push-push': 'error', 542 'unicorn/no-array-reduce': 'error', 543 'unicorn/no-console-spaces': 'error', 544 'unicorn/no-document-cookie': 'error', 545 'unicorn/no-empty-file': 'error', 546 'unicorn/no-hex-escape': 'error', 547 'unicorn/no-instanceof-array': 'error', 548 'unicorn/no-invalid-remove-event-listener': 'error', 549 'unicorn/no-lonely-if': 'error', 550 'unicorn/no-nested-ternary': 'error', 551 'unicorn/no-new-buffer': 'error', 552 'unicorn/no-object-as-default-parameter': 'error', 553 'unicorn/no-static-only-class': 'error', 554 'unicorn/no-thenable': 'error', 555 'unicorn/no-unnecessary-await': 'error', 556 'unicorn/no-unnecessary-polyfills': 'error', 557 'unicorn/no-unreadable-array-destructuring': 'error', 558 'unicorn/no-unreadable-iife': 'error', 559 'unicorn/no-useless-fallback-in-spread': 'error', 560 'unicorn/no-useless-length-check': 'error', 561 'unicorn/no-useless-promise-resolve-reject': 'error', 562 'unicorn/no-useless-spread': 'error', 563 'unicorn/no-useless-switch-case': 'error', 564 'unicorn/no-useless-undefined': 'error', 565 'unicorn/no-zero-fractions': 'error', 566 'unicorn/prefer-array-find': 'error', 567 'unicorn/prefer-array-flat': 'error', 568 'unicorn/prefer-array-flat-map': 'error', 569 'unicorn/prefer-array-index-of': 'error', 570 'unicorn/prefer-array-some': 'error', 571 'unicorn/prefer-date-now': 'error', 572 'unicorn/prefer-default-parameters': 'error', 573 'unicorn/prefer-dom-node-dataset': 'error', 574 'unicorn/prefer-dom-node-text-content': 'error', 575 'unicorn/prefer-event-target': 'error', 576 'unicorn/prefer-export-from': 'error', 577 'unicorn/prefer-includes': 'error', 578 'unicorn/prefer-keyboard-event-key': 'error', 579 'unicorn/prefer-logical-operator-over-ternary': 'error', 580 'unicorn/prefer-modern-math-apis': 'error', 581 'unicorn/prefer-module': 'error', 582 'unicorn/prefer-native-coercion-functions': 'error', 583 'unicorn/prefer-negative-index': 'error', 584 'unicorn/prefer-number-properties': 'error', 585 'unicorn/prefer-object-from-entries': 'error', 586 'unicorn/prefer-prototype-methods': 'error', 587 'unicorn/prefer-reflect-apply': 'error', 588 'unicorn/prefer-regexp-test': 'error', 589 'unicorn/prefer-set-has': 'error', 590 'unicorn/prefer-set-size': 'error', 591 'unicorn/prefer-spread': 'error', 592 'unicorn/prefer-string-starts-ends-with': 'error', 593 'unicorn/prefer-string-trim-start-end': 'error', 594 'unicorn/prefer-switch': 'error', 595 'unicorn/prefer-ternary': 'error', 596 'unicorn/relative-url-style': 'error', 597 'unicorn/require-array-join-separator': 'error', 598 'unicorn/require-number-to-fixed-digits-argument': 'error', 599 'unicorn/template-indent': 'error', 600 'unicorn/throw-new-error': 'error', 601 'sonarjs/max-switch-cases': 'error', 602 'sonarjs/no-all-duplicated-branches': 'error', 603 'sonarjs/no-collapsible-if': 'error', 604 'sonarjs/no-collection-size-mischeck': 'error', 605 'sonarjs/no-duplicated-branches': 'error', 606 'sonarjs/no-element-overwrite': 'error', 607 'sonarjs/no-empty-collection': 'error', 608 'sonarjs/no-extra-arguments': 'error', 609 'sonarjs/no-gratuitous-expressions': 'error', 610 'sonarjs/no-identical-conditions': 'error', 611 'sonarjs/no-identical-expressions': 'error', 612 'sonarjs/no-identical-functions': 'error', 613 'sonarjs/no-ignored-return': 'error', 614 'sonarjs/no-inverted-boolean-check': 'error', 615 'sonarjs/no-one-iteration-loop': 'error', 616 'sonarjs/no-redundant-boolean': 'error', 617 'sonarjs/no-redundant-jump': 'error', 618 'sonarjs/no-same-line-conditional': 'error', 619 'sonarjs/no-unused-collection': 'error', 620 'sonarjs/no-use-of-empty-return-value': 'error', 621 'sonarjs/no-useless-catch': 'error', 622 'sonarjs/non-existent-operator': 'error', 623 'sonarjs/prefer-immediate-return': 'error', 624 'sonarjs/prefer-object-literal': 'error', 625 'sonarjs/prefer-single-boolean-return': 'error', 626 'sonarjs/prefer-while': 'error', 627 }, 628 }, 629 ...typescriptEslint.configs.recommendedTypeChecked.map((config) => ({ 630 ...config, 631 files: [ 632 '**/*.js', 633 '**/*.ts', 634 ], 635 })), 636 { 637 files: [ 638 '**/*.js', 639 '**/*.ts', 640 ], 641 642 rules: { 643 '@typescript-eslint/no-floating-promises': ['error', { 644 ignoreIIFE: true, 645 }], 646 647 '@typescript-eslint/no-misused-promises': 'off', 648 '@typescript-eslint/no-redundant-type-constituents': 'error', 649 '@typescript-eslint/no-unsafe-argument': 'error', 650 '@typescript-eslint/no-unsafe-assignment': 'error', 651 '@typescript-eslint/no-unsafe-call': 'off', 652 '@typescript-eslint/no-unsafe-enum-comparison': 'off', 653 '@typescript-eslint/no-unsafe-member-access': 'off', 654 '@typescript-eslint/no-unsafe-return': 'off', 655 '@typescript-eslint/require-await': 'off', 656 '@typescript-eslint/restrict-template-expressions': 'off', 657 '@typescript-eslint/prefer-promise-reject-errors': 'off', 658 659 '@typescript-eslint/ban-ts-comment': ['error', { 660 'ts-expect-error': { 661 descriptionFormat: '^ - .+$', 662 }, 663 }], 664 665 '@typescript-eslint/no-empty-object-type': 'error', 666 '@typescript-eslint/no-unsafe-function-type': 'error', 667 '@typescript-eslint/no-wrapper-object-types': 'error', 668 '@typescript-eslint/no-explicit-any': 'error', 669 670 '@typescript-eslint/no-shadow': ['error', { 671 builtinGlobals: false, 672 }], 673 674 '@typescript-eslint/no-this-alias': 'error', 675 676 '@typescript-eslint/no-unused-vars': ['error', { 677 vars: 'local', 678 args: 'after-used', 679 argsIgnorePattern: '^_', 680 caughtErrors: 'none', 681 }], 682 }, 683 }, 684 { 685 files: [ 686 '**/*.ts', 687 ], 688 689 rules: { 690 '@stylistic/block-spacing': 'off', 691 692 '@stylistic/comma-dangle': ['error', { 693 arrays: 'always-multiline', 694 objects: 'always-multiline', 695 imports: 'always-multiline', 696 exports: 'always-multiline', 697 functions: 'always-multiline', 698 enums: 'always-multiline', 699 generics: 'always-multiline', 700 tuples: 'always-multiline', 701 }], 702 703 '@stylistic/indent-binary-ops': 'off', 704 705 '@stylistic/no-multiple-empty-lines': ['error', { 706 max: 1, 707 maxEOF: 0, 708 maxBOF: 0, 709 }], 710 711 '@stylistic/no-extra-parens': ['error', 'all'], 712 }, 713 }, 714 { 715 files: [ 716 '**/*.json', 717 ], 718 719 languageOptions: { 720 parser: parser, 721 }, 722 }, 723 { 724 files: [ 725 '.vscode/launch.json', 726 ], 727 728 rules: { 729 'jsonc/no-comments': 'off', 730 }, 731 }, 732 { 733 files: [ 734 'ext/data/schemas/options-schema.json', 735 ], 736 737 rules: { 738 '@stylistic/no-multi-spaces': 'off', 739 }, 740 }, 741 { 742 files: [ 743 'test/data/anki-note-builder-test-results.json', 744 'test/data/database-test-cases.json', 745 'test/data/translator-test-results-note-data1.json', 746 'test/data/translator-test-results.json', 747 ], 748 749 rules: { 750 'jsonc/indent': ['error', 2], 751 }, 752 }, 753 { 754 files: [ 755 'test/data/dictionaries/valid-dictionary1/term_bank_1.json', 756 'test/data/dictionaries/valid-dictionary1/term_bank_2.json', 757 ], 758 759 rules: { 760 'jsonc/array-element-newline': 'off', 761 'jsonc/object-property-newline': 'off', 762 }, 763 }, 764 { 765 files: [ 766 '**/*.js', 767 '**/*.ts', 768 ], 769 770 rules: { 771 'header/header': ['error', 'block', { 772 pattern: ' \\* Copyright \\(C\\) (20(23|24)-)?2025 Yomitan Authors(\n \\* Copyright \\(C\\) (20(16|17|18|19|20|21)-)?2022 Yomichan Authors)?\n \\*\n \\* This program is free software: you can redistribute it and/or modify\n \\* it under the terms of the GNU General Public License as published by\n \\* the Free Software Foundation, either version 3 of the License, or\n \\* \\(at your option\\) any later version\\.\n \\*\n \\* This program is distributed in the hope that it will be useful,\n \\* but WITHOUT ANY WARRANTY; without even the implied warranty of\n \\* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE\\. See the\n \\* GNU General Public License for more details\\.\n \\*\n \\* You should have received a copy of the GNU General Public License\n \\* along with this program\\. If not, see <https://www\\.gnu\\.org/licenses/>\\.\n ', 773 }], 774 }, 775 }, 776 { 777 files: [ 778 'ext/**/*.js', 779 ], 780 781 rules: { 782 'no-console': 'error', 783 }, 784 }, 785 { 786 files: [ 787 'test/**/*.js', 788 'dev/**/*.js', 789 '**/integration.spec.js', 790 '**/playwright.config.js', 791 '**/playwright-util.js', 792 '**/visual.spec.js', 793 ], 794 795 languageOptions: { 796 globals: { 797 ...Object.fromEntries(Object.entries(globals.browser).map(([key]) => [key, 'off'])), 798 ...globals.node, 799 ...Object.fromEntries(Object.entries(globals.webextensions).map(([key]) => [key, 'off'])), 800 }, 801 }, 802 }, 803 { 804 files: [ 805 'test/data/html/**/*.js', 806 ], 807 808 languageOptions: { 809 globals: { 810 ...globals.browser, 811 ...Object.fromEntries(Object.entries(globals.node).map(([key]) => [key, 'off'])), 812 ...Object.fromEntries(Object.entries(globals.webextensions).map(([key]) => [key, 'off'])), 813 }, 814 815 ecmaVersion: 5, 816 sourceType: 'script', 817 }, 818 }, 819 { 820 files: [ 821 'test/data/html/**/*.js', 822 ], 823 ignores: [ 824 'test/data/html/js/html-test-utilities.js', 825 ], 826 827 languageOptions: { 828 globals: { 829 HtmlTestUtilities: 'readonly', 830 }, 831 }, 832 }, 833 { 834 files: [ 835 'test/**/*.test.js', 836 ], 837 plugins: { 838 vitest, 839 }, 840 ...vitest.configs.recommended, 841 rules: { 842 'vitest/prefer-to-be': 'off', 843 }, 844 }, 845 ...compat.extends('plugin:@typescript-eslint/disable-type-checked').map((config) => ({ 846 ...config, 847 files: [ 848 'dev/lib/**/*.js', 849 'eslint.config.js', 850 ], 851 })), 852 { 853 files: [ 854 'ext/js/templates/template-renderer-frame-main.js', 855 ...await getDependencies(['ext/js/templates/template-renderer-frame-main.js']), 856 ], 857 858 languageOptions: { 859 globals: { 860 ...Object.fromEntries(Object.entries(globals.webextensions).map(([key]) => [key, 'off'])), 861 }, 862 }, 863 }, 864 { 865 files: [ 866 'ext/js/dictionary/dictionary-worker-main.js', 867 ...await getDependencies(['ext/js/dictionary/dictionary-worker-main.js']), 868 ], 869 870 languageOptions: { 871 globals: { 872 ...Object.fromEntries(Object.entries(globals.browser).map(([key]) => [key, 'off'])), 873 ...globals.worker, 874 }, 875 }, 876 }, 877 { 878 files: [ 879 'ext/js/background/background-main.js', 880 ...await getDependencies(['ext/js/background/background-main.js']), 881 ], 882 883 languageOptions: { 884 globals: { 885 ...Object.fromEntries(Object.entries(globals.browser).map(([key]) => [key, 'off'])), 886 ...globals.serviceworker, 887 FileReader: 'readonly', 888 Intl: 'readonly', 889 crypto: 'readonly', 890 AbortController: 'readonly', 891 }, 892 }, 893 }, 894 { 895 files: [ 896 'ext/data/recommended-dictionaries.json', 897 ], 898 899 rules: { 900 'jsonc/sort-keys': ['error', { 901 pathPattern: '.*', 902 hasProperties: ['name'], 903 order: ['name', 'description', 'homepage', 'downloadUrl'], 904 }, { 905 pathPattern: '.*', 906 907 order: { 908 type: 'asc', 909 }, 910 }], 911 }, 912 }, 913 { 914 files: [ 915 'ext/data/recommended-settings.json', 916 ], 917 918 rules: { 919 'jsonc/sort-keys': ['error', { 920 pathPattern: '.*', 921 order: ['modification', 'description'], 922 }, { 923 pathPattern: '.*', 924 925 order: { 926 type: 'asc', 927 }, 928 }], 929 }, 930 }, 931];