Upgrade eslint configuration and apply some rules on code

This commit is contained in:
ErickSkrauch 2019-05-15 18:56:13 +03:00
parent 77af422c03
commit 5547fd446b
21 changed files with 678 additions and 872 deletions

View File

@ -1,35 +1,35 @@
{ module.exports = {
"parser": "babel-eslint", parser: '@typescript-eslint/parser',
"plugins": [ parserOptions: {
"react" sourceType: 'module',
], ecmaVersion: 2018,
ecmaFeatures: {
"ecmaFeatures": { jsx: true,
"jsx": true, },
"modules": true, project: './tsconfig.json',
"classes": true,
"defaultParams": true,
"destructuring": true,
"spread": true,
"arrowFunctions": true,
"blockBindings": true,
"objectLiteralComputedProperties": true,
"objectLiteralDuplicateProperties": true,
"objectLiteralShorthandMethods": true,
"objectLiteralShorthandProperties": true,
"restParams": true,
"superInFunctions": true,
"templateStrings": true,
"experimentalObjectRestSpread": true
}, },
"env": { settings: {
react: {
version: 'detect',
},
},
env: {
"browser": true, "browser": true,
"commonjs": true, "commonjs": true,
"es6": true "es6": true
}, },
"extends": "eslint:recommended", plugins: [
'@typescript-eslint',
],
extends: [
'eslint:recommended',
'plugin:react/recommended',
'plugin:@typescript-eslint/recommended',
],
// @see: http://eslint.org/docs/rules/ // @see: http://eslint.org/docs/rules/
"rules": { "rules": {
@ -114,7 +114,7 @@
"no-path-concat": "warn", "no-path-concat": "warn",
// stylistic // stylistic
"array-bracket-spacing": "error", "array-bracket-spacing": "off", // disable because we want spaces on destructured arrays
"block-spacing": ["error", "never"], "block-spacing": ["error", "never"],
"brace-style": ["error", "1tbs", {"allowSingleLine": true}], "brace-style": ["error", "1tbs", {"allowSingleLine": true}],
"comma-spacing": "error", "comma-spacing": "error",
@ -180,13 +180,18 @@
"react/display-name": "warn", "react/display-name": "warn",
"react/forbid-prop-types": "warn", "react/forbid-prop-types": "warn",
"react/jsx-boolean-value": "warn", "react/jsx-boolean-value": "warn",
"react/jsx-closing-bracket-location": "warn", 'react/jsx-closing-bracket-location': ['warn', {
nonEmpty: 'line-aligned',
selfClosing: 'after-props',
}],
"react/jsx-curly-spacing": "warn", "react/jsx-curly-spacing": "warn",
"react/jsx-handler-names": ["warn", {"eventHandlerPrefix": "on", "eventHandlerPropPrefix": "on"}], "react/jsx-handler-names": ["warn", {"eventHandlerPrefix": "on", "eventHandlerPropPrefix": "on"}],
"react/jsx-indent-props": "warn", "react/jsx-indent-props": "warn",
"react/jsx-key": "warn", "react/jsx-key": "warn",
"react/jsx-max-props-per-line": ["warn", {"maximum": 3}], 'react/jsx-max-props-per-line': 'off',
"react/jsx-no-bind": "warn", "react/jsx-no-bind": ['error', {
allowArrowFunctions: true,
}],
"react/jsx-no-duplicate-props": "warn", "react/jsx-no-duplicate-props": "warn",
"react/jsx-no-literals": "off", "react/jsx-no-literals": "off",
"react/jsx-no-undef": "warn", "react/jsx-no-undef": "warn",
@ -205,9 +210,14 @@
"react/no-string-refs": "warn", "react/no-string-refs": "warn",
"react/no-unknown-property": "warn", "react/no-unknown-property": "warn",
"react/prefer-es6-class": "warn", "react/prefer-es6-class": "warn",
"react/prop-types": "warn", "react/prop-types": "off", // disable in favor of typescript
"react/react-in-jsx-scope": "off", "react/react-in-jsx-scope": "off",
"react/self-closing-comp": "warn", "react/self-closing-comp": "warn",
"react/sort-comp": ["warn", {"order": ["lifecycle", "render", "everything-else"]}] "react/sort-comp": ["warn", {"order": ["lifecycle", "render", "everything-else"]}],
}
} // TypeScript
'@typescript-eslint/array-type': ['error', 'generic'],
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/no-explicit-any': 'off',
},
};

