-
-
Notifications
You must be signed in to change notification settings - Fork 210
Do not autofix self-referential computed properties in require-computed-macros rule
#1121
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
base: master
Are you sure you want to change the base?
Conversation
require-computed-macros rule
| const isNotFixable = detectCircularKey(nodeComputedProperty, [text]); | ||
|
|
||
| if (isNotFixable) { | ||
| context.report({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of duplicating the context.report call, we should actually just return null inside the fixer function if we encounter a non-fixable situation. That goes for all these reporting functions and it will simplify all this code a lot.
fix(fixer) {
if (!isFixable(...)) { return null; }
...
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bmish I did that initially but it is linted against, I also suspect it's not good practice since it might cause eslint to report the violation as fixable when it is not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not linted against, we actually have some examples of autofixers with return null in our codebase. And it's not bad practice, in fact it's common practice to have autofixers which ignore certain situations, and this is how we do it. I can assure you it will result in much simpler code :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this was the lint rule it triggered https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/fixer-return.md
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using return null won't trigger that rule. return null indicates that you don't want to autofix in a particular situation.
| { | ||
| code: 'class Test { @computed() get foo() { return this.foo; } }', | ||
| options: [{ includeNativeGetters: true }], | ||
| output: 'class Test { @computed() get foo() { return this.foo; } }', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should use output: null to indicate there's no autofix, it's more clear and concise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wouldn't that imply the rule was deleting code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No. It means there's no autofix.
And there's actually a lint rule to enforce this but unfortunately it's not working on this code because the array of test cases has .map(addComputedImport) on it.
| errors: [{ message: ERROR_MESSAGE_MAP_BY, type: 'MethodDefinition' }], | ||
| }, | ||
|
|
||
| // Self Referential |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we're adding a few redundant test cases as well as missing some test cases.
We need the following test cases basic test cases which test a simple single-arg return expression that will be converted into the reads macro:
class Test { @computed() get foo() { return this.foo; } }class Test { foo = computed(function() { return this.foo; }) }// non-decorator styleimport EmberObject from '@ember/object'; EmberObject.extend({ foo: computed(function() { return this.foo; }) }// classic class
And we need to test other types of expressions that will be converted into other macros:
class Test { @computed() get a() { return this.a && this.b; } }// logical
*class Test { @computed() get a() { return this.a > this.b; } }// binary
*import EmberObject from '@ember/object'; EmberObject.extend({ computed(function() { return this.chores.filterBy('done', true); })// function
We don't need to test anything related to the dependent key arguments (computed('this-dependent-key-does-not-matter', function () {})) since those end up ignored anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The redundancy is intentional, it covers both forms of classic and both forms of class based declarations both with and without args being supplied to the computed as dependent keys (since I encountered errors from conversion from both in the wild).
Can add tests for a few of the others.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good. A comment next to each test case explaining what variation it is testing would help.
| } | ||
|
|
||
| function detectCircularKey(node, macroArgs) { | ||
| if (node.parent && node.parent.key) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There should always be a parent, but we do need to check what node type the parent is before we check its key. That way, we won't end up using the key of some unexpected kind of node.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oddly I believe I encountered a no parent situation in our own test suite. Will double check that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ESLint adds the parent when it runs the rule test cases. But if you write separate unit tests for this function by itself, then it won't have a parent. So feel free to add the parent guard but you only need if you write separate unit tests for the function itself.
partially resolves #1118 (we should still add a new rule)