Typescript中interface自動(dòng)化生成API文檔詳解
前言
最近在搞react組件庫,這兩天搞定了使用ast(抽象語法樹)去把interface轉(zhuǎn)為對(duì)象或者數(shù)組,這些數(shù)據(jù)就可以渲染為react組件的table或者markdown的table,啥意思呢,舉個(gè)例子:
UI層面
以下是interface的demo,被轉(zhuǎn)化
export interface TdAffixProps { /** * 指定滾動(dòng)的容器。數(shù)據(jù)類型為 String 時(shí),會(huì)被當(dāng)作選擇器處理,進(jìn)行節(jié)點(diǎn)查詢。示例:'body' 或 () => document.body * @default () => (() => window) */ container: any; /** * @desc 距離容器頂部達(dá)到指定距離后觸發(fā)固定 * @default 0 */ offsetBottom?: number; /** * @desc 距離容器底部達(dá)到指定距離后觸發(fā)固定 * @default 0 */ offsetTop?: number; /** * @desc 固釘定位層級(jí),樣式默認(rèn)為 500 */ zIndex?: number; /** * @desc 固定狀態(tài)發(fā)生變化時(shí)觸發(fā) */ onFixedChange?: (affixed: boolean, context: { top: number }) => void; }
轉(zhuǎn)化為類似:
數(shù)據(jù)層面
interface被轉(zhuǎn)化為數(shù)組,數(shù)組里的每一項(xiàng)如下,可以傳給table組件去渲染,當(dāng)然有人想渲染為markdown格式,那把下面的數(shù)組渲染為markdown的table就行了,沒啥難度。
{ "name": "TdAffixProps", "data": [ { "name": "container", "type": "any", "jsdoc": { "kind": 24, "description": "指定滾動(dòng)的容器。數(shù)據(jù)類型為 String 時(shí),會(huì)被當(dāng)作選擇器處理,進(jìn)行節(jié)點(diǎn)查詢。示例:'body' 或 () => document.body", "tags": [ { "kind": 25, "tagName": "default", "text": "() => (() => window)" } ] } }, { "name": "offsetBottom", "type": "number", "isOptionnal": "?", "jsdoc": { "kind": 24, "description": "", "tags": [ { "kind": 25, "tagName": "desc", "text": "距離容器頂部達(dá)到指定距離后觸發(fā)固定" }, { "kind": 25, "tagName": "default", "text": "0" } ] } }, { "name": "offsetTop", "type": "number", "isOptionnal": "?", "jsdoc": { "kind": 24, "description": "", "tags": [ { "kind": 25, "tagName": "desc", "text": "距離容器底部達(dá)到指定距離后觸發(fā)固定" }, { "kind": 25, "tagName": "default", "text": "0" } ] } }, { "name": "zIndex", "type": "number", "isOptionnal": "?", "jsdoc": { "kind": 24, "description": "", "tags": [ { "kind": 25, "tagName": "desc", "text": "固釘定位層級(jí),樣式默認(rèn)為 500" } ] } }, { "name": "onFixedChange", "type": "(affixed: boolean, context: { top: number }) => void", "isOptionnal": "?", "jsdoc": { "kind": 24, "description": "", "tags": [ { "kind": 25, "tagName": "desc", "text": "固定狀態(tài)發(fā)生變化時(shí)觸發(fā)" } ] } } ] }
我們需要的數(shù)據(jù)結(jié)構(gòu)
上面可以看到,我們需要的數(shù)據(jù)結(jié)構(gòu)是
{ name: xxx, // interface的名字, data: [ { name: xx, // interface里每一項(xiàng)的屬性名 type: xx, // interface里每一項(xiàng)的類型 isOptionnal: xx, // 是否是可選項(xiàng) jsDoc: {} // 后面細(xì)說 } ] }
簡單解釋一下jsdoc格式
JSDoc是一種文檔生成工具,可以用來為JavaScript代碼生成API文檔。它使用特殊的注釋格式來描述代碼中的類型、函數(shù)、變量等的用途、參數(shù)、返回值等信息。
例如,你可以在JavaScript代碼中使用如下的注釋來描述一個(gè)函數(shù):
/** * 描述文字 * @default 0 */ function sum(x, y) { return x + y; }
這段注釋會(huì)被解析為:
{ "kind": 24, // 忽略 "description": "描述文字", "tags": [ { "kind": 25, // 忽略 "tagName": "default", "text": 0 } ] }
AST解析技術(shù)選擇
為什么放棄babel
最開始我只知道babel,因?yàn)橛脀ebpack多了,不太了解ast相關(guān)的前端庫,然后很正常的這樣使用了,發(fā)現(xiàn)了問題:
const parser = require("@babel/parser") const traverse = require("@babel/traverse").default const generate = require('@babel/generator').default const fs = require("fs") fs.readFile('./type.ts', { encoding: 'utf-8' }, function (err, data) { if (err) throw err; const result = []; const ast = parser.parse(data, { sourceType: "unambiguous", plugins: ["typescript"] }); traverse(ast, { TSInterfaceDeclaration(path) { path.traverse({ TSPropertySignature(path) { console.log(path.node.key.name); console.log(path.node.leadingComments?.[0]?.value); }, }); } }); });
比如number這個(gè)類型在上述打印節(jié)點(diǎn)的時(shí)候的類型是TSNumberKeyword,但是我拿到TSNumberKeyword不是目的,我要number,這個(gè)咋辦,
你說簡單啊,做個(gè)映射
{ TSNumberKeyword: "number" }
好,我知道簡單的映射可以,但是還有function類型,我咋映射,我需要還原的嘛,然后我想到了直接用generator把類型片段還原,但是總感覺有點(diǎn)low。
其次,我沒法直接獲得jsdoc的類型,因?yàn)樽⑨尡举|(zhì)上就是字符串,然后自己去折騰為jsdoc格式。
所以我去看了一下arco cli里的轉(zhuǎn)換使用到了ts-morph這個(gè)庫,發(fā)現(xiàn)這個(gè)庫在我這個(gè)需求下,是非常適合的,接下來介紹。
順便提一句,我的實(shí)現(xiàn)比字節(jié)團(tuán)隊(duì)的arco cli要簡單非常非常多!
ts-morph
這個(gè)庫極大的緩解了不懂typescript繁瑣底層類型和方法的同學(xué),具體的方法和屬性真的也是挺多的。ts-morph是一個(gè)針對(duì) Typescrpit/Javascript的AST處理庫,可用于瀏覽、修改TS/JS的AST。
關(guān)于ts-morph的詳細(xì)文檔,參見其官網(wǎng):ts-morph.com/。
下面是我實(shí)現(xiàn)的基本思路(可以把里面的函數(shù)抽取為中間件,這樣更好維護(hù),目前懶得改了,類型沒認(rèn)真寫,大家可以在我的基礎(chǔ)上自己封裝適合自己業(yè)務(wù)的東西,思路還是很清晰的),后續(xù)會(huì)把它抽成一個(gè)單獨(dú)的庫給自己的react組件庫使用。
以下代碼說白了就一個(gè)簡單函數(shù),arco官方的cli工具雖然代碼也就200行的樣子,但是復(fù)雜度比我這個(gè)高很多。
自動(dòng)化生成代碼
import { Project } from "ts-morph"; const internalProject = new Project({ tsConfigFilePath: "./tsconfig.json", }); const sourceFile = internalProject.getSourceFile("./type.ts"); const interfaces = sourceFile!.getInterfaces(); const result:any[] = []; interfaces.forEach((inter_face)=>{ result.push({ name: '', data: [] }); const index = result.length - 1; result[index].name = inter_face.getName(); inter_face.getProperties().forEach((v) => { result[index].data.push({ name: v.getName(), type: v.getTypeNode()?.getText(), isOptionnal: v.getQuestionTokenNode()?.getText(), jsdoc:v.getJsDocs().map((jsDoc)=>{ return (jsDoc.getStructure()) })[0] }); }); }) console.log(result);
總結(jié)
到此這篇關(guān)于Typescript中interface自動(dòng)化生成API文檔的文章就介紹到這了,更多相關(guān)Typescript自動(dòng)化生成API文檔內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Typescript 中的 interface 和 type 到底有什么區(qū)別詳解
- 詳解TypeScript中type與interface的區(qū)別
- typeScript?核心基礎(chǔ)之接口interface
- TypeScript中正確使用interface和type的方法實(shí)例
- typescript中type和interface的區(qū)別有哪些
- TypeScript定義接口(interface)案例教程
- TypeScript中type和interface的區(qū)別及注意事項(xiàng)
- Typescript中 type 與 interface 的區(qū)別說明總結(jié)
相關(guān)文章
javascript實(shí)現(xiàn)帶節(jié)日和農(nóng)歷的日歷特效
這篇文章主要介紹了javascript實(shí)現(xiàn)帶節(jié)日和農(nóng)歷的日歷特效,效果十分棒,需要的朋友可以參考下2015-02-02JavaScript實(shí)現(xiàn)獲取某個(gè)元素相鄰兄弟節(jié)點(diǎn)的prev與next方法
這篇文章主要介紹了JavaScript實(shí)現(xiàn)獲取某個(gè)元素相鄰兄弟節(jié)點(diǎn)的prev與next方法,涉及JavaScript基于函數(shù)的判定及調(diào)用previousSibling與nextSibling的相關(guān)技巧,需要的朋友可以參考下2016-01-01javascript 折半查找字符在數(shù)組中的位置(有序列表)
折半查找字符在數(shù)組中的位置(有序列表),需要的朋友可以參考下。2010-12-12利用Webpack實(shí)現(xiàn)小程序多項(xiàng)目管理的方法
這篇文章主要介紹了利用Webpack實(shí)現(xiàn)小程序多項(xiàng)目管理的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-02-02使用JavaScript給圖片添加水印的實(shí)現(xiàn)方法封裝
圖片加水印是一種常見的圖像處理技術(shù),通常用于保護(hù)版權(quán)、防止盜用、增加圖片的識(shí)別度等多種場景,這篇文章主要給大家介紹了關(guān)于使用JavaScript給圖片添加水印的實(shí)現(xiàn)方法封裝,需要的朋友可以參考下2024-03-03二級(jí)域名或跨域共享Cookies的實(shí)現(xiàn)方法
適用于Asp。 在主域名設(shè)置的Cookie,在各子域名共用;適用于博客等提供二級(jí)域名。這個(gè)問題,以網(wǎng)上有眾多帖子,可惜都沒有完整解決。2008-08-08jJavaScript中toFixed()和正則表達(dá)式的坑
這篇文章主要介紹了jJavaScript中toFixed()和正則表達(dá)式的坑,toFixed方法可以把Number四舍五入為指定小數(shù)位數(shù)的數(shù)字,具體詳細(xì)內(nèi)容需要的小伙伴可以參考一下2022-04-04