Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release #551

Merged
merged 4 commits into from
Sep 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "@fishbrain/eslint-config-monorepo",
"private": true,
"description": "ESLint configs for Fishbrain projects",
"version": "6.0.5",
"version": "6.0.6",
"workspaces": [
"packages/*"
],
Expand Down
176 changes: 2 additions & 174 deletions packages/base/eslint.config.js
Original file line number Diff line number Diff line change
@@ -1,175 +1,3 @@
// @ts-check
import { config } from './index.js';

import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
import jestPlugin from 'eslint-plugin-jest';
import prettierPlugin from 'eslint-plugin-prettier';

const HTTP_CODES = [200, 201, 204, 301, 302, 400, 401, 404, 422, 500];
const HTML_HEADER_LEVELS = [1, 2, 3, 4, 5, 6];
const COMMON_MATH_VALUES = [24, 60, 100];
const COMMON_INDEX_VALUES = [-1, 0, 1];
const ALLOWED_NUMBERS = Array.from(
new Set(
COMMON_INDEX_VALUES.concat(
HTTP_CODES,
HTML_HEADER_LEVELS,
COMMON_MATH_VALUES,
),
),
);

export default tseslint.config(
eslint.configs.recommended,
...tseslint.configs.strictTypeChecked,
...tseslint.configs.stylisticTypeChecked,
{
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
},
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
jestPlugin.configs['flat/recommended'],
{
plugins: { prettier: prettierPlugin },
rules: {
// Core rules replaced by Typescript rules
'no-use-before-define': 'off',
'consistent-return': 'off', // TypeScript takes care of checking return
// 'import/no-unresolved': 'off', // Doesn't work properly with TypeScript // TODO:
'no-extra-parens': 'off',

// Additional Fishbrain rules
'@typescript-eslint/await-thenable': 'error',
'@typescript-eslint/ban-ts-ignore': 'off',
// This rule required so many exceptions that it was getting difficult to maintain. So
// just name things sensibly :)
'@typescript-eslint/naming-convention': 'off',
'@typescript-eslint/explicit-member-accessibility': 'off',
'@typescript-eslint/interface-name-prefix': 'off',
// Noop functions are a common pattern we use during testing, so we don't want to enable it.
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/no-explicit-any': ['error', { fixToUnknown: true }],
'@typescript-eslint/no-extraneous-class': 'error',
'@typescript-eslint/no-floating-promises': 'error',
'@typescript-eslint/no-for-in-array': 'error',
'@typescript-eslint/no-inferrable-types': 'off',
'@typescript-eslint/no-unused-vars': [
'error',
{
ignoreRestSiblings: true,
varsIgnorePattern: '^_',
argsIgnorePattern: '^_',
},
],
'@typescript-eslint/no-useless-constructor': 'error',
'@typescript-eslint/promise-function-async': 'error',
'@typescript-eslint/triple-slash-reference': [
'error',
{ types: 'prefer-import' },
],
'@typescript-eslint/prefer-readonly': 'error',

// Warns if a type assertion does not change the type of an expression
// https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-unnecessary-type-assertion.md
'@typescript-eslint/no-unnecessary-type-assertion': 'error',

// Enforce includes method over indexOf method
// https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/prefer-includes.md
'@typescript-eslint/prefer-includes': 'error',

// Enforce the use of String#startsWith and String#endsWith instead of other equivalent methods of checking substrings
// https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/prefer-string-starts-ends-with.md
'@typescript-eslint/prefer-string-starts-ends-with': 'error',

curly: ['error', 'all'],

// 'fp/no-delete': 'error',
// 'fp/no-let': 'error',
// 'fp/no-loops': 'error',
// 'fp/no-mutating-assign': 'error',
// 'fp/no-mutation': [
// 'error',
// {
// allowThis: true,
// },
// ],
// TODO:
// 'import/named': 'off', // Redundant when used with Typescript.
// 'import/no-extraneous-dependencies': [
// 'error',
// {
// devDependencies: [
// '**/*.test.tsx',
// '**/*.test.ts',
// '**/testing.tsx',
// '**/*.stories.tsx',
// '**/*.stories.ts',
// '**/setupTests.ts',
// '**/webpack.config.{js,ts}', // webpack config
// '**/webpack.config.*.{js,ts}', // webpack config
// ],
// },
// ],
// 'import/order': [
// 'error',
// {
// 'newlines-between': 'always-and-inside-groups',
// groups: [
// ['builtin', 'external'],
// ['internal', 'sibling', 'parent', 'index'],
// ],
// },
// ],
// 'import/prefer-default-export': 'off',
// // Allow typescript imports, airbnb has disallowed it
// 'import/extensions': [
// 'error',
// 'ignorePackages',
// {
// js: 'never',
// jsx: 'never',
// ts: 'never',
// tsx: 'never',
// },
// ],
'max-lines': ['error', { max: 300, skipComments: true }],

// Disallow Magic Numbers
// https://eslint.org/docs/rules/no-magic-numbers
'no-magic-numbers': [
'error',
{ ignoreArrayIndexes: true, ignore: ALLOWED_NUMBERS },
],

// disallow the use of console
// https://eslint.org/docs/rules/no-console
'no-console': 'off',
'prettier/prettier': 'error',

// Disallow assignments that can lead to race conditions due to usage of await or yield
// https://eslint.org/docs/rules/require-atomic-updates
'require-atomic-updates': 'error',

// no export from test file
// https://github.com/jest-community/eslint-plugin-jest/blob/master/docs/rules/no-export.md
// 'jest/no-export': 'error',

// TODO: Below is the "recommended" rules from eslint-plugin-import
// analysis/correctness
// 'import/no-unresolved': 'error', // TODO: dupe
// 'import/named': 'error', // TODO: dupe
// 'import/namespace': 'error',
// 'import/default': 'error',
// 'import/export': 'error',

// // red flags (thus, warnings)
// 'import/no-named-as-default': 'off', // TODO: Should error, but it doesn't work with eslint9 just yet.
// 'import/no-named-as-default-member': 'off', // TODO: Should error, but it doesn't work with eslint9 just yet.
// 'import/no-duplicates': 'warn',
},
},
);
export default config;
140 changes: 138 additions & 2 deletions packages/base/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,139 @@
import _config from './eslint.config.js';
import jestPlugin from 'eslint-plugin-jest';
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
import prettierPlugin from 'eslint-plugin-prettier';

