1
0
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:
Oscar Hinton
2025-01-28 16:40:52 +01:00
committed by GitHub
parent 08c42a8a27
commit 70ea75d8f7
29 changed files with 469 additions and 447 deletions

View File

@@ -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

View File

@@ -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).*/]"
}
]
}
}
]
}

View File

@@ -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:",

View File

@@ -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: {

View File

@@ -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";
};

View File

@@ -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
}

View File

@@ -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."
}
]
}
}
]
}

View File

@@ -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")));

View File

@@ -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 = [

View File

@@ -1,5 +0,0 @@
{
"env": {
"node": true
}
}

View File

@@ -1,3 +0,0 @@
{
"extends": "../../../../libs/admin-console/.eslintrc.json"
}

View File

@@ -1,6 +0,0 @@
{
"env": {
"browser": true,
"node": true
}
}

View File

@@ -1,5 +0,0 @@
{
"rules": {
"no-console": "off"
}
}

View File

@@ -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";

View File

@@ -1,3 +1,4 @@
/* eslint-disable no-console */
import "module-alias/register";
import { v4 as uuidv4 } from "uuid";

View File

@@ -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 = [

View File

@@ -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"
]
}
]
}
}

View File

@@ -1,3 +0,0 @@
{
"extends": "../../../../../libs/admin-console/.eslintrc.json"
}

View File

@@ -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";

View File

@@ -1,5 +0,0 @@
{
"env": {
"node": true
}
}

View File

@@ -1,3 +0,0 @@
{
"extends": "../../../../libs/admin-console/.eslintrc.json"
}

View File

@@ -1,3 +0,0 @@
{
"extends": "../../../../../libs/admin-console/.eslintrc.json"
}

378
eslint.config.mjs Normal file
View 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),
},
];
}

View File

@@ -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"
}
}
]
}

View File

@@ -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
View File

@@ -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",

View File

@@ -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",

View File

@@ -1,5 +0,0 @@
{
"env": {
"node": true
}
}

View File

@@ -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"]
}