Added a method for data type validation through type conversion to Zod schemas.

This commit is contained in:
Revone 2023-08-28 18:43:09 +08:00
parent de5a001b6a
commit 61f465fe99
12 changed files with 145 additions and 148 deletions

View file

@ -46,7 +46,7 @@ wide range of data structures
<td>Tree Multiset</td>
<td><img src="https://raw.githubusercontent.com/zrwusa/assets/master/images/data-structure-typed/assets/tick.svg" alt=""></td>
<td><img src="https://raw.githubusercontent.com/zrwusa/assets/master/images/data-structure-typed/assets/tick.svg" alt=""></td>
<td><a href="https://data-structure-typed-docs.vercel.app/classes/TreeMultiSet.html"><span>TreeMultiSet</span></a></td>
<td><a href="https://data-structure-typed-docs.vercel.app/classes/TreeMultiset.html"><span>TreeMultiset</span></a></td>
<td><img src="https://raw.githubusercontent.com/zrwusa/assets/master/images/data-structure-typed/assets/tick.svg" alt=""></td>
</tr>
<tr>

15
package-lock.json generated
View file

@ -1,13 +1,16 @@
{
"name": "data-structure-typed",
"version": "1.18.7",
"version": "1.18.8",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "data-structure-typed",
"version": "1.18.7",
"version": "1.18.8",
"license": "MIT",
"dependencies": {
"zod": "^3.22.2"
},
"devDependencies": {
"@types/jest": "^29.5.3",
"@types/node": "^20.4.9",
@ -5768,6 +5771,14 @@
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/zod": {
"version": "3.22.2",
"resolved": "https://registry.npmjs.org/zod/-/zod-3.22.2.tgz",
"integrity": "sha512-wvWkphh5WQsJbVk1tbx1l1Ly4yg+XecD+Mq280uBGt9wa5BKSWf4Mhp6GmrkPixhMxmabYY7RbzlwVP32pbGCg==",
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
}
}
}

View file

@ -63,5 +63,8 @@
"ts-jest": "^29.1.1",
"typedoc": "^0.24.8",
"typescript": "^4.9.5"
},
"dependencies": {
"zod": "^3.22.2"
}
}

View file

