mirror of
https://github.com/bitwarden/browser
synced 2025-12-06 00:13:28 +00:00
[PM-17496] Migrate eslint to flat config (#12806)
The legacy config is deprecated and will be removed in eslint 10. The flat config also allows us to write js functions which will assist in handling limitations with multiple identical rules.
This commit is contained in:
@@ -1,29 +0,0 @@
|
||||
**/build
|
||||
**/dist
|
||||
**/coverage
|
||||
.angular
|
||||
storybook-static
|
||||
|
||||
**/node_modules
|
||||
|
||||
**/webpack.*.js
|
||||
**/jest.config.js
|
||||
|
||||
apps/browser/config/config.js
|
||||
apps/browser/src/auth/scripts/duo.js
|
||||
apps/browser/webpack/manifest.js
|
||||
|
||||
apps/desktop/desktop_native
|
||||
apps/desktop/src/auth/scripts/duo.js
|
||||
|
||||
apps/web/config.js
|
||||
apps/web/scripts/*.js
|
||||
apps/web/tailwind.config.js
|
||||
|
||||
apps/cli/config/config.js
|
||||
|
||||
tailwind.config.js
|
||||
libs/components/tailwind.config.base.js
|
||||
libs/components/tailwind.config.js
|
||||
|
||||
scripts/*.js
|
||||
258
.eslintrc.json
258
.eslintrc.json
@@ -1,258 +0,0 @@
|
||||
{
|
||||
"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:@angular-eslint/recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:import/recommended",
|
||||
"plugin:import/typescript",
|
||||
"plugin:rxjs/recommended",
|
||||
"prettier",
|
||||
"plugin:storybook/recommended"
|
||||
],
|
||||
"settings": {
|
||||
"import/parsers": {
|
||||
"@typescript-eslint/parser": [".ts"]
|
||||
},
|
||||
"import/resolver": {
|
||||
"typescript": {
|
||||
"alwaysTryTypes": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"rules": {
|
||||
"@angular-eslint/component-class-suffix": 0,
|
||||
"@angular-eslint/contextual-lifecycle": 0,
|
||||
"@angular-eslint/directive-class-suffix": 0,
|
||||
"@angular-eslint/no-empty-lifecycle-method": 0,
|
||||
"@angular-eslint/no-host-metadata-property": 0,
|
||||
"@angular-eslint/no-input-rename": 0,
|
||||
"@angular-eslint/no-inputs-metadata-property": 0,
|
||||
"@angular-eslint/no-output-native": 0,
|
||||
"@angular-eslint/no-output-on-prefix": 0,
|
||||
"@angular-eslint/no-output-rename": 0,
|
||||
"@angular-eslint/no-outputs-metadata-property": 0,
|
||||
"@angular-eslint/use-lifecycle-interface": "error",
|
||||
"@angular-eslint/use-pipe-transform-interface": 0,
|
||||
"@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-expressions": ["error", { "allowTernary": true }],
|
||||
"@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": [
|
||||
{
|
||||
"target": ["libs/**/*"],
|
||||
"from": ["apps/**/*"],
|
||||
"message": "Libs should not import app-specific code."
|
||||
},
|
||||
{
|
||||
// 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"]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"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": ["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": ["**/src/**/*.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/**",
|
||||
"**/src/**/*" // Prevent relative imports across libs.
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"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/*",
|
||||
"**/src/**/*"
|
||||
]
|
||||
}
|
||||
],
|
||||
// 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).*/]"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
9
.github/renovate.json
vendored
9
.github/renovate.json
vendored
@@ -71,12 +71,8 @@
|
||||
},
|
||||
{
|
||||
"matchPackageNames": [
|
||||
"@angular-eslint/eslint-plugin-template",
|
||||
"@angular-eslint/eslint-plugin",
|
||||
"@angular-eslint/schematics",
|
||||
"@angular-eslint/template-parser",
|
||||
"@typescript-eslint/eslint-plugin",
|
||||
"@typescript-eslint/parser",
|
||||
"angular-eslint",
|
||||
"eslint-config-prettier",
|
||||
"eslint-import-resolver-typescript",
|
||||
"eslint-plugin-import",
|
||||
@@ -86,7 +82,8 @@
|
||||
"eslint-plugin-tailwindcss",
|
||||
"eslint",
|
||||
"husky",
|
||||
"lint-staged"
|
||||
"lint-staged",
|
||||
"typescript-eslint"
|
||||
],
|
||||
"description": "Architecture owned dependencies",
|
||||
"commitMessagePrefix": "[deps] Architecture:",
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { dirname, join } from "path";
|
||||
|
||||
import { StorybookConfig } from "@storybook/angular";
|
||||
import TsconfigPathsPlugin from "tsconfig-paths-webpack-plugin";
|
||||
import remarkGfm from "remark-gfm";
|
||||
import TsconfigPathsPlugin from "tsconfig-paths-webpack-plugin";
|
||||
|
||||
const config: StorybookConfig = {
|
||||
stories: [
|
||||
@@ -29,6 +30,8 @@ const config: StorybookConfig = {
|
||||
getAbsolutePath("@storybook/addon-designs"),
|
||||
getAbsolutePath("@storybook/addon-interactions"),
|
||||
{
|
||||
// @storybook/addon-docs is part of @storybook/addon-essentials
|
||||
// eslint-disable-next-line storybook/no-uninstalled-addons
|
||||
name: "@storybook/addon-docs",
|
||||
options: {
|
||||
mdxPluginOptions: {
|
||||
|
||||
@@ -50,10 +50,14 @@ const darkTheme = create({
|
||||
});
|
||||
|
||||
export const getPreferredColorScheme = () => {
|
||||
if (!globalThis || !globalThis.matchMedia) return "light";
|
||||
if (!globalThis || !globalThis.matchMedia) {
|
||||
return "light";
|
||||
}
|
||||
|
||||
const isDarkThemePreferred = globalThis.matchMedia("(prefers-color-scheme: dark)").matches;
|
||||
if (isDarkThemePreferred) return "dark";
|
||||
if (isDarkThemePreferred) {
|
||||
return "dark";
|
||||
}
|
||||
|
||||
return "light";
|
||||
};
|
||||
|
||||
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -7,5 +7,6 @@
|
||||
"**/_locales/*[^n]/messages.json": true
|
||||
},
|
||||
"rust-analyzer.linkedProjects": ["apps/desktop/desktop_native/Cargo.toml"],
|
||||
"typescript.tsdk": "node_modules/typescript/lib"
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"eslint.useFlatConfig": true
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"webextensions": true
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["src/**/*.ts"],
|
||||
"excludedFiles": [
|
||||
"src/**/{content,popup,spec}/**/*.ts",
|
||||
"src/**/autofill/{notification,overlay}/**/*.ts",
|
||||
"src/**/autofill/**/{autofill-overlay-content,collect-autofill-content,dom-element-visibility,insert-autofill-content}.service.ts",
|
||||
"src/**/*.spec.ts"
|
||||
],
|
||||
"rules": {
|
||||
"no-restricted-globals": [
|
||||
"error",
|
||||
{
|
||||
"name": "window",
|
||||
"message": "The `window` object is not available in service workers and may not be available within the background script. Consider using `self`, `globalThis`, or another global property instead."
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
import { dirname, join } from "path";
|
||||
import path from "path";
|
||||
import path, { dirname, join } from "path";
|
||||
|
||||
import type { StorybookConfig } from "@storybook/web-components-webpack5";
|
||||
import TsconfigPathsPlugin from "tsconfig-paths-webpack-plugin";
|
||||
import remarkGfm from "remark-gfm";
|
||||
import TsconfigPathsPlugin from "tsconfig-paths-webpack-plugin";
|
||||
|
||||
const getAbsolutePath = (value: string): string =>
|
||||
dirname(require.resolve(join(value, "package.json")));
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* eslint-disable no-undef, @typescript-eslint/no-var-requires */
|
||||
/* eslint-disable no-undef, @typescript-eslint/no-require-imports */
|
||||
const config = require("../../libs/components/tailwind.config.base");
|
||||
|
||||
config.content = [
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"env": {
|
||||
"node": true
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"extends": "../../../../libs/admin-console/.eslintrc.json"
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": true
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"rules": {
|
||||
"no-console": "off"
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-console */
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { homedir } from "os";
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-console */
|
||||
import "module-alias/register";
|
||||
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* eslint-disable no-undef, @typescript-eslint/no-var-requires */
|
||||
/* eslint-disable no-undef, @typescript-eslint/no-require-imports */
|
||||
const config = require("../../libs/components/tailwind.config.base");
|
||||
|
||||
config.content = [
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true
|
||||
},
|
||||
"rules": {
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
"patterns": [
|
||||
"**/app/core/*",
|
||||
"**/reports/*",
|
||||
"**/app/shared/*",
|
||||
"**/organizations/settings/*",
|
||||
"**/organizations/policies/*",
|
||||
"@bitwarden/web-vault/*",
|
||||
"src/**/*",
|
||||
"bitwarden_license"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"extends": "../../../../../libs/admin-console/.eslintrc.json"
|
||||
}
|
||||
@@ -11,6 +11,8 @@ import { AccountService } from "@bitwarden/common/auth/abstractions/account.serv
|
||||
import { CipherId } from "@bitwarden/common/types/guid";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
|
||||
// FIXME: remove `src` and fix import
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { Account } from "../../../../../../../libs/importer/src/importers/lastpass/access/models";
|
||||
import { RoutedVaultFilterService } from "../../individual-vault/vault-filter/services/routed-vault-filter.service";
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"env": {
|
||||
"node": true
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"extends": "../../../../libs/admin-console/.eslintrc.json"
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"extends": "../../../../../libs/admin-console/.eslintrc.json"
|
||||
}
|
||||
378
eslint.config.mjs
Normal file
378
eslint.config.mjs
Normal file
@@ -0,0 +1,378 @@
|
||||
// @ts-check
|
||||
|
||||
import eslint from "@eslint/js";
|
||||
import tseslint from "typescript-eslint";
|
||||
import angular from "angular-eslint";
|
||||
// @ts-ignore
|
||||
import importPlugin from "eslint-plugin-import";
|
||||
import eslintConfigPrettier from "eslint-config-prettier";
|
||||
import eslintPluginTailwindCSS from "eslint-plugin-tailwindcss";
|
||||
import rxjs from "eslint-plugin-rxjs";
|
||||
import angularRxjs from "eslint-plugin-rxjs-angular";
|
||||
import storybook from "eslint-plugin-storybook";
|
||||
|
||||
export default tseslint.config(
|
||||
...storybook.configs["flat/recommended"],
|
||||
{
|
||||
// Everything in this config object targets our TypeScript files (Components, Directives, Pipes etc)
|
||||
files: ["**/*.ts", "**/*.js"],
|
||||
extends: [
|
||||
eslint.configs.recommended,
|
||||
...tseslint.configs.recommended,
|
||||
//...tseslint.configs.stylistic,
|
||||
...angular.configs.tsRecommended,
|
||||
importPlugin.flatConfigs.recommended,
|
||||
importPlugin.flatConfigs.typescript,
|
||||
eslintConfigPrettier, // Disables rules that conflict with Prettier
|
||||
],
|
||||
plugins: {
|
||||
rxjs: rxjs,
|
||||
"rxjs-angular": angularRxjs,
|
||||
},
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
project: ["./tsconfig.eslint.json"],
|
||||
sourceType: "module",
|
||||
ecmaVersion: 2020,
|
||||
},
|
||||
},
|
||||
settings: {
|
||||
"import/parsers": {
|
||||
"@typescript-eslint/parser": [".ts"],
|
||||
},
|
||||
"import/resolver": {
|
||||
typescript: {
|
||||
alwaysTryTypes: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
processor: angular.processInlineTemplates,
|
||||
rules: {
|
||||
...rxjs.configs.recommended.rules,
|
||||
"rxjs-angular/prefer-takeuntil": ["error", { alias: ["takeUntilDestroyed"] }],
|
||||
"rxjs/no-exposed-subjects": ["error", { allowProtected: true }],
|
||||
|
||||
// TODO: Enable these.
|
||||
"@angular-eslint/component-class-suffix": 0,
|
||||
"@angular-eslint/contextual-lifecycle": 0,
|
||||
"@angular-eslint/directive-class-suffix": 0,
|
||||
"@angular-eslint/no-empty-lifecycle-method": 0,
|
||||
"@angular-eslint/no-host-metadata-property": 0,
|
||||
"@angular-eslint/no-input-rename": 0,
|
||||
"@angular-eslint/no-inputs-metadata-property": 0,
|
||||
"@angular-eslint/no-output-native": 0,
|
||||
"@angular-eslint/no-output-on-prefix": 0,
|
||||
"@angular-eslint/no-output-rename": 0,
|
||||
"@angular-eslint/no-outputs-metadata-property": 0,
|
||||
"@angular-eslint/use-lifecycle-interface": "error",
|
||||
"@angular-eslint/use-pipe-transform-interface": 0,
|
||||
|
||||
"@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-expressions": ["error", { allowTernary: true }],
|
||||
"@typescript-eslint/no-unused-vars": ["error", { args: "none" }],
|
||||
|
||||
curly: ["error", "all"],
|
||||
"no-console": "error",
|
||||
|
||||
"import/order": [
|
||||
"error",
|
||||
{
|
||||
alphabetize: {
|
||||
order: "asc",
|
||||
},
|
||||
"newlines-between": "always",
|
||||
pathGroups: [
|
||||
{
|
||||
pattern: "@bitwarden/**",
|
||||
group: "external",
|
||||
position: "after",
|
||||
},
|
||||
{
|
||||
pattern: "src/**/*",
|
||||
group: "parent",
|
||||
position: "before",
|
||||
},
|
||||
],
|
||||
pathGroupsExcludedImportTypes: ["builtin"],
|
||||
},
|
||||
],
|
||||
"import/namespace": ["off"], // This doesn't resolve namespace imports correctly, but TS will throw for this anyway
|
||||
"import/no-restricted-paths": [
|
||||
"error",
|
||||
{
|
||||
zones: [
|
||||
{
|
||||
target: ["libs/**/*"],
|
||||
from: ["apps/**/*"],
|
||||
message: "Libs should not import app-specific code.",
|
||||
},
|
||||
{
|
||||
// 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"],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
"import/no-unresolved": "off", // TODO: Look into turning off once each package is an actual package.,
|
||||
},
|
||||
},
|
||||
{
|
||||
// Everything in this config object targets our HTML files (external templates,
|
||||
// and inline templates as long as we have the `processor` set on our TypeScript config above)
|
||||
files: ["**/*.html"],
|
||||
extends: [
|
||||
// Apply the recommended Angular template rules
|
||||
// ...angular.configs.templateRecommended,
|
||||
// Apply the Angular template rules which focus on accessibility of our apps
|
||||
// ...angular.configs.templateAccessibility,
|
||||
],
|
||||
languageOptions: {
|
||||
parser: angular.templateParser,
|
||||
},
|
||||
plugins: {
|
||||
"@angular-eslint/template": angular.templatePlugin,
|
||||
tailwindcss: eslintPluginTailwindCSS,
|
||||
},
|
||||
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",
|
||||
},
|
||||
},
|
||||
|
||||
// Global quirks
|
||||
{
|
||||
files: ["apps/browser/src/**/*.ts", "libs/**/*.ts"],
|
||||
ignores: [
|
||||
"apps/browser/src/autofill/{deprecated/content,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: ["**/src/**/*.ts"],
|
||||
rules: {
|
||||
"no-restricted-imports": buildNoRestrictedImports(),
|
||||
},
|
||||
},
|
||||
|
||||
// App overrides. Be considerate if you override these.
|
||||
{
|
||||
files: ["apps/browser/src/**/*.ts"],
|
||||
ignores: [
|
||||
"apps/browser/src/**/{content,popup,spec}/**/*.ts",
|
||||
"apps/browser/src/**/autofill/{notification,overlay}/**/*.ts",
|
||||
"apps/browser/src/**/autofill/**/{autofill-overlay-content,collect-autofill-content,dom-element-visibility,insert-autofill-content}.service.ts",
|
||||
"apps/browser/src/**/*.spec.ts",
|
||||
],
|
||||
rules: {
|
||||
"no-restricted-globals": [
|
||||
"error",
|
||||
{
|
||||
name: "window",
|
||||
message:
|
||||
"The `window` object is not available in service workers and may not be available within the background script. Consider using `self`, `globalThis`, or another global property instead.",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ["bitwarden_license/bit-common/src/**/*.ts"],
|
||||
rules: {
|
||||
"no-restricted-imports": buildNoRestrictedImports(["@bitwarden/bit-common/*"]),
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ["apps/**/*.ts"],
|
||||
rules: {
|
||||
// Catches static imports
|
||||
"no-restricted-imports": buildNoRestrictedImports([
|
||||
"bitwarden_license/**",
|
||||
"@bitwarden/bit-common/*",
|
||||
"@bitwarden/bit-web/*",
|
||||
]),
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ["apps/web/src/**/*.ts"],
|
||||
rules: {
|
||||
"no-restricted-imports": buildNoRestrictedImports([
|
||||
"bitwarden_license/**",
|
||||
"@bitwarden/bit-common/*",
|
||||
"@bitwarden/bit-web/*",
|
||||
|
||||
"**/app/core/*",
|
||||
"**/reports/*",
|
||||
"**/app/shared/*",
|
||||
"**/organizations/settings/*",
|
||||
"**/organizations/policies/*",
|
||||
]),
|
||||
},
|
||||
},
|
||||
|
||||
/// Team overrides
|
||||
{
|
||||
files: ["**/src/platform/**/*.ts"],
|
||||
rules: {
|
||||
"no-restricted-imports": buildNoRestrictedImports([], true),
|
||||
},
|
||||
},
|
||||
{
|
||||
files: [
|
||||
"apps/cli/src/admin-console/**/*.ts",
|
||||
"apps/web/src/app/admin-console/**/*.ts",
|
||||
"bitwarden_license/bit-cli/src/admin-console/**/*.ts",
|
||||
"bitwarden_license/bit-web/src/app/admin-console/**/*.ts",
|
||||
"libs/admin-console/src/**/*.ts",
|
||||
],
|
||||
rules: {
|
||||
"@angular-eslint/component-class-suffix": "error",
|
||||
"@angular-eslint/contextual-lifecycle": "error",
|
||||
"@angular-eslint/directive-class-suffix": "error",
|
||||
"@angular-eslint/no-empty-lifecycle-method": "error",
|
||||
"@angular-eslint/no-input-rename": "error",
|
||||
"@angular-eslint/no-inputs-metadata-property": "error",
|
||||
"@angular-eslint/no-output-native": "error",
|
||||
"@angular-eslint/no-output-on-prefix": "error",
|
||||
"@angular-eslint/no-output-rename": "error",
|
||||
"@angular-eslint/no-outputs-metadata-property": "error",
|
||||
"@angular-eslint/use-lifecycle-interface": "error",
|
||||
"@angular-eslint/use-pipe-transform-interface": "error",
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ["libs/common/src/state-migrations/**/*.ts"],
|
||||
rules: {
|
||||
"import/no-restricted-paths": [
|
||||
"error",
|
||||
{
|
||||
basePath: "libs/common/src/state-migrations",
|
||||
zones: [
|
||||
{
|
||||
target: "./",
|
||||
from: "../",
|
||||
// Relative to from, not basePath
|
||||
except: ["state-migrations"],
|
||||
message:
|
||||
"State migrations should rarely import from the greater codebase. If you need to import from another location, take into account the likelihood of change in that code and consider copying to the migration instead.",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
// Keep ignores at the end
|
||||
{
|
||||
ignores: [
|
||||
"**/build/",
|
||||
"**/dist/",
|
||||
"**/coverage/",
|
||||
".angular/",
|
||||
"storybook-static/",
|
||||
|
||||
"**/node_modules/",
|
||||
|
||||
"**/webpack.*.js",
|
||||
"**/jest.config.js",
|
||||
|
||||
"apps/browser/config/config.js",
|
||||
"apps/browser/src/auth/scripts/duo.js",
|
||||
"apps/browser/webpack/manifest.js",
|
||||
|
||||
"apps/desktop/desktop_native",
|
||||
"apps/desktop/src/auth/scripts/duo.js",
|
||||
|
||||
"apps/web/config.js",
|
||||
"apps/web/scripts/*.js",
|
||||
"apps/web/tailwind.config.js",
|
||||
|
||||
"apps/cli/config/config.js",
|
||||
|
||||
"tailwind.config.js",
|
||||
"libs/components/tailwind.config.base.js",
|
||||
"libs/components/tailwind.config.js",
|
||||
|
||||
"scripts/*.js",
|
||||
],
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* // Helper function for building no-restricted-imports rule
|
||||
* @param {string[]} additionalForbiddenPatterns
|
||||
* @returns {any}
|
||||
*/
|
||||
function buildNoRestrictedImports(additionalForbiddenPatterns = [], skipPlatform = false) {
|
||||
return [
|
||||
"error",
|
||||
{
|
||||
patterns: [
|
||||
...(skipPlatform ? [] : ["**/platform/**/internal", "**/platform/messaging/**"]),
|
||||
"**/src/**/*", // Prevent relative imports across libs.
|
||||
].concat(additionalForbiddenPatterns),
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
{
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts"],
|
||||
"extends": ["plugin:@angular-eslint/recommended"],
|
||||
"rules": {
|
||||
"@angular-eslint/component-class-suffix": "error",
|
||||
"@angular-eslint/contextual-lifecycle": "error",
|
||||
"@angular-eslint/directive-class-suffix": "error",
|
||||
"@angular-eslint/no-empty-lifecycle-method": "error",
|
||||
"@angular-eslint/no-input-rename": "error",
|
||||
"@angular-eslint/no-inputs-metadata-property": "error",
|
||||
"@angular-eslint/no-output-native": "error",
|
||||
"@angular-eslint/no-output-on-prefix": "error",
|
||||
"@angular-eslint/no-output-rename": "error",
|
||||
"@angular-eslint/no-outputs-metadata-property": "error",
|
||||
"@angular-eslint/use-lifecycle-interface": "error",
|
||||
"@angular-eslint/use-pipe-transform-interface": "error"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
{
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*"],
|
||||
"rules": {
|
||||
"import/no-restricted-paths": [
|
||||
"error",
|
||||
{
|
||||
"basePath": "libs/common/src/state-migrations",
|
||||
"zones": [
|
||||
{
|
||||
"target": "./",
|
||||
"from": "../",
|
||||
// Relative to from, not basePath
|
||||
"except": ["state-migrations"],
|
||||
"message": "State migrations should rarely import from the greater codebase. If you need to import from another location, take into account the likelihood of change in that code and consider copying to the migration instead."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
68
package-lock.json
generated
68
package-lock.json
generated
@@ -77,10 +77,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "18.2.12",
|
||||
"@angular-eslint/eslint-plugin": "18.4.3",
|
||||
"@angular-eslint/eslint-plugin-template": "18.4.3",
|
||||
"@angular-eslint/schematics": "18.4.3",
|
||||
"@angular-eslint/template-parser": "18.4.3",
|
||||
"@angular/cli": "18.2.12",
|
||||
"@angular/compiler-cli": "18.2.13",
|
||||
"@babel/core": "7.24.9",
|
||||
@@ -121,10 +118,9 @@
|
||||
"@types/proper-lockfile": "4.1.4",
|
||||
"@types/retry": "0.12.5",
|
||||
"@types/zxcvbn": "4.4.5",
|
||||
"@typescript-eslint/eslint-plugin": "8.20.0",
|
||||
"@typescript-eslint/parser": "8.20.0",
|
||||
"@webcomponents/custom-elements": "1.6.0",
|
||||
"@yao-pkg/pkg": "5.16.1",
|
||||
"angular-eslint": "18.4.3",
|
||||
"autoprefixer": "10.4.20",
|
||||
"babel-loader": "9.2.1",
|
||||
"base64-loader": "1.0.0",
|
||||
@@ -176,6 +172,7 @@
|
||||
"tsconfig-paths-webpack-plugin": "4.2.0",
|
||||
"type-fest": "2.19.0",
|
||||
"typescript": "5.4.2",
|
||||
"typescript-eslint": "8.20.0",
|
||||
"typescript-strict-plugin": "^2.4.4",
|
||||
"url": "0.11.4",
|
||||
"util": "0.12.5",
|
||||
@@ -1240,6 +1237,20 @@
|
||||
"yarn": ">= 1.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular-eslint/builder": {
|
||||
"version": "18.4.3",
|
||||
"resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-18.4.3.tgz",
|
||||
"integrity": "sha512-NzmrXlr7GFE+cjwipY/CxBscZXNqnuK0us1mO6Z2T6MeH6m+rRcdlY/rZyKoRniyNNvuzl6vpEsfMIMmnfebrA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@angular-devkit/architect": ">= 0.1800.0 < 0.1900.0",
|
||||
"@angular-devkit/core": ">= 18.0.0 < 19.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.57.0 || ^9.0.0",
|
||||
"typescript": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular-eslint/bundled-angular-compiler": {
|
||||
"version": "18.4.3",
|
||||
"resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-18.4.3.tgz",
|
||||
@@ -10080,7 +10091,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.20.0.tgz",
|
||||
"integrity": "sha512-naduuphVw5StFfqp4Gq4WhIBE2gN1GEmMUExpJYknZJdRnc+2gDzB8Z3+5+/Kv33hPQRDGzQO/0opHE72lZZ6A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.10.0",
|
||||
"@typescript-eslint/scope-manager": "8.20.0",
|
||||
@@ -10259,7 +10269,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.20.0.tgz",
|
||||
"integrity": "sha512-gKXG7A5HMyjDIedBi6bUrDcun8GIjnI8qOwVLiY3rx6T/sHP/19XLJOnIq/FgQvWLHja5JN/LSE7eklNBr612g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.20.0",
|
||||
"@typescript-eslint/types": "8.20.0",
|
||||
@@ -10302,7 +10311,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.20.0.tgz",
|
||||
"integrity": "sha512-bPC+j71GGvA7rVNAHAtOjbVXbLN5PkwqMvy1cwGeaxUoRQXVuKCebRoLzm+IPW/NtFFpstn1ummSIasD5t60GA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/typescript-estree": "8.20.0",
|
||||
"@typescript-eslint/utils": "8.20.0",
|
||||
@@ -11106,6 +11114,28 @@
|
||||
"ajv": "^8.8.2"
|
||||
}
|
||||
},
|
||||
"node_modules/angular-eslint": {
|
||||
"version": "18.4.3",
|
||||
"resolved": "https://registry.npmjs.org/angular-eslint/-/angular-eslint-18.4.3.tgz",
|
||||
"integrity": "sha512-0ZjLzzADGRLUhZC8ZpwSo6CE/m6QhQB/oljMJ0mEfP+lB1sy1v8PBKNsJboIcfEEgGW669Z/efVQ3df88yJLYg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@angular-devkit/core": ">= 18.0.0 < 19.0.0",
|
||||
"@angular-devkit/schematics": ">= 18.0.0 < 19.0.0",
|
||||
"@angular-eslint/builder": "18.4.3",
|
||||
"@angular-eslint/eslint-plugin": "18.4.3",
|
||||
"@angular-eslint/eslint-plugin-template": "18.4.3",
|
||||
"@angular-eslint/schematics": "18.4.3",
|
||||
"@angular-eslint/template-parser": "18.4.3",
|
||||
"@typescript-eslint/types": "^8.0.0",
|
||||
"@typescript-eslint/utils": "^8.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.57.0 || ^9.0.0",
|
||||
"typescript": "*",
|
||||
"typescript-eslint": "^8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-colors": {
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
|
||||
@@ -31151,6 +31181,28 @@
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript-eslint": {
|
||||
"version": "8.20.0",
|
||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.20.0.tgz",
|
||||
"integrity": "sha512-Kxz2QRFsgbWj6Xcftlw3Dd154b3cEPFqQC+qMZrMypSijPd4UanKKvoKDrJ4o8AIfZFKAF+7sMaEIR8mTElozA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "8.20.0",
|
||||
"@typescript-eslint/parser": "8.20.0",
|
||||
"@typescript-eslint/utils": "8.20.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.57.0 || ^9.0.0",
|
||||
"typescript": ">=4.8.4 <5.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript-strict-plugin": {
|
||||
"version": "2.4.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript-strict-plugin/-/typescript-strict-plugin-2.4.4.tgz",
|
||||
|
||||
@@ -37,10 +37,7 @@
|
||||
],
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "18.2.12",
|
||||
"@angular-eslint/eslint-plugin": "18.4.3",
|
||||
"@angular-eslint/eslint-plugin-template": "18.4.3",
|
||||
"@angular-eslint/schematics": "18.4.3",
|
||||
"@angular-eslint/template-parser": "18.4.3",
|
||||
"@angular/cli": "18.2.12",
|
||||
"@angular/compiler-cli": "18.2.13",
|
||||
"@babel/core": "7.24.9",
|
||||
@@ -81,10 +78,9 @@
|
||||
"@types/proper-lockfile": "4.1.4",
|
||||
"@types/retry": "0.12.5",
|
||||
"@types/zxcvbn": "4.4.5",
|
||||
"@typescript-eslint/eslint-plugin": "8.20.0",
|
||||
"@typescript-eslint/parser": "8.20.0",
|
||||
"@webcomponents/custom-elements": "1.6.0",
|
||||
"@yao-pkg/pkg": "5.16.1",
|
||||
"angular-eslint": "18.4.3",
|
||||
"autoprefixer": "10.4.20",
|
||||
"babel-loader": "9.2.1",
|
||||
"base64-loader": "1.0.0",
|
||||
@@ -136,6 +132,7 @@
|
||||
"tsconfig-paths-webpack-plugin": "4.2.0",
|
||||
"type-fest": "2.19.0",
|
||||
"typescript": "5.4.2",
|
||||
"typescript-eslint": "8.20.0",
|
||||
"typescript-strict-plugin": "^2.4.4",
|
||||
"url": "0.11.4",
|
||||
"util": "0.12.5",
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"env": {
|
||||
"node": true
|
||||
}
|
||||
}
|
||||
@@ -47,6 +47,11 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
".storybook/main.ts",
|
||||
".storybook/manager.js",
|
||||
"apps/browser/src/autofill/content/components/.lit-storybook/main.ts"
|
||||
],
|
||||
"include": ["apps/**/*", "libs/**/*", "bitwarden_license/**/*", "scripts/**/*"],
|
||||
"exclude": ["**/build", "**/dist"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user