passbolt-styleguide
Version:
Passbolt styleguide contains common styling assets used by the different sites, plugin, etc.
231 lines (209 loc) • 7.07 kB
JavaScript
import globals from "globals";
import path from "path";
import { fileURLToPath } from "url";
// ESLint plugins import
import js from "@eslint/js";
import noUnsanitizedPlugin from "eslint-plugin-no-unsanitized";
import jestPlugin from "eslint-plugin-jest";
import reactPlugin from "eslint-plugin-react";
import importPlugin from "eslint-plugin-import";
import pluginSecurity from "eslint-plugin-security";
import nodePlugin from "eslint-plugin-n";
import * as regexpPlugin from "eslint-plugin-regexp";
import pluginPromise from "eslint-plugin-promise";
import prettierPlugin from "eslint-plugin-prettier";
import prettierConfig from "eslint-config-prettier";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
export default [
js.configs.recommended, // core JavaScript rules
reactPlugin.configs.flat.recommended, // React best practices
reactPlugin.configs.flat["jsx-runtime"], // JSX transform rules
importPlugin.flatConfigs.recommended, // import/export validations
pluginSecurity.configs.recommended,
nodePlugin.configs["flat/recommended-script"],
regexpPlugin.configs["flat/recommended"],
pluginPromise.configs["flat/recommended"],
prettierConfig, // Must be last - disables conflicts
{
files: ["**/*.{js,jsx,mjs,cjs}"],
languageOptions: {
ecmaVersion: 2024,
sourceType: "module",
parserOptions: {
ecmaFeatures: {
jsx: true,
},
},
globals: {
...globals.browser,
...globals.node,
...globals.es2024,
...globals.webextensions,
// Custom globals
global: "readonly",
port: "readonly",
},
},
plugins: {
"no-unsanitized": noUnsanitizedPlugin,
prettier: prettierPlugin,
},
settings: {
react: {
version: "detect",
},
regexp: {
// Allow PGP armor header character ranges (RFC 4880)
// !-9 and ;-~ match all printable ASCII except colon
allowedCharacterRanges: ["alphanumeric", "!-9", ";-~"],
},
"import/resolver": {
node: {
paths: [__dirname], // Add project root to resolution paths
extensions: [".js", ".jsx", ".mjs", ".cjs"],
},
alias: {
map: [["passbolt-styleguide", path.resolve(__dirname)]],
extensions: [".js", ".jsx", ".ts", ".tsx"],
},
},
},
rules: {
/*
* ============================================
* CUSTOM OVERRIDES
* ============================================
*/
"prettier/prettier": "warn",
// Critical rules not in recommended configs
curly: "error", // Always use braces
"no-implicit-coercion": "error", // No implicit type coercion
"no-implicit-globals": "error", // No implicit global variables
"no-unsanitized/method": "error", // Prevent XSS via innerHTML
"no-unsanitized/property": "error", // Prevent XSS via outerHTML
// Our specific preferences (override recommended)
"no-console": "off", // Allow console.log in dev
"react/display-name": "off", // Don't require display names
"react/prop-types": "off", // Skip PropTypes (future TypeScript)
"react/jsx-uses-react": "error", // Marks React as used when JSX is present
"no-useless-escape": "off", // Too many false positives
"func-names": ["error", "never"],
"import/no-named-as-default": "off",
"security/detect-object-injection": "off",
"security/detect-non-literal-regexp": "off",
"security/detect-unsafe-regex": "off",
"prefer-regex-literals": "off",
// Phantom dependency detection (CRITICAL)
"import/no-extraneous-dependencies": [
"error",
{
devDependencies: [
"**/*.test.{js,jsx}",
"**/*.spec.{js,jsx}",
"**/__tests__/**",
"**/test/**",
"**/tests/**",
"**/scripts/**",
"*.config.{js,mjs,cjs}",
"webpack.config.js",
],
optionalDependencies: false,
peerDependencies: true,
},
],
// Browser extension specific
"n/no-unsupported-features/node-builtins": "off", // We use browser APIs
"n/no-missing-import": "off", // Handled by import plugin
"n/no-missing-require": "off", // Handled by import plugin
},
},
/*
* ============================================
* TEST FILES CONFIGURATION
* ============================================
*/
{
files: [
"**/*.test.{js,jsx}",
"**/*.test.data.{js,jsx}",
"**/*.test.page.{js,jsx}",
"**/*.test.page.object.{js,jsx}",
"**/*.test.stories.{js,jsx}",
"**/*.spec.{js,jsx}",
"**/__tests__/**",
"**/test/mock/**",
],
languageOptions: {
globals: {
...globals.jest,
},
},
plugins: {
jest: jestPlugin,
},
rules: {
...jestPlugin.configs["flat/recommended"].rules,
// Test-specific overrides
"no-console": "off", // Allow console in tests
"import/no-extraneous-dependencies": "off", // Dev deps OK in tests
"n/no-unpublished-import": "off", // Dev deps OK in tests
"n/no-unpublished-require": "off",
"n/no-extraneous-import": "off",
"jest/prefer-expect-assertions": "off", // Not always needed
"security/detect-non-literal-fs-filename": "off",
// Forbid explicit imports of Jest globals (they are injected automatically)
"no-restricted-imports": [
"error",
{
paths: [
{
name: "expect",
message: "Use Jest's global `expect` instead.",
},
{
name: "jest",
message: "Use Jest's global `jest` instead.",
},
],
patterns: [
{
group: ["@jest/globals"],
message: "Use Jest's injected globals instead of importing from '@jest/globals'.",
},
],
},
],
// Rules muted during migration
"jest/no-conditional-expect": "off",
"jest/valid-title": "off",
"jest/no-alias-methods": "off",
"jest/no-export": "off",
"jest/valid-expect": "off",
"jest/no-identical-title": "off",
"jest/expect-expect": "off",
"jest/valid-expect-in-promise": "off",
"jest/no-disabled-tests": "off",
"jest/valid-describe-callback": "off",
"jest/no-focused-tests": "off",
"jest/no-standalone-expect": "off",
},
},
/*
* ============================================
* BUILD/CONFIG FILES
* ============================================
*/
{
files: ["*.config.{js,mjs,cjs}", "scripts/**/*.js", "webpack.config.js"],
languageOptions: {
globals: {
...globals.node,
},
},
rules: {
"no-console": "off", // Allow console in scripts
"import/no-extraneous-dependencies": "off", // Dev deps OK in configs
"n/no-unpublished-import": "off",
},
},
];