@wujibase/data-schema-core
v1.0.46
Published
```js import { DataStub, DataSchema, getPatchedDataSchema, getDefaultValue } from "@wujibase/data-schema-core" import "@wujibase/data-schema-core/lib/presets/vue" // 如果你使用 Vue 开发应用,请务必引入这个先
Keywords
Readme
DataSchema Core
import { DataStub, DataSchema, getPatchedDataSchema, getDefaultValue } from "@wujibase/data-schema-core"
import "@wujibase/data-schema-core/lib/presets/vue" // 如果你使用 Vue 开发应用,请务必引入这个先
// 然后写代码常用用法
1. 补全 DataSchema
DataSchema 里有灵活的 $ref 机制,可以描述无限嵌套的对象,但是这会使得解析工具变得困难。
先看一个例子
const rawSchema = {
type: 'object',
title: '神奇嵌套对象',
fields: [
{ id: 'name', type: 'string' },
{ id: 'extra' /* , type: 漏了 */, required: false },
{ id: 'children', type: 'array', items: { $ref: '#' } },
],
}可以看到上面编写的 DataSchema 描述了一个对象,但是存在奇怪的问题:
- name 字段没有定义
required - extra 字段没有定义 type
- children 字段是一个数组,但是它的数组项格式,引用了根类型(就是这个整体),是一个循环的类型定义引用:
# 上面的 DataSchema,大概描述的是这样的东西
{
name: 'foobar',
extra: '这个字段可能是任意类型',
children: [ # 这个的数组项,和最外层的数据结构是一样的
{
name: 'sub1',
children: []
},
{
name: 'sub2',
extra: {},
children: [
{
name: '无限嵌套children',
children: []
}
]
},
]
}如果直接使用一开始写的 DataSchema,那肯定是要考虑很多边界情况的。
因此,这个包提供了一个 getPatchedDataSchema 的方法,能够生成一个 补全过的,可能无限嵌套的 新 DataSchema。
const schema = getPatchedDataSchema(rawSchema);然后你会发现,你拿到了一个自动补全后的完整 DataSchema:
// ...前略
schema.type === 'object'
schema.fields === [
{
id: 'name',
type: 'string',
required: true, // object 的 fields 里,字段的 required 都补全了默认值
},
{
id: 'extra',
type: 'any', // 未定义类型的字段,补全了 type: any
required: false,
},
{
id: 'children',
type: 'array',
items: {
$ref: '#', // 原来声明的 $ref 还在,
type: 'object', // 同时,还补全了 type 信息
fields: [ // 以及根类型(就是整个 schema 本体)里定义的全部字段
{ ... },
{ ... },
{ ... } // 然后在这第三个字段里,又无限地自动补全了。
]
},
required: true,
}
]这种被补全过的,具备无限嵌套的 DataSchema,我们叫做 PatchedDataSchema。
现在,你可以安心地读取 PatchedDataSchema 里每一个数据类型的 type、fields、items 等信息了, 不需要担心默认值缺失、$ref 等问题。
注意,这个 PatchedDataSchema 因为可能有无限嵌套的情况,因此请不要拿他 JSON.stringify,
仅在代码中需要时,通过 getPatchedDataSchema 生成即可。
2. 生成默认值
const ans = getDefaultValue({
type: 'object',
fields: [
{ id: 'foo', type: 'string' },
{ id: 'bar', type: 'number' },
{ id: 'baz', type: 'boolean', required: false },
]
})
// ==> { foo: "", bar: 0 }其实 getDefaultValue 还有第二参数,可以传入一个配置对象,支持下面参数:
useLorem: boolean,默认字符串和数字会使用空值,可设置这个为 true 则使用Lorem IpsumincludeOptional: boolean,默认会抛弃 required 为 false 的 field,如果需要的话,可将这个选项开启mockArrayItems: number,默认对于所有 array 都是生成空数组,这里可指定条数,可生成一些数组项(如果存在无限嵌套的情况,请勿开启)ignoreCondition: boolean,默认在生成对象时会遵守字段的 condition 并选择性剔除一些字段,将此设置为 true 则保留全部字段
3. 从其他格式,生成 DataSchema
| | | | 模块 | 用例覆盖 | 需要额外安装的 npm 包
|---|-|-----|-----|----|---
| JSON Schema | ⇄ | Data Schema | lib/convertor/jsonSchema | ✓ |
| Protobuf | → | Data Schema | lib/convertor/protobuf | ✓ | protocol-buffers-schema
| JSON Data | → | Data Schema | lib/convertor/jsonData | ✓ |
| 无极 FieldInfo | ⇄ | Data Schema | lib/convertor/wuji | |
使用方式举例:
⚠️ 注意:这里转化出来的 DataSchema,不是 PatchedDataSchema。这两者的区别,详见上文《补全 DataSchema》
import { fromJsonData } from '@wujibase/data-schema-core/convertor/jsonData';
import { fromJSONSchema, toJSONSchema } from '@wujibase/data-schema-core/convertor/jsonSchema';
// 从一个实际的数据转化
// 这个方法有第二可选参数,IDE自动补全会告诉你
const schema1 = fromJsonData({
tags: ['aaa', 'bbb'],
num: 123.456,
int: 1234,
str: 'foobar',
bool: true,
})
// 从 JSON Schema 转为 DataSchema
const schema2 = fromJSONSchema({
type: 'object',
required: ['name'],
properties: {
name: { type: 'string' },
credit_card: { type: 'number', examples: [12345] },
type: { type: 'number', enum: [1, 2, 3] },
billing_address: {
type: 'array',
items: { type: 'string' },
},
},
})4. DataStub
如果你需要围绕 DataSchema + 实际数据,做一系列的操作, 想将不同的个字段,一个个绑定到不同的地方(比如编辑器组件),同时:
- 希望绑定到的地方,可以方便的获取当前字段的 schema 信息、上游、下级等
- 希望数据的读写更安全,不被链路上的 null 和 undefined 坑掉
- 希望读写行为有统一的、准确的 watch 能力
- 生成某字段的默认值
- (如果当前字段是一个 object)获取当前 object 可用 fields(DataSchema 支持定义字段的存在条件)
- (如果当前字段是有枚举定义的)获取枚举选项(DataSchema 支持定义动态枚举选项)
- ……
那么,你可以使用 schema + 初始 value,创建一个 DataStub,完成上述操作。并且,通过它还能获取到各个子字段的子 DataStub,如法炮制。
上述场景里需要的信息、能力,都可以在 DataStub 实例中找到。
const schema: DataSchema = {
type: 'array',
items: {
type: 'object',
fields: [
{ id: 'name', type: 'string' },
{ id: 'code', type: 'number' },
],
},
};
const stub = new DataStub({
schema,
value: null, // 初始值为 null
});
console.log(stub.schema); // 获取 schema,输出 Patched DataSchema
console.log(stub.value); // 一开始的初始值是 null
console.log(stub.length); // == 0 数组长度
stub.push({ name: 'xxx', code: 123 }); // 即使整个数据为 null,也可以 push
console.log(stub.value); // 然后就有数据了: [ { name: 'xxx', code: 123 } ]
console.log(stub.length); // == 1
// 子 DataStub 使用示例
const code1 = stub.getStubAtPath('[1].code') // 指向一个不存在的数据实体
console.log(code1.schema) // 取 schema,输出 { id: 'code', type: 'number', required: true }
console.log(code1.value) // 取值,虽然数据不存在,但只是输出 undefined,不会报错
code1.value = 1234 // 为不存在的路径( [1].code )赋值
console.log(code1.value) // 输出 1234
console.log(stub.value); // 输出 [ { name: 'xxx', code: 123 }, { code: 1234 } ]
console.log(stub.length); // == 2