Skip to content

Commit ecc74bf

Browse files
authored
Fix lint issues and enable refresh plugin (#3312)
* Update ESLint config * Add missing blocks to address warning * Add more missing blocks * Migrate react-router config to modern RR with lazy * Remove unnecessary double negation * Fix whitespace and type definitions * Refactor promise for readability * Update lint rules and add ignore * Remove trailing spaces and update comment * Remove old ESLint comments * Fix lint errors * Ignore error to preserve behavior
1 parent 9310259 commit ecc74bf

File tree

37 files changed

+204
-144
lines changed

37 files changed

+204
-144
lines changed

eslint.config.mjs

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
// @ts-check
22

3-
// import eslint from '@eslint/js';
3+
import eslint from '@eslint/js';
44
import reactPlugin from 'eslint-plugin-react';
55
import reactHooksPlugin from 'eslint-plugin-react-hooks';
66
import simpleImportSort from 'eslint-plugin-simple-import-sort';
7-
import { config, configs } from 'typescript-eslint';
8-
// import reactRefresh from 'eslint-plugin-react-refresh';
7+
import tseslint from 'typescript-eslint';
8+
import reactRefresh from 'eslint-plugin-react-refresh';
99

10-
export default config(
11-
{ ignores: ['eslint.config.mjs'] },
12-
// eslint.configs.recommended,
13-
...configs.recommended,
10+
export default tseslint.config(
11+
{ ignores: ['eslint.config.mjs', '**/*.snap'] },
12+
eslint.configs.recommended,
13+
tseslint.configs.recommended,
1414
// TODO: Enable when ready
15-
// {
16-
// plugins: {
17-
// 'react-refresh': reactRefresh
18-
// },
19-
// rules: {
20-
// 'react-refresh/only-export-components': 'warn'
21-
// }
22-
// },
15+
{
16+
plugins: {
17+
'react-refresh': reactRefresh
18+
},
19+
rules: {
20+
'react-refresh/only-export-components': 'warn'
21+
}
22+
},
2323
{
2424
files: ['**/*.ts*'],
2525
plugins: {
@@ -29,6 +29,7 @@ export default config(
2929
},
3030
rules: {
3131
...reactHooksPlugin.configs['recommended-latest'].rules,
32+
'no-empty': 'warn',
3233
'no-restricted-imports': [
3334
'error',
3435
{

src/commons/application/Application.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,11 +115,12 @@ const Application: React.FC = () => {
115115
dispatch(SessionActions.fetchUserAndCourse());
116116
}
117117
break;
118-
case MessageTypeNames.Text:
118+
case MessageTypeNames.Text: {
119119
const { workspaceLocation, code } = message;
120120
console.log(`FRONTEND: TextMessage: ${code}`);
121121
dispatch(WorkspaceActions.updateEditorValue(workspaceLocation, 0, code));
122122
break;
123+
}
123124
case MessageTypeNames.EvalEditor:
124125
dispatch(WorkspaceActions.evalEditor(message.workspaceLocation));
125126
break;
@@ -164,4 +165,9 @@ const Application: React.FC = () => {
164165
);
165166
};
166167

168+
// react-router lazy loading
169+
// https://reactrouter.com/en/main/route/lazy
170+
export const Component = Application;
171+
Component.displayName = 'Application';
172+
167173
export default Application;

src/commons/assessment/Assessment.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,4 +309,9 @@ const collapseButton = (label: string, isOpen: boolean, toggleFunc: () => void)
309309
/>
310310
);
311311

312+
// react-router lazy loading
313+
// https://reactrouter.com/en/main/route/lazy
314+
export const Component = Assessment;
315+
Component.displayName = 'Assessment';
316+
312317
export default Assessment;

src/commons/assessmentWorkspace/AssessmentWorkspace.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ const AssessmentWorkspace: React.FC<AssessmentWorkspaceProps> = props => {
357357
} = {};
358358

359359
switch (question.type) {
360-
case QuestionTypes.programming:
360+
case QuestionTypes.programming: {
361361
const programmingQuestionData: IProgrammingQuestion = question;
362362
options.autogradingResults = programmingQuestionData.autogradingResults;
363363
options.programPrependValue = programmingQuestionData.prepend;
@@ -378,14 +378,16 @@ const AssessmentWorkspace: React.FC<AssessmentWorkspaceProps> = props => {
378378
);
379379
}
380380
break;
381-
case QuestionTypes.voting:
381+
}
382+
case QuestionTypes.voting: {
382383
const votingQuestionData: IContestVotingQuestion = question;
383384
options.programPrependValue = votingQuestionData.prepend;
384385
if (props.fromContestLeaderboard) options.editorValue = code;
385386
options.programPostpendValue = votingQuestionData.postpend;
386387
// maybe the following dispatch can be placed in a better location
387388
dispatch(LeaderboardActions.setWorkspaceInitialRun(votingId));
388389
break;
390+
}
389391
case QuestionTypes.mcq:
390392
// Do nothing
391393
break;
@@ -413,7 +415,7 @@ const AssessmentWorkspace: React.FC<AssessmentWorkspaceProps> = props => {
413415
const questionType = question.type;
414416

415417
switch (questionType) {
416-
case QuestionTypes.mcq:
418+
case QuestionTypes.mcq: {
417419
const mcqQuestionData = question;
418420
sendToWebview(
419421
Messages.McqQuestion(
@@ -425,7 +427,8 @@ const AssessmentWorkspace: React.FC<AssessmentWorkspaceProps> = props => {
425427
)
426428
);
427429
break;
428-
case QuestionTypes.programming || QuestionTypes.voting:
430+
}
431+
case QuestionTypes.programming || QuestionTypes.voting: {
429432
const prepend = question.prepend;
430433
const code = question.answer ?? question.solutionTemplate;
431434
const breakpoints = editorTabs[0]?.breakpoints ?? [];
@@ -441,6 +444,7 @@ const AssessmentWorkspace: React.FC<AssessmentWorkspaceProps> = props => {
441444
)
442445
);
443446
break;
447+
}
444448
}
445449
if (options.editorValue) {
446450
// TODO: Hardcoded to make use of the first editor tab. Refactoring is needed for this workspace to enable Folder mode.

src/commons/editingWorkspace/EditingWorkspace.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -716,7 +716,7 @@ const EditingWorkspace: React.FC<EditingWorkspaceProps> = props => {
716716

717717
function uniq(a: string[]) {
718718
const seen: Record<string, boolean> = {};
719-
return a.filter(item => (seen.hasOwnProperty(item) ? false : (seen[item] = true)));
719+
return a.filter(item => (Object.hasOwnProperty.call(seen, item) ? false : (seen[item] = true)));
720720
}
721721

722722
export default EditingWorkspace;

src/commons/fileSystem/utils.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -103,19 +103,15 @@ export const retrieveFilesInWorkspaceAsRecord = (
103103
* @param fileSystem The file system instance.
104104
* @param files A mapping from file paths to file contents.
105105
*/
106-
export const overwriteFilesInWorkspace = (
106+
export const overwriteFilesInWorkspace = async (
107107
workspaceLocation: WorkspaceLocation,
108108
fileSystem: FSModule,
109109
files: Record<string, string>
110110
): Promise<void> => {
111-
return rmFilesInDirRecursively(fileSystem, WORKSPACE_BASE_PATHS[workspaceLocation]).then(() => {
112-
return new Promise(async (resolve, reject) => {
113-
for (const [filePath, fileContents] of Object.entries(files)) {
114-
await writeFileRecursively(fileSystem, filePath, fileContents).catch(err => reject(err));
115-
}
116-
resolve();
117-
});
118-
});
111+
await rmFilesInDirRecursively(fileSystem, WORKSPACE_BASE_PATHS[workspaceLocation]);
112+
for (const [filePath, fileContents] of Object.entries(files)) {
113+
await writeFileRecursively(fileSystem, filePath, fileContents);
114+
}
119115
};
120116

121117
/**

src/commons/sagas/BackendSaga.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
/*eslint no-eval: "error"*/
2-
/*eslint-env browser*/
31
import _ from 'lodash';
42
import type { SagaIterator } from 'redux-saga';
53
import { all, call, fork, put, select } from 'redux-saga/effects';

src/commons/sagas/__tests__/SafeEffects.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ describe('Test wrapSaga', () => {
2727

2828
test('wrapSaga handles errors appropriately', async () => {
2929
const errorToThrow = new Error();
30+
// eslint-disable-next-line require-yield
3031
const wrappedSaga = wrapSaga(function* () {
3132
throw errorToThrow;
3233
});

src/commons/sideContent/content/SideContentSubstVisualizer.tsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ const SideContentSubstVisualizer: React.FC<SubstVisualizerPropsAST> = props => {
199199
Custom AST renderer for Stepper (Inspired by astring library)
200200
This custom AST renderer utilizing the recursive approach of handling rendering of various StepperNodes by
201201
using nested <div> and <span>. Unlike React-ace, using our own renderer make our stepper more customizable. For example,
202-
we can add a code component that is hoverable by using with blueprint tooltip.
202+
we can add a code component that is hoverable by using with blueprint tooltip.
203203
*/
204204

205205
/** RenderContext holds relevant information to handle rendering. This will be carried along the recursive renderNode function
@@ -212,11 +212,12 @@ interface RenderContext {
212212
styleWrapper: StyleWrapper;
213213
}
214214

215-
/*
216-
StyleWrapper is a function that returns a styling function based on the node. For example,
217-
const wrapLiteral: StyleWrapper = (node)
218-
=> (preformatted) => node.type === "Literal" ? <div className="stepper-literal">preformatted</div> : preformatted;
219-
makes the default result from renderNode(node) wrapped with className stepper-literal for literal AST.
215+
/**
216+
StyleWrapper is a function that returns a styling function based on the node. For example,
217+
```tsx
218+
const wrapLiteral: StyleWrapper = (node) => (preformatted) => node.type === "Literal" ? <div className="stepper-literal">preformatted</div> : preformatted;
219+
```
220+
makes the default result from `renderNode(node)` wrapped with className `stepper-literal` for literal AST.
220221
*/
221222
type StyleWrapper = (node: StepperBaseNode) => (preformatted: React.ReactNode) => React.ReactNode;
222223

src/commons/sourceRecorder/SourceRecorderEditor.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,11 +137,12 @@ class SourcecastEditor extends React.PureComponent<SourceRecorderEditorProps, {}
137137
case 'cursorPositionChange':
138138
this.moveCursor(inputToApply.data);
139139
break;
140-
case 'selectionRangeData':
140+
case 'selectionRangeData': {
141141
const { range, isBackwards } = inputToApply.data;
142142
this.AceEditor.current!.editor.selection.setRange(range, isBackwards);
143143
break;
144-
case 'keyboardCommand':
144+
}
145+
case 'keyboardCommand': {
145146
const keyboardCommand = inputToApply.data;
146147
switch (keyboardCommand) {
147148
case 'run':
@@ -153,6 +154,7 @@ class SourcecastEditor extends React.PureComponent<SourceRecorderEditorProps, {}
153154
break;
154155
}
155156
break;
157+
}
156158
}
157159
}
158160

0 commit comments

Comments
 (0)