-
Notifications
You must be signed in to change notification settings - Fork 33
/
rule-finder.js
150 lines (120 loc) · 4.86 KB
/
rule-finder.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
const path = require('path');
const { ESLint, Linter } = require('eslint');
const glob = require('glob');
const difference = require('./array-diff');
const getSortedRules = require('./sort-rules');
const normalizePluginName = require('./normalize-plugin-name');
function _getConfigFile(specifiedFile) {
if (specifiedFile) {
if (path.isAbsolute(specifiedFile)) {
return specifiedFile;
}
return path.join(process.cwd(), specifiedFile);
}
// This is not being called with an arg. Use the package.json `main`
return require(path.join(process.cwd(), 'package.json')).main;
}
async function _getConfigs(overrideConfigFile, files) {
const esLint = new ESLint({
// Ignore any config applicable depending on the location on the filesystem
useEslintrc: false,
// Point to the particular config
overrideConfigFile
});
const configs = files.map(async filePath => (
await esLint.isPathIgnored(filePath) ? false : esLint.calculateConfigForFile(filePath)
));
return new Set((await Promise.all(configs)).filter(Boolean));
}
async function _getConfig(configFile, files) {
return Array.from(await _getConfigs(configFile, files)).reduce((prev, item) => {
return Object.assign(prev, item, {
rules: Object.assign({}, prev.rules, item.rules),
plugins: [...new Set([].concat(prev.plugins || [], item.plugins || []))]
});
}, {});
}
function _getCurrentNamesRules(config) {
return config.rules ? Object.keys(config.rules) : [];
}
function _isDeprecated(rule) {
return rule && rule.meta && rule.meta.deprecated;
}
function _notDeprecated(rule) {
return !_isDeprecated(rule);
}
function _getPluginRules(config) {
const pluginRules = new Map();
const plugins = config.plugins;
/* istanbul ignore else */
if (plugins) {
plugins.forEach(plugin => {
const normalized = normalizePluginName(plugin);
const pluginConfig = require(normalized.module);
const rules = pluginConfig.rules === undefined ? {} : pluginConfig.rules;
Object.keys(rules).forEach(ruleName =>
pluginRules.set(`${normalized.prefix}/${ruleName}`, rules[ruleName])
);
});
}
return pluginRules;
}
function _getCoreRules() {
return new Linter().getRules();
}
function _filterRuleNames(ruleNames, rules, predicate) {
return ruleNames.filter(ruleName => predicate(rules.get(ruleName)));
}
function _isNotCore(rule) {
return rule.indexOf('/') !== '-1';
}
function _escapeRegExp(str) {
return str.replace(/[\\^$.*+?()[\]{}|]/g, '\\$&');
}
function _createExtensionRegExp(extensions) {
const normalizedExts = extensions.map(ext => _escapeRegExp(
ext.startsWith('.') ? ext.slice(1) : ext
));
return new RegExp(`.\\.(?:${normalizedExts.join("|")})$`);
}
function RuleFinder(config, {omitCore, includeDeprecated}) {
let currentRuleNames = _getCurrentNamesRules(config);
if (omitCore) {
currentRuleNames = currentRuleNames.filter(_isNotCore);
}
const pluginRules = _getPluginRules(config); // eslint-disable-line vars-on-top
const coreRules = _getCoreRules();
const allRules = omitCore ? pluginRules : new Map([...coreRules, ...pluginRules]);
let allRuleNames = [...allRules.keys()];
let pluginRuleNames = [...pluginRules.keys()];
if (!includeDeprecated) {
allRuleNames = _filterRuleNames(allRuleNames, allRules, _notDeprecated);
pluginRuleNames = _filterRuleNames(pluginRuleNames, pluginRules, _notDeprecated);
}
const deprecatedRuleNames = _filterRuleNames(currentRuleNames, allRules, _isDeprecated);
const dedupedRuleNames = [...new Set(allRuleNames)];
const unusedRuleNames = difference(dedupedRuleNames, currentRuleNames);
// Get all the current rules instead of referring the extended files or documentation
this.getCurrentRules = () => getSortedRules(currentRuleNames);
// Get all the current rules' particular configuration
this.getCurrentRulesDetailed = () => config.rules;
// Get all the plugin rules instead of referring the extended files or documentation
this.getPluginRules = () => getSortedRules(pluginRuleNames);
// Get all the available rules instead of referring eslint and plugin packages or documentation
this.getAllAvailableRules = () => getSortedRules(dedupedRuleNames);
this.getUnusedRules = () => getSortedRules(unusedRuleNames);
// Get all the current rules that are deprecated
this.getDeprecatedRules = () => getSortedRules(deprecatedRuleNames);
}
async function createRuleFinder(specifiedFile, options) {
const configFile = _getConfigFile(specifiedFile);
const {ext = ['.js']} = options;
const extensionRegExp = _createExtensionRegExp(ext);
const files = glob.sync(`**/*`, {dot: true, matchBase: true})
.filter(file => extensionRegExp.test(file));
const config = await _getConfig(configFile, files);
return new RuleFinder(config, options);
}
module.exports = async function (specifiedFile, options = {}) {
return createRuleFinder(specifiedFile, options);
};