Skip to content

Commit

Permalink
RN: Move no-haste-imports ESLint Rule into Repository
Browse files Browse the repository at this point in the history
Summary:
Moves the `no-haste-imports` ESLint rule into the React Native repository because it was only intended to be used for internal development of React Native.

This will change `react-native/eslint-plugin` to no longer provide the `no-haste-imports` rule.

Changelog:
[General][Removed] - `react-native/eslint-plugin` no longer provides the `no-haste-imports` rule.

Reviewed By: lunaleaps

Differential Revision: D39858883

fbshipit-source-id: b8d91ce5996b615341cf60c6f839afac1e26dac9
  • Loading branch information
yungsters authored and facebook-github-bot committed Sep 27, 2022
1 parent 49b14cc commit 1ec69b1
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 35 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ module.exports = {
{
files: ['Libraries/**/*.js'],
rules: {
'@react-native-community/no-haste-imports': 2,
'@react-native-community/error-subclass-name': 2,
'@react-native-community/platform-colors': 2,
'@react-native/specs/react-native-modules': 2,
'lint/no-haste-imports': 2,
'lint/no-react-native-imports': 2,
},
},
Expand Down
4 changes: 0 additions & 4 deletions packages/eslint-plugin-react-native-community/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,6 @@ Add to your eslint config (`.eslintrc`, or `eslintConfig` field in `package.json

Enforces that error classes ( = classes with PascalCase names ending with `Error`) only extend other error classes, and that regular functions don't have names that could be mistaken for those of error classes.

### `no-haste-imports`

Disallows Haste module names in `import` statements and `require()` calls.

### `platform-colors`

Enforces that calls to `PlatformColor` and `DynamicColorIOS` are statically analyzable to enable performance optimizations.
1 change: 0 additions & 1 deletion packages/eslint-plugin-react-native-community/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,5 @@

exports.rules = {
'error-subclass-name': require('./error-subclass-name'),
'no-haste-imports': require('./no-haste-imports'),
'platform-colors': require('./platform-colors'),
};
99 changes: 99 additions & 0 deletions tools/eslint/rules/__tests__/no-haste-imports-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/

'use strict';

const rule = require('../no-haste-imports.js');
const {RuleTester} = require('eslint');

const ruleTester = new RuleTester({
parser: require.resolve('hermes-eslint'),
parserOptions: {
ecmaVersion: 6,
sourceType: 'module',
},
});

ruleTester.run('require(...)', rule, {
valid: [
{
code: `const X = require('x');`,
},
{
code: `const X = require('./X');`,
},
{
code: `const Y = require('X/Y');`,
},
],
invalid: [
{
code: `const X = require('X');`,
errors: [{messageId: 'hasteImport', data: {importPath: 'X'}}],
output: null, // Expect no autofix to be suggested.
},
{
code: `const useX = require('useX');`,
errors: [{messageId: 'hasteImport', data: {importPath: 'useX'}}],
output: null, // Expect no autofix to be suggested.
},
],
});

ruleTester.run('import(...)', rule, {
valid: [
{
code: `import('x');`,
},
{
code: `import('./X');`,
},
{
code: `import('X/Y');`,
},
],
invalid: [
{
code: `import('X');`,
errors: [{messageId: 'hasteImport', data: {importPath: 'X'}}],
output: null, // Expect no autofix to be suggested.
},
{
code: `import('useX');`,
errors: [{messageId: 'hasteImport', data: {importPath: 'useX'}}],
output: null, // Expect no autofix to be suggested.
},
],
});

ruleTester.run("import ... from '...'", rule, {
valid: [
{
code: `import X from 'x';`,
},
{
code: `import X from './X';`,
},
{
code: `import Y from 'X/Y';`,
},
],
invalid: [
{
code: `import X from 'X';`,
errors: [{messageId: 'hasteImport', data: {importPath: 'X'}}],
output: null, // Expect no autofix to be suggested.
},
{
code: `import useX from 'useX';`,
errors: [{messageId: 'hasteImport', data: {importPath: 'useX'}}],
output: null, // Expect no autofix to be suggested.
},
],
});
Original file line number Diff line number Diff line change
Expand Up @@ -7,40 +7,60 @@
* @format
*/

'use strict';

module.exports = {
meta: {
type: 'problem',
docs: {
description:
'disallow Haste module names in import statements and require calls',
description: 'Disallow importing Haste module names',
recommended: true,
},
messages: {
hasteImport:
"'{{importPath}}' seems to be a Haste module name; use path-based imports intead",
},
schema: [],
},

create(context) {
return {
ImportDeclaration(node) {
checkImportForHaste(context, node.source.value, node.source);
},
CallExpression(node) {
if (isStaticRequireCall(node)) {
const [firstArgument] = node.arguments;
checkImportForHaste(context, firstArgument.value, firstArgument);
if (
node.callee.type === 'Identifier' &&
node.callee.name === 'require' &&
node.arguments.length === 1
) {
processSource(node.arguments[0]);
}
},
ImportExpression(node) {
processSource(node.source);
},
ImportDeclaration(node) {
processSource(node.source);
},
};

function processSource(source) {
if (source.type !== 'Literal' || typeof source.value !== 'string') {
return;
}
const importPath = source.value;
if (!isLikelyHasteModuleName(importPath)) {
return;
}
context.report({
node: source,
messageId: 'hasteImport',
data: {
importPath,
},
});
}
},
};

function checkImportForHaste(context, importPath, node) {
if (isLikelyHasteModuleName(importPath)) {
context.report({
node,
message: `"${importPath}" appears to be a Haste module name. Use path-based imports instead.`,
});
}
}

function isLikelyHasteModuleName(importPath) {
// Our heuristic assumes an import path is a Haste module name if it is not a
// path and doesn't appear to be an npm package. For several years, npm has
Expand All @@ -59,15 +79,3 @@ function isLikelyHasteModuleName(importPath) {
/[A-Z]/.test(importPath)
);
}

function isStaticRequireCall(node) {
return (
node &&
node.callee &&
node.callee.type === 'Identifier' &&
node.callee.name === 'require' &&
node.arguments.length === 1 &&
node.arguments[0].type === 'Literal' &&
typeof node.arguments[0].value === 'string'
);
}

0 comments on commit 1ec69b1

Please sign in to comment.