Eslint 可以检查出代码中的错误和一些格式问题,并能自动修复,它的实现原理就是基于 AST (抽象语法树)。
通过 Parser 把源码解析成 AST 对象树,源码字符串中的各种信息就被保存到了这个对象树里,然后遍历 AST,对每一部分做检查就能实现 Lint 的功能,而自动 fix 的功能则是基于字符串替换实现的,指定某一段 range,替换成另一段文本即可。
说起来,Babel 也是基于 AST 实现的代码分析和转换,但是却不能检查和修复格式的问题,这是为什么呢?为什么 Eslint 可以检查格式而 Babel 不可以呢?
我们先写一个 Eslint 的 rule 来感受下 Eslint 是怎么检查和修复格式问题的。
大括号有两种主流写法,一种是同一行写:
if (name === 'guang') {
}
另一种是新开一行写:
if (name === 'guang')
{
}
我们写一个 eslint 的 rule 来检查大括号的格式并自动修复成同一行的格式。
Eslint 的检查是基于 AST,我们要检查的 AST 是块语句 BlockStatement。
关于什么代码是什么 AST 可以用 astexplorer.net 可视化的查看,parser 选择 espree (Eslint 默认的 parser):
具体来说检查的是 BlockStatement 的最开始的 token {
的行号,是不是和它前一个 token 在同一行。(token 是指最小的不可再细分的单词,比如关键字、变量名等标识符、各种分隔符等)
如果是同一行,则说明了是符合规范的。当然我们还可以进一步检查一下大括号 {
和前一个 token 之间有没有空格。
思路理清了,我们来写下代码:
Eslint 的 rule 的格式是这样的:
module.exports = {
meta: {
docs: {
description: "enforce consistent brace style for blocks"
},
fixable: true
},
create(context) {
return {
BlockStatement(node) {
}
}
}
};
分为 meta 和 create 两部分:
我们在 create 里声明了对 BlockStatement 节点的检查,它的参数就是对应的节点对象。
但是我们要检查的是 token,这个用 context 里的一个 api:
create(context) {
const sourceCode = context.getSourceCode();
return {
BlockStatement(node) {
const firstToken = sourceCode.getFirstToken(node);
const beforFirstToken = sourceCode.getTokenBefore(node);
}
}
}
我们从 context 中拿到了 sourceCode 的 api,它就是用来取 token 的。
我们用 getFirstToken 拿到了当前 node 的开始 token,也就是 {,
然后又拿到了当前 node 的前面一个节点的 token,也就是 ):
token 中保存了行列号信息,那么对比下行列号就知道是否有格式问题了:
如果 { 所在的行和 ) 所在的行不是同一行,就报错
if (firstToken.loc.start.line !== beforFirstToken.loc.start.line) {
context.report({
node,
loc: firstToken.loc,
message: '大括号格式不对'
});
}
修复的方式自然就是把 { 和 ) 之间的部分替换成一个空格,这个使用 fixer 提供的 api:replaceTextRange:
if (firstToken.loc.start.line !== beforFirstToken.loc.start.line) {
context.report({
node,
loc: firstToken.loc,
message: '大括号格式不对'
fix: fixer => {
return fixer.replaceTextRange([beforFirstToken.range[1], firstToken.range[0]], ' ');
}
});
}
同理,也可以检查出 { 和 ) 之间没有空格的格式错误,修复方式一样:
if (firstToken.loc.start.column === beforFirstToken.loc.start.column + 1){
context.report({
node,
loc: firstToken.loc,
message: '大括号前缺少空格',
fix: fixer => {
return fixer.replaceTextRange([beforFirstToken.range[1], firstToken.range[0]], ' ');
}
});
}
这样就实现了大括号格式的检查和自动修复。
我们来试下效果:
Eslint 除了提供命令行外,也提供了 api,我们调用它的 api 来测试 rule:
先创建 ESLint 对象,指定 rulePaths 也就是查找 rule 的目录为当前目录:
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 是不自动修复。
然后调用它的 lintText 代码来测试,返回的结果使用 formatter 打印:
(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);
})();
我们来试一下效果:
三处格式错误都检查出来了!
然后把 fix 设为 true,来测试下自动修复:
格式自动修复了!
这样我们就通过 Eslint 的 rule 实现了代码格式的检查和自动修复。
代码上传到了 github:https://github.com/QuarkGluonPlasma/eslint-plugin-exercize
那么再回到最开始的问题,为什么 Eslint 可以检查代码格式,而 Babel 不可以呢?
我们写了一个检查大括号格式的 rule,可以发现能够做格式检查关键是能找到关联的 token。
Eslint 的 AST 记录了所有的 token,token 中有行列号信息,而且 AST 中也保存了 range,也就是当前节点的开始结束位置。并且还提供了 SourceCode 的 api 可以根据 range 去查询 token。这是它能实现格式检查的原因。
而 Babel 其实也支持 range 和 token,但是却没有提供根据 range 查询 token 的 api,这是它不能做格式检查的原因。
其实 Babel 和 Eslint 原理差不多,但是 Eslint 是被设计来做代码错误和格式检查与修复的,而 Babel 是被设计用来做代码分析和转换的,目的不同,所以也就提供了不同的 api,能够做不同的事情。
Eslint 是用来检查代码中的错误和格式问题的,基于 AST,Babel 也是基于 AST 做的代码分析和转换,但是却不能检查格式。
为了探究原因,我们写了一个 EsLint 的检查大括号格式的 rule,通过 SourceCode 的 api 拿到 { 和 ) 的 token,对比下行列号来做检查。并且通过 fixer 的字符串替换做了自动修复。
写完之后,我们发现 EsLint 能做格式检查的原因是因为 AST 中记录了 range,也保留了 token信息,并且提供了根据 range 查询 token 的 api,而 Babel 没有。
EsLint 和 Babel 原理大同小异,但是有不同的设计目的,所以提供了不同的 api,有着不同的功能。
本文由哈喽比特于2年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/dZC7vIfFtamG_cMY8K4-TQ
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。