@ -5,11 +5,11 @@
* @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
* @license MIT License
*/
import type {BinaryTreeNodeId, TreeMultiSetNodeNested, TreeMultiSetOptions} from '../types';
import {ITreeMultiSet, ITreeMultiSetNode} from '../interfaces';
import type {BinaryTreeNodeId, TreeMultisetNodeNested, TreeMultisetOptions} from '../types';
import {ITreeMultiset, ITreeMultisetNode} from '../interfaces';
import {AVLTree, AVLTreeNode} from './avl-tree';
export class TreeMultiSetNode<T = any, FAMILY extends TreeMultiSetNode<T, FAMILY> = TreeMultiSetNodeNested<T>> extends AVLTreeNode<T, FAMILY> implements ITreeMultiSetNode<T, FAMILY> {
export class TreeMultisetNode<T = any, FAMILY extends TreeMultisetNode<T, FAMILY> = TreeMultisetNodeNested<T>> extends AVLTreeNode<T, FAMILY> implements ITreeMultisetNode<T, FAMILY> {
/**
* The function creates a new node in a binary tree with an optional value and count.
* @param {BinaryTreeNodeId} id - The `id` parameter is the identifier for the binary tree node. It is used to uniquely
@ -18,18 +18,18 @@ export class TreeMultiSetNode<T = any, FAMILY extends TreeMultiSetNode<T, FAMILY
* meaning it can be omitted when calling the `createNode` method.
* @param {number} [count] - The `count` parameter represents the number of occurrences of the value in the binary tree
* node. It is an optional parameter, so it can be omitted when calling the `createNode` method.
* @returns The method is returning a new instance of the TreeMultiSetNode class, casted as the FAMILY type.
* @returns The method is returning a new instance of the TreeMultisetNode class, casted as the FAMILY type.
*/
override createNode(id: BinaryTreeNodeId, val?: T, count?: number): FAMILY {
return new TreeMultiSetNode(id, val, count) as FAMILY;
return new TreeMultisetNode(id, val, count) as FAMILY;
}
}
/**
* The only distinction between a TreeMultiSet and a AVLTree lies in the ability of the former to store duplicate nodes through the utilization of counters.
* The only distinction between a TreeMultiset and a AVLTree lies in the ability of the former to store duplicate nodes through the utilization of counters.
*/
export class TreeMultiSet<N extends TreeMultiSetNode<N['val'], N> = TreeMultiSetNode> extends AVLTree<N> implements ITreeMultiSet<N> {
constructor(options?: TreeMultiSetOptions) {
export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultisetNode> extends AVLTree<N> implements ITreeMultiset<N> {
constructor(options?: TreeMultisetOptions) {
super({...options, isMergeDuplicatedVal: true});
}
@ -43,6 +43,6 @@ export class TreeMultiSet<N extends TreeMultiSetNode<N['val'], N> = TreeMultiSet
* @returns A new instance of the BSTNode class with the specified id, value, and count (if provided).
*/
override createNode(id: BinaryTreeNodeId, val?: N['val'], count?: number): N {
return new TreeMultiSetNode(id, val, count) as N;
return new TreeMultisetNode(id, val, count) as N;
}
}

View file

@ -1,12 +1,12 @@
import {TreeMultiSetNode} from '../binary-tree';
import {TreeMultisetNode} from '../binary-tree';
import {IBSTNode} from './bst';
import {IAVLTree} from './avl-tree';
export interface ITreeMultiSetNode<T, FAMILY extends ITreeMultiSetNode<T, FAMILY>> extends IBSTNode<T, FAMILY> {
export interface ITreeMultisetNode<T, FAMILY extends ITreeMultisetNode<T, FAMILY>> extends IBSTNode<T, FAMILY> {
}
export interface ITreeMultiSet<N extends TreeMultiSetNode<N['val'], N>> extends IAVLTree<N> {
export interface ITreeMultiset<N extends TreeMultisetNode<N['val'], N>> extends IAVLTree<N> {
}

View file

@ -1,8 +1,8 @@
import {TreeMultiSetNode} from '../binary-tree';
import {TreeMultisetNode} from '../binary-tree';
import {AVLTreeOptions} from './avl-tree';
export type TreeMultiSetNodeNested<T> = TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, TreeMultiSetNode<T, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
export type TreeMultisetNodeNested<T> = TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
export type TreeMultiSetOptions = Omit<AVLTreeOptions, 'isMergeDuplicatedVal'> & {
export type TreeMultisetOptions = Omit<AVLTreeOptions, 'isMergeDuplicatedVal'> & {
isMergeDuplicatedVal: true,
}

View file

@ -1,2 +1,3 @@
export * from './utils';
export * from './types';
export * from './types';
export * from './validate-type';

View file

@ -1 +1,2 @@
export * from './utils';
export * from './utils';
export * from './validate-type';

View file

@ -4,30 +4,3 @@ export type TrlFn = (...args: any[]) => any;
export type TrlAsyncFn = (...args: any[]) => any;
export type SpecifyOptional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
export type KeyValueObject = { [key: string]: any };
export type KeyValueObjectWithId = { [key: string]: any, id: string | number | symbol };
export type NonNumberNonObjectButDefined = string | boolean | symbol | null;
// export type ObjectWithoutId = Omit<object, 'id'>;
export type ObjectWithoutId = Omit<KeyValueObject, 'id'>;
// export type ObjectWithNonNumberId = object & {
// id: string | boolean | symbol | null | object | undefined;
// }
export type ObjectWithNonNumberId = {
[key: string]: any,
id: string | boolean | symbol | null | object | undefined;
}
// export type ObjectWithNumberId = object & {
// id: number;
// }
export type ObjectWithNumberId = {
[key: string]: any,
id: number;
}
export type DummyAny = string | number | boolean | null | undefined | object | symbol | void | Function | never;

View file

@ -0,0 +1,21 @@
export type KeyValueObject = { [key: string]: any };
export type KeyValueObjectWithId = { [key: string]: any, id: string | number | symbol };
export type NonNumberNonObjectButDefined = string | boolean | symbol | null;
export type ObjectWithoutId = Omit<KeyValueObject, 'id'>;
export type ObjectWithNonNumberId = {
[key: string]: any,
id: string | boolean | symbol | null | object | undefined;
}
export type ObjectWithNumberId = {
[key: string]: any,
id: number;
}
export type RestrictValById = NonNumberNonObjectButDefined | ObjectWithoutId | ObjectWithNonNumberId | ObjectWithNumberId;
export type DummyAny = string | number | boolean | null | undefined | object | symbol | void | Function | never;

View file

@ -1,3 +1,22 @@
import {z} from 'zod'
/**
* data-structure-typed
*
* @author Tyler Zeng
* @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
* @license MIT License
*/
import type {
NonNumberNonObjectButDefined,
ObjectWithNonNumberId,
ObjectWithNumberId,
ObjectWithoutId,
Thunk,
ToThunkFn,
TrlAsyncFn,
TrlFn
} from './types';
export const uuidV4 = function () {
return 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'.replace(/[x]/g, function (c) {
const r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
@ -22,24 +41,6 @@ export const arrayRemove = function <T>(array: T[], predicate: (item: T, index:
};
/**
* data-structure-typed
*
* @author Tyler Zeng
* @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
* @license MIT License
*/
import type {
NonNumberNonObjectButDefined,
ObjectWithNonNumberId,
ObjectWithNumberId,
ObjectWithoutId,
Thunk,
ToThunkFn,
TrlAsyncFn,
TrlFn
} from './types';
export const THUNK_SYMBOL = Symbol('thunk')
export const isThunk = (fnOrValue: any) => {
@ -85,86 +86,3 @@ export const trampolineAsync = (fn: TrlAsyncFn) => {
{cont}
)
}
// export class AutoPruneMap<K, V> extends Map<K, V> {
//
// private _proxySet: Set<V>;
// get proxySet(): Set<V> {
// return this._proxySet;
// }
//
// set proxySet(value: Set<V>) {
// this._proxySet = value;
// }
//
// private _isEmptyArrayAllowed: boolean;
//
// get isEmptyArrayAllowed(): boolean {
// return this._isEmptyArrayAllowed;
// }
//
// set isEmptyArrayAllowed(value: boolean) {
// this._isEmptyArrayAllowed = value;
// }
//
// constructor(isEmptyArrayAllowed: boolean = false) {
// super();
// this._isEmptyArrayAllowed = isEmptyArrayAllowed;
// this._proxySet = new Set<V>();
// }
//
// set(key: K, value: V): this {
// if (Array.isArray(value) && !this.proxySet.has(value)) {
// if(!this.isEmptyArrayAllowed && value.length === 0) return this;
// value = this.createArrayProxy(value, key);
// if (!this.proxySet.has(value)) this.proxySet.add(value);
// }
// super.set(key, value);
// return this;
// }
//
// private createArrayProxy(array: V & any[], key: K) {
// const that = this;
// const proxyHandler: ProxyHandler<V & any[]> = {
// set(target: any, property: PropertyKey, value: any): boolean {
// const result = Reflect.set(target, property, value);
// that.checkAndDeleteEmptyArray(key);
// return result;
// },
// deleteProperty(target: any, property: PropertyKey): boolean {
// const result = Reflect.deleteProperty(target, property);
// that.checkAndDeleteEmptyArray(key);
// return result;
// },
// }
// return new Proxy(array, proxyHandler);
// }
//
// private checkAndDeleteEmptyArray(key: K): void {
// const value = this.get(key);
//
// if (Array.isArray(value) && value.length === 0) {
// super.delete(key);
// }
// }
// }
export function isNonNumberNonObjectButDefined(val: any): val is NonNumberNonObjectButDefined {
return typeof val !== 'number' && typeof val !== 'object' && val !== undefined;
}
export function isObjectWithoutId(val: any): val is ObjectWithoutId {
return typeof val === 'object' && !('id' in val);
}
export function isObjectWithNonNumberId(val: any): val is ObjectWithNonNumberId {
return typeof val === 'object' && 'id' in val && typeof val.id !== 'number';
}
export function isObjectWithNumberId(val: any): val is ObjectWithNumberId {
return typeof val === 'object' && 'id' in val && typeof val.id === 'number';
}
export function isNumber(val: any): val is number {
return typeof val === 'number';
}

View file

@ -0,0 +1,69 @@
import {z} from 'zod';
import {NonNumberNonObjectButDefined, ObjectWithNonNumberId, ObjectWithNumberId, ObjectWithoutId} from './types';
export const nonNumberNonObjectButDefinedSchema = z.union([z.string(),
z.boolean(), z.any()])
.nullable()
export const keyValueObjectSchema = z.record(z.unknown())
export const objectWithoutIdSchema = keyValueObjectSchema.refine(obj => !('id' in obj), {
message: 'Object cannot contain the \'id\' field',
});
export const keyValueObjectWithIdSchema = z.record(z.any()).and(
z.object({
id: z.union([z.string(), z.number(), z.any()])
})
)
export const objectWithNonNumberIdSchema = z.record(z.any()).and(
z.object({
id: z
.union([z.string(), z.boolean(), z.any(), z.any(), z.undefined()])
.nullable()
})
)
export const objectWithNumberIdSchema = z.record(z.any()).and(
z.object({
id: z.number()
})
)
export const binaryTreeNodeValWithId = z.union([
nonNumberNonObjectButDefinedSchema,
objectWithoutIdSchema,
objectWithNonNumberIdSchema,
objectWithNumberIdSchema
])
export function parseBySchema(schema: z.Schema, val: any) {
try {
schema.parse(val);
return true;
} catch (error) {
return false;
}
}
export function isNonNumberNonObjectButDefined(val: any): val is NonNumberNonObjectButDefined {
return parseBySchema(nonNumberNonObjectButDefinedSchema, val);
}
export function isObjectWithoutId(val: any): val is ObjectWithoutId {
return parseBySchema(objectWithoutIdSchema, val);
}
export function isObjectWithNonNumberId(val: any): val is ObjectWithNonNumberId {
return parseBySchema(objectWithNonNumberIdSchema, val);
}
export function isObjectWithNumberId(val: any): val is ObjectWithNumberId {
return parseBySchema(objectWithNonNumberIdSchema, val);
}
export function isNumber(val: any): val is number {
return typeof val === 'number';
}