Skip to content

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

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

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 'react-native-gesture-handler';

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 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 @@ export class MigrationProcessor {

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

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

return {
Expand All @@ -60,12 +60,12 @@ export class MigrationProcessor {
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)!;
regularStorage.set(key, value);
}
Expand All @@ -81,7 +81,7 @@ export class MigrationProcessor {
private prepareStorages() {
const storageNames = StoragesArray;

for (let storageName of storageNames) {
for (const storageName of storageNames) {
const storage = createMigrationStorage(storageName);
storage.clearAll();
}
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,7 +29,7 @@ export class MigrationRunner implements IMigrationRunner {
currentVersion: number,
inboundVersion: number,
): Promise<MigrationOutput> {
let migrationKeys = this.getMigrationKeys(currentVersion, inboundVersion);
const migrationKeys = this.getMigrationKeys(currentVersion, inboundVersion);

Logger.log(
`[MigrationRunner]: migrationKeys: [${migrationKeys}]${
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ export class MigrationToVersion0001 implements IMigration {

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 @@ export class MigrationToVersion0001 implements IMigration {
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 @@ export class MigrationToVersion0001 implements IMigration {

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
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