继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

写一个 eslint 插件:vue template 中 class 顺序的检查和自动修复

智慧大石
关注TA
已关注
手记 337
粉丝 33
获赞 206

有小伙伴问我如何修复 vue template 中的 class 名的顺序、属性名顺序,还有 options 中的属性顺序的问题,用 eslint 可以做到么。

答案是能,但是需要写 eslint 插件来检查和修复。

考虑到他可能没有写过 eslint 插件,所以我先把相对简单的校验和修复 class 名的顺序的插件摘出来实现了一下。

思路分析

首先,eslint 是否能 parse vue 的模版呢?

是可以的,因为 eslint 的 parser 支持切换,而 vue 实现了对应的 parser,所以可以在 eslint 中使用 vue-eslint-parser 来解析模版。

我们可以使用 astexplorer.net 来看一下 parse 生成的 AST。

http://img4.mukewang.com/6134d8310001a2fa27321216.jpg

我们要处理的是 class 属性,也就是 VAttribute 的 value 部分

http://img1.mukewang.com/6134d83200012f9726781186.jpg

可以支持传入比较器来自定义顺序,排序完之后设置回去。

当然,vue 的模版支持 {} 来引用 data,这种我们不处理,可以过滤掉。

思路比较简单,下面我们写代码来实现一下。

代码实现

我们可以给插件起名为 vue-class-order。

首先,我们引入 eslint,设置 useEslintrc 为 false 也就是不使用配置文件,然后在 overrideConfig 属性设置各种配置,rules 里填入这个插件。

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


const engine = new ESLint({

    fix: false,

    overrideConfig: {

        parser: 'vue-eslint-parser',

        parserOptions: {

            sourceType: 'module'

        },

        rules: {

            "vue-class-order": [ "error" ]

        }

    },

    rulePaths: ['./'],

    useEslintrc: false

});


这里的 parser 要使用 vue-eslint-parser 才可以,并且 rulePaths 也就是查找 rule 的路径也要设置下。fix 设置为 false 代表不自动修复。

之后,调用它的 lintText 方法来对代码进行 lint。

(async function main() {

  const results = await engine.lintText(`

<template>

<div>

  <p class="c d e" >dongdong</p>

  <p class="c a b">guangguang</p>

</div>

</template>


<script>

export default {

};

</script>

`);


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


  const formatter = await engine.loadFormatter("stylish");

  const resultText = formatter.format(results);

  console.log(resultText);

})();


打印修复后的结果和格式化后的报错。

接下来就是实现这个插件了,我们的目标是检查 VAttribute 节点,并且用自定义的比较器来对 class 排序。

首先,在 rule 配置的地方加上一个参数:

rules: {

    "vue-class-order": [ "error", function(name1, name2) {

        return name1.charCodeAt(0) - name2.charCodeAt(0);

    }]

}


之后在插件里面取出来:

module.exports = {

     meta: {

         fixable: true

     },

     create(context) {

         const comparator = context.options[0];

         

     }

 };


这里的 comparator 就是从 context 中取出的参数。

插件的结构是 meta,create 两部分,meta 是各种描述插件本身的元信息,create 部分是插件的主要逻辑。

create 部分返回一个 visitor,声明对什么节点进行什么操作。但是因为我们用的 parser 是 vue 自定义的(vue-eslint-parser),所以这里 visitor 也要用它提供的,也就是:

module.exports = {

     meta: {

         fixable: true

     },

     create(context) {

         const comparator = context.options[0];

         return context.parserServices.defineTemplateBodyVisitor({

            "VAttribute[key.name=class]"(node) {  

                

            }

         });

     }

 };


在 context.parserServices.defineTemplateBodyVisitor 方法中传入具体的 visitor,比如我们需要对 VAttribute 节点做处理。

eslint 支持esqury 的写法,也就是可以通过选择器的方式来指定要处理的节点,这里我们指定 key.name 为 class 的 VAttribute 节点

http://img1.mukewang.com/6134d8b30001258b07361020.jpg

之后要拿到节点的值,排序一下,看看是否是对的,不对就报错。

"VAttribute[key.name=class]"(node) {  

    const classStr = node.value.value;

    if (!classStr.includes('{')) { //过滤掉有插值表达式的 class

        const curOrder = classStr.split(/\s/);

        const shouldOrder = [...curOrder].sort(comparator);

        if (curOrder.some((item, index) => curOrder[index] !== shouldOrder[index])) {

            context.report({

                node,

                message: 'className 顺序不对:' + classStr,

                loc: node.value.loc

            });

        }

    }

}


这样,我们就实现了对 vue 模版中 class 的顺序的 lint。

我们试一下效果:

http://img.mukewang.com/6134d8d100019e8411440902.jpg

我们实现了对 className 顺序的 lint!

当然,只报错不修复比较耍流氓,我们还得实现下自动修复。

修复的话就是把 value 的部分替换掉,也就是拿到 value 的 range(开始和结束的下标),把该 range 的文本使用 fixer 的 api 替换掉。(这里要考虑引号)

context.report({

    node,

    message: 'className 顺序不对:' + classStr,

    loc: node.value.loc,

    *fix(fixer) {

        const [ start, end ] = node.value.range;

        yield fixer.replaceTextRange([start + 1, end - 1], shouldOrder.join(' '))

    }

});


我们把 fixer 设置为 true,再跑一下:

http://img3.mukewang.com/6134d9080001d8d111921498.jpg

做了自动的修复,没有报错了!

我们实现了对 vue 模版中 class 的顺序的检查和自动修复!

总结

Eslint 可以基于 AST 做代码格式的检查和修复。

基于 AST 那就得有对应的 parser, eslint 支持 parser 的扩展,所以有很多 eslint parser 可用,要 parse vue 模版就可以用 vue-eslint-parser。可以用 astexplorer.net 可视化的查看。

我们要实现对 vue 模版中 class 的顺序的检查,分析之后就是要取出 key 为 class 的 VAttribute 节点的 value,然后根据传入的比较器进行排序,如果顺序不一致,就报错。并且还可以通过 fixer 的 api 进行自动修复,也就是对该段 range 的文本进行替换。

这里我们通过 api 来调用的 eslint,通过 cli 也一样。

这篇文章实现了一个相对简单的 eslint 插件,对 vue template 中的代码格式做了检查和修复,希望能够帮助大家入理清 eslint 插件开发的思路。


作者:zxg_神说要有光
链接:https://juejin.cn/post/7004452519782907917
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP