上节对eslint的配置进行了详细的解释,这节再来对源码进行分析一波。
执行eslint的流程图如下:
eslint的入口:eslint/bin/eslint.js#main
eslint.js是命令的执行文件,用来启动eslint,并向cli传递命令行参数。
...
await require("../lib/cli").execute(
process.argv, // 命令行eslint后面的参数
process.argv.includes("--stdin") ? await readStdin() : null // eslint命令行是否有--stdin,执行process.stdin读取需lint的内容
);
eslint/lib/cli.js#execute
cli.js#execute是eslint的核心,它解析eslint执行命令,调用有效的操作。它还扮演着读取文件、遍历目录,输入和输出的角色。
function execute(args, text) {
let options;
try {
options = CLIOptions.parse(args); // 解析eslint options
} catch (error) {
...
}
...
/**
* translateOptions(options) // 将cli options转换为cli-engine options
*
* engine是Eslint的实例,可以用eslint的API。
*
**/
const engine = new ESLint(translateOptions(options));
let results;
/**
* eslint --stdin的优先级高
**/
if (useStdin) {
results = await engine.lintText(text, {
filePath: options.stdinFilename,
warnIgnored: true
});
} else {
results = await engine.lintFiles(files);
}
if (options.fix) {
...
await ESLint.outputFixes(results); // 执行fix
}
if (options.quiet) {
...
results = ESLint.getErrorResults(results); // 执行quite
}
/**
* printResults 打印错误信息
**/
if (await printResults(engine, results, options.format, options.outputFile)) {
...
}
...
}
eslint/lib/eslint/eslint.js
eslint构造函数实例化cli-engine,并将cli-engine存储为私有属性。通过cli-engine封装一系列的API。
class ESLint {
/**
* Creates a new instance of the main ESLint API.
* @param {ESLintOptions} options The options for this instance.
*/
constructor(options = {
}) {
const processedOptions = processOptions(options); // 校验cli-engine options,返回标准的options
const cliEngine = new CLIEngine(processedOptions); // 获取cli-engine
...
// 初始化私有属性
privateMembersMap.set(this, {
cliEngine,
options: processedOptions
});
}
...
/**
* 修复有问题的文件
*/
static async outputFixes(results) {
await Promise.all(
results
.filter(result => {
if (typeof result !== "object" || result === null) {
throw new Error("'results' must include only objects");
}
return (
typeof result.output === "string" &&
path.isAbsolute(result.filePath)
);
})
.map(r => writeFile(r.filePath, r.output))
);
}
...
/**
* 根据配置执行需要检测的文件
* 返回检测结果
*/
async lintFiles(patterns) {
...
const {
cliEngine } = privateMembersMap.get(this);
return processCLIEngineLintReport(
cliEngine,
cliEngine.executeOnFiles(patterns)
);
}
/**
* 根据配置执行需要检测的文本
* 返回检测结果
*/
async lintText(code, options = {
}) {
...
const {
cliEngine } = privateMembersMap.get(this);
return processCLIEngineLintReport(
cliEngine,
cliEngine.executeOnText(code, filePath, warnIgnored)
);
}
/**
* 加载formatter
*/
async loadFormatter(name = "stylish") {
...
const {
cliEngine } = privateMembersMap.get(this);
const formatter