Skip to content

Commit b4db274

Browse files
committed
chore: fix lint issues
1 parent f759bd0 commit b4db274

21 files changed

+134
-201
lines changed

.eslintignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
node_modules/
22
dist/
33
storybook-static/
4+
jest.config.js
5+
coverage

src/DSVImport.test.tsx

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { ColumnType } from './models/column';
2-
import { DSVImport } from '.';
31
import React from 'react';
42
import { render, fireEvent } from '@testing-library/react';
3+
import { ColumnType } from './models/column';
4+
import { DSVImport } from '.';
55
import { useDSVImport } from './features/context';
66
import { ValidationError } from './models/validation';
77

@@ -11,7 +11,7 @@ describe('DSVImport', () => {
1111
const columns: ColumnType<TestType>[] = [
1212
{ key: 'forename', label: 'Forename' },
1313
{ key: 'surname', label: 'Surname' },
14-
{ key: 'email', label: 'Email', rules: [{ constraint: { unique: true }, message: 'Contains duplicates' }] }
14+
{ key: 'email', label: 'Email', rules: [{ constraint: { unique: true }, message: 'Contains duplicates' }] },
1515
];
1616

1717
interface Props<T> {
@@ -20,21 +20,22 @@ describe('DSVImport', () => {
2020
columns: ColumnType<T>[];
2121
}
2222

23-
const MinimalTextareaInput: React.FC = () => {
23+
function MinimalTextareaInput() {
2424
const [, dispatch] = useDSVImport();
2525

2626
const handleChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
2727
dispatch({ type: 'setRaw', raw: event.target.value });
2828
};
2929

30-
return <textarea onChange={handleChange}></textarea>;
31-
};
30+
return <textarea onChange={handleChange} />;
31+
}
3232

3333
const renderComponent = (props: Props<TestType>) => {
3434
return render(
35+
// eslint-disable-next-line react/jsx-props-no-spreading
3536
<DSVImport<TestType> {...props}>
3637
<MinimalTextareaInput />
37-
</DSVImport>
38+
</DSVImport>,
3839
);
3940
};
4041

@@ -57,13 +58,13 @@ describe('DSVImport', () => {
5758

5859
if (textarea) {
5960
fireEvent.change(textarea, {
60-
target: { value: 'Max,Muster,[email protected]\nMoritz,Muster,[email protected]' }
61+
target: { value: 'Max,Muster,[email protected]\nMoritz,Muster,[email protected]' },
6162
});
6263
}
6364

6465
expect(onValidationMock).toBeCalledWith([
6566
{ column: 'email', row: 0, message: 'Contains duplicates' },
66-
{ column: 'email', row: 1, message: 'Contains duplicates' }
67+
{ column: 'email', row: 1, message: 'Contains duplicates' },
6768
]);
6869
});
6970
});

src/DSVImport.tsx

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { PropsWithChildren, useReducer, useEffect } from 'react';
1+
import { PropsWithChildren, useReducer, useEffect, useMemo, Dispatch } from 'react';
22
import { ColumnType, GenericColumnType } from './models/column';
33
import { getDSVImportContext, useDSVImport, createReducer } from './features/context';
44
import { createParserMiddleware } from './middlewares/parserMiddleware';
@@ -10,29 +10,30 @@ import { createTransformerMiddleware } from './middlewares/transformerMiddleware
1010
import { Transformer } from './models/transformer';
1111
import { TextareaInput } from './components/inputs/TextareaInput';
1212
import { TablePreview } from './components/previews/TablePreview';
13+
import { Actions } from './models/actions';
1314

1415
interface EventListenerProps<T> {
1516
onChange?: (value: T[]) => void;
1617
onValidation?: (errors: ValidationError<T>[]) => void;
1718
}
1819

19-
const EventListener = <T extends GenericColumnType>(props: EventListenerProps<T>) => {
20+
function EventListener<T extends GenericColumnType>({ onChange, onValidation }: EventListenerProps<T>) {
2021
const [context] = useDSVImport<T>();
2122

2223
useEffect(() => {
23-
if (context.parsed && props.onChange) {
24-
props.onChange(context.parsed);
24+
if (context.parsed && onChange) {
25+
onChange(context.parsed);
2526
}
2627
}, [context.parsed]);
2728

2829
useEffect(() => {
29-
if (context.validation && props.onValidation) {
30-
props.onValidation(context.validation);
30+
if (context.validation && onValidation) {
31+
onValidation(context.validation);
3132
}
3233
}, [context.validation]);
3334

3435
return null;
35-
};
36+
}
3637

3738
export type Props<T> = {
3839
/**
@@ -56,22 +57,30 @@ export type Props<T> = {
5657
/**
5758
* This is the main component, which creates a context for it's children. All children can access the information of the `DSVImport`.
5859
*/
59-
export function DSVImport<T extends GenericColumnType>(props: PropsWithChildren<Props<T>>) {
60+
export function DSVImport<T extends GenericColumnType>({
61+
columns,
62+
onChange,
63+
onValidation,
64+
transformers,
65+
children,
66+
}: PropsWithChildren<Props<T>>) {
6067
const DSVImportContext = getDSVImportContext<T>();
61-
const initialValues: State<T> = { columns: props.columns, transformers: props.transformers };
68+
const initialValues: State<T> = { columns, transformers };
6269
const [state, dispatch] = useReducer(createReducer<T>(), initialValues);
6370
const enhancedDispatch = applyMiddlewares(
6471
state,
6572
dispatch,
6673
createParserMiddleware(),
6774
createTransformerMiddleware(),
68-
createValidatorMiddleware()
75+
createValidatorMiddleware(),
6976
);
7077

78+
const value = useMemo<[State<T>, Dispatch<Actions<T>>]>(() => [state, enhancedDispatch], [state]);
79+
7180
return (
72-
<DSVImportContext.Provider value={[state, enhancedDispatch]}>
73-
<EventListener<T> onChange={props.onChange} onValidation={props.onValidation} />
74-
{props.children}
81+
<DSVImportContext.Provider value={value}>
82+
<EventListener<T> onChange={onChange} onValidation={onValidation} />
83+
{children}
7584
</DSVImportContext.Provider>
7685
);
7786
}

src/components/inputs/TextareaInput.test.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { render, fireEvent } from '@testing-library/react';
22
import { TextareaInput } from './TextareaInput';
3-
import React from 'react';
43
import { ColumnType } from '../../models/column';
54
import { getDSVImportContext } from '../../features/context';
65
import { State } from '../../models/state';
@@ -15,9 +14,10 @@ describe('TextareaInput', () => {
1514

1615
const renderComponent = () => {
1716
return render(
17+
// eslint-disable-next-line react/jsx-no-constructed-context-values
1818
<Context.Provider value={[state, dispatchMock]}>
1919
<TextareaInput />
20-
</Context.Provider>
20+
</Context.Provider>,
2121
);
2222
};
2323

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import React from 'react';
22
import { useDSVImport } from '../../features/context';
33

4-
export const TextareaInput: React.FC = () => {
4+
export function TextareaInput() {
55
const [, dispatch] = useDSVImport();
66

77
const handleChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
88
dispatch({ type: 'setRaw', raw: event.target.value });
99
};
1010

11-
return <textarea onChange={handleChange}></textarea>;
12-
};
11+
return <textarea onChange={handleChange} />;
12+
}

src/components/previews/TablePreview.test.tsx

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { render } from '@testing-library/react';
2-
import React from 'react';
32
import { ColumnType } from '../../models/column';
43
import { TablePreview } from './TablePreview';
54
import { State } from '../../models/state';
@@ -10,7 +9,7 @@ describe('TablePreview', () => {
109
const columns: ColumnType<TestType>[] = [
1110
{ key: 'forename', label: 'Forename' },
1211
{ key: 'surname', label: 'Surname' },
13-
{ key: 'email', label: 'Email' }
12+
{ key: 'email', label: 'Email' },
1413
];
1514
const defaultState: State<TestType> = { columns };
1615
const Context = getDSVImportContext<TestType>();
@@ -19,9 +18,10 @@ describe('TablePreview', () => {
1918

2019
const renderComponent = (state = defaultState) => {
2120
return render(
21+
// eslint-disable-next-line react/jsx-no-constructed-context-values
2222
<Context.Provider value={[state, dispatchMock]}>
2323
<TablePreview />
24-
</Context.Provider>
24+
</Context.Provider>,
2525
);
2626
};
2727

@@ -41,8 +41,8 @@ describe('TablePreview', () => {
4141
...defaultState,
4242
parsed: [
4343
{ forename: 'Max', surname: 'Muster', email: '[email protected]' },
44-
{ forename: '', surname: '', email: '[email protected]' }
45-
]
44+
{ forename: '', surname: '', email: '[email protected]' },
45+
],
4646
});
4747
const tableBody = container.querySelector('tbody');
4848

@@ -57,22 +57,19 @@ describe('TablePreview', () => {
5757
...defaultState,
5858
parsed: [
5959
{ forename: 'Max', surname: 'Muster', email: '[email protected]' },
60-
{ forename: '', surname: '', email: '[email protected]' }
60+
{ forename: '', surname: '', email: '[email protected]' },
6161
],
6262
validation: [
6363
{ column: 'email', row: 0, message: 'Contains duplicates' },
6464
{ column: 'email', row: 1, message: 'Contains duplicates' },
6565
{ column: 'email', row: 1, message: 'No example address, please' },
66-
{ column: 'forename', row: 1, message: 'Forename is required' }
67-
]
66+
{ column: 'forename', row: 1, message: 'Forename is required' },
67+
],
6868
});
6969
const tableBody = container.querySelector('tbody');
7070

7171
expect(tableBody?.children[1].children[0]).toHaveClass('error');
7272
expect(tableBody?.children[1].children[0]).toHaveAttribute('title', 'Forename is required');
73-
expect(tableBody?.children[1].children[2]).toHaveAttribute(
74-
'title',
75-
'Contains duplicates;No example address, please'
76-
);
73+
expect(tableBody?.children[1].children[2]).toHaveAttribute('title', 'Contains duplicates;No example address, please');
7774
});
7875
});
Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,43 @@
1-
import React from 'react';
1+
import { PropsWithChildren } from 'react';
22
import { useDSVImport } from '../../features/context';
33

4+
function Cell({ columnKey, rowIndex, children }: PropsWithChildren<{ columnKey: string; rowIndex: number }>) {
5+
const [context] = useDSVImport();
6+
7+
const errors = context.validation?.filter((e) => e.column === columnKey && e.row === rowIndex);
8+
const messages = errors?.map((e) => e.message).join(';');
9+
10+
return (
11+
<td className={messages ? 'error' : ''} title={messages}>
12+
{children}
13+
</td>
14+
);
15+
}
16+
417
export interface TablePreviewProps {
518
className?: string;
619
}
720

8-
export const TablePreview: React.FC<TablePreviewProps> = (props) => {
21+
export function TablePreview({ className }: TablePreviewProps) {
922
const [context] = useDSVImport();
1023

11-
const getCellValidationError = (columnKey: string, rowIndex: number) => {
12-
if (context.validation) {
13-
return context.validation.filter((e) => e.column === columnKey && e.row === rowIndex);
14-
}
15-
};
16-
17-
const Cell: React.FC<{ columnKey: string; rowIndex: number }> = (props) => {
18-
const errors = getCellValidationError(props.columnKey, props.rowIndex);
19-
const messages = errors?.map((e) => e.message).join(';');
20-
21-
return (
22-
<td className={messages ? 'error' : ''} title={messages}>
23-
{props.children}
24-
</td>
25-
);
26-
};
27-
2824
return (
29-
<table className={props.className}>
25+
<table className={className}>
3026
<thead>
3127
<tr>
32-
{context.columns.map((column, columnIndex) => (
33-
<th key={columnIndex}>{column.label}</th>
28+
{context.columns.map((column) => (
29+
<th key={column.key}>{column.label}</th>
3430
))}
3531
</tr>
3632
</thead>
3733
<tbody>
3834
{context.parsed
3935
? context.parsed.map((row, rowIndex) => (
36+
// eslint-disable-next-line react/no-array-index-key
4037
<tr key={rowIndex}>
41-
{context.columns.map((column, columnIndex) => {
38+
{context.columns.map((column) => {
4239
return (
43-
<Cell key={columnIndex} columnKey={column.key.toString()} rowIndex={rowIndex}>
40+
<Cell key={column.key} columnKey={column.key.toString()} rowIndex={rowIndex}>
4441
{row[column.key]}
4542
</Cell>
4643
);
@@ -51,4 +48,4 @@ export const TablePreview: React.FC<TablePreviewProps> = (props) => {
5148
</tbody>
5249
</table>
5350
);
54-
};
51+
}

src/features/context.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { reducer, getDSVImportContext } from './context';
2-
import { State } from '../models/state';
31
import { useContext } from 'react';
42
import { renderHook } from '@testing-library/react-hooks';
3+
import { reducer, getDSVImportContext } from './context';
4+
import { State } from '../models/state';
55

66
describe('context', () => {
77
type TestType = unknown;

src/features/context.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { State, emptyState } from '../models/state';
21
import { createContext, Dispatch, useContext } from 'react';
2+
import { State, emptyState } from '../models/state';
33
import { Actions } from '../models/actions';
44
import { GenericColumnType } from '../models/column';
55

@@ -27,10 +27,10 @@ let contextSingleton: React.Context<[State<any>, Dispatch<Actions<any>>]>;
2727
export const getDSVImportContext = <T>() => {
2828
if (!contextSingleton) {
2929
contextSingleton = createContext<[State<T>, Dispatch<Actions<T>>]>([
30-
(emptyState as unknown) as State<T>,
30+
emptyState as unknown as State<T>,
3131
() => {
3232
throw new Error('Not initialized');
33-
}
33+
},
3434
]);
3535
}
3636
return contextSingleton as React.Context<[State<T>, Dispatch<Actions<T>>]>;

0 commit comments

Comments
 (0)