eslint-plugin-lob
Version:
Custom ESLint rules for Lob repositories
154 lines (124 loc) • 4.8 kB
JavaScript
;
var ERROR_MESSAGE = '{{error}} {{plural}} {{position}} equals for variable \'{{variable}}\'.';
function isDirectRequire (declaration) {
return declaration.init &&
declaration.init.type === 'CallExpression' &&
declaration.init.callee.name === 'require';
}
function isFunctionRequire (declaration) {
if (declaration.init && declaration.init.type === 'CallExpression') {
var callee = declaration.init.callee;
while (callee.type === 'CallExpression') {
callee = callee.callee;
}
return callee.name === 'require';
}
}
function isPropertyRequire (declaration) {
return declaration.init &&
declaration.init.type === 'MemberExpression' &&
declaration.init.object.type === 'CallExpression' &&
declaration.init.object.callee.name === 'require';
}
function isRequire (declaration) {
return isDirectRequire(declaration) || isPropertyRequire(declaration) || isFunctionRequire(declaration);
}
function isFactoryBuild (declaration) {
return declaration.init &&
declaration.init.type === 'CallExpression' &&
declaration.init.callee.object && declaration.init.callee.object.name && declaration.init.callee.object.name.indexOf('Factory') !== -1 &&
declaration.init.callee.property && declaration.init.callee.property.name === 'build';
}
function isPromisification (declaration) {
return declaration.init &&
declaration.init.type === 'CallExpression' &&
declaration.init.callee.object && declaration.init.callee.object.name === 'Bluebird' &&
declaration.init.callee.property &&
(declaration.init.callee.property.name === 'promisify' || declaration.init.callee.property.name === 'promisifyAll');
}
function shouldBeAligned (declaration) {
return isRequire(declaration) || isFactoryBuild(declaration) || isPromisification(declaration);
}
module.exports = {
meta: {
type: 'layout',
schema: []
},
create (ctx) {
var expectedEqualsLocations = [];
function getNextEqual (node) {
var sourceCode = ctx.sourceCode;
while (node && (node.type !== 'Punctuator' || node.value !== '=')) {
node = sourceCode.getTokenAfter(node);
}
return node;
}
function populateExpectedEqualsLocations (sourceNode) {
var declarations = sourceNode.parent.body.filter(function (node) {
var isDeclaration = node.type === 'VariableDeclaration';
var isInSourceBlock = node.loc.start.line >= sourceNode.loc.start.line;
return isDeclaration && isInSourceBlock && shouldBeAligned(node.declarations[0]);
});
var linesInBlock = [];
var prevNode;
var expectedEqualsLocation = declarations.reduce(function (maxLoc, node) {
if (prevNode && prevNode.loc.start.line + 1 < node.loc.start.line) {
return maxLoc;
}
linesInBlock.push(node.loc.start.line - 1);
prevNode = node;
var declaration = node.declarations[0];
var variableToken = declaration.id;
var newLoc = variableToken.loc.end.column + 1;
return maxLoc < newLoc ? newLoc : maxLoc;
}, 0);
linesInBlock.forEach(function (line) {
expectedEqualsLocations[line] = expectedEqualsLocation;
});
}
return {
VariableDeclaration (node) {
var sourceCode = ctx.sourceCode;
var declaration = node.declarations[0];
if (!shouldBeAligned(declaration)) {
return;
}
var variableToken = declaration.id;
var equalToken = getNextEqual(variableToken);
var nextToken = sourceCode.getTokenAfter(equalToken);
var line = variableToken.loc.start.line - 1;
if (typeof expectedEqualsLocations[line] === 'undefined') {
populateExpectedEqualsLocations(node);
}
var beforeDiff = equalToken.loc.start.column - expectedEqualsLocations[line];
if (beforeDiff !== 0) {
ctx.report({
node,
loc: equalToken.loc.start,
message: ERROR_MESSAGE,
data: {
error: beforeDiff > 0 ? 'Extra' : 'Missing',
plural: Math.abs(beforeDiff) === 1 ? 'space' : 'spaces',
position: 'before',
variable: variableToken.name
}
});
}
var afterDiff = nextToken.loc.start.column - (equalToken.loc.start.column + 2);
if (afterDiff !== 0) {
ctx.report({
node,
loc: nextToken.loc.start,
message: ERROR_MESSAGE,
data: {
error: afterDiff > 0 ? 'Extra' : 'Missing',
plural: Math.abs(afterDiff) === 1 ? 'space' : 'spaces',
position: 'after',
variable: variableToken.name
}
});
}
}
};
}
};