Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

M2-5381: Add initial set of linting rules for mobile repository #632

Merged
merged 4 commits into from
Apr 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,9 @@
!/*.ts
!/*.tsx

# Except for the ESLint & Prettier configs. We can ignore those
.eslintrc.js
.prettierrc.js

# This looks like a generated file
src/entities/flanker/ui/HtmlFlanker/visual-stimulus-response.html
164 changes: 123 additions & 41 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,52 +1,134 @@
module.exports = {
root: true,
extends: '@react-native',
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint', 'import'],
parser: '@babel/eslint-parser',
extends: [
'eslint:recommended',
'@react-native-community',
'plugin:react/recommended',
'prettier'
],
plugins: ['import', 'react', 'react-hooks', 'unused-imports', 'jest'],
rules: {
'react/react-in-jsx-scope': 'off',
'react/no-unstable-nested-components': 'off',
'react/jsx-newline': [2, { prevent: true, allowMultilines: true }],
'import/order': [
'error',
{
groups: [
['external', 'builtin'],
'internal',
['sibling', 'parent'],
'index',
],
pathGroups: [
{
pattern: '@(react|react-native)',
group: 'external',
position: 'before',
},
{
pattern:
'@(@app|@shared|@features|@screens|@entities|@assets|@jobs|@widgets)/**',
group: 'internal',
},
{
pattern: '@(@images)',
group: 'internal',
position: 'after',
},
],
pathGroupsExcludedImportTypes: ['internal', 'react'],
'newlines-between': 'always',
alphabetize: {
order: 'asc',
caseInsensitive: true,
},
},
],
'react-hooks/rules-of-hooks': 'warn',
'import/no-cycle': 'warn',
'constructor-super': 'warn',
'no-var': 'warn',
'no-caller': 'warn',
'array-callback-return': 'warn',
'no-eval': 'warn',
'no-extend-native': 'warn',
eqeqeq: ['warn', 'always'],
'no-script-url': 'warn',
'no-self-compare': 'warn',
'no-sequences': 'warn',
'no-nested-ternary': 'warn',
'no-unneeded-ternary': 'warn',
'no-debugger': 'warn',
'no-empty': 'warn',
'no-unused-labels': 'warn',
'prefer-const': 'warn',

// Required for unused-imports
'no-unused-vars': 'off',
'unused-imports/no-unused-imports': 'warn',
'unused-imports/no-unused-vars': [
'warn',
{
vars: 'all',
varsIgnorePattern: '^_',
args: 'after-used',
argsIgnorePattern: '^_',
},
],
'react-hooks/exhaustive-deps': 'warn',
'no-case-declarations': 'warn',
'no-unsafe-optional-chaining': 'warn',
'react/prop-types': 'warn',
'react/jsx-key': 'warn',
'react/jsx-no-duplicate-props': 'warn',
'react/jsx-no-target-blank': 'warn',
'react/jsx-no-undef': 'warn',
'react/no-danger-with-children': 'warn',
'react/no-deprecated': 'warn',
'react/no-direct-mutation-state': 'warn',
'react/no-find-dom-node': 'warn',
'react/no-is-mounted': 'warn',
'react/no-unescaped-entities': 'warn',
'react/no-unknown-property': 'warn',
'react/no-unsafe': 'warn',
'react/require-render-return': 'warn',
'react/display-name': 'off',
},
overrides: [
{
files: ['*.ts', '*.tsx'],
parser: '@typescript-eslint/parser',
parserOptions: {
project: './tsconfig.json',
},
plugins: ['@typescript-eslint'],
extends: [
'plugin:@typescript-eslint/eslint-recommended',
'plugin:@typescript-eslint/recommended-requiring-type-checking',
'prettier',
],
rules: {
'@typescript-eslint/no-shadow': ['error'],
'no-shadow': 'off',
'no-undef': 'off',
'react/react-in-jsx-scope': 'off',
'react/no-unstable-nested-components': 'off',
'react/jsx-newline': [2, { prevent: true, allowMultilines: true }],
'import/order': [
'error',
{
groups: [
['external', 'builtin'],
'internal',
['sibling', 'parent'],
'index',
],
pathGroups: [
{
pattern: '@(react|react-native)',
group: 'external',
position: 'before',
},
{
pattern:
'@(@app|@shared|@features|@screens|@entities|@assets|@jobs|@widgets)/**',
group: 'internal',
},
{
pattern: '@(@images)',
group: 'internal',
position: 'after',
},
],
pathGroupsExcludedImportTypes: ['internal', 'react'],
'newlines-between': 'always',
alphabetize: {
order: 'asc',
caseInsensitive: true,
},
},
],
'@typescript-eslint/no-shadow': ['error'],
'@typescript-eslint/no-non-null-assertion': 'warn',
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/no-duplicate-enum-values': 'warn',
'@typescript-eslint/no-floating-promises': 'warn',
'@typescript-eslint/no-unsafe-argument': 'warn',
'@typescript-eslint/no-unsafe-assignment': 'warn',
'@typescript-eslint/no-unsafe-member-access': 'warn',
'@typescript-eslint/no-unsafe-call': 'warn',
'@typescript-eslint/require-await': 'warn',
'@typescript-eslint/no-misused-promises': 'warn',
'@typescript-eslint/await-thenable': 'warn',
'@typescript-eslint/unbound-method': 'warn',
'@typescript-eslint/restrict-plus-operands': 'warn',
'@typescript-eslint/no-unsafe-return': 'warn',
'@typescript-eslint/restrict-template-expressions': 'warn',
'@typescript-eslint/no-unused-vars': 'off',
},
},
],
Expand Down
3 changes: 3 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,8 @@
!/*.js
!/*.ts

# Except for the ESLint config itself. We can ignore that
.eslintrc.js

# This looks like a generated file
src/entities/flanker/ui/HtmlFlanker/visual-stimulus-response.html
10 changes: 5 additions & 5 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

import { AppRegistry } from 'react-native';

import { jobRunner } from './src/shared/lib';
import { name as appName } from './app.json';
import App from './src/app';
import displayRemoteNotifications from './src/jobs/display-remote-notifications';
import localization from './src/jobs/localization';
import requestInterception from './src/jobs/request-interception';
import responseInterception from './src/jobs/response-interception';
import setBackgroundTask from './src/jobs/set-background-task';
import displayRemoteNotifications from './src/jobs/display-remote-notifications';
import localization from './src/jobs/localization';
import App from './src/app';
import { name as appName } from './app.json';
import { jobRunner } from './src/shared/lib';

jobRunner.runAll([
requestInterception,
Expand All @@ -19,7 +19,7 @@

jobRunner.runAllSync([localization, displayRemoteNotifications]);

function HeadlessCheck({ isHeadless }) {

Check warning on line 22 in index.js

View workflow job for this annotation

GitHub Actions / ESLint

index.js#L22

'isHeadless' is missing in props validation (react/prop-types)
if (isHeadless) {
return null;
}
Expand Down
3 changes: 2 additions & 1 deletion jest.components.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { jest } from '@jest/globals';
import React from 'react';

import { jest } from '@jest/globals';

jest.mock('@georstat/react-native-image-cache', () => {
return {
CachedImage: () => <></>,
Expand Down
17 changes: 14 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
"start": "react-native start",
"test": "jest --noStackTrace",
"lint": "eslint . --ext .js,.jsx,.ts,.tsx",
"lint:check": "yarn lint",
"lint:fix": "yarn lint --fix",
"prettier:check": "prettier '**/*.{js,jsx,ts,tsx}' --check",
"prettier:fix": "prettier '**/*.{js,jsx,ts,tsx}' --write",
"pods": "bundle exec pod install --project-directory=ios",
"prepare": "husky install",
"postinstall": "yarn patch-package",
Expand Down Expand Up @@ -123,6 +127,7 @@
},
"devDependencies": {
"@babel/core": "^7.20.0",
"@babel/eslint-parser": "^7.23.10",
"@babel/plugin-proposal-export-namespace-from": "^7.18.9",
"@babel/preset-env": "^7.20.0",
"@babel/runtime": "^7.20.0",
Expand All @@ -146,12 +151,18 @@
"babel-jest": "^29.6.3",
"babel-plugin-module-resolver": "^5.0.0",
"babel-plugin-transform-inline-environment-variables": "^0.4.4",
"eslint": "^8.19.0",
"eslint": "^8.50.0",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-jest": "^27.6.3",
"eslint-plugin-only-warn": "^1.1.0",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-unused-imports": "^3.0.0",
"husky": "^8.0.3",
"jest": "^29.6.3",
"lint-staged": "^15.2.0",
"prettier": "2.8.8",
"prettier": "^3.2.5",
"react-native-mmkv-flipper-plugin": "^1.0.0",
"react-query-native-devtools": "^4.0.0",
"react-test-renderer": "18.2.0",
Expand All @@ -173,4 +184,4 @@
"resolutions": {
"react": "18.2.0"
}
}
}
6 changes: 3 additions & 3 deletions src/abstract/lib/utils/progressConvert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,20 @@ import {
export const convertProgress = (storeProgress: StoreProgress): Progress => {
const result: Progress = {};

for (let appletId in storeProgress) {
for (const appletId in storeProgress) {
if (!result[appletId]) {
result[appletId] = {};
}
const entitiesProgress: StoreEntitiesProgress = storeProgress[appletId];

for (let entityId in entitiesProgress) {
for (const entityId in entitiesProgress) {
if (!result[appletId][entityId]) {
result[appletId][entityId] = {};
}

const eventsProgress: StoreEventsProgress = entitiesProgress[entityId];

for (let eventId in eventsProgress) {
for (const eventId in eventsProgress) {
const storePayload: StoreProgressPayload = eventsProgress[eventId];

const flowProgress = storePayload as FlowProgress;
Expand Down
8 changes: 4 additions & 4 deletions src/app/model/migrations/MigrationProcessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@

private getMigrationInput(): MigrationInput {
// @ts-ignore
// eslint-disable-next-line @typescript-eslint/no-unused-vars

const { _persist, ...reduxState } = this.reduxStore.getState();

return {
Expand All @@ -60,13 +60,13 @@
private updateStorages() {
const storageNames = StoragesArray;

for (let storageName of storageNames) {
for (const storageName of storageNames) {
const migrationStorage = createMigrationStorage(storageName);
const regularStorage = createRegularStorage(storageName);
const keys = migrationStorage.getAllKeys();

for (let key of keys) {
for (const key of keys) {
const value = migrationStorage.getString(key)!;

Check warning on line 69 in src/app/model/migrations/MigrationProcessor.ts

View workflow job for this annotation

GitHub Actions / ESLint

src/app/model/migrations/MigrationProcessor.ts#L69

Forbidden non-null assertion (@typescript-eslint/no-non-null-assertion)
regularStorage.set(key, value);
}
}
Expand All @@ -81,7 +81,7 @@
private prepareStorages() {
const storageNames = StoragesArray;

for (let storageName of storageNames) {
for (const storageName of storageNames) {
const storage = createMigrationStorage(storageName);
storage.clearAll();
}
Expand Down Expand Up @@ -127,7 +127,7 @@
return this.commitChanges(migrationOutput);
}
} catch (error) {
Logger.warn('[MigrationProcessor] Error occurred: \n\n' + error);

Check warning on line 130 in src/app/model/migrations/MigrationProcessor.ts

View workflow job for this annotation

GitHub Actions / ESLint

src/app/model/migrations/MigrationProcessor.ts#L130

Invalid operand for a '+' operation. Operands must each be a number or string. Got `unknown` (@typescript-eslint/restrict-plus-operands)
}
await Logger.send();
}
Expand Down
2 changes: 1 addition & 1 deletion src/app/model/migrations/MigrationRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@
currentVersion: number,
inboundVersion: number,
): Promise<MigrationOutput> {
let migrationKeys = this.getMigrationKeys(currentVersion, inboundVersion);
const migrationKeys = this.getMigrationKeys(currentVersion, inboundVersion);

Logger.log(
`[MigrationRunner]: migrationKeys: [${migrationKeys}]${

Check warning on line 35 in src/app/model/migrations/MigrationRunner.ts

View workflow job for this annotation

GitHub Actions / ESLint

src/app/model/migrations/MigrationRunner.ts#L35

Invalid type "number[]" of template literal expression (@typescript-eslint/restrict-template-expressions)
migrationKeys.length === 0 ? ', no need to run migrations' : ''
}`,
);
Expand All @@ -50,7 +50,7 @@
reduxState = migrationOutput.reduxState;
} catch (error) {
Logger.warn(
`[MigrationRunner.performMigration] Error occurred during execution migration v${version}: \n\n${error}`,

Check warning on line 53 in src/app/model/migrations/MigrationRunner.ts

View workflow job for this annotation

GitHub Actions / ESLint

src/app/model/migrations/MigrationRunner.ts#L53

Invalid type "unknown" of template literal expression (@typescript-eslint/restrict-template-expressions)
);
throw error;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,11 @@
): FlowStateTo {
const flowStateTo = { ...flowStateFrom } as FlowStateTo;

const eventDtos = this.queryDataUtils.getEventsDto(appletDto.id)!;

Check warning on line 104 in src/app/model/migrations/migrations/to0001/MigrationToVersion0001.ts

View workflow job for this annotation

GitHub Actions / ESLint

src/app/model/migrations/migrations/to0001/MigrationToVersion0001.ts#L104

Forbidden non-null assertion (@typescript-eslint/no-non-null-assertion)

const eventDto = eventDtos.find(e => e.id === eventId);

flowStateTo.flowName = activityFlowDto!.name;
flowStateTo.flowName = activityFlowDto.name;

if (eventDto) {
flowStateTo.scheduledDate =
Expand All @@ -114,7 +114,7 @@
Logger.warn("'[MigrationToVersion0001]: Event doesn't exist: " + eventId);
}

for (let pipelineItem of flowStateTo.pipeline) {
for (const pipelineItem of flowStateTo.pipeline) {
const activityDto = appletDto.activities.find(
a => a.id === pipelineItem.payload.activityId,
);
Expand Down Expand Up @@ -150,7 +150,7 @@

const progressFlowsFrom = selectNotCompletedFlows(reduxRootStateFrom);

for (let progressFlowFrom of progressFlowsFrom) {
for (const progressFlowFrom of progressFlowsFrom) {
const { appletId, flowId: entityId, eventId, payload } = progressFlowFrom;

let logAppletName = '',
Expand Down Expand Up @@ -187,7 +187,7 @@

const key = this.getFlowRecordKey(appletId, entityId, eventId);

const flowStateFrom: FlowStateFrom = this.getFlowState(key)!;

Check warning on line 190 in src/app/model/migrations/migrations/to0001/MigrationToVersion0001.ts

View workflow job for this annotation

GitHub Actions / ESLint

src/app/model/migrations/migrations/to0001/MigrationToVersion0001.ts#L190

Forbidden non-null assertion (@typescript-eslint/no-non-null-assertion)

logFlowStateFrom = JSON.stringify(flowStateFrom, null, 2);

Expand All @@ -203,7 +203,7 @@
flowProgressPayloadFrom.currentActivityId,
);
}
logCurrentActivityDto = JSON.stringify(currentActivityDto!, null, 2);

Check warning on line 206 in src/app/model/migrations/migrations/to0001/MigrationToVersion0001.ts

View workflow job for this annotation

GitHub Actions / ESLint

src/app/model/migrations/migrations/to0001/MigrationToVersion0001.ts#L206

Forbidden non-null assertion (@typescript-eslint/no-non-null-assertion)

const progressFlowTo = this.getUpdatedFlowProgress(
progressFlowFrom,
Expand All @@ -224,7 +224,7 @@
this.updateFlowState(key, flowStateTo);
} catch (error) {
Logger.warn(
`[MigrationToVersion0001.iterate]: Error occurred, appletName=${logAppletName}, flowName=${logFlowName}, progressFlowFrom=${logProgressFlowFrom}, flowStateFrom=${logFlowStateFrom}, currentActivityDto=${logCurrentActivityDto}, activityFlowDto=${logActivityFlowDto} \nerror: \n${error}`,

Check warning on line 227 in src/app/model/migrations/migrations/to0001/MigrationToVersion0001.ts

View workflow job for this annotation

GitHub Actions / ESLint

src/app/model/migrations/migrations/to0001/MigrationToVersion0001.ts#L227

Invalid type "unknown" of template literal expression (@typescript-eslint/restrict-template-expressions)
);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,17 @@ export const selectNotCompletedFlows = (

const appletIds = Object.keys(inProgressApplets);

for (let appletId of appletIds) {
for (const appletId of appletIds) {
const progressEntities = inProgressApplets[appletId] ?? {};

const entityIds = Object.keys(progressEntities);

for (let entityId of entityIds) {
for (const entityId of entityIds) {
const progressEvents = progressEntities[entityId] ?? {};

const eventIds = Object.keys(progressEvents);

for (let eventId of eventIds) {
for (const eventId of eventIds) {
const payload = progressEvents[eventId] ?? {};

if (
Expand Down Expand Up @@ -153,7 +153,7 @@ export const getUpdatedReduxState = (
},
};

for (let flow of progressFlowsTo) {
for (const flow of progressFlowsTo) {
result = {
...result,
applets: {
Expand Down
Loading
Loading