feat(stdlib): new modules + eslint/tsconfig migration

- Add array/async/etc. modules and type tests; migrate to eslint flat config
  and composite tsconfig (vitest typecheck enabled).
- Fix PubSub.emit to snapshot listeners before iterating (stable EventEmitter
  semantics; avoids invoking listeners added during the same emit).
This commit is contained in:
2026-06-07 16:29:08 +07:00
parent 008d85a8fd
commit 96f4cba4a8
118 changed files with 3511 additions and 240 deletions
+35 -3
View File
@@ -27,8 +27,40 @@ export type ExtractFromCollection<O, K>
: never
: never;
type Get<O, K> = ExtractFromCollection<O, Path<K>>;
export type Get<O, K> = ExtractFromCollection<O, Path<K>>;
export function get<O extends Collection, K extends string>(obj: O, path: K) {
return path.split('.').reduce((acc, key) => (acc as any)?.[key], obj) as Get<O, K> | undefined;
/**
* @name get
* @category Collections
* @description Safely read a deeply nested value from a collection by a dot-separated path
*
* @param {Collection} obj - The source object or array
* @param {string} path - Dot-separated path, e.g. `'user.addresses.0.street'`
* @returns {Get<O, K> | undefined} The resolved value, or `undefined` if any segment is missing
*
* @example
* get({ user: { name: 'John' } }, 'user.name'); // 'John'
* get({ items: [{ id: 1 }] }, 'items.0.id'); // 1
* get({ a: 1 }, 'a.b.c'); // undefined
*
* @since 0.0.4
*/
export function get<O extends Collection, K extends string>(obj: O, path: K): Get<O, K> | undefined {
let value: any = obj;
let start = 0;
// Walk the path without allocating an intermediate array of segments.
for (let i = 0, len = path.length; i <= len; i++) {
// Split on '.' (char code 46) or the end of the string.
if (i !== len && path.charCodeAt(i) !== 46)
continue;
if (value === null || value === undefined)
return undefined;
value = value[path.slice(start, i)];
start = i + 1;
}
return value;
}