自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

為什么 Eslint 可以檢查和修復(fù)格式問(wèn)題,而 Babel

開(kāi)發(fā) 項(xiàng)目管理
Eslint 可以檢查出代碼中的錯(cuò)誤和一些格式問(wèn)題,并能自動(dòng)修復(fù),它的實(shí)現(xiàn)原理就是基于 AST (抽象語(yǔ)法樹(shù))。

Eslint 可以檢查出代碼中的錯(cuò)誤和一些格式問(wèn)題,并能自動(dòng)修復(fù),它的實(shí)現(xiàn)原理就是基于 AST (抽象語(yǔ)法樹(shù))。

通過(guò) Parser 把源碼解析成 AST 對(duì)象樹(shù),源碼字符串中的各種信息就被保存到了這個(gè)對(duì)象樹(shù)里,然后遍歷 AST,對(duì)每一部分做檢查就能實(shí)現(xiàn) Lint 的功能,而自動(dòng) fix 的功能則是基于字符串替換實(shí)現(xiàn)的,指定某一段 range,替換成另一段文本即可。

說(shuō)起來(lái),Babel 也是基于 AST 實(shí)現(xiàn)的代碼分析和轉(zhuǎn)換,但是卻不能檢查和修復(fù)格式的問(wèn)題,這是為什么呢?為什么 Eslint 可以檢查格式而 Babel 不可以呢?

我們先寫一個(gè) Eslint 的 rule

來(lái)感受下 Eslint 是怎么檢查和修復(fù)格式問(wèn)題的。

Eslint 檢查格式的 rule大括號(hào)有兩種主流寫法,一種是同一行寫:

if (name === 'guang') {
}

另一種是新開(kāi)一行寫:

if (name === 'guang')
{
}

我們寫一個(gè) eslint 的 rule 來(lái)檢查大括號(hào)的格式并自動(dòng)修復(fù)成同一行的格式。

思路分析

Eslint 的檢查是基于 AST,我們要檢查的 AST 是塊語(yǔ)句 BlockStatement。

關(guān)于什么代碼是什么 AST 可以用 astexplorer.net 可視化的查看,parser 選擇 espree (Eslint 默認(rèn)的 parser):