View File

@ -16,7 +16,7 @@
"homepage": "https://gitlab.com/elyby/email-renderer#README", "homepage": "https://gitlab.com/elyby/email-renderer#README",
"scripts": { "scripts": {
"start": "webpack-dev-server --mode=development --progress --colors", "start": "webpack-dev-server --mode=development --progress --colors",
"lint": "eslint ./src", "lint": "eslint",
"i18n:collect": "./scripts/i18n-collect/index.js", "i18n:collect": "./scripts/i18n-collect/index.js",
"i18n:pull": "node scripts/i18n-crowdin/index.js pull", "i18n:pull": "node scripts/i18n-crowdin/index.js pull",
"i18n:push": "node scripts/i18n-crowdin/index.js push", "i18n:push": "node scripts/i18n-crowdin/index.js push",
@ -37,11 +37,12 @@
"@types/react": "^16.8.17", "@types/react": "^16.8.17",
"@types/react-intl": "^2.3.17", "@types/react-intl": "^2.3.17",
"@types/webpack-env": "^1.13.9", "@types/webpack-env": "^1.13.9",
"babel-eslint": "^6.0.0", "@typescript-eslint/eslint-plugin": "^1.9.0",
"@typescript-eslint/parser": "^1.9.0",
"babel-loader": "^8.0.5", "babel-loader": "^8.0.5",
"babel-preset-react-hot": "^1.0.5", "babel-preset-react-hot": "^1.0.5",
"eslint": "^3.1.1", "eslint": "^5.16.0",
"eslint-plugin-react": "^6.0.0", "eslint-plugin-react": "^7.13.0",
"extended-translations-loader": "file:webpack-utils/extended-translations-loader", "extended-translations-loader": "file:webpack-utils/extended-translations-loader",
"file-loader": "^3.0.1", "file-loader": "^3.0.1",
"html-webpack-plugin": "^3.2.0", "html-webpack-plugin": "^3.2.0",

View File

@ -1,3 +1,5 @@
/* eslint-disable @typescript-eslint/no-var-requires */
import React, { FunctionComponent } from 'react'; import React, { FunctionComponent } from 'react';
import { IntlProvider, addLocaleData } from 'react-intl'; import { IntlProvider, addLocaleData } from 'react-intl';

View File

@ -4,22 +4,20 @@ import styles from './styles';
import { Table } from 'components/table'; import { Table } from 'components/table';
const BaseLayout: FunctionComponent = ({ children }) => { const BaseLayout: FunctionComponent = ({ children }) => (
return ( <Table style={styles.body}>
<Table style={styles.body}> <tr>
<tr> <td>
<td> &nbsp;
&nbsp; </td>
</td> <td style={styles.container}>
<td style={styles.container}> {children}
{children} </td>
</td> <td>
<td> &nbsp;
&nbsp; </td>
</td> </tr>
</tr> </Table>
</Table> );
);
};
export default BaseLayout; export default BaseLayout;

View File

@ -1,19 +1,15 @@
import React, { FunctionComponent } from 'react'; import React, { FunctionComponent } from 'react';
const Html: FunctionComponent = ({ children }) => { const Html: FunctionComponent = ({ children }) => (
return ( <html>
<html> <head>
<head> <meta name="viewport" content="width=device-width" />
<meta name="viewport" content="width=device-width" /> <meta httpEquiv="Content-Type" content="text/html; charset=UTF-8" />
<meta httpEquiv="Content-Type" content="text/html; charset=UTF-8" /> </head>
</head> <body style={{ margin: 0 }}>
<body style={{ {children}
margin: 0 </body>
}}> </html>
{children} );
</body>
</html>
);
};
export default Html; export default Html;

View File

@ -15,25 +15,23 @@ interface Props {
color?: Colors; color?: Colors;
} }
const Code: FunctionComponent<Props> = ({ code, link, label, color = 'green' }) => { const Code: FunctionComponent<Props> = ({ code, link, label, color = 'green' }) => (
return ( <div style={styles.codeWrapper}>
<div style={styles.codeWrapper}> <div>
<div> <a href={link}>
<a href={link}> <Button style={styles.confirmEmailButton} color={color} label={label} />
<Button style={styles.confirmEmailButton} color={color} label={label} /> </a>
</a>
</div>
<div style={styles.or}>
<Message {...messages.or} />
</div>
<div style={styles.codeLabel}>
<Message {...messages.pass_code_in_field} />
</div>
<div style={styles.code}>
<Input value={code} color={color} />
</div>
</div> </div>
); <div style={styles.or}>
}; <Message {...messages.or} />
</div>
<div style={styles.codeLabel}>
<Message {...messages.pass_code_in_field} />
</div>
<div style={styles.code}>
<Input value={code} color={color} />
</div>
</div>
);
export default Code; export default Code;

View File

@ -2,12 +2,10 @@ import React, { FunctionComponent } from 'react';
import styles from './styles'; import styles from './styles';
const Content: FunctionComponent = ({ children }) => { const Content: FunctionComponent = ({ children }) => (
return ( <div style={styles.content}>
<div style={styles.content}> {children}
{children} </div>
</div> );
);
};
export default Content; export default Content;

View File

@ -11,20 +11,18 @@ interface Props {
title: ReactElement; title: ReactElement;
} }
const Userbar: FunctionComponent<Props> = ({ username, title }) => { const Userbar: FunctionComponent<Props> = ({ username, title }) => (
return ( <Table style={styles.headerImage}>
<Table style={styles.headerImage}> <tr>
<tr> <td style={styles.headerTextContainer}>
<td style={styles.headerTextContainer}> <div style={styles.welcomeUsername}>
<div style={styles.welcomeUsername}> <Message {...messages.hello_username} values={{username}} />
<Message {...messages.hello_username} values={{username}} /> </div>
</div>
{title} {title}
</td> </td>
</tr> </tr>
</Table> </Table>
); );
};
export default Userbar; export default Userbar;

