Skip to content
This repository has been archived by the owner on Mar 25, 2021. It is now read-only.

import-blacklist: support banning the import of specific named exports #3926

Merged
merged 4 commits into from
Dec 12, 2018

Conversation

ethanresnick
Copy link
Contributor

@ethanresnick ethanresnick commented May 23, 2018

PR checklist

Overview of change:

This extends the existing functionality of import-blacklist (without any breaking changes) to make it possible to blacklist imports of specific named exports from a module. The idea is that a module might have some exports that you don't want people to use in your project (even though they're not @deprecated or @internal to the module). For example, lodash has a pull method that removes items from an array, mutating the array in place; you may want to ban importing this method, to instead require that people use difference, which is like pull except that it doesn't mutate its argument.

Is there anything you'd like reviewers to focus on?

CHANGELOG.md entry:

[new-rule-option] [enhancement] import-blacklist: support blacklisting specific named exports

@ethanresnick ethanresnick changed the title import-blacklist: support banning specific named imports import-blacklist: support banning the import of specific named exports May 23, 2018
Copy link

@giladgray giladgray left a comment

Choose a reason for hiding this comment

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

this is very cool!

}
return acc;
},
{} as BannedImports, // tslint:disable-line no-object-literal-type-assertion

Choose a reason for hiding this comment

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

.reduce<BannedImports>(...) should allow you to remove this disable.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed

src/rules/importBlacklistRule.ts Outdated Show resolved Hide resolved
@ethanresnick
Copy link
Contributor Author

@giladgray Thanks for the review! I've responded to your comments inline.

src/rules/importBlacklistRule.ts Outdated Show resolved Hide resolved
import { difference } from "lodash";

import { pull, difference } from "lodash";
~~~~~~~~~~~~~~~~~~~~ [2]
Copy link
Contributor

Choose a reason for hiding this comment

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

is there a way to not underline difference?

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 assume so, but I really don't think it's worth it — the error message already specifies which is the problematic import.

@ethanresnick
Copy link
Contributor Author

@suchanlee @giladgray Is this good to merge?

@suchanlee
Copy link
Contributor

can you merge rebase off of latest master to fix the build?

@ethanresnick
Copy link
Contributor Author

@suchanlee Done!

@desfero
Copy link

desfero commented Sep 15, 2018

Any updates on enhancement?

@@ -54,9 +88,140 @@ export class Rule extends Lint.Rules.AbstractRule {
}

function walk(ctx: Lint.WalkContext<string[]>) {
type Options = Array<string | { [moduleName: string]: string[] }>;
Copy link

Choose a reason for hiding this comment

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

You can move Options out from walk function and correctly type options key without casting on line 99.

function walk(ctx: Lint.WalkCONTEXT< Array<string | { [moduleName: string]: string[] }>>) {

? parentNode.importClause
: undefined;

const importsDefaultExport = importClause && Boolean(importClause.name);
Copy link

Choose a reason for hiding this comment

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

I'm wondering whether there are any benefits of doing Boolean(importClause.name) over simple importClause.name here and on line 183 if strict-boolean-expressions is disabled?

@desfero
Copy link

desfero commented Sep 16, 2018

@ethanbond @suchanlee @giladgray maybe it's worth to add support for custom message why import was blocked (have a look please at similar PR to add support for blocking only specific named exports)

// Merge/normalize options.
// E.g., ["a", { "b": ["c"], "d": ["e"] }, "f", { "f": ["g"] }]
// becomes { "a": true, "b": Set(["c"]), "d": Set(["e"]), "f": true }.
const bannedImports = (ctx.options as Options).reduce<BannedImports>(
Copy link

Choose a reason for hiding this comment

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

Actually, it's probably worth for perf reason to move options normalization to the Rule class above as it's not worth to preprocess options for each file separately.

@ethanresnick
Copy link
Contributor Author

ethanresnick commented Sep 16, 2018

@desfero Thanks for the feedback!

You can move Options out from walk function and correctly type options key without casting on line 99.

Yup, that's nicer. I've pushed a fix for this.

I'm wondering whether there are any benefits of doing Boolean(importClause.name) over simple importClause.name here and on line 183 if strict-boolean-expressions is disabled?

I don't know, but I'd rather not disable lint rules if possible. strict-boolean-expressions is sort of a stylistic thing, imo, and if the TSLint team wants it enabled to make sure the variables actually hold a boolean, then I'm fine doing the casting.

maybe it's worth to add support for custom message why import was blocked

I really like this idea. Hopefully, we can get this merged first, though, and then add it. I think it would be as simple as allowing a [name, message] tuple or { name, message } object anywhere that a string is currently allowed in the options. That way, messages could be associated with specific named imports as well as whole modules:

[
  true, 
  "rxjs", 
  { "name": "lodash", "message": "use underscore" },
  { "underscore": [{ "name": "pick", "message": "use x instead" }, "y"] }
]

Actually, it's probably worth for perf reason to move options normalization to the Rule class above as it's not worth to preprocess options for each file separately.

Makes sense. I'm not sure exactly how the initialization of Rule classes happens, though, or whether it's kosher to add a constructor (which is presumably where I'd compute this), as none of the other Rules seem to define one. Open to input here from the TSLint team.

Copy link
Contributor

@JoshuaKGoldberg JoshuaKGoldberg left a comment

Choose a reason for hiding this comment

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

Rule messages could only mention importing or re-exporting as needed, but not a blocker for merging. ✔

@ericanderson ericanderson merged commit 09bc892 into palantir:master Dec 12, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants