Skip to content
This repository has been archived by the owner on Jul 15, 2023. It is now read-only.

fix: import-name options bugs and documentation #882

Closed
wants to merge 3 commits into from

Conversation

dosentmatter
Copy link

@dosentmatter dosentmatter commented Jul 19, 2019

PR checklist

  • Addresses an existing issue: fixes #0000
  • New feature, bugfix, or enhancement
    • Includes tests
  • Documentation update

Overview of change:

import-name rule has an off-by-one bug where it selects options starting from the wrong index. I updated the tests to match this.

I also noticed that for camelCase, it allowed the first letter to be upper-case. any-case is either PascalCase or camelCase, but since camelCase allowed the first letter to be upper case, any-case and camelCase are currently the same. I enforced the first letter to be lowercase.

I also updated the documentation. It's a bit lacking right now. It doesn't explain all of the allowed options.

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

Not completely related but, I found this bug from #881. In #881, I had other problems.

@msftclas
Copy link

msftclas commented Jul 19, 2019

CLA assistant check
All CLA requirements met.

@dosentmatter
Copy link
Author

Wonder why Travis CI is failing lint for node 6. The previous build failed too. strict-comparisons is a new rule. I see a fix for the false positive. Perhaps that will fix it. Haven't looked at why it only fails on node 6 and not other versions.

@dosentmatter dosentmatter changed the title Fix import-name options bugs and documentation Fix: import-name options bugs and documentation Jul 19, 2019
@dosentmatter dosentmatter changed the title Fix: import-name options bugs and documentation fix: import-name options bugs and documentation Jul 19, 2019
@IllusionMH
Copy link
Contributor

@dosentmatter thank you for the interest and PR. Will check it on weekend.

As for Node 6 - it was shipped with npm v3 that doesn't support package-lock.json files. Therefore it installs latest version of TSLint that has false positives instead of fixed version like builds with Node 8+. Error will go away with next TSLint release.

@IllusionMH IllusionMH self-requested a review July 19, 2019 07:32
@IllusionMH IllusionMH added the PR: Waiting for Reviewer A repository maintainer should take a look at the pull request soon! label Jul 19, 2019
The options begin at index 0. The previous developer might have gotten
it mixed up with initial `true` in the config array which controls
`ruleSeverity`, not `ruleArguments`.
Add documentation and examples of all the `import-name` options.
@dosentmatter
Copy link
Author

dosentmatter commented Jul 21, 2019

Actually, I made a mistake. Currently, any-case and camelCase are not exactly the same.

The current functionality is the following:
`PascalCase' allows (first letter must be uppercase):

import Foo from './foo';
import Foo from './Foo';

camelCase allows (first letter must match file name casing):

import foo from './foo';
import Foo from './foo';

any-case' allows (first letter is any case - PascalCase|camelCase`):

import foo from './foo';
import Foo from './foo';
import foo from './Foo';
import Foo from './foo';

What this means is that camelCase currently enforces that the first letter matches the file name casing. I updated my PR commit message. Let me know the desired functionality. If this wiki on camelCase is correct, it says

Some people and organizations, notably Microsoft,2 use the term camel case only for lower camel case

`camelCase` currently allows the first letter to be uppercase by
enforcing that it matches the casing of the file name first letter.
Enforce the first letter to be lowercase.
Copy link
Contributor

@IllusionMH IllusionMH left a comment

Choose a reason for hiding this comment

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

Overall changes to docs and code (except now redundant update to makeCamelCase) looks good, however this will be breaking change and might require better approach.

