返回顶部
首页 > 资讯 > 精选 >VSCode怎么实现一个代码诊断插件
  • 286
分享到

VSCode怎么实现一个代码诊断插件

2023-06-29 05:06:58 286人浏览 安东尼
摘要

这篇文章主要讲解了“vscode怎么实现一个代码诊断插件”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“VSCode怎么实现一个代码诊断插件”吧!基本原理Visual Studio Code

这篇文章主要讲解了“vscode怎么实现一个代码诊断插件”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“VSCode怎么实现一个代码诊断插件”吧!

基本原理

Visual Studio Code 的编程语言功能扩展是有 Language Server 来实现的,这很好理解,毕竟检查语言功能是耗费性能的,需要另起一个进程来作为语言服务,这就是 Language Server 语言服务器

Language Server 是一种特殊的 Visual Studio Code 扩展,可为许多编程语言提供编辑体验。使用语言服务器,您可以实现自动完成、错误检查(诊断)、跳转到定义以及VS Code 支持的许多其他语言功能。

既然有了服务器提供的语法检查功能,就需要客户端去连接语言服务器,然后和服务器进行交互,比如用户在客户端进行代码编辑时,进行语言检查。

当打开 Vue 文件时会激活插件,此时就会启动 Language Server,当文档发生变化时,语言服务器就会重新诊断代码,并把诊断结果发送给客户端。

代码诊断的效果是出现波浪线,鼠标移上显示提示消息,如果有快速修复,会在弹出提示的窗口下出现快速修复的按钮

动手实现

了解了代码诊断的基本原理之后,开始动手实现,从上面的基本原理可知,我们需要实现两大部分的功能:

  • 客户端与语言服务器交互

  • 语言服务器的诊断和快速修复功能

客户端与语言服务器交互

官方文档 提供了一个示例 - 用于纯文本文件的简单语言服务器,我们可以在这个示例的基础上去修改。

git clone https://GitHub.com/microsoft/vscode-extension-samples.git> cd vscode-extension-samples/lsp-sample> npm install> npm run compile> code .

首先在 client 建立服务器

// client/src/extension.tsexport function activate(context: ExtensionContext) {    ...    const clientOptions: LanguageClientOptions = {        documentSelector: [{ scheme: 'file', language: 'vue' }], // 打开 vue 文件时才激活        ...    };    client = new LanguageClient(...);    client.start();}

接着在 server/src/server.ts 中,编写于客户端的交互逻辑,比如在客户端文档发生变化的时候,校验代码:

// server/src/server.tsimport {    createConnection    TextDocuments,    ProposedFeatures,    ...} from 'vscode-languageserver/node';const connection = createConnection(ProposedFeatures.all);const documents: TextDocuments<TextDocument> = new TextDocuments(TextDocument);documents.onDidChangeContent(change => {    // 文档发生变化时,校验文档    validateTextDocument(change.document);});async function validateTextDocument(textDocument: TextDocument): Promise<void> {    ...    // 拿到诊断结果    const diagnostics = getDiagnostics(textDocument, settings);    // 发给客户端    connection.sendDiagnostics({ uri: textDocument.uri, diagnostics });}// 提供快速修复的操作connection.onCodeAction(provideCodeActions);async function provideCodeActions(params: CodeActionParams): Promise<CodeAction[]> {    ...    return quickfix(textDocument, params);}

在完成上面客户端与服务端交互之后,可以注意到这两个方法 getDiagnostics(textDocument, settings)quickfix(textDocument, params)。 这两个方法分别是为文档提供诊断数据和快速修复的操作。

代码诊断

1. 将代码文档转成 AST 语法树

在处理客户端传递过来的 Vue 代码文本的,需要通过 vue/compiler-dom 解析成三部分 ast 格式的数据结构,分别是 template、jsCSS, 由于现在前端代码使用的都是 typescript,JS 部分没有解析成 AST,因此需要使用 babel/parser 去解析 TypeScript 代码生成最终的 JS 的 AST 数据结构。

