merge-change
Version:
Advanced library for deep merging, patching, and immutable updates of data structures. Features declarative operations for specific merging behaviors, property management, custom type merging rules, and difference tracking. Supports complex data transform
66 lines (65 loc) • 3.31 kB
TypeScript
import { Type } from '../type/types';
import { ExtractPaths } from '../common-types/types';
import { FlatObject } from '../flat/types';
export declare enum Operations {
'$set' = "$set",
'$unset' = "$unset",
'$leave' = "$leave",
'$pull' = "$pull",
'$push' = "$push",
'$concat' = "$concat"
}
export type OperationsName = keyof typeof Operations;
export type OperationFn = (source: any, params: any) => boolean;
export declare enum MergeChangeKind {
MERGE = "merge",// cloning
PATCH = "patch",// change in source value
UPDATE = "update"
}
export type MergeMethodName = `${Type}_${Type}`;
export type MergeFn = (first: any, second: any, kind: MergeChangeKind, mc: MergeChangeFn) => unknown;
export type MergeMethods = Partial<Record<MergeMethodName, MergeFn>>;
export interface Mergeable {
Object: {
[key: string | number | symbol]: any;
} & {
toJSON?: never;
length?: never;
call?: never;
apply?: never;
prototype?: never;
[Symbol.match]?: never;
[Symbol.iterator]?: never;
};
}
type IsMergeable<T> = T extends Mergeable[keyof Mergeable] ? true : false;
type StripOperations<T> = IsMergeable<T> extends true ? {
[K in Exclude<keyof T, OperationsName>]: StripOperations<T[K]>;
} : T;
export type Merged<T, U> = RequiredDeep<U extends undefined ? never : IsMergeable<T> extends true ? IsMergeable<U> extends true ? {
[K in keyof T]: K extends keyof T & keyof U ? Merged<T[K], U[K]> : K extends keyof T ? T[K] : K extends keyof U ? StripOperations<U[K]> : never;
} : U : IsMergeable<U> extends true ? {
[Z in Exclude<keyof U, OperationsName>]: StripOperations<U[Z]>;
} : U>;
export type MergedAll<T extends any[]> = T extends [infer First, infer Second, ...infer Rest] ? Rest extends any[] ? MergedAll<[Merged<First, Second>, ...Rest]> : Merged<First, Second> : T extends [infer Only] ? Only : never;
export type MergeChangeFn = <T extends any[]>(...values: T) => MergedAll<T>;
export type PartialDeep<T> = T | (T extends (...args: any) => any ? T : T extends (infer U)[] ? PartialDeep<U>[] : IsMergeable<T> extends true ? {
[K in keyof T]?: PartialDeep<T[K]>;
} : T);
export type PatchOperation<T> = {
$set?: Partial<T | FlatObject<T>>;
$unset?: ExtractPaths<T, '.'>[];
$leave?: ExtractPaths<T, '.'>[];
$pull?: Record<ExtractPaths<T, '.'>, unknown>;
$push?: Record<ExtractPaths<T, '.'>, unknown>;
$concat?: Record<ExtractPaths<T, '.'>, unknown>;
};
export type Patch<T> = T extends BuildIn ? T : T extends (infer U)[] ? Patch<U>[] : IsMergeable<T> extends true ? {
[K in keyof T]?: Patch<T[K]>;
} & PatchOperation<T> : Exclude<T, undefined>;
export type Function = (...args: any) => any;
export type BuildIn = string | number | boolean | bigint | symbol | null | undefined | void | Date | RegExp | Function | Promise<any>;
export type RequiredDeep<T> = T extends BuildIn ? T : T extends ReadonlyArray<infer U> ? RequiredDeep<NonNullable<U>>[] : T extends Array<infer U> ? RequiredDeep<NonNullable<U>>[] : T extends Map<infer K, infer V> ? Map<RequiredDeep<NonNullable<K>>, RequiredDeep<NonNullable<V>>> : T extends Set<infer U> ? Set<RequiredDeep<NonNullable<U>>> : T extends object ? {
[K in keyof T]-?: RequiredDeep<NonNullable<T[K]>>;
} : T;
export {};