import jsEslint from '@eslint/js'; import stylistic from '@stylistic/eslint-plugin'; import jsdoc from 'eslint-plugin-jsdoc'; import prettierEslintRecommended from 'eslint-plugin-prettier/recommended'; import sonarJsEslint from 'eslint-plugin-sonarjs'; import eslintPluginUnicorn from 'eslint-plugin-unicorn'; import globals from 'globals'; import tsEslint from 'typescript-eslint'; import errorNameAsClassFieldRule from '../src/rules/error-name-as-class-field.lint.js'; import noRawDateRule from '../src/rules/no-raw-date.lint.js'; import noReadonlyPrimitiveRule from '../src/rules/no-readonly-primitive.lint.js'; import noRelativeImportOutsidePackageRule from '../src/rules/no-relative-import-outside-package.lint.js'; import noShouldInTestDescriptionRule from '../src/rules/no-should-in-test-description.lint.js'; import noUnderscoreVariableRule from '../src/rules/no-underscore-variable.lint.js'; import preferArrowObjectBlockBodyRule from '../src/rules/prefer-arrow-object-block-body.lint.js'; import preferEnsureErrorRule from '../src/rules/prefer-ensure-error.lint.js'; import preferIfElseChainRule from '../src/rules/prefer-if-else-chain.lint.js'; import preferMapEnumToObjectRule from '../src/rules/prefer-map-enum-to-object.lint.js'; import preferParamsObjectRule from '../src/rules/prefer-params-object.lint.js'; import preferParseUrlRule from '../src/rules/prefer-parse-url.lint.js'; import preferProtectedOverPrivateRule from '../src/rules/prefer-protected-over-private.lint.js'; import preferRemoveDuplicatesRule from '../src/rules/prefer-remove-duplicates.lint.js'; import preferSingleQuotesRule from '../src/rules/prefer-single-quotes.lint.js'; import preferToSortedRule from '../src/rules/prefer-to-sorted.lint.js'; import requireImportExtensionsRule from '../src/rules/require-import-extensions.lint.js'; export const globalVars = { ...globals.node, ...globals.browser, }; export function defineEslintConfig(repoDir: string) { return [ { ignores: [ '*.graphql', '*.html', '*.json', '*.sh', '*.snapshot.web.mjs', '*.snapshot', '*.sql', '*.yml', '**/.history/', '**/.not-committed/', '**/all-files-for-code-coverage.test.ts', '**/configs/', '**/coverage/', '**/dist-*/', '**/dist/', '**/test-files/', 'cspell.config.cjs', 'package-lock.json', 'eslint.config.ts', ], }, jsEslint.configs.recommended, ...tsEslint.configs.strictTypeChecked, sonarJsEslint.configs?.recommended, prettierEslintRecommended, { languageOptions: { parserOptions: { projectService: true, tsconfigRootDir: repoDir, }, globals: globalVars, }, plugins: { '@stylistic': stylistic, '@jsdoc': jsdoc, unicorn: eslintPluginUnicorn, '@virmator': { rules: { 'error-name-as-class-field': errorNameAsClassFieldRule, 'no-raw-date': noRawDateRule, 'no-readonly-primitive': noReadonlyPrimitiveRule, 'no-relative-import-outside-package': noRelativeImportOutsidePackageRule, 'no-should-in-test-description': noShouldInTestDescriptionRule, 'no-underscore-variable': noUnderscoreVariableRule, 'prefer-arrow-object-block-body': preferArrowObjectBlockBodyRule, 'prefer-ensure-error': preferEnsureErrorRule, 'prefer-if-else-chain': preferIfElseChainRule, 'prefer-map-enum-to-object': preferMapEnumToObjectRule, 'prefer-params-object': preferParamsObjectRule, 'prefer-parse-url': preferParseUrlRule, 'prefer-protected-over-private': preferProtectedOverPrivateRule, 'prefer-remove-duplicates': preferRemoveDuplicatesRule, 'prefer-single-quotes': preferSingleQuotesRule, 'prefer-to-sorted': preferToSortedRule, 'require-import-extensions': requireImportExtensionsRule, }, }, }, rules: { '@typescript-eslint/no-confusing-void-expression': 'off', '@typescript-eslint/no-duplicate-type-constituents': 'off', '@typescript-eslint/no-dynamic-delete': 'off', '@typescript-eslint/no-explicit-any': 'off', '@typescript-eslint/no-invalid-void-type': 'off', '@typescript-eslint/no-misused-promises': 'off', '@typescript-eslint/no-unnecessary-type-assertion': 'off', // incessant false failures '@typescript-eslint/no-unnecessary-type-parameters': 'off', '@typescript-eslint/no-unsafe-argument': 'off', '@typescript-eslint/no-unsafe-assignment': 'off', '@typescript-eslint/no-unsafe-call': 'off', '@typescript-eslint/no-unsafe-enum-comparison': 'off', '@typescript-eslint/no-unsafe-member-access': 'off', '@typescript-eslint/no-unsafe-return': 'off', '@typescript-eslint/no-useless-constructor': 'off', // this rule is always wrong '@typescript-eslint/prefer-reduce-type-parameter': 'off', '@typescript-eslint/return-await': 'off', '@typescript-eslint/unified-signatures': 'off', // this rule is always wrong 'sonarjs/cognitive-complexity': 'off', 'sonarjs/different-types-comparison': 'off', // this rule is wrong 'sonarjs/function-return-type': 'off', 'sonarjs/new-cap': 'off', 'sonarjs/no-alphabetical-sort': 'off', 'sonarjs/no-duplicate-string': 'off', 'sonarjs/no-empty-test-file': 'off', // this rule is wrong 'sonarjs/no-misused-promises': 'off', // this rule is wrong 'sonarjs/no-nested-conditional': 'off', 'sonarjs/no-nested-functions': 'off', 'sonarjs/no-redeclare': 'off', // this rule is wrong and will get caught by TS anyway 'sonarjs/no-redundant-optional': 'off', 'sonarjs/no-selector-parameter': 'off', 'sonarjs/no-undefined-argument': 'off', 'sonarjs/no-useless-constructor': 'off', // this rule is wrong 'sonarjs/prefer-nullish-coalescing': 'off', 'sonarjs/publicly-writable-directories': 'off', 'sonarjs/reduce-initial-value': 'off', 'sonarjs/prefer-regexp-exec': 'off', 'sonarjs/use-type-alias': 'off', 'sonarjs/void-use': 'off', 'sonarjs/deprecation': 'off', // duplicates @typescript-eslint/no-deprecated 'no-async-promise-executor': 'off', 'no-prototype-builtins': 'off', 'prettier/prettier': 'off', 'unicorn/new-for-builtins': 'error', 'unicorn/no-array-push-push': 'error', 'unicorn/no-await-in-promise-methods': 'error', 'unicorn/no-document-cookie': 'error', 'unicorn/no-empty-file': 'error', 'unicorn/no-for-loop': 'error', 'unicorn/no-instanceof-array': 'error', 'unicorn/no-invalid-fetch-options': 'error', 'unicorn/no-invalid-remove-event-listener': 'error', 'unicorn/no-length-as-slice-end': 'error', 'unicorn/no-lonely-if': 'error', 'unicorn/no-negated-condition': 'error', 'unicorn/no-negation-in-equality-check': 'error', 'unicorn/no-single-promise-in-promise-methods': 'error', 'unicorn/no-thenable': 'error', 'unicorn/no-unnecessary-await': 'error', // not sure on this one 'unicorn/no-unnecessary-polyfills': 'error', 'unicorn/no-unreadable-iife': 'error', 'unicorn/no-useless-fallback-in-spread': 'error', 'unicorn/no-useless-length-check': 'error', 'unicorn/no-useless-spread': 'error', 'unicorn/no-useless-switch-case': 'error', 'unicorn/no-zero-fractions': 'error', 'unicorn/numeric-separators-style': 'error', 'unicorn/prefer-array-find': 'error', 'unicorn/prefer-array-flat-map': 'error', 'unicorn/prefer-array-flat': 'error', 'unicorn/prefer-array-index-of': 'error', 'unicorn/prefer-array-some': 'error', 'unicorn/prefer-blob-reading-methods': 'error', 'unicorn/prefer-code-point': 'error', 'unicorn/prefer-date-now': 'error', 'unicorn/prefer-dom-node-append': 'error', 'unicorn/prefer-dom-node-remove': 'error', 'unicorn/prefer-event-target': 'error', 'unicorn/prefer-export-from': 'error', 'unicorn/prefer-includes': 'error', 'unicorn/prefer-logical-operator-over-ternary': 'error', 'unicorn/prefer-modern-dom-apis': 'error', 'unicorn/prefer-modern-math-apis': 'error', 'unicorn/prefer-module': 'error', 'unicorn/prefer-node-protocol': 'error', 'unicorn/prefer-set-size': 'error', 'unicorn/prefer-string-raw': 'error', 'unicorn/prefer-string-slice': 'error', 'unicorn/prefer-type-error': 'error', 'unicorn/throw-new-error': 'error', '@jsdoc/no-undefined-types': 'error', '@typescript-eslint/await-thenable': 'error', '@typescript-eslint/no-unused-vars': 'error', '@virmator/error-name-as-class-field': 'error', '@virmator/no-raw-date': 'error', '@virmator/no-readonly-primitive': 'error', '@virmator/no-relative-import-outside-package': 'error', '@virmator/no-should-in-test-description': 'error', '@virmator/no-underscore-variable': 'error', '@virmator/prefer-arrow-object-block-body': 'error', '@virmator/prefer-ensure-error': 'error', '@virmator/prefer-if-else-chain': 'error', '@virmator/prefer-map-enum-to-object': 'error', '@virmator/prefer-params-object': 'error', '@virmator/prefer-parse-url': 'error', '@virmator/prefer-protected-over-private': 'error', '@virmator/prefer-remove-duplicates': 'error', '@virmator/prefer-single-quotes': 'error', '@virmator/prefer-to-sorted': 'error', '@virmator/require-import-extensions': 'error', 'no-lonely-if': 'error', curly: 'error', 'object-shorthand': 'error', '@typescript-eslint/consistent-type-imports': [ 'error', { disallowTypeAnnotations: false, fixStyle: 'inline-type-imports', prefer: 'type-imports', }, ], '@typescript-eslint/no-floating-promises': [ 'error', { allowForKnownSafeCalls: [ { from: 'package', package: 'node:test', name: [ 'describe', 'it', ], }, ], allowForKnownSafePromises: [ { from: 'package', package: 'fastify', name: [ 'FastifyReply', ], }, ], checkThenables: true, }, ], '@stylistic/padding-line-between-statements': [ 'error', /** Require new lines between imports and everything else. */ { blankLine: 'always', prev: 'import', next: '*', }, /** Do not require new lines between imports and other imports. */ { blankLine: 'any', prev: 'import', next: 'import', }, ], '@stylistic/object-curly-newline': [ 'error', { ObjectExpression: { multiline: true, minProperties: 1, consistent: true, }, ObjectPattern: { multiline: true, consistent: true, }, ImportDeclaration: { multiline: true, consistent: true, }, ExportDeclaration: { multiline: true, consistent: true, }, }, ], '@typescript-eslint/explicit-member-accessibility': [ 'error', { accessibility: 'explicit', overrides: { constructors: 'no-public', }, }, ], '@typescript-eslint/restrict-template-expressions': [ 'error', { allow: [ { from: 'package', name: 'CSSResult', package: 'element-vir', }, { from: 'package', name: 'CSSResult', package: 'lit', }, { from: 'package', name: 'CSSResult', package: '@lit/reactive-element', }, ], allowNumber: true, }, ], 'no-console': [ 'error', { allow: [ 'info', 'error', 'warn', ], }, ], 'prefer-const': [ 'error', { ignoreReadBeforeAssign: true, }, ], }, }, { files: [ '**/*.js', '**/*.cjs', '**/*.mjs', ], ...tsEslint.configs.disableTypeChecked, }, { files: [ /** Be much more lenient with test files. */ '**/*.test.ts', '**/*.example.ts', ], rules: { '@typescript-eslint/no-unused-expressions': 'off', '@typescript-eslint/no-unused-vars': 'off', 'no-sparse-arrays': 'off', 'sonarjs/no-dead-store': 'off', 'sonarjs/no-empty-function': 'off', 'sonarjs/no-unused-expressions': 'off', 'sonarjs/pseudo-random': 'off', 'sonarjs/redundant-type-aliases': 'off', 'sonarjs/no-unused-vars': 'off', }, }, ]; }