From 9251f96ed08b2e6406cafab5e45cfcdb2a0d1e4d Mon Sep 17 00:00:00 2001 From: drizzer14 Date: Wed, 26 Jun 2024 16:18:54 +0300 Subject: [PATCH] feat: add set function --- src/index.ts | 1 + src/set.ts | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 src/set.ts diff --git a/src/index.ts b/src/index.ts index e4165c9..3fa8ebd 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,5 @@ export { default as get } from './get' +export { default as set } from './set' export { default as tap } from './tap' export { default as pipe } from './pipe' export { default as apply } from './apply' diff --git a/src/set.ts b/src/set.ts new file mode 100644 index 0000000..0484519 --- /dev/null +++ b/src/set.ts @@ -0,0 +1,117 @@ +/** + * @module Set + */ + +import type { Unshift } from './types/unshift' +import permutation3 from './permutation/permutation-3' +import type { Flatten, Flattenable } from './types/flatten' + +/** + * Sets the `Value` type inside a nested object type `Source` by provided `Path` + * written in dot-notation. + */ +export type Set< + Source extends Flattenable, + Path extends string, + Value +> = + Source extends Record + ? Path extends `${number}.${infer Right}` + ? Set + // @ts-ignore + : Path extends `${infer Left extends keyof Source}.${infer Right}` + ? { + [Key in keyof Source]: Key extends Exclude + ? Source[Key] + // @ts-ignore + : Set, Right, Value> + } + : Path extends keyof Source + ? { + [Key in keyof Source]: Key extends Exclude + ? Source[Key] + : Value + } + : never + : Source extends any[] + ? Path extends `${infer Index extends number}.${infer Right}` + ? Unshift, Right, Value>> + : Path extends `${infer Index extends number}` + ? Unshift + : never + : never + +/** + * Sets the `value` inside a nested `source` object by provided `path` + * written in dot-notation. + */ +// @ts-ignore +export default function set< + Source extends Flattenable, + Path extends Flatten, + Value +> ( + path: Path, + value: Value, + // @ts-ignore +): (source: Source) => Set + +/** + * Sets the `value` inside a nested `source` object by provided `path` + * written in dot-notation. + */ +// @ts-ignore +export default function set< + Source extends Flattenable, + Path extends Flatten, + Value +> ( + source: Source, + path: Path, + value: Value + // @ts-ignore +): Set + +/** + * Sets the `value` inside a nested `source` object by provided `path` + * written in dot-notation. + */ +export default function set (...args: [any, any, any?]): any { + // @ts-ignore + return permutation3( + // @ts-ignore + < + Source extends Flattenable, + Path extends Flatten, + Value + > ( + source: Source, + path: Path, + value: Value + // @ts-ignore + ): Set => { + // @ts-ignore + const keys = path.split('.') + const length = keys.length + + let result = structuredClone(source) + + if (length === 0) { + result[path as keyof Source] = value as Source[keyof Source] + } + + let scope: any = result[keys[0]! as keyof Source] + + for (let index = 1; index < length; index += 1) { + if (index === length - 1) { + scope[keys?.[index] as keyof typeof scope] = value + } else { + scope = scope?.[keys?.[index] as keyof typeof scope] + } + } + + // @ts-ignore + return result as Set + } + )(...args) +}