wangrong
2026-08-30 761e5c5fa871959f60e15c971c8d83f2b53d0af5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
import { isString, isObject, isNumber, isNull, isInteger, isEmpty, isBoolean } from 'lodash-es'
const isArray = Array.isArray
 
class Convert {
  constructor() {
    this._option = {
      $id: 'http://example.com/root.json',
      $schema: 'http://json-schema.org/draft-07/schema#'
    }
    this._object = null
  }
 
  /**
   * 转换函数
   * @param {*} object 需要转换的对象
   * @param {*} ?option 可选参数,目前只有能设置 root 节点的 $id 和 $schema
   */
  format(object, option = {}) {
    // 数据校验,确保传入的的object只能是对象或数组
    if (!isObject(object)) {
      throw new TypeError('传入参数只能是对象或数组')
    }
    // 合并属性
    this._option = Object.assign(this._option, option)
    // 需要转换的对象
    this._object = object
    let convertRes
    // 数组类型和对象类型结构不一样
    if (isArray(object)) {
      convertRes = this._arrayToSchema()
    } else {
      convertRes = this._objectToSchema()
    }
    // 释放
    this._object = null
    return convertRes
  }
 
  /**
   * 数组类型转换成JSONSCHEMA
   */
  _arrayToSchema() {
    // root节点基本信息
    const result = this._value2object(this._object, this._option.$id, '', true)
    if (this._object.length > 0) {
      const itemArr = []
      for (let index = 0; index < this._object.length; index++) {
        // 创建items对象的基本信息
        const objectItem = this._object[index]
        let item = this._value2object(objectItem, `#/items`, 'items')
        if (isObject(objectItem) && !isEmpty(objectItem)) {
          // 递归遍历
          const objectItemSchema = this._json2schema(objectItem, `#/items`)
          // 合并对象
          item = Object.assign(item, objectItemSchema)
        }
        itemArr.push(item)
      }
      result['items'] = itemArr
    }
    return result
  }
 
  /**
   * 对象类型转换成JSONSCHEMA
   */
  _objectToSchema() {
    let baseResult = this._value2object(this._object, this._option.$id, '', true)
    const objectSchema = this._json2schema(this._object)
    baseResult = Object.assign(baseResult, objectSchema)
    return baseResult
  }
 
  _json2schema(object, name = '') {
    // 如果递归值不是对象,那么return掉
    if (!isObject(object)) {
      return
    }
    // 处理当前路径$id
    if (name === '' || name === undefined) {
      name = '#'
    }
    const result = {}
    // 判断传入object是对象还是数组。
    if (isArray(object)) {
      result.items = {}
    } else {
      result.properties = {}
    }
    // 遍历传入的对象
    for (const key in object) {
      if (Object.prototype.hasOwnProperty.call(object, key)) {
        const element = object[key]
        // 如果只是undefined。跳过
        if (element === undefined) {
          continue
        }
        const $id = `${name}/properties/${key}`
        // 判断当前 element 的值 是否也是对象,如果是就继续递归,不是就赋值给result
        if (!result['properties']) {
          continue
        }
        if (isObject(element)) {
          // 创建当前属性的基本信息
          result['properties'][key] = this._value2object(element, $id, key)
          if (isArray(element)) {
            // 针对空数组和有值的数组做不同处理
            if (element.length > 0) {
              // 是数组
              const itemArr = []
              for (let index = 0; index < element.length; index++) {
                const elementItem = element[index]
                // 创建items对象的基本信息
                let item = this._value2object(elementItem, `${$id}/items`, key + 'items')
                // 判断第一项是否是对象,且对象属性不为空
                if (isObject(elementItem) && !isEmpty(elementItem)) {
                  // 新增的properties才合并进来
                  item = Object.assign(item, this._json2schema(elementItem, `${$id}/items`))
                }
                itemArr.push(item)
              }
              result['properties'][key]['items'] = itemArr
            }
          } else {
            // 不是数组,递归遍历获取,然后合并对象属性
            result['properties'][key] = Object.assign(
              result['properties'][key],
              this._json2schema(element, $id)
            )
          }
        } else {
          // 一般属性直接获取基本信息
          if (result['properties']) {
            result['properties'][key] = this._value2object(element, $id, key)
          }
        }
      }
    }
    return result
  }
 
  /**
   * 把json的值转换成对象类型
   * @param {*} value
   * @param {*} $id
   * @param {*} key
   */
  _value2object(value, $id, key = '', root = false) {
    const objectTemplate = {
      $id: $id,
      title: `The ${key} Schema`,
      mock: {
        mock: value
      }
    }
 
    // 判断是否为初始化root数据
    if (root) {
      objectTemplate['$schema'] = this._option.$schema
      objectTemplate['title'] = `The Root Schema`
      objectTemplate['mock'] = undefined
    }
    if (isBoolean(value)) {
      objectTemplate.type = 'boolean'
    } else if (isInteger(value)) {
      objectTemplate.type = 'integer'
    } else if (isNumber(value)) {
      objectTemplate.type = 'number'
    } else if (isString(value)) {
      objectTemplate.type = 'string'
    } else if (isNull(value)) {
      objectTemplate.type = 'null'
    } else if (isArray(value)) {
      objectTemplate.type = 'array'
      objectTemplate['mock'] = undefined
    } else if (isObject(value)) {
      objectTemplate.type = 'object'
      objectTemplate['mock'] = undefined
    }
 
    return objectTemplate
  }
}
export default Convert