mirror of
https://github.com/glitch-soc/mastodon
synced 2025-04-24 15:24:51 +00:00
Merge commit 'e8270e2807727e1cf6a47a40442b3038c5bca858' into glitch-soc/merge-upstream
Conflicts: - `.eslintrc.js`: Upstream moved it to `eslint.config.mjs`. Ported the glitch-soc changes there. - `yarn.lock`: Upstream updated dependencies close to glitch-soc-only dependencies. Ported upstream's changes.
This commit is contained in:
commit
e0406fcf02
38 changed files with 1227 additions and 963 deletions
|
@ -1,13 +0,0 @@
|
||||||
/build/**
|
|
||||||
/coverage/**
|
|
||||||
/db/**
|
|
||||||
/lib/**
|
|
||||||
/log/**
|
|
||||||
/node_modules/**
|
|
||||||
/nonobox/**
|
|
||||||
/public/**
|
|
||||||
!/public/embed.js
|
|
||||||
/spec/**
|
|
||||||
/tmp/**
|
|
||||||
/vendor/**
|
|
||||||
!.eslintrc.js
|
|
384
.eslintrc.js
384
.eslintrc.js
|
@ -1,384 +0,0 @@
|
||||||
// @ts-check
|
|
||||||
const { defineConfig } = require('eslint-define-config');
|
|
||||||
|
|
||||||
module.exports = defineConfig({
|
|
||||||
root: true,
|
|
||||||
|
|
||||||
extends: [
|
|
||||||
'eslint:recommended',
|
|
||||||
'plugin:react/recommended',
|
|
||||||
'plugin:react-hooks/recommended',
|
|
||||||
'plugin:jsx-a11y/recommended',
|
|
||||||
'plugin:import/recommended',
|
|
||||||
'plugin:promise/recommended',
|
|
||||||
'plugin:jsdoc/recommended',
|
|
||||||
],
|
|
||||||
|
|
||||||
env: {
|
|
||||||
browser: true,
|
|
||||||
node: true,
|
|
||||||
es6: true,
|
|
||||||
},
|
|
||||||
|
|
||||||
parser: '@typescript-eslint/parser',
|
|
||||||
|
|
||||||
plugins: [
|
|
||||||
'react',
|
|
||||||
'jsx-a11y',
|
|
||||||
'import',
|
|
||||||
'promise',
|
|
||||||
'@typescript-eslint',
|
|
||||||
'formatjs',
|
|
||||||
],
|
|
||||||
|
|
||||||
parserOptions: {
|
|
||||||
sourceType: 'module',
|
|
||||||
ecmaFeatures: {
|
|
||||||
jsx: true,
|
|
||||||
},
|
|
||||||
ecmaVersion: 2021,
|
|
||||||
requireConfigFile: false,
|
|
||||||
babelOptions: {
|
|
||||||
configFile: false,
|
|
||||||
presets: ['@babel/react', '@babel/env'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
settings: {
|
|
||||||
react: {
|
|
||||||
version: 'detect',
|
|
||||||
},
|
|
||||||
'import/ignore': [
|
|
||||||
'node_modules',
|
|
||||||
'\\.(css|scss|json)$',
|
|
||||||
],
|
|
||||||
'import/resolver': {
|
|
||||||
typescript: {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
rules: {
|
|
||||||
'consistent-return': 'error',
|
|
||||||
'dot-notation': 'error',
|
|
||||||
eqeqeq: ['error', 'always', { 'null': 'ignore' }],
|
|
||||||
'indent': ['error', 2],
|
|
||||||
'jsx-quotes': ['error', 'prefer-single'],
|
|
||||||
'semi': ['error', 'always'],
|
|
||||||
'no-catch-shadow': 'error',
|
|
||||||
'no-console': [
|
|
||||||
'warn',
|
|
||||||
{
|
|
||||||
allow: [
|
|
||||||
'error',
|
|
||||||
'warn',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'no-empty': ['error', { "allowEmptyCatch": true }],
|
|
||||||
'no-restricted-properties': [
|
|
||||||
'error',
|
|
||||||
{ property: 'substring', message: 'Use .slice instead of .substring.' },
|
|
||||||
{ property: 'substr', message: 'Use .slice instead of .substr.' },
|
|
||||||
],
|
|
||||||
'no-restricted-syntax': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
// eslint-disable-next-line no-restricted-syntax
|
|
||||||
selector: 'Literal[value=/•/], JSXText[value=/•/]',
|
|
||||||
// eslint-disable-next-line no-restricted-syntax
|
|
||||||
message: "Use '·' (middle dot) instead of '•' (bullet)",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'no-unused-expressions': 'error',
|
|
||||||
'no-unused-vars': 'off',
|
|
||||||
'@typescript-eslint/no-unused-vars': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
vars: 'all',
|
|
||||||
args: 'after-used',
|
|
||||||
destructuredArrayIgnorePattern: '^_',
|
|
||||||
ignoreRestSiblings: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'valid-typeof': 'error',
|
|
||||||
|
|
||||||
'react/jsx-filename-extension': ['error', { extensions: ['.jsx', 'tsx'] }],
|
|
||||||
'react/jsx-boolean-value': 'error',
|
|
||||||
'react/display-name': 'off',
|
|
||||||
'react/jsx-fragments': ['error', 'syntax'],
|
|
||||||
'react/jsx-equals-spacing': 'error',
|
|
||||||
'react/jsx-no-bind': 'error',
|
|
||||||
'react/jsx-no-useless-fragment': 'error',
|
|
||||||
'react/jsx-no-target-blank': ['error', { allowReferrer: true }],
|
|
||||||
'react/jsx-tag-spacing': 'error',
|
|
||||||
'react/jsx-uses-react': 'off', // not needed with new JSX transform
|
|
||||||
'react/jsx-wrap-multilines': 'error',
|
|
||||||
'react/react-in-jsx-scope': 'off', // not needed with new JSX transform
|
|
||||||
'react/self-closing-comp': 'error',
|
|
||||||
|
|
||||||
// recommended values found in https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/v6.8.0/src/index.js#L46
|
|
||||||
'jsx-a11y/click-events-have-key-events': 'off',
|
|
||||||
'jsx-a11y/label-has-associated-control': 'off',
|
|
||||||
'jsx-a11y/media-has-caption': 'off',
|
|
||||||
'jsx-a11y/no-autofocus': 'off',
|
|
||||||
// recommended rule is:
|
|
||||||
// 'jsx-a11y/no-interactive-element-to-noninteractive-role': [
|
|
||||||
// 'error',
|
|
||||||
// {
|
|
||||||
// tr: ['none', 'presentation'],
|
|
||||||
// canvas: ['img'],
|
|
||||||
// },
|
|
||||||
// ],
|
|
||||||
'jsx-a11y/no-interactive-element-to-noninteractive-role': 'off',
|
|
||||||
// recommended rule is:
|
|
||||||
// 'jsx-a11y/no-noninteractive-tabindex': [
|
|
||||||
// 'error',
|
|
||||||
// {
|
|
||||||
// tags: [],
|
|
||||||
// roles: ['tabpanel'],
|
|
||||||
// allowExpressionValues: true,
|
|
||||||
// },
|
|
||||||
// ],
|
|
||||||
'jsx-a11y/no-noninteractive-tabindex': 'off',
|
|
||||||
// recommended is full 'error'
|
|
||||||
'jsx-a11y/no-static-element-interactions': [
|
|
||||||
'warn',
|
|
||||||
{
|
|
||||||
handlers: [
|
|
||||||
'onClick',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
// See https://github.com/import-js/eslint-plugin-import/blob/v2.29.1/config/recommended.js
|
|
||||||
'import/extensions': [
|
|
||||||
'error',
|
|
||||||
'always',
|
|
||||||
{
|
|
||||||
js: 'never',
|
|
||||||
jsx: 'never',
|
|
||||||
mjs: 'never',
|
|
||||||
ts: 'never',
|
|
||||||
tsx: 'never',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'import/first': 'error',
|
|
||||||
'import/newline-after-import': 'error',
|
|
||||||
'import/no-anonymous-default-export': 'error',
|
|
||||||
'import/no-extraneous-dependencies': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
devDependencies: [
|
|
||||||
'.eslintrc.js',
|
|
||||||
'config/webpack/**',
|
|
||||||
'app/javascript/mastodon/performance.js',
|
|
||||||
'app/javascript/mastodon/test_setup.js',
|
|
||||||
'app/javascript/**/__tests__/**',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'import/no-amd': 'error',
|
|
||||||
'import/no-commonjs': 'error',
|
|
||||||
'import/no-import-module-exports': 'error',
|
|
||||||
'import/no-relative-packages': 'error',
|
|
||||||
'import/no-self-import': 'error',
|
|
||||||
'import/no-useless-path-segments': 'error',
|
|
||||||
'import/no-webpack-loader-syntax': 'error',
|
|
||||||
|
|
||||||
'import/order': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
alphabetize: { order: 'asc' },
|
|
||||||
'newlines-between': 'always',
|
|
||||||
groups: [
|
|
||||||
'builtin',
|
|
||||||
'external',
|
|
||||||
'internal',
|
|
||||||
'parent',
|
|
||||||
['index', 'sibling'],
|
|
||||||
'object',
|
|
||||||
],
|
|
||||||
pathGroups: [
|
|
||||||
// React core packages
|
|
||||||
{
|
|
||||||
pattern: '{react,react-dom,react-dom/client,prop-types}',
|
|
||||||
group: 'builtin',
|
|
||||||
position: 'after',
|
|
||||||
},
|
|
||||||
// I18n
|
|
||||||
{
|
|
||||||
pattern: '{react-intl,intl-messageformat}',
|
|
||||||
group: 'builtin',
|
|
||||||
position: 'after',
|
|
||||||
},
|
|
||||||
// Common React utilities
|
|
||||||
{
|
|
||||||
pattern: '{classnames,react-helmet,react-router,react-router-dom}',
|
|
||||||
group: 'external',
|
|
||||||
position: 'before',
|
|
||||||
},
|
|
||||||
// Immutable / Redux / data store
|
|
||||||
{
|
|
||||||
pattern: '{immutable,@reduxjs/toolkit,react-redux,react-immutable-proptypes,react-immutable-pure-component}',
|
|
||||||
group: 'external',
|
|
||||||
position: 'before',
|
|
||||||
},
|
|
||||||
// Internal packages
|
|
||||||
{
|
|
||||||
pattern: '{mastodon/**}',
|
|
||||||
group: 'internal',
|
|
||||||
position: 'after',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
pattern: '{flavours/glitch-soc/**}',
|
|
||||||
group: 'internal',
|
|
||||||
position: 'after',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
pathGroupsExcludedImportTypes: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
// Forbid imports from vanilla in glitch flavour
|
|
||||||
'import/no-restricted-paths': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
zones: [{
|
|
||||||
target: 'app/javascript/flavours/glitch/',
|
|
||||||
from: 'app/javascript/mastodon/',
|
|
||||||
message: 'Import from /flavours/glitch/ instead'
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
|
|
||||||
'promise/always-return': 'off',
|
|
||||||
'promise/catch-or-return': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
allowFinally: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'promise/no-callback-in-promise': 'off',
|
|
||||||
'promise/no-nesting': 'off',
|
|
||||||
'promise/no-promise-in-callback': 'off',
|
|
||||||
|
|
||||||
'formatjs/blocklist-elements': 'error',
|
|
||||||
'formatjs/enforce-default-message': ['error', 'literal'],
|
|
||||||
'formatjs/enforce-description': 'off', // description values not currently used
|
|
||||||
'formatjs/enforce-id': 'off', // Explicit IDs are used in the project
|
|
||||||
'formatjs/enforce-placeholders': 'off', // Issues in short_number.jsx
|
|
||||||
'formatjs/enforce-plural-rules': 'error',
|
|
||||||
'formatjs/no-camel-case': 'off', // disabledAccount is only non-conforming
|
|
||||||
'formatjs/no-complex-selectors': 'error',
|
|
||||||
'formatjs/no-emoji': 'error',
|
|
||||||
'formatjs/no-id': 'off', // IDs are used for translation keys
|
|
||||||
'formatjs/no-invalid-icu': 'error',
|
|
||||||
'formatjs/no-literal-string-in-jsx': 'off', // Should be looked at, but mainly flagging punctuation outside of strings
|
|
||||||
'formatjs/no-multiple-whitespaces': 'error',
|
|
||||||
'formatjs/no-offset': 'error',
|
|
||||||
'formatjs/no-useless-message': 'error',
|
|
||||||
'formatjs/prefer-formatted-message': 'error',
|
|
||||||
'formatjs/prefer-pound-in-plural': 'error',
|
|
||||||
|
|
||||||
'jsdoc/check-types': 'off',
|
|
||||||
'jsdoc/no-undefined-types': 'off',
|
|
||||||
'jsdoc/require-jsdoc': 'off',
|
|
||||||
'jsdoc/require-param-description': 'off',
|
|
||||||
'jsdoc/require-property-description': 'off',
|
|
||||||
'jsdoc/require-returns-description': 'off',
|
|
||||||
'jsdoc/require-returns': 'off',
|
|
||||||
},
|
|
||||||
|
|
||||||
overrides: [
|
|
||||||
{
|
|
||||||
files: [
|
|
||||||
'.eslintrc.js',
|
|
||||||
'*.config.js',
|
|
||||||
'.*rc.js',
|
|
||||||
'ide-helper.js',
|
|
||||||
'config/webpack/**/*',
|
|
||||||
'config/formatjs-formatter.js',
|
|
||||||
],
|
|
||||||
|
|
||||||
env: {
|
|
||||||
commonjs: true,
|
|
||||||
},
|
|
||||||
|
|
||||||
parserOptions: {
|
|
||||||
sourceType: 'script',
|
|
||||||
},
|
|
||||||
|
|
||||||
rules: {
|
|
||||||
'import/no-commonjs': 'off',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
files: [
|
|
||||||
'**/*.ts',
|
|
||||||
'**/*.tsx',
|
|
||||||
],
|
|
||||||
|
|
||||||
extends: [
|
|
||||||
'eslint:recommended',
|
|
||||||
'plugin:@typescript-eslint/strict-type-checked',
|
|
||||||
'plugin:@typescript-eslint/stylistic-type-checked',
|
|
||||||
'plugin:react/recommended',
|
|
||||||
'plugin:react-hooks/recommended',
|
|
||||||
'plugin:jsx-a11y/recommended',
|
|
||||||
'plugin:import/recommended',
|
|
||||||
'plugin:import/typescript',
|
|
||||||
'plugin:promise/recommended',
|
|
||||||
'plugin:jsdoc/recommended-typescript',
|
|
||||||
],
|
|
||||||
|
|
||||||
parserOptions: {
|
|
||||||
projectService: true,
|
|
||||||
tsconfigRootDir: __dirname,
|
|
||||||
},
|
|
||||||
|
|
||||||
rules: {
|
|
||||||
// Disable formatting rules that have been enabled in the base config
|
|
||||||
'indent': 'off',
|
|
||||||
|
|
||||||
// This is not needed as we use noImplicitReturns, which handles this in addition to understanding types
|
|
||||||
'consistent-return': 'off',
|
|
||||||
|
|
||||||
'import/consistent-type-specifier-style': ['error', 'prefer-top-level'],
|
|
||||||
|
|
||||||
'@typescript-eslint/consistent-type-definitions': ['warn', 'interface'],
|
|
||||||
'@typescript-eslint/consistent-type-exports': 'error',
|
|
||||||
'@typescript-eslint/consistent-type-imports': 'error',
|
|
||||||
"@typescript-eslint/prefer-nullish-coalescing": ['error', { ignorePrimitives: { boolean: true } }],
|
|
||||||
"@typescript-eslint/no-restricted-imports": [
|
|
||||||
"warn",
|
|
||||||
{
|
|
||||||
"name": "react-redux",
|
|
||||||
"importNames": ["useSelector", "useDispatch"],
|
|
||||||
"message": "Use typed hooks `useAppDispatch` and `useAppSelector` instead."
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"@typescript-eslint/restrict-template-expressions": ['warn', { allowNumber: true }],
|
|
||||||
'jsdoc/require-jsdoc': 'off',
|
|
||||||
|
|
||||||
// Those rules set stricter rules for TS files
|
|
||||||
// to enforce better practices when converting from JS
|
|
||||||
'import/no-default-export': 'warn',
|
|
||||||
'react/prefer-stateless-function': 'warn',
|
|
||||||
'react/function-component-definition': ['error', { namedComponents: 'arrow-function' }],
|
|
||||||
'react/jsx-uses-react': 'off', // not needed with new JSX transform
|
|
||||||
'react/react-in-jsx-scope': 'off', // not needed with new JSX transform
|
|
||||||
'react/prop-types': 'off',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
files: [
|
|
||||||
'**/__tests__/*.js',
|
|
||||||
'**/__tests__/*.jsx',
|
|
||||||
],
|
|
||||||
|
|
||||||
env: {
|
|
||||||
jest: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
],
|
|
||||||
});
|
|
8
.github/renovate.json5
vendored
8
.github/renovate.json5
vendored
|
@ -97,7 +97,13 @@
|
||||||
{
|
{
|
||||||
// Group all eslint-related packages with `eslint` in the same PR
|
// Group all eslint-related packages with `eslint` in the same PR
|
||||||
matchManagers: ['npm'],
|
matchManagers: ['npm'],
|
||||||
matchPackageNames: ['eslint', 'eslint-*', '@typescript-eslint/*'],
|
matchPackageNames: [
|
||||||
|
'eslint',
|
||||||
|
'eslint-*',
|
||||||
|
'typescript-eslint',
|
||||||
|
'@eslint/*',
|
||||||
|
'globals',
|
||||||
|
],
|
||||||
matchUpdateTypes: ['patch', 'minor'],
|
matchUpdateTypes: ['patch', 'minor'],
|
||||||
groupName: 'eslint (non-major)',
|
groupName: 'eslint (non-major)',
|
||||||
},
|
},
|
||||||
|
|
6
.github/workflows/lint-js.yml
vendored
6
.github/workflows/lint-js.yml
vendored
|
@ -11,7 +11,7 @@ on:
|
||||||
- 'tsconfig.json'
|
- 'tsconfig.json'
|
||||||
- '.nvmrc'
|
- '.nvmrc'
|
||||||
- '.prettier*'
|
- '.prettier*'
|
||||||
- '.eslint*'
|
- 'eslint.config.mjs'
|
||||||
- '**/*.js'
|
- '**/*.js'
|
||||||
- '**/*.jsx'
|
- '**/*.jsx'
|
||||||
- '**/*.ts'
|
- '**/*.ts'
|
||||||
|
@ -25,7 +25,7 @@ on:
|
||||||
- 'tsconfig.json'
|
- 'tsconfig.json'
|
||||||
- '.nvmrc'
|
- '.nvmrc'
|
||||||
- '.prettier*'
|
- '.prettier*'
|
||||||
- '.eslint*'
|
- 'eslint.config.mjs'
|
||||||
- '**/*.js'
|
- '**/*.js'
|
||||||
- '**/*.jsx'
|
- '**/*.jsx'
|
||||||
- '**/*.ts'
|
- '**/*.ts'
|
||||||
|
@ -44,7 +44,7 @@ jobs:
|
||||||
uses: ./.github/actions/setup-javascript
|
uses: ./.github/actions/setup-javascript
|
||||||
|
|
||||||
- name: ESLint
|
- name: ESLint
|
||||||
run: yarn lint:js --max-warnings 0
|
run: yarn workspaces foreach --all --parallel run lint:js --max-warnings 0
|
||||||
|
|
||||||
- name: Typecheck
|
- name: Typecheck
|
||||||
run: yarn typecheck
|
run: yarn typecheck
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
singleQuote: true,
|
singleQuote: true,
|
||||||
jsxSingleQuote: true
|
jsxSingleQuote: true
|
||||||
}
|
};
|
||||||
|
|
14
Gemfile.lock
14
Gemfile.lock
|
@ -404,7 +404,7 @@ GEM
|
||||||
llhttp-ffi (0.5.1)
|
llhttp-ffi (0.5.1)
|
||||||
ffi-compiler (~> 1.0)
|
ffi-compiler (~> 1.0)
|
||||||
rake (~> 13.0)
|
rake (~> 13.0)
|
||||||
logger (1.6.6)
|
logger (1.7.0)
|
||||||
lograge (0.14.0)
|
lograge (0.14.0)
|
||||||
actionpack (>= 4)
|
actionpack (>= 4)
|
||||||
activesupport (>= 4)
|
activesupport (>= 4)
|
||||||
|
@ -446,7 +446,7 @@ GEM
|
||||||
net-smtp (0.5.1)
|
net-smtp (0.5.1)
|
||||||
net-protocol
|
net-protocol
|
||||||
nio4r (2.7.4)
|
nio4r (2.7.4)
|
||||||
nokogiri (1.18.6)
|
nokogiri (1.18.7)
|
||||||
mini_portile2 (~> 2.8.2)
|
mini_portile2 (~> 2.8.2)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
oj (3.16.10)
|
oj (3.16.10)
|
||||||
|
@ -586,7 +586,7 @@ GEM
|
||||||
ox (2.14.22)
|
ox (2.14.22)
|
||||||
bigdecimal (>= 3.0)
|
bigdecimal (>= 3.0)
|
||||||
parallel (1.26.3)
|
parallel (1.26.3)
|
||||||
parser (3.3.7.3)
|
parser (3.3.7.4)
|
||||||
ast (~> 2.4.1)
|
ast (~> 2.4.1)
|
||||||
racc
|
racc
|
||||||
parslet (2.0.0)
|
parslet (2.0.0)
|
||||||
|
@ -760,15 +760,15 @@ GEM
|
||||||
rubocop-i18n (3.2.3)
|
rubocop-i18n (3.2.3)
|
||||||
lint_roller (~> 1.1)
|
lint_roller (~> 1.1)
|
||||||
rubocop (>= 1.72.1)
|
rubocop (>= 1.72.1)
|
||||||
rubocop-performance (1.24.0)
|
rubocop-performance (1.25.0)
|
||||||
lint_roller (~> 1.1)
|
lint_roller (~> 1.1)
|
||||||
rubocop (>= 1.72.1, < 2.0)
|
rubocop (>= 1.75.0, < 2.0)
|
||||||
rubocop-ast (>= 1.38.0, < 2.0)
|
rubocop-ast (>= 1.38.0, < 2.0)
|
||||||
rubocop-rails (2.30.3)
|
rubocop-rails (2.31.0)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 4.2.0)
|
||||||
lint_roller (~> 1.1)
|
lint_roller (~> 1.1)
|
||||||
rack (>= 1.1)
|
rack (>= 1.1)
|
||||||
rubocop (>= 1.72.1, < 2.0)
|
rubocop (>= 1.75.0, < 2.0)
|
||||||
rubocop-ast (>= 1.38.0, < 2.0)
|
rubocop-ast (>= 1.38.0, < 2.0)
|
||||||
rubocop-rspec (3.5.0)
|
rubocop-rspec (3.5.0)
|
||||||
lint_roller (~> 1.1)
|
lint_roller (~> 1.1)
|
||||||
|
|
|
@ -68,7 +68,7 @@ function loaded() {
|
||||||
|
|
||||||
if (id) message = localeData[id];
|
if (id) message = localeData[id];
|
||||||
|
|
||||||
if (!message) message = defaultMessage as string;
|
message ??= defaultMessage as string;
|
||||||
|
|
||||||
const messageFormat = new IntlMessageFormat(message, locale);
|
const messageFormat = new IntlMessageFormat(message, locale);
|
||||||
return messageFormat.format(values) as string;
|
return messageFormat.format(values) as string;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React from 'react';
|
import type React from 'react';
|
||||||
|
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import type { PropsWithChildren } from 'react';
|
import type { PropsWithChildren } from 'react';
|
||||||
import React from 'react';
|
import type React from 'react';
|
||||||
|
|
||||||
import { Router as OriginalRouter, useHistory } from 'react-router';
|
import { Router as OriginalRouter, useHistory } from 'react-router';
|
||||||
|
|
||||||
|
|
|
@ -9,48 +9,39 @@ import { reduceMotion } from 'mastodon/initial_state';
|
||||||
interface UploadProgressProps {
|
interface UploadProgressProps {
|
||||||
active: boolean;
|
active: boolean;
|
||||||
progress: number;
|
progress: number;
|
||||||
isProcessing: boolean;
|
isProcessing?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const UploadProgress: React.FC<UploadProgressProps> = ({
|
export const UploadProgress: React.FC<UploadProgressProps> = ({
|
||||||
active,
|
active,
|
||||||
progress,
|
progress,
|
||||||
isProcessing,
|
isProcessing = false,
|
||||||
}) => {
|
}) => {
|
||||||
const styles = useSpring({
|
const styles = useSpring({
|
||||||
from: { width: '0%' },
|
from: { width: '0%' },
|
||||||
to: { width: `${progress}%` },
|
to: { width: `${progress}%` },
|
||||||
reset: true,
|
immediate: reduceMotion || !active, // If this is not active, update the UI immediately.
|
||||||
immediate: reduceMotion,
|
|
||||||
});
|
});
|
||||||
if (!active) {
|
if (!active) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
let message;
|
|
||||||
|
|
||||||
if (isProcessing) {
|
|
||||||
message = (
|
|
||||||
<FormattedMessage
|
|
||||||
id='upload_progress.processing'
|
|
||||||
defaultMessage='Processing…'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
message = (
|
|
||||||
<FormattedMessage
|
|
||||||
id='upload_progress.label'
|
|
||||||
defaultMessage='Uploading…'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='upload-progress'>
|
<div className='upload-progress'>
|
||||||
<Icon id='upload' icon={UploadFileIcon} />
|
<Icon id='upload' icon={UploadFileIcon} />
|
||||||
|
|
||||||
<div className='upload-progress__message'>
|
<div className='upload-progress__message'>
|
||||||
{message}
|
{isProcessing ? (
|
||||||
|
<FormattedMessage
|
||||||
|
id='upload_progress.processing'
|
||||||
|
defaultMessage='Processing…'
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<FormattedMessage
|
||||||
|
id='upload_progress.label'
|
||||||
|
defaultMessage='Uploading…'
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className='upload-progress__backdrop'>
|
<div className='upload-progress__backdrop'>
|
||||||
<animated.div className='upload-progress__tracker' style={styles} />
|
<animated.div className='upload-progress__tracker' style={styles} />
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
/* eslint-disable import/no-commonjs --
|
|
||||||
We need to use CommonJS here due to preval */
|
|
||||||
// @preval
|
// @preval
|
||||||
// http://www.unicode.org/Public/emoji/5.0/emoji-test.txt
|
// http://www.unicode.org/Public/emoji/5.0/emoji-test.txt
|
||||||
// This file contains the compressed version of the emoji data from
|
// This file contains the compressed version of the emoji data from
|
||||||
|
|
|
@ -33,11 +33,8 @@ function processEmojiMapData(
|
||||||
shortCode?: ShortCodesToEmojiDataKey,
|
shortCode?: ShortCodesToEmojiDataKey,
|
||||||
) {
|
) {
|
||||||
const [native, _filename] = emojiMapData;
|
const [native, _filename] = emojiMapData;
|
||||||
let filename = emojiMapData[1];
|
// filename name can be derived from unicodeToFilename
|
||||||
if (!filename) {
|
const filename = emojiMapData[1] ?? unicodeToFilename(native);
|
||||||
// filename name can be derived from unicodeToFilename
|
|
||||||
filename = unicodeToFilename(native);
|
|
||||||
}
|
|
||||||
unicodeMapping[native] = {
|
unicodeMapping[native] = {
|
||||||
shortCode,
|
shortCode,
|
||||||
filename,
|
filename,
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
/* eslint-disable import/no-commonjs --
|
|
||||||
We need to use CommonJS here as its imported into a preval file (`emoji_compressed.js`) */
|
|
||||||
|
|
||||||
// taken from:
|
// taken from:
|
||||||
// https://github.com/twitter/twemoji/blob/47732c7/twemoji-generator.js#L848-L866
|
// https://github.com/twitter/twemoji/blob/47732c7/twemoji-generator.js#L848-L866
|
||||||
exports.unicodeToFilename = (str) => {
|
exports.unicodeToFilename = (str) => {
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
/* eslint-disable import/no-commonjs --
|
|
||||||
We need to use CommonJS here as its imported into a preval file (`emoji_compressed.js`) */
|
|
||||||
|
|
||||||
function padLeft(str, num) {
|
function padLeft(str, num) {
|
||||||
while (str.length < num) {
|
while (str.length < num) {
|
||||||
str = '0' + str;
|
str = '0' + str;
|
||||||
|
|
|
@ -911,6 +911,6 @@
|
||||||
"video.skip_backward": "Siirry taaksepäin",
|
"video.skip_backward": "Siirry taaksepäin",
|
||||||
"video.skip_forward": "Siirry eteenpäin",
|
"video.skip_forward": "Siirry eteenpäin",
|
||||||
"video.unmute": "Poista mykistys",
|
"video.unmute": "Poista mykistys",
|
||||||
"video.volume_down": "Laske äänenvoimakkuutta",
|
"video.volume_down": "Vähennä äänenvoimakkuutta",
|
||||||
"video.volume_up": "Nosta äänenvoimakkuutta"
|
"video.volume_up": "Lisää äänenvoimakkuutta"
|
||||||
}
|
}
|
||||||
|
|
|
@ -905,6 +905,12 @@
|
||||||
"video.expand": "동영상 확장",
|
"video.expand": "동영상 확장",
|
||||||
"video.fullscreen": "전체화면",
|
"video.fullscreen": "전체화면",
|
||||||
"video.hide": "동영상 숨기기",
|
"video.hide": "동영상 숨기기",
|
||||||
|
"video.mute": "음소거",
|
||||||
"video.pause": "일시정지",
|
"video.pause": "일시정지",
|
||||||
"video.play": "재생"
|
"video.play": "재생",
|
||||||
|
"video.skip_backward": "뒤로 건너뛰기",
|
||||||
|
"video.skip_forward": "앞으로 건너뛰기",
|
||||||
|
"video.unmute": "음소거 해제",
|
||||||
|
"video.volume_down": "음량 감소",
|
||||||
|
"video.volume_up": "음량 증가"
|
||||||
}
|
}
|
||||||
|
|
|
@ -697,6 +697,7 @@
|
||||||
"poll_button.remove_poll": "Remover enquete",
|
"poll_button.remove_poll": "Remover enquete",
|
||||||
"privacy.change": "Alterar privacidade do toot",
|
"privacy.change": "Alterar privacidade do toot",
|
||||||
"privacy.direct.long": "Todos mencionados na publicação",
|
"privacy.direct.long": "Todos mencionados na publicação",
|
||||||
|
"privacy.direct.short": "Menção privada",
|
||||||
"privacy.private.long": "Apenas seus seguidores",
|
"privacy.private.long": "Apenas seus seguidores",
|
||||||
"privacy.private.short": "Seguidores",
|
"privacy.private.short": "Seguidores",
|
||||||
"privacy.public.long": "Qualquer um dentro ou fora do Mastodon",
|
"privacy.public.long": "Qualquer um dentro ou fora do Mastodon",
|
||||||
|
@ -871,7 +872,9 @@
|
||||||
"subscribed_languages.target": "Alterar idiomas inscritos para {target}",
|
"subscribed_languages.target": "Alterar idiomas inscritos para {target}",
|
||||||
"tabs_bar.home": "Página inicial",
|
"tabs_bar.home": "Página inicial",
|
||||||
"tabs_bar.notifications": "Notificações",
|
"tabs_bar.notifications": "Notificações",
|
||||||
|
"terms_of_service.effective_as_of": "Em vigor a partir de {date}",
|
||||||
"terms_of_service.title": "Termos de serviço",
|
"terms_of_service.title": "Termos de serviço",
|
||||||
|
"terms_of_service.upcoming_changes_on": "Próximas mudanças em {date}",
|
||||||
"time_remaining.days": "{number, plural, one {# dia restante} other {# dias restantes}}",
|
"time_remaining.days": "{number, plural, one {# dia restante} other {# dias restantes}}",
|
||||||
"time_remaining.hours": "{number, plural, one {# hora restante} other {# horas restantes}}",
|
"time_remaining.hours": "{number, plural, one {# hora restante} other {# horas restantes}}",
|
||||||
"time_remaining.minutes": "{number, plural, one {# minuto restante} other {# minutos restantes}}",
|
"time_remaining.minutes": "{number, plural, one {# minuto restante} other {# minutos restantes}}",
|
||||||
|
@ -902,6 +905,12 @@
|
||||||
"video.expand": "Abrir vídeo",
|
"video.expand": "Abrir vídeo",
|
||||||
"video.fullscreen": "Tela cheia",
|
"video.fullscreen": "Tela cheia",
|
||||||
"video.hide": "Ocultar mídia",
|
"video.hide": "Ocultar mídia",
|
||||||
|
"video.mute": "Silenciar",
|
||||||
"video.pause": "Pausar",
|
"video.pause": "Pausar",
|
||||||
"video.play": "Executar"
|
"video.play": "Executar",
|
||||||
|
"video.skip_backward": "Retroceder",
|
||||||
|
"video.skip_forward": "Avançar",
|
||||||
|
"video.unmute": "Ativar som",
|
||||||
|
"video.volume_down": "Diminuir o volume",
|
||||||
|
"video.volume_up": "Aumentar o volume"
|
||||||
}
|
}
|
||||||
|
|
|
@ -156,7 +156,7 @@
|
||||||
"column.firehose": "Живая лента",
|
"column.firehose": "Живая лента",
|
||||||
"column.follow_requests": "Запросы на подписку",
|
"column.follow_requests": "Запросы на подписку",
|
||||||
"column.home": "Главная",
|
"column.home": "Главная",
|
||||||
"column.list_members": "Управление пользователями в списке",
|
"column.list_members": "Добавить или удалить из списка",
|
||||||
"column.lists": "Списки",
|
"column.lists": "Списки",
|
||||||
"column.mutes": "Игнорируемые пользователи",
|
"column.mutes": "Игнорируемые пользователи",
|
||||||
"column.notifications": "Уведомления",
|
"column.notifications": "Уведомления",
|
||||||
|
@ -173,7 +173,7 @@
|
||||||
"column_subheading.settings": "Настройки",
|
"column_subheading.settings": "Настройки",
|
||||||
"community.column_settings.local_only": "Только локальные",
|
"community.column_settings.local_only": "Только локальные",
|
||||||
"community.column_settings.media_only": "Только с медиафайлами",
|
"community.column_settings.media_only": "Только с медиафайлами",
|
||||||
"community.column_settings.remote_only": "Только удалённые",
|
"community.column_settings.remote_only": "Только с других серверов",
|
||||||
"compose.language.change": "Изменить язык",
|
"compose.language.change": "Изменить язык",
|
||||||
"compose.language.search": "Найти язык...",
|
"compose.language.search": "Найти язык...",
|
||||||
"compose.published.body": "Пост опубликован.",
|
"compose.published.body": "Пост опубликован.",
|
||||||
|
@ -181,7 +181,7 @@
|
||||||
"compose.saved.body": "Пост отредактирован.",
|
"compose.saved.body": "Пост отредактирован.",
|
||||||
"compose_form.direct_message_warning_learn_more": "Узнать больше",
|
"compose_form.direct_message_warning_learn_more": "Узнать больше",
|
||||||
"compose_form.encryption_warning": "Посты в Mastodon не защищены сквозным шифрованием. Не делитесь конфиденциальной информацией через Mastodon.",
|
"compose_form.encryption_warning": "Посты в Mastodon не защищены сквозным шифрованием. Не делитесь конфиденциальной информацией через Mastodon.",
|
||||||
"compose_form.hashtag_warning": "Этот пост не будет виден ни под одним из хэштегов, так как он не публичный. Только публичные посты можно найти по хэштегу.",
|
"compose_form.hashtag_warning": "Этот пост не появится в поиске по хэштегам, так как он не обозначен как публичный. Только публичные посты можно найти по хэштегу.",
|
||||||
"compose_form.lock_disclaimer": "Ваша учётная запись {locked}. Любой пользователь сможет подписаться на вас и просматривать посты для подписчиков.",
|
"compose_form.lock_disclaimer": "Ваша учётная запись {locked}. Любой пользователь сможет подписаться на вас и просматривать посты для подписчиков.",
|
||||||
"compose_form.lock_disclaimer.lock": "не закрыта",
|
"compose_form.lock_disclaimer.lock": "не закрыта",
|
||||||
"compose_form.placeholder": "О чём думаете?",
|
"compose_form.placeholder": "О чём думаете?",
|
||||||
|
@ -189,8 +189,8 @@
|
||||||
"compose_form.poll.multiple": "Несколько вариантов ответа",
|
"compose_form.poll.multiple": "Несколько вариантов ответа",
|
||||||
"compose_form.poll.option_placeholder": "Вариант {number}",
|
"compose_form.poll.option_placeholder": "Вариант {number}",
|
||||||
"compose_form.poll.single": "Один вариант ответа",
|
"compose_form.poll.single": "Один вариант ответа",
|
||||||
"compose_form.poll.switch_to_multiple": "Разрешить выбор нескольких вариантов",
|
"compose_form.poll.switch_to_multiple": "Переключить в режим выбора нескольких вариантов ответа",
|
||||||
"compose_form.poll.switch_to_single": "Переключить в режим выбора одного ответа",
|
"compose_form.poll.switch_to_single": "Переключить в режим выбора одного варианта ответа",
|
||||||
"compose_form.poll.type": "Тип",
|
"compose_form.poll.type": "Тип",
|
||||||
"compose_form.publish": "Опубликовать",
|
"compose_form.publish": "Опубликовать",
|
||||||
"compose_form.publish_form": "Опубликовать",
|
"compose_form.publish_form": "Опубликовать",
|
||||||
|
@ -208,11 +208,11 @@
|
||||||
"confirmations.delete_list.message": "Вы уверены, что хотите навсегда удалить этот список?",
|
"confirmations.delete_list.message": "Вы уверены, что хотите навсегда удалить этот список?",
|
||||||
"confirmations.delete_list.title": "Удалить список?",
|
"confirmations.delete_list.title": "Удалить список?",
|
||||||
"confirmations.discard_edit_media.confirm": "Сбросить",
|
"confirmations.discard_edit_media.confirm": "Сбросить",
|
||||||
"confirmations.discard_edit_media.message": "У вас есть несохранённые изменения в описании мультимедиа или предпросмотре, сбросить их?",
|
"confirmations.discard_edit_media.message": "У вас есть несохранённые изменения, касающиеся описания медиа или области предпросмотра, сбросить их?",
|
||||||
"confirmations.edit.confirm": "Редактировать",
|
"confirmations.edit.confirm": "Редактировать",
|
||||||
"confirmations.edit.message": "Если вы начнёте редактировать сейчас, то набираемый в данный момент пост будет стёрт. Вы уверены, что хотите продолжить?",
|
"confirmations.edit.message": "Если вы начнёте редактировать сейчас, то набираемый в данный момент пост будет стёрт. Вы уверены, что хотите продолжить?",
|
||||||
"confirmations.edit.title": "Стереть несохранённый черновик поста?",
|
"confirmations.edit.title": "Стереть несохранённый черновик поста?",
|
||||||
"confirmations.follow_to_list.confirm": "Подписаться, а затем добавить в список",
|
"confirmations.follow_to_list.confirm": "Подписаться и добавить",
|
||||||
"confirmations.follow_to_list.message": "Чтобы добавить пользователя {name} в список, вы должны быть на него подписаны.",
|
"confirmations.follow_to_list.message": "Чтобы добавить пользователя {name} в список, вы должны быть на него подписаны.",
|
||||||
"confirmations.follow_to_list.title": "Подписаться на пользователя?",
|
"confirmations.follow_to_list.title": "Подписаться на пользователя?",
|
||||||
"confirmations.logout.confirm": "Выйти",
|
"confirmations.logout.confirm": "Выйти",
|
||||||
|
@ -224,8 +224,8 @@
|
||||||
"confirmations.missing_alt_text.title": "Добавить альтернативный текст?",
|
"confirmations.missing_alt_text.title": "Добавить альтернативный текст?",
|
||||||
"confirmations.mute.confirm": "Игнорировать",
|
"confirmations.mute.confirm": "Игнорировать",
|
||||||
"confirmations.redraft.confirm": "Удалить и исправить",
|
"confirmations.redraft.confirm": "Удалить и исправить",
|
||||||
"confirmations.redraft.message": "Вы уверены, что хотите удалить и переписать этот пост? Отметки «избранного», продвижения и ответы к оригинальному посту будут потеряны.",
|
"confirmations.redraft.message": "Вы уверены, что хотите удалить этот пост и создать его заново? Взаимодействия, такие как добавление в избранное или продвижение, будут потеряны, а ответы к оригинальному посту перестанут на него ссылаться.",
|
||||||
"confirmations.redraft.title": "Создать пост заново?",
|
"confirmations.redraft.title": "Удалить и создать пост заново?",
|
||||||
"confirmations.reply.confirm": "Ответить",
|
"confirmations.reply.confirm": "Ответить",
|
||||||
"confirmations.reply.message": "Если вы начнёте составлять ответ сейчас, то набираемый в данный момент пост будет стёрт. Вы уверены, что хотите продолжить?",
|
"confirmations.reply.message": "Если вы начнёте составлять ответ сейчас, то набираемый в данный момент пост будет стёрт. Вы уверены, что хотите продолжить?",
|
||||||
"confirmations.reply.title": "Стереть несохранённый черновик поста?",
|
"confirmations.reply.title": "Стереть несохранённый черновик поста?",
|
||||||
|
@ -293,7 +293,7 @@
|
||||||
"emoji_button.search_results": "Результаты поиска",
|
"emoji_button.search_results": "Результаты поиска",
|
||||||
"emoji_button.symbols": "Символы",
|
"emoji_button.symbols": "Символы",
|
||||||
"emoji_button.travel": "Путешествия и места",
|
"emoji_button.travel": "Путешествия и места",
|
||||||
"empty_column.account_hides_collections": "Данный пользователь решил не предоставлять эту информацию",
|
"empty_column.account_hides_collections": "Пользователь предпочёл не раскрывать эту информацию",
|
||||||
"empty_column.account_suspended": "Учётная запись заблокирована",
|
"empty_column.account_suspended": "Учётная запись заблокирована",
|
||||||
"empty_column.account_timeline": "Здесь нет постов!",
|
"empty_column.account_timeline": "Здесь нет постов!",
|
||||||
"empty_column.account_unavailable": "Профиль недоступен",
|
"empty_column.account_unavailable": "Профиль недоступен",
|
||||||
|
@ -409,8 +409,9 @@
|
||||||
"home.show_announcements": "Показать объявления",
|
"home.show_announcements": "Показать объявления",
|
||||||
"ignore_notifications_modal.disclaimer": "Mastodon не может сообщить пользователям, что вы игнорируете их уведомления. Игнорирование уведомлений не остановит отправку самих сообщений.",
|
"ignore_notifications_modal.disclaimer": "Mastodon не может сообщить пользователям, что вы игнорируете их уведомления. Игнорирование уведомлений не остановит отправку самих сообщений.",
|
||||||
"ignore_notifications_modal.filter_instead": "Фильтровать",
|
"ignore_notifications_modal.filter_instead": "Фильтровать",
|
||||||
"ignore_notifications_modal.filter_to_avoid_confusion": "Фильтрация помогает избежать потенциальной путаницы",
|
"ignore_notifications_modal.filter_to_act_users": "Вы по-прежнему сможете принимать и отклонять запросы, а также отправлять жалобы на пользователей",
|
||||||
"ignore_notifications_modal.filter_to_review_separately": "Вы можете просматривать отфильтрованные уведомления отдельно",
|
"ignore_notifications_modal.filter_to_avoid_confusion": "Фильтрация поможет избежать возможной путаницы",
|
||||||
|
"ignore_notifications_modal.filter_to_review_separately": "Отфильтрованные уведомления можно просматривать отдельно",
|
||||||
"ignore_notifications_modal.ignore": "Игнорировать уведомления",
|
"ignore_notifications_modal.ignore": "Игнорировать уведомления",
|
||||||
"ignore_notifications_modal.limited_accounts_title": "Игнорировать уведомления от модерируемых учётных записей?",
|
"ignore_notifications_modal.limited_accounts_title": "Игнорировать уведомления от модерируемых учётных записей?",
|
||||||
"ignore_notifications_modal.new_accounts_title": "Игнорировать уведомления от новых учётных записей?",
|
"ignore_notifications_modal.new_accounts_title": "Игнорировать уведомления от новых учётных записей?",
|
||||||
|
|
|
@ -113,6 +113,7 @@ function clearAll(state) {
|
||||||
map.set('sensitive', state.get('default_sensitive'));
|
map.set('sensitive', state.get('default_sensitive'));
|
||||||
map.set('language', state.get('default_language'));
|
map.set('language', state.get('default_language'));
|
||||||
map.update('media_attachments', list => list.clear());
|
map.update('media_attachments', list => list.clear());
|
||||||
|
map.set('progress', 0);
|
||||||
map.set('poll', null);
|
map.set('poll', null);
|
||||||
map.set('idempotencyKey', uuid());
|
map.set('idempotencyKey', uuid());
|
||||||
});
|
});
|
||||||
|
@ -128,6 +129,7 @@ function appendMedia(state, media, file) {
|
||||||
map.update('media_attachments', list => list.push(media.set('unattached', true)));
|
map.update('media_attachments', list => list.push(media.set('unattached', true)));
|
||||||
map.set('is_uploading', false);
|
map.set('is_uploading', false);
|
||||||
map.set('is_processing', false);
|
map.set('is_processing', false);
|
||||||
|
map.set('progress', 0);
|
||||||
map.set('resetFileKey', Math.floor((Math.random() * 0x10000)));
|
map.set('resetFileKey', Math.floor((Math.random() * 0x10000)));
|
||||||
map.set('idempotencyKey', uuid());
|
map.set('idempotencyKey', uuid());
|
||||||
map.update('pending_media_attachments', n => n - 1);
|
map.update('pending_media_attachments', n => n - 1);
|
||||||
|
@ -296,6 +298,8 @@ const updatePoll = (state, index, value, maxOptions) => state.updateIn(['poll',
|
||||||
return tmp;
|
return tmp;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const calculateProgress = (loaded, total) => Math.min(Math.round((loaded / total) * 100), 100);
|
||||||
|
|
||||||
/** @type {import('@reduxjs/toolkit').Reducer<typeof initialState>} */
|
/** @type {import('@reduxjs/toolkit').Reducer<typeof initialState>} */
|
||||||
export const composeReducer = (state = initialState, action) => {
|
export const composeReducer = (state = initialState, action) => {
|
||||||
if (changeUploadCompose.fulfilled.match(action)) {
|
if (changeUploadCompose.fulfilled.match(action)) {
|
||||||
|
@ -402,15 +406,19 @@ export const composeReducer = (state = initialState, action) => {
|
||||||
case COMPOSE_UPLOAD_SUCCESS:
|
case COMPOSE_UPLOAD_SUCCESS:
|
||||||
return appendMedia(state, fromJS(action.media), action.file);
|
return appendMedia(state, fromJS(action.media), action.file);
|
||||||
case COMPOSE_UPLOAD_FAIL:
|
case COMPOSE_UPLOAD_FAIL:
|
||||||
return state.set('is_uploading', false).set('is_processing', false).update('pending_media_attachments', n => n - 1);
|
return state
|
||||||
|
.set('is_uploading', false)
|
||||||
|
.set('is_processing', false)
|
||||||
|
.set('progress', 0)
|
||||||
|
.update('pending_media_attachments', n => n - 1);
|
||||||
case COMPOSE_UPLOAD_UNDO:
|
case COMPOSE_UPLOAD_UNDO:
|
||||||
return removeMedia(state, action.media_id);
|
return removeMedia(state, action.media_id);
|
||||||
case COMPOSE_UPLOAD_PROGRESS:
|
case COMPOSE_UPLOAD_PROGRESS:
|
||||||
return state.set('progress', Math.round((action.loaded / action.total) * 100));
|
return state.set('progress', calculateProgress(action.loaded, action.total));
|
||||||
case THUMBNAIL_UPLOAD_REQUEST:
|
case THUMBNAIL_UPLOAD_REQUEST:
|
||||||
return state.set('isUploadingThumbnail', true);
|
return state.set('isUploadingThumbnail', true);
|
||||||
case THUMBNAIL_UPLOAD_PROGRESS:
|
case THUMBNAIL_UPLOAD_PROGRESS:
|
||||||
return state.set('thumbnailProgress', Math.round((action.loaded / action.total) * 100));
|
return state.set('thumbnailProgress', calculateProgress(action.loaded, action.total));
|
||||||
case THUMBNAIL_UPLOAD_FAIL:
|
case THUMBNAIL_UPLOAD_FAIL:
|
||||||
return state.set('isUploadingThumbnail', false);
|
return state.set('isUploadingThumbnail', false);
|
||||||
case THUMBNAIL_UPLOAD_SUCCESS:
|
case THUMBNAIL_UPLOAD_SUCCESS:
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
/* eslint-disable import/no-commonjs --
|
|
||||||
We need to use CommonJS here as its imported into a preval file (`emoji_compressed.js`) */
|
|
||||||
|
|
||||||
/* @preval */
|
/* @preval */
|
||||||
|
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
|
|
@ -39,7 +39,7 @@ pt-BR:
|
||||||
import:
|
import:
|
||||||
attributes:
|
attributes:
|
||||||
data:
|
data:
|
||||||
malformed: Está malformado
|
malformed: está malformado
|
||||||
list_account:
|
list_account:
|
||||||
attributes:
|
attributes:
|
||||||
account_id:
|
account_id:
|
||||||
|
@ -49,13 +49,19 @@ pt-BR:
|
||||||
attributes:
|
attributes:
|
||||||
reblog:
|
reblog:
|
||||||
taken: do toot já existe
|
taken: do toot já existe
|
||||||
|
terms_of_service:
|
||||||
|
attributes:
|
||||||
|
effective_date:
|
||||||
|
too_soon: está muito próxima, deve ser posterior a %{date}
|
||||||
user:
|
user:
|
||||||
attributes:
|
attributes:
|
||||||
|
date_of_birth:
|
||||||
|
below_limit: está abaixo do limite de idade
|
||||||
email:
|
email:
|
||||||
blocked: usa provedor de e-mail não permitido
|
blocked: usa provedor de e-mail não permitido
|
||||||
unreachable: parece não existir
|
unreachable: parece não existir
|
||||||
role_id:
|
role_id:
|
||||||
elevated: não pode maior que sua função atual
|
elevated: não pode ser maior que a sua função atual
|
||||||
user_role:
|
user_role:
|
||||||
attributes:
|
attributes:
|
||||||
permissions_as_keys:
|
permissions_as_keys:
|
||||||
|
|
|
@ -14,7 +14,7 @@ pt-BR:
|
||||||
not_found_in_database: "%{authentication_keys} ou senha inválida."
|
not_found_in_database: "%{authentication_keys} ou senha inválida."
|
||||||
omniauth_user_creation_failure: Erro ao criar uma conta para esta identidade.
|
omniauth_user_creation_failure: Erro ao criar uma conta para esta identidade.
|
||||||
pending: Sua conta está sendo revisada.
|
pending: Sua conta está sendo revisada.
|
||||||
timeout: Sua sessão expirou. Faça ‘login’ novamente para continuar.
|
timeout: Sua sessão expirou. Por favor, entre novamente para continuar.
|
||||||
unauthenticated: Você precisa entrar ou criar uma conta antes de continuar.
|
unauthenticated: Você precisa entrar ou criar uma conta antes de continuar.
|
||||||
unconfirmed: Você precisa confirmar o seu endereço de e-mail antes de continuar.
|
unconfirmed: Você precisa confirmar o seu endereço de e-mail antes de continuar.
|
||||||
mailer:
|
mailer:
|
||||||
|
@ -48,12 +48,12 @@ pt-BR:
|
||||||
subject: 'Mastodon: Instruções para alterar senha'
|
subject: 'Mastodon: Instruções para alterar senha'
|
||||||
title: Redefinir senha
|
title: Redefinir senha
|
||||||
two_factor_disabled:
|
two_factor_disabled:
|
||||||
explanation: O ‘login’ agora é possível usando apenas o endereço eletrônico e senha.
|
explanation: Agora você pode entrar usando apenas seu e-mail e senha.
|
||||||
subject: 'Mastodon: Autenticação de dois fatores desativada'
|
subject: 'Mastodon: Autenticação de dois fatores desativada'
|
||||||
subtitle: A autenticação de dois fatores foi desativada.
|
subtitle: A autenticação de dois fatores foi desativada.
|
||||||
title: 2FA desativada
|
title: 2FA desativada
|
||||||
two_factor_enabled:
|
two_factor_enabled:
|
||||||
explanation: Será necessário um código gerado pelo aplicativo de autenticação TOTP para fazer login.
|
explanation: Um código de autenticação de dois fatores será necessário para entrar em sua conta.
|
||||||
subject: 'Mastodon: Autenticação de dois fatores ativada'
|
subject: 'Mastodon: Autenticação de dois fatores ativada'
|
||||||
subtitle: A autenticação de dois fatores foi ativada para sua conta.
|
subtitle: A autenticação de dois fatores foi ativada para sua conta.
|
||||||
title: 2FA ativada
|
title: 2FA ativada
|
||||||
|
@ -75,11 +75,11 @@ pt-BR:
|
||||||
title: Uma das suas chaves de segurança foi excluída
|
title: Uma das suas chaves de segurança foi excluída
|
||||||
webauthn_disabled:
|
webauthn_disabled:
|
||||||
explanation: A autenticação por chaves de segurança foi desativada para sua conta.
|
explanation: A autenticação por chaves de segurança foi desativada para sua conta.
|
||||||
extra: Agora você pode fazer login usando apenas o código gerado pelo aplicativo de autenticação TOTP.
|
extra: Agora você pode entrar usando apenas o código de autenticação de dois fatores.
|
||||||
subject: 'Mastodon: Autenticação por chaves de segurança desativada'
|
subject: 'Mastodon: Autenticação por chaves de segurança desativada'
|
||||||
title: Chaves de segurança desativadas
|
title: Chaves de segurança desativadas
|
||||||
webauthn_enabled:
|
webauthn_enabled:
|
||||||
explanation: A autenticação por chave de segurança foi ativada para sua conta.
|
explanation: A autenticação por chave de segurança foi ativada.
|
||||||
extra: Sua chave de segurança agora pode ser usada para ‘login’.
|
extra: Sua chave de segurança agora pode ser usada para ‘login’.
|
||||||
subject: 'Mastodon: Autenticação por chaves de segurança ativada'
|
subject: 'Mastodon: Autenticação por chaves de segurança ativada'
|
||||||
title: Chaves de segurança ativadas
|
title: Chaves de segurança ativadas
|
||||||
|
|
|
@ -61,7 +61,7 @@ pt-BR:
|
||||||
title: Ocorreu um erro
|
title: Ocorreu um erro
|
||||||
new:
|
new:
|
||||||
prompt_html: "%{client_name} gostaria de permissão para acessar sua conta. <strong>Aprove esta solicitação apenas se você reconhecer e confiar nesta fonte.</strong>"
|
prompt_html: "%{client_name} gostaria de permissão para acessar sua conta. <strong>Aprove esta solicitação apenas se você reconhecer e confiar nesta fonte.</strong>"
|
||||||
review_permissions: Rever permissões
|
review_permissions: Revisar permissões
|
||||||
title: Autorização necessária
|
title: Autorização necessária
|
||||||
show:
|
show:
|
||||||
title: Copie este código de autorização e cole no aplicativo.
|
title: Copie este código de autorização e cole no aplicativo.
|
||||||
|
@ -130,7 +130,7 @@ pt-BR:
|
||||||
crypto: Criptografia de ponta a ponta
|
crypto: Criptografia de ponta a ponta
|
||||||
favourites: Favoritos
|
favourites: Favoritos
|
||||||
filters: Filtros
|
filters: Filtros
|
||||||
follow: Seguimentos, Silenciamentos e Bloqueios
|
follow: Seguidos, Silenciados e Bloqueados
|
||||||
follows: Seguidos
|
follows: Seguidos
|
||||||
lists: Listas
|
lists: Listas
|
||||||
media: Mídias anexadas
|
media: Mídias anexadas
|
||||||
|
@ -165,7 +165,7 @@ pt-BR:
|
||||||
admin:write:email_domain_blocks: executar ações de moderação em domínios de e-mail bloqueados
|
admin:write:email_domain_blocks: executar ações de moderação em domínios de e-mail bloqueados
|
||||||
admin:write:ip_blocks: executar ações de moderação em IPs bloqueados
|
admin:write:ip_blocks: executar ações de moderação em IPs bloqueados
|
||||||
admin:write:reports: executar ações de moderação em denúncias
|
admin:write:reports: executar ações de moderação em denúncias
|
||||||
crypto: usar criptografia de ponta-a-ponta
|
crypto: usar criptografia de ponta a ponta
|
||||||
follow: alterar o relacionamento das contas
|
follow: alterar o relacionamento das contas
|
||||||
profile: ler somente as informações do perfil da sua conta
|
profile: ler somente as informações do perfil da sua conta
|
||||||
push: receber notificações push
|
push: receber notificações push
|
||||||
|
|
|
@ -479,6 +479,16 @@ eo:
|
||||||
new:
|
new:
|
||||||
title: Importi domajnblokojn
|
title: Importi domajnblokojn
|
||||||
no_file: Neniu dosiero elektita
|
no_file: Neniu dosiero elektita
|
||||||
|
fasp:
|
||||||
|
debug:
|
||||||
|
callbacks:
|
||||||
|
delete: Forigi
|
||||||
|
providers:
|
||||||
|
delete: Forigi
|
||||||
|
name: Nomo
|
||||||
|
registrations:
|
||||||
|
confirm: Konfirmi
|
||||||
|
sign_in: Ensaluti
|
||||||
follow_recommendations:
|
follow_recommendations:
|
||||||
description_html: "<strong>Sekvorekomendoj helpi novajn uzantojn rapide trovi interesa enhavo</strong>. Ili rekalkulitas ĉiutage lau interagoj kaj sekvantokvantoj."
|
description_html: "<strong>Sekvorekomendoj helpi novajn uzantojn rapide trovi interesa enhavo</strong>. Ili rekalkulitas ĉiutage lau interagoj kaj sekvantokvantoj."
|
||||||
language: Por la lingvo
|
language: Por la lingvo
|
||||||
|
|
|
@ -473,6 +473,36 @@ ko:
|
||||||
new:
|
new:
|
||||||
title: 도메인 차단 불러오기
|
title: 도메인 차단 불러오기
|
||||||
no_file: 선택된 파일이 없습니다
|
no_file: 선택된 파일이 없습니다
|
||||||
|
fasp:
|
||||||
|
debug:
|
||||||
|
callbacks:
|
||||||
|
created_at: 생성일
|
||||||
|
delete: 삭제
|
||||||
|
ip: IP 주소
|
||||||
|
request_body: 요청 바디
|
||||||
|
title: 디버그 콜백
|
||||||
|
providers:
|
||||||
|
active: 활성
|
||||||
|
base_url: Base URL
|
||||||
|
callback: 콜백
|
||||||
|
delete: 삭제
|
||||||
|
edit: 제공자 편집
|
||||||
|
finish_registration: 등록 완료
|
||||||
|
name: 이름
|
||||||
|
providers: 제공자
|
||||||
|
public_key_fingerprint: 공개키 핑거프린트
|
||||||
|
registration_requested: 가입 요청됨
|
||||||
|
registrations:
|
||||||
|
confirm: 확인
|
||||||
|
description: FASP로부터 등록을 받았습니다. 본인이 시작하지 않았다면 거부하세요. 본인이 시작했다면 등록을 확인하기 전에 이름과 키 핑거프린트를 주의 깊게 비교하세요.
|
||||||
|
reject: 거부
|
||||||
|
title: FASP 가입 확인
|
||||||
|
save: 저장
|
||||||
|
select_capabilities: 권한 선택
|
||||||
|
sign_in: 가입
|
||||||
|
status: 상태
|
||||||
|
title: 연합우주 보조 서비스 제공자
|
||||||
|
title: FASP
|
||||||
follow_recommendations:
|
follow_recommendations:
|
||||||
description_html: "<strong>팔로우 추천은 새 사용자들이 관심 가는 콘텐트를 빠르게 찾을 수 있도록 도와줍니다</strong>. 사용자가 개인화 된 팔로우 추천이 만들어지기 위한 충분한 상호작용을 하지 않은 경우, 이 계정들이 대신 추천 됩니다. 이들은 해당 언어에 대해 많은 관심을 갖거나 많은 로컬 팔로워를 가지고 있는 계정들을 섞어서 날마다 다시 계산 됩니다."
|
description_html: "<strong>팔로우 추천은 새 사용자들이 관심 가는 콘텐트를 빠르게 찾을 수 있도록 도와줍니다</strong>. 사용자가 개인화 된 팔로우 추천이 만들어지기 위한 충분한 상호작용을 하지 않은 경우, 이 계정들이 대신 추천 됩니다. 이들은 해당 언어에 대해 많은 관심을 갖거나 많은 로컬 팔로워를 가지고 있는 계정들을 섞어서 날마다 다시 계산 됩니다."
|
||||||
language: 언어 필터
|
language: 언어 필터
|
||||||
|
|
|
@ -957,10 +957,15 @@ lv:
|
||||||
allow: Atļaut
|
allow: Atļaut
|
||||||
approved: Apstiprināts
|
approved: Apstiprināts
|
||||||
confirm_allow: Vai tiešām atļaut atlasītos tēmturus?
|
confirm_allow: Vai tiešām atļaut atlasītos tēmturus?
|
||||||
|
confirm_disallow: Vai tiešām neatļaut atlasītās birkas?
|
||||||
disallow: Neatļaut
|
disallow: Neatļaut
|
||||||
links:
|
links:
|
||||||
allow: Atļaut saiti
|
allow: Atļaut saiti
|
||||||
allow_provider: Atļaut publicētāju
|
allow_provider: Atļaut publicētāju
|
||||||
|
confirm_allow: Vai tiešām atļaut atlasītās saites?
|
||||||
|
confirm_allow_provider: Vai tiešām atļaut atlasītos nodrošinātājus?
|
||||||
|
confirm_disallow: Vai tiešām neatļaut atlasītās saites?
|
||||||
|
confirm_disallow_provider: Vai tiešām neatļaut atlasītos nodrošinātājus?
|
||||||
description_html: Šīs ir saites, kuras pašlaik bieži koplieto konti, no kuriem Tavs serveris redz ziņas. Tas var palīdzēt Taviem lietotājiem uzzināt, kas notiek pasaulē. Neviena saite netiek publiski rādīta, līdz tu apstiprini izdevēju. Tu vari arī atļaut vai noraidīt atsevišķas saites.
|
description_html: Šīs ir saites, kuras pašlaik bieži koplieto konti, no kuriem Tavs serveris redz ziņas. Tas var palīdzēt Taviem lietotājiem uzzināt, kas notiek pasaulē. Neviena saite netiek publiski rādīta, līdz tu apstiprini izdevēju. Tu vari arī atļaut vai noraidīt atsevišķas saites.
|
||||||
disallow: Neatļaut saiti
|
disallow: Neatļaut saiti
|
||||||
disallow_provider: Neatļaut publicētāju
|
disallow_provider: Neatļaut publicētāju
|
||||||
|
@ -985,6 +990,10 @@ lv:
|
||||||
statuses:
|
statuses:
|
||||||
allow: Ļaut veikt ierakstus
|
allow: Ļaut veikt ierakstus
|
||||||
allow_account: Atļaut autoru
|
allow_account: Atļaut autoru
|
||||||
|
confirm_allow: Vai tiešām atļaut atlasītos stāvokļus?
|
||||||
|
confirm_allow_account: Vai tiešām atļaut atlasītos kontus?
|
||||||
|
confirm_disallow: Vai tiešām neatļaut atlasītos stāvokļus?
|
||||||
|
confirm_disallow_account: Vai tiešām neatļaut atlasītos kontus?
|
||||||
description_html: Šie ir ieraksti, par kuriem zina Tavs serveris un kuri pašlaik tiek daudz kopīgoti un pievienoti izlasēm. Tas var palīdzēt jaunajiem lietotājiem un tiem, kuri atgriežas, atrast vairāk cilvēku, kam sekot. Neviens ieraksts netiek publiski rādīts, līdz apstiprināsi autoru un ja autors ļauj savu kontu ieteikt citiem. Tu vari arī atļaut vai noraidīt atsevišķus ierakstus.
|
description_html: Šie ir ieraksti, par kuriem zina Tavs serveris un kuri pašlaik tiek daudz kopīgoti un pievienoti izlasēm. Tas var palīdzēt jaunajiem lietotājiem un tiem, kuri atgriežas, atrast vairāk cilvēku, kam sekot. Neviens ieraksts netiek publiski rādīts, līdz apstiprināsi autoru un ja autors ļauj savu kontu ieteikt citiem. Tu vari arī atļaut vai noraidīt atsevišķus ierakstus.
|
||||||
disallow: Neļaut veikt ierakstus
|
disallow: Neļaut veikt ierakstus
|
||||||
disallow_account: Neatļaut autoru
|
disallow_account: Neatļaut autoru
|
||||||
|
|
|
@ -142,7 +142,7 @@ pt-BR:
|
||||||
only_password: Apenas senha
|
only_password: Apenas senha
|
||||||
password_and_2fa: Senha e autenticação de dois fatores
|
password_and_2fa: Senha e autenticação de dois fatores
|
||||||
sensitive: Sensíveis
|
sensitive: Sensíveis
|
||||||
sensitized: marcadas como sensíveis
|
sensitized: Marcadas como sensíveis
|
||||||
shared_inbox_url: Link da caixa de entrada compartilhada
|
shared_inbox_url: Link da caixa de entrada compartilhada
|
||||||
show:
|
show:
|
||||||
created_reports: Denúncias criadas
|
created_reports: Denúncias criadas
|
||||||
|
@ -309,6 +309,7 @@ pt-BR:
|
||||||
title: Auditar histórico
|
title: Auditar histórico
|
||||||
unavailable_instance: "(nome de domínio indisponível)"
|
unavailable_instance: "(nome de domínio indisponível)"
|
||||||
announcements:
|
announcements:
|
||||||
|
back: Voltar aos anúncios
|
||||||
destroyed_msg: Anúncio excluído!
|
destroyed_msg: Anúncio excluído!
|
||||||
edit:
|
edit:
|
||||||
title: Editar anúncio
|
title: Editar anúncio
|
||||||
|
@ -317,6 +318,8 @@ pt-BR:
|
||||||
new:
|
new:
|
||||||
create: Criar anúncio
|
create: Criar anúncio
|
||||||
title: Novo anúncio
|
title: Novo anúncio
|
||||||
|
preview:
|
||||||
|
explanation_html: 'Esse e-mail será enviado a <strong>%{display_count} usuários</strong>. O texto a seguir será incluído ao e-mail:'
|
||||||
publish: Publicar
|
publish: Publicar
|
||||||
published_msg: Anúncio publicado!
|
published_msg: Anúncio publicado!
|
||||||
scheduled_for: Agendado para %{time}
|
scheduled_for: Agendado para %{time}
|
||||||
|
@ -475,6 +478,25 @@ pt-BR:
|
||||||
new:
|
new:
|
||||||
title: Importar bloqueio de domínios
|
title: Importar bloqueio de domínios
|
||||||
no_file: Nenhum arquivo selecionado
|
no_file: Nenhum arquivo selecionado
|
||||||
|
fasp:
|
||||||
|
debug:
|
||||||
|
callbacks:
|
||||||
|
created_at: Criado em
|
||||||
|
delete: Apagar
|
||||||
|
ip: Endereço de IP
|
||||||
|
providers:
|
||||||
|
base_url: URL Base
|
||||||
|
delete: Apagar
|
||||||
|
finish_registration: Finalizar o cadastro
|
||||||
|
name: Nome
|
||||||
|
public_key_fingerprint: Impressão digital de chave pública
|
||||||
|
registration_requested: Cadastro solicitado
|
||||||
|
registrations:
|
||||||
|
confirm: Confirmar
|
||||||
|
reject: Rejeitar
|
||||||
|
save: Salvar
|
||||||
|
sign_in: Entrar
|
||||||
|
status: Estado
|
||||||
follow_recommendations:
|
follow_recommendations:
|
||||||
description_html: "<strong>A recomendação de contas ajuda os novos usuários a encontrar rapidamente conteúdo interessante</strong>. Quando um usuário ainda não tiver interagido o suficiente para gerar recomendações de contas, essas contas serão recomendadas. Essas recomendações são recalculadas diariamente a partir de uma lista de contas com alto engajamento e maior número de seguidores locais em uma dada língua."
|
description_html: "<strong>A recomendação de contas ajuda os novos usuários a encontrar rapidamente conteúdo interessante</strong>. Quando um usuário ainda não tiver interagido o suficiente para gerar recomendações de contas, essas contas serão recomendadas. Essas recomendações são recalculadas diariamente a partir de uma lista de contas com alto engajamento e maior número de seguidores locais em uma dada língua."
|
||||||
language: Na língua
|
language: Na língua
|
||||||
|
@ -939,6 +961,7 @@ pt-BR:
|
||||||
chance_to_review_html: "<strong>Os termos de serviço gerado não será publicado automaticamente.</strong>Você terá uma chance de revisar os resultados. Preencha os detalhes necessários para continuar"
|
chance_to_review_html: "<strong>Os termos de serviço gerado não será publicado automaticamente.</strong>Você terá uma chance de revisar os resultados. Preencha os detalhes necessários para continuar"
|
||||||
explanation_html: O modelo de termos de serviço fornecido é apenas para fins informativos e não deve ser interpretado como aconselhamento jurídico sobre qualquer assunto. Consulte seu próprio advogado para esclarecer sua situação e dúvidas jurídicas específicas.
|
explanation_html: O modelo de termos de serviço fornecido é apenas para fins informativos e não deve ser interpretado como aconselhamento jurídico sobre qualquer assunto. Consulte seu próprio advogado para esclarecer sua situação e dúvidas jurídicas específicas.
|
||||||
title: Configuração dos Termos de Serviço
|
title: Configuração dos Termos de Serviço
|
||||||
|
going_live_on_html: Em vigor a partir de %{date}
|
||||||
history: Histórico
|
history: Histórico
|
||||||
live: Em vigor
|
live: Em vigor
|
||||||
no_history: Ainda não há alterações registradas nos termos de serviço.
|
no_history: Ainda não há alterações registradas nos termos de serviço.
|
||||||
|
@ -1936,6 +1959,8 @@ pt-BR:
|
||||||
terms_of_service_changed:
|
terms_of_service_changed:
|
||||||
agreement: Ao continuar a usar %{domain}, você concorda com estes termos. Se discordar dos termos atualizados, poderá encerrar seu acordo com %{domain} a qualquer momento excluindo sua conta.
|
agreement: Ao continuar a usar %{domain}, você concorda com estes termos. Se discordar dos termos atualizados, poderá encerrar seu acordo com %{domain} a qualquer momento excluindo sua conta.
|
||||||
changelog: 'Em resumo, veja o que essa atualização significa para você:'
|
changelog: 'Em resumo, veja o que essa atualização significa para você:'
|
||||||
|
description: 'Você recebeu este e-mail porque faremos algumas mudanças nos Termos de Serviço do %{domain}. Essas atualizações entrarão em vigor a partir de %{date}. Veja o que mudou aqui:'
|
||||||
|
description_html: Você recebeu este e-mail porque faremos algumas mudanças nos Termos de Serviço do %{domain}. Essas atualizações entrarão em vigor a partir de <strong>%{date}</strong>. <a href="%{path}" target="_blank">Veja o que mudou aqui</a>.
|
||||||
sign_off: A equipe do %{domain}
|
sign_off: A equipe do %{domain}
|
||||||
subject: Atualizações dos nossos termos de serviço
|
subject: Atualizações dos nossos termos de serviço
|
||||||
subtitle: Os termos de serviço do %{domain} estão mudando.
|
subtitle: Os termos de serviço do %{domain} estão mudando.
|
||||||
|
|
|
@ -139,6 +139,7 @@ bg:
|
||||||
terms_of_service_generator:
|
terms_of_service_generator:
|
||||||
admin_email: Правните бележки включват насрещни известия, постановления на съда, заявки за сваляне и заявки от правоохранителните органи.
|
admin_email: Правните бележки включват насрещни известия, постановления на съда, заявки за сваляне и заявки от правоохранителните органи.
|
||||||
arbitration_address: Може да е същото като физическия адрес горе или "неприложимо", ако се употребява имейл.
|
arbitration_address: Може да е същото като физическия адрес горе или "неприложимо", ако се употребява имейл.
|
||||||
|
arbitration_website: Може да е уеб формуляр или "неналично", ако употребявате имейл.
|
||||||
choice_of_law: Град, регион, територия, щат или държава, чиито вътрешни материални права ще уреждат всички искове.
|
choice_of_law: Град, регион, територия, щат или държава, чиито вътрешни материални права ще уреждат всички искове.
|
||||||
dmca_email: Може да е същият имейл, използван за "Имейл адрес за правни известия" по-горе.
|
dmca_email: Може да е същият имейл, използван за "Имейл адрес за правни известия" по-горе.
|
||||||
domain: Неповторимо идентифициране на онлайн услугата, която предоставяте.
|
domain: Неповторимо идентифициране на онлайн услугата, която предоставяте.
|
||||||
|
|
|
@ -8,9 +8,9 @@ pt-BR:
|
||||||
display_name: Seu nome completo ou apelido.
|
display_name: Seu nome completo ou apelido.
|
||||||
fields: Sua página inicial, pronomes, idade ou qualquer coisa que quiser.
|
fields: Sua página inicial, pronomes, idade ou qualquer coisa que quiser.
|
||||||
indexable: Suas publicações públicas podem aparecer nos resultados da pesquisa em Mastodon. As pessoas que interagiram com suas publicações podem conseguir pesquisá-las independentemente disso.
|
indexable: Suas publicações públicas podem aparecer nos resultados da pesquisa em Mastodon. As pessoas que interagiram com suas publicações podem conseguir pesquisá-las independentemente disso.
|
||||||
note: 'Você pode @mencionar outras pessoas ou #hashtags.'
|
note: 'Você pode @mencionar outras pessoas ou usar #hashtags.'
|
||||||
show_collections: As pessoas poderão navegar entre os seus seguidores e seguidores. As pessoas que você segue verão que você as segue independentemente disso.
|
show_collections: As pessoas podem ver seus seguidores e quem você está seguindo. Os perfis que você seguir saberão que você os segue independentemente do que selecionar.
|
||||||
unlocked: As pessoas poderão seguir você sem solicitar aprovação. Desmarque caso você queira revisar as solicitações de seguidor e escolha se queira aceitar ou rejeitar novos seguidores.
|
unlocked: As pessoas poderão te seguir sem solicitar aprovação. Desmarque caso você queira revisar as solicitações.
|
||||||
account_alias:
|
account_alias:
|
||||||
acct: Especifique o usuário@domínio de onde veio
|
acct: Especifique o usuário@domínio de onde veio
|
||||||
account_migration:
|
account_migration:
|
||||||
|
@ -27,8 +27,8 @@ pt-BR:
|
||||||
disable: Impede o usuário de usar a conta, porém sem excluí-la ou suspendê-la.
|
disable: Impede o usuário de usar a conta, porém sem excluí-la ou suspendê-la.
|
||||||
none: Use isto para enviar uma advertência ao usuário, sem nenhuma outra ação.
|
none: Use isto para enviar uma advertência ao usuário, sem nenhuma outra ação.
|
||||||
sensitive: Marca todas as mídias do usuário como sensível.
|
sensitive: Marca todas as mídias do usuário como sensível.
|
||||||
silence: Impede o usuário de enviar postagens visualmente públicas, além de ocultar suas publicações e notificações dos que não o seguem. Ademais, fecha todas as denúncias contra esta conta.
|
silence: Impede o usuário de postar publicamente, restringe suas publicações e notificações a somente quem o segue. Encerra todas as denúncias contra esta conta.
|
||||||
suspend: Impede qualquer interação de ou para esta conta e exclui seu conteúdo. Reversível dentro de 30 dias. Ademais, fecha todas as denúncias contra esta conta.
|
suspend: Impede qualquer interação de ou para esta conta e exclui seu conteúdo. Reversível dentro de 30 dias. Encerra todas as denúncias contra esta conta.
|
||||||
warning_preset_id: Opcional. Você pode adicionar texto personalizado no final da advertência pré-definida
|
warning_preset_id: Opcional. Você pode adicionar texto personalizado no final da advertência pré-definida
|
||||||
announcement:
|
announcement:
|
||||||
all_day: Quando marcada, apenas as datas do período serão mostradas
|
all_day: Quando marcada, apenas as datas do período serão mostradas
|
||||||
|
@ -37,11 +37,11 @@ pt-BR:
|
||||||
starts_at: Opcional. Caso o comunicado esteja vinculado a um período específico
|
starts_at: Opcional. Caso o comunicado esteja vinculado a um período específico
|
||||||
text: Você pode usar a sintaxe do toot. Considere o espaço que o comunicado ocupará na tela do usuário
|
text: Você pode usar a sintaxe do toot. Considere o espaço que o comunicado ocupará na tela do usuário
|
||||||
appeal:
|
appeal:
|
||||||
text: Você só pode solicitar uma revisão uma vez
|
text: Você só pode recorrer uma vez
|
||||||
defaults:
|
defaults:
|
||||||
autofollow: Pessoas que criarem conta através de seu convite te seguirão automaticamente
|
autofollow: Pessoas que criarem conta através de seu convite te seguirão automaticamente
|
||||||
avatar: WEBP, PNG, GIF ou JPG. No máximo %{size}. Será reduzido para %{dimensions}px
|
avatar: WEBP, PNG, GIF ou JPG. No máximo %{size}. Será reduzido para %{dimensions}px
|
||||||
bot: Essa conta executa principalmente ações automatizadas e pode não ser monitorada
|
bot: Sinaliza aos outros de que essa conta executa principalmente ações automatizadas e pode não ser monitorada
|
||||||
context: Um ou mais contextos onde o filtro deve atuar
|
context: Um ou mais contextos onde o filtro deve atuar
|
||||||
current_password: Para fins de segurança, digite a senha da conta atual
|
current_password: Para fins de segurança, digite a senha da conta atual
|
||||||
current_username: Para confirmar, digite o nome de usuário da conta atual
|
current_username: Para confirmar, digite o nome de usuário da conta atual
|
||||||
|
@ -54,7 +54,7 @@ pt-BR:
|
||||||
password: Use pelo menos 8 caracteres
|
password: Use pelo menos 8 caracteres
|
||||||
phrase: Corresponderá independente de maiúsculas ou minúsculas, no texto ou no Aviso de Conteúdo de um toot
|
phrase: Corresponderá independente de maiúsculas ou minúsculas, no texto ou no Aviso de Conteúdo de um toot
|
||||||
scopes: Quais APIs o aplicativo vai ter permissão de acessar. Se você selecionar uma autorização de alto nível, você não precisa selecionar individualmente os outros.
|
scopes: Quais APIs o aplicativo vai ter permissão de acessar. Se você selecionar uma autorização de alto nível, você não precisa selecionar individualmente os outros.
|
||||||
setting_aggregate_reblogs: Não mostra novos impulsos para publicações já receberam recentemente (afeta somente os impulsos mais recentes)
|
setting_aggregate_reblogs: Não mostrar novos impulsos para publicações que já foram impulsionadas recentemente (afeta somente os impulsos mais recentes)
|
||||||
setting_always_send_emails: Normalmente, as notificações por e-mail não serão enviadas enquanto você estiver usando ativamente o Mastodon
|
setting_always_send_emails: Normalmente, as notificações por e-mail não serão enviadas enquanto você estiver usando ativamente o Mastodon
|
||||||
setting_default_sensitive: Mídia sensível está oculta por padrão e pode ser revelada com um clique
|
setting_default_sensitive: Mídia sensível está oculta por padrão e pode ser revelada com um clique
|
||||||
setting_display_media_default: Sempre ocultar mídia sensível
|
setting_display_media_default: Sempre ocultar mídia sensível
|
||||||
|
@ -75,12 +75,13 @@ pt-BR:
|
||||||
filters:
|
filters:
|
||||||
action: Escolher qual ação executar quando uma publicação corresponder ao filtro
|
action: Escolher qual ação executar quando uma publicação corresponder ao filtro
|
||||||
actions:
|
actions:
|
||||||
|
blur: Oculte a mídia com um aviso, porém mantenha o texto visível
|
||||||
hide: Esconder completamente o conteúdo filtrado, comportando-se como se ele não existisse
|
hide: Esconder completamente o conteúdo filtrado, comportando-se como se ele não existisse
|
||||||
warn: Ocultar o conteúdo filtrado por trás de um aviso mencionando o título do filtro
|
warn: Ocultar o conteúdo filtrado por trás de um aviso mencionando o título do filtro
|
||||||
form_admin_settings:
|
form_admin_settings:
|
||||||
activity_api_enabled: Contagem de publicações locais, usuários ativos e novos usuários semanais
|
activity_api_enabled: Contagem de publicações locais, usuários ativos e novos usuários semanais
|
||||||
app_icon: WEBP, PNG, GIF ou JPG. Sobrescrever o ícone padrão do aplicativo em dispositivos móveis com um ícone personalizado.
|
app_icon: WEBP, PNG, GIF ou JPG. Sobrescrever o ícone padrão do aplicativo em dispositivos móveis com um ícone personalizado.
|
||||||
backups_retention_period: Os usuários têm a capacidade de gerar arquivos de suas postagens para baixar mais tarde. Quando definido como um valor positivo, esses arquivos serão automaticamente excluídos do seu armazenamento após o número especificado de dias.
|
backups_retention_period: Os usuários podem gerar arquivos de suas postagens para baixar mais tarde. Quando definido como um valor positivo, esses arquivos serão automaticamente excluídos do seu armazenamento após o número especificado de dias.
|
||||||
bootstrap_timeline_accounts: Estas contas serão fixadas no topo das recomendações de novos usuários para seguir.
|
bootstrap_timeline_accounts: Estas contas serão fixadas no topo das recomendações de novos usuários para seguir.
|
||||||
closed_registrations_message: Exibido quando as inscrições estiverem fechadas
|
closed_registrations_message: Exibido quando as inscrições estiverem fechadas
|
||||||
content_cache_retention_period: Todas as postagens de outros servidores (incluindo boosts e respostas) serão excluídas após o número especificado de dias, sem levar a qualquer interação do usuário local com esses posts. Isto inclui postagens onde um usuário local o marcou como favorito ou favoritos. Menções privadas entre usuários de diferentes instâncias também serão perdidas e impossíveis de restaurar. O uso desta configuração destina-se a instâncias especiais de propósitos e quebra muitas expectativas dos usuários quando implementadas para uso de propósito geral.
|
content_cache_retention_period: Todas as postagens de outros servidores (incluindo boosts e respostas) serão excluídas após o número especificado de dias, sem levar a qualquer interação do usuário local com esses posts. Isto inclui postagens onde um usuário local o marcou como favorito ou favoritos. Menções privadas entre usuários de diferentes instâncias também serão perdidas e impossíveis de restaurar. O uso desta configuração destina-se a instâncias especiais de propósitos e quebra muitas expectativas dos usuários quando implementadas para uso de propósito geral.
|
||||||
|
@ -88,6 +89,7 @@ pt-BR:
|
||||||
favicon: WEBP, PNG, GIF ou JPG. Sobrescreve o favicon padrão do Mastodon com um ícone personalizado.
|
favicon: WEBP, PNG, GIF ou JPG. Sobrescreve o favicon padrão do Mastodon com um ícone personalizado.
|
||||||
mascot: Substitui a ilustração na interface web avançada.
|
mascot: Substitui a ilustração na interface web avançada.
|
||||||
media_cache_retention_period: Arquivos de mídia de mensagens de usuários remotos são armazenados em cache no seu servidor. Quando definido como valor positivo, a mídia será excluída após o número especificado de dias. Se os dados da mídia forem solicitados depois de excluídos, eles serão baixados novamente, se o conteúdo fonte ainda estiver disponível. Devido a restrições de quantas vezes os cartões de visualização de links sondam sites de terceiros, é recomendado definir este valor em pelo menos 14 dias, ou pré-visualização de links não serão atualizados a pedido antes desse tempo.
|
media_cache_retention_period: Arquivos de mídia de mensagens de usuários remotos são armazenados em cache no seu servidor. Quando definido como valor positivo, a mídia será excluída após o número especificado de dias. Se os dados da mídia forem solicitados depois de excluídos, eles serão baixados novamente, se o conteúdo fonte ainda estiver disponível. Devido a restrições de quantas vezes os cartões de visualização de links sondam sites de terceiros, é recomendado definir este valor em pelo menos 14 dias, ou pré-visualização de links não serão atualizados a pedido antes desse tempo.
|
||||||
|
min_age: Os usuários precisarão confirmar sua data de nascimento no cadastro
|
||||||
peers_api_enabled: Uma lista de nomes de domínio que este servidor encontrou no "fediverse". Nenhum dado é incluído aqui sobre se você concorda com os padroes operacionais de um determinado servidor, apenas que o seu servidor sabe disso. Esta ferramenta é utilizado por serviços que recolhem estatísticas sob as normas da federação (grupo de empresas que concordam sob paramentros operacionais específicos), em termos gerais.
|
peers_api_enabled: Uma lista de nomes de domínio que este servidor encontrou no "fediverse". Nenhum dado é incluído aqui sobre se você concorda com os padroes operacionais de um determinado servidor, apenas que o seu servidor sabe disso. Esta ferramenta é utilizado por serviços que recolhem estatísticas sob as normas da federação (grupo de empresas que concordam sob paramentros operacionais específicos), em termos gerais.
|
||||||
profile_directory: O diretório de perfis lista todos os usuários que optaram por permitir que suas contas sejam descobertas.
|
profile_directory: O diretório de perfis lista todos os usuários que optaram por permitir que suas contas sejam descobertas.
|
||||||
require_invite_text: 'Quando o cadastro de novas contas exigir aprovação manual, tornar obrigatório, ao invés de opcional, o texto de solicitação de convite: "Por que você deseja ingressar nessa comunidade?"'
|
require_invite_text: 'Quando o cadastro de novas contas exigir aprovação manual, tornar obrigatório, ao invés de opcional, o texto de solicitação de convite: "Por que você deseja ingressar nessa comunidade?"'
|
||||||
|
@ -132,14 +134,21 @@ pt-BR:
|
||||||
name: Você pode mudar a capitalização das letras, por exemplo, para torná-la mais legível
|
name: Você pode mudar a capitalização das letras, por exemplo, para torná-la mais legível
|
||||||
terms_of_service:
|
terms_of_service:
|
||||||
changelog: Pode ser estruturado com a sintaxe Markdown.
|
changelog: Pode ser estruturado com a sintaxe Markdown.
|
||||||
|
effective_date: Um intervalo de tempo razoável pode variar de 10 a 30 dias a partir da data em que notificar seus usuários.
|
||||||
text: Pode ser estruturado com a sintaxe Markdown.
|
text: Pode ser estruturado com a sintaxe Markdown.
|
||||||
terms_of_service_generator:
|
terms_of_service_generator:
|
||||||
admin_email: Avisos legais incluem contra-notificações, ordens judiciais, solicitações de remoção e solicitações de órgãos de fiscalização.
|
admin_email: Avisos legais incluem contra-notificações, ordens judiciais, solicitações de remoção e solicitações de órgãos de fiscalização.
|
||||||
|
arbitration_address: Pode ser o mesmo do endereço colocado cima, ou use "N/A" se estiver utilizando e-mail.
|
||||||
|
arbitration_website: Pode ser um formulário online, ou use "N/A" caso esteja utilizando um e-mail.
|
||||||
|
choice_of_law: Cidade, região, território ou estado cujas leis substantivas internas serão aplicáveis a todas e quaisquer reivindicações.
|
||||||
dmca_address: Para operadores dos EUA, utilize o endereço registrado no Diretório de Agentes Designados pela DMCA. Um endereço de Caixa Postal está disponível mediante solicitação direta; use a Solicitação de Isenção de Caixa Postal de Agente Designado pela DMCA para enviar um e-mail ao Escritório de Direitos Autorais, explicando que você é um moderador de conteúdo que trabalha em casa e teme vingança ou retaliação por suas ações, precisando usar uma Caixa Postal para remover seu endereço residencial da visualização pública.
|
dmca_address: Para operadores dos EUA, utilize o endereço registrado no Diretório de Agentes Designados pela DMCA. Um endereço de Caixa Postal está disponível mediante solicitação direta; use a Solicitação de Isenção de Caixa Postal de Agente Designado pela DMCA para enviar um e-mail ao Escritório de Direitos Autorais, explicando que você é um moderador de conteúdo que trabalha em casa e teme vingança ou retaliação por suas ações, precisando usar uma Caixa Postal para remover seu endereço residencial da visualização pública.
|
||||||
|
dmca_email: Pode ser o mesmo e-mail utilizado acima em "Endereço de e-mail para avisos legais".
|
||||||
domain: Identificação única do serviço online que você está fornecendo.
|
domain: Identificação única do serviço online que você está fornecendo.
|
||||||
jurisdiction: Liste o país onde quem paga as contas reside. Se for uma empresa ou outra entidade, liste o país onde ela está incorporada, e a cidade, região, território ou estado, conforme apropriado.
|
jurisdiction: Liste o país onde quem paga as contas reside. Se for uma empresa ou outra entidade, liste o país onde ela está incorporada, e a cidade, região, território ou estado, conforme apropriado.
|
||||||
|
min_age: Não deve ter menos que a idade mínima exigida pelas suas leis locais.
|
||||||
user:
|
user:
|
||||||
chosen_languages: Apenas as publicações dos idiomas selecionados serão exibidas nas linhas públicas
|
chosen_languages: Apenas as publicações dos idiomas selecionados serão exibidas nas linhas públicas
|
||||||
|
date_of_birth: Precisamos ter certeza de que você tem, no mínimo, %{age} anos para usar o Mastodon. Não armazenaremos essa informação.
|
||||||
role: A função controla quais permissões o usuário tem.
|
role: A função controla quais permissões o usuário tem.
|
||||||
user_role:
|
user_role:
|
||||||
color: Cor a ser usada para o cargo em toda a interface do usuário, como RGB no formato hexadecimal
|
color: Cor a ser usada para o cargo em toda a interface do usuário, como RGB no formato hexadecimal
|
||||||
|
@ -252,6 +261,7 @@ pt-BR:
|
||||||
name: Hashtag
|
name: Hashtag
|
||||||
filters:
|
filters:
|
||||||
actions:
|
actions:
|
||||||
|
blur: Oculte a mídia com um aviso
|
||||||
hide: Ocultar completamente
|
hide: Ocultar completamente
|
||||||
warn: Ocultar com um aviso
|
warn: Ocultar com um aviso
|
||||||
form_admin_settings:
|
form_admin_settings:
|
||||||
|
@ -265,6 +275,7 @@ pt-BR:
|
||||||
favicon: Favicon
|
favicon: Favicon
|
||||||
mascot: Mascote personalizado (legado)
|
mascot: Mascote personalizado (legado)
|
||||||
media_cache_retention_period: Período de retenção do cachê de mídia
|
media_cache_retention_period: Período de retenção do cachê de mídia
|
||||||
|
min_age: Requisito de idade mínimia
|
||||||
peers_api_enabled: Publicar lista de instâncias de servidor descobertas na API
|
peers_api_enabled: Publicar lista de instâncias de servidor descobertas na API
|
||||||
profile_directory: Ativar diretório de perfis
|
profile_directory: Ativar diretório de perfis
|
||||||
registrations_mode: Quem pode se inscrever
|
registrations_mode: Quem pode se inscrever
|
||||||
|
@ -330,16 +341,22 @@ pt-BR:
|
||||||
usable: Permitir que as publicações usem esta hashtag localmente
|
usable: Permitir que as publicações usem esta hashtag localmente
|
||||||
terms_of_service:
|
terms_of_service:
|
||||||
changelog: O que mudou?
|
changelog: O que mudou?
|
||||||
|
effective_date: Data de vigência
|
||||||
text: Termos de Serviço
|
text: Termos de Serviço
|
||||||
terms_of_service_generator:
|
terms_of_service_generator:
|
||||||
admin_email: Endereço de e-mail para avisos legais.
|
admin_email: Endereço de e-mail para avisos legais
|
||||||
arbitration_address: Endereço físico para avisos de arbitragem.
|
arbitration_address: Endereço físico para avisos de arbitragem.
|
||||||
arbitration_website: Site para submissão de notificações de arbitragem
|
arbitration_website: Site para submissão de notificações de arbitragem
|
||||||
|
choice_of_law: Lei de regência
|
||||||
dmca_address: Endereço físico para notificações de DMCA/direitos autorais
|
dmca_address: Endereço físico para notificações de DMCA/direitos autorais
|
||||||
dmca_email: Endereço de e-mail para notificações de DMCA/direitos autorais
|
dmca_email: Endereço de e-mail para notificações de DMCA/direitos autorais
|
||||||
domain: Domínio
|
domain: Domínio
|
||||||
jurisdiction: Jurisdicação legal
|
jurisdiction: Jurisdição legal
|
||||||
|
min_age: Idade mínima
|
||||||
user:
|
user:
|
||||||
|
date_of_birth_1i: Dia
|
||||||
|
date_of_birth_2i: Mês
|
||||||
|
date_of_birth_3i: Ano
|
||||||
role: Cargo
|
role: Cargo
|
||||||
time_zone: Fuso horário
|
time_zone: Fuso horário
|
||||||
user_role:
|
user_role:
|
||||||
|
|
419
eslint.config.mjs
Normal file
419
eslint.config.mjs
Normal file
|
@ -0,0 +1,419 @@
|
||||||
|
// @ts-check
|
||||||
|
|
||||||
|
import js from '@eslint/js';
|
||||||
|
import { globalIgnores } from 'eslint/config';
|
||||||
|
import formatjs from 'eslint-plugin-formatjs';
|
||||||
|
// @ts-expect-error -- No typings
|
||||||
|
import importPlugin from 'eslint-plugin-import';
|
||||||
|
import jsdoc from 'eslint-plugin-jsdoc';
|
||||||
|
import jsxA11Y from 'eslint-plugin-jsx-a11y';
|
||||||
|
import promisePlugin from 'eslint-plugin-promise';
|
||||||
|
import react from 'eslint-plugin-react';
|
||||||
|
import reactHooks from 'eslint-plugin-react-hooks';
|
||||||
|
import globals from 'globals';
|
||||||
|
import tseslint from 'typescript-eslint';
|
||||||
|
|
||||||
|
/** @type {import('typescript-eslint').ConfigArray} */
|
||||||
|
export const baseConfig = [
|
||||||
|
js.configs.recommended,
|
||||||
|
importPlugin.flatConfigs.recommended,
|
||||||
|
jsdoc.configs['flat/recommended'],
|
||||||
|
promisePlugin.configs['flat/recommended'],
|
||||||
|
{
|
||||||
|
linterOptions: {
|
||||||
|
reportUnusedDisableDirectives: 'error',
|
||||||
|
reportUnusedInlineConfigs: 'error',
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
'consistent-return': 'error',
|
||||||
|
'dot-notation': 'error',
|
||||||
|
|
||||||
|
eqeqeq: [
|
||||||
|
'error',
|
||||||
|
'always',
|
||||||
|
{
|
||||||
|
null: 'ignore',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
'no-console': [
|
||||||
|
'warn',
|
||||||
|
{
|
||||||
|
allow: ['error', 'warn'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
'no-empty': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
allowEmptyCatch: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
'no-restricted-properties': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
property: 'substring',
|
||||||
|
message: 'Use .slice instead of .substring.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
property: 'substr',
|
||||||
|
message: 'Use .slice instead of .substr.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
'no-unused-expressions': 'error',
|
||||||
|
'no-unused-vars': 'off',
|
||||||
|
|
||||||
|
'valid-typeof': 'error',
|
||||||
|
|
||||||
|
'import/extensions': [
|
||||||
|
'error',
|
||||||
|
'always',
|
||||||
|
{
|
||||||
|
js: 'never',
|
||||||
|
jsx: 'never',
|
||||||
|
mjs: 'never',
|
||||||
|
ts: 'never',
|
||||||
|
mts: 'never',
|
||||||
|
tsx: 'never',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'import/first': 'error',
|
||||||
|
'import/newline-after-import': 'error',
|
||||||
|
'import/no-anonymous-default-export': 'error',
|
||||||
|
'import/no-amd': 'error',
|
||||||
|
'import/no-commonjs': 'error',
|
||||||
|
'import/no-import-module-exports': 'error',
|
||||||
|
'import/no-relative-packages': 'error',
|
||||||
|
'import/no-self-import': 'error',
|
||||||
|
'import/no-useless-path-segments': 'error',
|
||||||
|
'import/order': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
alphabetize: {
|
||||||
|
order: 'asc',
|
||||||
|
},
|
||||||
|
|
||||||
|
'newlines-between': 'always',
|
||||||
|
|
||||||
|
groups: [
|
||||||
|
'builtin',
|
||||||
|
'external',
|
||||||
|
'internal',
|
||||||
|
'parent',
|
||||||
|
['index', 'sibling'],
|
||||||
|
'object',
|
||||||
|
],
|
||||||
|
|
||||||
|
pathGroups: [
|
||||||
|
{
|
||||||
|
pattern: '{react,react-dom,react-dom/client,prop-types}',
|
||||||
|
group: 'builtin',
|
||||||
|
position: 'after',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: '{react-intl,intl-messageformat}',
|
||||||
|
group: 'builtin',
|
||||||
|
position: 'after',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern:
|
||||||
|
'{classnames,react-helmet,react-router,react-router-dom}',
|
||||||
|
group: 'external',
|
||||||
|
position: 'before',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern:
|
||||||
|
'{immutable,@reduxjs/toolkit,react-redux,react-immutable-proptypes,react-immutable-pure-component}',
|
||||||
|
group: 'external',
|
||||||
|
position: 'before',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: '{mastodon/**}',
|
||||||
|
group: 'internal',
|
||||||
|
position: 'after',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: '{flavours/glitch-soc/**}',
|
||||||
|
group: 'internal',
|
||||||
|
position: 'after',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
pathGroupsExcludedImportTypes: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
'jsdoc/check-types': 'off',
|
||||||
|
'jsdoc/no-undefined-types': 'off',
|
||||||
|
'jsdoc/require-jsdoc': 'off',
|
||||||
|
'jsdoc/require-param-description': 'off',
|
||||||
|
'jsdoc/require-property-description': 'off',
|
||||||
|
'jsdoc/require-returns-description': 'off',
|
||||||
|
'jsdoc/require-returns': 'off',
|
||||||
|
|
||||||
|
// Forbid imports from vanilla in glitch flavour
|
||||||
|
'import/no-restricted-paths': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
zones: [
|
||||||
|
{
|
||||||
|
target: 'app/javascript/flavours/glitch/',
|
||||||
|
from: 'app/javascript/mastodon/',
|
||||||
|
message: 'Import from /flavours/glitch/ instead',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
'promise/always-return': 'off',
|
||||||
|
'promise/catch-or-return': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
allowFinally: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'promise/no-callback-in-promise': 'off',
|
||||||
|
'promise/no-nesting': 'off',
|
||||||
|
'promise/no-promise-in-callback': 'off',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default tseslint.config([
|
||||||
|
baseConfig,
|
||||||
|
globalIgnores([
|
||||||
|
'build/**/*',
|
||||||
|
'coverage/**/*',
|
||||||
|
'db/**/*',
|
||||||
|
'lib/**/*',
|
||||||
|
'log/**/*',
|
||||||
|
'node_modules/**/*',
|
||||||
|
'public/**/*',
|
||||||
|
'!public/embed.js',
|
||||||
|
'spec/**/*',
|
||||||
|
'tmp/**/*',
|
||||||
|
'vendor/**/*',
|
||||||
|
'streaming/**/*',
|
||||||
|
]),
|
||||||
|
react.configs.flat.recommended,
|
||||||
|
react.configs.flat['jsx-runtime'],
|
||||||
|
reactHooks.configs['recommended-latest'],
|
||||||
|
jsxA11Y.flatConfigs.recommended,
|
||||||
|
importPlugin.flatConfigs.react,
|
||||||
|
// @ts-expect-error -- For some reason the formatjs package exports an empty object?
|
||||||
|
formatjs.configs.strict,
|
||||||
|
{
|
||||||
|
languageOptions: {
|
||||||
|
globals: {
|
||||||
|
...globals.browser,
|
||||||
|
},
|
||||||
|
|
||||||
|
parser: tseslint.parser,
|
||||||
|
ecmaVersion: 2021,
|
||||||
|
sourceType: 'module',
|
||||||
|
},
|
||||||
|
|
||||||
|
settings: {
|
||||||
|
react: {
|
||||||
|
version: 'detect',
|
||||||
|
},
|
||||||
|
|
||||||
|
'import/ignore': ['node_modules', '\\.(css|scss|json)$'],
|
||||||
|
|
||||||
|
'import/resolver': {
|
||||||
|
typescript: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
rules: {
|
||||||
|
'no-restricted-syntax': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
// eslint-disable-next-line no-restricted-syntax
|
||||||
|
selector: 'Literal[value=/•/], JSXText[value=/•/]',
|
||||||
|
// eslint-disable-next-line no-restricted-syntax
|
||||||
|
message: "Use '·' (middle dot) instead of '•' (bullet)",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
'formatjs/enforce-description': 'off', // description values not currently used
|
||||||
|
'formatjs/enforce-id': 'off', // Explicit IDs are used in the project
|
||||||
|
'formatjs/enforce-placeholders': 'off', // Issues in short_number.jsx
|
||||||
|
'formatjs/no-invalid-icu': 'error',
|
||||||
|
'formatjs/no-literal-string-in-jsx': 'off', // Should be looked at, but mainly flagging punctuation outside of strings
|
||||||
|
'formatjs/no-multiple-plurals': 'off', // Should be looked at
|
||||||
|
|
||||||
|
'jsx-a11y/click-events-have-key-events': 'off',
|
||||||
|
'jsx-a11y/label-has-associated-control': 'off',
|
||||||
|
'jsx-a11y/media-has-caption': 'off',
|
||||||
|
'jsx-a11y/no-autofocus': 'off',
|
||||||
|
'jsx-a11y/no-interactive-element-to-noninteractive-role': 'off',
|
||||||
|
'jsx-a11y/no-noninteractive-tabindex': 'off',
|
||||||
|
'jsx-a11y/no-static-element-interactions': [
|
||||||
|
'warn',
|
||||||
|
{
|
||||||
|
handlers: ['onClick'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
'import/no-extraneous-dependencies': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
devDependencies: [
|
||||||
|
'eslint.config.mjs',
|
||||||
|
'config/webpack/**',
|
||||||
|
'app/javascript/mastodon/performance.js',
|
||||||
|
'app/javascript/mastodon/test_setup.js',
|
||||||
|
'app/javascript/**/__tests__/**',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'import/no-webpack-loader-syntax': 'error',
|
||||||
|
|
||||||
|
'react/jsx-filename-extension': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
extensions: ['.jsx', 'tsx'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
'react/jsx-boolean-value': 'error',
|
||||||
|
'react/display-name': 'off',
|
||||||
|
'react/jsx-fragments': ['error', 'syntax'],
|
||||||
|
'react/jsx-equals-spacing': 'error',
|
||||||
|
'react/jsx-no-bind': 'error',
|
||||||
|
'react/jsx-no-useless-fragment': 'error',
|
||||||
|
'react/jsx-no-target-blank': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
allowReferrer: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'react/jsx-tag-spacing': 'error',
|
||||||
|
'react/jsx-wrap-multilines': 'error',
|
||||||
|
'react/self-closing-comp': 'error',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
files: [
|
||||||
|
'app/javascript/mastodon/common.js',
|
||||||
|
'app/javascript/mastodon/features/emoji/unicode_to_unified_name.js',
|
||||||
|
'app/javascript/mastodon/features/emoji/emoji_compressed.js',
|
||||||
|
'app/javascript/mastodon/features/emoji/unicode_to_filename.js',
|
||||||
|
'app/javascript/flavours/glitch/common.js',
|
||||||
|
'app/javascript/flavours/glitch/entrypoints/common.js',
|
||||||
|
'app/javascript/flavours/glitch/features/emoji/unicode_to_unified_name.js',
|
||||||
|
'app/javascript/flavours/glitch/features/emoji/emoji_compressed.js',
|
||||||
|
'app/javascript/flavours/glitch/features/emoji/unicode_to_filename.js',
|
||||||
|
'app/javascript/mastodon/service_worker/web_push_locales.js',
|
||||||
|
'**/*.config.js',
|
||||||
|
'**/.*rc.js',
|
||||||
|
'**/ide-helper.js',
|
||||||
|
'config/webpack/**/*',
|
||||||
|
'config/formatjs-formatter.js',
|
||||||
|
],
|
||||||
|
|
||||||
|
languageOptions: {
|
||||||
|
globals: {
|
||||||
|
...globals.commonjs,
|
||||||
|
...globals.node,
|
||||||
|
},
|
||||||
|
|
||||||
|
ecmaVersion: 5,
|
||||||
|
sourceType: 'commonjs',
|
||||||
|
},
|
||||||
|
|
||||||
|
rules: {
|
||||||
|
'import/no-commonjs': 'off',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
files: ['**/*.ts', '**/*.tsx'],
|
||||||
|
|
||||||
|
extends: [
|
||||||
|
tseslint.configs.strictTypeChecked,
|
||||||
|
tseslint.configs.stylisticTypeChecked,
|
||||||
|
react.configs.flat.recommended,
|
||||||
|
react.configs.flat['jsx-runtime'],
|
||||||
|
reactHooks.configs['recommended-latest'],
|
||||||
|
jsxA11Y.flatConfigs.recommended,
|
||||||
|
importPlugin.flatConfigs.react,
|
||||||
|
importPlugin.flatConfigs.typescript,
|
||||||
|
jsdoc.configs['flat/recommended-typescript'],
|
||||||
|
],
|
||||||
|
|
||||||
|
languageOptions: {
|
||||||
|
parserOptions: {
|
||||||
|
projectService: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
rules: {
|
||||||
|
// This is not needed as we use noImplicitReturns, which handles this in addition to understanding types
|
||||||
|
'consistent-return': 'off',
|
||||||
|
|
||||||
|
'formatjs/enforce-plural-rules': 'off',
|
||||||
|
|
||||||
|
'import/consistent-type-specifier-style': ['error', 'prefer-top-level'],
|
||||||
|
'import/no-default-export': 'warn',
|
||||||
|
|
||||||
|
'jsdoc/require-jsdoc': 'off',
|
||||||
|
|
||||||
|
'react/prefer-stateless-function': 'warn',
|
||||||
|
'react/function-component-definition': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
namedComponents: 'arrow-function',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'react/prop-types': 'off',
|
||||||
|
|
||||||
|
'@typescript-eslint/consistent-type-definitions': ['warn', 'interface'],
|
||||||
|
'@typescript-eslint/consistent-type-exports': 'error',
|
||||||
|
'@typescript-eslint/consistent-type-imports': 'error',
|
||||||
|
'@typescript-eslint/prefer-nullish-coalescing': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
ignorePrimitives: {
|
||||||
|
boolean: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'@typescript-eslint/no-restricted-imports': [
|
||||||
|
'warn',
|
||||||
|
{
|
||||||
|
name: 'react-redux',
|
||||||
|
importNames: ['useSelector', 'useDispatch'],
|
||||||
|
message:
|
||||||
|
'Use typed hooks `useAppDispatch` and `useAppSelector` instead.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'@typescript-eslint/no-unused-vars': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
vars: 'all',
|
||||||
|
args: 'after-used',
|
||||||
|
destructuredArrayIgnorePattern: '^_',
|
||||||
|
ignoreRestSiblings: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'@typescript-eslint/restrict-template-expressions': [
|
||||||
|
'warn',
|
||||||
|
{
|
||||||
|
allowNumber: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
files: ['**/__tests__/*.js', '**/__tests__/*.jsx'],
|
||||||
|
|
||||||
|
languageOptions: {
|
||||||
|
globals: {
|
||||||
|
...globals.jest,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
|
@ -123,7 +123,14 @@ module Paperclip
|
||||||
end
|
end
|
||||||
|
|
||||||
def needs_convert?
|
def needs_convert?
|
||||||
needs_different_geometry? || needs_different_format? || needs_metadata_stripping?
|
strip_animations? || needs_different_geometry? || needs_different_format? || needs_metadata_stripping?
|
||||||
|
end
|
||||||
|
|
||||||
|
def strip_animations?
|
||||||
|
# Detecting whether the source image is animated across all our supported
|
||||||
|
# input file formats is not trivial, and converting unconditionally is just
|
||||||
|
# as simple for now
|
||||||
|
options[:style] == :static
|
||||||
end
|
end
|
||||||
|
|
||||||
def needs_different_geometry?
|
def needs_different_geometry?
|
||||||
|
|
26
package.json
26
package.json
|
@ -12,14 +12,14 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build:development": "cross-env RAILS_ENV=development NODE_ENV=development ./bin/webpack",
|
"build:development": "cross-env RAILS_ENV=development NODE_ENV=development ./bin/webpack",
|
||||||
"build:production": "cross-env RAILS_ENV=production NODE_ENV=production ./bin/webpack",
|
"build:production": "cross-env RAILS_ENV=production NODE_ENV=production ./bin/webpack",
|
||||||
"fix:js": "eslint . --ext=.js,.jsx,.ts,.tsx --cache --report-unused-disable-directives --fix",
|
"fix:js": "eslint . --cache --fix",
|
||||||
"fix:css": "stylelint --fix \"**/*.{css,scss}\"",
|
"fix:css": "stylelint --fix \"**/*.{css,scss}\"",
|
||||||
"fix": "yarn fix:js && yarn fix:css",
|
"fix": "yarn fix:js && yarn fix:css",
|
||||||
"format": "prettier --write --log-level warn .",
|
"format": "prettier --write --log-level warn .",
|
||||||
"format:check": "prettier --check --ignore-unknown .",
|
"format:check": "prettier --check --ignore-unknown .",
|
||||||
"i18n:extract": "formatjs extract 'app/javascript/**/*.{js,jsx,ts,tsx}' --ignore '**/*.d.ts' --out-file app/javascript/flavours/glitch/locales/en.json --format config/formatjs-formatter.js",
|
"i18n:extract": "formatjs extract 'app/javascript/**/*.{js,jsx,ts,tsx}' --ignore '**/*.d.ts' --out-file app/javascript/flavours/glitch/locales/en.json --format config/formatjs-formatter.js",
|
||||||
"jest": "cross-env NODE_ENV=test jest",
|
"jest": "cross-env NODE_ENV=test jest",
|
||||||
"lint:js": "eslint . --ext=.js,.jsx,.ts,.tsx --cache --report-unused-disable-directives",
|
"lint:js": "cd $INIT_CWD && eslint --cache --report-unused-disable-directives",
|
||||||
"lint:css": "stylelint \"**/*.{css,scss}\"",
|
"lint:css": "stylelint \"**/*.{css,scss}\"",
|
||||||
"lint": "yarn lint:js && yarn lint:css",
|
"lint": "yarn lint:js && yarn lint:css",
|
||||||
"postversion": "git push --tags",
|
"postversion": "git push --tags",
|
||||||
|
@ -145,6 +145,7 @@
|
||||||
"workbox-window": "^7.0.0"
|
"workbox-window": "^7.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@eslint/js": "^9.23.0",
|
||||||
"@formatjs/cli": "^6.1.1",
|
"@formatjs/cli": "^6.1.1",
|
||||||
"@testing-library/dom": "^10.2.0",
|
"@testing-library/dom": "^10.2.0",
|
||||||
"@testing-library/jest-dom": "^6.0.0",
|
"@testing-library/jest-dom": "^6.0.0",
|
||||||
|
@ -176,19 +177,17 @@
|
||||||
"@types/requestidlecallback": "^0.3.5",
|
"@types/requestidlecallback": "^0.3.5",
|
||||||
"@types/webpack": "^4.41.33",
|
"@types/webpack": "^4.41.33",
|
||||||
"@types/webpack-env": "^1.18.4",
|
"@types/webpack-env": "^1.18.4",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
||||||
"@typescript-eslint/parser": "^8.0.0",
|
|
||||||
"babel-jest": "^29.5.0",
|
"babel-jest": "^29.5.0",
|
||||||
"eslint": "^8.41.0",
|
"eslint": "^9.23.0",
|
||||||
"eslint-define-config": "^2.0.0",
|
"eslint-import-resolver-typescript": "^4.2.5",
|
||||||
"eslint-import-resolver-typescript": "^3.5.5",
|
"eslint-plugin-formatjs": "^5.3.1",
|
||||||
"eslint-plugin-formatjs": "^5.0.0",
|
|
||||||
"eslint-plugin-import": "~2.31.0",
|
"eslint-plugin-import": "~2.31.0",
|
||||||
"eslint-plugin-jsdoc": "^50.0.0",
|
"eslint-plugin-jsdoc": "^50.6.9",
|
||||||
"eslint-plugin-jsx-a11y": "~6.10.0",
|
"eslint-plugin-jsx-a11y": "~6.10.2",
|
||||||
"eslint-plugin-promise": "~7.2.0",
|
"eslint-plugin-promise": "~7.2.1",
|
||||||
"eslint-plugin-react": "^7.33.2",
|
"eslint-plugin-react": "^7.37.4",
|
||||||
"eslint-plugin-react-hooks": "^5.0.0",
|
"eslint-plugin-react-hooks": "^5.2.0",
|
||||||
|
"globals": "^16.0.0",
|
||||||
"husky": "^9.0.11",
|
"husky": "^9.0.11",
|
||||||
"jest": "^29.5.0",
|
"jest": "^29.5.0",
|
||||||
"jest-environment-jsdom": "^29.5.0",
|
"jest-environment-jsdom": "^29.5.0",
|
||||||
|
@ -199,6 +198,7 @@
|
||||||
"stylelint-config-prettier-scss": "^1.0.0",
|
"stylelint-config-prettier-scss": "^1.0.0",
|
||||||
"stylelint-config-standard-scss": "^14.0.0",
|
"stylelint-config-standard-scss": "^14.0.0",
|
||||||
"typescript": "^5.0.4",
|
"typescript": "^5.0.4",
|
||||||
|
"typescript-eslint": "^8.28.0",
|
||||||
"webpack-dev-server": "^3.11.3"
|
"webpack-dev-server": "^3.11.3"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
/* eslint-disable import/no-commonjs */
|
|
||||||
|
|
||||||
// @ts-check
|
|
||||||
|
|
||||||
// @ts-ignore - This needs to be a CJS file (eslint does not yet support ESM configs), and TS is complaining we use require
|
|
||||||
const { defineConfig } = require('eslint-define-config');
|
|
||||||
|
|
||||||
module.exports = defineConfig({
|
|
||||||
extends: ['../.eslintrc.js'],
|
|
||||||
env: {
|
|
||||||
browser: false,
|
|
||||||
},
|
|
||||||
parserOptions: {
|
|
||||||
project: true,
|
|
||||||
tsconfigRootDir: __dirname,
|
|
||||||
ecmaFeatures: {
|
|
||||||
jsx: false,
|
|
||||||
},
|
|
||||||
ecmaVersion: 2021,
|
|
||||||
},
|
|
||||||
rules: {
|
|
||||||
// In the streaming server we need to delete some variables to ensure
|
|
||||||
// garbage collection takes place on the values referenced by those objects;
|
|
||||||
// The alternative is to declare the variable as nullable, but then we need
|
|
||||||
// to assert it's in existence before every use, which becomes much harder
|
|
||||||
// to maintain.
|
|
||||||
'no-delete-var': 'off',
|
|
||||||
|
|
||||||
// This overrides the base configuration for this rule to pick up
|
|
||||||
// dependencies for the streaming server from the correct package.json file.
|
|
||||||
'import/no-extraneous-dependencies': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
devDependencies: ['streaming/.eslintrc.cjs'],
|
|
||||||
optionalDependencies: false,
|
|
||||||
peerDependencies: false,
|
|
||||||
includeTypes: true,
|
|
||||||
packageDir: __dirname,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'import/extensions': ['error', 'always'],
|
|
||||||
},
|
|
||||||
});
|
|
45
streaming/eslint.config.mjs
Normal file
45
streaming/eslint.config.mjs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
// @ts-check
|
||||||
|
|
||||||
|
import globals from 'globals';
|
||||||
|
import tseslint from 'typescript-eslint';
|
||||||
|
|
||||||
|
// eslint-disable-next-line import/no-relative-packages -- Must import from the root
|
||||||
|
import { baseConfig } from '../eslint.config.mjs';
|
||||||
|
|
||||||
|
export default tseslint.config([
|
||||||
|
baseConfig,
|
||||||
|
{
|
||||||
|
languageOptions: {
|
||||||
|
globals: globals.node,
|
||||||
|
|
||||||
|
parser: tseslint.parser,
|
||||||
|
ecmaVersion: 2021,
|
||||||
|
sourceType: 'module',
|
||||||
|
},
|
||||||
|
|
||||||
|
settings: {
|
||||||
|
'import/ignore': ['node_modules', '\\.(json)$'],
|
||||||
|
'import/resolver': {
|
||||||
|
typescript: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
rules: {
|
||||||
|
// In the streaming server we need to delete some variables to ensure
|
||||||
|
// garbage collection takes place on the values referenced by those objects;
|
||||||
|
// The alternative is to declare the variable as nullable, but then we need
|
||||||
|
// to assert it's in existence before every use, which becomes much harder
|
||||||
|
// to maintain.
|
||||||
|
'no-delete-var': 'off',
|
||||||
|
|
||||||
|
'import/no-extraneous-dependencies': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
devDependencies: ['**/*.config.mjs'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
'import/extensions': ['error', 'always'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
7
streaming/lint-staged.config.mjs
Normal file
7
streaming/lint-staged.config.mjs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
const config = {
|
||||||
|
'*': 'prettier --ignore-unknown --write',
|
||||||
|
'*.{js,ts}': 'eslint --fix',
|
||||||
|
'**/*.ts': () => 'tsc -p tsconfig.json --noEmit',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
|
@ -31,14 +31,16 @@
|
||||||
"ws": "^8.12.1"
|
"ws": "^8.12.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@eslint/js": "^9.23.0",
|
||||||
"@types/cors": "^2.8.16",
|
"@types/cors": "^2.8.16",
|
||||||
"@types/express": "^4.17.17",
|
"@types/express": "^4.17.17",
|
||||||
"@types/pg": "^8.6.6",
|
"@types/pg": "^8.6.6",
|
||||||
"@types/uuid": "^10.0.0",
|
"@types/uuid": "^10.0.0",
|
||||||
"@types/ws": "^8.5.9",
|
"@types/ws": "^8.5.9",
|
||||||
"eslint-define-config": "^2.0.0",
|
"globals": "^16.0.0",
|
||||||
"pino-pretty": "^13.0.0",
|
"pino-pretty": "^13.0.0",
|
||||||
"typescript": "^5.0.4"
|
"typescript": "^5.0.4",
|
||||||
|
"typescript-eslint": "^8.28.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"bufferutil": "^4.0.7",
|
"bufferutil": "^4.0.7",
|
||||||
|
|
|
@ -8,5 +8,5 @@
|
||||||
"tsBuildInfoFile": "../tmp/cache/streaming/tsconfig.tsbuildinfo",
|
"tsBuildInfoFile": "../tmp/cache/streaming/tsconfig.tsbuildinfo",
|
||||||
"paths": {}
|
"paths": {}
|
||||||
},
|
},
|
||||||
"include": ["./*.js", "./.eslintrc.cjs"]
|
"include": ["./*.js"]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue