resolver-demo
一个解析 Api 源码生成 Demo 代码的解析器
Installation
npm i @esydoc/resolver-demo -D
Usage
在 esydoc.config.js
文件中的resolves
字段添加@esydoc/resolver-demo
对应的配置就 ok 拉。
{
resolves: {
'@esydoc/resolver-demo': {
excludes: [],
includes: [],
output: {
template: 'hyext-demo-miniapp',
dist: path.join(__dirname, 'demo-miniapp'),
hostContext: {
projectName: 'esydoc-demo'
}
}
}
}
}
无。
API 配置文件对应配置
我们知道,esydoc 会为每个标记了@eapi 标签的接口源码,生成一份以接口命名的配置文件,这里的对应配置
是指resolver-demo
输出的相应配置。
For example:
某 api 文件配置
const demo: DemoConfig = {
modifed: {}
}
const apiConfig = {
demo: demo
}
export type Modified = { [path: string]: ModifiedNodeMember }
export type ModifiedArgs = Modified
export type ModifiedNodeMember =
| ValueDescriptionNode
| ((node: ValueDescriptionNode) => ValueDescriptionNode)
export type Interceptors = { onCall?: (...args: any[]) => any }
export type DemoConfig = {
modified: Modified
validate?: Validate
} & Interceptors
接下来,我们来说说这几个参数的作用
Modifed 对象
Modifed 对象是一个可以间接修改 ValueDescriptionNode
的一个配置对象,key 为访问节点的路径,value 为节点配置的子集
。
For example:
SDK 源码:
testApi(name, id) {
}
如果我想封装一下 id 这个参数,原本的 input 组件改成 switch, 我们可以这样操作:
module.exports = {
demo: {
modified: {
id: {
formItemType: 'switch',
defaultValue: false,
onCall(helper, val) {
if (val === false) {
return 10086
} else {
return 10010
}
}
}
}
}
}
通过上面简单的配置,我们关于 id 字段的 input 组件,就会变为 switch 组件,那我们就不需要手动输入 id 了。
节点访问范围
由于 resolver 将 AST 转换为 ValueDescriptionNode 的过程中,对其进行了最大深度为 3 的树压缩。
何为深度为 3 的压缩?
第一层是 args,代表调用的参数
第二层是 args[0],代表其中一个参数
第三层是 args[0].obj,代表其中一个参数的子参数(如果有)
第四层是 args[0].obj.obj 如果节点再有可嵌套的子节点
,此时节点的 value 值是可嵌套的子节点
渲染的值
举例子:
testApi(params) {
}
看上面的代码 这个params
是一个无尽嵌套的对象(举例而已,也不是无尽嵌套,也可能是个很复杂的对象),如果我们不做压缩,那表单UI会一直渲染下去,会无比复杂,这并不是我们想要的结果,我们可以通过 压缩 + 节点封装
对其进行优化处理:
module.exports = {
demo: {
modified: {
'params.nestObj.nestObj': {
formItemType: 'select',
options: [
{
value: Mode.One,
label: '模式1',
isDefault: true
},
{
value: Mode.Two,
label: '模式2',
isDefault: false
}
],
onCall(helper, mode) {
return getObjByMode(mode)
}
}
}
}
}
通过上述简单的封装,我们就可以直接通过选择 mode 去生成对应复杂的对象,而不需要每个字段都去配置。
特殊节点
对于 array 数据类型不支持元组,只支持数组,例如:Array<Member>
, 数组里面的成员数据结构都是唯一的,它的访问方式跟问对象节点相似:
source code
testApi(params) {
}
配置:
module.exports = {
demo: {
modified: {
'params.MOCK': {
formItemType: 'input',
onCall() {
}
}
}
}
}
我们看到可以通过 params.MOCK
路径就能访问 MOCK 节点的数据,而不是使用 params[0] ...params[n]
,
上面已经说的很清楚,不支持元组风格的独立性修改,只能改所有数组成员的数据结构。
合并策略
目前比较low:Object.assign(ValueDescriptionNode, ModifedNode)
,
你也自定义:
module.exports = {
demo: {
modified: {
'params': (node) => {
return node
}
}
}
}
ValueDescriptionNode
ValueDescriptionNode 是对 UI 表单的一种抽象,直接控制 UI 该渲染什么组件,由 AST Node 转换而来
export type FormItemOption = {
value: any
label: string
isDefault: boolean
}
export type FormItemOptions = FormItemOption[]
export type ValueDescriptionNode = {
id: string
name: string
valueType: string
description: string
value: any
defaultValue: any
formItemType: 'input' | 'select' | 'switch' | 'checkbox' | 'slef-impliment'
options?: FormItemOptions
parentNodeType?: string
} & Interceptors
下面挑一些比较有内涵的参数介绍一下
description
description 是一个有约定的参数注释,具体请看下面图片解析:
![img](./doc/description-2.png)
formItemType
resolver 的模板会根据 formItemType 的不同生成不一样的表单控件
- 'input' - 输入框
- 'select' - 选择框
- 'switch' - 开关
- 'slef-impliment' - 自我实现
slef-impliment
为什么会有这个选项?
因为参数的类型多种多样,有一些特殊的情况,你就无法用到那些表单控件,所以这里用 slef-impliment 去跳过控件的渲染
我目前总结的特殊情况有如下:
- 当参数是一个函数,你不能直接用 ui 控件去展示
- 当参数是一个很复杂的对象,我不建议你直接去展示,你可以设置 slef-impliment,直接或间接修改 value
- 当参数需要的数据不适合从表单控件中获取的时候(例如:我需要一个原型对象),直接或间接修改 value
Interceptors
目前可以 Interceptors 存在于 ValueDescriptionNode 或 demo config 中
intercept hooks
- onCall(helper, ...args) - 当接口调用时触发。
一共有 2 个粒度,第一个是针对每个参数的 onCall(helper, value)(ValueDescriptionNode.onCall), 另一个是针对调用参数的 onCall(helper, ...args)(config.onCall)
module.exports = {
demo: {
modified: {
id: {
onCall(helper, val) {
if (val === false) {
return 10086
} else {
return 10010
}
}
}
},
onCall(helper, name, id) {
return [name, id]
}
}
}
helper
从上文得知,interceptor 的回调函数会传入一个 helper 对象,这个 helper 封装了一些接口,方面用户获取运行时的一些资源。
helper.getJceInfo()
- 返回一个 jce 信息对象,用于 jce 相关接口调用,数据结构具体如下:
{
uri: '8856',
class: HUYA // 结构体wrapper
}
helper.tip(msg:string)
- 弹出 toast
validate
validate 配置提供高定制表单验证功能
所有字段验证
- 当
validate:true
时,所有字段都会被验证,验证规则为'required' - 当
validate:${rules}
时,所有字段都会使用被验证,验证规则为 rules, rules 可以是单个规则也可以是多个,例如:'required'或者'required|date|some rule'
指定某些字段验证
输出默认错误模式,每个规则都有默认的错误语句
{
validate:{
[name]: true | 'date' | 'required|date'
}
}
自定义错误模式
{
validate:{
[name]: {
rules: 'required',
errors: ['这个xx字段你必须要填哦~']
}
}
}
内置规则
required
- 判断字段是否空白date
- 检查日期 格式:YYYY-MM-DD hh:mm:ssphone
- 检查手机号码格式
、
模板
hyext-demo-miniapp
- Demo 虎牙小程序模板