DevUI是一支兼具设计视角和工程视角的团队,服务于华为云 DevCloud平台和华为内部数个中后台系统,服务于设计师和前端工程师。
官方网站: devui.design
Ng组件库: ng-devui(欢迎Star)
官方交流群:添加DevUI小助手(微信号:devui-official)进群
DevUIHelper插件:DevUIHelper-LSP(欢迎Star)
为了提高DevUI组件对于使用者的易用性:javascript
例如输入d-button
,vscode会自动联想,选中后会出现代码块:<d-button (btnClick)=‘’> </d-button>
1css
即提升开发者写出<d-button type=‘‘primary‘’></d-button>
的效率,当写完后鼠标悬浮到type上时,应该出现type的相关描述.
而类型,默认值与说明,应与网站中API页面type的描述保持一致.拆分一下能够有这两个需求:html
<d-
这样的组件标签,能够提示API
并补全,同时能够提示参数并补全.目前彷佛许多UI库尚未实现将api文档从网站搬到代码中,咱们或许能够实现"api文档赋能页面".前端
原始版本功能设想以下,鱼骨图靠近鱼头的部分意味着优先级较高,应优先开发。
作着作着伴随着解bug,新想法又冒出来:依赖查找报警/补全时图片提示/提供GUI的自定义图片....java
本插件站在了前辈的基础上,以及参考了Angular Language Service插件的解析器部分进行开发,总的逻辑是获取素材+合适工具=功能实现.插件开发细节如函数注册
/package配置
等请见前辈文章,很是感谢他们的分享!node
LSP
,对标签句通过词法/语法/语义分析生成AST
代替本来的正则匹配,并将本来的Local API替换为Server APIparser
,尝试新增对指令的全功能支持以及自定义命令实现快速开发等题外话:工具怎么找到呢?事先学到了是一个, 读文档看API是一个,读源码溯源是一个.git
目前的架构以下图所示:github
server.ts
为入口,经过LSP提供的TCP链接创建与语言服务器的链接以便HOST
统筹调用功能API,同时激活(初始化)Parser
与资源模块,一个依据源代码生成抽象语法树,一个依据根据API文档对应生成的资源文件(.json
等格式)生成资源树。Hunter
节点树与资源树之间架起一座桥梁,一方面从抽象语法树中获得节点信息后去资源树中查询对应资源,一方面也采用缓存的办法提升下一次的查询效率。Position
和对应资源(可能还须要处理资源)做为参数传入LSP提供的功能API,进而实现对应功能。整体上架构未离开获取素材+合适工具=功能实现的总逻辑,不过值得注意Hunter
类的存在解决了节点资源树一同刷新的问题,也赋予了二者各自更多的可能性。这也正是高内聚低耦合的好处。正则表达式
为供api调用,预计网络传输开销大于本地预处理,所以素材可express
Java
处理后导出成module模块node_modules
中模块中已集成素材示例:
export const HTML_SCHEMA=[ "accordion||这是一个accordion组件", "data||Array<any>或AccordionMenuType||null||数据源||必选,数据源,能够自定义数组或者使用预设的AccordionMenuType||true||false||[]", "titleKey||string||title||标题的属性名||可选,标题的属性名,item[titleKey]类型为string,为标题显示内容||false||false||[]", "loadingKey||string||loading||子菜单是否加载中的判断属性名||可选,子菜单是否加载中的判断属性名,item[loadingKey]类型为boolean||false||false||[]", "childrenKey||string||children||子菜单的属性名||可选,子菜单的属性名,item[childrenKey]类型为Array<any>||false||false||[]" ]
若是api文档不够规范影响素材处理,可与组件团队协调解决或者建议团队采用Angular doc
这样的业界规范。而为了解决版本化的问题,最好的方案则是将素材模块集成入对应组件库的node_modules
中,也能够考虑产品自带模块处理脚本。
正则表达式(regular expression)描述了一种字符串匹配的模式(pattern),能够用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串等。
对于组件的特征,如
d-button
的d-
,Antdesign的Button
大写的B
以及引入的模块
import { DevUIModule } from 'ng-devui'
开发过程当中的操做
[]
(属性),()
(事件)等均可以做为正则匹配条件来实现条件限制或触发,代码示例:
//devui的使用以d-开头,如d-button,以此作触发 const componentRegex = /<(d-[a-zA-Z0-9-]*)\b[^<>]***/g; // 匹配"",而不是""和空格或者""和>,以此作""不触发而""外可触发的条件限制 const attributeValue= /^=\"[\s\S]*\"(?! |(>)\1)/;
经过看vscode本身的API文档2,能够打开实现各类功能的新世界。有可能得耐心看,能够逐层了解接口与返回值,以registerHoverProvider
为例:
微软推出LSP,意图标准化语言工具和代码编辑器之间的通讯:
其实在Angular框架和Jdk中都自带了LSP
的实现.在VS Code中,语言服务器包含两个部分:
JavaScript
/ TypeScript
编写的普通VS Code扩展。该扩展能够访问全部VS Code命名空间API。依托于语言或语言工具开发者提供的素材库/符合规范的接口,只要C/S之间创建起可靠的链接(如TCP
),Language Server就能够执行静态程序分析为指定特征代码(如组件库代码)或所有代码创建抽象语法树,来获得LSP
所提供API的接口所需的参数,代码编辑器即可以实现Client端包括自动补全、悬浮提示和自动纠错在内的许多功能.
抽象语法树是程序源代码结构的树状表示。程序源代码通过词法分析器(Lexer
)获得各类不一样种类的单词(Token
),再由语法分析器(Parser
3)分析和语法检查后获得抽象语法树(AST
)。对于以下C
语言代码:
while(i < n){ sum += A[i++]; }
能够生成如图的AST结构:
一般AST的根节点表示整个程序,内部节点是抽象语法结构或者单词。AST的核心在于它能与输入源代码中的各个语法元素一一对应。正好事实上,LSP的大部分请求都是在表达"在指定位置执行规定动做"---这意味着插件开发者只须要考虑什么时候触发以及何处触发指定操做便可,所以常见的参数即
URI
change.document
position
语法树即可以准确地提供Token
(包括单词)的position
.这正是经过正则表达式的匹配没法达到的优势。
固然,当深刻语言的编译原理时,其实也能够建立本身的语言定义了,想象空间十分大.
当在server文件夹的package.json
中引入vscode-languageserver
:
"dependencies": { "vscode-languageserver": "^4.1.3" }
以后开发者就可使用server的API了.
. ├── client // Language Client: able to use vscode API │ ├── src │ │ ├── test // End to End tests for Language Client / Server │ │ └── extension.ts // Language Client entry point ├── package.json // The extension manifest └── server // Language Server └── src └── server.ts // Language Server entry point
如前对AST的介绍,html
/css
/ts
/.d.ts
的文件均可以解析成语法树。以html文件为例,能够将每一级标签做为一个DOM
节点,组件语句则通过词法/语法/语义分析打碎成token
。
好比对<d-button bsStyle="primary"></button>
分割成
d-button
)style
)primary
)=""
),然后对每一分割的元素周围划定识别的范围(keySpan
),压栈后经序列化最终生成AST语法树。如对下列使用了DevUI
组件库的代码:
<div class="main"> <div class="left"> <d-accordion [data]="menu" class="menu" [restrictOneOpen]="restrictOneOpen" (itemClick)="itemClick(**event)" (menuToggle)="menuToggle(**event)"> hello </d-accordion> </div> <div class="content"> <app-table></app-table> </div> </div>
本插件生成的AST可部分表示为:
不过必须
注意,相似的工做已经有
posthtml这样的工具作了
5,而且若是要解析
markdown
之类也有对应的库,本身在开发以前"不要重复造轮子”.
每个组件标签最后能够实现一棵单树,在这样的森林里最后能够对光标周围的某个节点(position
)读取后对其父亲和孩子查找来实现节点树于资源树节点的匹配,理论上还能够autofix
或者依赖检查的功能.
这样的森林能够经过初始化分析创建Snapshot
来保存,当局部树改变时,做为dirty data
处理局部刷新快照.在早期(指2.0版本)的时候,能够借鉴这个思路作成Map,也即认为是单节点的树来查询.
- 与Angular或者其余工具的AST生成有何不一样?
答:主要在于分析的范围。以Angular为例,它是全文的,而且依赖于ts的解析器;而分析组件库就只有devui的部分:d-button -- bsStyle -- primary
这样的三级.
- 能够复用其余工具的AST吗?
答:理论上能够,可是要实现如Angular的AST对本身的DevUI很差扩展,且显得臃肿.
- 能够在本地调用markdown的解析包,或者本地实现markdown的解析展现吗?
答:有准备尝试!
- 能够适配其余组件库吗?
答:能够!获取素材+合适工具=功能实现是通用的,而对于某些特殊状况,除了单独建树也能够采用相似于限定某种功能仅当使用组件的同时使用[]
绑定变量或者()
绑定函数时被激活的操做,就像Angular
对基于它自身的devui
组件作的。事实上,业界Rome更进一步,但愿把基于AST的全部功能都统一块儿来,不要每一个工具本身作一次AST解析。
getName()
导出成模块解耦考虑插件没必要要时没必要激活
@angualr
<
或d-
html
或ts
值得注意的是,在早期这个或许只能考虑读取本地文件6使用正则表达式检测app.module.ts
中是否引入了devui
的依赖从而避免无效启动插件浪费资源;当升级了工具--使用AST来获取元素Token
时,问题就迎刃而解了.
使用vsce
打包发布到vscode插件市场,打补丁更新的时候vsce publish patch
便可.注意可经过.vscodeignore
省略test
和out
等部分.
目前7DevUIHelper
4.0版本已在VSCode插件市场上线,欢迎star
,欢迎issue & pr
,欢迎使用! :-)
咱们是DevUI团队,欢迎来这里和咱们一块儿打造优雅高效的人机设计/研发体系。招聘邮箱:muyang2@huawei.com。
做者: 幕宾
责编: DevUI团队
《好用到飞起!VSCode插件DevUIHelper设计开发全攻略(二)》即将出炉,敬请期待~
往期文章推荐
《使用Git,10件你可能须要“反悔”的事》
《Web界面深色模式和主题化开发》
《手把手教你搭建一个灰度发布环境》
posthtml
转成的节点树对于位置信息不敏感,即上述的keySpan
.所以本项目选择了重写htmlparser
,后续可能会考虑在规范的posthtml
基础上添加节点的开始与结束信息. ↩ 2.0
版本及以前可见这个连接 ↩