diff --git a/.eslintrc.js b/.eslintrc.js index 2bbe301f04..9e965791b0 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -9,6 +9,7 @@ module.exports = { 'plugin:import/recommended', 'plugin:promise/recommended', 'plugin:jsdoc/recommended', + 'plugin:prettier/recommended', ], env: { @@ -62,20 +63,9 @@ module.exports = { }, rules: { - 'brace-style': 'warn', - 'comma-dangle': ['error', 'always-multiline'], - 'comma-spacing': [ - 'warn', - { - before: false, - after: true, - }, - ], - 'comma-style': ['warn', 'last'], 'consistent-return': 'error', 'dot-notation': 'error', eqeqeq: ['error', 'always', { 'null': 'ignore' }], - indent: ['warn', 2], 'jsx-quotes': ['error', 'prefer-single'], 'no-case-declarations': 'off', 'no-catch-shadow': 'error', @@ -95,7 +85,6 @@ module.exports = { { property: 'substr', message: 'Use .slice instead of .substr.' }, ], 'no-self-assign': 'off', - 'no-trailing-spaces': 'warn', 'no-unused-expressions': 'error', 'no-unused-vars': 'off', '@typescript-eslint/no-unused-vars': [ @@ -107,29 +96,14 @@ module.exports = { ignoreRestSiblings: true, }, ], - 'object-curly-spacing': ['error', 'always'], - 'padded-blocks': [ - 'error', - { - classes: 'always', - }, - ], - quotes: ['error', 'single'], - semi: 'error', 'valid-typeof': 'error', 'react/jsx-filename-extension': ['error', { extensions: ['.jsx', 'tsx'] }], 'react/jsx-boolean-value': 'error', - 'react/jsx-closing-bracket-location': ['error', 'line-aligned'], - 'react/jsx-curly-spacing': 'error', 'react/display-name': 'off', 'react/jsx-equals-spacing': 'error', - 'react/jsx-first-prop-new-line': ['error', 'multiline-multiprop'], - 'react/jsx-indent': ['error', 2], 'react/jsx-no-bind': 'error', 'react/jsx-no-target-blank': 'off', - 'react/jsx-tag-spacing': 'error', - 'react/jsx-wrap-multilines': 'error', 'react/no-deprecated': 'off', 'react/no-unknown-property': 'off', 'react/self-closing-comp': 'error', @@ -291,6 +265,7 @@ module.exports = { 'plugin:import/typescript', 'plugin:promise/recommended', 'plugin:jsdoc/recommended', + 'plugin:prettier/recommended', ], rules: { diff --git a/.github/dependabot.yml b/.github/dependabot.yml index ef16f1d482..af7efbe6cf 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -17,10 +17,6 @@ updates: - dependency-name: '@rails/ujs' versions: - '>= 7' - # TODO: This was ignored in https://github.com/mastodon/mastodon/pull/19120 - - dependency-name: 'uuid' - versions: - - '>= 9' # TODO: This requires code changes for migration - dependency-name: 'tesseract.js' versions: diff --git a/.prettierignore b/.prettierignore index 9bdf769112..2ea4075333 100644 --- a/.prettierignore +++ b/.prettierignore @@ -70,8 +70,6 @@ app/javascript/styles/mastodon/reset.scss # Ignore Javascript pending https://github.com/mastodon/mastodon/pull/23631 *.js *.jsx -*.ts -*.tsx # Ignore HTML till cleaned and included in CI *.html diff --git a/.prettierrc.js b/.prettierrc.js index 1d70813d51..af39b253f6 100644 --- a/.prettierrc.js +++ b/.prettierrc.js @@ -1,3 +1,4 @@ module.exports = { - singleQuote: true + singleQuote: true, + jsxSingleQuote: true } diff --git a/.rubocop.yml b/.rubocop.yml index e8454ca949..da26b68f5b 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -165,7 +165,7 @@ Metrics/MethodLength: - 'lib/mastodon/*_cli.rb' # Reason: -# https://docs.rubocop.org/rubocop/cops_style.html#stylerescuestandarderror +# https://docs.rubocop.org/rubocop/cops_metrics.html#metricsmodulelength Metrics/ModuleLength: CountAsOne: [array, heredoc] diff --git a/app/javascript/mastodon/blurhash.ts b/app/javascript/mastodon/blurhash.ts index cb1c3b2c82..dadf2b7f2c 100644 --- a/app/javascript/mastodon/blurhash.ts +++ b/app/javascript/mastodon/blurhash.ts @@ -98,9 +98,9 @@ export const decode83 = (str: string) => { }; export const intToRGB = (int: number) => ({ - r: Math.max(0, (int >> 16)), + r: Math.max(0, int >> 16), g: Math.max(0, (int >> 8) & 255), - b: Math.max(0, (int & 255)), + b: Math.max(0, int & 255), }); export const getAverageFromBlurhash = (blurhash: string) => { diff --git a/app/javascript/mastodon/compare_id.ts b/app/javascript/mastodon/compare_id.ts index 3ddfb76351..30b0572481 100644 --- a/app/javascript/mastodon/compare_id.ts +++ b/app/javascript/mastodon/compare_id.ts @@ -1,4 +1,4 @@ -export function compareId (id1: string, id2: string) { +export function compareId(id1: string, id2: string) { if (id1 === id2) { return 0; } diff --git a/app/javascript/mastodon/components/__tests__/display_name-test.jsx b/app/javascript/mastodon/components/__tests__/display_name-test.jsx index 0d040c4cd8..afb6c4758a 100644 --- a/app/javascript/mastodon/components/__tests__/display_name-test.jsx +++ b/app/javascript/mastodon/components/__tests__/display_name-test.jsx @@ -1,7 +1,7 @@ import React from 'react'; import renderer from 'react-test-renderer'; import { fromJS } from 'immutable'; -import DisplayName from '../display_name'; +import { DisplayName } from '../display_name'; describe('', () => { it('renders display name + account name', () => { diff --git a/app/javascript/mastodon/components/account.jsx b/app/javascript/mastodon/components/account.jsx index 20484cad3b..5fb17e69d7 100644 --- a/app/javascript/mastodon/components/account.jsx +++ b/app/javascript/mastodon/components/account.jsx @@ -2,7 +2,7 @@ import React from 'react'; import ImmutablePropTypes from 'react-immutable-proptypes'; import PropTypes from 'prop-types'; import { Avatar } from './avatar'; -import DisplayName from './display_name'; +import { DisplayName } from './display_name'; import { IconButton } from './icon_button'; import { defineMessages, injectIntl } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; diff --git a/app/javascript/mastodon/components/animated_number.tsx b/app/javascript/mastodon/components/animated_number.tsx index 20ffa1a4d0..f6c77d35ff 100644 --- a/app/javascript/mastodon/components/animated_number.tsx +++ b/app/javascript/mastodon/components/animated_number.tsx @@ -16,13 +16,10 @@ const obfuscatedCount = (count: number) => { type Props = { value: number; obfuscate?: boolean; -} -export const AnimatedNumber: React.FC = ({ - value, - obfuscate, -})=> { +}; +export const AnimatedNumber: React.FC = ({ value, obfuscate }) => { const [previousValue, setPreviousValue] = useState(value); - const [direction, setDirection] = useState<1|-1>(1); + const [direction, setDirection] = useState<1 | -1>(1); if (previousValue !== value) { setPreviousValue(value); @@ -30,24 +27,45 @@ export const AnimatedNumber: React.FC = ({ } const willEnter = useCallback(() => ({ y: -1 * direction }), [direction]); - const willLeave = useCallback(() => ({ y: spring(1 * direction, { damping: 35, stiffness: 400 }) }), [direction]); + const willLeave = useCallback( + () => ({ y: spring(1 * direction, { damping: 35, stiffness: 400 }) }), + [direction] + ); if (reduceMotion) { - return obfuscate ? <>{obfuscatedCount(value)} : ; + return obfuscate ? ( + <>{obfuscatedCount(value)} + ) : ( + + ); } - const styles = [{ - key: `${value}`, - data: value, - style: { y: spring(0, { damping: 35, stiffness: 400 }) }, - }]; + const styles = [ + { + key: `${value}`, + data: value, + style: { y: spring(0, { damping: 35, stiffness: 400 }) }, + }, + ]; return ( - - {items => ( + + {(items) => ( {items.map(({ key, data, style }) => ( - 0 ? 'absolute' : 'static', transform: `translateY(${style.y * 100}%)` }}>{obfuscate ? obfuscatedCount(data) : } + 0 ? 'absolute' : 'static', + transform: `translateY(${style.y * 100}%)`, + }} + > + {obfuscate ? obfuscatedCount(data) : } + ))} )} diff --git a/app/javascript/mastodon/components/avatar_overlay.tsx b/app/javascript/mastodon/components/avatar_overlay.tsx index e8dc88896f..1dbd533230 100644 --- a/app/javascript/mastodon/components/avatar_overlay.tsx +++ b/app/javascript/mastodon/components/avatar_overlay.tsx @@ -18,13 +18,19 @@ export const AvatarOverlay: React.FC = ({ baseSize = 36, overlaySize = 24, }) => { - const { hovering, handleMouseEnter, handleMouseLeave } = useHovering(autoPlayGif); - const accountSrc = hovering ? account?.get('avatar') : account?.get('avatar_static'); - const friendSrc = hovering ? friend?.get('avatar') : friend?.get('avatar_static'); + const { hovering, handleMouseEnter, handleMouseLeave } = + useHovering(autoPlayGif); + const accountSrc = hovering + ? account?.get('avatar') + : account?.get('avatar_static'); + const friendSrc = hovering + ? friend?.get('avatar') + : friend?.get('avatar_static'); return (
diff --git a/app/javascript/mastodon/components/blurhash.tsx b/app/javascript/mastodon/components/blurhash.tsx index 181e2183d0..7005136765 100644 --- a/app/javascript/mastodon/components/blurhash.tsx +++ b/app/javascript/mastodon/components/blurhash.tsx @@ -8,7 +8,7 @@ type Props = { dummy?: boolean; // Whether dummy mode is enabled. If enabled, nothing is rendered and canvas left untouched children?: never; [key: string]: any; -} +}; const Blurhash: React.FC = ({ hash, width = 32, diff --git a/app/javascript/mastodon/components/check.tsx b/app/javascript/mastodon/components/check.tsx index 57b810a0e5..73d65595ea 100644 --- a/app/javascript/mastodon/components/check.tsx +++ b/app/javascript/mastodon/components/check.tsx @@ -1,7 +1,15 @@ import React from 'react'; export const Check: React.FC = () => ( - - + + ); diff --git a/app/javascript/mastodon/components/display_name.jsx b/app/javascript/mastodon/components/display_name.jsx deleted file mode 100644 index 1dd9fb1d67..0000000000 --- a/app/javascript/mastodon/components/display_name.jsx +++ /dev/null @@ -1,79 +0,0 @@ -import React from 'react'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import PropTypes from 'prop-types'; -import { autoPlayGif } from 'mastodon/initial_state'; -import Skeleton from 'mastodon/components/skeleton'; - -export default class DisplayName extends React.PureComponent { - - static propTypes = { - account: ImmutablePropTypes.map, - others: ImmutablePropTypes.list, - localDomain: PropTypes.string, - }; - - handleMouseEnter = ({ currentTarget }) => { - if (autoPlayGif) { - return; - } - - const emojis = currentTarget.querySelectorAll('.custom-emoji'); - - for (var i = 0; i < emojis.length; i++) { - let emoji = emojis[i]; - emoji.src = emoji.getAttribute('data-original'); - } - }; - - handleMouseLeave = ({ currentTarget }) => { - if (autoPlayGif) { - return; - } - - const emojis = currentTarget.querySelectorAll('.custom-emoji'); - - for (var i = 0; i < emojis.length; i++) { - let emoji = emojis[i]; - emoji.src = emoji.getAttribute('data-static'); - } - }; - - render () { - const { others, localDomain } = this.props; - - let displayName, suffix, account; - - if (others && others.size > 1) { - displayName = others.take(2).map(a => ).reduce((prev, cur) => [prev, ', ', cur]); - - if (others.size - 2 > 0) { - suffix = `+${others.size - 2}`; - } - } else if ((others && others.size > 0) || this.props.account) { - if (others && others.size > 0) { - account = others.first(); - } else { - account = this.props.account; - } - - let acct = account.get('acct'); - - if (acct.indexOf('@') === -1 && localDomain) { - acct = `${acct}@${localDomain}`; - } - - displayName = ; - suffix = @{acct}; - } else { - displayName = ; - suffix = ; - } - - return ( - - {displayName} {suffix} - - ); - } - -} diff --git a/app/javascript/mastodon/components/display_name.tsx b/app/javascript/mastodon/components/display_name.tsx new file mode 100644 index 0000000000..0452dba794 --- /dev/null +++ b/app/javascript/mastodon/components/display_name.tsx @@ -0,0 +1,115 @@ +import React from 'react'; +import { autoPlayGif } from '..//initial_state'; +import Skeleton from './skeleton'; +import { Account } from '../../types/resources'; +import { List } from 'immutable'; + +type Props = { + account: Account; + others: List; + localDomain: string; +}; +export class DisplayName extends React.PureComponent { + handleMouseEnter: React.ReactEventHandler = ({ + currentTarget, + }) => { + if (autoPlayGif) { + return; + } + + const emojis = + currentTarget.querySelectorAll('img.custom-emoji'); + + emojis.forEach((emoji) => { + const originalSrc = emoji.getAttribute('data-original'); + if (originalSrc != null) emoji.src = originalSrc; + }); + }; + + handleMouseLeave: React.ReactEventHandler = ({ + currentTarget, + }) => { + if (autoPlayGif) { + return; + } + + const emojis = + currentTarget.querySelectorAll('img.custom-emoji'); + + emojis.forEach((emoji) => { + const staticSrc = emoji.getAttribute('data-static'); + if (staticSrc != null) emoji.src = staticSrc; + }); + }; + + render() { + const { others, localDomain } = this.props; + + let displayName: React.ReactNode, suffix: React.ReactNode, account: Account; + + if (others && others.size > 1) { + displayName = others + .take(2) + .map((a) => ( + + + + )) + .reduce((prev, cur) => [prev, ', ', cur]); + + if (others.size - 2 > 0) { + suffix = `+${others.size - 2}`; + } + } else if ((others && others.size > 0) || this.props.account) { + if (others && others.size > 0) { + account = others.first(); + } else { + account = this.props.account; + } + + let acct = account.get('acct'); + + if (acct.indexOf('@') === -1 && localDomain) { + acct = `${acct}@${localDomain}`; + } + + displayName = ( + + + + ); + suffix = @{acct}; + } else { + displayName = ( + + + + + + ); + suffix = ( + + + + ); + } + + return ( + + {displayName} {suffix} + + ); + } +} diff --git a/app/javascript/mastodon/components/gifv.tsx b/app/javascript/mastodon/components/gifv.tsx index 5d9f235e11..72914ba741 100644 --- a/app/javascript/mastodon/components/gifv.tsx +++ b/app/javascript/mastodon/components/gifv.tsx @@ -8,7 +8,7 @@ type Props = { width: number; height: number; onClick?: () => void; -} +}; export const GIFV: React.FC = ({ src, @@ -17,19 +17,23 @@ export const GIFV: React.FC = ({ width, height, onClick, -})=> { +}) => { const [loading, setLoading] = useState(true); - const handleLoadedData: React.ReactEventHandler = useCallback(() => { - setLoading(false); - }, [setLoading]); + const handleLoadedData: React.ReactEventHandler = + useCallback(() => { + setLoading(false); + }, [setLoading]); - const handleClick: React.MouseEventHandler = useCallback((e) => { - if (onClick) { - e.stopPropagation(); - onClick(); - } - }, [onClick]); + const handleClick: React.MouseEventHandler = useCallback( + (e) => { + if (onClick) { + e.stopPropagation(); + onClick(); + } + }, + [onClick] + ); return (
diff --git a/app/javascript/mastodon/components/icon.tsx b/app/javascript/mastodon/components/icon.tsx index f74437b555..4eb948dc76 100644 --- a/app/javascript/mastodon/components/icon.tsx +++ b/app/javascript/mastodon/components/icon.tsx @@ -7,6 +7,15 @@ type Props = { fixedWidth?: boolean; children?: never; [key: string]: any; -} -export const Icon: React.FC = ({ id, className, fixedWidth, ...other }) => - ; +}; +export const Icon: React.FC = ({ + id, + className, + fixedWidth, + ...other +}) => ( + +); diff --git a/app/javascript/mastodon/components/icon_button.tsx b/app/javascript/mastodon/components/icon_button.tsx index f9db287bb9..1786414009 100644 --- a/app/javascript/mastodon/components/icon_button.tsx +++ b/app/javascript/mastodon/components/icon_button.tsx @@ -25,13 +25,12 @@ type Props = { obfuscateCount?: boolean; href?: string; ariaHidden: boolean; -} +}; type States = { - activate: boolean, - deactivate: boolean, -} + activate: boolean; + deactivate: boolean; +}; export class IconButton extends React.PureComponent { - static defaultProps = { size: 18, active: false, @@ -47,7 +46,7 @@ export class IconButton extends React.PureComponent { deactivate: false, }; - UNSAFE_componentWillReceiveProps (nextProps: Props) { + UNSAFE_componentWillReceiveProps(nextProps: Props) { if (!nextProps.animate) return; if (this.props.active && !nextProps.active) { @@ -57,7 +56,7 @@ export class IconButton extends React.PureComponent { } } - handleClick: React.MouseEventHandler = (e) => { + handleClick: React.MouseEventHandler = (e) => { e.preventDefault(); if (!this.props.disabled && this.props.onClick != null) { @@ -83,7 +82,7 @@ export class IconButton extends React.PureComponent { } }; - render () { + render() { const style = { fontSize: `${this.props.size}px`, width: `${this.props.size * 1.28571429}px`, @@ -109,10 +108,7 @@ export class IconButton extends React.PureComponent { ariaHidden, } = this.props; - const { - activate, - deactivate, - } = this.state; + const { activate, deactivate } = this.state; const classes = classNames(className, 'icon-button', { active, @@ -130,7 +126,12 @@ export class IconButton extends React.PureComponent { let contents = ( - ); @@ -162,5 +163,4 @@ export class IconButton extends React.PureComponent { ); } - } diff --git a/app/javascript/mastodon/components/icon_with_badge.tsx b/app/javascript/mastodon/components/icon_with_badge.tsx index a4af86ca9b..bf86814c03 100644 --- a/app/javascript/mastodon/components/icon_with_badge.tsx +++ b/app/javascript/mastodon/components/icon_with_badge.tsx @@ -1,18 +1,25 @@ import React from 'react'; import { Icon } from './icon'; -const formatNumber = (num: number): number | string => num > 40 ? '40+' : num; +const formatNumber = (num: number): number | string => (num > 40 ? '40+' : num); type Props = { id: string; count: number; issueBadge: boolean; className: string; -} -export const IconWithBadge: React.FC = ({ id, count, issueBadge, className }) => ( +}; +export const IconWithBadge: React.FC = ({ + id, + count, + issueBadge, + className, +}) => ( - {count > 0 && {formatNumber(count)}} + {count > 0 && ( + {formatNumber(count)} + )} {issueBadge && } ); diff --git a/app/javascript/mastodon/components/not_signed_in_indicator.tsx b/app/javascript/mastodon/components/not_signed_in_indicator.tsx index 3bfee6ae91..53945d6a7a 100644 --- a/app/javascript/mastodon/components/not_signed_in_indicator.tsx +++ b/app/javascript/mastodon/components/not_signed_in_indicator.tsx @@ -4,7 +4,10 @@ import { FormattedMessage } from 'react-intl'; export const NotSignedInIndicator: React.FC = () => (
- +
); diff --git a/app/javascript/mastodon/components/radio_button.tsx b/app/javascript/mastodon/components/radio_button.tsx index 194b67afe1..829f471747 100644 --- a/app/javascript/mastodon/components/radio_button.tsx +++ b/app/javascript/mastodon/components/radio_button.tsx @@ -9,7 +9,13 @@ type Props = { label: React.ReactNode; }; -export const RadioButton: React.FC = ({ name, value, checked, onChange, label }) => { +export const RadioButton: React.FC = ({ + name, + value, + checked, + onChange, + label, +}) => { return (
, mastodon: Mastodon }} />
- +
{isLoading ? ( diff --git a/app/javascript/mastodon/components/image.tsx b/app/javascript/mastodon/components/server_hero_image.tsx similarity index 71% rename from app/javascript/mastodon/components/image.tsx rename to app/javascript/mastodon/components/server_hero_image.tsx index b332d4115b..d10b8a620b 100644 --- a/app/javascript/mastodon/components/image.tsx +++ b/app/javascript/mastodon/components/server_hero_image.tsx @@ -7,9 +7,14 @@ type Props = { srcSet?: string; blurhash?: string; className?: string; -} +}; -export const Image: React.FC = ({ src, srcSet, blurhash, className }) => { +export const ServerHeroImage: React.FC = ({ + src, + srcSet, + blurhash, + className, +}) => { const [loaded, setLoaded] = useState(false); const handleLoad = useCallback(() => { @@ -17,7 +22,10 @@ export const Image: React.FC = ({ src, srcSet, blurhash, className }) => }, [setLoaded]); return ( -
+
{blurhash && }
diff --git a/app/javascript/mastodon/components/status.jsx b/app/javascript/mastodon/components/status.jsx index 0ecfde15fd..b64e6e1015 100644 --- a/app/javascript/mastodon/components/status.jsx +++ b/app/javascript/mastodon/components/status.jsx @@ -4,7 +4,7 @@ import PropTypes from 'prop-types'; import { Avatar } from './avatar'; import { AvatarOverlay } from './avatar_overlay'; import { RelativeTimestamp } from './relative_timestamp'; -import DisplayName from './display_name'; +import { DisplayName } from './display_name'; import StatusContent from './status_content'; import StatusActionBar from './status_action_bar'; import StatusEmojiReactionsBar from './status_emoji_reactions_bar'; diff --git a/app/javascript/mastodon/containers/compose_container.jsx b/app/javascript/mastodon/containers/compose_container.jsx index a4c5f3cb49..9213c5614e 100644 --- a/app/javascript/mastodon/containers/compose_container.jsx +++ b/app/javascript/mastodon/containers/compose_container.jsx @@ -1,7 +1,7 @@ import React from 'react'; import { Provider } from 'react-redux'; import PropTypes from 'prop-types'; -import { store } from '../store/configureStore'; +import { store } from '../store'; import { hydrateStore } from '../actions/store'; import { IntlProvider, addLocaleData } from 'react-intl'; import { getLocale } from '../locales'; diff --git a/app/javascript/mastodon/containers/mastodon.jsx b/app/javascript/mastodon/containers/mastodon.jsx index 256ea8e2d9..9c6c9e5920 100644 --- a/app/javascript/mastodon/containers/mastodon.jsx +++ b/app/javascript/mastodon/containers/mastodon.jsx @@ -5,7 +5,7 @@ import { IntlProvider, addLocaleData } from 'react-intl'; import { Provider as ReduxProvider } from 'react-redux'; import { BrowserRouter, Route } from 'react-router-dom'; import { ScrollContext } from 'react-router-scroll-4'; -import { store } from 'mastodon/store/configureStore'; +import { store } from 'mastodon/store'; import UI from 'mastodon/features/ui'; import { fetchCustomEmojis } from 'mastodon/actions/custom_emojis'; import { hydrateStore } from 'mastodon/actions/store'; diff --git a/app/javascript/mastodon/features/about/index.jsx b/app/javascript/mastodon/features/about/index.jsx index 360bec5b79..1b731f1673 100644 --- a/app/javascript/mastodon/features/about/index.jsx +++ b/app/javascript/mastodon/features/about/index.jsx @@ -11,7 +11,7 @@ import Account from 'mastodon/containers/account_container'; import Skeleton from 'mastodon/components/skeleton'; import { Icon } from 'mastodon/components/icon'; import classNames from 'classnames'; -import { Image } from 'mastodon/components/image'; +import { ServerHeroImage } from 'mastodon/components/server_hero_image'; const messages = defineMessages({ title: { id: 'column.about', defaultMessage: 'About' }, @@ -121,7 +121,7 @@ class About extends React.PureComponent {
- `${value} ${key.replace('@', '')}`).join(', ')} className='about__header__hero' /> + `${value} ${key.replace('@', '')}`).join(', ')} className='about__header__hero' />

{isLoading ? : server.get('domain')}

Mastodon }} />

diff --git a/app/javascript/mastodon/features/account_timeline/components/moved_note.jsx b/app/javascript/mastodon/features/account_timeline/components/moved_note.jsx index 273583c0ad..29861612c3 100644 --- a/app/javascript/mastodon/features/account_timeline/components/moved_note.jsx +++ b/app/javascript/mastodon/features/account_timeline/components/moved_note.jsx @@ -3,7 +3,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; import { FormattedMessage } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; import { AvatarOverlay } from '../../../components/avatar_overlay'; -import DisplayName from '../../../components/display_name'; +import { DisplayName } from '../../../components/display_name'; import { Link } from 'react-router-dom'; export default class MovedNote extends ImmutablePureComponent { diff --git a/app/javascript/mastodon/features/compose/components/autosuggest_account.jsx b/app/javascript/mastodon/features/compose/components/autosuggest_account.jsx index 2c92016e86..a635657d9f 100644 --- a/app/javascript/mastodon/features/compose/components/autosuggest_account.jsx +++ b/app/javascript/mastodon/features/compose/components/autosuggest_account.jsx @@ -1,6 +1,6 @@ import React from 'react'; import { Avatar } from '../../../components/avatar'; -import DisplayName from '../../../components/display_name'; +import { DisplayName } from '../../../components/display_name'; import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; diff --git a/app/javascript/mastodon/features/compose/components/reply_indicator.jsx b/app/javascript/mastodon/features/compose/components/reply_indicator.jsx index 68cd7b0804..b3f1b1b482 100644 --- a/app/javascript/mastodon/features/compose/components/reply_indicator.jsx +++ b/app/javascript/mastodon/features/compose/components/reply_indicator.jsx @@ -3,7 +3,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; import PropTypes from 'prop-types'; import { Avatar } from '../../../components/avatar'; import { IconButton } from '../../../components/icon_button'; -import DisplayName from '../../../components/display_name'; +import { DisplayName } from '../../../components/display_name'; import { defineMessages, injectIntl } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; import AttachmentList from 'mastodon/components/attachment_list'; diff --git a/app/javascript/mastodon/features/directory/components/account_card.jsx b/app/javascript/mastodon/features/directory/components/account_card.jsx index 4951427151..1ef9d64813 100644 --- a/app/javascript/mastodon/features/directory/components/account_card.jsx +++ b/app/javascript/mastodon/features/directory/components/account_card.jsx @@ -5,7 +5,7 @@ import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { makeGetAccount } from 'mastodon/selectors'; import { Avatar } from 'mastodon/components/avatar'; -import DisplayName from 'mastodon/components/display_name'; +import { DisplayName } from 'mastodon/components/display_name'; import { Link } from 'react-router-dom'; import Button from 'mastodon/components/button'; import { FormattedMessage, injectIntl, defineMessages } from 'react-intl'; diff --git a/app/javascript/mastodon/features/follow_requests/components/account_authorize.jsx b/app/javascript/mastodon/features/follow_requests/components/account_authorize.jsx index b370b33ecb..5d0632b0f6 100644 --- a/app/javascript/mastodon/features/follow_requests/components/account_authorize.jsx +++ b/app/javascript/mastodon/features/follow_requests/components/account_authorize.jsx @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; import { Link } from 'react-router-dom'; import { Avatar } from '../../../components/avatar'; -import DisplayName from '../../../components/display_name'; +import { DisplayName } from '../../../components/display_name'; import { IconButton } from '../../../components/icon_button'; import { defineMessages, injectIntl } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; diff --git a/app/javascript/mastodon/features/list_adder/components/account.jsx b/app/javascript/mastodon/features/list_adder/components/account.jsx index 410f1537a5..5dc384aba6 100644 --- a/app/javascript/mastodon/features/list_adder/components/account.jsx +++ b/app/javascript/mastodon/features/list_adder/components/account.jsx @@ -4,7 +4,7 @@ import { makeGetAccount } from '../../../selectors'; import ImmutablePureComponent from 'react-immutable-pure-component'; import ImmutablePropTypes from 'react-immutable-proptypes'; import { Avatar } from '../../../components/avatar'; -import DisplayName from '../../../components/display_name'; +import { DisplayName } from '../../../components/display_name'; import { injectIntl } from 'react-intl'; const makeMapStateToProps = () => { diff --git a/app/javascript/mastodon/features/list_editor/components/account.jsx b/app/javascript/mastodon/features/list_editor/components/account.jsx index b46d0504a4..fc1d2d6071 100644 --- a/app/javascript/mastodon/features/list_editor/components/account.jsx +++ b/app/javascript/mastodon/features/list_editor/components/account.jsx @@ -5,7 +5,7 @@ import { makeGetAccount } from '../../../selectors'; import ImmutablePureComponent from 'react-immutable-pure-component'; import ImmutablePropTypes from 'react-immutable-proptypes'; import { Avatar } from '../../../components/avatar'; -import DisplayName from '../../../components/display_name'; +import { DisplayName } from '../../../components/display_name'; import { IconButton } from '../../../components/icon_button'; import { defineMessages, injectIntl } from 'react-intl'; import { removeFromListEditor, addToListEditor } from '../../../actions/lists'; diff --git a/app/javascript/mastodon/features/notifications/components/follow_request.jsx b/app/javascript/mastodon/features/notifications/components/follow_request.jsx index 0d930f0b1f..d8b2ca1cc9 100644 --- a/app/javascript/mastodon/features/notifications/components/follow_request.jsx +++ b/app/javascript/mastodon/features/notifications/components/follow_request.jsx @@ -2,7 +2,7 @@ import React from 'react'; import ImmutablePropTypes from 'react-immutable-proptypes'; import PropTypes from 'prop-types'; import { Avatar } from 'mastodon/components/avatar'; -import DisplayName from 'mastodon/components/display_name'; +import { DisplayName } from 'mastodon/components/display_name'; import { Link } from 'react-router-dom'; import { IconButton } from 'mastodon/components/icon_button'; import { defineMessages, injectIntl } from 'react-intl'; diff --git a/app/javascript/mastodon/features/picture_in_picture/components/header.jsx b/app/javascript/mastodon/features/picture_in_picture/components/header.jsx index c6d2a103dc..c1c04da548 100644 --- a/app/javascript/mastodon/features/picture_in_picture/components/header.jsx +++ b/app/javascript/mastodon/features/picture_in_picture/components/header.jsx @@ -6,7 +6,7 @@ import PropTypes from 'prop-types'; import { IconButton } from 'mastodon/components/icon_button'; import { Link } from 'react-router-dom'; import { Avatar } from 'mastodon/components/avatar'; -import DisplayName from 'mastodon/components/display_name'; +import { DisplayName } from 'mastodon/components/display_name'; import { defineMessages, injectIntl } from 'react-intl'; const messages = defineMessages({ diff --git a/app/javascript/mastodon/features/report/components/status_check_box.jsx b/app/javascript/mastodon/features/report/components/status_check_box.jsx index 373b8979e5..6ecb470c40 100644 --- a/app/javascript/mastodon/features/report/components/status_check_box.jsx +++ b/app/javascript/mastodon/features/report/components/status_check_box.jsx @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; import StatusContent from 'mastodon/components/status_content'; import { Avatar } from 'mastodon/components/avatar'; -import DisplayName from 'mastodon/components/display_name'; +import { DisplayName } from 'mastodon/components/display_name'; import { RelativeTimestamp } from 'mastodon/components/relative_timestamp'; import Option from './option'; import MediaAttachments from 'mastodon/components/media_attachments'; diff --git a/app/javascript/mastodon/features/status/components/detailed_status.jsx b/app/javascript/mastodon/features/status/components/detailed_status.jsx index 62a3ce282e..cb9302c8d2 100644 --- a/app/javascript/mastodon/features/status/components/detailed_status.jsx +++ b/app/javascript/mastodon/features/status/components/detailed_status.jsx @@ -2,7 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; import { Avatar } from '../../../components/avatar'; -import DisplayName from '../../../components/display_name'; +import { DisplayName } from '../../../components/display_name'; import StatusContent from '../../../components/status_content'; import StatusEmojiReactionsBar from '../../../components/status_emoji_reactions_bar'; import MediaGallery from '../../../components/media_gallery'; diff --git a/app/javascript/mastodon/features/ui/components/boost_modal.jsx b/app/javascript/mastodon/features/ui/components/boost_modal.jsx index 67e00e971b..2c1e4d401b 100644 --- a/app/javascript/mastodon/features/ui/components/boost_modal.jsx +++ b/app/javascript/mastodon/features/ui/components/boost_modal.jsx @@ -7,7 +7,7 @@ import Button from '../../../components/button'; import StatusContent from '../../../components/status_content'; import { Avatar } from '../../../components/avatar'; import { RelativeTimestamp } from '../../../components/relative_timestamp'; -import DisplayName from '../../../components/display_name'; +import { DisplayName } from '../../../components/display_name'; import ImmutablePureComponent from 'react-immutable-pure-component'; import { Icon } from 'mastodon/components/icon'; import AttachmentList from 'mastodon/components/attachment_list'; diff --git a/app/javascript/mastodon/is_mobile.ts b/app/javascript/mastodon/is_mobile.ts index 43819f85db..b2918eb4bf 100644 --- a/app/javascript/mastodon/is_mobile.ts +++ b/app/javascript/mastodon/is_mobile.ts @@ -16,10 +16,6 @@ export const layoutFromWindow = (): LayoutType => { } }; -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-expect-error -const iOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && window.MSStream != null; - const listenerOptions = supportsPassiveEvents ? { passive: true } : false; let userTouching = false; @@ -33,5 +29,3 @@ const touchListener = () => { window.addEventListener('touchstart', touchListener, listenerOptions); export const isUserTouching = () => userTouching; - -export const isIOS = () => iOS; diff --git a/app/javascript/mastodon/main.jsx b/app/javascript/mastodon/main.jsx index d8654adedb..c5960477db 100644 --- a/app/javascript/mastodon/main.jsx +++ b/app/javascript/mastodon/main.jsx @@ -2,7 +2,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { setupBrowserNotifications } from 'mastodon/actions/notifications'; import Mastodon from 'mastodon/containers/mastodon'; -import { store } from 'mastodon/store/configureStore'; +import { store } from 'mastodon/store'; import { me } from 'mastodon/initial_state'; import ready from 'mastodon/ready'; import * as perf from 'mastodon/performance'; diff --git a/app/javascript/mastodon/middleware/loading_bar.js b/app/javascript/mastodon/middleware/loading_bar.js deleted file mode 100644 index da8cc4c7d3..0000000000 --- a/app/javascript/mastodon/middleware/loading_bar.js +++ /dev/null @@ -1,25 +0,0 @@ -import { showLoading, hideLoading } from 'react-redux-loading-bar'; - -const defaultTypeSuffixes = ['PENDING', 'FULFILLED', 'REJECTED']; - -export default function loadingBarMiddleware(config = {}) { - const promiseTypeSuffixes = config.promiseTypeSuffixes || defaultTypeSuffixes; - - return ({ dispatch }) => next => (action) => { - if (action.type && !action.skipLoading) { - const [PENDING, FULFILLED, REJECTED] = promiseTypeSuffixes; - - const isPending = new RegExp(`${PENDING}$`, 'g'); - const isFulfilled = new RegExp(`${FULFILLED}$`, 'g'); - const isRejected = new RegExp(`${REJECTED}$`, 'g'); - - if (action.type.match(isPending)) { - dispatch(showLoading()); - } else if (action.type.match(isFulfilled) || action.type.match(isRejected)) { - dispatch(hideLoading()); - } - } - - return next(action); - }; -} diff --git a/app/javascript/mastodon/permissions.ts b/app/javascript/mastodon/permissions.ts index 9ea149e5f8..b583535c00 100644 --- a/app/javascript/mastodon/permissions.ts +++ b/app/javascript/mastodon/permissions.ts @@ -1,4 +1,4 @@ -export const PERMISSION_INVITE_USERS = 0x0000000000010000; -export const PERMISSION_MANAGE_USERS = 0x0000000000000400; +export const PERMISSION_INVITE_USERS = 0x0000000000010000; +export const PERMISSION_MANAGE_USERS = 0x0000000000000400; export const PERMISSION_MANAGE_FEDERATION = 0x0000000000000020; -export const PERMISSION_MANAGE_REPORTS = 0x0000000000000010; +export const PERMISSION_MANAGE_REPORTS = 0x0000000000000010; diff --git a/app/javascript/mastodon/base_polyfills.js b/app/javascript/mastodon/polyfills/base_polyfills.ts similarity index 58% rename from app/javascript/mastodon/base_polyfills.js rename to app/javascript/mastodon/polyfills/base_polyfills.ts index 91bc5d6dc8..64211c11e9 100644 --- a/app/javascript/mastodon/base_polyfills.js +++ b/app/javascript/mastodon/polyfills/base_polyfills.ts @@ -1,26 +1,16 @@ import 'intl'; import 'intl/locale-data/jsonp/en'; -import 'es6-symbol/implement'; -import assign from 'object-assign'; -import values from 'object.values'; -import { decode as decodeBase64 } from './utils/base64'; -import promiseFinally from 'promise.prototype.finally'; - -if (!Object.assign) { - Object.assign = assign; -} - -if (!Object.values) { - values.shim(); -} - -promiseFinally.shim(); +import 'core-js/features/object/assign'; +import 'core-js/features/object/values'; +import 'core-js/features/symbol'; +import 'core-js/features/promise/finally'; +import { decode as decodeBase64 } from '../utils/base64'; if (!HTMLCanvasElement.prototype.toBlob) { const BASE64_MARKER = ';base64,'; Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', { - value(callback, type = 'image/png', quality) { + value(callback: BlobCallback, type = 'image/png', quality: any) { const dataURL = this.toDataURL(type, quality); let data; diff --git a/app/javascript/mastodon/extra_polyfills.js b/app/javascript/mastodon/polyfills/extra_polyfills.ts similarity index 100% rename from app/javascript/mastodon/extra_polyfills.js rename to app/javascript/mastodon/polyfills/extra_polyfills.ts diff --git a/app/javascript/mastodon/load_polyfills.js b/app/javascript/mastodon/polyfills/index.ts similarity index 82% rename from app/javascript/mastodon/load_polyfills.js rename to app/javascript/mastodon/polyfills/index.ts index 7909dc4ea3..6d2e5426e4 100644 --- a/app/javascript/mastodon/load_polyfills.js +++ b/app/javascript/mastodon/polyfills/index.ts @@ -10,14 +10,14 @@ function importExtraPolyfills() { return import(/* webpackChunkName: "extra_polyfills" */ './extra_polyfills'); } -function loadPolyfills() { +export function loadPolyfills() { const needsBasePolyfills = !( - HTMLCanvasElement.prototype.toBlob && - window.Intl && - Object.assign && - Object.values && - window.Symbol && - Promise.prototype.finally + 'toBlob' in HTMLCanvasElement.prototype && + 'Intl' in window && + 'assign' in Object && + 'values' in Object && + 'Symbol' in window && + 'finally' in Promise.prototype ); // Latest version of Firefox and Safari do not have IntersectionObserver. @@ -36,5 +36,3 @@ function loadPolyfills() { needsExtraPolyfills && importExtraPolyfills(), ]); } - -export default loadPolyfills; diff --git a/app/javascript/mastodon/reducers/index.js b/app/javascript/mastodon/reducers/index.ts similarity index 97% rename from app/javascript/mastodon/reducers/index.js rename to app/javascript/mastodon/reducers/index.ts index dfbd58a234..0850548531 100644 --- a/app/javascript/mastodon/reducers/index.js +++ b/app/javascript/mastodon/reducers/index.ts @@ -93,4 +93,6 @@ const reducers = { followed_tags, }; -export default combineReducers(reducers); +const rootReducer = combineReducers(reducers); + +export { rootReducer }; diff --git a/app/javascript/mastodon/reducers/missed_updates.ts b/app/javascript/mastodon/reducers/missed_updates.ts index 628fed2a99..9c1a5cbd26 100644 --- a/app/javascript/mastodon/reducers/missed_updates.ts +++ b/app/javascript/mastodon/reducers/missed_updates.ts @@ -14,18 +14,18 @@ const initialState = Record({ export function missedUpdatesReducer( state = initialState, - action: Action, + action: Action ) { switch (action.type) { - case focusApp.type: - return state.set('focused', true).set('unread', 0); - case unfocusApp.type: - return state.set('focused', false); - case NOTIFICATIONS_UPDATE: - return state.get('focused') - ? state - : state.update('unread', (x) => x + 1); - default: - return state; + case focusApp.type: + return state.set('focused', true).set('unread', 0); + case unfocusApp.type: + return state.set('focused', false); + case NOTIFICATIONS_UPDATE: + return state.get('focused') + ? state + : state.update('unread', (x) => x + 1); + default: + return state; } } diff --git a/app/javascript/mastodon/scroll.ts b/app/javascript/mastodon/scroll.ts index 1e509c4175..625aab0c04 100644 --- a/app/javascript/mastodon/scroll.ts +++ b/app/javascript/mastodon/scroll.ts @@ -1,13 +1,23 @@ -const easingOutQuint = (x: number, t: number, b: number, c: number, d: number) => c * ((t = t / d - 1) * t * t * t * t + 1) + b; -const scroll = (node: Element, key: 'scrollTop' | 'scrollLeft', target: number) => { +const easingOutQuint = ( + x: number, + t: number, + b: number, + c: number, + d: number +) => c * ((t = t / d - 1) * t * t * t * t + 1) + b; +const scroll = ( + node: Element, + key: 'scrollTop' | 'scrollLeft', + target: number +) => { const startTime = Date.now(); - const offset = node[key]; - const gap = target - offset; - const duration = 1000; - let interrupt = false; + const offset = node[key]; + const gap = target - offset; + const duration = 1000; + let interrupt = false; const step = () => { - const elapsed = Date.now() - startTime; + const elapsed = Date.now() - startTime; const percentage = elapsed / duration; if (percentage > 1 || interrupt) { @@ -25,7 +35,14 @@ const scroll = (node: Element, key: 'scrollTop' | 'scrollLeft', target: number) }; }; -const isScrollBehaviorSupported = 'scrollBehavior' in document.documentElement.style; +const isScrollBehaviorSupported = + 'scrollBehavior' in document.documentElement.style; -export const scrollRight = (node: Element, position: number) => isScrollBehaviorSupported ? node.scrollTo({ left: position, behavior: 'smooth' }) : scroll(node, 'scrollLeft', position); -export const scrollTop = (node: Element) => isScrollBehaviorSupported ? node.scrollTo({ top: 0, behavior: 'smooth' }) : scroll(node, 'scrollTop', 0); +export const scrollRight = (node: Element, position: number) => + isScrollBehaviorSupported + ? node.scrollTo({ left: position, behavior: 'smooth' }) + : scroll(node, 'scrollLeft', position); +export const scrollTop = (node: Element) => + isScrollBehaviorSupported + ? node.scrollTo({ top: 0, behavior: 'smooth' }) + : scroll(node, 'scrollTop', 0); diff --git a/app/javascript/mastodon/store/configureStore.js b/app/javascript/mastodon/store/configureStore.js deleted file mode 100644 index cb17dd9ce8..0000000000 --- a/app/javascript/mastodon/store/configureStore.js +++ /dev/null @@ -1,16 +0,0 @@ -import { configureStore } from '@reduxjs/toolkit'; -import thunk from 'redux-thunk'; -import appReducer from '../reducers'; -import loadingBarMiddleware from '../middleware/loading_bar'; -import errorsMiddleware from '../middleware/errors'; -import soundsMiddleware from '../middleware/sounds'; - -export const store = configureStore({ - reducer: appReducer, - middleware: [ - thunk, - loadingBarMiddleware({ promiseTypeSuffixes: ['REQUEST', 'SUCCESS', 'FAIL'] }), - errorsMiddleware(), - soundsMiddleware(), - ], -}); diff --git a/app/javascript/mastodon/store/index.ts b/app/javascript/mastodon/store/index.ts new file mode 100644 index 0000000000..6c3e963d9e --- /dev/null +++ b/app/javascript/mastodon/store/index.ts @@ -0,0 +1,27 @@ +import { configureStore } from '@reduxjs/toolkit'; +import { rootReducer } from '../reducers'; +import { loadingBarMiddleware } from './middlewares/loading_bar'; +import { errorsMiddleware } from './middlewares/errors'; +import { soundsMiddleware } from './middlewares/sounds'; +import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'; + +export const store = configureStore({ + reducer: rootReducer, + middleware: (getDefaultMiddleware) => + getDefaultMiddleware() + .concat( + loadingBarMiddleware({ + promiseTypeSuffixes: ['REQUEST', 'SUCCESS', 'FAIL'], + }) + ) + .concat(errorsMiddleware) + .concat(soundsMiddleware()), +}); + +// Infer the `RootState` and `AppDispatch` types from the store itself +export type RootState = ReturnType; +// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState} +export type AppDispatch = typeof store.dispatch; + +export const useAppDispatch: () => AppDispatch = useDispatch; +export const useAppSelector: TypedUseSelectorHook = useSelector; diff --git a/app/javascript/mastodon/middleware/errors.js b/app/javascript/mastodon/store/middlewares/errors.ts similarity index 54% rename from app/javascript/mastodon/middleware/errors.js rename to app/javascript/mastodon/store/middlewares/errors.ts index 708df6bb8d..a5e99d04e6 100644 --- a/app/javascript/mastodon/middleware/errors.js +++ b/app/javascript/mastodon/store/middlewares/errors.ts @@ -1,9 +1,13 @@ -import { showAlertForError } from '../actions/alerts'; +import { Middleware } from 'redux'; +import { showAlertForError } from '../../actions/alerts'; +import { RootState } from '..'; const defaultFailSuffix = 'FAIL'; -export default function errorsMiddleware() { - return ({ dispatch }) => next => action => { +export const errorsMiddleware: Middleware, RootState> = + ({ dispatch }) => + (next) => + (action) => { if (action.type && !action.skipAlert) { const isFail = new RegExp(`${defaultFailSuffix}$`, 'g'); @@ -14,4 +18,3 @@ export default function errorsMiddleware() { return next(action); }; -} diff --git a/app/javascript/mastodon/store/middlewares/loading_bar.ts b/app/javascript/mastodon/store/middlewares/loading_bar.ts new file mode 100644 index 0000000000..183c0cf9d6 --- /dev/null +++ b/app/javascript/mastodon/store/middlewares/loading_bar.ts @@ -0,0 +1,42 @@ +import { showLoading, hideLoading } from 'react-redux-loading-bar'; +import { Middleware } from 'redux'; +import { RootState } from '..'; + +interface Config { + promiseTypeSuffixes?: string[]; +} + +const defaultTypeSuffixes: Config['promiseTypeSuffixes'] = [ + 'PENDING', + 'FULFILLED', + 'REJECTED', +]; + +export const loadingBarMiddleware = ( + config: Config = {} +): Middleware, RootState> => { + const promiseTypeSuffixes = config.promiseTypeSuffixes || defaultTypeSuffixes; + + return ({ dispatch }) => + (next) => + (action) => { + if (action.type && !action.skipLoading) { + const [PENDING, FULFILLED, REJECTED] = promiseTypeSuffixes; + + const isPending = new RegExp(`${PENDING}$`, 'g'); + const isFulfilled = new RegExp(`${FULFILLED}$`, 'g'); + const isRejected = new RegExp(`${REJECTED}$`, 'g'); + + if (action.type.match(isPending)) { + dispatch(showLoading()); + } else if ( + action.type.match(isFulfilled) || + action.type.match(isRejected) + ) { + dispatch(hideLoading()); + } + } + + return next(action); + }; +}; diff --git a/app/javascript/mastodon/middleware/sounds.js b/app/javascript/mastodon/store/middlewares/sounds.ts similarity index 54% rename from app/javascript/mastodon/middleware/sounds.js rename to app/javascript/mastodon/store/middlewares/sounds.ts index 7f23889836..e7c87df7ec 100644 --- a/app/javascript/mastodon/middleware/sounds.js +++ b/app/javascript/mastodon/store/middlewares/sounds.ts @@ -1,4 +1,12 @@ -const createAudio = sources => { +import { Middleware, AnyAction } from 'redux'; +import { RootState } from '..'; + +interface AudioSource { + src: string; + type: string; +} + +const createAudio = (sources: AudioSource[]) => { const audio = new Audio(); sources.forEach(({ type, src }) => { const source = document.createElement('source'); @@ -9,7 +17,7 @@ const createAudio = sources => { return audio; }; -const play = audio => { +const play = (audio: HTMLAudioElement) => { if (!audio.paused) { audio.pause(); if (typeof audio.fastSeek === 'function') { @@ -22,8 +30,11 @@ const play = audio => { audio.play(); }; -export default function soundsMiddleware() { - const soundCache = { +export const soundsMiddleware = (): Middleware< + Record, + RootState +> => { + const soundCache: { [key: string]: HTMLAudioElement } = { boop: createAudio([ { src: '/sounds/boop.ogg', @@ -36,11 +47,13 @@ export default function soundsMiddleware() { ]), }; - return () => next => action => { - if (action.meta && action.meta.sound && soundCache[action.meta.sound]) { - play(soundCache[action.meta.sound]); + return () => (next) => (action: AnyAction) => { + const sound = action?.meta?.sound; + + if (sound && soundCache[sound]) { + play(soundCache[sound]); } return next(action); }; -} +}; diff --git a/app/javascript/mastodon/utils/filters.ts b/app/javascript/mastodon/utils/filters.ts index 5af2aa96a4..e5c6422e0a 100644 --- a/app/javascript/mastodon/utils/filters.ts +++ b/app/javascript/mastodon/utils/filters.ts @@ -1,16 +1,16 @@ export const toServerSideType = (columnType: string) => { switch (columnType) { - case 'home': - case 'notifications': - case 'public': - case 'thread': - case 'account': - return columnType; - default: - if (columnType.indexOf('list:') > -1) { - return 'home'; - } else { - return 'public'; // community, account, hashtag - } + case 'home': + case 'notifications': + case 'public': + case 'thread': + case 'account': + return columnType; + default: + if (columnType.indexOf('list:') > -1) { + return 'home'; + } else { + return 'public'; // community, account, hashtag + } } }; diff --git a/app/javascript/mastodon/utils/hashtags.ts b/app/javascript/mastodon/utils/hashtags.ts index 358ce37f54..4c76cd7ded 100644 --- a/app/javascript/mastodon/utils/hashtags.ts +++ b/app/javascript/mastodon/utils/hashtags.ts @@ -5,17 +5,8 @@ const WORD = '\\p{L}\\p{M}\\p{N}\\p{Pc}'; const buildHashtagPatternRegex = () => { try { return new RegExp( - '(?:^|[^\\/\\)\\w])#((' + - '[' + WORD + '_]' + - '[' + WORD + HASHTAG_SEPARATORS + ']*' + - '[' + ALPHA + HASHTAG_SEPARATORS + ']' + - '[' + WORD + HASHTAG_SEPARATORS +']*' + - '[' + WORD + '_]' + - ')|(' + - '[' + WORD + '_]*' + - '[' + ALPHA + ']' + - '[' + WORD + '_]*' + - '))', 'iu', + `(?:^|[^\\/\\)\\w])#(([${WORD}_][${WORD}${HASHTAG_SEPARATORS}]*[${ALPHA}${HASHTAG_SEPARATORS}][${WORD}${HASHTAG_SEPARATORS}]*[${WORD}_])|([${WORD}_]*[${ALPHA}][${WORD}_]*))`, + 'iu' ); } catch { return /(?:^|[^/)\w])#(\w*[a-zA-Z·]\w*)/i; @@ -25,17 +16,8 @@ const buildHashtagPatternRegex = () => { const buildHashtagRegex = () => { try { return new RegExp( - '^((' + - '[' + WORD + '_]' + - '[' + WORD + HASHTAG_SEPARATORS + ']*' + - '[' + ALPHA + HASHTAG_SEPARATORS + ']' + - '[' + WORD + HASHTAG_SEPARATORS +']*' + - '[' + WORD + '_]' + - ')|(' + - '[' + WORD + '_]*' + - '[' + ALPHA + ']' + - '[' + WORD + '_]*' + - '))$', 'iu', + `^(([${WORD}_][${WORD}${HASHTAG_SEPARATORS}]*[${ALPHA}${HASHTAG_SEPARATORS}][${WORD}${HASHTAG_SEPARATORS}]*[${WORD}_])|([${WORD}_]*[${ALPHA}][${WORD}_]*))$`, + 'iu' ); } catch { return /^(\w*[a-zA-Z·]\w*)$/i; diff --git a/app/javascript/mastodon/utils/numbers.ts b/app/javascript/mastodon/utils/numbers.ts index 35af8a973c..a4a028c30e 100644 --- a/app/javascript/mastodon/utils/numbers.ts +++ b/app/javascript/mastodon/utils/numbers.ts @@ -21,7 +21,7 @@ const TEN_MILLIONS = DECIMAL_UNITS.MILLION * 10; * shortNumber(5936); * // => [5.936, 1000, 1] */ -export type ShortNumber = [number, DecimalUnits, 0 | 1] // Array of: shorten number, unit of shorten number and maximum fraction digits +export type ShortNumber = [number, DecimalUnits, 0 | 1]; // Array of: shorten number, unit of shorten number and maximum fraction digits export function toShortNumber(sourceNumber: number): ShortNumber { if (sourceNumber < DECIMAL_UNITS.THOUSAND) { return [sourceNumber, DECIMAL_UNITS.ONE, 0]; @@ -38,11 +38,7 @@ export function toShortNumber(sourceNumber: number): ShortNumber { sourceNumber < TEN_MILLIONS ? 1 : 0, ]; } else if (sourceNumber < DECIMAL_UNITS.TRILLION) { - return [ - sourceNumber / DECIMAL_UNITS.BILLION, - DECIMAL_UNITS.BILLION, - 0, - ]; + return [sourceNumber / DECIMAL_UNITS.BILLION, DECIMAL_UNITS.BILLION, 0]; } return [sourceNumber, DECIMAL_UNITS.ONE, 0]; @@ -56,7 +52,10 @@ export function toShortNumber(sourceNumber: number): ShortNumber { * pluralReady(1793, DECIMAL_UNITS.THOUSAND) * // => 1790 */ -export function pluralReady(sourceNumber: number, division: DecimalUnits): number { +export function pluralReady( + sourceNumber: number, + division: DecimalUnits +): number { if (division == null || division < DECIMAL_UNITS.HUNDRED) { return sourceNumber; } diff --git a/app/javascript/mastodon/uuid.ts b/app/javascript/mastodon/uuid.ts index cabbc0f4ed..6cadbd6bb0 100644 --- a/app/javascript/mastodon/uuid.ts +++ b/app/javascript/mastodon/uuid.ts @@ -1,8 +1,8 @@ export function uuid(a?: string): string { return a ? ( - (a as any as number) ^ + (a as any as number) ^ ((Math.random() * 16) >> ((a as any as number) / 4)) - ).toString(16) + ).toString(16) : ('' + 1e7 + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, uuid); } diff --git a/app/javascript/packs/application.js b/app/javascript/packs/application.js index 020f2b4a0e..ab87083659 100644 --- a/app/javascript/packs/application.js +++ b/app/javascript/packs/application.js @@ -1,5 +1,5 @@ import './public-path'; -import loadPolyfills from '../mastodon/load_polyfills'; +import { loadPolyfills } from '../mastodon/polyfills'; import { start } from '../mastodon/common'; start(); diff --git a/app/javascript/packs/public.jsx b/app/javascript/packs/public.jsx index 21c52fc12a..1ea39e05a6 100644 --- a/app/javascript/packs/public.jsx +++ b/app/javascript/packs/public.jsx @@ -1,9 +1,9 @@ import './public-path'; -import loadPolyfills from '../mastodon/load_polyfills'; +import escapeTextContentForBrowser from 'escape-html'; +import { loadPolyfills } from '../mastodon/polyfills'; +import ready from '../mastodon/ready'; import { start } from '../mastodon/common'; -import escapeTextContentForBrowser from 'escape-html'; -import ready from '../mastodon/ready'; import loadKeyboardExtensions from '../mastodon/load_keyboard_extensions'; import 'cocoon-js-vanilla'; import axios from 'axios'; @@ -12,7 +12,7 @@ import { defineMessages } from 'react-intl'; import * as IntlMessageFormat from 'intl-messageformat'; import { timeAgoString } from '../mastodon/components/relative_timestamp'; import { delegate } from '@rails/ujs'; -import * as emojify from '../mastodon/features/emoji/emoji'; +import emojify from '../mastodon/features/emoji/emoji'; import { getLocale } from '../mastodon/locales'; import React from 'react'; import ReactDOM from 'react-dom'; diff --git a/app/javascript/packs/share.jsx b/app/javascript/packs/share.jsx index 97c3c7b0e5..542a2f3ae8 100644 --- a/app/javascript/packs/share.jsx +++ b/app/javascript/packs/share.jsx @@ -1,5 +1,5 @@ import './public-path'; -import loadPolyfills from '../mastodon/load_polyfills'; +import { loadPolyfills } from '../mastodon/polyfills'; import { start } from '../mastodon/common'; import ready from '../mastodon/ready'; import ComposeContainer from '../mastodon/containers/compose_container'; diff --git a/app/javascript/types/resources.ts b/app/javascript/types/resources.ts index 28fad2719a..0906504150 100644 --- a/app/javascript/types/resources.ts +++ b/app/javascript/types/resources.ts @@ -1,10 +1,54 @@ import type { Record } from 'immutable'; -type AccountValues = { - id: number; +type CustomEmoji = Record<{ + shortcode: string; + static_url: string; + url: string; +}>; + +type AccountField = Record<{ + name: string; + value: string; + verified_at: string | null; +}>; + +type AccountApiResponseValues = { + acct: string; avatar: string; avatar_static: string; - [key: string]: any; + bot: boolean; + created_at: string; + discoverable: boolean; + display_name: string; + emojis: CustomEmoji[]; + fields: AccountField[]; + followers_count: number; + following_count: number; + group: boolean; + header: string; + header_static: string; + id: string; + last_status_at: string; + locked: boolean; + note: string; + statuses_count: number; + url: string; + username: string; }; -export type Account = Record; +type NormalizedAccountField = Record<{ + name_emojified: string; + value_emojified: string; + value_plain: string; +}>; + +type NormalizedAccountValues = { + display_name_html: string; + fields: NormalizedAccountField[]; + note_emojified: string; + note_plain: string; +}; + +export type Account = Record< + AccountApiResponseValues & NormalizedAccountValues +>; diff --git a/lib/mastodon/ip_blocks_cli.rb b/lib/mastodon/ip_blocks_cli.rb index 3b99595857..82a08753bc 100644 --- a/lib/mastodon/ip_blocks_cli.rb +++ b/lib/mastodon/ip_blocks_cli.rb @@ -11,7 +11,7 @@ module Mastodon true end - option :severity, required: true, enum: %w(no_access sign_up_requires_approval), desc: 'Severity of the block' + option :severity, required: true, enum: %w(no_access sign_up_requires_approval sign_up_block), desc: 'Severity of the block' option :comment, aliases: [:c], desc: 'Optional comment' option :duration, aliases: [:d], type: :numeric, desc: 'Duration of the block in seconds' option :force, type: :boolean, aliases: [:f], desc: 'Overwrite existing blocks' @@ -36,6 +36,12 @@ module Mastodon failed = 0 addresses.each do |address| + unless valid_ip_address?(address) + say("#{address} is invalid", :red) + failed += 1 + next + end + ip_block = IpBlock.find_by(ip: address) if ip_block.present? && !options[:force] @@ -79,6 +85,12 @@ module Mastodon skipped = 0 addresses.each do |address| + unless valid_ip_address?(address) + say("#{address} is invalid", :yellow) + skipped += 1 + next + end + ip_blocks = if options[:force] IpBlock.where('ip >>= ?', address) else @@ -126,5 +138,12 @@ module Mastodon :red end end + + def valid_ip_address?(ip_address) + IPAddr.new(ip_address) + true + rescue IPAddr::InvalidAddressError + false + end end end diff --git a/package.json b/package.json index 76deabc26b..b326dfd45a 100644 --- a/package.json +++ b/package.json @@ -52,13 +52,13 @@ "cocoon-js-vanilla": "^1.3.0", "color-blend": "^4.0.0", "compression-webpack-plugin": "^6.1.1", + "core-js": "^3.30.2", "cross-env": "^7.0.3", "css-loader": "^5.2.7", "cssnano": "^6.0.1", "detect-passive-events": "^2.0.3", "dotenv": "^16.0.3", "emoji-mart": "npm:emoji-mart-lazyload@latest", - "es6-symbol": "^3.1.3", "escape-html": "^1.0.3", "express": "^4.18.2", "file-loader": "^6.2.0", @@ -80,14 +80,11 @@ "mini-css-extract-plugin": "^1.6.2", "mkdirp": "^2.1.6", "npmlog": "^7.0.1", - "object-assign": "^4.1.1", - "object.values": "^1.1.6", "path-complete-extname": "^1.0.0", "pg": "^8.5.0", "pg-connection-string": "^2.5.0", "postcss": "^8.4.23", "postcss-loader": "^4.3.0", - "promise.prototype.finally": "^3.1.4", "prop-types": "^15.8.1", "punycode": "^2.3.0", "react": "^16.14.0", @@ -126,7 +123,7 @@ "tesseract.js": "^2.1.5", "tiny-queue": "^0.2.1", "twitter-text": "3.1.0", - "uuid": "^8.3.1", + "uuid": "^9.0.0", "webpack": "^4.46.0", "webpack-assets-manifest": "^4.0.6", "webpack-bundle-analyzer": "^4.8.0", @@ -176,17 +173,19 @@ "@types/react-toggle": "^4.0.3", "@types/redux-immutable": "^4.0.3", "@types/requestidlecallback": "^0.3.5", - "@types/uuid": "^8.3.4", + "@types/uuid": "^9.0.0", "@types/webpack": "^4.41.33", "@types/yargs": "^17.0.24", - "@typescript-eslint/eslint-plugin": "^5.59.2", - "@typescript-eslint/parser": "^5.59.2", + "@typescript-eslint/eslint-plugin": "^5.59.5", + "@typescript-eslint/parser": "^5.59.5", "babel-jest": "^29.5.0", "eslint": "^8.39.0", + "eslint-config-prettier": "^8.8.0", "eslint-plugin-formatjs": "^4.10.1", "eslint-plugin-import": "~2.27.5", "eslint-plugin-jsdoc": "^43.1.1", "eslint-plugin-jsx-a11y": "~6.7.1", + "eslint-plugin-prettier": "^4.2.1", "eslint-plugin-promise": "~6.1.1", "eslint-plugin-react": "~7.32.2", "eslint-plugin-react-hooks": "^4.6.0", diff --git a/tsconfig.json b/tsconfig.json index 09cea2a75f..2c2193d55f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,6 +2,7 @@ "compilerOptions": { "jsx": "react", "target": "esnext", + "module": "CommonJS", "moduleResolution": "node", "allowJs": true, "noEmit": true, diff --git a/yarn.lock b/yarn.lock index 3114f26a3e..cd0abca76a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2425,10 +2425,10 @@ dependencies: source-map "^0.6.1" -"@types/uuid@^8.3.4": - version "8.3.4" - resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc" - integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw== +"@types/uuid@^9.0.0": + version "9.0.1" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.1.tgz#98586dc36aee8dacc98cc396dbca8d0429647aa6" + integrity sha512-rFT3ak0/2trgvp4yYZo5iKFEPsET7vKydKF+VRCxlQ9bpheehyAJH89dAkaLEq/j/RZXJIqcgsmPJKUP1Z28HA== "@types/warning@^3.0.0": version "3.0.0" @@ -2475,15 +2475,15 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@^5.59.2": - version "5.59.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.2.tgz#684a2ce7182f3b4dac342eef7caa1c2bae476abd" - integrity sha512-yVrXupeHjRxLDcPKL10sGQ/QlVrA8J5IYOEWVqk0lJaSZP7X5DfnP7Ns3cc74/blmbipQ1htFNVGsHX6wsYm0A== +"@typescript-eslint/eslint-plugin@^5.59.5": + version "5.59.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.5.tgz#f156827610a3f8cefc56baeaa93cd4a5f32966b4" + integrity sha512-feA9xbVRWJZor+AnLNAr7A8JRWeZqHUf4T9tlP+TN04b05pFVhO5eN7/O93Y/1OUlLMHKbnJisgDURs/qvtqdg== dependencies: "@eslint-community/regexpp" "^4.4.0" - "@typescript-eslint/scope-manager" "5.59.2" - "@typescript-eslint/type-utils" "5.59.2" - "@typescript-eslint/utils" "5.59.2" + "@typescript-eslint/scope-manager" "5.59.5" + "@typescript-eslint/type-utils" "5.59.5" + "@typescript-eslint/utils" "5.59.5" debug "^4.3.4" grapheme-splitter "^1.0.4" ignore "^5.2.0" @@ -2491,31 +2491,31 @@ semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/parser@^5.59.2": - version "5.59.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.59.2.tgz#c2c443247901d95865b9f77332d9eee7c55655e8" - integrity sha512-uq0sKyw6ao1iFOZZGk9F8Nro/8+gfB5ezl1cA06SrqbgJAt0SRoFhb9pXaHvkrxUpZaoLxt8KlovHNk8Gp6/HQ== +"@typescript-eslint/parser@^5.59.5": + version "5.59.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.59.5.tgz#63064f5eafbdbfb5f9dfbf5c4503cdf949852981" + integrity sha512-NJXQC4MRnF9N9yWqQE2/KLRSOLvrrlZb48NGVfBa+RuPMN6B7ZcK5jZOvhuygv4D64fRKnZI4L4p8+M+rfeQuw== dependencies: - "@typescript-eslint/scope-manager" "5.59.2" - "@typescript-eslint/types" "5.59.2" - "@typescript-eslint/typescript-estree" "5.59.2" + "@typescript-eslint/scope-manager" "5.59.5" + "@typescript-eslint/types" "5.59.5" + "@typescript-eslint/typescript-estree" "5.59.5" debug "^4.3.4" -"@typescript-eslint/scope-manager@5.59.2": - version "5.59.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.59.2.tgz#f699fe936ee4e2c996d14f0fdd3a7da5ba7b9a4c" - integrity sha512-dB1v7ROySwQWKqQ8rEWcdbTsFjh2G0vn8KUyvTXdPoyzSL6lLGkiXEV5CvpJsEe9xIdKV+8Zqb7wif2issoOFA== +"@typescript-eslint/scope-manager@5.59.5": + version "5.59.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.59.5.tgz#33ffc7e8663f42cfaac873de65ebf65d2bce674d" + integrity sha512-jVecWwnkX6ZgutF+DovbBJirZcAxgxC0EOHYt/niMROf8p4PwxxG32Qdhj/iIQQIuOflLjNkxoXyArkcIP7C3A== dependencies: - "@typescript-eslint/types" "5.59.2" - "@typescript-eslint/visitor-keys" "5.59.2" + "@typescript-eslint/types" "5.59.5" + "@typescript-eslint/visitor-keys" "5.59.5" -"@typescript-eslint/type-utils@5.59.2": - version "5.59.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.59.2.tgz#0729c237503604cd9a7084b5af04c496c9a4cdcf" - integrity sha512-b1LS2phBOsEy/T381bxkkywfQXkV1dWda/z0PhnIy3bC5+rQWQDS7fk9CSpcXBccPY27Z6vBEuaPBCKCgYezyQ== +"@typescript-eslint/type-utils@5.59.5": + version "5.59.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.59.5.tgz#485b0e2c5b923460bc2ea6b338c595343f06fc9b" + integrity sha512-4eyhS7oGym67/pSxA2mmNq7X164oqDYNnZCUayBwJZIRVvKpBCMBzFnFxjeoDeShjtO6RQBHBuwybuX3POnDqg== dependencies: - "@typescript-eslint/typescript-estree" "5.59.2" - "@typescript-eslint/utils" "5.59.2" + "@typescript-eslint/typescript-estree" "5.59.5" + "@typescript-eslint/utils" "5.59.5" debug "^4.3.4" tsutils "^3.21.0" @@ -2524,10 +2524,10 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.0.tgz#3fcdac7dbf923ec5251545acdd9f1d42d7c4fe32" integrity sha512-yR2h1NotF23xFFYKHZs17QJnB51J/s+ud4PYU4MqdZbzeNxpgUr05+dNeCN/bb6raslHvGdd6BFCkVhpPk/ZeA== -"@typescript-eslint/types@5.59.2": - version "5.59.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.2.tgz#b511d2b9847fe277c5cb002a2318bd329ef4f655" - integrity sha512-LbJ/HqoVs2XTGq5shkiKaNTuVv5tTejdHgfdjqRUGdYhjW1crm/M7og2jhVskMt8/4wS3T1+PfFvL1K3wqYj4w== +"@typescript-eslint/types@5.59.5": + version "5.59.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.5.tgz#e63c5952532306d97c6ea432cee0981f6d2258c7" + integrity sha512-xkfRPHbqSH4Ggx4eHRIO/eGL8XL4Ysb4woL8c87YuAo8Md7AUjyWKa9YMwTL519SyDPrfEgKdewjkxNCVeJW7w== "@typescript-eslint/typescript-estree@5.59.0": version "5.59.0" @@ -2542,30 +2542,30 @@ semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/typescript-estree@5.59.2": - version "5.59.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.2.tgz#6e2fabd3ba01db5d69df44e0b654c0b051fe9936" - integrity sha512-+j4SmbwVmZsQ9jEyBMgpuBD0rKwi9RxRpjX71Brr73RsYnEr3Lt5QZ624Bxphp8HUkSKfqGnPJp1kA5nl0Sh7Q== +"@typescript-eslint/typescript-estree@5.59.5": + version "5.59.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.5.tgz#9b252ce55dd765e972a7a2f99233c439c5101e42" + integrity sha512-+XXdLN2CZLZcD/mO7mQtJMvCkzRfmODbeSKuMY/yXbGkzvA9rJyDY5qDYNoiz2kP/dmyAxXquL2BvLQLJFPQIg== dependencies: - "@typescript-eslint/types" "5.59.2" - "@typescript-eslint/visitor-keys" "5.59.2" + "@typescript-eslint/types" "5.59.5" + "@typescript-eslint/visitor-keys" "5.59.5" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/utils@5.59.2": - version "5.59.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.59.2.tgz#0c45178124d10cc986115885688db6abc37939f4" - integrity sha512-kSuF6/77TZzyGPhGO4uVp+f0SBoYxCDf+lW3GKhtKru/L8k/Hd7NFQxyWUeY7Z/KGB2C6Fe3yf2vVi4V9TsCSQ== +"@typescript-eslint/utils@5.59.5": + version "5.59.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.59.5.tgz#15b3eb619bb223302e60413adb0accd29c32bcae" + integrity sha512-sCEHOiw+RbyTii9c3/qN74hYDPNORb8yWCoPLmB7BIflhplJ65u2PBpdRla12e3SSTJ2erRkPjz7ngLHhUegxA== dependencies: "@eslint-community/eslint-utils" "^4.2.0" "@types/json-schema" "^7.0.9" "@types/semver" "^7.3.12" - "@typescript-eslint/scope-manager" "5.59.2" - "@typescript-eslint/types" "5.59.2" - "@typescript-eslint/typescript-estree" "5.59.2" + "@typescript-eslint/scope-manager" "5.59.5" + "@typescript-eslint/types" "5.59.5" + "@typescript-eslint/typescript-estree" "5.59.5" eslint-scope "^5.1.1" semver "^7.3.7" @@ -2577,12 +2577,12 @@ "@typescript-eslint/types" "5.59.0" eslint-visitor-keys "^3.3.0" -"@typescript-eslint/visitor-keys@5.59.2": - version "5.59.2" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.2.tgz#37a419dc2723a3eacbf722512b86d6caf7d3b750" - integrity sha512-EEpsO8m3RASrKAHI9jpavNv9NlEUebV4qmF1OWxSTtKSFBpC1NCmWazDQHFivRf0O1DV11BA645yrLEVQ0/Lig== +"@typescript-eslint/visitor-keys@5.59.5": + version "5.59.5" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.5.tgz#ba5b8d6791a13cf9fea6716af1e7626434b29b9b" + integrity sha512-qL+Oz+dbeBRTeyJTIy0eniD3uvqU7x+y1QceBismZ41hd4aBSRh8UAw4pZP0+XzLuPZmx4raNMq/I+59W2lXKA== dependencies: - "@typescript-eslint/types" "5.59.2" + "@typescript-eslint/types" "5.59.5" eslint-visitor-keys "^3.3.0" "@webassemblyjs/ast@1.9.0": @@ -4135,6 +4135,11 @@ core-js@^2.5.0: resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== +core-js@^3.30.2: + version "3.30.2" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.30.2.tgz#6528abfda65e5ad728143ea23f7a14f0dcf503fc" + integrity sha512-uBJiDmwqsbJCWHAwjrx3cvjbMXP7xD72Dmsn5LOJpiRmE3WbBbN5rCqQ2Qh6Ek6/eOrjlWngEynBWo4VxerQhg== + core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -4409,14 +4414,6 @@ csstype@^3.0.2: resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.6.tgz#865d0b5833d7d8d40f4e5b8a6d76aea3de4725ef" integrity sha512-+ZAmfyWMT7TiIlzdqJgjMb7S4f1beorDbWbsocyK4RaiqA5RTX3K14bnBWmmA9QEM0gRdsjyyrEmcyga8Zsxmw== -d@1, d@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" - integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA== - dependencies: - es5-ext "^0.10.50" - type "^1.0.1" - damerau-levenshtein@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7" @@ -4967,32 +4964,6 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" -es5-ext@^0.10.35, es5-ext@^0.10.50: - version "0.10.53" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.53.tgz#93c5a3acfdbef275220ad72644ad02ee18368de1" - integrity sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q== - dependencies: - es6-iterator "~2.0.3" - es6-symbol "~3.1.3" - next-tick "~1.0.0" - -es6-iterator@~2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" - integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c= - dependencies: - d "1" - es5-ext "^0.10.35" - es6-symbol "^3.1.1" - -es6-symbol@^3.1.1, es6-symbol@^3.1.3, es6-symbol@~3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" - integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA== - dependencies: - d "^1.0.1" - ext "^1.1.2" - escalade@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" @@ -5030,6 +5001,11 @@ escodegen@^2.0.0: optionalDependencies: source-map "~0.6.1" +eslint-config-prettier@^8.8.0: + version "8.8.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz#bfda738d412adc917fd7b038857110efe98c9348" + integrity sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA== + eslint-import-resolver-node@^0.3.7: version "0.3.7" resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz#83b375187d412324a1963d84fa664377a23eb4d7" @@ -5120,6 +5096,13 @@ eslint-plugin-jsx-a11y@~6.7.1: object.fromentries "^2.0.6" semver "^6.3.0" +eslint-plugin-prettier@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz#651cbb88b1dab98bfd42f017a12fa6b2d993f94b" + integrity sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ== + dependencies: + prettier-linter-helpers "^1.0.0" + eslint-plugin-promise@~6.1.1: version "6.1.1" resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz#269a3e2772f62875661220631bd4dafcb4083816" @@ -5425,13 +5408,6 @@ express@^4.17.1, express@^4.18.2: utils-merge "1.0.1" vary "~1.1.2" -ext@^1.1.2: - version "1.4.0" - resolved "https://registry.yarnpkg.com/ext/-/ext-1.4.0.tgz#89ae7a07158f79d35517882904324077e4379244" - integrity sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A== - dependencies: - type "^2.0.0" - extend-shallow@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" @@ -5466,6 +5442,11 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== +fast-diff@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" + integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== + fast-glob@^3.2.12, fast-glob@^3.2.9: version "3.2.12" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80" @@ -8234,11 +8215,6 @@ neo-async@^2.5.0, neo-async@^2.6.1, neo-async@^2.6.2: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== -next-tick@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" - integrity sha1-yobR/ogoFpsBICCOPchCS524NCw= - nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" @@ -9240,6 +9216,13 @@ prelude-ls@~1.1.2: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= +prettier-linter-helpers@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" + integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== + dependencies: + fast-diff "^1.1.2" + prettier@^2.8.8: version "2.8.8" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" @@ -9284,15 +9267,6 @@ promise-inflight@^1.0.1: resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= -promise.prototype.finally@^3.1.4: - version "3.1.4" - resolved "https://registry.yarnpkg.com/promise.prototype.finally/-/promise.prototype.finally-3.1.4.tgz#4e756a154e4db27fae24c6b18703495c31da3927" - integrity sha512-nNc3YbgMfLzqtqvO/q5DP6RR0SiHI9pUPGzyDf1q+usTwCN2kjvAnJkBb7bHe3o+fFSBPpsGMoYtaSi+LTNqng== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - prompts@^2.0.1: version "2.3.2" resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.3.2.tgz#480572d89ecf39566d2bd3fe2c9fccb7c4c0b068" @@ -11426,16 +11400,6 @@ type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" -type@^1.0.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" - integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg== - -type@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/type/-/type-2.0.0.tgz#5f16ff6ef2eb44f260494dae271033b29c09a9c3" - integrity sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow== - "typescript@^4.7 || 5", typescript@^5.0.4: version "5.0.4" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.0.4.tgz#b217fd20119bd61a94d4011274e0ab369058da3b" @@ -11654,10 +11618,10 @@ uuid@^3.3.2, uuid@^3.4.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== -uuid@^8.3.1: - version "8.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" - integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== +uuid@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5" + integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg== v8-compile-cache@^2.1.1, v8-compile-cache@^2.3.0: version "2.3.0"