{
  "root": true,
  "env": {
    "browser": true,
    "webextensions": true
  },
  "overrides": [
    {
      "files": ["*.ts", "*.js"],
      "plugins": ["@typescript-eslint", "rxjs", "rxjs-angular", "import"],
      "parser": "@typescript-eslint/parser",
      "parserOptions": {
        "project": ["./tsconfig.eslint.json"],
        "sourceType": "module",
        "ecmaVersion": 2020
      },
      "extends": [
        "eslint:recommended",
        "plugin:@typescript-eslint/recommended",
        "plugin:import/recommended",
        "plugin:import/typescript",
        "prettier",
        "plugin:rxjs/recommended",
        "plugin:storybook/recommended"
      ],
      "settings": {
        "import/parsers": {
          "@typescript-eslint/parser": [".ts"]
        },
        "import/resolver": {
          "typescript": {
            "alwaysTryTypes": true
          }
        }
      },
      "rules": {
        "@typescript-eslint/explicit-member-accessibility": [
          "error",
          { "accessibility": "no-public" }
        ],
        "@typescript-eslint/no-explicit-any": "off", // TODO: This should be re-enabled
        "@typescript-eslint/no-floating-promises": "error",
        "@typescript-eslint/no-misused-promises": ["error", { "checksVoidReturn": false }],
        "@typescript-eslint/no-this-alias": ["error", { "allowedNames": ["self"] }],
        "@typescript-eslint/no-unused-vars": ["error", { "args": "none" }],
        "no-console": "error",
        "import/no-unresolved": "off", // TODO: Look into turning off once each package is an actual package.
        "import/order": [
          "error",
          {
            "alphabetize": {
              "order": "asc"
            },
            "newlines-between": "always",
            "pathGroups": [
              {
                "pattern": "@bitwarden/**",
                "group": "external",
                "position": "after"
              },
              {
                "pattern": "src/**/*",
                "group": "parent",
                "position": "before"
              }
            ],
            "pathGroupsExcludedImportTypes": ["builtin"]
          }
        ],
        "rxjs-angular/prefer-takeuntil": ["error", { "alias": ["takeUntilDestroyed"] }],
        "rxjs/no-exposed-subjects": ["error", { "allowProtected": true }],
        "no-restricted-syntax": [
          "error",
          {
            "message": "Calling `svgIcon` directly is not allowed",
            "selector": "CallExpression[callee.name='svgIcon']"
          },
          {
            "message": "Accessing FormGroup using `get` is not allowed, use `.value` instead",
            "selector": "ChainExpression[expression.object.callee.property.name='get'][expression.property.name='value']"
          }
        ],
        "curly": ["error", "all"],
        "import/namespace": ["off"], // This doesn't resolve namespace imports correctly, but TS will throw for this anyway
        "import/no-restricted-paths": [
          "error",
          {
            "zones": [
              {
                // avoid specific frameworks or large dependencies in common
                "target": "./libs/common/**/*",
                "from": [
                  // Angular
                  "./libs/angular/**/*",
                  "./node_modules/@angular*/**/*",

                  // Node
                  "./libs/node/**/*",

                  //Generator
                  "./libs/tools/generator/components/**/*",
                  "./libs/tools/generator/core/**/*",
                  "./libs/tools/generator/extensions/**/*",

                  // Import/export
                  "./libs/importer/**/*",
                  "./libs/tools/export/vault-export/vault-export-core/**/*"
                ]
              },
              {
                // avoid import of unexported state objects
                "target": [
                  "!(libs)/**/*",
                  "libs/!(common)/**/*",
                  "libs/common/!(src)/**/*",
                  "libs/common/src/!(platform)/**/*",
                  "libs/common/src/platform/!(state)/**/*"
                ],
                "from": ["./libs/common/src/platform/state/**/*"],
                // allow module index import
                "except": ["**/state/index.ts"]
              }
            ]
          }
        ],
        "no-restricted-imports": ["error", { "patterns": ["src/**/*"] }]
      }
    },
    {
      "files": ["*.html"],
      "parser": "@angular-eslint/template-parser",
      "plugins": ["@angular-eslint/template", "tailwindcss"],
      "rules": {
        "@angular-eslint/template/button-has-type": "error",
        "tailwindcss/no-custom-classname": [
          "error",
          {
            // uses negative lookahead to whitelist any class that doesn't start with "tw-"
            // in other words: classnames that start with tw- must be valid TailwindCSS classes
            "whitelist": ["(?!(tw)\\-).*"]
          }
        ],
        "tailwindcss/enforces-negative-arbitrary-values": "error",
        "tailwindcss/enforces-shorthand": "error",
        "tailwindcss/no-contradicting-classname": "error"
      }
    },
    {
      "files": ["libs/admin-console/src/**/*.ts"],
      "rules": {
        "no-restricted-imports": [
          "error",
          { "patterns": ["@bitwarden/admin-console/*", "src/**/*"] }
        ]
      }
    },
    {
      "files": ["libs/angular/src/**/*.ts"],
      "rules": {
        "no-restricted-imports": ["error", { "patterns": ["@bitwarden/angular/*", "src/**/*"] }]
      }
    },
    {
      "files": ["libs/auth/src/**/*.ts"],
      "rules": {
        "no-restricted-imports": ["error", { "patterns": ["@bitwarden/auth/*", "src/**/*"] }]
      }
    },
    {
      "files": ["libs/billing/src/**/*.ts"],
      "rules": {
        "no-restricted-imports": ["error", { "patterns": ["@bitwarden/billing/*", "src/**/*"] }]
      }
    },
    {
      "files": ["libs/common/src/**/*.ts"],
      "rules": {
        "no-restricted-imports": ["error", { "patterns": ["@bitwarden/common/*", "src/**/*"] }]
      }
    },
    {
      "files": ["libs/components/src/**/*.ts"],
      "rules": {
        "no-restricted-imports": [
          "error",
          { "patterns": ["@bitwarden/components/*", "src/**/*", "@bitwarden/angular/*"] }
        ]
      }
    },
    {
      "files": ["libs/tools/generator/components/src/**/*.ts"],
      "rules": {
        "no-restricted-imports": [
          "error",
          { "patterns": ["@bitwarden/generator-components/*", "src/**/*"] }
        ]
      }
    },
    {
      "files": ["libs/tools/generator/core/src/**/*.ts"],
      "rules": {
        "no-restricted-imports": [
          "error",
          { "patterns": ["@bitwarden/generator-core/*", "src/**/*"] }
        ]
      }
    },
    {
      "files": ["libs/tools/generator/extensions/history/src/**/*.ts"],
      "rules": {
        "no-restricted-imports": [
          "error",
          { "patterns": ["@bitwarden/generator-history/*", "src/**/*"] }
        ]
      }
    },
    {
      "files": ["libs/tools/generator/extensions/legacy/src/**/*.ts"],
      "rules": {
        "no-restricted-imports": [
          "error",
          { "patterns": ["@bitwarden/generator-legacy/*", "src/**/*"] }
        ]
      }
    },
    {
      "files": ["libs/tools/generator/extensions/navigation/src/**/*.ts"],
      "rules": {
        "no-restricted-imports": [
          "error",
          { "patterns": ["@bitwarden/generator-navigation/*", "src/**/*"] }
        ]
      }
    },
    {
      "files": ["libs/tools/export/vault-export/vault-export-core/src/**/*.ts"],
      "rules": {
        "no-restricted-imports": [
          "error",
          { "patterns": ["@bitwarden/vault-export-core/*", "src/**/*"] }
        ]
      }
    },
    {
      "files": ["libs/tools/export/vault-export/vault-export-ui/src/**/*.ts"],
      "rules": {
        "no-restricted-imports": [
          "error",
          { "patterns": ["@bitwarden/vault-export-ui/*", "src/**/*"] }
        ]
      }
    },
    {
      "files": ["libs/importer/src/**/*.ts"],
      "rules": {
        "no-restricted-imports": ["error", { "patterns": ["@bitwarden/importer/*", "src/**/*"] }]
      }
    },
    {
      "files": ["libs/node/src/**/*.ts"],
      "rules": {
        "no-restricted-imports": ["error", { "patterns": ["@bitwarden/node/*", "src/**/*"] }]
      }
    },
    {
      "files": ["libs/platform/src/**/*.ts"],
      "rules": {
        "no-restricted-imports": ["error", { "patterns": ["@bitwarden/platform/*", "src/**/*"] }]
      }
    },
    {
      "files": ["libs/tools/send/send-ui/src/**/*.ts"],
      "rules": {
        "no-restricted-imports": ["error", { "patterns": ["@bitwarden/send-ui/*", "src/**/*"] }]
      }
    },
    {
      "files": ["libs/vault/src/**/*.ts"],
      "rules": {
        "no-restricted-imports": ["error", { "patterns": ["@bitwarden/vault/*", "src/**/*"] }]
      }
    },
    {
      "files": ["apps/browser/src/**/*.ts", "libs/**/*.ts"],
      "excludedFiles": [
        "apps/browser/src/autofill/{content,notification}/**/*.ts",
        "apps/browser/src/**/background/**/*.ts", // It's okay to have long lived listeners in the background
        "apps/browser/src/platform/background.ts"
      ],
      "rules": {
        "no-restricted-syntax": [
          "error",
          {
            "message": "Using addListener in the browser popup produces a memory leak in Safari, use `BrowserApi.addListener` instead",
            // This selector covers events like chrome.storage.onChange & chrome.runtime.onMessage
            "selector": "CallExpression > [object.object.object.name='chrome'][property.name='addListener']"
          },
          {
            "message": "Using addListener in the browser popup produces a memory leak in Safari, use `BrowserApi.addListener` instead",
            // This selector covers events like chrome.storage.local.onChange
            "selector": "CallExpression > [object.object.object.object.name='chrome'][property.name='addListener']"
          }
        ]
      }
    },
    {
      "files": ["**/*.ts"],
      "excludedFiles": ["**/platform/**/*.ts"],
      "rules": {
        "no-restricted-imports": [
          "error",
          {
            "patterns": [
              "**/platform/**/internal", // General internal pattern
              // All features that have been converted to barrel files
              "**/platform/messaging/**"
            ]
          }
        ]
      }
    },
    {
      "files": ["bitwarden_license/bit-common/src/**/*.ts"],
      "rules": {
        "no-restricted-imports": ["error", { "patterns": ["@bitwarden/bit-common/*", "src/**/*"] }]
      }
    },
    {
      "files": ["apps/**/*.ts"],
      "rules": {
        // Catches static imports
        "no-restricted-imports": [
          "error",
          {
            "patterns": ["biwarden_license/**", "@bitwarden/bit-common/*", "@bitwarden/bit-web/*"]
          }
        ],
        // Catches dynamic imports, e.g. in routing modules where modules are lazy-loaded
        "no-restricted-syntax": [
          "error",
          {
            "message": "Don't import Bitwarden licensed code into OSS code.",
            "selector": "ImportExpression > Literal.source[value=/.*(bitwarden_license|bit-common|bit-web).*/]"
          }
        ]
      }
    }
  ]
}