@@ -184,11 +184,16 @@ We recommend you specify exact versions of lint libraries, including `tslint-mic
</td>
<td>
The name of the imported module must match the name of the thing being imported. For special characters (<code>-</code>, <code>.</code>, <code>_</code>) remove them and make the following character uppercase.
For example, it is valid to name imported modules the same as the module name: <code>import Service = require('x/y/z/Service')</code> and <code>import Service from 'x/y/z/Service'</code>.
For example, it is valid to name imported modules the same as the module name: <code>import Service = require('./x/y/z/Service')</code> and <code>import Service from './x/y/z/Service'</code>.
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this change because of defaults?

But it is invalid to change the name being imported, such as: <code>import MyCoolService = require('x/y/z/Service')</code> and <code>import MyCoolService from 'x/y/z/Service'</code>.
When containing special characters such as <code>import $$ from 'my-awesome_library';</code> the corresponding configuration would look like <code>'import-name': [true, { 'myAwesomeLibrary': '$$' }]</code>.
Since version 2.0.9 it is possible to configure this rule with a list of exceptions.
For example, to allow <code>underscore</code> to be imported as <code>_</code>, add this configuration: <code>'import-name': [ true, { 'underscore': '_' }]</code>
The default is to ignore this rule for external modules <code>ignoreExternalModule: true</code> and to use camelCase <code>case: 'camelCase'</code>.
To not ignore this rule for external modules, add this configuration: <code>'import-name': [true, null, null, { ignoreExternalModule: false }]</code>.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
To not ignore this rule for external modules, add this configuration: <code>'import-name': [true, null, null, { ignoreExternalModule: false }]</code>.
To apply this rule for external modules, add this configuration: <code>'import-name': [true, null, null, { ignoreExternalModule: false }]</code>.

@@ -233,12 +233,14 @@ function walk(ctx: Lint.WalkContext<Option>) {
}

function makeCamelCase(input: string): string {
return input.replace(
let result = `${input.charAt(0)}${input.slice(1)}`;
Copy link
Contributor

Choose a reason for hiding this comment

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

Doesn't look like this changes anything (without .toLowerCase())

@@ -1299,8 +1299,7 @@
"ansi-regex": {
"version": "2.1.1",
"bundled": true,
"dev": true,
"optional": true
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you please rollback these changes to package-lock.json?

@@ -45,15 +45,15 @@ export class Rule extends Lint.Rules.AbstractRule {

if (options.ruleArguments instanceof Array) {
options.ruleArguments.forEach((opt: unknown, index: number) => {
if (index === 1 && isObject(opt)) {
if (index === 0 && isObject(opt)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This will be a breaking change. I thought that this might be side effect of migration to new rule format, however this behavior was in 6.0.0.
Looks like better solution is needed to avoid breaking change for those who added one more element to options array to match expected indices

@IllusionMH IllusionMH added Status: In Discussion Please continue discussing the proposed change before sending a pull request. Type: Breaking Change and removed PR: Waiting for Reviewer A repository maintainer should take a look at the pull request soon! labels Jul 22, 2019
@IllusionMH
Copy link
Contributor

I think that it might be possible to avoid breaking change with checks of structure check arguments length and then types arguments e.g. options.ruleArguments[0] is object, options.ruleArguments[1] is array, options.ruleArguments[2] is object (or null or undefined for elements that were skipped).
If not matched - check with shift by one element (to match current behavior in master).

@dosentmatter @JoshuaKGoldberg what do you think on about this approach? Is it possible to do it in general case? Is it worth to implement or better to consider earlier 7.0 with small scope?

@dosentmatter
Copy link
Author

dosentmatter commented Jul 22, 2019

Hey @IllusionMH, thanks for the review. I'll get to them when I have time. But I just want to respond to one of your comments first before I lose my train of thought.

I think that it might be possible to avoid breaking change with checks of structure check arguments length and then types arguments e.g. options.ruleArguments[0] is object, options.ruleArguments[1] is array, options.ruleArguments[2] is object (or null or undefined for elements that were skipped).
If not matched - check with shift by one element (to match current behavior in master).

@dosentmatter @JoshuaKGoldberg what do you think on about this approach? Is it possible to do it in general case? Is it worth to implement or better to consider earlier 7.0 with small scope?

I don't think it is possible to retain complete compatibility with the old code. The old code allowed element 0 to be any type, not just falsy values. It was completely ignored. So let's go over the case with a s length 1 options array:

[{}]
[true]
[undefined]
[null]
[{ 'React': 'react' }]
[{ 'Foo': './foo' }]

Although it is unlikely for someone to have an options array like this, all of these used to be ignored. If we now go and pass it to this.extractReplacements() because it is an object, it might break someone's linting. I looked at the code and ignoreExternalModule doesn't override the replacements, so React and Foo will be enforced.

However, maybe we can assume that not many people knew how to skip the 0th element. The base tslint.json just used true. The docs didn't explain it - are we required to maintain backward compatibility with an undocumented API? All the docs said was that you can pass in replacements to the 0th element, but it didn't work anyway because it was ignored. Searching up issues, I haven't seen anyone complain until #881, which was 15 days ago. In #881, I explained how to use the element skip workaround.

The only way you would know for sure to skip the 0th element is if you read the code, which is how I found it out.

@JoshuaKGoldberg
Copy link

Closing this PR per #876. It's always sad to see good work being closed, but we don't have the staffing or relevancy to take on more features. Thanks everyone!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Status: In Discussion Please continue discussing the proposed change before sending a pull request. Type: Breaking Change
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants