vueconf续:VIDE是怎么样从AST层分析vue文件进行提示的

Posted 大前端工程师

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vueconf续:VIDE是怎么样从AST层分析vue文件进行提示的相关的知识,希望对你有一定的参考价值。

vueconf后,加了好多微信朋友,问我AST层分析vue文件是怎么样做的,今天就特意写一篇文章说一下 从AST这个词出发,然后关联js,我们应该很快就会联想到babel,的确,vide也是基于babel来分析vue文件,从来在编辑器界面进行友好提示。

首先,vide在打开vue文件后,引擎就会判断,是否是vue文件,如果是vue文件,就会调用对vue文件分析的函数

第一步,利用child_process模块,开一个子进程,以免block整个ide,然后利用vue-template-compiler模块提取vue文件中的script部分,对js进行分析提取(目前只分析了js,之后会分析template和style)

第二步,提取完js部分后,我们就需要用到babylon(babel中的javascript的parser),通过babylon来分析之前的js片段,具体代码如下

 
   
   
 
  1. var result = babylon.parse(scriptContent, {

  2.    sourceType:'module',

  3.    plugins: '*'

  4.  })

第三步,用babylon解析完之后,我们就需要使用babel-traverse这个模块来遍历AST树了,根据traverse的原理,对相应的语句类型进行分析,从而提取出我们想要的内容

 
   
   
 
  1. traverse(result, {

  2.    //vue是通过export default来导出的,那就分析这个类型

  3.    ExportDefaultDeclaration (path) {

  4.      path.traverse({

  5.        ObjectProperty (subpath) {

  6.          if (subpath.parentPath.parentPath.type !== 'ExportDefaultDeclaration') {

  7.            return

  8.          }

  9.          //分析vue文件的函数及其参数和位置

  10.          if (subpath.node.key.name === 'methods') {

  11.            subpath.node.value.properties.forEach((property) => {

  12.              let name = property.key.name

  13.              let params = property.params.map((param) => {

  14.                return param.name ? param.name : param.left.name

  15.              })

  16.              mapResult.component.methods[name] = {

  17.                row: property.loc.start.line,

  18.                params

  19.              }

  20.            })

  21.          } else if (subpath.node.key.name === 'computed') {

  22.            // 获取通过computed计算的值

  23.            let properties = subpath.node.value.properties

  24.            properties.forEach((property) => {

  25.              if (property.key && property.key.name) {

  26.                mapResult.component.variables.push(property.key.name)

  27.              } else {

  28.                subpath.traverse({

  29.                  SpreadProperty (_path) {

  30.                    _path.traverse({

  31.                      ObjectExpression (__path) {

  32.                        __path.node.properties.forEach((property) => {

  33.                          if (property.key.name) {

  34.                            mapResult.component.variables.push(property.key.name)

  35.                          }

  36.                        })

  37.                      }

  38.                    })

  39.                  }

  40.                })

  41.              }

  42.            })

  43.          }

  44.        },

  45.        ObjectMethod (subpath) {

  46.          if (subpath.parentPath.parentPath.type !== 'ExportDefaultDeclaration') {

  47.            return

  48.          }

  49.          // 获取data返回的自动,组件的属性值

  50.          if (subpath.node.key.name === 'data' && subpath.node.kind === 'method') {

  51.            subpath.traverse({

  52.              ReturnStatement (path) {

  53.                path.node.argument.properties.forEach((property) => {

  54.                  mapResult.component.variables.push(property.key.name)

  55.                })

  56.              }

  57.            })

  58.          }

  59.        }

  60.      })

  61.    },

  62.    FunctionDeclaration (path) {

  63.      //分析常规函数

  64.      let node = path.node

  65.      let name = node.id.name

  66.      let params = []

  67.      try {

  68.        params = node.params.map((param) => {

  69.          if (param.type === 'ObjectPattern') {

  70.            return scriptContent.split('\n')[param.loc.start.line - 1].slice(param.loc.start.column, param.loc.end.column)

  71.          } else {

  72.            return param.name ? param.name : param.left.name

  73.          }

  74.        })

  75.      } catch (e) {}

  76.      let value = {

  77.        row: node.id.loc.start.line,

  78.        params

  79.      }

  80.      mapResult.funcs[name] = value

  81.    }

  82.  })

第四步,分析完后,得到相应的结果集,然后通过process.send把数据返回给父进程供ide的自动化提示

插件

vide-plugin-prompt-vue

总结

对于目前的vue提示插件,只做到了冰山一角,还可以深度挖掘,之后把全部的vue全家桶插件做完之后,再给大家讨论更多的。

如果大家有什么建议或者想要怎么样的功能,可以回复我,我之后把这些插件统一到vue全家桶开发插件当中,方便大家对vue的开发

回顾我以前的文章:



以上是关于vueconf续:VIDE是怎么样从AST层分析vue文件进行提示的的主要内容,如果未能解决你的问题,请参考以下文章

vue3源码分析——ast生成代码 - 掘金

vue3源码分析——ast生成代码 - 掘金

vue3源码分析——ast生成代码 - 掘金

爱奇艺怎么恢复老界面?

rest_init函数分析(续)

Python Ast介绍及应用