欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Typescript中interface自動(dòng)化生成API文檔詳解

 更新時(shí)間:2022年12月27日 08:15:25   作者:孟祥_成都  
ypeScript 的核心原則之一是對(duì)值所具有的結(jié)構(gòu)進(jìn)行類型檢查,下面這篇文章主要給大家介紹了關(guān)于Typescript中interface自動(dòng)化生成API文檔的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下

前言

最近在搞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)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論