Babel自动生成Attribute文档实现详解

news2024/11/14 20:24:36

这篇文章主要为大家介绍了Babel自动生成Attribute文档实现示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助!

1. 前言

利用Babel自动解析源码属性上的注释生成对应Markdown文档,这个场景的应用主要包括在组件库文档对组件属性的介绍中,这一篇就通过编写一个Babel插件来实现这个功能~

2. 开发自动生成属性文档插件

2.1 生成Babel插件模板:

  • 2.1.1 创建babel-plugin-auto-attr-doc文件夹;

  • 2.1.2 安装npm i -g yo generator-babel-plugin-x

  • 2.1.3 在新建目录下执行 yo babel-plugin-x:v7-ts

生成的插件模板如下:

babel-plugin-auto-attr-doc  
├─ lib  
│  └─ index.js  
├─ src  
│  └─ index.ts  
├─ __tests__
│  ├─ fixtures  
│  │  └─ example
│  │ ├─ actual.ts   
│  │ └─ expected.ts 
│  └─ index.js  
├─ package-lock.json
├─ package.json 
├─ README.md
└─ tsconfig.json

2.2 转换思路详解:

转换过程:利用Babel将Typescript脚本解析为AST,通过对AST结构分析抽离对应的注释部分,再拼接Markdown表格风格的语法;

源码要求:**我们应该将组件涉及到对外提供的属性统一到对应的types.ts文件管理,分别导出对应的type字段;

注释要求:**分别定义字段描述、类型、可选项、默认值4项,由于解析器关键词冲突原因,我们应该尽量避免;

/**
  * @cDescribe 类型
  * @cType string
  * @cOptions 
  * @cDefault 
  */
 export type IType = "primary" | "success" | "warning" | "danger" | "info";
 /**
  * @cDescribe 图标组件
  * @cType string
  * @cOptions 
  * @cDefault 
  */
 export type IIcon = string;
 /**
  * @cDescribe 是否为朴素按钮
  * @cType boolean
  * @cOptions 
  * @cDefault false
  */
 export type IPlain = boolean;
Markdown表格:**展示组件的属性、描述、类型、可选值和默认值这几项;

 

 

2.3 单元测试用例:

  • 准备插件待解析源码文件source-code.ts

  • 准备实际生成MD后应该显示的内容文件actual.md

| 属性名 | 说明 | 类型 | 可选值	| 默认值 |
| ------ | ---- | ---- | ----- | ----- |
| type | 类型 | string |  |  |
| icon | 图标组件 | string |  |  |
| plain | 是否为朴素按钮 | boolean |  | false |
  • 调整单元测试文件读取:

it(`should ${caseName.split("-").join(" ")}`, () => {
  const actualPath = path.join(fixtureDir, "source-code.ts");
  // 对源码进行加载解析
  transformFileSync(actualPath);
  // 读取我们准备好的md文件
  const actual = fs
.readFileSync(path.join(fixtureDir, "actual.md"))
.toString();
  // 读取插件解析生成的md文件
  const expected = fs
.readFileSync(path.join(fixtureDir, "api-doc.md"))
.toString();
  // diff
  const diff = diffChars(actual, expected);
  diff.length > 1 && _print(diff);
  expect(diff.length).toBe(1);
});

2.4 AST分析详解:

  • 通过在AST explorer的源码分析,我们在Babel中可以通过遍历ExportNamedDeclaration(命名导出声明);

  • leadingComments数组中可以取出所有注释文本的集合,在Babel处理时我们需要依次处理每一块注释后增加标记来避免重复处理;

  • (path.node.declaration as t.TypeAlias).id.name中取属性名称;

将注释文本通过doctrine模块解析为对象后和属性名合并对转换Markdown所需要的所有数据~

2.5 插件开发过程:

2.5.1 定义Comment、ApiTable类型对象:

type Comment =
  | {
  describe: string;
  type: any;
  options?: any;
  default?: any;
}
  | undefined;
