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
版本及以前可見這個連接 ↩