diff --git a/desktop/.eslintrc.js b/desktop/.eslintrc.js index 7c2b64fe0..18b477e94 100644 --- a/desktop/.eslintrc.js +++ b/desktop/.eslintrc.js @@ -9,6 +9,9 @@ const fbjs = require('eslint-config-fbjs'); +const rulesDirPlugin = require('eslint-plugin-rulesdir'); +rulesDirPlugin.RULES_DIR = 'eslint-rules'; + // enforces copy-right header and @format directive to be present in every file const pattern = /^\*\r?\n[\S\s]*Facebook[\S\s]* \* @format\r?\n/; @@ -30,6 +33,39 @@ const builtInModules = [ const prettierConfig = require('./.prettierrc.json'); +// We should forbid using "flipper" import. However, we have hundreds of plugins using it. +// So we forbid it everywhere but in "plugins" directory. +// To do that we need to keep "error" level of linting for most imports, but downlevel warning for "flipper" import to "warn". +// It is not possible OOTB by eslint. +// Instead, we create a clone of the "no-restricted-imports" rule and use it to split out restricted imports in two groups: warn and error. +// https://github.com/eslint/eslint/issues/14061#issuecomment-772490154 +const restrictedImportsUniversalErrorConfig = { + paths: [ + { + name: 'electron', + message: + "Direct imports from 'electron' are deprecated. Most functions can be found in getFlipperLib() from flipper-plugin package instead.", + }, + ], + patterns: [ + { + group: ['flipper-plugin/*'], + message: + "Imports from nested flipper-plugin directories are not allowed. Import from 'flipper-plugin' module directly. If it is missing an export, add it there with corresponding documentation (https://fbflipper.com/docs/extending/flipper-plugin/).", + }, + { + group: ['flipper-common/*'], + message: + "Imports from nested flipper-common directories are not allowed. Import from 'flipper-common' module directly. If it is missing an export, add it there.", + }, + { + group: ['flipper-ui-core/*'], + message: + "Imports from nested flipper-ui-core directories are not allowed. Import from 'flipper-ui-core' module directly. If it is missing an export, add it there.", + }, + ], +}; + module.exports = { parser: 'babel-eslint', root: true, @@ -45,6 +81,7 @@ module.exports = { 'flipper', 'promise', 'communist-spelling', + 'rulesdir', ], rules: { // disable rules from eslint-config-fbjs @@ -81,16 +118,17 @@ module.exports = { }, ], 'no-restricted-imports': [ - 1, + 'error', { - name: 'flipper', - message: - "Direct imports from 'flipper' are deprecated. Import from 'flipper-plugin' instead, which can be tested and distributed stand-alone. See https://fbflipper.com/docs/extending/sandy-migration for more details.", - }, - { - name: 'electron', - message: - "Direct imports from 'electron' are deprecated. Most functions can be found in getFlipperLib() from flipper-plugin package instead.", + ...restrictedImportsUniversalErrorConfig, + paths: [ + ...restrictedImportsUniversalErrorConfig.paths, + { + name: 'flipper', + message: + "Direct imports from 'flipper' are deprecated. Import from 'flipper-plugin' instead, which can be tested and distributed stand-alone. See https://fbflipper.com/docs/extending/sandy-migration for more details.", + }, + ], }, ], @@ -150,5 +188,26 @@ module.exports = { ], }, }, + { + files: ['plugins/**/*.ts', 'plugins/**/*.tsx'], + rules: { + 'no-restricted-imports': [ + 'error', + restrictedImportsUniversalErrorConfig, + ], + 'rulesdir/no-restricted-imports-clone': [ + 'warn', + { + paths: [ + { + name: 'flipper', + message: + "Direct imports from 'flipper' are deprecated. Import from 'flipper-plugin' instead, which can be tested and distributed stand-alone. See https://fbflipper.com/docs/extending/sandy-migration for more details.", + }, + ], + }, + ], + }, + }, ], }; diff --git a/desktop/eslint-rules/no-restricted-imports-clone.js b/desktop/eslint-rules/no-restricted-imports-clone.js new file mode 100644 index 000000000..b0bc30549 --- /dev/null +++ b/desktop/eslint-rules/no-restricted-imports-clone.js @@ -0,0 +1,12 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +// https://github.com/eslint/eslint/issues/14061#issuecomment-772490154 +const eslint = require('eslint'); +module.exports = new eslint.Linter().getRules().get('no-restricted-imports'); diff --git a/desktop/flipper-server-core/src/devices/ios/__tests__/IOSBridge.node.tsx b/desktop/flipper-server-core/src/devices/ios/__tests__/IOSBridge.node.tsx index 8239a0eea..88b9ee27b 100644 --- a/desktop/flipper-server-core/src/devices/ios/__tests__/IOSBridge.node.tsx +++ b/desktop/flipper-server-core/src/devices/ios/__tests__/IOSBridge.node.tsx @@ -14,6 +14,7 @@ jest.mock('promisify-child-process'); import {makeIOSBridge} from '../IOSBridge'; import * as promisifyChildProcess from 'promisify-child-process'; import {setFlipperServerConfig} from '../../../FlipperServerConfig'; +// eslint-disable-next-line node/no-extraneous-import import {getRenderHostInstance} from 'flipper-ui-core'; beforeEach(() => { diff --git a/desktop/flipper-server-core/src/devices/ios/__tests__/iOSDevice.node.tsx b/desktop/flipper-server-core/src/devices/ios/__tests__/iOSDevice.node.tsx index bbb613f2e..b5c226945 100644 --- a/desktop/flipper-server-core/src/devices/ios/__tests__/iOSDevice.node.tsx +++ b/desktop/flipper-server-core/src/devices/ios/__tests__/iOSDevice.node.tsx @@ -11,6 +11,7 @@ import {parseXcodeFromCoreSimPath} from '../iOSDeviceManager'; import {getLogger} from 'flipper-common'; import {IOSBridge} from '../IOSBridge'; import {FlipperServerImpl} from '../../../FlipperServerImpl'; +// eslint-disable-next-line node/no-extraneous-import import {getRenderHostInstance} from 'flipper-ui-core'; import { getFlipperServerConfig, diff --git a/desktop/flipper-ui-core/src/.eslintrc.js b/desktop/flipper-ui-core/src/.eslintrc.js deleted file mode 100644 index cad8e32d7..000000000 --- a/desktop/flipper-ui-core/src/.eslintrc.js +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - */ - -module.exports = { - rules: { - 'no-restricted-imports': [ - 'error', - { - // These paths lead to circular import issues in Flipper app and are forbidden - paths: ['flipper'], - patterns: ['flipper-ui-core/src/*'], - }, - ], - }, -}; diff --git a/desktop/flipper-ui-core/src/RenderHost.tsx b/desktop/flipper-ui-core/src/RenderHost.tsx index 56ca12ccb..70f2b27fd 100644 --- a/desktop/flipper-ui-core/src/RenderHost.tsx +++ b/desktop/flipper-ui-core/src/RenderHost.tsx @@ -9,6 +9,8 @@ import type {NotificationEvents} from './dispatcher/notifications'; import type {PluginNotification} from './reducers/notifications'; +// TODO: Fix me +// eslint-disable-next-line no-restricted-imports import type {NotificationConstructorOptions} from 'electron'; import {FlipperLib} from 'flipper-plugin'; import {FlipperServer, FlipperServerConfig} from 'flipper-common'; diff --git a/desktop/package.json b/desktop/package.json index 179a08be6..fdd84e0c4 100644 --- a/desktop/package.json +++ b/desktop/package.json @@ -149,6 +149,7 @@ "eslint-plugin-promise": "^5.1.1", "eslint-plugin-react": "^7.27.1", "eslint-plugin-react-hooks": "^4.3.0", + "eslint-plugin-rulesdir": "^0.2.1", "expand-tilde": "^2.0.2", "express": "^4.15.2", "fb-watchman": "^2.0.1", diff --git a/desktop/scripts/build-release.ts b/desktop/scripts/build-release.ts index 2dfa813aa..889748548 100755 --- a/desktop/scripts/build-release.ts +++ b/desktop/scripts/build-release.ts @@ -35,6 +35,7 @@ import copyPackageWithDependencies from './copy-package-with-dependencies'; import {staticDir, distDir} from './paths'; import yargs from 'yargs'; import {WinPackager} from 'app-builder-lib/out/winPackager'; +// eslint-disable-next-line no-restricted-imports import {Icon, getPublicIconUrl} from 'flipper-ui-core/src/utils/icons'; // Used in some places to avoid release-to-release changes. Needs diff --git a/desktop/scripts/jest-setup-after.ts b/desktop/scripts/jest-setup-after.ts index 57f4b70e1..8ed6184cf 100644 --- a/desktop/scripts/jest-setup-after.ts +++ b/desktop/scripts/jest-setup-after.ts @@ -24,6 +24,7 @@ import { } from 'flipper-common'; // Only import the type! +// eslint-disable-next-line node/no-extraneous-import import type {RenderHost} from 'flipper-ui-core'; const test = global.test; diff --git a/desktop/yarn.lock b/desktop/yarn.lock index 4575afeed..ae25f71f9 100644 --- a/desktop/yarn.lock +++ b/desktop/yarn.lock @@ -6203,6 +6203,11 @@ eslint-plugin-react@^7.27.1: semver "^6.3.0" string.prototype.matchall "^4.0.6" +eslint-plugin-rulesdir@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-rulesdir/-/eslint-plugin-rulesdir-0.2.1.tgz#e246bb9657e68eb0a30680c60775f40aa829ec0b" + integrity sha512-t7rQvEyfE4JZJu6dPl4/uVr6Fr0fxopBhzVbtq3isfOHMKdlIe9xW/5CtIaWZI0E1U+wzAk0lEnZC8laCD5YLA== + eslint-rule-composer@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz#79320c927b0c5c0d3d3d2b76c8b4a488f25bbaf9"