type ApiTable = {
  attributeName: any;
  attributeDescribe: any;
  attributeType: any;
  attributeOptions: any;
  attributeDefault: any;
};

2.5.2 插件主逻辑分析:

  • pre:初始化存放apidoc容器,避免在存放时找不到容器;

  • visitor:解析源码并获取组织MD内容数据暂存到apidoc中;

  • post:取出所有的apidoc内容解析并输出到本地文件中;

export default declare(
  (api: BabelAPI, options: Record<string, any>, dirname: string) => {
api.assertVersion(7);
return {
  name: "auto-attr-doc",
  pre(this: PluginPass, file: BabelFile) {
this.set("api-doc", []);
  },
  visitor: {
ExportNamedDeclaration(
  path: NodePath<t.ExportNamedDeclaration>,
  state: PluginPass
) {
  const apidoc = state.get("api-doc");
  // 处理 path.node.leadingComments 中未处理的数据后塞到apidoc中
  state.set("api-doc", apidoc);
},
  },
  post(this: PluginPass, file: BabelFile) {
const apidoc = this.get("api-doc");
const output = generateMD(apidoc);
const root = path.parse(file.opts.filename || "./").dir;
fs.writeFileSync(path.join(root, "api-doc.md"), output, {
  encoding: "utf-8",
});
  },
} as PluginObj<PluginPass>;
  }
);

2.5.3 主逻辑实现:

leadingComments数组会在依次访问ExportNamedDeclaration时不停增加,我们在处理掉当前索引的对象后增加一个处理过的标记skip,下次循环直接跳过;

通过parseComment函数解析后的对象可以通过tags数组获取到所有的注释项目,通过对应的title得到对应description内容;

在往apidoc存放数据时需要处理属性名称符合一定的规则,并将apidoc对象存放到原容器中;

{
  ExportNamedDeclaration(
path: NodePath<t.ExportNamedDeclaration>,
state: PluginPass
  ) {
const apidoc = state.get("api-doc");
let _comment: Comment = undefined;
path.node.leadingComments?.forEach((comment) => {
  if (!Reflect.has(comment, "skip")) {
const tags = parseComment(comment.value)?.tags;
_comment = {
  describe:
tags?.find((v) => v.title === "cDescribe")?.description || "",
  type: tags?.find((v) => v.title === "cType")?.description || "",
  options:
tags?.find((v) => v.title === "cOptions")?.description || "",
  default:
tags?.find((v) => v.title === "cDefault")?.description || "",
};
Reflect.set(comment, "skip", true);
  }
});
apidoc.push({
  attributeName: (path.node.declaration as t.TypeAlias).id.name.substr(1).toLocaleLowerCase(),
  attributeDescribe: _comment!.describe,
  attributeType: _comment!.type,
  attributeOptions: _comment!.options,
  attributeDefault: _comment!.default,
} as ApiTable);
state.set("api-doc", apidoc);
  },
}

2.5.4 注释解析函数:

const parseComment = (comment: string) => {
  if (!comment) {
return;
  }
  return doctrine.parse(comment, {
unwrap: true,
  });
};

2.5.5 Markdown表格拼装:

const generateMD = (apidoc: Array<ApiTable>) => {
  let raw = `| 属性名 | 说明 | 类型 | 可选值	| 默认值 |\n| ------ | ---- | ---- | ----- | ----- |\n`;
  apidoc.forEach((item) => {
raw += `| ${item.attributeName} | ${item.attributeDescribe} | ${item.attributeType} | ${item.attributeOptions} | ${item.attributeDefault} |\n`;
  });
  return raw;
};

2.5.6生成结果展示~

3. 总结

插件生成目前基本功能完成,注释解析可以通过Babel的插件选项来定义作为一个扩展方向,MD文件的生成可以通过对应工具转换,更多的输出文件类型也可以作为扩展方向,欢迎喜欢玩转Babel的小伙伴一起交流交流~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/59500.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot单元测试

