@coffeelint/cli
Version:
Lint your CoffeeScript
104 lines (89 loc) • 3.18 kB
JavaScript
(function() {
var MissingFatArrows,
indexOf = [].indexOf;
module.exports = MissingFatArrows = (function() {
class MissingFatArrows {
constructor() {
this.isCode = this.isCode.bind(this);
this.isClass = this.isClass.bind(this);
this.isValue = this.isValue.bind(this);
this.isObject = this.isObject.bind(this);
this.isFatArrowCode = this.isFatArrowCode.bind(this);
this.insideMethod = [false];
}
lintAST(node, astApi) {
this.astApi = astApi;
this.lintNode(node);
return void 0;
}
lintNode(node, methods = []) {
var error;
if (indexOf.call(methods, node) >= 0) {
this.insideMethod.push(true);
} else if (this.isClass(node)) {
this.insideMethod.push(false);
} else if ((this.isCode(node)) && this.insideMethod[this.insideMethod.length - 1] && !this.isFatArrowCode(node)) {
error = this.astApi.createError({
lineNumber: node.locationData.first_line + 1
});
this.errors.push(error);
}
node.eachChild((child) => {
return this.lintNode(child, (function() {
switch (false) {
case !this.isClass(node):
return this.methodsOfClass(node);
// Once we've hit a function, we know we can't be in the top
// level of a method anymore, so we can safely reset the methods
// to empty to save work.
case !this.isCode(node):
return [];
default:
return methods;
}
}).call(this));
});
if (indexOf.call(methods, node) >= 0 || this.isClass(node)) {
return this.insideMethod.pop();
}
}
isCode(node) {
return this.astApi.getNodeName(node) === 'Code';
}
isClass(node) {
return this.astApi.getNodeName(node) === 'Class';
}
isValue(node) {
return this.astApi.getNodeName(node) === 'Value';
}
isObject(node) {
return this.astApi.getNodeName(node) === 'Obj';
}
isFatArrowCode(node) {
return this.isCode(node) && node.bound;
}
methodsOfClass(classNode) {
var bodyNodes, returnNode;
bodyNodes = classNode.body.expressions;
returnNode = bodyNodes[bodyNodes.length - 1];
if ((returnNode != null) && this.isValue(returnNode) && this.isObject(returnNode.base)) {
return returnNode.base.properties.map(function(assignNode) {
return assignNode.value;
}).filter(this.isCode);
} else {
return [];
}
}
};
MissingFatArrows.prototype.rule = {
type: 'style',
name: 'prefer_fat_arrows_in_methods',
level: 'ignore',
message: 'Require fat arrows inside method bodies',
description: `Warns when you do not use a fat arrow for functions defined inside
method bodies. This assures that \`this\` is always bound to the
method's object inside the code block of a method.`
};
return MissingFatArrows;
}).call(this);
}).call(this);