---
env:
  es2020: true
  jest: true
  node: true

plugins:
  - '@typescript-eslint'
  - import
  - prettier

parser: '@typescript-eslint/parser'
parserOptions:
  ecmaVersion: 2020
  impliedStrict: true
  sourceType: script
  project: ./**/tsconfig.json

extends:
  - eslint:recommended
  - plugin:@typescript-eslint/eslint-recommended
  - plugin:@typescript-eslint/recommended
  - plugin:@typescript-eslint/recommended-requiring-type-checking
  - plugin:import/typescript
  - prettier
  - plugin:prettier/recommended

settings:
  import/parsers:
    '@typescript-eslint/parser': ['.ts', '.tsx']
  import/resolver:
    node: {}
    typescript:
      project: ./**/tsconfig.json

ignorePatterns:
  # Ignore Jest configuration file (it's excluded from tsconfig.json, so it's problematic!)
  - jest.config.ts

rules:
  # Custom Configurations

  'prettier/prettier':
    - error

  '@typescript-eslint/array-type':
    - error
    - default: array-simple
      readonly: array-simple

  '@typescript-eslint/await-thenable':
    - error

  '@typescript-eslint/explicit-module-boundary-types':
    - off

  '@typescript-eslint/explicit-member-accessibility':
    - error

  '@typescript-eslint/member-ordering':
    - error
    - default:
        - static-field
        - static-method
        - instance-field
        - constructor
        - instance-method

  '@typescript-eslint/no-empty-function':
    - error
    - allow: [constructors]

  '@typescript-eslint/no-floating-promises':
    - error

  '@typescript-eslint/no-for-in-array':
    - error

  '@typescript-eslint/no-misused-promises':
    - error

  '@typescript-eslint/no-require-imports':
    - error

  '@typescript-eslint/no-unsafe-assignment':
    - off

  '@typescript-eslint/no-unsafe-call':
    - off

  '@typescript-eslint/no-unsafe-member-access':
    - off

  '@typescript-eslint/no-unsafe-return':
    - off

  '@typescript-eslint/no-unused-vars':
    - error
    - args: all
      argsIgnorePattern: ^_
      caughtErrors: all
      vars: all
      varsIgnorePattern: ^_

  '@typescript-eslint/no-useless-constructor':
    - error

  '@typescript-eslint/prefer-for-of':
    - error

  '@typescript-eslint/prefer-nullish-coalescing':
    - error
    - ignoreMixedLogicalExpressions: true

  '@typescript-eslint/prefer-readonly':
    - error

  '@typescript-eslint/promise-function-async':
    - error
    - checkArrowFunctions: false

  '@typescript-eslint/restrict-template-expressions':
    - error
    - allowNumber: true
      allowBoolean: true
      allowAny: true
      allowNullish: true

  '@typescript-eslint/require-await':
    - error

  '@typescript-eslint/return-await':
    - error
    - 'in-try-catch'

  '@typescript-eslint/switch-exhaustiveness-check':
    - error

  'complexity':
    - off

  'dot-notation':
    - error

  'eqeqeq':
    - error
    - always
    - null: ignore

  'import/no-duplicates':
    - error

  'import/no-extraneous-dependencies':
    - error
    - devDependencies: # Only allow importing devDependencies from tests
        - '**/test/**'
        - '**/*.test.ts'
      optionalDependencies: false # Disallow importing optional dependencies (those shouldn't be used here)
      peerDependencies: false # Disallow importing peer dependencies (those shouldn't be used here)

  'import/no-unresolved':
    - error
    - ignore:
        - '@jsii/check-node/run' # @jsii/check-node uses an export map, which import/resolver does not (yet) support (https://github.com/import-js/eslint-plugin-import/issues/1868)
        - worker_threads # This isn't supported in all node versions (import is always guarded)

  'import/order':
    - error
    - alphabetize:
        order: asc
        caseInsensitive: true
      groups:
        - [builtin, external]
        - [parent, sibling]
        - [index, unknown]
      newlines-between: always

  'no-alert':
    - error

  'no-await-in-loop':
    - error

  'no-caller':
    - error

  'no-else-return':
    - error
    - allowElseIf: true

  'no-eval':
    - error

  'no-extra-bind':
    - error

  'no-implied-eval':
    - error

  'no-lone-blocks':
    - error

  'no-new-symbol':
    - error

  'no-proto':
    - error

  'no-restricted-properties':
    - error
    - { property: "substr", message: "Use .slice instead of .substr." }

  'no-return-await':
    - error

  'no-unused-expressions':
    - error

  'no-useless-call':
    - error

  'no-var':
    - error

  'prefer-const':
    - error

  'prefer-template':
    - error

  'eol-last':
    - error
    - always

  # Disabled rules
  '@typescript-eslint/explicit-function-return-type': off
  '@typescript-eslint/interface-name-prefix': off
  '@typescript-eslint/no-explicit-any': off
  '@typescript-eslint/no-non-null-assertion': off
  '@typescript-eslint/no-use-before-define': off
  '@typescript-eslint/unbound-method': off
  'no-case-declarations': off
  'require-atomic-updates': off

  # This is not a bad rule but it got sprung on us and our code loudly fails it
  # Disable to get the eslint upgrade to pass.
  '@typescript-eslint/no-unsafe-argument': off

  # 'consistent-return' actually decreases safety. Its use will enforce useless `throws`
  # statements, forcing a runtime error that occlude cases where the TypeScript type
  # checker would actually have caught something like a non-exhaustive `switch` statement
  # at compile time.
  'consistent-return': off