具體來(lái)說(shuō)檢查的是 BlockStatement 的最開(kāi)始的 token { 的行號(hào),是不是和它前一個(gè) token 在同一行。(token 是指最小的不可再細(xì)分的單詞,比如關(guān)鍵字、變量名等標(biāo)識(shí)符、各種分隔符等)

如果是同一行,則說(shuō)明了是符合規(guī)范的。當(dāng)然我們還可以進(jìn)一步檢查一下大括號(hào) { 和前一個(gè) token 之間有沒(méi)有空格。

思路理清了,我們來(lái)寫下代碼:

代碼實(shí)現(xiàn)

Eslint 的 rule 的格式是這樣的:

 module.exports = {
meta: {
docs: {
description: "enforce consistent brace style for blocks"
},

fixable: true
},

create(context) {
return {
BlockStatement(node) {
}
}
}
};

分為 meta 和 create 兩部分:

  • meta:描述各種元信息,比如文檔描述、是否可自動(dòng)修復(fù)等
  • create:實(shí)現(xiàn)對(duì)各種 AST 檢查的代碼,rule 的主體部分

我們?cè)?create 里聲明了對(duì) BlockStatement 節(jié)點(diǎn)的檢查,它的參數(shù)就是對(duì)應(yīng)的節(jié)點(diǎn)對(duì)象。

但是我們要檢查的是 token,這個(gè)用 context 里的一個(gè) api:

create(context) {
const sourceCode = context.getSourceCode();
return {
BlockStatement(node) {
const firstToken = sourceCode.getFirstToken(node);
const beforFirstToken = sourceCode.getTokenBefore(node);
}
}
}

我們從 context 中拿到了 sourceCode 的 api,它就是用來(lái)取 token 的。

我們用 getFirstToken 拿到了當(dāng)前 node 的開(kāi)始 token,也就是 {,

然后又拿到了當(dāng)前 node 的前面一個(gè)節(jié)點(diǎn)的 token,也就是 (:

token 中保存了行列號(hào)信息,那么對(duì)比下行列號(hào)就知道是否有格式問(wèn)題了:

如果 { 所在的行和 ) 所在的行不是同一行,就報(bào)錯(cuò)

if (firstToken.loc.start.line !== beforFirstToken.loc.start.line) {
context.report({
node,
loc: firstToken.loc,
message: '大括號(hào)格式不對(duì)'
});
}

修復(fù)的方式自然就是把 { 和 ) 之間的部分替換成一個(gè)空格,這個(gè)使用 fixer 提供的 api:replaceTextRange:

if (firstToken.loc.start.line !== beforFirstToken.loc.start.line) {
context.report({
node,
loc: firstToken.loc,
message: '大括號(hào)格式不對(duì)'
fix: fixer => {
return fixer.replaceTextRange([beforFirstToken.range[1], firstToken.range[0]], ' ');
}
});
}

同理,也可以檢查出 { 和 ) 之間沒(méi)有空格的格式錯(cuò)誤,修復(fù)方式一樣:

if (firstToken.loc.start.column === beforFirstToken.loc.start.column + 1){
context.report({
node,
loc: firstToken.loc,
message: '大括號(hào)前缺少空格',
fix: fixer => {
return fixer.replaceTextRange([beforFirstToken.range[1], firstToken.range[0]], ' ');
}
});
}

這樣就實(shí)現(xiàn)了大括號(hào)格式的檢查和自動(dòng)修復(fù)。

我們來(lái)試下效果:

測(cè)試 rule

Eslint 除了提供命令行外,也提供了 api,我們調(diào)用它的 api 來(lái)測(cè)試 rule:

先創(chuàng)建 ESLint 對(duì)象,指定 rulePaths 也就是查找 rule 的目錄為當(dāng)前目錄:

const { ESLint } = require("eslint");

const engine = new ESLint({
fix: false,
overrideConfig: {
parserOptions: {
ecmaVersion: 6,
},
rules: {
'my-brace-style': ['error']
}
},
rulePaths: [__dirname],
useEslintrc: false
});

useEslintrc 為 false 是不查找配置文件, fix 為 false 是不自動(dòng)修復(fù)。

然后調(diào)用它的 lintText 代碼來(lái)測(cè)試,返回的結(jié)果使用 formatter 打?。?/p>

(async function main() {
const results = await engine.lintText(`
if (print)
{
const num = a + b;
console.log(num);
}
for(let i = 0;i<100;i++)
{
console.log(i);
}
`);

console.log(results[0].output);

const formatter = await engine.loadFormatter("stylish");
const resultText = formatter.format(results);
console.log(resultText);
})();

我們來(lái)試一下效果:

三處格式錯(cuò)誤都檢查出來(lái)了!

然后把 fix 設(shè)為 true,來(lái)測(cè)試下自動(dòng)修復(fù):

格式自動(dòng)修復(fù)了!

這樣我們就通過(guò) Eslint 的 rule 實(shí)現(xiàn)了代碼格式的檢查和自動(dòng)修復(fù)。

代碼上傳到了 github:https://github.com/QuarkGluonPlasma/eslint-plugin-exercize

那么再回到最開(kāi)始的問(wèn)題,為什么 Eslint 可以檢查代碼格式,而 Babel 不可以呢?

為什么 Eslint 可以檢查格式 Babel 不可以

我們寫了一個(gè)檢查大括號(hào)格式的 rule,可以發(fā)現(xiàn)能夠做格式檢查關(guān)鍵是能找到關(guān)聯(lián)的 token。

Eslint 的 AST 記錄了所有的 token,token 中有行列號(hào)信息,而且 AST 中也保存了 range,也就是當(dāng)前節(jié)點(diǎn)的開(kāi)始結(jié)束位置。并且還提供了 SourceCode 的 api 可以根據(jù) range 去查詢 token。這是它能實(shí)現(xiàn)格式檢查的原因。

而 Babel 其實(shí)也支持 range 和 token,但是卻沒(méi)有提供根據(jù) range 查詢 token 的 api,這是它不能做格式檢查的原因。

其實(shí) Babel 和 Eslint 原理差不多,但是 Eslint 是被設(shè)計(jì)來(lái)做代碼錯(cuò)誤和格式檢查與修復(fù)的,而 Babel 是被設(shè)計(jì)用來(lái)做代碼分析和轉(zhuǎn)換的,目的不同,所以也就提供了不同的 api,能夠做不同的事情。

總結(jié)

Eslint 是用來(lái)檢查代碼中的錯(cuò)誤和格式問(wèn)題的,基于 AST,Babel 也是基于 AST 做的代碼分析和轉(zhuǎn)換,但是卻不能檢查格式。

為了探究原因,我們寫了一個(gè) EsLint 的檢查大括號(hào)格式的 rule,通過(guò) SourceCode 的 api 拿到 { 和 ( 的 token,對(duì)比下行列號(hào)來(lái)做檢查。并且通過(guò) fixer 的字符串替換做了自動(dòng)修復(fù)。

寫完之后,我們發(fā)現(xiàn) EsLint 能做格式檢查的原因是因?yàn)?AST 中記錄了 range,也保留了 token信息,并且提供了根據(jù) range 查詢 token 的 api,而 Babel 沒(méi)有。

EsLint 和 Babel 原理大同小異,但是有不同的設(shè)計(jì)目的,所以提供了不同的 api,有著不同的功能。

責(zé)任編輯:姜華 來(lái)源: 神光的編程秘籍
相關(guān)推薦

2021-09-02 13:38:48

Eslint Babel 插件

2021-09-07 13:06:32

Eslint Fix 功能算法

2021-09-02 16:15:29

開(kāi)發(fā)技能代碼

2021-09-11 19:46:14

配置

2021-09-05 11:37:31

Eslint插件Vue

2021-11-19 23:54:19

插件Eslint

2013-11-29 09:51:26

C++雙重檢查鎖定

2021-06-01 06:00:06

typescriptjavascript

2022-06-06 08:21:13

MySQL數(shù)據(jù)庫(kù)命令

2021-10-31 23:57:33

Eslint原理

2019-04-19 11:56:48

框架AI開(kāi)發(fā)

2013-03-25 10:14:18

NginxApache

2022-02-15 07:03:04

start 源碼run線程

2023-11-04 16:26:18

C語(yǔ)言數(shù)組

2022-05-24 08:31:05

C語(yǔ)言檢查數(shù)組

2019-12-27 14:47:06

Python編程語(yǔ)言

2012-10-10 16:52:21

CentOSDebianUbuntu

2021-08-14 09:04:58

TypeScriptJavaScript開(kāi)發(fā)

2021-10-30 19:57:00

HTTP2 HTTP

2023-09-26 11:28:08

代碼注釋軟件開(kāi)發(fā)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)