Configure ESLint and fix all reported issues

This commit is contained in:
Konrad Szwarc 2022-08-27 01:54:26 +02:00
parent 135ed17813
commit bf38e195ba
19 changed files with 2837 additions and 173 deletions

101
.eslintrc.json Normal file
View file

@ -0,0 +1,101 @@
{
"root": true,
"plugins": ["file-progress"],
"overrides": [
{
// All files.
"files": ["*.ts", "*.tsx", "*.cjs"],
"extends": [
"airbnb",
"plugin:eslint-comments/recommended",
"plugin:storybook/recommended",
"plugin:prettier/recommended" // This config needs to be the last one as it overrides rules from other configs.
],
"rules": {
// We prefer named exports as they ensure that import name is the same as the export name.
"import/prefer-default-export": 0,
"import/no-default-export": 2,
// Shows information about currently processing file in the console.
"file-progress/activate": 1,
// Removes eslint-disable comments when they are not needed.
"eslint-comments/no-unused-disable": 2,
// Ensure each eslint-disable has a description comment.
"eslint-comments/require-description": [2, { "ignore": ["eslint-enable"] }]
}
},
{
// TypeScript files.
"files": ["*.ts", "*.tsx"],
"plugins": ["simple-import-sort"],
"extends": [
"airbnb-typescript",
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/recommended-requiring-type-checking",
"plugin:prettier/recommended"
],
"parserOptions": {
"project": "./tsconfig.eslint.json"
},
"settings": {
"import/resolver": {
"typescript": { "project": "./tsconfig.eslint.json" }
}
},
"rules": {
// We can create an empty interface only when it extends other interface.
"@typescript-eslint/no-empty-interface": [2, { "allowSingleExtends": true }],
// Rules for imports and exports order.
"simple-import-sort/imports": [
2,
{
"groups": [
["^\\u0000"], // Side effects
["^@?\\w"], // Packages
["^"], // Absolute imports
["^\\."] // Relative imports
]
}
],
"simple-import-sort/exports": 2
}
},
{
// Files with React components.
"files": ["*.tsx"],
"extends": ["airbnb/hooks", "plugin:react/jsx-runtime", "plugin:prettier/recommended"],
"rules": {
// Write all components as arrow functions.
"react/function-component-definition": [
2,
{ "namedComponents": "arrow-function", "unnamedComponents": "arrow-function" }
],
// We use props spreading to pass props to the html elements under custom components.
"react/jsx-props-no-spreading": 0,
// Define values for optional props as by providing default arguments.
"react/require-default-props": [2, { "functions": "defaultArguments" }]
}
},
{
// Storybook stories
"files": ["*.stories.tsx"],
"rules": {
"import/no-default-export": 0
}
},
{
// Configuration files
"files": ["astro.config.ts", "tailwind.config.cjs", ".storybook/*"],
"rules": {
"import/no-default-export": 0,
"import/no-extraneous-dependencies": [2, { "devDependencies": true }]
}
}
],
"ignorePatterns": ["!.storybook"]
}

View file