View File

@ -5,20 +5,18 @@ import { Table } from 'components/table';
import styles from './styles'; import styles from './styles';
import logoImage from './logo.png'; import logoImage from './logo.png';
const Userbar: FunctionComponent = () => { const Userbar: FunctionComponent = () => (
return ( <Table style={styles.userbar}>
<Table style={styles.userbar}> <tr>
<tr> <td style={styles.marginColumn} />
<td style={styles.marginColumn} /> <td style={styles.logoColumn}>
<td style={styles.logoColumn}> <a href="http://ely.by" style={styles.logo}>
<a href="http://ely.by" style={styles.logo}> <img src={logoImage} alt="Ely.by" style={styles.logoImage} />
<img src={logoImage} alt="Ely.by" style={styles.logoImage} /> </a>
</a> </td>
</td> <td>&nbsp;</td>
<td>&nbsp;</td> </tr>
</tr> </Table>
</Table> );
);
};
export default Userbar; export default Userbar;

View File

@ -6,17 +6,15 @@ interface Props {
style?: CSSProperties; style?: CSSProperties;
} }
const Table: FunctionComponent<Props> = ({ children, style }) => { const Table: FunctionComponent<Props> = ({ children, style }) => (
return ( <table cellPadding="0" cellSpacing="0" style={{
<table cellPadding="0" cellSpacing="0" style={{ ...styles.table,
...styles.table, ...style
...style }}>
}}> <tbody>
<tbody> {children}
{children} </tbody>
</tbody> </table>
</table> );
);
};
export default Table; export default Table;

View File

@ -1,6 +1,6 @@
import React, { CSSProperties, FunctionComponent, ReactElement } from 'react'; import React, { CSSProperties, FunctionComponent, ReactElement } from 'react';
import { Colors, green } from 'components/ui/colors'; import { Colors } from 'components/ui/colors';
import styles from './styles'; import styles from './styles';
@ -10,17 +10,14 @@ interface Props {
color?: Colors; color?: Colors;
} }
const Button: FunctionComponent<Props> = ({ label, style, color = 'green' }) => { const Button: FunctionComponent<Props> = ({ label, style, color = 'green' }) => (
<div style={{
return ( ...styles.button,
<div style={{ ...styles[color],
...styles.button, ...style,
...styles[color], }}>
...style, {label}
}}> </div>
{label} );
</div>
);
};
export default Button; export default Button;

