-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
49. eslint 多语言规则 #50
Comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
盛夏到初秋,这次没有坐在窗边看不到磅礴的雨,只是这个夏天也少了烈日的暴晒,就这么过去了。去年台风天的黄昏,很好看,还拍了不少照片,到了今年,左等右等的,结果台风一刮,夏天就走了。2021好像也快要过去了。今年没有专门学习新的技术,中途换工作的,从2月拖到了6月,中间又忙了工作,梳理业务的,难得现在又空总结一下自己做的多语言。
多语言与 eslint
多语言为什么和
eslint
相关?通过eslint
规则来限制业务开发,凡是涉及到中文的,都应该有多语言的约束,否则提示error
。这样就很强约束了,在多人协作的时候尤其重要,保持团队的统一风格。这里说一下这个功能: 凡是涉及到中文的,都应该有多语言的约束。在
eslint
里面,这样的规则称之为rule
,比如我们经常看到的no-debugger
禁止使用 debugger,就是这样的。最后实现效果是这样的:当输入中文变量包括jsx
里面存在非法中文的时候,都会提示报红:加上代码提交之前的
lint-staged
检查就可以统一规范了。通用规则实现
在看多语言的
eslint
的规则实现之前可以看一下普通规则是如何的,我们就按上面的no-debugger
来看看,这个是eslint
内部的实现,用户只需要配置就好了,代码如下:eslint/lib/rules/no-debugger.js
这个文件蛮简单的,可以看出下面有个meta
和create
,前者不难猜出是配置信息,包括提示信息以及是否推荐这些;后面的则是出现debugger
语句的时候就提示报错context.report
。是不是很简单?回过头来可以看一下
eslint rule
官方教程,可以看到recommended
就是是否在eslint:recommended
扩展里面启用。最重要的create
方法,eslint
会去遍历代码的抽象语法树 AST,调用 rule 里面注册的方法检测节点,上面则是 degugger 节点。函数名是自己随便定义的?不是的,需要是对应的节点,可以通过 esprima 来解析来获得需要的函数名,比如下图,先有变量声明
VariableDeclaration
后有DebuggerStatement
。如果你把
no-debugger
中的DebuggerStatement
换成VariableDeclaration
,那每次声明变量都会异常。提到 AST 解析还是要说一下,espree
是eslint
的官方解析器,基于esprima
,并且输出结构相似。钩子实现上面的
no-debugger
比较简单,遇到DebuggerStatement
直接context.report
,就完成了整个上报过程了。其他需要主要的是规则代码的位置需要在
lib/rules/
下面,同时要有tests/lib/rules
以及对应的文档。多语言规则实现
通过上文
create
提示的实现,先是梳理常见的中文都是哪些节点,比如最常见的let a = '中文'
,在esprima
里面查询到的节点类型为Literal
;其他的还有两大块一个是jsx
里面的文字,比如<div>中文</div>
这样的,还有一个是字符串模版变量,比如 let a =中${name}文
。前者可以通JSXText
获取,后则稍微麻烦点,下面重点介绍一下:模版字符串
模版字符串解析的下图:
可以看到存在
quasis
和expressions
两个数组,前者是字符串信息,后面是表达式。i18next
本身是支持变量传入的,比如i18next.t('中{{value}}文', { value: name })
,变量从第二个参数里面传入,生成文案替换。由于表达式不一定是变量,可以采用value
名字自动生成名称。字段名称是生成了,后续还要获取到字段名称对应的
value
也就是name
这个字符串。存在变量名的可以直接获取,其他的比如i18next.t('中{{value}}文', { value: 1 + 1 })
,要如何获取到后面的1 + 1
呢?可以有如下写法在
eslint
规则里面会传入context
上下文,通过上下文可以获取到非常多的信息,比如上面的获取全文字符串,再通过range
,定位到具体的内容。忽略与修复
正常代码里面中文也是会有需要的地方,比如上报日志,埋点信息这些,甚至更加根本的如何识别
i18next.t('中文')
这样的表达式不报错呢?这样的表达式已经是正常写法了。所以这里需要ignore
正常表达式。进入节点通过匹配白名单的形式可以过滤掉,只是就上文的
i18next.t('中文')
匹配了函数,但是文案又是另外一个节点,如何做到两个关联到一起呢?这里就需要额外数组来记录当前关系,比如进入i18next.t
函数的时候,标记为true
,后面进入函数形参的时候,检查标记,为true
就忽略了。只是什么时候退出呢?这里有另外一个钩子CallExpression:exit
。由于存在多个嵌套的可能,所以用的是一个数组来维护,当exit
的时候退出。上面的例子,是遇到
debugger
的时候报错,那如何fix
呢,eslint
有修复功能。context.report
里面的传参fixer
函数,提供了不少方法。还用到了
fixer.replaceTextRange
,来精准替换。存量代码处理
对于老项目,直接用多语言的主要问题是,现有文案如何处理,要一个个替换显然不合理。最先的
i18next
提供了i18next-scanner
工具,只是起更多的是将现有的i18n._('Loading...')
这样的实现提出文案到json
文件里面。还有其他思路比如通过babel
的形式来解析,还有通过正则的形式来处理,两个方案都比较麻烦,容易出问题,于是我们这边有新的方案,本来也是通过eslint
的规则来处理,那为什么不用eslint
的解析器来提取词条呢?require('eslint').CLIEngine(options).executeOnFiles
获取到eslint
的分析结果,当然需要提前配置好规则,比如i18next/no-literal-string
这个。后续获取到结果后,将其输出为转换为json
文件输出就可以了,可以说这个规则一举两得。单测
用的是
require("eslint").RuleTester
比如下面:debug 的时候采用
create javascript debug terminal
的方式就可以了。总结
这次算是深入的研究
eslint
了,从单个规则到引擎扫描,还有测试,打开了自己了新天地,尤其是eslint
对团队规范的统一还是有很大帮助,后续的还可以添加typescript
帮助,将json
文件改为ts
,在文案里面缺少该词条就报错的,建立更加完整的机制。在三亚的酒店的窗边,眺望着远处的海岸线,觉得写写博客,旅游,生活可好了,只是心中想的还是想要进击,想要不断的提升自己,偶得半天安宁,还是好好偷闲。
惭愧这边文章是 2021.10 就写好了,结果拖到今天才发表,不过说来也奇怪感觉时间好像没有过多少一样,好像去三亚还是昨天的事情。
The text was updated successfully, but these errors were encountered: