@ekim088/toolkit 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # toolkit
2
+
3
+ A simple utility library.
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Creates a deep copy of a value.
3
+ * @param {*} value The value to clone.
4
+ * @returns {*} A copy of the value.
5
+ */
6
+ export default function clone<T = unknown>(value: T): T;
@@ -0,0 +1,20 @@
1
+ import clone from './clone';
2
+ import isBoolean from './isBoolean';
3
+ import isDeepEqual from './isDeepEqual';
4
+ import isNumber from './isNumber';
5
+ import isObject from './isObject';
6
+ import isString from './isString';
7
+ import memoizeOne from './memoizeOne';
8
+ import merge from './merge';
9
+ declare const _default: {
10
+ clone: typeof clone;
11
+ isBoolean: typeof isBoolean;
12
+ isDeepEqual: typeof isDeepEqual;
13
+ isNumber: typeof isNumber;
14
+ isObject: typeof isObject;
15
+ isString: typeof isString;
16
+ memoizeOne: typeof memoizeOne;
17
+ merge: typeof merge;
18
+ };
19
+ export default _default;
20
+ export * from './typeUtils';
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Tests if a value is a boolean datatype.
3
+ * @param {*} value The value to test.
4
+ * @returns {boolean} `true` if the value is a boolean.
5
+ */
6
+ export default function isBoolean(value: unknown): value is boolean;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Tests if two arguments are equal. Object literals and arrays are tested for
3
+ * deep equality while other objects are tested for strict equality.
4
+ * @param {*} a An argument to test.
5
+ * @param {*} b An argument to test.
6
+ * @returns {boolean} `true` if `a` and `b` are deeply equal.
7
+ */
8
+ export default function isDeepEqual(a: unknown, b: unknown): boolean;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Tests if a value is a number datatype.
3
+ * @param {*} value The value to test.
4
+ * @returns {boolean} `true` if the value is a number.
5
+ */
6
+ export default function isNumber(value: unknown): value is number;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Tests if a value is an object literal.
3
+ * @param {*} value The value to test.
4
+ * @returns {boolean} `true` if the value is an object. Returns `false` for
5
+ * arrays and `null`.
6
+ */
7
+ export default function isObject(value: unknown): value is object;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Tests if a value is a string datatype.
3
+ * @param {*} value The value to test.
4
+ * @returns {boolean} `true` if the value is a string.
5
+ */
6
+ export default function isString(value: unknown): value is string;
@@ -0,0 +1,18 @@
1
+ export type MemoizedFn<T extends (...args: any) => unknown> = T & {
2
+ /**
3
+ * Clears the cached function result.
4
+ */
5
+ clear(): void;
6
+ };
7
+ export type EqualityFn<T extends (...args: any) => unknown> = (newArgs: Parameters<T>, cachedArgs: Parameters<T>) => boolean;
8
+ /**
9
+ * Returns a memoized function that caches the last result of a function call.
10
+ * The cached result is returned if the function arguments remain the same. Only
11
+ * a single result is ever cached.
12
+ * @param {Function} fn The function to memoize.
13
+ * @param {Function} equalityFn A custom function to check equality between the
14
+ * current arguments and the cached arguments. Arguments are considered equal
15
+ * if the equality function returns `true`.
16
+ * @returns {Function} The memoized function.
17
+ */
18
+ export default function memoizeOne<T extends (...args: any) => unknown>(fn: T, equalityFn?: EqualityFn<T>): MemoizedFn<T>;
@@ -0,0 +1,11 @@
1
+ export type Merged<T extends object[]> = T extends [
2
+ infer FirstObj,
3
+ ...infer Rest
4
+ ] ? FirstObj & Merged<Rest extends object[] ? Rest : []> : {};
5
+ /**
6
+ * Deeply merges a list of objects into a single object. For duplicate
7
+ * properties, subsequent occurrences overwrite the previous.
8
+ * @param {object[]} objects Any number of object literals to merge.
9
+ * @returns {object} A new object with the properties of its source objects.
10
+ */
11
+ export default function merge<T extends object[]>(...objects: T): Merged<T>;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Derives the item type from an array.
3
+ */
4
+ export type ItemType<T> = T extends (infer U)[] ? U : never;
5
+ /**
6
+ * Declares an object and its nested objects as partials.
7
+ */
8
+ export type RecursivePartial<T> = {
9
+ [P in keyof T]?: T[P] extends Record<keyof any, unknown> ? RecursivePartial<T[P]> : T[P];
10
+ };
11
+ /**
12
+ * Makes a readonly object mutable.
13
+ */
14
+ export type Writeable<T> = {
15
+ -readonly [P in keyof T]: T[P];
16
+ };
17
+ /**
18
+ * Makes a readonly object and all nested objects mutable.
19
+ */
20
+ export type DeepWriteable<T> = {
21
+ -readonly [P in keyof T]: DeepWriteable<T[P]>;
22
+ };
package/lib/clone.js ADDED
@@ -0,0 +1,31 @@
1
+ import isObject from './isObject';
2
+ function cloneObject(obj) {
3
+ const clonedObj = {};
4
+ for (const key in obj) {
5
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
6
+ clonedObj[key] = clone(obj[key]);
7
+ }
8
+ }
9
+ return clonedObj;
10
+ }
11
+ /**
12
+ * Creates a deep copy of a value.
13
+ * @param {*} value The value to clone.
14
+ * @returns {*} A copy of the value.
15
+ */
16
+ export default function clone(value) {
17
+ if (Array.isArray(value)) {
18
+ return value.map(item => clone(item));
19
+ }
20
+ if (isObject(value)) {
21
+ return cloneObject(value);
22
+ }
23
+ if (typeof value === 'function') {
24
+ return Object.assign((...args) => value(...args), cloneObject(value) // transfer custom function properties
25
+ );
26
+ }
27
+ if (value instanceof Date) {
28
+ return new Date(value);
29
+ }
30
+ return value;
31
+ }
package/lib/index.js ADDED
@@ -0,0 +1,19 @@
1
+ import clone from './clone';
2
+ import isBoolean from './isBoolean';
3
+ import isDeepEqual from './isDeepEqual';
4
+ import isNumber from './isNumber';
5
+ import isObject from './isObject';
6
+ import isString from './isString';
7
+ import memoizeOne from './memoizeOne';
8
+ import merge from './merge';
9
+ export default {
10
+ clone,
11
+ isBoolean,
12
+ isDeepEqual,
13
+ isNumber,
14
+ isObject,
15
+ isString,
16
+ memoizeOne,
17
+ merge,
18
+ };
19
+ export * from './typeUtils';
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Tests if a value is a boolean datatype.
3
+ * @param {*} value The value to test.
4
+ * @returns {boolean} `true` if the value is a boolean.
5
+ */
6
+ export default function isBoolean(value) {
7
+ return typeof value === 'boolean';
8
+ }
@@ -0,0 +1,21 @@
1
+ import isObject from './isObject';
2
+ /**
3
+ * Tests if two arguments are equal. Object literals and arrays are tested for
4
+ * deep equality while other objects are tested for strict equality.
5
+ * @param {*} a An argument to test.
6
+ * @param {*} b An argument to test.
7
+ * @returns {boolean} `true` if `a` and `b` are deeply equal.
8
+ */
9
+ export default function isDeepEqual(a, b) {
10
+ if (typeof a !== typeof b) {
11
+ return false;
12
+ }
13
+ if (Array.isArray(a) && Array.isArray(b)) {
14
+ return (a.length === b.length &&
15
+ a.every((item, i) => isDeepEqual(item, b[i])));
16
+ }
17
+ if (isObject(a) && isObject(b)) {
18
+ return isDeepEqual(Object.entries(a), Object.entries(b));
19
+ }
20
+ return a === b;
21
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Tests if a value is a number datatype.
3
+ * @param {*} value The value to test.
4
+ * @returns {boolean} `true` if the value is a number.
5
+ */
6
+ export default function isNumber(value) {
7
+ return typeof value === 'number';
8
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Tests if a value is an object literal.
3
+ * @param {*} value The value to test.
4
+ * @returns {boolean} `true` if the value is an object. Returns `false` for
5
+ * arrays and `null`.
6
+ */
7
+ export default function isObject(value) {
8
+ return !!value && value.constructor === Object;
9
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Tests if a value is a string datatype.
3
+ * @param {*} value The value to test.
4
+ * @returns {boolean} `true` if the value is a string.
5
+ */
6
+ export default function isString(value) {
7
+ return typeof value === 'string';
8
+ }
@@ -0,0 +1,33 @@
1
+ import isDeepEqual from './isDeepEqual';
2
+ /**
3
+ * Returns a memoized function that caches the last result of a function call.
4
+ * The cached result is returned if the function arguments remain the same. Only
5
+ * a single result is ever cached.
6
+ * @param {Function} fn The function to memoize.
7
+ * @param {Function} equalityFn A custom function to check equality between the
8
+ * current arguments and the cached arguments. Arguments are considered equal
9
+ * if the equality function returns `true`.
10
+ * @returns {Function} The memoized function.
11
+ */
12
+ export default function memoizeOne(fn, equalityFn) {
13
+ let cache = null;
14
+ function memoizedFn(...args) {
15
+ if (cache &&
16
+ cache.cachedThis === this &&
17
+ (equalityFn
18
+ ? equalityFn(args, cache.cachedArgs)
19
+ : isDeepEqual(args, cache.cachedArgs))) {
20
+ return cache.cachedResult;
21
+ }
22
+ cache = {
23
+ cachedThis: this,
24
+ cachedArgs: args,
25
+ cachedResult: fn.apply(this, args),
26
+ };
27
+ return cache.cachedResult;
28
+ }
29
+ memoizedFn.clear = () => {
30
+ cache = null;
31
+ };
32
+ return memoizedFn;
33
+ }
package/lib/merge.js ADDED
@@ -0,0 +1,26 @@
1
+ import isObject from './isObject';
2
+ /**
3
+ * Deeply merges a list of objects into a single object. For duplicate
4
+ * properties, subsequent occurrences overwrite the previous.
5
+ * @param {object[]} objects Any number of object literals to merge.
6
+ * @returns {object} A new object with the properties of its source objects.
7
+ */
8
+ export default function merge(...objects) {
9
+ const mergedObj = {};
10
+ objects.forEach(obj => {
11
+ Object.keys(obj).forEach(key => {
12
+ const currentVal = mergedObj[key];
13
+ const valToMerge = obj[key];
14
+ if (isObject(currentVal) && isObject(valToMerge)) {
15
+ mergedObj[key] = merge(currentVal, valToMerge);
16
+ }
17
+ else if (Array.isArray(currentVal) && Array.isArray(valToMerge)) {
18
+ mergedObj[key] = currentVal.concat(valToMerge);
19
+ }
20
+ else {
21
+ mergedObj[key] = valToMerge;
22
+ }
23
+ });
24
+ });
25
+ return mergedObj;
26
+ }
@@ -0,0 +1 @@
1
+ export {};
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@ekim088/toolkit",
3
+ "description": "A simple utility library.",
4
+ "version": "0.1.0",
5
+ "author": "ekim088 <edward@cyberbird.co>",
6
+ "type": "module",
7
+ "license": "MIT",
8
+ "main": "./lib/index.js",
9
+ "types": "./lib/@types/index.d.ts",
10
+ "scripts": {
11
+ "build": "rm -rf ./lib && tsc",
12
+ "format": "yarn exec prettier . --write",
13
+ "lint": "yarn lint:js && yarn lint:types",
14
+ "lint:js": "eslint . --fix",
15
+ "lint:types": "tsc --noEmit",
16
+ "test": "vitest",
17
+ "test:ci": "vitest run",
18
+ "test:coverage": "vitest run --coverage",
19
+ "test:pre-commit": "vitest related --run",
20
+ "_postinstall": "husky",
21
+ "prepack": "pinst --disable",
22
+ "postpack": "pinst --enable"
23
+ },
24
+ "devDependencies": {
25
+ "@commitlint/cli": "^19.8.1",
26
+ "@commitlint/config-conventional": "^19.8.1",
27
+ "@eslint/js": "^9.27.0",
28
+ "@vitest/coverage-v8": "3.1.4",
29
+ "@vitest/eslint-plugin": "^1.2.1",
30
+ "eslint": "^9.27.0",
31
+ "eslint-plugin-jsdoc": "^50.6.17",
32
+ "global-jsdom": "^26.0.0",
33
+ "globals": "^16.2.0",
34
+ "husky": "^9.1.7",
35
+ "jsdom": "^26.1.0",
36
+ "lint-staged": "^16.0.0",
37
+ "pinst": "^3.0.0",
38
+ "prettier": "3.5.3",
39
+ "typescript": "^5.8.3",
40
+ "typescript-eslint": "^8.32.1",
41
+ "vitest": "^3.1.4"
42
+ },
43
+ "volta": {
44
+ "node": "22.16.0",
45
+ "yarn": "4.9.1"
46
+ }
47
+ }