View File

@ -7,7 +7,7 @@ function generateColor({ base }: Color): CSSProperties {
}; };
} }
type Styles = { interface Styles {
[key: string]: CSSProperties; [key: string]: CSSProperties;
} }

View File

@ -10,16 +10,14 @@ interface Props {
style?: CSSProperties; style?: CSSProperties;
} }
const Input: FunctionComponent<Props> = ({ value, style, color = 'green' }) => { const Input: FunctionComponent<Props> = ({ value, style, color = 'green' }) => (
return ( <div style={{
<div style={{ ...styles.input,
...styles.input, ...styles[color],
...styles[color], ...style,
...style }}>
}}> {value}
{value} </div>
</div> );
);
};
export default Input; export default Input;

View File

@ -7,28 +7,26 @@ interface Props {
onChange: (item: string) => any; onChange: (item: string) => any;
} }
const List: FunctionComponent<Props> = ({ label, items, active, onChange = () => {} }) => { const List: FunctionComponent<Props> = ({ label, items, active, onChange = () => {} }) => (
return ( <div>
<div> {label}:
{label}: {items.map((item) => (
{items.map((item) => <a
<a href="#"
href="#" key={item}
key={item} onClick={(event) => {
onClick={(event) => { event.preventDefault();
event.preventDefault(); onChange(item);
onChange(item); }}
}} style={{
style={{ padding: '0 5px',
padding: '0 5px', color: active === item ? 'red' : '',
color: active === item ? 'red' : '', }}
}} >
> {item}
{item} </a>
</a> ))}
)} </div>
</div> );
);
};
export default List; export default List;

View File

@ -14,37 +14,35 @@ interface Props {
code: string; code: string;
} }
const ForgotPassword: FunctionComponent<Props> = ({ username, link, code }) => { const ForgotPassword: FunctionComponent<Props> = ({ username, link, code }) => (
return ( <div>
<div> <Userbar />
<Userbar />
<Header username={username} title={ <Header username={username} title={
<HTMLMessage {...messages.forgot_the_password_image}/> <HTMLMessage {...messages.forgot_the_password_image}/>
} /> } />
<Content> <Content>
<Table> <Table>
<tr> <tr>
<td> <td>
<div style={styles.paragraph}> <div style={styles.paragraph}>
<Message {...messages.shit_happens} /> <Message {...messages.shit_happens} />
</div> </div>
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
<Code code={code} link={link} color="lightViolet" label={ <Code code={code} link={link} color="lightViolet" label={
<HTMLMessage {...messages.continue_image} /> <HTMLMessage {...messages.continue_image} />
} /> } />
</td> </td>
</tr> </tr>
</Table> </Table>
</Content> </Content>
<Footer /> <Footer />
</div> </div>
); );
};
export default ForgotPassword; export default ForgotPassword;

View File