const VueParser = require('@vue/compiler-dom');// 该函数返回诊断结果客户端function getDiagnostics(textDocument: TextDocument, settings: any): Diagnostic[] {const text = textDocument.getText();const res = VueParser.parse(text);const [template, script] = res.children;return [...analyzeTemplate(template), // 解析 template 得到诊断结果...analyzeScript(script, textDocument), // 解析 js 得到诊断结果];}// 分析 js 语法function analyzeScript(script: any, textDocument: TextDocument) {  const scriptAst = parser.parse(script.children[0]?.content, {    sourceType: 'module',    plugins: [      'typescript', // typescript      ['decorators', { decoratorsBeforeExport: true }], // 装饰器      'classProperties', // es6 class 写法      'classPrivateProperties',    ],  });
2. 遍历语法树对代码校验

在得到代码的语法树之后,我们需要对每一个代码节点进行检查,来判断是否符合 Code Review 的要求,因此需要遍历语法树来对每个节点处理。

使用深度优先搜索对 template 的 AST 进行遍历:

function deepLoopData(  data: AstTemplateInterface[],  handler: Function,  diagnostics: Diagnostic[],) {  function dfs(data: AstTemplateInterface[]) {    for (let i = 0; i < data.length; i++) {      handler(data[i], diagnostics); // 在这一步对代码进行处理      if (data[i]?.children?.length) {        dfs(data[i].children);      } else {        continue;      }    }  }  dfs(data);}function analyzeTemplate(template: any) {  const diagnostics: Diagnostic[] = [];  deepLoopData(template.children, templateHandler, diagnostics);  return diagnostics;}function templateHandler(currData: AstTemplateInterface, diagnostics: Diagnostic[]){   // ...对代码节点检查}

而对于 JS AST 遍历,可以使用 babel/traverse 遍历:

 traverse(scriptAst, {    enter(path: any) {      ...    } }
3. 发现不合规代码,生成诊断

根据 ast 语法节点去判断语法是否合规,如果不符合要求,需要在代码处生成诊断,一个基础的诊断对象(diagnostics)包括下面几个属性:

  • range:  诊断有问题的范围,也就是画波浪线的地方

  • severity: 严重性,分别有四个等级,不同等级标记的颜色不同,分别是:

    • Error: 1

    • Warning: 2

    • InfORMation:3

    • Hint:4

  • message: 诊断的提示信息

  • source: 来源,比如说来源是 Eslint

  • data:携带数据,可以将修复好的数据放在这里,用于后面的快速修复功能

比如实现一个提示函数过长的诊断:

function isLongFunction(node: Record<string, any>) {  return (    // 如果结束位置的行 - 开始位置的行 > 80 的话,我们认为这个函数写得太长了    node.type === 'ClaSSMethod' && node.loc.end.line - node.loc.start.line > 80  );}

在遍历 AST 时如果遇到某个节点是出现函数过长的时候,就往诊断数据中添加此诊断

traverse(scriptAst, {    enter(path: any) {        const { node } = path;        if (isLongFunction(node)) {            const diagnostic: Diagnostic ={                severity: DiagnosticSeverity.Warning,                range: getPositionRange(node, scriptStart),                message: '尽可能保持一个函数的单一职责原则,单个函数不宜超过 80 行',                source: 'Code Review 指南',            }            diagnostics.push(diagnostic);        }        ...       }});

文档中所有的诊断结果会保存在 diagnostics 数组中,最后通过交互返回给客户端。

4. 提供快速修复

上面那个函数过长的诊断没办法快速修复,如果能快速修复的话,可以将修正后的结果放在 diagnostics.data 。换个例子写一个快速修复, 比如 Vue template 属性排序不正确,我们需要把代码自动修复

// attributeOrderValidator 得到判断结果 和 修复后的代码const {isGoodSort, newText} = attributeOrderValidator(props, currData.loc.source);    if (!isGoodSort) {      const range = {        start: {          line: props[0].loc.start.line - 1,          character: props[0].loc.start.column - 1,        },        end: {          line: props[props.length - 1].loc.end.line - 1,          character: props[props.length - 1].loc.end.column - 1,        },      }      let diagnostic: Diagnostic = genDiagnostics(        'vue template 上的属性顺序',        range      );      if (newText) { // 如果有修复后的代码        // 将快速修复数据保存在 diagnostic.data        diagnostic.data = {          title: '按照 Code Review 指南的顺序修复',          newText,        }      }      diagnostics.push(diagnostic);    }

quickfix(textDocument, params)

export function quickfix(  textDocument: TextDocument,  params: CodeActionParams): CodeAction[] {  const diagnostics = params.context.diagnostics;  if (isNullOrUndefined(diagnostics) || diagnostics.length === 0) {    return [];  }  const codeActions: CodeAction[] = [];  diagnostics.forEach((diag) => {    if (diag.severity === DiagnosticSeverity.Warning) {      if (diag.data) { // 如果有快速修复数据        // 添加快速修复        codeActions.push({          title: (diag.data as any)?.title,          kind: CodeActionKind.QuickFix, // 快速修复          diagnostics: [diag], // 属于哪个诊断的操作          edit: {            changes: {                [params.textDocument.uri]: [                  {                    range: diag.range,                    newText: (diag.data as any)?.newText, // 修复后的内容                  },                ],              },           },        });    }   }});

有快速修复的诊断会保存在 codeActions 中,并且返回给客户端, 重新回看交互的代码,在 documents.onDidChangeContent 事件中,通过 connection.sendDiagnostics({ uri: textDocument.uri, diagnostics }) 把诊断发送给客户端。quickfix 结果通过 connection.onCodeAction 发给客户端。

import {    createConnection    TextDocuments,    ProposedFeatures,    ...} from 'vscode-languageserver/node';const connection = createConnection(ProposedFeatures.all);const documents: TextDocuments<TextDocument> = new TextDocuments(TextDocument);documents.onDidChangeContent(change => {    ...    // 拿到诊断结果    const diagnostics = getDiagnostics(textDocument, settings);    // 发给客户端    connection.sendDiagnostics({ uri: textDocument.uri, diagnostics });});// 提供快速修复的操作connection.onCodeAction(provideCodeActions);async function provideCodeActions(params: CodeActionParams): Promise<CodeAction[]> {    ...    return quickfix(textDocument, params);}

感谢各位的阅读,以上就是“VSCode怎么实现一个代码诊断插件”的内容了,经过本文的学习后,相信大家对VSCode怎么实现一个代码诊断插件这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

--结束END--

本文标题: VSCode怎么实现一个代码诊断插件

本文链接: https://lsjlt.com/news/322738.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • VSCode怎么实现一个代码诊断插件
    这篇文章主要讲解了“VSCode怎么实现一个代码诊断插件”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“VSCode怎么实现一个代码诊断插件”吧!基本原理Visual Studio Code ...
    99+
    2023-06-29
  • vscode怎么实现脚手架插件
    本篇内容介绍了“vscode怎么实现脚手架插件”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!安装使用vscode 安装 lowcode 插件...
    99+
    2023-06-30
  • 怎么用VuePress开发一个代码复制插件
    今天小编给大家分享一下怎么用VuePress开发一个代码复制插件的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。本地开发但是如...
    99+
    2023-06-28
  • jquery插件怎么实现代码雨特效
    这篇文章将为大家详细讲解有关jquery插件怎么实现代码雨特效,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。jquery是什么jquery是一个简洁而快速的JavaScript库,它具有独特的链式语法和短...
    99+
    2023-06-14
  • 让Python代码飞起来,高手必用十个VSCode插件
    作为一名 Python 程序员,VSCode 中的插件能够帮助我们更高效地进行开发,提高代码的质量和效率。在这篇文章中,我将为大家推荐一些常用的 Python VSCode 插件,希望能够帮助大家更好地利用 VSCode 进行 Python...
    99+
    2023-05-14
    程序员 Python VSCode
  • vue中怎么实现一个弹窗插件
    vue中怎么实现一个弹窗插件,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。popup.vue<template>  ...
    99+
    2024-04-02
  • vue.js中怎么实现一个分页插件
    这篇文章将为大家详细讲解有关vue.js中怎么实现一个分页插件,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。html代码:<div clas...
    99+
    2024-04-02
  • JavaScript中怎么实现一个插件系统
    这篇文章给大家介绍JavaScript中怎么实现一个插件系统,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。构建一个插件系统让我们从一个名为BetaCalc的示例项目开始。BetaCal...
    99+
    2024-04-02
  • vue中怎么实现一个购物车插件
    vue中怎么实现一个购物车插件,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。相关代码:<!DOCTYPE html> &...
    99+
    2024-04-02
  • vue中怎么实现一个无限轮播插件
    这篇文章给大家介绍vue中怎么实现一个无限轮播插件,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。思路:要实现无限轮播,需要在轮播图前后各加一张图片,加在前面的是轮播图的最后一张图片(重...
    99+
    2024-04-02
  • jquery插件实现代码雨特效
    本文实例为大家分享了jquery插件实现代码雨特效的具体代码,供大家参考,具体内容如下 代码雨特效 提供大概思路,虽然和目标的效果不一样,但是很容易举一反三改出对应效果的 效果如下 ...
    99+
    2024-04-02
  • Python一行代码实现一个文件服务器
    简述 Python有很多简单的工具库可用,其中有一个非常实用的工具库: SimpleHTTPServer 一行代码建立一个简单的python HTTP文件服务器 使用方法 $python -m SimpleHTTPServer S...
    99+
    2023-01-31
    代码 文件服务器 Python
  • 怎么实现mysql数据库性能诊断
    本篇文章给大家分享的是有关怎么实现mysql数据库性能诊断,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。 一:检查mysql所在的服务器的性...
    99+
    2024-04-02
  • jQuery中怎么实现一个浮动留言板插件
    jQuery中怎么实现一个浮动留言板插件,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。版本信息:Version: 1.0&nb...
    99+
    2024-04-02
  • linux中怎么利用CTags开发一个Sublime Text代码补完插件
    小编给大家分享一下linux中怎么利用CTags开发一个Sublime Text代码补完插件,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!开始编写新建插件刚开始接...
    99+
    2023-06-16
  • Android使用插件实现代码混淆
    目录1.下载AndroidProPlugin插件并安装重启 2.Android Studio安装插件3.成功安装AndroidProguardPlugin插件后我们在打包的...
    99+
    2024-04-02
  • vue如何实现一个弹窗插件
    这篇文章主要讲解了“vue如何实现一个弹窗插件”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“vue如何实现一个弹窗插件”吧!popup.vue<template> &l...
    99+
    2023-07-04
  • 怎么在html5中实现一个BUI折叠菜单插件
    本篇文章为大家展示了怎么在html5中实现一个BUI折叠菜单插件,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。一个点击显示隐藏的效果, 并且点击的时候, 会先把展开进行隐藏, 再展开自己的. 从界面...
    99+
    2023-06-09
  • 使用jquery怎么实现一个步骤进度轴插件
    使用jquery怎么实现一个步骤进度轴插件?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。代码部分*{margin: 0;padding: 0;}#div...
    99+
    2023-06-15
  • 80行代码写一个Webpack插件并发布到npm
    1. 前言 最近在学习 Webpack 相关的原理,以前只知道 Webpack 的配置方法,但并不知道其内部流程,经过一轮的学习,感觉获益良多,为了巩固学习的内容,我决定尝试自己动手...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作