文章目录1、什么是单元测试2、单元测试有哪些好处&#xff1f;3、SpringBoot 单元测试使用3.1 生成单元测试的类3.2 配置单元测试的类并添加SpringBootTest注解3.3 添加单元测试的业务代码3.4 进行测试并查看结果3.5 使用断言3.6 在不修改数据库的前提下&#xff0c;执行单元测…

室内温度控制仿真模型(Simulink+PLC)

本篇博客将会和大家一起一步步解读Simulink自带的仿真模型(Thermal Model of a House),之后再讨论PLC控制系统控制环境温度的一些经验方法。温度控制的大部分控制方法都是采用PID控制,有关PLC的PID控制相关内容可以参看专栏的其它文章,链接如下: 博途PLC 1200/1500PID P…

【LeetCode每日一题:1774. 最接近目标价格的甜点成本~~~递归+深度优先遍历】

题目描述 你打算做甜点&#xff0c;现在需要购买配料。目前共有 n 种冰激凌基料和 m 种配料可供选购。而制作甜点需要遵循以下几条规则&#xff1a; 必须选择 一种 冰激凌基料。 可以添加 一种或多种 配料&#xff0c;也可以不添加任何配料。 每种类型的配料 最多两份 。 给你…

java计算机毕业设计ssm人事考勤管理系统1u133(附源码、数据库)

java计算机毕业设计ssm人事考勤管理系统1u133&#xff08;附源码、数据库&#xff09; 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff0…

Spread 16.X FOR WPF 中文版 我就喜欢 Spread.NET

Spread 16.X FOR WPF 中文版您可以将 Microsoft Excel 的强大功能嵌入到 WPF 和 Silverlight 应用中&#xff0c;使用丰富的内嵌数据可视化功能展现核心数据和分析结果&#xff0c;按需自定制富有创意的表格模版以及发挥更多便捷高效的功能。Spread WPF-Silverlight 源自备受好…

RIoTBoard开发板系列笔记(十三)—— yocto SDK安装与使用

yocto是一个很强大的嵌入式image 构建工具&#xff0c;借助yocto可以轻松的构建出一个开发板镜像。如果我们想借助yocto开发一些应用层的程序&#xff0c;有以下两种方法可供选择&#xff1a; &#xff08;1&#xff09;按照yocto的构建规则添加自己的程序和编译脚步&#xff0…

通话蓝牙耳机什么牌子好?通话工作蓝牙耳机推荐

在一般人的印象中&#xff0c;蓝牙耳机主要是用于听听歌、打打游戏还有煲剧&#xff0c;&#xff0c;而对经常经常外出的商务差旅人士和音乐发烧友来说&#xff0c;蓝牙耳机的通话和续航也是重点关注的&#xff0c;因此&#xff0c;笔者专门整理了一些通话效果好的蓝牙耳机&…

微服务框架 SpringCloud微服务架构 9 初识 Docker 9.3 Docker 架构

微服务框架 【SpringCloudRabbitMQDockerRedis搜索分布式&#xff0c;系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 SpringCloud微服务架构 文章目录微服务框架SpringCloud微服务架构9 初识 Docker9.3 Docker 架构9.3.1 镜像和容器9.3.2 Docker 和DockerHub9…

【C/C++】C语言runtime调用技术

概述 C语言编译后&#xff0c;在可执行文件中会有 函数名信息。如果想要动态调用一个C函数&#xff0c;首先需要 根据函数名找到这个函数地址 &#xff0c;然后根据函数地址进行调用。 动态链接器已经提供一个 API&#xff1a;dlsym()&#xff0c;可以通过函数名字拿到函数地…

k8s中service资源与pod详解

文章目录一、Service1、创建集群内部可访问的Service2、创建集群外部也可访问的Service3、配置方式编写二、pod详解1、pod配置文件的资源列表2、pod配置3、启动命令4、port端口配置三、资源配额一、Service 通过上节课的学习&#xff0c;已经能够利用Deployment来创建一组Pod来…

