-
Notifications
You must be signed in to change notification settings - Fork 34
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
Updated no-broken-super-chain
rule to account for more lifecycle hooks …
#94
base: master
Are you sure you want to change the base?
Conversation
…nd more object types
no-broken-super-chain
rule[ to account for more lifecycle hooks …no-broken-super-chain
rule to account for more lifecycle hooks …
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.
Looking good! I left some notes inline with suggested cleanups to make, and I think we need a few more test cases to cover those things.
I'd suggest the following additional test cases:
- valid
Foo.extend(SomeMixin)
Foo.extend(SomeMixin, { init() { this._super(...arguments) } })
Foo.extend({ [
lol]: function() {})
lib/rules/no-broken-super-chain.js
Outdated
} | ||
} | ||
extendedObjects.forEach(extendedObj => { | ||
extendedObj.properties.forEach(property => { |
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 need to guard for extendedObj.properties
being undefined here (or filter out non ObjectExpression
s before .forEach
ing).
I believe the following test should be added (which will fail ATM but pass if we filtered non ObjectExpressions):
Foo.extend(SomeMixin, {
init() {
this._super(...arguments);
}
});
I'd suggest either of the following:
extendedObjects = node.arguments.filter(arg => arg.type === 'ObjectExpression');
// or
extendedObjects.forEach(extendedObj => {
if (extendedObj.type !== 'ObjectExpression') { return; }
// ...snip...
});
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 would also suggest adding a test case for this.
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.
Updated, and added test.
lib/rules/no-broken-super-chain.js
Outdated
} | ||
CallExpression(node) { | ||
if (isExtend(node)) { | ||
let superCount = 0; |
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.
Seems like this variable should be initialized from inside the extendedObjects.forEach
loop (then you wouldn't need to reset it to 0 at the end of the loop).
lib/rules/no-broken-super-chain.js
Outdated
|
||
if (propertyFnBody && propertyFnBody.body) { | ||
let expression; | ||
property.value.body.body.forEach(fnBody => { |
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 should likely use propertyFnBody.body
instead of property.value.body.body.forEach
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.
Can you rename fnBody
to expressionStatement
?
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.
- Correct. 2. Gladly
lib/rules/no-broken-super-chain.js
Outdated
property.value.body.body.forEach(fnBody => { | ||
expression = fnBody.expression; | ||
if (expression.type === 'CallExpression') { | ||
const line = expression.callee; |
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.
line
isn't super descriptive, maybe call this callee
?
lib/rules/no-broken-super-chain.js
Outdated
}); | ||
} | ||
|
||
superCount = 0; |
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 shouldn't be needed, we should initialize superCount
inside the loop...
lib/rules/no-broken-super-chain.js
Outdated
return firstArgumentToSuper && firstArgumentToSuper.type === 'SpreadElement' && firstArgumentToSuper.argument.name === 'arguments'; | ||
} else if (callee.property.name === 'apply') { | ||
const args = expression.arguments; | ||
return args.length >= 2 && args[0].type === 'ThisExpression' && args[1].name === 'arguments'; |
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.
When would args
be > 2
? I think we want args.length === 2
...
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.
+1
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.
Yeah, not sure what I had in mind here
lib/rules/no-broken-super-chain.js
Outdated
} | ||
|
||
module.exports = { | ||
meta: { | ||
docs: { | ||
description: 'Prevent the absence of `this._super(...arguments)` in `init()` calls or the use of `this` prior to `this._super()`', | ||
description: 'Prevent the absence of `this._super(...arguments)` in calls to various lifecycle hooks or the use of `this` prior to `this._super()`', |
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.
or the use of
this
prior tothis._super()
I don't think we do this at the moment, do we? I don't see the code that does it at least...
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.
good catch, also updated file description
lib/rules/no-broken-super-chain.js
Outdated
Controller: true, | ||
View: true | ||
}; | ||
const LIFECYCLE_HOOKS = ['init', 'willDestroy', 'willDestroyElement', 'destroy']; |
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.
@rwjblue to be 100% safe, I think we should add all life cycle hooks here. Otherwise, we have no guarantee that mixins will work as expected.
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.
Ya, makes sense. Do we have a canonical list?
I guess we can start with the ones listed in https://guides.emberjs.com/v2.16.0/components/the-component-lifecycle/...
lib/rules/no-broken-super-chain.js
Outdated
return firstArgumentToSuper && firstArgumentToSuper.type === 'SpreadElement' && firstArgumentToSuper.argument.name === 'arguments'; | ||
} else if (callee.property.name === 'apply') { | ||
const args = expression.arguments; | ||
return args.length >= 2 && args[0].type === 'ThisExpression' && args[1].name === 'arguments'; |
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.
+1
lib/rules/no-broken-super-chain.js
Outdated
} | ||
} | ||
extendedObjects.forEach(extendedObj => { | ||
extendedObj.properties.forEach(property => { |
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 would also suggest adding a test case for this.
return node && node.callee && node.callee.property && node.callee.property.name === 'extend'; | ||
} | ||
|
||
function isSuperCall(lineWithinFn) { |
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.
One more case we need to handle is:
Foo.extend({
init() {
return this._super(...argument);
}
});
This ^ is valid, the linting rule should not complain about it.
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.
Great catch. Updated to: expression = expressionStatement.type === 'ReturnStatement' ? expressionStatement.argument : expressionStatement.expression;
} | ||
});`, | ||
errors: [{ | ||
message: noThisBeforeSuper |
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.
Let’s remove this TODO commented test.
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.
When we add a rule about no this before super we will probably make it a new more focused rule anyways.
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.
Removed TODO
lib/rules/no-broken-super-chain.js
Outdated
Controller: true, | ||
View: true | ||
}; | ||
const LIFECYCLE_HOOKS = ['init', 'willDestroy', 'willDestroyElement', 'destroy']; |
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.
Ya, makes sense. Do we have a canonical list?
I guess we can start with the ones listed in https://guides.emberjs.com/v2.16.0/components/the-component-lifecycle/...
…and more object types. The rule now checks any object that's using
extend
, and validates theinit
,willDestroy
,destroy
andwillDestroyElement
hooks. In addition, I updated the rule to validate thatarguments
were correctly passed to the super call. Both of the below pass the rule:this._super(...arguments);
this._super.apply(this, arguments)