Skip to content

Commit

Permalink
add documentation for utill functions
Browse files Browse the repository at this point in the history
  • Loading branch information
ultrox committed May 19, 2024
1 parent 2364d43 commit 28cdb2f
Show file tree
Hide file tree
Showing 28 changed files with 260 additions and 14 deletions.
4 changes: 2 additions & 2 deletions reports/api-extractor.md
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ export type FormSubmitHandler<TFieldValues extends FieldValues> = (payload: {
method?: 'post' | 'put' | 'delete';
}) => unknown | Promise<unknown>;

// @public (undocumented)
// @public
export const get: <T>(object: T, path?: string, defaultValue?: unknown) => any;

// @public (undocumented)
Expand Down Expand Up @@ -531,7 +531,7 @@ export type ResolverSuccess<TFieldValues extends FieldValues = FieldValues> = {
errors: {};
};

// @public (undocumented)
// @public
export const set: (object: FieldValues, path: string, value?: unknown) => FieldValues;

// @public (undocumented)
Expand Down
4 changes: 4 additions & 0 deletions src/logic/generateId.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
/**
Generates a unique identifier string in the UUID v4 format.
NOT for serious cryptography.
*/
export default () => {
const d =
typeof performance === 'undefined' ? Date.now() : performance.now() * 1000;
Expand Down
20 changes: 19 additions & 1 deletion src/logic/getFocusFieldName.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,24 @@
import { FieldArrayMethodProps, InternalFieldName } from '../types';
import isUndefined from '../utils/isUndefined';

/**
* Constructs the focus name for a field array
* based on the given parameters. If the `shouldFocus`
* option is true or undefined, it returns a focus name.
* The focus name is constructed based on the
* `focusName` option, the `name` parameter,
* and either the `focusIndex` option or the provided `index`.
* If `shouldFocus` is false, it returns an empty string.
*
* @example
* getFocusName('field', 2, { shouldFocus: true });
* Output: "field.2."
*
* getFocusName('field', 2, { shouldFocus: true, focusName: 'apple' });
* Output: "apple"
*
* getFocusName('field', 2, { shouldFocus: false });
// Output: ""
*/
export default (
name: InternalFieldName,
index: number,
Expand Down
13 changes: 13 additions & 0 deletions src/logic/getValidationModes.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
import { VALIDATION_MODE } from '../constants';
import { Mode, ValidationModeFlags } from '../types';

/**
* Constructs validation mode flags based on the provided mode.
* This function returns an object with flags indicating which
* validation mode is active.
* @remarks If no mode is provided, it defaults to `onSubmit`.
*
* @example
* const flags = getValidationModeFlags(VALIDATION_MODE.onBlur);
* Output: { isOnBlur: true, ...<other>false}
*
* getValidationModeFlags();
* Output: { isOnSubmit: true, <other>false}
*/
export default (mode?: Mode): ValidationModeFlags => ({
isOnSubmit: !mode || mode === VALIDATION_MODE.onSubmit,
isOnBlur: mode === VALIDATION_MODE.onBlur,
Expand Down
28 changes: 28 additions & 0 deletions src/logic/iterateFieldsByAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,34 @@ import { FieldRefs, InternalFieldName, Ref } from '../types';
import { get } from '../utils';
import isObject from '../utils/isObject';

/**
* Iterates over field references and performs
* an action on each field. This function traverses
* through the field references, applying the given
* action to each field.
* @remarks The traversal can be limited to specific field names,
* and it can be aborted early based on the action's return value.
*
* @example
* const fields = {
* field1: {
* _f: {
* ref: document.createElement('input'),
* name: 'field1',
* }},
* field2: {
* _f: {
* refs: [document.createElement('input')],
* name: 'field2',
* }}};
*
* iterateFieldsByAction(fields, (ref, name) => {
* console.log(name, ref);
* });
* Output:
* field1 <input>
* field2 <input>
*/
const iterateFieldsByAction = (
fields: FieldRefs,
action: (ref: Ref, name: string) => 1 | undefined | void,
Expand Down
4 changes: 4 additions & 0 deletions src/utils/append.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import convertToArrayPayload from './convertToArrayPayload';

/**
* Add given value or array of values to the end of given array.
* @returns {T[]} A new array with the appended value(s).
*/
export default <T>(data: T[], value: T | T[]): T[] => [
...data,
...convertToArrayPayload(value),
Expand Down
6 changes: 5 additions & 1 deletion src/utils/cloneObject.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import isObject from './isObject';
import isPlainObject from './isPlainObject';
import isWeb from './isWeb';

/**
* Deeply clones a given object,
* including handling special types like Date and Set.
* It also handles arrays and plain objects.
*/
export default function cloneObject<T>(data: T): T {
let copy: any;
const isArray = Array.isArray(data);
Expand Down
8 changes: 8 additions & 0 deletions src/utils/compact.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,10 @@
/**
* @description Removes falsy values from an array.
* @returns {TValue[]} A new array with all falsy values removed.
* @example
* const array = [0, 1, false, 2, '', 3, null, undefined, NaN, 4];
* const compactedArray = compact(array);
* compactedArray // Output: [1, 2, 3, 4]
*/
export default <TValue>(value: TValue[]) =>
Array.isArray(value) ? value.filter(Boolean) : [];
3 changes: 3 additions & 0 deletions src/utils/convertToArrayPayload.ts
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
/**
* Put's given value into an array if it's not already an array.
*/
export default <T>(value: T) => (Array.isArray(value) ? value : [value]);
27 changes: 24 additions & 3 deletions src/utils/createSubject.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,41 @@
/**
* Implementation of an observable pattern.
* This pattern is used for implementing
* a publisher-subscriber system, where subscribers (observers)
* can listen to events or data changes
* emitted by a subject (observable).
*/
import { Noop } from '../types';

/**
* Observer that has a next method.
* This method is called when new data is emitted.
*/
export type Observer<T> = {
next: (value: T) => void;
};

/**
* A type representing a subscription that
* has an unsubscribe method. This method is used
* to stop receiving updates from the subject.
*/
export type Subscription = {
unsubscribe: Noop;
};

/**
* A type representing a subject that can be observed.
* It has an array of observers, methods to subscribe
* and unsubscribe observers, and a method to
* emit data to all observers.
*/
export type Subject<T> = {
readonly observers: Observer<T>[];
subscribe: (value: Observer<T>) => Subscription;
unsubscribe: Noop;
} & Observer<T>;

export default <T>(): Subject<T> => {
export default function createSubject<T>(): Subject<T> {
let _observers: Observer<T>[] = [];

const next = (value: T) => {
Expand Down Expand Up @@ -44,4 +65,4 @@ export default <T>(): Subject<T> => {
subscribe,
unsubscribe,
};
};
}
21 changes: 20 additions & 1 deletion src/utils/deepEqual.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,26 @@ import isObject from '../utils/isObject';

import isDateObject from './isDateObject';
import isPrimitive from './isPrimitive';

/**
* Compares two values deeply to determine
* if they are equal. Handles primitives,
* dates, objects, and arrays.
*
* @example
* const obj1 = { a: 1, b: { c: 2 } };
* const obj2 = { a: 1, b: { c: 2 } };
* deepEqual(obj1, obj2) // Output: true
*
* const obj3 = { a: 1, b: { c: 3 } };
* deepEqual(obj1, obj3) // Output: false
*
* const date1 = new Date(2020, 1, 1);
* const date2 = new Date(2020, 1, 1);
* deepEqual(date1, date2) // Output: true
*
* @remarks This function compares complex
* structures including nested objects and arrays.
*/
export default function deepEqual(object1: any, object2: any) {
if (isPrimitive(object1) || isPrimitive(object2)) {
return object1 === object2;
Expand Down
14 changes: 14 additions & 0 deletions src/utils/deepMerge.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
import isObject from './isObject';
import isPrimitive from './isPrimitive';

/**
* Deeply merges two objects. If either target or
* source is a primitive, the source is returned.
* Otherwise, recursively merges properties of the
* source object into the target object.
* @remarks This function mutates the target object.
* @remarks uses source keys for iteration
*
* @example
* const target = { a: 1, b: { c: 3 } };
* const source = { b: { d: 4 }, e: 5 };
* const result = deepMerge(target, source);
* result // Output: { a: 1, b: { c: 3, d: 4 }, e: 5 }
*/
export default function deepMerge<
T extends Record<keyof T, any>,
U extends Record<keyof U, any>,
Expand Down
5 changes: 5 additions & 0 deletions src/utils/fillEmptyArray.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
/**
* Converts an array to an array of
* `undefined` * values, or returns `undefined` if
* the input is not an array.
*/
export default <T>(value: T | T[]): undefined[] | undefined =>
Array.isArray(value) ? value.map(() => undefined) : undefined;
12 changes: 12 additions & 0 deletions src/utils/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,18 @@ import isNullOrUndefined from './isNullOrUndefined';
import isObject from './isObject';
import isUndefined from './isUndefined';

/**
* Safely retrieves the value at a given
* path within an object. If the value is not found or
* is undefined, it returns the provided default value.
* @example
* ```typescript
* const obj = { a: { b: { c: 42 }}};
* getNestedValue(obj, 'a.b.c') // Output: 42
* getNestedValue(obj, 'a.b.x', 'default') // Output: 'default'
* getNestedValue(obj, 'a.b.c.d', 'default') // Output: 'default'
* ```
*/
export default <T>(object: T, path?: string, defaultValue?: unknown): any => {
if (!path || !isObject(object)) {
return defaultValue;
Expand Down
3 changes: 3 additions & 0 deletions src/utils/insert.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import convertToArrayPayload from './convertToArrayPayload';

/**
* Insert value or values into specific index,
*/
export default function insert<T>(data: T[], index: number): (T | undefined)[];
export default function insert<T>(
data: T[],
Expand Down
4 changes: 4 additions & 0 deletions src/utils/isEmptyObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,9 @@ import { EmptyObject } from '../types';

import isObject from './isObject';

/**
* Checks if the given value is an object
* with no own properties
*/
export default (value: unknown): value is EmptyObject =>
isObject(value) && !Object.keys(value).length;
8 changes: 8 additions & 0 deletions src/utils/isKey.ts
Original file line number Diff line number Diff line change
@@ -1 +1,9 @@
/**
* Checks if a string is a valid key consisting of alphanumeric
* characters and underscores.
* @remarks (\w qualify _ as a valid character)
* @example
* isKey("valid_key") // Output: true
* isKey("invalid key!") // Output: false
*/
export default (value: string) => /^\w*$/.test(value);
10 changes: 9 additions & 1 deletion src/utils/isMessage.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import { Message } from '../types';
import isString from '../utils/isString';

/**
* Checks if the given value is a string
* and therefore qualifies as a `Message`.
* @example
* const val1 = "Hello, world!";
* const val2 = 123;
* isMessage(val1) // Output: true
* isMessage(val2) // Output: false
*/
export default (value: unknown): value is Message => isString(value);
3 changes: 3 additions & 0 deletions src/utils/noop.ts
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
/**
* No operation function.
*/
export default function noop() {}
4 changes: 3 additions & 1 deletion src/utils/objectHasFunction.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import isFunction from './isFunction';

/**
* Checks if an object contains at least one function as a property.
*/
export default <T>(data: T): boolean => {
for (const key in data) {
if (isFunction(data[key])) {
Expand Down
4 changes: 3 additions & 1 deletion src/utils/prepend.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import convertToArrayPayload from './convertToArrayPayload';

/**
* Add's value or an array of values to the beginning of an array.
*/
export default <T>(data: T[], value: T | T[]): T[] => [
...convertToArrayPayload(value),
...convertToArrayPayload(data),
Expand Down
10 changes: 9 additions & 1 deletion src/utils/remove.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import compact from './compact';
import convertToArrayPayload from './convertToArrayPayload';
import isUndefined from './isUndefined';

/**
* Removes elements from an array at the
* specified index or indexes. If no index is provided,
* an empty array is returned.
* @example
* const arr = ['a', 'b', 'c', 'd'];
* removeElements(arr, [1, 3]); // Output: ['a', 'c']
* removeElements(arr, 2); // Output: ['a', 'b', 'd']
*/
function removeAtIndexes<T>(data: T[], indexes: number[]): T[] {
let i = 0;
const temp = [...data];
Expand Down
10 changes: 10 additions & 0 deletions src/utils/set.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ import isKey from './isKey';
import isObject from './isObject';
import stringToPath from './stringToPath';

/**
* Sets the value at the specified path of the object.
* If a portion of the path does not exist, it is created.
* @example
* ```typescript
* const object = {};
* setValueAtPath(object, 'a.b.c', 42);
* Output: { a: { b: { c: 42 } } }
* ```
*/
export default (object: FieldValues, path: string, value?: unknown) => {
let index = -1;
const tempPath = isKey(path) ? [path] : stringToPath(path);
Expand Down
4 changes: 4 additions & 0 deletions src/utils/sleep.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
/**
* Promises that resolves after given amount of time.
* in milliseconds.
*/
export default (ms: number) =>
new Promise((resolve) => setTimeout(resolve, ms));

0 comments on commit 28cdb2f

Please sign in to comment.