diff --git a/mailpoet/assets/js/src/marketing_optin_block/frontend.ts b/mailpoet/assets/js/src/marketing_optin_block/frontend.ts index c44dd773fa..a8b7ec935e 100644 --- a/mailpoet/assets/js/src/marketing_optin_block/frontend.ts +++ b/mailpoet/assets/js/src/marketing_optin_block/frontend.ts @@ -6,8 +6,8 @@ import { registerCheckoutBlock } from '@woocommerce/blocks-checkout'; /** * Internal dependencies */ -import metadata from './block.json'; -import { FrontendBlock } from './block'; +import metadata from './block.json'; // eslint-disable-line import/no-duplicates -- ESLint detects these two as duplicates of each other +import { FrontendBlock } from './block'; // eslint-disable-line import/no-duplicates -- ESLint detects these two as duplicates of each other registerCheckoutBlock({ metadata, diff --git a/mailpoet/eslint.config.js b/mailpoet/eslint.config.js index c0a96b450e..baa530a834 100644 --- a/mailpoet/eslint.config.js +++ b/mailpoet/eslint.config.js @@ -1,5 +1,6 @@ const es5Config = require('@mailpoet/eslint-config/eslint-es5.config'); const es6Config = require('@mailpoet/eslint-config/eslint-es6.config'); +const esTsConfig = require('@mailpoet/eslint-config/eslint-ts.config'); module.exports = [ { @@ -13,4 +14,8 @@ module.exports = [ ...config, files: ['assets/js/src/**/*.jsx', 'tests/javascript/**/*.js'], })), + ...esTsConfig.map((config) => ({ + ...config, + files: ['assets/js/src/**/*.{ts,tsx}'], + })), ]; diff --git a/mailpoet/package.json b/mailpoet/package.json index 92fd02b76d..b865790a4b 100644 --- a/mailpoet/package.json +++ b/mailpoet/package.json @@ -4,8 +4,7 @@ "extends @wordpress/browserslist-config" ], "scripts": { - "lint": "eslint --max-warnings 0 'assets/js/src/**' && pnpm run lint-ts && pnpm run lint-tests", - "lint-ts": "ESLINT_USE_FLAT_CONFIG=false eslint -c ../packages/js/eslint-config/.eslintrc.ts.js --max-warnings 0 'assets/js/src/**/*.tsx' 'assets/js/src/**/*.ts'", + "lint": "eslint --max-warnings 0 'assets/js/src/**' && pnpm run lint-tests", "lint-tests": "ESLINT_USE_FLAT_CONFIG=false eslint -c ../packages/js/eslint-config/.eslintrc.tests_newsletter_editor.js --max-warnings 0 'tests/javascript_newsletter_editor'", "autoprefixer": "postcss assets/dist/css/*.css --use autoprefixer --no-map --replace", "scss": "sass assets/css/src/:assets/dist/css/ --style compressed", @@ -20,8 +19,7 @@ }, "lint-staged": { "*.{scss,css}": "pnpm run stylelint", - "!(*spec).{js,jsx}": "eslint --max-warnings 0", - "*.{tsx,ts}": "ESLINT_USE_FLAT_CONFIG=false eslint -c ../packages/js/eslint-config/.eslintrc.ts.js --max-warnings 0", + "!(*spec).{js,jsx,ts,tsx}": "eslint --max-warnings 0", "**/newsletter_editor/**/*spec.js": "ESLINT_USE_FLAT_CONFIG=false eslint -c ../packages/js/eslint-config/.eslintrc.tests_newsletter_editor.js --max-warnings 0", "*.php": [ "phplint", diff --git a/packages/js/eslint-config/.eslintrc.ts.js b/packages/js/eslint-config/.eslintrc.ts.js deleted file mode 100644 index 9ff23975ca..0000000000 --- a/packages/js/eslint-config/.eslintrc.ts.js +++ /dev/null @@ -1,398 +0,0 @@ -module.exports = { - extends: [ - 'eslint:recommended', - 'plugin:@typescript-eslint/recommended', - 'plugin:@typescript-eslint/recommended-requiring-type-checking', - 'airbnb', - 'airbnb-typescript', - 'plugin:react/jsx-runtime', - 'prettier', - ], - env: { - amd: true, - browser: true, - mocha: true, - }, - parser: '@typescript-eslint/parser', - parserOptions: { - tsconfigRootDir: '.', - project: ['./tsconfig.json'], - ecmaVersion: 6, - ecmaFeatures: { - jsx: true, - }, - }, - plugins: ['react-hooks', 'no-only-tests', '@typescript-eslint'], - settings: { - 'import/resolver': 'webpack', - 'import/core-modules': [ - '@woocommerce/blocks-checkout', - '@woocommerce/settings', - '@wordpress/a11y', - '@wordpress/api-fetch', - '@wordpress/block-editor', - '@wordpress/compose', - '@wordpress/data', - '@wordpress/escape-html', - '@wordpress/hooks', - '@wordpress/keycodes', - '@wordpress/url', - 'react', - ], - }, - rules: { - 'react/no-unstable-nested-components': ['error', { allowAsProps: true }], - // PropTypes - 'react/prop-types': 0, - 'react/jsx-props-no-spreading': 0, - 'react/require-default-props': 0, - // Hooks - 'react-hooks/rules-of-hooks': 'error', - 'react-hooks/exhaustive-deps': 'warn', - // Exceptions - '@typescript-eslint/no-explicit-any': 'error', // make it an error instead of warning - we treat them the same, this is more visible - 'no-void': 0, // can conflict with @typescript-eslint/no-floating-promises - 'react/jsx-no-useless-fragment': [ - 'error', - { - allowExpressions: true, - }, - ], - 'react/jsx-filename-extension': 0, - 'class-methods-use-this': 0, - '@typescript-eslint/no-unsafe-return': 0, // we need to disable it for wordpress select :( - '@typescript-eslint/no-unsafe-member-access': 0, // this needs to be off until we have typed assignments :( - '@typescript-eslint/no-unsafe-call': 0, // this needs to be off until we have typed assignments :( - '@typescript-eslint/no-unsafe-assignment': 0, // this needs to be off until we have typed assignments :( - 'import/extensions': 0, // we wouldn't be able to import jQuery without this line - 'import/no-named-as-default': 0, // we use named default exports at the moment - 'import/prefer-default-export': 0, // we want to stop using default exports and start using named exports - 'react/destructuring-assignment': 0, // that would be too many changes to fix this one - 'prefer-destructuring': 0, // that would be too many changes to fix this one - 'jsx-a11y/label-has-for': [ - 2, - { - required: { some: ['nesting', 'id'] }, // some of our labels are hidden and we cannot nest those - }, - ], - 'jsx-a11y/anchor-is-valid': 0, // cannot fix this one, it would break wprdpress themes - 'jsx-a11y/label-has-associated-control': [ - 2, - { - either: 'either', // control has to be either nested or associated via htmlFor - }, - ], - 'import/no-default-export': 1, // no default exports - '@typescript-eslint/no-misused-promises': [ - 'error', - { - checksVoidReturn: { - attributes: false, // it is OK to pass an async function to JSX attributes - }, - }, - ], - }, - overrides: [ - { - files: ['*.spec.ts'], - rules: { - 'no-unused-expressions': 'off', - }, - }, - { - files: ['**/_stories/*.tsx'], - rules: { - 'import/no-extraneous-dependencies': [ - 'error', - { devDependencies: true }, - ], - 'import/no-default-export': 0, - }, - }, - { - // this violation has been added by a formed employee and we don't know how that works any more, so ignore - files: [ - 'assets/js/src/common/premium_key/key_activation_button.tsx', - 'assets/js/src/settings/pages/advanced/reinstall.tsx', - 'assets/js/src/settings/pages/advanced/recalculate_subscriber_score.tsx', - 'assets/js/src/settings/pages/send_with/other/activate_or_cancel.tsx', - 'assets/js/src/settings/pages/send_with/send_with_choice.tsx', - ], - rules: { - '@typescript-eslint/await-thenable': 0, - }, - }, - { - // too many violations, skipping for now - files: [ - 'assets/js/src/announcements/feature_announcement.tsx', - 'assets/js/src/announcements/with_feature_announcement.tsx', - 'assets/js/src/common/controls/call_api.ts', - 'assets/js/src/common/form/react_select/react_select.tsx', - 'assets/js/src/common/functions/is_email.ts', - 'assets/js/src/common/functions/t.ts', - 'assets/js/src/common/listings/newsletter_stats/stats.tsx', - 'assets/js/src/common/listings/newsletter_status.tsx', - 'assets/js/src/common/set_from_address_modal.tsx', - 'assets/js/src/common/tabs/routed_tabs.tsx', - 'assets/js/src/common/thumbnail.ts', - 'assets/js/src/form_editor/blocks/submit/edit.tsx', - 'assets/js/src/form_editor/components/close_button_settings.tsx', - 'assets/js/src/form_editor/components/font_family_settings.tsx', - 'assets/js/src/form_editor/components/form_settings/form_placement_options/below_pages.tsx', - 'assets/js/src/form_editor/components/form_settings/form_placement_options/fixed_bar.tsx', - 'assets/js/src/form_editor/components/form_settings/form_placement_options/other.tsx', - 'assets/js/src/form_editor/components/form_settings/form_placement_options/popup.tsx', - 'assets/js/src/form_editor/components/form_settings/form_placement_options/settings_panels/animation_settings.tsx', - 'assets/js/src/form_editor/components/form_settings/form_placement_options/settings_panels/below_posts_settings.tsx', - 'assets/js/src/form_editor/components/form_settings/form_placement_options/settings_panels/fixed_bar_settings.tsx', - 'assets/js/src/form_editor/components/form_settings/form_placement_options/settings_panels/other_settings.tsx', - 'assets/js/src/form_editor/components/form_settings/form_placement_options/settings_panels/placement_settings.tsx', - 'assets/js/src/form_editor/components/form_settings/form_placement_options/settings_panels/popup_settings.tsx', - 'assets/js/src/form_editor/components/form_settings/form_placement_options/settings_panels/slide_in_settings.tsx', - 'assets/js/src/form_editor/components/form_settings/form_placement_options/slide_in.tsx', - 'assets/js/src/form_editor/components/form_settings/form_settings.tsx', - 'assets/js/src/form_editor/components/fullscreen.tsx', - 'assets/js/src/form_editor/components/history_redo.tsx', - 'assets/js/src/form_editor/components/history_undo.tsx', - 'assets/js/src/form_editor/components/preview/preview.tsx', - 'assets/js/src/form_editor/components/sidebar/default_sidebar.tsx', - 'assets/js/src/form_editor/components/sidebar/placement_settings_sidebar.tsx', - 'assets/js/src/form_editor/components/sidebar/sidebar.tsx', - 'assets/js/src/form_editor/components/tutorial.tsx', - 'assets/js/src/form_editor/form_preview.ts', - 'assets/js/src/form_editor/hooks.tsx', - 'assets/js/src/form_editor/rich_text/font_selection_format.tsx', - 'assets/js/src/form_editor/store/actions.ts', - 'assets/js/src/form_editor/store/reducers/change_active_sidebar.ts', - 'assets/js/src/form_editor/store/reducers/history_record.ts', - 'assets/js/src/form_editor/store/reducers/toggle_form.ts', - 'assets/js/src/form_editor/store/reducers/toggle_fullscreen.ts', - 'assets/js/src/form_editor/store/reducers/tutorial_dismiss.ts', - 'assets/js/src/form_editor/templates/selection.tsx', - 'assets/js/src/form_editor/templates/store/actions.ts', - 'assets/js/src/form_editor/utils/link_suggestions.tsx', - 'assets/js/src/logs/list.tsx', - 'assets/js/src/newsletters/automatic_emails/events/event_options.tsx', - 'assets/js/src/newsletters/campaign_stats/newsletter_general_stats.tsx', - 'assets/js/src/newsletters/campaign_stats/page.tsx', - 'assets/js/src/newsletters/listings/heading_steps.tsx', - 'assets/js/src/newsletters/send/congratulate/success_pitch_mss.tsx', - 'assets/js/src/newsletters/types.tsx', - 'assets/js/src/segments/dynamic/dynamic_segments_filters/email_opens_absolute_count.tsx', - 'assets/js/src/segments/dynamic/dynamic_segments_filters/email_statistics.tsx', - 'assets/js/src/segments/dynamic/dynamic_segments_filters/subscriber_subscribed_date.tsx', - 'assets/js/src/segments/dynamic/dynamic_segments_filters/subscriber_wordpress_role.tsx', - 'assets/js/src/segments/dynamic/dynamic_segments_filters/woocommerce.tsx', - 'assets/js/src/segments/dynamic/dynamic_segments_filters/woocommerce_subscription.tsx', - 'assets/js/src/segments/dynamic/form.tsx', - 'assets/js/src/segments/dynamic/subscribers_calculator.ts', - 'assets/js/src/segments/dynamic/subscribers_counter.tsx', - 'assets/js/src/segments/dynamic/validator.ts', - 'assets/js/src/settings/components/segments_select.tsx', - 'assets/js/src/settings/pages/basics/stats_notifications.tsx', - 'assets/js/src/settings/pages/basics/subscribe_on.tsx', - 'assets/js/src/settings/pages/send_with/other/sending_frequency.tsx', - 'assets/js/src/settings/pages/send_with/send_with_choice.tsx', - 'assets/js/src/settings/pages/woo_commerce/checkout_optin.tsx', - 'assets/js/src/settings/pages/woo_commerce/email_customizer.tsx', - 'assets/js/src/settings/pages/woo_commerce/enable_cookies.tsx', - 'assets/js/src/settings/pages/woo_commerce/subscribe_old_customers.tsx', - 'assets/js/src/settings/store/actions/settings.ts', - 'assets/js/src/settings/store/controls.ts', - 'assets/js/src/settings/store/hooks/useActions.ts', - 'assets/js/src/settings/store/hooks/useSelector.ts', - 'assets/js/src/settings/store/hooks/useSetting.ts', - 'assets/js/src/settings/store/index.ts', - 'assets/js/src/settings/store/normalize_settings.ts', - 'assets/js/src/settings/store/selectors.ts', - 'assets/js/src/settings/store/types.ts', - 'assets/js/src/subscribers/importExport/export.ts', - ], - rules: { - '@typescript-eslint/restrict-template-expressions': 0, - '@typescript-eslint/no-unsafe-return': 0, - }, - }, - { - // there are so many violations of this rule we need to keep slowly removing it - files: [ - 'assets/js/src/_storybook/action.ts', - 'assets/js/src/announcements/feature_announcement.tsx', - 'assets/js/src/announcements/with_feature_announcement.tsx', - 'assets/js/src/common/background/_stories/background.tsx', - 'assets/js/src/common/background/background.tsx', - 'assets/js/src/common/badge/_stories/badge.tsx', - 'assets/js/src/common/badge/badge.tsx', - 'assets/js/src/common/button/_stories/button.tsx', - 'assets/js/src/common/button/_stories/button_icons.tsx', - 'assets/js/src/common/button/button.tsx', - 'assets/js/src/common/categories/_stories/categories.tsx', - 'assets/js/src/common/categories/categories.tsx', - 'assets/js/src/common/categories/categories_item.tsx', - 'assets/js/src/common/controls/call_api.ts', - 'assets/js/src/common/controls/track_event.ts', - 'assets/js/src/common/datepicker/_stories/datepicker.tsx', - 'assets/js/src/common/datepicker/datepicker.tsx', - 'assets/js/src/common/form/checkbox/_stories/checkbox.tsx', - 'assets/js/src/common/form/checkbox/checkbox.tsx', - 'assets/js/src/common/form/checkbox/group.tsx', - 'assets/js/src/common/form/input/_stories/input.tsx', - 'assets/js/src/common/form/input/input.tsx', - 'assets/js/src/common/form/radio/_stories/radio.tsx', - 'assets/js/src/common/form/radio/group.tsx', - 'assets/js/src/common/form/radio/radio.tsx', - 'assets/js/src/common/form/react_select/_stories/react_select.tsx', - 'assets/js/src/common/form/react_select/react_select.tsx', - 'assets/js/src/common/form/select/_stories/select.tsx', - 'assets/js/src/common/form/textarea/_stories/textarea.tsx', - 'assets/js/src/common/form/textarea/textarea.tsx', - 'assets/js/src/common/form/toggle/_stories/toggle.tsx', - 'assets/js/src/common/form/toggle/toggle.tsx', - 'assets/js/src/common/form/yesno/_stories/yesno.tsx', - 'assets/js/src/common/form/yesno/yesno.tsx', - 'assets/js/src/common/functions/change_handlers.ts', - 'assets/js/src/common/hide_screen_options/hide_screen_options.tsx', - 'assets/js/src/common/listings/_stories/newsletter_stats.tsx', - 'assets/js/src/common/listings/_stories/newsletter_status.tsx', - 'assets/js/src/common/listings/newsletter_stats.tsx', - 'assets/js/src/common/listings/newsletter_stats/badge.tsx', - 'assets/js/src/common/listings/newsletter_stats/stats.tsx', - 'assets/js/src/common/listings/newsletter_status.tsx', - 'assets/js/src/common/loader/_stories/loader.tsx', - 'assets/js/src/common/loader/loader.tsx', - 'assets/js/src/common/modal/_stories/modal.tsx', - 'assets/js/src/common/modal/frame.tsx', - 'assets/js/src/common/modal/header.tsx', - 'assets/js/src/common/modal/modal.tsx', - 'assets/js/src/common/modal/overlay.tsx', - 'assets/js/src/common/premium_required/_stories/premium_required.tsx', - 'assets/js/src/common/premium_required/premium_required.tsx', - 'assets/js/src/common/preview/desktop_icon.tsx', - 'assets/js/src/common/preview/mobile_icon.tsx', - 'assets/js/src/common/remove_wrap_margin/remove_wrap_margin.tsx', - 'assets/js/src/common/set_from_address_modal.tsx', - 'assets/js/src/common/steps/_stories/steps.tsx', - 'assets/js/src/common/steps/content_wrapper_fix.tsx', - 'assets/js/src/common/steps/steps.tsx', - 'assets/js/src/common/steps/steps_content.tsx', - 'assets/js/src/common/subscribers_in_plan.tsx', - 'assets/js/src/common/tabs/_stories/tabs.tsx', - 'assets/js/src/common/tabs/_stories/tabs_icons.tsx', - 'assets/js/src/common/tabs/routed_tabs.tsx', - 'assets/js/src/common/tabs/tab.tsx', - 'assets/js/src/common/tabs/tabs.tsx', - 'assets/js/src/common/tag/_stories/tag.tsx', - 'assets/js/src/common/tag/_stories/tags.tsx', - 'assets/js/src/common/tag/tag.tsx', - 'assets/js/src/common/tag/tags.tsx', - 'assets/js/src/common/template_box/_stories/template_box.tsx', - 'assets/js/src/common/template_box/template_box.tsx', - 'assets/js/src/common/thumbnail.ts', - 'assets/js/src/common/tooltip/_stories/tooltip.tsx', - 'assets/js/src/common/tooltip/tooltip.tsx', - 'assets/js/src/common/top_bar/_stories/top_bar_no_children.tsx', - 'assets/js/src/common/top_bar/_stories/top_bar_with_children.tsx', - 'assets/js/src/common/top_bar/beamer_icon.tsx', - 'assets/js/src/common/top_bar/mailpoet_logo.tsx', - 'assets/js/src/common/top_bar/mailpoet_logo_mobile.tsx', - 'assets/js/src/common/top_bar/screen_options_fix.tsx', - 'assets/js/src/common/top_bar/top_bar.tsx', - 'assets/js/src/common/typography/heading/_stories/heading.tsx', - 'assets/js/src/common/typography/heading/heading.tsx', - 'assets/js/src/common/typography/list/_stories/list.tsx', - 'assets/js/src/common/typography/list/list.tsx', - 'assets/js/src/form_editor/store/actions.ts', - 'assets/js/src/form_editor/store/mapping/from_blocks/styles_mapper.ts', - 'assets/js/src/form_editor/store/mapping/to_blocks/styles_mapper.ts', - 'assets/js/src/form_editor/store/reducers/change_active_sidebar.ts', - 'assets/js/src/form_editor/store/reducers/history_record.ts', - 'assets/js/src/form_editor/store/reducers/toggle_form.ts', - 'assets/js/src/form_editor/store/reducers/toggle_fullscreen.ts', - 'assets/js/src/form_editor/store/reducers/toggle_sidebar.ts', - 'assets/js/src/form_editor/store/reducers/tutorial_dismiss.ts', - 'assets/js/src/form_editor/template_selection.tsx', - 'assets/js/src/form_editor/translations.ts', - 'assets/js/src/form_editor/utils/link_suggestions.tsx', - 'assets/js/src/newsletters/automatic_emails/events/event_options.tsx', - 'assets/js/src/newsletters/campaign_stats/newsletter_general_stats.tsx', - 'assets/js/src/newsletters/campaign_stats/newsletter_stats_info.tsx', - 'assets/js/src/newsletters/campaign_stats/page.tsx', - 'assets/js/src/notices/api_errors_notice.tsx', - 'assets/js/src/notices/invalid_mss_key_notice.tsx', - 'assets/js/src/notices/notice.tsx', - 'assets/js/src/notices/transactional_emails_propose_opt_in_notice.tsx', - 'assets/js/src/sending-paused-notices-fix-button.tsx', - 'assets/js/src/settings/components/inputs.tsx', - 'assets/js/src/settings/components/label.tsx', - 'assets/js/src/settings/components/pages_select.tsx', - 'assets/js/src/settings/components/save_button.tsx', - 'assets/js/src/settings/components/segments_select.tsx', - 'assets/js/src/settings/index.tsx', - 'assets/js/src/settings/pages/advanced/advanced.tsx', - 'assets/js/src/settings/pages/advanced/bounce_address.tsx', - 'assets/js/src/settings/pages/advanced/captcha.tsx', - 'assets/js/src/settings/pages/advanced/inactive_subscribers.tsx', - 'assets/js/src/settings/pages/advanced/libs_3rd_party.tsx', - 'assets/js/src/settings/pages/advanced/logging.tsx', - 'assets/js/src/settings/pages/advanced/reinstall.tsx', - 'assets/js/src/settings/pages/advanced/roles.tsx', - 'assets/js/src/settings/pages/advanced/share_data.tsx', - 'assets/js/src/settings/pages/advanced/task_scheduler.tsx', - 'assets/js/src/settings/pages/advanced/tracking.tsx', - 'assets/js/src/settings/pages/advanced/transactional.tsx', - 'assets/js/src/settings/pages/basics/basics.tsx', - 'assets/js/src/settings/pages/basics/default_sender.tsx', - 'assets/js/src/settings/pages/basics/gdpr_compliant.tsx', - 'assets/js/src/settings/pages/basics/manage_subscription.tsx', - 'assets/js/src/settings/pages/basics/new_subscriber_notifications.tsx', - 'assets/js/src/settings/pages/basics/shortcode.tsx', - 'assets/js/src/settings/pages/basics/stats_notifications.tsx', - 'assets/js/src/settings/pages/basics/subscribe_on.tsx', - 'assets/js/src/settings/pages/basics/unsubscribe_page.tsx', - 'assets/js/src/settings/pages/key_activation/key_activation.tsx', - 'assets/js/src/settings/pages/key_activation/messages/key_messages.tsx', - 'assets/js/src/settings/pages/key_activation/messages/mss_messages.tsx', - 'assets/js/src/settings/pages/key_activation/messages/premium_messages.tsx', - 'assets/js/src/settings/pages/key_activation/messages/service_unavailable_messages.tsx', - 'assets/js/src/settings/pages/send_with/other/activate_or_cancel.tsx', - 'assets/js/src/settings/pages/send_with/other/amazon_ses_fields.tsx', - 'assets/js/src/settings/pages/send_with/other/other_sending_methods.tsx', - 'assets/js/src/settings/pages/send_with/other/php_mail_fields.tsx', - 'assets/js/src/settings/pages/send_with/other/sendgrid_fields.tsx', - 'assets/js/src/settings/pages/send_with/other/sending_frequency.tsx', - 'assets/js/src/settings/pages/send_with/other/sending_method.tsx', - 'assets/js/src/settings/pages/send_with/other/smtp_fields.tsx', - 'assets/js/src/settings/pages/send_with/other/spf.tsx', - 'assets/js/src/settings/pages/send_with/other/test_sending.tsx', - 'assets/js/src/settings/pages/send_with/send_with.tsx', - 'assets/js/src/settings/pages/send_with/send_with_choice.tsx', - 'assets/js/src/settings/pages/signup_confirmation/confirmation_page.tsx', - 'assets/js/src/settings/pages/signup_confirmation/email_content.tsx', - 'assets/js/src/settings/pages/signup_confirmation/email_subject.tsx', - 'assets/js/src/settings/pages/signup_confirmation/enable_signup_confirmation.tsx', - 'assets/js/src/settings/pages/signup_confirmation/signup_confirmation.tsx', - 'assets/js/src/settings/pages/woo_commerce/checkout_optin.tsx', - 'assets/js/src/settings/pages/woo_commerce/email_customizer.tsx', - 'assets/js/src/settings/pages/woo_commerce/enable_cookies.tsx', - 'assets/js/src/settings/pages/woo_commerce/subscribe_old_customers.tsx', - 'assets/js/src/settings/pages/woo_commerce/woo_commerce.tsx', - 'assets/js/src/settings/settings.tsx', - 'assets/js/src/settings/store/actions/mss_and_premium.ts', - 'assets/js/src/settings/store/actions/open_woocommerce_customizer.ts', - 'assets/js/src/settings/store/actions/reinstall.ts', - 'assets/js/src/settings/store/actions/send_test_email.ts', - 'assets/js/src/settings/store/actions/settings.ts', - 'assets/js/src/settings/store/controls.ts', - 'assets/js/src/settings/store/create_reducer.ts', - 'assets/js/src/settings/store/index.ts', - 'assets/js/src/settings/store/make_default_state.ts', - 'assets/js/src/settings/store/selectors.ts', - ], - rules: { - '@typescript-eslint/explicit-function-return-type': 0, - '@typescript-eslint/explicit-module-boundary-types': 0, - }, - }, - ], -}; diff --git a/packages/js/eslint-config/eslint-ts.config.js b/packages/js/eslint-config/eslint-ts.config.js new file mode 100644 index 0000000000..c2aea6654f --- /dev/null +++ b/packages/js/eslint-config/eslint-ts.config.js @@ -0,0 +1,234 @@ +const FlatCompat = require('@eslint/eslintrc').FlatCompat; +const tsPlugin = require('@typescript-eslint/eslint-plugin'); +const tsParser = require('@typescript-eslint/parser'); +const airbnbConfig = require('eslint-config-airbnb'); +const airbnbTsConfig = require('eslint-config-airbnb-typescript'); +const prettierConfig = require('eslint-config-prettier'); +const webpackResolver = require('eslint-import-resolver-webpack'); +const noOnlyTestsPlugin = require('eslint-plugin-no-only-tests'); +const reactJsxRuntimeConfig = require('eslint-plugin-react/configs/jsx-runtime'); +const reactHooksPlugin = require('eslint-plugin-react-hooks'); +const globals = require('globals'); + +// fix @typescript-eslint/eslint-plugin configs to work with the new ESLint config format +const tsConfigsPath = `${__dirname}/node_modules/@typescript-eslint/eslint-plugin/dist/configs`; +const tsConfigs = Object.fromEntries( + Object.entries(tsPlugin.configs).map(([name, config]) => [ + name, + { + ...config, + extends: (config.extends ?? []).map((path) => + path.replace('./configs', tsConfigsPath), + ), + }, + ]), +); + +// compat configs +const compat = new FlatCompat({ baseDirectory: __dirname }); +const tsRecommendedCompatConfig = compat.config(tsConfigs.recommended); +const tsRequiringTypeCheckingCompatConfig = compat.config( + tsConfigs['recommended-requiring-type-checking'], +); +const airbnbCompatConfig = compat.config(airbnbConfig); +const airbnbTsCompatConfig = compat.config(airbnbTsConfig); +const prettierCompatConfig = compat.config(prettierConfig); + +// React plugin is already defined by airbnb config. This fixes: +// TypeError: Key "plugins": Cannot redefine plugin "react" +delete reactJsxRuntimeConfig.plugins.react; + +module.exports = [ + ...tsRecommendedCompatConfig, + ...tsRequiringTypeCheckingCompatConfig, + ...airbnbCompatConfig, + ...airbnbTsCompatConfig, + reactJsxRuntimeConfig, + ...prettierCompatConfig, + { + languageOptions: { + parser: tsParser, + parserOptions: { + tsconfigRootDir: '.', + project: ['./tsconfig.json'], + ecmaVersion: 6, + ecmaFeatures: { + jsx: true, + }, + }, + globals: { + ...globals.browser, + }, + }, + settings: { + 'import/resolver': { webpack: webpackResolver }, + 'import/parsers': { + // prevent "parserPath is required" error with the new ESLint config format + '@typescript-eslint/parser': ['.ts', '.tsx', '.js', '.jsx'], + }, + }, + plugins: { + 'react-hooks': reactHooksPlugin, + 'no-only-tests': noOnlyTestsPlugin, + }, + rules: { + 'react/no-unstable-nested-components': ['error', { allowAsProps: true }], + // PropTypes + 'react/prop-types': 0, + 'react/jsx-props-no-spreading': 0, + 'react/require-default-props': 0, + // Hooks + 'react-hooks/rules-of-hooks': 'error', + 'react-hooks/exhaustive-deps': 'warn', + // Exceptions + '@typescript-eslint/no-explicit-any': 'error', // make it an error instead of warning - we treat them the same, this is more visible + 'no-void': 0, // can conflict with @typescript-eslint/no-floating-promises + 'react/jsx-no-useless-fragment': [ + 'error', + { + allowExpressions: true, + }, + ], + 'react/jsx-filename-extension': 0, + 'class-methods-use-this': 0, + '@typescript-eslint/no-unsafe-return': 2, // we need to disable it for wordpress select :( + '@typescript-eslint/no-unsafe-member-access': 0, // this needs to be off until we have typed assignments :( + '@typescript-eslint/no-unsafe-call': 0, // this needs to be off until we have typed assignments :( + '@typescript-eslint/no-unsafe-assignment': 0, // this needs to be off until we have typed assignments :( + 'import/extensions': 0, // we wouldn't be able to import jQuery without this line + 'import/no-named-as-default': 0, // we use named default exports at the moment + 'import/prefer-default-export': 0, // we want to stop using default exports and start using named exports + 'react/destructuring-assignment': 0, // that would be too many changes to fix this one + 'prefer-destructuring': 0, // that would be too many changes to fix this one + 'jsx-a11y/label-has-for': [ + 2, + { + required: { some: ['nesting', 'id'] }, // some of our labels are hidden and we cannot nest those + }, + ], + 'jsx-a11y/anchor-is-valid': 0, // cannot fix this one, it would break wprdpress themes + 'jsx-a11y/label-has-associated-control': [ + 2, + { + either: 'either', // control has to be either nested or associated via htmlFor + }, + ], + 'import/no-default-export': 1, // no default exports + '@typescript-eslint/no-misused-promises': [ + 'error', + { + checksVoidReturn: { + attributes: false, // it is OK to pass an async function to JSX attributes + }, + }, + ], + }, + }, + + // allow Storybook stories to use dev dependencies and default exports + { + files: ['**/_stories/*.tsx'], + rules: { + 'import/no-extraneous-dependencies': ['error', { devDependencies: true }], + 'import/no-default-export': 0, + }, + }, + + // existing violations that we should fix at some point + { + files: [ + 'assets/js/src/common/premium_key/key_activation_button.tsx', + 'assets/js/src/settings/pages/advanced/reinstall.tsx', + 'assets/js/src/settings/pages/advanced/recalculate_subscriber_score.tsx', + 'assets/js/src/settings/pages/send_with/other/activate_or_cancel.tsx', + 'assets/js/src/settings/pages/send_with/send_with_choice.tsx', + ], + rules: { + '@typescript-eslint/await-thenable': 0, + }, + }, + { + files: [ + 'assets/js/src/common/tabs/routed_tabs.tsx', + 'assets/js/src/common/thumbnail.ts', + 'assets/js/src/form_editor/components/form_settings/form_placement_options/settings_panels/placement_settings.tsx', + 'assets/js/src/form_editor/form_preview.ts', + 'assets/js/src/newsletters/campaign_stats/newsletter_general_stats.tsx', + 'assets/js/src/newsletters/types.tsx', + 'assets/js/src/settings/store/normalize_settings.ts', + 'assets/js/src/subscribers/importExport/export.ts', + ], + rules: { + '@typescript-eslint/restrict-template-expressions': 0, + }, + }, + { + files: [ + 'assets/js/src/ajax.ts', + 'assets/js/src/automation/editor/components/automation/index.tsx', + 'assets/js/src/automation/editor/components/automation/separator.tsx', + 'assets/js/src/automation/editor/components/header/index.tsx', + 'assets/js/src/automation/editor/components/header/inserter_toggle.tsx', + 'assets/js/src/automation/editor/components/sidebar/header.tsx', + 'assets/js/src/automation/editor/index.tsx', + 'assets/js/src/automation/editor/store/actions.ts', + 'assets/js/src/automation/integrations/core/steps/delay/edit.tsx', + 'assets/js/src/automation/integrations/mailpoet/steps/send_email/edit/edit_newsletter.tsx', + 'assets/js/src/automation/integrations/mailpoet/steps/send_email/edit/email_panel.tsx', + 'assets/js/src/automation/integrations/mailpoet/steps/send_email/edit/reply_to_panel.tsx', + 'assets/js/src/automation/integrations/mailpoet/steps/send_email/index.tsx', + 'assets/js/src/automation/listing/store/reducer.ts', + 'assets/js/src/common/error_boundary/utils.ts', + 'assets/js/src/common/functions/parsley_helper_functions.ts', + 'assets/js/src/common/listings/newsletter_stats/stats.tsx', + 'assets/js/src/common/top_bar/mailpoet_logo_responsive.tsx', + 'assets/js/src/date.ts', + 'assets/js/src/form/fields/tokenField.tsx', + 'assets/js/src/form_editor/components/form_settings/form_placement_options/settings_panels/placement_settings.tsx', + 'assets/js/src/form_editor/form_preview.ts', + 'assets/js/src/form_editor/store/blocks_to_form_body.ts', + 'assets/js/src/form_editor/store/controls.tsx', + 'assets/js/src/form_editor/store/reducers/change_active_sidebar.ts', + 'assets/js/src/form_editor/store/reducers/toggle_form.ts', + 'assets/js/src/form_editor/store/reducers/toggle_fullscreen.ts', + 'assets/js/src/form_editor/store/reducers/toggle_sidebar.ts', + 'assets/js/src/form_editor/store/reducers/tutorial_dismiss.ts', + 'assets/js/src/form_editor/store/selectors.ts', + 'assets/js/src/homepage/components/product-discovery.tsx', + 'assets/js/src/homepage/components/task-list.tsx', + 'assets/js/src/marketing_optin_block/frontend.ts', + 'assets/js/src/newsletter_editor/behaviors/TextEditorBehavior.ts', + 'assets/js/src/newsletter_editor/blocks/coupon.tsx', + 'assets/js/src/newsletter_editor/blocks/coupon/settings_header.tsx', + 'assets/js/src/newsletters/automatic_emails/events/event_options.tsx', + 'assets/js/src/newsletters/listings/heading_steps.tsx', + 'assets/js/src/newsletters/send.tsx', + 'assets/js/src/newsletters/send/congratulate/success_pitch_mss.tsx', + 'assets/js/src/newsletters/send/ga_tracking.tsx', + 'assets/js/src/newsletters/send/re_engagement.tsx', + 'assets/js/src/newsletters/send/standard.tsx', + 'assets/js/src/newsletters/types.tsx', + 'assets/js/src/notices/email_volume_limit_notice.tsx', + 'assets/js/src/segments/dynamic/dynamic_segments_filters/subscriber_tag.tsx', + 'assets/js/src/segments/dynamic/dynamic_segments_filters/woocommerce.tsx', + 'assets/js/src/segments/dynamic/subscribers_counter.tsx', + 'assets/js/src/segments/dynamic/validator.ts', + 'assets/js/src/sending-paused-notices-resume-button.ts', + 'assets/js/src/settings/pages/basics/stats_notifications.tsx', + 'assets/js/src/settings/pages/basics/subscribe_on.tsx', + 'assets/js/src/settings/pages/signup_confirmation/confirmation_email_customizer.tsx', + 'assets/js/src/settings/pages/woo_commerce/checkout_optin.tsx', + 'assets/js/src/settings/pages/woo_commerce/email_customizer.tsx', + 'assets/js/src/settings/pages/woo_commerce/subscribe_old_customers.tsx', + 'assets/js/src/settings/store/actions/settings.ts', + 'assets/js/src/settings/store/hooks/useSelector.ts', + 'assets/js/src/settings/store/hooks/useSetting.ts', + 'assets/js/src/settings/store/normalize_settings.ts', + 'assets/js/src/subscribers/importExport/export.ts', + 'assets/js/src/wizard/welcome_wizard_controller.tsx', + ], + rules: { + '@typescript-eslint/no-unsafe-return': 0, + }, + }, +];