@ -1,30 +1,22 @@
import type { StorybookViteConfig } from '@storybook/builder-vite';
import tsconfigPaths from 'vite-tsconfig-paths';
import postcss from 'postcss';
import { mergeConfig } from 'vite';
import tsconfigPaths from 'vite-tsconfig-paths';
const config: StorybookViteConfig = {
const storybookViteConfig: StorybookViteConfig = {
stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
addons: [
'@storybook/addon-essentials',
{
name: '@storybook/addon-postcss',
options: {
postcssLoaderOptions: {
implementation: require('postcss'),
},
},
options: { postcssLoaderOptions: { implementation: postcss } },
},
],
framework: '@storybook/react',
typescript: { check: false },
core: { builder: '@storybook/builder-vite' },
features: {
storyStoreV7: true,
},
viteFinal: (config) =>
mergeConfig(config, {
plugins: [tsconfigPaths()],
}),
features: { storyStoreV7: true },
viteFinal: (config) => mergeConfig(config, { plugins: [tsconfigPaths()] }),
};
export default config;
export default storybookViteConfig;

View file

@ -1,5 +1 @@
import 'tailwindcss/tailwind.css';
export const parameters = {
actions: { argTypesRegex: '^on[A-Z].*' },
};

View file

@ -1,6 +1,6 @@
import { defineConfig } from 'astro/config';
import react from '@astrojs/react';
import tailwind from '@astrojs/tailwind';
import { defineConfig } from 'astro/config';
// https://astro.build/config
export default defineConfig({

2777
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -8,10 +8,16 @@
"build": "astro build",
"preview": "astro preview",
"astro": "astro",
"check": "tsc --jsx preserve --skipLibCheck",
"lint": "eslint . --ext .cjs,.ts,.tsx --ignore-path .gitignore",
"lint:ts": "tsc --jsx preserve --skipLibCheck",
"storybook": "start-storybook -p 6006",
"build-storybook": "build-storybook"
},
"dependencies": {
"clsx": "^1.2.1",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@astrojs/react": "^1.0.0",
"@astrojs/tailwind": "^1.0.0",
@ -22,11 +28,27 @@
"@storybook/react": "^6.5.10",
"@types/react": "^18.0.17",
"@types/react-dom": "^18.0.6",
"@typescript-eslint/eslint-plugin": "^5.35.1",
"@typescript-eslint/parser": "^5.35.1",
"astro": "^1.0.8",
"clsx": "^1.2.1",
"eslint": "^8.23.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-airbnb-typescript": "^17.0.0",
"eslint-config-prettier": "^8.5.0",
"eslint-import-resolver-typescript": "^3.5.0",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-file-progress": "^1.3.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jsx-a11y": "^6.6.1",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.31.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-simple-import-sort": "^7.0.0",
"eslint-plugin-storybook": "^0.6.4",
"postcss": "^8.4.16",
"prettier": "^2.7.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"tailwindcss": "^3.1.8",
"vite": "^3.0.9",
"vite-tsconfig-paths": "^3.5.0"
}
}

View file

@ -1,16 +1,16 @@
import type { ComponentStory, ComponentMeta } from '@storybook/react';
import type { ComponentMeta, ComponentStory } from '@storybook/react';
import ButtonComponent from './button';
import * as C from './button';
export default {
title: 'Button',
component: ButtonComponent,
component: C.Button,
argTypes: {
onClick: { action: 'onClick' },
},
} as ComponentMeta<typeof ButtonComponent>;
} as ComponentMeta<typeof C.Button>;
export const Button: ComponentStory<typeof ButtonComponent> = (args) => <ButtonComponent {...args} />;
export const Button: ComponentStory<typeof C.Button> = (args) => <C.Button {...args} />;
Button.args = {
children: 'Button text',

View file

@ -3,7 +3,7 @@ import type { ComponentPropsWithoutRef } from 'react';
interface ButtonProps extends ComponentPropsWithoutRef<'button'> {}
const Button = ({ className, ...props }: ButtonProps) => (
export const Button = ({ className, ...props }: ButtonProps) => (
<button
type="button"
className={clsx(
@ -13,5 +13,3 @@ const Button = ({ className, ...props }: ButtonProps) => (
{...props}
/>
);
export default Button;

View file

@ -1 +1 @@
export { default as Button } from './button';
export { Button } from './button';

View file

@ -1 +1 @@
export { default as LabelledValue } from './labelled-value';
export { LabelledValue } from './labelled-value';

View file

@ -1,15 +1,13 @@
import type { ComponentStory, ComponentMeta } from '@storybook/react';
import type { ComponentMeta, ComponentStory } from '@storybook/react';
import LabelledValueComponent from './labelled-value';
import * as C from './labelled-value';
export default {
title: 'LabelledValue',
component: LabelledValueComponent,
} as ComponentMeta<typeof LabelledValueComponent>;
component: C.LabelledValue,
} as ComponentMeta<typeof C.LabelledValue>;
export const LabelledValue: ComponentStory<typeof LabelledValueComponent> = (args) => (
<LabelledValueComponent {...args} />
);
export const LabelledValue: ComponentStory<typeof C.LabelledValue> = (args) => <C.LabelledValue {...args} />;
LabelledValue.args = {
label: 'Label',

View file

@ -1,15 +1,13 @@
import type { ComponentPropsWithoutRef } from 'react';
import clsx from 'clsx';
import type { ComponentPropsWithoutRef } from 'react';
interface LabelledValueProps extends ComponentPropsWithoutRef<'div'> {
label: string;
}
const LabelledValue = ({ label, children, className, ...props }: LabelledValueProps) => (
export const LabelledValue = ({ label, children, className, ...props }: LabelledValueProps) => (
<div className={clsx('text-base space-x-1', className)} {...props}>
<span className="font-medium text-gray-700">{label}:</span>
<span className="font-normal text-gray-500">{children}</span>
</div>
);
export default LabelledValue;

View file

@ -1 +1 @@
export { default as SectionCard } from './section-card';
export { SectionCard } from './section-card';

View file

@ -1,13 +1,13 @@
import type { ComponentStory, ComponentMeta } from '@storybook/react';
import type { ComponentMeta, ComponentStory } from '@storybook/react';
import SectionCardComponent from './section-card';
import * as C from './section-card';
export default {
title: 'SectionCard',
component: SectionCardComponent,
} as ComponentMeta<typeof SectionCardComponent>;
component: C.SectionCard,
} as ComponentMeta<typeof C.SectionCard>;
export const SectionCard: ComponentStory<typeof SectionCardComponent> = (args) => <SectionCardComponent {...args} />;
export const SectionCard: ComponentStory<typeof C.SectionCard> = (args) => <C.SectionCard {...args} />;
SectionCard.args = {
children: 'Card content',

View file

@ -3,8 +3,6 @@ import type { ComponentPropsWithoutRef } from 'react';
interface SectionCardProps extends ComponentPropsWithoutRef<'div'> {}
const SectionCard = ({ className, ...props }: SectionCardProps) => (
export const SectionCard = ({ className, ...props }: SectionCardProps) => (
<div className={clsx('p-8 bg-white rounded-2xl shadow-lg', className)} {...props} />
);
export default SectionCard;

View file

@ -1 +1 @@
export { default as Typography } from './typography';
export { Typography } from './typography';

View file

@ -1,13 +1,13 @@
import type { ComponentStory, ComponentMeta } from '@storybook/react';
import type { ComponentMeta, ComponentStory } from '@storybook/react';
import TypographyComponent from './typography';
import * as C from './typography';
export default {
title: 'Typography',
component: TypographyComponent,
} as ComponentMeta<typeof TypographyComponent>;
component: C.Typography,
} as ComponentMeta<typeof C.Typography>;
export const Typography: ComponentStory<typeof TypographyComponent> = (args) => <TypographyComponent {...args} />;
export const Typography: ComponentStory<typeof C.Typography> = (args) => <C.Typography {...args} />;
Typography.args = {
children: 'Typography text',

View file

@ -1,5 +1,5 @@
import type { ComponentPropsWithoutRef } from 'react';
import clsx from 'clsx';
import type { ComponentPropsWithoutRef } from 'react';
type TypographyVariant =
| 'item-title'
@ -40,10 +40,8 @@ const variantToClassName = {
paragraph: 'text-base leading-relaxed font-normal text-gray-500',
};
const Typography = ({ variant = 'paragraph', className, ...props }: TypographyProps) => {
export const Typography = ({ variant = 'paragraph', className, ...props }: TypographyProps) => {
const Element = variantToElement[variant];
return <Element className={clsx(variantToClassName[variant], className)} {...props} />;
};
export default Typography;

4
tsconfig.eslint.json Normal file
View file

@ -0,0 +1,4 @@
{
"extends": "./tsconfig.json",
"include": ["**/*.ts", "**/*.tsx", "**/*.js", ".storybook/*.ts"]
}