123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098 |
- /*!
- * TSBuffer Validator v2.1.2
- * -----------------------------------------
- * MIT LICENSE
- * KingWorks (C) Copyright 2023
- * https://github.com/k8w/tsbuffer-validator
- */
- import 'k8w-extend-native';
- import { __assign } from 'tslib';
- import { SchemaType } from 'tsbuffer-schema';
- var ProtoHelper = /** @class */ (function () {
- function ProtoHelper(proto) {
- this._schemaWithUuids = [];
- this._unionPropertiesCache = {};
- this._flatInterfaceSchemaCache = {};
- this._parseMappedTypeCache = new WeakMap();
- this.proto = proto;
- }
- /** 将ReferenceTypeSchema层层转换为它最终实际引用的类型 */
- ProtoHelper.prototype.parseReference = function (schema) {
- // Reference
- if (schema.type === SchemaType.Reference) {
- var parsedSchema = this.proto[schema.target];
- if (!parsedSchema) {
- throw new Error("Cannot find reference target: ".concat(schema.target));
- }
- if (this.isTypeReference(parsedSchema)) {
- return this.parseReference(parsedSchema);
- }
- else {
- return parsedSchema;
- }
- }
- // IndexedAccess
- else if (schema.type === SchemaType.IndexedAccess) {
- if (!this.isInterface(schema.objectType)) {
- throw new Error("Error objectType: ".concat(schema.objectType.type));
- }
- // find prop item
- var flat = this.getFlatInterfaceSchema(schema.objectType);
- var propItem = flat.properties.find(function (v) { return v.name === schema.index; });
- var propType = void 0;
- if (propItem) {
- propType = propItem.type;
- }
- else {
- if (flat.indexSignature) {
- propType = flat.indexSignature.type;
- }
- else {
- throw new Error("Error index: ".concat(schema.index));
- }
- }
- // optional -> | undefined
- if (propItem && propItem.optional && // 引用的字段是optional
- (propItem.type.type !== SchemaType.Union // 自身不为Union
- // 或自身为Union,但没有undefined成员条件
- || propItem.type.members.findIndex(function (v) { return v.type.type === SchemaType.Literal && v.type.literal === undefined; }) === -1)) {
- propType = {
- type: SchemaType.Union,
- members: [
- { id: 0, type: propType },
- {
- id: 1,
- type: {
- type: SchemaType.Literal,
- literal: undefined
- }
- }
- ]
- };
- }
- return this.isTypeReference(propType) ? this.parseReference(propType) : propType;
- }
- else if (schema.type === SchemaType.Keyof) {
- var flatInterface = this.getFlatInterfaceSchema(schema.target);
- return {
- type: SchemaType.Union,
- members: flatInterface.properties.map(function (v, i) { return ({
- id: i,
- type: {
- type: SchemaType.Literal,
- literal: v.name
- }
- }); })
- };
- }
- else {
- return schema;
- }
- };
- ProtoHelper.prototype.isInterface = function (schema, excludeReference) {
- if (excludeReference === void 0) { excludeReference = false; }
- if (!excludeReference && this.isTypeReference(schema)) {
- var parsed = this.parseReference(schema);
- return this.isInterface(parsed, excludeReference);
- }
- else {
- return schema.type === SchemaType.Interface || this.isMappedType(schema) && this.parseMappedType(schema).type === SchemaType.Interface;
- }
- };
- ProtoHelper.prototype.isMappedType = function (schema) {
- return schema.type === SchemaType.Pick ||
- schema.type === SchemaType.Partial ||
- schema.type === SchemaType.Omit ||
- schema.type === SchemaType.Overwrite;
- };
- ProtoHelper.prototype.isTypeReference = function (schema) {
- return schema.type === SchemaType.Reference || schema.type === SchemaType.IndexedAccess || schema.type === SchemaType.Keyof;
- };
- ProtoHelper.prototype._getSchemaUuid = function (schema) {
- var schemaWithUuid = schema;
- if (!schemaWithUuid.uuid) {
- schemaWithUuid.uuid = this._schemaWithUuids.push(schemaWithUuid);
- }
- return schemaWithUuid.uuid;
- };
- ProtoHelper.prototype.getUnionProperties = function (schema) {
- var uuid = this._getSchemaUuid(schema);
- if (!this._unionPropertiesCache[uuid]) {
- this._unionPropertiesCache[uuid] = this._addUnionProperties([], schema.members.map(function (v) { return v.type; }));
- }
- return this._unionPropertiesCache[uuid];
- };
- /**
- * unionProperties: 在Union或Intersection类型中,出现在任意member中的字段
- */
- ProtoHelper.prototype._addUnionProperties = function (unionProperties, schemas) {
- for (var i = 0, len = schemas.length; i < len; ++i) {
- var schema = this.parseReference(schemas[i]);
- // Interface及其Ref 加入interfaces
- if (this.isInterface(schema)) {
- var flat = this.getFlatInterfaceSchema(schema);
- flat.properties.forEach(function (v) {
- unionProperties.binaryInsert(v.name, true);
- });
- if (flat.indexSignature) {
- var key = "[[".concat(flat.indexSignature.keyType, "]]");
- unionProperties.binaryInsert(key, true);
- }
- }
- // Intersection/Union 递归合并unionProperties
- else if (schema.type === SchemaType.Intersection || schema.type === SchemaType.Union) {
- this._addUnionProperties(unionProperties, schema.members.map(function (v) { return v.type; }));
- }
- else if (this.isMappedType(schema)) {
- this._addUnionProperties(unionProperties, [this.parseMappedType(schema)]);
- }
- }
- return unionProperties;
- };
- /**
- * 将unionProperties 扩展到 InterfaceTypeSchema中(optional的any类型)
- * 以此来跳过对它们的检查(用于Intersection/Union)
- */
- ProtoHelper.prototype.applyUnionProperties = function (schema, unionProperties) {
- var newSchema = __assign(__assign({}, schema), { properties: schema.properties.slice() });
- var _loop_1 = function (prop) {
- if (prop === '[[String]]') {
- newSchema.indexSignature = newSchema.indexSignature || {
- keyType: SchemaType.String,
- type: { type: SchemaType.Any }
- };
- }
- else if (prop === '[[Number]]') {
- newSchema.indexSignature = newSchema.indexSignature || {
- keyType: SchemaType.Number,
- type: { type: SchemaType.Any }
- };
- }
- else if (!schema.properties.find(function (v) { return v.name === prop; })) {
- newSchema.properties.push({
- id: -1,
- name: prop,
- optional: true,
- type: {
- type: SchemaType.Any
- }
- });
- }
- };
- for (var _i = 0, unionProperties_1 = unionProperties; _i < unionProperties_1.length; _i++) {
- var prop = unionProperties_1[_i];
- _loop_1(prop);
- }
- return newSchema;
- };
- /**
- * 将interface及其引用转换为展平的schema
- */
- ProtoHelper.prototype.getFlatInterfaceSchema = function (schema) {
- var uuid = this._getSchemaUuid(schema);
- // from cache
- if (this._flatInterfaceSchemaCache[uuid]) {
- return this._flatInterfaceSchemaCache[uuid];
- }
- if (this.isTypeReference(schema)) {
- var parsed = this.parseReference(schema);
- if (parsed.type !== SchemaType.Interface) {
- throw new Error("Cannot flatten non interface type: ".concat(parsed.type));
- }
- this._flatInterfaceSchemaCache[uuid] = this.getFlatInterfaceSchema(parsed);
- }
- else if (schema.type === SchemaType.Interface) {
- this._flatInterfaceSchemaCache[uuid] = this._flattenInterface(schema);
- }
- else if (this.isMappedType(schema)) {
- this._flatInterfaceSchemaCache[uuid] = this._flattenMappedType(schema);
- }
- else {
- // @ts-expect-error
- throw new Error('Invalid interface type: ' + schema.type);
- }
- return this._flatInterfaceSchemaCache[uuid];
- };
- /**
- * 展平interface
- */
- ProtoHelper.prototype._flattenInterface = function (schema) {
- var properties = {};
- var indexSignature;
- // 自身定义的properties和indexSignature优先级最高
- if (schema.properties) {
- for (var _i = 0, _a = schema.properties; _i < _a.length; _i++) {
- var prop = _a[_i];
- properties[prop.name] = {
- optional: prop.optional,
- type: prop.type
- };
- }
- }
- if (schema.indexSignature) {
- indexSignature = schema.indexSignature;
- }
- // extends的优先级次之,补全没有定义的字段
- if (schema.extends) {
- for (var _b = 0, _c = schema.extends; _b < _c.length; _b++) {
- var extend = _c[_b];
- // 解引用
- var parsedExtRef = this.parseReference(extend.type);
- if (this.isMappedType(parsedExtRef)) {
- parsedExtRef = this._flattenMappedType(parsedExtRef);
- }
- if (!this.isInterface(parsedExtRef)) {
- throw new Error('SchemaError: extends must from interface but from ' + parsedExtRef.type);
- }
- // 递归展平extends
- var flatenExtendsSchema = this.getFlatInterfaceSchema(parsedExtRef);
- // properties
- if (flatenExtendsSchema.properties) {
- for (var _d = 0, _e = flatenExtendsSchema.properties; _d < _e.length; _d++) {
- var prop = _e[_d];
- if (!properties[prop.name]) {
- properties[prop.name] = {
- optional: prop.optional,
- type: prop.type
- };
- }
- }
- }
- // indexSignature
- if (flatenExtendsSchema.indexSignature && !indexSignature) {
- indexSignature = flatenExtendsSchema.indexSignature;
- }
- }
- }
- return {
- type: SchemaType.Interface,
- properties: Object.entries(properties).map(function (v, i) { return ({
- id: i,
- name: v[0],
- optional: v[1].optional,
- type: v[1].type
- }); }),
- indexSignature: indexSignature
- };
- };
- /** 将MappedTypeSchema转换为展平的Interface
- */
- ProtoHelper.prototype._flattenMappedType = function (schema) {
- // target 解引用
- var target;
- if (this.isTypeReference(schema.target)) {
- var parsed = this.parseReference(schema.target);
- target = parsed;
- }
- else {
- target = schema.target;
- }
- var flatTarget;
- // 内层仍然为MappedType 递归之
- if (target.type === SchemaType.Pick || target.type === SchemaType.Partial || target.type === SchemaType.Omit || target.type === SchemaType.Overwrite) {
- flatTarget = this._flattenMappedType(target);
- }
- else if (target.type === SchemaType.Interface) {
- flatTarget = this._flattenInterface(target);
- }
- else {
- throw new Error("Invalid target.type: ".concat(target.type));
- }
- // 开始执行Mapped逻辑
- if (schema.type === SchemaType.Pick) {
- var properties = [];
- var _loop_2 = function (key) {
- var propItem = flatTarget.properties.find(function (v) { return v.name === key; });
- if (propItem) {
- properties.push({
- id: properties.length,
- name: key,
- optional: propItem.optional,
- type: propItem.type
- });
- }
- else if (flatTarget.indexSignature) {
- properties.push({
- id: properties.length,
- name: key,
- type: flatTarget.indexSignature.type
- });
- }
- };
- for (var _i = 0, _a = schema.keys; _i < _a.length; _i++) {
- var key = _a[_i];
- _loop_2(key);
- }
- return {
- type: SchemaType.Interface,
- properties: properties
- };
- }
- else if (schema.type === SchemaType.Partial) {
- for (var _b = 0, _c = flatTarget.properties; _b < _c.length; _b++) {
- var v = _c[_b];
- v.optional = true;
- }
- return flatTarget;
- }
- else if (schema.type === SchemaType.Omit) {
- var _loop_3 = function (key) {
- flatTarget.properties.removeOne(function (v) { return v.name === key; });
- };
- for (var _d = 0, _e = schema.keys; _d < _e.length; _d++) {
- var key = _e[_d];
- _loop_3(key);
- }
- return flatTarget;
- }
- else if (schema.type === SchemaType.Overwrite) {
- var overwrite = this.getFlatInterfaceSchema(schema.overwrite);
- if (overwrite.indexSignature) {
- flatTarget.indexSignature = overwrite.indexSignature;
- }
- var _loop_4 = function (prop) {
- flatTarget.properties.removeOne(function (v) { return v.name === prop.name; });
- flatTarget.properties.push(prop);
- };
- for (var _f = 0, _g = overwrite.properties; _f < _g.length; _f++) {
- var prop = _g[_f];
- _loop_4(prop);
- }
- return flatTarget;
- }
- else {
- throw new Error("Unknown type: ".concat(schema.type));
- }
- };
- ProtoHelper.prototype.parseMappedType = function (schema) {
- var cache = this._parseMappedTypeCache.get(schema);
- if (cache) {
- return cache;
- }
- // 解嵌套,例如:Pick<Pick<Omit, XXX, 'a'|'b'>>>
- var parents = [];
- var child = schema;
- do {
- parents.push(child);
- child = this.parseReference(child.target);
- } while (this.isMappedType(child));
- // 最内层是 interface,直接返回(validator 会验证 key 匹配)
- if (child.type === SchemaType.Interface) {
- this._parseMappedTypeCache.set(schema, child);
- return child;
- }
- // PickOmit<A|B> === PickOmit<A> | PickOmit<B>
- else if (child.type === SchemaType.Union || child.type === SchemaType.Intersection) {
- var newSchema = {
- type: child.type,
- members: child.members.map(function (v) {
- // 从里面往外装
- var type = v.type;
- for (var i = parents.length - 1; i > -1; --i) {
- var parent_1 = parents[i];
- type = __assign(__assign({}, parent_1), { target: type });
- }
- return {
- id: v.id,
- type: type
- };
- })
- };
- this._parseMappedTypeCache.set(schema, newSchema);
- return newSchema;
- }
- else {
- throw new Error("Unsupported pattern ".concat(schema.type, "<").concat(child.type, ">"));
- }
- };
- return ProtoHelper;
- }());
- var _a;
- /** @internal */
- var ErrorType;
- (function (ErrorType) {
- ErrorType["TypeError"] = "TypeError";
- ErrorType["InvalidScalarType"] = "InvalidScalarType";
- ErrorType["TupleOverLength"] = "TupleOverLength";
- ErrorType["InvalidEnumValue"] = "InvalidEnumValue";
- ErrorType["InvalidLiteralValue"] = "InvalidLiteralValue";
- ErrorType["MissingRequiredProperty"] = "MissingRequiredProperty";
- ErrorType["ExcessProperty"] = "ExcessProperty";
- ErrorType["InvalidNumberKey"] = "InvalidNumberKey";
- ErrorType["UnionTypesNotMatch"] = "UnionTypesNotMatch";
- ErrorType["UnionMembersNotMatch"] = "UnionMembersNotMatch";
- ErrorType["CustomError"] = "CustomError";
- })(ErrorType || (ErrorType = {}));
- /** @internal */
- var ErrorMsg = (_a = {},
- _a[ErrorType.TypeError] = function (expect, actual) { return "Expected type to be `".concat(expect, "`, actually `").concat(actual, "`."); },
- _a[ErrorType.InvalidScalarType] = function (value, scalarType) { return "`".concat(value, "` is not a valid `").concat(scalarType, "`."); },
- _a[ErrorType.TupleOverLength] = function (valueLength, schemaLength) { return "Value has ".concat(valueLength, " elements but schema allows only ").concat(schemaLength, "."); },
- _a[ErrorType.InvalidEnumValue] = function (value) { return "`".concat(value, "` is not a valid enum member."); },
- _a[ErrorType.InvalidLiteralValue] = function (expected, actual) { return "Expected to equals `".concat(stringify(expected), "`, actually `").concat(stringify(actual), "`"); },
- _a[ErrorType.MissingRequiredProperty] = function (propName) { return "Missing required property `".concat(propName, "`."); },
- _a[ErrorType.ExcessProperty] = function (propName) { return "Excess property `".concat(propName, "` should not exists."); },
- _a[ErrorType.InvalidNumberKey] = function (key) { return "`".concat(key, "` is not a valid key, the key here should be a `number`."); },
- // Union
- _a[ErrorType.UnionTypesNotMatch] = function (value, types) { return "`".concat(stringify(value), "` is not matched to `").concat(types.join(' | '), "`"); },
- _a[ErrorType.UnionMembersNotMatch] = function (memberErrors) { return "No union member matched, detail:\n".concat(memberErrors.map(function (v, i) { return " <".concat(i, "> ").concat(v.errMsg); }).join('\n')); },
- _a[ErrorType.CustomError] = function (errMsg) { return errMsg; },
- _a);
- /** @internal */
- function stringify(value) {
- if (typeof value === 'string') {
- var output = JSON.stringify(value);
- return "'" + output.substr(1, output.length - 2) + "'";
- }
- return JSON.stringify(value);
- }
- /** @internal */
- var ValidateResultError = /** @class */ (function () {
- function ValidateResultError(error) {
- this.isSucc = false;
- this.error = error;
- }
- Object.defineProperty(ValidateResultError.prototype, "errMsg", {
- get: function () {
- return ValidateResultError.getErrMsg(this.error);
- },
- enumerable: false,
- configurable: true
- });
- ValidateResultError.getErrMsg = function (error) {
- var _a;
- var errMsg = ErrorMsg[error.type].apply(ErrorMsg, error.params);
- if ((_a = error.inner) === null || _a === void 0 ? void 0 : _a.property.length) {
- return "Property `".concat(error.inner.property.join('.'), "`: ").concat(errMsg);
- }
- else {
- return errMsg;
- }
- };
- return ValidateResultError;
- }());
- /** @internal */
- var ValidateResultUtil = /** @class */ (function () {
- function ValidateResultUtil() {
- }
- ValidateResultUtil.error = function (type) {
- var params = [];
- for (var _i = 1; _i < arguments.length; _i++) {
- params[_i - 1] = arguments[_i];
- }
- return new ValidateResultError({
- type: type,
- params: params
- });
- };
- ValidateResultUtil.innerError = function (property, value, schema, error) {
- var _a;
- if (error.error.inner) {
- if (typeof property === 'string') {
- error.error.inner.property.unshift(property);
- }
- else {
- (_a = error.error.inner.property).unshift.apply(_a, property);
- }
- }
- else {
- error.error.inner = {
- property: typeof property === 'string' ? [property] : property,
- value: value,
- schema: schema
- };
- }
- return error;
- };
- ValidateResultUtil.succ = { isSucc: true };
- return ValidateResultUtil;
- }());
- var typedArrays = {
- Int8Array: Int8Array,
- Int16Array: Int16Array,
- Int32Array: Int32Array,
- BigInt64Array: typeof BigInt64Array !== 'undefined' ? BigInt64Array : undefined,
- Uint8Array: Uint8Array,
- Uint16Array: Uint16Array,
- Uint32Array: Uint32Array,
- BigUint64Array: typeof BigUint64Array !== 'undefined' ? BigUint64Array : undefined,
- Float32Array: Float32Array,
- Float64Array: Float64Array
- };
- /**
- * TSBuffer Schema Validator
- * @public
- */
- var TSBufferValidator = /** @class */ (function () {
- function TSBufferValidator(proto, options) {
- /**
- * Default options
- */
- this.options = {
- excessPropertyChecks: true,
- strictNullChecks: false,
- cloneProto: true
- };
- if (options) {
- this.options = __assign(__assign({}, this.options), options);
- }
- this.proto = this.options.cloneProto ? Object.merge({}, proto) : proto;
- this.protoHelper = new ProtoHelper(this.proto);
- }
- /**
- * Validate whether the value is valid to the schema
- * @param value - Value to be validated.
- * @param schemaId - Schema or schema ID.
- * For example, the schema ID for type `Test` in `a/b.ts` may be `a/b/Test`.
- */
- TSBufferValidator.prototype.validate = function (value, schemaOrId, options) {
- var _a, _b;
- var schema;
- var schemaId;
- // Get schema
- if (typeof schemaOrId === 'string') {
- schemaId = schemaOrId;
- schema = this.proto[schemaId];
- if (!schema) {
- throw new Error("Cannot find schema: ".concat(schemaId));
- }
- }
- else {
- schema = schemaOrId;
- }
- // Merge default options
- return this._validate(value, schema, __assign(__assign({}, options), { excessPropertyChecks: (_a = options === null || options === void 0 ? void 0 : options.excessPropertyChecks) !== null && _a !== void 0 ? _a : this.options.excessPropertyChecks, strictNullChecks: (_b = options === null || options === void 0 ? void 0 : options.strictNullChecks) !== null && _b !== void 0 ? _b : this.options.strictNullChecks }));
- };
- TSBufferValidator.prototype._validate = function (value, schema, options) {
- var _a;
- var vRes;
- // Validate
- switch (schema.type) {
- case SchemaType.Boolean:
- vRes = this._validateBooleanType(value, schema);
- break;
- case SchemaType.Number:
- vRes = this._validateNumberType(value, schema);
- break;
- case SchemaType.String:
- vRes = this._validateStringType(value, schema);
- break;
- case SchemaType.Array:
- vRes = this._validateArrayType(value, schema, options);
- break;
- case SchemaType.Tuple:
- vRes = this._validateTupleType(value, schema, options);
- break;
- case SchemaType.Enum:
- vRes = this._validateEnumType(value, schema);
- break;
- case SchemaType.Any:
- vRes = this._validateAnyType(value);
- break;
- case SchemaType.Literal:
- vRes = this._validateLiteralType(value, schema, (_a = options === null || options === void 0 ? void 0 : options.strictNullChecks) !== null && _a !== void 0 ? _a : this.options.strictNullChecks);
- break;
- case SchemaType.Object:
- vRes = this._validateObjectType(value, schema);
- break;
- case SchemaType.Interface:
- vRes = this._validateInterfaceType(value, schema, options);
- break;
- case SchemaType.Buffer:
- vRes = this._validateBufferType(value, schema);
- break;
- case SchemaType.IndexedAccess:
- case SchemaType.Reference:
- case SchemaType.Keyof:
- vRes = this._validateReferenceType(value, schema, options);
- break;
- case SchemaType.Union:
- vRes = this._validateUnionType(value, schema, options);
- break;
- case SchemaType.Intersection:
- vRes = this._validateIntersectionType(value, schema, options);
- break;
- case SchemaType.Pick:
- case SchemaType.Omit:
- case SchemaType.Partial:
- case SchemaType.Overwrite:
- vRes = this._validateMappedType(value, schema, options);
- break;
- case SchemaType.Date:
- vRes = this._validateDateType(value);
- break;
- case SchemaType.NonNullable:
- vRes = this._validateNonNullableType(value, schema, options);
- break;
- case SchemaType.Custom:
- var res = schema.validate(value);
- vRes = res.isSucc ? ValidateResultUtil.succ : ValidateResultUtil.error(ErrorType.CustomError, res.errMsg);
- break;
- // 错误的type
- default:
- // @ts-expect-error
- throw new Error("Unsupported schema type: ".concat(schema.type));
- }
- // prune
- if (options === null || options === void 0 ? void 0 : options.prune) {
- // don't need prune, return original value
- if (options.prune.output === undefined) {
- options.prune.output = value;
- }
- // output to parent
- if (options.prune.parent) {
- options.prune.parent.value[options.prune.parent.key] = options.prune.output;
- }
- }
- return vRes;
- };
- /**
- * 修剪 Object,移除 Schema 中未定义的 Key
- * 需要确保 value 类型合法
- * @param value - value to be validated
- * @param schemaOrId -Schema or schema ID.
- * @returns Validate result and pruned value. if validate failed, `pruneOutput` would be undefined.
- */
- TSBufferValidator.prototype.prune = function (value, schemaOrId, options) {
- var _a;
- var schema = typeof schemaOrId === 'string' ? this.proto[schemaOrId] : schemaOrId;
- if (!schema) {
- throw new Error('Cannot find schema: ' + schemaOrId);
- }
- var prune = {};
- var vRes = this._validate(value, schema, __assign(__assign({}, options), { prune: prune, excessPropertyChecks: false, strictNullChecks: (_a = options === null || options === void 0 ? void 0 : options.strictNullChecks) !== null && _a !== void 0 ? _a : this.options.strictNullChecks }));
- if (vRes.isSucc) {
- vRes.pruneOutput = prune.output;
- }
- return vRes;
- };
- TSBufferValidator.prototype._validateBooleanType = function (value, schema) {
- var type = this._getTypeof(value);
- if (type === 'boolean') {
- return ValidateResultUtil.succ;
- }
- else {
- return ValidateResultUtil.error(ErrorType.TypeError, 'boolean', type);
- }
- };
- TSBufferValidator.prototype._validateNumberType = function (value, schema) {
- // 默认为double
- var scalarType = schema.scalarType || 'double';
- // Wrong Type
- var type = this._getTypeof(value);
- var rightType = scalarType.indexOf('big') > -1 ? 'bigint' : 'number';
- if (type !== rightType) {
- return ValidateResultUtil.error(ErrorType.TypeError, rightType, type);
- }
- // scalarType类型检测
- // 整形却为小数
- if (scalarType !== 'double' && type === 'number' && !Number.isInteger(value)) {
- return ValidateResultUtil.error(ErrorType.InvalidScalarType, value, scalarType);
- }
- // 无符号整形却为负数
- if (scalarType.indexOf('uint') > -1 && value < 0) {
- return ValidateResultUtil.error(ErrorType.InvalidScalarType, value, scalarType);
- }
- return ValidateResultUtil.succ;
- };
- TSBufferValidator.prototype._validateStringType = function (value, schema) {
- var type = this._getTypeof(value);
- return type === 'string' ? ValidateResultUtil.succ : ValidateResultUtil.error(ErrorType.TypeError, 'string', type);
- };
- TSBufferValidator.prototype._validateArrayType = function (value, schema, options) {
- // is Array type
- var type = this._getTypeof(value);
- if (type !== SchemaType.Array) {
- return ValidateResultUtil.error(ErrorType.TypeError, SchemaType.Array, type);
- }
- // prune output
- var prune = options.prune;
- if (prune) {
- prune.output = Array.from({ length: value.length });
- }
- // validate elementType
- for (var i = 0; i < value.length; ++i) {
- var elemValidateResult = this._validate(value[i], schema.elementType, __assign(__assign({}, options), { prune: (prune === null || prune === void 0 ? void 0 : prune.output) ? {
- parent: {
- value: prune.output,
- key: i
- }
- } : undefined }));
- if (!elemValidateResult.isSucc) {
- return ValidateResultUtil.innerError('' + i, value[i], schema.elementType, elemValidateResult);
- }
- }
- return ValidateResultUtil.succ;
- };
- TSBufferValidator.prototype._validateTupleType = function (value, schema, options) {
- // is Array type
- var type = this._getTypeof(value);
- if (type !== SchemaType.Array) {
- return ValidateResultUtil.error(ErrorType.TypeError, SchemaType.Array, type);
- }
- var prune = options.prune;
- // validate length
- // excessPropertyChecks 与 prune互斥
- if (!prune && options.excessPropertyChecks && value.length > schema.elementTypes.length) {
- return ValidateResultUtil.error(ErrorType.TupleOverLength, value.length, schema.elementTypes.length);
- }
- // prune output
- if (prune) {
- prune.output = Array.from({ length: Math.min(value.length, schema.elementTypes.length) });
- }
- // validate elementType
- for (var i = 0; i < schema.elementTypes.length; ++i) {
- // MissingRequiredProperty: NotOptional && is undefined
- if (value[i] === undefined || value[i] === null && !options.strictNullChecks) {
- var canBeNull = this._canBeNull(schema.elementTypes[i]);
- var canBeUndefined = schema.optionalStartIndex !== undefined && i >= schema.optionalStartIndex || this._canBeUndefined(schema.elementTypes[i]);
- var isOptional = canBeUndefined || !options.strictNullChecks && canBeNull;
- // skip undefined property
- if (isOptional) {
- // Prune null & undefined->null
- if (prune === null || prune === void 0 ? void 0 : prune.output) {
- if (value[i] === null && canBeNull
- || value[i] === undefined && !canBeUndefined && canBeNull) {
- prune.output[i] = null;
- }
- }
- continue;
- }
- else {
- return ValidateResultUtil.error(ErrorType.MissingRequiredProperty, i);
- }
- }
- // element type check
- var elemValidateResult = this._validate(value[i], schema.elementTypes[i], {
- prune: (prune === null || prune === void 0 ? void 0 : prune.output) ? {
- parent: {
- value: prune.output,
- key: i
- }
- } : undefined,
- strictNullChecks: options.strictNullChecks,
- excessPropertyChecks: options.excessPropertyChecks
- });
- if (!elemValidateResult.isSucc) {
- return ValidateResultUtil.innerError('' + i, value[i], schema.elementTypes[i], elemValidateResult);
- }
- }
- return ValidateResultUtil.succ;
- };
- TSBufferValidator.prototype._canBeUndefined = function (schema) {
- var _this = this;
- if (schema.type === SchemaType.Union) {
- return schema.members.some(function (v) { return _this._canBeUndefined(v.type); });
- }
- if (schema.type === SchemaType.Literal && schema.literal === undefined) {
- return true;
- }
- return false;
- };
- TSBufferValidator.prototype._canBeNull = function (schema) {
- var _this = this;
- if (schema.type === SchemaType.Union) {
- return schema.members.some(function (v) { return _this._canBeNull(v.type); });
- }
- if (schema.type === SchemaType.Literal && schema.literal === null) {
- return true;
- }
- return false;
- };
- TSBufferValidator.prototype._validateEnumType = function (value, schema) {
- // must be string or number
- var type = this._getTypeof(value);
- if (type !== 'string' && type !== 'number') {
- return ValidateResultUtil.error(ErrorType.TypeError, 'string | number', type);
- }
- // 有值与预设相同
- if (schema.members.some(function (v) { return v.value === value; })) {
- return ValidateResultUtil.succ;
- }
- else {
- return ValidateResultUtil.error(ErrorType.InvalidEnumValue, value);
- }
- };
- TSBufferValidator.prototype._validateAnyType = function (value) {
- return ValidateResultUtil.succ;
- };
- TSBufferValidator.prototype._validateLiteralType = function (value, schema, strictNullChecks) {
- // 非strictNullChecks严格模式,null undefined同等对待
- if (!strictNullChecks && (schema.literal === null || schema.literal === undefined)) {
- return value === null || value === undefined ?
- ValidateResultUtil.succ
- : ValidateResultUtil.error(ErrorType.InvalidLiteralValue, schema.literal, value);
- }
- return value === schema.literal ?
- ValidateResultUtil.succ
- : ValidateResultUtil.error(ErrorType.InvalidLiteralValue, schema.literal, value);
- };
- TSBufferValidator.prototype._validateObjectType = function (value, schema) {
- var type = this._getTypeof(value);
- return type === 'Object' || type === 'Array' ? ValidateResultUtil.succ : ValidateResultUtil.error(ErrorType.TypeError, 'Object', type);
- };
- TSBufferValidator.prototype._validateInterfaceType = function (value, schema, options) {
- var type = this._getTypeof(value);
- if (type !== 'Object') {
- return ValidateResultUtil.error(ErrorType.TypeError, 'Object', type);
- }
- // 先展平
- var flatSchema = this.protoHelper.getFlatInterfaceSchema(schema);
- // From union or intersecton type
- if (options.unionProperties) {
- flatSchema = this.protoHelper.applyUnionProperties(flatSchema, options.unionProperties);
- }
- return this._validateFlatInterface(value, flatSchema, options);
- };
- TSBufferValidator.prototype._validateMappedType = function (value, schema, options) {
- var parsed = this.protoHelper.parseMappedType(schema);
- if (parsed.type === SchemaType.Interface) {
- return this._validateInterfaceType(value, schema, options);
- }
- else if (parsed.type === SchemaType.Union) {
- return this._validateUnionType(value, parsed, options);
- }
- else if (parsed.type === SchemaType.Intersection) {
- return this._validateIntersectionType(value, parsed, options);
- }
- // @ts-expect-error
- throw new Error("Invalid ".concat(schema.type, " target type: ").concat(parsed.type));
- };
- TSBufferValidator.prototype._validateFlatInterface = function (value, schema, options) {
- // interfaceSignature强制了key必须是数字的情况
- if (schema.indexSignature && schema.indexSignature.keyType === SchemaType.Number) {
- for (var key in value) {
- if (!this._isNumberKey(key)) {
- return ValidateResultUtil.error(ErrorType.InvalidNumberKey, key);
- }
- }
- }
- var prune = options.prune;
- if (prune) {
- prune.output = {};
- }
- // Excess property check (与prune互斥)
- if (!prune && options.excessPropertyChecks && !schema.indexSignature) {
- var validProperties_1 = schema.properties.map(function (v) { return v.name; });
- var firstExcessProperty = Object.keys(value).find(function (v) { return validProperties_1.indexOf(v) === -1; });
- if (firstExcessProperty) {
- return ValidateResultUtil.error(ErrorType.ExcessProperty, firstExcessProperty);
- }
- }
- // 校验properties
- if (schema.properties) {
- for (var _i = 0, _a = schema.properties; _i < _a.length; _i++) {
- var property = _a[_i];
- // MissingRequiredProperty: is undefined && !isOptional
- if (value[property.name] === undefined || value[property.name] === null && !options.strictNullChecks) {
- var canBeNull = this._canBeNull(property.type);
- var canBeUndefined = property.optional || this._canBeUndefined(property.type);
- var isOptional = canBeUndefined || !options.strictNullChecks && canBeNull;
- // skip undefined optional property
- if (isOptional) {
- // Prune null & undefined->null
- if (prune === null || prune === void 0 ? void 0 : prune.output) {
- if (value[property.name] === null && canBeNull
- || value[property.name] === undefined && !canBeUndefined && canBeNull) {
- prune.output[property.name] = null;
- }
- }
- continue;
- }
- else {
- return ValidateResultUtil.error(ErrorType.MissingRequiredProperty, property.name);
- }
- }
- // property本身验证
- var vRes = this._validate(value[property.name], property.type, {
- prune: (prune === null || prune === void 0 ? void 0 : prune.output) && property.id > -1 ? {
- parent: {
- value: prune.output,
- key: property.name
- }
- } : undefined,
- strictNullChecks: options.strictNullChecks,
- excessPropertyChecks: options.excessPropertyChecks
- });
- if (!vRes.isSucc) {
- return ValidateResultUtil.innerError(property.name, value[property.name], property.type, vRes);
- }
- }
- }
- // 检测indexSignature
- if (schema.indexSignature) {
- for (var key in value) {
- // only prune is (property is pruned already)
- // let memberPrune: ValidatePruneOptions | undefined = schema.properties.some(v => v.name === key) ? undefined : {};
- // validate each field
- var vRes = this._validate(value[key], schema.indexSignature.type, {
- prune: (prune === null || prune === void 0 ? void 0 : prune.output) ? {
- parent: {
- value: prune.output,
- key: key
- }
- } : undefined,
- strictNullChecks: options.strictNullChecks,
- excessPropertyChecks: options.excessPropertyChecks
- });
- if (!vRes.isSucc) {
- return ValidateResultUtil.innerError(key, value[key], schema.indexSignature.type, vRes);
- }
- }
- }
- return ValidateResultUtil.succ;
- };
- TSBufferValidator.prototype._validateBufferType = function (value, schema) {
- var _a, _b;
- var type = this._getTypeof(value);
- if (type !== 'Object') {
- return ValidateResultUtil.error(ErrorType.TypeError, schema.arrayType || 'ArrayBuffer', type);
- }
- else if (schema.arrayType) {
- var typeArrayClass = typedArrays[schema.arrayType];
- if (!typeArrayClass) {
- throw new Error("Error TypedArray type: ".concat(schema.arrayType));
- }
- return value instanceof typeArrayClass ? ValidateResultUtil.succ : ValidateResultUtil.error(ErrorType.TypeError, schema.arrayType, (_a = value === null || value === void 0 ? void 0 : value.constructor) === null || _a === void 0 ? void 0 : _a.name);
- }
- else {
- return value instanceof ArrayBuffer ? ValidateResultUtil.succ : ValidateResultUtil.error(ErrorType.TypeError, 'ArrayBuffer', (_b = value === null || value === void 0 ? void 0 : value.constructor) === null || _b === void 0 ? void 0 : _b.name);
- }
- };
- TSBufferValidator.prototype._validateReferenceType = function (value, schema, options) {
- return this._validate(value, this.protoHelper.parseReference(schema), options);
- };
- TSBufferValidator.prototype._validateUnionType = function (value, schema, options) {
- var _this = this;
- options.unionProperties = options.unionProperties || this.protoHelper.getUnionProperties(schema);
- var isObjectPrune = false;
- var prune = options.prune;
- if (prune && value && Object.getPrototypeOf(value) === Object.prototype) {
- isObjectPrune = true;
- prune.output = {};
- }
- // 有一成功则成功
- var isSomeSucc = false;
- var memberErrors = [];
- for (var i = 0; i < schema.members.length; ++i) {
- var member = schema.members[i];
- var memberType = this.protoHelper.isTypeReference(member.type) ? this.protoHelper.parseReference(member.type) : member.type;
- var memberPrune = prune ? {} : undefined;
- var vRes = this._validate(value, memberType, __assign(__assign({}, options), { prune: memberPrune }));
- if (vRes.isSucc) {
- isSomeSucc = true;
- // if prune object: must prune all members
- if (isObjectPrune) {
- prune.output = __assign(__assign({}, prune.output), memberPrune.output);
- }
- // not prune object: stop checking after 1st member matched
- else {
- break;
- }
- }
- else {
- memberErrors.push(vRes);
- }
- }
- // 有一成功则成功;
- if (isSomeSucc) {
- return ValidateResultUtil.succ;
- }
- // 全部失败,则失败
- else {
- // All member error is the same, return the first
- var msg0_1 = memberErrors[0].errMsg;
- if (memberErrors.every(function (v) { return v.errMsg === msg0_1; })) {
- return memberErrors[0];
- }
- // mutual exclusion: return the only one
- var nonLiteralErrors = memberErrors.filter(function (v) { return v.error.type !== ErrorType.InvalidLiteralValue; });
- if (nonLiteralErrors.length === 1) {
- return nonLiteralErrors[0];
- }
- // All member error without inner: show simple msg
- if (memberErrors.every(function (v) { return !v.error.inner && (v.error.type === ErrorType.TypeError || v.error.type === ErrorType.InvalidLiteralValue); })) {
- var valueType = this._getTypeof(value);
- var expectedTypes = memberErrors.map(function (v) { return v.error.type === ErrorType.TypeError ? v.error.params[0] : _this._getTypeof(v.error.params[0]); }).distinct();
- // Expected type A|B|C, actually type D
- if (expectedTypes.indexOf(valueType) === -1) {
- return ValidateResultUtil.error(ErrorType.TypeError, expectedTypes.join(' | '), this._getTypeof(value));
- }
- // `'D'` is not matched to `'A'|'B'|'C'`
- if (valueType !== 'Object' && valueType !== SchemaType.Array) {
- var types = memberErrors.map(function (v) { return v.error.type === ErrorType.TypeError ? v.error.params[0] : stringify(v.error.params[0]); }).distinct();
- return ValidateResultUtil.error(ErrorType.UnionTypesNotMatch, value, types);
- }
- }
- // other errors
- return ValidateResultUtil.error(ErrorType.UnionMembersNotMatch, memberErrors);
- }
- };
- TSBufferValidator.prototype._validateIntersectionType = function (value, schema, options) {
- options.unionProperties = options.unionProperties || this.protoHelper.getUnionProperties(schema);
- var isObjectPrune = false;
- var prune = options.prune;
- if (prune && value && Object.getPrototypeOf(value) === Object.prototype) {
- prune.output = {};
- isObjectPrune = true;
- }
- // 有一失败则失败
- for (var i = 0, len = schema.members.length; i < len; ++i) {
- // 验证member
- var memberType = schema.members[i].type;
- memberType = this.protoHelper.isTypeReference(memberType) ? this.protoHelper.parseReference(memberType) : memberType;
- var memberPrune = prune ? {} : undefined;
- var vRes = this._validate(value, memberType, __assign(__assign({}, options), { prune: memberPrune }));
- // 有一失败则失败
- if (!vRes.isSucc) {
- return vRes;
- }
- if (isObjectPrune) {
- prune.output = __assign(__assign({}, prune.output), memberPrune.output);
- }
- }
- // 全成功则成功
- return ValidateResultUtil.succ;
- };
- TSBufferValidator.prototype._validateDateType = function (value) {
- if (value instanceof Date) {
- return ValidateResultUtil.succ;
- }
- else {
- return ValidateResultUtil.error(ErrorType.TypeError, 'Date', this._getTypeof(value));
- }
- };
- TSBufferValidator.prototype._validateNonNullableType = function (value, schema, options) {
- var type = this._getTypeof(value);
- if ((type === 'null' || type === 'undefined') && schema.target.type !== 'Any') {
- return ValidateResultUtil.error(ErrorType.TypeError, 'NonNullable', type);
- }
- return this._validate(value, schema.target, options);
- };
- TSBufferValidator.prototype._isNumberKey = function (key) {
- var int = parseInt(key);
- return !(isNaN(int) || ('' + int) !== key);
- };
- TSBufferValidator.prototype._getTypeof = function (value) {
- var type = typeof value;
- if (type === 'object') {
- if (value === null) {
- return 'null';
- }
- else if (Array.isArray(value)) {
- return SchemaType.Array;
- }
- else {
- return 'Object';
- }
- }
- return type;
- };
- return TSBufferValidator;
- }());
- export { ProtoHelper, TSBufferValidator };
|