mirror of
https://github.com/glitch-soc/mastodon
synced 2025-04-24 15:24:51 +00:00
Upgrade to ESLint v9 flat config (#34324)
Co-authored-by: Nick Schonning <nschonni@gmail.com>
This commit is contained in:
parent
9686ae7060
commit
e8270e2807
21 changed files with 1011 additions and 874 deletions
|
@ -1,13 +0,0 @@
|
|||
/build/**
|
||||
/coverage/**
|
||||
/db/**
|
||||
/lib/**
|
||||
/log/**
|
||||
/node_modules/**
|
||||
/nonobox/**
|
||||
/public/**
|
||||
!/public/embed.js
|
||||
/spec/**
|
||||
/tmp/**
|
||||
/vendor/**
|
||||
!.eslintrc.js
|
367
.eslintrc.js
367
.eslintrc.js
|
@ -1,367 +0,0 @@
|
|||
// @ts-check
|
||||
const { defineConfig } = require('eslint-define-config');
|
||||
|
||||
module.exports = defineConfig({
|
||||
root: true,
|
||||
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:react/recommended',
|
||||
'plugin:react-hooks/recommended',
|
||||
'plugin:jsx-a11y/recommended',
|
||||
'plugin:import/recommended',
|
||||
'plugin:promise/recommended',
|
||||
'plugin:jsdoc/recommended',
|
||||
],
|
||||
|
||||
env: {
|
||||
browser: true,
|
||||
node: true,
|
||||
es6: true,
|
||||
},
|
||||
|
||||
parser: '@typescript-eslint/parser',
|
||||
|
||||
plugins: [
|
||||
'react',
|
||||
'jsx-a11y',
|
||||
'import',
|
||||
'promise',
|
||||
'@typescript-eslint',
|
||||
'formatjs',
|
||||
],
|
||||
|
||||
parserOptions: {
|
||||
sourceType: 'module',
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
},
|
||||
ecmaVersion: 2021,
|
||||
requireConfigFile: false,
|
||||
babelOptions: {
|
||||
configFile: false,
|
||||
presets: ['@babel/react', '@babel/env'],
|
||||
},
|
||||
},
|
||||
|
||||
settings: {
|
||||
react: {
|
||||
version: 'detect',
|
||||
},
|
||||
'import/ignore': [
|
||||
'node_modules',
|
||||
'\\.(css|scss|json)$',
|
||||
],
|
||||
'import/resolver': {
|
||||
typescript: {},
|
||||
},
|
||||
},
|
||||
|
||||
rules: {
|
||||
'consistent-return': 'error',
|
||||
'dot-notation': 'error',
|
||||
eqeqeq: ['error', 'always', { 'null': 'ignore' }],
|
||||
'indent': ['error', 2],
|
||||
'jsx-quotes': ['error', 'prefer-single'],
|
||||
'semi': ['error', 'always'],
|
||||
'no-catch-shadow': 'error',
|
||||
'no-console': [
|
||||
'warn',
|
||||
{
|
||||
allow: [
|
||||
'error',
|
||||
'warn',
|
||||
],
|
||||
},
|
||||
],
|
||||
'no-empty': ['error', { "allowEmptyCatch": true }],
|
||||
'no-restricted-properties': [
|
||||
'error',
|
||||
{ property: 'substring', message: 'Use .slice instead of .substring.' },
|
||||
{ property: 'substr', message: 'Use .slice instead of .substr.' },
|
||||
],
|
||||
'no-restricted-syntax': [
|
||||
'error',
|
||||
{
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
selector: 'Literal[value=/•/], JSXText[value=/•/]',
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
message: "Use '·' (middle dot) instead of '•' (bullet)",
|
||||
},
|
||||
],
|
||||
'no-unused-expressions': 'error',
|
||||
'no-unused-vars': 'off',
|
||||
'@typescript-eslint/no-unused-vars': [
|
||||
'error',
|
||||
{
|
||||
vars: 'all',
|
||||
args: 'after-used',
|
||||
destructuredArrayIgnorePattern: '^_',
|
||||
ignoreRestSiblings: true,
|
||||
},
|
||||
],
|
||||
'valid-typeof': 'error',
|
||||
|
||||
'react/jsx-filename-extension': ['error', { extensions: ['.jsx', 'tsx'] }],
|
||||
'react/jsx-boolean-value': 'error',
|
||||
'react/display-name': 'off',
|
||||
'react/jsx-fragments': ['error', 'syntax'],
|
||||
'react/jsx-equals-spacing': 'error',
|
||||
'react/jsx-no-bind': 'error',
|
||||
'react/jsx-no-useless-fragment': 'error',
|
||||
'react/jsx-no-target-blank': ['error', { allowReferrer: true }],
|
||||
'react/jsx-tag-spacing': 'error',
|
||||
'react/jsx-uses-react': 'off', // not needed with new JSX transform
|
||||
'react/jsx-wrap-multilines': 'error',
|
||||
'react/react-in-jsx-scope': 'off', // not needed with new JSX transform
|
||||
'react/self-closing-comp': 'error',
|
||||
|
||||
// recommended values found in https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/v6.8.0/src/index.js#L46
|
||||
'jsx-a11y/click-events-have-key-events': 'off',
|
||||
'jsx-a11y/label-has-associated-control': 'off',
|
||||
'jsx-a11y/media-has-caption': 'off',
|
||||
'jsx-a11y/no-autofocus': 'off',
|
||||
// recommended rule is:
|
||||
// 'jsx-a11y/no-interactive-element-to-noninteractive-role': [
|
||||
// 'error',
|
||||
// {
|
||||
// tr: ['none', 'presentation'],
|
||||
// canvas: ['img'],
|
||||
// },
|
||||
// ],
|
||||
'jsx-a11y/no-interactive-element-to-noninteractive-role': 'off',
|
||||
// recommended rule is:
|
||||
// 'jsx-a11y/no-noninteractive-tabindex': [
|
||||
// 'error',
|
||||
// {
|
||||
// tags: [],
|
||||
// roles: ['tabpanel'],
|
||||
// allowExpressionValues: true,
|
||||
// },
|
||||
// ],
|
||||
'jsx-a11y/no-noninteractive-tabindex': 'off',
|
||||
// recommended is full 'error'
|
||||
'jsx-a11y/no-static-element-interactions': [
|
||||
'warn',
|
||||
{
|
||||
handlers: [
|
||||
'onClick',
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
// See https://github.com/import-js/eslint-plugin-import/blob/v2.29.1/config/recommended.js
|
||||
'import/extensions': [
|
||||
'error',
|
||||
'always',
|
||||
{
|
||||
js: 'never',
|
||||
jsx: 'never',
|
||||
mjs: 'never',
|
||||
ts: 'never',
|
||||
tsx: 'never',
|
||||
},
|
||||
],
|
||||
'import/first': 'error',
|
||||
'import/newline-after-import': 'error',
|
||||
'import/no-anonymous-default-export': 'error',
|
||||
'import/no-extraneous-dependencies': [
|
||||
'error',
|
||||
{
|
||||
devDependencies: [
|
||||
'.eslintrc.js',
|
||||
'config/webpack/**',
|
||||
'app/javascript/mastodon/performance.js',
|
||||
'app/javascript/mastodon/test_setup.js',
|
||||
'app/javascript/**/__tests__/**',
|
||||
],
|
||||
},
|
||||
],
|
||||
'import/no-amd': 'error',
|
||||
'import/no-commonjs': 'error',
|
||||
'import/no-import-module-exports': 'error',
|
||||
'import/no-relative-packages': 'error',
|
||||
'import/no-self-import': 'error',
|
||||
'import/no-useless-path-segments': 'error',
|
||||
'import/no-webpack-loader-syntax': 'error',
|
||||
|
||||
'import/order': [
|
||||
'error',
|
||||
{
|
||||
alphabetize: { order: 'asc' },
|
||||
'newlines-between': 'always',
|
||||
groups: [
|
||||
'builtin',
|
||||
'external',
|
||||
'internal',
|
||||
'parent',
|
||||
['index', 'sibling'],
|
||||
'object',
|
||||
],
|
||||
pathGroups: [
|
||||
// React core packages
|
||||
{
|
||||
pattern: '{react,react-dom,react-dom/client,prop-types}',
|
||||
group: 'builtin',
|
||||
position: 'after',
|
||||
},
|
||||
// I18n
|
||||
{
|
||||
pattern: '{react-intl,intl-messageformat}',
|
||||
group: 'builtin',
|
||||
position: 'after',
|
||||
},
|
||||
// Common React utilities
|
||||
{
|
||||
pattern: '{classnames,react-helmet,react-router,react-router-dom}',
|
||||
group: 'external',
|
||||
position: 'before',
|
||||
},
|
||||
// Immutable / Redux / data store
|
||||
{
|
||||
pattern: '{immutable,@reduxjs/toolkit,react-redux,react-immutable-proptypes,react-immutable-pure-component}',
|
||||
group: 'external',
|
||||
position: 'before',
|
||||
},
|
||||
// Internal packages
|
||||
{
|
||||
pattern: '{mastodon/**}',
|
||||
group: 'internal',
|
||||
position: 'after',
|
||||
},
|
||||
],
|
||||
pathGroupsExcludedImportTypes: [],
|
||||
},
|
||||
],
|
||||
|
||||
'promise/always-return': 'off',
|
||||
'promise/catch-or-return': [
|
||||
'error',
|
||||
{
|
||||
allowFinally: true,
|
||||
},
|
||||
],
|
||||
'promise/no-callback-in-promise': 'off',
|
||||
'promise/no-nesting': 'off',
|
||||
'promise/no-promise-in-callback': 'off',
|
||||
|
||||
'formatjs/blocklist-elements': 'error',
|
||||
'formatjs/enforce-default-message': ['error', 'literal'],
|
||||
'formatjs/enforce-description': 'off', // description values not currently used
|
||||
'formatjs/enforce-id': 'off', // Explicit IDs are used in the project
|
||||
'formatjs/enforce-placeholders': 'off', // Issues in short_number.jsx
|
||||
'formatjs/enforce-plural-rules': 'error',
|
||||
'formatjs/no-camel-case': 'off', // disabledAccount is only non-conforming
|
||||
'formatjs/no-complex-selectors': 'error',
|
||||
'formatjs/no-emoji': 'error',
|
||||
'formatjs/no-id': 'off', // IDs are used for translation keys
|
||||
'formatjs/no-invalid-icu': 'error',
|
||||
'formatjs/no-literal-string-in-jsx': 'off', // Should be looked at, but mainly flagging punctuation outside of strings
|
||||
'formatjs/no-multiple-whitespaces': 'error',
|
||||
'formatjs/no-offset': 'error',
|
||||
'formatjs/no-useless-message': 'error',
|
||||
'formatjs/prefer-formatted-message': 'error',
|
||||
'formatjs/prefer-pound-in-plural': 'error',
|
||||
|
||||
'jsdoc/check-types': 'off',
|
||||
'jsdoc/no-undefined-types': 'off',
|
||||
'jsdoc/require-jsdoc': 'off',
|
||||
'jsdoc/require-param-description': 'off',
|
||||
'jsdoc/require-property-description': 'off',
|
||||
'jsdoc/require-returns-description': 'off',
|
||||
'jsdoc/require-returns': 'off',
|
||||
},
|
||||
|
||||
overrides: [
|
||||
{
|
||||
files: [
|
||||
'.eslintrc.js',
|
||||
'*.config.js',
|
||||
'.*rc.js',
|
||||
'ide-helper.js',
|
||||
'config/webpack/**/*',
|
||||
'config/formatjs-formatter.js',
|
||||
],
|
||||
|
||||
env: {
|
||||
commonjs: true,
|
||||
},
|
||||
|
||||
parserOptions: {
|
||||
sourceType: 'script',
|
||||
},
|
||||
|
||||
rules: {
|
||||
'import/no-commonjs': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: [
|
||||
'**/*.ts',
|
||||
'**/*.tsx',
|
||||
],
|
||||
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/strict-type-checked',
|
||||
'plugin:@typescript-eslint/stylistic-type-checked',
|
||||
'plugin:react/recommended',
|
||||
'plugin:react-hooks/recommended',
|
||||
'plugin:jsx-a11y/recommended',
|
||||
'plugin:import/recommended',
|
||||
'plugin:import/typescript',
|
||||
'plugin:promise/recommended',
|
||||
'plugin:jsdoc/recommended-typescript',
|
||||
],
|
||||
|
||||
parserOptions: {
|
||||
projectService: true,
|
||||
tsconfigRootDir: __dirname,
|
||||
},
|
||||
|
||||
rules: {
|
||||
// Disable formatting rules that have been enabled in the base config
|
||||
'indent': 'off',
|
||||
|
||||
// This is not needed as we use noImplicitReturns, which handles this in addition to understanding types
|
||||
'consistent-return': 'off',
|
||||
|
||||
'import/consistent-type-specifier-style': ['error', 'prefer-top-level'],
|
||||
|
||||
'@typescript-eslint/consistent-type-definitions': ['warn', 'interface'],
|
||||
'@typescript-eslint/consistent-type-exports': 'error',
|
||||
'@typescript-eslint/consistent-type-imports': 'error',
|
||||
"@typescript-eslint/prefer-nullish-coalescing": ['error', { ignorePrimitives: { boolean: true } }],
|
||||
"@typescript-eslint/no-restricted-imports": [
|
||||
"warn",
|
||||
{
|
||||
"name": "react-redux",
|
||||
"importNames": ["useSelector", "useDispatch"],
|
||||
"message": "Use typed hooks `useAppDispatch` and `useAppSelector` instead."
|
||||
}
|
||||
],
|
||||
"@typescript-eslint/restrict-template-expressions": ['warn', { allowNumber: true }],
|
||||
'jsdoc/require-jsdoc': 'off',
|
||||
|
||||
// Those rules set stricter rules for TS files
|
||||
// to enforce better practices when converting from JS
|
||||
'import/no-default-export': 'warn',
|
||||
'react/prefer-stateless-function': 'warn',
|
||||
'react/function-component-definition': ['error', { namedComponents: 'arrow-function' }],
|
||||
'react/jsx-uses-react': 'off', // not needed with new JSX transform
|
||||
'react/react-in-jsx-scope': 'off', // not needed with new JSX transform
|
||||
'react/prop-types': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: [
|
||||
'**/__tests__/*.js',
|
||||
'**/__tests__/*.jsx',
|
||||
],
|
||||
|
||||
env: {
|
||||
jest: true,
|
||||
},
|
||||
}
|
||||
],
|
||||
});
|
8
.github/renovate.json5
vendored
8
.github/renovate.json5
vendored
|
@ -97,7 +97,13 @@
|
|||
{
|
||||
// Group all eslint-related packages with `eslint` in the same PR
|
||||
matchManagers: ['npm'],
|
||||
matchPackageNames: ['eslint', 'eslint-*', '@typescript-eslint/*'],
|
||||
matchPackageNames: [
|
||||
'eslint',
|
||||
'eslint-*',
|
||||
'typescript-eslint',
|
||||
'@eslint/*',
|
||||
'globals',
|
||||
],
|
||||
matchUpdateTypes: ['patch', 'minor'],
|
||||
groupName: 'eslint (non-major)',
|
||||
},
|
||||
|
|
6
.github/workflows/lint-js.yml
vendored
6
.github/workflows/lint-js.yml
vendored
|
@ -11,7 +11,7 @@ on:
|
|||
- 'tsconfig.json'
|
||||
- '.nvmrc'
|
||||
- '.prettier*'
|
||||
- '.eslint*'
|
||||
- 'eslint.config.mjs'
|
||||
- '**/*.js'
|
||||
- '**/*.jsx'
|
||||
- '**/*.ts'
|
||||
|
@ -25,7 +25,7 @@ on:
|
|||
- 'tsconfig.json'
|
||||
- '.nvmrc'
|
||||
- '.prettier*'
|
||||
- '.eslint*'
|
||||
- 'eslint.config.mjs'
|
||||
- '**/*.js'
|
||||
- '**/*.jsx'
|
||||
- '**/*.ts'
|
||||
|
@ -44,7 +44,7 @@ jobs:
|
|||
uses: ./.github/actions/setup-javascript
|
||||
|
||||
- name: ESLint
|
||||
run: yarn lint:js --max-warnings 0
|
||||
run: yarn workspaces foreach --all --parallel run lint:js --max-warnings 0
|
||||
|
||||
- name: Typecheck
|
||||
run: yarn typecheck
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
module.exports = {
|
||||
singleQuote: true,
|
||||
jsxSingleQuote: true
|
||||
}
|
||||
};
|
||||
|
|
|
@ -68,7 +68,7 @@ function loaded() {
|
|||
|
||||
if (id) message = localeData[id];
|
||||
|
||||
if (!message) message = defaultMessage as string;
|
||||
message ??= defaultMessage as string;
|
||||
|
||||
const messageFormat = new IntlMessageFormat(message, locale);
|
||||
return messageFormat.format(values) as string;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import React from 'react';
|
||||
import type React from 'react';
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import type { PropsWithChildren } from 'react';
|
||||
import React from 'react';
|
||||
import type React from 'react';
|
||||
|
||||
import { Router as OriginalRouter, useHistory } from 'react-router';
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* eslint-disable import/no-commonjs --
|
||||
We need to use CommonJS here due to preval */
|
||||
// @preval
|
||||
// http://www.unicode.org/Public/emoji/5.0/emoji-test.txt
|
||||
// This file contains the compressed version of the emoji data from
|
||||
|
|
|
@ -33,11 +33,8 @@ function processEmojiMapData(
|
|||
shortCode?: ShortCodesToEmojiDataKey,
|
||||
) {
|
||||
const [native, _filename] = emojiMapData;
|
||||
let filename = emojiMapData[1];
|
||||
if (!filename) {
|
||||
// filename name can be derived from unicodeToFilename
|
||||
filename = unicodeToFilename(native);
|
||||
}
|
||||
const filename = emojiMapData[1] ?? unicodeToFilename(native);
|
||||
unicodeMapping[native] = {
|
||||
shortCode,
|
||||
filename,
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
/* eslint-disable import/no-commonjs --
|
||||
We need to use CommonJS here as its imported into a preval file (`emoji_compressed.js`) */
|
||||
|
||||
// taken from:
|
||||
// https://github.com/twitter/twemoji/blob/47732c7/twemoji-generator.js#L848-L866
|
||||
exports.unicodeToFilename = (str) => {
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
/* eslint-disable import/no-commonjs --
|
||||
We need to use CommonJS here as its imported into a preval file (`emoji_compressed.js`) */
|
||||
|
||||
function padLeft(str, num) {
|
||||
while (str.length < num) {
|
||||
str = '0' + str;
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
/* eslint-disable import/no-commonjs --
|
||||
We need to use CommonJS here as its imported into a preval file (`emoji_compressed.js`) */
|
||||
|
||||
/* @preval */
|
||||
|
||||
const fs = require('fs');
|
||||
|
|
395
eslint.config.mjs
Normal file
395
eslint.config.mjs
Normal file
|
@ -0,0 +1,395 @@
|
|||
// @ts-check
|
||||
|
||||
import js from '@eslint/js';
|
||||
import { globalIgnores } from 'eslint/config';
|
||||
import formatjs from 'eslint-plugin-formatjs';
|
||||
// @ts-expect-error -- No typings
|
||||
import importPlugin from 'eslint-plugin-import';
|
||||
import jsdoc from 'eslint-plugin-jsdoc';
|
||||
import jsxA11Y from 'eslint-plugin-jsx-a11y';
|
||||
import promisePlugin from 'eslint-plugin-promise';
|
||||
import react from 'eslint-plugin-react';
|
||||
import reactHooks from 'eslint-plugin-react-hooks';
|
||||
import globals from 'globals';
|
||||
import tseslint from 'typescript-eslint';
|
||||
|
||||
/** @type {import('typescript-eslint').ConfigArray} */
|
||||
export const baseConfig = [
|
||||
js.configs.recommended,
|
||||
importPlugin.flatConfigs.recommended,
|
||||
jsdoc.configs['flat/recommended'],
|
||||
promisePlugin.configs['flat/recommended'],
|
||||
{
|
||||
linterOptions: {
|
||||
reportUnusedDisableDirectives: 'error',
|
||||
reportUnusedInlineConfigs: 'error',
|
||||
},
|
||||
rules: {
|
||||
'consistent-return': 'error',
|
||||
'dot-notation': 'error',
|
||||
|
||||
eqeqeq: [
|
||||
'error',
|
||||
'always',
|
||||
{
|
||||
null: 'ignore',
|
||||
},
|
||||
],
|
||||
|
||||
'no-console': [
|
||||
'warn',
|
||||
{
|
||||
allow: ['error', 'warn'],
|
||||
},
|
||||
],
|
||||
|
||||
'no-empty': [
|
||||
'error',
|
||||
{
|
||||
allowEmptyCatch: true,
|
||||
},
|
||||
],
|
||||
|
||||
'no-restricted-properties': [
|
||||
'error',
|
||||
{
|
||||
property: 'substring',
|
||||
message: 'Use .slice instead of .substring.',
|
||||
},
|
||||
{
|
||||
property: 'substr',
|
||||
message: 'Use .slice instead of .substr.',
|
||||
},
|
||||
],
|
||||
|
||||
'no-unused-expressions': 'error',
|
||||
'no-unused-vars': 'off',
|
||||
|
||||
'valid-typeof': 'error',
|
||||
|
||||
'import/extensions': [
|
||||
'error',
|
||||
'always',
|
||||
{
|
||||
js: 'never',
|
||||
jsx: 'never',
|
||||
mjs: 'never',
|
||||
ts: 'never',
|
||||
mts: 'never',
|
||||
tsx: 'never',
|
||||
},
|
||||
],
|
||||
'import/first': 'error',
|
||||
'import/newline-after-import': 'error',
|
||||
'import/no-anonymous-default-export': 'error',
|
||||
'import/no-amd': 'error',
|
||||
'import/no-commonjs': 'error',
|
||||
'import/no-import-module-exports': 'error',
|
||||
'import/no-relative-packages': 'error',
|
||||
'import/no-self-import': 'error',
|
||||
'import/no-useless-path-segments': 'error',
|
||||
'import/order': [
|
||||
'error',
|
||||
{
|
||||
alphabetize: {
|
||||
order: 'asc',
|
||||
},
|
||||
|
||||
'newlines-between': 'always',
|
||||
|
||||
groups: [
|
||||
'builtin',
|
||||
'external',
|
||||
'internal',
|
||||
'parent',
|
||||
['index', 'sibling'],
|
||||
'object',
|
||||
],
|
||||
|
||||
pathGroups: [
|
||||
{
|
||||
pattern: '{react,react-dom,react-dom/client,prop-types}',
|
||||
group: 'builtin',
|
||||
position: 'after',
|
||||
},
|
||||
{
|
||||
pattern: '{react-intl,intl-messageformat}',
|
||||
group: 'builtin',
|
||||
position: 'after',
|
||||
},
|
||||
{
|
||||
pattern:
|
||||
'{classnames,react-helmet,react-router,react-router-dom}',
|
||||
group: 'external',
|
||||
position: 'before',
|
||||
},
|
||||
{
|
||||
pattern:
|
||||
'{immutable,@reduxjs/toolkit,react-redux,react-immutable-proptypes,react-immutable-pure-component}',
|
||||
group: 'external',
|
||||
position: 'before',
|
||||
},
|
||||
{
|
||||
pattern: '{mastodon/**}',
|
||||
group: 'internal',
|
||||
position: 'after',
|
||||
},
|
||||
],
|
||||
|
||||
pathGroupsExcludedImportTypes: [],
|
||||
},
|
||||
],
|
||||
|
||||
'jsdoc/check-types': 'off',
|
||||
'jsdoc/no-undefined-types': 'off',
|
||||
'jsdoc/require-jsdoc': 'off',
|
||||
'jsdoc/require-param-description': 'off',
|
||||
'jsdoc/require-property-description': 'off',
|
||||
'jsdoc/require-returns-description': 'off',
|
||||
'jsdoc/require-returns': 'off',
|
||||
|
||||
'promise/always-return': 'off',
|
||||
'promise/catch-or-return': [
|
||||
'error',
|
||||
{
|
||||
allowFinally: true,
|
||||
},
|
||||
],
|
||||
'promise/no-callback-in-promise': 'off',
|
||||
'promise/no-nesting': 'off',
|
||||
'promise/no-promise-in-callback': 'off',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export default tseslint.config([
|
||||
baseConfig,
|
||||
globalIgnores([
|
||||
'build/**/*',
|
||||
'coverage/**/*',
|
||||
'db/**/*',
|
||||
'lib/**/*',
|
||||
'log/**/*',
|
||||
'node_modules/**/*',
|
||||
'public/**/*',
|
||||
'!public/embed.js',
|
||||
'spec/**/*',
|
||||
'tmp/**/*',
|
||||
'vendor/**/*',
|
||||
'streaming/**/*',
|
||||
]),
|
||||
react.configs.flat.recommended,
|
||||
react.configs.flat['jsx-runtime'],
|
||||
reactHooks.configs['recommended-latest'],
|
||||
jsxA11Y.flatConfigs.recommended,
|
||||
importPlugin.flatConfigs.react,
|
||||
// @ts-expect-error -- For some reason the formatjs package exports an empty object?
|
||||
formatjs.configs.strict,
|
||||
{
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.browser,
|
||||
},
|
||||
|
||||
parser: tseslint.parser,
|
||||
ecmaVersion: 2021,
|
||||
sourceType: 'module',
|
||||
},
|
||||
|
||||
settings: {
|
||||
react: {
|
||||
version: 'detect',
|
||||
},
|
||||
|
||||
'import/ignore': ['node_modules', '\\.(css|scss|json)$'],
|
||||
|
||||
'import/resolver': {
|
||||
typescript: {},
|
||||
},
|
||||
},
|
||||
|
||||
rules: {
|
||||
'no-restricted-syntax': [
|
||||
'error',
|
||||
{
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
selector: 'Literal[value=/•/], JSXText[value=/•/]',
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
message: "Use '·' (middle dot) instead of '•' (bullet)",
|
||||
},
|
||||
],
|
||||
|
||||
'formatjs/enforce-description': 'off', // description values not currently used
|
||||
'formatjs/enforce-id': 'off', // Explicit IDs are used in the project
|
||||
'formatjs/enforce-placeholders': 'off', // Issues in short_number.jsx
|
||||
'formatjs/no-invalid-icu': 'error',
|
||||
'formatjs/no-literal-string-in-jsx': 'off', // Should be looked at, but mainly flagging punctuation outside of strings
|
||||
'formatjs/no-multiple-plurals': 'off', // Should be looked at
|
||||
|
||||
'jsx-a11y/click-events-have-key-events': 'off',
|
||||
'jsx-a11y/label-has-associated-control': 'off',
|
||||
'jsx-a11y/media-has-caption': 'off',
|
||||
'jsx-a11y/no-autofocus': 'off',
|
||||
'jsx-a11y/no-interactive-element-to-noninteractive-role': 'off',
|
||||
'jsx-a11y/no-noninteractive-tabindex': 'off',
|
||||
'jsx-a11y/no-static-element-interactions': [
|
||||
'warn',
|
||||
{
|
||||
handlers: ['onClick'],
|
||||
},
|
||||
],
|
||||
|
||||
'import/no-extraneous-dependencies': [
|
||||
'error',
|
||||
{
|
||||
devDependencies: [
|
||||
'eslint.config.mjs',
|
||||
'config/webpack/**',
|
||||
'app/javascript/mastodon/performance.js',
|
||||
'app/javascript/mastodon/test_setup.js',
|
||||
'app/javascript/**/__tests__/**',
|
||||
],
|
||||
},
|
||||
],
|
||||
'import/no-webpack-loader-syntax': 'error',
|
||||
|
||||
'react/jsx-filename-extension': [
|
||||
'error',
|
||||
{
|
||||
extensions: ['.jsx', 'tsx'],
|
||||
},
|
||||
],
|
||||
|
||||
'react/jsx-boolean-value': 'error',
|
||||
'react/display-name': 'off',
|
||||
'react/jsx-fragments': ['error', 'syntax'],
|
||||
'react/jsx-equals-spacing': 'error',
|
||||
'react/jsx-no-bind': 'error',
|
||||
'react/jsx-no-useless-fragment': 'error',
|
||||
'react/jsx-no-target-blank': [
|
||||
'error',
|
||||
{
|
||||
allowReferrer: true,
|
||||
},
|
||||
],
|
||||
'react/jsx-tag-spacing': 'error',
|
||||
'react/jsx-wrap-multilines': 'error',
|
||||
'react/self-closing-comp': 'error',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: [
|
||||
'app/javascript/mastodon/common.js',
|
||||
'app/javascript/mastodon/features/emoji/unicode_to_unified_name.js',
|
||||
'app/javascript/mastodon/features/emoji/emoji_compressed.js',
|
||||
'app/javascript/mastodon/features/emoji/unicode_to_filename.js',
|
||||
'app/javascript/mastodon/service_worker/web_push_locales.js',
|
||||
'**/*.config.js',
|
||||
'**/.*rc.js',
|
||||
'**/ide-helper.js',
|
||||
'config/webpack/**/*',
|
||||
'config/formatjs-formatter.js',
|
||||
],
|
||||
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.commonjs,
|
||||
...globals.node,
|
||||
},
|
||||
|
||||
ecmaVersion: 5,
|
||||
sourceType: 'commonjs',
|
||||
},
|
||||
|
||||
rules: {
|
||||
'import/no-commonjs': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.ts', '**/*.tsx'],
|
||||
|
||||
extends: [
|
||||
tseslint.configs.strictTypeChecked,
|
||||
tseslint.configs.stylisticTypeChecked,
|
||||
react.configs.flat.recommended,
|
||||
react.configs.flat['jsx-runtime'],
|
||||
reactHooks.configs['recommended-latest'],
|
||||
jsxA11Y.flatConfigs.recommended,
|
||||
importPlugin.flatConfigs.react,
|
||||
importPlugin.flatConfigs.typescript,
|
||||
jsdoc.configs['flat/recommended-typescript'],
|
||||
],
|
||||
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
projectService: true,
|
||||
},
|
||||
},
|
||||
|
||||
rules: {
|
||||
// This is not needed as we use noImplicitReturns, which handles this in addition to understanding types
|
||||
'consistent-return': 'off',
|
||||
|
||||
'formatjs/enforce-plural-rules': 'off',
|
||||
|
||||
'import/consistent-type-specifier-style': ['error', 'prefer-top-level'],
|
||||
'import/no-default-export': 'warn',
|
||||
|
||||
'jsdoc/require-jsdoc': 'off',
|
||||
|
||||
'react/prefer-stateless-function': 'warn',
|
||||
'react/function-component-definition': [
|
||||
'error',
|
||||
{
|
||||
namedComponents: 'arrow-function',
|
||||
},
|
||||
],
|
||||
'react/prop-types': 'off',
|
||||
|
||||
'@typescript-eslint/consistent-type-definitions': ['warn', 'interface'],
|
||||
'@typescript-eslint/consistent-type-exports': 'error',
|
||||
'@typescript-eslint/consistent-type-imports': 'error',
|
||||
'@typescript-eslint/prefer-nullish-coalescing': [
|
||||
'error',
|
||||
{
|
||||
ignorePrimitives: {
|
||||
boolean: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/no-restricted-imports': [
|
||||
'warn',
|
||||
{
|
||||
name: 'react-redux',
|
||||
importNames: ['useSelector', 'useDispatch'],
|
||||
message:
|
||||
'Use typed hooks `useAppDispatch` and `useAppSelector` instead.',
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/no-unused-vars': [
|
||||
'error',
|
||||
{
|
||||
vars: 'all',
|
||||
args: 'after-used',
|
||||
destructuredArrayIgnorePattern: '^_',
|
||||
ignoreRestSiblings: true,
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/restrict-template-expressions': [
|
||||
'warn',
|
||||
{
|
||||
allowNumber: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/__tests__/*.js', '**/__tests__/*.jsx'],
|
||||
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.jest,
|
||||
},
|
||||
},
|
||||
},
|
||||
]);
|
26
package.json
26
package.json
|
@ -12,14 +12,14 @@
|
|||
"scripts": {
|
||||
"build:development": "cross-env RAILS_ENV=development NODE_ENV=development ./bin/webpack",
|
||||
"build:production": "cross-env RAILS_ENV=production NODE_ENV=production ./bin/webpack",
|
||||
"fix:js": "eslint . --ext=.js,.jsx,.ts,.tsx --cache --report-unused-disable-directives --fix",
|
||||
"fix:js": "eslint . --cache --fix",
|
||||
"fix:css": "stylelint --fix \"**/*.{css,scss}\"",
|
||||
"fix": "yarn fix:js && yarn fix:css",
|
||||
"format": "prettier --write --log-level warn .",
|
||||
"format:check": "prettier --check --ignore-unknown .",
|
||||
"i18n:extract": "formatjs extract 'app/javascript/**/*.{js,jsx,ts,tsx}' --ignore '**/*.d.ts' --out-file app/javascript/mastodon/locales/en.json --format config/formatjs-formatter.js",
|
||||
"jest": "cross-env NODE_ENV=test jest",
|
||||
"lint:js": "eslint . --ext=.js,.jsx,.ts,.tsx --cache --report-unused-disable-directives",
|
||||
"lint:js": "cd $INIT_CWD && eslint --cache --report-unused-disable-directives",
|
||||
"lint:css": "stylelint \"**/*.{css,scss}\"",
|
||||
"lint": "yarn lint:js && yarn lint:css",
|
||||
"postversion": "git push --tags",
|
||||
|
@ -142,6 +142,7 @@
|
|||
"workbox-window": "^7.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.23.0",
|
||||
"@formatjs/cli": "^6.1.1",
|
||||
"@testing-library/dom": "^10.2.0",
|
||||
"@testing-library/jest-dom": "^6.0.0",
|
||||
|
@ -173,19 +174,17 @@
|
|||
"@types/requestidlecallback": "^0.3.5",
|
||||
"@types/webpack": "^4.41.33",
|
||||
"@types/webpack-env": "^1.18.4",
|
||||
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
||||
"@typescript-eslint/parser": "^8.0.0",
|
||||
"babel-jest": "^29.5.0",
|
||||
"eslint": "^8.41.0",
|
||||
"eslint-define-config": "^2.0.0",
|
||||
"eslint-import-resolver-typescript": "^3.5.5",
|
||||
"eslint-plugin-formatjs": "^5.0.0",
|
||||
"eslint": "^9.23.0",
|
||||
"eslint-import-resolver-typescript": "^4.2.5",
|
||||
"eslint-plugin-formatjs": "^5.3.1",
|
||||
"eslint-plugin-import": "~2.31.0",
|
||||
"eslint-plugin-jsdoc": "^50.0.0",
|
||||
"eslint-plugin-jsx-a11y": "~6.10.0",
|
||||
"eslint-plugin-promise": "~7.2.0",
|
||||
"eslint-plugin-react": "^7.33.2",
|
||||
"eslint-plugin-react-hooks": "^5.0.0",
|
||||
"eslint-plugin-jsdoc": "^50.6.9",
|
||||
"eslint-plugin-jsx-a11y": "~6.10.2",
|
||||
"eslint-plugin-promise": "~7.2.1",
|
||||
"eslint-plugin-react": "^7.37.4",
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"globals": "^16.0.0",
|
||||
"husky": "^9.0.11",
|
||||
"jest": "^29.5.0",
|
||||
"jest-environment-jsdom": "^29.5.0",
|
||||
|
@ -196,6 +195,7 @@
|
|||
"stylelint-config-prettier-scss": "^1.0.0",
|
||||
"stylelint-config-standard-scss": "^14.0.0",
|
||||
"typescript": "^5.0.4",
|
||||
"typescript-eslint": "^8.28.0",
|
||||
"webpack-dev-server": "^3.11.3"
|
||||
},
|
||||
"resolutions": {
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
/* eslint-disable import/no-commonjs */
|
||||
|
||||
// @ts-check
|
||||
|
||||
// @ts-ignore - This needs to be a CJS file (eslint does not yet support ESM configs), and TS is complaining we use require
|
||||
const { defineConfig } = require('eslint-define-config');
|
||||
|
||||
module.exports = defineConfig({
|
||||
extends: ['../.eslintrc.js'],
|
||||
env: {
|
||||
browser: false,
|
||||
},
|
||||
parserOptions: {
|
||||
project: true,
|
||||
tsconfigRootDir: __dirname,
|
||||
ecmaFeatures: {
|
||||
jsx: false,
|
||||
},
|
||||
ecmaVersion: 2021,
|
||||
},
|
||||
rules: {
|
||||
// In the streaming server we need to delete some variables to ensure
|
||||
// garbage collection takes place on the values referenced by those objects;
|
||||
// The alternative is to declare the variable as nullable, but then we need
|
||||
// to assert it's in existence before every use, which becomes much harder
|
||||
// to maintain.
|
||||
'no-delete-var': 'off',
|
||||
|
||||
// This overrides the base configuration for this rule to pick up
|
||||
// dependencies for the streaming server from the correct package.json file.
|
||||
'import/no-extraneous-dependencies': [
|
||||
'error',
|
||||
{
|
||||
devDependencies: ['streaming/.eslintrc.cjs'],
|
||||
optionalDependencies: false,
|
||||
peerDependencies: false,
|
||||
includeTypes: true,
|
||||
packageDir: __dirname,
|
||||
},
|
||||
],
|
||||
'import/extensions': ['error', 'always'],
|
||||
},
|
||||
});
|
45
streaming/eslint.config.mjs
Normal file
45
streaming/eslint.config.mjs
Normal file
|
@ -0,0 +1,45 @@
|
|||
// @ts-check
|
||||
|
||||
import globals from 'globals';
|
||||
import tseslint from 'typescript-eslint';
|
||||
|
||||
// eslint-disable-next-line import/no-relative-packages -- Must import from the root
|
||||
import { baseConfig } from '../eslint.config.mjs';
|
||||
|
||||
export default tseslint.config([
|
||||
baseConfig,
|
||||
{
|
||||
languageOptions: {
|
||||
globals: globals.node,
|
||||
|
||||
parser: tseslint.parser,
|
||||
ecmaVersion: 2021,
|
||||
sourceType: 'module',
|
||||
},
|
||||
|
||||
settings: {
|
||||
'import/ignore': ['node_modules', '\\.(json)$'],
|
||||
'import/resolver': {
|
||||
typescript: {},
|
||||
},
|
||||
},
|
||||
|
||||
rules: {
|
||||
// In the streaming server we need to delete some variables to ensure
|
||||
// garbage collection takes place on the values referenced by those objects;
|
||||
// The alternative is to declare the variable as nullable, but then we need
|
||||
// to assert it's in existence before every use, which becomes much harder
|
||||
// to maintain.
|
||||
'no-delete-var': 'off',
|
||||
|
||||
'import/no-extraneous-dependencies': [
|
||||
'error',
|
||||
{
|
||||
devDependencies: ['**/*.config.mjs'],
|
||||
},
|
||||
],
|
||||
|
||||
'import/extensions': ['error', 'always'],
|
||||
},
|
||||
},
|
||||
]);
|
7
streaming/lint-staged.config.mjs
Normal file
7
streaming/lint-staged.config.mjs
Normal file
|
@ -0,0 +1,7 @@
|
|||
const config = {
|
||||
'*': 'prettier --ignore-unknown --write',
|
||||
'*.{js,ts}': 'eslint --fix',
|
||||
'**/*.ts': () => 'tsc -p tsconfig.json --noEmit',
|
||||
};
|
||||
|
||||
export default config;
|
|
@ -31,14 +31,16 @@
|
|||
"ws": "^8.12.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.23.0",
|
||||
"@types/cors": "^2.8.16",
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/pg": "^8.6.6",
|
||||
"@types/uuid": "^10.0.0",
|
||||
"@types/ws": "^8.5.9",
|
||||
"eslint-define-config": "^2.0.0",
|
||||
"globals": "^16.0.0",
|
||||
"pino-pretty": "^13.0.0",
|
||||
"typescript": "^5.0.4"
|
||||
"typescript": "^5.0.4",
|
||||
"typescript-eslint": "^8.28.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"bufferutil": "^4.0.7",
|
||||
|
|
|
@ -8,5 +8,5 @@
|
|||
"tsBuildInfoFile": "../tmp/cache/streaming/tsconfig.tsbuildinfo",
|
||||
"paths": {}
|
||||
},
|
||||
"include": ["./*.js", "./.eslintrc.cjs"]
|
||||
"include": ["./*.js"]
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue