Refactored rules
This commit is contained in:
5
rules/.eslintrc
Normal file
5
rules/.eslintrc
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"env": {
|
||||
"es6": true
|
||||
}
|
||||
}
|
||||
8
rules/index.js
Normal file
8
rules/index.js
Normal file
@@ -0,0 +1,8 @@
|
||||
module.exports = {
|
||||
rules: {
|
||||
'no-duplicate-requires': require('./no-duplicate-requires').rule,
|
||||
'no-unused-requires': require('./no-unused-requires').rule,
|
||||
'requires-first': require('./requires-first').rule,
|
||||
'valid-requires': require('./valid-requires').rule
|
||||
}
|
||||
};
|
||||
46
rules/no-duplicate-requires.js
Normal file
46
rules/no-duplicate-requires.js
Normal file
@@ -0,0 +1,46 @@
|
||||
const util = require('./util');
|
||||
|
||||
exports.rule = {
|
||||
meta: {
|
||||
docs: {
|
||||
description: 'disallow duplicate goog.require() calls'
|
||||
},
|
||||
fixable: 'code'
|
||||
},
|
||||
|
||||
create: function(context) {
|
||||
const alreadyRequired = {};
|
||||
|
||||
return {
|
||||
ExpressionStatement: function(statement) {
|
||||
if (util.isRequireStatement(statement)) {
|
||||
const expression = statement.expression;
|
||||
|
||||
if (!expression.arguments[0]) {
|
||||
return;
|
||||
}
|
||||
const name = expression.arguments[0].value;
|
||||
|
||||
if (alreadyRequired[name]) {
|
||||
const source = context.getSourceCode();
|
||||
|
||||
return context.report({
|
||||
node: statement,
|
||||
message: `Duplicate goog.require('${name}')`,
|
||||
fix: function(fixer) {
|
||||
const afterToken = source.getTokenAfter(statement);
|
||||
const range = [
|
||||
statement.range[0],
|
||||
afterToken ? afterToken.range[0] : statement.range[1]
|
||||
];
|
||||
return fixer.removeRange(range);
|
||||
}
|
||||
});
|
||||
}
|
||||
alreadyRequired[name] = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
};
|
||||
111
rules/no-unused-requires.js
Normal file
111
rules/no-unused-requires.js
Normal file
@@ -0,0 +1,111 @@
|
||||
const util = require('./util');
|
||||
|
||||
function getName(node) {
|
||||
if (node.type !== 'MemberExpression') {
|
||||
return;
|
||||
}
|
||||
if (node.property.type !== 'Identifier' || node.property.computed) {
|
||||
return;
|
||||
}
|
||||
let objectName;
|
||||
if (node.object.type === 'Identifier' && !node.object.computed) {
|
||||
objectName = node.object.name;
|
||||
} else if (node.object.type === 'MemberExpression' && !node.object.computed) {
|
||||
objectName = getName(node.object);
|
||||
}
|
||||
if (!objectName) {
|
||||
return;
|
||||
}
|
||||
return `${objectName}.${node.property.name}`;
|
||||
}
|
||||
|
||||
exports.rule = {
|
||||
meta: {
|
||||
docs: {
|
||||
description: 'disallow unused goog.require() calls'
|
||||
},
|
||||
fixable: 'code'
|
||||
},
|
||||
|
||||
create: function(context) {
|
||||
|
||||
// a lookup of goog.require() nodes by argument
|
||||
const requireStatements = {};
|
||||
|
||||
// used names from member expressions that match the goog.require() arg
|
||||
const usedNames = {};
|
||||
|
||||
return {
|
||||
|
||||
ExpressionStatement: function(statement) {
|
||||
if (util.isRequireStatement(statement)) {
|
||||
const expression = statement.expression;
|
||||
const arg = expression.arguments[0];
|
||||
if (!arg || !arg.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
const name = arg.value;
|
||||
const ancestors = context.getAncestors();
|
||||
const parent = ancestors[ancestors.length - 1];
|
||||
if (!parent) {
|
||||
return;
|
||||
}
|
||||
|
||||
requireStatements[name] = statement;
|
||||
}
|
||||
},
|
||||
|
||||
MemberExpression: function(node) {
|
||||
const name = getName(node);
|
||||
if (name in requireStatements) {
|
||||
const requiredAncestor = context.getAncestors().some(ancestorNode => !!requireStatements[getName(ancestorNode)]);
|
||||
if (!requiredAncestor) {
|
||||
usedNames[name] = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Identifier: function(node) {
|
||||
const name = node.name;
|
||||
if (name in requireStatements) {
|
||||
const ancestors = context.getAncestors();
|
||||
if (ancestors.length && ancestors[0].type === 'MemberExpression') {
|
||||
const requiredAncestor = context.getAncestors().some(ancestorNode => !!requireStatements[getName(ancestorNode)]);
|
||||
if (!requiredAncestor) {
|
||||
usedNames[name] = true;
|
||||
}
|
||||
} else {
|
||||
usedNames[name] = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
'Program:exit': function(node) {
|
||||
const source = context.getSourceCode();
|
||||
|
||||
for (let name in requireStatements) {
|
||||
|
||||
if (!usedNames[name]) {
|
||||
const unusedRequire = requireStatements[name];
|
||||
|
||||
context.report({
|
||||
node: unusedRequire,
|
||||
message: `Unused ${source.getText(unusedRequire)}`,
|
||||
fix: function(fixer) {
|
||||
const afterToken = source.getTokenAfter(unusedRequire);
|
||||
const range = [
|
||||
unusedRequire.range[0],
|
||||
afterToken ? afterToken.range[0] : unusedRequire.range[1]
|
||||
];
|
||||
return fixer.removeRange(range);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
};
|
||||
6
rules/package.json
Normal file
6
rules/package.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "eslint-plugin-openlayers-internal",
|
||||
"version": "1.0.0",
|
||||
"description": "Custom ESLint rules for the OpenLayers project",
|
||||
"main": "index.js"
|
||||
}
|
||||
28
rules/requires-first.js
Normal file
28
rules/requires-first.js
Normal file
@@ -0,0 +1,28 @@
|
||||
const util = require('./util');
|
||||
|
||||
exports.rule = {
|
||||
meta: {
|
||||
docs: {
|
||||
description: 'require that all goog.require() precede other statements (except goog.provide())'
|
||||
}
|
||||
},
|
||||
|
||||
create: function(context) {
|
||||
return {
|
||||
Program: function(program) {
|
||||
let otherSeen = false;
|
||||
|
||||
program.body.forEach(statement => {
|
||||
if (util.isRequireStatement(statement)) {
|
||||
if (otherSeen) {
|
||||
return context.report(statement, 'Expected goog.require() to precede other statements');
|
||||
}
|
||||
} else if (!util.isProvideStatement(statement)) {
|
||||
otherSeen = true;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
28
rules/util.js
Normal file
28
rules/util.js
Normal file
@@ -0,0 +1,28 @@
|
||||
function isGoogCallExpression(node, name) {
|
||||
const callee = node.callee;
|
||||
return callee && callee.type === 'MemberExpression' &&
|
||||
callee.object.type === 'Identifier' && callee.object.name === 'goog' &&
|
||||
callee.property.type === 'Identifier' && !callee.property.computed &&
|
||||
callee.property.name === name;
|
||||
}
|
||||
|
||||
function isGoogStatement(node, name) {
|
||||
return node.expression && node.expression.type === 'CallExpression' &&
|
||||
isGoogCallExpression(node.expression, name);
|
||||
}
|
||||
|
||||
exports.isProvideExpression = function(node) {
|
||||
return isGoogCallExpression(node, 'provide');
|
||||
};
|
||||
|
||||
exports.isProvideStatement = function(node) {
|
||||
return isGoogStatement(node, 'provide');
|
||||
};
|
||||
|
||||
exports.isRequireExpression = function(node) {
|
||||
return isGoogCallExpression(node, 'require');
|
||||
};
|
||||
|
||||
exports.isRequireStatement = function(node) {
|
||||
return isGoogStatement(node, 'require');
|
||||
};
|
||||
36
rules/valid-requires.js
Normal file
36
rules/valid-requires.js
Normal file
@@ -0,0 +1,36 @@
|
||||
const util = require('./util');
|
||||
|
||||
exports.rule = {
|
||||
meta: {
|
||||
docs: {
|
||||
description: 'require that all goog.require() have a valid arg and appear at the top level'
|
||||
}
|
||||
},
|
||||
|
||||
create: function(context) {
|
||||
return {
|
||||
CallExpression: function(expression) {
|
||||
if (util.isRequireExpression(expression)) {
|
||||
const ancestors = context.getAncestors();
|
||||
const parent = ancestors[ancestors.length - 1];
|
||||
if (parent.type !== 'ExpressionStatement') {
|
||||
return context.report(expression, 'Expected goog.require() to in an expression statement');
|
||||
}
|
||||
|
||||
if (ancestors.length !== 2) {
|
||||
return context.report(expression, 'Expected goog.require() to be at the top level');
|
||||
}
|
||||
|
||||
if (expression.arguments.length !== 1) {
|
||||
return context.report(expression, 'Expected one argument for goog.require()');
|
||||
}
|
||||
|
||||
const arg = expression.arguments[0];
|
||||
if (arg.type !== 'Literal' || !arg.value || typeof arg.value !== 'string') {
|
||||
return context.report(expression, 'Expected goog.require() to be called with a string');
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user