npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@esydoc/resolver-demo

v2.1.3

Published

> TODO: description

Downloads

204

Readme

resolver-demo

一个解析 Api 源码生成 Demo 代码的解析器

Installation

npm i @esydoc/resolver-demo -D

Usage

esydoc.config.js文件中的resolves字段添加@esydoc/resolver-demo对应的配置就 ok 拉。

// for example in esydoc.config.js
{
  resolves: {
    '@esydoc/resolver-demo': {
      excludes: [], // glob Exp
      includes: [], // glob Exp
      output: {
        template: 'hyext-demo-miniapp',
        dist: path.join(__dirname, 'demo-miniapp'),
        hostContext: {
          projectName: 'esydoc-demo'
        }
      }
    }
  }
}

Esydoc Extra Config

无。

API 配置文件对应配置

我们知道,esydoc 会为每个标记了@eapi 标签的接口源码,生成一份以接口命名的配置文件,这里的对应配置是指resolver-demo输出的相应配置。

For example:

某 api 文件配置

const demo: DemoConfig = {
  modifed: {} // 可以修改参数描述节点的一个对象
}

const apiConfig = {
  demo: demo // 属于 resolver-demo 配置
}
export type Modified = { [path: string]: ModifiedNodeMember } // 配置需要修改的 描述节点, path 是访问路径

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 源码:

 /**
   * test api
   * @eapi
   * @param {string} name 输入参数
   * @param {number} id 输入参数
   * @returns {Promise<void>} 调用结果
   */
  testApi(name, id) {

  }

如果我想封装一下 id 这个参数,原本的 input 组件改成 switch, 我们可以这样操作:

// testApi接口配置
module.exports = {
  demo: {
    modified: {
      id: {
        // rewrite node propertys
        formItemType: 'switch', // 原来是string
        defaultValue: false, // 原来是 ''
        onCall(helper, val) {
          // 增加一个 intercept hook 拦截输入控制输出
          if (val === false) {
            return 10086
          } else {
            return 10010
          }
        }
      }
    }
  }
}

 通过上面简单的配置,我们关于 id 字段的 input 组件,就会变为 switch 组件,那我们就不需要手动输入 id 了。

节点访问范围

由于 resolver 将 AST 转换为 ValueDescriptionNode 的过程中,对其进行了最大深度为 3 的树压缩。

何为深度为 3 的压缩?

// 1 -> 2 -> 3
// args -> args[0] -> args[0].obj

第一层是 args,代表调用的参数

第二层是 args[0],代表其中一个参数

第三层是 args[0].obj,代表其中一个参数的子参数(如果有)

第四层是 args[0].obj.obj 如果节点再有可嵌套的子节点,此时节点的 value 值是可嵌套的子节点渲染的值

举例子:

/**
 * @edata 
 * @typedef {Object} NestObj
 * @property {NestObj} nestObj 
 */
 /**
   * test api
   * @eapi
   * @param {NestObj} params 输入参数
   * @returns {Promise<void>} 调用结果
   */
  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 数据类型不支持元组,只支持数组,例如:Array<Member>, 数组里面的成员数据结构都是唯一的,它的访问方式跟问对象节点相似:

source code

  /**
   * @edata
   * @typedef {Object} MOCK
   * @property {string} md5 资源的md5
   * @property {string} fileName 文件名
   * @property {Object} [param] 额外参数
   */

  /**
   * test api
   * @eapi
   * @param {Array<MOCK>} params 输入参数
   * @returns {Promise<void>} 调用结果
   */
  testApi(params) {

  }

配置:

module.exports = {
  demo: {
    modified: {
      'params.MOCK': {
        // rewrite node propertys
        formItemType: 'input',
        onCall() {
          // do someting
        }
      }
    }
  }
}

我们看到可以通过 params.MOCK 路径就能访问 MOCK 节点的数据,而不是使用 params[0] ...params[n], 上面已经说的很清楚,不支持元组风格的独立性修改,只能改所有数组成员的数据结构。

合并策略

目前比较low:Object.assign(ValueDescriptionNode, ModifedNode),

你也自定义:

module.exports = {
  demo: {
    modified: {
      'params': (node) => {
        // custom modifed
        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 // formItemType = select | checkbox存在
  parentNodeType?: string
} & Interceptors

下面挑一些比较有内涵的参数介绍一下

description

description 是一个有约定的参数注释,具体请看下面图片解析:

img img

formItemType

resolver 的模板会根据 formItemType 的不同生成不一样的表单控件

  • 'input' - 输入框
  • 'select' - 选择框
  • 'switch' - 开关
  • 'slef-impliment' - 自我实现

slef-impliment

为什么会有这个选项?

因为参数的类型多种多样,有一些特殊的情况,你就无法用到那些表单控件,所以这里用 slef-impliment 去跳过控件的渲染

我目前总结的特殊情况有如下:

  1. 当参数是一个函数,你不能直接用 ui 控件去展示
  2. 当参数是一个很复杂的对象,我不建议你直接去展示,你可以设置 slef-impliment,直接或间接修改 value
  3. 当参数需要的数据不适合从表单控件中获取的时候(例如:我需要一个原型对象),直接或间接修改 value

Interceptors

目前可以 Interceptors 存在于 ValueDescriptionNode 或 demo config 中

intercept hooks

  • onCall(helper, ...args) - 当接口调用时触发。

一共有 2 个粒度,第一个是针对每个参数的 onCall(helper, value)(ValueDescriptionNode.onCall), 另一个是针对调用参数的 onCall(helper, ...args)(config.onCall)

// testApi接口配置
module.exports = {
  demo: {
    modified: {
      id: {
        onCall(helper, val) {
          // 粒度 1
          if (val === false) {
            return 10086
          } else {
            return 10010
          }
        }
      }
    },
    onCall(helper, name, id) {
      // 粒度 2
      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' // true - 默认使用’required‘, {rule} - 动态指定规则
  }
}

自定义错误模式

{
  validate:{
    [name]: {
      rules: 'required',
      errors: ['这个xx字段你必须要填哦~']
    }
  }
}

内置规则

  • required - 判断字段是否空白
  • date - 检查日期 格式:YYYY-MM-DD hh:mm:ss
  • phone - 检查手机号码格式

模板

  • hyext-demo-miniapp - Demo 虎牙小程序模板