Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: add jsdocs #126

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
46 changes: 42 additions & 4 deletions src/defu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,26 +46,64 @@ function _defu<T>(
return object;
}

// Create defu wrapper with optional merger and multi arg support
/**
* Creates a new `defu` function that can optionally use a custom merger.
*
* @param {Merger} [merger] - An optional merger function to handle the merge logic. See {@link Merger}.
* @return {DefuFunction} - A `defu` function capable of merging multiple objects with support for custom merging.
* See {@link DefuFunction}.
* @example
* const ext = createDefu((obj, key, value) => {
* if (typeof obj[key] === "number" && typeof value === "number") {
* obj[key] += value;
* return true;
* }
* });
* ext({ cost: 15 }, { cost: 10 }); // { cost: 25 }
*/
export function createDefu(merger?: Merger): DefuFunction {
return (...arguments_) =>
// eslint-disable-next-line unicorn/no-array-reduce
arguments_.reduce((p, c) => _defu(p, c, "", merger), {} as any);
}

// Standard version
/**
* The standard `defu` function created without a custom function. See {@link createDefu}.
*/
export const defu = createDefu() as DefuInstance;
export default defu;

// Custom version with function merge support
/**
* Custom `defu` function that specifically merges functions by taking the current value as a function
* with the previous value as an argument. See {@link createDefu}.
* @example
* defuFn(
* {
* ignore: (val) => val.filter((item) => item !== "dist"),
* count: (count) => count + 20
* },
* { ignore: ["node_modules", "dist"], count: 10 },
* ); // { ignore: ["node_modules"], count: 30 }
*/
export const defuFn = createDefu((object, key, currentValue) => {
if (object[key] !== undefined && typeof currentValue === "function") {
object[key] = currentValue(object[key]);
return true;
}
});

// Custom version with function merge support only for defined arrays
/**
* A custom `defu` function that applies a function merger only to array properties.
* See {@link createDefu}.
* @example
* defuArrayFn(
* {
* ignore: (val) => val.filter(i => i !== 'dist'),
* count: () => 20
* },
* { ignore: ['node_modules', 'dist'], count: 10 }
* ); // { ignore: ['node_modules'], count: 20 }
*/
export const defuArrayFn = createDefu((object, key, currentValue) => {
if (Array.isArray(object[key]) && typeof currentValue === "function") {
object[key] = currentValue(object[key]);
Expand Down
56 changes: 56 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
/**
* Represents a generic input object that can have string, number or symbol keys and values of any type.
*/
export type Input = Record<string | number | symbol, any>;
/**
* Represents types of input that should be ignored during merge operations.
* This includes primitive types, arrays, empty objects and undefined.
*/
export type IgnoredInput =
| boolean
| number
Expand All @@ -7,15 +14,41 @@ export type IgnoredInput =
| Record<never, any>
| undefined;

/**
* Defines a function type for custom merge strategies in defu functions.
* @returns {any} - The result of the custom merge operation, if any.
* @template T - The type of the target object.
* @template K - The type of keys in the target object.
*/
export type Merger = <T extends Input, K extends keyof T>(
/**
* The target object to merge into.
*/
object: T,

/**
* The current key in the object being processed.
*/
key: keyof T,

/**
* The value corresponding to the key in the source object.
*/
value: T[K],

/**
* A string representing the namespace path to the key.
*/
namespace: string,
) => any;

type nullish = null | undefined | void;

/**
* Merges two input objects with rules for handling conflicts and special types such as arrays and null values.
* @template Target - The type of target object.
* @template Defaults - The type of the default object.
*/
export type MergeObjects<
Destination extends Input,
Defaults extends Input,
Expand All @@ -33,6 +66,11 @@ export type MergeObjects<
: Merge<Destination[Key], Defaults[Key]>; // eslint-disable-line no-use-before-define
};

/**
* Recursively merges a source object with an array of default objects or ignored input.
* @template S - The type of the source object.
* @template D - The type of array containing default or ignored input objects.
*/
export type Defu<
S extends Input,
D extends Array<Input | IgnoredInput>,
Expand All @@ -48,6 +86,11 @@ export type Defu<
: S
: S;

/**
* Defines a function type that merges a source object with a set of default or ignored inputs.
* @template Source - The type of the source object.
* @template Defaults - The type of array containing the default or ignored inputs.
*/
export type DefuFn = <
Source extends Input,
Defaults extends Array<Input | IgnoredInput>,
Expand All @@ -56,6 +99,9 @@ export type DefuFn = <
...defaults: Defaults
) => Defu<Source, Defaults>;

/**
* Represents an instance of a defu function, including utility methods such as `fn' and `arrayFn'.
*/
export interface DefuInstance {
<Source extends Input, Defaults extends Array<Input | IgnoredInput>>(
source: Source | IgnoredInput,
Expand All @@ -66,6 +112,11 @@ export interface DefuInstance {
extend(merger?: Merger): DefuFn;
}

/**
* Merges two arrays into one, combining the types of elements in both arrays.
* @template Target - The type of the target array.
* @template source - The type of the source array.
*/
export type MergeArrays<Destination, Source> = Destination extends Array<
infer DestinationType
>
Expand All @@ -74,6 +125,11 @@ export type MergeArrays<Destination, Source> = Destination extends Array<
: Source | Array<DestinationType>
: Source | Destination;

/**
* Defines rules for merging two objects, handling special cases such as arrays, functions and null values.
* @template Target - The type of target object.
* @template Defaults - The type of the default object.
*/
export type Merge<Destination extends Input, Defaults extends Input> =
// Remove explicitly null types
Destination extends nullish
Expand Down