eslint-traverser
Version:
A utility that helps traverse code the way ESLint does
129 lines (111 loc) • 4.1 kB
JavaScript
;
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
var uniqueId = require('lodash/uniqueId');
var iteratee = require('lodash/iteratee');
var constant = require('lodash/constant');
var isFunction = require('lodash/isFunction');
var noop = require('lodash/noop');
var mapValues = require('lodash/mapValues');
var assign = require('lodash/assign');
var every = require('lodash/every');
function throwMessage(message) {
throw Error(message);
}
var MISSING_TYPE = 'Missing mandatory parameter - type - Must be a String';
var MISSING_CB = 'Missing mandatory parameter - cb - Must be a Function';
var getRestParams = function getRestParams(rest) {
var cb = rest.pop();
if (!isFunction(cb)) {
throwMessage(MISSING_CB);
}
var matches = iteratee(rest.pop() || constant(true));
return { cb: cb, matches: matches };
};
var runOneTimeRule = function runOneTimeRule(code, config, rule) {
var linter = require('eslint').linter;
var ruleId = uniqueId();
linter.defineRule(ruleId, rule);
var actualConfig = assign({}, config, {
rules: _defineProperty({}, ruleId, 2),
parserOptions: assign({
ecmaVersion: 6
}, config.parserOptions)
});
linter.verify(code, actualConfig);
};
var runOneTimeRuleForType = function runOneTimeRuleForType(code, config, type, logic) {
runOneTimeRule(code, config, function (context) {
return _defineProperty({}, type, function (node) {
logic(node, context);
});
});
};
function isParserOption(key) {
return key === 'ecmaVersion' || key === 'sourceType' || key === 'ecmaFeatures';
}
function isOnlyParserOptions(config) {
return every(Object.keys(config), isParserOption);
}
module.exports = function (code) {
var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
if (isOnlyParserOptions(config)) {
config = { parserOptions: config };
}
if (!code) {
throw Error('Code must be a string.');
}
if (config.rules) {
throw Error('Do not specify rules in the config.');
}
return {
get: function get() {
var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : throwMessage(MISSING_TYPE);
for (var _len = arguments.length, rest = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
rest[_key - 1] = arguments[_key];
}
var _getRestParams = getRestParams(rest);
var cb = _getRestParams.cb;
var matches = _getRestParams.matches;
runOneTimeRuleForType(code, config, type, function (node, context) {
if (matches(node)) {
cb(node, context);
}
});
},
first: function first() {
var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : throwMessage(MISSING_TYPE);
for (var _len2 = arguments.length, rest = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
rest[_key2 - 1] = arguments[_key2];
}
var _getRestParams2 = getRestParams(rest);
var cb = _getRestParams2.cb;
var matches = _getRestParams2.matches;
var found = false;
runOneTimeRuleForType(code, config, type, function (node, context) {
if (matches(node) && !found) {
found = true;
cb(node, context);
}
});
},
runRuleCode: function runRuleCode(rule) {
runOneTimeRule(code, config, rule);
},
visitAll: function visitAll() {
var visitors = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var cb = arguments[1];
if (!isFunction(cb)) {
throwMessage(MISSING_CB);
}
var origExitVisitor = visitors['Program:exit'] || noop;
runOneTimeRule(code, config, function (context) {
return assign({}, visitors, {
'Program:exit': function ProgramExit(node) {
origExitVisitor(node);
cb(node, context);
}
});
});
}
};
};