export const config = _config;
const HTTP_CODES = [200, 201, 204, 301, 302, 400, 401, 404, 422, 500];
const HTML_HEADER_LEVELS = [1, 2, 3, 4, 5, 6];
const COMMON_MATH_VALUES = [24, 60, 100];
const COMMON_INDEX_VALUES = [-1, 0, 1];
const ALLOWED_NUMBERS = Array.from(
new Set(
COMMON_INDEX_VALUES.concat(
HTTP_CODES,
HTML_HEADER_LEVELS,
COMMON_MATH_VALUES,
),
),
);

const baseConfig = [
eslint.configs.recommended,
...tseslint.configs.strictTypeChecked,
...tseslint.configs.stylisticTypeChecked,
{
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
},
{ plugins: { prettier: prettierPlugin } },
];

const customRules = {
rules: {
'@typescript-eslint/no-empty-function': 'off', // Noop functions are a common pattern we use during testing, so we don't want to enable it.
'@typescript-eslint/no-explicit-any': ['error', { fixToUnknown: true }],
'@typescript-eslint/no-unused-vars': [
'error',
{
ignoreRestSiblings: true,
varsIgnorePattern: '^_',
argsIgnorePattern: '^_',
},
],
'@typescript-eslint/promise-function-async': 'error',
'@typescript-eslint/restrict-template-expressions': [
'error',
{
allowAny: true,
allowNumber: true,
},
],
curly: ['error', 'all'],
'max-lines': ['error', { max: 300, skipComments: true }],
'no-magic-numbers': [
'error',
{ ignoreArrayIndexes: true, ignore: ALLOWED_NUMBERS },
],
'prettier/prettier': 'error',
'require-atomic-updates': 'error',

// 'fp/no-delete': 'error',
// 'fp/no-let': 'error',
// 'fp/no-loops': 'error',
// 'fp/no-mutating-assign': 'error',
// 'fp/no-mutation': [
// 'error',
// {
// allowThis: true,
// },
// ],
// TODO:
// 'import/named': 'off', // Redundant when used with Typescript.
// 'import/no-extraneous-dependencies': [
// 'error',
// {
// devDependencies: [
// '**/*.test.tsx',
// '**/*.test.ts',
// '**/testing.tsx',
// '**/*.stories.tsx',
// '**/*.stories.ts',
// '**/setupTests.ts',
// '**/webpack.config.{js,ts}', // webpack config
// '**/webpack.config.*.{js,ts}', // webpack config
// ],
// },
// ],
// 'import/order': [
// 'error',
// {
// 'newlines-between': 'always-and-inside-groups',
// groups: [
// ['builtin', 'external'],
// ['internal', 'sibling', 'parent', 'index'],
// ],
// },
// ],
// 'import/prefer-default-export': 'off',
// // Allow typescript imports, airbnb has disallowed it
// 'import/extensions': [
// 'error',
// 'ignorePackages',
// {
// js: 'never',
// jsx: 'never',
// ts: 'never',
// tsx: 'never',
// },
// ],

// no export from test file
// https://github.com/jest-community/eslint-plugin-jest/blob/master/docs/rules/no-export.md
// 'jest/no-export': 'error',

// TODO: Below is the "recommended" rules from eslint-plugin-import
// analysis/correctness
// 'import/no-unresolved': 'error', // TODO: dupe
// 'import/named': 'error', // TODO: dupe
// 'import/namespace': 'error',
// 'import/default': 'error',
// 'import/export': 'error',

// // red flags (thus, warnings)
// 'import/no-named-as-default': 'off', // TODO: Should error, but it doesn't work with eslint9 just yet.
// 'import/no-named-as-default-member': 'off', // TODO: Should error, but it doesn't work with eslint9 just yet.
// 'import/no-duplicates': 'warn',
},
};

