@ocavue/utils 1.3.1 → 1.4.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/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/checker.test.ts +22 -1
- package/src/checker.ts +7 -0
- package/src/map-values.ts +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,10 @@ declare function isMap(value: unknown): value is Map<unknown, unknown>;
|
|
|
11
11
|
* Checks if the given value is a Set.
|
|
12
12
|
*/
|
|
13
13
|
declare function isSet(value: unknown): value is Set<unknown>;
|
|
14
|
+
/**
|
|
15
|
+
* Returns true if the given value is not null or undefined.
|
|
16
|
+
*/
|
|
17
|
+
declare function isNotNullish<T>(value: T): value is NonNullable<T>;
|
|
14
18
|
//#endregion
|
|
15
19
|
//#region src/counter.d.ts
|
|
16
20
|
/**
|
|
@@ -546,5 +550,5 @@ declare function once<T>(fn: () => T): () => T;
|
|
|
546
550
|
*/
|
|
547
551
|
declare function sleep(ms: number): Promise<void>;
|
|
548
552
|
//#endregion
|
|
549
|
-
export { Counter, DefaultMap, DefaultWeakMap, type ObjectEntries, WeakCounter, formatBytes, getDocument, getDocumentElement, getId, getWindow, isDeepEqual, isDocument, isDocumentFragment, isElement, isElementLike, isHTMLElement, isMap, isMathMLElement, isNodeLike, isObject, isSVGElement, isSet, isShadowRoot, isTextNode, isWindowLike, mapGroupBy, mapValues, objectEntries, objectGroupBy, once, sleep };
|
|
553
|
+
export { Counter, DefaultMap, DefaultWeakMap, type ObjectEntries, WeakCounter, formatBytes, getDocument, getDocumentElement, getId, getWindow, isDeepEqual, isDocument, isDocumentFragment, isElement, isElementLike, isHTMLElement, isMap, isMathMLElement, isNodeLike, isNotNullish, isObject, isSVGElement, isSet, isShadowRoot, isTextNode, isWindowLike, mapGroupBy, mapValues, objectEntries, objectGroupBy, once, sleep };
|
|
550
554
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/checker.ts","../src/counter.ts","../src/default-map.ts","../src/dom.ts","../src/format-bytes.ts","../src/get-id.ts","../src/is-deep-equal.ts","../src/map-group-by.ts","../src/map-values.ts","../src/object-entries.ts","../src/object-group-by.ts","../src/once.ts","../src/sleep.ts"],"sourcesContent":[],"mappings":";;AAGA;AASA;AAOgB,iBAhBA,QAAA,CAgBmC,KAAA,EAAA,OAAA,CAAA,EAAA,KAAA,IAdvC,MAcuC,CAAA,MAAA,GAAA,MAAA,GAAA,MAAA,EAAA,OAAA,CAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/checker.ts","../src/counter.ts","../src/default-map.ts","../src/dom.ts","../src/format-bytes.ts","../src/get-id.ts","../src/is-deep-equal.ts","../src/map-group-by.ts","../src/map-values.ts","../src/object-entries.ts","../src/object-group-by.ts","../src/once.ts","../src/sleep.ts"],"sourcesContent":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,9 @@ function isMap(value) {
|
|
|
7
7
|
function isSet(value) {
|
|
8
8
|
return value instanceof Set;
|
|
9
9
|
}
|
|
10
|
+
function isNotNullish(value) {
|
|
11
|
+
return value != null;
|
|
12
|
+
}
|
|
10
13
|
var Counter = class extends Map {
|
|
11
14
|
constructor(iterable) {
|
|
12
15
|
super(iterable);
|
|
@@ -181,6 +184,6 @@ function once(fn) {
|
|
|
181
184
|
function sleep(ms) {
|
|
182
185
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
183
186
|
}
|
|
184
|
-
export { Counter, DefaultMap, DefaultWeakMap, WeakCounter, formatBytes, getDocument, getDocumentElement, getId, getWindow, isDeepEqual, isDocument, isDocumentFragment, isElement, isElementLike, isHTMLElement, isMap, isMathMLElement, isNodeLike, isObject, isSVGElement, isSet, isShadowRoot, isTextNode, isWindowLike, mapGroupBy, mapValues, objectEntries, objectGroupBy, once, sleep };
|
|
187
|
+
export { Counter, DefaultMap, DefaultWeakMap, WeakCounter, formatBytes, getDocument, getDocumentElement, getId, getWindow, isDeepEqual, isDocument, isDocumentFragment, isElement, isElementLike, isHTMLElement, isMap, isMathMLElement, isNodeLike, isNotNullish, isObject, isSVGElement, isSet, isShadowRoot, isTextNode, isWindowLike, mapGroupBy, mapValues, objectEntries, objectGroupBy, once, sleep };
|
|
185
188
|
|
|
186
189
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["NodeType.ELEMENT_NODE","NodeType.TEXT_NODE","NodeType.DOCUMENT_NODE","NodeType.DOCUMENT_FRAGMENT_NODE","result: Partial<Record<K, T[]>>","result: T"],"sources":["../src/checker.ts","../src/counter.ts","../src/default-map.ts","../src/dom-node-type.ts","../src/dom.ts","../src/format-bytes.ts","../src/get-id.ts","../src/is-deep-equal.ts","../src/map-group-by.ts","../src/map-values.ts","../src/object-entries.ts","../src/object-group-by.ts","../src/once.ts","../src/sleep.ts"],"sourcesContent":["/**\n * Checks if the given value is an object.\n */\nexport function isObject(\n value: unknown,\n): value is Record<string | symbol | number, unknown> {\n return value != null && typeof value === 'object'\n}\n\n/**\n * Checks if the given value is a Map.\n */\nexport function isMap(value: unknown): value is Map<unknown, unknown> {\n return value instanceof Map\n}\n\n/**\n * Checks if the given value is a Set.\n */\nexport function isSet(value: unknown): value is Set<unknown> {\n return value instanceof Set\n}\n","/**\n * A map that counts occurrences of keys.\n *\n * @example\n * ```typescript\n * // Count word occurrences\n * const wordCounter = new Counter<string>()\n * const words = ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']\n *\n * for (const word of words) {\n * wordCounter.increment(word)\n * }\n *\n * console.log(wordCounter.get('apple')) // 3\n * console.log(wordCounter.get('banana')) // 2\n * console.log(wordCounter.get('cherry')) // 1\n * console.log(wordCounter.get('orange')) // 0 (defaults to 0)\n * ```\n *\n * @example\n * ```typescript\n * // Initialize with existing counts\n * const counter = new Counter<string>([\n * ['red', 5],\n * ['blue', 3],\n * ['green', 7]\n * ])\n *\n * counter.increment('red', 2) // red: 5 -> 7\n * counter.decrement('blue') // blue: 3 -> 2\n * counter.increment('yellow') // yellow: 0 -> 1\n *\n * console.log(counter.get('red')) // 7\n * console.log(counter.get('blue')) // 2\n * console.log(counter.get('yellow')) // 1\n * ```\n *\n * @example\n * ```typescript\n * // Track event frequencies\n * const eventCounter = new Counter<string>()\n *\n * eventCounter.increment('click', 5)\n * eventCounter.increment('hover', 3)\n * eventCounter.increment('click', 2)\n *\n * // Get most common events\n * const events = [...eventCounter.entries()]\n * .sort((a, b) => b[1] - a[1])\n *\n * console.log(events) // [['click', 7], ['hover', 3]]\n * ```\n */\nexport class Counter<K> extends Map<K, number> {\n constructor(iterable?: Iterable<readonly [K, number]>) {\n super(iterable)\n }\n\n override get(key: K): number {\n return super.get(key) ?? 0\n }\n\n /**\n * Increments the count for a key by a given amount (default 1).\n */\n increment(key: K, amount = 1): void {\n this.set(key, this.get(key) + amount)\n }\n\n /**\n * Decrements the count for a key by a given amount (default 1).\n */\n decrement(key: K, amount = 1): void {\n this.set(key, this.get(key) - amount)\n }\n}\n\n/**\n * A weak map that counts occurrences of object keys.\n *\n * Similar to {@link Counter} but uses WeakMap as the base, allowing garbage collection of keys.\n *\n * @example\n * ```typescript\n * // Track reference counts for DOM elements\n * const elementRefs = new WeakCounter<HTMLElement>()\n *\n * function addReference(element: HTMLElement) {\n * elementRefs.increment(element)\n * console.log(`References: ${elementRefs.get(element)}`)\n * }\n *\n * function removeReference(element: HTMLElement) {\n * elementRefs.decrement(element)\n * console.log(`References: ${elementRefs.get(element)}`)\n * }\n *\n * const div = document.createElement('div')\n * addReference(div) // References: 1\n * addReference(div) // References: 2\n * removeReference(div) // References: 1\n * ```\n *\n * @example\n * ```typescript\n * // Count object interactions without preventing garbage collection\n * const objectInteractions = new WeakCounter<object>()\n *\n * function handleInteraction(obj: object, count = 1) {\n * objectInteractions.increment(obj, count)\n * }\n *\n * const user = { id: 1, name: 'Alice' }\n * const session = { sessionId: 'abc123' }\n *\n * handleInteraction(user, 3)\n * handleInteraction(session, 1)\n * handleInteraction(user, 2)\n *\n * console.log(objectInteractions.get(user)) // 5\n * console.log(objectInteractions.get(session)) // 1\n * // When user and session are no longer referenced elsewhere,\n * // they can be garbage collected along with their counts\n * ```\n *\n * @example\n * ```typescript\n * // Initialize with existing counts\n * const cache1 = {}\n * const cache2 = {}\n * const cache3 = {}\n *\n * const hitCounter = new WeakCounter<object>([\n * [cache1, 10],\n * [cache2, 5],\n * [cache3, 15]\n * ])\n *\n * hitCounter.increment(cache1, 3) // 10 -> 13\n * console.log(hitCounter.get(cache1)) // 13\n * console.log(hitCounter.get(cache2)) // 5\n * ```\n */\nexport class WeakCounter<K extends WeakKey> extends WeakMap<K, number> {\n constructor(entries?: readonly (readonly [K, number])[] | null) {\n super(entries)\n }\n\n override get(key: K): number {\n return super.get(key) ?? 0\n }\n\n /**\n * Increments the count for a key by a given amount (default 1).\n */\n increment(key: K, amount = 1): void {\n this.set(key, this.get(key) + amount)\n }\n\n /**\n * Decrements the count for a key by a given amount (default 1).\n */\n decrement(key: K, amount = 1): void {\n this.set(key, this.get(key) - amount)\n }\n}\n","/**\n * A map that automatically creates values for missing keys using a factory function.\n *\n * Similar to Python's [defaultdict](https://docs.python.org/3.13/library/collections.html#collections.defaultdict).\n *\n * @example\n * ```typescript\n * // Group items by category using arrays\n * const groupByCategory = new DefaultMap<string, string[]>(() => [])\n *\n * groupByCategory.get('fruits').push('apple', 'banana')\n * groupByCategory.get('vegetables').push('carrot')\n * groupByCategory.get('fruits').push('orange')\n *\n * console.log(groupByCategory.get('fruits')) // ['apple', 'banana', 'orange']\n * console.log(groupByCategory.get('vegetables')) // ['carrot']\n * console.log(groupByCategory.get('dairy')) // [] (auto-created)\n * ```\n *\n * @example\n * ```typescript\n * // Build a graph with adjacency lists\n * const graph = new DefaultMap<string, Set<string>>(() => new Set())\n *\n * graph.get('A').add('B').add('C')\n * graph.get('B').add('C').add('D')\n * graph.get('C').add('D')\n *\n * console.log([...graph.get('A')]) // ['B', 'C']\n * console.log([...graph.get('B')]) // ['C', 'D']\n * console.log([...graph.get('E')]) // [] (auto-created empty set)\n * ```\n *\n * @example\n * ```typescript\n * // Initialize with existing entries\n * const scores = new DefaultMap<string, number>(\n * () => 0,\n * [\n * ['Alice', 100],\n * ['Bob', 85]\n * ]\n * )\n *\n * scores.set('Alice', scores.get('Alice') + 10) // 100 -> 110\n * console.log(scores.get('Alice')) // 110\n * console.log(scores.get('Bob')) // 85\n * console.log(scores.get('Charlie')) // 0 (auto-created)\n * ```\n *\n * @example\n * ```typescript\n * // Nested DefaultMaps for 2D data structures\n * const matrix = new DefaultMap<number, DefaultMap<number, number>>(\n * () => new DefaultMap<number, number>(() => 0)\n * )\n *\n * matrix.get(0).set(0, 1)\n * matrix.get(0).set(1, 2)\n * matrix.get(1).set(1, 3)\n *\n * console.log(matrix.get(0).get(0)) // 1\n * console.log(matrix.get(0).get(1)) // 2\n * console.log(matrix.get(1).get(0)) // 0 (auto-created)\n * console.log(matrix.get(2).get(3)) // 0 (both auto-created)\n * ```\n */\nexport class DefaultMap<K, V> extends Map<K, V> {\n private readonly defaultFactory: () => V\n\n constructor(defaultFactory: () => V, iterable?: Iterable<readonly [K, V]>) {\n super(iterable)\n this.defaultFactory = defaultFactory\n }\n\n override get(key: K): V {\n if (this.has(key)) {\n return super.get(key)!\n }\n const value = this.defaultFactory()\n this.set(key, value)\n return value\n }\n}\n\n/**\n * A weak map that automatically creates values for missing keys using a factory function.\n *\n * Similar to {@link DefaultMap} but uses WeakMap as the base, allowing garbage collection of keys.\n *\n * @example\n * ```typescript\n * // Store metadata for DOM elements without preventing garbage collection\n * const elementMetadata = new DefaultWeakMap<HTMLElement, { clicks: number; hovers: number }>(\n * () => ({ clicks: 0, hovers: 0 })\n * )\n *\n * const button = document.querySelector('button')!\n * const div = document.querySelector('div')!\n *\n * elementMetadata.get(button).clicks++\n * elementMetadata.get(button).clicks++\n * elementMetadata.get(div).hovers++\n *\n * console.log(elementMetadata.get(button)) // { clicks: 2, hovers: 0 }\n * console.log(elementMetadata.get(div)) // { clicks: 0, hovers: 1 }\n * // When elements are removed from DOM and not referenced,\n * // their metadata can be garbage collected\n * ```\n *\n * @example\n * ```typescript\n * // Cache computed properties for objects\n * const computedCache = new DefaultWeakMap<object, Map<string, any>>(\n * () => new Map()\n * )\n *\n * function getOrCompute(obj: object, key: string, compute: () => any) {\n * const cache = computedCache.get(obj)\n * if (!cache.has(key)) {\n * cache.set(key, compute())\n * }\n * return cache.get(key)\n * }\n *\n * const user = { name: 'Alice', age: 30 }\n * const displayName = getOrCompute(user, 'displayName', () => user.name.toUpperCase())\n * const birthYear = getOrCompute(user, 'birthYear', () => new Date().getFullYear() - user.age)\n *\n * console.log(displayName) // 'ALICE'\n * console.log(birthYear) // 1994 (or current year - 30)\n * ```\n *\n * @example\n * ```typescript\n * // Initialize with existing entries\n * const obj1 = {}\n * const obj2 = {}\n *\n * const objectData = new DefaultWeakMap<object, string[]>(\n * () => [],\n * [\n * [obj1, ['tag1', 'tag2']],\n * [obj2, ['tag3']]\n * ]\n * )\n *\n * objectData.get(obj1).push('tag4')\n * console.log(objectData.get(obj1)) // ['tag1', 'tag2', 'tag4']\n * console.log(objectData.get(obj2)) // ['tag3']\n *\n * const obj3 = {}\n * console.log(objectData.get(obj3)) // [] (auto-created)\n * ```\n *\n * @example\n * ```typescript\n * // Track event listeners per element using both DefaultWeakMap and DefaultMap\n * const eventListeners = new DefaultWeakMap<EventTarget, DefaultMap<string, Function[]>>(\n * () => new DefaultMap<string, Function[]>(() => [])\n * )\n *\n * function addListener(target: EventTarget, event: string, handler: Function) {\n * eventListeners.get(target).get(event).push(handler)\n * }\n *\n * const element = document.createElement('button')\n * addListener(element, 'click', () => console.log('clicked'))\n * addListener(element, 'click', () => console.log('also clicked'))\n * addListener(element, 'hover', () => console.log('hovered'))\n *\n * console.log(eventListeners.get(element).get('click').length) // 2\n * console.log(eventListeners.get(element).get('hover').length) // 1\n * // No need for has() checks or null assertions - everything auto-initializes!\n * ```\n */\nexport class DefaultWeakMap<K extends WeakKey, V> extends WeakMap<K, V> {\n private readonly defaultFactory: () => V\n\n constructor(\n defaultFactory: () => V,\n entries?: readonly (readonly [K, V])[] | null,\n ) {\n super(entries)\n this.defaultFactory = defaultFactory\n }\n\n override get(key: K): V {\n if (this.has(key)) {\n return super.get(key)!\n }\n const value = this.defaultFactory()\n this.set(key, value)\n return value\n }\n}\n","// prettier-ignore\nexport const ELEMENT_NODE = 1 satisfies typeof Node.ELEMENT_NODE;\n// prettier-ignore\nexport const ATTRIBUTE_NODE = 2 satisfies typeof Node.ATTRIBUTE_NODE;\n// prettier-ignore\nexport const TEXT_NODE = 3 satisfies typeof Node.TEXT_NODE;\n// prettier-ignore\nexport const CDATA_SECTION_NODE = 4 satisfies typeof Node.CDATA_SECTION_NODE;\n// prettier-ignore\nexport const ENTITY_REFERENCE_NODE = 5 satisfies typeof Node.ENTITY_REFERENCE_NODE;\n// prettier-ignore\nexport const ENTITY_NODE = 6 satisfies typeof Node.ENTITY_NODE;\n// prettier-ignore\nexport const PROCESSING_INSTRUCTION_NODE = 7 satisfies typeof Node.PROCESSING_INSTRUCTION_NODE;\n// prettier-ignore\nexport const COMMENT_NODE = 8 satisfies typeof Node.COMMENT_NODE;\n// prettier-ignore\nexport const DOCUMENT_NODE = 9 satisfies typeof Node.DOCUMENT_NODE;\n// prettier-ignore\nexport const DOCUMENT_TYPE_NODE = 10 satisfies typeof Node.DOCUMENT_TYPE_NODE;\n// prettier-ignore\nexport const DOCUMENT_FRAGMENT_NODE = 11 satisfies typeof Node.DOCUMENT_FRAGMENT_NODE;\n// prettier-ignore\nexport const NOTATION_NODE = 12 satisfies typeof Node.NOTATION_NODE;\n","import { isObject } from './checker'\nimport * as NodeType from './dom-node-type'\n\n/**\n * Checks if the given DOM node is an Element.\n */\nexport function isElement(node: Node): node is Element {\n return node.nodeType === NodeType.ELEMENT_NODE\n}\n\n/**\n * Checks if the given DOM node is a Text node.\n */\nexport function isTextNode(node: Node): node is Text {\n return node.nodeType === NodeType.TEXT_NODE\n}\n\n/**\n * Checks if the given DOM node is an HTMLElement.\n */\nexport function isHTMLElement(node: Node): node is HTMLElement {\n return isElement(node) && node.namespaceURI === 'http://www.w3.org/1999/xhtml'\n}\n\n/**\n * Checks if the given DOM node is an SVGElement.\n */\nexport function isSVGElement(node: Node): node is SVGElement {\n return isElement(node) && node.namespaceURI === 'http://www.w3.org/2000/svg'\n}\n\n/**\n * Checks if the given DOM node is an MathMLElement.\n */\nexport function isMathMLElement(node: Node): node is MathMLElement {\n return (\n isElement(node) &&\n node.namespaceURI === 'http://www.w3.org/1998/Math/MathML'\n )\n}\n\n/**\n * Checks if the given DOM node is a Document.\n */\nexport function isDocument(node: Node): node is Document {\n return node.nodeType === NodeType.DOCUMENT_NODE\n}\n\n/**\n * Checks if the given DOM node is a DocumentFragment.\n */\nexport function isDocumentFragment(node: Node): node is DocumentFragment {\n return node.nodeType === NodeType.DOCUMENT_FRAGMENT_NODE\n}\n\n/**\n * Checks if the given DOM node is a ShadowRoot.\n */\nexport function isShadowRoot(node: Node): node is ShadowRoot {\n return isDocumentFragment(node) && 'host' in node && isElementLike(node.host)\n}\n\n/**\n * Checks if an unknown value is likely a DOM node.\n */\nexport function isNodeLike(value: unknown): value is Node {\n return isObject(value) && value.nodeType !== undefined\n}\n\n/**\n * Checks if an unknown value is likely a DOM element.\n */\nexport function isElementLike(value: unknown): value is Element {\n return (\n isObject(value) &&\n value.nodeType === NodeType.ELEMENT_NODE &&\n typeof value.nodeName === 'string'\n )\n}\n\n/**\n * Checks if the given value is likely a Window object.\n */\nexport function isWindowLike(value: unknown): value is Window {\n return isObject(value) && value.window === value\n}\n\n/**\n * Gets the window object for the given target or the global window object if no\n * target is provided.\n */\nexport function getWindow(\n target?: Node | ShadowRoot | Document | null,\n): Window & typeof globalThis {\n if (target) {\n if (isShadowRoot(target)) {\n return getWindow(target.host)\n }\n if (isDocument(target)) {\n return target.defaultView || window\n }\n if (isElement(target)) {\n return target.ownerDocument?.defaultView || window\n }\n }\n return window\n}\n\n/**\n * Gets the document for the given target or the global document if no target is\n * provided.\n */\nexport function getDocument(\n target?: Element | Window | Node | Document | null,\n): Document {\n if (target) {\n if (isWindowLike(target)) {\n return target.document\n }\n if (isDocument(target)) {\n return target\n }\n return target.ownerDocument || document\n }\n return document\n}\n\n/**\n * Gets a reference to the root node of the document based on the given target.\n */\nexport function getDocumentElement(\n target?: Element | Node | Window | Document | null,\n): HTMLElement {\n return getDocument(target).documentElement\n}\n","/**\n * Formats a number of bytes into a human-readable string.\n * @param bytes - The number of bytes to format.\n * @returns A string representing the number of bytes in a human-readable format.\n */\nexport function formatBytes(bytes: number): string {\n const units = ['B', 'KB', 'MB', 'GB']\n let unitIndex = 0\n let num = bytes\n while (Math.abs(num) >= 1024 && unitIndex < units.length - 1) {\n num /= 1024\n unitIndex++\n }\n const fraction = unitIndex === 0 && num % 1 === 0 ? 0 : 1\n return `${num.toFixed(fraction)}${units[unitIndex]}`\n}\n","let id = 0\n\nlet maxSafeInteger = Number.MAX_SAFE_INTEGER\n\n/**\n * Sets the maximum safe integer for the id generator. Only for testing purposes.\n *\n * @internal\n */\nexport function setMaxSafeInteger(max: number) {\n maxSafeInteger = max\n}\n\n/**\n * Generates a unique positive integer.\n */\nexport function getId(): number {\n id++\n if (id >= maxSafeInteger) {\n id = 1\n }\n return id\n}\n","import { isMap, isSet } from './checker'\n\n/**\n * Whether two values are deeply equal.\n */\nexport function isDeepEqual(a: unknown, b: unknown): boolean {\n if (a === b) {\n return true\n }\n\n // Handle null and undefined early\n if (a == null || b == null) {\n return false\n }\n\n const aType = typeof a\n const bType = typeof b\n if (aType !== bType) {\n return false\n }\n\n if (aType === 'number' && Number.isNaN(a) && Number.isNaN(b)) {\n return true\n }\n\n if (Array.isArray(a)) {\n if (!Array.isArray(b)) {\n return false\n }\n if (a.length !== b.length) {\n return false\n }\n const size = a.length\n for (let i = 0; i < size; i++) {\n if (!isDeepEqual(a[i], b[i])) {\n return false\n }\n }\n return true\n }\n\n if (isSet(a)) {\n if (!isSet(b)) {\n return false\n }\n if (a.size !== b.size) {\n return false\n }\n for (const value of a) {\n if (!b.has(value)) {\n return false\n }\n }\n return true\n }\n\n if (isMap(a)) {\n if (!isMap(b)) {\n return false\n }\n if (a.size !== b.size) {\n return false\n }\n for (const key of a.keys()) {\n if (!b.has(key)) {\n return false\n }\n if (!isDeepEqual(a.get(key), b.get(key))) {\n return false\n }\n }\n return true\n }\n\n if (typeof a === 'object' && typeof b === 'object') {\n const aKeys = Object.keys(a)\n const bKeys = Object.keys(b)\n if (aKeys.length !== bKeys.length) {\n return false\n }\n for (const key of aKeys) {\n if (\n !isDeepEqual(\n (a as Record<string, unknown>)[key],\n (b as Record<string, unknown>)[key],\n )\n ) {\n return false\n }\n }\n return true\n }\n\n return false\n}\n","/**\n * @internal\n */\nexport function mapGroupByPolyfill<K, T>(\n items: Iterable<T>,\n keySelector: (item: T, index: number) => K,\n): Map<K, T[]> {\n const map = new Map<K, T[]>()\n let index = 0\n for (const item of items) {\n const key = keySelector(item, index)\n const group = map.get(key)\n if (group) {\n group.push(item)\n } else {\n map.set(key, [item])\n }\n index++\n }\n return map\n}\n\n/**\n * A polyfill for the [`Map.groupBy()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/groupBy) static method.\n *\n * @public\n */\nexport function mapGroupBy<K, T>(\n items: Iterable<T>,\n keySelector: (item: T, index: number) => K,\n): Map<K, T[]> {\n return Map.groupBy\n ? Map.groupBy(items, keySelector)\n : mapGroupByPolyfill(items, keySelector)\n}\n","/**\n * Creates a new object with the same keys as the input object, but with values\n * transformed by the provided callback function. Similar to `Array.prototype.map()`\n * but for object values.\n\n * @param object - The object whose values will be transformed.\n * @param callback - A function that transforms each value. Receives the value and\n * its corresponding key as arguments.\n * @returns A new object with the same keys but transformed values.\n *\n * @example\n * ```typescript\n * const prices = { apple: 1, banana: 2, orange: 3 }\n * const doubled = mapValues(prices, (price) => price * 2)\n * // Result: { apple: 2, banana: 4, orange: 6 }\n * ```\n *\n * @example\n * ```typescript\n * const users = { john: 25, jane: 30, bob: 35 }\n * const greetings = mapValues(users, (age, name) => `${name} is ${age} years old`)\n * // Result: { john: 'john is 25 years old', jane: 'jane is 30 years old', bob: 'bob is 35 years old' }\n * ```\n *\n * @example\n * ```typescript\n * const data = { a: '1', b: '2', c: '3' }\n * const numbers = mapValues(data, (str) => parseInt(str, 10))\n * // Result: { a: 1, b: 2, c: 3 }\n * ```\n *\n * @public\n */\nexport function mapValues<ValueIn, ValueOut>(\n object: Record<string, ValueIn>,\n callback: (value: ValueIn, key: string) => ValueOut,\n): Record<string, ValueOut> {\n let result = {} as Record<string, ValueOut>\n for (const [key, value] of Object.entries(object)) {\n result[key] = callback(value, key)\n }\n return result\n}\n","/**\n * A TypeScript utility type that represents the entries of an object as a union of tuple types.\n * Each tuple contains a key-value pair where the key and value types are precisely typed\n * according to the input object type.\n *\n * @example\n * ```typescript\n * type MyObject = { a: 1; b: 'B' }\n * type MyEntries = ObjectEntries<MyObject>\n * // ^ [\"a\", 1] | [\"b\", \"B\"]\n * ```\n *\n * @public\n */\nexport type ObjectEntries<T extends Record<string, any>> = {\n [K in keyof T]: [K, T[K]]\n}[keyof T]\n\n/**\n * A type-safe wrapper around\n * [`Object.entries()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries)\n * that preserves the exact types of object keys and values. Unlike the standard\n * `Object.entries()` which returns `[string, any][]`, this function returns an\n * array of tuples where each tuple is precisely typed according to the input\n * object's structure.\n *\n * This is particularly useful when working with objects that have known, fixed\n * property types and you want to maintain type safety when iterating over\n * entries.\n *\n * @example\n * ```typescript\n * const myObject = { a: 1, b: 'hello', c: true } as const\n * const entries = objectEntries(myObject)\n * // Type: ([\"a\", 1] | [\"b\", \"hello\"] | [\"c\", true])[]\n *\n * for (const [key, value] of entries) {\n * // key is typed as \"a\" | \"b\" | \"c\"\n * // value is typed as 1 | \"hello\" | true\n * console.log(`${key}: ${value}`)\n * }\n * ```\n *\n * @example\n * ```typescript\n * interface User {\n * name: string\n * age: number\n * active: boolean\n * }\n *\n * const user: User = { name: 'Alice', age: 30, active: true }\n * const entries = objectEntries(user)\n * // Type: ([\"name\", string] | [\"age\", number] | [\"active\", boolean])[]\n * ```\n *\n * @public\n */\nexport function objectEntries<T extends Record<string, any>>(\n obj: T,\n): ObjectEntries<T>[] {\n return Object.entries(obj)\n}\n","/**\n * @internal\n */\nexport function objectGroupByPolyfill<K extends PropertyKey, T>(\n items: Iterable<T>,\n keySelector: (item: T, index: number) => K,\n): Partial<Record<K, T[]>> {\n const result: Partial<Record<K, T[]>> = {}\n let index = 0\n for (const item of items) {\n const key = keySelector(item, index)\n const group = result[key]\n if (group) {\n group.push(item)\n } else {\n result[key] = [item]\n }\n index++\n }\n return result\n}\n\n/**\n * A polyfill for the [`Object.groupBy()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/groupBy) static method.\n *\n * @public\n */\nexport function objectGroupBy<K extends PropertyKey, T>(\n items: Iterable<T>,\n keySelector: (item: T, index: number) => K,\n): Partial<Record<K, T[]>> {\n return Object.groupBy\n ? Object.groupBy(items, keySelector)\n : objectGroupByPolyfill(items, keySelector)\n}\n","/**\n * Creates a function that will only execute the provided function once.\n * Subsequent calls will return the cached result from the first execution.\n *\n * @param fn The function to execute once\n * @returns A function that will only execute the provided function once\n * @example\n * ```ts\n * const getValue = once(() => expensiveOperation())\n * getValue() // executes expensiveOperation\n * getValue() // returns cached result\n * ```\n */\nexport function once<T>(fn: () => T): () => T {\n let called = false\n let result: T\n return () => {\n if (!called) {\n result = fn()\n called = true\n // @ts-expect-error - micro-optimization for memory management\n fn = undefined\n }\n return result\n }\n}\n","/**\n * Returns a Promise that resolves after a specified number of milliseconds.\n *\n * @param ms - The number of milliseconds to wait.\n *\n * @example\n * ```js\n * await sleep(1000) // Wait 1 second\n * ```\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["NodeType.ELEMENT_NODE","NodeType.TEXT_NODE","NodeType.DOCUMENT_NODE","NodeType.DOCUMENT_FRAGMENT_NODE","result: Partial<Record<K, T[]>>","result: T"],"sources":["../src/checker.ts","../src/counter.ts","../src/default-map.ts","../src/dom-node-type.ts","../src/dom.ts","../src/format-bytes.ts","../src/get-id.ts","../src/is-deep-equal.ts","../src/map-group-by.ts","../src/map-values.ts","../src/object-entries.ts","../src/object-group-by.ts","../src/once.ts","../src/sleep.ts"],"sourcesContent":["/**\n * Checks if the given value is an object.\n */\nexport function isObject(\n value: unknown,\n): value is Record<string | symbol | number, unknown> {\n return value != null && typeof value === 'object'\n}\n\n/**\n * Checks if the given value is a Map.\n */\nexport function isMap(value: unknown): value is Map<unknown, unknown> {\n return value instanceof Map\n}\n\n/**\n * Checks if the given value is a Set.\n */\nexport function isSet(value: unknown): value is Set<unknown> {\n return value instanceof Set\n}\n\n/**\n * Returns true if the given value is not null or undefined.\n */\nexport function isNotNullish<T>(value: T): value is NonNullable<T> {\n return value != null\n}\n","/**\n * A map that counts occurrences of keys.\n *\n * @example\n * ```typescript\n * // Count word occurrences\n * const wordCounter = new Counter<string>()\n * const words = ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']\n *\n * for (const word of words) {\n * wordCounter.increment(word)\n * }\n *\n * console.log(wordCounter.get('apple')) // 3\n * console.log(wordCounter.get('banana')) // 2\n * console.log(wordCounter.get('cherry')) // 1\n * console.log(wordCounter.get('orange')) // 0 (defaults to 0)\n * ```\n *\n * @example\n * ```typescript\n * // Initialize with existing counts\n * const counter = new Counter<string>([\n * ['red', 5],\n * ['blue', 3],\n * ['green', 7]\n * ])\n *\n * counter.increment('red', 2) // red: 5 -> 7\n * counter.decrement('blue') // blue: 3 -> 2\n * counter.increment('yellow') // yellow: 0 -> 1\n *\n * console.log(counter.get('red')) // 7\n * console.log(counter.get('blue')) // 2\n * console.log(counter.get('yellow')) // 1\n * ```\n *\n * @example\n * ```typescript\n * // Track event frequencies\n * const eventCounter = new Counter<string>()\n *\n * eventCounter.increment('click', 5)\n * eventCounter.increment('hover', 3)\n * eventCounter.increment('click', 2)\n *\n * // Get most common events\n * const events = [...eventCounter.entries()]\n * .sort((a, b) => b[1] - a[1])\n *\n * console.log(events) // [['click', 7], ['hover', 3]]\n * ```\n */\nexport class Counter<K> extends Map<K, number> {\n constructor(iterable?: Iterable<readonly [K, number]>) {\n super(iterable)\n }\n\n override get(key: K): number {\n return super.get(key) ?? 0\n }\n\n /**\n * Increments the count for a key by a given amount (default 1).\n */\n increment(key: K, amount = 1): void {\n this.set(key, this.get(key) + amount)\n }\n\n /**\n * Decrements the count for a key by a given amount (default 1).\n */\n decrement(key: K, amount = 1): void {\n this.set(key, this.get(key) - amount)\n }\n}\n\n/**\n * A weak map that counts occurrences of object keys.\n *\n * Similar to {@link Counter} but uses WeakMap as the base, allowing garbage collection of keys.\n *\n * @example\n * ```typescript\n * // Track reference counts for DOM elements\n * const elementRefs = new WeakCounter<HTMLElement>()\n *\n * function addReference(element: HTMLElement) {\n * elementRefs.increment(element)\n * console.log(`References: ${elementRefs.get(element)}`)\n * }\n *\n * function removeReference(element: HTMLElement) {\n * elementRefs.decrement(element)\n * console.log(`References: ${elementRefs.get(element)}`)\n * }\n *\n * const div = document.createElement('div')\n * addReference(div) // References: 1\n * addReference(div) // References: 2\n * removeReference(div) // References: 1\n * ```\n *\n * @example\n * ```typescript\n * // Count object interactions without preventing garbage collection\n * const objectInteractions = new WeakCounter<object>()\n *\n * function handleInteraction(obj: object, count = 1) {\n * objectInteractions.increment(obj, count)\n * }\n *\n * const user = { id: 1, name: 'Alice' }\n * const session = { sessionId: 'abc123' }\n *\n * handleInteraction(user, 3)\n * handleInteraction(session, 1)\n * handleInteraction(user, 2)\n *\n * console.log(objectInteractions.get(user)) // 5\n * console.log(objectInteractions.get(session)) // 1\n * // When user and session are no longer referenced elsewhere,\n * // they can be garbage collected along with their counts\n * ```\n *\n * @example\n * ```typescript\n * // Initialize with existing counts\n * const cache1 = {}\n * const cache2 = {}\n * const cache3 = {}\n *\n * const hitCounter = new WeakCounter<object>([\n * [cache1, 10],\n * [cache2, 5],\n * [cache3, 15]\n * ])\n *\n * hitCounter.increment(cache1, 3) // 10 -> 13\n * console.log(hitCounter.get(cache1)) // 13\n * console.log(hitCounter.get(cache2)) // 5\n * ```\n */\nexport class WeakCounter<K extends WeakKey> extends WeakMap<K, number> {\n constructor(entries?: readonly (readonly [K, number])[] | null) {\n super(entries)\n }\n\n override get(key: K): number {\n return super.get(key) ?? 0\n }\n\n /**\n * Increments the count for a key by a given amount (default 1).\n */\n increment(key: K, amount = 1): void {\n this.set(key, this.get(key) + amount)\n }\n\n /**\n * Decrements the count for a key by a given amount (default 1).\n */\n decrement(key: K, amount = 1): void {\n this.set(key, this.get(key) - amount)\n }\n}\n","/**\n * A map that automatically creates values for missing keys using a factory function.\n *\n * Similar to Python's [defaultdict](https://docs.python.org/3.13/library/collections.html#collections.defaultdict).\n *\n * @example\n * ```typescript\n * // Group items by category using arrays\n * const groupByCategory = new DefaultMap<string, string[]>(() => [])\n *\n * groupByCategory.get('fruits').push('apple', 'banana')\n * groupByCategory.get('vegetables').push('carrot')\n * groupByCategory.get('fruits').push('orange')\n *\n * console.log(groupByCategory.get('fruits')) // ['apple', 'banana', 'orange']\n * console.log(groupByCategory.get('vegetables')) // ['carrot']\n * console.log(groupByCategory.get('dairy')) // [] (auto-created)\n * ```\n *\n * @example\n * ```typescript\n * // Build a graph with adjacency lists\n * const graph = new DefaultMap<string, Set<string>>(() => new Set())\n *\n * graph.get('A').add('B').add('C')\n * graph.get('B').add('C').add('D')\n * graph.get('C').add('D')\n *\n * console.log([...graph.get('A')]) // ['B', 'C']\n * console.log([...graph.get('B')]) // ['C', 'D']\n * console.log([...graph.get('E')]) // [] (auto-created empty set)\n * ```\n *\n * @example\n * ```typescript\n * // Initialize with existing entries\n * const scores = new DefaultMap<string, number>(\n * () => 0,\n * [\n * ['Alice', 100],\n * ['Bob', 85]\n * ]\n * )\n *\n * scores.set('Alice', scores.get('Alice') + 10) // 100 -> 110\n * console.log(scores.get('Alice')) // 110\n * console.log(scores.get('Bob')) // 85\n * console.log(scores.get('Charlie')) // 0 (auto-created)\n * ```\n *\n * @example\n * ```typescript\n * // Nested DefaultMaps for 2D data structures\n * const matrix = new DefaultMap<number, DefaultMap<number, number>>(\n * () => new DefaultMap<number, number>(() => 0)\n * )\n *\n * matrix.get(0).set(0, 1)\n * matrix.get(0).set(1, 2)\n * matrix.get(1).set(1, 3)\n *\n * console.log(matrix.get(0).get(0)) // 1\n * console.log(matrix.get(0).get(1)) // 2\n * console.log(matrix.get(1).get(0)) // 0 (auto-created)\n * console.log(matrix.get(2).get(3)) // 0 (both auto-created)\n * ```\n */\nexport class DefaultMap<K, V> extends Map<K, V> {\n private readonly defaultFactory: () => V\n\n constructor(defaultFactory: () => V, iterable?: Iterable<readonly [K, V]>) {\n super(iterable)\n this.defaultFactory = defaultFactory\n }\n\n override get(key: K): V {\n if (this.has(key)) {\n return super.get(key)!\n }\n const value = this.defaultFactory()\n this.set(key, value)\n return value\n }\n}\n\n/**\n * A weak map that automatically creates values for missing keys using a factory function.\n *\n * Similar to {@link DefaultMap} but uses WeakMap as the base, allowing garbage collection of keys.\n *\n * @example\n * ```typescript\n * // Store metadata for DOM elements without preventing garbage collection\n * const elementMetadata = new DefaultWeakMap<HTMLElement, { clicks: number; hovers: number }>(\n * () => ({ clicks: 0, hovers: 0 })\n * )\n *\n * const button = document.querySelector('button')!\n * const div = document.querySelector('div')!\n *\n * elementMetadata.get(button).clicks++\n * elementMetadata.get(button).clicks++\n * elementMetadata.get(div).hovers++\n *\n * console.log(elementMetadata.get(button)) // { clicks: 2, hovers: 0 }\n * console.log(elementMetadata.get(div)) // { clicks: 0, hovers: 1 }\n * // When elements are removed from DOM and not referenced,\n * // their metadata can be garbage collected\n * ```\n *\n * @example\n * ```typescript\n * // Cache computed properties for objects\n * const computedCache = new DefaultWeakMap<object, Map<string, any>>(\n * () => new Map()\n * )\n *\n * function getOrCompute(obj: object, key: string, compute: () => any) {\n * const cache = computedCache.get(obj)\n * if (!cache.has(key)) {\n * cache.set(key, compute())\n * }\n * return cache.get(key)\n * }\n *\n * const user = { name: 'Alice', age: 30 }\n * const displayName = getOrCompute(user, 'displayName', () => user.name.toUpperCase())\n * const birthYear = getOrCompute(user, 'birthYear', () => new Date().getFullYear() - user.age)\n *\n * console.log(displayName) // 'ALICE'\n * console.log(birthYear) // 1994 (or current year - 30)\n * ```\n *\n * @example\n * ```typescript\n * // Initialize with existing entries\n * const obj1 = {}\n * const obj2 = {}\n *\n * const objectData = new DefaultWeakMap<object, string[]>(\n * () => [],\n * [\n * [obj1, ['tag1', 'tag2']],\n * [obj2, ['tag3']]\n * ]\n * )\n *\n * objectData.get(obj1).push('tag4')\n * console.log(objectData.get(obj1)) // ['tag1', 'tag2', 'tag4']\n * console.log(objectData.get(obj2)) // ['tag3']\n *\n * const obj3 = {}\n * console.log(objectData.get(obj3)) // [] (auto-created)\n * ```\n *\n * @example\n * ```typescript\n * // Track event listeners per element using both DefaultWeakMap and DefaultMap\n * const eventListeners = new DefaultWeakMap<EventTarget, DefaultMap<string, Function[]>>(\n * () => new DefaultMap<string, Function[]>(() => [])\n * )\n *\n * function addListener(target: EventTarget, event: string, handler: Function) {\n * eventListeners.get(target).get(event).push(handler)\n * }\n *\n * const element = document.createElement('button')\n * addListener(element, 'click', () => console.log('clicked'))\n * addListener(element, 'click', () => console.log('also clicked'))\n * addListener(element, 'hover', () => console.log('hovered'))\n *\n * console.log(eventListeners.get(element).get('click').length) // 2\n * console.log(eventListeners.get(element).get('hover').length) // 1\n * // No need for has() checks or null assertions - everything auto-initializes!\n * ```\n */\nexport class DefaultWeakMap<K extends WeakKey, V> extends WeakMap<K, V> {\n private readonly defaultFactory: () => V\n\n constructor(\n defaultFactory: () => V,\n entries?: readonly (readonly [K, V])[] | null,\n ) {\n super(entries)\n this.defaultFactory = defaultFactory\n }\n\n override get(key: K): V {\n if (this.has(key)) {\n return super.get(key)!\n }\n const value = this.defaultFactory()\n this.set(key, value)\n return value\n }\n}\n","// prettier-ignore\nexport const ELEMENT_NODE = 1 satisfies typeof Node.ELEMENT_NODE;\n// prettier-ignore\nexport const ATTRIBUTE_NODE = 2 satisfies typeof Node.ATTRIBUTE_NODE;\n// prettier-ignore\nexport const TEXT_NODE = 3 satisfies typeof Node.TEXT_NODE;\n// prettier-ignore\nexport const CDATA_SECTION_NODE = 4 satisfies typeof Node.CDATA_SECTION_NODE;\n// prettier-ignore\nexport const ENTITY_REFERENCE_NODE = 5 satisfies typeof Node.ENTITY_REFERENCE_NODE;\n// prettier-ignore\nexport const ENTITY_NODE = 6 satisfies typeof Node.ENTITY_NODE;\n// prettier-ignore\nexport const PROCESSING_INSTRUCTION_NODE = 7 satisfies typeof Node.PROCESSING_INSTRUCTION_NODE;\n// prettier-ignore\nexport const COMMENT_NODE = 8 satisfies typeof Node.COMMENT_NODE;\n// prettier-ignore\nexport const DOCUMENT_NODE = 9 satisfies typeof Node.DOCUMENT_NODE;\n// prettier-ignore\nexport const DOCUMENT_TYPE_NODE = 10 satisfies typeof Node.DOCUMENT_TYPE_NODE;\n// prettier-ignore\nexport const DOCUMENT_FRAGMENT_NODE = 11 satisfies typeof Node.DOCUMENT_FRAGMENT_NODE;\n// prettier-ignore\nexport const NOTATION_NODE = 12 satisfies typeof Node.NOTATION_NODE;\n","import { isObject } from './checker'\nimport * as NodeType from './dom-node-type'\n\n/**\n * Checks if the given DOM node is an Element.\n */\nexport function isElement(node: Node): node is Element {\n return node.nodeType === NodeType.ELEMENT_NODE\n}\n\n/**\n * Checks if the given DOM node is a Text node.\n */\nexport function isTextNode(node: Node): node is Text {\n return node.nodeType === NodeType.TEXT_NODE\n}\n\n/**\n * Checks if the given DOM node is an HTMLElement.\n */\nexport function isHTMLElement(node: Node): node is HTMLElement {\n return isElement(node) && node.namespaceURI === 'http://www.w3.org/1999/xhtml'\n}\n\n/**\n * Checks if the given DOM node is an SVGElement.\n */\nexport function isSVGElement(node: Node): node is SVGElement {\n return isElement(node) && node.namespaceURI === 'http://www.w3.org/2000/svg'\n}\n\n/**\n * Checks if the given DOM node is an MathMLElement.\n */\nexport function isMathMLElement(node: Node): node is MathMLElement {\n return (\n isElement(node) &&\n node.namespaceURI === 'http://www.w3.org/1998/Math/MathML'\n )\n}\n\n/**\n * Checks if the given DOM node is a Document.\n */\nexport function isDocument(node: Node): node is Document {\n return node.nodeType === NodeType.DOCUMENT_NODE\n}\n\n/**\n * Checks if the given DOM node is a DocumentFragment.\n */\nexport function isDocumentFragment(node: Node): node is DocumentFragment {\n return node.nodeType === NodeType.DOCUMENT_FRAGMENT_NODE\n}\n\n/**\n * Checks if the given DOM node is a ShadowRoot.\n */\nexport function isShadowRoot(node: Node): node is ShadowRoot {\n return isDocumentFragment(node) && 'host' in node && isElementLike(node.host)\n}\n\n/**\n * Checks if an unknown value is likely a DOM node.\n */\nexport function isNodeLike(value: unknown): value is Node {\n return isObject(value) && value.nodeType !== undefined\n}\n\n/**\n * Checks if an unknown value is likely a DOM element.\n */\nexport function isElementLike(value: unknown): value is Element {\n return (\n isObject(value) &&\n value.nodeType === NodeType.ELEMENT_NODE &&\n typeof value.nodeName === 'string'\n )\n}\n\n/**\n * Checks if the given value is likely a Window object.\n */\nexport function isWindowLike(value: unknown): value is Window {\n return isObject(value) && value.window === value\n}\n\n/**\n * Gets the window object for the given target or the global window object if no\n * target is provided.\n */\nexport function getWindow(\n target?: Node | ShadowRoot | Document | null,\n): Window & typeof globalThis {\n if (target) {\n if (isShadowRoot(target)) {\n return getWindow(target.host)\n }\n if (isDocument(target)) {\n return target.defaultView || window\n }\n if (isElement(target)) {\n return target.ownerDocument?.defaultView || window\n }\n }\n return window\n}\n\n/**\n * Gets the document for the given target or the global document if no target is\n * provided.\n */\nexport function getDocument(\n target?: Element | Window | Node | Document | null,\n): Document {\n if (target) {\n if (isWindowLike(target)) {\n return target.document\n }\n if (isDocument(target)) {\n return target\n }\n return target.ownerDocument || document\n }\n return document\n}\n\n/**\n * Gets a reference to the root node of the document based on the given target.\n */\nexport function getDocumentElement(\n target?: Element | Node | Window | Document | null,\n): HTMLElement {\n return getDocument(target).documentElement\n}\n","/**\n * Formats a number of bytes into a human-readable string.\n * @param bytes - The number of bytes to format.\n * @returns A string representing the number of bytes in a human-readable format.\n */\nexport function formatBytes(bytes: number): string {\n const units = ['B', 'KB', 'MB', 'GB']\n let unitIndex = 0\n let num = bytes\n while (Math.abs(num) >= 1024 && unitIndex < units.length - 1) {\n num /= 1024\n unitIndex++\n }\n const fraction = unitIndex === 0 && num % 1 === 0 ? 0 : 1\n return `${num.toFixed(fraction)}${units[unitIndex]}`\n}\n","let id = 0\n\nlet maxSafeInteger = Number.MAX_SAFE_INTEGER\n\n/**\n * Sets the maximum safe integer for the id generator. Only for testing purposes.\n *\n * @internal\n */\nexport function setMaxSafeInteger(max: number) {\n maxSafeInteger = max\n}\n\n/**\n * Generates a unique positive integer.\n */\nexport function getId(): number {\n id++\n if (id >= maxSafeInteger) {\n id = 1\n }\n return id\n}\n","import { isMap, isSet } from './checker'\n\n/**\n * Whether two values are deeply equal.\n */\nexport function isDeepEqual(a: unknown, b: unknown): boolean {\n if (a === b) {\n return true\n }\n\n // Handle null and undefined early\n if (a == null || b == null) {\n return false\n }\n\n const aType = typeof a\n const bType = typeof b\n if (aType !== bType) {\n return false\n }\n\n if (aType === 'number' && Number.isNaN(a) && Number.isNaN(b)) {\n return true\n }\n\n if (Array.isArray(a)) {\n if (!Array.isArray(b)) {\n return false\n }\n if (a.length !== b.length) {\n return false\n }\n const size = a.length\n for (let i = 0; i < size; i++) {\n if (!isDeepEqual(a[i], b[i])) {\n return false\n }\n }\n return true\n }\n\n if (isSet(a)) {\n if (!isSet(b)) {\n return false\n }\n if (a.size !== b.size) {\n return false\n }\n for (const value of a) {\n if (!b.has(value)) {\n return false\n }\n }\n return true\n }\n\n if (isMap(a)) {\n if (!isMap(b)) {\n return false\n }\n if (a.size !== b.size) {\n return false\n }\n for (const key of a.keys()) {\n if (!b.has(key)) {\n return false\n }\n if (!isDeepEqual(a.get(key), b.get(key))) {\n return false\n }\n }\n return true\n }\n\n if (typeof a === 'object' && typeof b === 'object') {\n const aKeys = Object.keys(a)\n const bKeys = Object.keys(b)\n if (aKeys.length !== bKeys.length) {\n return false\n }\n for (const key of aKeys) {\n if (\n !isDeepEqual(\n (a as Record<string, unknown>)[key],\n (b as Record<string, unknown>)[key],\n )\n ) {\n return false\n }\n }\n return true\n }\n\n return false\n}\n","/**\n * @internal\n */\nexport function mapGroupByPolyfill<K, T>(\n items: Iterable<T>,\n keySelector: (item: T, index: number) => K,\n): Map<K, T[]> {\n const map = new Map<K, T[]>()\n let index = 0\n for (const item of items) {\n const key = keySelector(item, index)\n const group = map.get(key)\n if (group) {\n group.push(item)\n } else {\n map.set(key, [item])\n }\n index++\n }\n return map\n}\n\n/**\n * A polyfill for the [`Map.groupBy()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/groupBy) static method.\n *\n * @public\n */\nexport function mapGroupBy<K, T>(\n items: Iterable<T>,\n keySelector: (item: T, index: number) => K,\n): Map<K, T[]> {\n return Map.groupBy\n ? Map.groupBy(items, keySelector)\n : mapGroupByPolyfill(items, keySelector)\n}\n","/**\n * Creates a new object with the same keys as the input object, but with values\n * transformed by the provided callback function. Similar to `Array.prototype.map()`\n * but for object values.\n\n * @param object - The object whose values will be transformed.\n * @param callback - A function that transforms each value. Receives the value and\n * its corresponding key as arguments.\n * @returns A new object with the same keys but transformed values.\n *\n * @example\n * ```typescript\n * const prices = { apple: 1, banana: 2, orange: 3 }\n * const doubled = mapValues(prices, (price) => price * 2)\n * // Result: { apple: 2, banana: 4, orange: 6 }\n * ```\n *\n * @example\n * ```typescript\n * const users = { john: 25, jane: 30, bob: 35 }\n * const greetings = mapValues(users, (age, name) => `${name} is ${age} years old`)\n * // Result: { john: 'john is 25 years old', jane: 'jane is 30 years old', bob: 'bob is 35 years old' }\n * ```\n *\n * @example\n * ```typescript\n * const data = { a: '1', b: '2', c: '3' }\n * const numbers = mapValues(data, (str) => parseInt(str, 10))\n * // Result: { a: 1, b: 2, c: 3 }\n * ```\n *\n * @public\n */\nexport function mapValues<ValueIn, ValueOut>(\n object: Record<string, ValueIn>,\n callback: (value: ValueIn, key: string) => ValueOut,\n): Record<string, ValueOut> {\n const result = {} as Record<string, ValueOut>\n for (const [key, value] of Object.entries(object)) {\n result[key] = callback(value, key)\n }\n return result\n}\n","/**\n * A TypeScript utility type that represents the entries of an object as a union of tuple types.\n * Each tuple contains a key-value pair where the key and value types are precisely typed\n * according to the input object type.\n *\n * @example\n * ```typescript\n * type MyObject = { a: 1; b: 'B' }\n * type MyEntries = ObjectEntries<MyObject>\n * // ^ [\"a\", 1] | [\"b\", \"B\"]\n * ```\n *\n * @public\n */\nexport type ObjectEntries<T extends Record<string, any>> = {\n [K in keyof T]: [K, T[K]]\n}[keyof T]\n\n/**\n * A type-safe wrapper around\n * [`Object.entries()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries)\n * that preserves the exact types of object keys and values. Unlike the standard\n * `Object.entries()` which returns `[string, any][]`, this function returns an\n * array of tuples where each tuple is precisely typed according to the input\n * object's structure.\n *\n * This is particularly useful when working with objects that have known, fixed\n * property types and you want to maintain type safety when iterating over\n * entries.\n *\n * @example\n * ```typescript\n * const myObject = { a: 1, b: 'hello', c: true } as const\n * const entries = objectEntries(myObject)\n * // Type: ([\"a\", 1] | [\"b\", \"hello\"] | [\"c\", true])[]\n *\n * for (const [key, value] of entries) {\n * // key is typed as \"a\" | \"b\" | \"c\"\n * // value is typed as 1 | \"hello\" | true\n * console.log(`${key}: ${value}`)\n * }\n * ```\n *\n * @example\n * ```typescript\n * interface User {\n * name: string\n * age: number\n * active: boolean\n * }\n *\n * const user: User = { name: 'Alice', age: 30, active: true }\n * const entries = objectEntries(user)\n * // Type: ([\"name\", string] | [\"age\", number] | [\"active\", boolean])[]\n * ```\n *\n * @public\n */\nexport function objectEntries<T extends Record<string, any>>(\n obj: T,\n): ObjectEntries<T>[] {\n return Object.entries(obj)\n}\n","/**\n * @internal\n */\nexport function objectGroupByPolyfill<K extends PropertyKey, T>(\n items: Iterable<T>,\n keySelector: (item: T, index: number) => K,\n): Partial<Record<K, T[]>> {\n const result: Partial<Record<K, T[]>> = {}\n let index = 0\n for (const item of items) {\n const key = keySelector(item, index)\n const group = result[key]\n if (group) {\n group.push(item)\n } else {\n result[key] = [item]\n }\n index++\n }\n return result\n}\n\n/**\n * A polyfill for the [`Object.groupBy()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/groupBy) static method.\n *\n * @public\n */\nexport function objectGroupBy<K extends PropertyKey, T>(\n items: Iterable<T>,\n keySelector: (item: T, index: number) => K,\n): Partial<Record<K, T[]>> {\n return Object.groupBy\n ? Object.groupBy(items, keySelector)\n : objectGroupByPolyfill(items, keySelector)\n}\n","/**\n * Creates a function that will only execute the provided function once.\n * Subsequent calls will return the cached result from the first execution.\n *\n * @param fn The function to execute once\n * @returns A function that will only execute the provided function once\n * @example\n * ```ts\n * const getValue = once(() => expensiveOperation())\n * getValue() // executes expensiveOperation\n * getValue() // returns cached result\n * ```\n */\nexport function once<T>(fn: () => T): () => T {\n let called = false\n let result: T\n return () => {\n if (!called) {\n result = fn()\n called = true\n // @ts-expect-error - micro-optimization for memory management\n fn = undefined\n }\n return result\n }\n}\n","/**\n * Returns a Promise that resolves after a specified number of milliseconds.\n *\n * @param ms - The number of milliseconds to wait.\n *\n * @example\n * ```js\n * await sleep(1000) // Wait 1 second\n * ```\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ocavue/utils",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.4.0",
|
|
5
5
|
"description": "A collection of utility functions for the browser and other environments",
|
|
6
6
|
"author": "ocavue <ocavue@gmail.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"dist"
|
|
38
38
|
],
|
|
39
39
|
"devDependencies": {
|
|
40
|
-
"@ocavue/eslint-config": "^3.
|
|
40
|
+
"@ocavue/eslint-config": "^3.10.0",
|
|
41
41
|
"@ocavue/tsconfig": "^0.6.2",
|
|
42
42
|
"@size-limit/preset-small-lib": "^12.0.0",
|
|
43
43
|
"@types/node": "^24.9.2",
|
package/src/checker.test.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { describe, expect, it } from 'vitest'
|
|
4
4
|
|
|
5
|
-
import { isMap, isObject, isSet } from './checker'
|
|
5
|
+
import { isMap, isNotNullish, isObject, isSet } from './checker'
|
|
6
6
|
|
|
7
7
|
describe('isObject', () => {
|
|
8
8
|
it('returns true for plain objects', () => {
|
|
@@ -72,3 +72,24 @@ describe('isSet', () => {
|
|
|
72
72
|
expect(isSet(42)).toBe(false)
|
|
73
73
|
})
|
|
74
74
|
})
|
|
75
|
+
|
|
76
|
+
describe('isNotNullish', () => {
|
|
77
|
+
it('returns false for null and undefined', () => {
|
|
78
|
+
expect(isNotNullish(null)).toBe(false)
|
|
79
|
+
expect(isNotNullish(undefined)).toBe(false)
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
it('returns true for non-nullish values', () => {
|
|
83
|
+
expect(isNotNullish(0)).toBe(true)
|
|
84
|
+
expect(isNotNullish(-1)).toBe(true)
|
|
85
|
+
expect(isNotNullish('')).toBe(true)
|
|
86
|
+
expect(isNotNullish('hello')).toBe(true)
|
|
87
|
+
expect(isNotNullish(true)).toBe(true)
|
|
88
|
+
expect(isNotNullish(false)).toBe(true)
|
|
89
|
+
expect(isNotNullish({})).toBe(true)
|
|
90
|
+
expect(isNotNullish([])).toBe(true)
|
|
91
|
+
expect(isNotNullish(new Map())).toBe(true)
|
|
92
|
+
expect(isNotNullish(new Set())).toBe(true)
|
|
93
|
+
expect(isNotNullish(0n)).toBe(true)
|
|
94
|
+
})
|
|
95
|
+
})
|
package/src/checker.ts
CHANGED
|
@@ -20,3 +20,10 @@ export function isMap(value: unknown): value is Map<unknown, unknown> {
|
|
|
20
20
|
export function isSet(value: unknown): value is Set<unknown> {
|
|
21
21
|
return value instanceof Set
|
|
22
22
|
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Returns true if the given value is not null or undefined.
|
|
26
|
+
*/
|
|
27
|
+
export function isNotNullish<T>(value: T): value is NonNullable<T> {
|
|
28
|
+
return value != null
|
|
29
|
+
}
|
package/src/map-values.ts
CHANGED
|
@@ -35,7 +35,7 @@ export function mapValues<ValueIn, ValueOut>(
|
|
|
35
35
|
object: Record<string, ValueIn>,
|
|
36
36
|
callback: (value: ValueIn, key: string) => ValueOut,
|
|
37
37
|
): Record<string, ValueOut> {
|
|
38
|
-
|
|
38
|
+
const result = {} as Record<string, ValueOut>
|
|
39
39
|
for (const [key, value] of Object.entries(object)) {
|
|
40
40
|
result[key] = callback(value, key)
|
|
41
41
|
}
|