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

Add prefer-import-module-contents custom rule #37

Merged
merged 1 commit into from
Nov 24, 2021
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
44 changes: 43 additions & 1 deletion eslint-plugin-expensify/prefer-import-module-contents.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,40 @@ function isEverySpecifierImport(specifiers = []) {
return _.every(specifiers, specifier => specifier.type === 'ImportSpecifier');
}

/**
* Make an exception for propTypes since they are sometimes bundled with modules.
*
* @param {Array} specifiers
* @returns {Boolean}
*/
function hasPropTypesSpecifier(specifiers) {
return _.some(specifiers, specifier => /proptypes/.test(lodashGet(specifier, 'imported.name', '').toLowerCase()));
}

/**
* @param {String} source
* @returns {Boolean}
*/
function isHigherOrderComponent(source) {
return /with/.test(source.toLowerCase());
}

/**
* @param {String} source
* @returns {Boolean}
*/
function isContextComponent(source) {
return /context|provider/.test(source.toLowerCase());
}

Comment on lines +31 to +46

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain why we're ignoring these types of components?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we can re-visit whether we want to do this or not later. But basically there are some really common patterns where an HOC is a default export and it's propTypes or something else is a named export which makes it harder to follow the advice to use import * as syntax.

I couldn't work out how to improve this so opted to just make exceptions for things that are basically "internal" libraries like HOCs or Providers. My thinking is that it is OK to treat these like 3rd party libs or Onyx - but mostly I am lazy and didn't want to update too many things at once.

/**
* @param {String} source
* @returns {Boolean}
*/
function isJSONFile(source) {
return /\.json/.test(source.toLowerCase());
}

module.exports = {
create: context => ({
ImportDeclaration(node) {
Expand All @@ -26,14 +60,22 @@ module.exports = {
return;
}

if (isFromNodeModules(sourceValue)) {
if (isFromNodeModules(sourceValue)
|| isHigherOrderComponent(sourceValue)
|| isContextComponent(sourceValue)
|| isJSONFile(sourceValue)
) {
return;
}

if (!node.specifiers || !node.specifiers.length) {
return;
}

if (hasPropTypesSpecifier(node.specifiers)) {
return;
}

if (!isEverySpecifierImport(node.specifiers)) {
return;
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "eslint-config-expensify",
"version": "2.0.18",
"version": "2.0.19",
"description": "Expensify's ESLint configuration following our style guide",
"main": "index.js",
"repository": {
Expand Down
1 change: 1 addition & 0 deletions rules/expensify.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ module.exports = {
'rulesdir/no-inline-named-export': 'error',
'rulesdir/prefer-underscore-method': 'error',
'rulesdir/no-useless-compose': 'error',
'rulesdir/prefer-import-module-contents': 'error',
},
};