@tuzhanai/schema-manager
Version:
343 lines (342 loc) • 12 kB
JavaScript
"use strict";
/**
* @gz/schema-manager
*
* @author Zongmin Lei <leizongmin@gmail.com>
* @author Yourtion Guo <yourtion@gmail.com>
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseTypeName = exports.SchemaType = exports.SchemaManager = void 0;
const assert = __importStar(require("assert"));
const value_type_manager_1 = require("@tuzhanai/value-type-manager");
__exportStar(require("@tuzhanai/value-type-manager"), exports);
class SchemaManager {
constructor(options = {}) {
this.options = options;
this.map = new Map();
if (options.type) {
this.type = options.type;
}
else {
this.type = new value_type_manager_1.ValueTypeManager();
}
}
/**
* 获取 abortEarly 选项
*/
get isAbortEarly() {
return this.options.abortEarly || false;
}
/**
* 注册Schema
* @param name 名称
* @param fields 字段具体信息
*/
register(name, fields) {
this.map.set(name, new SchemaType(this, fields, name));
return this;
}
/**
* 是否已注册指定Schema
* @param type 名称
*/
has(type) {
return this.map.has(type);
}
/**
* 获取指定Schema
* @param type 名称
*/
get(type) {
const s = this.map.get(type);
assert.ok(s, `schema type "${type}" does not exists`);
return s;
}
/**
* 遍历类型
* @param iter 迭代函数
*/
forEach(iter) {
return this.map.forEach(iter);
}
/**
* 创建Schema但不自动注册
* @param fields 字段信息
* @param name Schema名称
*/
create(fields, name) {
return new SchemaType(this, fields, name);
}
/**
* 检查指定Schema并返回值
* @param type 名称
* @param input 输入值
*/
value(type, input) {
const { name, isArray } = parseTypeName(type);
if (this.has(name)) {
return this.get(type).value(input, isArray);
}
const ret = this.baseTypeValue(name, isArray, input, {}, undefined);
if (ret.ok)
return ret;
return { ...ret, missingParamaters: [], invalidParamaters: [], invalidParamaterTypes: [] };
}
/**
* 检查指定基本类型并返回值
* @param type 名称
* @param isArray 是否为数组
* @param input 输入值
* @param params 类型参数
* @param format 是否格式化
*/
baseTypeValue(type, isArray, input, params, format) {
if (isArray) {
// 数组
if (!Array.isArray(input)) {
return { ok: false, message: `expected an ${type} array but got ${input}`, value: input };
}
const messages = [];
const values = [];
for (let i = 0; i < input.length; i++) {
const ret = this.type.value(type, input[i], params, format);
if (!ret.ok) {
messages.push(`at array index ${i}: ${ret.message}`);
if (this.isAbortEarly)
break;
}
values.push(ret.value);
}
if (messages.length > 0) {
return { ok: false, message: messages.join("\n"), value: values };
}
return { ok: true, message: "success", value: values };
}
return this.type.value(type, input, params, format);
}
}
exports.SchemaManager = SchemaManager;
class SchemaType {
constructor(manager, fields, name = "") {
this.manager = manager;
this.fields = fields;
this.name = name;
}
/**
* 从当前Schema获取仅包含指定字段的新Schema
* @param fieldNames
*/
pick(...fieldNames) {
fieldNames.sort();
const fields = {};
for (const n of fieldNames) {
fields[n] = this.fields[n];
}
return new SchemaType(this.manager, fields, this.name && `Pick<${this.name}, ${fieldNames.map((n) => `"${n}"`).join(" | ")}>`);
}
/**
* 从当前Schema获取所有字段为可选的新Schema
*/
partial() {
const fields = {};
for (const n in this.fields) {
fields[n] = { ...this.fields[n], required: false };
}
return new SchemaType(this.manager, fields, this.name && `Partial<${this.name}>`);
}
/**
* 从当前Schema获取所有字段为必填的新Schema
*/
required() {
const fields = {};
for (const n in this.fields) {
fields[n] = { ...this.fields[n], required: true };
}
return new SchemaType(this.manager, fields, this.name && `Required<${this.name}>`);
}
/**
* 检查Schema并返回值
* @param input
*/
value(input, isArray = false) {
if (isArray) {
// 数组
if (!Array.isArray(input)) {
return { ok: false, message: `expected an ${this.name} array but got ${input}`, value: input };
}
const messages = [];
const values = [];
for (let i = 0; i < input.length; i++) {
const ret = this.value(input[i], false);
if (!ret.ok) {
messages.push(`at array index ${i}: ${ret.message}`);
if (this.manager.isAbortEarly)
break;
}
values.push(ret.value);
}
if (messages.length > 0) {
return { ok: false, message: messages.join("\n"), value: values };
}
return { ok: true, message: "success", value: values };
}
const messages = [];
const missingParamaters = [];
const invalidParamaters = [];
const invalidParamaterTypes = [];
const values = {};
// 遍历处理输入的 input 信息,与 对应的 Schema Type 的配置进行比较
for (const n in this.fields) {
const f = this.fields[n];
const v = input[n] === undefined ? f.default : input[n];
// 判断是否缺失某个字段
if (v === undefined) {
if (f.required) {
messages.push(`missing required paramater ${n}`);
missingParamaters.push(n);
if (this.manager.isAbortEarly)
break;
}
// 没有该字段,直接循环下一个 字段
continue;
}
let ret;
if (f.type instanceof SchemaType) {
ret = f.type.value(v);
}
else {
const { name, isArray } = parseTypeName(f.type);
if (this.manager.has(name)) {
ret = this.manager.get(name).value(v, isArray);
}
else {
ret = this.manager.baseTypeValue(name, isArray, v, f.params, f.format);
}
}
if (!ret.ok) {
messages.push(`at paramater ${n}: ${ret.message}`);
invalidParamaters.push(n);
invalidParamaterTypes.push(f.type instanceof SchemaType ? f.type.name : f.type);
if (this.manager.isAbortEarly)
break;
}
values[n] = ret.value;
}
if (messages.length > 0) {
return {
ok: false,
message: messages.join("\n"),
missingParamaters,
invalidParamaters,
invalidParamaterTypes,
value: values,
};
}
return { ok: true, message: "success", value: values };
}
/**
* 获取 schema swagger 的展开信息
* @param {boolean} [isArray=false]
* @returns {Record<string, any>} ISchemaTypeFieldInfo
* @memberof SchemaType
*/
swaggerValue() {
const values = {};
const required = [];
for (const n in this.fields) {
const f = this.fields[n];
values[n] = {};
// 判断是否是嵌套的 Schema
if (f.type instanceof SchemaType) {
let { required, properties } = f.type.swaggerValue();
values[n] = {
type: "object",
required: required,
properties: properties,
};
}
else {
const { name, isArray } = parseTypeName(f.type);
if (this.manager.has(name) && isArray) {
let { required, properties } = this.manager.get(name).swaggerValue();
values[n].type = "array";
values[n].description = f.comment || "";
values[n].items = {
type: "object",
required: required,
properties: properties,
};
}
else if (this.manager.has(name)) {
let { required, properties } = this.manager.get(name).swaggerValue();
values[n] = {
type: "object",
required: required,
description: f.comment || "",
properties: properties,
};
}
else if (isArray) {
values[n] = {
type: "array",
description: f.comment,
enum: f.params || [],
items: {
type: this.manager.type.get(name).info.swaggerType,
},
};
f.default ? (values[n].default = f.default) : "";
f.required ? required.push(n) : "";
}
else {
values[n] = {
type: this.manager.type.get(name).info.swaggerType,
description: f.comment,
enum: f.params || [],
};
f.default ? (values[n].default = f.default) : "";
f.required ? required.push(n) : "";
}
}
}
return {
required,
properties: values,
};
}
}
exports.SchemaType = SchemaType;
/**
* 解析类型名称 判断在书写类型的时候 是否是 "type[]" 这种格式,是否是数组类型
* @param type 类型
*/
function parseTypeName(type) {
if (type.slice(-2) === "[]") {
return { name: type.slice(0, -2), isArray: true };
}
return { name: type, isArray: false };
}
exports.parseTypeName = parseTypeName;
exports.default = SchemaManager;