@ -18,105 +18,103 @@ interface Props {
code: string; code: string;
} }
const Register: FunctionComponent<Props> = ({ username, link, code }) => { const Register: FunctionComponent<Props> = ({ username, link, code }) => (
return ( <div>
<div> <Userbar />
<Userbar />
<Header username={username} title={ <Header username={username} title={
<HTMLMessage {...messages.welcome_image} /> <HTMLMessage {...messages.welcome_image} />
} /> } />
<Content> <Content>
<Table> <Table>
<tr> <tr>
<td> <td>
<div style={styles.paragraph}> <div style={styles.paragraph}>
<Message {...messages.we_glad_to_see_you} /> <Message {...messages.we_glad_to_see_you} />
</div> </div>
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
<Code code={code} link={link} color="blue" label={ <Code code={code} link={link} color="blue" label={
<HTMLMessage {...messages.confirm_email_image} /> <HTMLMessage {...messages.confirm_email_image} />
} /> } />
</td> </td>
</tr> </tr>
<tr> <tr>
<td style={{ <td style={{
...styles.contentCenterCell, ...styles.contentCenterCell,
...styles.whatsNextText, ...styles.whatsNextText,
}}> }}>
<HTMLMessage {...messages.whats_next_image} /> <HTMLMessage {...messages.whats_next_image} />
</td> </td>
</tr> </tr>
<tr> <tr>
<td style={styles.todoItem}> <td style={styles.todoItem}>
<Table> <Table>
<tr> <tr>
<td style={styles.todoItemIcon}> <td style={styles.todoItemIcon}>
<img src={violetManImage} style={styles.todoItemIconImage} /> <img src={violetManImage} style={styles.todoItemIconImage} />
</td> </td>
<td style={styles.todoItemContent}> <td style={styles.todoItemContent}>
<HTMLMessage {...messages.choose_you_skin_image} /> <HTMLMessage {...messages.choose_you_skin_image} />
<div style={{ <div style={{
...styles.paragraph, ...styles.paragraph,
...styles.todoItemText ...styles.todoItemText
}}> }}>
<Message {...messages.choose_you_skin_text} /> <Message {...messages.choose_you_skin_text} />
</div> </div>
</td> </td>
</tr> </tr>
</Table> </Table>
</td> </td>
</tr> </tr>
<tr> <tr>
<td style={styles.todoItem}> <td style={styles.todoItem}>
<Table> <Table>
<tr> <tr>
<td style={styles.todoItemIcon}> <td style={styles.todoItemIcon}>
<img src={orangeManImage} style={styles.todoItemIconImage} /> <img src={orangeManImage} style={styles.todoItemIconImage} />
</td> </td>
<td style={styles.todoItemContent}> <td style={styles.todoItemContent}>
<HTMLMessage {...messages.install_our_patch_image} /> <HTMLMessage {...messages.install_our_patch_image} />
<div style={{ <div style={{
...styles.paragraph, ...styles.paragraph,
...styles.todoItemText ...styles.todoItemText
}}> }}>
<Message {...messages.install_our_patch_text} /> <Message {...messages.install_our_patch_text} />
</div> </div>
</td> </td>
</tr> </tr>
</Table> </Table>
</td> </td>
</tr> </tr>
<tr> <tr>
<td style={styles.todoItem}> <td style={styles.todoItem}>
<Table> <Table>
<tr> <tr>
<td style={styles.todoItemIcon}> <td style={styles.todoItemIcon}>
<img src={darkBlueManImage} style={styles.todoItemIconImage} /> <img src={darkBlueManImage} style={styles.todoItemIconImage} />
</td> </td>
<td style={styles.todoItemContent}> <td style={styles.todoItemContent}>
<HTMLMessage {...messages.useTLLauncher} /> <HTMLMessage {...messages.useTLLauncher} />
<div style={{ <div style={{
...styles.paragraph, ...styles.paragraph,
...styles.todoItemText ...styles.todoItemText
}}> }}>
<Message {...messages.useTLLauncherText} /> <Message {...messages.useTLLauncherText} />
</div> </div>
</td> </td>
</tr> </tr>
</Table> </Table>
</td> </td>
</tr> </tr>
</Table> </Table>
</Content> </Content>
<Footer /> <Footer />
</div> </div>
); );
};
export default Register; export default Register;

View File

@ -6,7 +6,7 @@ declare module 'i18n/index.json' {
englishName: string; englishName: string;
progress: number; progress: number;
isReleased: boolean; isReleased: boolean;
}, };
}; };
export default content; export default content;
} }

View File

@ -1,3 +1,5 @@
/* eslint-disable @typescript-eslint/no-var-requires */
// NOTE: we are requiring with require(), to enable dynamic dependencies // NOTE: we are requiring with require(), to enable dynamic dependencies
// depending on ENV, where App is running in. // depending on ENV, where App is running in.
// This allows us better support of hmr and reduces bundle size // This allows us better support of hmr and reduces bundle size

View File

@ -1,9 +1,9 @@
declare module "*.png" { declare module '*.png' {
const content: string; const content: string;
export default content; export default content;
} }
declare module "*.jpg" { declare module '*.jpg' {
const content: string; const content: string;
export default content; export default content;
} }

View File

@ -3,7 +3,7 @@ declare module '*.intl.json' {
[key: string]: { [key: string]: {
id: string; id: string;
defaultMessage: string; defaultMessage: string;
}, };
}; };
export default content; export default content;
} }

934
yarn.lock

File diff suppressed because it is too large Load Diff