export const configWithoutJest = tseslint.config(...baseConfig, customRules);
export const config = tseslint.config(
...baseConfig,
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
jestPlugin.configs['flat/recommended'],
customRules,
);
2 changes: 1 addition & 1 deletion packages/base/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@fishbrain/eslint-config-base",
"packageManager": "yarn@4.4.1",
"version": "6.0.5",
"version": "6.0.6",
"type": "module",
"exports": "./index.js",
"scripts": {
Expand Down
48 changes: 2 additions & 46 deletions packages/react/eslint.config.js
Original file line number Diff line number Diff line change
@@ -1,47 +1,3 @@
/* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-argument */
// @ts-check
import { config } from './index.js';

import tseslint from 'typescript-eslint';
import reactPlugin from 'eslint-plugin-react';
import jsxA11yPlugin from 'eslint-plugin-jsx-a11y';
import compatPlugin from 'eslint-plugin-compat';
import globals from 'globals';

import { config } from '@fishbrain/eslint-config-base';

export default tseslint.config(
...config,
{
...reactPlugin.configs.flat.recommended,
settings: { react: { version: 'detect' } },
languageOptions: {
...reactPlugin.configs.flat.recommended.languageOptions,
globals: {
...globals.browser,
},
},
},
jsxA11yPlugin.flatConfigs.recommended,
compatPlugin.configs['flat/recommended'],
{
rules: {
// 'jsx-a11y/label-has-for': 'off', // This is deprecated but in the recommended extension for some reason // TODO: Check if needed
'jsx-a11y/media-has-caption': 'off',
'jsx-a11y/no-onchange': 'off',
'no-alert': 'error',
'no-console': 'warn',
'react/jsx-filename-extension': [
'warn',
{ extensions: ['.tsx', '.jsx'] },
],
'react/jsx-max-props-per-line': ['warn', { when: 'multiline' }],
'react/no-render-return-value': 'off',
'react/prop-types': 'off', // No need for prop types with Typescript
'react/react-in-jsx-scope': 'off',

// TODO: Disabled until https://github.com/facebook/react/issues/28313 is resolved.
// 'react-hooks/exhaustive-deps': 'error',
// 'react-hooks/rules-of-hooks': 'error',
},
},
);
export default config;
Loading