diff --git a/.changeset/slimy-cows-lose.md b/.changeset/slimy-cows-lose.md new file mode 100644 index 000000000000..cb293484cac1 --- /dev/null +++ b/.changeset/slimy-cows-lose.md @@ -0,0 +1,5 @@ +--- +'@masknet/typed-message-react': minor +--- + +Require React.use now diff --git a/eslint.config.js b/eslint.config.js index f2dc078dd054..17fd1b25a8d0 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1,18 +1,19 @@ // cSpell:disable // @ts-check +import eslint from '@eslint/js' +import { defineConfig } from 'eslint/config' import tseslint from 'typescript-eslint' -import UnicornPlugin from 'eslint-plugin-unicorn' +import unicorn from 'eslint-plugin-unicorn' import UnusedImportsPlugin from 'eslint-plugin-unused-imports' +// @ts-expect-error import UnusedClassesPlugin from 'eslint-plugin-tss-unused-classes' -import ReactHooksPlugin from 'eslint-plugin-react-hooks' import ReactCompilerPlugin from 'eslint-plugin-react-compiler' import ImportPlugin from 'eslint-plugin-import-x' import ReactPlugin from '@eslint-react/eslint-plugin' import MasknetPlugin from '@masknet/eslint-plugin' -import ReactQueryPlugin from '@tanstack/eslint-plugin-query' -import LinguiPlugin from 'eslint-plugin-lingui' +import tanstackReactQuery from '@tanstack/eslint-plugin-query' +import lingui from 'eslint-plugin-lingui' import { createTypeScriptImportResolver } from 'eslint-import-resolver-typescript' -import { fixupPluginRules } from '@eslint/compat' const deferPackages = [ 'wallet.ts', @@ -31,23 +32,93 @@ const deferPackages = [ // if the fix needs big rewrite (e.g. XHR => fetch), use 'error' to notice the developer early. // for RegEx rules, always uses 'error'. +/** @type {Partial} */ +const disabledRules = { + // Not compatible + // with TypeScript + 'no-unused-vars': 'off', + 'unicorn/no-optional-chaining-on-undeclared-variable': 'off', + // TypeScript can do the check + 'unicorn/no-array-callback-reference': 'off', + 'unicorn/no-invalid-argument-count': 'off', + // false positives + 'unicorn/no-useless-coercion': 'off', + 'unicorn/prefer-spread': 'off', // TypedArrays + 'unicorn/require-number-to-fixed-digits-argument': 'off', // BigNumber + // WebExtension: in Firefox content scripts, window !== globalThis (instanceof SandBox). + 'unicorn/no-unnecessary-global-this': 'off', + 'unicorn/prefer-global-this': 'off', + // with Prettier + 'unicorn/number-literal-case': 'off', + + // bad practice + 'unicorn/prefer-top-level-await': 'off', // top-level await is bad for applications. scripts are ok. + + // too strict + '@typescript-eslint/no-deprecated': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-namespace': 'off', // namespace T {}, they won't support type only namespace + '@typescript-eslint/no-non-null-assertion': 'off', + 'lingui/no-expression-in-message': 'off', + 'unicorn/no-array-reduce': 'off', + 'unicorn/no-await-expression-member': 'off', + 'unicorn/no-break-in-nested-loop': 'off', + 'unicorn/no-computed-property-existence-check': 'off', + + // style, readibility and convention + 'unicorn/consistent-class-member-order': 'off', + 'unicorn/explicit-length-check': 'off', + 'unicorn/filename-case': 'off', + 'unicorn/import-style': 'off', + 'unicorn/max-nested-calls': 'off', + 'unicorn/no-for-each': 'off', + 'unicorn/no-nested-ternary': 'off', + 'unicorn/no-non-function-verb-prefix': 'off', + 'unicorn/no-null': 'off', + 'unicorn/no-unreadable-for-of-expression': 'off', + 'unicorn/no-useless-else': 'off', // useless else sometime is more readable than early return. + 'unicorn/prefer-await': 'off', // sometimes a .then/catch more readable + 'unicorn/prefer-includes-over-repeated-comparisons': 'off', // not worth + 'unicorn/prefer-switch': 'off', // switch is bad + 'unicorn/switch-case-braces': 'off', // we have a rule that warns for decelaration in switch case + + // TODO: review, maybe add them back + '@tanstack/query/prefer-query-options': 'off', + '@typescript-eslint/no-confusing-void-expression': 'off', + '@typescript-eslint/no-floating-promises': 'off', + '@typescript-eslint/no-invalid-void-type': 'off', + '@typescript-eslint/no-misused-promises': 'off', + '@typescript-eslint/no-unnecessary-condition': 'off', + '@typescript-eslint/no-unnecessary-type-assertion': 'off', + '@typescript-eslint/no-unnecessary-type-conversion': 'off', + '@typescript-eslint/no-unsafe-argument': 'off', + '@typescript-eslint/no-unsafe-assignment': 'off', + '@typescript-eslint/no-unsafe-call': 'off', + '@typescript-eslint/no-unsafe-enum-comparison': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', + '@typescript-eslint/no-unsafe-return': 'off', + '@typescript-eslint/no-unused-vars': 'off', + '@typescript-eslint/prefer-promise-reject-errors': 'off', + '@typescript-eslint/require-await': 'off', + '@typescript-eslint/restrict-plus-operands': 'off', + '@typescript-eslint/restrict-template-expressions': 'off', + '@typescript-eslint/triple-slash-reference': 'off', + '@typescript-eslint/unbound-method': 'off', + 'unicorn/consistent-boolean-name': 'off', + 'unicorn/consistent-compound-words': 'off', + 'unicorn/name-replacements': 'off', + 'unicorn/no-top-level-assignment-in-function': 'off', + 'unicorn/no-top-level-side-effects': 'off', + 'unicorn/prefer-number-coercion': 'off', +} + +/** @type {Partial} */ const avoidMistakeRules = { // Libraries - '@tanstack/query/exhaustive-deps': 'error', // avoid unstable results from the hook being deps - '@tanstack/query/stable-query-client': 'error', - '@tanstack/query/infinite-query-property-order': 'warn', // help TypeScript to infer type correctly '@tanstack/query/no-rest-destructuring': 'error', - '@tanstack/query/no-unstable-deps': 'error', // avoid unstable results from the hook being deps - '@tanstack/query/no-void-query-fn': 'error', // query function should always return something - '@lingui/no-single-tag-to-translate': 'error', - // https://github.com/lingui/eslint-plugin/issues/104 - // '@lingui/no-single-variables-to-translate': 'error', - '@lingui/no-trans-inside-trans': 'error', - '@lingui/t-call-in-function': 'error', + 'lingui/no-plural-inside-trans': 'error', // Code quality - 'no-invalid-regexp': 'error', // RegEx - 'unicorn/no-abusive-eslint-disable': 'error', // disable a rule requires a reason '@typescript-eslint/ban-ts-comment': [ 'error', { @@ -59,13 +130,13 @@ const avoidMistakeRules = { }, ], // disable a rule requires a reason /// React bad practice - 'react/no-children-count': 'error', - 'react/no-children-for-each': 'error', - // 'react/no-children-map': 'error', - 'react/no-children-only': 'error', - // 'react/no-children-prop': 'error', - 'react/no-children-to-array': 'error', - // 'react/no-clone-element': 'error', + '@eslint-react/no-children-count': 'error', + '@eslint-react/no-children-for-each': 'error', + // '@eslint-react/no-children-map': 'error', + '@eslint-react/no-children-only': 'error', + // '@eslint-react/no-children-prop': 'error', + '@eslint-react/no-children-to-array': 'error', + // '@eslint-react/no-clone-element': 'error', 'react-compiler/react-compiler': 'error', /// TypeScript bad practice '@typescript-eslint/no-restricted-types': [ @@ -96,94 +167,74 @@ const avoidMistakeRules = { }, ], '@typescript-eslint/no-empty-object-type': ['error', { allowInterfaces: 'with-single-extends' }], - // '@typescript-eslint/no-invalid-void-type': 'warn', // Disallow void type outside of generic or return types - '@typescript-eslint/no-misused-new': 'error', // wrong 'new ()' or 'constructor()' signatures - '@typescript-eslint/no-unsafe-function-type': 'error', - // '@typescript-eslint/no-unsafe-type-assertion': 'error', // bans `expr as T` - '@typescript-eslint/no-wrapper-object-types': 'error', /// Unicode support - 'no-misleading-character-class': 'error', // RegEx 'require-unicode-regexp': 'error', // RegEx modern RegEx with Unicode support - 'unicorn/prefer-code-point': 'error', // '@masknet/no-builtin-base64': 'warn', // Note: it fixes to Node's Buffer /// type safety // '@typescript-eslint/method-signature-style': 'warn', // method signature is bivariant - '@typescript-eslint/no-non-null-asserted-optional-chain': 'error', // bans foo?.bar! - // '@typescript-eslint/no-unsafe-argument': 'error', // bans call(any) - // '@typescript-eslint/no-unsafe-assignment': 'error', // bans a = any - // '@typescript-eslint/no-unsafe-call': 'error', // bans any() - // '@typescript-eslint/no-unsafe-member-access': 'error', // bans a = any.prop - // '@typescript-eslint/no-unsafe-return': 'error', // bans return any - '@typescript-eslint/prefer-return-this-type': 'error', // use `: this` properly - // '@typescript-eslint/restrict-plus-operands': 'error', // stronger `a + b` check - // '@typescript-eslint/restrict-template-expressions': 'error', // bans `${nonString}` // '@typescript-eslint/strict-boolean-expressions': 'error', // stronger check for nullable string/number/boolean // '@typescript-eslint/switch-exhaustiveness-check': 'error', // switch should be exhaustive - // '@typescript-eslint/unbound-method': 'error', // requires `this` to be set properly // '@masknet/type-no-force-cast-via-top-type': 'error', // expr as any as T // Security - 'no-script-url': 'error', // javascript: - // 'unicorn/require-post-message-target-origin': 'warn', // postMessage(data, 'origin') - 'react/dom/no-dangerously-set-innerhtml': 'error', // dangerouslySetInnerHTML - 'react/dom/no-dangerously-set-innerhtml-with-children': 'error', // dangerouslySetInnerHTML + children - 'react/dom/no-missing-iframe-sandbox': 'error', //