vue.js生命周期函数

Vue生命周期 beforecreate : 举个例子&#xff1a;可以在这加个loading事件created &#xff1a;在这结束loading&#xff0c;还做一些初始化&#xff0c;实现函数自执行mounted &#xff1a; 在这发起后端请求&#xff0c;拿回数据&#xff0c;配合路由钩子做一些事情beforeD…

QT系列第1节 QT中窗口使用简介

QT中窗口按照使用场景分类&#xff0c;可以分成两大类&#xff0c;一类是独立显示的窗口&#xff0c;主要是 QWidget &#xff0c;QDialog &#xff0c;QMainWindow&#xff0c;一类是嵌套在别的窗口的子窗口&#xff0c;包含各种控件以及子窗口&#xff0c;窗口类图如下&#…

CV攻城狮入门VIT(vision transformer)之旅——VIT代码实战篇

&#x1f34a;作者简介&#xff1a;秃头小苏&#xff0c;致力于用最通俗的语言描述问题 &#x1f34a;专栏推荐&#xff1a;深度学习网络原理与实战 &#x1f34a;近期目标&#xff1a;写好专栏的每一篇文章 &#x1f34a;支持小苏&#xff1a;点赞&#x1f44d;&#x1f3fc;、…

超越所有Anchor-free方法!PP-YOLOE-R:一种高效的目标检测网络

点击下方卡片&#xff0c;关注“自动驾驶之心”公众号ADAS巨卷干货&#xff0c;即可获取点击进入→自动驾驶之心【目标检测】技术交流群后台回复【PPYOLO】获取论文、代码等更多资料&#xff01;超越所有Anchor-free方法&#xff01;PP-YOLOE-R&#xff1a;一种高效的目标检测网…

基于粒子群优化算法的微型燃气轮机冷热电联供系统优化调度(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️❤️&#x1f4a5;&#x1f4a5;&#x1f4a5; &#x1f389;作者研究&#xff1a;&#x1f3c5;&#x1f3c5;&#x1f3c5;主要研究方向是电力系统和智能算法、机器学…

APISIX安装与灰度、蓝绿发布

文章目录1、安装1.1、基于docker安装1.2、基于RPM安装2、灰度发布与蓝绿发布测试2.1、compose安装nginx2.1.1、创建目录2.1.2、编辑nginx.conf配置文件2.1.3、编辑docker-compose.yml文件2.1.4、启动nginx2.2、部署apisix和apisix-dashboard2.3、traffic-split插件实现灰度和蓝…

【能效管理】安科瑞远程预付费系统在江西某沃尔玛收费管理的应用

摘要&#xff1a;文章根据用电远程管控原理&#xff0c;设计了用电预付费远程管理终端及管理系统&#xff0c;该系统以智能远程预付费电表、智能网关以及预付费管理软件实现了商业综合体的用电管理&#xff0c;实现了欠费自动分闸&#xff0c;充值后自动合闸&#xff0c;并辅助…

我用diffusion把姐妹cos成了灭霸的模样

卷友们好&#xff0c;我是rumor。关注早的朋友们应该知道&#xff0c;我有个姐妹&#xff0c;她去年回深圳老家了&#xff0c;本来我觉得还ok&#xff0c;还能再约着一起旅游。谁知道一年多了&#xff0c;我还没出过北京&#xff08;微笑。以前有个快乐源泉&#xff0c;就是照她…

谈谈Vue项目打包的方式

目录 一、相关配置 情况一&#xff08;使用的工具是 vue-cil&#xff09; 情况二&#xff08;使用的工具是 webpack&#xff09; 二、打包 &#x1f4da; 参考资料 这篇文章主要为大家介绍了Vue项目的打包方式&#xff0c;具有一定的参考价值&#xff0c;感兴趣的小伙伴…

[附源码]计算机毕业设计基于springboot的低碳生活记录网站

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…