mirror of
https://github.com/zrwusa/data-structure-typed.git
synced 2024-11-23 12:54:04 +00:00
Added a method for data type validation through type conversion to Zod schemas.
This commit is contained in:
parent
de5a001b6a
commit
61f465fe99
|
@ -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
15
package-lock.json
generated
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,5 +63,8 @@
|
|||
"ts-jest": "^29.1.1",
|
||||
"typedoc": "^0.24.8",
|
||||
"typescript": "^4.9.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"zod": "^3.22.2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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> {
|
||||
|
||||
|
||||
}
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
export * from './utils';
|
||||
export * from './types';
|
||||
export * from './types';
|
||||
export * from './validate-type';
|
|
@ -1 +1,2 @@
|
|||
export * from './utils';
|
||||
export * from './utils';
|
||||
export * from './validate-type';
|
|
@ -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;
|
21
src/utils/types/validate-type.ts
Normal file
21
src/utils/types/validate-type.ts
Normal 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;
|
|
@ -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';
|
||||
}
|
69
src/utils/validate-type.ts
Normal file
69
src/utils/validate-type.ts
Normal 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';
|
||||
}
|
Loading…
Reference in a new issue